• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Windows/Control/Dialog.cpp
2 
3 #include "StdAfx.h"
4 
5 // #include "../../Windows/DLL.h"
6 
7 #ifndef _UNICODE
8 #include "../../Common/StringConvert.h"
9 #endif
10 
11 #include "Dialog.h"
12 
13 extern HINSTANCE g_hInstance;
14 #ifndef _UNICODE
15 extern bool g_IsNT;
16 #endif
17 
18 namespace NWindows {
19 namespace NControl {
20 
DialogProcedure(HWND dialogHWND,UINT message,WPARAM wParam,LPARAM lParam)21 static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
22 {
23   CWindow tempDialog(dialogHWND);
24   if (message == WM_INITDIALOG)
25     tempDialog.SetUserDataLongPtr(lParam);
26   CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
27   if (dialog == NULL)
28     return FALSE;
29   if (message == WM_INITDIALOG)
30     dialog->Attach(dialogHWND);
31 
32   /* MSDN: The dialog box procedure should return
33        TRUE  - if it processed the message
34        FALSE - if it did not process the message
35      If the dialog box procedure returns FALSE,
36      the dialog manager performs the default dialog operation in response to the message.
37   */
38 
39   try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
40   catch(...) { return TRUE; }
41 }
42 
OnMessage(UINT message,WPARAM wParam,LPARAM lParam)43 bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
44 {
45   switch (message)
46   {
47     case WM_INITDIALOG: return OnInit();
48     case WM_COMMAND: return OnCommand(wParam, lParam);
49     case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam);
50     case WM_TIMER: return OnTimer(wParam, lParam);
51     case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
52     case WM_DESTROY: return OnDestroy();
53     case WM_HELP: OnHelp(); return true;
54     /*
55         OnHelp(
56           #ifdef UNDER_CE
57           (void *)
58           #else
59           (LPHELPINFO)
60           #endif
61           lParam);
62         return true;
63     */
64     default: return false;
65   }
66 }
67 
OnCommand(WPARAM wParam,LPARAM lParam)68 bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam)
69 {
70   return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
71 }
72 
OnCommand(int code,int itemID,LPARAM lParam)73 bool CDialog::OnCommand(int code, int itemID, LPARAM lParam)
74 {
75   if (code == BN_CLICKED)
76     return OnButtonClicked(itemID, (HWND)lParam);
77   return false;
78 }
79 
OnButtonClicked(int buttonID,HWND)80 bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */)
81 {
82   switch (buttonID)
83   {
84     case IDOK: OnOK(); break;
85     case IDCANCEL: OnCancel(); break;
86     case IDCLOSE: OnClose(); break;
87     case IDHELP: OnHelp(); break;
88     default: return false;
89   }
90   return true;
91 }
92 
93 
GetWorkAreaRect(RECT * rect,HWND hwnd)94 static bool GetWorkAreaRect(RECT *rect, HWND hwnd)
95 {
96   if (hwnd)
97   {
98     #ifndef UNDER_CE
99     /* MonitorFromWindow() is supported in Win2000+
100        MonitorFromWindow() : retrieves a handle to the display monitor that has the
101          largest area of intersection with the bounding rectangle of a specified window.
102        dwFlags: Determines the function's return value if the window does not intersect any display monitor.
103          MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window.
104          MONITOR_DEFAULTTONULL    : Returns NULL.
105          MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor.
106     */
107     const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
108     if (hmon)
109     {
110       MONITORINFO mi;
111       memset(&mi, 0, sizeof(mi));
112       mi.cbSize = sizeof(mi);
113       if (GetMonitorInfoA(hmon, &mi))
114       {
115         *rect = mi.rcWork;
116         return true;
117       }
118     }
119     #endif
120   }
121 
122   /* Retrieves the size of the work area on the primary display monitor.
123      The work area is the portion of the screen not obscured
124      by the system taskbar or by application desktop toolbars.
125      Any DPI virtualization mode of the caller has no effect on this output. */
126 
127   return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));
128 }
129 
130 
IsDialogSizeOK(int xSize,int ySize,HWND hwnd)131 bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd)
132 {
133   // it returns for system font. Real font uses another values
134   const LONG v = GetDialogBaseUnits();
135   const int x = LOWORD(v);
136   const int y = HIWORD(v);
137 
138   RECT rect;
139   GetWorkAreaRect(&rect, hwnd);
140   const int wx = RECT_SIZE_X(rect);
141   const int wy = RECT_SIZE_Y(rect);
142   return
143     xSize / 4 * x <= wx &&
144     ySize / 8 * y <= wy;
145 }
146 
GetMargins(int margin,int & x,int & y)147 bool CDialog::GetMargins(int margin, int &x, int &y)
148 {
149   x = margin;
150   y = margin;
151   RECT rect;
152   rect.left = 0;
153   rect.top = 0;
154   rect.right = margin;
155   rect.bottom = margin;
156   if (!MapRect(&rect))
157     return false;
158   x = rect.right - rect.left;
159   y = rect.bottom - rect.top;
160   return true;
161 }
162 
Units_To_Pixels_X(int units)163 int CDialog::Units_To_Pixels_X(int units)
164 {
165   RECT rect;
166   rect.left = 0;
167   rect.top = 0;
168   rect.right = units;
169   rect.bottom = units;
170   if (!MapRect(&rect))
171     return units * 3 / 2;
172   return rect.right - rect.left;
173 }
174 
GetItemSizes(int id,int & x,int & y)175 bool CDialog::GetItemSizes(int id, int &x, int &y)
176 {
177   RECT rect;
178   if (!::GetWindowRect(GetItem(id), &rect))
179     return false;
180   x = RECT_SIZE_X(rect);
181   y = RECT_SIZE_Y(rect);
182   return true;
183 }
184 
GetClientRectOfItem(int id,RECT & rect)185 void CDialog::GetClientRectOfItem(int id, RECT &rect)
186 {
187   ::GetWindowRect(GetItem(id), &rect);
188   ScreenToClient(&rect);
189 }
190 
MoveItem(int id,int x,int y,int width,int height,bool repaint)191 bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint)
192 {
193   return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));
194 }
195 
196 
197 /*
198 typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)(
199     HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
200 
201 static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect)
202 {
203   // dll load and free is too slow : 300 calls in second.
204   NDLL::CLibrary dll;
205   if (!dll.Load(FTEXT("dwmapi.dll")))
206     return false;
207   Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" );
208   if (f)
209   {
210     #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9
211     // 30000 per second
212     RECT r;
213     if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK)
214     {
215       *rect = r;
216       return true;
217     }
218   }
219   return false;
220 }
221 */
222 
223 
IsRect_Small_Inside_Big(const RECT & sm,const RECT & big)224 static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big)
225 {
226   return sm.left   >= big.left
227       && sm.right  <= big.right
228       && sm.top    >= big.top
229       && sm.bottom <= big.bottom;
230 }
231 
232 
AreRectsOverlapped(const RECT & r1,const RECT & r2)233 static bool AreRectsOverlapped(const RECT &r1, const RECT &r2)
234 {
235   return r1.left   < r2.right
236       && r1.right  > r2.left
237       && r1.top    < r2.bottom
238       && r1.bottom > r2.top;
239 }
240 
241 
AreRectsEqual(const RECT & r1,const RECT & r2)242 static bool AreRectsEqual(const RECT &r1, const RECT &r2)
243 {
244   return r1.left   == r2.left
245       && r1.right  == r2.right
246       && r1.top    == r2.top
247       && r1.bottom == r2.bottom;
248 }
249 
250 
NormalizeSize(bool fullNormalize)251 void CDialog::NormalizeSize(bool fullNormalize)
252 {
253   RECT workRect;
254   if (!GetWorkAreaRect(&workRect, *this))
255     return;
256   RECT rect;
257   if (!GetWindowRect(&rect))
258     return;
259   int xs = RECT_SIZE_X(rect);
260   int ys = RECT_SIZE_Y(rect);
261 
262   // we don't want to change size using workRect, if window is outside of WorkArea
263   if (!AreRectsOverlapped(rect, workRect))
264     return;
265 
266   /* here rect and workRect are overlapped, but it can be false
267      overlapping of small shadow when window in another display. */
268 
269   const int xsW = RECT_SIZE_X(workRect);
270   const int ysW = RECT_SIZE_Y(workRect);
271   if (xs <= xsW && ys <= ysW)
272     return; // size of window is OK
273   if (fullNormalize)
274   {
275     Show(SW_SHOWMAXIMIZED);
276     return;
277   }
278   int x = workRect.left;
279   int y = workRect.top;
280   if (xs < xsW)  x += (xsW - xs) / 2;  else xs = xsW;
281   if (ys < ysW)  y += (ysW - ys) / 2;  else ys = ysW;
282   Move(x, y, xs, ys, true);
283 }
284 
285 
NormalizePosition()286 void CDialog::NormalizePosition()
287 {
288   RECT workRect;
289   if (!GetWorkAreaRect(&workRect, *this))
290     return;
291 
292   RECT rect2 = workRect;
293   bool useWorkArea = true;
294   const HWND parentHWND = GetParent();
295 
296   if (parentHWND)
297   {
298     RECT workRectParent;
299     if (!GetWorkAreaRect(&workRectParent, parentHWND))
300       return;
301 
302     // if windows are in different monitors, we use only workArea of current window
303 
304     if (AreRectsEqual(workRectParent, workRect))
305     {
306       // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {}
307       CWindow wnd(parentHWND);
308       if (wnd.GetWindowRect(&rect2))
309       {
310         // it's same monitor. So we try to use parentHWND rect.
311         /* we don't want to change position, if parent window is not inside work area.
312            In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow.
313            In maximize mode : window is outside of workRect.
314            if parent window is inside workRect, we will use parent window instead of workRect */
315         if (IsRect_Small_Inside_Big(rect2, workRect))
316           useWorkArea = false;
317       }
318     }
319   }
320 
321   RECT rect;
322   if (!GetWindowRect(&rect))
323     return;
324 
325   if (useWorkArea)
326   {
327     // we don't want to move window, if it's already inside.
328     if (IsRect_Small_Inside_Big(rect, workRect))
329       return;
330     // we don't want to move window, if it's outside of workArea
331     if (!AreRectsOverlapped(rect, workRect))
332       return;
333     rect2 = workRect;
334   }
335 
336   {
337     const int xs = RECT_SIZE_X(rect);
338     const int ys = RECT_SIZE_Y(rect);
339     const int xs2 = RECT_SIZE_X(rect2);
340     const int ys2 = RECT_SIZE_Y(rect2);
341     // we don't want to change position if parent is smaller.
342     if (xs <= xs2 && ys <= ys2)
343     {
344       const int x = rect2.left + (xs2 - xs) / 2;
345       const int y = rect2.top  + (ys2 - ys) / 2;
346 
347       if (x != rect.left || y != rect.top)
348         Move(x, y, xs, ys, true);
349       // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
350       return;
351     }
352   }
353 }
354 
355 
356 
Create(LPCTSTR templateName,HWND parentWindow)357 bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)
358 {
359   HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
360   if (aHWND == 0)
361     return false;
362   Attach(aHWND);
363   return true;
364 }
365 
Create(LPCTSTR templateName,HWND parentWindow)366 INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
367 {
368   return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
369 }
370 
371 #ifndef _UNICODE
372 
Create(LPCWSTR templateName,HWND parentWindow)373 bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow)
374 {
375   HWND aHWND;
376   if (g_IsNT)
377     aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
378   else
379   {
380     AString name;
381     LPCSTR templateNameA;
382     if (IS_INTRESOURCE(templateName))
383       templateNameA = (LPCSTR)templateName;
384     else
385     {
386       name = GetSystemString(templateName);
387       templateNameA = name;
388     }
389     aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
390   }
391   if (aHWND == 0)
392     return false;
393   Attach(aHWND);
394   return true;
395 }
396 
Create(LPCWSTR templateName,HWND parentWindow)397 INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow)
398 {
399   if (g_IsNT)
400     return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
401   AString name;
402   LPCSTR templateNameA;
403   if (IS_INTRESOURCE(templateName))
404     templateNameA = (LPCSTR)templateName;
405   else
406   {
407     name = GetSystemString(templateName);
408     templateNameA = name;
409   }
410   return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
411 }
412 #endif
413 
414 }}
415