KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > swt > widgets > ToolBar


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 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  *******************************************************************************/

11 package org.eclipse.swt.widgets;
12
13
14 import org.eclipse.swt.internal.*;
15 import org.eclipse.swt.internal.win32.*;
16 import org.eclipse.swt.*;
17 import org.eclipse.swt.graphics.*;
18
19 /**
20  * Instances of this class support the layout of selectable
21  * tool bar items.
22  * <p>
23  * The item children that may be added to instances of this class
24  * must be of type <code>ToolItem</code>.
25  * </p><p>
26  * Note that although this class is a subclass of <code>Composite</code>,
27  * it does not make sense to add <code>Control</code> children to it,
28  * or set a layout on it.
29  * </p><p>
30  * <dl>
31  * <dt><b>Styles:</b></dt>
32  * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd>
33  * <dt><b>Events:</b></dt>
34  * <dd>(none)</dd>
35  * </dl>
36  * <p>
37  * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
38  * </p><p>
39  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
40  * </p>
41  */

42 public class ToolBar extends Composite {
43     int lastFocusId;
44     ToolItem [] items;
45     boolean ignoreResize, ignoreMouse;
46     ImageList imageList, disabledImageList, hotImageList;
47     static final int ToolBarProc;
48     static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true);
49     static {
50         WNDCLASS lpWndClass = new WNDCLASS ();
51         OS.GetClassInfo (0, ToolBarClass, lpWndClass);
52         ToolBarProc = lpWndClass.lpfnWndProc;
53     }
54     
55     /*
56     * From the Windows SDK for TB_SETBUTTONSIZE:
57     *
58     * "If an application does not explicitly
59     * set the button size, the size defaults
60     * to 24 by 22 pixels".
61     */

62     static final int DEFAULT_WIDTH = 24;
63     static final int DEFAULT_HEIGHT = 22;
64
65 /**
66  * Constructs a new instance of this class given its parent
67  * and a style value describing its behavior and appearance.
68  * <p>
69  * The style value is either one of the style constants defined in
70  * class <code>SWT</code> which is applicable to instances of this
71  * class, or must be built by <em>bitwise OR</em>'ing together
72  * (that is, using the <code>int</code> "|" operator) two or more
73  * of those <code>SWT</code> style constants. The class description
74  * lists the style constants that are applicable to the class.
75  * Style bits are also inherited from superclasses.
76  * </p>
77  *
78  * @param parent a composite control which will be the parent of the new instance (cannot be null)
79  * @param style the style of control to construct
80  *
81  * @exception IllegalArgumentException <ul>
82  * <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
83  * </ul>
84  * @exception SWTException <ul>
85  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
86  * <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
87  * </ul>
88  *
89  * @see SWT#FLAT
90  * @see SWT#WRAP
91  * @see SWT#RIGHT
92  * @see SWT#HORIZONTAL
93  * @see SWT#SHADOW_OUT
94  * @see SWT#VERTICAL
95  * @see Widget#checkSubclass()
96  * @see Widget#getStyle()
97  */

98 public ToolBar (Composite parent, int style) {
99     super (parent, checkStyle (style));
100     /*
101     * Ensure that either of HORIZONTAL or VERTICAL is set.
102     * NOTE: HORIZONTAL and VERTICAL have the same values
103     * as H_SCROLL and V_SCROLL so it is necessary to first
104     * clear these bits to avoid scroll bars and then reset
105     * the bits using the original style supplied by the
106     * programmer.
107     *
108     * NOTE: The CCS_VERT style cannot be applied when the
109     * widget is created because of this conflict.
110     */

111     if ((style & SWT.VERTICAL) != 0) {
112         this.style |= SWT.VERTICAL;
113         int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
114         /*
115         * Feature in Windows. When a tool bar has the style
116         * TBSTYLE_LIST and has a drop down item, Window leaves
117         * too much padding around the button. This affects
118         * every button in the tool bar and makes the preferred
119         * height too big. The fix is to set the TBSTYLE_LIST
120         * when the tool bar contains both text and images.
121         *
122         * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
123         * set before any item is added or the tool bar does
124         * not lay out properly. The work around does not run
125         * in this case.
126         */

127         if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
128             if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST;
129         }
130         OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.CCS_VERT);
131     } else {
132         this.style |= SWT.HORIZONTAL;
133     }
134 }
135
136 int callWindowProc (int hwnd, int msg, int wParam, int lParam) {
137     if (handle == 0) return 0;
138     /*
139     * Bug in Windows. For some reason, during the processing
140     * of WM_SYSCHAR, the tool bar window proc does not call the
141     * default window proc causing mnemonics for the menu bar
142     * to be ignored. The fix is to always call the default
143     * window proc for WM_SYSCHAR.
144     */

145     if (msg == OS.WM_SYSCHAR) {
146         return OS.DefWindowProc (hwnd, msg, wParam, lParam);
147     }
148     return OS.CallWindowProc (ToolBarProc, hwnd, msg, wParam, lParam);
149 }
150
151 static int checkStyle (int style) {
152     /*
153     * On Windows, only flat tool bars can be traversed.
154     */

155     if ((style & SWT.FLAT) == 0) style |= SWT.NO_FOCUS;
156     
157     /*
158     * A vertical tool bar cannot wrap because TB_SETROWS
159     * fails when the toolbar has TBSTYLE_WRAPABLE.
160     */

161     if ((style & SWT.VERTICAL) != 0) style &= ~SWT.WRAP;
162         
163     /*
164     * Even though it is legal to create this widget
165     * with scroll bars, they serve no useful purpose
166     * because they do not automatically scroll the
167     * widget's client area. The fix is to clear
168     * the SWT style.
169     */

170     return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
171 }
172
173 void checkBuffered () {
174     super.checkBuffered ();
175     if (OS.COMCTL32_MAJOR >= 6) style |= SWT.DOUBLE_BUFFERED;
176 }
177
178 protected void checkSubclass () {
179     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
180 }
181
182 public Point computeSize (int wHint, int hHint, boolean changed) {
183     checkWidget ();
184     int width = 0, height = 0;
185     if ((style & SWT.VERTICAL) != 0) {
186         RECT rect = new RECT ();
187         TBBUTTON lpButton = new TBBUTTON ();
188         int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
189         for (int i=0; i<count; i++) {
190             OS.SendMessage (handle, OS.TB_GETITEMRECT, i, rect);
191             height = Math.max (height, rect.bottom);
192             OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton);
193             if ((lpButton.fsStyle & OS.BTNS_SEP) != 0) {
194                 TBBUTTONINFO info = new TBBUTTONINFO ();
195                 info.cbSize = TBBUTTONINFO.sizeof;
196                 info.dwMask = OS.TBIF_SIZE;
197                 OS.SendMessage (handle, OS.TB_GETBUTTONINFO, lpButton.idCommand, info);
198                 width = Math.max (width, info.cx);
199             } else {
200                 width = Math.max (width, rect.right);
201             }
202         }
203     } else {
204         RECT oldRect = new RECT ();
205         OS.GetWindowRect (handle, oldRect);
206         int oldWidth = oldRect.right - oldRect.left;
207         int oldHeight = oldRect.bottom - oldRect.top;
208         int border = getBorderWidth ();
209         int newWidth = wHint == SWT.DEFAULT ? 0x3FFF : wHint + border * 2;
210         int newHeight = hHint == SWT.DEFAULT ? 0x3FFF : hHint + border * 2;
211         boolean redraw = drawCount == 0 && OS.IsWindowVisible (handle);
212         ignoreResize = true;
213         if (redraw) OS.UpdateWindow (handle);
214         int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
215         SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags);
216         int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
217         if (count != 0) {
218             RECT rect = new RECT ();
219             OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, rect);
220             width = Math.max (width, rect.right);
221             height = Math.max (height, rect.bottom);
222         }
223         SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags);
224         if (redraw) OS.ValidateRect (handle, null);
225         ignoreResize = false;
226     }
227     
228     /*
229     * From the Windows SDK for TB_SETBUTTONSIZE:
230     *
231     * "If an application does not explicitly
232     * set the button size, the size defaults
233     * to 24 by 22 pixels".
234     */

