1 /** DGui project file. 2 3 Copyright: Trogu Antonio Davide 2011-2013 4 5 License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 7 Authors: Trogu Antonio Davide 8 */ 9 module dguihub.form; 10 11 public import dguihub.core.dialogs.dialogresult; 12 public import dguihub.menubar; 13 14 private import dguihub.core.utils; 15 import dguihub.layout.layoutcontrol; 16 import dguihub.core.events.eventargs; 17 18 alias CancelEventArgs!(Form) CancelFormEventArgs; 19 20 enum FormBits : ulong { 21 none = 0, 22 modalCompleted = 1, 23 } 24 25 enum FormBorderStyle : ubyte { 26 none = 0, 27 manual = 1, // Internal Use 28 fixedSingle = 2, 29 fixed3d = 4, 30 fixedDialog = 8, 31 sizeable = 16, 32 fixedToolWindow = 32, 33 sizeableToolWindow = 64, 34 } 35 36 enum FormStartPosition : ubyte { 37 manual = 0, 38 centerParent = 1, 39 centerScreen = 2, 40 defaultLocation = 4, 41 } 42 43 class Form : LayoutControl { 44 private FormBits _fBits = FormBits.none; 45 private FormStartPosition _startPosition = FormStartPosition.manual; 46 private FormBorderStyle _formBorder = FormBorderStyle.sizeable; 47 private DialogResult _dlgResult = DialogResult.cancel; 48 private HWND _hActiveWnd; 49 private Icon _formIcon; 50 private MenuBar _menu; 51 52 public Event!(Control, EventArgs) close; 53 public Event!(Control, CancelFormEventArgs) closing; 54 55 public this() { 56 this.setStyle(WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX, true); 57 } 58 59 @property public final void formBorderStyle(FormBorderStyle fbs) { 60 if (this.created) { 61 uint style = 0, exStyle = 0; 62 63 makeFormBorderStyle(this._formBorder, style, exStyle); // Vecchio Stile. 64 this.setStyle(style, false); 65 this.setExStyle(exStyle, false); 66 67 style = 0; 68 exStyle = 0; 69 70 makeFormBorderStyle(fbs, style, exStyle); // Nuovo Stile. 71 this.setStyle(style, true); 72 this.setExStyle(exStyle, true); 73 } 74 75 this._formBorder = fbs; 76 } 77 78 @property public final void controlBox(bool b) { 79 this.setStyle(WS_SYSMENU, b); 80 } 81 82 @property public final void maximizeBox(bool b) { 83 this.setStyle(WS_MAXIMIZEBOX, b); 84 } 85 86 @property public final void minimizeBox(bool b) { 87 this.setStyle(WS_MINIMIZEBOX, b); 88 } 89 90 @property public final void showInTaskbar(bool b) { 91 this.setExStyle(WS_EX_APPWINDOW, b); 92 } 93 94 @property public final MenuBar menu() { 95 return this._menu; 96 } 97 98 @property public final void menu(MenuBar mb) { 99 if (this.created) { 100 if (this._menu) { 101 this._menu.dispose(); 102 } 103 104 mb.create(); 105 SetMenu(this._handle, mb.handle); 106 } 107 108 this._menu = mb; 109 } 110 111 @property public final Icon icon() { 112 return this._formIcon; 113 } 114 115 @property public final void icon(Icon ico) { 116 if (this.created) { 117 if (this._formIcon) { 118 this._formIcon.dispose(); 119 } 120 121 this.sendMessage(WM_SETICON, ICON_BIG, cast(LPARAM)ico.handle); 122 this.sendMessage(WM_SETICON, ICON_SMALL, cast(LPARAM)ico.handle); 123 } 124 125 this._formIcon = ico; 126 } 127 128 @property public final void topMost(bool b) { 129 this.setExStyle(WS_EX_TOPMOST, b); 130 } 131 132 @property public final void startPosition(FormStartPosition fsp) { 133 this._startPosition = fsp; 134 } 135 136 private void doEvents() { 137 MSG m = void; 138 139 while (GetMessageW(&m, null, 0, 0)) { 140 if (Form.hasBit(this._cBits, ControlBits.modalControl) 141 && Form.hasBit(this._fBits, FormBits.modalCompleted)) { 142 break; 143 } else if (!IsDialogMessageW(this._handle, &m)) { 144 TranslateMessage(&m); 145 DispatchMessageW(&m); 146 } 147 } 148 } 149 150 public override void show() { 151 super.show(); 152 153 this.doEvents(); 154 } 155 156 public final DialogResult showDialog() { 157 Form.setBit(this._cBits, ControlBits.modalControl, true); 158 this._hActiveWnd = GetActiveWindow(); 159 EnableWindow(this._hActiveWnd, false); 160 161 this.show(); 162 return this._dlgResult; 163 } 164 165 private final void doFormStartPosition() { 166 if ((this._startPosition is FormStartPosition.centerParent 167 && !this.parent) || this._startPosition is FormStartPosition.centerScreen) { 168 Rect wa = Screen.workArea; 169 Rect b = this._bounds; 170 171 this._bounds.position = Point((wa.width - b.width) / 2, (wa.height - b.height) / 2); 172 } else if (this._startPosition is FormStartPosition.centerParent) { 173 Rect pr = this.parent.bounds; 174 Rect b = this._bounds; 175 176 this._bounds.position = Point(pr.left + (pr.width - b.width) / 2, 177 pr.top + (pr.height - b.height) / 2); 178 } else if (this._startPosition is FormStartPosition.defaultLocation) { 179 this._bounds.position = Point(CW_USEDEFAULT, CW_USEDEFAULT); 180 } 181 } 182 183 private static void makeFormBorderStyle(FormBorderStyle fbs, ref uint style, ref uint exStyle) { 184 switch (fbs) { 185 case FormBorderStyle.fixed3d: 186 style &= ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME); 187 exStyle &= ~(WS_EX_TOOLWINDOW | WS_EX_STATICEDGE); 188 189 style |= WS_CAPTION; 190 exStyle |= WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME; 191 break; 192 193 case FormBorderStyle.fixedDialog: 194 style &= ~(WS_BORDER | WS_THICKFRAME); 195 exStyle &= ~(WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); 196 197 style |= WS_CAPTION | WS_DLGFRAME; 198 exStyle |= WS_EX_DLGMODALFRAME | WS_EX_WINDOWEDGE; 199 break; 200 201 case FormBorderStyle.fixedSingle: 202 style &= ~(WS_THICKFRAME | WS_DLGFRAME); 203 exStyle &= ~(WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE | WS_EX_STATICEDGE); 204 205 style |= WS_CAPTION | WS_BORDER; 206 exStyle |= WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME; 207 break; 208 209 case FormBorderStyle.fixedToolWindow: 210 style &= ~(WS_BORDER | WS_THICKFRAME | WS_DLGFRAME); 211 exStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_STATICEDGE); 212 213 style |= WS_CAPTION; 214 exStyle |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE | WS_EX_DLGMODALFRAME; 215 break; 216 217 case FormBorderStyle.sizeable: 218 style &= ~(WS_BORDER | WS_DLGFRAME); 219 exStyle &= ~(WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE); 220 221 style |= WS_CAPTION | WS_THICKFRAME; 222 exStyle |= WS_EX_WINDOWEDGE; 223 break; 224 225 case FormBorderStyle.sizeableToolWindow: 226 style &= ~(WS_BORDER | WS_DLGFRAME); 227 exStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME | WS_EX_STATICEDGE); 228 229 style |= WS_THICKFRAME | WS_CAPTION; 230 exStyle |= WS_EX_TOOLWINDOW | WS_EX_WINDOWEDGE; 231 break; 232 233 case FormBorderStyle.none: 234 style &= ~(WS_BORDER | WS_THICKFRAME | WS_CAPTION | WS_DLGFRAME); 235 exStyle &= ~( 236 WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME 237 | WS_EX_STATICEDGE | WS_EX_WINDOWEDGE); 238 break; 239 240 default: 241 assert(0, "Unknown Form Border Style"); 242 //break; 243 } 244 } 245 246 protected override void onDGuiMessage(ref Message m) { 247 switch (m.msg) { 248 case DGUI_SETDIALOGRESULT: { 249 this._dlgResult = cast(DialogResult)m.wParam; 250 251 Form.setBit(this._fBits, FormBits.modalCompleted, true); 252 ShowWindow(this._handle, SW_HIDE); // Hide this window (it waits to be destroyed) 253 EnableWindow(this._hActiveWnd, true); 254 SetActiveWindow(this._hActiveWnd); // Restore the previous active window 255 } 256 break; 257 258 default: 259 break; 260 } 261 262 super.onDGuiMessage(m); 263 } 264 265 protected override void createControlParams(ref CreateControlParams ccp) { 266 uint style = 0, exStyle = 0; 267 makeFormBorderStyle(this._formBorder, style, exStyle); 268 269 this.setStyle(style, true); 270 this.setExStyle(exStyle, true); 271 ccp.className = WC_FORM; 272 ccp.defaultCursor = SystemCursors.arrow; 273 274 this.doFormStartPosition(); 275 super.createControlParams(ccp); 276 } 277 278 protected override void onHandleCreated(EventArgs e) { 279 if (this._menu) { 280 this._menu.create(); 281 SetMenu(this._handle, this._menu.handle); 282 DrawMenuBar(this._handle); 283 } 284 285 if (this._formIcon) { 286 Message m = Message(this._handle, WM_SETICON, ICON_BIG, 287 cast(LPARAM)this._formIcon.handle); 288 this.originalWndProc(m); 289 290 m.msg = ICON_SMALL; 291 this.originalWndProc(m); 292 } 293 294 super.onHandleCreated(e); 295 } 296 297 protected override void wndProc(ref Message m) { 298 switch (m.msg) { 299 case WM_CLOSE: { 300 scope CancelFormEventArgs e = new CancelFormEventArgs(this); 301 this.onClosing(e); 302 303 if (!e.cancel) { 304 this.onClose(EventArgs.empty); 305 306 if (Form.hasBit(this._cBits, ControlBits.modalControl)) { 307 EnableWindow(this._hActiveWnd, true); 308 SetActiveWindow(this._hActiveWnd); 309 } 310 311 super.wndProc(m); 312 } 313 314 m.result = 0; 315 } 316 break; 317 318 case WM_CONTEXTMENU: { 319 // Display default shortcut menu in case of click on window's caption. 320 321 Rect r = void; 322 GetClientRect(handle, &r.rect); 323 324 auto pt = Point(LOWORD(m.lParam), HIWORD(m.lParam)); 325 convertPoint(pt, null, this); 326 if (pt.inRect(r)) 327 goto default; 328 329 originalWndProc(m); 330 } 331 break; 332 333 default: 334 super.wndProc(m); 335 break; 336 } 337 } 338 339 protected void onClosing(CancelFormEventArgs e) { 340 this.closing(this, e); 341 } 342 343 protected void onClose(EventArgs e) { 344 this.close(this, e); 345 } 346 }