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 }