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