235     if (width == 0) width = DEFAULT_WIDTH;
236     if (height == 0) height = DEFAULT_HEIGHT;
237     if (wHint != SWT.DEFAULT) width = wHint;
238     if (hHint != SWT.DEFAULT) height = hHint;
239     Rectangle trim = computeTrim (0, 0, width, height);
240     width = trim.width; height = trim.height;
241     return new Point (width, height);
242 }
243
244 public Rectangle computeTrim (int x, int y, int width, int height) {
245     checkWidget ();
246     Rectangle trim = super.computeTrim (x, y, width, height);
247     int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
248     if ((bits & OS.CCS_NODIVIDER) == 0) trim.height += 2;
249     return trim;
250 }
251
252 void createHandle () {
253     super.createHandle ();
254     state &= ~CANVAS;
255     
256     /*
257     * Feature in Windows. When TBSTYLE_FLAT is used to create
258     * a flat toolbar, for some reason TBSTYLE_TRANSPARENT is
259     * also set. This causes the toolbar to flicker when it is
260     * moved or resized. The fix is to clear TBSTYLE_TRANSPARENT.
261     *
262     * NOTE: This work around is unnecessary on XP. There is no
263     * flickering and clearing the TBSTYLE_TRANSPARENT interferes
264     * with the XP theme.
265     */

266     if ((style & SWT.FLAT) != 0) {
267         if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
268             int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
269             bits &= ~OS.TBSTYLE_TRANSPARENT;
270             OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
271         }
272     }
273
274     /*
275     * Feature in Windows. Despite the fact that the
276     * tool tip text contains \r\n, the tooltip will
277     * not honour the new line unless TTM_SETMAXTIPWIDTH
278     * is set. The fix is to set TTM_SETMAXTIPWIDTH to
279     * a large value.
280     */

281     /*
282     * These lines are intentionally commented. The tool
283     * bar currently sets this value to 300 so it is not
284     * necessary to set TTM_SETMAXTIPWIDTH.
285     */

286 // int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
287
// OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
288

289     /*
290     * Feature in Windows. When the control is created,
291     * it does not use the default system font. A new HFONT
292     * is created and destroyed when the control is destroyed.
293     * This means that a program that queries the font from
294     * this control, uses the font in another control and then
295     * destroys this control will have the font unexpectedly
296     * destroyed in the other control. The fix is to assign
297     * the font ourselves each time the control is created.
298     * The control will not destroy a font that it did not
299     * create.
300     */

301     int hFont = OS.GetStockObject (OS.SYSTEM_FONT);
302     OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
303
304     /* Set the button struct, bitmap and button sizes */
305     OS.SendMessage (handle, OS.TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0);
306     OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
307     OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
308
309     /* Set the extended style bits */
310     int bits = OS.TBSTYLE_EX_DRAWDDARROWS | OS.TBSTYLE_EX_MIXEDBUTTONS | OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
311     if (OS.COMCTL32_MAJOR >= 6) bits |= OS.TBSTYLE_EX_DOUBLEBUFFER;
312     OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits);
313 }
314
315 void createItem (ToolItem item, int index) {
316     int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
317     if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
318     int id = 0;
319     while (id < items.length && items [id] != null) id++;
320     if (id == items.length) {
321         ToolItem [] newItems = new ToolItem [items.length + 4];
322         System.arraycopy (items, 0, newItems, 0, items.length);
323         items = newItems;
324     }
325     int bits = item.widgetStyle ();
326     TBBUTTON lpButton = new TBBUTTON ();
327     lpButton.idCommand = id;
328     lpButton.fsStyle = (byte) bits;
329     lpButton.fsState = (byte) OS.TBSTATE_ENABLED;
330     
331     /*
332     * Bug in Windows. Despite the fact that the image list
333     * index has never been set for the item, Windows always
334     * assumes that the image index for the item is valid.
335     * When an item is inserted, the image index is zero.
336     * Therefore, when the first image is inserted and is
337     * assigned image index zero, every item draws with this
338     * image. The fix is to set the image index to none
339     * when the item is created. This is not necessary in
340     * the case when the item has the BTNS_SEP style because
341     * separators cannot show images.
342     */

343     if ((bits & OS.BTNS_SEP) == 0) lpButton.iBitmap = OS.I_IMAGENONE;
344     if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, lpButton) == 0) {
345         error (SWT.ERROR_ITEM_NOT_ADDED);
346     }
347     items [item.id = id] = item;
348     if ((style & SWT.VERTICAL) != 0) setRowCount (count + 1);
349     layoutItems ();
350 }
351
352 void createWidget () {
353     super.createWidget ();
354     items = new ToolItem [4];
355     lastFocusId = -1;
356 }
357
358 int defaultBackground () {
359     if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE);
360     return super.defaultBackground ();
361 }
362
363 void destroyItem (ToolItem item) {
364     TBBUTTONINFO info = new TBBUTTONINFO ();
365     info.cbSize = TBBUTTONINFO.sizeof;
366     info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE;
367     int index = OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, info);
368     /*
369     * Feature in Windows. For some reason, a tool item that has
370     * the style BTNS_SEP does not return I_IMAGENONE when queried
371     * for an image index, despite the fact that no attempt has been
372     * made to assign an image to the item. As a result, operations
373     * on an image list that use the wrong index cause random results.
374     * The fix is to ensure that the tool item is not a separator
375     * before using the image index. Since separators cannot have
376     * an image and one is never assigned, this is not a problem.
377     */

