]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.eclipse.swt.win32.win32.x86_64/src/org/eclipse/swt/custom/SashForm.java
90b067c63d38e88a6007d2643d76492b78602b3e
[simantics/platform.git] / bundles / org.eclipse.swt.win32.win32.x86_64 / src / org / eclipse / swt / custom / SashForm.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2016 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.swt.custom;
15
16
17 import org.eclipse.swt.*;
18 import org.eclipse.swt.graphics.*;
19 import org.eclipse.swt.widgets.*;
20
21 /**
22  * The SashForm is a composite control that lays out its children in a
23  * row or column arrangement (as specified by the orientation) and places
24  * a Sash between each child. One child may be maximized to occupy the
25  * entire size of the SashForm.  The relative sizes of the children may
26  * be specified using weights.
27  * <dl>
28  * <dt><b>Styles:</b></dt>
29  * <dd>HORIZONTAL, VERTICAL, SMOOTH</dd>
30  * </dl>
31  *
32  * @see <a href="http://www.eclipse.org/swt/snippets/#sashform">SashForm snippets</a>
33  * @see <a href="http://www.eclipse.org/swt/examples.php">SWT Example: CustomControlExample</a>
34  * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
35  */
36 public class SashForm extends Composite {
37
38         /**
39         * The width of all sashes in the form.
40         */
41         public int SASH_WIDTH = 3;
42
43         int sashStyle;
44         Sash[] sashes = new Sash[0];
45         // Remember background and foreground
46         // colors to determine whether to set
47         // sashes to the default color (null) or
48         // a specific color
49         Color background = null;
50         Color foreground = null;
51         Control[] controls = new Control[0];
52         Control maxControl = null;
53         Listener sashListener;
54         static final int DRAG_MINIMUM = 20;
55
56 /**
57  * Constructs a new instance of this class given its parent
58  * and a style value describing its behavior and appearance.
59  * <p>
60  * The style value is either one of the style constants defined in
61  * class <code>SWT</code> which is applicable to instances of this
62  * class, or must be built by <em>bitwise OR</em>'ing together
63  * (that is, using the <code>int</code> "|" operator) two or more
64  * of those <code>SWT</code> style constants. The class description
65  * lists the style constants that are applicable to the class.
66  * Style bits are also inherited from superclasses.
67  * </p>
68  *
69  * @param parent a widget which will be the parent of the new instance (cannot be null)
70  * @param style the style of widget to construct
71  *
72  * @exception IllegalArgumentException <ul>
73  *    <li>ERROR_NULL_ARGUMENT - if the parent is null</li>
74  * </ul>
75  * @exception SWTException <ul>
76  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the parent</li>
77  * </ul>
78  *
79  * @see SWT#HORIZONTAL
80  * @see SWT#VERTICAL
81  * @see #getStyle()
82  */
83 public SashForm(Composite parent, int style) {
84         super(parent, checkStyle(style));
85         super.setLayout(new SashFormLayout());
86         sashStyle = ((style & SWT.VERTICAL) != 0) ? SWT.HORIZONTAL : SWT.VERTICAL;
87         if ((style & SWT.BORDER) != 0) sashStyle |= SWT.BORDER;
88         if ((style & SWT.SMOOTH) != 0) sashStyle |= SWT.SMOOTH;
89         sashListener = e -> onDragSash(e);
90 }
91 static int checkStyle (int style) {
92         int mask = SWT.BORDER | SWT.LEFT_TO_RIGHT | SWT.RIGHT_TO_LEFT;
93         return style & mask;
94 }
95 Sash createSash() {
96         Sash sash = new Sash(this, sashStyle);
97         sash.setBackground(background);
98         sash.setForeground(foreground);
99         sash.setToolTipText(getToolTipText());
100         sash.addListener(SWT.Selection, sashListener);
101         return sash;
102 }
103 /**
104  * Returns SWT.HORIZONTAL if the controls in the SashForm are laid out side by side
105  * or SWT.VERTICAL   if the controls in the SashForm are laid out top to bottom.
106  *
107  * <p>
108  * To retrieve the bidi orientation of the SashForm use <code>{@link #getStyle()}</code>
109  * and test if the SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT bits are set.
110  * </p>
111  *
112  * @return SWT.HORIZONTAL or SWT.VERTICAL
113  */
114 @Override
115 public int getOrientation() {
116         /*
117          * This call is intentionally commented out, to allow this getter method to be
118          * called from a thread which is different from one that created the widget.
119          */
120         //checkWidget();
121         return (sashStyle & SWT.VERTICAL) != 0 ? SWT.HORIZONTAL : SWT.VERTICAL;
122 }
123 /**
124  * Returns the width of the sashes when the controls in the SashForm are
125  * laid out.
126  *
127  * @return the width of the sashes
128  *
129  * @exception SWTException <ul>
130  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
131  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
132  * </ul>
133  *
134  * @since 3.4
135  */
136 public int getSashWidth() {
137         checkWidget();
138         return SASH_WIDTH;
139 }
140 @Override
141 public int getStyle() {
142         int style = super.getStyle();
143         style |= getOrientation() == SWT.VERTICAL ? SWT.VERTICAL : SWT.HORIZONTAL;
144         if ((sashStyle & SWT.SMOOTH) != 0) style |= SWT.SMOOTH;
145         return style;
146 }
147 /**
148  * Answer the control that currently is maximized in the SashForm.
149  * This value may be null.
150  *
151  * @return the control that currently is maximized or null
152  */
153 public Control getMaximizedControl(){
154         /*
155          * This call is intentionally commented out, to allow this getter method to be
156          * called from a thread which is different from one that created the widget.
157          */
158         //checkWidget();
159         return this.maxControl;
160 }
161 /**
162  * Answer the relative weight of each child in the SashForm.  The weight represents the
163  * percent of the total width (if SashForm has Horizontal orientation) or
164  * total height (if SashForm has Vertical orientation) each control occupies.
165  * The weights are returned in order of the creation of the widgets (weight[0]
166  * corresponds to the weight of the first child created).
167  *
168  * @return the relative weight of each child
169  *
170  * @exception SWTException <ul>
171  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
172  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
173  * </ul>
174  */
175
176 public int[] getWeights() {
177         checkWidget();
178         Control[] cArray = getControls(false);
179         int[] ratios = new int[cArray.length];
180         for (int i = 0; i < cArray.length; i++) {
181                 Object data = cArray[i].getLayoutData();
182                 if (data != null && data instanceof SashFormData) {
183                         ratios[i] = (int)(((SashFormData)data).weight * 1000 >> 16);
184                 } else {
185                         ratios[i] = 200;
186                 }
187         }
188         return ratios;
189 }
190 Control[] getControls(boolean onlyVisible) {
191         Control[] children = getChildren();
192         Control[] result = new Control[0];
193         for (int i = 0; i < children.length; i++) {
194                 if (children[i] instanceof Sash) continue;
195                 if (onlyVisible && !children[i].getVisible()) continue;
196
197                 Control[] newResult = new Control[result.length + 1];
198                 System.arraycopy(result, 0, newResult, 0, result.length);
199                 newResult[result.length] = children[i];
200                 result = newResult;
201         }
202         return result;
203 }
204 void onDragSash(Event event) {
205         Sash sash = (Sash)event.widget;
206         int sashIndex = -1;
207         for (int i= 0; i < sashes.length; i++) {
208                 if (sashes[i] == sash) {
209                         sashIndex = i;
210                         break;
211                 }
212         }
213         if (sashIndex == -1) return;
214
215         Control c1 = controls[sashIndex];
216         Control c2 = controls[sashIndex + 1];
217         Rectangle b1 = c1.getBounds();
218         Rectangle b2 = c2.getBounds();
219
220         Rectangle sashBounds = sash.getBounds();
221         Rectangle area = getClientArea();
222         boolean correction = false;
223         if (getOrientation() == SWT.HORIZONTAL) {
224                 correction = b1.width < DRAG_MINIMUM || b2.width < DRAG_MINIMUM;
225                 int totalWidth = b2.x + b2.width - b1.x;
226                 int shift = event.x - sashBounds.x;
227                 b1.width += shift;
228                 b2.x += shift;
229                 b2.width -= shift;
230                 if (b1.width < DRAG_MINIMUM) {
231                         b1.width = DRAG_MINIMUM;
232                         b2.x = b1.x + b1.width + sashBounds.width;
233                         b2.width = totalWidth - b2.x;
234                         event.x = b1.x + b1.width;
235                         event.doit = false;
236                 }
237                 if (b2.width < DRAG_MINIMUM) {
238                         b1.width = totalWidth - DRAG_MINIMUM - sashBounds.width;
239                         b2.x = b1.x + b1.width + sashBounds.width;
240                         b2.width = DRAG_MINIMUM;
241                         event.x = b1.x + b1.width;
242                         event.doit = false;
243                 }
244                 Object data1 = c1.getLayoutData();
245                 if (data1 == null || !(data1 instanceof SashFormData)) {
246                         data1 = new SashFormData();
247                         c1.setLayoutData(data1);
248                 }
249                 Object data2 = c2.getLayoutData();
250                 if (data2 == null || !(data2 instanceof SashFormData)) {
251                         data2 = new SashFormData();
252                         c2.setLayoutData(data2);
253                 }
254                 ((SashFormData)data1).weight = (((long)b1.width << 16) + area.width - 1) / area.width;
255                 ((SashFormData)data2).weight = (((long)b2.width << 16) + area.width - 1) / area.width;
256         } else {
257                 correction = b1.height < DRAG_MINIMUM || b2.height < DRAG_MINIMUM;
258                 int totalHeight = b2.y + b2.height - b1.y;
259                 int shift = event.y - sashBounds.y;
260                 b1.height += shift;
261                 b2.y += shift;
262                 b2.height -= shift;
263                 if (b1.height < DRAG_MINIMUM) {
264                         b1.height = DRAG_MINIMUM;
265                         b2.y = b1.y + b1.height + sashBounds.height;
266                         b2.height = totalHeight - b2.y;
267                         event.y = b1.y + b1.height;
268                         event.doit = false;
269                 }
270                 if (b2.height < DRAG_MINIMUM) {
271                         b1.height = totalHeight - DRAG_MINIMUM - sashBounds.height;
272                         b2.y = b1.y + b1.height + sashBounds.height;
273                         b2.height = DRAG_MINIMUM;
274                         event.y = b1.y + b1.height;
275                         event.doit = false;
276                 }
277                 Object data1 = c1.getLayoutData();
278                 if (data1 == null || !(data1 instanceof SashFormData)) {
279                         data1 = new SashFormData();
280                         c1.setLayoutData(data1);
281                 }
282                 Object data2 = c2.getLayoutData();
283                 if (data2 == null || !(data2 instanceof SashFormData)) {
284                         data2 = new SashFormData();
285                         c2.setLayoutData(data2);
286                 }
287                 ((SashFormData)data1).weight = (((long)b1.height << 16) + area.height - 1) / area.height;
288                 ((SashFormData)data2).weight = (((long)b2.height << 16) + area.height - 1) / area.height;
289         }
290         if (correction || (event.doit && event.detail != SWT.DRAG)) {
291                 c1.setBounds(b1);
292                 sash.setBounds(event.x, event.y, event.width, event.height);
293                 c2.setBounds(b2);
294         }
295 }
296 /**
297  * If orientation is SWT.HORIZONTAL, lay the controls in the SashForm
298  * out side by side.  If orientation is SWT.VERTICAL, lay the
299  * controls in the SashForm out top to bottom.
300  *
301  * <p>
302  * Since 3.7, this method can also be called with SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT
303  * to change the bidi orientation of the SashForm.
304  * </p>
305  *
306  * @param orientation SWT.HORIZONTAL or SWT.VERTICAL, SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT
307  *
308  * @see Control#setOrientation(int)
309  *
310  * @exception SWTException <ul>
311  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
312  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
313  *    <li>ERROR_INVALID_ARGUMENT - if the value of orientation is not SWT.HORIZONTAL or SWT.VERTICAL, SWT.RIGHT_TO_LEFT or SWT.LEFT_TO_RIGHT
314  * </ul>
315  */
316 @Override
317 public void setOrientation(int orientation) {
318         checkWidget();
319         if (orientation == SWT.RIGHT_TO_LEFT || orientation == SWT.LEFT_TO_RIGHT) {
320                 super.setOrientation(orientation);
321                 return;
322         }
323         if (getOrientation() == orientation) return;
324         if (orientation != SWT.HORIZONTAL && orientation != SWT.VERTICAL) {
325                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
326         }
327         sashStyle &= ~(SWT.HORIZONTAL | SWT.VERTICAL);
328         sashStyle |= orientation == SWT.VERTICAL ? SWT.HORIZONTAL : SWT.VERTICAL;
329         for (int i = 0; i < sashes.length; i++) {
330                 sashes[i].dispose();
331                 sashes[i] = createSash();
332         }
333         layout(false);
334 }
335 @Override
336 public void setBackground (Color color) {
337         super.setBackground(color);
338         background = color;
339         for (int i = 0; i < sashes.length; i++) {
340                 sashes[i].setBackground(background);
341         }
342 }
343 @Override
344 public void setForeground (Color color) {
345         super.setForeground(color);
346         foreground = color;
347         for (int i = 0; i < sashes.length; i++) {
348                 sashes[i].setForeground(foreground);
349         }
350 }
351 /**
352  * Sets the layout which is associated with the receiver to be
353  * the argument which may be null.
354  * <p>
355  * Note: No Layout can be set on this Control because it already
356  * manages the size and position of its children.
357  * </p>
358  *
359  * @param layout the receiver's new layout or null
360  *
361  * @exception SWTException <ul>
362  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
363  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
364  * </ul>
365  */
366 @Override
367 public void setLayout (Layout layout) {
368         checkWidget();
369         return;
370 }
371 /**
372  * Specify the control that should take up the entire client area of the SashForm.
373  * If one control has been maximized, and this method is called with a different control,
374  * the previous control will be minimized and the new control will be maximized.
375  * If the value of control is null, the SashForm will minimize all controls and return to
376  * the default layout where all controls are laid out separated by sashes.
377  *
378  * @param control the control to be maximized or null
379  *
380  * @exception SWTException <ul>
381  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
382  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
383  * </ul>
384  */
385 public void setMaximizedControl(Control control){
386         checkWidget();
387         if (control == null) {
388                 if (maxControl != null) {
389                         this.maxControl = null;
390                         layout(false);
391                         for (int i= 0; i < sashes.length; i++){
392                                 sashes[i].setVisible(true);
393                         }
394                 }
395                 return;
396         }
397
398         for (int i= 0; i < sashes.length; i++){
399                 sashes[i].setVisible(false);
400         }
401         maxControl = control;
402         layout(false);
403 }
404
405 /**
406  * Specify the width of the sashes when the controls in the SashForm are
407  * laid out.
408  *
409  * @param width the width of the sashes
410  *
411  * @exception SWTException <ul>
412  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
413  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
414  * </ul>
415  *
416  * @since 3.4
417  */
418 public void setSashWidth(int width) {
419         checkWidget();
420         if (SASH_WIDTH == width) return;
421         SASH_WIDTH = width;
422         layout(false);
423 }
424 @Override
425 public void setToolTipText(String string) {
426         super.setToolTipText(string);
427         for (int i = 0; i < sashes.length; i++) {
428                 sashes[i].setToolTipText(string);
429         }
430 }
431 /**
432  * Specify the relative weight of each child in the SashForm.  This will determine
433  * what percent of the total width (if SashForm has Horizontal orientation) or
434  * total height (if SashForm has Vertical orientation) each control will occupy.
435  * The weights must be positive values and there must be an entry for each
436  * non-sash child of the SashForm.
437  *
438  * @param weights the relative weight of each child
439  *
440  * @exception SWTException <ul>
441  *    <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
442  *    <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
443  *    <li>ERROR_INVALID_ARGUMENT - if the weights value is null or of incorrect length (must match the number of children)</li>
444  * </ul>
445  */
446 public void setWeights(int[] weights) {
447         checkWidget();
448         Control[] cArray = getControls(false);
449         if (weights == null || weights.length != cArray.length) {
450                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
451         }
452
453         int total = 0;
454         for (int i = 0; i < weights.length; i++) {
455                 if (weights[i] < 0) {
456                         SWT.error(SWT.ERROR_INVALID_ARGUMENT);
457                 }
458                 total += weights[i];
459         }
460         if (total == 0) {
461                 SWT.error(SWT.ERROR_INVALID_ARGUMENT);
462         }
463         for (int i = 0; i < cArray.length; i++) {
464                 Object data = cArray[i].getLayoutData();
465                 if (data == null || !(data instanceof SashFormData)) {
466                         data = new SashFormData();
467                         cArray[i].setLayoutData(data);
468                 }
469                 ((SashFormData)data).weight = (((long)weights[i] << 16) + total - 1) / total;
470         }
471
472         layout(false);
473 }
474 }