root/dwt/widgets/ExpandItem.d

Revision 246:fd9c62a2998e, 17.2 kB (checked in by Frank Benoit <benoit@tionex.de>, 5 months ago)

Updater SWT 3.4M7 to 3.4

Line 
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 dwt.widgets.ExpandItem;
14
15 import dwt.widgets.Item;
16 import dwt.widgets.Widget;
17
18 import dwt.graphics.GC;
19 import dwt.graphics.Image;
20 import dwt.internal.win32.OS;
21 import dwt.widgets.Control;
22 import dwt.widgets.ExpandBar;
23 import dwt.widgets.Item;
24
25 import dwt.DWT;
26 import dwt.DWTException;
27 import dwt.graphics.GC;
28 import dwt.graphics.Image;
29 import dwt.graphics.Rectangle;
30 import dwt.internal.win32.OS;
31
32 import dwt.dwthelper.utils;
33
34 /**
35  * Instances of this class represent a selectable user interface object
36  * that represents a expandable item in a expand bar.
37  * <p>
38  * <dl>
39  * <dt><b>Styles:</b></dt>
40  * <dd>(none)</dd>
41  * <dt><b>Events:</b></dt>
42  * <dd>(none)</dd>
43  * </dl>
44  * </p><p>
45  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
46  * </p>
47  *
48  * @see ExpandBar
49  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
50  *
51  * @since 3.2
52  */
53 public class ExpandItem : Item {
54     ExpandBar parent;
55     Control control;
56     bool expanded, hover;
57     int x, y, width, height;
58     int imageHeight, imageWidth;
59     static const int TEXT_INSET = 6;
60     static const int BORDER = 1;
61     static const int CHEVRON_SIZE = 24;
62
63 /**
64  * Constructs a new instance of this class given its parent
65  * and a style value describing its behavior and appearance.
66  * <p>
67  * The style value is either one of the style constants defined in
68  * class <code>DWT</code> which is applicable to instances of this
69  * class, or must be built by <em>bitwise OR</em>'ing together
70  * (that is, using the <code>int</code> "|" operator) two or more
71  * of those <code>DWT</code> style constants. The class description
72  * lists the style constants that are applicable to the class.
73  * Style bits are also inherited from superclasses.
74  * </p>
75  *
76  * @param parent a composite control which will be the parent of the new instance (cannot be null)
77  * @param style the style of control to construct
78  *
79  * @exception IllegalArgumentException <ul>
80  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
81  * </ul>
82  * @exception DWTException <ul>
83  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
84  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
85  * </ul>
86  *
87  * @see Widget#checkSubclass
88  * @see Widget#getStyle
89  */
90 public this (ExpandBar parent, int style) {
91     this (parent, style, checkNull (parent).getItemCount ());
92 }
93
94 /**
95  * Constructs a new instance of this class given its parent, a
96  * style value describing its behavior and appearance, and the index
97  * at which to place it in the items maintained by its parent.
98  * <p>
99  * The style value is either one of the style constants defined in
100  * class <code>DWT</code> which is applicable to instances of this
101  * class, or must be built by <em>bitwise OR</em>'ing together
102  * (that is, using the <code>int</code> "|" operator) two or more
103  * of those <code>DWT</code> style constants. The class description
104  * lists the style constants that are applicable to the class.
105  * Style bits are also inherited from superclasses.
106  * </p>
107  *
108  * @param parent a composite control which will be the parent of the new instance (cannot be null)
109  * @param style the style of control to construct
110  * @param index the zero-relative index to store the receiver in its parent
111  *
112  * @exception IllegalArgumentException <ul>
113  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
114  *    <li>ERROR_INVALID_RANGE - if the index is not between 0 and the number of elements in the parent (inclusive)</li>
115  * </ul>
116  * @exception DWTException <ul>
117  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
118  *    <li>ERROR_INVALID_SUBCLASS - if this class is not an allowed subclass</li>
119  * </ul>
120  *
121  * @see Widget#checkSubclass
122  * @see Widget#getStyle
123  */
124 public this (ExpandBar parent, int style, int index) {
125     super (parent, style);
126     this.parent = parent;
127     parent.createItem (this, style, index);
128 }
129
130 static ExpandBar checkNull (ExpandBar control) {
131     if (control is null) DWT.error (DWT.ERROR_NULL_ARGUMENT);
132     return control;
133 }
134
135 private void drawChevron (HDC hDC, RECT* rect) {
136     HBRUSH oldBrush = OS.SelectObject (hDC, OS.GetSysColorBrush (OS.COLOR_BTNFACE));
137     OS.PatBlt (hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
138     OS.SelectObject (hDC, oldBrush);
139     rect.left += 4;
140     rect.top += 4;
141     rect.right -= 4;
142     rect.bottom -= 4;
143     HPEN hPen = OS.CreatePen (OS.PS_SOLID, 1, parent.foreground);
144     HPEN oldPen = OS.SelectObject (hDC, hPen);
145     int [] polyline1, polyline2;
146     if (expanded) {
147         int px = rect.left + 5;
148         int py = rect.top + 7;
149         polyline1 = [
150                 px,py, px+1,py, px+1,py-1, px+2,py-1, px+2,py-2, px+3,py-2, px+3,py-3,
151                 px+3,py-2, px+4,py-2, px+4,py-1, px+5,py-1, px+5,py, px+7,py];
152         py += 4;
153         polyline2 = [
154                 px,py, px+1,py, px+1,py-1, px+2,py-1, px+2,py-2, px+3,py-2, px+3,py-3,
155                 px+3,py-2, px+4,py-2, px+4,py-1,  px+5,py-1, px+5,py, px+7,py];
156     } else {
157         int px = rect.left + 5;
158         int py = rect.top + 4;
159         polyline1 = [
160                 px,py, px+1,py, px+1,py+1, px+2,py+1, px+2,py+2, px+3,py+2, px+3,py+3,
161                 px+3,py+2, px+4,py+2, px+4,py+1,  px+5,py+1, px+5,py, px+7,py];
162         py += 4;
163         polyline2 = [
164                 px,py, px+1,py, px+1,py+1, px+2,py+1, px+2,py+2, px+3,py+2, px+3,py+3,
165                 px+3,py+2, px+4,py+2, px+4,py+1,  px+5,py+1, px+5,py, px+7,py];
166     }
167     OS.Polyline (hDC, cast(POINT*)polyline1.ptr, polyline1.length / 2);
168     OS.Polyline (hDC, cast(POINT*)polyline2.ptr, polyline2.length / 2);
169     if (hover) {
170         HPEN whitePen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_3DHILIGHT));
171         HPEN darkGrayPen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_3DSHADOW));
172         OS.SelectObject (hDC, whitePen);
173         int [] points1 = [
174                 rect.left, rect.bottom,
175                 rect.left, rect.top,
176                 rect.right, rect.top];
177         OS.Polyline (hDC, cast(POINT*)points1.ptr, points1.length / 2);
178         OS.SelectObject (hDC, darkGrayPen);
179         int [] points2 = [
180                 rect.right, rect.top,
181                 rect.right, rect.bottom,
182                 rect.left, rect.bottom];
183         OS.Polyline (hDC, cast(POINT*)points2.ptr, points2.length / 2);
184         OS.SelectObject (hDC, oldPen);
185         OS.DeleteObject (whitePen);
186         OS.DeleteObject (darkGrayPen);
187     } else {
188         OS.SelectObject (hDC, oldPen);
189     }
190     OS.DeleteObject (hPen);
191 }
192
193 void drawItem (GC gc, HTHEME hTheme, RECT* clipRect, bool drawFocus) {
194     auto hDC = gc.handle;
195     int headerHeight = parent.getBandHeight ();
196     RECT rect;
197     OS.SetRect (&rect, x, y, x + width, y + headerHeight);
198     if (hTheme !is null) {
199         OS.DrawThemeBackground (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, &rect, clipRect);
200     } else {
201         HBRUSH oldBrush = OS.SelectObject (hDC, OS.GetSysColorBrush (OS.COLOR_BTNFACE));
202         OS.PatBlt (hDC, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, OS.PATCOPY);
203         OS.SelectObject (hDC, oldBrush);
204     }
205     if (image !is null) {
206         rect.left += ExpandItem.TEXT_INSET;
207         if (imageHeight > headerHeight) {
208             gc.drawImage (image, rect.left, rect.top + headerHeight - imageHeight);
209         } else {
210             gc.drawImage (image, rect.left, rect.top + (headerHeight - imageHeight) / 2);
211         }
212         rect.left += imageWidth;
213     }
214     if (text.length > 0) {
215         rect.left += ExpandItem.TEXT_INSET;
216         TCHAR[] buffer = StrToTCHARs ( text/+, parent.getCodePage ()+/ );
217         if (hTheme !is null) {
218             OS.DrawThemeText (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, buffer.ptr, buffer.length, OS.DT_VCENTER | OS.DT_SINGLELINE, 0, &rect);
219         } else {
220             int oldBkMode = OS.SetBkMode (hDC, OS.TRANSPARENT);
221             OS.DrawText (hDC, buffer.ptr, buffer.length, &rect, OS.DT_VCENTER | OS.DT_SINGLELINE);
222             OS.SetBkMode (hDC, oldBkMode);
223         }
224     }
225     int chevronSize = ExpandItem.CHEVRON_SIZE;
226     rect.left = rect.right - chevronSize;
227     rect.top = y + (headerHeight - chevronSize) / 2;
228     rect.bottom = rect.top + chevronSize;
229     if (hTheme !is null) {
230         int partID = expanded ? OS.EBP_NORMALGROUPCOLLAPSE : OS.EBP_NORMALGROUPEXPAND;
231         int stateID = hover ? OS.EBNGC_HOT : OS.EBNGC_NORMAL;
232         OS.DrawThemeBackground (hTheme, hDC, partID, stateID, &rect, clipRect);
233     } else {
234         drawChevron (hDC, &rect);
235     }
236     if (drawFocus) {
237         OS.SetRect (&rect, x + 1, y + 1, x + width - 2, y + headerHeight - 2);
238         OS.DrawFocusRect (hDC, &rect);
239     }
240     if (expanded) {
241         if (!parent.isAppThemed ()) {
242             HPEN pen = OS.CreatePen (OS.PS_SOLID, 1, OS.GetSysColor (OS.COLOR_BTNFACE));
243             HPEN oldPen = OS.SelectObject (hDC, pen);
244             int [] points = [
245                     x, y + headerHeight,
246                     x, y + headerHeight + height,
247                     x + width - 1, y + headerHeight + height,
248                     x + width - 1, y + headerHeight - 1];
249             OS.Polyline (hDC, cast(POINT*) points.ptr, points.length / 2);
250             OS.SelectObject (hDC, oldPen);
251             OS.DeleteObject (pen);
252         }
253     }
254 }
255
256 override void destroyWidget () {
257     parent.destroyItem (this);
258     releaseHandle ();
259 }
260
261 /**
262  * Returns the control that is shown when the item is expanded.
263  * If no control has been set, return <code>null</code>.
264  *
265  * @return the control
266  *
267  * @exception DWTException <ul>
268  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
269  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
270  * </ul>
271  */
272 public Control getControl () {
273     checkWidget ();
274     return control;
275 }
276
277 /**
278  * Returns <code>true</code> if the receiver is expanded,
279  * and false otherwise.
280  *
281  * @return the expanded state
282  *
283  * @exception DWTException <ul>
284  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
285  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
286  * </ul>
287  */
288 public bool getExpanded () {
289     checkWidget ();
290     return expanded;
291 }
292
293 /**
294  * Returns the height of the receiver's header
295  *
296  * @return the height of the header
297  *
298  * @exception DWTException <ul>
299  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
300  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
301  * </ul>
302  */
303 public int getHeaderHeight () {
304     checkWidget ();
305     return Math.max (parent.getBandHeight (), imageHeight);
306 }
307
308 /**
309  * Gets the height of the receiver.
310  *
311  * @return the height
312  *
313  * @exception DWTException <ul>
314  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
315  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
316  * </ul>
317  */
318 public int getHeight () {
319     checkWidget ();
320     return height;
321 }
322
323 /**
324  * Returns the receiver's parent, which must be a <code>ExpandBar</code>.
325  *
326  * @return the receiver's parent
327  *
328  * @exception DWTException <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 ExpandBar getParent () {
334     checkWidget ();
335     return parent;
336 }
337
338 int getPreferredWidth (HTHEME hTheme, HDC hDC) {
339     int width = ExpandItem.TEXT_INSET * 2 + ExpandItem.CHEVRON_SIZE;
340     if (image !is null) {
341         width += ExpandItem.TEXT_INSET + imageWidth;
342     }
343     if (text.length > 0) {
344         RECT rect;
345         TCHAR[] buffer = StrToTCHARs (/+parent.getCodePage (),+/ text);
346         if (hTheme !is null) {
347             OS.GetThemeTextExtent (hTheme, hDC, OS.EBP_NORMALGROUPHEAD, 0, buffer.ptr, buffer.length, OS.DT_SINGLELINE, null, &rect);
348         } else {
349             OS.DrawText (hDC, buffer.ptr, buffer.length, &rect, OS.DT_CALCRECT);
350         }
351         width += (rect.right - rect.left);
352     }
353     return width;
354 }
355
356 bool isHover (int x, int y) {
357     int bandHeight = parent.getBandHeight ();
358     return this.x < x && x < (this.x + width) && this.y < y && y < (this.y + bandHeight);
359 }
360
361 void redraw (bool all) {
362     auto parentHandle = parent.handle;
363     int headerHeight = parent.getBandHeight ();
364     RECT rect;
365     int left = all ? x : x + width - headerHeight;
366     OS.SetRect (&rect, left, y, x + width, y + headerHeight);
367     OS.InvalidateRect (parentHandle, &rect, true);
368     if (imageHeight > headerHeight) {
369         OS.SetRect (&rect, x + ExpandItem.TEXT_INSET, y + headerHeight - imageHeight, x + ExpandItem.TEXT_INSET + imageWidth, y);
370         OS.InvalidateRect (parentHandle, &rect, true);
371     }
372     if (!parent.isAppThemed ()) {
373         OS.SetRect (&rect, x, y + headerHeight, x + width, y + headerHeight + height + 1);
374         OS.InvalidateRect (parentHandle, &rect, true);
375     }
376 }
377
378 override void releaseHandle () {
379     super.releaseHandle ();
380     parent = null;
381 }
382
383 override void releaseWidget () {
384     super.releaseWidget ();
385     control = null;
386 }
387
388 void setBounds (int x, int y, int width, int height, bool move, bool size) {
389     redraw (true);
390     int headerHeight = parent.getBandHeight ();
391     if (move) {
392         if (imageHeight > headerHeight) {
393             y += (imageHeight - headerHeight);
394         }
395         this.x = x;
396         this.y = y;
397         redraw (true);
398     }
399     if (size) {
400         this.width = width;
401         this.height = height;
402         redraw (true);
403     }
404     if (control !is null && !control.isDisposed ()) {
405         if (!parent.isAppThemed ()) {
406             x += BORDER;
407             width = Math.max (0, width - BORDER * 2);
408             height = Math.max (0, height - BORDER);
409         }
410         if (move && size) control.setBounds (x, y + headerHeight, width, height);
411         if (move && !size) control.setLocation (x, y + headerHeight);
412         if (!move && size) control.setSize (width, height);
413     }
414 }
415
416 /**
417  * Sets the control that is shown when the item is expanded.
418  *
419  * @param control the new control (or null)
420  *
421  * @exception IllegalArgumentException <ul>
422  *    <li>ERROR_INVALID_ARGUMENT - if the control has been disposed</li>
423  *    <li>ERROR_INVALID_PARENT - if the control is not in the same widget tree</li>
424  * </ul>
425  * @exception DWTException <ul>
426  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
427  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
428  * </ul>
429  */
430 public void setControl (Control control) {
431     checkWidget ();
432     if (control !is null) {
433         if (control.isDisposed ()) error (DWT.ERROR_INVALID_ARGUMENT);
434         if (control.parent !is parent) error (DWT.ERROR_INVALID_PARENT);
435     }
436     this.control = control;
437     if (control !is null) {
438         int headerHeight = parent.getBandHeight ();
439         control.setVisible (expanded);
440         if (!parent.isAppThemed ()) {
441             int width = Math.max (0, this.width - BORDER * 2);
442             int height = Math.max (0, this.height - BORDER);
443             control.setBounds (x + BORDER, y + headerHeight, width, height);
444         } else {
445             control.setBounds (x, y + headerHeight, width, height);
446         }
447     }
448 }
449
450 /**
451  * Sets the expanded state of the receiver.
452  *
453  * @param expanded the new expanded state
454  *
455  * @exception DWTException <ul>
456  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
457  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
458  * </ul>
459  */
460 public void setExpanded (bool expanded) {
461     checkWidget ();
462     this.expanded = expanded;
463     parent.showItem (this);
464 }
465
466 /**
467  * Sets the height of the receiver. This is height of the item when it is expanded,
468  * excluding the height of the header.
469  *
470  * @param height the new height
471  *
472  * @exception DWTException <ul>
473  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
474  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
475  * </ul>
476  */
477 public void setHeight (int height) {
478     checkWidget ();
479     if (height < 0) return;
480     setBounds (0, 0, width, height, false, true);
481     if (expanded) parent.layoutItems (parent.indexOf (this) + 1, true);
482 }
483
484 override public void setImage (Image image) {
485     super.setImage (image);
486     int oldImageHeight = imageHeight;
487     if (image !is null) {
488         Rectangle bounds = image.getBounds ();
489         imageHeight = bounds.height;
490         imageWidth = bounds.width;
491     } else {
492         imageHeight = imageWidth = 0;
493     }
494     if (oldImageHeight !is imageHeight) {
495         parent.layoutItems (parent.indexOf (this), true);
496     } else {
497         redraw (true);
498     }
499 }
500
501 override public void setText (String string) {
502     super.setText (string);
503     redraw (true);
504 }
505 }
Note: See TracBrowser for help on using the browser.