378     if ((info.fsStyle & OS.BTNS_SEP) == 0 && info.iImage != OS.I_IMAGENONE) {
379         if (imageList != null) imageList.put (info.iImage, null);
380         if (hotImageList != null) hotImageList.put (info.iImage, null);
381         if (disabledImageList != null) disabledImageList.put (info.iImage, null);
382     }
383     OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0);
384     if (item.id == lastFocusId) lastFocusId = -1;
385     items [item.id] = null;
386     item.id = -1;
387     int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
388     if (count == 0) {
389         if (imageList != null) {
390             OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
391             display.releaseToolImageList (imageList);
392         }
393         if (hotImageList != null) {
394             OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
395             display.releaseToolHotImageList (hotImageList);
396         }
397         if (disabledImageList != null) {
398             OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
399             display.releaseToolDisabledImageList (disabledImageList);
400         }
401         imageList = hotImageList = disabledImageList = null;
402         items = new ToolItem [4];
403     }
404     if ((style & SWT.VERTICAL) != 0) setRowCount (count - 1);
405     layoutItems ();
406 }
407
408 void enableWidget (boolean enabled) {
409     super.enableWidget (enabled);
410     /*
411     * Bug in Windows. When a tool item with the style
412     * BTNS_CHECK or BTNS_CHECKGROUP is selected and then
413     * disabled, the item does not draw using the disabled
414     * image. The fix is to use the disabled image in all
415     * image lists for the item.
416     *
417     * Feature in Windows. When a tool bar is disabled,
418     * the text draws disabled but the images do not.
419     * The fix is to use the disabled image in all image
420     * lists for all items.
421     */

422     for (int i=0; i<items.length; i++) {
423         ToolItem item = items [i];
424         if (item != null) {
425             if ((item.style & SWT.SEPARATOR) == 0) {
426                 item.updateImages (enabled && item.getEnabled ());
427             }
428         }
429     }
430 }
431
432 ImageList getDisabledImageList () {
433     return disabledImageList;
434 }
435
436 ImageList getHotImageList () {
437     return hotImageList;
438 }
439
440 ImageList getImageList () {
441     return imageList;
442 }
443
444 /**
445  * Returns the item at the given, zero-relative index in the
446  * receiver. Throws an exception if the index is out of range.
447  *
448  * @param index the index of the item to return
449  * @return the item at the given index
450  *
451  * @exception IllegalArgumentException <ul>
452  * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
453  * </ul>
454  * @exception SWTException <ul>
455  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
456  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
457  * </ul>
458  */

459 public ToolItem getItem (int index) {
460     checkWidget ();
461     int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
462     if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
463     TBBUTTON lpButton = new TBBUTTON ();
464     int result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
465     if (result == 0) error (SWT.ERROR_CANNOT_GET_ITEM);
466     return items [lpButton.idCommand];
467 }
468
469 /**
470  * Returns the item at the given point in the receiver
471  * or null if no such item exists. The point is in the
472  * coordinate system of the receiver.
473  *
474  * @param point the point used to locate the item
475  * @return the item at the given point
476  *
477  * @exception IllegalArgumentException <ul>
478  * <li>ERROR_NULL_ARGUMENT - if the point is null</li>
479  * </ul>
480  * @exception SWTException <ul>
481  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
482  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
483  * </ul>
484  */

485 public ToolItem getItem (Point point) {
486     checkWidget ();
487     if (point == null) error (SWT.ERROR_NULL_ARGUMENT);
488     ToolItem [] items = getItems ();
489     for (int i=0; i<items.length; i++) {
490         Rectangle rect = items [i].getBounds ();
491         if (rect.contains (point)) return items [i];
492     }
493     return null;
494 }
495
496 /**
497  * Returns the number of items contained in the receiver.
498  *
499  * @return the number of items
500  *
501  * @exception SWTException <ul>
502  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
503  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
504  * </ul>
505  */

506 public int getItemCount () {
507     checkWidget ();
508     return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
509 }
510
511 /**
512  * Returns an array of <code>ToolItem</code>s which are the items
513  * in the receiver.
514  * <p>
515  * Note: This is not the actual structure used by the receiver
516  * to maintain its list of items, so modifying the array will
517  * not affect the receiver.
518  * </p>
519  *
520  * @return the items in the receiver
521  *
522  * @exception SWTException <ul>
523  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
524  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
525  * </ul>
526  */

