001 /* ========================================================================
002 * JCommon : a free general purpose class library for the Java(tm) platform
003 * ========================================================================
004 *
005 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006 *
007 * Project Info: http://www.jfree.org/jcommon/index.html
008 *
009 * This library is free software; you can redistribute it and/or modify it
010 * under the terms of the GNU Lesser General Public License as published by
011 * the Free Software Foundation; either version 2.1 of the License, or
012 * (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but
015 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
016 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
017 * License for more details.
018 *
019 * You should have received a copy of the GNU Lesser General Public
020 * License along with this library; if not, write to the Free Software
021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
022 * USA.
023 *
024 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
025 * in the United States and other countries.]
026 *
027 * -----------------
028 * RadialLayout.java
029 * -----------------
030 * (C) Copyright 2003, 2004, by Bryan Scott (for Australian Antarctic Division).
031 *
032 * Original Author: Bryan Scott (for Australian Antarctic Division);
033 * Contributor(s): David Gilbert (for Object Refinery Limited);
034 *
035 *
036 * Changes:
037 * --------
038 * 30-Jun-2003 : Version 1 (BS);
039 * 24-Jul-2003 : Completed missing Javadocs (DG);
040 *
041 */
042
043 package org.jfree.layout;
044
045 import java.awt.Checkbox;
046 import java.awt.Component;
047 import java.awt.Container;
048 import java.awt.Dimension;
049 import java.awt.Frame;
050 import java.awt.Insets;
051 import java.awt.LayoutManager;
052 import java.awt.Panel;
053 import java.io.Serializable;
054
055 /**
056 * RadialLayout is a component layout manager. Compents are laid out in a
057 * circle. If only one component is contained in the layout it is positioned
058 * centrally, otherwise components are evenly spaced around the centre with
059 * the first component placed to the North.
060 *<P>
061 * This code was developed to display CTD rosette firing control
062 *
063 * WARNING: Not thoughly tested, use at own risk.
064 *
065 * @author Bryan Scott (for Australian Antarctic Division)
066 */
067
068 public class RadialLayout implements LayoutManager, Serializable {
069
070 /** For serialization. */
071 private static final long serialVersionUID = -7582156799248315534L;
072
073 /** The minimum width. */
074 private int minWidth = 0;
075
076 /** The minimum height. */
077 private int minHeight = 0;
078
079 /** The maximum component width. */
080 private int maxCompWidth = 0;
081
082 /** The maximum component height. */
083 private int maxCompHeight = 0;
084
085 /** The preferred width. */
086 private int preferredWidth = 0;
087
088 /** The preferred height. */
089 private int preferredHeight = 0;
090
091 /** Size unknown flag. */
092 private boolean sizeUnknown = true;
093
094 /**
095 * Constructs this layout manager with default properties.
096 */
097 public RadialLayout() {
098 super();
099 }
100
101 /**
102 * Not used.
103 *
104 * @param comp the component.
105 */
106 public void addLayoutComponent(final Component comp) {
107 // not used
108 }
109
110 /**
111 * Not used.
112 *
113 * @param comp the component.
114 */
115 public void removeLayoutComponent(final Component comp) {
116 // not used
117 }
118
119 /**
120 * Not used.
121 *
122 * @param name the component name.
123 * @param comp the component.
124 */
125 public void addLayoutComponent(final String name, final Component comp) {
126 // not used
127 }
128
129 /**
130 * Not used.
131 *
132 * @param name the component name.
133 * @param comp the component.
134 */
135 public void removeLayoutComponent(final String name, final Component comp) {
136 // not used
137 }
138
139 /**
140 * Sets the sizes attribute of the RadialLayout object.
141 *
142 * @param parent the parent.
143 *
144 * @see LayoutManager
145 */
146 private void setSizes(final Container parent) {
147 final int nComps = parent.getComponentCount();
148 //Reset preferred/minimum width and height.
149 this.preferredWidth = 0;
150 this.preferredHeight = 0;
151 this.minWidth = 0;
152 this.minHeight = 0;
153 for (int i = 0; i < nComps; i++) {
154 final Component c = parent.getComponent(i);
155 if (c.isVisible()) {
156 final Dimension d = c.getPreferredSize();
157 if (this.maxCompWidth < d.width) {
158 this.maxCompWidth = d.width;
159 }
160 if (this.maxCompHeight < d.height) {
161 this.maxCompHeight = d.height;
162 }
163 this.preferredWidth += d.width;
164 this.preferredHeight += d.height;
165 }
166 }
167 this.preferredWidth = this.preferredWidth / 2;
168 this.preferredHeight = this.preferredHeight / 2;
169 this.minWidth = this.preferredWidth;
170 this.minHeight = this.preferredHeight;
171 }
172
173 /**
174 * Returns the preferred size.
175 *
176 * @param parent the parent.
177 *
178 * @return The preferred size.
179 * @see LayoutManager
180 */
181 public Dimension preferredLayoutSize(final Container parent) {
182 final Dimension dim = new Dimension(0, 0);
183 setSizes(parent);
184
185 //Always add the container's insets!
186 final Insets insets = parent.getInsets();
187 dim.width = this.preferredWidth + insets.left + insets.right;
188 dim.height = this.preferredHeight + insets.top + insets.bottom;
189
190 this.sizeUnknown = false;
191 return dim;
192 }
193
194 /**
195 * Returns the minimum size.
196 *
197 * @param parent the parent.
198 *
199 * @return The minimum size.
200 * @see LayoutManager
201 */
202 public Dimension minimumLayoutSize(final Container parent) {
203 final Dimension dim = new Dimension(0, 0);
204
205 //Always add the container's insets!
206 final Insets insets = parent.getInsets();
207 dim.width = this.minWidth + insets.left + insets.right;
208 dim.height = this.minHeight + insets.top + insets.bottom;
209
210 this.sizeUnknown = false;
211 return dim;
212 }
213
214 /**
215 * This is called when the panel is first displayed, and every time its size
216 * changes.
217 * Note: You CAN'T assume preferredLayoutSize or minimumLayoutSize will be
218 * called -- in the case of applets, at least, they probably won't be.
219 *
220 * @param parent the parent.
221 * @see LayoutManager
222 */
223 public void layoutContainer(final Container parent) {
224 final Insets insets = parent.getInsets();
225 final int maxWidth = parent.getSize().width
226 - (insets.left + insets.right);
227 final int maxHeight = parent.getSize().height
228 - (insets.top + insets.bottom);
229 final int nComps = parent.getComponentCount();
230 int x = 0;
231 int y = 0;
232
233 // Go through the components' sizes, if neither preferredLayoutSize nor
234 // minimumLayoutSize has been called.
235 if (this.sizeUnknown) {
236 setSizes(parent);
237 }
238
239 if (nComps < 2) {
240 final Component c = parent.getComponent(0);
241 if (c.isVisible()) {
242 final Dimension d = c.getPreferredSize();
243 c.setBounds(x, y, d.width, d.height);
244 }
245 }
246 else {
247 double radialCurrent = Math.toRadians(90);
248 final double radialIncrement = 2 * Math.PI / nComps;
249 final int midX = maxWidth / 2;
250 final int midY = maxHeight / 2;
251 final int a = midX - this.maxCompWidth;
252 final int b = midY - this.maxCompHeight;
253 for (int i = 0; i < nComps; i++) {
254 final Component c = parent.getComponent(i);
255 if (c.isVisible()) {
256 final Dimension d = c.getPreferredSize();
257 x = (int) (midX
258 - (a * Math.cos(radialCurrent))
259 - (d.getWidth() / 2)
260 + insets.left);
261 y = (int) (midY
262 - (b * Math.sin(radialCurrent))
263 - (d.getHeight() / 2)
264 + insets.top);
265
266 // Set the component's size and position.
267 c.setBounds(x, y, d.width, d.height);
268 }
269 radialCurrent += radialIncrement;
270 }
271 }
272 }
273
274 /**
275 * Returns the class name.
276 *
277 * @return The class name.
278 */
279 public String toString() {
280 return getClass().getName();
281 }
282
283 /**
284 * Run a demonstration.
285 *
286 * @param args ignored.
287 *
288 * @throws Exception when an error occurs.
289 */
290 public static void main(final String[] args) throws Exception {
291 final Frame frame = new Frame();
292 final Panel panel = new Panel();
293 panel.setLayout(new RadialLayout());
294
295 panel.add(new Checkbox("One"));
296 panel.add(new Checkbox("Two"));
297 panel.add(new Checkbox("Three"));
298 panel.add(new Checkbox("Four"));
299 panel.add(new Checkbox("Five"));
300 panel.add(new Checkbox("One"));
301 panel.add(new Checkbox("Two"));
302 panel.add(new Checkbox("Three"));
303 panel.add(new Checkbox("Four"));
304 panel.add(new Checkbox("Five"));
305
306 frame.add(panel);
307 frame.setSize(300, 500);
308 frame.setVisible(true);
309 }
310
311 }