Initial version of node map facilities.
git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@281 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// $Id: DuplicateEdgeException.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an action is attempted on an edge that is already
|
||||||
|
* present in the involved node.
|
||||||
|
*/
|
||||||
|
public class DuplicateEdgeException extends NodeMapException
|
||||||
|
{
|
||||||
|
public DuplicateEdgeException ()
|
||||||
|
{
|
||||||
|
super("error.duplicate_edge");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// $Id: DuplicateNodeException.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an action is attempted on a node that is already
|
||||||
|
* present in the node map.
|
||||||
|
*/
|
||||||
|
public class DuplicateNodeException extends NodeMapException
|
||||||
|
{
|
||||||
|
public DuplicateNodeException ()
|
||||||
|
{
|
||||||
|
super("error.duplicate_node");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// $Id: Edge.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
import java.awt.Graphics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The edge class represents an edge connecting two nodes.
|
||||||
|
*/
|
||||||
|
public abstract class Edge
|
||||||
|
{
|
||||||
|
/** The source node. */
|
||||||
|
public Node src;
|
||||||
|
|
||||||
|
/** The destination node. */
|
||||||
|
public Node dst;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an edge object connecting the given nodes.
|
||||||
|
*
|
||||||
|
* @param src the source node.
|
||||||
|
* @param dst the destination node.
|
||||||
|
*/
|
||||||
|
public Edge (Node src, Node dst)
|
||||||
|
{
|
||||||
|
this.src = src;
|
||||||
|
this.dst = dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paint the edge to the given graphics context.
|
||||||
|
*
|
||||||
|
* @param g the graphics context.
|
||||||
|
*/
|
||||||
|
public abstract void paint (Graphics g);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string representation of this edge.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
StringBuffer buf = new StringBuffer();
|
||||||
|
buf.append("[");
|
||||||
|
toString(buf);
|
||||||
|
return buf.append("]").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This should be overridden by derived classes (which should be sure
|
||||||
|
* to call <code>super.toString()</code>) to append the derived class
|
||||||
|
* specific event information to the string buffer.
|
||||||
|
*/
|
||||||
|
public void toString (StringBuffer buf)
|
||||||
|
{
|
||||||
|
buf.append("src=").append(src);
|
||||||
|
buf.append(", dst=").append(dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// $Id: LayoutManager.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The layout manager class provides an interface that lays out nodes
|
||||||
|
* in a node map via some preordained desirable methodology.
|
||||||
|
*/
|
||||||
|
public interface LayoutManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Lay out the nodes in the list in the fashion dictated by this
|
||||||
|
* particular layout manager. The node positions are updated via
|
||||||
|
* {@link Node#setPosition} such that subsequent rendering of the
|
||||||
|
* nodes will place them in appropriate positions.
|
||||||
|
*
|
||||||
|
* @param root the root node for the graph.
|
||||||
|
* @param nodes the list of nodes.
|
||||||
|
*/
|
||||||
|
public void layout (Node root, List nodes);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// $Id: Log.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A placeholder class that contains a reference to the log object used by
|
||||||
|
* the nodemap package.
|
||||||
|
*/
|
||||||
|
public class Log
|
||||||
|
{
|
||||||
|
public static com.samskivert.util.Log log =
|
||||||
|
new com.samskivert.util.Log("nodemap");
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void debug (String message)
|
||||||
|
{
|
||||||
|
log.debug(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void info (String message)
|
||||||
|
{
|
||||||
|
log.info(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void warning (String message)
|
||||||
|
{
|
||||||
|
log.warning(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convenience function. */
|
||||||
|
public static void logStackTrace (Throwable t)
|
||||||
|
{
|
||||||
|
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// $Id: NoSuchNodeException.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when a node cannot be found in the node map.
|
||||||
|
*/
|
||||||
|
public class NoSuchNodeException extends NodeMapException
|
||||||
|
{
|
||||||
|
public NoSuchNodeException ()
|
||||||
|
{
|
||||||
|
super("error.no_such_node");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,179 @@
|
|||||||
|
//
|
||||||
|
// $Id: Node.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The node class represents a single node in a directed graph of nodes.
|
||||||
|
*
|
||||||
|
* @see NodeMap
|
||||||
|
*/
|
||||||
|
public abstract class Node
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct a node with the given attributes.
|
||||||
|
*
|
||||||
|
* @param name the node name.
|
||||||
|
* @param width the width in pixels.
|
||||||
|
* @param height the height in pixels.
|
||||||
|
*/
|
||||||
|
public Node (String name, int width, int height)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
_width = width;
|
||||||
|
_height = height;
|
||||||
|
|
||||||
|
_pos = new Point();
|
||||||
|
_edges = new ArrayList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a connecting edge to this node. An edge may not be
|
||||||
|
* added to the node more than once.
|
||||||
|
*
|
||||||
|
* @param e the new edge.
|
||||||
|
*/
|
||||||
|
protected void addEdge (Edge e) throws DuplicateEdgeException
|
||||||
|
{
|
||||||
|
// don't allow adding the same edge object twice
|
||||||
|
if (_edges.contains(e)) {
|
||||||
|
throw new DuplicateEdgeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// save off the new connecting edge
|
||||||
|
_edges.add(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an <code>Iterator</code> object that iterates over the
|
||||||
|
* edges leaving this node.
|
||||||
|
*
|
||||||
|
* @return the iterator object.
|
||||||
|
*/
|
||||||
|
public Iterator getEdges ()
|
||||||
|
{
|
||||||
|
return (Collections.unmodifiableList(_edges)).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node's current position in pixels.
|
||||||
|
*
|
||||||
|
* @return point the node position.
|
||||||
|
*/
|
||||||
|
public Point getPosition ()
|
||||||
|
{
|
||||||
|
return _pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the node's position in pixels.
|
||||||
|
*
|
||||||
|
* @param x the x-position.
|
||||||
|
* @param y the y-position.
|
||||||
|
*/
|
||||||
|
public void setPosition (int x, int y)
|
||||||
|
{
|
||||||
|
_pos.setLocation(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the node contains the given point.
|
||||||
|
*
|
||||||
|
* @param x the x-position.
|
||||||
|
* @param y the y-position.
|
||||||
|
*
|
||||||
|
* @return true if the node contains the point, false if not.
|
||||||
|
*/
|
||||||
|
public boolean contains (int x, int y)
|
||||||
|
{
|
||||||
|
return (x >= _pos.x && x <= (_pos.x + _width) &&
|
||||||
|
y >= _pos.y && y <= (_pos.y + _height));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node width in pixels.
|
||||||
|
*/
|
||||||
|
public int getWidth ()
|
||||||
|
{
|
||||||
|
return _width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the node height in pixels.
|
||||||
|
*/
|
||||||
|
public int getHeight ()
|
||||||
|
{
|
||||||
|
return _height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the node to the given graphics context.
|
||||||
|
*
|
||||||
|
* @param g the graphics context.
|
||||||
|
*/
|
||||||
|
public abstract void paint (Graphics g);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the node's connecting edges to the given graphics context.
|
||||||
|
*
|
||||||
|
* @param g the graphics context.
|
||||||
|
*/
|
||||||
|
public void paintEdges (Graphics g)
|
||||||
|
{
|
||||||
|
int size = _edges.size();
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
((Edge)_edges.get(ii)).paint(g);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse-entered events for this node.
|
||||||
|
*/
|
||||||
|
public void handleMouseEntered ()
|
||||||
|
{
|
||||||
|
Log.info("handleMouseEntered [n=" + this + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse-exited events for this node.
|
||||||
|
*/
|
||||||
|
public void handleMouseExited ()
|
||||||
|
{
|
||||||
|
Log.info("handleMouseExited [n=" + this + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse-clicked events for this node.
|
||||||
|
*
|
||||||
|
* @param x the x-coordinate in intra-node pixels.
|
||||||
|
* @param y the y-coordinate in intra-node pixels.
|
||||||
|
*/
|
||||||
|
public void handleMouseClicked (int x, int y)
|
||||||
|
{
|
||||||
|
Log.info("handleMouseClicked [n=" + this + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a string representation of this node.
|
||||||
|
*/
|
||||||
|
public String toString ()
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The position in pixel coordinates. */
|
||||||
|
protected Point _pos;
|
||||||
|
|
||||||
|
/** The dimensions in pixel coordinates. */
|
||||||
|
protected int _width, _height;
|
||||||
|
|
||||||
|
/** The node name. */
|
||||||
|
protected String _name;
|
||||||
|
|
||||||
|
/** The edges leaving this node. */
|
||||||
|
protected ArrayList _edges;
|
||||||
|
}
|
||||||
@@ -0,0 +1,270 @@
|
|||||||
|
//
|
||||||
|
// $Id: NodeMap.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The node map class represents a directed graph of nodes comprised
|
||||||
|
* of {@link Node} objects. A user-specifiable {@link LayoutManager}
|
||||||
|
* is used to lay out the nodes in the graph.
|
||||||
|
*/
|
||||||
|
public class NodeMap
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Construct a node map object with the given layout manager.
|
||||||
|
*
|
||||||
|
* @param lgmr the layout manager.
|
||||||
|
*/
|
||||||
|
public NodeMap (LayoutManager lmgr)
|
||||||
|
{
|
||||||
|
_lmgr = lmgr;
|
||||||
|
_nodes = new ArrayList();
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Force the nodes in the map to be re-laid out.
|
||||||
|
*/
|
||||||
|
public void layout ()
|
||||||
|
{
|
||||||
|
// do nothing if we have no nodes
|
||||||
|
if (_nodes.size() == 0) return;
|
||||||
|
|
||||||
|
// default to using the first node as the root
|
||||||
|
if (_root == null) {
|
||||||
|
_root = (Node)_nodes.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lay out the nodes
|
||||||
|
_lmgr.layout(_root, _nodes);
|
||||||
|
|
||||||
|
// update bounding node positions
|
||||||
|
updateBounds();
|
||||||
|
|
||||||
|
// note that we're no longer dirty
|
||||||
|
_dirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the bounding rectangle that wholly contains the node map.
|
||||||
|
*/
|
||||||
|
protected void updateBounds ()
|
||||||
|
{
|
||||||
|
Iterator iter = _nodes.iterator();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
Node n = (Node)iter.next();
|
||||||
|
Point pos = n.getPosition();
|
||||||
|
int wid = n.getWidth(), hei = n.getHeight();
|
||||||
|
|
||||||
|
_minx = Math.min(_minx, pos.x);
|
||||||
|
_maxx = Math.max(_maxx, pos.x + wid);
|
||||||
|
_miny = Math.min(_miny, pos.y);
|
||||||
|
_maxy = Math.max(_maxy, pos.y + hei);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the node map to the given graphics context.
|
||||||
|
*
|
||||||
|
* @param g the graphics context.
|
||||||
|
*/
|
||||||
|
public void paint (Graphics g)
|
||||||
|
{
|
||||||
|
// lay out the nodes if necessary
|
||||||
|
if (_dirty) {
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
// translate context to node map origin
|
||||||
|
g.translate(-_minx, -_miny);
|
||||||
|
|
||||||
|
// render all node edges
|
||||||
|
int size = _nodes.size();
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
Node n = (Node)_nodes.get(ii);
|
||||||
|
n.paintEdges(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render all nodes
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
Node n = (Node)_nodes.get(ii);
|
||||||
|
n.paint(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
// highlight the last node entered
|
||||||
|
if (_lastnode != null) {
|
||||||
|
g.setColor(Color.red);
|
||||||
|
Point pos = _lastnode.getPosition();
|
||||||
|
int wid = _lastnode.getWidth(), hei = _lastnode.getHeight();
|
||||||
|
g.drawRect(pos.x, pos.y, wid, hei);
|
||||||
|
}
|
||||||
|
|
||||||
|
// restore original origin
|
||||||
|
g.translate(_minx, _miny);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given node to the node map. A given node may not be
|
||||||
|
* present in the node map more than once.
|
||||||
|
*
|
||||||
|
* @param n the node to add.
|
||||||
|
*/
|
||||||
|
public void addNode (Node n) throws DuplicateNodeException
|
||||||
|
{
|
||||||
|
// don't allow adding a node more than once
|
||||||
|
if (_nodes.contains(n)) {
|
||||||
|
throw new DuplicateNodeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the node
|
||||||
|
_nodes.add(n);
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given edge to the node. Edges may not be added to a
|
||||||
|
* node more than once, or to a node that is not present in the
|
||||||
|
* node map.
|
||||||
|
*
|
||||||
|
* @param n the node.
|
||||||
|
* @param e the edge to add.
|
||||||
|
*/
|
||||||
|
public void addEdge (Node n, Edge e)
|
||||||
|
throws NoSuchNodeException, DuplicateEdgeException
|
||||||
|
{
|
||||||
|
// don't allow adding an edge to an unknown node
|
||||||
|
if (!_nodes.contains(n)) {
|
||||||
|
throw new NoSuchNodeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the edge to the node
|
||||||
|
n.addEdge(e);
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the root node for the node map. The given node must be
|
||||||
|
* present in the node map.
|
||||||
|
*
|
||||||
|
* @param n the root node.
|
||||||
|
*/
|
||||||
|
public void setRootNode (Node n) throws NoSuchNodeException
|
||||||
|
{
|
||||||
|
if (!_nodes.contains(n)) {
|
||||||
|
throw new NoSuchNodeException();
|
||||||
|
}
|
||||||
|
|
||||||
|
_root = n;
|
||||||
|
_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the dimensions of the node map in pixels.
|
||||||
|
*/
|
||||||
|
public Dimension getSize ()
|
||||||
|
{
|
||||||
|
// lay out the nodes if necessary
|
||||||
|
if (_dirty) {
|
||||||
|
layout();
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Dimension(_maxx - _minx, _maxy - _miny);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse-moved events passed on by the containing panel.
|
||||||
|
* Inform any affected nodes of mouse-entered and mouse-exited
|
||||||
|
* events.
|
||||||
|
*
|
||||||
|
* @param x the mouse x-coordinate.
|
||||||
|
* @param y the ymouse y-coordinate.
|
||||||
|
*/
|
||||||
|
public void handleMouseMoved (int x, int y)
|
||||||
|
{
|
||||||
|
Node enternode = null;
|
||||||
|
|
||||||
|
// translate coordinates to node map origin
|
||||||
|
x += _minx;
|
||||||
|
y += _miny;
|
||||||
|
|
||||||
|
int size = _nodes.size();
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
Node n = (Node)_nodes.get(ii);
|
||||||
|
|
||||||
|
if (n.contains(x, y)) {
|
||||||
|
|
||||||
|
// bail if we're in the same node we were in last
|
||||||
|
if (_lastnode == n) return;
|
||||||
|
|
||||||
|
// note that we're entering this node
|
||||||
|
enternode = n;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit the last node, if any
|
||||||
|
if (_lastnode != null) {
|
||||||
|
_lastnode.handleMouseExited();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enter the new node, if any
|
||||||
|
if (enternode != null) {
|
||||||
|
enternode.handleMouseEntered();
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the last node entered
|
||||||
|
_lastnode = enternode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle mouse-clicked events passed on by the containing panel.
|
||||||
|
* Inform any affected nodes of mouse-clicked events.
|
||||||
|
*
|
||||||
|
* @param x the mouse x-coordinate.
|
||||||
|
* @param y the ymouse y-coordinate.
|
||||||
|
*/
|
||||||
|
public void handleMouseClicked (int x, int y)
|
||||||
|
{
|
||||||
|
// translate coordinates to node map origin
|
||||||
|
x += _minx;
|
||||||
|
y += _miny;
|
||||||
|
|
||||||
|
int size = _nodes.size();
|
||||||
|
for (int ii = 0; ii < size; ii++) {
|
||||||
|
Node n = (Node)_nodes.get(ii);
|
||||||
|
|
||||||
|
if (n.contains(x, y)) {
|
||||||
|
|
||||||
|
// inform the node of the mouse click, with
|
||||||
|
// coordinates translated to suit node interior
|
||||||
|
Point pos = n.getPosition();
|
||||||
|
n.handleMouseClicked(x - pos.x, y - pos.y);
|
||||||
|
|
||||||
|
// nodes can't overlap for now, so we're done
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The layout manager. */
|
||||||
|
protected LayoutManager _lmgr;
|
||||||
|
|
||||||
|
/** The nodes in the node map. */
|
||||||
|
protected ArrayList _nodes;
|
||||||
|
|
||||||
|
/** The root node. */
|
||||||
|
protected Node _root;
|
||||||
|
|
||||||
|
/** The bounding box coordinates. */
|
||||||
|
protected int _minx, _maxx, _miny, _maxy;
|
||||||
|
|
||||||
|
/** The last node the mouse entered. */
|
||||||
|
protected Node _lastnode;
|
||||||
|
|
||||||
|
/** Whether the node map needs to be laid out. */
|
||||||
|
protected boolean _dirty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
//
|
||||||
|
// $Id: NodeMapException.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when an error occurs while performing certain activities
|
||||||
|
* involving a node map object.
|
||||||
|
*/
|
||||||
|
public class NodeMapException extends Exception
|
||||||
|
{
|
||||||
|
public NodeMapException (String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
//
|
||||||
|
// $Id: NodeMapPanel.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import javax.swing.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The node map panel handles display of a node map and passes Swing
|
||||||
|
* UI events on to the appropriate node map event handling methods.
|
||||||
|
*/
|
||||||
|
public class NodeMapPanel extends JPanel
|
||||||
|
implements MouseListener, MouseMotionListener
|
||||||
|
{
|
||||||
|
public NodeMapPanel (NodeMap map)
|
||||||
|
{
|
||||||
|
_map = map;
|
||||||
|
|
||||||
|
// listen to our mouse events
|
||||||
|
addMouseListener(this);
|
||||||
|
addMouseMotionListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paintComponent (Graphics g)
|
||||||
|
{
|
||||||
|
super.paintComponent(g);
|
||||||
|
_map.paint(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension getPreferredSize ()
|
||||||
|
{
|
||||||
|
return _map.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** MouseListener interface methods */
|
||||||
|
|
||||||
|
public void mouseClicked (MouseEvent e)
|
||||||
|
{
|
||||||
|
_map.handleMouseClicked(e.getX(), e.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mousePressed (MouseEvent e) { }
|
||||||
|
public void mouseReleased (MouseEvent e) { }
|
||||||
|
public void mouseEntered (MouseEvent e) { }
|
||||||
|
public void mouseExited (MouseEvent e) { }
|
||||||
|
|
||||||
|
/** MouseMotionListener interface methods */
|
||||||
|
|
||||||
|
public void mouseMoved (MouseEvent e)
|
||||||
|
{
|
||||||
|
_map.handleMouseMoved(e.getX(), e.getY());
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mouseDragged (MouseEvent e) { }
|
||||||
|
|
||||||
|
/** The node map. */
|
||||||
|
protected NodeMap _map;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
//
|
||||||
|
// $Id: DirectionalEdge.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap.direction;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import com.threerings.nodemap.*;
|
||||||
|
|
||||||
|
public class DirectionalEdge extends Edge
|
||||||
|
{
|
||||||
|
/** The edge direction as a {@link Directions} constant. */
|
||||||
|
public int dir;
|
||||||
|
|
||||||
|
public DirectionalEdge (Node src, Node dst, int dir)
|
||||||
|
{
|
||||||
|
super(src, dst);
|
||||||
|
this.dir = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paint (Graphics g)
|
||||||
|
{
|
||||||
|
g.setColor(Color.black);
|
||||||
|
|
||||||
|
Point spos = src.getPosition(), dpos = dst.getPosition();
|
||||||
|
|
||||||
|
int csx = spos.x + (src.getWidth() / 2);
|
||||||
|
int csy = spos.y + (src.getHeight() / 2);
|
||||||
|
|
||||||
|
int cdx = dpos.x + (dst.getWidth() / 2);
|
||||||
|
int cdy = dpos.y + (dst.getHeight() / 2);
|
||||||
|
|
||||||
|
g.drawLine(csx, csy, cdx, cdy);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// $Id: DirectionalLayoutManager.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap.direction;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import com.threerings.nodemap.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directional layout manager lays nodes out according to the
|
||||||
|
* eight cardinal directions as specified in the {@link Directions}
|
||||||
|
* class. The nodes must be connected with {@link DirectionalEdge}
|
||||||
|
* edges.
|
||||||
|
*/
|
||||||
|
public class DirectionalLayoutManager implements LayoutManager
|
||||||
|
{
|
||||||
|
public DirectionalLayoutManager (int edgelen)
|
||||||
|
{
|
||||||
|
_edgelen = edgelen;
|
||||||
|
_closed = new HashMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void layout (Node root, List nodes)
|
||||||
|
{
|
||||||
|
_closed.clear();
|
||||||
|
|
||||||
|
// lay out all nodes
|
||||||
|
layoutNode(root, 0, 0, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void layoutNode (Node root, int x, int y, Node n)
|
||||||
|
{
|
||||||
|
// consider each node only once for now
|
||||||
|
if (_closed.containsKey(n)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the node's location
|
||||||
|
n.setPosition(x, y);
|
||||||
|
|
||||||
|
// remember that we've placed this node
|
||||||
|
_closed.put(n, null);
|
||||||
|
|
||||||
|
Iterator iter = n.getEdges();
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
DirectionalEdge e = (DirectionalEdge)iter.next();
|
||||||
|
|
||||||
|
int tx = x, ty = y;
|
||||||
|
int wid = e.dst.getWidth(), hei = e.dst.getHeight();
|
||||||
|
|
||||||
|
// shift the node in the appropriate direction
|
||||||
|
switch (e.dir) {
|
||||||
|
case Directions.NORTH:
|
||||||
|
tx -= (_edgelen + wid);
|
||||||
|
ty -= (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.NORTHEAST:
|
||||||
|
ty -= (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.EAST:
|
||||||
|
tx += (_edgelen + wid);
|
||||||
|
ty -= (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.SOUTHEAST:
|
||||||
|
tx += (_edgelen + wid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.SOUTH:
|
||||||
|
tx += (_edgelen + wid);
|
||||||
|
ty += (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.SOUTHWEST:
|
||||||
|
ty += (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.WEST:
|
||||||
|
tx -= (_edgelen + wid);
|
||||||
|
ty += (_edgelen + hei);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Directions.NORTHWEST:
|
||||||
|
tx -= (_edgelen + wid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
layoutNode(root, tx, ty, e.dst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The length of the edges between nodes in pixels. */
|
||||||
|
protected int _edgelen;
|
||||||
|
|
||||||
|
/** The set of nodes already positioned. */
|
||||||
|
protected HashMap _closed;
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
//
|
||||||
|
// $Id: Directions.java,v 1.1 2001/08/20 22:56:55 shaper Exp $
|
||||||
|
|
||||||
|
package com.threerings.nodemap.direction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides a holding place for constants referenced by the
|
||||||
|
* classes that support and make use of directional node maps.
|
||||||
|
*/
|
||||||
|
public class Directions
|
||||||
|
{
|
||||||
|
/** Constants for the eight cardinal compass-point directions. */
|
||||||
|
public static final int NORTH = 0;
|
||||||
|
public static final int NORTHEAST = 1;
|
||||||
|
public static final int EAST = 2;
|
||||||
|
public static final int SOUTHEAST = 3;
|
||||||
|
public static final int SOUTH = 4;
|
||||||
|
public static final int SOUTHWEST = 5;
|
||||||
|
public static final int WEST = 6;
|
||||||
|
public static final int NORTHWEST = 7;
|
||||||
|
|
||||||
|
/** The number of directions. */
|
||||||
|
public static final int NUM_DIRECTIONS = 8;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user