527 public ToolItem [] getItems () {
528     checkWidget ();
529     int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
530     TBBUTTON lpButton = new TBBUTTON ();
531     ToolItem [] result = new ToolItem [count];
532     for (int i=0; i<count; i++) {
533         OS.SendMessage (handle, OS.TB_GETBUTTON, i, lpButton);
534         result [i] = items [lpButton.idCommand];
535     }
536     return result;
537 }
538
539 /**
540  * Returns the number of rows in the receiver. When
541  * the receiver has the <code>WRAP</code> style, the
542  * number of rows can be greater than one. Otherwise,
543  * the number of rows is always one.
544  *
545  * @return the number of items
546  *
547  * @exception SWTException <ul>
548  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
549  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
550  * </ul>
551  */

552 public int getRowCount () {
553     checkWidget ();
554     if ((style & SWT.VERTICAL) != 0) {
555         return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
556     }
557     return OS.SendMessage (handle, OS.TB_GETROWS, 0, 0);
558 }
559
560 /**
561  * Searches the receiver's list starting at the first item
562  * (index 0) until an item is found that is equal to the
563  * argument, and returns the index of that item. If no item
564  * is found, returns -1.
565  *
566  * @param item the search item
567  * @return the index of the item
568  *
569  * @exception IllegalArgumentException <ul>
570  * <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
571  * <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</li>
572  * </ul>
573  * @exception SWTException <ul>
574  * <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
575  * <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
576  * </ul>
577  */

578 public int indexOf (ToolItem item) {
579     checkWidget ();
580     if (item == null) error (SWT.ERROR_NULL_ARGUMENT);
581     if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
582     return OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0);
583 }
584
585 void layoutItems () {
586     /*
587     * Feature in Windows. When a tool bar has the style
588     * TBSTYLE_LIST and has a drop down item, Window leaves
589     * too much padding around the button. This affects
590     * every button in the tool bar and makes the preferred
591     * height too big. The fix is to set the TBSTYLE_LIST
592     * when the tool bar contains both text and images.
593     *
594     * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
595     * set before any item is added or the tool bar does
596     * not lay out properly. The work around does not run
597     * in this case.
598     */

599     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
600         if ((style & SWT.RIGHT) != 0 && (style & SWT.VERTICAL) == 0) {
601             boolean hasText = false, hasImage = false;
602             for (int i=0; i<items.length; i++) {
603                 ToolItem item = items [i];
604                 if (item != null) {
605                     if (!hasText) hasText = item.text.length () != 0;
606                     if (!hasImage) hasImage = item.image != null;
607                     if (hasText && hasImage) break;
608                 }
609             }
610             int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
611             if (hasText && hasImage) {
612                 newBits |= OS.TBSTYLE_LIST;
613             } else {
614                 newBits &= ~OS.TBSTYLE_LIST;
615             }
616             if (newBits != oldBits) {
617                 setDropDownItems (false);
618                 OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
619                 /*
620                 * Feature in Windows. For some reason, when the style
621                 * is changed to TBSTYLE_LIST, Windows does not lay out
622                 * the tool items. The fix is to use WM_SETFONT to force
623                 * the tool bar to redraw and lay out.
624                 */

625                 int hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
626                 OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
627                 setDropDownItems (true);
628             }
629         }
630     }
631     
632     if ((style & SWT.WRAP) != 0) {
633         OS.SendMessage (handle, OS.TB_AUTOSIZE, 0, 0);
634     }
635     /*
636     * When the tool bar is vertical, make the width of each button
637     * be the width of the widest button in the tool bar. Note that
638     * when the tool bar contains a drop down item, it needs to take
639     * into account extra padding.
640     */

641     if ((style & SWT.VERTICAL) != 0) {
642         TBBUTTONINFO info = new TBBUTTONINFO ();
643         info.cbSize = TBBUTTONINFO.sizeof;
644         info.dwMask = OS.TBIF_SIZE;
645         int size = OS.SendMessage (handle, OS.TB_GETBUTTONSIZE, 0, 0);
646         info.cx = (short) (size & 0xFFFF);
647         int index = 0;
648         while (index < items.length) {
649             ToolItem item = items [index];
650             if (item != null && (item.style & SWT.DROP_DOWN) != 0) break;
651             index++;
652         }
653         if (index < items.length) {
654             int padding = OS.SendMessage (handle, OS.TB_GETPADDING, 0, 0);
655             info.cx += (padding & 0xFFFF) * 2;
656         }
657         for (int i=0; i<items.length; i++) {
658             ToolItem item = items [i];
659             if (item != null && (item.style & SWT.SEPARATOR) == 0) {
660                 OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, info);
661             }
662         }
663     }
664     for (int i=0; i<items.length; i++) {
665         ToolItem item = items [i];
666         if (item != null) item.resizeControl ();
667     }
668 }
669
670 boolean mnemonicHit (char ch) {
671     int key = Display.wcsToMbcs (ch);
672     int [] id = new int [1];
673     if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) == 0) {
674         return false;
675     }
676     if ((style & SWT.FLAT) != 0 && !setTabGroupFocus ()) return false;
677     int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0);
678     if (index == -1) return false;
679     OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
680     items [id [0]].click (false);
681     return true;
682 }
683
684 boolean mnemonicMatch (char ch) {
685     int key = Display.wcsToMbcs (ch);
686     int [] id = new int [1];
687     if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) == 0) {
688         return false;
689     }
690     /*
691     * Feature in Windows. TB_MAPACCELERATOR matches either the mnemonic
692     * character or the first character in a tool item. This behavior is
693     * undocumented and unwanted. The fix is to ensure that the tool item
694     * contains a mnemonic when TB_MAPACCELERATOR returns true.
695     */

