1 /*******************************************************************************
2  * Copyright (c) 2000, 2008 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  * Port to the D programming language:
11  *     Frank Benoit <benoit@tionex.de>
12  *******************************************************************************/
13 module org.eclipse.swt.widgets.CoolItem;
14 
15 import java.lang.all;
16 import org.eclipse.swt.SWT;
17 import org.eclipse.swt.SWTException;
18 import org.eclipse.swt.events.SelectionEvent;
19 import org.eclipse.swt.events.SelectionListener;
20 import org.eclipse.swt.graphics.Color;
21 import org.eclipse.swt.graphics.GC;
22 import org.eclipse.swt.graphics.Image;
23 import org.eclipse.swt.graphics.ImageData;
24 import org.eclipse.swt.graphics.PaletteData;
25 import org.eclipse.swt.graphics.Point;
26 import org.eclipse.swt.graphics.RGB;
27 import org.eclipse.swt.graphics.Rectangle;
28 import org.eclipse.swt.widgets.Item;
29 import org.eclipse.swt.widgets.Control;
30 import org.eclipse.swt.widgets.CoolBar;
31 import org.eclipse.swt.widgets.ToolBar;
32 import org.eclipse.swt.widgets.Event;
33 import org.eclipse.swt.widgets.TypedListener;
34 import org.eclipse.swt.widgets.ToolBar;
35 import org.eclipse.swt.widgets.ToolItem;
36 import org.eclipse.swt.widgets.Listener;
37 
38 /**
39  * Instances of this class are selectable user interface
40  * objects that represent the dynamically positionable
41  * areas of a <code>CoolBar</code>.
42  * <dl>
43  * <dt><b>Styles:</b></dt>
44  * <dd>DROP_DOWN</dd>
45  * <dt><b>Events:</b></dt>
46  * <dd>Selection</dd>
47  * </dl>
48  * <p>
49  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
50  * </p>
51  * 
52  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
53  */
54 public class CoolItem : Item {
55     Control control;
56     CoolBar parent;
57     bool ideal;
58     int preferredWidth, preferredHeight, minimumWidth, minimumHeight, requestedWidth;
59     Rectangle itemBounds;
60 
61     static const int MARGIN_WIDTH = 4;
62     static const int GRABBER_WIDTH = 2;
63     static const int MINIMUM_WIDTH = (2 * MARGIN_WIDTH) + GRABBER_WIDTH;
64 
65     private int CHEVRON_HORIZONTAL_TRIM = -1;           //platform dependent values
66     private int CHEVRON_VERTICAL_TRIM = -1;
67     private static const int CHEVRON_LEFT_MARGIN = 2;
68     private static const int CHEVRON_IMAGE_WIDTH = 8;   //Width to draw the double arrow
69 
70     ToolBar chevron;
71     bool wrap;
72     Image arrowImage = null;
73 
74 /**
75  * Constructs a new instance of this class given its parent
76  * (which must be a <code>CoolBar</code>) and a style value
77  * describing its behavior and appearance. The item is added
78  * to the end of the items maintained by its parent.
79  * <p>
80  * The style value is either one of the style constants defined in
81  * class <code>SWT</code> which is applicable to instances of this
82  * class, or must be built by <em>bitwise OR</em>'ing together
83  * (that is, using the <code>int</code> "|" operator) two or more
84  * of those <code>SWT</code> style constants. The class description
85  * lists the style constants that are applicable to the class.
86  * Style bits are also inherited from superclasses.
87  * </p>
88  *
89  * @param parent a composite control which will be the parent of the new instance (cannot be null)
90  * @param style the style of control to construct
91  *
92  * @exception IllegalArgumentException <ul>
93  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
94  * </ul>
95  * @exception SWTException <ul>
96  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
97  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
98  * </ul>
99  *
100  * @see SWT#DROP_DOWN
101  * @see Widget#checkSubclass
102  * @see Widget#getStyle
103  */
104 public this (CoolBar parent, int style) {
105     super(parent, style);
106     itemBounds = new Rectangle(0, 0, 0, 0);
107     this.parent = parent;
108     parent.createItem (this, parent.getItemCount());
109     calculateChevronTrim ();
110 }
111 /**
112  * Constructs a new instance of this class given its parent
113  * (which must be a <code>CoolBar</code>), a style value
114  * describing its behavior and appearance, and the index
115  * at which to place it in the items maintained by its parent.
116  * <p>
117  * The style value is either one of the style constants defined in
118  * class <code>SWT</code> which is applicable to instances of this
119  * class, or must be built by <em>bitwise OR</em>'ing together
120  * (that is, using the <code>int</code> "|" operator) two or more
121  * of those <code>SWT</code> style constants. The class description
122  * lists the style constants that are applicable to the class.
123  * Style bits are also inherited from superclasses.
124  * </p>
125  *
126  * @param parent a composite control which will be the parent of the new instance (cannot be null)
127  * @param style the style of control to construct
128  * @param index the zero-relative index at which to store the receiver in its parent
129  *
130  * @exception IllegalArgumentException <ul>
131  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
132  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
133  * </ul>
134  * @exception SWTException <ul>
135  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
136  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
137  * </ul>
138  *
139  * @see SWT#DROP_DOWN
140  * @see Widget#checkSubclass
141  * @see Widget#getStyle
142  */
143 public this (CoolBar parent, int style, int index) {
144     super(parent, style);
145     itemBounds = new Rectangle(0, 0, 0, 0);
146     this.parent = parent;
147     parent.createItem (this, index);
148     calculateChevronTrim ();
149 }
150 /**
151  * Adds the listener to the collection of listeners that will
152  * be notified when the control is selected by the user, by sending it one
153  * of the messages defined in the <code>SelectionListener</code>
154  * interface.
155  * <p>
156  * If <code>widgetSelected</code> is called when the mouse is over
157  * the drop-down arrow (or 'chevron') portion of the cool item,
158  * the event object detail field contains the value <code>SWT.ARROW</code>,
159  * and the x and y fields in the event object represent the point at
160  * the bottom left of the chevron, where the menu should be popped up.
161  * <code>widgetDefaultSelected</code> is not called.
162  * </p>
163  *
164  * @param listener the listener which should be notified when the control is selected by the user
165  *
166  * @exception IllegalArgumentException <ul>
167  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
168  * </ul>
169  * @exception SWTException <ul>
170  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
171  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
172  * </ul>
173  *
174  * @see SelectionListener
175  * @see #removeSelectionListener
176  * @see SelectionEvent
177  *
178  * @since 2.0
179  */
180 public void addSelectionListener(SelectionListener listener) {
181     checkWidget();
182     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
183     TypedListener typedListener = new TypedListener (listener);
184     addListener (SWT.Selection,typedListener);
185     addListener (SWT.DefaultSelection,typedListener);
186 }
187 protected override void checkSubclass () {
188     if (!isValidSubclass ()) error (SWT.ERROR_INVALID_SUBCLASS);
189 }
190 /*
191  * Find the trim size of the Toolbar widget in the current platform.
192  */
193 void calculateChevronTrim () {
194     ToolBar tb = new ToolBar (parent, SWT.FLAT);
195     ToolItem ti = new ToolItem (tb, SWT.PUSH);
196     Image image = new Image (display, 1, 1);
197     ti.setImage (image);
198     Point size = tb.computeSize (SWT.DEFAULT, SWT.DEFAULT);
199     size = parent.fixPoint(size.x, size.y);
200     CHEVRON_HORIZONTAL_TRIM = size.x - 1;
201     CHEVRON_VERTICAL_TRIM = size.y - 1;
202     tb.dispose ();
203     ti.dispose ();
204     image.dispose ();
205 }
206 /**
207  * Returns the preferred size of the receiver.
208  * <p>
209  * The <em>preferred size</em> of a <code>CoolItem</code> is the size that
210  * it would best be displayed at. The width hint and height hint arguments
211  * allow the caller to ask the instance questions such as "Given a particular
212  * width, how high does it need to be to show all of the contents?"
213  * To indicate that the caller does not wish to constrain a particular
214  * dimension, the constant <code>SWT.DEFAULT</code> is passed for the hint.
215  * </p>
216  *
217  * @param wHint the width hint (can be <code>SWT.DEFAULT</code>)
218  * @param hHint the height hint (can be <code>SWT.DEFAULT</code>)
219  * @return the preferred size
220  *
221  * @exception SWTException <ul>
222  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
223  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
224  * </ul>
225  *
226  * @see Layout
227  * @see #getBounds
228  * @see #getSize
229  * @see Control#getBorderWidth
230  * @see Scrollable#computeTrim
231  * @see Scrollable#getClientArea
232  */
233 public Point computeSize (int wHint, int hHint) {
234     checkWidget();
235     int width = wHint, height = hHint;
236     if (wHint is SWT.DEFAULT) width = 32;
237     if (hHint is SWT.DEFAULT) height = 32;
238     if ((parent.style & SWT.VERTICAL) !is 0) {
239         height += MINIMUM_WIDTH;
240     } else {
241         width += MINIMUM_WIDTH;
242     }
243     return new Point (width, height);
244 }
245 public override void dispose () {
246     if (isDisposed()) return;
247 
248     /*
249      * Must call parent.destroyItem() before super.dispose(), since it needs to
250      * query the bounds to properly remove the item.
251      */
252     parent.destroyItem(this);
253     super.dispose ();
254     parent = null;
255     control = null;
256 
257     /*
258      * Although the parent for the chevron is the CoolBar (CoolItem can not be the parent)
259      * it has to be disposed with the item
260      */
261     if (chevron !is null && !chevron.isDisposed()) chevron.dispose();
262     chevron = null;
263     if (arrowImage !is null && !arrowImage.isDisposed()) arrowImage.dispose();
264     arrowImage = null;
265 }
266 
267 Image createArrowImage (int width, int height) {
268     Point point = parent.fixPoint(width, height);
269     width = point.x;
270     height = point.y;
271     Color foreground = parent.getForeground ();
272     Color black = display.getSystemColor (SWT.COLOR_BLACK);
273     Color background = parent.getBackground ();
274 
275     PaletteData palette = new PaletteData ( [foreground.getRGB(), background.getRGB(), black.getRGB() ] );
276     ImageData imageData = new ImageData (width, height, 4, palette);
277     imageData.transparentPixel = 1;
278     Image image = new Image (display, imageData);
279 
280     GC gc = new GC (image, parent.getStyle() & SWT.RIGHT_TO_LEFT);
281     gc.setBackground (background);
282     gc.fillRectangle (0, 0, width, height);
283     gc.setForeground (black);
284 
285     int startX = 0 ;
286     if ((parent.style & SWT.VERTICAL) !is 0) {
287         startX = width - CHEVRON_IMAGE_WIDTH;
288     }
289     int startY = height / 6;
290     int step = 2;
291     gc.drawLine (startX, startY, startX + step, startY + step);
292     gc.drawLine (startX, startY + (2 * step), startX + step, startY + step);
293     startX++;
294     gc.drawLine (startX, startY, startX + step, startY + step);
295     gc.drawLine (startX, startY + (2 * step), startX + step, startY + step);
296     startX += 3;
297     gc.drawLine (startX, startY, startX + step, startY + step);
298     gc.drawLine (startX, startY + (2 * step), startX + step, startY + step);
299     startX++;
300     gc.drawLine (startX, startY, startX + step, startY + step);
301     gc.drawLine (startX, startY + (2 * step), startX + step, startY + step);
302     gc.dispose ();
303     return image;
304 }
305 /**
306  * Returns a rectangle describing the receiver's size and location
307  * relative to its parent.
308  *
309  * @return the receiver's bounding rectangle
310  *
311  * @exception SWTException <ul>
312  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
313  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
314  * </ul>
315  */
316 public Rectangle getBounds () {
317     checkWidget();
318     return parent.fixRectangle(itemBounds.x, itemBounds.y, itemBounds.width, itemBounds.height);
319 }
320 Rectangle internalGetBounds () {
321     return new Rectangle(itemBounds.x, itemBounds.y, itemBounds.width, itemBounds.height);
322 }
323 /**
324  * Returns the control that is associated with the receiver.
325  *
326  * @return the control that is contained by the receiver
327  *
328  * @exception SWTException <ul>
329  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
330  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
331  * </ul>
332  */
333 public Control getControl () {
334     checkWidget();
335     return control;
336 }
337 /**
338  * Returns the minimum size that the cool item can
339  * be resized to using the cool item's gripper.
340  *
341  * @return a point containing the minimum width and height of the cool item, in pixels
342  *
343  * @exception SWTException <ul>
344  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
345  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
346  * </ul>
347  *
348  * @since 2.0
349  */
350 public Point getMinimumSize () {
351     checkWidget();
352     return parent.fixPoint(minimumWidth, minimumHeight);
353 }
354 /**
355  * Returns the receiver's parent, which must be a <code>CoolBar</code>.
356  *
357  * @return the receiver's parent
358  *
359  * @exception SWTException <ul>
360  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
361  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
362  * </ul>
363  */
364 public CoolBar getParent () {
365     checkWidget();
366     return parent;
367 }
368 /**
369  * Returns a point describing the receiver's ideal size.
370  * The x coordinate of the result is the ideal width of the receiver.
371  * The y coordinate of the result is the ideal height of the receiver.
372  *
373  * @return the receiver's ideal size
374  *
375  * @exception SWTException <ul>
376  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
377  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
378  * </ul>
379  */
380 public Point getPreferredSize () {
381     checkWidget();
382     return parent.fixPoint(preferredWidth, preferredHeight);
383 }
384 /**
385  * Returns a point describing the receiver's size. The
386  * x coordinate of the result is the width of the receiver.
387  * The y coordinate of the result is the height of the
388  * receiver.
389  *
390  * @return the receiver's size
391  *
392  * @exception SWTException <ul>
393  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
394  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
395  * </ul>
396  */
397 public Point getSize () {
398     checkWidget();
399     return parent.fixPoint(itemBounds.width, itemBounds.height);
400 }
401 int internalGetMinimumWidth () {
402     int width = minimumWidth + MINIMUM_WIDTH;
403     if ((style & SWT.DROP_DOWN) !is 0 && width < preferredWidth) {
404         width += CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN;
405     }
406     return width;
407 }
408 /*
409  *  Called when the chevron is selected.
410  */
411 void onSelection (Event ev) {
412     Rectangle bounds = chevron.getBounds();
413     Event event = new Event();
414     event.detail = SWT.ARROW;
415     if ((parent.style & SWT.VERTICAL) !is 0) {
416         event.x = bounds.x + bounds.width;
417         event.y = bounds.y;
418     } else {
419         event.x = bounds.x;
420         event.y = bounds.y + bounds.height;
421     }
422     postEvent (SWT.Selection, event);
423 }
424 /**
425  * Removes the listener from the collection of listeners that
426  * will be notified when the control is selected by the user.
427  *
428  * @param listener the listener which should no longer be notified
429  *
430  * @exception IllegalArgumentException <ul>
431  *    <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
432  * </ul>
433  * @exception SWTException <ul>
434  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
435  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
436  * </ul>
437  *
438  * @see SelectionListener
439  * @see #addSelectionListener
440  *
441  * @since 2.0
442  */
443 public void removeSelectionListener(SelectionListener listener) {
444     checkWidget();
445     if (listener is null) error (SWT.ERROR_NULL_ARGUMENT);
446     if (eventTable is null) return;
447     eventTable.unhook (SWT.Selection, listener);
448     eventTable.unhook (SWT.DefaultSelection,listener);
449 }
450 void setBounds (int x, int y, int width, int height) {
451     itemBounds.x = x;
452     itemBounds.y = y;
453     itemBounds.width = width;
454     itemBounds.height = height;
455     if (control !is null) {
456         int controlWidth = width - MINIMUM_WIDTH;
457         if ((style & SWT.DROP_DOWN) !is 0 && width < preferredWidth) {
458             controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN;
459         }
460         control.setBounds (parent.fixRectangle(x + MINIMUM_WIDTH,   y, controlWidth, height));
461     }
462     updateChevron();
463 }
464 /**
465  * Sets the control that is associated with the receiver
466  * to the argument.
467  *
468  * @param control the new control that will be contained by the receiver
469  *
470  * @exception IllegalArgumentException <ul>
471  *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
472  *    <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
473  * </ul>
474  * @exception SWTException <ul>
475  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
476  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
477  * </ul>
478  */
479 public void setControl (Control control) {
480     checkWidget();
481     if (control !is null) {
482         if (control.isDisposed()) error (SWT.ERROR_INVALID_ARGUMENT);
483         if (control.parent !is parent) error (SWT.ERROR_INVALID_PARENT);
484     }
485     this.control = control;
486     if (control !is null) {
487         int controlWidth = itemBounds.width - MINIMUM_WIDTH;
488         if ((style & SWT.DROP_DOWN) !is 0 && itemBounds.width < preferredWidth) {
489             controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN;
490         }
491         control.setBounds (parent.fixRectangle(itemBounds.x + MINIMUM_WIDTH, itemBounds.y, controlWidth, itemBounds.height));
492     }
493 }
494 /**
495  * Sets the minimum size that the cool item can be resized to
496  * using the cool item's gripper, to the point specified by the arguments.
497  *
498  * @param width the minimum width of the cool item, in pixels
499  * @param height the minimum height of the cool item, in pixels
500  *
501  * @exception SWTException <ul>
502  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
503  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
504  * </ul>
505  *
506  * @since 2.0
507  */
508 public void setMinimumSize (int width, int height) {
509     checkWidget ();
510     Point point = parent.fixPoint(width, height);
511     minimumWidth = point.x;
512     minimumHeight = point.y;
513 }
514 /**
515  * Sets the minimum size that the cool item can be resized to
516  * using the cool item's gripper, to the point specified by the argument.
517  *
518  * @param size a point representing the minimum width and height of the cool item, in pixels
519  *
520  * @exception IllegalArgumentException <ul>
521  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
522  * </ul>
523  * @exception SWTException <ul>
524  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
525  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
526  * </ul>
527  *
528  * @since 2.0
529  */
530 public void setMinimumSize (Point size) {
531     checkWidget ();
532     if (size is null) error(SWT.ERROR_NULL_ARGUMENT);
533     setMinimumSize(size.x, size.y);
534 }
535 /**
536  * Sets the receiver's ideal size to the point specified by the arguments.
537  *
538  * @param width the new ideal width for the receiver
539  * @param height the new ideal height for the receiver
540  *
541  * @exception SWTException <ul>
542  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
543  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
544  * </ul>
545  */
546 public void setPreferredSize (int width, int height) {
547     checkWidget();
548     ideal = true;
549     Point point = parent.fixPoint(width, height);
550     preferredWidth = Math.max (point.x, MINIMUM_WIDTH);
551     preferredHeight = point.y;
552 }
553 /**
554  * Sets the receiver's ideal size to the point specified by the argument.
555  *
556  * @param size the new ideal size for the receiver
557  *
558  * @exception IllegalArgumentException <ul>
559  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
560  * </ul>
561  * @exception SWTException <ul>
562  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
563  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
564  * </ul>
565  */
566 public void setPreferredSize (Point size) {
567     checkWidget();
568     if (size is null) error(SWT.ERROR_NULL_ARGUMENT);
569     setPreferredSize(size.x, size.y);
570 }
571 /**
572  * Sets the receiver's size to the point specified by the arguments.
573  * <p>
574  * Note: Attempting to set the width or height of the
575  * receiver to a negative number will cause that
576  * value to be set to zero instead.
577  * </p>
578  *
579  * @param width the new width for the receiver
580  * @param height the new height for the receiver
581  *
582  * @exception SWTException <ul>
583  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
584  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
585  * </ul>
586  */
587 public void setSize (int width, int height) {
588     checkWidget();
589     Point point = parent.fixPoint(width, height);
590     width = Math.max(point.x, minimumWidth + MINIMUM_WIDTH);
591     height = point.y;
592     if (!ideal) {
593         preferredWidth = width;
594         preferredHeight = height;
595     }
596     itemBounds.width = requestedWidth = width;
597     itemBounds.height = height;
598     if (control !is null) {
599         int controlWidth = width - MINIMUM_WIDTH;
600         if ((style & SWT.DROP_DOWN) !is 0 && width < preferredWidth) {
601             controlWidth -= CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM + CHEVRON_LEFT_MARGIN;
602         }
603         control.setSize(parent.fixPoint(controlWidth, height));
604     }
605     parent.relayout();
606     updateChevron();
607 }
608 /**
609  * Sets the receiver's size to the point specified by the argument.
610  * <p>
611  * Note: Attempting to set the width or height of the
612  * receiver to a negative number will cause them to be
613  * set to zero instead.
614  * </p>
615  *
616  * @param size the new size for the receiver
617  *
618  * @exception IllegalArgumentException <ul>
619  *    <li>ERROR_NULL_ARGUMENT - if the point is null</li>
620  * </ul>
621  * @exception SWTException <ul>
622  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
623  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
624  * </ul>
625  */
626 public void setSize (Point size) {
627     checkWidget();
628     if (size is null) error (SWT.ERROR_NULL_ARGUMENT);
629     setSize (size.x, size.y);
630 }
631 void updateChevron() {
632     if (control !is null) {
633         int width = itemBounds.width;
634         if ((style & SWT.DROP_DOWN) !is 0 && width < preferredWidth) {
635             if (chevron is null) {
636                 chevron = new ToolBar (parent, SWT.FLAT | SWT.NO_FOCUS);
637                 ToolItem toolItem = new ToolItem (chevron, SWT.PUSH);
638                 toolItem.addListener (SWT.Selection, new class () Listener {
639                     public void handleEvent (Event event) {
640                         this.outer.onSelection (event);
641                     }
642                 });
643             }
644             int controlHeight, currentImageHeight = 0;
645             if ((parent.style & SWT.VERTICAL) !is 0) {
646                 controlHeight = control.getSize ().x;
647                 if (arrowImage !is null) currentImageHeight = arrowImage.getBounds().width;
648             } else {
649                 controlHeight = control.getSize ().y;
650                 if (arrowImage !is null) currentImageHeight = arrowImage.getBounds().height;
651             }
652             int height = Math.min (controlHeight, itemBounds.height);
653             int imageHeight = Math.max(1, height - CHEVRON_VERTICAL_TRIM);
654             if (currentImageHeight !is imageHeight) {
655                 Image image = createArrowImage (CHEVRON_IMAGE_WIDTH, imageHeight);
656                 chevron.getItem (0).setImage (image);
657                 if (arrowImage !is null) arrowImage.dispose ();
658                 arrowImage = image;
659             }
660             chevron.setBackground (parent.getBackground());
661             chevron.setBounds (parent.fixRectangle (
662                 itemBounds.x + width - CHEVRON_LEFT_MARGIN - CHEVRON_IMAGE_WIDTH - CHEVRON_HORIZONTAL_TRIM,
663                 itemBounds.y,
664                 CHEVRON_IMAGE_WIDTH + CHEVRON_HORIZONTAL_TRIM,
665                 height));
666             chevron.setVisible(true);
667         } else {
668             if (chevron !is null) {
669                 chevron.setVisible(false);
670             }
671         }
672     }
673 }
674 }