Mercurial > projects > dwt-mac
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 } |