summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteffen Pingel2013-04-27 11:53:31 (EDT)
committerSteffen Pingel2013-04-27 11:53:31 (EDT)
commite08ca15862ce9048b24563487ab3cbe3dc567fd3 (patch)
treeeff5d1959d4ed43e73f0fceeeaf892aa6364c13d
parent63affb5792c41444db7597554591bc67cca1c99b (diff)
downloadorg.eclipse.mylyn.commons-e08ca15862ce9048b24563487ab3cbe3dc567fd3.zip
org.eclipse.mylyn.commons-e08ca15862ce9048b24563487ab3cbe3dc567fd3.tar.gz
org.eclipse.mylyn.commons-e08ca15862ce9048b24563487ab3cbe3dc567fd3.tar.bz2
385332: [api] make FillWidthLayout publicrefs/changes/83/12283/1
Change-Id: I591df04447a39367a36f02d1bb73901578e87b46 Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=385332
-rw-r--r--org.eclipse.mylyn.commons.ui/src/org/eclipse/mylyn/commons/ui/FillWidthLayout.java240
1 files changed, 240 insertions, 0 deletions
diff --git a/org.eclipse.mylyn.commons.ui/src/org/eclipse/mylyn/commons/ui/FillWidthLayout.java b/org.eclipse.mylyn.commons.ui/src/org/eclipse/mylyn/commons/ui/FillWidthLayout.java
new file mode 100644
index 0000000..e408ccb
--- /dev/null
+++ b/org.eclipse.mylyn.commons.ui/src/org/eclipse/mylyn/commons/ui/FillWidthLayout.java
@@ -0,0 +1,240 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2010 David Green and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * David Green - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.mylyn.commons.ui;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.ScrolledComposite;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.ScrollBar;
+import org.eclipse.ui.forms.widgets.ILayoutExtension;
+import org.eclipse.ui.forms.widgets.Section;
+
+/**
+ * A layout that uses the width hint or client area of a composite to recommend the width of its children, allowing
+ * children to fill the width and specify their preferred height for a given width. Intended for use with a composite
+ * that contains a single child that should fill available horizontal space.
+ *
+ * @author David Green
+ * @since 3.9
+ */
+public class FillWidthLayout extends Layout implements ILayoutExtension {
+
+ private final int marginLeft;
+
+ private final int marginRight;
+
+ private final int marginTop;
+
+ private final int marginBottom;
+
+ private final int widthHintMargin;
+
+ private Composite layoutAdvisor;
+
+ private int lastWidthHint;
+
+ private Point lastComputedSize;
+
+ /**
+ * Creates an instance with no margin.
+ */
+ public FillWidthLayout() {
+ this(0, 0, 0, 0);
+ }
+
+ /**
+ * Creates an instance with specifying margins.
+ *
+ * @param marginLeft
+ * the left margin in pixels, or 0 if there should be none
+ * @param marginRight
+ * the right margin in pixels, or 0 if there should be none
+ * @param marginTop
+ * the top margin in pixels, or 0 if there should be none
+ * @param marginBottom
+ * the bottom margin in pixels, or 0 if there should be none
+ */
+ public FillWidthLayout(int marginLeft, int marginRight, int marginTop, int marginBottom) {
+ this(null, marginLeft, marginRight, marginTop, marginBottom);
+ }
+
+ /**
+ * Creates an instance with specifying margins and a {@link #getLayoutAdvisor() layout advisor}.
+ *
+ * @param layoutAdvisor
+ * the composite that is used to advise on layout based on its {@link Composite#getClientArea() client
+ * area}.
+ * @param marginLeft
+ * the left margin in pixels, or 0 if there should be none
+ * @param marginRight
+ * the right margin in pixels, or 0 if there should be none
+ * @param marginTop
+ * the top margin in pixels, or 0 if there should be none
+ * @param marginBottom
+ * the bottom margin in pixels, or 0 if there should be none
+ */
+ public FillWidthLayout(Composite layoutAdvisor, int marginLeft, int marginRight, int marginTop, int marginBottom) {
+ this.layoutAdvisor = layoutAdvisor;
+ this.marginLeft = marginLeft;
+ this.marginRight = marginRight;
+ this.marginTop = marginTop;
+ this.marginBottom = marginBottom;
+ if (Platform.OS_MACOSX.equals(Platform.getOS())) {
+ this.widthHintMargin = 15;
+ } else {
+ this.widthHintMargin = 18;
+ }
+ }
+
+ /**
+ * Calculate the client area of the given container, accommodating for insets and margins.
+ */
+ private int calculateWidthHint(Composite container) {
+ return calculateWidthHint(container, layoutAdvisor == null);
+ }
+
+ /**
+ * Calculate the client area of the given container, accommodating for insets and margins.
+ */
+ private int calculateWidthHint(Composite container, boolean layoutAdvisorHit) {
+ if (container == layoutAdvisor) {
+ layoutAdvisorHit = true;
+ }
+ Rectangle clientArea = container.getClientArea();
+ int horizontalMargin = 0;
+ if (clientArea.width <= 1 || !layoutAdvisorHit) { // sometimes client area is incorrectly reported as 1
+ clientArea.width = calculateWidthHint(container.getParent(), layoutAdvisorHit);
+ }
+ Layout bodyLayout = container.getLayout();
+ if (bodyLayout instanceof GridLayout) {
+ GridLayout gridLayout = (GridLayout) bodyLayout;
+ horizontalMargin = (gridLayout.marginWidth * 2) + gridLayout.marginLeft + gridLayout.marginRight;
+ } else if (bodyLayout instanceof FillLayout) {
+ FillLayout fillLayout = (FillLayout) bodyLayout;
+ horizontalMargin = fillLayout.marginWidth * 2;
+ } else if (container instanceof Section) {
+ horizontalMargin = ((Section) container).marginWidth * 2;
+ } else if (container instanceof CTabFolder) {
+ CTabFolder folder = (CTabFolder) container;
+ horizontalMargin = folder.marginWidth * 2;
+ }
+ if (container instanceof ScrolledComposite) {
+ ScrolledComposite composite = (ScrolledComposite) container;
+ ScrollBar verticalBar = composite.getVerticalBar();
+ if (verticalBar != null) {
+ int verticalBarWidth = verticalBar.getSize().x;
+ horizontalMargin += Math.max(15, verticalBarWidth);
+ }
+ }
+ return clientArea.width - horizontalMargin;
+ }
+
+ @Override
+ protected Point computeSize(Composite composite, int widthHint, int heightHint, boolean flushCache) {
+ Control[] children = composite.getChildren();
+ if (children.length == 0) {
+ return new Point(0, 0);
+ }
+ if (widthHint <= 0) {
+ widthHint = calculateWidthHint(composite);
+ widthHint -= widthHintMargin;
+ }
+
+ int horizontalMargin = marginLeft + marginRight;
+ if (widthHint < horizontalMargin) {
+ widthHint = horizontalMargin;
+ }
+
+ if (lastComputedSize == null || widthHint != lastWidthHint) {
+ int resultX = 1;
+ int resultY = 1;
+ int controlWidthHint = Math.max(horizontalMargin, widthHint - horizontalMargin - 2);
+ for (Control control : children) {
+ Point sz = control.computeSize(controlWidthHint, -1, true);
+ resultX = Math.max(resultX, sz.x);
+ resultY = Math.max(resultY, sz.y);
+ }
+
+ lastWidthHint = widthHint;
+ lastComputedSize = new Point(resultX + horizontalMargin, resultY + marginTop + marginBottom);
+ }
+ return new Point(lastComputedSize.x, lastComputedSize.y + 1);
+ }
+
+ @Override
+ protected void layout(Composite composite, boolean flushCache) {
+ Rectangle area = composite.getClientArea();
+ if (area.width == 0) {
+ area.width = calculateWidthHint(composite);
+ }
+
+ // account for margins
+ area.x += marginLeft;
+ area.y += marginTop;
+ area.width -= (marginRight + marginLeft);
+ area.height -= (marginBottom + marginTop);
+
+ Control[] children = composite.getChildren();
+ for (Control control : children) {
+ control.setBounds(area);
+ }
+ }
+
+ /**
+ * Returns the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}
+ * .
+ *
+ * @return the layout advisor, or null if there is none
+ */
+ public Composite getLayoutAdvisor() {
+ return layoutAdvisor;
+ }
+
+ /**
+ * Sets the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}.
+ *
+ * @param layoutAdvisor
+ * the layout advisor, or null if there is none
+ */
+ public void setLayoutAdvisor(Composite layoutAdvisor) {
+ this.layoutAdvisor = layoutAdvisor;
+ }
+
+ /**
+ * Flushes all cached information about control sizes.
+ */
+ public void flush() {
+ lastComputedSize = null;
+ }
+
+ public int computeMaximumWidth(Composite parent, boolean changed) {
+ int width = marginLeft + marginRight;
+ Control[] children = parent.getChildren();
+ for (Control control : children) {
+ width = Math.max(control.computeSize(SWT.DEFAULT, 0, changed).x + marginLeft + marginRight, width);
+ }
+ return width;
+ }
+
+ public int computeMinimumWidth(Composite parent, boolean changed) {
+ return marginLeft + marginRight;
+ }
+
+}