diff options
Diffstat (limited to '3rdparty/lzma/CPP/Windows/Control/Dialog.cpp')
-rw-r--r-- | 3rdparty/lzma/CPP/Windows/Control/Dialog.cpp | 289 |
1 files changed, 242 insertions, 47 deletions
diff --git a/3rdparty/lzma/CPP/Windows/Control/Dialog.cpp b/3rdparty/lzma/CPP/Windows/Control/Dialog.cpp index 9df3ef5ef24..c8f1bd27c79 100644 --- a/3rdparty/lzma/CPP/Windows/Control/Dialog.cpp +++ b/3rdparty/lzma/CPP/Windows/Control/Dialog.cpp @@ -2,6 +2,8 @@ #include "StdAfx.h" +// #include "../../Windows/DLL.h" + #ifndef _UNICODE #include "../../Common/StringConvert.h" #endif @@ -16,7 +18,14 @@ extern bool g_IsNT; namespace NWindows { namespace NControl { -static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) +static +#ifdef Z7_OLD_WIN_SDK + BOOL +#else + INT_PTR +#endif +APIENTRY +DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam) { CWindow tempDialog(dialogHWND); if (message == WM_INITDIALOG) @@ -26,6 +35,14 @@ static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, WPARAM wP return FALSE; if (message == WM_INITDIALOG) dialog->Attach(dialogHWND); + + /* MSDN: The dialog box procedure should return + TRUE - if it processed the message + FALSE - if it did not process the message + If the dialog box procedure returns FALSE, + the dialog manager performs the default dialog operation in response to the message. + */ + try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); } catch(...) { return TRUE; } } @@ -35,10 +52,11 @@ bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_INITDIALOG: return OnInit(); - case WM_COMMAND: return OnCommand(wParam, lParam); + case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam); case WM_TIMER: return OnTimer(wParam, lParam); case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam)); + case WM_DESTROY: return OnDestroy(); case WM_HELP: OnHelp(); return true; /* OnHelp( @@ -54,47 +72,104 @@ bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) } } -bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam) +/* +bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam) { return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); } +*/ -bool CDialog::OnCommand(int code, int itemID, LPARAM lParam) +bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam) { if (code == BN_CLICKED) return OnButtonClicked(itemID, (HWND)lParam); return false; } -bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */) +bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */) { switch (buttonID) { case IDOK: OnOK(); break; case IDCANCEL: OnCancel(); break; + case IDCLOSE: OnClose(); break; case IDHELP: OnHelp(); break; default: return false; } return true; } -static bool GetWorkAreaRect(RECT *rect) +#ifndef UNDER_CE +/* in win2000/win98 : monitor functions are supported. + We need dynamic linking, if we want nt4/win95 support in program. + Even if we compile the code with low (WINVER) value, we still + want to use monitor functions. So we declare missing functions here */ +// #if (WINVER < 0x0500) +#ifndef MONITOR_DEFAULTTOPRIMARY +extern "C" { +DECLARE_HANDLE(HMONITOR); +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; +WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags); +WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi); +} +#endif +#endif + +static bool GetWorkAreaRect(RECT *rect, HWND hwnd) { - // use another function for multi-monitor. + if (hwnd) + { + #ifndef UNDER_CE + /* MonitorFromWindow() is supported in Win2000+ + MonitorFromWindow() : retrieves a handle to the display monitor that has the + largest area of intersection with the bounding rectangle of a specified window. + dwFlags: Determines the function's return value if the window does not intersect any display monitor. + MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window. + MONITOR_DEFAULTTONULL : Returns NULL. + MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor. + */ + const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); + if (hmon) + { + MONITORINFO mi; + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + if (GetMonitorInfoA(hmon, &mi)) + { + *rect = mi.rcWork; + return true; + } + } + #endif + } + + /* Retrieves the size of the work area on the primary display monitor. + The work area is the portion of the screen not obscured + by the system taskbar or by application desktop toolbars. + Any DPI virtualization mode of the caller has no effect on this output. */ + return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0)); } -bool IsDialogSizeOK(int xSize, int ySize) + +bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd) { // it returns for system font. Real font uses another values - LONG v = GetDialogBaseUnits(); - int x = LOWORD(v); - int y = HIWORD(v); + const LONG v = GetDialogBaseUnits(); + const int x = LOWORD(v); + const int y = HIWORD(v); RECT rect; - GetWorkAreaRect(&rect); - int wx = RECT_SIZE_X(rect); - int wy = RECT_SIZE_Y(rect); + GetWorkAreaRect(&rect, hwnd); + const int wx = RECT_SIZE_X(rect); + const int wy = RECT_SIZE_Y(rect); return xSize / 4 * x <= wx && ySize / 8 * y <= wy; @@ -128,7 +203,7 @@ int CDialog::Units_To_Pixels_X(int units) return rect.right - rect.left; } -bool CDialog::GetItemSizes(int id, int &x, int &y) +bool CDialog::GetItemSizes(unsigned id, int &x, int &y) { RECT rect; if (!::GetWindowRect(GetItem(id), &rect)) @@ -138,62 +213,182 @@ bool CDialog::GetItemSizes(int id, int &x, int &y) return true; } -void CDialog::GetClientRectOfItem(int id, RECT &rect) +void CDialog::GetClientRectOfItem(unsigned id, RECT &rect) { ::GetWindowRect(GetItem(id), &rect); ScreenToClient(&rect); } -bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint) +bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint) { return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint))); } + +/* +typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)( + HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute); + +static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect) +{ + // dll load and free is too slow : 300 calls in second. + NDLL::CLibrary dll; + if (!dll.Load(FTEXT("dwmapi.dll"))) + return false; + Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" ); + if (f) + { + #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9 + // 30000 per second + RECT r; + if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK) + { + *rect = r; + return true; + } + } + return false; +} +*/ + + +static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big) +{ + return sm.left >= big.left + && sm.right <= big.right + && sm.top >= big.top + && sm.bottom <= big.bottom; +} + + +static bool AreRectsOverlapped(const RECT &r1, const RECT &r2) +{ + return r1.left < r2.right + && r1.right > r2.left + && r1.top < r2.bottom + && r1.bottom > r2.top; +} + + +static bool AreRectsEqual(const RECT &r1, const RECT &r2) +{ + return r1.left == r2.left + && r1.right == r2.right + && r1.top == r2.top + && r1.bottom == r2.bottom; +} + + void CDialog::NormalizeSize(bool fullNormalize) { RECT workRect; - GetWorkAreaRect(&workRect); - int xSize = RECT_SIZE_X(workRect); - int ySize = RECT_SIZE_Y(workRect); + if (!GetWorkAreaRect(&workRect, *this)) + return; RECT rect; - GetWindowRect(&rect); - int xSize2 = RECT_SIZE_X(rect); - int ySize2 = RECT_SIZE_Y(rect); - bool needMove = (xSize2 > xSize || ySize2 > ySize); - if (xSize2 > xSize || (needMove && fullNormalize)) + if (!GetWindowRect(&rect)) + return; + int xs = RECT_SIZE_X(rect); + int ys = RECT_SIZE_Y(rect); + + // we don't want to change size using workRect, if window is outside of WorkArea + if (!AreRectsOverlapped(rect, workRect)) + return; + + /* here rect and workRect are overlapped, but it can be false + overlapping of small shadow when window in another display. */ + + const int xsW = RECT_SIZE_X(workRect); + const int ysW = RECT_SIZE_Y(workRect); + if (xs <= xsW && ys <= ysW) + return; // size of window is OK + if (fullNormalize) + { + Show(SW_SHOWMAXIMIZED); + return; + } + int x = workRect.left; + int y = workRect.top; + if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW; + if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW; + Move(x, y, xs, ys, true); +} + + +void CDialog::NormalizePosition() +{ + RECT workRect; + if (!GetWorkAreaRect(&workRect, *this)) + return; + + RECT rect2 = workRect; + bool useWorkArea = true; + const HWND parentHWND = GetParent(); + + if (parentHWND) { - rect.left = workRect.left; - rect.right = workRect.right; - xSize2 = xSize; + RECT workRectParent; + if (!GetWorkAreaRect(&workRectParent, parentHWND)) + return; + + // if windows are in different monitors, we use only workArea of current window + + if (AreRectsEqual(workRectParent, workRect)) + { + // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {} + CWindow wnd(parentHWND); + if (wnd.GetWindowRect(&rect2)) + { + // it's same monitor. So we try to use parentHWND rect. + /* we don't want to change position, if parent window is not inside work area. + In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow. + In maximize mode : window is outside of workRect. + if parent window is inside workRect, we will use parent window instead of workRect */ + if (IsRect_Small_Inside_Big(rect2, workRect)) + useWorkArea = false; + } + } } - if (ySize2 > ySize || (needMove && fullNormalize)) + + RECT rect; + if (!GetWindowRect(&rect)) + return; + + if (useWorkArea) { - rect.top = workRect.top; - rect.bottom = workRect.bottom; - ySize2 = ySize; + // we don't want to move window, if it's already inside. + if (IsRect_Small_Inside_Big(rect, workRect)) + return; + // we don't want to move window, if it's outside of workArea + if (!AreRectsOverlapped(rect, workRect)) + return; + rect2 = workRect; } - if (needMove) + { - if (fullNormalize) - Show(SW_SHOWMAXIMIZED); - else - Move(rect.left, rect.top, xSize2, ySize2, true); + const int xs = RECT_SIZE_X(rect); + const int ys = RECT_SIZE_Y(rect); + const int xs2 = RECT_SIZE_X(rect2); + const int ys2 = RECT_SIZE_Y(rect2); + // we don't want to change position if parent is smaller. + if (xs <= xs2 && ys <= ys2) + { + const int x = rect2.left + (xs2 - xs) / 2; + const int y = rect2.top + (ys2 - ys) / 2; + + if (x != rect.left || y != rect.top) + Move(x, y, xs, ys, true); + // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE); + return; + } } } -void CDialog::NormalizePosition() -{ - RECT workRect, rect; - GetWorkAreaRect(&workRect); - GetWindowRect(&rect); - if (rect.bottom > workRect.bottom && rect.top > workRect.top) - Move(rect.left, workRect.top, RECT_SIZE_X(rect), RECT_SIZE_Y(rect), true); -} + bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) { - HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); - if (aHWND == 0) + const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + if (!aHWND) return false; Attach(aHWND); return true; |