001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visual.layout;
042:
043: import org.netbeans.api.visual.widget.Widget;
044: import org.netbeans.api.visual.layout.Layout;
045: import org.netbeans.api.visual.layout.LayoutFactory;
046:
047: import java.awt.*;
048: import java.util.*;
049:
050: /**
051: * @author David Kaspar
052: */
053: public final class FlowLayout implements Layout {
054:
055: private boolean verticalOrientation;
056: private LayoutFactory.SerialAlignment alignment;
057: private int gap;
058:
059: public FlowLayout(boolean verticalOrientation,
060: LayoutFactory.SerialAlignment alignment, int gap) {
061: this .verticalOrientation = verticalOrientation;
062: this .alignment = alignment;
063: this .gap = gap;
064: }
065:
066: public void layout(Widget widget) {
067: int max = 0;
068: Collection<Widget> children = widget.getChildren();
069: if (verticalOrientation) {
070: for (Widget child : children) {
071: if (!child.isVisible())
072: continue;
073: Rectangle preferredBounds = child.getPreferredBounds();
074: int i = preferredBounds.width;
075: if (i > max)
076: max = i;
077: }
078: int pos = 0;
079: for (Widget child : children) {
080: Rectangle preferredBounds = child.getPreferredBounds();
081: int x = preferredBounds.x;
082: int y = preferredBounds.y;
083: int width = preferredBounds.width;
084: int height = preferredBounds.height;
085: int lx = -x;
086: int ly = pos - y;
087: switch (alignment) {
088: case CENTER:
089: lx += (max - width) / 2;
090: break;
091: case JUSTIFY:
092: width = max;
093: break;
094: case LEFT_TOP:
095: break;
096: case RIGHT_BOTTOM:
097: lx += max - width;
098: break;
099: }
100: if (child.isVisible()) {
101: child.resolveBounds(new Point(lx, ly),
102: new Rectangle(x, y, width, height));
103: pos += height + gap;
104: } else
105: child.resolveBounds(new Point(lx, ly),
106: new Rectangle(x, y, 0, 0));
107: }
108: } else {
109: for (Widget child : children) {
110: if (!child.isVisible())
111: continue;
112: Rectangle preferredBounds = child.getPreferredBounds();
113: int i = preferredBounds.height;
114: if (i > max)
115: max = i;
116: }
117: int pos = 0;
118: for (Widget child : children) {
119: Rectangle preferredBounds = child.getPreferredBounds();
120: int x = preferredBounds.x;
121: int y = preferredBounds.y;
122: int width = preferredBounds.width;
123: int height = preferredBounds.height;
124: int lx = pos - x;
125: int ly = -y;
126: switch (alignment) {
127: case CENTER:
128: ly += (max - height) / 2;
129: break;
130: case JUSTIFY:
131: height = max;
132: break;
133: case LEFT_TOP:
134: break;
135: case RIGHT_BOTTOM:
136: ly += max - height;
137: break;
138: }
139: if (child.isVisible()) {
140: child.resolveBounds(new Point(lx, ly),
141: new Rectangle(x, y, width, height));
142: pos += width + gap;
143: } else
144: child.resolveBounds(new Point(lx, ly),
145: new Rectangle(x, y, 0, 0));
146: }
147: }
148: }
149:
150: public boolean requiresJustification(Widget widget) {
151: return true;
152: }
153:
154: public void justify(Widget widget) {
155: Rectangle parentBounds = widget.getClientArea();
156: int totalWeight = 0;
157: int totalGap = 0;
158: java.util.List<Widget> children = widget.getChildren();
159: for (int a = 0; a < children.size(); a++) {
160: Widget child = children.get(a);
161: if (!child.isVisible())
162: continue;
163: totalWeight += resolveWeight(widget, child);
164:
165: if (a > 0)
166: totalGap -= gap;
167: if (verticalOrientation)
168: totalGap -= child.getBounds().height;
169: else
170: totalGap -= child.getBounds().width;
171: }
172: totalGap += verticalOrientation ? parentBounds.height
173: : parentBounds.width;
174: if (totalGap < 0)
175: totalWeight = totalGap = 0;
176:
177: int gapAdd = 0;
178: int weightAdd = 0;
179:
180: int parentX1 = parentBounds.x;
181: int parentX2 = parentX1 + parentBounds.width;
182: int parentY1 = parentBounds.y;
183: int parentY2 = parentY1 + parentBounds.height;
184:
185: for (Widget child : widget.getChildren()) {
186: Point childLocation = child.getLocation();
187: Rectangle childBounds = child.getBounds();
188:
189: if (verticalOrientation) {
190: switch (alignment) {
191: case CENTER:
192: childLocation.x = (parentX1 + parentX2 - childBounds.width) / 2;
193: break;
194: case JUSTIFY:
195: childLocation.x = parentX1;
196: childBounds.width = parentX2 - parentX1;
197: break;
198: case LEFT_TOP:
199: childLocation.x = parentX1;
200: break;
201: case RIGHT_BOTTOM:
202: childLocation.x = parentX2 - childBounds.width;
203: break;
204: }
205: if (totalWeight > 0 && child.isVisible()) {
206: childLocation.y += gapAdd;
207: int weight = resolveWeight(widget, child);
208: int gap = (weightAdd + weight) * totalGap
209: / totalWeight;
210: childBounds.height += gap - gapAdd;
211: gapAdd = gap;
212: weightAdd += weight;
213: }
214: childLocation.x -= childBounds.x;
215: childLocation.y += parentY1;
216: } else {
217: switch (alignment) {
218: case CENTER:
219: childLocation.y = (parentY1 + parentY2 - childBounds.height) / 2;
220: break;
221: case JUSTIFY:
222: childLocation.y = parentY1;
223: childBounds.height = parentY2 - parentY1;
224: break;
225: case LEFT_TOP:
226: childLocation.y = parentY1;
227: break;
228: case RIGHT_BOTTOM:
229: childLocation.y = parentY2 - childBounds.height;
230: break;
231: }
232: if (totalWeight > 0 && child.isVisible()) {
233: childLocation.x += gapAdd;
234: int weight = resolveWeight(widget, child);
235: int gap = (weightAdd + weight) * totalGap
236: / totalWeight;
237: childBounds.width += gap - gapAdd;
238: gapAdd = gap;
239: weightAdd += weight;
240: }
241: childLocation.y -= childBounds.y;
242: childLocation.x += parentX1;
243: }
244:
245: child.resolveBounds(childLocation, childBounds);
246: }
247: }
248:
249: private static int resolveWeight(Widget widget, Widget child) {
250: Object o = widget.getChildConstraint(child);
251: if (o instanceof Number) {
252: int weight = ((Number) o).intValue();
253: if (weight > 0)
254: return weight;
255: }
256: return 0;
257: }
258:
259: }
|