/******************************************************************************* * 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 org.andork.awt.layout; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.Point; import java.awt.Rectangle; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; public enum Side { TOP { @Override public Axis axis() { return Axis.Y; } @Override public String borderLayoutAnchor() { return BorderLayout.NORTH; } @Override public int direction() { return -1; } @Override public int gbcAnchor() { return GridBagConstraints.NORTH; } @Override public int get(Insets insets) { return insets.top; } @Override public Side inverse() { return LEFT; } @Override public int location(Rectangle bounds) { return bounds.y; } @Override public Side nextClockwise() { return RIGHT; } @Override public Side nextCounterClockwise() { return LEFT; } @Override public Side opposite() { return BOTTOM; } @Override public Cursor resizeCursor() { return Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR); } @Override public void set(Insets insets, int value) { insets.top = value; } @Override public void setLocation(Rectangle bounds, int location) { bounds.y = location; } @Override public void stretch(Rectangle bounds, int location) { bounds.height += bounds.y - location; bounds.y = location; } @Override public int swingConstant() { return SwingConstants.TOP; } }, BOTTOM { @Override public Axis axis() { return Axis.Y; } @Override public String borderLayoutAnchor() { return BorderLayout.SOUTH; } @Override public int direction() { return 1; } @Override public int gbcAnchor() { return GridBagConstraints.SOUTH; } @Override public int get(Insets insets) { return insets.bottom; } @Override public Side inverse() { return RIGHT; } @Override public int location(Rectangle bounds) { return bounds.y + bounds.height; } @Override public Side nextClockwise() { return LEFT; } @Override public Side nextCounterClockwise() { return RIGHT; } @Override public Side opposite() { return TOP; } @Override public Cursor resizeCursor() { return Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR); } @Override public void set(Insets insets, int value) { insets.bottom = value; } @Override public void setLocation(Rectangle bounds, int location) { bounds.y = location - bounds.height; } @Override public void stretch(Rectangle bounds, int location) { bounds.height = location - bounds.y; } @Override public int swingConstant() { return SwingConstants.BOTTOM; } }, LEFT { @Override public Axis axis() { return Axis.X; } @Override public String borderLayoutAnchor() { return BorderLayout.WEST; } @Override public int direction() { return -1; } @Override public int gbcAnchor() { return GridBagConstraints.WEST; } @Override public int get(Insets insets) { return insets.left; } @Override public Side inverse() { return TOP; } @Override public int location(Rectangle bounds) { return bounds.x; } @Override public Side nextClockwise() { return TOP; } @Override public Side nextCounterClockwise() { return BOTTOM; } @Override public Side opposite() { return RIGHT; } @Override public Cursor resizeCursor() { return Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR); } @Override public void set(Insets insets, int value) { insets.left = value; } @Override public void setLocation(Rectangle bounds, int location) { bounds.x = location; } @Override public void stretch(Rectangle bounds, int location) { bounds.width += bounds.x - location; bounds.x = location; } @Override public int swingConstant() { return SwingConstants.LEFT; } }, RIGHT { @Override public Axis axis() { return Axis.X; } @Override public String borderLayoutAnchor() { return BorderLayout.EAST; } @Override public int direction() { return 1; } @Override public int gbcAnchor() { return GridBagConstraints.EAST; } @Override public int get(Insets insets) { return insets.right; } @Override public Side inverse() { return BOTTOM; } @Override public int location(Rectangle bounds) { return bounds.x + bounds.width; } @Override public Side nextClockwise() { return BOTTOM; } @Override public Side nextCounterClockwise() { return TOP; } @Override public Side opposite() { return LEFT; } @Override public Cursor resizeCursor() { return Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR); } @Override public void set(Insets insets, int value) { insets.right = value; } @Override public void setLocation(Rectangle bounds, int location) { bounds.x = location - bounds.width; } @Override public void stretch(Rectangle bounds, int location) { bounds.width = location - bounds.x; } @Override public int swingConstant() { return SwingConstants.RIGHT; } }; public static Side fromAxis(Axis axis, int direction) { if (direction == 0) { throw new IllegalArgumentException("direction must be nonzero"); } switch (axis) { case X: return direction > 0 ? RIGHT : LEFT; case Y: return direction < 0 ? BOTTOM : TOP; default: throw new IllegalArgumentException("axis must be non-null"); } } public static Side fromGbcAnchor(int gbcAnchor) { switch (gbcAnchor) { case GridBagConstraints.NORTH: return TOP; case GridBagConstraints.EAST: return RIGHT; case GridBagConstraints.SOUTH: return BOTTOM; case GridBagConstraints.WEST: return LEFT; default: throw new IllegalArgumentException("gbcAnchor must be NORTH, EAST, SOUTH, or WEST"); } } public static Side fromSwingConstant(int swingConstant) { switch (swingConstant) { case SwingConstants.TOP: return TOP; case SwingConstants.BOTTOM: return BOTTOM; case SwingConstants.LEFT: return LEFT; case SwingConstants.RIGHT: return RIGHT; default: throw new IllegalArgumentException("swingConstant must be TOP, BOTTOM, LEFT, or RIGHT"); } } /** * @return the axis this side is positioned along (for example, even though * the top side is a horizontal line, its position is on the y axis, * so its axis is {@link Axis#Y}). */ public abstract Axis axis(); public abstract String borderLayoutAnchor(); public Point center(Component comp) { return center(comp.getBounds()); } public Point center(Rectangle bounds) { Point p = new Point(); axis().set(p, location(bounds)); Axis opposite = axis().opposite(); opposite.set(p, opposite.center(bounds)); return p; } /** * @return a unit increment along this side's axis from the center of the * bounds toward the side (for example, the direction for * {@link #TOP} is -1, for {@link #RIGHT} is 1). */ public abstract int direction(); public abstract int gbcAnchor(); public abstract int get(Insets insets); public void grow(Rectangle bounds, int amount) { setLocation(bounds, location(bounds) + amount * direction()); } public int inset(Container parent) { return get(parent.getInsets()); } public int insetLocalLocation(Container parent) { return localLocation(parent) - direction() * inset(parent); } /** * @return the side this becomes if the x and y axes are inverted. */ public abstract Side inverse(); public boolean isLower() { return direction() < 0; } public boolean isUpper() { return direction() > 0; } public int localLocation(Component comp) { return location(SwingUtilities.getLocalBounds(comp)); } public int location(Component comp) { return location(comp.getBounds()); } public abstract int location(Rectangle bounds); public abstract Side nextClockwise(); public abstract Side nextCounterClockwise(); public abstract Side opposite(); public abstract Cursor resizeCursor(); public abstract void set(Insets insets, int value); public abstract void setLocation(Rectangle bounds, int location); public abstract void stretch(Rectangle bounds, int location); public abstract int swingConstant(); }