/*
* ChartLayout.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.app.gui.chart;
import java.awt.*;
/**
* A layout manager similar to BorderLayout but with specific regions for
* parts of a chart (plot, axis, titles, etc.).
*
* @author Andrew Rambaut
*/
public class ChartLayout implements LayoutManager2 {
int hgap;
int vgap;
Component title = null;
Component xLabel = null;
Component yLabel = null;
Component chart = null;
/**
* Constructs a new ChartLayout.
*/
public ChartLayout() {
this(0, 0);
}
/**
* Constructs a ChartLayout with the specified gaps.
*
* @param hgap the horizontal gap
* @param vgap the vertical gap
*/
public ChartLayout(int hgap, int vgap) {
this.hgap = hgap;
this.vgap = vgap;
}
/**
* @return the horizontal gap between components.
*/
public int getHgap() {
return hgap;
}
/**
* Sets the horizontal gap between components.
*
* @param hgap the horizontal gap between components
*/
public void setHgap(int hgap) {
this.hgap = hgap;
}
/**
* @return the vertical gap between components.
*/
public int getVgap() {
return vgap;
}
/**
* Sets the vertical gap between components.
*
* @param vgap the vertical gap between components
*/
public void setVgap(int vgap) {
this.vgap = vgap;
}
/**
* Adds the specified named component to the layout.
*
* @param comp the component to be added
*/
public void addLayoutComponent(Component comp, Object constraints) {
synchronized (comp.getTreeLock()) {
if ((constraints == null) || (constraints instanceof String)) {
addLayoutComponent((String) constraints, comp);
} else {
throw new IllegalArgumentException("cannot add to layout: constraint must be a string (or null)");
}
}
}
/**
* @deprecated replaced by <code>addLayoutComponent(Component, Object)</code>.
*/
public void addLayoutComponent(String name, Component comp) {
synchronized (comp.getTreeLock()) {
/* Special case: treat null the same as "Chart". */
if (name == null) {
name = "Chart";
}
if ("Chart".equals(name) || "Table".equals(name)) {
chart = comp;
} else if ("Title".equals(name)) {
title = comp;
} else if ("XLabel".equals(name)) {
xLabel = comp;
} else if ("YLabel".equals(name)) {
yLabel = comp;
} else {
throw new IllegalArgumentException("cannot add to layout: unknown constraint: " + name);
}
}
}
/**
* Removes the specified component from the layout.
*
* @param comp the component to be removed
*/
public void removeLayoutComponent(Component comp) {
synchronized (comp.getTreeLock()) {
if (comp == chart) {
chart = null;
} else if (comp == title) {
title = null;
} else if (comp == xLabel) {
xLabel = null;
} else if (comp == yLabel) {
yLabel = null;
}
}
}
/**
* Returns the minimum dimensions needed to layout the components
* contained in the specified target container.
*
* @param target the Container on which to do the layout
* @see Container
* @see #preferredLayoutSize
*/
public Dimension minimumLayoutSize(Container target) {
synchronized (target.getTreeLock()) {
Dimension dim = new Dimension(0, 0);
if ((chart != null) && chart.isVisible()) {
Dimension d = chart.getMinimumSize();
dim.width = d.width;
dim.height = d.height;
}
if ((xLabel != null) && xLabel.isVisible()) {
Dimension d = xLabel.getMinimumSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
if ((yLabel != null) && yLabel.isVisible()) {
Dimension d = yLabel.getMinimumSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((title != null) && title.isVisible()) {
Dimension d = title.getMinimumSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
Insets insets = target.getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.top + insets.bottom;
return dim;
}
}
/**
* Returns the preferred dimensions for this layout given the components
* in the specified target container.
*
* @param target the component which needs to be laid out
* @see Container
* @see #minimumLayoutSize
*/
public Dimension preferredLayoutSize(Container target) {
synchronized (target.getTreeLock()) {
Dimension dim = new Dimension(0, 0);
if ((chart != null) && chart.isVisible()) {
Dimension d = chart.getPreferredSize();
dim.width = d.width;
dim.height = d.height;
}
if ((xLabel != null) && xLabel.isVisible()) {
Dimension d = xLabel.getPreferredSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
if ((yLabel != null) && yLabel.isVisible()) {
Dimension d = yLabel.getPreferredSize();
dim.width += d.width + hgap;
dim.height = Math.max(d.height, dim.height);
}
if ((title != null) && title.isVisible()) {
Dimension d = title.getPreferredSize();
dim.width = Math.max(d.width, dim.width);
dim.height += d.height + vgap;
}
Insets insets = target.getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.top + insets.bottom;
return dim;
}
}
/**
* Returns the maximum dimensions for this layout given the components
* in the specified target container.
*
* @param target the component which needs to be laid out
*/
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
/**
* Returns the alignment along the x axis. This specifies how
* the component would like to be aligned relative to other
* components. The value should be a number between 0 and 1
* where 0 represents alignment along the origin, 1 is aligned
* the furthest away from the origin, 0.5 is centered, etc.
*/
public float getLayoutAlignmentX(Container parent) {
return 0.5f;
}
/**
* Returns the alignment along the y axis. This specifies how
* the component would like to be aligned relative to other
* components. The value should be a number between 0 and 1
* where 0 represents alignment along the origin, 1 is aligned
* the furthest away from the origin, 0.5 is centered, etc.
*/
public float getLayoutAlignmentY(Container parent) {
return 0.5f;
}
/**
* Invalidates the layout, indicating that if the layout manager
* has cached information it should be discarded.
*/
public void invalidateLayout(Container target) {
}
/**
* Lays out the specified container. This method will actually reshape the
* components in the specified target container in order to satisfy the
* constraints of the CompassLayout object.
*
* @param target the component being laid out
* @see Container
*/
public void layoutContainer(Container target) {
synchronized (target.getTreeLock()) {
Insets insets = target.getInsets();
Dimension d;
d = target.getSize();
int top = insets.top;
int bottom = d.height - insets.bottom;
int left = insets.left;
int right = d.width - insets.right;
// defines the centre box.
int top1 = top;
int bottom1 = bottom;
int left1 = left;
if ((xLabel != null) && xLabel.isVisible()) {
d = xLabel.getPreferredSize();
bottom1 -= d.height + vgap;
}
if ((yLabel != null) && yLabel.isVisible()) {
d = yLabel.getPreferredSize();
left1 += d.width + hgap;
}
if ((title != null) && title.isVisible()) {
d = title.getPreferredSize();
top1 += d.height + vgap;
}
if ((xLabel != null) && xLabel.isVisible())
xLabel.setBounds(left1, bottom1, right - left1, bottom - bottom1);
if ((yLabel != null) && yLabel.isVisible())
yLabel.setBounds(left, top1, left1 - left, bottom1 - top1);
if ((title != null) && title.isVisible())
title.setBounds(left, top, right - left, top1 - top);
if ((chart != null) && chart.isVisible())
chart.setBounds(left1, top1, right - left1, bottom1 - top1);
}
}
/**
* Returns the String representation of this CompassLayout's values.
*/
public String toString() {
return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
}
}