001: /*******************************************************************************
002: * Copyright (c) 2004, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.layout;
011:
012: import org.eclipse.swt.SWT;
013: import org.eclipse.swt.graphics.Point;
014: import org.eclipse.swt.graphics.Rectangle;
015: import org.eclipse.swt.layout.GridData;
016:
017: /**
018: * <code>CellData</code> is the layout data object associated with
019: * <code>CellLayout</code>. You can attach a CellData object to a
020: * control by using the <code>setLayoutData</code> method. CellData
021: * objects are optional. If you do not attach any layout data to a control,
022: * it will behave just like attaching a CellData created using its default
023: * constructor.
024: *
025: * @since 3.0
026: **/
027: public final class CellData {
028:
029: /**
030: * hintType flag (value = 0) indicating that the control's computeSize method should be used
031: * to determine the control size. If modifierType is set to NONE, then the widthHint
032: * and heightHint fields will be ignored.
033: */
034: public final static int NONE = 0;
035:
036: /**
037: * hintType flag (value = 1) indicating that the widthHint and heightHint should be used
038: * as the control's size instead of the result of computeSize
039: * <p>
040: * This flag is useful for list boxes, text boxes, tree controls, and other controls
041: * whose contents can change dynamically. For example, create a tree control and set
042: * its width and height hints to the default size for that control. This will cause
043: * the hints to be used instead of the preferred size of the tree control.</p>
044: */
045: public final static int OVERRIDE = 1;
046:
047: /**
048: * hintType(value = 2) indicating that the width of the control should be no less than
049: * widthHint (if provided) and the height of the control should be no less
050: * than heightHint (if provided).
051: * <p>
052: * This flag is useful for buttons. For example, set the width and height hints to
053: * the default button size. This will use the default button size unless the button
054: * label is too large to fit on the button.
055: * </p>
056: */
057: public final static int MINIMUM = 2;
058:
059: /**
060: * hintType flag (value = 3) indicating that the width of the control should be no more than
061: * widthHint (if provided) and the height of the control should be no more
062: * than heightHint (if provided).
063: * <p>
064: * This flag is useful for wrapping text. For example, set heightHint to SWT.DEFAULT
065: * and set widthHint to the desired number of pixels after which text should wrap. This
066: * will cause the text to wrap after the given number of pixels, but will not allocate
067: * extra space in the column if the text widget does not fill an entire line.
068: * </p>
069: */
070: public final static int MAXIMUM = 3;
071:
072: /**
073: * This flag controls how the width and height hints are to be treated. See the constants
074: * above.
075: */
076: public int hintType = OVERRIDE;
077:
078: /**
079: * Width hint. This modifies the width of the control, in pixels. If set to SWT.DEFAULT,
080: * this dimension will not be constrained. Depending on the value of modifierType,
081: * this may be a minimum size, a maximum size, or simply replace the preferred control
082: * size.
083: */
084: public int widthHint = SWT.DEFAULT;
085:
086: /**
087: * Height hint. This modifies the height of the control, in pixels. If set to SWT.DEFAULT,
088: * this dimension will not be constrained. Depending on the value of modifierType,
089: * this will be a minimum size, a maximum size, or a replacement for the control's preferred
090: * size.
091: */
092: public int heightHint = SWT.DEFAULT;
093:
094: /**
095: * Number of rows spanned by this cell (default = 1)
096: */
097: public int verticalSpan = 1;
098:
099: /**
100: * Number of columns spanned by this cell (default = 1)
101: */
102: public int horizontalSpan = 1;
103:
104: /**
105: * Horizontal alignment of the control within the cell. May be one
106: * of SWT.LEFT, SWT.RIGHT, SWT.CENTER, or SWT.NORMAL. SWT.NORMAL indicates
107: * that the control should be made as wide as the cell.
108: */
109: public int horizontalAlignment = SWT.FILL;
110:
111: /**
112: * Vertical alignment of the control within the cell. May be one of
113: * SWT.TOP, SWT.BOTTOM, SWT.CENTER, or SWT.NORMAL. SWT.NORMAL indicates
114: * that the control should be made as wide as the cell.
115: */
116: public int verticalAlignment = SWT.FILL;
117:
118: /**
119: * Horizontal indentation (pixels). Positive values move the control
120: * to the right, negative to the left.
121: */
122: public int horizontalIndent = 0;
123:
124: /**
125: * Vertical indentation (pixels). Positive values move the control
126: * down, negative values move the control up.
127: */
128: public int verticalIndent = 0;
129:
130: /**
131: * Constructs a CellData with default properties
132: */
133: public CellData() {
134: // Use the default values for all fields.
135: }
136:
137: /**
138: * Creates a new CellData that with properties that are as close as possible to
139: * the given GridData. This is used for converting GridLayouts into CellLayouts.
140: *
141: * @param data
142: */
143: public CellData(GridData data) {
144: verticalSpan = data.verticalSpan;
145: horizontalSpan = data.horizontalSpan;
146:
147: switch (data.horizontalAlignment) {
148: case GridData.BEGINNING:
149: horizontalAlignment = SWT.LEFT;
150: break;
151: case GridData.CENTER:
152: horizontalAlignment = SWT.CENTER;
153: break;
154: case GridData.END:
155: horizontalAlignment = SWT.RIGHT;
156: break;
157: case GridData.FILL:
158: horizontalAlignment = SWT.FILL;
159: break;
160: }
161:
162: switch (data.verticalAlignment) {
163: case GridData.BEGINNING:
164: verticalAlignment = SWT.LEFT;
165: break;
166: case GridData.CENTER:
167: verticalAlignment = SWT.CENTER;
168: break;
169: case GridData.END:
170: verticalAlignment = SWT.RIGHT;
171: break;
172: case GridData.FILL:
173: verticalAlignment = SWT.FILL;
174: break;
175: }
176:
177: widthHint = data.widthHint;
178: heightHint = data.heightHint;
179: horizontalIndent = data.horizontalIndent;
180: hintType = OVERRIDE;
181: }
182:
183: /**
184: * Copies the given CellData
185: *
186: * @param newData
187: */
188: public CellData(CellData newData) {
189: hintType = newData.hintType;
190: widthHint = newData.widthHint;
191: heightHint = newData.heightHint;
192: horizontalAlignment = newData.horizontalAlignment;
193: verticalAlignment = newData.verticalAlignment;
194: horizontalSpan = newData.horizontalSpan;
195: verticalSpan = newData.verticalSpan;
196: }
197:
198: /**
199: * Sets the size hint for this control. This is used to modify the control's
200: * preferred size. If one dimension should remain unmodified, that hint can be
201: * set to SWT.DEFAULT. Using a size hint of CellData.MINIMUM ensures that the preferred
202: * control size is larger than the hint. Using a size hint of CellData.MAXIMUM ensures
203: * that the preferred size is smaller than the hint. Using a size hint of CellData.OVERRIDE
204: * ensures that the preferred size is always equal to the hint.
205: *
206: * @param hintType one of CellData.MINIMUM, CellData.MAXIMUM, or CellData.OVERRIDE
207: * @param hint size hint (in pixels). If either dimension is set to SWT.DEFAULT, the
208: * hint will not affect that dimension
209: * @return this
210: */
211: public CellData setHint(int hintType, Point hint) {
212: return setHint(hintType, hint.x, hint.y);
213: }
214:
215: /**
216: * Sets the size hint for this control. This is used to modify the control's
217: * preferred size. If one dimension should remain unmodified, that hint can be
218: * set to SWT.DEFAULT. Using a size hint of CellData.MINIMUM ensures that the preferred
219: * control size is larger than the hint. Using a size hint of CellData.MAXIMUM ensures
220: * that the preferred size is smaller than the hint. Using a size hint of CellData.OVERRIDE
221: * ensures that the preferred size is always equal to the hint. If both hints are equal
222: * to SWT.DEFAULT, then the control's preferred size is unmodified.
223: *
224: * @param hintType one of CellData.MINIMUM, CellData.MAXIMUM, or CellData.OVERRIDE
225: * @param horizontal horizontal hint (pixels). A value of SWT.DEFAULT will leave the result
226: * of the control's computeSize method unmodified.
227: * @param vertical vertical hint (pixels). A value of SWT.DEFAULT will leave the result of
228: * the control's computeSize method unmodified.
229: * @return this
230: */
231: public CellData setHint(int hintType, int horizontal, int vertical) {
232: this .hintType = hintType;
233: this .heightHint = vertical;
234: this .widthHint = horizontal;
235:
236: return this ;
237: }
238:
239: /**
240: * Sets the alignment for this control
241: *
242: * @param horizontalAlignment one of SWT.LEFT, SWT.RIGHT, SWT.FILL, or SWT.CENTER
243: * @param verticalAlignment one of SWT.TOP, SWT.BOTTOM, SWT.FILL, or SWT.CENTER
244: * @return this
245: */
246: public CellData align(int horizontalAlignment, int verticalAlignment) {
247: this .horizontalAlignment = horizontalAlignment;
248: this .verticalAlignment = verticalAlignment;
249:
250: return this ;
251: }
252:
253: /**
254: * Sets the number of rows and columns spanned by this control.
255: *
256: * @param horizontalSpan number of columns spanned by the control (> 0)
257: * @param verticalSpan number of rows spanned by the control (> 0)
258: * @return this
259: */
260: public CellData span(int horizontalSpan, int verticalSpan) {
261: this .horizontalSpan = horizontalSpan;
262: this .verticalSpan = verticalSpan;
263:
264: return this ;
265: }
266:
267: /**
268: * Sets the indentation for this control. The indentation is added to
269: * the control's position within the cell. For example, indentation of
270: * (10,4) will move the control right by 10 pixels and down by 4 pixels.
271: *
272: * @param indent indentation (pixels)
273: * @return this
274: */
275: public CellData indent(Point indent) {
276: return this .indent(indent.x, indent.y);
277: }
278:
279: /**
280: * Sets the indentation for this cell
281: *
282: * @param horizontalIndent distance (pixels) to move the control to the right
283: * @param verticalIndent distance (pixels) to move the control down
284: * @return this
285: */
286: public CellData indent(int horizontalIndent, int verticalIndent) {
287: this .horizontalIndent = horizontalIndent;
288: this .verticalIndent = verticalIndent;
289:
290: return this ;
291: }
292:
293: /**
294: * Returns the preferred size of the given control, given the known dimensions of
295: * its cell.
296: *
297: * @param toCompute the control whose size is to be computed
298: * @param cellWidth width of the cell, in pixels (or SWT.DEFAULT if unknown)
299: * @param cellHeight height of the cell, in pixels (or SWT.DEFAULT if unknown)
300: * @return the preferred size of the given control, in pixels
301: */
302: public Point computeSize(SizeCache toCompute, int cellWidth,
303: int cellHeight) {
304:
305: int absHorizontalIndent = Math.abs(horizontalIndent);
306: int absVerticalIndent = Math.abs(verticalIndent);
307:
308: // If we're going to indent, subtract off the space that will be required for indentation from
309: // the available space
310: if (cellWidth != SWT.DEFAULT) {
311: cellWidth -= absHorizontalIndent;
312: }
313:
314: if (cellHeight != SWT.DEFAULT) {
315: cellHeight -= absVerticalIndent;
316: }
317:
318: int controlWidth = horizontalAlignment == SWT.FILL ? cellWidth
319: : SWT.DEFAULT;
320: int controlHeight = verticalAlignment == SWT.FILL ? cellHeight
321: : SWT.DEFAULT;
322:
323: // Note: this could be optimized further. If we're using a MAXIMUM hint and
324: // non-FILL alignment, we could simply call computeMaximumBoundedSize using the
325: // minimum of the cell size and the hint as the boundary -- basically, rather
326: // than applying two limits for the hint and the cell boundary, we can do it in
327: // one step and reduce the size computations by half (for this specific case).
328: Point controlSize = computeControlSize(toCompute, controlWidth,
329: controlHeight);
330:
331: if (cellWidth != SWT.DEFAULT && controlSize.x > cellWidth) {
332: controlSize = computeControlSize(toCompute, cellWidth,
333: controlHeight);
334: if (cellHeight != SWT.DEFAULT && controlSize.y > cellHeight) {
335: controlSize.y = cellHeight;
336: }
337: } else if (cellHeight != SWT.DEFAULT
338: && controlSize.y > cellHeight) {
339: controlSize = computeControlSize(toCompute, controlWidth,
340: cellHeight);
341: if (cellWidth != SWT.DEFAULT && controlSize.x > cellWidth) {
342: controlSize.x = cellWidth;
343: }
344: }
345:
346: // If we're going to indent, add the indentation to the required space
347: controlSize.x += absHorizontalIndent;
348: controlSize.y += absVerticalIndent;
349:
350: return controlSize;
351: }
352:
353: /**
354: * Arranges the given control within the given rectangle using the
355: * criteria described by this CellData.
356: *
357: * @param control
358: * @param cellBounds
359: * @since 3.0
360: */
361: public void positionControl(SizeCache cache, Rectangle cellBounds) {
362:
363: int startx = cellBounds.x;
364: int starty = cellBounds.y;
365: int availableWidth = cellBounds.width - horizontalIndent;
366: int availableHeight = cellBounds.height - verticalIndent;
367:
368: Point size = computeSize(cache, availableWidth, availableHeight);
369:
370: // Horizontal justification
371: switch (horizontalAlignment) {
372: case SWT.RIGHT:
373: startx = cellBounds.x + availableWidth - size.x;
374: break;
375: case SWT.CENTER:
376: startx = cellBounds.x + (availableWidth - size.x) / 2;
377: break;
378: }
379:
380: // Vertical justification
381: switch (verticalAlignment) {
382: case SWT.BOTTOM:
383: starty = cellBounds.y + availableHeight - size.y;
384: break;
385: case SWT.CENTER:
386: starty = cellBounds.y + (availableHeight - size.y) / 2;
387: break;
388: }
389:
390: // Position the control
391: cache.getControl().setBounds(startx + horizontalIndent,
392: starty + verticalIndent, size.x, size.y);
393: }
394:
395: /**
396: * Returns the preferred size of the given control in this cell, given one or both
397: * known dimensions of the control. This differs from computeSize, which takes known
398: * dimensions of the <b>cell</b> as arguments.
399: *
400: * @param toCompute
401: * @param controlWidth
402: * @param controlHeight
403: * @return
404: * @since 3.0
405: */
406: private Point computeControlSize(SizeCache toCompute,
407: int controlWidth, int controlHeight) {
408: switch (hintType) {
409: case OVERRIDE:
410: return computeOverrideSize(toCompute, controlWidth,
411: controlHeight, widthHint, heightHint);
412: case MINIMUM:
413: return computeMinimumBoundedSize(toCompute, controlWidth,
414: controlHeight, widthHint, heightHint);
415: case MAXIMUM:
416: return computeMaximumBoundedSize(toCompute, controlWidth,
417: controlHeight, widthHint, heightHint);
418: }
419:
420: return computeRawSize(toCompute, controlWidth, controlHeight);
421: }
422:
423: /**
424: * Computes the size of the control, given its outer dimensions. This should be used in
425: * place of calling Control.computeSize, since Control.computeSize takes control-specific
426: * inner dimensions as hints.
427: *
428: * @param toCompute Control whose size will be computed
429: * @param controlWidth width of the control (pixels or SWT.DEFAULT if unknown)
430: * @param controlHeight height of the control (pixels or SWT.DEFAULT if unknown)
431: * @return preferred dimensions of the control
432: */
433: private static Point computeRawSize(SizeCache toCompute,
434: int controlWidth, int controlHeight) {
435: if (controlWidth != SWT.DEFAULT && controlHeight != SWT.DEFAULT) {
436: return new Point(controlWidth, controlHeight);
437: }
438:
439: // Known bug: we pass the OUTER dimension of the control into computeSize, even though
440: // SWT expects a control-specific inner dimension as width and height hints. Currently,
441: // SWT does not provide any means to convert outer dimensions into inner dimensions.
442: // Fortunately, the outer and inner dimensions tend to be quite close so we
443: // pass in the outer dimension and adjust the result if it differs from one of the
444: // hints. This may cause incorrect text wrapping in rare cases, and should be fixed
445: // once SWT provides a way to convert the outer dimension of a control into a valid
446: // width or height hint for Control.computeSize. Note that the distinction between outer
447: // and inner dimensions is undocumented in SWT, and most examples also contain this
448: // bug.
449: Point result = toCompute.computeSize(controlWidth,
450: controlHeight);
451:
452: // Hack: If the result of computeSize differs from the width or height-hints, adjust it.
453: // See above. Don't remove this hack until SWT provides some way to pass correct width
454: // and height hints into computeSize. Once this happens, these conditions should always
455: // return false and the hack will have no effect.
456: if (controlWidth != SWT.DEFAULT) {
457: result.x = controlWidth;
458: } else if (controlHeight != SWT.DEFAULT) {
459: result.y = controlHeight;
460: }
461:
462: return result;
463: }
464:
465: /**
466: * Computes the preferred size of the control. Optionally, one or both dimensions
467: * may be fixed to a given size.
468: *
469: * @param control object that can compute the size of the control of interest
470: * @param wHint known width (or SWT.DEFAULT if the width needs to be computed)
471: * @param hHint known height (or SWT.DEFAULT if the height needs to be computed)
472: * @param overrideW width that should always be returned by the control,
473: * or SWT.DEFAULT if the width is not being constrained
474: * @param overrideH height that should always be returned by the control,
475: * or SWT.DEFAULT if the height is not being constrained
476: * @return
477: */
478: private static Point computeOverrideSize(SizeCache control,
479: int wHint, int hHint, int overrideW, int overrideH) {
480: int resultWidth = overrideW;
481: int resultHeight = overrideH;
482:
483: if (wHint != SWT.DEFAULT) {
484: resultWidth = wHint;
485: }
486:
487: if (hHint != SWT.DEFAULT) {
488: resultHeight = hHint;
489: }
490:
491: if (resultWidth == SWT.DEFAULT || resultHeight == SWT.DEFAULT) {
492: Point result = computeRawSize(control, resultWidth,
493: resultHeight);
494:
495: return result;
496: }
497:
498: return new Point(resultWidth, resultHeight);
499: }
500:
501: /**
502: * Computes the size for the control, optionally bounding the size in the x and
503: * y directions. The various hints are used to determine which dimensions are
504: * already known and which dimensions need to be computed.
505: *
506: * @param control The control whose size should be computed
507: * @param wHint known width (or SWT.DEFAULT if the width needs to be computed)
508: * @param hHint known height (or SWT.DEFAULT if the height needs to be computed)
509: * @param boundedWidth maximum width for the control (or SWT.DEFAULT if the width is unbounded)
510: * @param boundedHeight maximum height for the control (or SWT.DEFAULT if the height is unbounded)
511: * @return the preferred size of the control, given that it cannot exceed the given bounds
512: */
513: private static Point computeMaximumBoundedSize(SizeCache control,
514: int wHint, int hHint, int boundedWidth, int boundedHeight) {
515: Point controlSize = computeRawSize(control, wHint, hHint);
516:
517: if (wHint == SWT.DEFAULT && boundedWidth != SWT.DEFAULT
518: && controlSize.x > boundedWidth) {
519: return computeMaximumBoundedSize(control, boundedWidth,
520: hHint, boundedWidth, boundedHeight);
521: }
522:
523: if (hHint == SWT.DEFAULT && boundedHeight != SWT.DEFAULT
524: && controlSize.y > boundedHeight) {
525: return computeMaximumBoundedSize(control, wHint,
526: boundedHeight, boundedWidth, boundedHeight);
527: }
528:
529: return controlSize;
530: }
531:
532: private static Point computeMinimumBoundedSize(SizeCache control,
533: int wHint, int hHint, int minimumWidth, int minimumHeight) {
534:
535: Point controlSize = computeRawSize(control, wHint, hHint);
536:
537: if (minimumWidth != SWT.DEFAULT && wHint == SWT.DEFAULT
538: && controlSize.x < minimumWidth) {
539: return computeMinimumBoundedSize(control, minimumWidth,
540: hHint, minimumWidth, minimumHeight);
541: }
542:
543: if (minimumHeight != SWT.DEFAULT && hHint == SWT.DEFAULT
544: && controlSize.y < minimumHeight) {
545: return computeMinimumBoundedSize(control, wHint,
546: minimumHeight, minimumWidth, minimumHeight);
547: }
548:
549: return controlSize;
550: }
551:
552: }
|