All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.swt.widgets.ToolBar Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2000, 2021 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.swt.widgets;


import java.util.*;

import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.win32.*;

/**
 * Instances of this class support the layout of selectable
 * tool bar items.
 * 

* The item children that may be added to instances of this class * must be of type ToolItem. *

* Note that although this class is a subclass of Composite, * it does not make sense to add Control children to it, * or set a layout on it. *

*
*
Styles:
*
FLAT, WRAP, RIGHT, HORIZONTAL, VERTICAL, SHADOW_OUT
*
Events:
*
(none)
*
*

* Note: Only one of the styles HORIZONTAL and VERTICAL may be specified. *

* IMPORTANT: This class is not intended to be subclassed. *

* * @see ToolBar, ToolItem snippets * @see SWT Example: ControlExample * @see Sample code and further information * @noextend This class is not intended to be subclassed by clients. */ public class ToolBar extends Composite { int lastFocusId, lastArrowId, lastHotId, _width, _height, _count = -1, _wHint = -1, _hHint = -1; long currentToolItemToolTip; ToolItem [] items; ToolItem [] tabItemList; boolean ignoreResize, ignoreMouse; ImageList imageList, disabledImageList, hotImageList; static final long ToolBarProc; static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true); static { WNDCLASS lpWndClass = new WNDCLASS (); OS.GetClassInfo (0, ToolBarClass, lpWndClass); ToolBarProc = lpWndClass.lpfnWndProc; DPIZoomChangeRegistry.registerHandler(ToolBar::handleDPIChange, ToolBar.class); } /* * 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 final int DEFAULT_WIDTH = 24; static final int DEFAULT_HEIGHT = 22; /** * Constructs a new instance of this class given its parent * and a style value describing its behavior and appearance. *

* The style value is either one of the style constants defined in * class SWT which is applicable to instances of this * class, or must be built by bitwise OR'ing together * (that is, using the int "|" operator) two or more * of those SWT style constants. The class description * lists the style constants that are applicable to the class. * Style bits are also inherited from superclasses. *

* * @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
    *
  • ERROR_NULL_ARGUMENT - if the parent is null
  • *
* @exception SWTException
    *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent
  • *
  • ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass
  • *
* * @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 ToolBar (Composite parent, int style) { 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) != 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.IsAppThemed ()) { if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST; } OS.SetWindowLong (handle, OS.GWL_STYLE, bits | OS.CCS_VERT); } else { this.style |= SWT.HORIZONTAL; } } @Override long callWindowProc (long hwnd, int msg, long wParam, long lParam) { if (handle == 0) 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 == 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) == 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) != 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 (); style |= SWT.DOUBLE_BUFFERED; } @Override protected void checkSubclass () { if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS); } @Override public void layout (boolean changed) { checkWidget (); clearSizeCache(changed); super.layout(changed); } void clearSizeCache(boolean changed) { // If changed, discard the cached layout information if (changed) { _count = _wHint = _hHint = -1; } } @Override Point computeSizeInPixels (int wHint, int hHint, boolean changed) { int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (count == this._count && wHint == this._wHint && hHint == this._hHint) { // Return already cached values calculated previously return new Point (_width, _height); } this._count = count; this._wHint = wHint; this._hHint = hHint; int width = 0, height = 0; if ((style & SWT.VERTICAL) != 0) { RECT rect = new RECT (); TBBUTTON lpButton = new TBBUTTON (); for (int i=0; i= 0) { ToolItem item = items [index]; if (item.isTabGroup ()) return item; index--; } return super.computeTabGroup (); } @Override Widget [] computeTabList () { ToolItem [] items = _getItems (); if (tabItemList == null) { int i = 0; while (i < items.length && items [i].control == null) i++; if (i == items.length) return super.computeTabList (); } Widget result [] = {}; if (!isTabGroup () || !isEnabled () || !isVisible ()) return result; ToolItem [] list = tabList != null ? _getTabItemList () : items; for (ToolItem child : list) { Widget [] childList = child.computeTabList (); if (childList.length != 0) { Widget [] newResult = new Widget [result.length + childList.length]; System.arraycopy (result, 0, newResult, 0, result.length); System.arraycopy (childList, 0, newResult, result.length, childList.length); result = newResult; } } if (result.length == 0) result = new Widget [] {this}; return result; } @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) != 0) { if (!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. */ // 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. */ long 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_DOUBLEBUFFER; OS.SendMessage (handle, OS.TB_SETEXTENDEDSTYLE, 0, bits); } void createItem (ToolItem item, int index) { int count = (int)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] != null) id++; if (id == 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 = new TBBUTTON (); lpButton.idCommand = id; lpButton.fsStyle = (byte) bits; lpButton.fsState = (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) == 0) lpButton.iBitmap = OS.I_IMAGENONE; if (OS.SendMessage (handle, OS.TB_INSERTBUTTON, index, lpButton) == 0) { error (SWT.ERROR_ITEM_NOT_ADDED); } items [item.id = id] = item; if ((style & SWT.VERTICAL) != 0) setRowCount (count + 1); layoutItems (); } @Override void createWidget () { super.createWidget (); items = new ToolItem [4]; lastFocusId = lastArrowId = lastHotId = -1; } @Override int applyThemeBackground () { return -1; /* No Change */ } void destroyItem (ToolItem item) { TBBUTTONINFO info = new TBBUTTONINFO (); info.cbSize = TBBUTTONINFO.sizeof; info.dwMask = OS.TBIF_IMAGE | OS.TBIF_STYLE; int index = (int)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) == 0 && info.iImage != OS.I_IMAGENONE) { if (imageList != null) imageList.put (info.iImage, null); if (hotImageList != null) hotImageList.put (info.iImage, null); if (disabledImageList != null) disabledImageList.put (info.iImage, null); } OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0); if (item.id == lastFocusId) lastFocusId = -1; if (item.id == lastArrowId) lastArrowId = -1; if (item.id == lastHotId) lastHotId = -1; items [item.id] = null; item.id = -1; int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (count == 0) { if (imageList != null) { OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); display.releaseToolImageList (imageList); } if (hotImageList != null) { OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); display.releaseToolHotImageList (hotImageList); } if (disabledImageList != null) { OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, 0); display.releaseToolDisabledImageList (disabledImageList); } imageList = hotImageList = disabledImageList = null; items = new ToolItem [4]; } if ((style & SWT.VERTICAL) != 0) setRowCount (count - 1); layoutItems (); } @Override void enableWidget (boolean 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 (ToolItem item : items) { if (item != null) { if ((item.style & SWT.SEPARATOR) == 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
    *
  • ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the list minus 1 (inclusive)
  • *