696     int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0);
697     if (index == -1) return false;
698     return findMnemonic (items [id [0]].text) != '\0';
699 }
700
701 void releaseChildren (boolean destroy) {
702     if (items != null) {
703         for (int i=0; i<items.length; i++) {
704             ToolItem item = items [i];
705             if (item != null && !item.isDisposed ()) {
706                 item.release (false);
707             }
708         }
709         items = null;
710     }
711     super.releaseChildren (destroy);
712 }
713
714 void releaseWidget () {
715     super.releaseWidget ();
716     if (imageList != null) {
717         OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
718         display.releaseToolImageList (imageList);
719     }
720     if (hotImageList != null) {
721         OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
722         display.releaseToolHotImageList (hotImageList);
723     }
724     if (disabledImageList != null) {
725         OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
726         display.releaseToolDisabledImageList (disabledImageList);
727     }
728     imageList = hotImageList = disabledImageList = null;
729 }
730
731 void removeControl (Control control) {
732     super.removeControl (control);
733     for (int i=0; i<items.length; i++) {
734         ToolItem item = items [i];
735         if (item != null && item.control == control) {
736             item.setControl (null);
737         }
738     }
739 }
740
741 void setBackgroundImage (int hBitmap) {
742     super.setBackgroundImage (hBitmap);
743     setBackgroundTransparent (hBitmap != 0);
744 }
745
746 void setBackgroundPixel (int pixel) {
747     super.setBackgroundPixel (pixel);
748     setBackgroundTransparent (pixel != -1);
749 }
750
751 void setBackgroundTransparent (boolean transparent) {
752     /*
753     * Feature in Windows. When TBSTYLE_TRANSPARENT is set
754     * in a tool bar that is drawing a background, images in
755     * the image list that include transparency information
756     * do not draw correctly. The fix is to clear and set
757     * TBSTYLE_TRANSPARENT depending on the background color.
758     *
759     * NOTE: This work around is unnecessary on XP. The
760     * TBSTYLE_TRANSPARENT style is never cleared on that
761     * platform.
762     */

763     if ((style & SWT.FLAT) != 0) {
764         if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
765             int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
766             if (!transparent && findBackgroundControl () == null) {
767                 bits &= ~OS.TBSTYLE_TRANSPARENT;
768             } else {
769                 bits |= OS.TBSTYLE_TRANSPARENT;
770             }
771             OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
772         }
773     }
774 }
775
776 void setBounds (int x, int y, int width, int height, int flags) {
777     /*
778     * Feature in Windows. For some reason, when a tool bar is
779     * repositioned more than once using DeferWindowPos () into
780     * the same HDWP, the toolbar redraws more than once, defeating
781     * the purpose of DeferWindowPos (). The fix is to end the
782     * deferred positioning before the next tool bar is added,
783     * ensuring that only one tool bar position is deferred at
784     * any given time.
785     */

786     if (parent.lpwp != null) {
787         if (drawCount == 0 && OS.IsWindowVisible (handle)) {
788             parent.setResizeChildren (false);
789             parent.setResizeChildren (true);
790         }
791     }
792     super.setBounds (x, y, width, height, flags);
793 }
794
795 void setDefaultFont () {
796     super.setDefaultFont ();
797     OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
798     OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
799 }
800
801 void setDropDownItems (boolean set) {
802     /*
803     * Feature in Windows. When the first button in a tool bar
804     * is a drop down item, Window leaves too much padding around
805     * the button. This affects every button in the tool bar and
806     * makes the preferred height too big. The fix is clear the
807     * BTNS_DROPDOWN before Windows lays out the tool bar and set
808     * the bit afterwards.
809     *
810     * NOTE: This work around only runs when the tool bar contains
811     * both text and images.
812     */

813     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
814         boolean hasText = false, hasImage = false;
815         for (int i=0; i<items.length; i++) {
816             ToolItem item = items [i];
817             if (item != null) {
818                 if (!hasText) hasText = item.text.length () != 0;
819                 if (!hasImage) hasImage = item.image != null;
820                 if (hasText && hasImage) break;
821             }
822         }
823         if (hasImage && !hasText) {
824             for (int i=0; i<items.length; i++) {
825                 ToolItem item = items [i];
826                 if (item != null && (item.style & SWT.DROP_DOWN) != 0) {
827                     TBBUTTONINFO info = new TBBUTTONINFO ();
828                     info.cbSize = TBBUTTONINFO.sizeof;
829                     info.dwMask = OS.TBIF_STYLE;
830                     OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, info);
831                     if (set) {
832                         info.fsStyle |= OS.BTNS_DROPDOWN;
833                     } else {
834                         info.fsStyle &= ~OS.BTNS_DROPDOWN;
835                     }
836                     OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, info);
837                 }
838             }
839         }
840     }
841 }
842
843 void setDisabledImageList (ImageList imageList) {
844     if (disabledImageList == imageList) return;
845     int hImageList = 0;
846     if ((disabledImageList = imageList) != null) {
847         hImageList = disabledImageList.getHandle ();
848     }
849     setDropDownItems (false);
850     OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList);
851     setDropDownItems (true);
852 }
853
854 public void setFont (Font font) {
855     checkWidget ();
856     setDropDownItems (false);
857     super.setFont (font);
858     setDropDownItems (true);
859     /*
860     * Bug in Windows. When WM_SETFONT is sent to a tool bar
861     * that contains only separators, causes the bitmap and button
862     * sizes to be set. The fix is to reset these sizes after the font
863     * has been changed when the tool bar contains only separators.
864     */

865     int index = 0;
866     int mask = SWT.PUSH | SWT.CHECK | SWT.RADIO | SWT.DROP_DOWN;
867     while (index < items.length) {
868         ToolItem item = items [index];
869         if (item != null && (item.style & mask) != 0) break;
870         index++;
871     }
872     if (index == items.length) {
873         OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
874         OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
875     }
876     layoutItems ();
877 }
878
879 void setHotImageList (ImageList imageList) {
880     if (hotImageList == imageList) return;
881     int hImageList = 0;
882     if ((hotImageList = imageList) != null) {
883         hImageList = hotImageList.getHandle ();
884     }
885     setDropDownItems (false);
886     OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList);
887     setDropDownItems (true);
888 }
889
890 void setImageList (ImageList imageList) {
891     if (this.imageList == imageList) return;
892     int hImageList = 0;
893     if ((this.imageList = imageList) != null) {
894         hImageList = imageList.getHandle ();
895     }
896     setDropDownItems (false);
897     OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList);
898     setDropDownItems (true);
899 }
900
901 public boolean setParent (Composite parent) {
902     checkWidget ();
903     if (!super.setParent (parent)) return false;
904     OS.SendMessage (handle, OS.TB_SETPARENT, parent.handle, 0);
905     return true;
906 }
907
908 public void setRedraw (boolean redraw) {
909     checkWidget ();
910     setDropDownItems (false);
911     super.setRedraw (redraw);
912     setDropDownItems (true);
913 }
914
915 void setRowCount (int count) {
916     if ((style & SWT.VERTICAL) != 0) {
917         /*
918         * Feature in Windows. When the TB_SETROWS is used to set the
919         * number of rows in a tool bar, the tool bar is resized to show
920         * the items. This is unexpected. The fix is to save and restore
921         * the current size of the tool bar.
922         */

923         RECT rect = new RECT ();
924         OS.GetWindowRect (handle, rect);
925         OS.MapWindowPoints (0, parent.handle, rect, 2);
926         ignoreResize = true;
927         /*
928         * Feature in Windows. When the last button in a tool bar has the
929         * style BTNS_SEP and TB_SETROWS is used to set the number of rows
930         * in the tool bar, depending on the number of buttons, the toolbar
931         * will wrap items with the style BTNS_CHECK, even when the fLarger
932         * flags is used to force the number of rows to be larger than the
933         * number of items. The fix is to set the number of rows to be two
934         * larger than the actual number of rows in the tool bar. When items
935         * are being added, as long as the number of rows is at least one
936         * item larger than the count, the tool bar is laid out properly.
937         * When items are being removed, setting the number of rows to be
938         * one more than the item count has no effect. The number of rows
939         * is already one more causing TB_SETROWS to do nothing. Therefore,
940         * choosing two instead of one as the row increment fixes both cases.
941         */

942         count += 2;
943         OS.SendMessage (handle, OS.TB_SETROWS, (1 << 16) | count, 0);
944         int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER;
945         SetWindowPos (handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
946         ignoreResize = false;
947     }
948 }
949
950 boolean setTabItemFocus () {
951     int index = 0;
952     while (index < items.length) {
953         ToolItem item = items [index];
954         if (item != null && (item.style & SWT.SEPARATOR) == 0) {
955             if (item.getEnabled ()) break;
956         }
957         index++;
958     }
959     if (index == items.length) return false;
960     return super.setTabItemFocus ();
961 }
962
963 String JavaDoc toolTipText (NMTTDISPINFO hdr) {
964     if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) {
965         return null;
966     }
967     /*
968     * Bug in Windows. On Windows XP, when TB_SETHOTITEM is
969     * used to set the hot item, the tool bar control attempts
970     * to display the tool tip, even when the cursor is not in
971     * the hot item. The fix is to detect this case and fail to
972     * provide the string, causing no tool tip to be displayed.
973     */

974     if (!hasCursor ()) return ""; //$NON-NLS-1$
975
int index = hdr.idFrom;
976     int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
977     if (hwndToolTip == hdr.hwndFrom) {
978         if (toolTipText != null) return ""; //$NON-NLS-1$
979
if (0 <= index && index < items.length) {
980             ToolItem item = items [index];
981             if (item != null) return item.toolTipText;
982         }
983     }
984     return super.toolTipText (hdr);
985 }
986
987 int widgetStyle () {
988     int bits = super.widgetStyle () | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS | OS.TBSTYLE_CUSTOMERASE;
989     if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) bits |= OS.TBSTYLE_TRANSPARENT;
990     if ((style & SWT.SHADOW_OUT) == 0) bits |= OS.CCS_NODIVIDER;
991     if ((style & SWT.WRAP) != 0) bits |= OS.TBSTYLE_WRAPABLE;
992     if ((style & SWT.FLAT) != 0) bits |= OS.TBSTYLE_FLAT;
993     /*
994     * Feature in Windows. When a tool bar has the style
995     * TBSTYLE_LIST and has a drop down item, Window leaves
996     * too much padding around the button. This affects
997     * every button in the tool bar and makes the preferred
998     * height too big. The fix is to set the TBSTYLE_LIST
999     * when the tool bar contains both text and images.
1000    *
1001    * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
1002    * set before any item is added or the tool bar does
1003    * not lay out properly. The work around does not run
1004    * in this case.
1005    */

