Implement LBS_COMBOBOX, and make use of it.
[wine] / programs / wineconsole / dialog.c
1 /* dialog management for wineconsole
2  * USER32 backend
3  * Copyright (c) 2001, 2002 Eric Pouech
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23
24 #define NONAMELESSUNION
25 #define NONAMELESSSTRUCT
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winnls.h"
31 #include "commctrl.h"
32 #include "prsht.h"
33 #include "winecon_user.h"
34
35 #include "wine/debug.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(wineconsole);
38
39 struct dialog_info
40 {
41     struct config_data  config;         /* configuration used for dialog box */
42     struct inner_data*  data;           /* pointer to current winecon info */
43     HWND                hDlg;           /* handle to active propsheet */
44     int                 nFont;          /* number of font size in size LB */
45     struct font_info
46     {
47         UINT                    height;
48         UINT                    weight;
49         WCHAR                   faceName[LF_FACESIZE];
50     }                   *font;          /* array of nFont. index sync'ed with SIZE LB */
51 };
52
53 /******************************************************************
54  *              WCUSER_OptionDlgProc
55  *
56  * Dialog prop for the option property sheet
57  */
58 static BOOL WINAPI WCUSER_OptionDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
59 {
60     struct dialog_info*         di;
61     unsigned                    idc;
62
63     switch (msg)
64     {
65     case WM_INITDIALOG:
66         di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
67         di->hDlg = hDlg;
68         SetWindowLong(hDlg, DWL_USER, (DWORD)di);
69
70         if (di->config.cursor_size <= 25)       idc = IDC_OPT_CURSOR_SMALL;
71         else if (di->config.cursor_size <= 50)  idc = IDC_OPT_CURSOR_MEDIUM;
72         else                                    idc = IDC_OPT_CURSOR_LARGE;
73         SendDlgItemMessage(hDlg, idc, BM_SETCHECK, BST_CHECKED, 0L);
74         SetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, WINECON_GetHistorySize(di->data->hConIn),  FALSE);
75         SendDlgItemMessage(hDlg, IDC_OPT_HIST_NODOUBLE, BM_SETCHECK,
76                            (di->config.history_nodup) ? BST_CHECKED : BST_UNCHECKED, 0L);
77         SendDlgItemMessage(hDlg, IDC_OPT_CONF_CTRL, BM_SETCHECK,
78                            (di->config.menu_mask & MK_CONTROL) ? BST_CHECKED : BST_UNCHECKED, 0L);
79         SendDlgItemMessage(hDlg, IDC_OPT_CONF_SHIFT, BM_SETCHECK,
80                            (di->config.menu_mask & MK_SHIFT) ? BST_CHECKED : BST_UNCHECKED, 0L);
81         SendDlgItemMessage(hDlg, IDC_OPT_QUICK_EDIT, BM_SETCHECK,
82                            (di->config.quick_edit) ? BST_CHECKED : BST_UNCHECKED, 0L);
83         return FALSE; /* because we set the focus */
84     case WM_COMMAND:
85         break;
86     case WM_NOTIFY:
87     {
88         NMHDR*  nmhdr = (NMHDR*)lParam;
89         DWORD   val;
90         BOOL    done;
91
92         di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
93
94         switch (nmhdr->code)
95         {
96         case PSN_SETACTIVE:
97             /* needed in propsheet to keep properly the selected radio button
98              * otherwise, the focus would be set to the first tab stop in the
99              * propsheet, which would always activate the first radio button
100              */
101             if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED)
102                 idc = IDC_OPT_CURSOR_SMALL;
103             else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED)
104                 idc = IDC_OPT_CURSOR_MEDIUM;
105             else
106                 idc = IDC_OPT_CURSOR_LARGE;
107             PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hDlg, idc), TRUE);
108             di->hDlg = hDlg;
109             break;
110         case PSN_APPLY:
111             if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_SMALL) == BST_CHECKED) val = 25;
112             else if (IsDlgButtonChecked(hDlg, IDC_OPT_CURSOR_MEDIUM) == BST_CHECKED) val = 50;
113             else val = 100;
114             di->config.cursor_size = val;
115
116             val = GetDlgItemInt(hDlg, IDC_OPT_HIST_SIZE, &done, FALSE);
117             if (done) di->config.history_size = val;
118
119             val = (IsDlgButtonChecked(hDlg, IDC_OPT_HIST_NODOUBLE) & BST_CHECKED) ? TRUE : FALSE;
120             di->config.history_nodup = val;
121
122             val = 0;
123             if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_CTRL) & BST_CHECKED)  val |= MK_CONTROL;
124             if (IsDlgButtonChecked(hDlg, IDC_OPT_CONF_SHIFT) & BST_CHECKED) val |= MK_SHIFT;
125             di->config.menu_mask = val;
126
127             val = (IsDlgButtonChecked(hDlg, IDC_OPT_QUICK_EDIT) & BST_CHECKED) ? TRUE : FALSE;
128             di->config.quick_edit = val;
129
130             SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
131             return TRUE;
132         default:
133             return FALSE;
134         }
135         break;
136     }
137     default:
138         return FALSE;
139     }
140     return TRUE;
141 }
142
143 /******************************************************************
144  *              WCUSER_FontPreviewProc
145  *
146  * Window proc for font previewer in font property sheet
147  */
148 static LRESULT WINAPI WCUSER_FontPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
149 {
150     switch (msg)
151     {
152     case WM_CREATE:
153         SetWindowLong(hWnd, 0, 0);
154         break;
155     case WM_GETFONT:
156         return GetWindowLong(hWnd, 0);
157     case WM_SETFONT:
158         SetWindowLong(hWnd, 0, wParam);
159         if (LOWORD(lParam))
160         {
161             InvalidateRect(hWnd, NULL, TRUE);
162             UpdateWindow(hWnd);
163         }
164         break;
165     case WM_DESTROY:
166         {
167             HFONT hFont = (HFONT)GetWindowLong(hWnd, 0L);
168             if (hFont) DeleteObject(hFont);
169         }
170         break;
171     case WM_PAINT:
172         {
173             PAINTSTRUCT         ps;
174             int                 font_idx;
175             int                 size_idx;
176             struct dialog_info* di;
177             HFONT               hFont, hOldFont;
178
179             di = (struct dialog_info*)GetWindowLong(GetParent(hWnd), DWL_USER);
180             BeginPaint(hWnd, &ps);
181
182             font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
183             size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
184
185             hFont = (HFONT)GetWindowLong(hWnd, 0L);
186             if (hFont)
187             {
188                 WCHAR   buf1[256];
189                 WCHAR   buf2[256];
190                 int     len1, len2;
191
192                 len1 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_1,
193                                   buf1, sizeof(buf1) / sizeof(WCHAR));
194                 len2 = LoadString(GetModuleHandle(NULL), IDS_FNT_PREVIEW_2,
195                                   buf2, sizeof(buf2) / sizeof(WCHAR));
196                 buf1[len1] = buf2[len2] = 0;
197                 if (len1)
198                 {
199                     hOldFont = SelectObject(ps.hdc, hFont);
200                     SetBkColor(ps.hdc, WCUSER_ColorMap[GetWindowLong(GetDlgItem(di->hDlg, IDC_FNT_COLOR_BK), 0)]);
201                     SetTextColor(ps.hdc, WCUSER_ColorMap[GetWindowLong(GetDlgItem(di->hDlg, IDC_FNT_COLOR_FG), 0)]);
202                     TextOut(ps.hdc, 0, 0, buf1, len1);
203                     if (len2)
204                         TextOut(ps.hdc, 0, di->font[size_idx].height, buf2, len2);
205                     SelectObject(ps.hdc, hOldFont);
206                 }
207             }
208             EndPaint(hWnd, &ps);
209         }
210         break;
211     default:
212         return DefWindowProc(hWnd, msg, wParam, lParam);
213     }
214     return 0L;
215 }
216
217 /******************************************************************
218  *              WCUSER_ColorPreviewProc
219  *
220  * Window proc for color previewer in font property sheet
221  */
222 static LRESULT WINAPI WCUSER_ColorPreviewProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
223 {
224     switch (msg)
225     {
226     case WM_PAINT:
227         {
228             PAINTSTRUCT     ps;
229             int             i, step;
230             RECT            client, r;
231             HBRUSH          hbr;
232
233             BeginPaint(hWnd, &ps);
234             GetClientRect(hWnd, &client);
235             step = client.right / 8;
236
237             for (i = 0; i < 16; i++)
238             {
239                 r.top = (i / 8) * (client.bottom / 2);
240                 r.bottom = r.top + client.bottom / 2;
241                 r.left = (i & 7) * step;
242                 r.right = r.left + step;
243                 hbr = CreateSolidBrush(WCUSER_ColorMap[i]);
244                 FillRect(ps.hdc, &r, hbr);
245                 DeleteObject(hbr);
246                 if (GetWindowLong(hWnd, 0) == i)
247                 {
248                     HPEN        hOldPen;
249                     int         i = 2;
250
251                     hOldPen = SelectObject(ps.hdc, GetStockObject(WHITE_PEN));
252                     r.right--; r.bottom--;
253                     for (;;)
254                     {
255                         MoveToEx(ps.hdc, r.left, r.bottom, NULL);
256                         LineTo(ps.hdc, r.left, r.top);
257                         LineTo(ps.hdc, r.right, r.top);
258                         SelectObject(ps.hdc, GetStockObject(BLACK_PEN));
259                         LineTo(ps.hdc, r.right, r.bottom);
260                         LineTo(ps.hdc, r.left, r.bottom);
261
262                         if (--i == 0) break;
263                         r.left++; r.top++; r.right--; r.bottom--;
264                         SelectObject(ps.hdc, GetStockObject(WHITE_PEN));
265                     }
266                     SelectObject(ps.hdc, hOldPen);
267                 }
268             }
269             EndPaint(hWnd, &ps);
270             break;
271         }
272     case WM_LBUTTONDOWN:
273         {
274             int             i, step;
275             RECT            client;
276
277             GetClientRect(hWnd, &client);
278             step = client.right / 8;
279             i = (HIWORD(lParam) >= client.bottom / 2) ? 8 : 0;
280             i += LOWORD(lParam) / step;
281             SetWindowLong(hWnd, 0, i);
282             InvalidateRect(GetDlgItem(GetParent(hWnd), IDC_FNT_PREVIEW), NULL, FALSE);
283             InvalidateRect(hWnd, NULL, FALSE);
284         }
285         break;
286     default:
287         return DefWindowProc(hWnd, msg, wParam, lParam);
288     }
289     return 0L;
290 }
291
292 /******************************************************************
293  *              font_enum
294  *
295  * enumerates all the font names with at least one valid font
296  */
297 static int CALLBACK font_enum_size2(const LOGFONT* lf, const TEXTMETRIC* tm,
298                                     DWORD FontType, LPARAM lParam)
299 {
300     struct dialog_info* di = (struct dialog_info*)lParam;
301
302     WCUSER_DumpTextMetric(tm, FontType);
303     if (WCUSER_ValidateFontMetric(di->data, tm, FontType))
304     {
305         di->nFont++;
306     }
307
308     return 1;
309 }
310
311 static int CALLBACK font_enum(const LOGFONT* lf, const TEXTMETRIC* tm,
312                               DWORD FontType, LPARAM lParam)
313 {
314     struct dialog_info* di = (struct dialog_info*)lParam;
315
316     WCUSER_DumpLogFont("DlgFamily: ", lf, FontType);
317     if (WCUSER_ValidateFont(di->data, lf))
318     {
319         if (FontType & RASTER_FONTTYPE)
320         {
321             di->nFont = 0;
322             EnumFontFamilies(PRIVATE(di->data)->hMemDC, lf->lfFaceName, font_enum_size2, (LPARAM)di);
323         }
324         else
325             di->nFont = 1;
326
327         if (di->nFont)
328         {
329             SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_ADDSTRING,
330                                0, (LPARAM)lf->lfFaceName);
331         }
332     }
333
334     return 1;
335 }
336
337 /******************************************************************
338  *              font_enum_size
339  *
340  *
341  */
342 static int CALLBACK font_enum_size(const LOGFONT* lf, const TEXTMETRIC* tm,
343                                    DWORD FontType, LPARAM lParam)
344 {
345     struct dialog_info* di = (struct dialog_info*)lParam;
346     WCHAR               buf[32];
347     static const WCHAR  fmt[] = {'%','l','d',0};
348
349     WCUSER_DumpTextMetric(tm, FontType);
350     if (di->nFont == 0 && !(FontType & RASTER_FONTTYPE))
351     {
352         static const int sizes[] = {8,9,10,11,12,14,16,18,20,22,24,26,28,36,48,72};
353         int i;
354
355         di->nFont = sizeof(sizes) / sizeof(sizes[0]);
356         di->font = HeapAlloc(GetProcessHeap(), 0, di->nFont * sizeof(di->font[0]));
357         for (i = 0; i < di->nFont; i++)
358         {
359             /* drop sizes where window size wouldn't fit on screen */
360             if (sizes[i] * di->data->curcfg.win_height > GetSystemMetrics(SM_CYSCREEN))
361             {
362                 di->nFont = i;
363                 break;
364             }
365             di->font[i].height = sizes[i];
366             di->font[i].weight = 400;
367             lstrcpy(di->font[i].faceName, lf->lfFaceName);
368             wsprintf(buf, fmt, sizes[i]);
369             SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, i, (LPARAM)buf);
370         }
371         /* don't need to enumerate other */
372         return 0;
373     }
374
375     if (WCUSER_ValidateFontMetric(di->data, tm, FontType))
376     {
377         int     idx;
378
379         /* we want the string to be sorted with a numeric order, not a lexicographic...
380          * do the job by hand... get where to insert the new string
381          */
382         for (idx = 0; idx < di->nFont && tm->tmHeight > di->font[idx].height; idx++);
383         while (idx < di->nFont &&
384                tm->tmHeight == di->font[idx].height &&
385                tm->tmWeight > di->font[idx].weight)
386             idx++;
387         if (idx == di->nFont ||
388             tm->tmHeight != di->font[idx].height ||
389             tm->tmWeight < di->font[idx].weight)
390         {
391             /* here we need to add the new entry */
392             wsprintf(buf, fmt, tm->tmHeight);
393             SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_INSERTSTRING, idx, (LPARAM)buf);
394
395             /* now grow our arrays and insert the values at the same index than in the list box */
396             di->font = HeapReAlloc(GetProcessHeap(), 0, di->font, sizeof(*di->font) * (di->nFont + 1));
397             if (idx != di->nFont)
398                 memmove(&di->font[idx + 1], &di->font[idx], (di->nFont - idx) * sizeof(*di->font));
399             di->font[idx].height = tm->tmHeight;
400             di->font[idx].weight = tm->tmWeight;
401             lstrcpy(di->font[idx].faceName, lf->lfFaceName);
402             di->nFont++;
403         }
404     }
405     return 1;
406 }
407
408 /******************************************************************
409  *              select_font
410  *
411  *
412  */
413 static BOOL  select_font(struct dialog_info* di)
414 {
415     int         font_idx, size_idx;
416     WCHAR       buf[256];
417     WCHAR       fmt[128];
418     LOGFONT     lf;
419     HFONT       hFont, hOldFont;
420     struct config_data config;
421
422     font_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
423     size_idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
424
425     if (font_idx < 0 || size_idx < 0 || size_idx >= di->nFont)
426         return FALSE;
427
428     WCUSER_FillLogFont(&lf, di->font[size_idx].faceName,
429                        di->font[size_idx].height, di->font[size_idx].weight);
430     hFont = WCUSER_CopyFont(&config, PRIVATE(di->data)->hWnd, &lf);
431     if (!hFont) return FALSE;
432
433     if (config.cell_height != di->font[size_idx].height)
434         WINE_TRACE("mismatched heights (%u<>%u)\n",
435                    config.cell_height, di->font[size_idx].height);
436     hOldFont = (HFONT)SendDlgItemMessage(di->hDlg, IDC_FNT_PREVIEW, WM_GETFONT, 0L, 0L);
437
438     SendDlgItemMessage(di->hDlg, IDC_FNT_PREVIEW, WM_SETFONT, (DWORD)hFont, TRUE);
439     if (hOldFont) DeleteObject(hOldFont);
440
441     LoadString(GetModuleHandle(NULL), IDS_FNT_DISPLAY, fmt, sizeof(fmt) / sizeof(WCHAR));
442     wsprintf(buf, fmt, config.cell_width, config.cell_height);
443
444     SendDlgItemMessage(di->hDlg, IDC_FNT_FONT_INFO, WM_SETTEXT, 0, (LPARAM)buf);
445
446     return TRUE;
447 }
448
449 /******************************************************************
450  *              fill_list_size
451  *
452  * fills the size list box according to selected family in font LB
453  */
454 static BOOL  fill_list_size(struct dialog_info* di, BOOL doInit)
455 {
456     int         idx;
457     WCHAR       lfFaceName[LF_FACESIZE];
458
459     idx = SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETCURSEL, 0L, 0L);
460     if (idx < 0) return FALSE;
461
462     SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_GETTEXT, idx, (LPARAM)lfFaceName);
463     SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_RESETCONTENT, 0L, 0L);
464     if (di->font) HeapFree(GetProcessHeap(), 0, di->font);
465     di->nFont = 0;
466     di->font = NULL;
467
468     EnumFontFamilies(PRIVATE(di->data)->hMemDC, lfFaceName, font_enum_size, (LPARAM)di);
469
470     if (doInit)
471     {
472         int     ref = -1;
473
474         for (idx = 0; idx < di->nFont; idx++)
475         {
476             if (!lstrcmp(di->font[idx].faceName, di->config.face_name) &&
477                 di->font[idx].height == di->config.cell_height &&
478                 di->font[idx].weight == di->config.font_weight)
479             {
480                 if (ref == -1) ref = idx;
481                 else WINE_TRACE("Several matches found: ref=%d idx=%d\n", ref, idx);
482             }
483         }
484         idx = (ref == -1) ? 0 : ref;
485     }
486     else
487         idx = 0;
488     SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_SIZE, LB_SETCURSEL, idx, 0L);
489     select_font(di);
490     return TRUE;
491 }
492
493 /******************************************************************
494  *              fill_list_font
495  *
496  * Fills the font LB
497  */
498 static BOOL fill_list_font(struct dialog_info* di)
499 {
500     SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_RESETCONTENT, 0L, 0L);
501     EnumFontFamilies(PRIVATE(di->data)->hMemDC, NULL, font_enum, (LPARAM)di);
502     if (SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SELECTSTRING,
503                            (WPARAM)-1, (LPARAM)di->config.face_name) == LB_ERR)
504         SendDlgItemMessage(di->hDlg, IDC_FNT_LIST_FONT, LB_SETCURSEL, 0L, 0L);
505     fill_list_size(di, TRUE);
506     return TRUE;
507 }
508
509 /******************************************************************
510  *              WCUSER_FontDlgProc
511  *
512  * Dialog proc for the Font property sheet
513  */
514 static BOOL WINAPI WCUSER_FontDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
515 {
516     struct dialog_info*         di;
517
518     switch (msg)
519     {
520     case WM_INITDIALOG:
521         di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
522         di->hDlg = hDlg;
523         SetWindowLong(hDlg, DWL_USER, (DWORD)di);
524         /* remove dialog from this control, font will be reset when listboxes are filled */
525         SendDlgItemMessage(hDlg, IDC_FNT_PREVIEW, WM_SETFONT, 0L, 0L);
526         fill_list_font(di);
527         SetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_BK), 0, (di->config.def_attr >> 4) & 0x0F);
528         SetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_FG), 0, di->config.def_attr & 0x0F);
529         break;
530     case WM_COMMAND:
531         di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
532         switch (LOWORD(wParam))
533         {
534         case IDC_FNT_LIST_FONT:
535             if (HIWORD(wParam) == LBN_SELCHANGE)
536             {
537                 fill_list_size(di, FALSE);
538             }
539             break;
540         case IDC_FNT_LIST_SIZE:
541             if (HIWORD(wParam) == LBN_SELCHANGE)
542             {
543                 select_font(di);
544             }
545             break;
546         }
547         break;
548     case WM_NOTIFY:
549     {
550         NMHDR*  nmhdr = (NMHDR*)lParam;
551         DWORD   val;
552
553         di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
554         switch (nmhdr->code)
555         {
556         case PSN_SETACTIVE:
557             di->hDlg = hDlg;
558             break;
559         case PSN_APPLY:
560             val = SendDlgItemMessage(hDlg, IDC_FNT_LIST_SIZE, LB_GETCURSEL, 0L, 0L);
561
562             if (val < di->nFont)
563             {
564                 LOGFONT lf;
565
566                 WCUSER_FillLogFont(&lf, di->font[val].faceName,
567                                    di->font[val].height, di->font[val].weight);
568                 DeleteObject(WCUSER_CopyFont(&di->config,
569                                              PRIVATE(di->data)->hWnd, &lf));
570             }
571
572             val = (GetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_BK), 0) << 4) |
573                 GetWindowLong(GetDlgItem(hDlg, IDC_FNT_COLOR_FG), 0);
574             di->config.def_attr = val;
575
576             SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
577             return TRUE;
578         default:
579             return FALSE;
580         }
581         break;
582     }
583     default:
584         return FALSE;
585     }
586     return TRUE;
587 }
588
589 /******************************************************************
590  *              WCUSER_ConfigDlgProc
591  *
592  * Dialog proc for the config property sheet
593  */
594 static BOOL WINAPI WCUSER_ConfigDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
595 {
596     struct dialog_info*         di;
597
598     switch (msg)
599     {
600     case WM_INITDIALOG:
601         di = (struct dialog_info*)((PROPSHEETPAGEA*)lParam)->lParam;
602         di->hDlg = hDlg;
603         SetWindowLong(hDlg, DWL_USER, (DWORD)di);
604         SetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,   di->config.sb_width,   FALSE);
605         SetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT,  di->config.sb_height,  FALSE);
606         SetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  di->config.win_width,  FALSE);
607         SetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, di->config.win_height, FALSE);
608         SendDlgItemMessage(hDlg, IDC_CNF_CLOSE_EXIT, BM_SETCHECK,
609                            (di->config.exit_on_die) ? BST_CHECKED : BST_UNCHECKED, 0L);
610         {
611             static const WCHAR s1[] = {'W','i','n','3','2',0};
612             static const WCHAR s2[] = {'E','m','a','c','s',0};
613
614             SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_ADDSTRING,
615                                0, (LPARAM)s1);
616             SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_ADDSTRING,
617                                0, (LPARAM)s2);
618             SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_SETCURSEL,
619                                di->config.edition_mode, 0);
620         }
621
622         break;
623     case WM_COMMAND:
624         di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
625         switch (LOWORD(wParam))
626         {
627         }
628         break;
629     case WM_NOTIFY:
630     {
631         NMHDR*          nmhdr = (NMHDR*)lParam;
632         int             win_w, win_h, sb_w, sb_h;
633         BOOL            st1, st2;
634
635         di = (struct dialog_info*)GetWindowLong(hDlg, DWL_USER);
636         switch (nmhdr->code)
637         {
638         case PSN_SETACTIVE:
639             di->hDlg = hDlg;
640             break;
641         case PSN_APPLY:
642             sb_w = GetDlgItemInt(hDlg, IDC_CNF_SB_WIDTH,  &st1, FALSE);
643             sb_h = GetDlgItemInt(hDlg, IDC_CNF_SB_HEIGHT, &st2, FALSE);
644             if (!st1 || ! st2)
645             {
646                 SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_INVALID);        
647                 return TRUE;
648             }
649             win_w = GetDlgItemInt(hDlg, IDC_CNF_WIN_WIDTH,  &st1, FALSE);
650             win_h = GetDlgItemInt(hDlg, IDC_CNF_WIN_HEIGHT, &st2, FALSE);
651             if (!st1 || !st2)
652             {
653                 SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_INVALID); 
654                 return TRUE;
655             }
656             if (win_w > sb_w || win_h > sb_h)
657             {
658                 WCHAR   cap[256];
659                 WCHAR   txt[256];
660
661                 LoadString(GetModuleHandle(NULL), IDS_DLG_TIT_ERROR, 
662                            cap, sizeof(cap) / sizeof(WCHAR));
663                 LoadString(GetModuleHandle(NULL), IDS_DLG_ERR_SBWINSIZE, 
664                            txt, sizeof(txt) / sizeof(WCHAR));
665                 
666                 MessageBox(hDlg, txt, cap, MB_OK);
667                 SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_INVALID); 
668                 return TRUE;
669             }
670             di->config.win_width  = win_w;
671             di->config.win_height = win_h;
672             di->config.sb_width  = sb_w;
673             di->config.sb_height = sb_h;
674
675             di->config.exit_on_die = IsDlgButtonChecked(hDlg, IDC_CNF_CLOSE_EXIT) ? 1 : 0;
676             di->config.edition_mode = SendDlgItemMessage(hDlg, IDC_CNF_EDITION_MODE, CB_GETCURSEL,
677                                                          0, 0);
678             SetWindowLong(hDlg, DWL_MSGRESULT, PSNRET_NOERROR);
679             return TRUE;
680         default:
681             return FALSE;
682         }
683         break;
684     }
685     default:
686         return FALSE;
687     }
688     return TRUE;
689 }
690
691 /******************************************************************
692  *              WCUSER_SaveDlgProc
693  *
694  *      Dialog Procedure for choosing how to handle modification to the
695  * console settings.
696  */
697 static BOOL WINAPI WCUSER_SaveDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
698 {
699     switch (msg)
700     {
701     case WM_INITDIALOG:
702         break;
703     case WM_COMMAND:
704         switch (LOWORD(wParam))
705         {
706         case IDOK:
707             EndDialog(hDlg,
708                       (IsDlgButtonChecked(hDlg, IDC_SAV_SAVE) == BST_CHECKED) ?
709                       IDC_SAV_SAVE : IDC_SAV_SESSION);
710             break;
711         case IDCANCEL:
712             EndDialog(hDlg, IDCANCEL); break;
713         }
714         break;
715     default:
716         return FALSE;
717     }
718     return TRUE;
719 }
720
721 /******************************************************************
722  *              WCUSER_GetProperties
723  *
724  * Runs the dialog box to set up the wineconsole options
725  */
726 BOOL WCUSER_GetProperties(struct inner_data* data, BOOL current)
727 {
728     HPROPSHEETPAGE      psPage[3];
729     PROPSHEETPAGE       psp;
730     PROPSHEETHEADER     psHead;
731     WCHAR               buff[256];
732     WNDCLASS            wndclass;
733     static const WCHAR szFntPreview[] = {'W','i','n','e','C','o','n','F','o','n','t','P','r','e','v','i','e','w',0};
734     static const WCHAR szColorPreview[] = {'W','i','n','e','C','o','n','C','o','l','o','r','P','r','e','v','i','e','w',0};
735     struct dialog_info  di;
736     struct config_data  defcfg;
737     struct config_data* refcfg;
738     BOOL                save, modify_session;
739
740     InitCommonControls();
741
742     di.data = data;
743     if (current)
744     {
745         refcfg = &data->curcfg;
746         save = FALSE;
747     }
748     else
749     {
750         WINECON_RegLoad(NULL, refcfg = &defcfg);
751         save = TRUE;
752     }
753     di.config = *refcfg;
754     di.nFont = 0;
755     di.font = NULL;
756
757     modify_session = FALSE;
758
759     wndclass.style         = 0;
760     wndclass.lpfnWndProc   = WCUSER_FontPreviewProc;
761     wndclass.cbClsExtra    = 0;
762     wndclass.cbWndExtra    = 4; /* for hFont */
763     wndclass.hInstance     = GetModuleHandle(NULL);
764     wndclass.hIcon         = 0;
765     wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
766     wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
767     wndclass.lpszMenuName  = NULL;
768     wndclass.lpszClassName = szFntPreview;
769     RegisterClass(&wndclass);
770
771     wndclass.style         = 0;
772     wndclass.lpfnWndProc   = WCUSER_ColorPreviewProc;
773     wndclass.cbClsExtra    = 0;
774     wndclass.cbWndExtra    = sizeof(DWORD);
775     wndclass.hInstance     = GetModuleHandle(NULL);
776     wndclass.hIcon         = 0;
777     wndclass.hCursor       = LoadCursor(0, IDC_ARROW);
778     wndclass.hbrBackground = GetStockObject(BLACK_BRUSH);
779     wndclass.lpszMenuName  = NULL;
780     wndclass.lpszClassName = szColorPreview;
781     RegisterClass(&wndclass);
782
783     memset(&psp, 0, sizeof(psp));
784     psp.dwSize = sizeof(psp);
785     psp.dwFlags = 0;
786     psp.hInstance = wndclass.hInstance;
787     psp.lParam = (LPARAM)&di;
788
789     psp.u.pszTemplate = MAKEINTRESOURCE(IDD_OPTION);
790     psp.pfnDlgProc = WCUSER_OptionDlgProc;
791     psPage[0] = CreatePropertySheetPage(&psp);
792
793     psp.u.pszTemplate = MAKEINTRESOURCE(IDD_FONT);
794     psp.pfnDlgProc = WCUSER_FontDlgProc;
795     psPage[1] = CreatePropertySheetPage(&psp);
796
797     psp.u.pszTemplate = MAKEINTRESOURCE(IDD_CONFIG);
798     psp.pfnDlgProc = WCUSER_ConfigDlgProc;
799     psPage[2] = CreatePropertySheetPage(&psp);
800
801     memset(&psHead, 0, sizeof(psHead));
802     psHead.dwSize = sizeof(psHead);
803
804     if (!LoadString(GetModuleHandle(NULL),
805                     (current) ? IDS_DLG_TIT_CURRENT : IDS_DLG_TIT_DEFAULT,
806                     buff, sizeof(buff) / sizeof(buff[0])))
807     {
808         buff[0] = 'S';
809         buff[1] = 'e';
810         buff[2] = 't';
811         buff[3] = 'u';
812         buff[4] = 'p';
813         buff[5] = '\0';
814     }
815
816     psHead.pszCaption = buff;
817     psHead.nPages = 3;
818     psHead.hwndParent = PRIVATE(data)->hWnd;
819     psHead.u3.phpage = psPage;
820
821     WINECON_DumpConfig("init", refcfg);
822
823     PropertySheet(&psHead);
824
825     if (memcmp(refcfg, &di.config, sizeof(*refcfg)) == 0)
826         return TRUE;
827
828     WINECON_DumpConfig("ref", refcfg);
829     WINECON_DumpConfig("cur", &di.config);
830     if (refcfg == &data->curcfg)
831     {
832         switch (DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_SAVE_SETTINGS),
833                           PRIVATE(data)->hWnd, WCUSER_SaveDlgProc))
834         {
835         case IDC_SAV_SAVE:      save = TRUE; modify_session = TRUE; break;
836         case IDC_SAV_SESSION:   modify_session = TRUE; break;
837         case IDCANCEL:          break;
838         default: WINE_ERR("ooch\n");
839         }
840     }
841
842     if (modify_session) WINECON_SetConfig(data, &di.config, FALSE);
843     if (save)           WINECON_RegSave(&di.config);
844
845     return TRUE;
846 }