Added
Link Here
|
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2004, 2008 David Green 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 |
* David Green - initial API and implementation |
10 |
*******************************************************************************/ |
11 |
|
12 |
package org.eclipse.mylyn.internal.tasks.ui.editors; |
13 |
|
14 |
import org.eclipse.core.runtime.Platform; |
15 |
import org.eclipse.swt.custom.CTabFolder; |
16 |
import org.eclipse.swt.custom.ScrolledComposite; |
17 |
import org.eclipse.swt.graphics.Point; |
18 |
import org.eclipse.swt.graphics.Rectangle; |
19 |
import org.eclipse.swt.layout.FillLayout; |
20 |
import org.eclipse.swt.layout.GridLayout; |
21 |
import org.eclipse.swt.widgets.Composite; |
22 |
import org.eclipse.swt.widgets.Control; |
23 |
import org.eclipse.swt.widgets.Layout; |
24 |
import org.eclipse.swt.widgets.ScrollBar; |
25 |
import org.eclipse.ui.forms.widgets.Section; |
26 |
|
27 |
/** |
28 |
* A layout that uses the width hint or client area of a composite to recommend the width of its children, allowing |
29 |
* children to fill the width and specify their preferred height for a given width. |
30 |
* |
31 |
* Intended for use with a composite that contains a single child that should fill available horizontal space. |
32 |
* |
33 |
* @author David Green |
34 |
*/ |
35 |
public class FillWidthLayout extends Layout { |
36 |
|
37 |
private final int marginLeft; |
38 |
|
39 |
private final int marginRight; |
40 |
|
41 |
private final int marginTop; |
42 |
|
43 |
private final int marginBottom; |
44 |
|
45 |
private int widthHintMargin = 15; |
46 |
|
47 |
private Composite layoutAdvisor; |
48 |
|
49 |
/** |
50 |
* create with 0 margins |
51 |
* |
52 |
*/ |
53 |
public FillWidthLayout() { |
54 |
this(0, 0, 0, 0); |
55 |
} |
56 |
|
57 |
/** |
58 |
* create while specifying margins |
59 |
* |
60 |
* @param marginLeft |
61 |
* the left margin in pixels, or 0 if there should be none |
62 |
* @param marginRight |
63 |
* the right margin in pixels, or 0 if there should be none |
64 |
* @param marginTop |
65 |
* the top margin in pixels, or 0 if there should be none |
66 |
* @param marginBottom |
67 |
* the bottom margin in pixels, or 0 if there should be none |
68 |
*/ |
69 |
public FillWidthLayout(int marginLeft, int marginRight, int marginTop, int marginBottom) { |
70 |
this(null, marginLeft, marginRight, marginTop, marginBottom); |
71 |
} |
72 |
|
73 |
/** |
74 |
* create specifying margins and a {@link #getLayoutAdvisor() layout advisor}. |
75 |
* |
76 |
* @param layoutAdvisor |
77 |
* the composite that is used to advise on layout based on its {@link Composite#getClientArea() client |
78 |
* area}. |
79 |
* @param marginLeft |
80 |
* the left margin in pixels, or 0 if there should be none |
81 |
* @param marginRight |
82 |
* the right margin in pixels, or 0 if there should be none |
83 |
* @param marginTop |
84 |
* the top margin in pixels, or 0 if there should be none |
85 |
* @param marginBottom |
86 |
* the bottom margin in pixels, or 0 if there should be none |
87 |
*/ |
88 |
public FillWidthLayout(Composite layoutAdvisor, int marginLeft, int marginRight, int marginTop, int marginBottom) { |
89 |
this.layoutAdvisor = layoutAdvisor; |
90 |
this.marginLeft = marginLeft; |
91 |
this.marginRight = marginRight; |
92 |
this.marginTop = marginTop; |
93 |
this.marginBottom = marginBottom; |
94 |
if (Platform.OS_MACOSX.equals(Platform.getOS())) { |
95 |
widthHintMargin = 15; |
96 |
} else { |
97 |
widthHintMargin = 25; |
98 |
} |
99 |
} |
100 |
|
101 |
/** |
102 |
* calculate the client area of the given container, accomodating for insets and margins. |
103 |
*/ |
104 |
private int calculateWidthHint(Composite container) { |
105 |
return calculateWidthHint(container, layoutAdvisor == null); |
106 |
} |
107 |
|
108 |
/** |
109 |
* calculate the client area of the given container, accomodating for insets and margins. |
110 |
*/ |
111 |
private int calculateWidthHint(Composite container, boolean layoutAdvisorHit) { |
112 |
if (container == layoutAdvisor) { |
113 |
layoutAdvisorHit = true; |
114 |
} |
115 |
Rectangle clientArea = container.getClientArea(); |
116 |
int horizontalMargin = 0; |
117 |
if (clientArea.width <= 1 || !layoutAdvisorHit) { // sometimes client area is incorrectly reported as 1 |
118 |
clientArea.width = calculateWidthHint(container.getParent(), layoutAdvisorHit); |
119 |
} |
120 |
Layout bodyLayout = container.getLayout(); |
121 |
if (bodyLayout instanceof GridLayout) { |
122 |
GridLayout gridLayout = (GridLayout) bodyLayout; |
123 |
horizontalMargin = (gridLayout.marginWidth * 2) + gridLayout.marginLeft + gridLayout.marginRight; |
124 |
} else if (bodyLayout instanceof FillLayout) { |
125 |
FillLayout fillLayout = (FillLayout) bodyLayout; |
126 |
horizontalMargin = fillLayout.marginWidth * 2; |
127 |
} else if (container instanceof Section) { |
128 |
horizontalMargin = ((Section) container).marginWidth * 2; |
129 |
} else if (container instanceof CTabFolder) { |
130 |
CTabFolder folder = (CTabFolder) container; |
131 |
horizontalMargin = folder.marginWidth * 2; |
132 |
} |
133 |
if (container instanceof ScrolledComposite) { |
134 |
ScrolledComposite composite = (ScrolledComposite) container; |
135 |
ScrollBar verticalBar = composite.getVerticalBar(); |
136 |
if (verticalBar != null) { |
137 |
int verticalBarWidth = verticalBar.getSize().x; |
138 |
horizontalMargin += Math.max(15, verticalBarWidth); |
139 |
} |
140 |
} |
141 |
return clientArea.width - horizontalMargin; |
142 |
} |
143 |
|
144 |
@Override |
145 |
protected Point computeSize(Composite composite, int widthHint, int heightHint, boolean flushCache) { |
146 |
int resultX = 1; |
147 |
int resultY = 1; |
148 |
|
149 |
Control[] children = composite.getChildren(); |
150 |
|
151 |
if (widthHint <= 0) { |
152 |
widthHint = calculateWidthHint(composite); |
153 |
if (widthHint < 300) { |
154 |
widthHint = 300; |
155 |
} else { |
156 |
widthHint -= widthHintMargin; |
157 |
} |
158 |
} |
159 |
|
160 |
int horizontalMargin = marginLeft + marginRight; |
161 |
|
162 |
for (Control control : children) { |
163 |
Point sz = control.computeSize(widthHint - horizontalMargin, -1, flushCache); |
164 |
|
165 |
resultX = Math.max(resultX, sz.x); |
166 |
resultY = Math.max(resultY, sz.y); |
167 |
} |
168 |
|
169 |
return new Point(resultX + horizontalMargin, resultY + marginTop + marginBottom); |
170 |
} |
171 |
|
172 |
@Override |
173 |
protected void layout(Composite composite, boolean flushCache) { |
174 |
|
175 |
Rectangle area = composite.getClientArea(); |
176 |
if (area.width == 0) { |
177 |
area.width = calculateWidthHint(composite); |
178 |
} |
179 |
|
180 |
// account for margins |
181 |
area.x += marginLeft; |
182 |
area.y += marginTop; |
183 |
area.width -= (marginRight + marginLeft); |
184 |
area.height -= (marginBottom + marginTop); |
185 |
|
186 |
Control[] children = composite.getChildren(); |
187 |
|
188 |
for (Control control : children) { |
189 |
control.setBounds(area); |
190 |
} |
191 |
} |
192 |
|
193 |
/** |
194 |
* the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}. |
195 |
* |
196 |
* @return the layout advisor, or null if there is none |
197 |
*/ |
198 |
public Composite getLayoutAdvisor() { |
199 |
return layoutAdvisor; |
200 |
} |
201 |
|
202 |
/** |
203 |
* the composite that is used to advise on layout based on its {@link Composite#getClientArea() client area}. |
204 |
* |
205 |
* @param layoutAdvisor |
206 |
* the layout advisor, or null if there is none |
207 |
*/ |
208 |
public void setLayoutAdvisor(Composite layoutAdvisor) { |
209 |
this.layoutAdvisor = layoutAdvisor; |
210 |
} |
211 |
|
212 |
} |