blob: c36970f5861549f49c93eef7516382ee250c9a8b [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
* This file is made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*/
import org.eclipse.swt.internal.win32.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
/**
* 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</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>
*/
public class ToolBar extends Composite {
int lastFocusId;
ToolItem [] items;
ImageList imageList, disabledImageList, hotImageList;
static final int ToolBarProc;
static final TCHAR ToolBarClass = new TCHAR (0, OS.TOOLBARCLASSNAME, true);
static {
WNDCLASS lpWndClass = new WNDCLASS ();
OS.GetClassInfo (0, ToolBarClass, lpWndClass);
ToolBarProc = lpWndClass.lpfnWndProc;
}
/*
* 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.
* <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#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.
*/
if ((style & SWT.VERTICAL) != 0) {
this.style |= SWT.VERTICAL;
} else {
this.style |= SWT.HORIZONTAL;
}
}
int callWindowProc (int msg, int wParam, int 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 (handle, msg, wParam, lParam);
}
return OS.CallWindowProc (ToolBarProc, handle, 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 toobar has TBSTYLE_WRAPABLE.
*/
/*
* This code is intentionally commented.
*/
//if ((style & SWT.VERTICAL) != 0) style &= ~SWT.WRAP;
/*
* The TB_SETROWS calls are currently commented, so force
* the wrap style if this bar is vertical.
*/
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);
}
protected void checkSubclass () {
if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
}
public Point computeSize (int wHint, int hHint, boolean changed) {
checkWidget ();
if (layout != null) {
return super.computeSize (wHint, hHint, changed);
}
int width = 0, height = 0;
RECT oldRect = new RECT ();
OS.GetWindowRect (handle, oldRect);
int oldWidth = oldRect.right - oldRect.left;
int oldHeight = oldRect.bottom - oldRect.top;
int newWidth = wHint, newHeight = hHint;
if (newWidth == SWT.DEFAULT) newWidth = 0x3FFF;
if (newHeight == SWT.DEFAULT) newHeight = 0x3FFF;
int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOREDRAW | OS.SWP_NOZORDER;
OS.SetWindowPos (handle, 0, 0, 0, newWidth, newHeight, flags);
int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
if (count != 0) {
RECT rect = new RECT ();
OS.SendMessage (handle, OS.TB_GETITEMRECT, count - 1, rect);
width = Math.max (width, rect.right);
height = Math.max (height, rect.bottom);
}
OS.SetWindowPos (handle, 0, 0, 0, oldWidth, oldHeight, flags);
/*
* 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 == 0) width = DEFAULT_WIDTH;
if (height == 0) height = DEFAULT_HEIGHT;
if (wHint != SWT.DEFAULT) width = wHint;
if (hHint != SWT.DEFAULT) height = hHint;
Rectangle trim = computeTrim (0, 0, width, height);
width = trim.width; height = trim.height;
return new Point (width, height);
}
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) == 0) trim.height += 2;
return trim;
}
void createHandle () {
super.createHandle ();
state &= ~CANVAS;
/*
* 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.
*/
int hwndToolTip = OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
/*
* This line is intentionally commented. The tool
* bar currently sets this value to 300 so it is
* not necessary to set TTM_SETMAXTIPWIDTH.
*/
// OS.SendMessage (hwndToolTip, OS.TTM_SETMAXTIPWIDTH, 0, 0x7FFF);
/*
* Feature in Windows. When the tool tip control is
* created, the parent of the tool tip is the shell.
* If SetParent () is used to reparent the tool bar
* into a new shell, the tool tip is not reparented
* and pops up underneath the new shell. The fix is
* to make sure the tool tip is a topmost window.
*/
/*
* Bug in Windows 98 and NT. Setting the tool tip to be the
* top most window using HWND_TOPMOST can result in a parent
* dialog shell being moved behind its parent if the dialog
* has a sibling that is currently on top. The fix is to lock
* the z-order of the active window.
*/
Display display = getDisplay ();
int flags = OS.SWP_NOACTIVATE | OS.SWP_NOMOVE | OS.SWP_NOSIZE;
display.lockActiveWindow = true;
OS.SetWindowPos (hwndToolTip, OS.HWND_TOPMOST, 0, 0, 0, 0, flags);
display.lockActiveWindow = false;
/*
* 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.
*/
int 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.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] != 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;
/*
* This code is intentionally commented.
*/
// if ((style & SWT.VERTICAL) != 0) {
// OS.SendMessage (handle, OS.TB_SETROWS, count+1, 0);
// }
layoutItems ();
}
void createWidget () {
super.createWidget ();
items = new ToolItem [4];
lastFocusId = -1;
}
int defaultBackground () {
if (OS.IsWinCE) return OS.GetSysColor (OS.COLOR_BTNFACE);
return super.defaultBackground ();
}
void destroyItem (ToolItem item) {
TBBUTTONINFO info = new TBBUTTONINFO ();
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) == 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);
}
int result = OS.SendMessage (handle, OS.TB_DELETEBUTTON, index, 0);
if (item.id == lastFocusId) lastFocusId = -1;
items [item.id] = null;
item.id = -1;
int count = OS.SendMessage (handle, OS.TB_BUTTONCOUNT, 0, 0);
if (count == 0) {
Display display = getDisplay ();
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];
}
/*
* This code is intentionally commented.
*/
// if ((style & SWT.VERTICAL) != 0) {
// OS.SendMessage (handle, OS.TB_SETROWS, count-1, 0);
// }
layoutItems ();
}
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 = new TBBUTTON ();
int 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 <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener 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 == 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>TabItem</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 = new TBBUTTON ();
ToolItem [] result = new ToolItem [count];
for (int i=0; i<count; i++) {
int code = 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 ();
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 == 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 () {
for (int i=0; i<items.length; i++) {
ToolItem item = items [i];
if (item != null) item.resizeControl ();
}
}
boolean mnemonicHit (char ch) {
int key = wcsToMbcs (ch);
int [] id = new int [1];
if (OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) == 0) {
return false;
}
if (!setTabGroupFocus ()) return false;
int index = 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;
}
boolean mnemonicMatch (char ch) {
int key = wcsToMbcs (ch);
int [] id = new int [1];
return OS.SendMessage (handle, OS.TB_MAPACCELERATOR, key, id) != 0;
}
void releaseWidget () {
for (int i=0; i<items.length; i++) {
ToolItem item = items [i];
if (item != null && !item.isDisposed ()) {
item.releaseImages ();
item.releaseWidget ();
}
}
items = null;
Display display = getDisplay ();
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;
super.releaseWidget ();
}
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 puropse of DeferWindowPos (). The fix is to end the
* defered positioning before the next tool bar is added,
* ensuring that only one tool bar position is deferred at
* any given time.
*/
if (parent.hdwp != 0) {
if (drawCount == 0 && OS.IsWindowVisible (handle)) {
int oldHdwp = parent.hdwp;
parent.hdwp = 0;
OS.EndDeferWindowPos (oldHdwp);
int count = parent.getChildrenCount ();
parent.hdwp = OS.BeginDeferWindowPos (count);
}
}
super.setBounds (x, y, width, height, flags);
}
void setDefaultFont () {
super.setDefaultFont ();
OS.SendMessage (handle, OS.TB_SETBITMAPSIZE, 0, 0);
OS.SendMessage (handle, OS.TB_SETBUTTONSIZE, 0, 0);
}
void setDisabledImageList (ImageList imageList) {
if (disabledImageList == imageList) return;
int hImageList = 0;
if ((disabledImageList = imageList) != null) {
hImageList = disabledImageList.getHandle ();
}
OS.SendMessage (handle, OS.TB_SETDISABLEDIMAGELIST, 0, hImageList);
}
void setHotImageList (ImageList imageList) {
if (hotImageList == imageList) return;
int hImageList = 0;
if ((hotImageList = imageList) != null) {
hImageList = hotImageList.getHandle ();
}
OS.SendMessage (handle, OS.TB_SETHOTIMAGELIST, 0, hImageList);
}
void setImageList (ImageList imageList) {
if (this.imageList == imageList) return;
int hImageList = 0;
if ((this.imageList = imageList) != null) {
hImageList = imageList.getHandle ();
}
OS.SendMessage (handle, OS.TB_SETIMAGELIST, 0, hImageList);
}
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 ();
}
int toolTipHandle () {
return OS.SendMessage (handle, OS.TB_GETTOOLTIPS, 0, 0);
}
String toolTipText (NMTTDISPINFO hdr) {
if ((hdr.uFlags & OS.TTF_IDISHWND) != 0) {
return null;
}
int index = hdr.idFrom;
int hwndToolTip = toolTipHandle ();
if (hwndToolTip == hdr.hwndFrom) {
if ((0 <= index) && (index < items.length)) {
ToolItem item = items [index];
if (item != null) return item.toolTipText;
}
}
return super.toolTipText (hdr);
}
int widgetStyle () {
int bits = super.widgetStyle () | OS.CCS_NODIVIDER | OS.CCS_NORESIZE | OS.TBSTYLE_TOOLTIPS;
if ((style & SWT.WRAP) != 0) bits |= OS.TBSTYLE_WRAPABLE;
if ((style & SWT.FLAT) != 0) bits |= OS.TBSTYLE_FLAT;
if ((style & SWT.RIGHT) != 0) bits |= OS.TBSTYLE_LIST;
return bits;
}
TCHAR windowClass () {
return ToolBarClass;
}
int windowProc () {
return ToolBarProc;
}
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 != null) return result;
return new LRESULT (OS.DLGC_BUTTON);
}
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 != null) return result;
return LRESULT.ZERO;
}
LRESULT WM_KEYDOWN (int wParam, int lParam) {
LRESULT result = super.WM_KEYDOWN (wParam, lParam);
if (result != null) return result;
switch (wParam) {
case OS.VK_RETURN:
case OS.VK_SPACE:
int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
if (index != -1) {
TBBUTTON lpButton = new TBBUTTON ();
int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
if (code != 0) {
items [lpButton.idCommand].click (wParam == OS.VK_RETURN);
return LRESULT.ZERO;
}
}
}
return result;
}
LRESULT WM_KILLFOCUS (int wParam, int lParam) {
int index = OS.SendMessage (handle, OS.TB_GETHOTITEM, 0, 0);
TBBUTTON lpButton = new TBBUTTON ();
int code = OS.SendMessage (handle, OS.TB_GETBUTTON, index, lpButton);
if (code != 0) lastFocusId = lpButton.idCommand;
return super.WM_KILLFOCUS (wParam, lParam);
}
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 != null) return result;
return LRESULT.ZERO;
}
LRESULT WM_SETFOCUS (int wParam, int lParam) {
LRESULT result = super.WM_SETFOCUS (wParam, lParam);
if (lastFocusId != -1 && handle == OS.GetFocus ()) {
int index = OS.SendMessage (handle, OS.TB_COMMANDTOINDEX, lastFocusId, 0);
OS.SendMessage (handle, OS.TB_SETHOTITEM, index, 0);
}
return result;
}
LRESULT WM_SIZE (int wParam, int lParam) {
LRESULT result = super.WM_SIZE (wParam, lParam);
/*
* It is possible (but unlikely), that application
* code could have disposed the widget in the resize
* event. If this happens, end the processing of the
* Windows message by returning the result of the
* WM_SIZE message.
*/
if (isDisposed ()) return result;
layoutItems ();
return result;
}
LRESULT WM_WINDOWPOSCHANGING (int wParam, int lParam) {
LRESULT result = super.WM_WINDOWPOSCHANGING (wParam, lParam);
if (result != null) 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 != 0) return result;
if ((style & SWT.WRAP) == 0) return result;
if (!OS.IsWindowVisible (handle)) return result;
if (OS.SendMessage (handle, OS.TB_GETROWS, 0, 0) == 1) {
return result;
}
WINDOWPOS lpwp = new WINDOWPOS ();
OS.MoveMemory (lpwp, lParam, WINDOWPOS.sizeof);
if ((lpwp.flags & (OS.SWP_NOSIZE | OS.SWP_NOREDRAW)) != 0) {
return result;
}
RECT oldRect = new RECT ();
OS.GetClientRect (handle, oldRect);
RECT newRect = new RECT ();
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 = new RECT ();
rect.left = oldWidth - 2;
rect.right = oldWidth;
rect.bottom = newRect.bottom - newRect.top;
OS.InvalidateRect (handle, rect, false);
}
return result;
}
LRESULT wmCommandChild (int wParam, int lParam) {
ToolItem child = items [wParam & 0xFFFF];
if (child == null) return null;
return child.wmCommandChild (wParam, lParam);
}
LRESULT wmNotifyChild (int wParam, int lParam) {
NMHDR hdr = new NMHDR ();
OS.MoveMemory (hdr, lParam, NMHDR.sizeof);
switch (hdr.code) {
case OS.TBN_DROPDOWN:
NMTOOLBAR lpnmtb = new NMTOOLBAR ();
OS.MoveMemory (lpnmtb, lParam, NMTOOLBAR.sizeof);
ToolItem child = items [lpnmtb.iItem];
if (child != null) {
Event event = new Event ();
event.detail = SWT.ARROW;
child.postEvent (SWT.Selection, event);
return null;
}
break;
}
return super.wmNotifyChild (wParam, lParam);
}
}