package prefuse.action.layout;
import java.awt.Insets;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import prefuse.Display;
import prefuse.action.GroupAction;
import prefuse.util.PrefuseLib;
import prefuse.visual.VisualItem;
/**
* Abstract base class providing convenience methods for layout algorithms.
*
* @author <a href="http://jheer.org">jeffrey heer</a>
*/
public abstract class Layout extends GroupAction {
/** The explicitly set layout bounds. May be null. */
protected Rectangle2D m_bounds = null;
/** The explicitly set anchor point at which the layout can
* be centered or rooted. May be null. */
protected Point2D m_anchor = null;
protected boolean m_margin = false;
protected Insets m_insets = new Insets(0,0,0,0);
protected double[] m_bpts = new double[4];
protected Rectangle2D m_tmpb = new Rectangle2D.Double();
protected Point2D m_tmpa = new Point2D.Double();
// ------------------------------------------------------------------------
/**
* Create a new Layout.
*/
public Layout() {
super();
}
/**
* Create a new Layout.
* @param group the data group to layout.
*/
public Layout(String group) {
super(group);
}
public Layout(String group, long duration) {
super(group, duration);
}
// ------------------------------------------------------------------------
/**
* Set the margins the layout should observe within its layout bounds.
* @param top the top margin, in pixels
* @param left the left margin, in pixels
* @param bottom the bottom margin, in pixels
* @param right the right margin, in pixels
*/
public void setMargin(int top, int left, int bottom, int right) {
m_insets.top = top;
m_insets.left = left;
m_insets.bottom = bottom;
m_insets.right = right;
m_margin = true;
}
/**
* Returns the bounds in which the layout should be computed. If the
* bounds have been explicitly set, that value is used. Otherwise,
* an attempt is made to compute the bounds based upon the display
* region of the first display found in this action's associated
* Visualization.
* @return the layout bounds within which to constain the layout.
*/
public Rectangle2D getLayoutBounds() {
if ( m_bounds != null )
return m_bounds;
if ( m_vis != null && m_vis.getDisplayCount() > 0 )
{
Display d = m_vis.getDisplay(0);
Insets i = m_margin ? m_insets : d.getInsets(m_insets);
m_bpts[0] = i.left;
m_bpts[1] = i.top;
m_bpts[2] = d.getWidth()-i.right;
m_bpts[3] = d.getHeight()-i.bottom;
d.getInverseTransform().transform(m_bpts,0,m_bpts,0,2);
m_tmpb.setRect(m_bpts[0],m_bpts[1],
m_bpts[2]-m_bpts[0],
m_bpts[3]-m_bpts[1]);
return m_tmpb;
} else {
return null;
}
}
/**
* Explicitly set the layout bounds. A reference to the input rectangle
* instance is maintained, not a copy, and so any subsequent changes to
* the rectangle object will also change the layout bounds.
* @param b a rectangle specifying the layout bounds. A reference to this
* same instance is kept.
*/
public void setLayoutBounds(Rectangle2D b) {
m_bounds = b;
}
/**
* Return the layout anchor at which to center or root the layout. How this
* point is used (if it is used at all) is dependent on the particular
* Layout implementation. If no anchor point has been explicitly set, the
* center coordinate for the first display found in this action's
* associated Visualization is used, if available.
* @return the layout anchor point.
*/
public Point2D getLayoutAnchor() {
if ( m_anchor != null )
return m_anchor;
m_tmpa.setLocation(0,0);
if ( m_vis != null ) {
Display d = m_vis.getDisplay(0);
m_tmpa.setLocation(d.getWidth()/2.0,d.getHeight()/2.0);
d.getInverseTransform().transform(m_tmpa, m_tmpa);
}
return m_tmpa;
}
/**
* Explicitly set the layout anchor point. The provided object will be
* used directly (rather than copying its values), so subsequent
* changes to that point object will change the layout anchor.
* @param a the layout anchor point to use
*/
public void setLayoutAnchor(Point2D a) {
m_anchor = a;
}
/**
* Convenience method for setting an x-coordinate. The start value of the
* x-coordinate will be set to the current value, and the current and end
* values will be set to the provided x-coordinate. If the current value
* is not a number (NaN), the x-coordinate of the provided referrer
* item (if non null) will be used to set the start coordinate.
* @param item the item to set
* @param referrer the referrer item to use for the start location if
* the current valu eis not a number (NaN)
* @param x the x-coordinate value to set. This will be set for both
* the current and end values.
* @see prefuse.util.PrefuseLib#setX(VisualItem, VisualItem, double)
*/
public void setX(VisualItem item, VisualItem referrer, double x) {
PrefuseLib.setX(item, referrer, x);
}
/**
* Convenience method for setting an y-coordinate. The start value of the
* y-coordinate will be set to the current value, and the current and end
* values will be set to the provided y-coordinate. If the current value
* is not a number (NaN), the y-coordinate of the provided referrer
* item (if non null) will be used to set the start coordinate.
* @param item the item to set
* @param referrer the referrer item to use for the start location if
* the current valu eis not a number (NaN)
* @param y the y-coordinate value to set. This will be set for both
* the current and end values.
* @see prefuse.util.PrefuseLib#setY(VisualItem, VisualItem, double)
*/
public void setY(VisualItem item, VisualItem referrer, double y) {
PrefuseLib.setY(item, referrer, y);
}
} // end of abstract class Layout