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