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