001: /*
002: * MyGWT Widget Library
003: * Copyright(c) 2007, MyGWT.
004: * licensing@mygwt.net
005: *
006: * http://mygwt.net/license
007: */
008: package net.mygwt.ui.client.widget.layout;
009:
010: import java.util.HashMap;
011: import java.util.Map;
012:
013: import net.mygwt.ui.client.Events;
014: import net.mygwt.ui.client.MyDOM;
015: import net.mygwt.ui.client.MyGWT;
016: import net.mygwt.ui.client.Style;
017: import net.mygwt.ui.client.event.BaseEvent;
018: import net.mygwt.ui.client.event.Listener;
019: import net.mygwt.ui.client.util.Rectangle;
020: import net.mygwt.ui.client.widget.Component;
021: import net.mygwt.ui.client.widget.Layout;
022: import net.mygwt.ui.client.widget.SplitBar;
023: import net.mygwt.ui.client.widget.WidgetContainer;
024:
025: import com.google.gwt.user.client.Element;
026: import com.google.gwt.user.client.ui.Widget;
027:
028: /**
029: * A border layout lays out it children, arranging and resizing its widgets to
030: * fit in five regions: north, south, east, west, and center. Each region may
031: * contain no more than one widget, and is identified by a corresponding
032: * constant: NORTH, SOUTH, EAST, WEST, and CENTER.
033: *
034: * <p>
035: * Note: Only regions containing a component can be resized.
036: * </p>
037: */
038: public class BorderLayout extends Layout {
039:
040: protected Map splitBars;
041:
042: private int spacing = 4;
043: private int margin = 4;
044: private int minimumSize = 100;
045: private Widget north, south;
046: private Widget west, east, center;
047: private Element ct;
048:
049: /**
050: * Creates a new border layout.
051: */
052: public BorderLayout() {
053: splitBars = new HashMap();
054: }
055:
056: /**
057: * Returns the margin.
058: *
059: * @return the margin in pixels
060: */
061: public int getMargin() {
062: return margin;
063: }
064:
065: /**
066: * Returns the minimum size.
067: *
068: * @return the minimum size
069: */
070: public int getMinimumSize() {
071: return minimumSize;
072: }
073:
074: /**
075: * Returns the spacing.
076: *
077: * @return the spacing in pixels
078: */
079: public int getSpacing() {
080: return spacing;
081: }
082:
083: /**
084: * Sets the number of pixels of indentation that will be placed along the
085: * sides of the panel. Default value is 4.
086: *
087: * @param margin the margin
088: */
089: public void setMargin(int margin) {
090: this .margin = margin;
091: }
092:
093: /**
094: * Sets the minimum size of a region when resizing. Default value is 100.
095: *
096: * @param minimumSize the new minimumSize
097: */
098: public void setMinimumSize(int minimumSize) {
099: this .minimumSize = minimumSize;
100: }
101:
102: /**
103: * Sets the amount of spacing between regions. Default value is 4.
104: *
105: * @param spacing the spacing in pixels
106: */
107: public void setSpacing(int spacing) {
108: this .spacing = spacing;
109: }
110:
111: protected SplitBar createSplitBar(int region, Component component) {
112: return new SplitBar(region, component);
113: }
114:
115: protected void onLayout(WidgetContainer c, Element target) {
116: super .onLayout(c, target);
117:
118: ct = c.getLayoutTarget();
119: MyDOM.makePositionable(ct);
120:
121: north = getRegionWidget(Style.NORTH);
122: south = getRegionWidget(Style.SOUTH);
123: west = getRegionWidget(Style.WEST);
124: east = getRegionWidget(Style.EAST);
125: center = getRegionWidget(Style.CENTER);
126:
127: if (center == null) {
128: throw new RuntimeException(
129: "BorderLayout requires a widget in the center region.");
130: }
131:
132: Rectangle rect = MyDOM.getBounds(ct, true);
133:
134: if (MyGWT.isSafari) {
135: rect.width -= 1;
136: rect.height -= 1;
137: }
138:
139: int height = rect.height;
140: int width = rect.width;
141:
142: int t = rect.y + margin;
143: int b = t + height - (2 * margin);
144: int l = rect.x + margin;
145: int r = l + width - (2 * margin);
146:
147: // NORTH
148: if (north != null) {
149: BorderLayoutData northData = (BorderLayoutData) c
150: .getLayoutData(north);
151:
152: if (northData.resizeable && north instanceof Component) {
153: initSplitBar(Style.SOUTH, (Component) north, northData);
154: } else {
155: removeSplitBar(Style.SOUTH);
156: }
157:
158: if (northData.exclude) {
159: north.setVisible(false);
160: setSplitBarEnabled(Style.SOUTH, false);
161: } else {
162: float northHeight = northData.size;
163: if (northHeight <= 1) {
164: northHeight = height * northHeight;
165: }
166: north.setVisible(true);
167: setSplitBarEnabled(Style.EAST, false);
168: setBounds(north, l, t, r - l, (int) northHeight);
169: t += northHeight + spacing;
170: }
171:
172: }
173:
174: // SOUTH
175: if (south != null) {
176: BorderLayoutData southData = (BorderLayoutData) c
177: .getLayoutData(south);
178: if (southData.resizeable && south instanceof Component) {
179: initSplitBar(Style.NORTH, (Component) south, southData);
180: } else {
181: removeSplitBar(Style.NORTH);
182: }
183:
184: if (southData.exclude) {
185: south.setVisible(false);
186: setSplitBarEnabled(Style.NORTH, false);
187: } else {
188: float southHeight = southData.size;
189: if (southHeight <= 1) {
190: southHeight = height * southHeight;
191: }
192: south.setVisible(true);
193: setBounds(south, l, (int) (b - southHeight), r - l,
194: (int) southHeight);
195: b -= southHeight + spacing;
196: }
197:
198: }
199:
200: // EAST
201: if (east != null) {
202: BorderLayoutData eastData = (BorderLayoutData) c
203: .getLayoutData(east);
204: if (eastData.resizeable && east instanceof Component) {
205: initSplitBar(Style.WEST, (Component) east, eastData);
206: } else {
207: removeSplitBar(Style.WEST);
208: }
209:
210: if (eastData.exclude) {
211: east.setVisible(false);
212: setSplitBarEnabled(Style.WEST, false);
213: } else {
214: float eastWidth = eastData.size;
215: if (eastWidth <= 1) {
216: eastWidth = width * eastWidth;
217: }
218: east.setVisible(true);
219: setSplitBarEnabled(Style.EAST, true);
220: setBounds(east, (int) (r - eastWidth), t,
221: (int) eastWidth, b - t);
222: r -= eastWidth + spacing;
223: }
224:
225: }
226:
227: // WEST
228: if (west != null) {
229: final BorderLayoutData westData = (BorderLayoutData) c
230: .getLayoutData(west);
231: if (westData.resizeable && west instanceof Component) {
232: initSplitBar(Style.EAST, (Component) west, westData);
233: } else {
234: removeSplitBar(Style.EAST);
235: }
236:
237: if (westData.exclude) {
238: west.setVisible(false);
239: setSplitBarEnabled(Style.EAST, false);
240: } else {
241: float westWidth = westData.size;
242: if (westWidth <= 1) {
243: westWidth = width * westWidth;
244: }
245: west.setVisible(true);
246: setBounds(west, l, t, (int) westWidth, b - t);
247: l += westWidth + spacing;
248: }
249: }
250:
251: // CENTER
252: if (center != null) {
253: setBounds(center, l, t, r - l, b - t);
254: }
255:
256: }
257:
258: private Widget getRegionWidget(int region) {
259: for (int i = 0; i < container.getWidgetCount(); i++) {
260: MyDOM.makePositionable(container.getWidget(i).getElement(),
261: true);
262: }
263: for (int i = 0; i < container.getWidgetCount(); i++) {
264: Widget w = container.getWidget(i);
265: if (container.getLayoutData(w) != null
266: && container.getLayoutData(w) instanceof BorderLayoutData) {
267: BorderLayoutData data = (BorderLayoutData) container
268: .getLayoutData(w);
269: if (data.region == region) {
270: return w;
271: }
272: }
273: }
274:
275: return null;
276: }
277:
278: private void initSplitBar(final int region, Component comp,
279: final BorderLayoutData data) {
280: SplitBar bar = (SplitBar) splitBars.get(new Integer(region));
281: if (bar == null || bar.getResizeWidget() != comp) {
282: bar = createSplitBar(region, comp);
283: final SplitBar fBar = bar;
284: Listener splitBarListener = new Listener() {
285:
286: public void handleEvent(BaseEvent be) {
287: switch (be.type) {
288: case Events.DragStart:
289: switch (region) {
290: case Style.WEST: {
291: int min = Math.max(minimumSize,
292: data.minimumSize);
293: int max = east.getOffsetWidth()
294: + center.getOffsetWidth()
295: - minimumSize;
296: if (data.maximumSize > 0) {
297: max = Math.min(max, data.maximumSize);
298: }
299: fBar.setMinSize(min);
300: fBar.setMaxSize(max);
301: break;
302: }
303: case Style.EAST: {
304: int min = Math.max(minimumSize,
305: data.minimumSize);
306: int max = west.getOffsetWidth()
307: + center.getOffsetWidth()
308: - minimumSize;
309: max = Math.min(data.maximumSize, max);
310: fBar.setMinSize(min);
311: fBar.setMaxSize(max);
312: break;
313: }
314: case Style.NORTH:
315: int max = south.getOffsetHeight()
316: + center.getOffsetHeight()
317: - minimumSize;
318: max = Math.min(max, data.maximumSize);
319: fBar.setMaxSize(max);
320: break;
321: case Style.SOUTH:
322: // TODO
323: break;
324: }
325: break;
326: }
327:
328: }
329:
330: };
331:
332: bar.addListener(Events.DragStart, splitBarListener);
333: bar.addListener(Events.DragEnd, splitBarListener);
334: bar.setMinSize(data.minimumSize);
335: bar.setMaxSize(data.maximumSize == 0 ? bar.getMaxSize()
336: : data.maximumSize);
337: bar.setBarWidth(6);
338: bar.setAutoSize(false);
339: bar.addListener(Events.Resize, new Listener() {
340: public void handleEvent(BaseEvent be) {
341: if (be.size < 1) {
342: return;
343: }
344: if (data.size < 1.1) {
345: float size = 0;
346: if (region == Style.SOUTH
347: || region == Style.NORTH) {
348: size = MyDOM.getHeight(ct);
349: } else {
350: size = MyDOM.getWidth(ct);
351: }
352: data.size = be.size / size;
353: } else {
354: data.size = be.size;
355: }
356: layout(container);
357: }
358: });
359: splitBars.put(new Integer(region), bar);
360: }
361: }
362:
363: private void removeSplitBar(int region) {
364: splitBars.put(new Integer(region), null);
365: }
366:
367: private void setSplitBarEnabled(int region, boolean enabled) {
368: SplitBar bar = (SplitBar) splitBars.get(new Integer(region));
369: if (bar != null) {
370:
371: }
372: }
373:
374: }
|