diff --git a/projects/samskivert/src/java/com/samskivert/swing/DimenInfo.java b/projects/samskivert/src/java/com/samskivert/swing/DimenInfo.java new file mode 100644 index 00000000..c55bab96 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/DimenInfo.java @@ -0,0 +1,44 @@ +// +// $Id: DimenInfo.java,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +package com.samskivert.swing; + +import java.awt.Dimension; + +/** + * This record is used by the group layout managers to return a set of + * statistics computed for their target widgets. + */ +public class DimenInfo +{ + public int count; + + public int totwid; + public int tothei; + + public int maxwid; + public int maxhei; + + public int numfix; + public int fixwid; + public int fixhei; + + public int totweight; + + public Dimension[] dimens; + + public String toString () + { + StringBuffer buf = new StringBuffer(); + buf.append("[count=").append(count); + buf.append(", totwid=").append(totwid); + buf.append(", tothei=").append(tothei); + buf.append(", maxwid=").append(maxwid); + buf.append(", maxhei=").append(maxhei); + buf.append(", numfix=").append(numfix); + buf.append(", fixwid=").append(fixwid); + buf.append(", fixhei=").append(fixhei); + buf.append(", totweight=").append(totweight); + return buf.append("]").toString(); + } +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/GroupLayout.java b/projects/samskivert/src/java/com/samskivert/swing/GroupLayout.java new file mode 100644 index 00000000..d0c8e900 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/GroupLayout.java @@ -0,0 +1,281 @@ +// +// $Id: GroupLayout.java,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +package com.samskivert.swing; + +import java.awt.*; +import javax.swing.SwingConstants; +import java.util.HashMap; + +/** + * Group layout managers lay out widgets in horizontal or vertical groups. + */ +public abstract class GroupLayout + implements LayoutManager2, SwingConstants +{ + /** + * The group layout managers supports two constraints: fixedness + * and weight. A fixed component will not be stretched along the major + * axis of the group. Those components that are stretched will have + * the extra space divided among them according to their weight + * (specifically receiving the ratio of their weight to the total + * weight of all of the free components in the container). + * + *

