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