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.toolbar;
10
11 import dgui.core.controls.subclassedcontrol;
12 import dgui.core.utils;
13 public import dgui.imagelist;
14
15 enum ToolButtonStyle: ubyte
16 {
17 button = TBSTYLE_BUTTON,
18 separator = TBSTYLE_SEP,
19 dropdown = TBSTYLE_DROPDOWN,
20 }
21
22 class ToolButton
23 {
24 public Event!(ToolButton, EventArgs) click;
25
26 private ToolBar _owner;
27 private ContextMenu _ctxMenu;
28 private ToolButtonStyle _tbs;
29 private int _imgIndex;
30 private bool _enabled;
31
32 package this(ToolBar tb, ToolButtonStyle tbs, int imgIndex, bool enabled)
33 {
34 this._owner = tb;
35 this._tbs = tbs;
36 this._imgIndex = imgIndex;
37 this._enabled = enabled;
38 }
39
40 @property public final int index()
41 {
42 if(this._owner && this._owner.created && this._owner.buttons)
43 {
44 int i = 0;
45
46 foreach(ToolButton tbtn; this._owner.buttons)
47 {
48 if(tbtn is this)
49 {
50 return i;
51 }
52
53 i++;
54 }
55 }
56
57 return -1;
58 }
59
60 @property public final ToolButtonStyle style()
61 {
62 return this._tbs;
63 }
64
65 @property public final void style(ToolButtonStyle tbs)
66 {
67 this._tbs = tbs;
68
69 if(this._owner && this._owner.created)
70 {
71 TBBUTTONINFOW tbinfo = void;
72
73 tbinfo.cbSize = TBBUTTONINFOW.sizeof;
74 tbinfo.dwMask = TBIF_BYINDEX | TBIF_STYLE;
75 tbinfo.fsStyle = tbs;
76
77 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo);
78 }
79 }
80
81 @property public final int imageIndex()
82 {
83 return this._imgIndex;
84 }
85
86 @property public final void imageIndex(int idx)
87 {
88 this._imgIndex = idx;
89
90 if(this._owner && this._owner.created)
91 {
92 TBBUTTONINFOW tbinfo = void;
93
94 tbinfo.cbSize = TBBUTTONINFOW.sizeof;
95 tbinfo.dwMask = TBIF_BYINDEX | TBIF_IMAGE;
96 tbinfo.iImage = idx;
97
98 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo);
99 }
100 }
101
102 @property public final bool enabled()
103 {
104 return this._enabled;
105 }
106
107 @property public final void enabled(bool b)
108 {
109 this._enabled = b;
110
111 if(this._owner && this._owner.created)
112 {
113 TBBUTTONINFOW tbinfo = void;
114
115 tbinfo.cbSize = TBBUTTONINFOW.sizeof;
116 tbinfo.dwMask = TBIF_BYINDEX | TBIF_STATE;
117 this._owner.sendMessage(TB_GETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo); //Ricavo i dati completi.
118
119 b ? (tbinfo.fsState |= TBSTATE_ENABLED) : (tbinfo.fsState &= ~TBSTATE_ENABLED);
120 this._owner.sendMessage(TB_SETBUTTONINFOW, this.index, cast(LPARAM)&tbinfo);
121 }
122 }
123
124 @property public ContextMenu contextMenu()
125 {
126 return this._ctxMenu;
127 }
128
129 @property public void contextMenu(ContextMenu cm)
130 {
131 this._ctxMenu = cm;
132 }
133
134 @property public final ToolBar toolBar()
135 {
136 return this._owner;
137 }
138
139 package void onToolBarButtonClick(EventArgs e)
140 {
141 this.click(this, e);
142 }
143 }
144
145 class ToolBar: SubclassedControl
146 {
147 private Collection!(ToolButton) _buttons;
148 private ImageList _imgList;
149
150 @property public final ImageList imageList()
151 {
152 return this._imgList;
153 }
154
155 @property public final void imageList(ImageList imgList)
156 {
157 this._imgList = imgList;
158
159 if(this.created)
160 {
161 this.sendMessage(TB_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle);
162 }
163 }
164
165 public final ToolButton addDropdownButton(int imgIndex, ContextMenu ctxMenu, bool en = true)
166 {
167 if(!this._buttons)
168 {
169 this._buttons = new Collection!(ToolButton)();
170 }
171
172 ToolButton tb = new ToolButton(this, ToolButtonStyle.dropdown, imgIndex, en);
173 tb.contextMenu = ctxMenu;
174 this._buttons.add(tb);
175
176 if(this.created)
177 {
178 ToolBar.addItem(tb);
179 }
180
181 return tb;
182 }
183
184 public final ToolButton addButton(int imgIndex, bool en = true)
185 {
186 if(!this._buttons)
187 {
188 this._buttons = new Collection!(ToolButton)();
189 }
190
191 ToolButton tb = new ToolButton(this, ToolButtonStyle.button, imgIndex, en);
192 this._buttons.add(tb);
193
194 if(this.created)
195 {
196 ToolBar.addItem(tb);
197 }
198
199 return tb;
200 }
201
202 public final void addSeparator()
203 {
204 if(!this._buttons)
205 {
206 this._buttons = new Collection!(ToolButton)();
207 }
208
209 ToolButton tb = new ToolButton(this, ToolButtonStyle.separator, -1, true);
210 this._buttons.add(tb);
211
212 if(this.created)
213 {
214 ToolBar.addItem(tb);
215 }
216 }
217
218 public final void removeButton(int idx)
219 {
220 this._buttons.removeAt(idx);
221
222 if(this.created)
223 {
224 this.sendMessage(TB_DELETEBUTTON, idx, 0);
225 }
226 }
227
228 @property public final ToolButton[] buttons()
229 {
230 if(this._buttons)
231 {
232 return this._buttons.get();
233 }
234
235 return null;
236 }
237
238 private void forceToolbarSize()
239 {
240 uint sz = this.sendMessage(TB_GETBUTTONSIZE, 0, 0);
241
242 this.size = Size(LOWORD(sz), HIWORD(sz));
243 }
244
245 private static void addItem(ToolButton tb)
246 {
247 TBBUTTON tbtn;
248
249 switch(tb.style)
250 {
251 case ToolButtonStyle.button, ToolButtonStyle.dropdown:
252 tbtn.iBitmap = tb.imageIndex;
253 tbtn.fsStyle = cast(ubyte)tb.style;
254 tbtn.fsState = cast(ubyte)(tb.enabled ? TBSTATE_ENABLED : 0);
255 tbtn.dwData = winCast!(uint)(tb);
256 break;
257
258 case ToolButtonStyle.separator:
259 tbtn.fsStyle = cast(ubyte)tb.style;
260 break;
261
262 default:
263 assert(false, "Unknown ToolButton Style");
264 }
265
266 if(tb.toolBar._dock is DockStyle.left || tb.toolBar._dock is DockStyle.right)
267 {
268 tbtn.fsState |= TBSTATE_WRAP;
269 }
270
271 tb.toolBar.sendMessage(TB_INSERTBUTTONW, tb.index, cast(LPARAM)&tbtn);
272 }
273
274 protected override void createControlParams(ref CreateControlParams ccp)
275 {
276 ccp.superclassName = WC_TOOLBAR;
277 ccp.className = WC_DTOOLBAR;
278 this.setStyle(TBSTYLE_FLAT | CCS_NODIVIDER | CCS_NOPARENTALIGN, true);
279
280 if(this._dock is DockStyle.none)
281 {
282 this._dock = DockStyle.top;
283 }
284
285 if(this._dock is DockStyle.left || this._dock is DockStyle.right)
286 {
287 this.setStyle(CCS_VERT, true);
288 }
289
290 super.createControlParams(ccp);
291 }
292
293 protected override void onHandleCreated(EventArgs e)
294 {
295 this.sendMessage(TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0);
296 int exStyle = this.sendMessage(TB_GETEXTENDEDSTYLE, 0, 0);
297 this.sendMessage(TB_SETEXTENDEDSTYLE, 0, exStyle | TBSTYLE_EX_DRAWDDARROWS);
298 this.forceToolbarSize(); // HACK: Forza il ridimensionamento della barra strumenti.
299
300 if(this._imgList)
301 {
302 this.sendMessage(TB_SETIMAGELIST, 0, cast(LPARAM)this._imgList.handle);
303 }
304
305 if(this._buttons)
306 {
307 foreach(ToolButton tb; this._buttons)
308 {
309 ToolBar.addItem(tb);
310 }
311 }
312
313 super.onHandleCreated(e);
314 }
315
316 protected override void onReflectedMessage(ref Message m)
317 {
318 switch(m.msg)
319 {
320 case WM_NOTIFY:
321 {
322 NMHDR* pNmhdr = cast(NMHDR*)m.lParam;
323
324 switch(pNmhdr.code)
325 {
326 case NM_CLICK:
327 {
328 NMMOUSE* pNMouse = cast(NMMOUSE*)m.lParam;
329 ToolButton tBtn = winCast!(ToolButton)(pNMouse.dwItemData);
330
331 if(tBtn)
332 {
333 tBtn.onToolBarButtonClick(EventArgs.empty); //FIXME!
334 }
335 }
336 break;
337
338 case TBN_DROPDOWN:
339 {
340 NMTOOLBARW* pNmToolbar = cast(NMTOOLBARW*)m.lParam;
341
342 Point pt = Cursor.position;
343 convertPoint(pt, null, this);
344 int idx = this.sendMessage(TB_HITTEST, 0, cast(LPARAM)&pt.point);
345
346 if(idx != -1)
347 {
348 ToolButton tbtn = this._buttons[idx];
349
350 if(tbtn && tbtn.contextMenu)
351 {
352 tbtn.contextMenu.popupMenu(this._handle, Cursor.position);
353 }
354 }
355 }
356 break;
357
358 default:
359 break;
360 }
361 }
362 break;
363
364 default:
365 break;
366 }
367
368 super.onReflectedMessage(m);
369 }
370
371 protected override void wndProc(ref Message m)
372 {
373 if(m.msg == WM_WINDOWPOSCHANGING)
374 {
375 /*
376 * HACK: Forza il ridimensionamento della barra strumenti.
377 */
378
379 WINDOWPOS* pWindowPos = cast(WINDOWPOS*)m.lParam;
380 uint sz = this.sendMessage(TB_GETBUTTONSIZE, 0, 0);
381
382 switch(this._dock)
383 {
384 case DockStyle.top, DockStyle.bottom:
385 pWindowPos.cy = HIWORD(sz);
386 break;
387
388 case DockStyle.left, DockStyle.right:
389 pWindowPos.cx = LOWORD(sz);
390 break;
391
392 default:
393 break;
394 }
395 }
396
397 super.wndProc(m);
398 }
399 }