1006    if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
1007        if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST;
1008    }
1009    return bits;
1010}
1011
1012TCHAR windowClass () {
1013    return ToolBarClass;
1014}
1015
1016int windowProc () {
1017    return ToolBarProc;
1018}
1019
1020LRESULT WM_CAPTURECHANGED (int wParam, int lParam) {
1021    LRESULT result = super.WM_CAPTURECHANGED (wParam, lParam);
1022    if (result != null) return result;
1023    /*
1024    * Bug in Windows. When the tool bar loses capture while an
1025    * item is pressed, the item remains pressed. The fix is
1026    * unpress all items using TB_SETSTATE and TBSTATE_PRESSED.
1027    */

1028    for (int i=0; i<items.length; i++) {
1029        ToolItem item = items [i];
1030        if (item != null) {
1031            int fsState = OS.SendMessage (handle, OS.TB_GETSTATE, item.id, 0);
1032            if ((fsState & OS.TBSTATE_PRESSED) != 0) {
1033                fsState &= ~OS.TBSTATE_PRESSED;
1034                OS.SendMessage (handle, OS.TB_SETSTATE, item.id, fsState);
1035            }
1036        }
1037    }
1038    return result;
1039}
1040
1041LRESULT WM_CHAR (int wParam, int lParam) {
1042    LRESULT result = super.WM_CHAR (wParam, lParam);
1043    if (result != null) return result;
1044    switch (wParam) {
1045        case ' ':
1046            int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
1047            if (index != -1) {
1048                TBBUTTON lpButton = new TBBUTTON ();
1049                int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
1050                if (code != 0) {
1051                    items [lpButton.idCommand].click (false);
1052                    return LRESULT.ZERO;
1053                }
1054            }
1055    }
1056    return result;
1057}
1058
1059LRESULT WM_COMMAND (int wParam, int lParam) {
1060    /*
1061    * Feature in Windows. When the toolbar window
1062    * proc processes WM_COMMAND, it forwards this
1063    * message to its parent. This is done so that
1064    * children of this control that send this message
1065    * type to their parent will notify not only
1066    * this control but also the parent of this control,
1067    * which is typically the application window and
1068    * the window that is looking for the message.
1069    * If the control did not forward the message,
1070    * applications would have to subclass the control
1071    * window to see the message. Because the control
1072    * window is subclassed by SWT, the message
1073    * is delivered twice, once by SWT and once when
1074    * the message is forwarded by the window proc.
1075    * The fix is to avoid calling the window proc
1076    * for this control.
1077    */

1078    LRESULT result = super.WM_COMMAND (wParam, lParam);
1079    if (result != null) return result;
1080    return LRESULT.ZERO;
1081}
1082
1083LRESULT WM_ERASEBKGND (int wParam, int lParam) {
1084    LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
1085    /*
1086    * Bug in Windows. For some reason, NM_CUSTOMDRAW with
1087    * CDDS_PREERASE and CDDS_POSTERASE is never sent for
1088    * versions of Windows earlier than XP. The fix is to
1089    * draw the background in WM_ERASEBKGND;
1090    */

1091    if (findBackgroundControl () != null) {
1092        if (OS.COMCTL32_MAJOR < 6) {
1093            drawBackground (wParam);
1094            return LRESULT.ONE;
1095        }
1096    }
1097    return result;
1098}
1099
1100LRESULT WM_GETDLGCODE (int wParam, int lParam) {
1101    LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
1102    /*
1103    * Return DLGC_BUTTON so that mnemonics will be
1104    * processed without needing to press the ALT key
1105    * when the widget has focus.
1106    */

1107    if (result != null) return result;
1108    return new LRESULT (OS.DLGC_BUTTON);
1109}
1110
1111LRESULT WM_KEYDOWN (int wParam, int lParam) {
1112    LRESULT result = super.WM_KEYDOWN (wParam, lParam);
1113    if (result != null) return result;
1114    switch (wParam) {
1115        case OS.VK_SPACE:
1116            /*
1117            * Ensure that the window proc does not process VK_SPACE
1118            * so that it can be handled in WM_CHAR. This allows the
1119            * application the opportunity to cancel the operation.
1120            */

1121            return LRESULT.ZERO;
1122    }
1123    return result;
1124}
1125
1126LRESULT WM_KILLFOCUS (int wParam, int lParam) {
1127    int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
1128    TBBUTTON lpButton = new TBBUTTON ();
1129    int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
1130    if (code != 0) lastFocusId = lpButton.idCommand;
1131    return super.WM_KILLFOCUS (wParam, lParam);
1132}
1133
1134LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
1135    if (ignoreMouse) return null;
1136    return super.WM_LBUTTONDOWN (wParam, lParam);
1137}
1138
1139LRESULT WM_LBUTTONUP (int wParam, int lParam) {
1140    if (ignoreMouse) return null;
1141    return super.WM_LBUTTONUP (wParam, lParam);
1142}
1143
1144LRESULT WM_MOUSELEAVE (int wParam, int lParam) {
1145    LRESULT result = super.WM_MOUSELEAVE (wParam, lParam);
1146    if (result != null) return result;
1147    /*
1148    * Bug in Windows. On XP, when a tooltip is
1149    * hidden due to a time out or mouse press,
1150    * the tooltip remains active although no
1151    * longer visible and won't show again until
1152    * another tooltip becomes active. If there
1153    * is only one tooltip in the window, it will
1154    * never show again. The fix is to remove the
1155    * current tooltip and add it again every time
1156    * the mouse leaves the control.
1157    */

1158    if (OS.COMCTL32_MAJOR >= 6) {
1159        TOOLINFO lpti = new TOOLINFO ();
1160        lpti.cbSize = TOOLINFO.sizeof;
1161        int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
1162        if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, lpti) != 0) {
1163            if ((lpti.uFlags & OS.TTF_IDISHWND) == 0) {
1164                OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, lpti);
1165                OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, lpti);
1166            }
1167        }
1168    }
1169    return result;
1170}
1171
1172LRESULT WM_NOTIFY (int wParam, int lParam) {
1173    /*
1174    * Feature in Windows. When the toolbar window
1175    * proc processes WM_NOTIFY, it forwards this
1176    * message to its parent. This is done so that
1177    * children of this control that send this message
1178    * type to their parent will notify not only
1179    * this control but also the parent of this control,
1180    * which is typically the application window and
1181    * the window that is looking for the message.
1182    * If the control did not forward the message,
1183    * applications would have to subclass the control
1184    * window to see the message. Because the control
1185    * window is subclassed by SWT, the message
1186    * is delivered twice, once by SWT and once when
1187    * the message is forwarded by the window proc.
1188    * The fix is to avoid calling the window proc
1189    * for this control.
1190    */

1191    LRESULT result = super.WM_NOTIFY (wParam, lParam);
1192    if (result != null) return result;
1193    return LRESULT.ZERO;
1194}
1195
1196LRESULT WM_SETFOCUS (int wParam, int lParam) {
1197    LRESULT result = super.WM_SETFOCUS (wParam, lParam);
1198    if (lastFocusId != -1 && handle == OS.GetFocus ()) {
1199        int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0);
1200        OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
1201    }
1202    return result;
1203}
1204
1205LRESULT WM_SIZE (int wParam, int lParam) {
1206    if (ignoreResize) {
1207        int code = callWindowProc (handle, OS.WM_SIZE, wParam, lParam);
1208        if (code == 0) return LRESULT.ZERO;
1209        return new LRESULT (code);
1210    }
1211    LRESULT result = super.WM_SIZE (wParam, lParam);
1212    if (isDisposed ()) return result;
1213    /*
1214    * Bug in Windows. The code in Windows that determines
1215    * when tool items should wrap seems to use the window
1216    * bounds rather than the client area. Unfortunately,
1217    * tool bars with the style TBSTYLE_EX_HIDECLIPPEDBUTTONS
1218    * use the client area. This means that buttons which
1219    * overlap the border are hidden before they are wrapped.
1220    * The fix is to compute TBSTYLE_EX_HIDECLIPPEDBUTTONS
1221    * and set it each time the tool bar is resized.
1222    */

1223    if ((style & SWT.BORDER) != 0 && (style & SWT.WRAP) != 0) {
1224        RECT windowRect = new RECT ();
1225        OS.GetWindowRect (handle, windowRect);
1226        int index = 0, border = getBorderWidth () * 2;
1227        RECT rect = new RECT ();
1228        int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
1229        while (index < count) {
1230            OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect);
1231            OS.MapWindowPoints (handle, 0, rect, 2);
1232            if (rect.right > windowRect.right - border * 2) break;
1233            index++;
1234        }
1235        int bits = OS.SendMessage (handle, OS.TB_GETEXTENDEDSTYLE, 0, 0);
1236        if (index == count) {
1237            bits |= OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
1238        } else {
1239            bits &= ~OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
1240        }
1241        OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits);
1242    }
1243    layoutItems ();
1244    return result;
1245}
1246
1247LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
1248    LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
1249    if (result != null) return result;
1250    if (ignoreResize) return result;
1251    /*
1252    * Bug in Windows. When a flat tool bar is wrapped,
1253    * Windows draws a horizontal separator between the
1254    * rows. The tool bar does not draw the first or
1255    * the last two pixels of this separator. When the
1256    * toolbar is resized to be bigger, only the new
1257    * area is drawn and the last two pixels, which are
1258    * blank are drawn over by separator. This leaves
1259    * garbage on the screen. The fix is to damage the
1260    * pixels.
1261    */

