1- // this file is part of notepad++
2- // Copyright (C)2003 Don HO ( [email protected] ) 3- //
4- // This program is free software; you can redistribute it and/or
5- // modify it under the terms of the GNU General Public License
6- // as published by the Free Software Foundation; either
7- // version 2 of the License, or ( at your option) any later version.
1+ // This file is part of Notepad++ project
2+ // Copyright (C)2022 Don HO <[email protected] > 3+
4+ // This program is free software: you can redistribute it and/or modify
5+ // it under the terms of the GNU General Public License as published by
6+ // the Free Software Foundation, either version 3 of the License, or
7+ // at your option any later version.
88//
9- // This program is distributed in the hope that it will be useful,
10- // but WITHOUT ANY WARRANTY; without even the implied warranty of
11- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12- // GNU General Public License for more details.
9+ // This program is distributed in the hope that it will be useful,
10+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
11+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+ // GNU General Public License for more details.
1313//
14- // You should have received a copy of the GNU General Public License
15- // along with this program; if not, write to the Free Software
16- // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
14+ // You should have received a copy of the GNU General Public License
15+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
1716
1817#include < stdio.h>
18+ #include < string>
19+ #include < windows.h>
1920#include " StaticDialog.h"
2021
22+ StaticDialog::~StaticDialog ()
23+ {
24+ if (isCreated ())
25+ {
26+ // Prevent run_dlgProc from doing anything, since its virtual
27+ ::SetWindowLongPtr (_hSelf, GWLP_USERDATA, NULL );
28+ destroy ();
29+ }
30+ }
31+
32+ void StaticDialog::destroy ()
33+ {
34+ ::SendMessage (_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGREMOVE, reinterpret_cast <WPARAM>(_hSelf));
35+ ::DestroyWindow (_hSelf);
36+ }
37+
38+ POINT StaticDialog::getTopPoint (HWND hwnd, bool isLeft) const
39+ {
40+ RECT rc;
41+ ::GetWindowRect (hwnd, &rc);
42+
43+ POINT p;
44+ if (isLeft)
45+ p.x = rc.left ;
46+ else
47+ p.x = rc.right ;
48+
49+ p.y = rc.top ;
50+ ::ScreenToClient (_hSelf, &p);
51+ return p;
52+ }
53+
2154void StaticDialog::goToCenter ()
2255{
2356 RECT rc;
@@ -33,6 +66,111 @@ void StaticDialog::goToCenter()
3366 ::SetWindowPos (_hSelf, HWND_TOP, x, y, _rc.right - _rc.left, _rc.bottom - _rc.top, SWP_SHOWWINDOW);
3467}
3568
69+ void StaticDialog::display (bool toShow, bool enhancedPositioningCheckWhenShowing) const
70+ {
71+ if (toShow)
72+ {
73+ if (enhancedPositioningCheckWhenShowing)
74+ {
75+ RECT testPositionRc, candidateRc;
76+
77+ getWindowRect (testPositionRc);
78+
79+ candidateRc = getViewablePositionRect (testPositionRc);
80+
81+ if ((testPositionRc.left != candidateRc.left ) || (testPositionRc.top != candidateRc.top ))
82+ {
83+ ::MoveWindow (_hSelf, candidateRc.left, candidateRc.top,
84+ candidateRc.right - candidateRc.left, candidateRc.bottom - candidateRc.top, TRUE );
85+ }
86+ }
87+ else
88+ {
89+ // If the user has switched from a dual monitor to a single monitor since we last
90+ // displayed the dialog, then ensure that it's still visible on the single monitor.
91+ RECT workAreaRect = { 0 };
92+ RECT rc = { 0 };
93+ ::SystemParametersInfo (SPI_GETWORKAREA, 0 , &workAreaRect, 0 );
94+ ::GetWindowRect (_hSelf, &rc);
95+ int newLeft = rc.left ;
96+ int newTop = rc.top ;
97+ int margin = ::GetSystemMetrics (SM_CYSMCAPTION);
98+
99+ if (newLeft > ::GetSystemMetrics (SM_CXVIRTUALSCREEN) - margin)
100+ newLeft -= rc.right - workAreaRect.right ;
101+ if (newLeft + (rc.right - rc.left ) < ::GetSystemMetrics (SM_XVIRTUALSCREEN) + margin)
102+ newLeft = workAreaRect.left ;
103+ if (newTop > ::GetSystemMetrics (SM_CYVIRTUALSCREEN) - margin)
104+ newTop -= rc.bottom - workAreaRect.bottom ;
105+ if (newTop + (rc.bottom - rc.top ) < ::GetSystemMetrics (SM_YVIRTUALSCREEN) + margin)
106+ newTop = workAreaRect.top ;
107+
108+ if ((newLeft != rc.left ) || (newTop != rc.top )) // then the virtual screen size has shrunk
109+ // Remember that MoveWindow wants width/height.
110+ ::MoveWindow (_hSelf, newLeft, newTop, rc.right - rc.left, rc.bottom - rc.top, TRUE );
111+ }
112+ }
113+
114+ Window::display (toShow);
115+ }
116+
117+ RECT StaticDialog::getViewablePositionRect (RECT testPositionRc) const
118+ {
119+ HMONITOR hMon = ::MonitorFromRect (&testPositionRc, MONITOR_DEFAULTTONULL);
120+
121+ MONITORINFO mi;
122+ mi.cbSize = sizeof (MONITORINFO);
123+
124+ bool rectPosViewableWithoutChange = false ;
125+
126+ if (hMon != NULL )
127+ {
128+ // rect would be at least partially visible on a monitor
129+
130+ ::GetMonitorInfo (hMon, &mi);
131+
132+ int margin = ::GetSystemMetrics (SM_CYBORDER) + ::GetSystemMetrics (SM_CYSIZEFRAME) + ::GetSystemMetrics (SM_CYCAPTION);
133+
134+ // require that the title bar of the window be in a viewable place so the user can see it to grab it with the mouse
135+ if ((testPositionRc.top >= mi.rcWork .top ) && (testPositionRc.top + margin <= mi.rcWork .bottom ) &&
136+ // require that some reasonable amount of width of the title bar be in the viewable area:
137+ (testPositionRc.right - (margin * 2 ) > mi.rcWork .left ) && (testPositionRc.left + (margin * 2 ) < mi.rcWork .right ))
138+ {
139+ rectPosViewableWithoutChange = true ;
140+ }
141+ }
142+ else
143+ {
144+ // rect would not have been visible on a monitor; get info about the nearest monitor to it
145+
146+ hMon = ::MonitorFromRect (&testPositionRc, MONITOR_DEFAULTTONEAREST);
147+
148+ ::GetMonitorInfo (hMon, &mi);
149+ }
150+
151+ RECT returnRc = testPositionRc;
152+
153+ if (!rectPosViewableWithoutChange)
154+ {
155+ // reposition rect so that it would be viewable on current/nearest monitor, centering if reasonable
156+
157+ LONG testRectWidth = testPositionRc.right - testPositionRc.left ;
158+ LONG testRectHeight = testPositionRc.bottom - testPositionRc.top ;
159+ LONG monWidth = mi.rcWork .right - mi.rcWork .left ;
160+ LONG monHeight = mi.rcWork .bottom - mi.rcWork .top ;
161+
162+ returnRc.left = mi.rcWork .left ;
163+ if (testRectWidth < monWidth) returnRc.left += (monWidth - testRectWidth) / 2 ;
164+ returnRc.right = returnRc.left + testRectWidth;
165+
166+ returnRc.top = mi.rcWork .top ;
167+ if (testRectHeight < monHeight) returnRc.top += (monHeight - testRectHeight) / 2 ;
168+ returnRc.bottom = returnRc.top + testRectHeight;
169+ }
170+
171+ return returnRc;
172+ }
173+
36174HGLOBAL StaticDialog::makeRTLResource (int dialogID, DLGTEMPLATE **ppMyDlgTemplate)
37175{
38176 // Get Dlg Template resource
@@ -44,32 +182,49 @@ HGLOBAL StaticDialog::makeRTLResource(int dialogID, DLGTEMPLATE **ppMyDlgTemplat
44182 if (!hDlgTemplate)
45183 return NULL ;
46184
47- DLGTEMPLATE *pDlgTemplate = reinterpret_cast <DLGTEMPLATE *>(::LockResource (hDlgTemplate));
185+ DLGTEMPLATE *pDlgTemplate = static_cast <DLGTEMPLATE *>(::LockResource (hDlgTemplate));
48186 if (!pDlgTemplate)
49187 return NULL ;
50188
51189 // Duplicate Dlg Template resource
52190 unsigned long sizeDlg = ::SizeofResource (_hInst, hDialogRC);
53191 HGLOBAL hMyDlgTemplate = ::GlobalAlloc (GPTR, sizeDlg);
54- if (hMyDlgTemplate)
55- {
56- *ppMyDlgTemplate = reinterpret_cast <DLGTEMPLATE *>(::GlobalLock (hMyDlgTemplate));
57- if (*ppMyDlgTemplate)
58- {
59- ::memcpy (*ppMyDlgTemplate, pDlgTemplate, sizeDlg);
60-
61- DLGTEMPLATEEX *pMyDlgTemplateEx = reinterpret_cast <DLGTEMPLATEEX *>(*ppMyDlgTemplate);
62- if (pMyDlgTemplateEx->signature == 0xFFFF )
63- pMyDlgTemplateEx->exStyle |= WS_EX_LAYOUTRTL;
64- else
65- (*ppMyDlgTemplate)->dwExtendedStyle |= WS_EX_LAYOUTRTL;
66- }
67- }
192+ *ppMyDlgTemplate = static_cast <DLGTEMPLATE *>(::GlobalLock (hMyDlgTemplate));
193+
194+ ::memcpy (*ppMyDlgTemplate, pDlgTemplate, sizeDlg);
195+
196+ DLGTEMPLATEEX *pMyDlgTemplateEx = reinterpret_cast <DLGTEMPLATEEX *>(*ppMyDlgTemplate);
197+ if (pMyDlgTemplateEx->signature == 0xFFFF )
198+ pMyDlgTemplateEx->exStyle |= WS_EX_LAYOUTRTL;
199+ else
200+ (*ppMyDlgTemplate)->dwExtendedStyle |= WS_EX_LAYOUTRTL;
68201
69202 return hMyDlgTemplate;
70203}
71204
72- void StaticDialog::create (int dialogID, bool isRTL)
205+ std::wstring GetLastErrorAsString (DWORD errorCode)
206+ {
207+ std::wstring errorMsg (L" " );
208+ // Get the error message, if any.
209+ // If both error codes (passed error n GetLastError) are 0, then return empty
210+ if (errorCode == 0 )
211+ errorCode = GetLastError ();
212+ if (errorCode == 0 )
213+ return errorMsg; // No error message has been recorded
214+
215+ LPWSTR messageBuffer = nullptr ;
216+ FormatMessageW (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
217+ nullptr , errorCode, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0 , nullptr );
218+
219+ errorMsg += messageBuffer;
220+
221+ // Free the buffer.
222+ LocalFree (messageBuffer);
223+
224+ return errorMsg;
225+ }
226+
227+ void StaticDialog::create (int dialogID, bool isRTL, bool msgDestParent)
73228{
74229 if (isRTL)
75230 {
@@ -83,15 +238,14 @@ void StaticDialog::create(int dialogID, bool isRTL)
83238
84239 if (!_hSelf)
85240 {
86- DWORD err = ::GetLastError ();
87- char errMsg[256 ] {};
88- sprintf_s (errMsg, " CreateDialogParam() return NULL.\r GetLastError() == %lu" , err);
89- ::MessageBoxA (NULL , errMsg, " In StaticDialog::create()" , MB_OK);
241+ std::wstring errMsg = TEXT (" CreateDialogParam() return NULL.\r GetLastError(): " );
242+ errMsg += GetLastErrorAsString (0 );
243+ ::MessageBox (NULL , errMsg.c_str(), TEXT(" In StaticDialog::create()" ), MB_OK);
90244 return ;
91245 }
92246
93247 // if the destination of message NPPM_MODELESSDIALOG is not its parent, then it's the grand-parent
94- ::SendMessage (_hParent, NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast <WPARAM>(_hSelf));
248+ ::SendMessage (msgDestParent ? _hParent : (::GetParent(_hParent)) , NPPM_MODELESSDIALOG, MODELESSDIALOGADD, reinterpret_cast<WPARAM>(_hSelf));
95249}
96250
97251INT_PTR CALLBACK StaticDialog::dlgProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
@@ -157,4 +311,3 @@ void StaticDialog::alignWith(HWND handle, HWND handle2Align, PosAlign pos, POINT
157311
158312 ::ScreenToClient (_hSelf, &point);
159313}
160-
0 commit comments