blob: ae8dcb103ef3368bcad01af32eb677cf5d112e98 [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import org.eclipse.swt.internal.*;
import org.eclipse.swt.internal.motif.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.events.*;
/**
* Instances of this class represent a selectable user interface object
* that represents a button in a tool bar.
* <p>
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>PUSH, CHECK, RADIO, SEPARATOR, DROP_DOWN</dd>
* <dt><b>Events:</b></dt>
* <dd>Selection</dd>
* </dl>
* </p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
*/
public class ToolItem extends Item {
ToolBar parent;
Image hotImage, disabledImage;
String toolTipText;
Control control;
boolean set;
static final int DEFAULT_WIDTH = 24;
static final int DEFAULT_HEIGHT = 22;
static final int DEFAULT_SEPARATOR_WIDTH = 8;
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>ToolBar</code>) and a style value
* describing its behavior and appearance. The item is added
* to the end of the items maintained by its parent.
* <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
* for all SWT widget classes should include a comment which
* describes the style constants which are applicable to the class.
* </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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public ToolItem (ToolBar parent, int style) {
super (parent, checkStyle (style));
this.parent = parent;
parent.createItem (this, parent.getItemCount ());
parent.relayout ();
}
/**
* Constructs a new instance of this class given its parent
* (which must be a <code>ToolBar</code>), a style value
* describing its behavior and appearance, and the index
* at which to place it in the items maintained by its parent.
* <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
* for all SWT widget classes should include a comment which
* describes the style constants which are applicable to the class.
* </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
* @param index the index to store the receiver in its parent
*
* @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
* @see Widget#checkSubclass
* @see Widget#getStyle
*/
public ToolItem (ToolBar parent, int style, int index) {
super (parent, checkStyle (style));
this.parent = parent;
parent.createItem (this, index);
parent.relayout ();
}
/**
* Adds the listener to the collection of listeners who will
* be notified when the control is selected, by sending
* it one of the messages defined in the <code>SelectionListener</code>
* interface.
* <p>
* When <code>widgetSelected</code> is called when the mouse is over the arrow portion of a drop-down tool,
* the event object detail field contains the value <code>SWT.ARROW</code>.
* <code>widgetDefaultSelected</code> is not called.
* </p>
*
* @param listener the listener which should be notified
*
* @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>
*
* @see SelectionListener
* @see #removeSelectionListener
* @see SelectionEvent
*/
public void addSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection,typedListener);
addListener(SWT.DefaultSelection,typedListener);
}
static int checkStyle (int style) {
return checkBits (style, SWT.PUSH, SWT.CHECK, SWT.RADIO, SWT.SEPARATOR, SWT.DROP_DOWN, 0);
}
protected void checkSubclass () {
if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
}
void createHandle (int index) {
state |= HANDLE;
int parentHandle = parent.handle;
if ((style & SWT.SEPARATOR) != 0) {
int orientation = (parent.style & SWT.HORIZONTAL) != 0 ? OS.XmVERTICAL : OS.XmHORIZONTAL;
int [] argList = {
OS.XmNheight, orientation == OS.XmVERTICAL ? DEFAULT_HEIGHT : DEFAULT_SEPARATOR_WIDTH,
OS.XmNwidth, orientation == OS.XmHORIZONTAL ? DEFAULT_WIDTH : DEFAULT_SEPARATOR_WIDTH,
OS.XmNancestorSensitive, 1,
OS.XmNpositionIndex, index,
OS.XmNorientation, orientation,
OS.XmNseparatorType, (parent.style & SWT.FLAT) != 0 ? OS.XmSHADOW_ETCHED_IN : OS.XmSHADOW_ETCHED_OUT,
};
handle = OS.XmCreateSeparator (parentHandle, null, argList, argList.length / 2);
if (handle == 0) error (SWT.ERROR_NO_HANDLES);
return;
}
int [] argList = {
OS.XmNwidth, DEFAULT_WIDTH,
OS.XmNheight, DEFAULT_HEIGHT,
OS.XmNrecomputeSize, 0,
OS.XmNhighlightThickness, (parent.style & SWT.NO_FOCUS) != 0 ? 0 : 1,
OS.XmNmarginWidth, 2,
OS.XmNmarginHeight, 1,
OS.XmNtraversalOn, (parent.style & SWT.NO_FOCUS) != 0 ? 0 : 1,
OS.XmNpositionIndex, index,
OS.XmNshadowType, OS.XmSHADOW_OUT,
OS.XmNancestorSensitive, 1,
};
handle = OS.XmCreateDrawnButton (parentHandle, null, argList, argList.length / 2);
if (handle == 0) error (SWT.ERROR_NO_HANDLES);
int pixel = parent.getBackgroundPixel ();
setBackgroundPixel (pixel);
}
void click (boolean dropDown, XInputEvent xEvent) {
if ((style & SWT.RADIO) != 0) {
selectRadio ();
} else {
if ((style & SWT.CHECK) != 0) setSelection(!set);
}
Event event = new Event ();
if ((style & SWT.DROP_DOWN) != 0) {
if (dropDown) event.detail = SWT.ARROW;
}
if (xEvent != null) setInputState (event, xEvent);
postEvent (SWT.Selection, event);
}
Point computeSize () {
if ((style & SWT.SEPARATOR) != 0) {
int [] argList = {
OS.XmNwidth, 0,
OS.XmNheight, 0,
};
OS.XtGetValues (handle, argList, argList.length / 2);
int width = argList [1], height = argList [3];
return new Point(width, height);
}
int [] argList = {
OS.XmNmarginHeight, 0,
OS.XmNmarginWidth, 0,
OS.XmNshadowThickness, 0,
};
OS.XtGetValues (handle, argList, argList.length / 2);
int marginHeight = argList [1], marginWidth = argList [3];
int shadowThickness = argList [5];
if ((parent.style & SWT.FLAT) != 0) {
Display display = getDisplay ();
shadowThickness = Math.min (2, display.buttonShadowThickness);
}
int textWidth = 0, textHeight = 0;
if (text.length () != 0) {
GC gc = new GC (parent);
int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_MNEMONIC;
Point textExtent = gc.textExtent (text, flags);
textWidth = textExtent.x;
textHeight = textExtent.y;
gc.dispose ();
}
int imageWidth = 0, imageHeight = 0;
if (image != null) {
Rectangle rect = image.getBounds ();
imageWidth = rect.width;
imageHeight = rect.height;
}
int width = 0, height = 0;
if ((parent.style & SWT.RIGHT) != 0) {
width = imageWidth + textWidth;
height = Math.max (imageHeight, textHeight);
if (imageWidth != 0 && textWidth != 0) width += 2;
} else {
height = imageHeight + textHeight;
if (imageHeight != 0 && textHeight != 0) height += 2;
width = Math.max (imageWidth, textWidth);
}
if ((style & SWT.DROP_DOWN) != 0) width += 12;
if (width != 0) {
width += (marginWidth + shadowThickness) * 2 + 2;
} else {
width = DEFAULT_WIDTH;
}
if (height != 0) {
height += (marginHeight + shadowThickness) * 2 + 2;
} else {
height = DEFAULT_HEIGHT;
}
return new Point (width, height);
}
void createWidget (int index) {
super.createWidget (index);
toolTipText = "";
parent.relayout ();
}
public void dispose () {
if (isDisposed()) return;
ToolBar parent = this.parent;
super.dispose ();
parent.relayout ();
}
/**
* Returns a rectangle describing the receiver's size and location
* relative to its parent.
*
* @return the receiver's bounding rectangle
*
* @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 Rectangle getBounds () {
checkWidget();
int [] argList = {OS.XmNx, 0, OS.XmNy, 0, OS.XmNwidth, 0, OS.XmNheight, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
return new Rectangle ((short) argList [1], (short) argList [3], argList [5], argList [7]);
}
/**
* Returns the control that is used to fill the bounds of
* the item when the items is a <code>SEPARATOR</code>.
*
* @return the control
*
* @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 Control getControl () {
checkWidget();
return control;
}
/**
* Returns the receiver's disabled image if it has one, or null
* if it does not.
* <p>
* The disabled image is displayed when the receiver is disabled.
* </p>
*
* @return the receiver's disabled image
*
* @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 Image getDisabledImage () {
checkWidget();
return disabledImage;
}
/**
* Returns <code>true</code> if the receiver is enabled, and
* <code>false</code> otherwise.
* <p>
* A disabled control is typically not selectable from the
* user interface and draws with an inactive or "grayed" look.
* </p>
*
* @return the receiver's enabled state
*
* @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 boolean getEnabled () {
checkWidget();
int [] argList = {OS.XmNsensitive, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
return argList [1] != 0;
}
public Display getDisplay () {
Composite parent = this.parent;
if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
return parent.getDisplay ();
}
/**
* Returns the receiver's hot image if it has one, or null
* if it does not.
* <p>
* The hot image is displayed when the mouse enters the receiver.
* </p>
*
* @return the receiver's hot image
*
* @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 Image getHotImage () {
checkWidget();
return hotImage;
}
/**
* Returns the receiver's parent, which must be a <code>ToolBar</code>.
*
* @return the receiver's parent
*
* @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 ToolBar getParent () {
checkWidget();
return parent;
}
/**
* Returns <code>true</code> if the receiver is selected,
* and false otherwise.
* <p>
* When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
* it is selected when it is checked. When it is of type <code>TOGGLE</code>,
* it is selected when it is pushed.
* </p>
*
* @return the selection state
*
* @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 boolean getSelection () {
checkWidget();
if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return false;
return set;
}
/**
* Returns the receiver's tool tip text, or null if it has not been set.
*
* @return the receiver's tool tip text
*
* @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 String getToolTipText () {
checkWidget();
return toolTipText;
}
/**
* Gets the width of the receiver.
*
* @return the width
*
* @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 getWidth () {
checkWidget();
int [] argList = {OS.XmNwidth, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
return argList [1];
}
boolean hasCursor () {
int [] unused = new int [1], buffer = new int [1];
int xDisplay = OS.XtDisplay (handle);
int xWindow, xParent = OS.XDefaultRootWindow (xDisplay);
do {
if (OS.XQueryPointer (
xDisplay, xParent, unused, buffer,
unused, unused, unused, unused, unused) == 0) return false;
if ((xWindow = buffer [0]) != 0) xParent = xWindow;
} while (xWindow != 0);
return handle == OS.XtWindowToWidget (xDisplay, xParent);
}
void hookEvents () {
super.hookEvents ();
if ((style & SWT.SEPARATOR) != 0) return;
int windowProc = getDisplay ().windowProc;
OS.XtAddEventHandler (handle, OS.KeyPressMask, false, windowProc, SWT.KeyDown);
OS.XtAddEventHandler (handle, OS.KeyReleaseMask, false, windowProc, SWT.KeyUp);
OS.XtAddEventHandler (handle, OS.ButtonPressMask, false, windowProc, SWT.MouseDown);
OS.XtAddEventHandler (handle, OS.ButtonReleaseMask, false, windowProc, SWT.MouseUp);
OS.XtAddEventHandler (handle, OS.PointerMotionMask, false, windowProc, SWT.MouseMove);
OS.XtAddEventHandler (handle, OS.EnterWindowMask, false, windowProc, SWT.MouseEnter);
OS.XtAddEventHandler (handle, OS.LeaveWindowMask, false, windowProc, SWT.MouseExit);
OS.XtAddCallback (handle, OS.XmNexposeCallback, windowProc, SWT.Paint);
}
/**
* Returns <code>true</code> if the receiver is enabled, and
* <code>false</code> otherwise.
* <p>
* A disabled control is typically not selectable from the
* user interface and draws with an inactive or "grayed" look.
* </p>
*
* @return the receiver's enabled state
*
* @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 boolean isEnabled () {
checkWidget();
return getEnabled () && parent.isEnabled ();
}
void manageChildren () {
OS.XtManageChild (handle);
}
void redraw () {
int display = OS.XtDisplay (handle);
if (display == 0) return;
int window = OS.XtWindow (handle);
if (window == 0) return;
OS.XClearArea (display, window, 0, 0, 0, 0, true);
}
void releaseChild () {
super.releaseChild ();
parent.destroyItem (this);
}
void releaseWidget () {
Display display = getDisplay ();
display.releaseToolTipHandle (handle);
super.releaseWidget ();
parent = null;
control = null;
toolTipText = null;
image = disabledImage = hotImage = null;
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the control is selected.
*
* @param listener the listener which should be notified
*
* @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>
*
* @see SelectionListener
* @see #addSelectionListener
*/
public void removeSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook(SWT.Selection, listener);
eventTable.unhook(SWT.DefaultSelection,listener);
}
void selectRadio () {
this.setSelection (true);
ToolItem [] items = parent.getItems ();
int index = 0;
while (index < items.length && items [index] != this) index++;
ToolItem item;
int i = index;
while (--i >= 0 && ((item = items [i]).style & SWT.RADIO) != 0) {
item.setSelection (false);
}
i = index;
while (++i < items.length && ((item = items [i]).style & SWT.RADIO) != 0) {
item.setSelection (false);
}
}
void setBackgroundPixel(int pixel) {
int [] argList = {OS.XmNforeground, 0, OS.XmNhighlightColor, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
OS.XmChangeColor (handle, pixel);
OS.XtSetValues (handle, argList, argList.length / 2);
}
void setBounds (int x, int y, int width, int height) {
if (control != null) control.setBounds(x, y, width, height);
/*
* Feature in Motif. Motif will not allow a window
* to have a zero width or zero height. The fix is
* to ensure these values are never zero.
*/
int newWidth = Math.max (width, 1), newHeight = Math.max (height, 1);
OS.XtConfigureWidget (handle, x, y, newWidth, newHeight, 0);
}
/**
* Sets the control that is used to fill the bounds of
* the item when the items is a <code>SEPARATOR</code>.
*
* @param control the new control
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
* <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</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 void setControl (Control control) {
checkWidget();
if (control != null) {
if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
if (control.parent != parent) error (SWT.ERROR_INVALID_PARENT);
}
if ((style & SWT.SEPARATOR) == 0) return;
this.control = control;
if (control != null && !control.isDisposed ()) {
control.setBounds (getBounds ());
}
}
/**
* Enables the receiver if the argument is <code>true</code>,
* and disables it otherwise.
* <p>
* A disabled control is typically
* not selectable from the user interface and draws with an
* inactive or "grayed" look.
* </p>
*
* @param enabled the new enabled state
*
* @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 void setEnabled (boolean enabled) {
checkWidget();
int [] argList = {OS.XmNsensitive, enabled ? 1 : 0};
OS.XtSetValues (handle, argList, argList.length / 2);
}
/**
* Sets the receiver's disabled image to the argument, which may be
* null indicating that no disabled image should be displayed.
* <p>
* The disbled image is displayed when the receiver is disabled.
* </p>
*
* @param image the disabled image to display on the receiver (may be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the image 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 void setDisabledImage (Image image) {
checkWidget();
if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
if ((style & SWT.SEPARATOR) != 0) return;
disabledImage = image;
if (!getEnabled ()) redraw ();
}
/**
* Sets the receiver's hot image to the argument, which may be
* null indicating that no hot image should be displayed.
* <p>
* The hot image is displayed when the mouse enters the receiver.
* </p>
*
* @param image the hot image to display on the receiver (may be null)
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_INVALID_ARGUMENT - if the image 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 void setHotImage (Image image) {
checkWidget();
if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
if ((style & SWT.SEPARATOR) != 0) return;
hotImage = image;
if ((parent.style & SWT.FLAT) != 0) redraw ();
}
public void setImage (Image image) {
checkWidget();
if (image != null && image.isDisposed()) error(SWT.ERROR_INVALID_ARGUMENT);
if ((style & SWT.SEPARATOR) != 0) return;
super.setImage (image);
Point size = computeSize ();
setSize (size.x, size.y);
redraw ();
}
/**
* Sets the selection state of the receiver.
* <p>
* When the receiver is of type <code>CHECK</code> or <code>RADIO</code>,
* it is selected when it is checked. When it is of type <code>TOGGLE</code>,
* it is selected when it is pushed.
* </p>
*
* @param selected the new selection state
*
* @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 void setSelection (boolean selected) {
checkWidget();
if ((style & (SWT.CHECK | SWT.RADIO)) == 0) return;
if (selected == set) return;
set = selected;
setDrawPressed (set);
}
void setSize (int width, int height) {
int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
if (argList [1] != width || argList [3] != height) {
OS.XtResizeWidget (handle, width, height, 0);
parent.relayout ();
}
}
public void setText (String string) {
checkWidget();
if (string == null) error (SWT.ERROR_NULL_ARGUMENT);
if ((style & SWT.SEPARATOR) != 0) return;
super.setText (string);
Point size = computeSize ();
setSize (size.x, size.y);
redraw ();
}
/**
* Sets the receiver's tool tip text to the argument, which
* may be null indicating that no tool tip text should be shown.
*
* @param string the new tool tip text (or null)
*
* @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 void setToolTipText (String string) {
checkWidget();
toolTipText = string;
}
/**
* Sets the width of the receiver.
*
* @param width the new width
*
* @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 void setWidth (int width) {
checkWidget();
if ((style & SWT.SEPARATOR) == 0) return;
if (width < 0) return;
int [] argList = {OS.XmNheight, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
setSize (width, argList [1]);
if (control != null && !control.isDisposed ()) {
control.setBounds (getBounds ());
}
}
void setDrawPressed (boolean value) {
int shadowType = value ? OS.XmSHADOW_IN : OS.XmSHADOW_OUT;
int [] argList = {OS.XmNshadowType, shadowType};
OS.XtSetValues(handle, argList, argList.length / 2);
}
int processKeyDown (int callData) {
XKeyEvent xEvent = new XKeyEvent ();
OS.memmove (xEvent, callData, XKeyEvent.sizeof);
/*
* Forward the key event to the parent.
* This is necessary so that mouse listeners
* in the parent will be called, despite the
* fact that the event did not really occur
* in X in the parent. This is done to be
* compatible with Windows.
*/
xEvent.window = OS.XtWindow (parent.handle);
// OS.memmove (callData, xEvent, XKeyEvent.sizeof);
parent.processKeyDown (callData);
return 0;
}
int processKeyUp (int callData) {
XKeyEvent xEvent = new XKeyEvent ();
OS.memmove (xEvent, callData, XKeyEvent.sizeof);
int [] keysym = new int [1];
OS.XLookupString (xEvent, null, 0, keysym, null);
keysym [0] &= 0xFFFF;
switch (keysym [0]) {
case OS.XK_space:
case OS.XK_Return:
click (keysym [0] == OS.XK_Return, xEvent);
break;
}
/*
* Forward the key event to the parent.
* This is necessary so that mouse listeners
* in the parent will be called, despite the
* fact that the event did not really occur
* in X in the parent. This is done to be
* compatible with Windows.
*/
xEvent.window = OS.XtWindow (parent.handle);
// OS.memmove (callData, xEvent, XKeyEvent.sizeof);
parent.processKeyUp (callData);
return 0;
}
int processMouseDown (int callData) {
Display display = getDisplay ();
// Shell shell = parent.getShell ();
display.hideToolTip ();
XButtonEvent xEvent = new XButtonEvent ();
OS.memmove (xEvent, callData, XButtonEvent.sizeof);
if (xEvent.button == 1) {
if (!set && (style & SWT.RADIO) == 0) {
setDrawPressed (!set);
}
}
/*
* Forward the mouse event to the parent.
* This is necessary so that mouse listeners
* in the parent will be called, despite the
* fact that the event did not really occur
* in X in the parent. This is done to be
* compatible with Windows.
*/
int [] argList = {OS.XmNx, 0, OS.XmNy, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
xEvent.window = OS.XtWindow (parent.handle);
xEvent.x += argList [1]; xEvent.y += argList [3];
OS.memmove (callData, xEvent, XButtonEvent.sizeof);
parent.processMouseDown (callData);
/*
* It is possible that the shell may be
* disposed at this point. If this happens
* don't send the activate and deactivate
* events.
*/
// if (!shell.isDisposed()) {
// shell.setActiveControl (parent);
// }
return 0;
}
int processMouseEnter (int callData) {
XCrossingEvent xEvent = new XCrossingEvent ();
OS.memmove (xEvent, callData, XCrossingEvent.sizeof);
if ((xEvent.state & OS.Button1Mask) != 0) setDrawPressed (!set);
else if ((parent.style & SWT.FLAT) != 0) redraw ();
return 0;
}
int processMouseExit (int callData) {
Display display = getDisplay ();
display.removeMouseHoverTimeOut ();
display.hideToolTip ();
XCrossingEvent xEvent = new XCrossingEvent ();
OS.memmove (xEvent, callData, XCrossingEvent.sizeof);
if ((xEvent.state & OS.Button1Mask) != 0) setDrawPressed (set);
else if ((parent.style & SWT.FLAT) != 0) redraw ();
return 0;
}
Point toControl (Point point) {
short [] root_x = new short [1], root_y = new short [1];
OS.XtTranslateCoords (handle, (short) 0, (short) 0, root_x, root_y);
return new Point (point.x - root_x [0], point.y - root_y [0]);
}
boolean translateMnemonic (int key, XKeyEvent xEvent) {
return parent.translateMnemonic (key, xEvent);
}
boolean translateTraversal (int key, XKeyEvent xEvent) {
return parent.translateTraversal (key, xEvent);
}
int processMouseHover (int id) {
Display display = getDisplay ();
Point local = toControl (display.getCursorLocation ());
display.showToolTip (handle, toolTipText);
return 0;
}
int processMouseMove (int callData) {
Display display = getDisplay ();
display.addMouseHoverTimeOut (handle);
/*
* Forward the mouse event to the parent.
* This is necessary so that mouse listeners
* in the parent will be called, despite the
* fact that the event did not really occur
* in X in the parent. This is done to be
* compatible with Windows.
*/
XButtonEvent xEvent = new XButtonEvent ();
OS.memmove (xEvent, callData, XButtonEvent.sizeof);
int [] argList = {OS.XmNx, 0, OS.XmNy, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
xEvent.window = OS.XtWindow (parent.handle);
xEvent.x += argList [1]; xEvent.y += argList [3];
/*
* This code is intentionally commented.
* Currently, the implementation of the
* mouse move code in the parent interferes
* with tool tips for tool items.
*/
// OS.memmove (callData, xEvent, XButtonEvent.sizeof);
// parent.processMouseMove (callData);
parent.sendMouseEvent (SWT.MouseMove, 0, xEvent);
return 0;
}
int processMouseUp (int callData) {
Display display = getDisplay ();
display.hideToolTip();
XButtonEvent xEvent = new XButtonEvent ();
OS.memmove (xEvent, callData, XButtonEvent.sizeof);
if (xEvent.button == 1) {
int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
int width = argList [1], height = argList [3];
if (0 <= xEvent.x && xEvent.x < width && 0 <= xEvent.y && xEvent.y < height) {
click (xEvent.x > width - 12, xEvent);
}
setDrawPressed(set);
}
/*
* Forward the mouse event to the parent.
* This is necessary so that mouse listeners
* in the parent will be called, despite the
* fact that the event did not really occur
* in X in the parent. This is done to be
* compatible with Windows.
*/
int [] argList = {OS.XmNx, 0, OS.XmNy, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
xEvent.window = OS.XtWindow (parent.handle);
xEvent.x += argList [1]; xEvent.y += argList [3];
OS.memmove (callData, xEvent, XButtonEvent.sizeof);
parent.processMouseUp (callData);
return 0;
}
int processPaint (int callData) {
if ((style & SWT.SEPARATOR) != 0) return 0;
int xDisplay = OS.XtDisplay (handle);
if (xDisplay == 0) return 0;
int xWindow = OS.XtWindow (handle);
if (xWindow == 0) return 0;
int [] argList = {
OS.XmNcolormap, 0,
OS.XmNwidth, 0,
OS.XmNheight, 0,
};
OS.XtGetValues (handle, argList, argList.length / 2);
int width = argList [3], height = argList [5];
Image currentImage = image;
boolean enabled = getEnabled();
if ((parent.style & SWT.FLAT) != 0) {
Display display = getDisplay ();
boolean hasCursor = hasCursor ();
/* Set the shadow thickness */
int thickness = 0;
if (set || (hasCursor && enabled)) {
thickness = Math.min (2, display.buttonShadowThickness);
}
argList = new int [] {OS.XmNshadowThickness, thickness};
OS.XtSetValues (handle, argList, argList.length / 2);
/* Determine if hot image should be used */
if (enabled && hasCursor && hotImage != null) {
currentImage = hotImage;
}
}
ToolDrawable wrapper = new ToolDrawable ();
wrapper.device = getDisplay ();
wrapper.display = xDisplay;
wrapper.drawable = xWindow;
wrapper.fontList = parent.fontList;
wrapper.colormap = argList [1];
GC gc = new GC (wrapper);
XmAnyCallbackStruct cb = new XmAnyCallbackStruct ();
OS.memmove (cb, callData, XmAnyCallbackStruct.sizeof);
if (cb.event != 0) {
XExposeEvent xEvent = new XExposeEvent ();
OS.memmove (xEvent, cb.event, XExposeEvent.sizeof);
Rectangle rect = new Rectangle (xEvent.x, xEvent.y, xEvent.width, xEvent.height);
gc.setClipping (rect);
}
if (!enabled) {
Display display = getDisplay ();
currentImage = disabledImage;
if (currentImage == null) {
currentImage = new Image (display, image, SWT.IMAGE_DISABLE);
}
Color disabledColor = display.getSystemColor (SWT.COLOR_WIDGET_NORMAL_SHADOW);
gc.setForeground (disabledColor);
} else {
gc.setForeground (parent.getForeground ());
}
gc.setBackground (parent.getBackground ());
int textX = 0, textY = 0, textWidth = 0, textHeight = 0;
if (text.length () != 0) {
int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_MNEMONIC;
Point textExtent = gc.textExtent (text, flags);
textWidth = textExtent.x;
textHeight = textExtent.y;
}
int imageX = 0, imageY = 0, imageWidth = 0, imageHeight = 0;
if (currentImage != null) {
Rectangle imageBounds = currentImage.getBounds ();
imageWidth = imageBounds.width;
imageHeight = imageBounds.height;
}
int spacing = 0;
if (textWidth != 0 && imageWidth != 0) spacing = 2;
if ((parent.style & SWT.RIGHT) != 0) {
imageX = (width - imageWidth - textWidth - spacing) / 2;
imageY = (height - imageHeight) / 2;
textX = spacing + imageX + imageWidth;
textY = (height - textHeight) / 2;
} else {
imageX = (width - imageWidth) / 2;
imageY = (height - imageHeight - textHeight - spacing) / 2;
textX = (width - textWidth) / 2;
textY = spacing + imageY + imageHeight;
}
if ((style & SWT.DROP_DOWN) != 0) {
textX -= 6; imageX -=6;
}
if (textWidth > 0) {
int flags = SWT.DRAW_DELIMITER | SWT.DRAW_TAB | SWT.DRAW_MNEMONIC;
gc.drawText(text, textX, textY, flags);
}
if (imageWidth > 0) gc.drawImage(currentImage, imageX, imageY);
if ((style & SWT.DROP_DOWN) != 0) {
int startX = width - 12, startY = (height - 2) / 2;
int [] arrow = {startX, startY, startX + 3, startY + 3, startX + 6, startY};
gc.setBackground (parent.getForeground ());
gc.fillPolygon (arrow);
gc.drawPolygon (arrow);
}
gc.dispose ();
if (!enabled && disabledImage == null) {
if (currentImage != null) currentImage.dispose ();
}
return 0;
}
void propagateWidget (boolean enabled) {
propagateHandle (enabled, handle);
/*
* Tool items participate in focus traversal only when
* the tool bar takes focus.
*/
if ((parent.style & SWT.NO_FOCUS) != 0) {
if (enabled) {
int [] argList = {OS.XmNtraversalOn, 0};
OS.XtSetValues (handle, argList, argList.length / 2);
}
}
}
}