1262    if (drawCount != 0) return result;
1263    if ((style & SWT.WRAP) == 0) return result;
1264    if (!OS.IsWindowVisible (handle)) return result;
1265    if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) == 1) {
1266        return result;
1267    }
1268    WINDOWPOS lpwp = new WINDOWPOS ();
1269    OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
1270    if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
1271        return result;
1272    }
1273    RECT oldRect = new RECT ();
1274    OS.GetClientRect (handle, oldRect);
1275    RECT newRect = new RECT ();
1276    OS.SetRect (newRect, 0, 0, lpwp.cx, lpwp.cy);
1277    OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, newRect);
1278    int oldWidth = oldRect.right - oldRect.left;
1279    int newWidth = newRect.right - newRect.left;
1280    if (newWidth > oldWidth) {
1281        RECT rect = new RECT ();
1282        int newHeight = newRect.bottom - newRect.top;
1283        OS.SetRect (rect, oldWidth - 2, 0, oldWidth, newHeight);
1284        OS.InvalidateRect (handle, rect, false);
1285    }
1286    return result;
1287}
1288
1289LRESULT wmCommandChild (int wParam, int lParam) {
1290    ToolItem child = items [wParam & 0xFFFF];
1291    if (child == null) return null;
1292    return child.wmCommandChild (wParam, lParam);
1293}
1294
1295LRESULT wmNotifyChild (NMHDR hdr, int wParam, int lParam) {
1296    switch (hdr.code) {
1297        case OS.TBN_DROPDOWN:
1298            NMTOOLBAR lpnmtb = new NMTOOLBAR ();
1299            OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof);
1300            ToolItem child = items [lpnmtb.iItem];
1301            if (child != null) {
1302                Event event = new Event ();
1303                event.detail = SWT.ARROW;
1304                int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0);
1305                RECT rect = new RECT ();
1306                OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect);
1307                event.x = rect.left;
1308                event.y = rect.bottom;
1309                child.postEvent (SWT.Selection, event);
1310            }
1311            break;
1312        case OS.NM_CUSTOMDRAW:
1313            if (OS.COMCTL32_MAJOR < 6) break;
1314            /*
1315            * Bug in Windows. For some reason, under the XP Silver
1316            * theme, tool bars continue to draw using the gray color
1317            * from the default Blue theme. The fix is to draw the
1318            * background.
1319            */

