/* * Copyright (C) 2004 The Concord Consortium, Inc., * 10 Concord Crossing, Concord, MA 01742 * * Web Site: http://www.concord.org * Email: info@concord.org * * This library 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.1 of the License, or (at your option) any later version. * * This library 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 this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * END LICENSE */ package org.concord.swing; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; public class SelectableItem implements Selectable { protected Component componentItem; protected Boundary boundary = new Boundary(this); protected boolean selected = false; protected SelectableContainer container; protected Color defaultColor = Color.BLACK; protected Color activeColor = Color.RED; public SelectableItem(SelectableContainer container) { this.container = container; } public void draw(Graphics g) { boundary.draw(g); } public Component getComponent() { return componentItem; } public void setComponent(Component item) { componentItem = item; if (componentItem != null) { boundary.setBounds(item.getBounds()); } } public Boundary getBoundary() { return boundary; } /* (non-Javadoc) * @see org.concord.swing.Selectable#isSelected() */ public boolean isSelected() { return selected; } /* (non-Javadoc) * @see org.concord.swing.Selectable#setSelected(boolean) */ public void setSelected(boolean value) { selected = value; } /* (non-Javadoc) * @see org.concord.swing.Selectable#toggleSelected() */ public void toggleSelected() { // TODO Auto-generated method stub } /* (non-Javadoc) * @see org.concord.swing.Selectable#contains(int, int) */ public boolean contains(int x, int y) { return boundary.contains(x, y); } public boolean isActive() { return container.getActiveObject() == this; } public class Handle extends Rectangle { public static final int TOP_LEFT = 0; public static final int TOP_MIDDLE = 1; public static final int TOP_RIGHT = 2; public static final int MIDDLE_RIGHT = 3; public static final int BOTTOM_RIGHT = 4; public static final int BOTTOM_MIDDLE = 5; public static final int BOTTOM_LEFT = 6; public static final int MIDDLE_LEFT = 7; public static final int DRAG = 8; public static final int HANDLE_WIDTH = 6; public static final int HANDLE_HEIGHT = 6; public static final int MIN_WIDTH = HANDLE_WIDTH - 2; public static final int MIN_HEIGHT = HANDLE_HEIGHT - 2; public final Rectangle [] scaleFactors = { new Rectangle( 1, 1, -1, -1), new Rectangle( 0, 1, 0, -1), new Rectangle( 0, 1, 1, -1), new Rectangle( 0, 0, 1, 0), new Rectangle( 0, 0, 1, 1), new Rectangle( 0, 0, 0, 1), new Rectangle( 1, 0, -1, 1), new Rectangle( 1, 0, -1, 0), new Rectangle( 1, 1, 1, 1) }; protected Rectangle factors; protected int position = -1; protected Boundary parent; protected Rectangle dragBounds = new Rectangle(); public Handle(Boundary parent, int position, int w, int h) { this.width = w; this.height = h; this.position = position; this.parent = parent; factors = scaleFactors[position]; } public void scale(int dx, int dy) { Rectangle b = boundary.getBounds(); b.width += factors.width * dx; b.height += factors.height * dy; if (b.width < MIN_WIDTH) { b.width = MIN_WIDTH; } else { b.x += factors.x * dx; } if (b.height < MIN_HEIGHT) { b.height = MIN_HEIGHT; } else { b.y += factors.y * dy; } boundary.setBounds(b.x, b.y, b.width, b.height); } public void setHandleBounds(int x, int y, int w, int h) { switch (position) { case TOP_LEFT: this.x = x - width - 1; this.y = y - height - 1; break; case TOP_MIDDLE: this.x = x + w / 2 + 1 - width / 2; this.y = y - height - 1; break; case TOP_RIGHT: this.x = x + w + 2; this.y = y - height - 1; break; case MIDDLE_RIGHT: this.x = x + w + 2; this.y = y + h / 2 + 1 - height / 2; break; case BOTTOM_RIGHT: this.x = x + w + 2; this.y = y + h + 2; break; case BOTTOM_MIDDLE: this.x = x + w / 2 + 1 - width / 2; this.y = y + h + 2; break; case BOTTOM_LEFT: this.x = x - width - 1; this.y = y + h + 2; break; case MIDDLE_LEFT: this.x = x - width - 1; this.y = y + h / 2 + 1 - height / 2; break; case DRAG: dragBounds.x = x - width - 1; dragBounds.y = y - height - 1; dragBounds.width = w + 2 * width + 2; dragBounds.height = h + 2 * height + 2; break; } } public boolean contains(int x, int y) { if (position == DRAG) { return dragBounds.contains(x, y); } return super.contains(x, y); } public int getPosition() { return position; } } public class Boundary extends Rectangle { protected int handleWidth = Handle.HANDLE_WIDTH; protected int handleHeight = Handle.HANDLE_HEIGHT; protected Handle [] handles = new Handle[9]; protected Selectable parent; private Handle selectedHandle; public Boundary(Selectable selectable) { parent = selectable; } public void setBounds(Rectangle b) { setBounds(b.x, b.y, b.width, b.height); } public void setHandleSize(int width, int height) { handleWidth = width; handleHeight = height; for (int i = 0; i < handles.length; i++) { if (handles[i] == null) { handles[i] = new Handle(this, i, handleWidth, handleHeight); } else { handles[i].setSize(handleWidth, handleHeight); } } } public void setBounds(int x, int y, int width, int height) { componentItem.setBounds(x, y, width, height); x--; y--; width++; height++; super.setBounds(x, y, width, height); setHandleSize(handleWidth, handleHeight); for (int i = 0; i < handles.length; i++) { handles[i].setHandleBounds(x, y, width, height); } } public Rectangle getBounds() { return componentItem.getBounds(); } public Point getLocation() { return componentItem.getLocation(); } public void setLocation(int x, int y) { Dimension size = getSize(); setBounds(x, y, size.width, size.height); } public void setLocation(Point location) { setLocation(location.x, location.y); } public Dimension getSize() { return componentItem.getSize(); } public void setSize(int width, int height) { Point location = getLocation(); setBounds(location.x, location.y, width, height); } public void setSize(Dimension size) { setSize(size.width, size.height); } public Handle getSelectedHandle() { return selectedHandle; } public Selectable getParent() { return parent; } public Handle findHandle(int x, int y) { for (int i = 0; i < handles.length; i++) { if (handles[i].contains(x, y)) { return handles[i]; } } return null; } public boolean contains(int x, int y) { selectedHandle = findHandle(x, y); return selectedHandle instanceof Handle; } public void draw(Graphics g) { if (parent.isActive()) { g.setColor(activeColor); } g.drawRect(x, y, width, height); if (parent.isSelected()) { for (int i = 0; i < handles.length; i++) { Rectangle b = handles[i]; if (i == Handle.DRAG) { b = handles[i].dragBounds; g.drawRect(b.x, b.y, b.width, b.height); } else g.fillRect(b.x, b.y, b.width, b.height); } } g.setColor(defaultColor); } } }