xref: /reactos/dll/cpl/console/layout.c (revision ccef43f3)
1 /*
2  * PROJECT:         ReactOS Console Configuration DLL
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            dll/cpl/console/layout.c
5  * PURPOSE:         Layout dialog
6  * PROGRAMMERS:     Johannes Anderwald (johannes.anderwald@reactos.org)
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 #include "console.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* CONSOLE WINDOW PREVIEW Control *********************************************/
16 
17 #define WIN_PREVIEW_CLASS L"WinPreview"
18 
19 typedef struct _WINPREV_DATA
20 {
21     HWND hWnd;      // The window which this structure refers to
22     RECT rcMaxArea; // Maximum rectangle in which the preview window can be sized
23     SIZE siPreview; // Actual size of the preview window
24     SIZE siVirtScr; // Width and Height of the virtual screen
25     PVOID pData;    // Private data
26 } WINPREV_DATA, *PWINPREV_DATA;
27 
28 static LRESULT CALLBACK
29 WinPrevProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
30 
31 BOOL
32 RegisterWinPrevClass(
33     IN HINSTANCE hInstance)
34 {
35     WNDCLASSW WndClass;
36 
37     WndClass.lpszClassName = WIN_PREVIEW_CLASS;
38     WndClass.lpfnWndProc = WinPrevProc;
39     WndClass.style = 0;
40     WndClass.hInstance = hInstance;
41     WndClass.hIcon = NULL;
42     WndClass.hCursor = LoadCursorW(NULL, MAKEINTRESOURCEW(IDC_ARROW));
43     WndClass.hbrBackground =  (HBRUSH)(COLOR_BACKGROUND + 1);
44     WndClass.lpszMenuName = NULL;
45     WndClass.cbClsExtra = 0;
46     WndClass.cbWndExtra = 0; // sizeof(PWINPREV_DATA);
47 
48     return (RegisterClassW(&WndClass) != 0);
49 }
50 
51 BOOL
52 UnRegisterWinPrevClass(
53     IN HINSTANCE hInstance)
54 {
55     return UnregisterClassW(WIN_PREVIEW_CLASS, hInstance);
56 }
57 
58 static VOID
59 WinPrev_OnDisplayChange(
60     IN PWINPREV_DATA pData)
61 {
62     // RECT rcNew;
63 
64     pData->siVirtScr.cx = GetSystemMetrics(SM_CXVIRTUALSCREEN);
65     pData->siVirtScr.cy = GetSystemMetrics(SM_CYVIRTUALSCREEN);
66 
67     /*
68      * The rescaling factor "siPreview / siVirtScr" should be the minimum of the ratios
69      *    pData->rcMaxArea.right  / pData->siVirtScr.cx , and
70      *    pData->rcMaxArea.bottom / pData->siVirtScr.cy ,
71      * or equivalently, the maximum of the inverse of these ratios.
72      * This condition is equivalent to the following inequality being tested.
73      */
74     // if (pData->siVirtScr.cx / pData->rcMaxArea.right >= pData->siVirtScr.cy / pData->rcMaxArea.bottom)
75     if (pData->siVirtScr.cx * pData->rcMaxArea.bottom >= pData->siVirtScr.cy * pData->rcMaxArea.right)
76     {
77         pData->siPreview.cx = MulDiv(pData->siVirtScr.cx, pData->rcMaxArea.right, pData->siVirtScr.cx);
78         pData->siPreview.cy = MulDiv(pData->siVirtScr.cy, pData->rcMaxArea.right, pData->siVirtScr.cx);
79     }
80     else
81     {
82         pData->siPreview.cx = MulDiv(pData->siVirtScr.cx, pData->rcMaxArea.bottom, pData->siVirtScr.cy);
83         pData->siPreview.cy = MulDiv(pData->siVirtScr.cy, pData->rcMaxArea.bottom, pData->siVirtScr.cy);
84     }
85 
86     /*
87      * Now, the lengths in screen-units can be rescaled into preview-units with:
88      *    MulDiv(cx, pData->siPreview.cx, pData->siVirtScr.cx);
89      * and:
90      *    MulDiv(cy, pData->siPreview.cy, pData->siVirtScr.cy);
91      */
92 
93 #if 0 // TODO: Investigate!
94     /*
95      * Since both rcMaxArea and siPreview are client window area sizes,
96      * transform them into window sizes.
97      */
98     SetRect(&rcNew, 0, 0, pData->siPreview.cx, pData->siPreview.cy);
99     AdjustWindowRect(&rcNew,
100                      WS_BORDER,
101                      // GetWindowLongPtrW(pData->hWnd, GWL_STYLE) & ~WS_OVERLAPPED,
102                      FALSE);
103     OffsetRect(&rcNew, -rcNew.left, -rcNew.top);
104     rcNew.right += 2;
105     rcNew.bottom += 2;
106 #endif
107 
108     SetWindowPos(pData->hWnd,
109                  0 /* HWND_TOP */,
110                  0, 0,
111                  pData->siPreview.cx, pData->siPreview.cy,
112                  // rcNew.right, rcNew.bottom,
113                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE);
114 }
115 
116 #define RescaleCX(pData, len)   \
117     MulDiv((len), (pData)->siPreview.cx, (pData)->siVirtScr.cx)
118 
119 #define RescaleCY(pData, len)   \
120     MulDiv((len), (pData)->siPreview.cy, (pData)->siVirtScr.cy)
121 
122 #define RescaleRect(pData, rect)    \
123 do { \
124     (rect).left   = RescaleCX((pData), (rect).left);    \
125     (rect).right  = RescaleCX((pData), (rect).right);   \
126     (rect).top    = RescaleCY((pData), (rect).top);     \
127     (rect).bottom = RescaleCY((pData), (rect).bottom);  \
128 } while (0)
129 
130 #if 0
131 static VOID
132 WinPrev_OnSize(VOID)
133 {
134 }
135 #endif
136 
137 static VOID
138 WinPrev_OnDraw(
139     IN HDC hDC,
140     IN PWINPREV_DATA pData)
141 {
142     PCONSOLE_STATE_INFO pConInfo = (PCONSOLE_STATE_INFO)pData->pData;
143     HBRUSH hBrush;
144     RECT rcWin, fRect;
145     SIZE /*siBorder,*/ siFrame, siButton, siScroll;
146     SIZE resize;
147 
148     RECT rcItem;
149 
150     GetClientRect(pData->hWnd, &rcItem);
151 
152     /*
153      * Retrieve some system metrics and rescale them.
154      * They will be added separately, so that to always round the sizes up.
155      */
156 
157     /* Don't care about border as it is almost always 1 and <= frame size */
158     /* Example: Frame = 4, or 13 ... while Border = 1 */
159     // siBorder.cx = GetSystemMetrics(SM_CXBORDER);
160     // siBorder.cy = GetSystemMetrics(SM_CYBORDER);
161 
162     /* Window frame size */
163     siFrame.cx = GetSystemMetrics(SM_CXFRAME);
164     if (siFrame.cx > 0)
165     {
166         siFrame.cx = RescaleCX(pData, siFrame.cx);
167         siFrame.cx = max(1, siFrame.cx);
168     }
169     siFrame.cy = GetSystemMetrics(SM_CYFRAME);
170     if (siFrame.cy > 0)
171     {
172         siFrame.cy = RescaleCY(pData, siFrame.cy);
173         siFrame.cy = max(1, siFrame.cy);
174     }
175 
176     /* Window caption buttons */
177     siButton.cx = GetSystemMetrics(SM_CXSIZE);
178     siButton.cx = RescaleCX(pData, siButton.cx);
179     siButton.cx = max(1, siButton.cx);
180 
181     siButton.cy = GetSystemMetrics(SM_CYSIZE);
182     siButton.cy = RescaleCY(pData, siButton.cy);
183     siButton.cy = max(1, siButton.cy);
184 
185     /* Enlarge them for improving their appearance */
186     // siButton.cx *= 2;
187     siButton.cy *= 2;
188 
189     /* Dimensions of the scrollbars */
190     siScroll.cx = GetSystemMetrics(SM_CXVSCROLL);
191     siScroll.cx = RescaleCX(pData, siScroll.cx);
192     siScroll.cx = max(1, siScroll.cx);
193 
194     siScroll.cy = GetSystemMetrics(SM_CYHSCROLL);
195     siScroll.cy = RescaleCY(pData, siScroll.cy);
196     siScroll.cy = max(1, siScroll.cy);
197 
198 
199     // FIXME: Use SM_CXMIN, SM_CYMIN ??
200 
201 
202     /*
203      * Compute the console window layout
204      */
205 
206     if (FontPreview.hFont == NULL)
207         RefreshFontPreview(&FontPreview, pConInfo);
208 
209     /* We start with the console client area, rescaled for the preview */
210     SetRect(&rcWin, 0, 0,
211             pConInfo->WindowSize.X * FontPreview.CharWidth,
212             pConInfo->WindowSize.Y * FontPreview.CharHeight);
213     RescaleRect(pData, rcWin);
214 
215     /* Add the scrollbars if needed (does not account for any frame) */
216     if (pConInfo->WindowSize.X < pConInfo->ScreenBufferSize.X)
217     {
218         /* Horizontal scrollbar */
219         rcWin.bottom += siScroll.cy;
220         // NOTE: If an additional exterior frame is needed, add +1
221     }
222     else
223     {
224         /* No scrollbar */
225         siScroll.cy = 0;
226     }
227     if (pConInfo->WindowSize.Y < pConInfo->ScreenBufferSize.Y)
228     {
229         /* Vertical scrollbar */
230         rcWin.right += siScroll.cx;
231         // NOTE: If an additional exterior frame is needed, add +1
232     }
233     else
234     {
235         /* No scrollbar */
236         siScroll.cx = 0;
237     }
238 
239     /* Add the title bar, taking into account the frames */
240     rcWin.top -= siButton.cy - 1;
241 
242     /* If we have a non-zero window frame size, add an interior border and the frame */
243     resize.cx = (siFrame.cx > 0 ? 1 + siFrame.cx : 0);
244     resize.cy = (siFrame.cy > 0 ? 1 + siFrame.cy : 0);
245 
246     /* Add the outer border */
247     ++resize.cx, ++resize.cy;
248 
249     InflateRect(&rcWin, resize.cx, resize.cy);
250 
251     /* Finally, move the window rectangle back to its correct origin */
252     OffsetRect(&rcWin, -rcWin.left, -rcWin.top);
253 
254     if ( pConInfo->WindowPosition.x == MAXDWORD &&
255          pConInfo->WindowPosition.y == MAXDWORD )
256     {
257         // OffsetRect(&rcWin, (rcItem.right - rcItem.left) / 3, (rcItem.bottom - rcItem.top) / 3);
258         OffsetRect(&rcWin, 0, 0);
259     }
260     else
261     {
262         OffsetRect(&rcWin,
263                    RescaleCX(pData, pConInfo->WindowPosition.x),
264                    RescaleCY(pData, pConInfo->WindowPosition.y));
265     }
266 
267 
268     /*
269      * Paint the preview window
270      */
271 
272     /* Fill the background with desktop colour */
273     FillRect(hDC, &rcItem, GetSysColorBrush(COLOR_BACKGROUND));
274 
275     /*
276      * Draw the exterior frame. Use 'FillRect' instead of 'FrameRect'
277      * so that, when we want to draw frames around other elements,
278      * we can just instead separate them with space instead of redrawing
279      * a frame with 'FrameRect'.
280      */
281     FillRect(hDC, &rcWin, GetSysColorBrush(COLOR_WINDOWFRAME));
282     InflateRect(&rcWin, -1, -1);
283 
284     /* Draw the border */
285     hBrush = GetSysColorBrush(COLOR_ACTIVEBORDER);
286     if (siFrame.cx > 0)
287     {
288         SetRect(&fRect, rcWin.left, rcWin.top, rcWin.left + siFrame.cx, rcWin.bottom);
289         FillRect(hDC, &fRect, hBrush);
290         SetRect(&fRect, rcWin.right - siFrame.cx, rcWin.top, rcWin.right, rcWin.bottom);
291         FillRect(hDC, &fRect, hBrush);
292 
293         InflateRect(&rcWin, -siFrame.cx, 0);
294     }
295     if (siFrame.cy > 0)
296     {
297         SetRect(&fRect, rcWin.left, rcWin.top, rcWin.right, rcWin.top + siFrame.cy);
298         FillRect(hDC, &fRect, hBrush);
299         SetRect(&fRect, rcWin.left, rcWin.bottom - siFrame.cy, rcWin.right, rcWin.bottom);
300         FillRect(hDC, &fRect, hBrush);
301 
302         InflateRect(&rcWin, 0, -siFrame.cy);
303     }
304 
305     /* Draw the interior frame if we had a border */
306     if (siFrame.cx > 0 || siFrame.cy > 0)
307     {
308 #if 0 // See the remark above
309         SetRect(&fRect, rcWin.left, rcWin.top, rcWin.right, rcWin.bottom);
310         FrameRect(hDC, &fRect, GetSysColorBrush(COLOR_WINDOWFRAME));
311 #endif
312         InflateRect(&rcWin, (siFrame.cx > 0 ? -1 : 0), (siFrame.cy > 0 ? -1 : 0));
313     }
314 
315     /* Draw the console window title bar */
316     hBrush = GetSysColorBrush(COLOR_BTNFACE);
317 
318     /* Draw the system menu (left button) */
319     SetRect(&fRect, rcWin.left, rcWin.top, rcWin.left + siButton.cx, rcWin.top + siButton.cy - 2);
320     // DrawFrameControl(hDC, &fRect, DFC_CAPTION, DFCS_CAPTIONCLOSE);
321     FillRect(hDC, &fRect, hBrush);
322     fRect.right++; // Separation
323 
324     /* Draw the caption bar */
325     SetRect(&fRect, fRect.right, fRect.top, rcWin.right - 2 * (siButton.cx + 1), fRect.bottom);
326     FillRect(hDC, &fRect, GetSysColorBrush(COLOR_ACTIVECAPTION));
327     fRect.right++; // Separation
328 
329     /* Draw the minimize menu (first right button) */
330     SetRect(&fRect, fRect.right, fRect.top, fRect.right + siButton.cx, fRect.bottom);
331     // DrawFrameControl(hDC, &fRect, DFC_CAPTION, DFCS_CAPTIONMIN);
332     FillRect(hDC, &fRect, hBrush);
333     fRect.right++; // Separation
334 
335     /* Draw the maximize menu (second right button) */
336     SetRect(&fRect, fRect.right, fRect.top, fRect.right + siButton.cx, fRect.bottom);
337     // DrawFrameControl(hDC, &fRect, DFC_CAPTION, DFCS_CAPTIONMAX);
338     FillRect(hDC, &fRect, hBrush);
339 
340     rcWin.top += siButton.cy - 1;
341 
342     /* Add the scrollbars if needed */
343     if (siScroll.cy > 0 || siScroll.cx > 0)
344     {
345         LONG right, bottom;
346 
347         right  = rcWin.right;
348         bottom = rcWin.bottom;
349 
350         /*
351          * If both the horizontal and vertical scrollbars are present,
352          * reserve some space for the "dead square" at the bottom right.
353          */
354         if (siScroll.cy > 0 && siScroll.cx > 0)
355         {
356             right  -= (1 + siScroll.cx);
357             bottom -= (1 + siScroll.cy);
358         }
359 
360         hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
361 
362         /* Horizontal scrollbar */
363         if (siScroll.cy > 0)
364         {
365             SetRect(&fRect, rcWin.left, rcWin.bottom - siScroll.cy, right, rcWin.bottom);
366             FillRect(hDC, &fRect, hBrush);
367         }
368 
369         /* Vertical scrollbar */
370         if (siScroll.cx > 0)
371         {
372             SetRect(&fRect, rcWin.right - siScroll.cx, rcWin.top, rcWin.right, bottom);
373             FillRect(hDC, &fRect, hBrush);
374         }
375 
376         /*
377          * If both the horizontal and vertical scrollbars are present,
378          * draw the "dead square" at the bottom right.
379          */
380         if (siScroll.cy > 0 && siScroll.cx > 0)
381         {
382             SetRect(&fRect, rcWin.right - siScroll.cx, rcWin.bottom - siScroll.cy, rcWin.right, rcWin.bottom);
383             FillRect(hDC, &fRect, hBrush);
384         }
385 
386         // NOTE: If an additional exterior frame is needed, remove +1 for each direction
387         rcWin.right  -= siScroll.cx;
388         rcWin.bottom -= siScroll.cy;
389     }
390 
391     /* Draw the console background */
392     hBrush = CreateSolidBrush(pConInfo->ColorTable[BkgdAttribFromAttrib(pConInfo->ScreenAttributes)]);
393     FillRect(hDC, &rcWin, hBrush ? hBrush : GetStockObject(BLACK_BRUSH));
394     if (hBrush) DeleteObject(hBrush);
395 }
396 
397 static LRESULT CALLBACK
398 WinPrevProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
399 {
400     PWINPREV_DATA pData;
401 
402     pData = (PWINPREV_DATA)GetWindowLongPtrW(hWnd, GWLP_USERDATA);
403 
404     switch (msg)
405     {
406         case WM_CREATE:
407         {
408             pData = (PWINPREV_DATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pData));
409             if (!pData)
410             {
411                 /* We failed to allocate our private data, halt the window creation */
412                 return (LRESULT)-1;
413             }
414             pData->hWnd  = hWnd;
415             pData->pData = ConInfo;
416             GetClientRect(pData->hWnd, &pData->rcMaxArea);
417             // LPCREATESTRUCT::cx and cy give window (not client) size
418             WinPrev_OnDisplayChange(pData);
419             SetWindowLongPtrW(hWnd, GWLP_USERDATA, (LONG_PTR)pData);
420             break;
421         }
422 
423         case WM_DESTROY:
424         {
425             if (pData)
426                 HeapFree(GetProcessHeap(), 0, pData);
427             break;
428         }
429 
430         case WM_DISPLAYCHANGE:
431         {
432             WinPrev_OnDisplayChange(pData);
433             UpdateWindow(hWnd);
434             // InvalidateRect(hWnd, NULL, FALSE);
435             break;
436         }
437 
438         case WM_SIZE:
439             break;
440 
441         case WM_ERASEBKGND:
442             return 1;
443 
444         case WM_PAINT:
445         {
446             PAINTSTRUCT ps;
447             BeginPaint(hWnd, &ps);
448             WinPrev_OnDraw(ps.hdc, pData);
449             EndPaint(hWnd, &ps);
450             return 0;
451         }
452     }
453 
454     return DefWindowProcW(hWnd, msg, wParam, lParam);
455 }
456 
457 
458 /* CONSOLE TEXT PREVIEW *******************************************************/
459 
460 const WCHAR szPreviewText[] =
461     L"C:\\ReactOS>dir\n"                         \
462     L"SYSTEM       <DIR>      13-04-15  5:00a\n" \
463     L"SYSTEM32     <DIR>      13-04-15  5:00a\n" \
464     L"readme   txt       1739 13-04-15  5:00a\n" \
465     L"explorer exe    3329536 13-04-15  5:00a\n" \
466     L"vgafonts cab      18736 13-04-15  5:00a\n" \
467     L"setuplog txt        313 13-04-15  5:00a\n" \
468     L"win      ini       7005 13-04-15  5:00a\n" ;
469 
470 VOID
471 PaintText(
472     IN LPDRAWITEMSTRUCT drawItem,
473     IN PCONSOLE_STATE_INFO pConInfo,
474     IN TEXT_TYPE TextMode)
475 {
476     USHORT CurrentAttrib;
477     COLORREF pbkColor, ptColor;
478     COLORREF nbkColor, ntColor;
479     HBRUSH hBrush;
480     HFONT hOldFont;
481 
482     if (TextMode == Screen)
483         CurrentAttrib = pConInfo->ScreenAttributes;
484     else if (TextMode == Popup)
485         CurrentAttrib = pConInfo->PopupAttributes;
486     else
487         return;
488 
489     nbkColor = pConInfo->ColorTable[BkgdAttribFromAttrib(CurrentAttrib)];
490     ntColor  = pConInfo->ColorTable[TextAttribFromAttrib(CurrentAttrib)];
491 
492     /* Draw the console background */
493     hBrush = CreateSolidBrush(nbkColor);
494     FillRect(drawItem->hDC, &drawItem->rcItem, hBrush ? hBrush : GetStockObject(BLACK_BRUSH));
495     if (hBrush) DeleteObject(hBrush);
496 
497     /* Refresh the font preview, getting a new font if necessary */
498     if (FontPreview.hFont == NULL)
499         RefreshFontPreview(&FontPreview, pConInfo);
500     /* Recheck hFont since RefreshFontPreview() may not have updated it */
501     if (FontPreview.hFont == NULL)
502         return;
503 
504     /* Draw the preview text using the current font */
505     hOldFont = SelectObject(drawItem->hDC, FontPreview.hFont);
506     // if (!hOldFont) return;
507 
508     /* Add a few space between the preview window border and the text sample */
509     InflateRect(&drawItem->rcItem, -2, -2);
510 
511     ptColor  = SetTextColor(drawItem->hDC, ntColor);
512     pbkColor = SetBkColor(drawItem->hDC, nbkColor);
513     DrawTextW(drawItem->hDC, szPreviewText, (INT)wcslen(szPreviewText), &drawItem->rcItem, 0);
514     SetTextColor(drawItem->hDC, ptColor);
515     SetBkColor(drawItem->hDC, pbkColor);
516 
517     SelectObject(drawItem->hDC, hOldFont);
518 }
519 
520 
521 /* LAYOUT DIALOG **************************************************************/
522 
523 INT_PTR
524 CALLBACK
525 LayoutProc(HWND hDlg,
526            UINT uMsg,
527            WPARAM wParam,
528            LPARAM lParam)
529 {
530     switch (uMsg)
531     {
532         case WM_INITDIALOG:
533         {
534             /* Multi-monitor support */
535             LONG  xVirtScr,  yVirtScr; // Coordinates of the top-left virtual screen
536             LONG cxVirtScr, cyVirtScr; // Width and Height of the virtual screen
537             LONG cxFrame  , cyFrame  ; // Thickness of the window frame
538 
539             xVirtScr  = GetSystemMetrics(SM_XVIRTUALSCREEN);
540             yVirtScr  = GetSystemMetrics(SM_YVIRTUALSCREEN);
541             cxVirtScr = GetSystemMetrics(SM_CXVIRTUALSCREEN);
542             cyVirtScr = GetSystemMetrics(SM_CYVIRTUALSCREEN);
543             cxFrame   = GetSystemMetrics(SM_CXFRAME);
544             cyFrame   = GetSystemMetrics(SM_CYFRAME);
545 
546             SendDlgItemMessageW(hDlg, IDC_UPDOWN_SCREEN_BUFFER_HEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(9999, 1));
547             SendDlgItemMessageW(hDlg, IDC_UPDOWN_SCREEN_BUFFER_WIDTH , UDM_SETRANGE, 0, (LPARAM)MAKELONG(9999, 1));
548             SendDlgItemMessageW(hDlg, IDC_UPDOWN_WINDOW_SIZE_HEIGHT, UDM_SETRANGE, 0, (LPARAM)MAKELONG(9999, 1));
549             SendDlgItemMessageW(hDlg, IDC_UPDOWN_WINDOW_SIZE_WIDTH , UDM_SETRANGE, 0, (LPARAM)MAKELONG(9999, 1));
550 
551             SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, ConInfo->ScreenBufferSize.Y, FALSE);
552             SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH , ConInfo->ScreenBufferSize.X, FALSE);
553             SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT, ConInfo->WindowSize.Y, FALSE);
554             SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH , ConInfo->WindowSize.X, FALSE);
555 
556             SendDlgItemMessageW(hDlg, IDC_UPDOWN_WINDOW_POS_LEFT, UDM_SETRANGE, 0,
557                                 (LPARAM)MAKELONG(xVirtScr + cxVirtScr - cxFrame, xVirtScr - cxFrame));
558             SendDlgItemMessageW(hDlg, IDC_UPDOWN_WINDOW_POS_TOP , UDM_SETRANGE, 0,
559                                 (LPARAM)MAKELONG(yVirtScr + cyVirtScr - cyFrame, yVirtScr - cyFrame));
560 
561             SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_LEFT, ConInfo->WindowPosition.x, TRUE);
562             SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_TOP , ConInfo->WindowPosition.y, TRUE);
563 
564             if (ConInfo->AutoPosition)
565             {
566                 EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_LEFT, FALSE);
567                 EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_TOP , FALSE);
568                 EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_LEFT, FALSE);
569                 EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_TOP , FALSE);
570             }
571             CheckDlgButton(hDlg, IDC_CHECK_SYSTEM_POS_WINDOW,
572                            ConInfo->AutoPosition ? BST_CHECKED : BST_UNCHECKED);
573 
574             return TRUE;
575         }
576 
577         case WM_DISPLAYCHANGE:
578         {
579             /* Retransmit to the preview window */
580             SendDlgItemMessageW(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW,
581                                 WM_DISPLAYCHANGE, wParam, lParam);
582             break;
583         }
584 
585         case WM_NOTIFY:
586         {
587             LPPSHNOTIFY lppsn = (LPPSHNOTIFY)lParam;
588 
589             if (lppsn->hdr.code == UDN_DELTAPOS)
590             {
591                 LPNMUPDOWN lpnmud = (LPNMUPDOWN)lParam;
592                 DWORD wheight, wwidth;
593                 DWORD sheight, swidth;
594                 DWORD left, top;
595 
596                 if (lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_SIZE_WIDTH)
597                 {
598                     wwidth = lpnmud->iPos + lpnmud->iDelta;
599                 }
600                 else
601                 {
602                     wwidth = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH, NULL, FALSE);
603                 }
604 
605                 if (lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_SIZE_HEIGHT)
606                 {
607                     wheight = lpnmud->iPos + lpnmud->iDelta;
608                 }
609                 else
610                 {
611                     wheight = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT, NULL, FALSE);
612                 }
613 
614                 if (lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_WIDTH)
615                 {
616                     swidth = lpnmud->iPos + lpnmud->iDelta;
617                 }
618                 else
619                 {
620                     swidth = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, NULL, FALSE);
621                 }
622 
623                 if (lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_HEIGHT)
624                 {
625                     sheight = lpnmud->iPos + lpnmud->iDelta;
626                 }
627                 else
628                 {
629                     sheight = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, NULL, FALSE);
630                 }
631 
632                 if (lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_POS_LEFT)
633                 {
634                     left = lpnmud->iPos + lpnmud->iDelta;
635                 }
636                 else
637                 {
638                     left = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_LEFT, NULL, TRUE);
639                 }
640 
641                 if (lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_POS_TOP)
642                 {
643                     top = lpnmud->iPos + lpnmud->iDelta;
644                 }
645                 else
646                 {
647                     top = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_TOP, NULL, TRUE);
648                 }
649 
650                 if (lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_SIZE_WIDTH || lppsn->hdr.idFrom == IDC_UPDOWN_WINDOW_SIZE_HEIGHT)
651                 {
652                     /* Automatically adjust screen buffer size when window size enlarges */
653                     if (wwidth >= swidth)
654                     {
655                         SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, wwidth, TRUE);
656                         swidth = wwidth;
657                     }
658                     if (wheight >= sheight)
659                     {
660                         SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, wheight, TRUE);
661                         sheight = wheight;
662                     }
663                 }
664 
665                 /* Be sure that the (new) screen buffer sizes are in the correct range */
666                 swidth  = min(max(swidth , 1), 0xFFFF);
667                 sheight = min(max(sheight, 1), 0xFFFF);
668 
669                 if (lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_WIDTH || lppsn->hdr.idFrom == IDC_UPDOWN_SCREEN_BUFFER_HEIGHT)
670                 {
671                     /* Automatically adjust window size when screen buffer decreases */
672                     if (wwidth > swidth)
673                     {
674                         SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH, swidth, TRUE);
675                         wwidth = swidth;
676                     }
677                     if (wheight > sheight)
678                     {
679                         SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT, sheight, TRUE);
680                         wheight = sheight;
681                     }
682                 }
683 
684                 ConInfo->ScreenBufferSize.X = (SHORT)swidth;
685                 ConInfo->ScreenBufferSize.Y = (SHORT)sheight;
686                 ConInfo->WindowSize.X = (SHORT)wwidth;
687                 ConInfo->WindowSize.Y = (SHORT)wheight;
688                 ConInfo->WindowPosition.x = left;
689                 ConInfo->WindowPosition.y = top;
690 
691                 InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
692                 PropSheet_Changed(GetParent(hDlg), hDlg);
693             }
694             break;
695         }
696 
697         case WM_COMMAND:
698         {
699             if (HIWORD(wParam) == EN_KILLFOCUS)
700             {
701                 switch (LOWORD(wParam))
702                 {
703                 case IDC_EDIT_SCREEN_BUFFER_WIDTH:
704                 {
705                     DWORD swidth, wwidth;
706 
707                     swidth = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, NULL, FALSE);
708                     wwidth = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH  , NULL, FALSE);
709 
710                     /* Be sure that the (new) screen buffer width is in the correct range */
711                     swidth = min(max(swidth, 1), 0xFFFF);
712 
713                     /* Automatically adjust window size when screen buffer decreases */
714                     if (wwidth > swidth)
715                     {
716                         wwidth = swidth;
717                         SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH, wwidth, TRUE);
718                     }
719 
720                     ConInfo->ScreenBufferSize.X = (SHORT)swidth;
721                     ConInfo->WindowSize.X       = (SHORT)wwidth;
722 
723                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
724                     PropSheet_Changed(GetParent(hDlg), hDlg);
725                     break;
726                 }
727 
728                 case IDC_EDIT_WINDOW_SIZE_WIDTH:
729                 {
730                     DWORD swidth, wwidth;
731 
732                     swidth = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, NULL, FALSE);
733                     wwidth = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_WIDTH  , NULL, FALSE);
734 
735                     /* Automatically adjust screen buffer size when window size enlarges */
736                     if (wwidth >= swidth)
737                     {
738                         swidth = wwidth;
739 
740                         /* Be sure that the (new) screen buffer width is in the correct range */
741                         swidth = min(max(swidth, 1), 0xFFFF);
742 
743                         SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_WIDTH, swidth, TRUE);
744                     }
745 
746                     ConInfo->ScreenBufferSize.X = (SHORT)swidth;
747                     ConInfo->WindowSize.X       = (SHORT)wwidth;
748 
749                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
750                     PropSheet_Changed(GetParent(hDlg), hDlg);
751                     break;
752                 }
753 
754                 case IDC_EDIT_SCREEN_BUFFER_HEIGHT:
755                 {
756                     DWORD sheight, wheight;
757 
758                     sheight = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, NULL, FALSE);
759                     wheight = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT  , NULL, FALSE);
760 
761                     /* Be sure that the (new) screen buffer width is in the correct range */
762                     sheight = min(max(sheight, 1), 0xFFFF);
763 
764                     /* Automatically adjust window size when screen buffer decreases */
765                     if (wheight > sheight)
766                     {
767                         wheight = sheight;
768                         SetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT, wheight, TRUE);
769                     }
770 
771                     ConInfo->ScreenBufferSize.Y = (SHORT)sheight;
772                     ConInfo->WindowSize.Y       = (SHORT)wheight;
773 
774                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
775                     PropSheet_Changed(GetParent(hDlg), hDlg);
776                     break;
777                 }
778 
779                 case IDC_EDIT_WINDOW_SIZE_HEIGHT:
780                 {
781                     DWORD sheight, wheight;
782 
783                     sheight = GetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, NULL, FALSE);
784                     wheight = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_SIZE_HEIGHT  , NULL, FALSE);
785 
786                     /* Automatically adjust screen buffer size when window size enlarges */
787                     if (wheight >= sheight)
788                     {
789                         sheight = wheight;
790 
791                         /* Be sure that the (new) screen buffer width is in the correct range */
792                         sheight = min(max(sheight, 1), 0xFFFF);
793 
794                         SetDlgItemInt(hDlg, IDC_EDIT_SCREEN_BUFFER_HEIGHT, sheight, TRUE);
795                     }
796 
797                     ConInfo->ScreenBufferSize.Y = (SHORT)sheight;
798                     ConInfo->WindowSize.Y       = (SHORT)wheight;
799 
800                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
801                     PropSheet_Changed(GetParent(hDlg), hDlg);
802                     break;
803                 }
804 
805                 case IDC_EDIT_WINDOW_POS_LEFT:
806                 case IDC_EDIT_WINDOW_POS_TOP:
807                 {
808                     ConInfo->WindowPosition.x = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_LEFT, NULL, TRUE);
809                     ConInfo->WindowPosition.y = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_TOP , NULL, TRUE);
810 
811                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
812                     PropSheet_Changed(GetParent(hDlg), hDlg);
813                     break;
814                 }
815                 }
816             }
817             else
818             if (HIWORD(wParam) == BN_CLICKED &&
819                 LOWORD(wParam) == IDC_CHECK_SYSTEM_POS_WINDOW)
820             {
821                 if (IsDlgButtonChecked(hDlg, IDC_CHECK_SYSTEM_POS_WINDOW) == BST_CHECKED)
822                 {
823                     EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_LEFT, FALSE);
824                     EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_TOP , FALSE);
825                     EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_LEFT, FALSE);
826                     EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_TOP , FALSE);
827 
828                     ConInfo->AutoPosition = TRUE;
829                     // Do not touch ConInfo->WindowPosition !!
830 
831                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
832                     PropSheet_Changed(GetParent(hDlg), hDlg);
833                 }
834                 else
835                 {
836                     ULONG left, top;
837 
838                     left = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_LEFT, NULL, TRUE);
839                     top  = GetDlgItemInt(hDlg, IDC_EDIT_WINDOW_POS_TOP , NULL, TRUE);
840 
841                     EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_LEFT, TRUE);
842                     EnableDlgItem(hDlg, IDC_EDIT_WINDOW_POS_TOP , TRUE);
843                     EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_LEFT, TRUE);
844                     EnableDlgItem(hDlg, IDC_UPDOWN_WINDOW_POS_TOP , TRUE);
845 
846                     ConInfo->AutoPosition     = FALSE;
847                     ConInfo->WindowPosition.x = left;
848                     ConInfo->WindowPosition.y = top;
849 
850                     InvalidateRect(GetDlgItem(hDlg, IDC_STATIC_LAYOUT_WINDOW_PREVIEW), NULL, TRUE);
851                     PropSheet_Changed(GetParent(hDlg), hDlg);
852                 }
853             }
854 
855             break;
856         }
857 
858         default:
859             break;
860     }
861 
862     return FALSE;
863 }
864