1320            NMCUSTOMDRAW nmcd = new NMCUSTOMDRAW ();
1321            OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof);
1322// if (drawCount != 0 || !OS.IsWindowVisible (handle)) {
1323
// if (!OS.IsWinCE && OS.WindowFromDC (nmcd.hdc) == handle) break;
1324
// }
1325
switch (nmcd.dwDrawStage) {
1326                case OS.CDDS_PREERASE: {
1327                    /*
1328                    * Bug in Windows. When a tool bar does not have the style
1329                    * TBSTYLE_FLAT, the rectangle to be erased in CDDS_PREERASE
1330                    * is empty. The fix is to draw the whole client area.
1331                    */

1332                    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
1333                    if ((bits & OS.TBSTYLE_FLAT) == 0) {
1334                        drawBackground (nmcd.hdc);
1335                    } else {
1336                        RECT rect = new RECT ();
1337                        OS.SetRect (rect, nmcd.left, nmcd.top, nmcd.right, nmcd.bottom);
1338                        drawBackground (nmcd.hdc, rect);
1339                    }
1340                    return new LRESULT (OS.CDRF_SKIPDEFAULT);
1341                }
1342            }
1343            break;
1344        case OS.TBN_HOTITEMCHANGE:
1345            if (!OS.IsWinCE) {
1346                NMTBHOTITEM lpnmhi = new NMTBHOTITEM ();
1347                OS.MoveMemory (lpnmhi, lParam, NMTBHOTITEM.sizeof);
1348                switch (lpnmhi.dwFlags) {
1349                    case OS.HICF_ARROWKEYS:
1350                        RECT client = new RECT ();
1351                        OS.GetClientRect (handle, client);
1352                        int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmhi.idNew, 0);
1353                        RECT rect = new RECT ();
1354                        OS.SendMessage (handle, OS.TB_GETITEMRECT, index, rect);
1355                        if (rect.right > client.right || rect.bottom > client.bottom) {
1356                            return LRESULT.ONE;
1357                        }
1358                        break;
1359                }
1360            }
1361            break;
1362    }
1363    return super.wmNotifyChild (hdr, wParam, lParam);
1364}
1365
1366}
1367
Popular Tags