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 043package org.jfree.layout; 044 045import java.awt.Checkbox; 046import java.awt.Component; 047import java.awt.Container; 048import java.awt.Dimension; 049import java.awt.Frame; 050import java.awt.Insets; 051import java.awt.LayoutManager; 052import java.awt.Panel; 053import 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 068public 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}