1 // This file is part of Notepad++ project 2 // Copyright (C)2003 Don HO <don.h@free.fr> 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. 8 // 9 // Note that the GPL places important restrictions on "derived works", yet 10 // it does not provide a detailed definition of that term. To avoid 11 // misunderstandings, we consider an application to constitute a 12 // "derivative work" for the purpose of this license if it does any of the 13 // following: 14 // 1. Integrates source code from Notepad++. 15 // 2. Integrates/includes/aggregates Notepad++ into a proprietary executable 16 // installer, such as those produced by InstallShield. 17 // 3. Links to a library or executes a program that does any of the above. 18 // 19 // This program is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU General Public License for more details. 23 // 24 // You should have received a copy of the GNU General Public License 25 // along with this program; if not, write to the Free Software 26 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27 /** 28 * 29 * 30 * License: GPL-2.0 or later 31 */ 32 module npp_api.powereditor.wincontrols.staticdialog.staticdialog; 33 34 35 version (Windows): 36 version (Not_betterC): 37 38 pragma(lib, "kernel32.lib"); 39 pragma(lib, "user32.lib"); 40 41 private static import core.sys.windows.basetsd; 42 private static import core.sys.windows.winbase; 43 private static import core.sys.windows.windef; 44 private static import core.sys.windows.winuser; 45 private static import core.stdc.config; 46 private static import core.stdc.string; 47 private static import std.utf; 48 private static import std.format; 49 private static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs; 50 private static import npp_api.powereditor.wincontrols.window; 51 private static import npp_api.pluginfunc.npp_msgs; 52 53 enum PosAlign 54 { 55 left, 56 right, 57 top, 58 bottom, 59 } 60 61 /** 62 * The structure has more fields but are variable length 63 */ 64 extern (C) 65 struct DLGTEMPLATEEX 66 { 67 static import core.sys.windows.windef; 68 69 core.sys.windows.windef.WORD dlgVer; 70 core.sys.windows.windef.WORD signature; 71 core.sys.windows.windef.DWORD helpID; 72 core.sys.windows.windef.DWORD exStyle; 73 core.sys.windows.windef.DWORD style; 74 core.sys.windows.windef.WORD cDlgItems; 75 short x; 76 short y; 77 short cx; 78 short cy; 79 } 80 81 abstract class StaticDialog : npp_api.powereditor.wincontrols.window.Window 82 { 83 static import core.sys.windows.basetsd; 84 static import core.sys.windows.winbase; 85 static import core.sys.windows.windef; 86 static import core.sys.windows.winuser; 87 static import core.stdc.config; 88 static import core.stdc.string; 89 static import std.utf; 90 static import std.format; 91 static import npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs; 92 static import npp_api.pluginfunc.npp_msgs; 93 94 public: 95 nothrow @nogc 96 ~this() 97 98 do 99 { 100 if (this.isCreated()) { 101 // Prevent run_dlgProc from doing anything, since its virtual 102 core.sys.windows.winuser.SetWindowLongPtrW(this._hSelf, core.sys.windows.winuser.GWLP_USERDATA, 0); 103 104 this.destroy(); 105 } 106 } 107 108 void create(void* dialog_p, int dialogID, bool isRTL = false, bool msgDestParent = true) 109 110 in 111 { 112 static assert(core.sys.windows.windef.LPARAM.sizeof >= dialog_p.sizeof); 113 assert(dialog_p != null); 114 } 115 116 do 117 { 118 if (isRTL) { 119 core.sys.windows.winuser.DLGTEMPLATE* pMyDlgTemplate = core.sys.windows.windef.NULL; 120 core.sys.windows.windef.HGLOBAL hMyDlgTemplate = this.makeRTLResource(dialogID, &pMyDlgTemplate); 121 this._hSelf = core.sys.windows.winuser.CreateDialogIndirectParamW(this._hInst, cast(core.sys.windows.winuser.LPCDLGTEMPLATEW)(pMyDlgTemplate), this._hParent, &this.dlgProc, cast(core.sys.windows.windef.LPARAM)(dialog_p)); 122 core.sys.windows.winbase.GlobalFree(hMyDlgTemplate); 123 } else { 124 this._hSelf = core.sys.windows.winuser.CreateDialogParamW(this._hInst, core.sys.windows.winuser.MAKEINTRESOURCEW(dialogID), this._hParent, &this.dlgProc, cast(core.sys.windows.windef.LPARAM)(dialog_p)); 125 } 126 127 if (this._hSelf == core.sys.windows.windef.NULL) { 128 throw new Exception(std.utf.toUTF8(std.format.format!("CreateDialogParamW() return NULL.\rGetLastError(): %d")(core.sys.windows.winbase.GetLastError()))); 129 } 130 131 // if the destination of message NPPM_MODELESSDIALOG is not its parent, then it's the grand-parent 132 core.sys.windows.winuser.SendMessageW(((msgDestParent) ? (this._hParent) : (core.sys.windows.winuser.GetParent(this._hParent))), npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.NPPM_MODELESSDIALOG, npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.MODELESSDIALOGADD, cast(core.sys.windows.windef.WPARAM)(this._hSelf)); 133 } 134 135 pure nothrow @safe @nogc 136 bool isCreated() const 137 138 do 139 { 140 return (this._hSelf != core.sys.windows.windef.NULL); 141 } 142 143 nothrow @nogc 144 void goToCenter() 145 146 do 147 { 148 core.sys.windows.windef.RECT rc; 149 core.sys.windows.winuser.GetClientRect(this._hParent, &rc); 150 core.sys.windows.windef.POINT center; 151 center.x = rc.left + (rc.right - rc.left) / 2; 152 center.y = rc.top + (rc.bottom - rc.top) / 2; 153 core.sys.windows.winuser.ClientToScreen(this._hParent, ¢er); 154 155 int x = center.x - (this._rc.right - this._rc.left) / 2; 156 int y = center.y - (this._rc.bottom - this._rc.top) / 2; 157 158 core.sys.windows.winuser.SetWindowPos(this._hSelf, core.sys.windows.winuser.HWND_TOP, x, y, this._rc.right - this._rc.left, this._rc.bottom - this._rc.top, core.sys.windows.winuser.SWP_SHOWWINDOW); 159 } 160 161 nothrow @nogc 162 override void destroy() 163 164 do 165 { 166 npp_api.pluginfunc.npp_msgs.send_NPPM_MODELESSDIALOG(this._hParent, npp_api.powereditor.misc.pluginsmanager.notepad_plus_msgs.MODELESSDIALOGREMOVE, this._hSelf); 167 core.sys.windows.winuser.DestroyWindow(this._hSelf); 168 } 169 170 nothrow @nogc 171 override void display(bool toShow) 172 173 do 174 { 175 if (toShow) { 176 // If the user has switched from a dual monitor to a single monitor since we last 177 // displayed the dialog, then ensure that it's still visible on the single monitor. 178 core.sys.windows.windef.RECT workAreaRect = {0}; 179 core.sys.windows.windef.RECT rc = {0}; 180 core.sys.windows.winuser.SystemParametersInfoW(core.sys.windows.winuser.SPI_GETWORKAREA, 0, &workAreaRect, 0); 181 core.sys.windows.winuser.GetWindowRect(this._hSelf, &rc); 182 int newLeft = rc.left; 183 int newTop = rc.top; 184 int margin = core.sys.windows.winuser.GetSystemMetrics(core.sys.windows.winuser.SM_CYSMCAPTION); 185 186 if (newLeft > core.sys.windows.winuser.GetSystemMetrics(core.sys.windows.winuser.SM_CXVIRTUALSCREEN) - margin) { 187 newLeft -= rc.right - workAreaRect.right; 188 } 189 190 if (newLeft + (rc.right - rc.left) < core.sys.windows.winuser.GetSystemMetrics(core.sys.windows.winuser.SM_XVIRTUALSCREEN) + margin) { 191 newLeft = workAreaRect.left; 192 } 193 194 if (newTop > core.sys.windows.winuser.GetSystemMetrics(core.sys.windows.winuser.SM_CYVIRTUALSCREEN) - margin) { 195 newTop -= rc.bottom - workAreaRect.bottom; 196 } 197 198 if (newTop + (rc.bottom - rc.top) < core.sys.windows.winuser.GetSystemMetrics(core.sys.windows.winuser.SM_YVIRTUALSCREEN) + margin) { 199 newTop = workAreaRect.top; 200 } 201 202 if ((newLeft != rc.left) || (newTop != rc.top)) // then the virtual screen size has shrunk 203 // Remember that core.sys.windows.winuser.MoveWindow wants width/height. 204 { 205 core.sys.windows.winuser.MoveWindow(this._hSelf, newLeft, newTop, rc.right - rc.left, rc.bottom - rc.top, core.sys.windows.windef.TRUE); 206 } 207 } 208 209 super.display(toShow); 210 } 211 212 nothrow @nogc 213 core.sys.windows.windef.POINT getTopPoint(core.sys.windows.windef.HWND hwnd, bool isLeft) 214 215 do 216 { 217 core.sys.windows.windef.RECT rc; 218 core.sys.windows.winuser.GetWindowRect(hwnd, &rc); 219 220 core.sys.windows.windef.POINT p; 221 222 if (isLeft) { 223 p.x = rc.left; 224 } else { 225 p.x = rc.right; 226 } 227 228 p.y = rc.top; 229 core.sys.windows.winuser.ScreenToClient(this._hSelf, &p); 230 231 return p; 232 } 233 234 protected: 235 core.sys.windows.windef.RECT _rc; 236 237 extern (Windows) 238 nothrow @nogc 239 static core.sys.windows.basetsd.INT_PTR dlgProc(core.sys.windows.windef.HWND hwnd, core.sys.windows.windef.UINT message, core.sys.windows.windef.WPARAM wParam, core.sys.windows.windef.LPARAM lParam) 240 241 in 242 { 243 } 244 245 do 246 { 247 switch (message) { 248 case core.sys.windows.winuser.WM_INITDIALOG: 249 StaticDialog* pStaticDlg = cast(StaticDialog*)(lParam); 250 251 (*pStaticDlg)._hSelf = hwnd; 252 core.sys.windows.winuser.SetWindowLongPtrW(hwnd, core.sys.windows.winuser.GWLP_USERDATA, cast(core.sys.windows.basetsd.LONG_PTR)(lParam)); 253 core.sys.windows.winuser.GetWindowRect(hwnd, &((*pStaticDlg)._rc)); 254 (*pStaticDlg).run_dlgProc(message, wParam, lParam); 255 256 return core.sys.windows.windef.TRUE; 257 258 default: 259 StaticDialog* pStaticDlg = cast(StaticDialog*)(core.sys.windows.winuser.GetWindowLongPtrW(hwnd, core.sys.windows.winuser.GWLP_USERDATA)); 260 261 if (pStaticDlg == core.sys.windows.windef.NULL) { 262 return core.sys.windows.windef.FALSE; 263 } 264 265 return (*pStaticDlg).run_dlgProc(message, wParam, lParam); 266 } 267 } 268 269 extern (Windows) 270 nothrow @nogc 271 core.sys.windows.basetsd.INT_PTR run_dlgProc(core.sys.windows.windef.UINT message, core.sys.windows.windef.WPARAM wParam, core.sys.windows.windef.LPARAM lParam); 272 273 nothrow @nogc 274 void alignWith(core.sys.windows.windef.HWND handle, core.sys.windows.windef.HWND handle2Align, .PosAlign pos, ref core.sys.windows.windef.POINT point) 275 276 in 277 { 278 } 279 280 do 281 { 282 core.sys.windows.windef.RECT rc, rc2; 283 core.sys.windows.winuser.GetWindowRect(handle, &rc); 284 285 point.x = rc.left; 286 point.y = rc.top; 287 288 switch (pos) { 289 case .PosAlign.left: 290 core.sys.windows.winuser.GetWindowRect(handle2Align, &rc2); 291 point.x -= rc2.right - rc2.left; 292 293 break; 294 295 case .PosAlign.right: 296 core.sys.windows.winuser.GetWindowRect(handle, &rc2); 297 point.x += rc2.right - rc2.left; 298 299 break; 300 301 case .PosAlign.top: 302 core.sys.windows.winuser.GetWindowRect(handle2Align, &rc2); 303 point.y -= rc2.bottom - rc2.top; 304 305 break; 306 307 case .PosAlign.bottom: 308 core.sys.windows.winuser.GetWindowRect(handle, &rc2); 309 point.y += rc2.bottom - rc2.top; 310 311 break; 312 313 default: 314 break; 315 } 316 317 core.sys.windows.winuser.ScreenToClient(this._hSelf, &point); 318 } 319 320 nothrow @nogc 321 core.sys.windows.windef.HGLOBAL makeRTLResource(int dialogID, core.sys.windows.winuser.DLGTEMPLATE** ppMyDlgTemplate) 322 323 in 324 { 325 assert(ppMyDlgTemplate != null); 326 } 327 328 do 329 { 330 // Get Dlg Template resource 331 core.sys.windows.windef.HRSRC hDialogRC = core.sys.windows.winbase.FindResourceW(this._hInst, core.sys.windows.winuser.MAKEINTRESOURCEW(dialogID), core.sys.windows.winuser.RT_DIALOG); 332 333 if (hDialogRC == core.sys.windows.windef.NULL) { 334 return core.sys.windows.windef.NULL; 335 } 336 337 core.sys.windows.windef.HGLOBAL hDlgTemplate = core.sys.windows.winbase.LoadResource(this._hInst, hDialogRC); 338 339 if (hDlgTemplate == core.sys.windows.windef.NULL) { 340 return core.sys.windows.windef.NULL; 341 } 342 343 core.sys.windows.winuser.DLGTEMPLATE* pDlgTemplate = cast(core.sys.windows.winuser.DLGTEMPLATE*)(core.sys.windows.winbase.LockResource(hDlgTemplate)); 344 345 if (pDlgTemplate == core.sys.windows.windef.NULL) { 346 return core.sys.windows.windef.NULL; 347 } 348 349 // Duplicate Dlg Template resource 350 core.stdc.config.c_ulong sizeDlg = core.sys.windows.winbase.SizeofResource(this._hInst, hDialogRC); 351 core.sys.windows.windef.HGLOBAL hMyDlgTemplate = core.sys.windows.winbase.GlobalAlloc(core.sys.windows.winbase.GPTR, sizeDlg); 352 *ppMyDlgTemplate = cast(core.sys.windows.winuser.DLGTEMPLATE*)(core.sys.windows.winbase.GlobalLock(hMyDlgTemplate)); 353 354 core.stdc..string.memcpy(*ppMyDlgTemplate, pDlgTemplate, sizeDlg); 355 356 .DLGTEMPLATEEX* pMyDlgTemplateEx = cast(.DLGTEMPLATEEX*)(*ppMyDlgTemplate); 357 358 if ((*pMyDlgTemplateEx).signature == 0xFFFF) { 359 (*pMyDlgTemplateEx).exStyle |= core.sys.windows.winuser.WS_EX_LAYOUTRTL; 360 } else { 361 (*ppMyDlgTemplate).dwExtendedStyle |= core.sys.windows.winuser.WS_EX_LAYOUTRTL; 362 } 363 364 return hMyDlgTemplate; 365 } 366 }