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.custom.ViewForm;
14 
15 import java.lang.all;
16 
17 
18 
19 import org.eclipse.swt.SWT;
20 import org.eclipse.swt.SWTException;
21 import org.eclipse.swt.graphics.Color;
22 import org.eclipse.swt.graphics.GC;
23 import org.eclipse.swt.graphics.Point;
24 import org.eclipse.swt.graphics.RGB;
25 import org.eclipse.swt.graphics.Rectangle;
26 import org.eclipse.swt.widgets.Composite;
27 import org.eclipse.swt.widgets.Control;
28 import org.eclipse.swt.widgets.Event;
29 import org.eclipse.swt.widgets.Layout;
30 import org.eclipse.swt.widgets.Listener;
31 import org.eclipse.swt.custom.ViewFormLayout;
32 
33 /**
34  * Instances of this class implement a Composite that positions and sizes
35  * children and allows programmatic control of layout and border parameters.
36  * ViewForm is used in the workbench to lay out a view's label/menu/toolbar
37  * local bar.
38  * <p>
39  * Note that although this class is a subclass of <code>Composite</code>,
40  * it does not make sense to set a layout on it.
41  * </p><p>
42  * <dl>
43  * <dt><b>Styles:</b></dt>
44  * <dd>BORDER, FLAT</dd>
45  * <dt><b>Events:</b></dt>
46  * <dd>(None)</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 
55 public class ViewForm : Composite {
56 
57     /**
58      * marginWidth specifies the number of pixels of horizontal margin
59      * that will be placed along the left and right edges of the form.
60      *
61      * The default value is 0.
62      */
63     public int marginWidth = 0;
64     /**
65      * marginHeight specifies the number of pixels of vertical margin
66      * that will be placed along the top and bottom edges of the form.
67      *
68      * The default value is 0.
69      */
70     public int marginHeight = 0;
71     /**
72      * horizontalSpacing specifies the number of pixels between the right
73      * edge of one cell and the left edge of its neighbouring cell to
74      * the right.
75      *
76      * The default value is 1.
77      */
78     public int horizontalSpacing = 1;
79     /**
80      * verticalSpacing specifies the number of pixels between the bottom
81      * edge of one cell and the top edge of its neighbouring cell underneath.
82      *
83      * The default value is 1.
84      */
85     public int verticalSpacing = 1;
86 
87     /**
88      * Color of innermost line of drop shadow border.
89      *
90      * NOTE This field is badly named and can not be fixed for backwards compatibility.
91      * It should be capitalized.
92      *
93      * @deprecated
94      */
95     public static RGB borderInsideRGB;
96     /**
97      * Color of middle line of drop shadow border.
98      *
99      * NOTE This field is badly named and can not be fixed for backwards compatibility.
100      * It should be capitalized.
101      *
102      * @deprecated
103      */
104     public static RGB borderMiddleRGB;
105     /**
106      * Color of outermost line of drop shadow border.
107      *
108      * NOTE This field is badly named and can not be fixed for backwards compatibility.
109      * It should be capitalized.
110      *
111      * @deprecated
112      */
113     public static RGB borderOutsideRGB;
114 
115     // SWT widgets
116     Control topLeft;
117     Control topCenter;
118     Control topRight;
119     Control content;
120 
121     // Configuration and state info
122     bool separateTopCenter = false;
123     bool showBorder = false;
124 
125     int separator = -1;
126     int borderTop = 0;
127     int borderBottom = 0;
128     int borderLeft = 0;
129     int borderRight = 0;
130     int highlight = 0;
131     Point oldSize;
132 
133     Color selectionBackground;
134 
135     static const int OFFSCREEN = -200;
136     static const int BORDER1_COLOR = SWT.COLOR_WIDGET_NORMAL_SHADOW;
137     static const int SELECTION_BACKGROUND = SWT.COLOR_LIST_BACKGROUND;
138 
139 
140     static this(){
141         borderInsideRGB  = new RGB (132, 130, 132);
142         borderMiddleRGB  = new RGB (143, 141, 138);
143         borderOutsideRGB = new RGB (171, 168, 165);
144     }
145 /**
146  * Constructs a new instance of this class given its parent
147  * and a style value describing its behavior and appearance.
148  * <p>
149  * The style value is either one of the style constants defined in
150  * class <code>SWT</code> which is applicable to instances of this
151  * class, or must be built by <em>bitwise OR</em>'ing together
152  * (that is, using the <code>int</code> "|" operator) two or more
153  * of those <code>SWT</code> style constants. The class description
154  * lists the style constants that are applicable to the class.
155  * Style bits are also inherited from superclasses.
156  * </p>
157  *
158  * @param parent a widget which will be the parent of the new instance (cannot be null)
159  * @param style the style of widget to construct
160  *
161  * @exception IllegalArgumentException <ul>
162  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
163  * </ul>
164  * @exception SWTException <ul>
165  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
166  * </ul>
167  *
168  * @see SWT#BORDER
169  * @see SWT#FLAT
170  * @see #getStyle()
171  */
172 public this(Composite parent, int style) {
173     super(parent, checkStyle(style));
174     super.setLayout(new ViewFormLayout());
175 
176     setBorderVisible((style & SWT.BORDER) !is 0);
177 
178     Listener listener = new class() Listener {
179         public void handleEvent(Event e) {
180             switch (e.type) {
181                 case SWT.Dispose: onDispose(); break;
182                 case SWT.Paint: onPaint(e.gc); break;
183                 case SWT.Resize: onResize(); break;
184                 default:
185             }
186         }
187     };
188 
189     int[] events = [SWT.Dispose, SWT.Paint, SWT.Resize];
190 
191     for (int i = 0; i < events.length; i++) {
192         addListener(events[i], listener);
193     }
194 }
195 
196 static int checkStyle (int style) {
197     int mask = SWT.FLAT | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
198     return style & mask | SWT.NO_REDRAW_RESIZE;
199 }
200 
201 //protected void checkSubclass () {
202 //  String name = getClass().getName ();
203 //  String validName = ViewForm.class.getName();
204 //  if (validName != (name)) {
205 //      SWT.error (SWT.ERROR_INVALID_SUBCLASS);
206 //  }
207 //}
208 
209 public override Rectangle computeTrim (int x, int y, int width, int height) {
210     checkWidget ();
211     int trimX = x - borderLeft - highlight;
212     int trimY = y - borderTop - highlight;
213     int trimWidth = width + borderLeft + borderRight + 2*highlight;
214     int trimHeight = height + borderTop + borderBottom + 2*highlight;
215     return new Rectangle(trimX, trimY, trimWidth, trimHeight);
216 }
217 public override Rectangle getClientArea() {
218     checkWidget();
219     Rectangle clientArea = super.getClientArea();
220     clientArea.x += borderLeft;
221     clientArea.y += borderTop;
222     clientArea.width -= borderLeft + borderRight;
223     clientArea.height -= borderTop + borderBottom;
224     return clientArea;
225 }
226 /**
227 * Returns the content area.
228 *
229 * @return the control in the content area of the pane or null
230 */
231 public Control getContent() {
232     //checkWidget();
233     return content;
234 }
235 /**
236 * Returns Control that appears in the top center of the pane.
237 * Typically this is a toolbar.
238 *
239 * @return the control in the top center of the pane or null
240 */
241 public Control getTopCenter() {
242     //checkWidget();
243     return topCenter;
244 }
245 /**
246 * Returns the Control that appears in the top left corner of the pane.
247 * Typically this is a label such as CLabel.
248 *
249 * @return the control in the top left corner of the pane or null
250 */
251 public Control getTopLeft() {
252     //checkWidget();
253     return topLeft;
254 }
255 /**
256 * Returns the control in the top right corner of the pane.
257 * Typically this is a Close button or a composite with a Menu and Close button.
258 *
259 * @return the control in the top right corner of the pane or null
260 */
261 public Control getTopRight() {
262     //checkWidget();
263     return topRight;
264 }
265 void onDispose() {
266     topLeft = null;
267     topCenter = null;
268     topRight = null;
269     content = null;
270     oldSize = null;
271     selectionBackground = null;
272 }
273 void onPaint(GC gc) {
274     Color gcForeground = gc.getForeground();
275     Point size = getSize();
276     Color border = getDisplay().getSystemColor(BORDER1_COLOR);
277     if (showBorder) {
278         gc.setForeground(border);
279         gc.drawRectangle(0, 0, size.x - 1, size.y - 1);
280         if (highlight > 0) {
281             int x1 = 1;
282             int y1 = 1;
283             int x2 = size.x - 1;
284             int y2 = size.y - 1;
285             int[] shape = [x1,y1, x2,y1, x2,y2, x1,y2, x1,y1+highlight,
286                                x1+highlight,y1+highlight, x1+highlight,y2-highlight,
287                                x2-highlight,y2-highlight, x2-highlight,y1+highlight, x1,y1+highlight];
288             Color highlightColor = getDisplay().getSystemColor(SWT.COLOR_LIST_SELECTION);
289             gc.setBackground(highlightColor);
290             gc.fillPolygon(shape);
291         }
292     }
293     if (separator > -1) {
294         gc.setForeground(border);
295         gc.drawLine(borderLeft + highlight, separator, size.x - borderLeft - borderRight - highlight, separator);
296     }
297     gc.setForeground(gcForeground);
298 }
299 void onResize() {
300     Point size = getSize();
301     if (oldSize is null || oldSize.x is 0 || oldSize.y is 0) {
302         redraw();
303     } else {
304         int width = 0;
305         if (oldSize.x < size.x) {
306             width = size.x - oldSize.x + borderRight + highlight;
307         } else if (oldSize.x > size.x) {
308             width = borderRight + highlight;
309         }
310         redraw(size.x - width, 0, width, size.y, false);
311 
312         int height = 0;
313         if (oldSize.y < size.y) {
314             height = size.y - oldSize.y + borderBottom + highlight;
315         }
316         if (oldSize.y > size.y) {
317             height = borderBottom + highlight;
318         }
319         redraw(0, size.y - height, size.x, height, false);
320     }
321     oldSize = size;
322 }
323 /**
324 * Sets the content.
325 * Setting the content to null will remove it from
326 * the pane - however, the creator of the content must dispose of the content.
327 *
328 * @param content the control to be displayed in the content area or null
329 *
330 * @exception SWTException <ul>
331 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
332 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
333 *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this ViewForm</li>
334 * </ul>
335 */
336 public void setContent(Control content) {
337     checkWidget();
338     if (content !is null && content.getParent() !is this) {
339         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
340     }
341     if (this.content !is null && !this.content.isDisposed()) {
342         this.content.setBounds(OFFSCREEN, OFFSCREEN, 0, 0);
343     }
344     this.content = content;
345     layout(false);
346 }
347 /**
348  * Sets the layout which is associated with the receiver to be
349  * the argument which may be null.
350  * <p>
351  * Note: No Layout can be set on this Control because it already
352  * manages the size and position of its children.
353  * </p>
354  *
355  * @param layout the receiver's new layout or null
356  *
357  * @exception SWTException <ul>
358  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
359  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
360  * </ul>
361  */
362 public override void setLayout (Layout layout) {
363     checkWidget();
364     return;
365 }
366 void setSelectionBackground (Color color) {
367     checkWidget();
368     if (selectionBackground is color) return;
369     if (color is null) color = getDisplay().getSystemColor(SELECTION_BACKGROUND);
370     selectionBackground = color;
371     redraw();
372 }
373 /**
374 * Set the control that appears in the top center of the pane.
375 * Typically this is a toolbar.
376 * The topCenter is optional.  Setting the topCenter to null will remove it from
377 * the pane - however, the creator of the topCenter must dispose of the topCenter.
378 *
379 * @param topCenter the control to be displayed in the top center or null
380 *
381 * @exception SWTException <ul>
382 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
383 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
384 *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this ViewForm</li>
385 * </ul>
386 */
387 public void setTopCenter(Control topCenter) {
388     checkWidget();
389     if (topCenter !is null && topCenter.getParent() !is this) {
390         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
391     }
392     if (this.topCenter !is null && !this.topCenter.isDisposed()) {
393         Point size = this.topCenter.getSize();
394         this.topCenter.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
395     }
396     this.topCenter = topCenter;
397     layout(false);
398 }
399 /**
400 * Set the control that appears in the top left corner of the pane.
401 * Typically this is a label such as CLabel.
402 * The topLeft is optional.  Setting the top left control to null will remove it from
403 * the pane - however, the creator of the control must dispose of the control.
404 *
405 * @param c the control to be displayed in the top left corner or null
406 *
407 * @exception SWTException <ul>
408 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
409 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
410 *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this ViewForm</li>
411 * </ul>
412 */
413 public void setTopLeft(Control c) {
414     checkWidget();
415     if (c !is null && c.getParent() !is this) {
416         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
417     }
418     if (this.topLeft !is null && !this.topLeft.isDisposed()) {
419         Point size = this.topLeft.getSize();
420         this.topLeft.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
421     }
422     this.topLeft = c;
423     layout(false);
424 }
425 /**
426 * Set the control that appears in the top right corner of the pane.
427 * Typically this is a Close button or a composite with a Menu and Close button.
428 * The topRight is optional.  Setting the top right control to null will remove it from
429 * the pane - however, the creator of the control must dispose of the control.
430 *
431 * @param c the control to be displayed in the top right corner or null
432 *
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 *    <li>ERROR_INVALID_ARGUMENT - if the control is not a child of this ViewForm</li>
437 * </ul>
438 */
439 public void setTopRight(Control c) {
440     checkWidget();
441     if (c !is null && c.getParent() !is this) {
442         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
443     }
444     if (this.topRight !is null && !this.topRight.isDisposed()) {
445         Point size = this.topRight.getSize();
446         this.topRight.setLocation(OFFSCREEN - size.x, OFFSCREEN - size.y);
447     }
448     this.topRight = c;
449     layout(false);
450 }
451 /**
452 * Specify whether the border should be displayed or not.
453 *
454 * @param show true if the border should be displayed
455 *
456 * @exception SWTException <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 * </ul>
460 */
461 public void setBorderVisible(bool show) {
462     checkWidget();
463     if (showBorder is show) return;
464 
465     showBorder = show;
466     if (showBorder) {
467         borderLeft = borderTop = borderRight = borderBottom = 1;
468         if ((getStyle() & SWT.FLAT)is 0) highlight = 2;
469     } else {
470         borderBottom = borderTop = borderLeft = borderRight = 0;
471         highlight = 0;
472     }
473     layout(false);
474     redraw();
475 }
476 /**
477 * If true, the topCenter will always appear on a separate line by itself, otherwise the
478 * topCenter will appear in the top row if there is room and will be moved to the second row if
479 * required.
480 *
481 * @param show true if the topCenter will always appear on a separate line by itself
482 *
483 * @exception SWTException <ul>
484 *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
485 *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
486 * </ul>
487 */
488 public void setTopCenterSeparate(bool show) {
489     checkWidget();
490     separateTopCenter = show;
491     layout(false);
492 }
493 }