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 }