Implemented a group layout manager that works like the One True Layout
System (as conceived in the Magic User Interface library [MUI] on the Amiga so long ago). Component weights are not yet supported, but fixedness works which is mainly what I need. git-svn-id: https://samskivert.googlecode.com/svn/trunk@23 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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).
|
||||
*
|
||||
* <p/> 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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user