/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program 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 General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package com.andork.plot;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.Rectangle;
import java.util.HashMap;
import java.util.Map;
import javax.swing.SwingUtilities;
import org.andork.awt.layout.Corner;
import org.andork.awt.layout.RectangleUtils;
import com.andork.plot.PlotAxis.Orientation;
public class PlotPanelLayout implements LayoutManager2 {
private static enum SizeType {
MINIMUM, PREFERRED, MAXIMUM;
}
private final Map<Component, Object> constraints = new HashMap<Component, Object>();
@Override
public void addLayoutComponent(Component comp, Object constraints) {
this.constraints.put(comp, constraints);
}
@Override
public void addLayoutComponent(String name, Component comp) {
}
@Override
public float getLayoutAlignmentX(Container target) {
return 0;
}
@Override
public float getLayoutAlignmentY(Container target) {
return 0;
}
private Dimension getSize(Component comp, SizeType sizeType) {
switch (sizeType) {
case MAXIMUM:
return comp.getMaximumSize();
case PREFERRED:
return comp.getPreferredSize();
case MINIMUM:
return comp.getMinimumSize();
default:
throw new IllegalArgumentException("invalid sizeType: " + sizeType);
}
}
@Override
public void invalidateLayout(Container target) {
}
@Override
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
Insets plotInsets = new Insets(0, 0, 0, 0);
Dimension prefSize = preferredLayoutSize(parent);
Dimension actualSize = parent.getSize();
SizeType hSizeType = actualSize.width >= prefSize.width ? SizeType.PREFERRED : SizeType.MINIMUM;
SizeType vSizeType = actualSize.height >= prefSize.height ? SizeType.PREFERRED : SizeType.MINIMUM;
for (Component comp : parent.getComponents()) {
if (!comp.isVisible()) {
continue;
}
if (comp instanceof PlotAxis) {
PlotAxis axis = (PlotAxis) comp;
switch (axis.getLabelPosition()) {
case TOP:
plotInsets.top += getSize(axis, vSizeType).height;
break;
case LEFT:
plotInsets.left += getSize(axis, hSizeType).width;
break;
case BOTTOM:
plotInsets.bottom += getSize(axis, vSizeType).height;
break;
case RIGHT:
plotInsets.right += getSize(axis, hSizeType).width;
break;
}
}
}
Rectangle insetBounds = RectangleUtils.insetCopy(SwingUtilities.getLocalBounds(parent), insets);
Rectangle plotBounds = RectangleUtils.insetCopy(insetBounds, plotInsets);
Insets axisInsets = (Insets) insets.clone();
int plotLeft = insets.left + plotInsets.left;
int plotTop = insets.top + plotInsets.top;
int plotWidth = parent.getWidth() - insets.left - plotInsets.left - insets.right - plotInsets.right;
int plotHeight = parent.getHeight() - insets.top - plotInsets.top - insets.bottom - plotInsets.bottom;
for (Component comp : parent.getComponents()) {
if (comp instanceof PlotAxis) {
PlotAxis axis = (PlotAxis) comp;
Dimension size;
switch (axis.getLabelPosition()) {
case TOP:
size = getSize(axis, vSizeType);
axis.setBounds(plotLeft, axisInsets.top, plotWidth, size.height);
axisInsets.top += size.height;
break;
case LEFT:
size = getSize(axis, hSizeType);
axis.setBounds(axisInsets.left, plotTop, size.width, plotHeight);
axisInsets.bottom += size.height;
break;
case BOTTOM:
size = getSize(axis, vSizeType);
axis.setBounds(plotLeft, parent.getHeight() - axisInsets.bottom - size.height, plotWidth,
size.height);
axisInsets.bottom += size.height;
break;
case RIGHT:
size = getSize(axis, hSizeType);
axis.setBounds(parent.getWidth() - axisInsets.right - size.width, plotTop, size.width, plotHeight);
axisInsets.right += size.width;
break;
}
} else {
Object constraints = this.constraints.get(comp);
if (constraints != null && constraints instanceof Corner) {
Corner corner = (Corner) constraints;
Rectangle bounds = new Rectangle();
corner.setLocation(bounds, corner.location(insetBounds));
corner.opposite().stretch(bounds, corner.location(plotBounds));
comp.setBounds(bounds);
} else {
comp.setBounds(plotLeft, plotTop, plotWidth, plotHeight);
}
}
}
}
private Dimension layoutSize(Container parent, SizeType sizeType) {
Dimension plotSize = new Dimension();
Dimension axisSize = new Dimension();
for (Component comp : parent.getComponents()) {
if (!comp.isVisible()) {
continue;
}
if (comp instanceof Plot) {
Dimension size = getSize(comp, sizeType);
plotSize.width = Math.max(plotSize.width, size.width);
plotSize.height = Math.max(plotSize.height, size.height);
} else if (comp instanceof PlotAxis) {
PlotAxis axis = (PlotAxis) comp;
Dimension size = getSize(comp, sizeType);
if (axis.getOrientation() == Orientation.HORIZONTAL) {
axisSize.height += size.height;
axisSize.width = Math.max(axisSize.width, size.width);
} else {
axisSize.width += size.width;
axisSize.height = Math.max(axisSize.height, size.height);
}
}
}
Insets insets = parent.getInsets();
return new Dimension(plotSize.width + axisSize.width + insets.left + insets.right,
plotSize.height + axisSize.height + insets.top + insets.bottom);
}
@Override
public Dimension maximumLayoutSize(Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
@Override
public Dimension minimumLayoutSize(Container parent) {
return layoutSize(parent, SizeType.MINIMUM);
}
@Override
public Dimension preferredLayoutSize(Container parent) {
return layoutSize(parent, SizeType.PREFERRED);
}
@Override
public void removeLayoutComponent(Component comp) {
constraints.remove(comp);
}
}