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