// Copyright (c) 1996-98 The Regents of the University of California. All // Rights Reserved. Permission to use, copy, modify, and distribute this // software and its documentation for educational, research and non-profit // purposes, without fee, and without a written agreement is hereby granted, // provided that the above copyright notice and this paragraph appear in all // copies. Permission to incorporate this software into commercial products may // be obtained by contacting the University of California. David F. Redmiles // Department of Information and Computer Science (ICS) University of // California Irvine, California 92697-3425 Phone: 714-824-3823. This software // program and documentation are copyrighted by The Regents of the University // of California. The software program and documentation are supplied "as is", // without any accompanying services from The Regents. The Regents do not // warrant that the operation of the program will be uninterrupted or // error-free. The end-user understands that the program was developed for // research purposes and is advised not to rely exclusively on the program for // any reason. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY // PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY // DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE // SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF // CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, // ENHANCEMENTS, OR MODIFICATIONS. // File: Fig.java // Classes: Fig // Original Author: ics125b spring 1996 // $Id: Fig.java,v 1.24 1997/06/10 23:42:39 jrobbins Exp $ package uci.graphedit; import java.applet.*; import java.awt.*; import java.io.*; import java.util.*; import uci.util.*; import uci.ui.*; /** This class is the abstract base class for basic drawing objects * such as rectangles, lines, text, circles, etc. Also, class FigList * implements a composite figure. Fig's are Diagram elements that can * be placed in any LayerDiagram. Fig's are also used to define the * look of Perspective's on NetNode's.
* * * FEATURE: basic_shapes. * * @see FigRect * @see FigLine * @see FigText * @see FigCircle */ public abstract class Fig extends DiagramElement { //////////////////////////////////////////////////////// // constants /** Height and width in pixels of (square) rectangles used for handle. */ public static final int HAND_SIZE = 6; /** When selecting a small or thin object it is useful to allow * nearby mouse clicks. GRIP_MARGIN specifies how near these clicks * have to be. needs-more-work: This should be a preference. */ public static final int GRIP_MARGIN = 4; /** The smallest size of any Fig. Is this really needed? To limiting?*/ public static final int MIN_SIZE = 4; //////////////////////////////////////////////////////// // instance variables /** _handleRects[] and _numHandles together specify the number and * position of handles for directly manipulating a Fig. In the * future, this may be replaced with instances of a class * Handle. Needs-More-Work: More of this logic should be moved to * SelectionHandles. */ protected Rectangle _handleRects[]; private int _numHandles; /** Graphical attributes of figures. Other code that is accessing * these attruibutes should use the get and set functions for * graphical attributes. * * @see DiagramElement#get */ /** Width of fig object. */ protected int objectWidth; /** Height of fig object. */ protected int objectHeight; /** Outline color of fig object. */ protected Color objectLineColor = Color.black; /** Fill color of fig object. */ protected Color objectFillColor = Color.white; /** Thickness of line around object, for now limited to 0 or 1. */ protected int lineWidth = 1; /** True if the object should fill in its area. */ protected boolean filled = true; /** Future color of shadows. */ protected Color _shadowColor = Color.gray; /** Future offset of shadows. */ protected Point _shadowOffset = new Point(0, 0); /** Construct a new Fig with the given attributes and number of handles. */ public Fig(int x, int y, int width, int height, Color line_color, Color fill_color, int nHands) { position(x,y); objectWidth = width; objectHeight = height; objectLineColor = line_color; objectFillColor = fill_color; _numHandles = nHands; _handleRects = new Rectangle[_numHandles]; for (int i = 0; i < _numHandles; ++i) { _handleRects[i] = new Rectangle(0, 0, HAND_SIZE, HAND_SIZE); } owner(null); } /** Most subclasses will not use this constructor, it is only useful * for subclasses that redefine most of the infrastructure provided * by class Fig. */ public Fig() { } /** Return a handle ID for the handle under the mouse, or -1 if * none. Needs-More-Work: in the future, return a Handle instance or * null. */ public int pickHandle(int x, int y) { for (int i = 0; i < _numHandles; ++i) { if (_handleRects[i].inside(x, y)) { return i; } } return -1; } /** Draw the handles on this Fig. Needs-More-Work: should be done in * class SelectionHandles and future class Handle. */ public void drawHandles(Graphics g) { g.setColor(Globals.prefs().handleColor(this)); for (int i = 0; i < _numHandles; ++i) { Rectangle handle = _handleRects[i]; g.fillRect(handle.x, handle.y, handle.width, handle.height); } } /** Internal function to change the line color attribute. Other code * should use put(String key, Object value). */ public void setLineColor(Color col) { objectLineColor = col; } public Color getLineColor() { return objectLineColor; } /** Internal function to change the fill color attribute. Other code * should use put(String key, Object value). */ public void setFillColor(Color col) { objectFillColor = col; } public Color getFillColor() { return objectFillColor; } /** Internal function to change the whether fill color attribute is used. * Other code should use put(String key, Object value). */ public void setFilled(boolean f) { filled = f; } public boolean getFilled() { return filled; } /** Internal function to change the line width attribute is used. * Other code should use put(String key, Object value). */ public void setLineWidth(int w) { lineWidth = Math.max(0, Math.min(1, w)); } public int getLineWidth() { return lineWidth; } public Color getShadowColor() { return _shadowColor; } public void setShadowColor(Color c) { _shadowColor = c; } public Point getShadowOffset() { return _shadowOffset; } public void setShadowOffset(Point p) { _shadowOffset = p; } public Object get(String key) { if (key.equals(pLINE_WIDTH)) return new Integer(getLineWidth()); else if (key.equals(pLINE_COLOR)) return getLineColor(); else if (key.equals(pFILL_COLOR)) return getFillColor(); else if (key.equals(pFILLED)) return getFilled() ? Boolean.TRUE : Boolean.FALSE; else if (key.equals(pSHADOW_COLOR)) return getShadowColor(); else if (key.equals(pSHADOW_OFFSET)) return getShadowOffset(); else return super.get(key); } public boolean put(String key, Object value) { if (key.equals(pLINE_WIDTH)) setLineWidth(((Integer)value).intValue()); else if (key.equals(pLINE_COLOR)) setLineColor((Color) value); else if (key.equals(pFILL_COLOR)) setFillColor((Color) value); else if (key.equals(pFILLED)) setFilled(((Boolean) value).booleanValue()); else if (key.equals(pSHADOW_COLOR)) setShadowColor((Color) value); else if (key.equals(pSHADOW_OFFSET)) setShadowOffset((Point) value); else return super.put(key, value); changedProp(key); return true; } private static Vector _PropKeys = null; public Enumeration keysIn(String category) { if (_PropKeys == null) { _PropKeys = new Vector(); _PropKeys.addElement(pLINE_WIDTH); _PropKeys.addElement(pLINE_COLOR); _PropKeys.addElement(pFILLED); _PropKeys.addElement(pFILL_COLOR); } Enumeration propEnum = _PropKeys.elements(); if (category.equals("Color")) return new EnumerationComposite(super.keysIn(category), propEnum); return super.keysIn(category); } public boolean canPut(String key) { return key.equals(pLINE_WIDTH) || key.equals(pLINE_COLOR) || key.equals(pFILLED)|| key.equals(pFILL_COLOR) || key.equals(pSHADOW_OFFSET) || key.equals(pSHADOW_COLOR) || super.canPut(key); } /** Abstract method to draw this Fig. */ public abstract void draw(Graphics g); /** Draw this item as the current selected item. */ public abstract void drawSelected(Graphics g); /** Return a Rectangle that completely encloses this Fig. */ public Rectangle getBoundingBox() { Point p = position(); int minX = Math.min(p.x, p.x + objectWidth); int minY = Math.min(p.y, p.y + objectHeight); int maxX = Math.max(p.x, p.x + objectWidth); int maxY = Math.max(p.y, p.y + objectHeight); return new Rectangle(minX, minY, maxX - minX, maxY - minY); } public void setWidth(int w) { objectWidth = w; } public void setHeight(int h) { objectHeight = h; } public void resize(int w, int h) { objectWidth = w; objectHeight = h; } /** Change some attribute of this Fig when the user drags one of its * handles. By default, assume that every handle changes the position * of the Fig. */ public void dragHandle(int mX, int mY, int anX, int anY, Handle h) { translate(mX + anX, mY + anY); } /** Resize the object for drag on creation. It bypasses the things * done in resize so that the position of the object can be kept as * the anchor point. Needs-More-Work: do I really need this * function? * * @see FigLine#drag */ public void createDrag(int anchorX, int anchorY, int x, int y, int snapX, int snapY) { int newX = Math.min(anchorX, snapX); int newY = Math.min(anchorY, snapY); int newWidth = Math.max(anchorX, snapX) - newX; int newHeight = Math.max(anchorY, snapY) - newY; position(newX, newY); objectWidth = newWidth; objectHeight = newHeight; } } /* end class Fig */