aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows/Control/Dialog.cpp
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2021-12-27 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-03-18 15:35:13 +0500
commitf19f813537c7aea1c20749c914e756b54a9c3cf5 (patch)
tree816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/Windows/Control/Dialog.cpp
parent98e06a519b63b81986abe76d28887f6984a7732b (diff)
download7zip-21.07.tar.gz
7zip-21.07.tar.bz2
7zip-21.07.zip
'21.07'21.07
Diffstat (limited to 'CPP/Windows/Control/Dialog.cpp')
-rw-r--r--CPP/Windows/Control/Dialog.cpp414
1 files changed, 414 insertions, 0 deletions
diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp
new file mode 100644
index 0000000..9ddd234
--- /dev/null
+++ b/CPP/Windows/Control/Dialog.cpp
@@ -0,0 +1,414 @@
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
13extern HINSTANCE g_hInstance;
14#ifndef _UNICODE
15extern bool g_IsNT;
16#endif
17
18namespace NWindows {
19namespace NControl {
20
21static 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
43bool 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
68bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam)
69{
70 return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
71}
72
73bool 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
80bool 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
94static 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
131bool 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
147bool 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
163int 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
175bool 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
185void CDialog::GetClientRectOfItem(int id, RECT &rect)
186{
187 ::GetWindowRect(GetItem(id), &rect);
188 ScreenToClient(&rect);
189}
190
191bool 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/*
198typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)(
199 HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
200
201static 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
224static 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
233static 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
242static 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
251void 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
286void 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
357bool 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
366INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
367{
368 return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
369}
370
371#ifndef _UNICODE
372
373bool 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
397INT_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}}