Mercurial > projects > dwt2
comparison org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/ToolBar.d @ 0:6dd524f61e62
add dwt win and basic java stuff
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 02 Mar 2009 14:44:16 +0100 |
parents | |
children | 6bf2837c50fe |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:6dd524f61e62 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2008 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.swt.widgets.ToolBar; | |
14 | |
15 import org.eclipse.swt.SWT; | |
16 import org.eclipse.swt.SWTException; | |
17 import org.eclipse.swt.graphics.Font; | |
18 import org.eclipse.swt.graphics.Point; | |
19 import org.eclipse.swt.graphics.Rectangle; | |
20 import org.eclipse.swt.internal.ImageList; | |
21 import org.eclipse.swt.internal.win32.OS; | |
22 | |
23 import org.eclipse.swt.widgets.Composite; | |
24 import org.eclipse.swt.widgets.ToolItem; | |
25 import org.eclipse.swt.widgets.Control; | |
26 import org.eclipse.swt.widgets.Display; | |
27 import org.eclipse.swt.widgets.Event; | |
28 | |
29 import java.lang.all; | |
30 | |
31 | |
32 /** | |
33 * Instances of this class support the layout of selectable | |
34 * tool bar items. | |
35 * <p> | |
36 * The item children that may be added to instances of this class | |
37 * must be of type <code>ToolItem</code>. | |
38 * </p><p> | |
39 * Note that although this class is a subclass of <code>Composite</code>, | |
40 * it does not make sense to add <code>Control</code> children to it, | |
41 * or set a layout on it. | |
42 * </p><p> | |
43 * <dl> | |
44 * <dt><b>Styles:</b></dt> | |
45 * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd> | |
46 * <dt><b>Events:</b></dt> | |
47 * <dd>(none)</dd> | |
48 * </dl> | |
49 * <p> | |
50 * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. | |
51 * </p><p> | |
52 * IMPORTANT: This class is <em>not</em> intended to be subclassed. | |
53 * </p> | |
54 * | |
55 * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem snippets</a> | |
56 * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a> | |
57 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a> | |
58 */ | |
59 public class ToolBar : Composite { | |
60 | |
61 alias Composite.computeSize computeSize; | |
62 alias Composite.setBackgroundImage setBackgroundImage; | |
63 alias Composite.setBounds setBounds; | |
64 alias Composite.windowProc windowProc; | |
65 | |
66 int lastFocusId; | |
67 ToolItem [] items; | |
68 bool ignoreResize, ignoreMouse; | |
69 ImageList imageList, disabledImageList, hotImageList; | |
70 private static /+const+/ WNDPROC ToolBarProc; | |
71 static const TCHAR[] ToolBarClass = OS.TOOLBARCLASSNAME; | |
72 | |
73 private static bool static_this_completed = false; | |
74 private static void static_this() { | |
75 if( static_this_completed ){ | |
76 return; | |
77 } | |
78 synchronized { | |
79 if( static_this_completed ){ | |
80 return; | |
81 } | |
82 WNDCLASS lpWndClass; | |
83 OS.GetClassInfo (null, ToolBarClass.ptr, &lpWndClass); | |
84 ToolBarProc = lpWndClass.lpfnWndProc; | |
85 static_this_completed = true; | |
86 } | |
87 } | |
88 | |
89 | |
90 | |
91 | |
92 /* | |
93 * From the Windows SDK for TB_SETBUTTONSIZE: | |
94 * | |
95 * "If an application does not explicitly | |
96 * set the button size, the size defaults | |
97 * to 24 by 22 pixels". | |
98 */ | |
99 static const int DEFAULT_WIDTH = 24; | |
100 static const int DEFAULT_HEIGHT = 22; | |
101 | |
102 /** | |
103 * Constructs a new instance of this class given its parent | |
104 * and a style value describing its behavior and appearance. | |
105 * <p> | |
106 * The style value is either one of the style constants defined in | |
107 * class <code>SWT</code> which is applicable to instances of this | |
108 * class, or must be built by <em>bitwise OR</em>'ing together | |
109 * (that is, using the <code>int</code> "|" operator) two or more | |
110 * of those <code>SWT</code> style constants. The class description | |
111 * lists the style constants that are applicable to the class. | |
112 * Style bits are also inherited from superclasses. | |
113 * </p> | |
114 * | |
115 * @param parent a composite control which will be the parent of the new instance (cannot be null) | |
116 * @param style the style of control to construct | |
117 * | |
118 * @exception IllegalArgumentException <ul> | |
119 * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> | |
120 * </ul> | |
121 * @exception SWTException <ul> | |
122 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li> | |
123 * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li> | |
124 * </ul> | |
125 * | |
126 * @see SWT#FLAT | |
127 * @see SWT#WRAP | |
128 * @see SWT#RIGHT | |
129 * @see SWT#HORIZONTAL | |
130 * @see SWT#SHADOW_OUT | |
131 * @see SWT#VERTICAL | |
132 * @see Widget#checkSubclass() | |
133 * @see Widget#getStyle() | |
134 */ | |
135 public this (Composite parent, int style) { | |
136 static_this(); | |
137 super (parent, checkStyle (style)); | |
138 /* | |
139 * Ensure that either of HORIZONTAL or VERTICAL is set. | |
140 * NOTE: HORIZONTAL and VERTICAL have the same values | |
141 * as H_SCROLL and V_SCROLL so it is necessary to first | |
142 * clear these bits to avoid scroll bars and then reset | |
143 * the bits using the original style supplied by the | |
144 * programmer. | |
145 * | |
146 * NOTE: The CCS_VERT style cannot be applied when the | |
147 * widget is created because of this conflict. | |
148 */ | |
149 if ((style & SWT.VERTICAL) !is 0) { | |
150 this.style |= SWT.VERTICAL; | |
151 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); | |
152 /* | |
153 * Feature in Windows. When a tool bar has the style | |
154 * TBSTYLE_LIST and has a drop down item, Window leaves | |
155 * too much padding around the button. This affects | |
156 * every button in the tool bar and makes the preferred | |
157 * height too big. The fix is to set the TBSTYLE_LIST | |
158 * when the tool bar contains both text and images. | |
159 * | |
160 * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST | |
161 * set before any item is added or the tool bar does | |
162 * not lay out properly. The work around does not run | |
163 * in this case. | |
164 */ | |
165 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) { | |
166 if ((style & SWT.RIGHT) !is 0) bits |= OS.TBSTYLE_LIST; | |
167 } | |
168 OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.CCS_VERT); | |
169 } else { | |
170 this.style |= SWT.HORIZONTAL; | |
171 } | |
172 } | |
173 | |
174 override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) { | |
175 if (handle is null) return 0; | |
176 /* | |
177 * Bug in Windows. For some reason, during the processing | |
178 * of WM_SYSCHAR, the tool bar window proc does not call the | |
179 * default window proc causing mnemonics for the menu bar | |
180 * to be ignored. The fix is to always call the default | |
181 * window proc for WM_SYSCHAR. | |
182 */ | |
183 if (msg is OS.WM_SYSCHAR) { | |
184 return OS.DefWindowProc (hwnd, msg, wParam, lParam); | |
185 } | |
186 return OS.CallWindowProc (ToolBarProc, hwnd, msg, wParam, lParam); | |
187 } | |
188 | |
189 static int checkStyle (int style) { | |
190 /* | |
191 * On Windows, only flat tool bars can be traversed. | |
192 */ | |
193 if ((style & SWT.FLAT) is 0) style |= SWT.NO_FOCUS; | |
194 | |
195 /* | |
196 * A vertical tool bar cannot wrap because TB_SETROWS | |
197 * fails when the toolbar has TBSTYLE_WRAPABLE. | |
198 */ | |
199 if ((style & SWT.VERTICAL) !is 0) style &= ~SWT.WRAP; | |
200 | |
201 /* | |
202 * Even though it is legal to create this widget | |
203 * with scroll bars, they serve no useful purpose | |
204 * because they do not automatically scroll the | |
205 * widget's client area. The fix is to clear | |
206 * the SWT style. | |
207 */ | |
208 return style & ~(SWT.H_SCROLL | SWT.V_SCROLL); | |
209 } | |
210 | |
211 override void checkBuffered () { | |
212 super.checkBuffered (); | |
213 if (OS.COMCTL32_MAJOR >= 6) style |= SWT.DOUBLE_BUFFERED; | |
214 } | |
215 | |
216 override protected void checkSubclass () { | |
217 if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); | |
218 } | |
219 | |
220 override public Point computeSize (int wHint, int hHint, bool changed) { | |
221 checkWidget (); | |
222 int width = 0, height = 0; | |
223 if ((style & SWT.VERTICAL) !is 0) { | |
224 RECT rect; | |
225 TBBUTTON lpButton; | |
226 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
227 for (int i=0; i<count; i++) { | |
228 OS.SendMessage (handle, OS.TB_GETITEMRECT, i, &rect); | |
229 height = Math.max (height, rect.bottom); | |
230 OS.SendMessage (handle, OS.TB_GETBUTTON, i, &lpButton); | |
231 if ((lpButton.fsStyle & OS.BTNS_SEP) !is 0) { | |
232 TBBUTTONINFO info; | |
233 info.cbSize = TBBUTTONINFO.sizeof; | |
234 info.dwMask = OS.TBIF_SIZE; | |
235 OS.SendMessage (handle, OS.TB_GETBUTTONINFO, lpButton.idCommand, &info); | |
236 width = Math.max (width, info.cx); | |
237 } else { | |
238 width = Math.max (width, rect.right); | |
239 } | |
240 } | |
241 } else { | |
242 RECT oldRect; | |
243 OS.GetWindowRect (handle, &oldRect); | |
244 int oldWidth = oldRect.right - oldRect.left; | |
245 int oldHeight = oldRect.bottom - oldRect.top; | |
246 int border = getBorderWidth (); | |
247 int newWidth = wHint is SWT.DEFAULT ? 0x3FFF : wHint + border * 2; | |
248 int newHeight = hHint is SWT.DEFAULT ? 0x3FFF : hHint + border * 2; | |
249 bool redraw = drawCount is 0 && OS.IsWindowVisible (handle); | |
250 ignoreResize = true; | |
251 if (redraw) OS.UpdateWindow (handle); | |
252 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER; | |
253 SetWindowPos (handle, null, 0, 0, newWidth, newHeight, flags); | |
254 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
255 if (count !is 0) { | |
256 RECT rect; | |
257 OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, &rect); | |
258 width = Math.max (width, rect.right); | |
259 height = Math.max (height, rect.bottom); | |
260 } | |
261 SetWindowPos (handle, null, 0, 0, oldWidth, oldHeight, flags); | |
262 if (redraw) OS.ValidateRect (handle, null); | |
263 ignoreResize = false; | |
264 } | |
265 | |
266 /* | |
267 * From the Windows SDK for TB_SETBUTTONSIZE: | |
268 * | |
269 * "If an application does not explicitly | |
270 * set the button size, the size defaults | |
271 * to 24 by 22 pixels". | |
272 */ | |
273 if (width is 0) width = DEFAULT_WIDTH; | |
274 if (height is 0) height = DEFAULT_HEIGHT; | |
275 if (wHint !is SWT.DEFAULT) width = wHint; | |
276 if (hHint !is SWT.DEFAULT) height = hHint; | |
277 Rectangle trim = computeTrim (0, 0, width, height); | |
278 width = trim.width; height = trim.height; | |
279 return new Point (width, height); | |
280 } | |
281 | |
282 override public Rectangle computeTrim (int x, int y, int width, int height) { | |
283 checkWidget (); | |
284 Rectangle trim = super.computeTrim (x, y, width, height); | |
285 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); | |
286 if ((bits & OS.CCS_NODIVIDER) is 0) trim.height += 2; | |
287 return trim; | |
288 } | |
289 | |
290 override void createHandle () { | |
291 super.createHandle (); | |
292 state &= ~CANVAS; | |
293 | |
294 /* | |
295 * Feature in Windows. When TBSTYLE_FLAT is used to create | |
296 * a flat toolbar, for some reason TBSTYLE_TRANSPARENT is | |
297 * also set. This causes the toolbar to flicker when it is | |
298 * moved or resized. The fix is to clear TBSTYLE_TRANSPARENT. | |
299 * | |
300 * NOTE: This work around is unnecessary on XP. There is no | |
301 * flickering and clearing the TBSTYLE_TRANSPARENT interferes | |
302 * with the XP theme. | |
303 */ | |
304 if ((style & SWT.FLAT) !is 0) { | |
305 if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) { | |
306 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); | |
307 bits &= ~OS.TBSTYLE_TRANSPARENT; | |
308 OS.SetWindowLong (handle, OS.GWL_STYLE, bits); | |
309 } | |
310 } | |
311 | |
312 /* | |
313 * Feature in Windows. Despite the fact that the | |
314 * tool tip text contains \r\n, the tooltip will | |
315 * not honour the new line unless TTM_SETMAXTIPWIDTH | |
316 * is set. The fix is to set TTM_SETMAXTIPWIDTH to | |
317 * a large value. | |
318 */ | |
319 /* | |
320 * These lines are intentionally commented. The tool | |
321 * bar currently sets this value to 300 so it is not | |
322 * necessary to set TTM_SETMAXTIPWIDTH. | |
323 */ | |
324 // int /*long*/ hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); | |
325 // OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF); | |
326 | |
327 /* | |
328 * Feature in Windows. When the control is created, | |
329 * it does not use the default system font. A new HFONT | |
330 * is created and destroyed when the control is destroyed. | |
331 * This means that a program that queries the font from | |
332 * this control, uses the font in another control and then | |
333 * destroys this control will have the font unexpectedly | |
334 * destroyed in the other control. The fix is to assign | |
335 * the font ourselves each time the control is created. | |
336 * The control will not destroy a font that it did not | |
337 * create. | |
338 */ | |
339 HFONT hFont = OS.GetStockObject (OS.SYSTEM_FONT); | |
340 OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); | |
341 | |
342 /* Set the button struct, bitmap and button sizes */ | |
343 OS.SendMessage (handle, OS.TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0); | |
344 OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); | |
345 OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); | |
346 | |
347 /* Set the extended style bits */ | |
348 int bits = OS.TBSTYLE_EX_DRAWDDARROWS | OS.TBSTYLE_EX_MIXEDBUTTONS | OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS; | |
349 if (OS.COMCTL32_MAJOR >= 6) bits |= OS.TBSTYLE_EX_DOUBLEBUFFER; | |
350 OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits); | |
351 } | |
352 | |
353 void createItem (ToolItem item, int index) { | |
354 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
355 if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE); | |
356 int id = 0; | |
357 while (id < items.length && items [id] !is null) id++; | |
358 if (id is items.length) { | |
359 ToolItem [] newItems = new ToolItem [items.length + 4]; | |
360 System.arraycopy (items, 0, newItems, 0, items.length); | |
361 items = newItems; | |
362 } | |
363 int bits = item.widgetStyle (); | |
364 TBBUTTON lpButton; | |
365 lpButton.idCommand = id; | |
366 lpButton.fsStyle = cast(byte) bits; | |
367 lpButton.fsState = cast(byte) OS.TBSTATE_ENABLED; | |
368 | |
369 /* | |
370 * Bug in Windows. Despite the fact that the image list | |
371 * index has never been set for the item, Windows always | |
372 * assumes that the image index for the item is valid. | |
373 * When an item is inserted, the image index is zero. | |
374 * Therefore, when the first image is inserted and is | |
375 * assigned image index zero, every item draws with this | |
376 * image. The fix is to set the image index to none | |
377 * when the item is created. This is not necessary in | |
378 * the case when the item has the BTNS_SEP style because | |
379 * separators cannot show images. | |
380 */ | |
381 if ((bits & OS.BTNS_SEP) is 0) lpButton.iBitmap = OS.I_IMAGENONE; | |
382 if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, &lpButton) is 0) { | |
383 error (SWT.ERROR_ITEM_NOT_ADDED); | |
384 } | |
385 items [item.id = id] = item; | |
386 if ((style & SWT.VERTICAL) !is 0) setRowCount (count + 1); | |
387 layoutItems (); | |
388 } | |
389 | |
390 override void createWidget () { | |
391 super.createWidget (); | |
392 items = new ToolItem [4]; | |
393 lastFocusId = -1; | |
394 } | |
395 | |
396 override int defaultBackground () { | |
397 static if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE); | |
398 return super.defaultBackground (); | |
399 } | |
400 | |
401 void destroyItem (ToolItem item) { | |
402 TBBUTTONINFO info; | |
403 info.cbSize = TBBUTTONINFO.sizeof; | |
404 info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE; | |
405 int index = OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, &info); | |
406 /* | |
407 * Feature in Windows. For some reason, a tool item that has | |
408 * the style BTNS_SEP does not return I_IMAGENONE when queried | |
409 * for an image index, despite the fact that no attempt has been | |
410 * made to assign an image to the item. As a result, operations | |
411 * on an image list that use the wrong index cause random results. | |
412 * The fix is to ensure that the tool item is not a separator | |
413 * before using the image index. Since separators cannot have | |
414 * an image and one is never assigned, this is not a problem. | |
415 */ | |
416 if ((info.fsStyle & OS.BTNS_SEP) is 0 && info.iImage !is OS.I_IMAGENONE) { | |
417 if (imageList !is null) imageList.put (info.iImage, null); | |
418 if (hotImageList !is null) hotImageList.put (info.iImage, null); | |
419 if (disabledImageList !is null) disabledImageList.put (info.iImage, null); | |
420 } | |
421 OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0); | |
422 if (item.id is lastFocusId) lastFocusId = -1; | |
423 items [item.id] = null; | |
424 item.id = -1; | |
425 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
426 if (count is 0) { | |
427 if (imageList !is null) { | |
428 OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); | |
429 display.releaseToolImageList (imageList); | |
430 } | |
431 if (hotImageList !is null) { | |
432 OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); | |
433 display.releaseToolHotImageList (hotImageList); | |
434 } | |
435 if (disabledImageList !is null) { | |
436 OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); | |
437 display.releaseToolDisabledImageList (disabledImageList); | |
438 } | |
439 imageList = hotImageList = disabledImageList = null; | |
440 items = new ToolItem [4]; | |
441 } | |
442 if ((style & SWT.VERTICAL) !is 0) setRowCount (count - 1); | |
443 layoutItems (); | |
444 } | |
445 | |
446 override void enableWidget (bool enabled) { | |
447 super.enableWidget (enabled); | |
448 /* | |
449 * Bug in Windows. When a tool item with the style | |
450 * BTNS_CHECK or BTNS_CHECKGROUP is selected and then | |
451 * disabled, the item does not draw using the disabled | |
452 * image. The fix is to use the disabled image in all | |
453 * image lists for the item. | |
454 * | |
455 * Feature in Windows. When a tool bar is disabled, | |
456 * the text draws disabled but the images do not. | |
457 * The fix is to use the disabled image in all image | |
458 * lists for all items. | |
459 */ | |
460 for (int i=0; i<items.length; i++) { | |
461 ToolItem item = items [i]; | |
462 if (item !is null) { | |
463 if ((item.style & SWT.SEPARATOR) is 0) { | |
464 item.updateImages (enabled && item.getEnabled ()); | |
465 } | |
466 } | |
467 } | |
468 } | |
469 | |
470 ImageList getDisabledImageList () { | |
471 return disabledImageList; | |
472 } | |
473 | |
474 ImageList getHotImageList () { | |
475 return hotImageList; | |
476 } | |
477 | |
478 ImageList getImageList () { | |
479 return imageList; | |
480 } | |
481 | |
482 /** | |
483 * Returns the item at the given, zero-relative index in the | |
484 * receiver. Throws an exception if the index is out of range. | |
485 * | |
486 * @param index the index of the item to return | |
487 * @return the item at the given index | |
488 * | |
489 * @exception IllegalArgumentException <ul> | |
490 * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li> | |
491 * </ul> | |
492 * @exception SWTException <ul> | |
493 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
494 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
495 * </ul> | |
496 */ | |
497 public ToolItem getItem (int index) { | |
498 checkWidget (); | |
499 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
500 if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE); | |
501 TBBUTTON lpButton; | |
502 int result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton); | |
503 if (result is 0) error (SWT.ERROR_CANNOT_GET_ITEM); | |
504 return items [lpButton.idCommand]; | |
505 } | |
506 | |
507 /** | |
508 * Returns the item at the given point in the receiver | |
509 * or null if no such item exists. The point is in the | |
510 * coordinate system of the receiver. | |
511 * | |
512 * @param point the point used to locate the item | |
513 * @return the item at the given point | |
514 * | |
515 * @exception IllegalArgumentException <ul> | |
516 * <li>ERROR_NULL_ARGUMENT - if the point is null</li> | |
517 * </ul> | |
518 * @exception SWTException <ul> | |
519 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
520 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
521 * </ul> | |
522 */ | |
523 public ToolItem getItem (Point point) { | |
524 checkWidget (); | |
525 if (point is null) error (SWT.ERROR_NULL_ARGUMENT); | |
526 ToolItem [] items = getItems (); | |
527 for (int i=0; i<items.length; i++) { | |
528 Rectangle rect = items [i].getBounds (); | |
529 if (rect.contains (point)) return items [i]; | |
530 } | |
531 return null; | |
532 } | |
533 | |
534 /** | |
535 * Returns the number of items contained in the receiver. | |
536 * | |
537 * @return the number of items | |
538 * | |
539 * @exception SWTException <ul> | |
540 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
541 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
542 * </ul> | |
543 */ | |
544 public int getItemCount () { | |
545 checkWidget (); | |
546 return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
547 } | |
548 | |
549 /** | |
550 * Returns an array of <code>ToolItem</code>s which are the items | |
551 * in the receiver. | |
552 * <p> | |
553 * Note: This is not the actual structure used by the receiver | |
554 * to maintain its list of items, so modifying the array will | |
555 * not affect the receiver. | |
556 * </p> | |
557 * | |
558 * @return the items in the receiver | |
559 * | |
560 * @exception SWTException <ul> | |
561 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
562 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
563 * </ul> | |
564 */ | |
565 public ToolItem [] getItems () { | |
566 checkWidget (); | |
567 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
568 TBBUTTON lpButton; | |
569 ToolItem [] result = new ToolItem [count]; | |
570 for (int i=0; i<count; i++) { | |
571 OS.SendMessage (handle, OS.TB_GETBUTTON, i, &lpButton); | |
572 result [i] = items [lpButton.idCommand]; | |
573 } | |
574 return result; | |
575 } | |
576 | |
577 /** | |
578 * Returns the number of rows in the receiver. When | |
579 * the receiver has the <code>WRAP</code> style, the | |
580 * number of rows can be greater than one. Otherwise, | |
581 * the number of rows is always one. | |
582 * | |
583 * @return the number of items | |
584 * | |
585 * @exception SWTException <ul> | |
586 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
587 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
588 * </ul> | |
589 */ | |
590 public int getRowCount () { | |
591 checkWidget (); | |
592 if ((style & SWT.VERTICAL) !is 0) { | |
593 return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
594 } | |
595 return OS.SendMessage (handle, OS.TB_GETROWS, 0, 0); | |
596 } | |
597 | |
598 /** | |
599 * Searches the receiver's list starting at the first item | |
600 * (index 0) until an item is found that is equal to the | |
601 * argument, and returns the index of that item. If no item | |
602 * is found, returns -1. | |
603 * | |
604 * @param item the search item | |
605 * @return the index of the item | |
606 * | |
607 * @exception IllegalArgumentException <ul> | |
608 * <li>ERROR_NULL_ARGUMENT - if the tool item is null</li> | |
609 * <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</li> | |
610 * </ul> | |
611 * @exception SWTException <ul> | |
612 * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li> | |
613 * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li> | |
614 * </ul> | |
615 */ | |
616 public int indexOf (ToolItem item) { | |
617 checkWidget (); | |
618 if (item is null) error (SWT.ERROR_NULL_ARGUMENT); | |
619 if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); | |
620 return OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0); | |
621 } | |
622 | |
623 void layoutItems () { | |
624 /* | |
625 * Feature in Windows. When a tool bar has the style | |
626 * TBSTYLE_LIST and has a drop down item, Window leaves | |
627 * too much padding around the button. This affects | |
628 * every button in the tool bar and makes the preferred | |
629 * height too big. The fix is to set the TBSTYLE_LIST | |
630 * when the tool bar contains both text and images. | |
631 * | |
632 * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST | |
633 * set before any item is added or the tool bar does | |
634 * not lay out properly. The work around does not run | |
635 * in this case. | |
636 */ | |
637 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) { | |
638 if ((style & SWT.RIGHT) !is 0 && (style & SWT.VERTICAL) is 0) { | |
639 bool hasText = false, hasImage = false; | |
640 for (int i=0; i<items.length; i++) { | |
641 ToolItem item = items [i]; | |
642 if (item !is null) { | |
643 if (!hasText) hasText = item.text.length !is 0; | |
644 if (!hasImage) hasImage = item.image !is null; | |
645 if (hasText && hasImage) break; | |
646 } | |
647 } | |
648 int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits; | |
649 if (hasText && hasImage) { | |
650 newBits |= OS.TBSTYLE_LIST; | |
651 } else { | |
652 newBits &= ~OS.TBSTYLE_LIST; | |
653 } | |
654 if (newBits !is oldBits) { | |
655 setDropDownItems (false); | |
656 OS.SetWindowLong (handle, OS.GWL_STYLE, newBits); | |
657 /* | |
658 * Feature in Windows. For some reason, when the style | |
659 * is changed to TBSTYLE_LIST, Windows does not lay out | |
660 * the tool items. The fix is to use WM_SETFONT to force | |
661 * the tool bar to redraw and lay out. | |
662 */ | |
663 auto hFont = cast(HFONT) OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); | |
664 OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); | |
665 setDropDownItems (true); | |
666 } | |
667 } | |
668 } | |
669 | |
670 if ((style & SWT.WRAP) !is 0) { | |
671 OS.SendMessage (handle, OS.TB_AUTOSIZE, 0, 0); | |
672 } | |
673 /* | |
674 * When the tool bar is vertical, make the width of each button | |
675 * be the width of the widest button in the tool bar. Note that | |
676 * when the tool bar contains a drop down item, it needs to take | |
677 * into account extra padding. | |
678 */ | |
679 if ((style & SWT.VERTICAL) !is 0) { | |
680 TBBUTTONINFO info; | |
681 info.cbSize = TBBUTTONINFO.sizeof; | |
682 info.dwMask = OS.TBIF_SIZE; | |
683 int /*long*/ size = OS.SendMessage (handle, OS.TB_GETBUTTONSIZE, 0, 0); | |
684 info.cx = cast(short) OS.LOWORD (size); | |
685 int index = 0; | |
686 while (index < items.length) { | |
687 ToolItem item = items [index]; | |
688 if (item !is null && (item.style & SWT.DROP_DOWN) !is 0) break; | |
689 index++; | |
690 } | |
691 if (index < items.length) { | |
692 int /*long*/ padding = OS.SendMessage (handle, OS.TB_GETPADDING, 0, 0); | |
693 info.cx += OS.LOWORD (padding) * 2; | |
694 } | |
695 for (int i=0; i<items.length; i++) { | |
696 ToolItem item = items [i]; | |
697 if (item !is null && (item.style & SWT.SEPARATOR) is 0) { | |
698 OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, &info); | |
699 } | |
700 } | |
701 } | |
702 for (int i=0; i<items.length; i++) { | |
703 ToolItem item = items [i]; | |
704 if (item !is null) item.resizeControl (); | |
705 } | |
706 } | |
707 | |
708 override bool mnemonicHit (wchar ch) { | |
709 int key = Display.wcsToMbcs (ch); | |
710 int id; | |
711 if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, &id) is 0) { | |
712 return false; | |
713 } | |
714 if ((style & SWT.FLAT) !is 0 && !setTabGroupFocus ()) return false; | |
715 int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id, 0); | |
716 if (index is -1) return false; | |
717 OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0); | |
718 items [id].click (false); | |
719 return true; | |
720 } | |
721 | |
722 override bool mnemonicMatch (wchar ch) { | |
723 int key = Display.wcsToMbcs (ch); | |
724 int id; | |
725 if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, &id) is 0) { | |
726 return false; | |
727 } | |
728 /* | |
729 * Feature in Windows. TB_MAPACCELERATOR matches either the mnemonic | |
730 * character or the first character in a tool item. This behavior is | |
731 * undocumented and unwanted. The fix is to ensure that the tool item | |
732 * contains a mnemonic when TB_MAPACCELERATOR returns true. | |
733 */ | |
734 int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id, 0); | |
735 if (index is -1) return false; | |
736 return findMnemonic (items [id].text) !is '\0'; | |
737 } | |
738 | |
739 override void releaseChildren (bool destroy) { | |
740 if (items !is null) { | |
741 for (int i=0; i<items.length; i++) { | |
742 ToolItem item = items [i]; | |
743 if (item !is null && !item.isDisposed ()) { | |
744 item.release (false); | |
745 } | |
746 } | |
747 items = null; | |
748 } | |
749 super.releaseChildren (destroy); | |
750 } | |
751 | |
752 override void releaseWidget () { | |
753 super.releaseWidget (); | |
754 if (imageList !is null) { | |
755 OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); | |
756 display.releaseToolImageList (imageList); | |
757 } | |
758 if (hotImageList !is null) { | |
759 OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); | |
760 display.releaseToolHotImageList (hotImageList); | |
761 } | |
762 if (disabledImageList !is null) { | |
763 OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); | |
764 display.releaseToolDisabledImageList (disabledImageList); | |
765 } | |
766 imageList = hotImageList = disabledImageList = null; | |
767 } | |
768 | |
769 override void removeControl (Control control) { | |
770 super.removeControl (control); | |
771 for (int i=0; i<items.length; i++) { | |
772 ToolItem item = items [i]; | |
773 if (item !is null && item.control is control) { | |
774 item.setControl (null); | |
775 } | |
776 } | |
777 } | |
778 | |
779 override void setBackgroundImage (HBITMAP hBitmap) { | |
780 super.setBackgroundImage (hBitmap); | |
781 setBackgroundTransparent (hBitmap !is null); | |
782 } | |
783 | |
784 override void setBackgroundPixel (int pixel) { | |
785 super.setBackgroundPixel (pixel); | |
786 setBackgroundTransparent (pixel !is -1); | |
787 } | |
788 | |
789 void setBackgroundTransparent (bool transparent) { | |
790 /* | |
791 * Feature in Windows. When TBSTYLE_TRANSPARENT is set | |
792 * in a tool bar that is drawing a background, images in | |
793 * the image list that include transparency information | |
794 * do not draw correctly. The fix is to clear and set | |
795 * TBSTYLE_TRANSPARENT depending on the background color. | |
796 * | |
797 * NOTE: This work around is unnecessary on XP. The | |
798 * TBSTYLE_TRANSPARENT style is never cleared on that | |
799 * platform. | |
800 */ | |
801 if ((style & SWT.FLAT) !is 0) { | |
802 if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) { | |
803 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); | |
804 if (!transparent && findBackgroundControl () is null) { | |
805 bits &= ~OS.TBSTYLE_TRANSPARENT; | |
806 } else { | |
807 bits |= OS.TBSTYLE_TRANSPARENT; | |
808 } | |
809 OS.SetWindowLong (handle, OS.GWL_STYLE, bits); | |
810 } | |
811 } | |
812 } | |
813 | |
814 override void setBounds (int x, int y, int width, int height, int flags) { | |
815 /* | |
816 * Feature in Windows. For some reason, when a tool bar is | |
817 * repositioned more than once using DeferWindowPos () into | |
818 * the same HDWP, the toolbar redraws more than once, defeating | |
819 * the purpose of DeferWindowPos (). The fix is to end the | |
820 * deferred positioning before the next tool bar is added, | |
821 * ensuring that only one tool bar position is deferred at | |
822 * any given time. | |
823 */ | |
824 if (parent.lpwp !is null) { | |
825 if (drawCount is 0 && OS.IsWindowVisible (handle)) { | |
826 parent.setResizeChildren (false); | |
827 parent.setResizeChildren (true); | |
828 } | |
829 } | |
830 super.setBounds (x, y, width, height, flags); | |
831 } | |
832 | |
833 override void setDefaultFont () { | |
834 super.setDefaultFont (); | |
835 OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); | |
836 OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); | |
837 } | |
838 | |
839 void setDropDownItems (bool set) { | |
840 /* | |
841 * Feature in Windows. When the first button in a tool bar | |
842 * is a drop down item, Window leaves too much padding around | |
843 * the button. This affects every button in the tool bar and | |
844 * makes the preferred height too big. The fix is clear the | |
845 * BTNS_DROPDOWN before Windows lays out the tool bar and set | |
846 * the bit afterwards. | |
847 * | |
848 * NOTE: This work around only runs when the tool bar contains | |
849 * both text and images. | |
850 */ | |
851 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) { | |
852 bool hasText = false, hasImage = false; | |
853 for (int i=0; i<items.length; i++) { | |
854 ToolItem item = items [i]; | |
855 if (item !is null) { | |
856 if (!hasText) hasText = item.text.length !is 0; | |
857 if (!hasImage) hasImage = item.image !is null; | |
858 if (hasText && hasImage) break; | |
859 } | |
860 } | |
861 if (hasImage && !hasText) { | |
862 for (int i=0; i<items.length; i++) { | |
863 ToolItem item = items [i]; | |
864 if (item !is null && (item.style & SWT.DROP_DOWN) !is 0) { | |
865 TBBUTTONINFO info; | |
866 info.cbSize = TBBUTTONINFO.sizeof; | |
867 info.dwMask = OS.TBIF_STYLE; | |
868 OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, &info); | |
869 if (set) { | |
870 info.fsStyle |= OS.BTNS_DROPDOWN; | |
871 } else { | |
872 info.fsStyle &= ~OS.BTNS_DROPDOWN; | |
873 } | |
874 OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, &info); | |
875 } | |
876 } | |
877 } | |
878 } | |
879 } | |
880 | |
881 void setDisabledImageList (ImageList imageList) { | |
882 if (disabledImageList is imageList) return; | |
883 HBITMAP hImageList; | |
884 if ((disabledImageList = imageList) !is null) { | |
885 hImageList = disabledImageList.getHandle (); | |
886 } | |
887 setDropDownItems (false); | |
888 OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList); | |
889 setDropDownItems (true); | |
890 } | |
891 | |
892 override public void setFont (Font font) { | |
893 checkWidget (); | |
894 setDropDownItems (false); | |
895 super.setFont (font); | |
896 setDropDownItems (true); | |
897 /* | |
898 * Bug in Windows. When WM_SETFONT is sent to a tool bar | |
899 * that contains only separators, causes the bitmap and button | |
900 * sizes to be set. The fix is to reset these sizes after the font | |
901 * has been changed when the tool bar contains only separators. | |
902 */ | |
903 int index = 0; | |
904 int mask = SWT.PUSH | SWT.CHECK | SWT.RADIO | SWT.DROP_DOWN; | |
905 while (index < items.length) { | |
906 ToolItem item = items [index]; | |
907 if (item !is null && (item.style & mask) !is 0) break; | |
908 index++; | |
909 } | |
910 if (index is items.length) { | |
911 OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); | |
912 OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); | |
913 } | |
914 layoutItems (); | |
915 } | |
916 | |
917 void setHotImageList (ImageList imageList) { | |
918 if (hotImageList is imageList) return; | |
919 HBITMAP hImageList; | |
920 if ((hotImageList = imageList) !is null) { | |
921 hImageList = hotImageList.getHandle (); | |
922 } | |
923 setDropDownItems (false); | |
924 OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList); | |
925 setDropDownItems (true); | |
926 } | |
927 | |
928 void setImageList (ImageList imageList) { | |
929 if (this.imageList is imageList) return; | |
930 HBITMAP hImageList; | |
931 if ((this.imageList = imageList) !is null) { | |
932 hImageList = imageList.getHandle (); | |
933 } | |
934 setDropDownItems (false); | |
935 OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList); | |
936 setDropDownItems (true); | |
937 } | |
938 | |
939 override public bool setParent (Composite parent) { | |
940 checkWidget (); | |
941 if (!super.setParent (parent)) return false; | |
942 OS.SendMessage (handle, OS.TB_SETPARENT, parent.handle, 0); | |
943 return true; | |
944 } | |
945 | |
946 override public void setRedraw (bool redraw) { | |
947 checkWidget (); | |
948 setDropDownItems (false); | |
949 super.setRedraw (redraw); | |
950 setDropDownItems (true); | |
951 } | |
952 | |
953 void setRowCount (int count) { | |
954 if ((style & SWT.VERTICAL) !is 0) { | |
955 /* | |
956 * Feature in Windows. When the TB_SETROWS is used to set the | |
957 * number of rows in a tool bar, the tool bar is resized to show | |
958 * the items. This is unexpected. The fix is to save and restore | |
959 * the current size of the tool bar. | |
960 */ | |
961 RECT rect; | |
962 OS.GetWindowRect (handle, &rect); | |
963 OS.MapWindowPoints (null, parent.handle, cast(POINT*) &rect, 2); | |
964 ignoreResize = true; | |
965 /* | |
966 * Feature in Windows. When the last button in a tool bar has the | |
967 * style BTNS_SEP and TB_SETROWS is used to set the number of rows | |
968 * in the tool bar, depending on the number of buttons, the toolbar | |
969 * will wrap items with the style BTNS_CHECK, even when the fLarger | |
970 * flags is used to force the number of rows to be larger than the | |
971 * number of items. The fix is to set the number of rows to be two | |
972 * larger than the actual number of rows in the tool bar. When items | |
973 * are being added, as long as the number of rows is at least one | |
974 * item larger than the count, the tool bar is laid out properly. | |
975 * When items are being removed, setting the number of rows to be | |
976 * one more than the item count has no effect. The number of rows | |
977 * is already one more causing TB_SETROWS to do nothing. Therefore, | |
978 * choosing two instead of one as the row increment fixes both cases. | |
979 */ | |
980 count += 2; | |
981 OS.SendMessage (handle, OS.TB_SETROWS, OS.MAKEWPARAM (count, 1), 0); | |
982 int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER; | |
983 SetWindowPos (handle, null, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags); | |
984 ignoreResize = false; | |
985 } | |
986 } | |
987 | |
988 override bool setTabItemFocus () { | |
989 int index = 0; | |
990 while (index < items.length) { | |
991 ToolItem item = items [index]; | |
992 if (item !is null && (item.style & SWT.SEPARATOR) is 0) { | |
993 if (item.getEnabled ()) break; | |
994 } | |
995 index++; | |
996 } | |
997 if (index is items.length) return false; | |
998 return super.setTabItemFocus (); | |
999 } | |
1000 | |
1001 override String toolTipText (NMTTDISPINFO* hdr) { | |
1002 if ((hdr.uFlags & OS.TTF_IDISHWND) !is 0) { | |
1003 return null; | |
1004 } | |
1005 /* | |
1006 * Bug in Windows. On Windows XP, when TB_SETHOTITEM is | |
1007 * used to set the hot item, the tool bar control attempts | |
1008 * to display the tool tip, even when the cursor is not in | |
1009 * the hot item. The fix is to detect this case and fail to | |
1010 * provide the string, causing no tool tip to be displayed. | |
1011 */ | |
1012 if (!hasCursor ()) return ""; //$NON-NLS-1$ | |
1013 int index = hdr.hdr.idFrom; | |
1014 auto hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); | |
1015 if (hwndToolTip is hdr.hdr.hwndFrom) { | |
1016 /* | |
1017 * Bug in Windows. For some reason the reading order | |
1018 * in NMTTDISPINFO is sometimes set incorrectly. The | |
1019 * reading order seems to change every time the mouse | |
1020 * enters the control from the top edge. The fix is | |
1021 * to explicitly set TTF_RTLREADING. | |
1022 */ | |
1023 if ((style & SWT.RIGHT_TO_LEFT) !is 0) { | |
1024 hdr.uFlags |= OS.TTF_RTLREADING; | |
1025 } else { | |
1026 hdr.uFlags &= ~OS.TTF_RTLREADING; | |
1027 } | |
1028 if (toolTipText_ !is null) return ""; //$NON-NLS-1$ | |
1029 if (0 <= index && index < items.length) { | |
1030 ToolItem item = items [index]; | |
1031 if (item !is null) return item.toolTipText; | |
1032 } | |
1033 } | |
1034 return super.toolTipText (hdr); | |
1035 } | |
1036 | |
1037 override int widgetStyle () { | |
1038 int bits = super.widgetStyle () | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS | OS.TBSTYLE_CUSTOMERASE; | |
1039 if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) bits |= OS.TBSTYLE_TRANSPARENT; | |
1040 if ((style & SWT.SHADOW_OUT) is 0) bits |= OS.CCS_NODIVIDER; | |
1041 if ((style & SWT.WRAP) !is 0) bits |= OS.TBSTYLE_WRAPABLE; | |
1042 if ((style & SWT.FLAT) !is 0) bits |= OS.TBSTYLE_FLAT; | |
1043 /* | |
1044 * Feature in Windows. When a tool bar has the style | |
1045 * TBSTYLE_LIST and has a drop down item, Window leaves | |
1046 * too much padding around the button. This affects | |
1047 * every button in the tool bar and makes the preferred | |
1048 * height too big. The fix is to set the TBSTYLE_LIST | |
1049 * when the tool bar contains both text and images. | |
1050 * | |
1051 * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST | |
1052 * set before any item is added or the tool bar does | |
1053 * not lay out properly. The work around does not run | |
1054 * in this case. | |
1055 */ | |
1056 if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) { | |
1057 if ((style & SWT.RIGHT) !is 0) bits |= OS.TBSTYLE_LIST; | |
1058 } | |
1059 return bits; | |
1060 } | |
1061 | |
1062 override String windowClass () { | |
1063 return TCHARsToStr(ToolBarClass); | |
1064 } | |
1065 | |
1066 override int windowProc () { | |
1067 return cast(int)ToolBarProc; | |
1068 } | |
1069 | |
1070 override LRESULT WM_CAPTURECHANGED (int wParam, int lParam) { | |
1071 LRESULT result = super.WM_CAPTURECHANGED (wParam, lParam); | |
1072 if (result !is null) return result; | |
1073 /* | |
1074 * Bug in Windows. When the tool bar loses capture while an | |
1075 * item is pressed, the item remains pressed. The fix is | |
1076 * unpress all items using TB_SETSTATE and TBSTATE_PRESSED. | |
1077 */ | |
1078 for (int i=0; i<items.length; i++) { | |
1079 ToolItem item = items [i]; | |
1080 if (item !is null) { | |
1081 int fsState = OS.SendMessage (handle, OS.TB_GETSTATE, item.id, 0); | |
1082 if ((fsState & OS.TBSTATE_PRESSED) !is 0) { | |
1083 fsState &= ~OS.TBSTATE_PRESSED; | |
1084 OS.SendMessage (handle, OS.TB_SETSTATE, item.id, fsState); | |
1085 } | |
1086 } | |
1087 } | |
1088 return result; | |
1089 } | |
1090 | |
1091 override LRESULT WM_CHAR (int wParam, int lParam) { | |
1092 LRESULT result = super.WM_CHAR (wParam, lParam); | |
1093 if (result !is null) return result; | |
1094 switch (wParam) { | |
1095 case ' ': | |
1096 int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0); | |
1097 if (index !is -1) { | |
1098 TBBUTTON lpButton; | |
1099 int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton); | |
1100 if (code !is 0) { | |
1101 items [lpButton.idCommand].click (false); | |
1102 return LRESULT.ZERO; | |
1103 } | |
1104 } | |
1105 default: | |
1106 } | |
1107 return result; | |
1108 } | |
1109 | |
1110 override LRESULT WM_COMMAND (int wParam, int lParam) { | |
1111 /* | |
1112 * Feature in Windows. When the toolbar window | |
1113 * proc processes WM_COMMAND, it forwards this | |
1114 * message to its parent. This is done so that | |
1115 * children of this control that send this message | |
1116 * type to their parent will notify not only | |
1117 * this control but also the parent of this control, | |
1118 * which is typically the application window and | |
1119 * the window that is looking for the message. | |
1120 * If the control did not forward the message, | |
1121 * applications would have to subclass the control | |
1122 * window to see the message. Because the control | |
1123 * window is subclassed by SWT, the message | |
1124 * is delivered twice, once by SWT and once when | |
1125 * the message is forwarded by the window proc. | |
1126 * The fix is to avoid calling the window proc | |
1127 * for this control. | |
1128 */ | |
1129 LRESULT result = super.WM_COMMAND (wParam, lParam); | |
1130 if (result !is null) return result; | |
1131 return LRESULT.ZERO; | |
1132 } | |
1133 | |
1134 override LRESULT WM_ERASEBKGND (int wParam, int lParam) { | |
1135 LRESULT result = super.WM_ERASEBKGND (wParam, lParam); | |
1136 /* | |
1137 * Bug in Windows. For some reason, NM_CUSTOMDRAW with | |
1138 * CDDS_PREERASE and CDDS_POSTERASE is never sent for | |
1139 * versions of Windows earlier than XP. The fix is to | |
1140 * draw the background in WM_ERASEBKGND; | |
1141 */ | |
1142 if (findBackgroundControl () !is null) { | |
1143 if (OS.COMCTL32_MAJOR < 6) { | |
1144 drawBackground (cast(HANDLE) wParam); | |
1145 return LRESULT.ONE; | |
1146 } | |
1147 } | |
1148 return result; | |
1149 } | |
1150 | |
1151 override LRESULT WM_GETDLGCODE (int wParam, int lParam) { | |
1152 LRESULT result = super.WM_GETDLGCODE (wParam, lParam); | |
1153 /* | |
1154 * Return DLGC_BUTTON so that mnemonics will be | |
1155 * processed without needing to press the ALT key | |
1156 * when the widget has focus. | |
1157 */ | |
1158 if (result !is null) return result; | |
1159 return new LRESULT (OS.DLGC_BUTTON); | |
1160 } | |
1161 | |
1162 override LRESULT WM_KEYDOWN (int wParam, int lParam) { | |
1163 LRESULT result = super.WM_KEYDOWN (wParam, lParam); | |
1164 if (result !is null) return result; | |
1165 switch (wParam) { | |
1166 case OS.VK_SPACE: | |
1167 /* | |
1168 * Ensure that the window proc does not process VK_SPACE | |
1169 * so that it can be handled in WM_CHAR. This allows the | |
1170 * application the opportunity to cancel the operation. | |
1171 */ | |
1172 return LRESULT.ZERO; | |
1173 default: | |
1174 } | |
1175 return result; | |
1176 } | |
1177 | |
1178 override LRESULT WM_KILLFOCUS (int wParam, int lParam) { | |
1179 int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0); | |
1180 TBBUTTON lpButton; | |
1181 int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton); | |
1182 if (code !is 0) lastFocusId = lpButton.idCommand; | |
1183 return super.WM_KILLFOCUS (wParam, lParam); | |
1184 } | |
1185 | |
1186 override LRESULT WM_LBUTTONDOWN (int wParam, int lParam) { | |
1187 if (ignoreMouse) return null; | |
1188 return super.WM_LBUTTONDOWN (wParam, lParam); | |
1189 } | |
1190 | |
1191 override LRESULT WM_LBUTTONUP (int wParam, int lParam) { | |
1192 if (ignoreMouse) return null; | |
1193 return super.WM_LBUTTONUP (wParam, lParam); | |
1194 } | |
1195 | |
1196 override LRESULT WM_MOUSELEAVE (int wParam, int lParam) { | |
1197 LRESULT result = super.WM_MOUSELEAVE (wParam, lParam); | |
1198 if (result !is null) return result; | |
1199 /* | |
1200 * Bug in Windows. On XP, when a tooltip is | |
1201 * hidden due to a time out or mouse press, | |
1202 * the tooltip remains active although no | |
1203 * longer visible and won't show again until | |
1204 * another tooltip becomes active. If there | |
1205 * is only one tooltip in the window, it will | |
1206 * never show again. The fix is to remove the | |
1207 * current tooltip and add it again every time | |
1208 * the mouse leaves the control. | |
1209 */ | |
1210 if (OS.COMCTL32_MAJOR >= 6) { | |
1211 TOOLINFO lpti; | |
1212 lpti.cbSize = OS.TOOLINFO_sizeof; | |
1213 auto hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); | |
1214 if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, &lpti) !is 0) { | |
1215 if ((lpti.uFlags & OS.TTF_IDISHWND) is 0) { | |
1216 OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, &lpti); | |
1217 OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, &lpti); | |
1218 } | |
1219 } | |
1220 } | |
1221 return result; | |
1222 } | |
1223 | |
1224 override LRESULT WM_NOTIFY (int wParam, int lParam) { | |
1225 /* | |
1226 * Feature in Windows. When the toolbar window | |
1227 * proc processes WM_NOTIFY, it forwards this | |
1228 * message to its parent. This is done so that | |
1229 * children of this control that send this message | |
1230 * type to their parent will notify not only | |
1231 * this control but also the parent of this control, | |
1232 * which is typically the application window and | |
1233 * the window that is looking for the message. | |
1234 * If the control did not forward the message, | |
1235 * applications would have to subclass the control | |
1236 * window to see the message. Because the control | |
1237 * window is subclassed by SWT, the message | |
1238 * is delivered twice, once by SWT and once when | |
1239 * the message is forwarded by the window proc. | |
1240 * The fix is to avoid calling the window proc | |
1241 * for this control. | |
1242 */ | |
1243 LRESULT result = super.WM_NOTIFY (wParam, lParam); | |
1244 if (result !is null) return result; | |
1245 return LRESULT.ZERO; | |
1246 } | |
1247 | |
1248 override LRESULT WM_SETFOCUS (int wParam, int lParam) { | |
1249 LRESULT result = super.WM_SETFOCUS (wParam, lParam); | |
1250 if (lastFocusId !is -1 && handle is OS.GetFocus ()) { | |
1251 int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0); | |
1252 OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0); | |
1253 } | |
1254 return result; | |
1255 } | |
1256 | |
1257 override LRESULT WM_SIZE (int wParam, int lParam) { | |
1258 if (ignoreResize) { | |
1259 int /*long*/ code = callWindowProc (handle, OS.WM_SIZE, wParam, lParam); | |
1260 if (code is 0) return LRESULT.ZERO; | |
1261 return new LRESULT (code); | |
1262 } | |
1263 LRESULT result = super.WM_SIZE (wParam, lParam); | |
1264 if (isDisposed ()) return result; | |
1265 /* | |
1266 * Bug in Windows. The code in Windows that determines | |
1267 * when tool items should wrap seems to use the window | |
1268 * bounds rather than the client area. Unfortunately, | |
1269 * tool bars with the style TBSTYLE_EX_HIDECLIPPEDBUTTONS | |
1270 * use the client area. This means that buttons which | |
1271 * overlap the border are hidden before they are wrapped. | |
1272 * The fix is to compute TBSTYLE_EX_HIDECLIPPEDBUTTONS | |
1273 * and set it each time the tool bar is resized. | |
1274 */ | |
1275 if ((style & SWT.BORDER) !is 0 && (style & SWT.WRAP) !is 0) { | |
1276 RECT windowRect; | |
1277 OS.GetWindowRect (handle, &windowRect); | |
1278 int index = 0, border = getBorderWidth () * 2; | |
1279 RECT rect; | |
1280 int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); | |
1281 while (index < count) { | |
1282 OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect); | |
1283 OS.MapWindowPoints (handle, null, cast(POINT*) &rect, 2); | |
1284 if (rect.right > windowRect.right - border * 2) break; | |
1285 index++; | |
1286 } | |
1287 int bits = OS.SendMessage (handle, OS.TB_GETEXTENDEDSTYLE, 0, 0); | |
1288 if (index is count) { | |
1289 bits |= OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS; | |
1290 } else { | |
1291 bits &= ~OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS; | |
1292 } | |
1293 OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits); | |
1294 } | |
1295 layoutItems (); | |
1296 return result; | |
1297 } | |
1298 | |
1299 override LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) { | |
1300 LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam); | |
1301 if (result !is null) return result; | |
1302 if (ignoreResize) return result; | |
1303 /* | |
1304 * Bug in Windows. When a flat tool bar is wrapped, | |
1305 * Windows draws a horizontal separator between the | |
1306 * rows. The tool bar does not draw the first or | |
1307 * the last two pixels of this separator. When the | |
1308 * toolbar is resized to be bigger, only the new | |
1309 * area is drawn and the last two pixels, which are | |
1310 * blank are drawn over by separator. This leaves | |
1311 * garbage on the screen. The fix is to damage the | |
1312 * pixels. | |
1313 */ | |
1314 if (drawCount !is 0) return result; | |
1315 if ((style & SWT.WRAP) is 0) return result; | |
1316 if (!OS.IsWindowVisible (handle)) return result; | |
1317 if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) is 1) { | |
1318 return result; | |
1319 } | |
1320 WINDOWPOS* lpwp = cast(WINDOWPOS*)lParam; | |
1321 //OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof); | |
1322 if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) !is 0) { | |
1323 return result; | |
1324 } | |
1325 RECT oldRect; | |
1326 OS.GetClientRect (handle, &oldRect); | |
1327 RECT newRect; | |
1328 OS.SetRect (&newRect, 0, 0, lpwp.cx, lpwp.cy); | |
1329 OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &newRect); | |
1330 int oldWidth = oldRect.right - oldRect.left; | |
1331 int newWidth = newRect.right - newRect.left; | |
1332 if (newWidth > oldWidth) { | |
1333 RECT rect; | |
1334 int newHeight = newRect.bottom - newRect.top; | |
1335 OS.SetRect (&rect, oldWidth - 2, 0, oldWidth, newHeight); | |
1336 OS.InvalidateRect (handle, &rect, false); | |
1337 } | |
1338 return result; | |
1339 } | |
1340 | |
1341 override LRESULT wmCommandChild (int wParam, int lParam) { | |
1342 ToolItem child = items [OS.LOWORD (wParam)]; | |
1343 if (child is null) return null; | |
1344 return child.wmCommandChild (wParam, lParam); | |
1345 } | |
1346 | |
1347 override LRESULT wmNotifyChild (NMHDR* hdr, int wParam, int lParam) { | |
1348 switch (hdr.code) { | |
1349 case OS.TBN_DROPDOWN: | |
1350 NMTOOLBAR* lpnmtb = cast(NMTOOLBAR*)lParam; | |
1351 //OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof); | |
1352 ToolItem child = items [lpnmtb.iItem]; | |
1353 if (child !is null) { | |
1354 Event event = new Event (); | |
1355 event.detail = SWT.ARROW; | |
1356 int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0); | |
1357 RECT rect; | |
1358 OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect); | |
1359 event.x = rect.left; | |
1360 event.y = rect.bottom; | |
1361 child.postEvent (SWT.Selection, event); | |
1362 } | |
1363 break; | |
1364 case OS.NM_CUSTOMDRAW: | |
1365 if (OS.COMCTL32_MAJOR < 6) break; | |
1366 /* | |
1367 * Bug in Windows. For some reason, under the XP Silver | |
1368 * theme, tool bars continue to draw using the gray color | |
1369 * from the default Blue theme. The fix is to draw the | |
1370 * background. | |
1371 */ | |
1372 NMCUSTOMDRAW* nmcd = cast(NMCUSTOMDRAW*)lParam; | |
1373 //OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof); | |
1374 // if (drawCount !is 0 || !OS.IsWindowVisible (handle)) { | |
1375 // if (!OS.IsWinCE && OS.WindowFromDC (nmcd.hdc) is handle) break; | |
1376 // } | |
1377 switch (nmcd.dwDrawStage) { | |
1378 case OS.CDDS_PREERASE: { | |
1379 /* | |
1380 * Bug in Windows. When a tool bar does not have the style | |
1381 * TBSTYLE_FLAT, the rectangle to be erased in CDDS_PREERASE | |
1382 * is empty. The fix is to draw the whole client area. | |
1383 */ | |
1384 int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); | |
1385 if ((bits & OS.TBSTYLE_FLAT) is 0) { | |
1386 drawBackground (nmcd.hdc); | |
1387 } else { | |
1388 RECT rect; | |
1389 OS.SetRect (&rect, nmcd.rc.left, nmcd.rc.top, nmcd.rc.right, nmcd.rc.bottom); | |
1390 drawBackground (nmcd.hdc, &rect); | |
1391 } | |
1392 return new LRESULT (OS.CDRF_SKIPDEFAULT); | |
1393 } | |
1394 default: | |
1395 } | |
1396 break; | |
1397 case OS.TBN_HOTITEMCHANGE: | |
1398 static if (!OS.IsWinCE) { | |
1399 auto lpnmhi = cast(NMTBHOTITEM*)lParam; | |
1400 //OS.MoveMemory (lpnmhi, lParam, NMTBHOTITEM.sizeof); | |
1401 switch (lpnmhi.dwFlags) { | |
1402 case OS.HICF_ARROWKEYS: | |
1403 RECT client; | |
1404 OS.GetClientRect (handle, &client); | |
1405 int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmhi.idNew, 0); | |
1406 RECT rect; | |
1407 OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect); | |
1408 if (rect.right > client.right || rect.bottom > client.bottom) { | |
1409 return LRESULT.ONE; | |
1410 } | |
1411 break; | |
1412 default: | |
1413 } | |
1414 } | |
1415 break; | |
1416 default: | |
1417 } | |
1418 return super.wmNotifyChild (hdr, wParam, lParam); | |
1419 } | |
1420 | |
1421 } | |
1422 |