If a constraints object is constructed with fixedness set to + * true and with a weight, the weight will be ignored. + */ + public static class Constraints + { + /** Whether or not this component is fixed. */ + public boolean fixed = false; + + /** + * The weight of this component relative to the other components + * in the container. + */ + public int weight = 1; + + /** + * Constructs a new constraints object with the specified + * fixedness and weight. + */ + public Constraints (boolean fixed) + { + this.fixed = fixed; + } + + /** + * Constructs a new constraints object with the specified + * fixedness and weight. + */ + public Constraints (int weight) + { + this.weight = weight; + } + } + + /** + * A constraints object that indicates that the component should be + * fixed and have the default weight of one. This is so commonly used + * that we create and make this object available here. + */ + public final static Constraints FIXED = new Constraints(true); + + /** + * Do not adjust the widgets on this axis. + */ + public final static int NONE = 0; + + /** + * Stretch all the widgets to their maximum possible size on this + * axis. + */ + public final static int STRETCH = 1; + + /** + * Stretch all the widgets to be equal to the size of the largest + * widget on this axis. + */ + public final static int EQUALIZE = 2; + + public void setPolicy (int policy) + { + _policy = policy; + } + + public int getPolicy () + { + return _policy; + } + + public void setOffAxisPolicy (int offpolicy) + { + _offpolicy = offpolicy; + } + + public int getOffAxisPolicy () + { + return _offpolicy; + } + + public void setGap (int gap) + { + _gap = gap; + } + + public int getGap () + { + return _gap; + } + + public void setJustification (int justification) + { + _justification = justification; + } + + public int getJustification () + { + return _justification; + } + + public void addLayoutComponent (String name, Component comp) + { + // nothing to do here + } + + public void removeLayoutComponent (Component comp) + { + if (_constraints != null) { + _constraints.remove(comp); + } + } + + public void addLayoutComponent (Component comp, Object constraints) + { + if (constraints != null) { + if (constraints instanceof Constraints) { + if (_constraints == null) { + _constraints = new HashMap(); + } + _constraints.put(comp, constraints); + + } else { + throw new RuntimeException("GroupLayout constraints " + + "object must be of type " + + "GroupLayout.Constraints"); + } + } + } + + public float getLayoutAlignmentX (Container target) + { + // we don't support alignment like this + return 0f; + } + + public float getLayoutAlignmentY (Container target) + { + // we don't support alignment like this + return 0f; + } + + public Dimension minimumLayoutSize (Container parent) + { + return getLayoutSize(parent, MINIMUM); + } + + public Dimension preferredLayoutSize (Container parent) + { + return getLayoutSize(parent, PREFERRED); + } + + public Dimension maximumLayoutSize (Container parent) + { + return getLayoutSize(parent, MAXIMUM); + } + + protected abstract Dimension getLayoutSize (Container parent, int type); + + public abstract void layoutContainer (Container parent); + + public void invalidateLayout (Container target) + { + // nothing to do here + } + + protected boolean isFixed (Component child) + { + if (_constraints == null) { + return false; + } + + Constraints c = (Constraints)_constraints.get(child); + if (c != null) { + return c.fixed; + } + + return false; + } + + protected int getWeight (Component child) + { + if (_constraints == null) { + return 1; + } + + Constraints c = (Constraints)_constraints.get(child); + if (c != null) { + return c.weight; + } + + return 1; + } + + /** + * Computes dimensions of the children widgets that are useful for the + * group layout managers. + */ + protected DimenInfo computeDimens (Container parent, int type) + { + int count = parent.getComponentCount(); + DimenInfo info = new DimenInfo(); + info.dimens = new Dimension[count]; + + for (int i = 0; i < count; i++) { + Component child = parent.getComponent(i); + if (!child.isVisible()) { + continue; + } + + Dimension csize; + switch (type) { + case MINIMUM: + csize = child.getMinimumSize(); + break; + + case MAXIMUM: + csize = child.getMaximumSize(); + break; + + default: + csize = child.getPreferredSize(); + break; + } + + info.count++; + info.totwid += csize.width; + info.tothei += csize.height; + + if (csize.width > info.maxwid) { + info.maxwid = csize.width; + } + if (csize.height > info.maxhei) { + info.maxhei = csize.height; + } + + if (isFixed(child)) { + info.fixwid += csize.width; + info.fixhei += csize.height; + info.numfix++; + + } else { + info.totweight += getWeight(child); + } + + info.dimens[i] = csize; + } + + return info; + } + + protected int _policy = NONE; + protected int _offpolicy = NONE; + protected int _gap = 5; + protected int _justification = CENTER; + + protected HashMap _constraints; + + protected static final int MINIMUM = 0; + protected static final int PREFERRED = 1; + protected static final int MAXIMUM = 2; +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/GroupLayoutTest.java b/projects/samskivert/src/java/com/samskivert/swing/GroupLayoutTest.java new file mode 100644 index 00000000..6278df7a --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/GroupLayoutTest.java @@ -0,0 +1,40 @@ +// +// $Id: GroupLayoutTest.java,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +package com.samskivert.swing; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; + +public class GroupLayoutTest +{ + public static void main (String[] args) + { + JFrame frame = new JFrame("GroupLayoutTest"); + JPanel panel = new JPanel(); + GroupLayout layout = new HGroupLayout(); + layout.setJustification(GroupLayout.CENTER); + layout.setPolicy(GroupLayout.STRETCH); + layout.setGap(15); + panel.setLayout(layout); + + JButton butone = new JButton("One"); + panel.add(butone, GroupLayout.FIXED); + JButton buttwo = new JButton("Two"); + panel.add(buttwo, GroupLayout.FIXED); + JButton butthree = new JButton("Three to get ready"); + panel.add(butthree, GroupLayout.FIXED); + + frame.addWindowListener(new WindowAdapter () + { + public void windowClosing (WindowEvent e) + { + System.exit(0); + } + }); + frame.getContentPane().add(panel, BorderLayout.CENTER); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/HGroupLayout.java b/projects/samskivert/src/java/com/samskivert/swing/HGroupLayout.java new file mode 100644 index 00000000..e8be578d --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/HGroupLayout.java @@ -0,0 +1,149 @@ +// +// $Id: HGroupLayout.java,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +package com.samskivert.swing; + +import java.awt.*; + +public class HGroupLayout extends GroupLayout +{ + public HGroupLayout (int policy, int offpolicy, int gap, + int justification) + { + _policy = policy; + _offpolicy = offpolicy; + _gap = gap; + _justification = justification; + } + + public HGroupLayout (int policy, int gap, int justification) + { + _policy = policy; + _gap = gap; + _justification = justification; + } + + public HGroupLayout (int policy, int justification) + { + _policy = policy; + _justification = justification; + } + + public HGroupLayout (int policy) + { + _policy = policy; + } + + public HGroupLayout () + { + } + + protected Dimension getLayoutSize (Container parent, int type) + { + DimenInfo info = computeDimens(parent, type); + Dimension dims = new Dimension(); + + switch (_policy) { + case STRETCH: + case EQUALIZE: + dims.width = info.maxwid * (info.count - info.numfix) + + info.fixwid + _gap * info.count; + break; + + case NONE: + default: + dims.width = info.totwid + _gap * info.count; + break; + } + + dims.width -= _gap; + dims.height = info.maxhei; + + return dims; + } + + public void layoutContainer (Container parent) + { + Rectangle b = parent.bounds(); + DimenInfo info = computeDimens(parent, PREFERRED); + + int nk = parent.getComponentCount(); + int sx = 0, sy = 0; + int totwid, totgap = _gap * (info.count-1); + int freecount = info.count - info.numfix; + + // do the on-axis policy calculations + int defwid = 0; + switch (_policy) { + case STRETCH: + if (freecount > 0) { + defwid = (b.width - info.fixwid - totgap) / freecount; + totwid = b.width; + } else { + totwid = info.fixwid + totgap; + } + break; + + case EQUALIZE: + defwid = info.maxwid; + totwid = info.fixwid + defwid * freecount + totgap; + break; + + default: + case NONE: + totwid = info.totwid + totgap; + break; + } + + // do the off-axis policy calculations + int defhei = 0; + switch (_offpolicy) { + case STRETCH: + defhei = b.height; + break; + + case EQUALIZE: + sy = (b.height - info.maxhei)/2; + defhei = info.maxhei; + break; + + default: + case NONE: + break; + } + + // do the justification-related calculations + switch (_justification) { + case CENTER: + sx = (b.width - totwid)/2; + break; + case RIGHT: + sx = b.width - totwid; + break; + } + + // do the layout + for (int i = 0; i < nk; i++) { + // skip non-visible kids + if (info.dimens[i] == null) { + continue; + } + + Component child = parent.getComponent(i); + int newwid = defwid; + int newhei = defhei; + + if (_policy == NONE || isFixed(child)) { + newwid = info.dimens[i].width; + } + + if (_offpolicy == NONE) { + newhei = info.dimens[i].height; + sy = (b.height - newhei)/2; + } + + child.setBounds(sx, sy, newwid, newhei); + sx += child.size().width + _gap; + } + } +} diff --git a/projects/samskivert/src/java/com/samskivert/swing/Makefile b/projects/samskivert/src/java/com/samskivert/swing/Makefile new file mode 100644 index 00000000..54755f16 --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/Makefile @@ -0,0 +1,13 @@ +# +# $Id: Makefile,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +ROOT = ../../.. + +SRCS = \ + DimenInfo.java \ + GroupLayout.java \ + GroupLayoutTest.java \ + HGroupLayout.java \ + VGroupLayout.java \ + +include $(ROOT)/build/Makefile.java diff --git a/projects/samskivert/src/java/com/samskivert/swing/VGroupLayout.java b/projects/samskivert/src/java/com/samskivert/swing/VGroupLayout.java new file mode 100644 index 00000000..a0b61fce --- /dev/null +++ b/projects/samskivert/src/java/com/samskivert/swing/VGroupLayout.java @@ -0,0 +1,149 @@ +// +// $Id: VGroupLayout.java,v 1.1 2000/12/07 05:41:07 mdb Exp $ + +package com.samskivert.swing; + +import java.awt.*; + +public class VGroupLayout extends GroupLayout +{ + public VGroupLayout (int policy, int offpolicy, int gap, + int justification) + { + _policy = policy; + _offpolicy = offpolicy; + _gap = gap; + _justification = justification; + } + + public VGroupLayout (int policy, int gap, int justification) + { + _policy = policy; + _gap = gap; + _justification = justification; + } + + public VGroupLayout (int policy, int justification) + { + _policy = policy; + _justification = justification; + } + + public VGroupLayout (int policy) + { + _policy = policy; + } + + public VGroupLayout () + { + } + + protected Dimension getLayoutSize (Container parent, int type) + { + DimenInfo info = computeDimens(parent, type); + Dimension dims = new Dimension(); + + switch (_policy) { + case STRETCH: + case EQUALIZE: + dims.height = info.maxhei * (info.count - info.numfix) + + info.fixhei + _gap * info.count; + break; + + case NONE: + default: + dims.height = info.tothei + _gap * info.count; + break; + } + + dims.height -= _gap; + dims.width = info.maxwid; + + return dims; + } + + public void layoutContainer (Container parent) + { + Rectangle b = parent.bounds(); + DimenInfo info = computeDimens(parent, PREFERRED); + + int nk = parent.getComponentCount(); + int sx = 0, sy = 0; + int tothei, totgap = _gap * (info.count-1); + int freecount = info.count - info.numfix; + + // do the on-axis policy calculations + int defhei = 0; + switch (_policy) { + case STRETCH: + if (freecount > 0) { + defhei = (b.height - info.fixhei - totgap) / freecount; + tothei = b.height; + } else { + tothei = info.fixhei + totgap; + } + break; + + case EQUALIZE: + defhei = info.maxhei; + tothei = info.fixhei + defhei * freecount + totgap; + break; + + default: + case NONE: + tothei = info.tothei + totgap; + break; + } + + // do the off-axis policy calculations + int defwid = 0; + switch (_offpolicy) { + case STRETCH: + defwid = b.width; + break; + + case EQUALIZE: + sx = (b.width - info.maxwid)/2; + defwid = info.maxwid; + break; + + default: + case NONE: + break; + } + + // do the justification-related calculations + switch (_justification) { + case CENTER: + sy = (b.height - tothei)/2; + break; + case RIGHT: + sy = b.height - tothei; + break; + } + + // do the layout + for (int i = 0; i < nk; i++) { + // skip non-visible kids + if (info.dimens[i] == null) { + continue; + } + + Component child = parent.getComponent(i); + int newhei = defhei; + int newwid = defwid; + + if (_policy == NONE || isFixed(child)) { + newhei = info.dimens[i].height; + } + + if (_offpolicy == NONE) { + newwid = info.dimens[i].width; + sx = (b.width - newwid)/2; + } + + child.setBounds(sx, sy, newwid, newhei); + sy += child.size().height + _gap; + } + } +}