root/dwt/custom/CBanner.d

Revision 246:fd9c62a2998e, 17.5 kB (checked in by Frank Benoit <benoit@tionex.de>, 6 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.custom.CBanner;
14
15
16
17 import dwt.DWT;
18 import dwt.DWTException;
19 import dwt.graphics.Color;
20 import dwt.graphics.Cursor;
21 import dwt.graphics.GC;
22 import dwt.graphics.Point;
23 import dwt.graphics.RGB;
24 import dwt.graphics.Rectangle;
25 import dwt.widgets.Composite;
26 import dwt.widgets.Control;
27 import dwt.widgets.Event;
28 import dwt.widgets.Layout;
29 import dwt.widgets.Listener;
30 import dwt.custom.CBannerLayout;
31
32 import Math = tango.math.Math;
33
34
35 /**
36  * Instances of this class implement a Composite that lays out its
37  * children and allows programmatic control of the layout. It draws
38  * a separator between the left and right children which can be dragged
39  * to resize the right control.
40  * CBanner is used in the workbench to layout the toolbar area and
41  * perspective switching toolbar.
42  * <p>
43  * Note that although this class is a subclass of <code>Composite</code>,
44  * it does not make sense to set a layout on it.
45  * </p><p>
46  * <dl>
47  * <dt><b>Styles:</b></dt>
48  * <dd>NONE</dd>
49  * <dt><b>Events:</b></dt>
50  * <dd>(None)</dd>
51  * </dl>
52  * <p>
53  * IMPORTANT: This class is <em>not</em> intended to be subclassed.
54  * </p>
55  *
56  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
57  *
58  * @since 3.0
59  */
60
61 public class CBanner : Composite {
62
63     Control left;
64     Control right;
65     Control bottom;
66
67     bool simple = true;
68
69     int[] curve;
70     int curveStart = 0;
71     Rectangle curveRect;
72     int curve_width = 5;
73     int curve_indent = -2;
74
75     int rightWidth = DWT.DEFAULT;
76     int rightMinWidth = 0;
77     int rightMinHeight = 0;
78     Cursor resizeCursor;
79     bool dragging = false;
80     int rightDragDisplacement = 0;
81
82     static const int OFFSCREEN = -200;
83     static const int BORDER_BOTTOM = 2;
84     static const int BORDER_TOP = 3;
85     static const int BORDER_STRIPE = 1;
86     static const int CURVE_TAIL = 200;
87     static const int BEZIER_RIGHT = 30;
88     static const int BEZIER_LEFT = 30;
89     static const int MIN_LEFT = 10;
90     static int BORDER1 = DWT.COLOR_WIDGET_HIGHLIGHT_SHADOW;
91
92
93 /**
94  * Constructs a new instance of this class given its parent
95  * and a style value describing its behavior and appearance.
96  * <p>
97  * The style value is either one of the style constants defined in
98  * class <code>DWT</code> which is applicable to instances of this
99  * class, or must be built by <em>bitwise OR</em>'ing together
100  * (that is, using the <code>int</code> "|" operator) two or more
101  * of those <code>DWT</code> style constants. The class description
102  * lists the style constants that are applicable to the class.
103  * Style bits are also inherited from superclasses.
104  * </p>
105  *
106  * @param parent a widget which will be the parent of the new instance (cannot be null)
107  * @param style the style of widget to construct
108  *
109  * @exception IllegalArgumentException <ul>
110  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
111  * </ul>
112  * @exception DWTException <ul>
113  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
114  * </ul>
115  *
116  */
117 public this(Composite parent, int style) {
118     curveRect = new Rectangle(0, 0, 0, 0);
119     super(parent, checkStyle(style));
120     super.setLayout(new CBannerLayout());
121     resizeCursor = new Cursor(getDisplay(), DWT.CURSOR_SIZEWE);
122
123     Listener listener = new class() Listener {
124         public void handleEvent(Event e) {
125             switch (e.type) {
126                 case DWT.Dispose:
127                     onDispose(); break;
128                 case DWT.MouseDown:
129                     onMouseDown (e.x, e.y); break;
130                 case DWT.MouseExit:
131                     onMouseExit(); break;
132                 case DWT.MouseMove:
133                     onMouseMove(e.x, e.y); break;
134                 case DWT.MouseUp:
135                     onMouseUp(); break;
136                 case DWT.Paint:
137                     onPaint(e.gc); break;
138                 case DWT.Resize:
139                     onResize(); break;
140                 default:
141             }
142         }
143     };
144     int[] events = [DWT.Dispose, DWT.MouseDown, DWT.MouseExit, DWT.MouseMove, DWT.MouseUp, DWT.Paint, DWT.Resize];
145     for (int i = 0; i < events.length; i++) {
146         addListener(events[i], listener);
147     }
148 }
149 static int[] bezier(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int count) {
150     // The parametric equations for a Bezier curve for x[t] and y[t] where  0 <= t <=1 are:
151     // x[t] = x0+3(x1-x0)t+3(x0+x2-2x1)t^2+(x3-x0+3x1-3x2)t^3
152     // y[t] = y0+3(y1-y0)t+3(y0+y2-2y1)t^2+(y3-y0+3y1-3y2)t^3
153     double a0 = x0;
154     double a1 = 3*(x1 - x0);
155     double a2 = 3*(x0 + x2 - 2*x1);
156     double a3 = x3 - x0 + 3*x1 - 3*x2;
157     double b0 = y0;
158     double b1 = 3*(y1 - y0);
159     double b2 = 3*(y0 + y2 - 2*y1);
160     double b3 = y3 - y0 + 3*y1 - 3*y2;
161
162     int[] polygon = new int[2*count + 2];
163     for (int i = 0; i <= count; i++) {
164         double t = cast(double)i / cast(double)count;
165         polygon[2*i] = cast(int)(a0 + a1*t + a2*t*t + a3*t*t*t);
166         polygon[2*i + 1] = cast(int)(b0 + b1*t + b2*t*t + b3*t*t*t);
167     }
168     return polygon;
169 }
170 static int checkStyle (int style) {
171     return DWT.NONE;
172 }
173 /**
174 * Returns the Control that appears on the bottom side of the banner.
175 *
176 * @return the control that appears on the bottom side of the banner or null
177 *
178 * @exception DWTException <ul>
179 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
180 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
181 * </ul>
182 *
183 * @since 3.0
184 */
185 public Control getBottom() {
186     checkWidget();
187     return bottom;
188 }
189 public override Rectangle getClientArea() {
190     return new Rectangle(0, 0, 0, 0);
191 }
192
193 /**
194 * Returns the Control that appears on the left side of the banner.
195 *
196 * @return the control that appears on the left side of the banner or null
197 *
198 * @exception DWTException <ul>
199 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
200 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
201 * </ul>
202 *
203 * @since 3.0
204 */
205 public Control getLeft() {
206     checkWidget();
207     return left;
208 }
209
210 /**
211 * Returns the Control that appears on the right side of the banner.
212 *
213 * @return the control that appears on the right side of the banner or null
214 *
215 * @exception DWTException <ul>
216 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
217 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
218 * </ul>
219 *
220 * @since 3.0
221 */
222 public Control getRight() {
223     checkWidget();
224     return right;
225 }
226 /**
227  * Returns the minimum size of the control that appears on the right of the banner.
228  *
229  * @return the minimum size of the control that appears on the right of the banner
230  *
231  * @since 3.1
232  */
233 public Point getRightMinimumSize() {
234     checkWidget();
235     return new Point(rightMinWidth, rightMinHeight);
236 }
237 /**
238  * Returns the width of the control that appears on the right of the banner.
239  *
240  * @return the width of the control that appears on the right of the banner
241  *
242  * @since 3.0
243  */
244 public int getRightWidth() {
245     checkWidget();
246     if (right is null) return 0;
247     if (rightWidth is DWT.DEFAULT) {
248         Point size = right.computeSize(DWT.DEFAULT, DWT.DEFAULT, false);
249         return size.x;
250     }
251     return rightWidth;
252 }
253 /**
254  * Returns <code>true</code> if the CBanner is rendered
255  * with a simple, traditional shape.
256  *
257  * @return <code>true</code> if the CBanner is rendered with a simple shape
258  *
259  * @since 3.0
260  */
261 public bool getSimple() {
262     checkWidget();
263     return simple;
264 }
265 void onDispose() {
266     if (resizeCursor !is null) resizeCursor.dispose();
267     resizeCursor = null;
268     left = null;
269     right = null;
270     bottom = null;
271 }
272 void onMouseDown (int x, int y) {
273     if (curveRect.contains(x, y)) {
274         dragging = true;
275         rightDragDisplacement = curveStart - x + curve_width - curve_indent;
276     }
277 }
278 void onMouseExit() {
279     if (!dragging) setCursor(null);
280 }
281 void onMouseMove(int x, int y) {
282     if (dragging) {
283         Point size = getSize();
284         if (!(0 < x && x < size.x)) return;
285         rightWidth = Math.max(0, size.x - x - rightDragDisplacement);
286         if (rightMinWidth is DWT.DEFAULT) {
287             Point minSize = right.computeSize(rightMinWidth, rightMinHeight);
288             rightWidth = Math.max(minSize.x, rightWidth);
289         } else {
290             rightWidth = Math.max(rightMinWidth, rightWidth);
291         }
292         layout(false);
293         return;
294     }
295     if (curveRect.contains(x, y)) {
296         setCursor(resizeCursor);
297     } else {
298         setCursor(null);
299     }
300 }
301 void onMouseUp () {
302     dragging = false;
303 }
304 void onPaint(GC gc) {
305 //   Useful for debugging paint problems
306 //  {
307 //  Point size = getSize();
308 //  gc.setBackground(getDisplay().getSystemColor(DWT.COLOR_GREEN));
309 //  gc.fillRectangle(-10, -10, size.x+20, size.y+20);
310 //  }
311     if (left is null && right is null) return;
312     Point size = getSize();
313     Color border1 = getDisplay().getSystemColor(BORDER1);
314     if (bottom !is null) {
315         int y = bottom.getBounds().y - BORDER_STRIPE - 1;
316         gc.setForeground(border1);
317         gc.drawLine(0, y, size.x, y);
318     }
319     if (left is null || right is null) return;
320     int[] line1 = new int[curve.length+6];
321     int index = 0;
322     int x = curveStart;
323     line1[index++] = x + 1;
324     line1[index++] = size.y - BORDER_STRIPE;
325     for (int i = 0; i < curve.length/2; i++) {
326         line1[index++]=x+curve[2*i];
327         line1[index++]=curve[2*i+1];
328     }
329     line1[index++] = x + curve_width;
330     line1[index++] = 0;
331     line1[index++] = size.x;
332     line1[index++] = 0;
333
334     Color background = getBackground();
335
336     if (getDisplay().getDepth() >= 15) {
337         // Anti- aliasing
338         int[] line2 = new int[line1.length];
339         index = 0;
340         for (int i = 0; i < line1.length/2; i++) {
341             line2[index] = line1[index++]  - 1;
342             line2[index] = line1[index++];
343         }
344         int[] line3 = new int[line1.length];
345         index = 0;
346         for (int i = 0; i < line1.length/2; i++) {
347             line3[index] = line1[index++] + 1;
348             line3[index] = line1[index++];
349         }
350         RGB from = border1.getRGB();
351         RGB to = background.getRGB();
352         int red = from.red + 3*(to.red - from.red)/4;
353         int green = from.green + 3*(to.green - from.green)/4;
354         int blue = from.blue + 3*(to.blue - from.blue)/4;
355         Color color = new Color(getDisplay(), red, green, blue);
356         gc.setForeground(color);
357         gc.drawPolyline(line2);
358         gc.drawPolyline(line3);
359         color.dispose();
360
361         // draw tail fading to background
362         int x1 = Math.max(0, curveStart - CURVE_TAIL);
363         gc.setForeground(background);
364         gc.setBackground(border1);
365         gc.fillGradientRectangle(x1, size.y - BORDER_STRIPE, curveStart-x1+1, 1, false);
366     } else {
367         // draw solid tail
368         int x1 = Math.max(0, curveStart - CURVE_TAIL);
369         gc.setForeground(border1);
370         gc.drawLine(x1, size.y - BORDER_STRIPE, curveStart+1, size.y - BORDER_STRIPE);
371     }
372
373     // draw border
374     gc.setForeground(border1);
375     gc.drawPolyline(line1);
376 }
377
378 void onResize() {
379     updateCurve(getSize().y);
380 }
381 /**
382 * Set the control that appears on the bottom side of the banner.
383 * The bottom control is optional.  Setting the bottom control to null will remove it from
384 * the banner - however, the creator of the control must dispose of the control.
385 *
386 * @param control the control to be displayed on the bottom or null
387 *
388 * @exception DWTException <ul>
389 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
390 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
391 *    <li>ERROR_INVALID_ARGUMENT - if the bottom control was not created as a child of the receiver</li>
392 * </ul>
393 *
394 * @since 3.0
395 */
396 public void setBottom(Control control) {
397     checkWidget();
398     if (control !is null && control.getParent() !is this) {
399         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
400     }
401     if (bottom !is null && !bottom.isDisposed()) {
402         Point size = bottom.getSize();
403         bottom.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
404     }
405     bottom = control;
406     layout(false);
407 }
408 /**
409  * Sets the layout which is associated with the receiver to be
410  * the argument which may be null.
411  * <p>
412  * Note: No Layout can be set on this Control because it already
413  * manages the size and position of its children.
414  * </p>
415  *
416  * @param layout the receiver's new layout or null
417  *
418  * @exception DWTException <ul>
419  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
420  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
421  * </ul>
422  */
423 public override void setLayout (Layout layout) {
424     checkWidget();
425     return;
426 }
427
428 /**
429 * Set the control that appears on the left side of the banner.
430 * The left control is optional.  Setting the left control to null will remove it from
431 * the banner - however, the creator of the control must dispose of the control.
432 *
433 * @param control the control to be displayed on the left or null
434 *
435 * @exception DWTException <ul>
436 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
437 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
438 *    <li>ERROR_INVALID_ARGUMENT - if the left control was not created as a child of the receiver</li>
439 * </ul>
440 *
441 * @since 3.0
442 */
443 public void setLeft(Control control) {
444     checkWidget();
445     if (control !is null && control.getParent() !is this) {
446         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
447     }
448     if (left !is null && !left.isDisposed()) {
449         Point size = left.getSize();
450         left.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
451     }
452     left = control;
453     layout(false);
454 }
455 /**
456 * Set the control that appears on the right side of the banner.
457 * The right control is optional.  Setting the right control to null will remove it from
458 * the banner - however, the creator of the control must dispose of the control.
459 *
460 * @param control the control to be displayed on the right or null
461 *
462 * @exception DWTException <ul>
463 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
464 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
465 *    <li>ERROR_INVALID_ARGUMENT - if the right control was not created as a child of the receiver</li>
466 * </ul>
467 *
468 * @since 3.0
469 */
470 public void setRight(Control control) {
471     checkWidget();
472     if (control !is null && control.getParent() !is this) {
473         DWT.error(DWT.ERROR_INVALID_ARGUMENT);
474     }
475     if (right !is null && !right.isDisposed()) {
476         Point size = right.getSize();
477         right.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
478     }
479     right = control;
480     layout(false);
481 }
482 /**
483  * Set the minimum height of the control that appears on the right side of the banner.
484  *
485  * @param size the minimum size of the control on the right
486  *
487  * @exception DWTException <ul>
488  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
489  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
490  *    <li>ERROR_INVALID_ARGUMENT - if the size is null or the values of size are less than DWT.DEFAULT</li>
491  * </ul>
492  *
493  * @since 3.1
494  */
495 public void setRightMinimumSize(Point size) {
496     checkWidget();
497     if (size is null || size.x < DWT.DEFAULT || size.y < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
498     rightMinWidth = size.x;
499     rightMinHeight = size.y;
500     layout(false);
501 }
502 /**
503  * Set the width of the control that appears on the right side of the banner.
504  *
505  * @param width the width of the control on the right
506  *
507  * @exception DWTException <ul>
508  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
509  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
510  *    <li>ERROR_INVALID_ARGUMENT - if width is less than DWT.DEFAULT</li>
511  * </ul>
512  *
513  * @since 3.0
514  */
515 public void setRightWidth(int width) {
516     checkWidget();
517     if (width < DWT.DEFAULT) DWT.error(DWT.ERROR_INVALID_ARGUMENT);
518     rightWidth = width;
519     layout(false);
520 }
521 /**
522  * Sets the shape that the CBanner will use to render itself.
523  *
524  * @param simple <code>true</code> if the CBanner should render itself in a simple, traditional style
525  *
526  * @exception DWTException <ul>
527  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
528  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
529  * </ul>
530  *
531  * @since 3.0
532  */
533 public void setSimple(bool simple) {
534     checkWidget();
535     if (this.simple !is simple) {
536         this.simple = simple;
537         if (simple) {
538             curve_width = 5;
539             curve_indent = -2;
540         } else {
541             curve_width = 50;
542             curve_indent = 5;
543         }
544         updateCurve(getSize().y);
545         layout(false);
546         redraw();
547     }
548 }
549 void updateCurve(int height) {
550     int h = height - BORDER_STRIPE;
551     if (simple) {
552         curve = [0,h, 1,h, 2,h-1, 3,h-2,
553                                    3,2, 4,1, 5,0];
554     } else {
555         curve = bezier(0, h+1, BEZIER_LEFT, h+1,
556                              curve_width-BEZIER_RIGHT, 0, curve_width, 0,
557                              curve_width);
558     }
559 }
560 }
Note: See TracBrowser for help on using the browser.