* @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public ToolItem getItem (int index) { checkWidget (); int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (!(0 <= index && index < count)) error (SWT.ERROR_INVALID_RANGE); TBBUTTON lpButton = new TBBUTTON (); long result = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton); if (result == 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
    *
  • ERROR_NULL_ARGUMENT - if the point is null
  • *
* @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public ToolItem getItem (Point point) { checkWidget (); if (point == null) error (SWT.ERROR_NULL_ARGUMENT); return getItemInPixels(DPIUtil.scaleUp(point, getZoom())); } ToolItem getItemInPixels (Point point) { for (ToolItem item : getItems ()) { Rectangle rect = item.getBoundsInPixels (); if (rect.contains (point)) return item; } return null; } /** * Returns the number of items contained in the receiver. * * @return the number of items * * @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public int getItemCount () { checkWidget (); return (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); } /** * Returns an array of ToolItems which are the items * in the receiver. *

* 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. *

* * @return the items in the receiver * * @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public ToolItem [] getItems () { checkWidget (); return _getItems (); } ToolItem [] _getItems () { int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); TBBUTTON lpButton = new TBBUTTON (); ToolItem [] result = new ToolItem [count]; for (int i=0; iWRAP
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
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public int getRowCount () { checkWidget (); if ((style & SWT.VERTICAL) != 0) { return (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); } return (int)OS.SendMessage (handle, OS.TB_GETROWS, 0, 0); } ToolItem [] _getTabItemList () { if (tabItemList == null) return tabItemList; int count = 0; for (ToolItem item : tabItemList) { if (!item.isDisposed ()) count++; } if (count == tabItemList.length) return tabItemList; ToolItem [] newList = new ToolItem [count]; int index = 0; for (ToolItem item : tabItemList) { if (!item.isDisposed ()) { newList [index++] = item; } } tabItemList = newList; return tabItemList; } /** * 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
    *
  • ERROR_NULL_ARGUMENT - if the tool item is null
  • *
  • ERROR_INVALID_ARGUMENT - if the tool item has been disposed
  • *
* @exception SWTException
    *
  • ERROR_WIDGET_DISPOSED - if the receiver has been disposed
  • *
  • ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver
  • *
*/ public int indexOf (ToolItem item) { checkWidget (); if (item == null) error (SWT.ERROR_NULL_ARGUMENT); if (item.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT); return (int)OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, item.id, 0); } void layoutItems () { clearSizeCache(true); /* * 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.IsAppThemed ()) { if ((style & SWT.RIGHT) != 0 && (style & SWT.VERTICAL) == 0) { boolean hasText = false, hasImage = false; for (ToolItem item : items) { if (item != null) { if (!hasText) hasText = item.text.length () != 0; if (!hasImage) hasImage = item.image != 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 != 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. */ long hFont = OS.SendMessage (handle, OS.WM_GETFONT, 0, 0); OS.SendMessage (handle, OS.WM_SETFONT, hFont, 0); setDropDownItems (true); } } } /* * Feature in Windows. When a tool bar is not flagged TBSTYLE_LIST already (SWT.RIGHT) * and contains both text and images, but not text + image in a single 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, so that Windows can condense the unused space. */ if (OS.IsAppThemed()) { if ((style & SWT.RIGHT) == 0 && (style & SWT.HORIZONTAL) != 0) { boolean hasText = false, hasImage = false, hasTextAndImageInSingleItem = false; for (ToolItem item : items) { if (item != null) { boolean itemHasText = false, itemHasImage = false; itemHasText = item.text.length() != 0; itemHasImage = item.image != null; if (!hasText) { hasText = itemHasText; } if (!hasImage) { hasImage = itemHasImage; } if (itemHasText && itemHasImage) { hasTextAndImageInSingleItem = true; break; } } } int oldBits = OS.GetWindowLong(handle, OS.GWL_STYLE), newBits = oldBits; if (hasText && hasImage && !hasTextAndImageInSingleItem) { newBits |= OS.TBSTYLE_LIST; } else { newBits &= ~OS.TBSTYLE_LIST; } if (newBits != 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. */ long hFont = OS.SendMessage(handle, OS.WM_GETFONT, 0, 0); OS.SendMessage(handle, OS.WM_SETFONT, hFont, 0); setDropDownItems(true); } } } if ((style & SWT.WRAP) != 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) != 0) { int itemCount = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); if (itemCount > 1) { TBBUTTONINFO info = new TBBUTTONINFO (); info.cbSize = TBBUTTONINFO.sizeof; info.dwMask = OS.TBIF_SIZE; long size = OS.SendMessage (handle, OS.TB_GETBUTTONSIZE, 0, 0); info.cx = (short) OS.LOWORD (size); int index = 0, extraPadding = 0; while (index < items.length) { ToolItem item = items [index]; if (item != null && (item.style & SWT.DROP_DOWN) != 0) { /* * Specifying 1 pixel extra padding to avoid truncation * of widest item in the tool-bar when a tool-bar has * SWT.VERTICAL style and any of the items in the * tool-bar has SWT.DROP_DOWN style, Refer bug#437206 */ extraPadding = 1; break; } index++; } if (index < items.length) { long padding = OS.SendMessage (handle, OS.TB_GETPADDING, 0, 0); info.cx += OS.LOWORD (padding + extraPadding) * 2; } for (ToolItem item : items) { if (item != null && (item.style & SWT.SEPARATOR) == 0) { OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, info); } } } } /* * Feature on Windows. When SWT.WRAP or SWT.VERTICAL are set * the separator items with control are implemented using BTNS_BUTTON * instead of BTNS_SEP. When that is the case and TBSTYLE_LIST is * set, the layout of the ToolBar recalculates the width for all * BTNS_BUTTON based on the text and bitmap of the item. * This is not strictly wrong, but the user defined width for the * separators has to be respected if set. * The fix is to detect this case and reset the cx width for the item. */ if ((style & (SWT.WRAP | SWT.VERTICAL)) != 0) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if ((bits & OS.TBSTYLE_LIST) != 0) { TBBUTTONINFO info = new TBBUTTONINFO (); info.cbSize = TBBUTTONINFO.sizeof; info.dwMask = OS.TBIF_SIZE; for (ToolItem item : items) { if (item != null && item.cx > 0) { info.cx = item.cx; OS.SendMessage (handle, OS.TB_SETBUTTONINFO, item.id, info); } } } } for (ToolItem item : items) { if (item != null) item.resizeControl (); } } @Override boolean mnemonicHit (char ch) { int [] id = new int [1]; if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, ch, id) == 0) { return false; } if ((style & SWT.FLAT) != 0 && !setTabGroupFocus ()) return false; int index = (int)OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0); if (index == -1) return false; OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0); items [id [0]].click (false); return true; } @Override boolean mnemonicMatch (char ch) { int [] id = new int [1]; if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, ch, id) == 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 = (int)OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, id [0], 0); if (index == -1) return false; return findMnemonic (items [id [0]].text) != '\0'; } @Override void releaseChildren (boolean destroy) { if (items != null) { for (ToolItem item : items) { if (item != null && !item.isDisposed ()) { item.release (false); } } items = null; } super.releaseChildren (destroy); } @Override void releaseWidget () { super.releaseWidget (); if (imageList != null) { OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, 0); display.releaseToolImageList (imageList); } if (hotImageList != null) { OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, 0); display.releaseToolHotImageList (hotImageList); } if (disabledImageList != 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 (ToolItem item : items) { if (item != null && item.control == control) { item.setControl (null); } } } @Override void reskinChildren (int flags) { if (items != null) { for (ToolItem item : items) { if (item != null) item.reskin (flags); } } super.reskinChildren (flags); } @Override void setBackgroundImage (long hBitmap) { super.setBackgroundImage (hBitmap); setBackgroundTransparent (hBitmap != 0); } @Override void setBackgroundPixel (int pixel) { super.setBackgroundPixel (pixel); setBackgroundTransparent (pixel != -1); } void setBackgroundTransparent (boolean 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) != 0) { if (!OS.IsAppThemed ()) { int bits = OS.GetWindowLong (handle, OS.GWL_STYLE); if (!transparent && findBackgroundControl () == null) { bits &= ~OS.TBSTYLE_TRANSPARENT; } else { bits |= OS.TBSTYLE_TRANSPARENT; } OS.SetWindowLong (handle, OS.GWL_STYLE, bits); } } } @Override void setBoundsInPixels (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 != null) { if (getDrawing () && OS.IsWindowVisible (handle)) { parent.setResizeChildren (false); parent.setResizeChildren (true); } } super.setBoundsInPixels (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 (boolean 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 * only images. */ if (OS.IsAppThemed ()) { boolean hasText = false, hasImage = false; for (ToolItem item : items) { if (item != null) { if (!hasText) hasText = item.text.length () != 0; if (!hasImage) hasImage = item.image != null; if (hasText && hasImage) break; } } if (hasImage && !hasText) { for (ToolItem item : items) { if (item != null && (item.style & SWT.DROP_DOWN) != 0) { TBBUTTONINFO info = new TBBUTTONINFO (); 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) { long hImageList = 0; if ((disabledImageList = imageList) != null) { hImageList = OS.SendMessage(handle, OS.TB_GETDISABLEDIMAGELIST, 0, 0); long newImageList = disabledImageList.getHandle(getZoom()); if (hImageList == newImageList) return; hImageList = newImageList; } 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 != null && (item.style & mask) != 0) break; index++; } if (index == items.length) { OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0); OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0); } layoutItems (); } void setHotImageList (ImageList imageList) { long hImageList = 0; if ((hotImageList = imageList) != null) { hImageList = OS.SendMessage(handle, OS.TB_GETHOTIMAGELIST, 0, 0); long newImageList = hotImageList.getHandle(getZoom()); if (hImageList == newImageList) return; hImageList = newImageList; } setDropDownItems (false); OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList); setDropDownItems (true); } void setImageList (ImageList imageList) { long hImageList = 0; if ((this.imageList = imageList) != null) { hImageList = OS.SendMessage(handle, OS.TB_GETIMAGELIST, 0, 0); long newImageList = imageList.getHandle(getZoom()); if (hImageList == newImageList) return; hImageList = newImageList; } setDropDownItems (false); OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList); setDropDownItems (true); } @Override public boolean setParent (Composite parent) { checkWidget (); if (!super.setParent (parent)) return false; long hwndParent = parent.handle; OS.SendMessage (handle, OS.TB_SETPARENT, hwndParent, 0); /* * Bug in Windows. When a tool bar is reparented, the tooltip * control that is automatically created for the item is not * reparented to the new shell. The fix is to move the tooltip * over using SetWindowLongPtr(). Note that for some reason, * SetParent() does not work. */ long hwndShell = parent.getShell ().handle; long hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); OS.SetWindowLongPtr (hwndToolTip, OS.GWLP_HWNDPARENT, hwndShell); return true; } @Override public void setRedraw (boolean redraw) { checkWidget (); setDropDownItems (false); super.setRedraw (redraw); setDropDownItems (true); } void setRowCount (int count) { if ((style & SWT.VERTICAL) != 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 = new RECT (); OS.GetWindowRect (handle, rect); OS.MapWindowPoints (0, parent.handle, 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; OS.SetWindowPos (handle, 0, 0, 0, rect.right - rect.left, rect.bottom - rect.top, flags); ignoreResize = false; } } /*public*/ void setTabItemList (ToolItem [] tabList) { checkWidget (); if (tabList != null) { for (ToolItem item : tabList) { if (item == null) error (SWT.ERROR_INVALID_ARGUMENT); if (item.isDisposed ()) error (SWT.ERROR_INVALID_ARGUMENT); if (item.parent != this) error (SWT.ERROR_INVALID_PARENT); } ToolItem [] newList = new ToolItem [tabList.length]; System.arraycopy (tabList, 0, newList, 0, tabList.length); tabList = newList; } this.tabItemList = tabList; } @Override boolean setTabItemFocus () { int index = 0; while (index < items.length) { ToolItem item = items [index]; if (item != null && (item.style & SWT.SEPARATOR) == 0) { if (item.getEnabled ()) break; } index++; } if (index == items.length) return false; return super.setTabItemFocus (); } @Override boolean updateTextDirection(int textDirection) { if (super.updateTextDirection(textDirection)) { ToolItem [] items = _getItems (); int i = items.length; while (i-- > 0) { items[i].updateTextDirection(style & SWT.FLIP_TEXT_DIRECTION); } return true; } return false; } @Override String toolTipText (NMTTDISPINFO hdr) { if ((hdr.uFlags & OS.TTF_IDISHWND) != 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 = (int)hdr.idFrom; long hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0); if (hwndToolTip == hdr.hwndFrom) { if (currentToolItemToolTip != hwndToolTip) { maybeEnableDarkSystemTheme(hdr.hwndFrom); currentToolItemToolTip = 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. */ int flags = SWT.RIGHT_TO_LEFT | SWT.FLIP_TEXT_DIRECTION; if ((style & flags) != 0 && (style & flags) != flags) { hdr.uFlags |= OS.TTF_RTLREADING; } else { hdr.uFlags &= ~OS.TTF_RTLREADING; } if (toolTipText != null) return ""; //$NON-NLS-1$ if (0 <= index && index < items.length) { ToolItem item = items [index]; if (item != null) { /* * Bug in Windows. When the arrow keys are used to change * the hot item, for some reason, Windows displays the tool * tip for the hot item in at (0, 0) on the screen rather * than next to the current hot item. This fix is to disallow * tool tips while the user is traversing with the arrow keys. */ if (lastArrowId != -1) return ""; return item.toolTipText; } } } return super.toolTipText (hdr); } @Override void updateOrientation () { super.updateOrientation (); if (imageList != null) { Point size = imageList.getImageSize (); ImageList newImageList = display.getImageListToolBar (style & SWT.RIGHT_TO_LEFT, size.x, size.y, getZoom()); ImageList newHotImageList = display.getImageListToolBarHot (style & SWT.RIGHT_TO_LEFT, size.x, size.y, getZoom()); ImageList newDisabledImageList = display.getImageListToolBarDisabled (style & SWT.RIGHT_TO_LEFT, size.x, size.y, getZoom()); TBBUTTONINFO info = new TBBUTTONINFO (); info.cbSize = TBBUTTONINFO.sizeof; info.dwMask = OS.TBIF_IMAGE; int count = (int)OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0); for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy