diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.eclipse.swt.win32.win32.x86/src/org/eclipse/swt/widgets/ToolBar.d	Mon Mar 02 14:44:16 2009 +0100
@@ -0,0 +1,1422 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module org.eclipse.swt.widgets.ToolBar;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.internal.ImageList;
+import org.eclipse.swt.internal.win32.OS;
+
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.ToolItem;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Event;
+
+import java.lang.all;
+
+
+/**
+ * Instances of this class support the layout of selectable
+ * tool bar items.
+ * <p>
+ * The item children that may be added to instances of this class
+ * must be of type <code>ToolItem</code>.
+ * </p><p>
+ * Note that although this class is a subclass of <code>Composite</code>,
+ * it does not make sense to add <code>Control</code> children to it,
+ * or set a layout on it.
+ * </p><p>
+ * <dl>
+ * <dt><b>Styles:</b></dt>
+ * <dd>FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT</dd>
+ * <dt><b>Events:</b></dt>
+ * <dd>(none)</dd>
+ * </dl>
+ * <p>
+ * Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
+ * </p><p>
+ * IMPORTANT: This class is <em>not</em> intended to be subclassed.
+ * </p>
+ *
+ * @see <a href="http://www.eclipse.org/swt/snippets/#toolbar">ToolBar, ToolItem snippets</a>
+ * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: ControlExample</a>
+ * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
+ */
+public class ToolBar : Composite {
+
+    alias Composite.computeSize computeSize;
+    alias Composite.setBackgroundImage setBackgroundImage;
+    alias Composite.setBounds setBounds;
+    alias Composite.windowProc windowProc;
+
+    int lastFocusId;
+    ToolItem [] items;
+    bool ignoreResize, ignoreMouse;
+    ImageList imageList, disabledImageList, hotImageList;
+    private static /+const+/ WNDPROC ToolBarProc;
+    static const TCHAR[] ToolBarClass = OS.TOOLBARCLASSNAME;
+
+    private static bool static_this_completed = false;
+    private static void static_this() {
+        if( static_this_completed ){
+            return;
+        }
+        synchronized {
+            if( static_this_completed ){
+                return;
+            }
+            WNDCLASS lpWndClass;
+            OS.GetClassInfo (null, ToolBarClass.ptr, &lpWndClass);
+            ToolBarProc = lpWndClass.lpfnWndProc;
+            static_this_completed = true;
+        }
+    }
+
+
+
+
+    /*
+    * From the Windows SDK for TB_SETBUTTONSIZE:
+    *
+    *   "If an application does not explicitly
+    *   set the button size, the size defaults
+    *   to 24 by 22 pixels".
+    */
+    static const int DEFAULT_WIDTH = 24;
+    static const int DEFAULT_HEIGHT = 22;
+
+/**
+ * Constructs a new instance of this class given its parent
+ * and a style value describing its behavior and appearance.
+ * <p>
+ * The style value is either one of the style constants defined in
+ * class <code>SWT</code> which is applicable to instances of this
+ * class, or must be built by <em>bitwise OR</em>'ing together
+ * (that is, using the <code>int</code> "|" operator) two or more
+ * of those <code>SWT</code> style constants. The class description
+ * lists the style constants that are applicable to the class.
+ * Style bits are also inherited from superclasses.
+ * </p>
+ *
+ * @param parent a composite control which will be the parent of the new instance (cannot be null)
+ * @param style the style of control to construct
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
+ *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
+ * </ul>
+ *
+ * @see SWT#FLAT
+ * @see SWT#WRAP
+ * @see SWT#RIGHT
+ * @see SWT#HORIZONTAL
+ * @see SWT#SHADOW_OUT
+ * @see SWT#VERTICAL
+ * @see Widget#checkSubclass()
+ * @see Widget#getStyle()
+ */
+public this (Composite parent, int style) {
+    static_this();
+    super (parent, checkStyle (style));
+    /*
+    * Ensure that either of HORIZONTAL or VERTICAL is set.
+    * NOTE: HORIZONTAL and VERTICAL have the same values
+    * as H_SCROLL and V_SCROLL so it is necessary to first
+    * clear these bits to avoid scroll bars and then reset
+    * the bits using the original style supplied by the
+    * programmer.
+    *
+    * NOTE: The CCS_VERT style cannot be applied when the
+    * widget is created because of this conflict.
+    */
+    if ((style & SWT.VERTICAL) !is 0) {
+        this.style |= SWT.VERTICAL;
+        int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+        /*
+        * Feature in Windows.  When a tool bar has the style
+        * TBSTYLE_LIST and has a drop down item, Window leaves
+        * too much padding around the button.  This affects
+        * every button in the tool bar and makes the preferred
+        * height too big.  The fix is to set the TBSTYLE_LIST
+        * when the tool bar contains both text and images.
+        *
+        * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
+        * set before any item is added or the tool bar does
+        * not lay out properly.  The work around does not run
+        * in this case.
+        */
+        if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
+            if ((style & SWT.RIGHT) !is 0) bits |= OS.TBSTYLE_LIST;
+        }
+        OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.CCS_VERT);
+    } else {
+        this.style |= SWT.HORIZONTAL;
+    }
+}
+
+override int callWindowProc (HWND hwnd, int msg, int wParam, int lParam) {
+    if (handle is null) return 0;
+    /*
+    * Bug in Windows.  For some reason, during the processing
+    * of WM_SYSCHAR, the tool bar window proc does not call the
+    * default window proc causing mnemonics for the menu bar
+    * to be ignored.  The fix is to always call the default
+    * window proc for WM_SYSCHAR.
+    */
+    if (msg is OS.WM_SYSCHAR) {
+        return OS.DefWindowProc (hwnd, msg, wParam, lParam);
+    }
+    return OS.CallWindowProc (ToolBarProc, hwnd, msg, wParam, lParam);
+}
+
+static int checkStyle (int style) {
+    /*
+    * On Windows, only flat tool bars can be traversed.
+    */
+    if ((style & SWT.FLAT) is 0) style |= SWT.NO_FOCUS;
+
+    /*
+    * A vertical tool bar cannot wrap because TB_SETROWS
+    * fails when the toolbar has TBSTYLE_WRAPABLE.
+    */
+    if ((style & SWT.VERTICAL) !is 0) style &= ~SWT.WRAP;
+
+    /*
+    * Even though it is legal to create this widget
+    * with scroll bars, they serve no useful purpose
+    * because they do not automatically scroll the
+    * widget's client area.  The fix is to clear
+    * the SWT style.
+    */
+    return style & ~(SWT.H_SCROLL | SWT.V_SCROLL);
+}
+
+override void checkBuffered () {
+    super.checkBuffered ();
+    if (OS.COMCTL32_MAJOR >= 6) style |= SWT.DOUBLE_BUFFERED;
+}
+
+override protected void checkSubclass () {
+    if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
+}
+
+override public Point computeSize (int wHint, int hHint, bool changed) {
+    checkWidget ();
+    int width = 0, height = 0;
+    if ((style & SWT.VERTICAL) !is 0) {
+        RECT rect;
+        TBBUTTON lpButton;
+        int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+        for (int i=0; i<count; i++) {
+            OS.SendMessage (handle, OS.TB_GETITEMRECT, i, &rect);
+            height = Math.max (height, rect.bottom);
+            OS.SendMessage (handle, OS.TB_GETBUTTON, i, &lpButton);
+            if ((lpButton.fsStyle & OS.BTNS_SEP) !is 0) {
+                TBBUTTONINFO info;
+                info.cbSize = TBBUTTONINFO.sizeof;
+                info.dwMask = OS.TBIF_SIZE;
+                OS.SendMessage (handle, OS.TB_GETBUTTONINFO, lpButton.idCommand, &info);
+                width = Math.max (width, info.cx);
+            } else {
+                width = Math.max (width, rect.right);
+            }
+        }
+    } else {
+        RECT oldRect;
+        OS.GetWindowRect (handle, &oldRect);
+        int oldWidth = oldRect.right - oldRect.left;
+        int oldHeight = oldRect.bottom - oldRect.top;
+        int border = getBorderWidth ();
+        int newWidth = wHint is SWT.DEFAULT ? 0x3FFF : wHint + border * 2;
+        int newHeight = hHint is SWT.DEFAULT ? 0x3FFF : hHint + border * 2;
+        bool redraw = drawCount is 0 && OS.IsWindowVisible (handle);
+        ignoreResize = true;
+        if (redraw) OS.UpdateWindow (handle);
+        int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
+        SetWindowPos (handle, null, 0, 0, newWidth, newHeight, flags);
+        int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+        if (count !is 0) {
+            RECT rect;
+            OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, &rect);
+            width = Math.max (width, rect.right);
+            height = Math.max (height, rect.bottom);
+        }
+        SetWindowPos (handle, null, 0, 0, oldWidth, oldHeight, flags);
+        if (redraw) OS.ValidateRect (handle, null);
+        ignoreResize = false;
+    }
+
+    /*
+    * From the Windows SDK for TB_SETBUTTONSIZE:
+    *
+    *   "If an application does not explicitly
+    *   set the button size, the size defaults
+    *   to 24 by 22 pixels".
+    */
+    if (width is 0) width = DEFAULT_WIDTH;
+    if (height is 0) height = DEFAULT_HEIGHT;
+    if (wHint !is SWT.DEFAULT) width = wHint;
+    if (hHint !is SWT.DEFAULT) height = hHint;
+    Rectangle trim = computeTrim (0, 0, width, height);
+    width = trim.width;  height = trim.height;
+    return new Point (width, height);
+}
+
+override public Rectangle computeTrim (int x, int y, int width, int height) {
+    checkWidget ();
+    Rectangle trim = super.computeTrim (x, y, width, height);
+    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+    if ((bits & OS.CCS_NODIVIDER) is 0) trim.height += 2;
+    return trim;
+}
+
+override void createHandle () {
+    super.createHandle ();
+    state &= ~CANVAS;
+
+    /*
+    * Feature in Windows.  When TBSTYLE_FLAT is used to create
+    * a flat toolbar, for some reason TBSTYLE_TRANSPARENT is
+    * also set.  This causes the toolbar to flicker when it is
+    * moved or resized.  The fix is to clear TBSTYLE_TRANSPARENT.
+    *
+    * NOTE:  This work around is unnecessary on XP.  There is no
+    * flickering and clearing the TBSTYLE_TRANSPARENT interferes
+    * with the XP theme.
+    */
+    if ((style & SWT.FLAT) !is 0) {
+        if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
+            int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+            bits &= ~OS.TBSTYLE_TRANSPARENT;
+            OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+        }
+    }
+
+    /*
+    * Feature in Windows.  Despite the fact that the
+    * tool tip text contains \r\n, the tooltip will
+    * not honour the new line unless TTM_SETMAXTIPWIDTH
+    * is set.  The fix is to set TTM_SETMAXTIPWIDTH to
+    * a large value.
+    */
+    /*
+    * These lines are intentionally commented.  The tool
+    * bar currently sets this value to 300 so it is not
+    * necessary to set TTM_SETMAXTIPWIDTH.
+    */
+//  int /*long*/ hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
+//  OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
+
+    /*
+    * Feature in Windows.  When the control is created,
+    * it does not use the default system font.  A new HFONT
+    * is created and destroyed when the control is destroyed.
+    * This means that a program that queries the font from
+    * this control, uses the font in another control and then
+    * destroys this control will have the font unexpectedly
+    * destroyed in the other control.  The fix is to assign
+    * the font ourselves each time the control is created.
+    * The control will not destroy a font that it did not
+    * create.
+    */
+    HFONT hFont = OS.GetStockObject (OS.SYSTEM_FONT);
+    OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
+
+    /* Set the button struct, bitmap and button sizes */
+    OS.SendMessage (handle, OS.TB_BUTTONSTRUCTSIZE, TBBUTTON.sizeof, 0);
+    OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
+    OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
+
+    /* Set the extended style bits */
+    int bits = OS.TBSTYLE_EX_DRAWDDARROWS | OS.TBSTYLE_EX_MIXEDBUTTONS | OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
+    if (OS.COMCTL32_MAJOR >= 6) bits |= OS.TBSTYLE_EX_DOUBLEBUFFER;
+    OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits);
+}
+
+void createItem (ToolItem item, int index) {
+    int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+    if (!(0 <= index && index <= count)) error (SWT.ERROR_INVALID_RANGE);
+    int id = 0;
+    while (id < items.length && items [id] !is null) id++;
+    if (id is items.length) {
+        ToolItem [] newItems = new ToolItem [items.length + 4];
+        System.arraycopy (items, 0, newItems, 0, items.length);
+        items = newItems;
+    }
+    int bits = item.widgetStyle ();
+    TBBUTTON lpButton;
+    lpButton.idCommand = id;
+    lpButton.fsStyle = cast(byte) bits;
+    lpButton.fsState = cast(byte) OS.TBSTATE_ENABLED;
+
+    /*
+    * Bug in Windows.  Despite the fact that the image list
+    * index has never been set for the item, Windows always
+    * assumes that the image index for the item is valid.
+    * When an item is inserted, the image index is zero.
+    * Therefore, when the first image is inserted and is
+    * assigned image index zero, every item draws with this
+    * image.  The fix is to set the image index to none
+    * when the item is created.  This is not necessary in
+    * the case when the item has the BTNS_SEP style because
+    * separators cannot show images.
+    */
+    if ((bits & OS.BTNS_SEP) is 0) lpButton.iBitmap = OS.I_IMAGENONE;
+    if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, &lpButton) is 0) {
+        error (SWT.ERROR_ITEM_NOT_ADDED);
+    }
+    items [item.id = id] = item;
+    if ((style & SWT.VERTICAL) !is 0) setRowCount (count + 1);
+    layoutItems ();
+}
+
+override void createWidget () {
+    super.createWidget ();
+    items = new ToolItem [4];
+    lastFocusId = -1;
+}
+
+override int defaultBackground () {
+    static if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE);
+    return super.defaultBackground ();
+}
+
+void destroyItem (ToolItem item) {
+    TBBUTTONINFO info;
+    info.cbSize = TBBUTTONINFO.sizeof;
+    info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE;
+    int index = OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, &info);
+    /*
+    * Feature in Windows.  For some reason, a tool item that has
+    * the style BTNS_SEP does not return I_IMAGENONE when queried
+    * for an image index, despite the fact that no attempt has been
+    * made to assign an image to the item.  As a result, operations
+    * on an image list that use the wrong index cause random results.
+    * The fix is to ensure that the tool item is not a separator
+    * before using the image index.  Since separators cannot have
+    * an image and one is never assigned, this is not a problem.
+    */
+    if ((info.fsStyle & OS.BTNS_SEP) is 0 && info.iImage !is OS.I_IMAGENONE) {
+        if (imageList !is null) imageList.put (info.iImage, null);
+        if (hotImageList !is null) hotImageList.put (info.iImage, null);
+        if (disabledImageList !is null) disabledImageList.put (info.iImage, null);
+    }
+    OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0);
+    if (item.id is lastFocusId) lastFocusId = -1;
+    items [item.id] = null;
+    item.id = -1;
+    int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+    if (count is 0) {
+        if (imageList !is null) {
+            OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
+            display.releaseToolImageList (imageList);
+        }
+        if (hotImageList !is null) {
+            OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
+            display.releaseToolHotImageList (hotImageList);
+        }
+        if (disabledImageList !is null) {
+            OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
+            display.releaseToolDisabledImageList (disabledImageList);
+        }
+        imageList = hotImageList = disabledImageList = null;
+        items = new ToolItem [4];
+    }
+    if ((style & SWT.VERTICAL) !is 0) setRowCount (count - 1);
+    layoutItems ();
+}
+
+override void enableWidget (bool enabled) {
+    super.enableWidget (enabled);
+    /*
+    * Bug in Windows.  When a tool item with the style
+    * BTNS_CHECK or BTNS_CHECKGROUP is selected and then
+    * disabled, the item does not draw using the disabled
+    * image.  The fix is to use the disabled image in all
+    * image lists for the item.
+    *
+    * Feature in Windows.  When a tool bar is disabled,
+    * the text draws disabled but the images do not.
+    * The fix is to use the disabled image in all image
+    * lists for all items.
+    */
+    for (int i=0; i<items.length; i++) {
+        ToolItem item = items [i];
+        if (item !is null) {
+            if ((item.style & SWT.SEPARATOR) is 0) {
+                item.updateImages (enabled && item.getEnabled ());
+            }
+        }
+    }
+}
+
+ImageList getDisabledImageList () {
+    return disabledImageList;
+}
+
+ImageList getHotImageList () {
+    return hotImageList;
+}
+
+ImageList getImageList () {
+    return imageList;
+}
+
+/**
+ * Returns the item at the given, zero-relative index in the
+ * receiver. Throws an exception if the index is out of range.
+ *
+ * @param index the index of the item to return
+ * @return the item at the given index
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public ToolItem getItem (int index) {
+    checkWidget ();
+    int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+    if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE);
+    TBBUTTON lpButton;
+    int result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton);
+    if (result is 0) error (SWT.ERROR_CANNOT_GET_ITEM);
+    return items [lpButton.idCommand];
+}
+
+/**
+ * Returns the item at the given point in the receiver
+ * or null if no such item exists. The point is in the
+ * coordinate system of the receiver.
+ *
+ * @param point the point used to locate the item
+ * @return the item at the given point
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public ToolItem getItem (Point point) {
+    checkWidget ();
+    if (point is null) error (SWT.ERROR_NULL_ARGUMENT);
+    ToolItem [] items = getItems ();
+    for (int i=0; i<items.length; i++) {
+        Rectangle rect = items [i].getBounds ();
+        if (rect.contains (point)) return items [i];
+    }
+    return null;
+}
+
+/**
+ * Returns the number of items contained in the receiver.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getItemCount () {
+    checkWidget ();
+    return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+}
+
+/**
+ * Returns an array of <code>ToolItem</code>s which are the items
+ * in the receiver.
+ * <p>
+ * Note: This is not the actual structure used by the receiver
+ * to maintain its list of items, so modifying the array will
+ * not affect the receiver.
+ * </p>
+ *
+ * @return the items in the receiver
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public ToolItem [] getItems () {
+    checkWidget ();
+    int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+    TBBUTTON lpButton;
+    ToolItem [] result = new ToolItem [count];
+    for (int i=0; i<count; i++) {
+        OS.SendMessage (handle, OS.TB_GETBUTTON, i, &lpButton);
+        result [i] = items [lpButton.idCommand];
+    }
+    return result;
+}
+
+/**
+ * Returns the number of rows in the receiver. When
+ * the receiver has the <code>WRAP</code> style, the
+ * number of rows can be greater than one.  Otherwise,
+ * the number of rows is always one.
+ *
+ * @return the number of items
+ *
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int getRowCount () {
+    checkWidget ();
+    if ((style & SWT.VERTICAL) !is 0) {
+        return OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+    }
+    return OS.SendMessage (handle, OS.TB_GETROWS, 0, 0);
+}
+
+/**
+ * Searches the receiver's list starting at the first item
+ * (index 0) until an item is found that is equal to the
+ * argument, and returns the index of that item. If no item
+ * is found, returns -1.
+ *
+ * @param item the search item
+ * @return the index of the item
+ *
+ * @exception IllegalArgumentException <ul>
+ *    <li>ERROR_NULL_ARGUMENT - if the tool item is null</li>
+ *    <li>ERROR_INVALID_ARGUMENT - if the tool item has been disposed</li>
+ * </ul>
+ * @exception SWTException <ul>
+ *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
+ *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
+ * </ul>
+ */
+public int indexOf (ToolItem item) {
+    checkWidget ();
+    if (item is null) error (SWT.ERROR_NULL_ARGUMENT);
+    if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
+    return OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0);
+}
+
+void layoutItems () {
+    /*
+    * Feature in Windows.  When a tool bar has the style
+    * TBSTYLE_LIST and has a drop down item, Window leaves
+    * too much padding around the button.  This affects
+    * every button in the tool bar and makes the preferred
+    * height too big.  The fix is to set the TBSTYLE_LIST
+    * when the tool bar contains both text and images.
+    *
+    * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
+    * set before any item is added or the tool bar does
+    * not lay out properly.  The work around does not run
+    * in this case.
+    */
+    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
+        if ((style & SWT.RIGHT) !is 0 && (style & SWT.VERTICAL) is 0) {
+            bool hasText = false, hasImage = false;
+            for (int i=0; i<items.length; i++) {
+                ToolItem item = items [i];
+                if (item !is null) {
+                    if (!hasText) hasText = item.text.length !is 0;
+                    if (!hasImage) hasImage = item.image !is null;
+                    if (hasText && hasImage) break;
+                }
+            }
+            int oldBits = OS.GetWindowLong (handle, OS.GWL_STYLE), newBits = oldBits;
+            if (hasText && hasImage) {
+                newBits |= OS.TBSTYLE_LIST;
+            } else {
+                newBits &= ~OS.TBSTYLE_LIST;
+            }
+            if (newBits !is oldBits) {
+                setDropDownItems (false);
+                OS.SetWindowLong (handle, OS.GWL_STYLE, newBits);
+                /*
+                * Feature in Windows.  For some reason, when the style
+                * is changed to TBSTYLE_LIST, Windows does not lay out
+                * the tool items.  The fix is to use WM_SETFONT to force
+                * the tool bar to redraw and lay out.
+                */
+                auto hFont = cast(HFONT) OS.SendMessage (handle, OS.WM_GETFONT, 0, 0);
+                OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0);
+                setDropDownItems (true);
+            }
+        }
+    }
+
+    if ((style & SWT.WRAP) !is 0) {
+        OS.SendMessage (handle, OS.TB_AUTOSIZE, 0, 0);
+    }
+    /*
+    *  When the tool bar is vertical, make the width of each button
+    *  be the width of the widest button in the tool bar.  Note that
+    *  when the tool bar contains a drop down item, it needs to take
+    *  into account extra padding.
+    */
+    if ((style & SWT.VERTICAL) !is 0) {
+        TBBUTTONINFO info;
+        info.cbSize = TBBUTTONINFO.sizeof;
+        info.dwMask = OS.TBIF_SIZE;
+        int /*long*/ size = OS.SendMessage (handle, OS.TB_GETBUTTONSIZE, 0, 0);
+        info.cx = cast(short) OS.LOWORD (size);
+        int index = 0;
+        while (index < items.length) {
+            ToolItem item = items [index];
+            if (item !is null && (item.style & SWT.DROP_DOWN) !is 0) break;
+            index++;
+        }
+        if (index < items.length) {
+            int /*long*/ padding = OS.SendMessage (handle, OS.TB_GETPADDING, 0, 0);
+            info.cx += OS.LOWORD (padding) * 2;
+        }
+        for (int i=0; i<items.length; i++) {
+            ToolItem item = items [i];
+            if (item !is null && (item.style & SWT.SEPARATOR) is 0) {
+                OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, &info);
+            }
+        }
+    }
+    for (int i=0; i<items.length; i++) {
+        ToolItem item = items [i];
+        if (item !is null) item.resizeControl ();
+    }
+}
+
+override bool mnemonicHit (wchar ch) {
+    int key = Display.wcsToMbcs (ch);
+    int id;
+    if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, &id) is 0) {
+        return false;
+    }
+    if ((style & SWT.FLAT) !is 0 && !setTabGroupFocus ()) return false;
+    int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id, 0);
+    if (index is -1) return false;
+    OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
+    items [id].click (false);
+    return true;
+}
+
+override bool mnemonicMatch (wchar ch) {
+    int key = Display.wcsToMbcs (ch);
+    int id;
+    if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, &id) is 0) {
+        return false;
+    }
+    /*
+    * Feature in Windows.  TB_MAPACCELERATOR matches either the mnemonic
+    * character or the first character in a tool item.  This behavior is
+    * undocumented and unwanted.  The fix is to ensure that the tool item
+    * contains a mnemonic when TB_MAPACCELERATOR returns true.
+    */
+    int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id, 0);
+    if (index is -1) return false;
+    return findMnemonic (items [id].text) !is '\0';
+}
+
+override void releaseChildren (bool destroy) {
+    if (items !is null) {
+        for (int i=0; i<items.length; i++) {
+            ToolItem item = items [i];
+            if (item !is null && !item.isDisposed ()) {
+                item.release (false);
+            }
+        }
+        items = null;
+    }
+    super.releaseChildren (destroy);
+}
+
+override void releaseWidget () {
+    super.releaseWidget ();
+    if (imageList !is null) {
+        OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0);
+        display.releaseToolImageList (imageList);
+    }
+    if (hotImageList !is null) {
+        OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0);
+        display.releaseToolHotImageList (hotImageList);
+    }
+    if (disabledImageList !is null) {
+        OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0);
+        display.releaseToolDisabledImageList (disabledImageList);
+    }
+    imageList = hotImageList = disabledImageList = null;
+}
+
+override void removeControl (Control control) {
+    super.removeControl (control);
+    for (int i=0; i<items.length; i++) {
+        ToolItem item = items [i];
+        if (item !is null && item.control is control) {
+            item.setControl (null);
+        }
+    }
+}
+
+override void setBackgroundImage (HBITMAP hBitmap) {
+    super.setBackgroundImage (hBitmap);
+    setBackgroundTransparent (hBitmap !is null);
+}
+
+override void setBackgroundPixel (int pixel) {
+    super.setBackgroundPixel (pixel);
+    setBackgroundTransparent (pixel !is -1);
+}
+
+void setBackgroundTransparent (bool transparent) {
+    /*
+    * Feature in Windows.  When TBSTYLE_TRANSPARENT is set
+    * in a tool bar that is drawing a background, images in
+    * the image list that include transparency information
+    * do not draw correctly.  The fix is to clear and set
+    * TBSTYLE_TRANSPARENT depending on the background color.
+    *
+    * NOTE:  This work around is unnecessary on XP.  The
+    * TBSTYLE_TRANSPARENT style is never cleared on that
+    * platform.
+    */
+    if ((style & SWT.FLAT) !is 0) {
+        if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
+            int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+            if (!transparent && findBackgroundControl () is null) {
+                bits &= ~OS.TBSTYLE_TRANSPARENT;
+            } else {
+                bits |= OS.TBSTYLE_TRANSPARENT;
+            }
+            OS.SetWindowLong (handle, OS.GWL_STYLE, bits);
+        }
+    }
+}
+
+override void setBounds (int x, int y, int width, int height, int flags) {
+    /*
+    * Feature in Windows.  For some reason, when a tool bar is
+    * repositioned more than once using DeferWindowPos () into
+    * the same HDWP, the toolbar redraws more than once, defeating
+    * the purpose of DeferWindowPos ().  The fix is to end the
+    * deferred positioning before the next tool bar is added,
+    * ensuring that only one tool bar position is deferred at
+    * any given time.
+    */
+    if (parent.lpwp !is null) {
+        if (drawCount is 0 && OS.IsWindowVisible (handle)) {
+            parent.setResizeChildren (false);
+            parent.setResizeChildren (true);
+        }
+    }
+    super.setBounds (x, y, width, height, flags);
+}
+
+override void setDefaultFont () {
+    super.setDefaultFont ();
+    OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
+    OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
+}
+
+void setDropDownItems (bool set) {
+    /*
+    * Feature in Windows.  When the first button in a tool bar
+    * is a drop down item, Window leaves too much padding around
+    * the button.  This affects every button in the tool bar and
+    * makes the preferred height too big.  The fix is clear the
+    * BTNS_DROPDOWN before Windows lays out the tool bar and set
+    * the bit afterwards.
+    *
+    * NOTE:  This work around only runs when the tool bar contains
+    * both text and images.
+    */
+    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) {
+        bool hasText = false, hasImage = false;
+        for (int i=0; i<items.length; i++) {
+            ToolItem item = items [i];
+            if (item !is null) {
+                if (!hasText) hasText = item.text.length !is 0;
+                if (!hasImage) hasImage = item.image !is null;
+                if (hasText && hasImage) break;
+            }
+        }
+        if (hasImage && !hasText) {
+            for (int i=0; i<items.length; i++) {
+                ToolItem item = items [i];
+                if (item !is null && (item.style & SWT.DROP_DOWN) !is 0) {
+                    TBBUTTONINFO info;
+                    info.cbSize = TBBUTTONINFO.sizeof;
+                    info.dwMask = OS.TBIF_STYLE;
+                    OS.SendMessage (handle, OS.TB_GETBUTTONINFO, item.id, &info);
+                    if (set) {
+                        info.fsStyle |= OS.BTNS_DROPDOWN;
+                    } else {
+                        info.fsStyle &= ~OS.BTNS_DROPDOWN;
+                    }
+                    OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, &info);
+                }
+            }
+        }
+    }
+}
+
+void setDisabledImageList (ImageList imageList) {
+    if (disabledImageList is imageList) return;
+    HBITMAP hImageList;
+    if ((disabledImageList = imageList) !is null) {
+        hImageList = disabledImageList.getHandle ();
+    }
+    setDropDownItems (false);
+    OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList);
+    setDropDownItems (true);
+}
+
+override public void setFont (Font font) {
+    checkWidget ();
+    setDropDownItems (false);
+    super.setFont (font);
+    setDropDownItems (true);
+    /*
+    * Bug in Windows.  When WM_SETFONT is sent to a tool bar
+    * that contains only separators, causes the bitmap and button
+    * sizes to be set.  The fix is to reset these sizes after the font
+    * has been changed when the tool bar contains only separators.
+    */
+    int index = 0;
+    int mask = SWT.PUSH | SWT.CHECK | SWT.RADIO | SWT.DROP_DOWN;
+    while (index < items.length) {
+        ToolItem item = items [index];
+        if (item !is null && (item.style & mask) !is 0) break;
+        index++;
+    }
+    if (index is items.length) {
+        OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
+        OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
+    }
+    layoutItems ();
+}
+
+void setHotImageList (ImageList imageList) {
+    if (hotImageList is imageList) return;
+    HBITMAP hImageList;
+    if ((hotImageList = imageList) !is null) {
+        hImageList = hotImageList.getHandle ();
+    }
+    setDropDownItems (false);
+    OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList);
+    setDropDownItems (true);
+}
+
+void setImageList (ImageList imageList) {
+    if (this.imageList is imageList) return;
+    HBITMAP hImageList;
+    if ((this.imageList = imageList) !is null) {
+        hImageList = imageList.getHandle ();
+    }
+    setDropDownItems (false);
+    OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList);
+    setDropDownItems (true);
+}
+
+override public bool setParent (Composite parent) {
+    checkWidget ();
+    if (!super.setParent (parent)) return false;
+    OS.SendMessage (handle, OS.TB_SETPARENT, parent.handle, 0);
+    return true;
+}
+
+override public void setRedraw (bool redraw) {
+    checkWidget ();
+    setDropDownItems (false);
+    super.setRedraw (redraw);
+    setDropDownItems (true);
+}
+
+void setRowCount (int count) {
+    if ((style & SWT.VERTICAL) !is 0) {
+        /*
+        * Feature in Windows.  When the TB_SETROWS is used to set the
+        * number of rows in a tool bar, the tool bar is resized to show
+        * the items.  This is unexpected.  The fix is to save and restore
+        * the current size of the tool bar.
+        */
+        RECT rect;
+        OS.GetWindowRect (handle, &rect);
+        OS.MapWindowPoints (null, parent.handle, cast(POINT*) &rect, 2);
+        ignoreResize = true;
+        /*
+        * Feature in Windows.  When the last button in a tool bar has the
+        * style BTNS_SEP and TB_SETROWS is used to set the number of rows
+        * in the tool bar, depending on the number of buttons, the toolbar
+        * will wrap items with the style BTNS_CHECK, even when the fLarger
+        * flags is used to force the number of rows to be larger than the
+        * number of items.  The fix is to set the number of rows to be two
+        * larger than the actual number of rows in the tool bar.  When items
+        * are being added, as long as the number of rows is at least one
+        * item larger than the count, the tool bar is laid out properly.
+        * When items are being removed, setting the number of rows to be
+        * one more than the item count has no effect.  The number of rows
+        * is already one more causing TB_SETROWS to do nothing.  Therefore,
+        * choosing two instead of one as the row increment fixes both cases.
+        */
+        count += 2;
+        OS.SendMessage (handle, OS.TB_SETROWS, OS.MAKEWPARAM (count, 1), 0);
+        int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOZORDER;
+        SetWindowPos (handle, null, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags);
+        ignoreResize = false;
+    }
+}
+
+override bool setTabItemFocus () {
+    int index = 0;
+    while (index < items.length) {
+        ToolItem item = items [index];
+        if (item !is null && (item.style & SWT.SEPARATOR) is 0) {
+            if (item.getEnabled ()) break;
+        }
+        index++;
+    }
+    if (index is items.length) return false;
+    return super.setTabItemFocus ();
+}
+
+override String toolTipText (NMTTDISPINFO* hdr) {
+    if ((hdr.uFlags & OS.TTF_IDISHWND) !is 0) {
+        return null;
+    }
+    /*
+    * Bug in Windows.  On Windows XP, when TB_SETHOTITEM is
+    * used to set the hot item, the tool bar control attempts
+    * to display the tool tip, even when the cursor is not in
+    * the hot item.  The fix is to detect this case and fail to
+    * provide the string, causing no tool tip to be displayed.
+    */
+    if (!hasCursor ()) return ""; //$NON-NLS-1$
+    int index = hdr.hdr.idFrom;
+    auto hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
+    if (hwndToolTip is hdr.hdr.hwndFrom) {
+        /*
+        * Bug in Windows. For some reason the reading order
+        * in NMTTDISPINFO is sometimes set incorrectly.  The
+        * reading order seems to change every time the mouse
+        * enters the control from the top edge.  The fix is
+        * to explicitly set TTF_RTLREADING.
+        */
+        if ((style & SWT.RIGHT_TO_LEFT) !is 0) {
+            hdr.uFlags |= OS.TTF_RTLREADING;
+        } else {
+            hdr.uFlags &= ~OS.TTF_RTLREADING;
+        }
+        if (toolTipText_ !is null) return ""; //$NON-NLS-1$
+        if (0 <= index && index < items.length) {
+            ToolItem item = items [index];
+            if (item !is null) return item.toolTipText;
+        }
+    }
+    return super.toolTipText (hdr);
+}
+
+override int widgetStyle () {
+    int bits = super.widgetStyle () | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS | OS.TBSTYLE_CUSTOMERASE;
+    if (OS.COMCTL32_MAJOR >= 6 && OS.IsAppThemed ()) bits |= OS.TBSTYLE_TRANSPARENT;
+    if ((style & SWT.SHADOW_OUT) is 0) bits |= OS.CCS_NODIVIDER;
+    if ((style & SWT.WRAP) !is 0) bits |= OS.TBSTYLE_WRAPABLE;
+    if ((style & SWT.FLAT) !is 0) bits |= OS.TBSTYLE_FLAT;
+    /*
+    * Feature in Windows.  When a tool bar has the style
+    * TBSTYLE_LIST and has a drop down item, Window leaves
+    * too much padding around the button.  This affects
+    * every button in the tool bar and makes the preferred
+    * height too big.  The fix is to set the TBSTYLE_LIST
+    * when the tool bar contains both text and images.
+    *
+    * NOTE: Tool bars with CCS_VERT must have TBSTYLE_LIST
+    * set before any item is added or the tool bar does
+    * not lay out properly.  The work around does not run
+    * in this case.
+    */
+    if (OS.COMCTL32_MAJOR < 6 || !OS.IsAppThemed ()) {
+        if ((style & SWT.RIGHT) !is 0) bits |= OS.TBSTYLE_LIST;
+    }
+    return bits;
+}
+
+override String windowClass () {
+    return TCHARsToStr(ToolBarClass);
+}
+
+override int windowProc () {
+    return cast(int)ToolBarProc;
+}
+
+override LRESULT WM_CAPTURECHANGED (int wParam, int lParam) {
+    LRESULT result = super.WM_CAPTURECHANGED (wParam, lParam);
+    if (result !is null) return result;
+    /*
+    * Bug in Windows.  When the tool bar loses capture while an
+    * item is pressed, the item remains pressed.  The fix is
+    * unpress all items using TB_SETSTATE and TBSTATE_PRESSED.
+    */
+    for (int i=0; i<items.length; i++) {
+        ToolItem item = items [i];
+        if (item !is null) {
+            int fsState = OS.SendMessage (handle, OS.TB_GETSTATE, item.id, 0);
+            if ((fsState & OS.TBSTATE_PRESSED) !is 0) {
+                fsState &= ~OS.TBSTATE_PRESSED;
+                OS.SendMessage (handle, OS.TB_SETSTATE, item.id, fsState);
+            }
+        }
+    }
+    return result;
+}
+
+override LRESULT WM_CHAR (int wParam, int lParam) {
+    LRESULT result = super.WM_CHAR (wParam, lParam);
+    if (result !is null) return result;
+    switch (wParam) {
+        case ' ':
+            int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
+            if (index !is -1) {
+                TBBUTTON lpButton;
+                int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton);
+                if (code !is 0) {
+                    items [lpButton.idCommand].click (false);
+                    return LRESULT.ZERO;
+                }
+            }
+        default:
+    }
+    return result;
+}
+
+override LRESULT WM_COMMAND (int wParam, int lParam) {
+    /*
+    * Feature in Windows.  When the toolbar window
+    * proc processes WM_COMMAND, it forwards this
+    * message to its parent.  This is done so that
+    * children of this control that send this message
+    * type to their parent will notify not only
+    * this control but also the parent of this control,
+    * which is typically the application window and
+    * the window that is looking for the message.
+    * If the control did not forward the message,
+    * applications would have to subclass the control
+    * window to see the message. Because the control
+    * window is subclassed by SWT, the message
+    * is delivered twice, once by SWT and once when
+    * the message is forwarded by the window proc.
+    * The fix is to avoid calling the window proc
+    * for this control.
+    */
+    LRESULT result = super.WM_COMMAND (wParam, lParam);
+    if (result !is null) return result;
+    return LRESULT.ZERO;
+}
+
+override LRESULT WM_ERASEBKGND (int wParam, int lParam) {
+    LRESULT result = super.WM_ERASEBKGND (wParam, lParam);
+    /*
+    * Bug in Windows.  For some reason, NM_CUSTOMDRAW with
+    * CDDS_PREERASE and CDDS_POSTERASE is never sent for
+    * versions of Windows earlier than XP.  The fix is to
+    * draw the background in WM_ERASEBKGND;
+    */
+    if (findBackgroundControl () !is null) {
+        if (OS.COMCTL32_MAJOR < 6) {
+            drawBackground (cast(HANDLE) wParam);
+            return LRESULT.ONE;
+        }
+    }
+    return result;
+}
+
+override LRESULT WM_GETDLGCODE (int wParam, int lParam) {
+    LRESULT result = super.WM_GETDLGCODE (wParam, lParam);
+    /*
+    * Return DLGC_BUTTON so that mnemonics will be
+    * processed without needing to press the ALT key
+    * when the widget has focus.
+    */
+    if (result !is null) return result;
+    return new LRESULT (OS.DLGC_BUTTON);
+}
+
+override LRESULT WM_KEYDOWN (int wParam, int lParam) {
+    LRESULT result = super.WM_KEYDOWN (wParam, lParam);
+    if (result !is null) return result;
+    switch (wParam) {
+        case OS.VK_SPACE:
+            /*
+            * Ensure that the window proc does not process VK_SPACE
+            * so that it can be handled in WM_CHAR.  This allows the
+            * application the opportunity to cancel the operation.
+            */
+            return LRESULT.ZERO;
+        default:
+    }
+    return result;
+}
+
+override LRESULT WM_KILLFOCUS (int wParam, int lParam) {
+    int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
+    TBBUTTON lpButton;
+    int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, &lpButton);
+    if (code !is 0) lastFocusId = lpButton.idCommand;
+    return super.WM_KILLFOCUS (wParam, lParam);
+}
+
+override LRESULT WM_LBUTTONDOWN (int wParam, int lParam) {
+    if (ignoreMouse) return null;
+    return super.WM_LBUTTONDOWN (wParam, lParam);
+}
+
+override LRESULT WM_LBUTTONUP (int wParam, int lParam) {
+    if (ignoreMouse) return null;
+    return super.WM_LBUTTONUP (wParam, lParam);
+}
+
+override LRESULT WM_MOUSELEAVE (int wParam, int lParam) {
+    LRESULT result = super.WM_MOUSELEAVE (wParam, lParam);
+    if (result !is null) return result;
+    /*
+    * Bug in Windows.  On XP, when a tooltip is
+    * hidden due to a time out or mouse press,
+    * the tooltip remains active although no
+    * longer visible and won't show again until
+    * another tooltip becomes active.  If there
+    * is only one tooltip in the window,  it will
+    * never show again.  The fix is to remove the
+    * current tooltip and add it again every time
+    * the mouse leaves the control.
+    */
+    if (OS.COMCTL32_MAJOR >= 6) {
+        TOOLINFO lpti;
+        lpti.cbSize = OS.TOOLINFO_sizeof;
+        auto hwndToolTip = cast(HWND) OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
+        if (OS.SendMessage (hwndToolTip, OS.TTM_GETCURRENTTOOL, 0, &lpti) !is 0) {
+            if ((lpti.uFlags & OS.TTF_IDISHWND) is 0) {
+                OS.SendMessage (hwndToolTip, OS.TTM_DELTOOL, 0, &lpti);
+                OS.SendMessage (hwndToolTip, OS.TTM_ADDTOOL, 0, &lpti);
+            }
+        }
+    }
+    return result;
+}
+
+override LRESULT WM_NOTIFY (int wParam, int lParam) {
+    /*
+    * Feature in Windows.  When the toolbar window
+    * proc processes WM_NOTIFY, it forwards this
+    * message to its parent.  This is done so that
+    * children of this control that send this message
+    * type to their parent will notify not only
+    * this control but also the parent of this control,
+    * which is typically the application window and
+    * the window that is looking for the message.
+    * If the control did not forward the message,
+    * applications would have to subclass the control
+    * window to see the message. Because the control
+    * window is subclassed by SWT, the message
+    * is delivered twice, once by SWT and once when
+    * the message is forwarded by the window proc.
+    * The fix is to avoid calling the window proc
+    * for this control.
+    */
+    LRESULT result = super.WM_NOTIFY (wParam, lParam);
+    if (result !is null) return result;
+    return LRESULT.ZERO;
+}
+
+override LRESULT WM_SETFOCUS (int wParam, int lParam) {
+    LRESULT result = super.WM_SETFOCUS (wParam, lParam);
+    if (lastFocusId !is -1 && handle is OS.GetFocus ()) {
+        int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0);
+        OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
+    }
+    return result;
+}
+
+override LRESULT WM_SIZE (int wParam, int lParam) {
+    if (ignoreResize) {
+        int /*long*/ code = callWindowProc (handle, OS.WM_SIZE, wParam, lParam);
+        if (code is 0) return LRESULT.ZERO;
+        return new LRESULT (code);
+    }
+    LRESULT result = super.WM_SIZE (wParam, lParam);
+    if (isDisposed ()) return result;
+    /*
+    * Bug in Windows.  The code in Windows that determines
+    * when tool items should wrap seems to use the window
+    * bounds rather than the client area.  Unfortunately,
+    * tool bars with the style TBSTYLE_EX_HIDECLIPPEDBUTTONS
+    * use the client area.  This means that buttons which
+    * overlap the border are hidden before they are wrapped.
+    * The fix is to compute TBSTYLE_EX_HIDECLIPPEDBUTTONS
+    * and set it each time the tool bar is resized.
+    */
+    if ((style & SWT.BORDER) !is 0 && (style & SWT.WRAP) !is 0) {
+        RECT windowRect;
+        OS.GetWindowRect (handle, &windowRect);
+        int index = 0, border = getBorderWidth () * 2;
+        RECT rect;
+        int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
+        while (index < count) {
+            OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect);
+            OS.MapWindowPoints (handle, null, cast(POINT*) &rect, 2);
+            if (rect.right > windowRect.right - border * 2) break;
+            index++;
+        }
+        int bits = OS.SendMessage (handle, OS.TB_GETEXTENDEDSTYLE, 0, 0);
+        if (index is count) {
+            bits |= OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
+        } else {
+            bits &= ~OS.TBSTYLE_EX_HIDECLIPPEDBUTTONS;
+        }
+        OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits);
+    }
+    layoutItems ();
+    return result;
+}
+
+override LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
+    LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
+    if (result !is null) return result;
+    if (ignoreResize) return result;
+    /*
+    * Bug in Windows.  When a flat tool bar is wrapped,
+    * Windows draws a horizontal separator between the
+    * rows.  The tool bar does not draw the first or
+    * the last two pixels of this separator.  When the
+    * toolbar is resized to be bigger, only the new
+    * area is drawn and the last two pixels, which are
+    * blank are drawn over by separator.  This leaves
+    * garbage on the screen.  The fix is to damage the
+    * pixels.
+    */
+    if (drawCount !is 0) return result;
+    if ((style & SWT.WRAP) is 0) return result;
+    if (!OS.IsWindowVisible (handle)) return result;
+    if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) is 1) {
+        return result;
+    }
+    WINDOWPOS* lpwp = cast(WINDOWPOS*)lParam;
+    //OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
+    if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) !is 0) {
+        return result;
+    }
+    RECT oldRect;
+    OS.GetClientRect (handle, &oldRect);
+    RECT newRect;
+    OS.SetRect (&newRect, 0, 0, lpwp.cx, lpwp.cy);
+    OS.SendMessage (handle, OS.WM_NCCALCSIZE, 0, &newRect);
+    int oldWidth = oldRect.right - oldRect.left;
+    int newWidth = newRect.right - newRect.left;
+    if (newWidth > oldWidth) {
+        RECT rect;
+        int newHeight = newRect.bottom - newRect.top;
+        OS.SetRect (&rect, oldWidth - 2, 0, oldWidth, newHeight);
+        OS.InvalidateRect (handle, &rect, false);
+    }
+    return result;
+}
+
+override LRESULT wmCommandChild (int wParam, int lParam) {
+    ToolItem child = items [OS.LOWORD (wParam)];
+    if (child is null) return null;
+    return child.wmCommandChild (wParam, lParam);
+}
+
+override LRESULT wmNotifyChild (NMHDR* hdr, int wParam, int lParam) {
+    switch (hdr.code) {
+        case OS.TBN_DROPDOWN:
+            NMTOOLBAR* lpnmtb = cast(NMTOOLBAR*)lParam;
+            //OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof);
+            ToolItem child = items [lpnmtb.iItem];
+            if (child !is null) {
+                Event event = new Event ();
+                event.detail = SWT.ARROW;
+                int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmtb.iItem, 0);
+                RECT rect;
+                OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect);
+                event.x = rect.left;
+                event.y = rect.bottom;
+                child.postEvent (SWT.Selection, event);
+            }
+            break;
+        case OS.NM_CUSTOMDRAW:
+            if (OS.COMCTL32_MAJOR < 6) break;
+            /*
+            * Bug in Windows.  For some reason, under the XP Silver
+            * theme, tool bars continue to draw using the gray color
+            * from the default Blue theme.  The fix is to draw the
+            * background.
+            */
+            NMCUSTOMDRAW* nmcd = cast(NMCUSTOMDRAW*)lParam;
+            //OS.MoveMemory (nmcd, lParam, NMCUSTOMDRAW.sizeof);
+//          if (drawCount !is 0 || !OS.IsWindowVisible (handle)) {
+//              if (!OS.IsWinCE && OS.WindowFromDC (nmcd.hdc) is handle) break;
+//          }
+            switch (nmcd.dwDrawStage) {
+                case OS.CDDS_PREERASE: {
+                    /*
+                    * Bug in Windows.  When a tool bar does not have the style
+                    * TBSTYLE_FLAT, the rectangle to be erased in CDDS_PREERASE
+                    * is empty.  The fix is to draw the whole client area.
+                    */
+                    int bits = OS.GetWindowLong (handle, OS.GWL_STYLE);
+                    if ((bits & OS.TBSTYLE_FLAT) is 0) {
+                        drawBackground (nmcd.hdc);
+                    } else {
+                        RECT rect;
+                        OS.SetRect (&rect, nmcd.rc.left, nmcd.rc.top, nmcd.rc.right, nmcd.rc.bottom);
+                        drawBackground (nmcd.hdc, &rect);
+                    }
+                    return new LRESULT (OS.CDRF_SKIPDEFAULT);
+                }
+                default:
+            }
+            break;
+        case OS.TBN_HOTITEMCHANGE:
+            static if (!OS.IsWinCE) {
+                auto lpnmhi = cast(NMTBHOTITEM*)lParam;
+                //OS.MoveMemory (lpnmhi, lParam, NMTBHOTITEM.sizeof);
+                switch (lpnmhi.dwFlags) {
+                    case OS.HICF_ARROWKEYS:
+                        RECT client;
+                        OS.GetClientRect (handle, &client);
+                        int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lpnmhi.idNew, 0);
+                        RECT rect;
+                        OS.SendMessage (handle, OS.TB_GETITEMRECT, index, &rect);
+                        if (rect.right > client.right || rect.bottom > client.bottom) {
+                            return LRESULT.ONE;
+                        }
+                        break;
+                    default:
+                }
+            }
+            break;
+        default:
+    }
+    return super.wmNotifyChild (hdr, wParam, lParam);
+}
+
+}
+