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