comparison dwt/layout/FormLayout.d @ 40:fbe68c33eeee

Sync layout with dwt-linux
author Frank Benoit <benoit@tionex.de>
date Tue, 07 Oct 2008 14:41:31 +0200
parents a9ab4c738ed8
children d8635bb48c7c
comparison
equal deleted inserted replaced
39:43be986a1372 40:fbe68c33eeee
1 /******************************************************************************* 1 /*******************************************************************************
2 * Copyright (c) 2000, 2007 IBM Corporation and others. 2 * Copyright (c) 2000, 2008 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials 3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0 4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at 5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html 6 * http://www.eclipse.org/legal/epl-v10.html
7 * 7 *
8 * Contributors: 8 * Contributors:
9 * IBM Corporation - initial API and implementation 9 * IBM Corporation - initial API and implementation
10 * Port to the D programming language:
11 * Frank Benoit <benoit@tionex.de>
10 *******************************************************************************/ 12 *******************************************************************************/
11 module dwt.layout.FormLayout; 13 module dwt.layout.FormLayout;
12 14
13 import dwt.dwthelper.utils; 15 import dwt.layout.FormAttachment;
14 16 import dwt.layout.FormData;
15 import dwt.DWT; 17 import dwt.DWT;
16 import dwt.graphics.Point; 18 import dwt.graphics.Point;
17 import dwt.graphics.Rectangle; 19 import dwt.graphics.Rectangle;
18 import dwt.widgets.Composite;
19 import dwt.widgets.Control; 20 import dwt.widgets.Control;
20 import dwt.widgets.Layout; 21 import dwt.widgets.Layout;
22 import dwt.widgets.Composite;
21 import dwt.widgets.Scrollable; 23 import dwt.widgets.Scrollable;
22 24
25 import tango.util.Convert;
26 import Math = tango.math.Math;
27 import dwt.dwthelper.utils;
28
23 /** 29 /**
24 * Instances of this class control the position and size of the 30 * Instances of this class control the position and size of the
25 * children of a composite control by using <code>FormAttachments</code> 31 * children of a composite control by using <code>FormAttachments</code>
26 * to optionally configure the left, top, right and bottom edges of 32 * to optionally configure the left, top, right and bottom edges of
27 * each child. 33 * each child.
28 * <p> 34 * <p>
29 * The following example code creates a <code>FormLayout</code> and then sets 35 * The following example code creates a <code>FormLayout</code> and then sets
55 * data2.right = new FormAttachment(100, 0); 61 * data2.right = new FormAttachment(100, 0);
56 * button2.setLayoutData(data2); 62 * button2.setLayoutData(data2);
57 * </pre> 63 * </pre>
58 * </p> 64 * </p>
59 * <p> 65 * <p>
60 * Each side of a child control can be attached to a position in the parent 66 * Each side of a child control can be attached to a position in the parent
61 * composite, or to other controls within the <code>Composite</code> by 67 * composite, or to other controls within the <code>Composite</code> by
62 * creating instances of <code>FormAttachment</code> and setting them into 68 * creating instances of <code>FormAttachment</code> and setting them into
63 * the top, bottom, left, and right fields of the child's <code>FormData</code>. 69 * the top, bottom, left, and right fields of the child's <code>FormData</code>.
64 * </p> 70 * </p>
65 * <p> 71 * <p>
81 * the right edge of <code>button1</code> to the left edge of <code>button2</code> 87 * the right edge of <code>button1</code> to the left edge of <code>button2</code>
82 * and then attach the left edge of <code>button2</code> to the right edge of 88 * and then attach the left edge of <code>button2</code> to the right edge of
83 * <code>button1</code>. This will over constrain the layout, causing undefined 89 * <code>button1</code>. This will over constrain the layout, causing undefined
84 * behavior. The algorithm will terminate, but the results are undefined. 90 * behavior. The algorithm will terminate, but the results are undefined.
85 * </p> 91 * </p>
86 * 92 *
87 * @see FormData 93 * @see FormData
88 * @see FormAttachment 94 * @see FormAttachment
89 * 95 * @see <a href="http://www.eclipse.org/swt/snippets/#formlayout">FormLayout snippets</a>
96 * @see <a href="http://www.eclipse.org/swt/examples.php">DWT Example: LayoutExample</a>
97 * @see <a href="http://www.eclipse.org/swt/">Sample code and further information</a>
98 *
90 * @since 2.0 99 * @since 2.0
91 *
92 */ 100 */
93 public final class FormLayout : Layout { 101 public final class FormLayout : Layout {
94 102
95 /** 103 /**
96 * marginWidth specifies the number of pixels of horizontal margin 104 * marginWidth specifies the number of pixels of horizontal margin
97 * that will be placed along the left and right edges of the layout. 105 * that will be placed along the left and right edges of the layout.
98 * 106 *
99 * The default value is 0. 107 * The default value is 0.
100 */ 108 */
101 public int marginWidth = 0; 109 public int marginWidth = 0;
102 110
103 /** 111 /**
104 * marginHeight specifies the number of pixels of vertical margin 112 * marginHeight specifies the number of pixels of vertical margin
105 * that will be placed along the top and bottom edges of the layout. 113 * that will be placed along the top and bottom edges of the layout.
106 * 114 *
107 * The default value is 0. 115 * The default value is 0.
108 */ 116 */
109 public int marginHeight = 0; 117 public int marginHeight = 0;
110 118
111 119
112 /** 120 /**
113 * marginLeft specifies the number of pixels of horizontal margin 121 * marginLeft specifies the number of pixels of horizontal margin
114 * that will be placed along the left edge of the layout. 122 * that will be placed along the left edge of the layout.
115 * 123 *
116 * The default value is 0. 124 * The default value is 0.
117 * 125 *
118 * @since 3.1 126 * @since 3.1
119 */ 127 */
120 public int marginLeft = 0; 128 public int marginLeft = 0;
121 129
122 /** 130 /**
123 * marginTop specifies the number of pixels of vertical margin 131 * marginTop specifies the number of pixels of vertical margin
124 * that will be placed along the top edge of the layout. 132 * that will be placed along the top edge of the layout.
125 * 133 *
126 * The default value is 0. 134 * The default value is 0.
127 * 135 *
128 * @since 3.1 136 * @since 3.1
129 */ 137 */
130 public int marginTop = 0; 138 public int marginTop = 0;
131 139
132 /** 140 /**
133 * marginRight specifies the number of pixels of horizontal margin 141 * marginRight specifies the number of pixels of horizontal margin
134 * that will be placed along the right edge of the layout. 142 * that will be placed along the right edge of the layout.
135 * 143 *
136 * The default value is 0. 144 * The default value is 0.
137 * 145 *
138 * @since 3.1 146 * @since 3.1
139 */ 147 */
140 public int marginRight = 0; 148 public int marginRight = 0;
141 149
142 /** 150 /**
143 * marginBottom specifies the number of pixels of vertical margin 151 * marginBottom specifies the number of pixels of vertical margin
144 * that will be placed along the bottom edge of the layout. 152 * that will be placed along the bottom edge of the layout.
145 * 153 *
146 * The default value is 0. 154 * The default value is 0.
147 * 155 *
148 * @since 3.1 156 * @since 3.1
149 */ 157 */
150 public int marginBottom = 0; 158 public int marginBottom = 0;
151 159
152 /** 160 /**
153 * spacing specifies the number of pixels between the edge of one control 161 * spacing specifies the number of pixels between the edge of one control
154 * and the edge of its neighbouring control. 162 * and the edge of its neighbouring control.
155 * 163 *
156 * The default value is 0. 164 * The default value is 0.
157 * 165 *
158 * @since 3.0 166 * @since 3.0
159 */ 167 */
160 public int spacing = 0; 168 public int spacing = 0;
161 169
162 /** 170 /**
163 * Constructs a new instance of this class. 171 * Constructs a new instance of this class.
164 */ 172 */
165 public this () { 173 public this () {
166 } 174 }
167 175
168 /* 176 /*
169 * Computes the preferred height of the form with 177 * Computes the preferred height of the form with
170 * respect to the preferred height of the control. 178 * respect to the preferred height of the control.
171 * 179 *
172 * Given that the equations for top cast(T) and bottom cast(B) 180 * Given that the equations for top (T) and bottom (B)
173 * of the control in terms of the height of the form cast(X) 181 * of the control in terms of the height of the form (X)
174 * are: 182 * are:
175 * T = AX + B 183 * T = AX + B
176 * B = CX + D 184 * B = CX + D
177 * 185 *
178 * The equation for the height of the control cast(H) 186 * The equation for the height of the control (H)
179 * is bottom cast(B) minus top cast(T) or (H = B - T) or: 187 * is bottom (B) minus top (T) or (H = B - T) or:
180 * 188 *
181 * H = (CX + D) - (AX + B) 189 * H = (CX + D) - (AX + B)
182 * 190 *
183 * Solving for cast(X), the height of the form, we get: 191 * Solving for (X), the height of the form, we get:
184 * 192 *
185 * X = (H + B - D) / (C - A) 193 * X = (H + B - D) / (C - A)
186 * 194 *
187 * When (A = C), (C - A = 0) and the equation has no 195 * When (A = C), (C - A = 0) and the equation has no
188 * solution for X. This is a special case meaning that 196 * solution for X. This is a special case meaning that
189 * the control does not constrain the height of the 197 * the control does not constrain the height of the
190 * form. In this case, we need to arbitrarily define 198 * form. In this case, we need to arbitrarily define
191 * the height of the form cast(X): 199 * the height of the form (X):
192 * 200 *
193 * Case 1: A = C, A = 0, C = 0 201 * Case 1: A = C, A = 0, C = 0
194 * 202 *
195 * Let X = D, the distance from the top of the form 203 * Let X = D, the distance from the top of the form
196 * to the bottom edge of the control. In this case, 204 * to the bottom edge of the control. In this case,
197 * the control was attached to the top of the form 205 * the control was attached to the top of the form
198 * and the form needs to be large enough to show the 206 * and the form needs to be large enough to show the
199 * bottom edge of the control. 207 * bottom edge of the control.
200 * 208 *
201 * Case 2: A = C, A = 1, C = 1 209 * Case 2: A = C, A = 1, C = 1
202 * 210 *
203 * Let X = -B, the distance from the bottom of the 211 * Let X = -B, the distance from the bottom of the
204 * form to the top edge of the control. In this case, 212 * form to the top edge of the control. In this case,
205 * the control was attached to the bottom of the form 213 * the control was attached to the bottom of the form
206 * and the only way that the control would be visible 214 * and the only way that the control would be visible
207 * is if the offset is negative. If the offset is 215 * is if the offset is negative. If the offset is
208 * positive, there is no possible height for the form 216 * positive, there is no possible height for the form
209 * that will show the control as it will always be 217 * that will show the control as it will always be
210 * below the bottom edge of the form. 218 * below the bottom edge of the form.
211 * 219 *
212 * Case 3: A = C, A !is 0, C !is 0 and A !is 1, C !is 0 220 * Case 3: A = C, A !is 0, C !is 0 and A !is 1, C !is 0
213 * 221 *
214 * Let X = D / (1 - C), the distance from the top of the 222 * Let X = D / (1 - C), the distance from the top of the
215 * form to the bottom edge of the control. In this case, 223 * form to the bottom edge of the control. In this case,
216 * since C is not 0 or 1, it must be a fraction, U / V. 224 * since C is not 0 or 1, it must be a fraction, U / V.
217 * The offset D is the distance from CX to the bottom edge 225 * The offset D is the distance from CX to the bottom edge
218 * of the control. This represents a fraction of the form 226 * of the control. This represents a fraction of the form
219 * (1 - C)X. Since the height of a fraction of the form is 227 * (1 - C)X. Since the height of a fraction of the form is
220 * known, the height of the entire form can be found by setting 228 * known, the height of the entire form can be found by setting
221 * (1 - C)X = D. We solve this equation for X in terms of U 229 * (1 - C)X = D. We solve this equation for X in terms of U
222 * and V, giving us X = (U * D) / (U - V). Similarly, if the 230 * and V, giving us X = (U * D) / (U - V). Similarly, if the
223 * offset D is negative, the control is positioned above CX. 231 * offset D is negative, the control is positioned above CX.
224 * The offset -B is the distance from the top edge of the control 232 * The offset -B is the distance from the top edge of the control
225 * to CX. We can find the height of the entire form by setting 233 * to CX. We can find the height of the entire form by setting
226 * CX = -B. Solving in terms of U and V gives us X = (-B * V) / U. 234 * CX = -B. Solving in terms of U and V gives us X = (-B * V) / U.
227 */ 235 */
228 int computeHeight (Control control, FormData data, bool flushCache) { 236 int computeHeight (Control control, FormData data, bool flushCache) {
229 FormAttachment top = data.getTopAttachment (control, spacing, flushCache); 237 FormAttachment top = data.getTopAttachment (control, spacing, flushCache);
230 FormAttachment bottom = data.getBottomAttachment (control, spacing, flushCache); 238 FormAttachment bottom = data.getBottomAttachment (control, spacing, flushCache);
233 if (bottom.numerator is 0) return bottom.offset; 241 if (bottom.numerator is 0) return bottom.offset;
234 if (bottom.numerator is bottom.denominator) return -top.offset; 242 if (bottom.numerator is bottom.denominator) return -top.offset;
235 if (bottom.offset <= 0) { 243 if (bottom.offset <= 0) {
236 return -top.offset * top.denominator / bottom.numerator; 244 return -top.offset * top.denominator / bottom.numerator;
237 } 245 }
238 int divider = bottom.denominator - bottom.numerator; 246 int divider = bottom.denominator - bottom.numerator;
239 return bottom.denominator * bottom.offset / divider; 247 return bottom.denominator * bottom.offset / divider;
240 } 248 }
241 return height.solveY (data.getHeight (control, flushCache)); 249 return height.solveY (data.getHeight (control, flushCache));
242 } 250 }
243 251
244 protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) { 252 override protected Point computeSize (Composite composite, int wHint, int hHint, bool flushCache) {
245 Point size = layout (composite, false, 0, 0, wHint, hHint, flushCache); 253 Point size = layout (composite, false, 0, 0, wHint, hHint, flushCache);
246 if (wHint !is DWT.DEFAULT) size.x = wHint; 254 if (wHint !is DWT.DEFAULT) size.x = wHint;
247 if (hHint !is DWT.DEFAULT) size.y = hHint; 255 if (hHint !is DWT.DEFAULT) size.y = hHint;
248 return size; 256 return size;
249 } 257 }
250 258
251 protected bool flushCache (Control control) { 259 override protected bool flushCache (Control control) {
252 Object data = control.getLayoutData (); 260 Object data = control.getLayoutData ();
253 if (data !is null) (cast(FormData) data).flushCache (); 261 if (data !is null) (cast(FormData) data).flushCache ();
254 return true; 262 return true;
255 } 263 }
256 264
257 String getName () { 265 String getName () {
258 String string = getClass ().getName (); 266 String string = this.classinfo.name;
259 int index = string.lastIndexOf ('.'); 267 int index = string.lastIndexOf('.');
260 if (index is -1) return string; 268 if (index is -1 ) return string;
261 return string.substring (index + 1, string.length ()); 269 return string[ index + 1 .. string.length ];
262 } 270 }
263 271
264 /* 272 /*
265 * Computes the preferred height of the form with 273 * Computes the preferred height of the form with
266 * respect to the preferred height of the control. 274 * respect to the preferred height of the control.
273 if (right.numerator is 0) return right.offset; 281 if (right.numerator is 0) return right.offset;
274 if (right.numerator is right.denominator) return -left.offset; 282 if (right.numerator is right.denominator) return -left.offset;
275 if (right.offset <= 0) { 283 if (right.offset <= 0) {
276 return -left.offset * left.denominator / left.numerator; 284 return -left.offset * left.denominator / left.numerator;
277 } 285 }
278 int divider = right.denominator - right.numerator; 286 int divider = right.denominator - right.numerator;
279 return right.denominator * right.offset / divider; 287 return right.denominator * right.offset / divider;
280 } 288 }
281 return width.solveY (data.getWidth (control, flushCache)); 289 return width.solveY (data.getWidth (control, flushCache));
282 } 290 }
283 291
284 protected void layout (Composite composite, bool flushCache) { 292 override protected void layout (Composite composite, bool flushCache) {
285 Rectangle rect = composite.getClientArea (); 293 Rectangle rect = composite.getClientArea ();
286 int x = rect.x + marginLeft + marginWidth; 294 int x = rect.x + marginLeft + marginWidth;
287 int y = rect.y + marginTop + marginHeight; 295 int y = rect.y + marginTop + marginHeight;
288 int width = Math.max (0, rect.width - marginLeft - 2 * marginWidth - marginRight); 296 int width = Math.max (0, rect.width - marginLeft - 2 * marginWidth - marginRight);
289 int height = Math.max (0, rect.height - marginTop - 2 * marginHeight - marginBottom); 297 int height = Math.max (0, rect.height - marginTop - 2 * marginHeight - marginBottom);
311 FormAttachment right = data.getRightAttachment (child, spacing, flushCache); 319 FormAttachment right = data.getRightAttachment (child, spacing, flushCache);
312 int x1 = left.solveX (width), x2 = right.solveX (width); 320 int x1 = left.solveX (width), x2 = right.solveX (width);
313 if (data.height is DWT.DEFAULT && !data.needed) { 321 if (data.height is DWT.DEFAULT && !data.needed) {
314 int trim = 0; 322 int trim = 0;
315 //TEMPORARY CODE 323 //TEMPORARY CODE
316 if ( null !is cast(Scrollable)child ) { 324 if ( auto sa = cast(Scrollable)child) {
317 Rectangle rect = (cast(Scrollable) child).computeTrim (0, 0, 0, 0); 325 Rectangle rect = sa.computeTrim (0, 0, 0, 0);
318 trim = rect.width; 326 trim = rect.width;
319 } else { 327 } else {
320 trim = child.getBorderWidth () * 2; 328 trim = child.getBorderWidth () * 2;
321 } 329 }
322 data.cacheWidth = data.cacheHeight = -1; 330 data.cacheWidth = data.cacheHeight = -1;
371 * Returns a string containing a concise, human-readable 379 * Returns a string containing a concise, human-readable
372 * description of the receiver. 380 * description of the receiver.
373 * 381 *
374 * @return a string representation of the layout 382 * @return a string representation of the layout
375 */ 383 */
376 public String toString () { 384 override public String toString () {
377 String string = getName ()+" {"; 385 String string = getName ()~" {";
378 if (marginWidth !is 0) string += "marginWidth="+marginWidth+" "; 386 if (marginWidth !is 0) string ~= "marginWidth="~to!(String)(marginWidth)~" ";
379 if (marginHeight !is 0) string += "marginHeight="+marginHeight+" "; 387 if (marginHeight !is 0) string ~= "marginHeight="~to!(String)(marginHeight)~" ";
380 if (marginLeft !is 0) string += "marginLeft="+marginLeft+" "; 388 if (marginLeft !is 0) string ~= "marginLeft="~to!(String)(marginLeft)~" ";
381 if (marginRight !is 0) string += "marginRight="+marginRight+" "; 389 if (marginRight !is 0) string ~= "marginRight="~to!(String)(marginRight)~" ";
382 if (marginTop !is 0) string += "marginTop="+marginTop+" "; 390 if (marginTop !is 0) string ~= "marginTop="~to!(String)(marginTop)~" ";
383 if (marginBottom !is 0) string += "marginBottom="+marginBottom+" "; 391 if (marginBottom !is 0) string ~= "marginBottom="~to!(String)(marginBottom)~" ";
384 if (spacing !is 0) string += "spacing="+spacing+" "; 392 if (spacing !is 0) string ~= "spacing="~to!(String)(spacing)~" ";
385 string = string.trim(); 393 string = string.trim();
386 string += "}"; 394 string ~= "}";
387 return string; 395 return string;
388 } 396 }
389 } 397 }