package fr.upd.jby; import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; /** * Using this layout in a real application is a sin. * It has been designed to demonstrate how to implement a LayoutManager. * It lays components one below * the other, starting from the top of the container space, * and such that, left and right margins * draw a sinusoid. * * Source code <a href="SinLayout.java.html">here</a> and a sample * <a href="../../../SinExample.java.html">here</a>. * * @author J.-B. Yunès * @version 1.0 * @since 1.6 */ public class SinLayout implements LayoutManager { private java.util.List<Component> components; private Dimension preferredSize; private int componentPerCycle, maxValue; /** * Constructs a default SinLayout which glues component's borders * to the respective left and right borders of their container. */ public SinLayout() { componentPerCycle = 1; maxValue = 0; components = new Vector<Component>(); } /** * Constructs a SinLayout which glues component's borders to * the respective left and right sinusoidal border of their container, * with strict respect to their minimum size. * @param cpc the number of component per period of the sinusoid. * @param zenith the zenith of the sinusoid, in pixels. */ public SinLayout(int cpc,int zenith) { this(); if (cpc>0) componentPerCycle = cpc; if (maxValue>=0 && maxValue<200) maxValue = zenith; } /** * Adds the specified component to the layout. Not used by this class. */ public void addLayoutComponent(String n,Component c) { // Never used... } private int leftGap(int i) { return (int)Math.abs(Math.sin(i*Math.PI/componentPerCycle)*maxValue); } /** * Lays out the container. * @param c the container to be laid out */ public void layoutContainer(Container c) { synchronized (c.getTreeLock()) { int width = c.getSize().width; int i=0, h=0; for (Component co : c.getComponents()) { if (!co.isVisible()) continue; Dimension d = co.getPreferredSize(); int cw = Math.max(width-2*leftGap(i),co.getMinimumSize().width); System.out.println(""+width+" "+d+" "+co.getMinimumSize()); if (!co.getSize().equals(new Dimension(cw,d.height))) { co.setSize(cw,d.height); } Point l = new Point((c.getSize().width-co.getSize().width)/2,h); if (!co.getLocation().equals(l)) { co.setLocation(l); } i++; h += co.getSize().height; } } } /** * Returns the minimum dimensions needed to layout the * <em>visible</em> components contained in the specified target container. * @param c the container to bo laid out. */ public Dimension minimumLayoutSize(Container c) { synchronized (c.getTreeLock()) { int w=1000, h=0, i=0; if (c.getComponentCount()==0) return new Dimension(10,10); for (Component co : c.getComponents()) { if (!co.isVisible()) continue; h += co.getMinimumSize().height; w = Math.min(w,co.getMinimumSize().width+2*leftGap(i)); i++; } return new Dimension(w,h); } } /** * Returns the preferred dimensions for this layout given the * <em>visible</em> components in the specified target container. * @param c the container to bo laid out. */ public Dimension preferredLayoutSize(Container c) { synchronized (c.getTreeLock()) { int w=0, h=0, i=0; if (c.getComponentCount()==0) return new Dimension(10,10); for (Component co : c.getComponents()) { if (!co.isVisible()) continue; h += co.getPreferredSize().height; w = Math.max(w,co.getPreferredSize().width+2*leftGap(i)); i++; } preferredSize = new Dimension(w,h); return preferredSize; } } /** * Removes the specified component from the layout. Forces a repaint to * clean the space previously used by the component in the container. * @param c the component to be removed. */ public void removeLayoutComponent(Component c) { synchronized (c.getTreeLock()) { // Force a repaint to clean the space used by the component // At this point the component has not been removed from the // container then we are able to procastinate a repaint... c.getParent().repaint(c.getLocation().x,c.getLocation().y, c.getSize().width,c.getSize().height); } } }