Mercurial > projects > dwt-mac
diff dwt/widgets/CoolItem.d @ 0:380af2bdd8e5
Upload of whole dwt tree
author | Jacob Carlborg <doob@me.com> <jacob.carlborg@gmail.com> |
---|---|
date | Sat, 09 Aug 2008 17:00:02 +0200 |
parents | |
children | 649b8e223d5a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dwt/widgets/CoolItem.d Sat Aug 09 17:00:02 2008 +0200 @@ -0,0 +1,661 @@ +/******************************************************************************* + * Copyright (c) 2000, 2007 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +module dwt.widgets.CoolItem; + +import dwt.dwthelper.utils; + + +import dwt.DWT; +import dwt.DWTException; +import dwt.events.SelectionEvent; +import dwt.events.SelectionListener; +import dwt.graphics.Color; +import dwt.graphics.GC; +import dwt.graphics.Image; +import dwt.graphics.ImageData; +import dwt.graphics.PaletteData; +import dwt.graphics.Point; +import dwt.graphics.RGB; +import dwt.graphics.Rectangle; + +/** + * Instances of this class are selectable user interface + * objects that represent the dynamically positionable + * areas of a <code>CoolBar</code>. + * <dl> + * <dt><b>Styles:</b></dt> + * <dd>DROP_DOWN</dd> + * <dt><b>Events:</b></dt> + * <dd>Selection</dd> + * </dl> + * <p> + * IMPORTANT: This class is <em>not</em> intended to be subclassed. + * </p> + */ +public class CoolItem extends Item { + Control control; + CoolBar parent; + bool ideal; + int preferredWidth, preferredHeight, minimumWidth, minimumHeight, requestedWidth; + Rectangle itemBounds = new Rectangle(0, 0, 0, 0); + + static final int MARGIN_WIDTH = 4; + static final int GRABBER_WIDTH = 2; + static final int MINIMUM_WIDTH = (2 * MARGIN_WIDTH) + GRABBER_WIDTH; + + private int CHEVRON_HORIZONTAL_TRIM = -1; //platform dependent values + private int CHEVRON_VERTICAL_TRIM = -1; + private static final int CHEVRON_LEFT_MARGIN = 2; + private static final int CHEVRON_IMAGE_WIDTH = 8; //Width to draw the double arrow + + ToolBar chevron; + bool wrap; + Image arrowImage = null; + +/** + * Constructs a new instance of this class given its parent + * (which must be a <code>CoolBar</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>DWT</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>DWT</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 DWTException <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 DWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public CoolItem (CoolBar parent, int style) { + super(parent, style); + this.parent = parent; + parent.createItem (this, parent.getItemCount()); + calculateChevronTrim (); +} +/** + * Constructs a new instance of this class given its parent + * (which must be a <code>CoolBar</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>DWT</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>DWT</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 + * @param index the zero-relative index at which to store the receiver in its parent + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the parent is null</li> + * <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li> + * </ul> + * @exception DWTException <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 DWT#DROP_DOWN + * @see Widget#checkSubclass + * @see Widget#getStyle + */ +public CoolItem (CoolBar parent, int style, int index) { + super(parent, style); + this.parent = parent; + parent.createItem (this, index); + calculateChevronTrim (); +} +/** + * Adds the listener to the collection of listeners that will + * be notified when the control is selected by the user, by sending it one + * of the messages defined in the <code>SelectionListener</code> + * interface. + * <p> + * If <code>widgetSelected</code> is called when the mouse is over + * the drop-down arrow (or 'chevron') portion of the cool item, + * the event object detail field contains the value <code>DWT.ARROW</code>, + * and the x and y fields in the event object represent the point at + * the bottom left of the chevron, where the menu should be popped up. + * <code>widgetDefaultSelected</code> is not called. + * </p> + * + * @param listener the listener which should be notified when the control is selected by the user + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <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 + * + * @since 2.0 + */ +public void addSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + TypedListener typedListener = new TypedListener (listener); + addListener (DWT.Selection,typedListener); + addListener (DWT.DefaultSelection,typedListener); +} +protected void checkSubclass () { + if (!isValidSubclass ()) error (DWT.ERROR_INVALID_SUBCLASS); +} +/* + * Find the trim size of the Toolbar widget in the current platform. + */ +void calculateChevronTrim () { + ToolBar tb = new ToolBar (parent, DWT.FLAT); + ToolItem ti = new ToolItem (tb, DWT.PUSH); + Image image = new Image (display, 1, 1); + ti.setImage (image); + Point size = tb.computeSize (DWT.DEFAULT, DWT.DEFAULT); + size = parent.fixPoint(size.x, size.y); + CHEVRON_HORIZONTAL_TRIM = size.x - 1; + CHEVRON_VERTICAL_TRIM = size.y - 1; + tb.dispose (); + ti.dispose (); + image.dispose (); +} +/** + * Returns the preferred size of the receiver. + * <p> + * The <em>preferred size</em> of a <code>CoolItem</code> is the size that + * it would best be displayed at. The width hint and height hint arguments + * allow the caller to ask the instance questions such as "Given a particular + * width, how high does it need to be to show all of the contents?" + * To indicate that the caller does not wish to constrain a particular + * dimension, the constant <code>DWT.DEFAULT</code> is passed for the hint. + * </p> + * + * @param wHint the width hint (can be <code>DWT.DEFAULT</code>) + * @param hHint the height hint (can be <code>DWT.DEFAULT</code>) + * @return the preferred size + * + * @exception DWTException <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 Layout + * @see #getBounds + * @see #getSize + * @see Control#getBorderWidth + * @see Scrollable#computeTrim + * @see Scrollable#getClientArea + */ +public Point computeSize (int wHint, int hHint) { + checkWidget(); + int width = wHint, height = hHint; + if (wHint is DWT.DEFAULT) width = 32; + if (hHint is DWT.DEFAULT) height = 32; + if ((parent.style & DWT.VERTICAL) !is 0) { + height += MINIMUM_WIDTH; + } else { + width += MINIMUM_WIDTH; + } + return new Point (width, height); +} +public void dispose () { + if (isDisposed()) return; + + /* + * Must call parent.destroyItem() before super.dispose(), since it needs to + * query the bounds to properly remove the item. + */ + parent.destroyItem(this); + super.dispose (); + parent = null; + control = null; + + /* + * Although the parent for the chevron is the CoolBar (CoolItem can not be the parent) + * it has to be disposed with the item + */ + if (chevron !is null && !chevron.isDisposed()) chevron.dispose(); + chevron = null; + if (arrowImage !is null && !arrowImage.isDisposed()) arrowImage.dispose(); + arrowImage = null; +} + +Image createArrowImage (int width, int height) { + Point point = parent.fixPoint(width, height); + width = point.x; + height = point.y; + Color foreground = parent.getForeground (); + Color black = display.getSystemColor (DWT.COLOR_BLACK); + Color background = parent.getBackground (); + + PaletteData palette = new PaletteData (new RGB[]{foreground.getRGB(), background.getRGB(), black.getRGB()}); + ImageData imageData = new ImageData (width, height, 4, palette); + imageData.transparentPixel = 1; + Image image = new Image (display, imageData); + + GC gc = new GC (image, parent.getStyle() & DWT.RIGHT_TO_LEFT); + gc.setBackground (background); + gc.fillRectangle (0, 0, width, height); + gc.setForeground (black); + + int startX = 0 ; + if ((parent.style & DWT.VERTICAL) !is 0) { + startX = width - CHEVRON_IMAGE_WIDTH; + } + int startY = height / 6; + int step = 2; + gc.drawLine (startX, startY, startX + step, startY + step); + gc.drawLine (startX, startY + (2 * step), startX + step, startY + step); + startX++; + gc.drawLine (startX, startY, startX + step, startY + step); + gc.drawLine (startX, startY + (2 * step), startX + step, startY + step); + startX += 3; + gc.drawLine (startX, startY, startX + step, startY + step); + gc.drawLine (startX, startY + (2 * step), startX + step, startY + step); + startX++; + gc.drawLine (startX, startY, startX + step, startY + step); + gc.drawLine (startX, startY + (2 * step), startX + step, startY + step); + gc.dispose (); + return image; +} +/** + * Returns a rectangle describing the receiver's size and location + * relative to its parent. + * + * @return the receiver's bounding rectangle + * + * @exception DWTException <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(); + return parent.fixRectangle(itemBounds.x, itemBounds.y, itemBounds.width, itemBounds.height); +} +Rectangle internalGetBounds () { + return new Rectangle(itemBounds.x, itemBounds.y, itemBounds.width, itemBounds.height); +} +/** + * Returns the control that is associated with the receiver. + * + * @return the control that is contained by the receiver + * + * @exception DWTException <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 minimum size that the cool item can + * be resized to using the cool item's gripper. + * + * @return a point containing the minimum width and height of the cool item, in pixels + * + * @exception DWTException <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> + * + * @since 2.0 + */ +public Point getMinimumSize () { + checkWidget(); + return parent.fixPoint(minimumWidth, minimumHeight); +} +/** + * Returns the receiver's parent, which must be a <code>CoolBar</code>. + * + * @return the receiver's parent + * + * @exception DWTException <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 CoolBar getParent () { + checkWidget(); + return parent; +} +/** + * Returns a point describing the receiver's ideal size. + * The x coordinate of the result is the ideal width of the receiver. + * The y coordinate of the result is the ideal height of the receiver. + * + * @return the receiver's ideal size + * + * @exception DWTException <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 Point getPreferredSize () { + checkWidget(); + return parent.fixPoint(preferredWidth, preferredHeight); +} +/** + * Returns a point describing the receiver's size. The + * x coordinate of the result is the width of the receiver. + * The y coordinate of the result is the height of the + * receiver. + * + * @return the receiver's size + * + * @exception DWTException <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 Point getSize () { + checkWidget(); + return parent.fixPoint(itemBounds.width, itemBounds.height); +} +int internalGetMinimumWidth () { + int width = minimumWidth + MINIMUM_WIDTH; + if ((style & DWT.DROP_DOWN) !is 0 && width < preferredWidth) { + width += CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN; + } + return width; +} +/* + * Called when the chevron is selected. + */ +void onSelection (Event ev) { + Rectangle bounds = chevron.getBounds(); + Event event = new Event(); + event.detail = DWT.ARROW; + if ((parent.style & DWT.VERTICAL) !is 0) { + event.x = bounds.x + bounds.width; + event.y = bounds.y; + } else { + event.x = bounds.x; + event.y = bounds.y + bounds.height; + } + postEvent (DWT.Selection, event); +} +/** + * Removes the listener from the collection of listeners that + * will be notified when the control is selected by the user. + * + * @param listener the listener which should no longer be notified + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the listener is null</li> + * </ul> + * @exception DWTException <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 + * + * @since 2.0 + */ +public void removeSelectionListener(SelectionListener listener) { + checkWidget(); + if (listener is null) error (DWT.ERROR_NULL_ARGUMENT); + if (eventTable is null) return; + eventTable.unhook (DWT.Selection, listener); + eventTable.unhook (DWT.DefaultSelection,listener); +} +void setBounds (int x, int y, int width, int height) { + itemBounds.x = x; + itemBounds.y = y; + itemBounds.width = width; + itemBounds.height = height; + if (control !is null) { + int controlWidth = width - MINIMUM_WIDTH; + if ((style & DWT.DROP_DOWN) !is 0 && width < preferredWidth) { + controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN; + } + control.setBounds (parent.fixRectangle(x + MINIMUM_WIDTH, y, controlWidth, height)); + } + updateChevron(); +} +/** + * Sets the control that is associated with the receiver + * to the argument. + * + * @param control the new control that will be contained by the receiver + * + * @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 DWTException <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 !is null) { + if (control.isDisposed()) error (DWT.ERROR_INVALID_ARGUMENT); + if (control.parent !is parent) error (DWT.ERROR_INVALID_PARENT); + } + this.control = control; + if (control !is null) { + int controlWidth = itemBounds.width - MINIMUM_WIDTH; + if ((style & DWT.DROP_DOWN) !is 0 && itemBounds.width < preferredWidth) { + controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN; + } + control.setBounds (parent.fixRectangle(itemBounds.x + MINIMUM_WIDTH, itemBounds.y, controlWidth, itemBounds.height)); + } +} +/** + * Sets the minimum size that the cool item can be resized to + * using the cool item's gripper, to the point specified by the arguments. + * + * @param width the minimum width of the cool item, in pixels + * @param height the minimum height of the cool item, in pixels + * + * @exception DWTException <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> + * + * @since 2.0 + */ +public void setMinimumSize (int width, int height) { + checkWidget (); + Point point = parent.fixPoint(width, height); + minimumWidth = point.x; + minimumHeight = point.y; +} +/** + * Sets the minimum size that the cool item can be resized to + * using the cool item's gripper, to the point specified by the argument. + * + * @param size a point representing the minimum width and height of the cool item, in pixels + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception DWTException <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> + * + * @since 2.0 + */ +public void setMinimumSize (Point size) { + checkWidget (); + if (size is null) error(DWT.ERROR_NULL_ARGUMENT); + setMinimumSize(size.x, size.y); +} +/** + * Sets the receiver's ideal size to the point specified by the arguments. + * + * @param width the new ideal width for the receiver + * @param height the new ideal height for the receiver + * + * @exception DWTException <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 setPreferredSize (int width, int height) { + checkWidget(); + ideal = true; + Point point = parent.fixPoint(width, height); + preferredWidth = Math.max (point.x, MINIMUM_WIDTH); + preferredHeight = point.y; +} +/** + * Sets the receiver's ideal size to the point specified by the argument. + * + * @param size the new ideal size for the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception DWTException <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 setPreferredSize (Point size) { + checkWidget(); + if (size is null) error(DWT.ERROR_NULL_ARGUMENT); + setPreferredSize(size.x, size.y); +} +/** + * Sets the receiver's size to the point specified by the arguments. + * <p> + * Note: Attempting to set the width or height of the + * receiver to a negative number will cause that + * value to be set to zero instead. + * </p> + * + * @param width the new width for the receiver + * @param height the new height for the receiver + * + * @exception DWTException <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 setSize (int width, int height) { + checkWidget(); + Point point = parent.fixPoint(width, height); + width = Math.max(point.x, minimumWidth + MINIMUM_WIDTH); + height = point.y; + if (!ideal) { + preferredWidth = width; + preferredHeight = height; + } + itemBounds.width = requestedWidth = width; + itemBounds.height = height; + if (control !is null) { + int controlWidth = width - MINIMUM_WIDTH; + if ((style & DWT.DROP_DOWN) !is 0 && width < preferredWidth) { + controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN; + } + control.setSize(parent.fixPoint(controlWidth, height)); + } + parent.relayout(); + updateChevron(); +} +/** + * Sets the receiver's size to the point specified by the argument. + * <p> + * Note: Attempting to set the width or height of the + * receiver to a negative number will cause them to be + * set to zero instead. + * </p> + * + * @param size the new size for the receiver + * + * @exception IllegalArgumentException <ul> + * <li>ERROR_NULL_ARGUMENT - if the point is null</li> + * </ul> + * @exception DWTException <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 setSize (Point size) { + checkWidget(); + if (size is null) error (DWT.ERROR_NULL_ARGUMENT); + setSize (size.x, size.y); +} +void updateChevron() { + if (control !is null) { + int width = itemBounds.width; + if ((style & DWT.DROP_DOWN) !is 0 && width < preferredWidth) { + if (chevron is null) { + chevron = new ToolBar (parent, DWT.FLAT | DWT.NO_FOCUS); + ToolItem toolItem = new ToolItem (chevron, DWT.PUSH); + toolItem.addListener (DWT.Selection, new Listener() { + public void handleEvent (Event event) { + CoolItem.this.onSelection (event); + } + }); + } + int controlHeight, currentImageHeight = 0; + if ((parent.style & DWT.VERTICAL) !is 0) { + controlHeight = control.getSize ().x; + if (arrowImage !is null) currentImageHeight = arrowImage.getBounds().width; + } else { + controlHeight = control.getSize ().y; + if (arrowImage !is null) currentImageHeight = arrowImage.getBounds().height; + } + int height = Math.min (controlHeight, itemBounds.height); + int imageHeight = Math.max(1, height - CHEVRON_VERTICAL_TRIM); + if (currentImageHeight !is imageHeight) { + Image image = createArrowImage (CHEVRON_IMAGE_WIDTH, imageHeight); + chevron.getItem (0).setImage (image); + if (arrowImage !is null) arrowImage.dispose (); + arrowImage = image; + } + chevron.setBackground (parent.getBackground()); + chevron.setBounds (parent.fixRectangle ( + itemBounds.x + width - CHEVRON_LEFT_MARGIN - CHEVRON_IMAGE_WIDTH - CHEVRON_HORIZONTAL_TRIM, + itemBounds.y, + CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM, + height)); + chevron.setVisible(true); + } else { + if (chevron !is null) { + chevron.setVisible(false); + } + } + } +} +}