diff --git a/extras/pom.xml b/extras/pom.xml index 8c4204f..213c43d 100644 --- a/extras/pom.xml +++ b/extras/pom.xml @@ -1,53 +1,53 @@ - 4.0.0 - - piccolo2d-parent - org.piccolo2d - 1.3-SNAPSHOT - ../parent/pom.xml - - piccolo2d-extras - Piccolo2D Extras - http://code.google.com/p/piccolo2d/ - - A revolutionary way to create robust, full-featured graphical - applications in Java and C#, with striking visual effects such - as zooming, animation and multiple representations. - - - - org.piccolo2d - piccolo2d-core - ${project.version} - - - - swt - - swt-win32 - 3.0m8 - compile - - - - - - - maven-javadoc-plugin - - 1.4 - false - package - - - http://java.sun.com/j2se/1.4.2/docs/api/ - - - - + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> +4.0.0 + + piccolo2d-parent + org.piccolo2d + 1.3-SNAPSHOT + ../parent/pom.xml + + piccolo2d-extras + Piccolo2D Extras + http://code.google.com/p/piccolo2d/ + + A revolutionary way to create robust, full-featured graphical + applications in Java and C#, with striking visual effects such + as zooming, animation and multiple representations. + + + + org.piccolo2d + piccolo2d-core + ${project.version} + + + + swt + + swt-win32 + 3.0m8 + compile + + + + + + + maven-javadoc-plugin + + 1.4 + false + package + + + http://java.sun.com/j2se/1.4.2/docs/api/ + + + + maven-checkstyle-plugin @@ -55,6 +55,6 @@ false - - + + diff --git a/extras/src/build/conf/checkstyle.xml b/extras/src/build/conf/checkstyle.xml index 446472a..c4f2ce0 100644 --- a/extras/src/build/conf/checkstyle.xml +++ b/extras/src/build/conf/checkstyle.xml @@ -36,10 +36,6 @@ - - - - @@ -97,7 +93,9 @@ - + + + @@ -128,7 +126,9 @@ - + + + @@ -159,10 +159,6 @@ - - - - diff --git a/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java b/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java index 2233740..7948f58 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/PApplet.java @@ -6,64 +6,65 @@ import edu.umd.cs.piccolo.PCanvas; /** - * PApplet is meant to be subclassed by applications that just need a PCanvas - * embedded in a web page. - * + * PApplet is meant to be subclassed by applications that just need a + * PCanvas embedded in a web page. + * * @version 1.0 * @author Jesse Grosjean */ public class PApplet extends JApplet { - private PCanvas canvas; + private PCanvas canvas; - public void init() { - setBackground(null); + public void init() { + setBackground(null); - canvas = createCanvas(); - getContentPane().add(canvas); - validate(); - canvas.requestFocus(); - beforeInitialize(); - - // Manipulation of Piccolo's scene graph should be done from Swings - // event dispatch thread since Piccolo is not thread safe. This code calls - // initialize() from that thread once the PFrame is initialized, so you are - // safe to start working with Piccolo in the initialize() method. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - PApplet.this.initialize(); - repaint(); - } - }); - } - - public PCanvas getCanvas() { - return canvas; - } - - public PCanvas createCanvas() { - return new PCanvas(); - } - - //**************************************************************** - // Initialize - //**************************************************************** + canvas = createCanvas(); + getContentPane().add(canvas); + validate(); + canvas.requestFocus(); + beforeInitialize(); - /** - * This method will be called before the initialize() method and will be - * called on the thread that is constructing this object. - */ - public void beforeInitialize() { - } + // Manipulation of Piccolo's scene graph should be done from Swings + // event dispatch thread since Piccolo is not thread safe. This code + // calls initialize() from that thread once the PFrame is initialized, + // so you are safe to start working with Piccolo in the initialize() + // method. + SwingUtilities.invokeLater(new Runnable() { + public void run() { + PApplet.this.initialize(); + repaint(); + } + }); + } - /** - * Subclasses should override this method and add their - * Piccolo initialization code there. This method will be called on the - * swing event dispatch thread. Note that the constructors of PFrame - * subclasses may not be complete when this method is called. If you need to - * initailize some things in your class before this method is called place - * that code in beforeInitialize(); - */ - public void initialize() { - } + public PCanvas getCanvas() { + return canvas; + } + + public PCanvas createCanvas() { + return new PCanvas(); + } + + // **************************************************************** + // Initialize + // **************************************************************** + + /** + * This method will be called before the initialize() method and will be + * called on the thread that is constructing this object. + */ + public void beforeInitialize() { + } + + /** + * Subclasses should override this method and add their Piccolo + * initialization code there. This method will be called on the swing event + * dispatch thread. Note that the constructors of PFrame subclasses may not + * be complete when this method is called. If you need to initailize some + * things in your class before this method is called place that code in + * beforeInitialize(); + */ + public void initialize() { + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java b/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java index 77ef011..61f7f15 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/PFrame.java @@ -48,203 +48,210 @@ import edu.umd.cs.piccolo.PCanvas; /** - * PFrame is meant to be subclassed by applications that just need a PCanvas in a JFrame. - * It also includes full screen mode functionality when run in JDK 1.4. These - * subclasses should override the initialize method and start adding their own - * code there. Look in the examples package to see lots of uses of PFrame. - * + * PFrame is meant to be subclassed by applications that just need a + * PCanvas in a JFrame. It also includes full screen mode functionality when run + * in JDK 1.4. These subclasses should override the initialize method and start + * adding their own code there. Look in the examples package to see lots of uses + * of PFrame. + * * @version 1.0 * @author Jesse Grosjean */ public class PFrame extends JFrame { - private PCanvas canvas; - private GraphicsDevice graphicsDevice; - private EventListener escapeFullScreenModeListener; + private PCanvas canvas; + private GraphicsDevice graphicsDevice; + private EventListener escapeFullScreenModeListener; - public PFrame() { - this("", false, null); - } + public PFrame() { + this("", false, null); + } - public PFrame(String title, boolean fullScreenMode, PCanvas aCanvas) { - this(title, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), fullScreenMode, aCanvas); - } + public PFrame(String title, boolean fullScreenMode, PCanvas aCanvas) { + this(title, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(), fullScreenMode, aCanvas); + } - public PFrame(String title, GraphicsDevice aDevice, final boolean fullScreenMode, final PCanvas aCanvas) { - super(title, aDevice.getDefaultConfiguration()); - - graphicsDevice = aDevice; - - setBackground(null); - setBounds(getDefaultFrameBounds()); - - try { - setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } catch (SecurityException e) {} // expected from applets - - if (aCanvas == null) { - canvas = new PCanvas(); - } else { - canvas = aCanvas; - } - - setContentPane(canvas); - validate(); - setFullScreenMode(fullScreenMode); - canvas.requestFocus(); - beforeInitialize(); + public PFrame(String title, GraphicsDevice aDevice, final boolean fullScreenMode, final PCanvas aCanvas) { + super(title, aDevice.getDefaultConfiguration()); - // Manipulation of Piccolo's scene graph should be done from Swings - // event dispatch thread since Piccolo is not thread safe. This code calls - // initialize() from that thread once the PFrame is initialized, so you are - // safe to start working with Piccolo in the initialize() method. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - PFrame.this.initialize(); - repaint(); - } - }); - } + graphicsDevice = aDevice; - public PCanvas getCanvas() { - return canvas; - } - - public Rectangle getDefaultFrameBounds() { - return new Rectangle(100, 100, 400, 400); - } - - //**************************************************************** - // Full Screen Display Mode - //**************************************************************** + setBackground(null); + setBounds(getDefaultFrameBounds()); - public boolean isFullScreenMode() { - return graphicsDevice.getFullScreenWindow() != null; - } - - public void setFullScreenMode(boolean fullScreenMode) { - if (fullScreenMode) { - addEscapeFullScreenModeListener(); - - if (isDisplayable()) { - dispose(); - } - - setUndecorated(true); - setResizable(false); - graphicsDevice.setFullScreenWindow(this); - - if (graphicsDevice.isDisplayChangeSupported()) { - chooseBestDisplayMode(graphicsDevice); - } - validate(); - } else { - removeEscapeFullScreenModeListener(); - - if (isDisplayable()) { - dispose(); - } - - setUndecorated(false); - setResizable(true); - graphicsDevice.setFullScreenWindow(null); - validate(); - setVisible(true); - } - } - - protected void chooseBestDisplayMode(GraphicsDevice device) { - DisplayMode best = getBestDisplayMode(device); - if (best != null) { - device.setDisplayMode(best); - } - } - - protected DisplayMode getBestDisplayMode(GraphicsDevice device) { - Iterator itr = getPreferredDisplayModes(device).iterator(); - while (itr.hasNext()) { - DisplayMode each = (DisplayMode) itr.next(); - DisplayMode[] modes = device.getDisplayModes(); - for (int i = 0; i < modes.length; i++) { - if (modes[i].getWidth() == each.getWidth() && - modes[i].getHeight() == each.getHeight() && - modes[i].getBitDepth() == each.getBitDepth()) { - return each; - } - } - } - - return null; - } - - /** - * By default return the current display mode. Subclasses may override this method - * to return other modes in the collection. - */ - protected Collection getPreferredDisplayModes(GraphicsDevice device) { - ArrayList result = new ArrayList(); - - result.add(device.getDisplayMode()); - /*result.add(new DisplayMode(640, 480, 32, 0)); - result.add(new DisplayMode(640, 480, 16, 0)); - result.add(new DisplayMode(640, 480, 8, 0));*/ - - return result; - } + try { + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + } + catch (SecurityException e) { + } // expected from applets - /** - * This method adds a key listener that will take this PFrame out of full - * screen mode when the escape key is pressed. This is called for you - * automatically when the frame enters full screen mode. - */ - public void addEscapeFullScreenModeListener() { - removeEscapeFullScreenModeListener(); - escapeFullScreenModeListener = new KeyAdapter() { - public void keyPressed(KeyEvent aEvent) { - if (aEvent.getKeyCode() == KeyEvent.VK_ESCAPE) { - setFullScreenMode(false); - } - } - }; - canvas.addKeyListener((KeyListener)escapeFullScreenModeListener); - } - - /** - * This method removes the escape full screen mode key listener. It will be - * called for you automatically when full screen mode exits, but the method - * has been made public for applications that wish to use other methods for - * exiting full screen mode. - */ - public void removeEscapeFullScreenModeListener() { - if (escapeFullScreenModeListener != null) { - canvas.removeKeyListener((KeyListener)escapeFullScreenModeListener); - escapeFullScreenModeListener = null; - } - } - - //**************************************************************** - // Initialize - //**************************************************************** + if (aCanvas == null) { + canvas = new PCanvas(); + } + else { + canvas = aCanvas; + } - /** - * This method will be called before the initialize() method and will be - * called on the thread that is constructing this object. - */ - public void beforeInitialize() { - } + setContentPane(canvas); + validate(); + setFullScreenMode(fullScreenMode); + canvas.requestFocus(); + beforeInitialize(); - /** - * Subclasses should override this method and add their - * Piccolo initialization code there. This method will be called on the - * swing event dispatch thread. Note that the constructors of PFrame - * subclasses may not be complete when this method is called. If you need to - * initailize some things in your class before this method is called place - * that code in beforeInitialize(); - */ - public void initialize() { - } + // Manipulation of Piccolo's scene graph should be done from Swings + // event dispatch thread since Piccolo is not thread safe. This code + // calls initialize() from that thread once the PFrame is initialized, + // so you are safe to start working with Piccolo in the initialize() + // method. + SwingUtilities.invokeLater(new Runnable() { + public void run() { + PFrame.this.initialize(); + repaint(); + } + }); + } - public static void main(String[] argv) { - new PFrame(); - } + public PCanvas getCanvas() { + return canvas; + } + + public Rectangle getDefaultFrameBounds() { + return new Rectangle(100, 100, 400, 400); + } + + // **************************************************************** + // Full Screen Display Mode + // **************************************************************** + + public boolean isFullScreenMode() { + return graphicsDevice.getFullScreenWindow() != null; + } + + public void setFullScreenMode(boolean fullScreenMode) { + if (fullScreenMode) { + addEscapeFullScreenModeListener(); + + if (isDisplayable()) { + dispose(); + } + + setUndecorated(true); + setResizable(false); + graphicsDevice.setFullScreenWindow(this); + + if (graphicsDevice.isDisplayChangeSupported()) { + chooseBestDisplayMode(graphicsDevice); + } + validate(); + } + else { + removeEscapeFullScreenModeListener(); + + if (isDisplayable()) { + dispose(); + } + + setUndecorated(false); + setResizable(true); + graphicsDevice.setFullScreenWindow(null); + validate(); + setVisible(true); + } + } + + protected void chooseBestDisplayMode(GraphicsDevice device) { + DisplayMode best = getBestDisplayMode(device); + if (best != null) { + device.setDisplayMode(best); + } + } + + protected DisplayMode getBestDisplayMode(GraphicsDevice device) { + Iterator itr = getPreferredDisplayModes(device).iterator(); + while (itr.hasNext()) { + DisplayMode each = (DisplayMode) itr.next(); + DisplayMode[] modes = device.getDisplayModes(); + for (int i = 0; i < modes.length; i++) { + if (modes[i].getWidth() == each.getWidth() && modes[i].getHeight() == each.getHeight() + && modes[i].getBitDepth() == each.getBitDepth()) { + return each; + } + } + } + + return null; + } + + /** + * By default return the current display mode. Subclasses may override this + * method to return other modes in the collection. + */ + protected Collection getPreferredDisplayModes(GraphicsDevice device) { + ArrayList result = new ArrayList(); + + result.add(device.getDisplayMode()); + /* + * result.add(new DisplayMode(640, 480, 32, 0)); result.add(new + * DisplayMode(640, 480, 16, 0)); result.add(new DisplayMode(640, 480, + * 8, 0)); + */ + + return result; + } + + /** + * This method adds a key listener that will take this PFrame out of full + * screen mode when the escape key is pressed. This is called for you + * automatically when the frame enters full screen mode. + */ + public void addEscapeFullScreenModeListener() { + removeEscapeFullScreenModeListener(); + escapeFullScreenModeListener = new KeyAdapter() { + public void keyPressed(KeyEvent aEvent) { + if (aEvent.getKeyCode() == KeyEvent.VK_ESCAPE) { + setFullScreenMode(false); + } + } + }; + canvas.addKeyListener((KeyListener) escapeFullScreenModeListener); + } + + /** + * This method removes the escape full screen mode key listener. It will be + * called for you automatically when full screen mode exits, but the method + * has been made public for applications that wish to use other methods for + * exiting full screen mode. + */ + public void removeEscapeFullScreenModeListener() { + if (escapeFullScreenModeListener != null) { + canvas.removeKeyListener((KeyListener) escapeFullScreenModeListener); + escapeFullScreenModeListener = null; + } + } + + // **************************************************************** + // Initialize + // **************************************************************** + + /** + * This method will be called before the initialize() method and will be + * called on the thread that is constructing this object. + */ + public void beforeInitialize() { + } + + /** + * Subclasses should override this method and add their Piccolo + * initialization code there. This method will be called on the swing event + * dispatch thread. Note that the constructors of PFrame subclasses may not + * be complete when this method is called. If you need to initailize some + * things in your class before this method is called place that code in + * beforeInitialize(); + */ + public void initialize() { + } + + public static void main(String[] argv) { + new PFrame(); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java b/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java index e38a6df..6608814 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/activities/PPathActivity.java @@ -32,78 +32,82 @@ import edu.umd.cs.piccolo.activities.PInterpolatingActivity; /** - * PPathActivity is the abstract base class for all path - * activity interpolators. Path activities interpolate between multiple states - * over the duration of the activity. + * PPathActivity is the abstract base class for all path activity + * interpolators. Path activities interpolate between multiple states over the + * duration of the activity. *

* Knots are used to determine when in time the activity should move from state * to state. Knot values should be increasing in value from 0 to 1 inclusive. * This class is based on the Java 3D PathInterpolator object, see that class * documentation for more information on the basic concepts used in this classes * design. + *

*

* See PPositionPathActivity for a concrete path activity that will animate * through a list of points. - *

- * @version 1.0 + *

+ * + * @version 1.0 * @author Jesse Grosjean */ public abstract class PPathActivity extends PInterpolatingActivity { - - protected float[] knots; - public PPathActivity(long duration, long stepRate, float[] knots) { - this(duration, stepRate, 0, PInterpolatingActivity.SOURCE_TO_DESTINATION, knots); - } - - public PPathActivity(long duration, long stepRate, int loopCount, int mode, float[] knots) { - super(duration, stepRate, loopCount, mode); - setKnots(knots); - } - - public int getKnotsLength() { - return knots.length; - } - - public void setKnots(float[] knots) { - this.knots = knots; - } - - public float[] getKnots() { - return knots; - } + protected float[] knots; - public void setKnot(int index, float knot) { - knots[index] = knot; - } - - public float getKnot(int index) { - return knots[index]; - } - - public void setRelativeTargetValue(float zeroToOne) { - int currentKnotIndex = 0; - - while (zeroToOne > knots[currentKnotIndex]) { - currentKnotIndex++; - } + public PPathActivity(long duration, long stepRate, float[] knots) { + this(duration, stepRate, 0, PInterpolatingActivity.SOURCE_TO_DESTINATION, knots); + } - int startKnot = currentKnotIndex - 1; - int endKnot = currentKnotIndex; - - if (startKnot < 0) startKnot = 0; - if (endKnot > getKnotsLength() - 1) endKnot = getKnotsLength() - 1; - - float currentRange = knots[endKnot] - knots[startKnot]; - float currentPointOnRange = zeroToOne - knots[startKnot]; - float normalizedPointOnRange = currentPointOnRange; - - if (currentRange != 0) { - normalizedPointOnRange = currentPointOnRange / currentRange; - } - - setRelativeTargetValue(normalizedPointOnRange, startKnot, endKnot); - } - - public abstract void setRelativeTargetValue(float zeroToOne, int startKnot, int endKnot); + public PPathActivity(long duration, long stepRate, int loopCount, int mode, float[] knots) { + super(duration, stepRate, loopCount, mode); + setKnots(knots); + } + + public int getKnotsLength() { + return knots.length; + } + + public void setKnots(float[] knots) { + this.knots = knots; + } + + public float[] getKnots() { + return knots; + } + + public void setKnot(int index, float knot) { + knots[index] = knot; + } + + public float getKnot(int index) { + return knots[index]; + } + + public void setRelativeTargetValue(float zeroToOne) { + int currentKnotIndex = 0; + + while (zeroToOne > knots[currentKnotIndex]) { + currentKnotIndex++; + } + + int startKnot = currentKnotIndex - 1; + int endKnot = currentKnotIndex; + + if (startKnot < 0) + startKnot = 0; + if (endKnot > getKnotsLength() - 1) + endKnot = getKnotsLength() - 1; + + float currentRange = knots[endKnot] - knots[startKnot]; + float currentPointOnRange = zeroToOne - knots[startKnot]; + float normalizedPointOnRange = currentPointOnRange; + + if (currentRange != 0) { + normalizedPointOnRange = currentPointOnRange / currentRange; + } + + setRelativeTargetValue(normalizedPointOnRange, startKnot, endKnot); + } + + public abstract void setRelativeTargetValue(float zeroToOne, int startKnot, int endKnot); } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java b/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java index f476913..bc63b24 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/activities/PPositionPathActivity.java @@ -38,113 +38,114 @@ /** * PPositionPathActivity animates through a sequence of points. - *

- * @version 1.0 + * + * @version 1.0 * @author Jesse Grosjean */ public class PPositionPathActivity extends PPathActivity { - protected Point2D[] positions; - protected Target target; + protected Point2D[] positions; + protected Target target; - public interface Target { - public void setPosition(double x, double y); - } + public interface Target { + public void setPosition(double x, double y); + } - public PPositionPathActivity(long duration, long stepRate, Target aTarget) { - this(duration, stepRate, aTarget, null, null); - } + public PPositionPathActivity(long duration, long stepRate, Target aTarget) { + this(duration, stepRate, aTarget, null, null); + } - public PPositionPathActivity(long duration, long stepRate, Target aTarget, float[] knots, Point2D[] positions) { - this(duration, stepRate, 1, PInterpolatingActivity.SOURCE_TO_DESTINATION, aTarget, knots, positions); - } + public PPositionPathActivity(long duration, long stepRate, Target aTarget, float[] knots, Point2D[] positions) { + this(duration, stepRate, 1, PInterpolatingActivity.SOURCE_TO_DESTINATION, aTarget, knots, positions); + } - public PPositionPathActivity(long duration, long stepRate, int loopCount, int mode, Target aTarget, float[] knots, Point2D[] positions) { - super(duration, stepRate, loopCount, mode, knots); - target = aTarget; - this.positions = positions; - } + public PPositionPathActivity(long duration, long stepRate, int loopCount, int mode, Target aTarget, float[] knots, + Point2D[] positions) { + super(duration, stepRate, loopCount, mode, knots); + target = aTarget; + this.positions = positions; + } - protected boolean isAnimation() { - return true; - } + protected boolean isAnimation() { + return true; + } - public Point2D[] getPositions() { - return positions; - } + public Point2D[] getPositions() { + return positions; + } - public Point2D getPosition(int index) { - return positions[index]; - } + public Point2D getPosition(int index) { + return positions[index]; + } - public void setPositions(Point2D[] positions) { - this.positions = positions; - } + public void setPositions(Point2D[] positions) { + this.positions = positions; + } - public void setPosition(int index, Point2D position) { - positions[index] = position; - } + public void setPosition(int index, Point2D position) { + positions[index] = position; + } - public void setPositions(GeneralPath path) { - PathIterator pi = path.getPathIterator(null, 1); - ArrayList points = new ArrayList(); - float point[] = new float[6]; - float distanceSum = 0; - float lastMoveToX = 0; - float lastMoveToY = 0; - - while (!pi.isDone()) { - int type = pi.currentSegment(point); - - switch (type) { - case PathIterator.SEG_MOVETO: - points.add(new Point2D.Float(point[0], point[1])); - lastMoveToX = point[0]; - lastMoveToY = point[1]; - break; + public void setPositions(GeneralPath path) { + PathIterator pi = path.getPathIterator(null, 1); + ArrayList points = new ArrayList(); + float point[] = new float[6]; + float distanceSum = 0; + float lastMoveToX = 0; + float lastMoveToY = 0; - case PathIterator.SEG_LINETO: - points.add(new Point2D.Float(point[0], point[1])); - break; + while (!pi.isDone()) { + int type = pi.currentSegment(point); - case PathIterator.SEG_CLOSE: - points.add(new Point2D.Float(lastMoveToX, lastMoveToY)); - break; - - case PathIterator.SEG_QUADTO: - case PathIterator.SEG_CUBICTO: - throw new RuntimeException(); - } - - if (points.size() > 1) { - Point2D last = (Point2D) points.get(points.size() - 2); - Point2D current = (Point2D) points.get(points.size() - 1); - distanceSum += last.distance(current); - } - - pi.next(); - } - - int size = points.size(); - Point2D newPositions[] = new Point2D[size]; - float newKnots[] = new float[size]; - - for (int i = 0; i < size; i++) { - newPositions[i] = (Point2D) points.get(i); - if (i > 0) { - float dist = (float) newPositions[i - 1].distance(newPositions[i]); - newKnots[i] = newKnots[i - 1] + (dist / distanceSum); - } - } - - setPositions(newPositions); - setKnots(newKnots); - } - - public void setRelativeTargetValue(float zeroToOne, int startKnot, int endKnot) { - Point2D start = getPosition(startKnot); - Point2D end = getPosition(endKnot); - target.setPosition(start.getX() + (zeroToOne * (end.getX() - start.getX())), - start.getY() + (zeroToOne * (end.getY() - start.getY()))); - } + switch (type) { + case PathIterator.SEG_MOVETO: + points.add(new Point2D.Float(point[0], point[1])); + lastMoveToX = point[0]; + lastMoveToY = point[1]; + break; + + case PathIterator.SEG_LINETO: + points.add(new Point2D.Float(point[0], point[1])); + break; + + case PathIterator.SEG_CLOSE: + points.add(new Point2D.Float(lastMoveToX, lastMoveToY)); + break; + + case PathIterator.SEG_QUADTO: + case PathIterator.SEG_CUBICTO: + throw new RuntimeException(); + } + + if (points.size() > 1) { + Point2D last = (Point2D) points.get(points.size() - 2); + Point2D current = (Point2D) points.get(points.size() - 1); + distanceSum += last.distance(current); + } + + pi.next(); + } + + int size = points.size(); + Point2D newPositions[] = new Point2D[size]; + float newKnots[] = new float[size]; + + for (int i = 0; i < size; i++) { + newPositions[i] = (Point2D) points.get(i); + if (i > 0) { + float dist = (float) newPositions[i - 1].distance(newPositions[i]); + newKnots[i] = newKnots[i - 1] + (dist / distanceSum); + } + } + + setPositions(newPositions); + setKnots(newKnots); + } + + public void setRelativeTargetValue(float zeroToOne, int startKnot, int endKnot) { + Point2D start = getPosition(startKnot); + Point2D end = getPosition(endKnot); + target.setPosition(start.getX() + (zeroToOne * (end.getX() - start.getX())), start.getY() + + (zeroToOne * (end.getY() - start.getY()))); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java index 38ed096..fa21ba0 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PNavigationEventHandler.java @@ -51,367 +51,376 @@ import edu.umd.cs.piccolo.util.PDimension; /** - * PNavigationEventHandler implements simple focus based navigation. Uses + * PNavigationEventHandler implements simple focus based navigation. Uses * mouse button one or the arrow keys to set a new focus. Animates the canvas - * view to keep the focus node on the screen and at 100 percent scale with minimal - * view movement. - *

+ * view to keep the focus node on the screen and at 100 percent scale with + * minimal view movement. + * * @version 1.0 * @author Jesse Grosjean */ public class PNavigationEventHandler extends PBasicInputEventHandler { - public static final int NORTH = 0; - public static final int SOUTH = 1; - public static final int EAST = 2; - public static final int WEST = 3; - public static final int IN = 4; - public static final int OUT = 5; - - private static Hashtable NODE_TO_GLOBAL_NODE_CENTER_MAPPING = new Hashtable(); - - private PNode focusNode; - private PActivity navigationActivity; - - public PNavigationEventHandler() { - super(); - setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); - } + public static final int NORTH = 0; + public static final int SOUTH = 1; + public static final int EAST = 2; + public static final int WEST = 3; + public static final int IN = 4; + public static final int OUT = 5; - //**************************************************************** - // Focus Change Events. - //**************************************************************** - - public void keyPressed(PInputEvent e) { - PNode oldLocation = focusNode; - - switch (e.getKeyCode()) { - case KeyEvent.VK_LEFT: - moveFocusLeft(e); - break; + private static Hashtable NODE_TO_GLOBAL_NODE_CENTER_MAPPING = new Hashtable(); - case KeyEvent.VK_RIGHT: - moveFocusRight(e); - break; + private PNode focusNode; + private PActivity navigationActivity; - case KeyEvent.VK_UP: - case KeyEvent.VK_PAGE_UP: - if (e.isAltDown()) { - moveFocusOut(e); - } else { - moveFocusUp(e); - } - break; + public PNavigationEventHandler() { + super(); + setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + } - case KeyEvent.VK_DOWN: - case KeyEvent.VK_PAGE_DOWN: - if (e.isAltDown()) { - moveFocusIn(e); - } else { - moveFocusDown(e); - } - break; - } + // **************************************************************** + // Focus Change Events. + // **************************************************************** - if (focusNode != null && oldLocation != focusNode) { - directCameraViewToFocus(e.getCamera(), focusNode, 500); - } - } - - public void mousePressed(PInputEvent aEvent) { - moveFocusToMouseOver(aEvent); - - if (focusNode != null) { - directCameraViewToFocus(aEvent.getCamera(), focusNode, 500); - aEvent.getInputManager().setKeyboardFocus(aEvent.getPath()); - } - } - - //**************************************************************** - // Focus Movement - Moves the focus the specified direction. Left, - // right, up, down mean move the focus to the closest sibling of the - // current focus node that exists in that direction. Move in means - // move the focus to a child of the current focus, move out means - // move the focus to the parent of the current focus. - //**************************************************************** - - public void moveFocusDown(PInputEvent e) { - PNode n = getNeighborInDirection(SOUTH); + public void keyPressed(PInputEvent e) { + PNode oldLocation = focusNode; - if (n != null) { - focusNode = n; - } - } - - public void moveFocusIn(PInputEvent e) { - PNode n = getNeighborInDirection(IN); + switch (e.getKeyCode()) { + case KeyEvent.VK_LEFT: + moveFocusLeft(e); + break; - if (n != null) { - focusNode = n; - } - } - - public void moveFocusLeft(PInputEvent e) { - PNode n = getNeighborInDirection(WEST); + case KeyEvent.VK_RIGHT: + moveFocusRight(e); + break; - if (n != null) { - focusNode = n; - } - } - - public void moveFocusOut(PInputEvent e) { - PNode n = getNeighborInDirection(OUT); + case KeyEvent.VK_UP: + case KeyEvent.VK_PAGE_UP: + if (e.isAltDown()) { + moveFocusOut(e); + } + else { + moveFocusUp(e); + } + break; - if (n != null) { - focusNode = n; - } - } - - public void moveFocusRight(PInputEvent e) { - PNode n = getNeighborInDirection(EAST); + case KeyEvent.VK_DOWN: + case KeyEvent.VK_PAGE_DOWN: + if (e.isAltDown()) { + moveFocusIn(e); + } + else { + moveFocusDown(e); + } + break; + } - if (n != null) { - focusNode = n; - } - } - - public void moveFocusUp(PInputEvent e) { - PNode n = getNeighborInDirection(NORTH); + if (focusNode != null && oldLocation != focusNode) { + directCameraViewToFocus(e.getCamera(), focusNode, 500); + } + } - if (n != null) { - focusNode = n; - } - } + public void mousePressed(PInputEvent aEvent) { + moveFocusToMouseOver(aEvent); - public void moveFocusToMouseOver(PInputEvent e) { - PNode focus = e.getPickedNode(); - if (!(focus instanceof PCamera)) { - focusNode = focus; - } - } - - public PNode getNeighborInDirection(int aDirection) { - if (focusNode == null) return null; + if (focusNode != null) { + directCameraViewToFocus(aEvent.getCamera(), focusNode, 500); + aEvent.getInputManager().setKeyboardFocus(aEvent.getPath()); + } + } - NODE_TO_GLOBAL_NODE_CENTER_MAPPING.clear(); + // **************************************************************** + // Focus Movement - Moves the focus the specified direction. Left, + // right, up, down mean move the focus to the closest sibling of the + // current focus node that exists in that direction. Move in means + // move the focus to a child of the current focus, move out means + // move the focus to the parent of the current focus. + // **************************************************************** - Point2D highlightCenter = focusNode.getGlobalFullBounds().getCenter2D(); - NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(focusNode, highlightCenter); + public void moveFocusDown(PInputEvent e) { + PNode n = getNeighborInDirection(SOUTH); - List l = getNeighbors(); - sortNodesByDistanceFromPoint(l, highlightCenter); + if (n != null) { + focusNode = n; + } + } - Iterator i = l.iterator(); - while (i.hasNext()) { - PNode each = (PNode) i.next(); - if (nodeIsNeighborInDirection(each, aDirection)) { - return each; - } - } + public void moveFocusIn(PInputEvent e) { + PNode n = getNeighborInDirection(IN); - return null; - } - - public List getNeighbors() { - ArrayList result = new ArrayList(); - - if (focusNode == null) return result; - if (focusNode.getParent() == null) return result; + if (n != null) { + focusNode = n; + } + } - PNode focusParent = focusNode.getParent(); + public void moveFocusLeft(PInputEvent e) { + PNode n = getNeighborInDirection(WEST); - Iterator i = focusParent.getChildrenIterator(); + if (n != null) { + focusNode = n; + } + } - while (i.hasNext()) { - PNode each = (PNode) i.next(); - if (each != focusNode && each.getPickable()) { - result.add(each); - } - } + public void moveFocusOut(PInputEvent e) { + PNode n = getNeighborInDirection(OUT); - result.add(focusParent); + if (n != null) { + focusNode = n; + } + } - i = focusNode.getChildrenIterator(); - while (i.hasNext()) { - result.add(i.next()); - } + public void moveFocusRight(PInputEvent e) { + PNode n = getNeighborInDirection(EAST); - return result; - } + if (n != null) { + focusNode = n; + } + } - public boolean nodeIsNeighborInDirection(PNode aNode, int aDirection) { - switch (aDirection) { - case IN: { - return aNode.isDescendentOf(focusNode); - } + public void moveFocusUp(PInputEvent e) { + PNode n = getNeighborInDirection(NORTH); - case OUT: { - return aNode.isAncestorOf(focusNode); - } - - default: { - if (aNode.isAncestorOf(focusNode) || aNode.isDescendentOf(focusNode)) { - return false; - } - } - } + if (n != null) { + focusNode = n; + } + } - Point2D highlightCenter = (Point2D) NODE_TO_GLOBAL_NODE_CENTER_MAPPING.get(focusNode); - Point2D nodeCenter = (Point2D) NODE_TO_GLOBAL_NODE_CENTER_MAPPING.get(aNode); + public void moveFocusToMouseOver(PInputEvent e) { + PNode focus = e.getPickedNode(); + if (!(focus instanceof PCamera)) { + focusNode = focus; + } + } - double ytest1 = nodeCenter.getX() - highlightCenter.getX() + highlightCenter.getY(); - double ytest2 = -nodeCenter.getX() + highlightCenter.getX() + highlightCenter.getY(); + public PNode getNeighborInDirection(int aDirection) { + if (focusNode == null) + return null; - switch (aDirection) { - case NORTH: { - if (nodeCenter.getY() < highlightCenter.getY()) { - if (nodeCenter.getY() < ytest1 && nodeCenter.getY() < ytest2) { - return true; - } - } - break; - } + NODE_TO_GLOBAL_NODE_CENTER_MAPPING.clear(); - case EAST: { - if (nodeCenter.getX() > highlightCenter.getX()) { - if (nodeCenter.getY() < ytest1 && nodeCenter.getY() > ytest2) { - return true; - } - } - break; - } + Point2D highlightCenter = focusNode.getGlobalFullBounds().getCenter2D(); + NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(focusNode, highlightCenter); - case SOUTH: { - if (nodeCenter.getY() > highlightCenter.getY()) { - if (nodeCenter.getY() > ytest1 && nodeCenter.getY() > ytest2) { - return true; - } - } - break; - } - case WEST: { - if (nodeCenter.getX() < highlightCenter.getX()) { - if (nodeCenter.getY() > ytest1 && nodeCenter.getY() < ytest2) { - return true; - } - } - break; - } - } - return false; - } - - public void sortNodesByDistanceFromPoint(List aNodesList, final Point2D aPoint) { - Collections.sort(aNodesList, new Comparator() { - public int compare(Object o1, Object o2) { - PNode each1 = (PNode) o1; - PNode each2 = (PNode) o2; - Point2D each1Center = each1.getGlobalFullBounds().getCenter2D(); - Point2D each2Center = each2.getGlobalFullBounds().getCenter2D(); + List l = getNeighbors(); + sortNodesByDistanceFromPoint(l, highlightCenter); - NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(each1, each1Center); - NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(each2, each2Center); + Iterator i = l.iterator(); + while (i.hasNext()) { + PNode each = (PNode) i.next(); + if (nodeIsNeighborInDirection(each, aDirection)) { + return each; + } + } - double distance1 = aPoint.distance(each1Center); - double distance2 = aPoint.distance(each2Center); + return null; + } - if (distance1 < distance2) { - return -1; - } else if (distance1 == distance2) { - return 0; - } else { - return 1; - } - } - }); - } - - //**************************************************************** - // Canvas Movement - The canvas view is updated so that the current - // focus remains visible on the screen at 100 percent scale. - //**************************************************************** + public List getNeighbors() { + ArrayList result = new ArrayList(); - protected PActivity animateCameraViewTransformTo(final PCamera aCamera, AffineTransform aTransform, int duration) { - boolean wasOldAnimation = false; - - // first stop any old animations. - if (navigationActivity != null) { - navigationActivity.terminate(); - wasOldAnimation = true; - } - - if (duration == 0) { - aCamera.setViewTransform(aTransform); - return null; - } + if (focusNode == null) + return result; + if (focusNode.getParent() == null) + return result; - AffineTransform source = aCamera.getViewTransformReference(); + PNode focusParent = focusNode.getParent(); - if (!source.equals(aTransform)) { - navigationActivity = aCamera.animateViewToTransform(aTransform, duration); - ((PTransformActivity)navigationActivity).setSlowInSlowOut(!wasOldAnimation); - return navigationActivity; - } - - return null; - } + Iterator i = focusParent.getChildrenIterator(); - public PActivity directCameraViewToFocus(PCamera aCamera, PNode aFocusNode, int duration) { - focusNode = aFocusNode; - AffineTransform originalViewTransform = aCamera.getViewTransform(); + while (i.hasNext()) { + PNode each = (PNode) i.next(); + if (each != focusNode && each.getPickable()) { + result.add(each); + } + } - // Scale the canvas to include - PDimension d = new PDimension(1, 0); - focusNode.globalToLocal(d); - - double scaleFactor = d.getWidth() / aCamera.getViewScale(); - Point2D scalePoint = focusNode.getGlobalFullBounds().getCenter2D(); - if (scaleFactor != 1) { - aCamera.scaleViewAboutPoint(scaleFactor, scalePoint.getX(), scalePoint.getY()); - } - - // Pan the canvas to include the view bounds with minimal canvas - // movement. - aCamera.animateViewToPanToBounds(focusNode.getGlobalFullBounds(), 0); + result.add(focusParent); - // Get rid of any white space. The canvas may be panned and - // zoomed in to do this. But make sure not stay constrained by max - // magnification. - //fillViewWhiteSpace(aCamera); + i = focusNode.getChildrenIterator(); + while (i.hasNext()) { + result.add(i.next()); + } - AffineTransform resultingTransform = aCamera.getViewTransform(); - aCamera.setViewTransform(originalViewTransform); + return result; + } - // Animate the canvas so that it ends up with the given - // view transform. - return animateCameraViewTransformTo(aCamera, resultingTransform, duration); - } + public boolean nodeIsNeighborInDirection(PNode aNode, int aDirection) { + switch (aDirection) { + case IN: { + return aNode.isDescendentOf(focusNode); + } - protected void fillViewWhiteSpace(PCamera aCamera) { - PBounds rootBounds = aCamera.getRoot().getFullBoundsReference(); - PBounds viewBounds = aCamera.getViewBounds(); + case OUT: { + return aNode.isAncestorOf(focusNode); + } - if (!rootBounds.contains(aCamera.getViewBounds())) { - aCamera.animateViewToPanToBounds(rootBounds, 0); - aCamera.animateViewToPanToBounds(focusNode.getGlobalFullBounds(), 0); + default: { + if (aNode.isAncestorOf(focusNode) || aNode.isDescendentOf(focusNode)) { + return false; + } + } + } - // center content. - double dx = 0; - double dy = 0; - viewBounds = aCamera.getViewBounds(); + Point2D highlightCenter = (Point2D) NODE_TO_GLOBAL_NODE_CENTER_MAPPING.get(focusNode); + Point2D nodeCenter = (Point2D) NODE_TO_GLOBAL_NODE_CENTER_MAPPING.get(aNode); - if (viewBounds.getWidth() > rootBounds.getWidth()) { // then center along x axis. - double boundsCenterX = rootBounds.getMinX() + (rootBounds.getWidth() / 2); - double viewBoundsCenterX = viewBounds.getMinX() + (viewBounds.getWidth() / 2); - dx = viewBoundsCenterX - boundsCenterX; - } + double ytest1 = nodeCenter.getX() - highlightCenter.getX() + highlightCenter.getY(); + double ytest2 = -nodeCenter.getX() + highlightCenter.getX() + highlightCenter.getY(); - if (viewBounds.getHeight() > rootBounds.getHeight()) { // then center along y axis. - double boundsCenterY = rootBounds.getMinY() + (rootBounds.getHeight() / 2); - double viewBoundsCenterY = viewBounds.getMinY() + (viewBounds.getHeight() / 2); - dy = viewBoundsCenterY - boundsCenterY; - } - aCamera.translateView(dx, dy); - } - } + switch (aDirection) { + case NORTH: { + if (nodeCenter.getY() < highlightCenter.getY()) { + if (nodeCenter.getY() < ytest1 && nodeCenter.getY() < ytest2) { + return true; + } + } + break; + } + + case EAST: { + if (nodeCenter.getX() > highlightCenter.getX()) { + if (nodeCenter.getY() < ytest1 && nodeCenter.getY() > ytest2) { + return true; + } + } + break; + } + + case SOUTH: { + if (nodeCenter.getY() > highlightCenter.getY()) { + if (nodeCenter.getY() > ytest1 && nodeCenter.getY() > ytest2) { + return true; + } + } + break; + } + case WEST: { + if (nodeCenter.getX() < highlightCenter.getX()) { + if (nodeCenter.getY() > ytest1 && nodeCenter.getY() < ytest2) { + return true; + } + } + break; + } + } + return false; + } + + public void sortNodesByDistanceFromPoint(List aNodesList, final Point2D aPoint) { + Collections.sort(aNodesList, new Comparator() { + public int compare(Object o1, Object o2) { + PNode each1 = (PNode) o1; + PNode each2 = (PNode) o2; + Point2D each1Center = each1.getGlobalFullBounds().getCenter2D(); + Point2D each2Center = each2.getGlobalFullBounds().getCenter2D(); + + NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(each1, each1Center); + NODE_TO_GLOBAL_NODE_CENTER_MAPPING.put(each2, each2Center); + + double distance1 = aPoint.distance(each1Center); + double distance2 = aPoint.distance(each2Center); + + if (distance1 < distance2) { + return -1; + } + else if (distance1 == distance2) { + return 0; + } + else { + return 1; + } + } + }); + } + + // **************************************************************** + // Canvas Movement - The canvas view is updated so that the current + // focus remains visible on the screen at 100 percent scale. + // **************************************************************** + + protected PActivity animateCameraViewTransformTo(final PCamera aCamera, AffineTransform aTransform, int duration) { + boolean wasOldAnimation = false; + + // first stop any old animations. + if (navigationActivity != null) { + navigationActivity.terminate(); + wasOldAnimation = true; + } + + if (duration == 0) { + aCamera.setViewTransform(aTransform); + return null; + } + + AffineTransform source = aCamera.getViewTransformReference(); + + if (!source.equals(aTransform)) { + navigationActivity = aCamera.animateViewToTransform(aTransform, duration); + ((PTransformActivity) navigationActivity).setSlowInSlowOut(!wasOldAnimation); + return navigationActivity; + } + + return null; + } + + public PActivity directCameraViewToFocus(PCamera aCamera, PNode aFocusNode, int duration) { + focusNode = aFocusNode; + AffineTransform originalViewTransform = aCamera.getViewTransform(); + + // Scale the canvas to include + PDimension d = new PDimension(1, 0); + focusNode.globalToLocal(d); + + double scaleFactor = d.getWidth() / aCamera.getViewScale(); + Point2D scalePoint = focusNode.getGlobalFullBounds().getCenter2D(); + if (scaleFactor != 1) { + aCamera.scaleViewAboutPoint(scaleFactor, scalePoint.getX(), scalePoint.getY()); + } + + // Pan the canvas to include the view bounds with minimal canvas + // movement. + aCamera.animateViewToPanToBounds(focusNode.getGlobalFullBounds(), 0); + + // Get rid of any white space. The canvas may be panned and + // zoomed in to do this. But make sure not stay constrained by max + // magnification. + // fillViewWhiteSpace(aCamera); + + AffineTransform resultingTransform = aCamera.getViewTransform(); + aCamera.setViewTransform(originalViewTransform); + + // Animate the canvas so that it ends up with the given + // view transform. + return animateCameraViewTransformTo(aCamera, resultingTransform, duration); + } + + protected void fillViewWhiteSpace(PCamera aCamera) { + PBounds rootBounds = aCamera.getRoot().getFullBoundsReference(); + PBounds viewBounds = aCamera.getViewBounds(); + + if (!rootBounds.contains(aCamera.getViewBounds())) { + aCamera.animateViewToPanToBounds(rootBounds, 0); + aCamera.animateViewToPanToBounds(focusNode.getGlobalFullBounds(), 0); + + // center content. + double dx = 0; + double dy = 0; + viewBounds = aCamera.getViewBounds(); + + if (viewBounds.getWidth() > rootBounds.getWidth()) { + // then center along x axis. + double boundsCenterX = rootBounds.getMinX() + (rootBounds.getWidth() / 2); + double viewBoundsCenterX = viewBounds.getMinX() + (viewBounds.getWidth() / 2); + dx = viewBoundsCenterX - boundsCenterX; + } + + if (viewBounds.getHeight() > rootBounds.getHeight()) { + // then center along y axis. + double boundsCenterY = rootBounds.getMinY() + (rootBounds.getHeight() / 2); + double viewBoundsCenterY = viewBounds.getMinY() + (viewBounds.getHeight() / 2); + dy = viewBoundsCenterY - boundsCenterY; + } + aCamera.translateView(dx, dy); + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PNotification.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PNotification.java index 0fa8e4e..1f3acff 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PNotification.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PNotification.java @@ -39,54 +39,55 @@ /** * PNotification objects encapsulate information so that it can be - * broadcast to other objects by a PNotificationCenter. A PNotification contains a - * name, an object, and an optional properties map. The name is a tag + * broadcast to other objects by a PNotificationCenter. A PNotification contains + * a name, an object, and an optional properties map. The name is a tag * identifying the notification. The object is any object that the poster of the * notification wants to send to observers of that notification (typically, it * is the object that posted the notification). The properties map stores other * related objects, if any. - *

+ *

* You don't usually create your own notifications directly. The - * PNotificationCenter method postNotification() allow you to conveniently post a - * notification without creating it first. - *

+ * PNotificationCenter method postNotification() allow you to conveniently post + * a notification without creating it first. + *

+ * * @author Jesse Grosjean */ public class PNotification { - - protected String name; - protected Object source; - protected Map properties; - public PNotification(String name, Object source, Map properties) { - this.name = name; - this.source = source; - this.properties = properties; - } + protected String name; + protected Object source; + protected Map properties; - /** - * Return the name of the notification. This is the same as the name used to - * register with the notfication center. - */ - public String getName() { - return name; - } + public PNotification(String name, Object source, Map properties) { + this.name = name; + this.source = source; + this.properties = properties; + } - /** - * Return the object associated with this notification. This is most often - * the same object that posted the notfication. It may be null. - */ - public Object getObject() { - return source; - } + /** + * Return the name of the notification. This is the same as the name used to + * register with the notfication center. + */ + public String getName() { + return name; + } - /** - * Return a property associated with the notfication. - */ - public Object getProperty(Object key) { - if (properties != null) { - return properties.get(key); - } - return null; - } + /** + * Return the object associated with this notification. This is most often + * the same object that posted the notfication. It may be null. + */ + public Object getObject() { + return source; + } + + /** + * Return a property associated with the notfication. + */ + public Object getProperty(Object key) { + if (properties != null) { + return properties.get(key); + } + return null; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PNotificationCenter.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PNotificationCenter.java index f9a6325..9b7d9bd 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PNotificationCenter.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PNotificationCenter.java @@ -52,325 +52,337 @@ * them to all interested listeners. Unlike standard Java events, the event * listeners don't need to know about the event source, and the event source * doesn't need to maintain the list of listeners. - *

+ *

* Listeners of the notfications center are held by weak references. So the * notfication center will not create garbage collection problems as standard * java event listeners do. - *

+ *

+ * * @author Jesse Grosjean */ public class PNotificationCenter { - public static final Object NULL_MARKER = new Object(); + public static final Object NULL_MARKER = new Object(); - protected static PNotificationCenter DEFAULT_CENTER; + protected static PNotificationCenter DEFAULT_CENTER; - protected HashMap listenersMap; - protected ReferenceQueue keyQueue; + protected HashMap listenersMap; + protected ReferenceQueue keyQueue; - public static PNotificationCenter defaultCenter() { - if (DEFAULT_CENTER == null) { - DEFAULT_CENTER = new PNotificationCenter(); - } - return DEFAULT_CENTER; - } + public static PNotificationCenter defaultCenter() { + if (DEFAULT_CENTER == null) { + DEFAULT_CENTER = new PNotificationCenter(); + } + return DEFAULT_CENTER; + } - private PNotificationCenter() { - listenersMap = new HashMap(); - keyQueue = new ReferenceQueue(); - } + private PNotificationCenter() { + listenersMap = new HashMap(); + keyQueue = new ReferenceQueue(); + } - //**************************************************************** - // Add Listener Methods - //**************************************************************** + // **************************************************************** + // Add Listener Methods + // **************************************************************** - /** - * Registers the 'listener' to receive notifications with the name - * 'notificationName' and/or containing 'object'. When a matching - * notification is posted the callBackMethodName message will be sent to the - * listener with a single PNotification argument. If notificationName is null - * then the listener will receive all notifications with an object matching - * 'object'. If 'object' is null the listener will receive all notifications - * with the name 'notificationName'. - */ - public void addListener(Object listener, String callbackMethodName, String notificationName, Object object) { - processKeyQueue(); + /** + * Registers the 'listener' to receive notifications with the name + * 'notificationName' and/or containing 'object'. When a matching + * notification is posted the callBackMethodName message will be sent to the + * listener with a single PNotification argument. If notificationName is + * null then the listener will receive all notifications with an object + * matching 'object'. If 'object' is null the listener will receive all + * notifications with the name 'notificationName'. + */ + public void addListener(Object listener, String callbackMethodName, String notificationName, Object object) { + processKeyQueue(); - Object name = notificationName; - Method method = null; + Object name = notificationName; + Method method = null; - try { - method = listener.getClass().getMethod(callbackMethodName, new Class[] { PNotification.class }); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - return; - } - - if (name == null) name = NULL_MARKER; - if (object == null) object = NULL_MARKER; + try { + method = listener.getClass().getMethod(callbackMethodName, new Class[] { PNotification.class }); + } + catch (NoSuchMethodException e) { + e.printStackTrace(); + return; + } - Object key = new CompoundKey(name, object); - Object value = new CompoundValue(listener, method); + if (name == null) + name = NULL_MARKER; + if (object == null) + object = NULL_MARKER; - List list = (List) listenersMap.get(key); - if (list == null) { - list = new ArrayList(); - listenersMap.put(new CompoundKey(name, object, keyQueue), list); - } + Object key = new CompoundKey(name, object); + Object value = new CompoundValue(listener, method); - if (!list.contains(value)) { - list.add(value); - } - } + List list = (List) listenersMap.get(key); + if (list == null) { + list = new ArrayList(); + listenersMap.put(new CompoundKey(name, object, keyQueue), list); + } - //**************************************************************** - // Remove Listener Methods - //**************************************************************** + if (!list.contains(value)) { + list.add(value); + } + } - /** - * Removes the listener so that it no longer recives notfications from this - * notfication center. - */ - public void removeListener(Object listener) { - processKeyQueue(); + // **************************************************************** + // Remove Listener Methods + // **************************************************************** - Iterator i = new LinkedList(listenersMap.keySet()).iterator(); - while (i.hasNext()) { - removeListener(listener, i.next()); - } - } + /** + * Removes the listener so that it no longer recives notfications from this + * notfication center. + */ + public void removeListener(Object listener) { + processKeyQueue(); - /** - * Removes the listeners as the listener of notifications matching - * notificationName and object. If listener is null all listeners matching - * notificationName and object are removed. If notificationName is null the - * listener will be removed from all notifications containing the object. If - * the object is null then the listener will be removed from all - * notifications matching notficationName. - */ - public void removeListener(Object listener, String notificationName, Object object) { - processKeyQueue(); + Iterator i = new LinkedList(listenersMap.keySet()).iterator(); + while (i.hasNext()) { + removeListener(listener, i.next()); + } + } - List keys = matchingKeys(notificationName, object); - Iterator it = keys.iterator(); - while (it.hasNext()) { - removeListener(listener, it.next()); - } - } + /** + * Removes the listeners as the listener of notifications matching + * notificationName and object. If listener is null all listeners matching + * notificationName and object are removed. If notificationName is null the + * listener will be removed from all notifications containing the object. If + * the object is null then the listener will be removed from all + * notifications matching notficationName. + */ + public void removeListener(Object listener, String notificationName, Object object) { + processKeyQueue(); - //**************************************************************** - // Post PNotification Methods - //**************************************************************** + List keys = matchingKeys(notificationName, object); + Iterator it = keys.iterator(); + while (it.hasNext()) { + removeListener(listener, it.next()); + } + } - /** - * Post a new notfication with notificationName and object. The object is - * typically the object posting the notification. The object may be null. - */ - public void postNotification(String notificationName, Object object) { - postNotification(notificationName, object, null); - } + // **************************************************************** + // Post PNotification Methods + // **************************************************************** - /** - * Creates a notification with the name notificationName, associates it with - * the object, and posts it to this notification center. The object is - * typically the object posting the notification. It may be nil. - */ - public void postNotification(String notificationName, Object object, Map userInfo) { - postNotification(new PNotification(notificationName, object, userInfo)); - } + /** + * Post a new notfication with notificationName and object. The object is + * typically the object posting the notification. The object may be null. + */ + public void postNotification(String notificationName, Object object) { + postNotification(notificationName, object, null); + } - /** - * Post the notification to this notification center. Most often clients will - * instead use one of this classes convenience postNotifcations methods. - */ - public void postNotification(PNotification aNotification) { - List mergedListeners = new LinkedList(); - List listenersList; - - Object name = aNotification.getName(); - Object object = aNotification.getObject(); + /** + * Creates a notification with the name notificationName, associates it with + * the object, and posts it to this notification center. The object is + * typically the object posting the notification. It may be nil. + */ + public void postNotification(String notificationName, Object object, Map userInfo) { + postNotification(new PNotification(notificationName, object, userInfo)); + } - if (name != null) { - if (object != null) { // both are specified - listenersList = (List) listenersMap.get(new CompoundKey(name, object)); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } - listenersList = (List) listenersMap.get(new CompoundKey(name, NULL_MARKER)); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } - listenersList = (List) listenersMap.get(new CompoundKey(NULL_MARKER, object)); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } - } else { // object is null - listenersList = (List) listenersMap.get(new CompoundKey(name, NULL_MARKER)); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } - } - } else if (object != null) { // name is null - listenersList = (List) listenersMap.get(new CompoundKey(NULL_MARKER, object)); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } - } + /** + * Post the notification to this notification center. Most often clients + * will instead use one of this classes convenience postNotifcations + * methods. + */ + public void postNotification(PNotification aNotification) { + List mergedListeners = new LinkedList(); + List listenersList; - Object key = new CompoundKey(NULL_MARKER, NULL_MARKER); - listenersList = (List) listenersMap.get(key); - if (listenersList != null) { - mergedListeners.addAll(listenersList); - } + Object name = aNotification.getName(); + Object object = aNotification.getObject(); - CompoundValue value; - Iterator it = mergedListeners.iterator(); + if (name != null) { + if (object != null) { // both are specified + listenersList = (List) listenersMap.get(new CompoundKey(name, object)); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } + listenersList = (List) listenersMap.get(new CompoundKey(name, NULL_MARKER)); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } + listenersList = (List) listenersMap.get(new CompoundKey(NULL_MARKER, object)); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } + } + else { // object is null + listenersList = (List) listenersMap.get(new CompoundKey(name, NULL_MARKER)); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } + } + } + else if (object != null) { // name is null + listenersList = (List) listenersMap.get(new CompoundKey(NULL_MARKER, object)); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } + } - while (it.hasNext()) { - value = (CompoundValue) it.next(); - if (value.get() == null) { - it.remove(); - } else { - try { - value.getMethod().invoke(value.get(), new Object[] { aNotification }); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } - } - } - } + Object key = new CompoundKey(NULL_MARKER, NULL_MARKER); + listenersList = (List) listenersMap.get(key); + if (listenersList != null) { + mergedListeners.addAll(listenersList); + } - //**************************************************************** - // Implementation classes and methods - //**************************************************************** + CompoundValue value; + Iterator it = mergedListeners.iterator(); - protected List matchingKeys(String name, Object object) { - List result = new LinkedList(); + while (it.hasNext()) { + value = (CompoundValue) it.next(); + if (value.get() == null) { + it.remove(); + } + else { + try { + value.getMethod().invoke(value.get(), new Object[] { aNotification }); + } + catch (IllegalAccessException e) { + e.printStackTrace(); + } + catch (InvocationTargetException e) { + e.printStackTrace(); + } + } + } + } - Iterator it = listenersMap.keySet().iterator(); - while (it.hasNext()) { - CompoundKey key = (CompoundKey) it.next(); - if ((name == null) || (name == key.name())) { - if ((object == null) || (object == key.get())) { - result.add(key); - } - } - } + // **************************************************************** + // Implementation classes and methods + // **************************************************************** - return result; - } - - protected void removeListener(Object listener, Object key) { - if (listener == null) { - listenersMap.remove(key); - return; - } + protected List matchingKeys(String name, Object object) { + List result = new LinkedList(); - List list = (List) listenersMap.get(key); - if (list == null) - return; + Iterator it = listenersMap.keySet().iterator(); + while (it.hasNext()) { + CompoundKey key = (CompoundKey) it.next(); + if ((name == null) || (name == key.name())) { + if ((object == null) || (object == key.get())) { + result.add(key); + } + } + } - Iterator it = list.iterator(); - while (it.hasNext()) { - Object observer = ((CompoundValue) it.next()).get(); - if ((observer == null) || (listener == observer)) { - it.remove(); - } - } - - if (list.size() == 0) { - listenersMap.remove(key); - } - } - - protected void processKeyQueue() { - CompoundKey key; - while ((key = (CompoundKey) keyQueue.poll()) != null) { - listenersMap.remove(key); - } - } - - protected static class CompoundKey extends WeakReference { + return result; + } - private Object name; - private int hashCode; + protected void removeListener(Object listener, Object key) { + if (listener == null) { + listenersMap.remove(key); + return; + } - public CompoundKey(Object aName, Object anObject) { - super(anObject); - name = aName; - hashCode = aName.hashCode() + anObject.hashCode(); - } + List list = (List) listenersMap.get(key); + if (list == null) + return; - public CompoundKey(Object aName, Object anObject, ReferenceQueue aQueue) { - super(anObject, aQueue); - name = aName; - hashCode = aName.hashCode() + anObject.hashCode(); - } + Iterator it = list.iterator(); + while (it.hasNext()) { + Object observer = ((CompoundValue) it.next()).get(); + if ((observer == null) || (listener == observer)) { + it.remove(); + } + } - public Object name() { - return name; - } + if (list.size() == 0) { + listenersMap.remove(key); + } + } - public int hashCode() { - return hashCode; - } + protected void processKeyQueue() { + CompoundKey key; + while ((key = (CompoundKey) keyQueue.poll()) != null) { + listenersMap.remove(key); + } + } - public boolean equals(Object anObject) { - if (this == anObject) return true; - CompoundKey key = (CompoundKey) anObject; - if (name == key.name || (name != null && name.equals(key.name))) { - Object object = get(); - if (object != null) { - if ( object == (key.get())) { - return true; - } - } - } - return false; - } + protected static class CompoundKey extends WeakReference { - public String toString() { - return "[CompoundKey:" + name() + ":" + get() + "]"; - } - } + private Object name; + private int hashCode; - protected static class CompoundValue extends WeakReference { + public CompoundKey(Object aName, Object anObject) { + super(anObject); + name = aName; + hashCode = aName.hashCode() + anObject.hashCode(); + } - protected int hashCode; - protected Method method; + public CompoundKey(Object aName, Object anObject, ReferenceQueue aQueue) { + super(anObject, aQueue); + name = aName; + hashCode = aName.hashCode() + anObject.hashCode(); + } - public CompoundValue(Object object, Method method) { - super(object); - hashCode = object.hashCode(); - this.method = method; - } + public Object name() { + return name; + } - public Method getMethod() { - return method; - } + public int hashCode() { + return hashCode; + } - public int hashCode() { - return hashCode; - } + public boolean equals(Object anObject) { + if (this == anObject) + return true; + CompoundKey key = (CompoundKey) anObject; + if (name == key.name || (name != null && name.equals(key.name))) { + Object object = get(); + if (object != null) { + if (object == (key.get())) { + return true; + } + } + } + return false; + } - public boolean equals(Object object) { - if (this == object) return true; - CompoundValue value = (CompoundValue) object; - if (method == value.method || (method != null && method.equals(value.method))) { - Object o = get(); - if (o != null) { - if (o == value.get()) { - return true; - } - } - } - return false; - } + public String toString() { + return "[CompoundKey:" + name() + ":" + get() + "]"; + } + } - public String toString() { - return "[CompoundValue:" + get() + ":" + getMethod().getName() + "]"; - } - } + protected static class CompoundValue extends WeakReference { + + protected int hashCode; + protected Method method; + + public CompoundValue(Object object, Method method) { + super(object); + hashCode = object.hashCode(); + this.method = method; + } + + public Method getMethod() { + return method; + } + + public int hashCode() { + return hashCode; + } + + public boolean equals(Object object) { + if (this == object) + return true; + CompoundValue value = (CompoundValue) object; + if (method == value.method || (method != null && method.equals(value.method))) { + Object o = get(); + if (o != null) { + if (o == value.get()) { + return true; + } + } + } + return false; + } + + public String toString() { + return "[CompoundValue:" + get() + ":" + getMethod().getName() + "]"; + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java index 8383eb6..901080c 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PSelectionEventHandler.java @@ -55,607 +55,625 @@ import edu.umd.cs.piccolox.handles.PBoundsHandle; /** - * PSelectionEventHandler provides standard interaction for selection. Clicking - * selects the object under the cursor. Shift-clicking allows multiple objects to be - * selected. Dragging offers marquee selection. Pressing the delete key deletes - * the selection by default. + * PSelectionEventHandler provides standard interaction for + * selection. Clicking selects the object under the cursor. Shift-clicking + * allows multiple objects to be selected. Dragging offers marquee selection. + * Pressing the delete key deletes the selection by default. + * * @version 1.0 * @author Ben Bederson - */ + */ public class PSelectionEventHandler extends PDragSequenceEventHandler { - public static final String SELECTION_CHANGED_NOTIFICATION = "SELECTION_CHANGED_NOTIFICATION"; + public static final String SELECTION_CHANGED_NOTIFICATION = "SELECTION_CHANGED_NOTIFICATION"; - final static int DASH_WIDTH = 5; - final static int NUM_STROKES = 10; - - private HashMap selection = null; // The current selection - private List selectableParents = null; // List of nodes whose children can be selected - private PPath marquee = null; - private PNode marqueeParent = null; // Node that marquee is added to as a child - private Point2D presspt = null; - private Point2D canvasPressPt = null; - private float strokeNum = 0; - private Stroke[] strokes = null; - private HashMap allItems = null; // Used within drag handler temporarily - private ArrayList unselectList = null; // Used within drag handler temporarily - private HashMap marqueeMap = null; - private PNode pressNode = null; // Node pressed on (or null if none) - private boolean deleteKeyActive = true; // True if DELETE key should delete selection - private Paint marqueePaint; - private float marqueePaintTransparency = 1.0f; - - /** - * Creates a selection event handler. - * @param marqueeParent The node to which the event handler dynamically adds a marquee - * (temporarily) to represent the area being selected. - * @param selectableParent The node whose children will be selected - * by this event handler. - */ - public PSelectionEventHandler(PNode marqueeParent, PNode selectableParent) { - this.marqueeParent = marqueeParent; - this.selectableParents = new ArrayList(); - this.selectableParents.add(selectableParent); - init(); - } + final static int DASH_WIDTH = 5; + final static int NUM_STROKES = 10; - /** - * Creates a selection event handler. - * @param marqueeParent The node to which the event handler dynamically adds a marquee - * (temporarily) to represent the area being selected. - * @param selectableParents A list of nodes whose children will be selected - * by this event handler. - */ - public PSelectionEventHandler(PNode marqueeParent, List selectableParents) { - this.marqueeParent = marqueeParent; - this.selectableParents = selectableParents; - init(); - } + // The current selection + private HashMap selection = null; + // List of nodes whose children can be selected + private List selectableParents = null; + private PPath marquee = null; + // Node that marquee is added to as a child + private PNode marqueeParent = null; + private Point2D presspt = null; + private Point2D canvasPressPt = null; + private float strokeNum = 0; + private Stroke[] strokes = null; + // Used within drag handler temporarily + private HashMap allItems = null; + // Used within drag handler temporarily + private ArrayList unselectList = null; + private HashMap marqueeMap = null; + // Node pressed on (or null if none) + private PNode pressNode = null; + // True if DELETE key should delete selection + private boolean deleteKeyActive = true; + private Paint marqueePaint; + private float marqueePaintTransparency = 1.0f; - protected void init() { - float[] dash = { DASH_WIDTH, DASH_WIDTH }; - strokes = new Stroke[NUM_STROKES]; - for (int i = 0; i < NUM_STROKES; i++) { - strokes[i] = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, dash, i); - } - - selection = new HashMap(); - allItems = new HashMap(); - unselectList = new ArrayList(); - marqueeMap = new HashMap(); - } + /** + * Creates a selection event handler. + * + * @param marqueeParent The node to which the event handler dynamically adds + * a marquee (temporarily) to represent the area being selected. + * @param selectableParent The node whose children will be selected by this + * event handler. + */ + public PSelectionEventHandler(PNode marqueeParent, PNode selectableParent) { + this.marqueeParent = marqueeParent; + this.selectableParents = new ArrayList(); + this.selectableParents.add(selectableParent); + init(); + } - /////////////////////////////////////////////////////// - // Public static methods for manipulating the selection - /////////////////////////////////////////////////////// - - public void select(Collection items) { - boolean changes = false; - Iterator itemIt = items.iterator(); - while (itemIt.hasNext()) { - PNode node = (PNode)itemIt.next(); - changes |= internalSelect(node); - } - if (changes) { - postSelectionChanged(); - } - } + /** + * Creates a selection event handler. + * + * @param marqueeParent The node to which the event handler dynamically adds + * a marquee (temporarily) to represent the area being selected. + * @param selectableParents A list of nodes whose children will be selected + * by this event handler. + */ + public PSelectionEventHandler(PNode marqueeParent, List selectableParents) { + this.marqueeParent = marqueeParent; + this.selectableParents = selectableParents; + init(); + } - public void select(Map items) { - select( items.keySet() ); - } + protected void init() { + float[] dash = { DASH_WIDTH, DASH_WIDTH }; + strokes = new Stroke[NUM_STROKES]; + for (int i = 0; i < NUM_STROKES; i++) { + strokes[i] = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, dash, i); + } - private boolean internalSelect( PNode node ) { - if (isSelected(node)) { - return false; - } + selection = new HashMap(); + allItems = new HashMap(); + unselectList = new ArrayList(); + marqueeMap = new HashMap(); + } - selection.put(node, Boolean.TRUE); - decorateSelectedNode(node); - return true; - } + // ///////////////////////////////////////////////////// + // Public static methods for manipulating the selection + // ///////////////////////////////////////////////////// - private void postSelectionChanged() - { - PNotificationCenter.defaultCenter().postNotification(SELECTION_CHANGED_NOTIFICATION, this); - } + public void select(Collection items) { + boolean changes = false; + Iterator itemIt = items.iterator(); + while (itemIt.hasNext()) { + PNode node = (PNode) itemIt.next(); + changes |= internalSelect(node); + } + if (changes) { + postSelectionChanged(); + } + } - public void select(PNode node) { - if (internalSelect(node)) { - postSelectionChanged(); - } - } + public void select(Map items) { + select(items.keySet()); + } - public void decorateSelectedNode(PNode node) { - PBoundsHandle.addBoundsHandlesTo(node); - } - - public void unselect(Collection items) { - boolean changes = false; - Iterator itemIt = items.iterator(); - while (itemIt.hasNext()) { - PNode node = (PNode)itemIt.next(); - changes |= internalUnselect(node); - } - if (changes) { - postSelectionChanged(); - } - } + private boolean internalSelect(PNode node) { + if (isSelected(node)) { + return false; + } - private boolean internalUnselect( PNode node ) { - if (!isSelected(node)) { - return false; - } + selection.put(node, Boolean.TRUE); + decorateSelectedNode(node); + return true; + } - undecorateSelectedNode(node); - selection.remove(node); - return true; - } + private void postSelectionChanged() { + PNotificationCenter.defaultCenter().postNotification(SELECTION_CHANGED_NOTIFICATION, this); + } - public void unselect(PNode node) { - if( internalUnselect(node) ) { - postSelectionChanged(); - } - } + public void select(PNode node) { + if (internalSelect(node)) { + postSelectionChanged(); + } + } - public void undecorateSelectedNode(PNode node) { - PBoundsHandle.removeBoundsHandlesFrom(node); - } + public void decorateSelectedNode(PNode node) { + PBoundsHandle.addBoundsHandlesTo(node); + } - public void unselectAll() { - // Because unselect() removes from selection, we need to - // take a copy of it first so it isn't changed while we're iterating - ArrayList sel = new ArrayList(selection.keySet()); - unselect( sel ); - } + public void unselect(Collection items) { + boolean changes = false; + Iterator itemIt = items.iterator(); + while (itemIt.hasNext()) { + PNode node = (PNode) itemIt.next(); + changes |= internalUnselect(node); + } + if (changes) { + postSelectionChanged(); + } + } - public boolean isSelected(PNode node) { - if ((node != null) && (selection.containsKey(node))) { - return true; - } else { - return false; - } - } + private boolean internalUnselect(PNode node) { + if (!isSelected(node)) { + return false; + } - /** - * Returns a copy of the currently selected nodes. - */ - public Collection getSelection() { - ArrayList sel = new ArrayList(selection.keySet()); - return sel; - } + undecorateSelectedNode(node); + selection.remove(node); + return true; + } - /** - * Gets a reference to the currently selected nodes. You should not modify or store - * this collection. - */ - public Collection getSelectionReference() - { - return Collections.unmodifiableCollection( selection.keySet() ); - } + public void unselect(PNode node) { + if (internalUnselect(node)) { + postSelectionChanged(); + } + } - /** - * Determine if the specified node is selectable (i.e., if it is a child - * of the one the list of selectable parents. - */ - protected boolean isSelectable(PNode node) { - boolean selectable = false; + public void undecorateSelectedNode(PNode node) { + PBoundsHandle.removeBoundsHandlesFrom(node); + } - Iterator parentsIt = selectableParents.iterator(); - while (parentsIt.hasNext()) { - PNode parent = (PNode)parentsIt.next(); - if (parent.getChildrenReference().contains(node)) { - selectable = true; - break; - } - else if (parent instanceof PCamera) { - for(int i=0; i<((PCamera)parent).getLayerCount(); i++) { - PLayer layer = ((PCamera)parent).getLayer(i); - if (layer.getChildrenReference().contains(node)) { - selectable = true; - break; - } - } - } - } - - return selectable; - } + public void unselectAll() { + // Because unselect() removes from selection, we need to + // take a copy of it first so it isn't changed while we're iterating + ArrayList sel = new ArrayList(selection.keySet()); + unselect(sel); + } - ////////////////////////////////////////////////////// - // Methods for modifying the set of selectable parents - ////////////////////////////////////////////////////// + public boolean isSelected(PNode node) { + if ((node != null) && (selection.containsKey(node))) { + return true; + } + else { + return false; + } + } - public void addSelectableParent(PNode node) { - selectableParents.add(node); - } - - public void removeSelectableParent(PNode node) { - selectableParents.remove(node); - } - - public void setSelectableParent(PNode node) { - selectableParents.clear(); - selectableParents.add(node); - } - - public void setSelectableParents(Collection c) { - selectableParents.clear(); - selectableParents.addAll(c); - } + /** + * Returns a copy of the currently selected nodes. + */ + public Collection getSelection() { + ArrayList sel = new ArrayList(selection.keySet()); + return sel; + } - public Collection getSelectableParents() { - return new ArrayList(selectableParents); - } + /** + * Gets a reference to the currently selected nodes. You should not modify + * or store this collection. + */ + public Collection getSelectionReference() { + return Collections.unmodifiableCollection(selection.keySet()); + } - //////////////////////////////////////////////////////// - // The overridden methods from PDragSequenceEventHandler - //////////////////////////////////////////////////////// - - protected void startDrag(PInputEvent e) { - super.startDrag(e); + /** + * Determine if the specified node is selectable (i.e., if it is a child of + * the one the list of selectable parents. + */ + protected boolean isSelectable(PNode node) { + boolean selectable = false; - initializeSelection(e); + Iterator parentsIt = selectableParents.iterator(); + while (parentsIt.hasNext()) { + PNode parent = (PNode) parentsIt.next(); + if (parent.getChildrenReference().contains(node)) { + selectable = true; + break; + } + else if (parent instanceof PCamera) { + for (int i = 0; i < ((PCamera) parent).getLayerCount(); i++) { + PLayer layer = ((PCamera) parent).getLayer(i); + if (layer.getChildrenReference().contains(node)) { + selectable = true; + break; + } + } + } + } - if (isMarqueeSelection(e)) { - initializeMarquee(e); + return selectable; + } - if (!isOptionSelection(e)) { - startMarqueeSelection(e); - } - else { - startOptionMarqueeSelection(e); - } - } - else { - if (!isOptionSelection(e)) { - startStandardSelection(e); - } else { - startStandardOptionSelection(e); - } - } - } + // //////////////////////////////////////////////////// + // Methods for modifying the set of selectable parents + // //////////////////////////////////////////////////// - protected void drag(PInputEvent e) { - super.drag(e); + public void addSelectableParent(PNode node) { + selectableParents.add(node); + } - if (isMarqueeSelection(e)) { - updateMarquee(e); + public void removeSelectableParent(PNode node) { + selectableParents.remove(node); + } - if (!isOptionSelection(e)) { - computeMarqueeSelection(e); - } - else { - computeOptionMarqueeSelection(e); - } - } else { - dragStandardSelection(e); - } - } + public void setSelectableParent(PNode node) { + selectableParents.clear(); + selectableParents.add(node); + } - protected void endDrag(PInputEvent e) { - super.endDrag(e); + public void setSelectableParents(Collection c) { + selectableParents.clear(); + selectableParents.addAll(c); + } + + public Collection getSelectableParents() { + return new ArrayList(selectableParents); + } + + // ////////////////////////////////////////////////////// + // The overridden methods from PDragSequenceEventHandler + // ////////////////////////////////////////////////////// + + protected void startDrag(PInputEvent e) { + super.startDrag(e); + + initializeSelection(e); + + if (isMarqueeSelection(e)) { + initializeMarquee(e); + + if (!isOptionSelection(e)) { + startMarqueeSelection(e); + } + else { + startOptionMarqueeSelection(e); + } + } + else { + if (!isOptionSelection(e)) { + startStandardSelection(e); + } + else { + startStandardOptionSelection(e); + } + } + } + + protected void drag(PInputEvent e) { + super.drag(e); + + if (isMarqueeSelection(e)) { + updateMarquee(e); + + if (!isOptionSelection(e)) { + computeMarqueeSelection(e); + } + else { + computeOptionMarqueeSelection(e); + } + } + else { + dragStandardSelection(e); + } + } + + protected void endDrag(PInputEvent e) { + super.endDrag(e); + + if (isMarqueeSelection(e)) { + endMarqueeSelection(e); + } + else { + endStandardSelection(e); + } + } + + // ////////////////////////// + // Additional methods + // ////////////////////////// + + public boolean isOptionSelection(PInputEvent pie) { + return pie.isShiftDown(); + } + + protected boolean isMarqueeSelection(PInputEvent pie) { + return (pressNode == null); + } + + protected void initializeSelection(PInputEvent pie) { + canvasPressPt = pie.getCanvasPosition(); + presspt = pie.getPosition(); + pressNode = pie.getPath().getPickedNode(); + if (pressNode instanceof PCamera) { + pressNode = null; + } + } + + protected void initializeMarquee(PInputEvent e) { + marquee = PPath.createRectangle((float) presspt.getX(), (float) presspt.getY(), 0, 0); + marquee.setPaint(marqueePaint); + marquee.setTransparency(marqueePaintTransparency); + marquee.setStrokePaint(Color.black); + marquee.setStroke(strokes[0]); + marqueeParent.addChild(marquee); + + marqueeMap.clear(); + } + + protected void startOptionMarqueeSelection(PInputEvent e) { + } + + protected void startMarqueeSelection(PInputEvent e) { + unselectAll(); + } - if (isMarqueeSelection(e)) { - endMarqueeSelection(e); - } - else { - endStandardSelection(e); - } - } + protected void startStandardSelection(PInputEvent pie) { + // Option indicator not down - clear selection, and start fresh + if (!isSelected(pressNode)) { + unselectAll(); - //////////////////////////// - // Additional methods - //////////////////////////// + if (isSelectable(pressNode)) { + select(pressNode); + } + } + } - public boolean isOptionSelection(PInputEvent pie) { - return pie.isShiftDown(); - } + protected void startStandardOptionSelection(PInputEvent pie) { + // Option indicator is down, toggle selection + if (isSelectable(pressNode)) { + if (isSelected(pressNode)) { + unselect(pressNode); + } + else { + select(pressNode); + } + } + } - protected boolean isMarqueeSelection(PInputEvent pie) { - return (pressNode == null); - } + protected void updateMarquee(PInputEvent pie) { + PBounds b = new PBounds(); - protected void initializeSelection(PInputEvent pie) { - canvasPressPt = pie.getCanvasPosition(); - presspt = pie.getPosition(); - pressNode = pie.getPath().getPickedNode(); - if (pressNode instanceof PCamera) { - pressNode = null; - } - } + if (marqueeParent instanceof PCamera) { + b.add(canvasPressPt); + b.add(pie.getCanvasPosition()); + } + else { + b.add(presspt); + b.add(pie.getPosition()); + } - protected void initializeMarquee(PInputEvent e) { - marquee = PPath.createRectangle((float)presspt.getX(), (float)presspt.getY(), 0, 0); - marquee.setPaint(marqueePaint); - marquee.setTransparency(marqueePaintTransparency); - marquee.setStrokePaint(Color.black); - marquee.setStroke(strokes[0]); - marqueeParent.addChild(marquee); + marquee.globalToLocal(b); + marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); + b.reset(); + b.add(presspt); + b.add(pie.getPosition()); - marqueeMap.clear(); - } + allItems.clear(); + PNodeFilter filter = createNodeFilter(b); + Iterator parentsIt = selectableParents.iterator(); + while (parentsIt.hasNext()) { + PNode parent = (PNode) parentsIt.next(); - protected void startOptionMarqueeSelection(PInputEvent e) { - } + Collection items; + if (parent instanceof PCamera) { + items = new ArrayList(); + for (int i = 0; i < ((PCamera) parent).getLayerCount(); i++) { + ((PCamera) parent).getLayer(i).getAllNodes(filter, items); + } + } + else { + items = parent.getAllNodes(filter, null); + } - protected void startMarqueeSelection(PInputEvent e) { - unselectAll(); - } - - protected void startStandardSelection(PInputEvent pie) { - // Option indicator not down - clear selection, and start fresh - if (!isSelected(pressNode)) { - unselectAll(); - - if (isSelectable(pressNode)) { - select(pressNode); - } - } - } + Iterator itemsIt = items.iterator(); + while (itemsIt.hasNext()) { + allItems.put(itemsIt.next(), Boolean.TRUE); + } + } + } - protected void startStandardOptionSelection(PInputEvent pie) { - // Option indicator is down, toggle selection - if (isSelectable(pressNode)) { - if (isSelected(pressNode)) { - unselect(pressNode); - } else { - select(pressNode); - } - } - } + protected void computeMarqueeSelection(PInputEvent pie) { + unselectList.clear(); + // Make just the items in the list selected + // Do this efficiently by first unselecting things not in the list + Iterator selectionEn = selection.keySet().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); + if (!allItems.containsKey(node)) { + unselectList.add(node); + } + } + unselect(unselectList); - protected void updateMarquee(PInputEvent pie) { - PBounds b = new PBounds(); + // Then select the rest + selectionEn = allItems.keySet().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); + if (!selection.containsKey(node) && !marqueeMap.containsKey(node) && isSelectable(node)) { + marqueeMap.put(node, Boolean.TRUE); + } + else if (!isSelectable(node)) { + selectionEn.remove(); + } + } - if (marqueeParent instanceof PCamera) { - b.add(canvasPressPt); - b.add(pie.getCanvasPosition()); - } - else { - b.add(presspt); - b.add(pie.getPosition()); - } + select(allItems); + } - marquee.globalToLocal(b); - marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); - b.reset(); - b.add(presspt); - b.add(pie.getPosition()); + protected void computeOptionMarqueeSelection(PInputEvent pie) { + unselectList.clear(); + Iterator selectionEn = selection.keySet().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); + if (!allItems.containsKey(node) && marqueeMap.containsKey(node)) { + marqueeMap.remove(node); + unselectList.add(node); + } + } + unselect(unselectList); - allItems.clear(); - PNodeFilter filter = createNodeFilter(b); - Iterator parentsIt = selectableParents.iterator(); - while (parentsIt.hasNext()) { - PNode parent = (PNode) parentsIt.next(); - - Collection items; - if (parent instanceof PCamera) { - items = new ArrayList(); - for(int i=0; i<((PCamera)parent).getLayerCount(); i++) { - ((PCamera)parent).getLayer(i).getAllNodes(filter,items); - } - } - else { - items = parent.getAllNodes(filter, null); - } - - Iterator itemsIt = items.iterator(); - while (itemsIt.hasNext()) { - allItems.put(itemsIt.next(), Boolean.TRUE); - } - } - } + // Then select the rest + selectionEn = allItems.keySet().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); + if (!selection.containsKey(node) && !marqueeMap.containsKey(node) && isSelectable(node)) { + marqueeMap.put(node, Boolean.TRUE); + } + else if (!isSelectable(node)) { + selectionEn.remove(); + } + } - protected void computeMarqueeSelection(PInputEvent pie) { - unselectList.clear(); - // Make just the items in the list selected - // Do this efficiently by first unselecting things not in the list - Iterator selectionEn = selection.keySet().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); - if (!allItems.containsKey(node)) { - unselectList.add(node); - } - } - unselect(unselectList); - - // Then select the rest - selectionEn = allItems.keySet().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); - if (!selection.containsKey(node) && !marqueeMap.containsKey(node) && isSelectable(node)) { - marqueeMap.put(node,Boolean.TRUE); - } - else if (!isSelectable(node)) { - selectionEn.remove(); - } - } - - select(allItems); - } + select(allItems); + } - protected void computeOptionMarqueeSelection(PInputEvent pie) { - unselectList.clear(); - Iterator selectionEn = selection.keySet().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); - if (!allItems.containsKey(node) && marqueeMap.containsKey(node)) { - marqueeMap.remove(node); - unselectList.add(node); - } - } - unselect(unselectList); - + protected PNodeFilter createNodeFilter(PBounds bounds) { + return new BoundsFilter(bounds); + } - // Then select the rest - selectionEn = allItems.keySet().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); - if (!selection.containsKey(node) && !marqueeMap.containsKey(node) && isSelectable(node)) { - marqueeMap.put(node,Boolean.TRUE); - } - else if (!isSelectable(node)) { - selectionEn.remove(); - } - } + protected PBounds getMarqueeBounds() { + if (marquee != null) { + return marquee.getBounds(); + } + return new PBounds(); + } - select(allItems); - } + protected void dragStandardSelection(PInputEvent e) { + // There was a press node, so drag selection + PDimension d = e.getCanvasDelta(); + e.getTopCamera().localToView(d); - protected PNodeFilter createNodeFilter(PBounds bounds) { - return new BoundsFilter(bounds); - } + PDimension gDist = new PDimension(); + Iterator selectionEn = getSelection().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); - protected PBounds getMarqueeBounds() { - if (marquee != null) { - return marquee.getBounds(); - } - return new PBounds(); - } + gDist.setSize(d); + node.getParent().globalToLocal(gDist); + node.offset(gDist.getWidth(), gDist.getHeight()); + } + } - protected void dragStandardSelection(PInputEvent e) { - // There was a press node, so drag selection - PDimension d = e.getCanvasDelta(); - e.getTopCamera().localToView(d); + protected void endMarqueeSelection(PInputEvent e) { + // Remove marquee + allItems.clear(); + marqueeMap.clear(); + marquee.removeFromParent(); + marquee = null; + } - PDimension gDist = new PDimension(); - Iterator selectionEn = getSelection().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); + protected void endStandardSelection(PInputEvent e) { + pressNode = null; + } - gDist.setSize(d); - node.getParent().globalToLocal(gDist); - node.offset(gDist.getWidth(), gDist.getHeight()); - } - } + /** + * This gets called continuously during the drag, and is used to animate the + * marquee + */ + protected void dragActivityStep(PInputEvent aEvent) { + if (marquee != null) { + float origStrokeNum = strokeNum; + strokeNum = (strokeNum + 0.5f) % NUM_STROKES; // Increment by + // partial steps to + // slow down animation + if ((int) strokeNum != (int) origStrokeNum) { + marquee.setStroke(strokes[(int) strokeNum]); + } + } + } - protected void endMarqueeSelection(PInputEvent e) { - // Remove marquee - allItems.clear(); - marqueeMap.clear(); - marquee.removeFromParent(); - marquee = null; - } + /** + * Delete selection when delete key is pressed (if enabled) + */ + public void keyPressed(PInputEvent e) { + switch (e.getKeyCode()) { + case KeyEvent.VK_DELETE: + if (deleteKeyActive) { + Iterator selectionEn = selection.keySet().iterator(); + while (selectionEn.hasNext()) { + PNode node = (PNode) selectionEn.next(); + node.removeFromParent(); + } + selection.clear(); + } + } + } - protected void endStandardSelection(PInputEvent e) { - pressNode = null; - } + public boolean getSupportDeleteKey() { + return deleteKeyActive; + } - /** - * This gets called continuously during the drag, and is used to animate the marquee - */ - protected void dragActivityStep(PInputEvent aEvent) { - if (marquee != null) { - float origStrokeNum = strokeNum; - strokeNum = (strokeNum + 0.5f) % NUM_STROKES; // Increment by partial steps to slow down animation - if ((int)strokeNum != (int)origStrokeNum) { - marquee.setStroke(strokes[(int)strokeNum]); - } - } - } + public boolean isDeleteKeyActive() { + return deleteKeyActive; + } - /** - * Delete selection when delete key is pressed (if enabled) - */ - public void keyPressed(PInputEvent e) { - switch (e.getKeyCode()) { - case KeyEvent.VK_DELETE: - if (deleteKeyActive) { - Iterator selectionEn = selection.keySet().iterator(); - while (selectionEn.hasNext()) { - PNode node = (PNode) selectionEn.next(); - node.removeFromParent(); - } - selection.clear(); - } - } - } + /** + * Specifies if the DELETE key should delete the selection + */ + public void setDeleteKeyActive(boolean deleteKeyActive) { + this.deleteKeyActive = deleteKeyActive; + } - public boolean getSupportDeleteKey() { - return deleteKeyActive; - } + // //////////////////// + // Inner classes + // //////////////////// - public boolean isDeleteKeyActive() { - return deleteKeyActive; - } + protected class BoundsFilter implements PNodeFilter { + PBounds localBounds = new PBounds(); + PBounds bounds; - /** - * Specifies if the DELETE key should delete the selection - */ - public void setDeleteKeyActive(boolean deleteKeyActive) { - this.deleteKeyActive = deleteKeyActive; - } + protected BoundsFilter(PBounds bounds) { + this.bounds = bounds; + } - ////////////////////// - // Inner classes - ////////////////////// + public boolean accept(PNode node) { + localBounds.setRect(bounds); + node.globalToLocal(localBounds); - protected class BoundsFilter implements PNodeFilter { - PBounds localBounds = new PBounds(); - PBounds bounds; - - protected BoundsFilter(PBounds bounds) { - this.bounds = bounds; - } + boolean boundsIntersects = node.intersects(localBounds); + boolean isMarquee = (node == marquee); + return (node.getPickable() && boundsIntersects && !isMarquee && !selectableParents.contains(node) && !isCameraLayer(node)); + } - public boolean accept(PNode node) { - localBounds.setRect(bounds); - node.globalToLocal(localBounds); - - boolean boundsIntersects = node.intersects(localBounds); - boolean isMarquee = (node == marquee); - return (node.getPickable() && boundsIntersects && !isMarquee && !selectableParents.contains(node) && !isCameraLayer(node)); - } + public boolean acceptChildrenOf(PNode node) { + return selectableParents.contains(node) || isCameraLayer(node); + } - public boolean acceptChildrenOf(PNode node) { - return selectableParents.contains(node) || isCameraLayer(node); - } - - public boolean isCameraLayer(PNode node) { - if (node instanceof PLayer) { - for(Iterator i=selectableParents.iterator(); i.hasNext();) { - PNode parent = (PNode)i.next(); - if (parent instanceof PCamera) { - if (((PCamera)parent).indexOfLayer((PLayer)node) != -1) { - return true; - } - } - } - } - return false; - } - } + public boolean isCameraLayer(PNode node) { + if (node instanceof PLayer) { + for (Iterator i = selectableParents.iterator(); i.hasNext();) { + PNode parent = (PNode) i.next(); + if (parent instanceof PCamera) { + if (((PCamera) parent).indexOfLayer((PLayer) node) != -1) { + return true; + } + } + } + } + return false; + } + } - /** - * Indicates the color used to paint the marquee. - * @return the paint for interior of the marquee - */ - public Paint getMarqueePaint() { - return marqueePaint; - } + /** + * Indicates the color used to paint the marquee. + * + * @return the paint for interior of the marquee + */ + public Paint getMarqueePaint() { + return marqueePaint; + } - /** - * Sets the color used to paint the marquee. - * @param paint the paint color - */ - public void setMarqueePaint(Paint paint) { - this.marqueePaint = paint; - } + /** + * Sets the color used to paint the marquee. + * + * @param paint the paint color + */ + public void setMarqueePaint(Paint paint) { + this.marqueePaint = paint; + } - /** - * Indicates the transparency level for the interior of the marquee. - * @return Returns the marquee paint transparency, zero to one - */ - public float getMarqueePaintTransparency() { - return marqueePaintTransparency; - } + /** + * Indicates the transparency level for the interior of the marquee. + * + * @return Returns the marquee paint transparency, zero to one + */ + public float getMarqueePaintTransparency() { + return marqueePaintTransparency; + } - /** - * Sets the transparency level for the interior of the marquee. - * @param marqueePaintTransparency The marquee paint transparency to set. - */ - public void setMarqueePaintTransparency(float marqueePaintTransparency) { - this.marqueePaintTransparency = marqueePaintTransparency; - } + /** + * Sets the transparency level for the interior of the marquee. + * + * @param marqueePaintTransparency The marquee paint transparency to set. + */ + public void setMarqueePaintTransparency(float marqueePaintTransparency) { + this.marqueePaintTransparency = marqueePaintTransparency; + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PStyledTextEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PStyledTextEventHandler.java index 64af73c..6d5ee8d 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PStyledTextEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PStyledTextEventHandler.java @@ -27,7 +27,7 @@ * Piccolo was written at the Human-Computer Interaction Laboratory www.cs.umd.edu/hcil by Jesse Grosjean * under the supervision of Ben Bederson. The Piccolo website is www.cs.umd.edu/hcil/piccolo. */ - package edu.umd.cs.piccolox.event; +package edu.umd.cs.piccolox.event; import java.awt.Color; import java.awt.Dimension; @@ -65,217 +65,217 @@ */ public class PStyledTextEventHandler extends PBasicInputEventHandler { - protected PCanvas canvas; + protected PCanvas canvas; - protected JTextComponent editor; + protected JTextComponent editor; - protected DocumentListener docListener; + protected DocumentListener docListener; - protected PStyledText editedText; + protected PStyledText editedText; - /** - * Basic constructor for PStyledTextEventHandler - */ - public PStyledTextEventHandler(PCanvas canvas) { - super(); + /** + * Basic constructor for PStyledTextEventHandler + */ + public PStyledTextEventHandler(PCanvas canvas) { + super(); - this.canvas = canvas; - initEditor(createDefaultEditor()); - } + this.canvas = canvas; + initEditor(createDefaultEditor()); + } - /** - * Constructor for PStyledTextEventHandler that allows an editor to be specified - */ - public PStyledTextEventHandler(PCanvas canvas, JTextComponent editor) { - super(); + /** + * Constructor for PStyledTextEventHandler that allows an editor to be + * specified + */ + public PStyledTextEventHandler(PCanvas canvas, JTextComponent editor) { + super(); - this.canvas = canvas; - initEditor(editor); - } + this.canvas = canvas; + initEditor(editor); + } - protected void initEditor(JTextComponent newEditor) { - editor = newEditor; - - canvas.setLayout(null); - canvas.add(editor); - editor.setVisible(false); - - docListener = createDocumentListener(); - } + protected void initEditor(JTextComponent newEditor) { + editor = newEditor; - protected JTextComponent createDefaultEditor() { - JTextPane tComp = new JTextPane() { + canvas.setLayout(null); + canvas.add(editor); + editor.setVisible(false); - /** - * Set some rendering hints - if we don't then the rendering can be inconsistent. Also, - * Swing doesn't work correctly with fractional metrics. - */ - public void paint(Graphics g) { - Graphics2D g2 = (Graphics2D)g; - - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); - - super.paint(g); - } - }; - tComp.setBorder(new CompoundBorder(new LineBorder(Color.black),new EmptyBorder(3,3,3,3))); - return tComp; - } + docListener = createDocumentListener(); + } - protected DocumentListener createDocumentListener() { - return new DocumentListener() { - public void removeUpdate(DocumentEvent e) { - reshapeEditorLater(); - } - - public void insertUpdate(DocumentEvent e) { - reshapeEditorLater(); - } - - public void changedUpdate(DocumentEvent e) { - reshapeEditorLater(); - } - }; - } + protected JTextComponent createDefaultEditor() { + JTextPane tComp = new JTextPane() { - public PStyledText createText() { - PStyledText newText = new PStyledText(); - - Document doc = editor.getUI().getEditorKit(editor).createDefaultDocument(); - if (doc instanceof StyledDocument) { - if (!doc.getDefaultRootElement().getAttributes().isDefined(StyleConstants.FontFamily) - || !doc.getDefaultRootElement().getAttributes().isDefined(StyleConstants.FontSize)) { + /** + * Set some rendering hints - if we don't then the rendering can be + * inconsistent. Also, Swing doesn't work correctly with fractional + * metrics. + */ + public void paint(Graphics g) { + Graphics2D g2 = (Graphics2D) g; - Font eFont = editor.getFont(); - SimpleAttributeSet sas = new SimpleAttributeSet(); - sas.addAttribute(StyleConstants.FontFamily, eFont.getFamily()); - sas.addAttribute(StyleConstants.FontSize, new Integer(eFont.getSize())); + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); + g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); - ((StyledDocument) doc).setParagraphAttributes(0, doc.getLength(), sas, false); - } - } - newText.setDocument(doc); - - return newText; - } + super.paint(g); + } + }; + tComp.setBorder(new CompoundBorder(new LineBorder(Color.black), new EmptyBorder(3, 3, 3, 3))); + return tComp; + } - public void mousePressed(PInputEvent inputEvent) { - PNode pickedNode = inputEvent.getPickedNode(); - - stopEditing(); - - if (pickedNode instanceof PStyledText) { - startEditing(inputEvent,(PStyledText)pickedNode); - } - else if (pickedNode instanceof PCamera) { - PStyledText newText = createText(); - Insets pInsets = newText.getInsets(); - canvas.getLayer().addChild(newText); - newText.translate(inputEvent.getPosition().getX()-pInsets.left,inputEvent.getPosition().getY()-pInsets.top); - startEditing(inputEvent, newText); - } - } - - public void startEditing(PInputEvent event, PStyledText text) { - // Get the node's top right hand corner - Insets pInsets = text.getInsets(); - Point2D nodePt = new Point2D.Double(text.getX()+pInsets.left,text.getY()+pInsets.top); - text.localToGlobal(nodePt); - event.getTopCamera().viewToLocal(nodePt); + protected DocumentListener createDocumentListener() { + return new DocumentListener() { + public void removeUpdate(DocumentEvent e) { + reshapeEditorLater(); + } - // Update the editor to edit the specified node - editor.setDocument(text.getDocument()); - editor.setVisible(true); + public void insertUpdate(DocumentEvent e) { + reshapeEditorLater(); + } - Insets bInsets = editor.getBorder().getBorderInsets(editor); - editor.setLocation((int)nodePt.getX()-bInsets.left,(int)nodePt.getY()-bInsets.top); - reshapeEditorLater(); + public void changedUpdate(DocumentEvent e) { + reshapeEditorLater(); + } + }; + } - dispatchEventToEditor(event); - canvas.repaint(); + public PStyledText createText() { + PStyledText newText = new PStyledText(); - text.setEditing(true); - text.getDocument().addDocumentListener(docListener); - editedText = text; - } - - public void stopEditing() { - if (editedText != null) { - editedText.getDocument().removeDocumentListener(docListener); - editedText.setEditing(false); + Document doc = editor.getUI().getEditorKit(editor).createDefaultDocument(); + if (doc instanceof StyledDocument) { + if (!doc.getDefaultRootElement().getAttributes().isDefined(StyleConstants.FontFamily) + || !doc.getDefaultRootElement().getAttributes().isDefined(StyleConstants.FontSize)) { - if (editedText.getDocument().getLength() == 0) { - editedText.removeFromParent(); - } - else { - editedText.syncWithDocument(); - } + Font eFont = editor.getFont(); + SimpleAttributeSet sas = new SimpleAttributeSet(); + sas.addAttribute(StyleConstants.FontFamily, eFont.getFamily()); + sas.addAttribute(StyleConstants.FontSize, new Integer(eFont.getSize())); - editor.setVisible(false); - canvas.repaint(); - - editedText = null; - } - } + ((StyledDocument) doc).setParagraphAttributes(0, doc.getLength(), sas, false); + } + } + newText.setDocument(doc); - public void dispatchEventToEditor(final PInputEvent e) { - // We have to nest the mouse press in two invoke laters so that it is - // fired so that the component has been completely validated at the new size - // and the mouse event has the correct offset - SwingUtilities.invokeLater(new Runnable() { - public void run() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - MouseEvent me = - new MouseEvent( - editor, - MouseEvent.MOUSE_PRESSED, - e.getWhen(), - e.getModifiers() | InputEvent.BUTTON1_MASK, - (int) (e.getCanvasPosition().getX() - editor.getX()), - (int) (e.getCanvasPosition().getY() - editor.getY()), - 1, - false); - editor.dispatchEvent(me); - } - }); - } - }); - } + return newText; + } - - public void reshapeEditor() { - if (editedText != null) { - // Update the size to fit the new document - note that it is a 2 stage process - Dimension prefSize = editor.getPreferredSize(); - - Insets pInsets = editedText.getInsets(); - Insets jInsets = editor.getInsets(); - - int width = (editedText.getConstrainWidthToTextWidth()) ? (int)prefSize.getWidth() : (int)(editedText.getWidth()-pInsets.left-pInsets.right+jInsets.left+jInsets.right+3.0); - prefSize.setSize(width,prefSize.getHeight()); - editor.setSize(prefSize); + public void mousePressed(PInputEvent inputEvent) { + PNode pickedNode = inputEvent.getPickedNode(); - prefSize = editor.getPreferredSize(); - int height = (editedText.getConstrainHeightToTextHeight()) ? (int)prefSize.getHeight() : (int)(editedText.getHeight()-pInsets.top-pInsets.bottom+jInsets.top+jInsets.bottom+3.0); - prefSize.setSize(width,height); - editor.setSize(prefSize); - } - } + stopEditing(); - /** - * Sometimes we need to invoke this later because the document events seem to get fired - * before the text is actually incorporated into the document - */ - protected void reshapeEditorLater() { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - reshapeEditor(); - } - }); - } - + if (pickedNode instanceof PStyledText) { + startEditing(inputEvent, (PStyledText) pickedNode); + } + else if (pickedNode instanceof PCamera) { + PStyledText newText = createText(); + Insets pInsets = newText.getInsets(); + canvas.getLayer().addChild(newText); + newText.translate(inputEvent.getPosition().getX() - pInsets.left, inputEvent.getPosition().getY() + - pInsets.top); + startEditing(inputEvent, newText); + } + } + + public void startEditing(PInputEvent event, PStyledText text) { + // Get the node's top right hand corner + Insets pInsets = text.getInsets(); + Point2D nodePt = new Point2D.Double(text.getX() + pInsets.left, text.getY() + pInsets.top); + text.localToGlobal(nodePt); + event.getTopCamera().viewToLocal(nodePt); + + // Update the editor to edit the specified node + editor.setDocument(text.getDocument()); + editor.setVisible(true); + + Insets bInsets = editor.getBorder().getBorderInsets(editor); + editor.setLocation((int) nodePt.getX() - bInsets.left, (int) nodePt.getY() - bInsets.top); + reshapeEditorLater(); + + dispatchEventToEditor(event); + canvas.repaint(); + + text.setEditing(true); + text.getDocument().addDocumentListener(docListener); + editedText = text; + } + + public void stopEditing() { + if (editedText != null) { + editedText.getDocument().removeDocumentListener(docListener); + editedText.setEditing(false); + + if (editedText.getDocument().getLength() == 0) { + editedText.removeFromParent(); + } + else { + editedText.syncWithDocument(); + } + + editor.setVisible(false); + canvas.repaint(); + + editedText = null; + } + } + + public void dispatchEventToEditor(final PInputEvent e) { + // We have to nest the mouse press in two invoke laters so that it is + // fired so that the component has been completely validated at the new + // size and the mouse event has the correct offset + SwingUtilities.invokeLater(new Runnable() { + public void run() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + MouseEvent me = new MouseEvent(editor, MouseEvent.MOUSE_PRESSED, e.getWhen(), e.getModifiers() + | InputEvent.BUTTON1_MASK, (int) (e.getCanvasPosition().getX() - editor.getX()), + (int) (e.getCanvasPosition().getY() - editor.getY()), 1, false); + editor.dispatchEvent(me); + } + }); + } + }); + } + + public void reshapeEditor() { + if (editedText != null) { + // Update the size to fit the new document - note that it is a 2 + // stage process + Dimension prefSize = editor.getPreferredSize(); + + Insets pInsets = editedText.getInsets(); + Insets jInsets = editor.getInsets(); + + int width = (editedText.getConstrainWidthToTextWidth()) ? (int) prefSize.getWidth() : (int) (editedText + .getWidth() + - pInsets.left - pInsets.right + jInsets.left + jInsets.right + 3.0); + prefSize.setSize(width, prefSize.getHeight()); + editor.setSize(prefSize); + + prefSize = editor.getPreferredSize(); + int height = (editedText.getConstrainHeightToTextHeight()) ? (int) prefSize.getHeight() : (int) (editedText + .getHeight() + - pInsets.top - pInsets.bottom + jInsets.top + jInsets.bottom + 3.0); + prefSize.setSize(width, height); + editor.setSize(prefSize); + } + } + + /** + * Sometimes we need to invoke this later because the document events seem + * to get fired before the text is actually incorporated into the document + */ + protected void reshapeEditorLater() { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + reshapeEditor(); + } + }); + } + } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/event/PZoomToEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/event/PZoomToEventHandler.java index 9a07a14..b3edc7d 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/event/PZoomToEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/event/PZoomToEventHandler.java @@ -41,31 +41,32 @@ /** * PZoomToEventHandler is used to zoom the camera view to the node * clicked on with button one. - *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PZoomToEventHandler extends PBasicInputEventHandler { - public PZoomToEventHandler() { - setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); - } + public PZoomToEventHandler() { + setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + } - public void mousePressed(PInputEvent aEvent) { - zoomTo(aEvent); - } + public void mousePressed(PInputEvent aEvent) { + zoomTo(aEvent); + } - protected void zoomTo(final PInputEvent aEvent) { - PBounds zoomToBounds; - PNode picked = aEvent.getPickedNode(); - - if (picked instanceof PCamera) { - PCamera c = (PCamera) picked; - zoomToBounds = c.getUnionOfLayerFullBounds(); - } else { - zoomToBounds = picked.getGlobalFullBounds(); - } - - aEvent.getCamera().animateViewToCenterBounds(zoomToBounds, true, 500); - } + protected void zoomTo(final PInputEvent aEvent) { + PBounds zoomToBounds; + PNode picked = aEvent.getPickedNode(); + + if (picked instanceof PCamera) { + PCamera c = (PCamera) picked; + zoomToBounds = c.getUnionOfLayerFullBounds(); + } + else { + zoomToBounds = picked.getGlobalFullBounds(); + } + + aEvent.getCamera().animateViewToCenterBounds(zoomToBounds, true, 500); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/handles/PBoundsHandle.java b/extras/src/main/java/edu/umd/cs/piccolox/handles/PBoundsHandle.java index 14d536f..300cb2d 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/handles/PBoundsHandle.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/handles/PBoundsHandle.java @@ -48,296 +48,307 @@ /** * PBoundsHandle a handle for resizing the bounds of another node. If a * bounds handle is dragged such that the other node's width or height becomes - * negative then the each drag handle's locator assciated with that - * other node is "flipped" so that they are attached to and dragging a different - * corner of the nodes bounds. - *

+ * negative then the each drag handle's locator assciated with that other node + * is "flipped" so that they are attached to and dragging a different corner of + * the nodes bounds. + * * @version 1.0 * @author Jesse Grosjean */ public class PBoundsHandle extends PHandle { - - private transient PBasicInputEventHandler handleCursorHandler; - - public static void addBoundsHandlesTo(PNode aNode) { - aNode.addChild(new PBoundsHandle(PBoundsLocator.createEastLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createWestLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); - aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); - } - public static void addStickyBoundsHandlesTo(PNode aNode, PCamera camera) { - camera.addChild(new PBoundsHandle(PBoundsLocator.createEastLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createWestLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); - camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); - } - - public static void removeBoundsHandlesFrom(PNode aNode) { - ArrayList handles = new ArrayList(); + private transient PBasicInputEventHandler handleCursorHandler; - Iterator i = aNode.getChildrenIterator(); - while (i.hasNext()) { - PNode each = (PNode) i.next(); - if (each instanceof PBoundsHandle) { - handles.add(each); - } - } - aNode.removeChildren(handles); - } - - public PBoundsHandle(PBoundsLocator aLocator) { - super(aLocator); - } - - protected void installHandleEventHandlers() { - super.installHandleEventHandlers(); - handleCursorHandler = new PBasicInputEventHandler() { - boolean cursorPushed = false; - public void mouseEntered(PInputEvent aEvent) { - if (!cursorPushed) { - aEvent.pushCursor(getCursorFor(((PBoundsLocator)getLocator()).getSide())); - cursorPushed = true; - } - } - public void mouseExited(PInputEvent aEvent) { - PPickPath focus = aEvent.getInputManager().getMouseFocus(); - if (cursorPushed) { - if (focus == null || focus.getPickedNode() != PBoundsHandle.this) { - aEvent.popCursor(); - cursorPushed = false; - } - } - } - public void mouseReleased(PInputEvent event) { - if (cursorPushed) { - event.popCursor(); - cursorPushed = false; - } - } - }; - addInputEventListener(handleCursorHandler); - } + public static void addBoundsHandlesTo(PNode aNode) { + aNode.addChild(new PBoundsHandle(PBoundsLocator.createEastLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createWestLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); + aNode.addChild(new PBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); + } - /** - * Return the event handler that is responsible for setting the mouse - * cursor when it enters/exits this handle. - */ - public PBasicInputEventHandler getHandleCursorEventHandler() { - return handleCursorHandler; - } + public static void addStickyBoundsHandlesTo(PNode aNode, PCamera camera) { + camera.addChild(new PBoundsHandle(PBoundsLocator.createEastLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createWestLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); + camera.addChild(new PBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); + } - public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - l.getNode().startResizeBounds(); - } - - public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - - PNode n = l.getNode(); - PBounds b = n.getBounds(); + public static void removeBoundsHandlesFrom(PNode aNode) { + ArrayList handles = new ArrayList(); - PNode parent = getParent(); - if (parent != n && parent instanceof PCamera) { - ((PCamera)parent).localToView(aLocalDimension); - } + Iterator i = aNode.getChildrenIterator(); + while (i.hasNext()) { + PNode each = (PNode) i.next(); + if (each instanceof PBoundsHandle) { + handles.add(each); + } + } + aNode.removeChildren(handles); + } - localToGlobal(aLocalDimension); - n.globalToLocal(aLocalDimension); - - double dx = aLocalDimension.getWidth(); - double dy = aLocalDimension.getHeight(); - - switch (l.getSide()) { - case SwingConstants.NORTH: - b.setRect(b.x, b.y + dy, b.width, b.height - dy); - break; - - case SwingConstants.SOUTH: - b.setRect(b.x, b.y, b.width, b.height + dy); - break; - - case SwingConstants.EAST: - b.setRect(b.x, b.y, b.width + dx, b.height); - break; - - case SwingConstants.WEST: - b.setRect(b.x + dx, b.y, b.width - dx, b.height); - break; - - case SwingConstants.NORTH_WEST: - b.setRect(b.x + dx, b.y + dy, b.width - dx, b.height - dy); - break; - - case SwingConstants.SOUTH_WEST: - b.setRect(b.x + dx, b.y, b.width - dx, b.height + dy); - break; - - case SwingConstants.NORTH_EAST: - b.setRect(b.x, b.y + dy, b.width + dx, b.height - dy); - break; - - case SwingConstants.SOUTH_EAST: - b.setRect(b.x, b.y, b.width + dx, b.height + dy); - break; - } + public PBoundsHandle(PBoundsLocator aLocator) { + super(aLocator); + } - boolean flipX = false; - boolean flipY = false; - - if (b.width < 0) { - flipX = true; - b.width = -b.width; - b.x -= b.width; - } - - if (b.height < 0) { - flipY = true; - b.height = -b.height; - b.y -= b.height; - } - - if (flipX || flipY) { - flipSiblingBoundsHandles(flipX, flipY); - } - - n.setBounds(b); - } - - public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - l.getNode().endResizeBounds(); - } - - public void flipSiblingBoundsHandles(boolean flipX, boolean flipY) { - Iterator i = getParent().getChildrenIterator(); - while (i.hasNext()) { - Object each = i.next(); - if (each instanceof PBoundsHandle) { - ((PBoundsHandle)each).flipHandleIfNeeded(flipX, flipY); - } - } - } - - public void flipHandleIfNeeded(boolean flipX, boolean flipY) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - - if (flipX || flipY) { - switch (l.getSide()) { - case SwingConstants.NORTH: { - if (flipY) { - l.setSide(SwingConstants.SOUTH); - } - break; - } - - case SwingConstants.SOUTH: { - if (flipY) { - l.setSide(SwingConstants.NORTH); - } - break; - } - - case SwingConstants.EAST: { - if (flipX) { - l.setSide(SwingConstants.WEST); - } - break; - } - - case SwingConstants.WEST: { - if (flipX) { - l.setSide(SwingConstants.EAST); - } - break; - } - - case SwingConstants.NORTH_WEST: { - if (flipX && flipY) { - l.setSide(SwingConstants.SOUTH_EAST); - } else if (flipX) { - l.setSide(SwingConstants.NORTH_EAST); - } else if (flipY) { - l.setSide(SwingConstants.SOUTH_WEST); - } - - break; - } - - case SwingConstants.SOUTH_WEST: { - if (flipX && flipY) { - l.setSide(SwingConstants.NORTH_EAST); - } else if (flipX) { - l.setSide(SwingConstants.SOUTH_EAST); - } else if (flipY) { - l.setSide(SwingConstants.NORTH_WEST); - } - break; - } - - case SwingConstants.NORTH_EAST: { - if (flipX && flipY) { - l.setSide(SwingConstants.SOUTH_WEST); - } else if (flipX) { - l.setSide(SwingConstants.NORTH_WEST); - } else if (flipY) { - l.setSide(SwingConstants.SOUTH_EAST); - } - break; - } - - case SwingConstants.SOUTH_EAST: { - if (flipX && flipY) { - l.setSide(SwingConstants.NORTH_WEST); - } else if (flipX) { - l.setSide(SwingConstants.SOUTH_WEST); - } else if (flipY) { - l.setSide(SwingConstants.NORTH_EAST); - } - break; - } - } - } - - // reset locator to update layout - setLocator(l); - } - - public Cursor getCursorFor(int side) { - switch (side) { - case SwingConstants.NORTH: - return new Cursor(Cursor.N_RESIZE_CURSOR); + protected void installHandleEventHandlers() { + super.installHandleEventHandlers(); + handleCursorHandler = new PBasicInputEventHandler() { + boolean cursorPushed = false; - case SwingConstants.SOUTH: - return new Cursor(Cursor.S_RESIZE_CURSOR); - - case SwingConstants.EAST: - return new Cursor(Cursor.E_RESIZE_CURSOR); - - case SwingConstants.WEST: - return new Cursor(Cursor.W_RESIZE_CURSOR); - - case SwingConstants.NORTH_WEST: - return new Cursor(Cursor.NW_RESIZE_CURSOR); - - case SwingConstants.SOUTH_WEST: - return new Cursor(Cursor.SW_RESIZE_CURSOR); - - case SwingConstants.NORTH_EAST: - return new Cursor(Cursor.NE_RESIZE_CURSOR); - - case SwingConstants.SOUTH_EAST: - return new Cursor(Cursor.SE_RESIZE_CURSOR); - } - return null; - } + public void mouseEntered(PInputEvent aEvent) { + if (!cursorPushed) { + aEvent.pushCursor(getCursorFor(((PBoundsLocator) getLocator()).getSide())); + cursorPushed = true; + } + } + + public void mouseExited(PInputEvent aEvent) { + PPickPath focus = aEvent.getInputManager().getMouseFocus(); + if (cursorPushed) { + if (focus == null || focus.getPickedNode() != PBoundsHandle.this) { + aEvent.popCursor(); + cursorPushed = false; + } + } + } + + public void mouseReleased(PInputEvent event) { + if (cursorPushed) { + event.popCursor(); + cursorPushed = false; + } + } + }; + addInputEventListener(handleCursorHandler); + } + + /** + * Return the event handler that is responsible for setting the mouse cursor + * when it enters/exits this handle. + */ + public PBasicInputEventHandler getHandleCursorEventHandler() { + return handleCursorHandler; + } + + public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + l.getNode().startResizeBounds(); + } + + public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + + PNode n = l.getNode(); + PBounds b = n.getBounds(); + + PNode parent = getParent(); + if (parent != n && parent instanceof PCamera) { + ((PCamera) parent).localToView(aLocalDimension); + } + + localToGlobal(aLocalDimension); + n.globalToLocal(aLocalDimension); + + double dx = aLocalDimension.getWidth(); + double dy = aLocalDimension.getHeight(); + + switch (l.getSide()) { + case SwingConstants.NORTH: + b.setRect(b.x, b.y + dy, b.width, b.height - dy); + break; + + case SwingConstants.SOUTH: + b.setRect(b.x, b.y, b.width, b.height + dy); + break; + + case SwingConstants.EAST: + b.setRect(b.x, b.y, b.width + dx, b.height); + break; + + case SwingConstants.WEST: + b.setRect(b.x + dx, b.y, b.width - dx, b.height); + break; + + case SwingConstants.NORTH_WEST: + b.setRect(b.x + dx, b.y + dy, b.width - dx, b.height - dy); + break; + + case SwingConstants.SOUTH_WEST: + b.setRect(b.x + dx, b.y, b.width - dx, b.height + dy); + break; + + case SwingConstants.NORTH_EAST: + b.setRect(b.x, b.y + dy, b.width + dx, b.height - dy); + break; + + case SwingConstants.SOUTH_EAST: + b.setRect(b.x, b.y, b.width + dx, b.height + dy); + break; + } + + boolean flipX = false; + boolean flipY = false; + + if (b.width < 0) { + flipX = true; + b.width = -b.width; + b.x -= b.width; + } + + if (b.height < 0) { + flipY = true; + b.height = -b.height; + b.y -= b.height; + } + + if (flipX || flipY) { + flipSiblingBoundsHandles(flipX, flipY); + } + + n.setBounds(b); + } + + public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + l.getNode().endResizeBounds(); + } + + public void flipSiblingBoundsHandles(boolean flipX, boolean flipY) { + Iterator i = getParent().getChildrenIterator(); + while (i.hasNext()) { + Object each = i.next(); + if (each instanceof PBoundsHandle) { + ((PBoundsHandle) each).flipHandleIfNeeded(flipX, flipY); + } + } + } + + public void flipHandleIfNeeded(boolean flipX, boolean flipY) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + + if (flipX || flipY) { + switch (l.getSide()) { + case SwingConstants.NORTH: { + if (flipY) { + l.setSide(SwingConstants.SOUTH); + } + break; + } + + case SwingConstants.SOUTH: { + if (flipY) { + l.setSide(SwingConstants.NORTH); + } + break; + } + + case SwingConstants.EAST: { + if (flipX) { + l.setSide(SwingConstants.WEST); + } + break; + } + + case SwingConstants.WEST: { + if (flipX) { + l.setSide(SwingConstants.EAST); + } + break; + } + + case SwingConstants.NORTH_WEST: { + if (flipX && flipY) { + l.setSide(SwingConstants.SOUTH_EAST); + } + else if (flipX) { + l.setSide(SwingConstants.NORTH_EAST); + } + else if (flipY) { + l.setSide(SwingConstants.SOUTH_WEST); + } + + break; + } + + case SwingConstants.SOUTH_WEST: { + if (flipX && flipY) { + l.setSide(SwingConstants.NORTH_EAST); + } + else if (flipX) { + l.setSide(SwingConstants.SOUTH_EAST); + } + else if (flipY) { + l.setSide(SwingConstants.NORTH_WEST); + } + break; + } + + case SwingConstants.NORTH_EAST: { + if (flipX && flipY) { + l.setSide(SwingConstants.SOUTH_WEST); + } + else if (flipX) { + l.setSide(SwingConstants.NORTH_WEST); + } + else if (flipY) { + l.setSide(SwingConstants.SOUTH_EAST); + } + break; + } + + case SwingConstants.SOUTH_EAST: { + if (flipX && flipY) { + l.setSide(SwingConstants.NORTH_WEST); + } + else if (flipX) { + l.setSide(SwingConstants.SOUTH_WEST); + } + else if (flipY) { + l.setSide(SwingConstants.NORTH_EAST); + } + break; + } + } + } + + // reset locator to update layout + setLocator(l); + } + + public Cursor getCursorFor(int side) { + switch (side) { + case SwingConstants.NORTH: + return new Cursor(Cursor.N_RESIZE_CURSOR); + + case SwingConstants.SOUTH: + return new Cursor(Cursor.S_RESIZE_CURSOR); + + case SwingConstants.EAST: + return new Cursor(Cursor.E_RESIZE_CURSOR); + + case SwingConstants.WEST: + return new Cursor(Cursor.W_RESIZE_CURSOR); + + case SwingConstants.NORTH_WEST: + return new Cursor(Cursor.NW_RESIZE_CURSOR); + + case SwingConstants.SOUTH_WEST: + return new Cursor(Cursor.SW_RESIZE_CURSOR); + + case SwingConstants.NORTH_EAST: + return new Cursor(Cursor.NE_RESIZE_CURSOR); + + case SwingConstants.SOUTH_EAST: + return new Cursor(Cursor.SE_RESIZE_CURSOR); + } + return null; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/handles/PHandle.java b/extras/src/main/java/edu/umd/cs/piccolox/handles/PHandle.java index 8f2a2c7..a42fba6 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/handles/PHandle.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/handles/PHandle.java @@ -51,170 +51,174 @@ import edu.umd.cs.piccolox.util.PNodeLocator; /** - * PHandle is used to modify some aspect of Piccolo when it - * is dragged. Each handle has a PLocator that it uses to automatically position - * itself. See PBoundsHandle for an example of a handle that resizes the bounds - * of another node. - *

+ * PHandle is used to modify some aspect of Piccolo when it is dragged. + * Each handle has a PLocator that it uses to automatically position itself. See + * PBoundsHandle for an example of a handle that resizes the bounds of another + * node. + * * @version 1.0 * @author Jesse Grosjean */ public class PHandle extends PPath { - public static float DEFAULT_HANDLE_SIZE = 8; - public static Shape DEFAULT_HANDLE_SHAPE = new Ellipse2D.Float(0f, 0f, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); - public static Color DEFAULT_COLOR = Color.white; - - private PLocator locator; - private transient PDragSequenceEventHandler handleDragger; + public static float DEFAULT_HANDLE_SIZE = 8; + public static Shape DEFAULT_HANDLE_SHAPE = new Ellipse2D.Float(0f, 0f, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); + public static Color DEFAULT_COLOR = Color.white; - /** - * Construct a new handle that will use the given locator - * to locate itself on its parent node. - */ - public PHandle(PLocator aLocator) { - super(DEFAULT_HANDLE_SHAPE); - locator = aLocator; - setPaint(DEFAULT_COLOR); - installHandleEventHandlers(); - } + private PLocator locator; + private transient PDragSequenceEventHandler handleDragger; - protected void installHandleEventHandlers() { - handleDragger = new PDragSequenceEventHandler() { - protected void startDrag(PInputEvent event) { - super.startDrag(event); - startHandleDrag(event.getPositionRelativeTo(PHandle.this), event); - } - protected void drag(PInputEvent event) { - super.drag(event); - PDimension aDelta = event.getDeltaRelativeTo(PHandle.this); - if (aDelta.getWidth() != 0 || aDelta.getHeight() != 0) { - dragHandle(aDelta, event); - } - } - protected void endDrag(PInputEvent event) { - super.endDrag(event); - endHandleDrag(event.getPositionRelativeTo(PHandle.this), event); - } - }; + /** + * Construct a new handle that will use the given locator to locate itself + * on its parent node. + */ + public PHandle(PLocator aLocator) { + super(DEFAULT_HANDLE_SHAPE); + locator = aLocator; + setPaint(DEFAULT_COLOR); + installHandleEventHandlers(); + } - addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - relocateHandle(); - } - }); - - handleDragger.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); - handleDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); - handleDragger.getEventFilter().setAcceptsMouseEntered(false); - handleDragger.getEventFilter().setAcceptsMouseExited(false); - handleDragger.getEventFilter().setAcceptsMouseMoved(false); // no need for moved events for handle interaction, - // so reject them so we don't consume them - addInputEventListener(handleDragger); - } - - /** - * Return the event handler that is responsible for the drag handle - * interaction. - */ - public PDragSequenceEventHandler getHandleDraggerHandler() { - return handleDragger; - } + protected void installHandleEventHandlers() { + handleDragger = new PDragSequenceEventHandler() { + protected void startDrag(PInputEvent event) { + super.startDrag(event); + startHandleDrag(event.getPositionRelativeTo(PHandle.this), event); + } - /** - * Get the locator that this handle uses to position itself on its - * parent node. - */ - public PLocator getLocator() { - return locator; - } - - /** - * Set the locator that this handle uses to position itself on its - * parent node. - */ - public void setLocator(PLocator aLocator) { - locator = aLocator; - invalidatePaint(); - relocateHandle(); - } - - //**************************************************************** - // Handle Dragging - These are the methods the subclasses should - // normally override to give a handle unique behavior. - //**************************************************************** - - /** - * Override this method to get notified when the handle starts to get dragged. - */ - public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - } - - /** - * Override this method to get notified as the handle is dragged. - */ - public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { - } - - /** - * Override this method to get notified when the handle stops getting dragged. - */ - public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - } - - //**************************************************************** - // Layout - When a handle's parent's layout changes the handle - // invalidates its own layout and then repositions itself on its - // parents bounds using its locator to determine that new - // position. - //**************************************************************** - - public void setParent(PNode newParent) { - super.setParent(newParent); - relocateHandle(); - } - - public void parentBoundsChanged() { - relocateHandle(); - } - - /** - * Force this handle to relocate itself using its locator. - */ - public void relocateHandle() { - if (locator != null) { - PBounds b = getBoundsReference(); - Point2D aPoint = locator.locatePoint(null); - - if (locator instanceof PNodeLocator) { - PNode located = ((PNodeLocator)locator).getNode(); - PNode parent = getParent(); - - located.localToGlobal(aPoint); - globalToLocal(aPoint); - - if (parent != located && parent instanceof PCamera) { - ((PCamera)parent).viewToLocal(aPoint); - } - } - - double newCenterX = aPoint.getX(); - double newCenterY = aPoint.getY(); + protected void drag(PInputEvent event) { + super.drag(event); + PDimension aDelta = event.getDeltaRelativeTo(PHandle.this); + if (aDelta.getWidth() != 0 || aDelta.getHeight() != 0) { + dragHandle(aDelta, event); + } + } - if (newCenterX != b.getCenterX() || - newCenterY != b.getCenterY()) { - - centerBoundsOnPoint(newCenterX, newCenterY); - } - } - } - - //**************************************************************** - // Serialization - //**************************************************************** - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - installHandleEventHandlers(); - } + protected void endDrag(PInputEvent event) { + super.endDrag(event); + endHandleDrag(event.getPositionRelativeTo(PHandle.this), event); + } + }; + + addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + relocateHandle(); + } + }); + + handleDragger.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + handleDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); + handleDragger.getEventFilter().setAcceptsMouseEntered(false); + handleDragger.getEventFilter().setAcceptsMouseExited(false); + // no need for moved events for handle interaction, + handleDragger.getEventFilter().setAcceptsMouseMoved(false); + // so reject them so we don't consume them + addInputEventListener(handleDragger); + } + + /** + * Return the event handler that is responsible for the drag handle + * interaction. + */ + public PDragSequenceEventHandler getHandleDraggerHandler() { + return handleDragger; + } + + /** + * Get the locator that this handle uses to position itself on its parent + * node. + */ + public PLocator getLocator() { + return locator; + } + + /** + * Set the locator that this handle uses to position itself on its parent + * node. + */ + public void setLocator(PLocator aLocator) { + locator = aLocator; + invalidatePaint(); + relocateHandle(); + } + + // **************************************************************** + // Handle Dragging - These are the methods the subclasses should + // normally override to give a handle unique behavior. + // **************************************************************** + + /** + * Override this method to get notified when the handle starts to get + * dragged. + */ + public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + } + + /** + * Override this method to get notified as the handle is dragged. + */ + public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { + } + + /** + * Override this method to get notified when the handle stops getting + * dragged. + */ + public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + } + + // **************************************************************** + // Layout - When a handle's parent's layout changes the handle + // invalidates its own layout and then repositions itself on its + // parents bounds using its locator to determine that new + // position. + // **************************************************************** + + public void setParent(PNode newParent) { + super.setParent(newParent); + relocateHandle(); + } + + public void parentBoundsChanged() { + relocateHandle(); + } + + /** + * Force this handle to relocate itself using its locator. + */ + public void relocateHandle() { + if (locator != null) { + PBounds b = getBoundsReference(); + Point2D aPoint = locator.locatePoint(null); + + if (locator instanceof PNodeLocator) { + PNode located = ((PNodeLocator) locator).getNode(); + PNode parent = getParent(); + + located.localToGlobal(aPoint); + globalToLocal(aPoint); + + if (parent != located && parent instanceof PCamera) { + ((PCamera) parent).viewToLocal(aPoint); + } + } + + double newCenterX = aPoint.getX(); + double newCenterY = aPoint.getY(); + + if (newCenterX != b.getCenterX() || newCenterY != b.getCenterY()) { + + centerBoundsOnPoint(newCenterX, newCenterY); + } + } + } + + // **************************************************************** + // Serialization + // **************************************************************** + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + installHandleEventHandlers(); + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/handles/PStickyHandleManager.java b/extras/src/main/java/edu/umd/cs/piccolox/handles/PStickyHandleManager.java index a74c6be..8ff8774 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/handles/PStickyHandleManager.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/handles/PStickyHandleManager.java @@ -35,54 +35,54 @@ import edu.umd.cs.piccolo.util.PPickPath; public class PStickyHandleManager extends PNode { - - private PNode target; - private PCamera camera; - - public PStickyHandleManager(PCamera newCamera, PNode newTarget) { - setCameraTarget(newCamera, newTarget); - PBoundsHandle.addBoundsHandlesTo(this); - } - public void setCameraTarget(PCamera newCamera, PNode newTarget) { - camera = newCamera; - camera.addChild(this); - target = newTarget; - } - - public boolean setBounds(double x, double y, double width, double height) { - PBounds b = new PBounds(x, y, width, height); - camera.localToGlobal(b); - camera.localToView(b); - target.globalToLocal(b); - target.setBounds(b); - return super.setBounds(x, y, width, height); - } - - protected boolean getBoundsVolatile() { - return true; - } + private PNode target; + private PCamera camera; - public PBounds getBoundsReference() { - PBounds targetBounds = target.getFullBounds(); - camera.viewToLocal(targetBounds); - camera.globalToLocal(targetBounds); - PBounds bounds = super.getBoundsReference(); - bounds.setRect(targetBounds); - return super.getBoundsReference(); - } + public PStickyHandleManager(PCamera newCamera, PNode newTarget) { + setCameraTarget(newCamera, newTarget); + PBoundsHandle.addBoundsHandlesTo(this); + } - public void startResizeBounds() { - super.startResizeBounds(); - target.startResizeBounds(); - } + public void setCameraTarget(PCamera newCamera, PNode newTarget) { + camera = newCamera; + camera.addChild(this); + target = newTarget; + } - public void endResizeBounds() { - super.endResizeBounds(); - target.endResizeBounds(); - } + public boolean setBounds(double x, double y, double width, double height) { + PBounds b = new PBounds(x, y, width, height); + camera.localToGlobal(b); + camera.localToView(b); + target.globalToLocal(b); + target.setBounds(b); + return super.setBounds(x, y, width, height); + } - public boolean pickAfterChildren(PPickPath pickPath) { - return false; - } + protected boolean getBoundsVolatile() { + return true; + } + + public PBounds getBoundsReference() { + PBounds targetBounds = target.getFullBounds(); + camera.viewToLocal(targetBounds); + camera.globalToLocal(targetBounds); + PBounds bounds = super.getBoundsReference(); + bounds.setRect(targetBounds); + return super.getBoundsReference(); + } + + public void startResizeBounds() { + super.startResizeBounds(); + target.startResizeBounds(); + } + + public void endResizeBounds() { + super.endResizeBounds(); + target.endResizeBounds(); + } + + public boolean pickAfterChildren(PPickPath pickPath) { + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/P3DRect.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/P3DRect.java index b810656..37e6c18 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/P3DRect.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/P3DRect.java @@ -36,134 +36,137 @@ import edu.umd.cs.piccolox.*; /** - * This is a simple node that draws a "3D" rectangle within the bounds of the node. - * Drawing a 3D rectangle in a zooming environment is a little tricky because - * if you just use the regular (Java2D) 3D rectangle, the 3D borders get scaled, - * and that is ugly. This version always draws the 3D border at fixed 2 pixel width. + * This is a simple node that draws a "3D" rectangle within the bounds of the + * node. Drawing a 3D rectangle in a zooming environment is a little tricky + * because if you just use the regular (Java2D) 3D rectangle, the 3D borders get + * scaled, and that is ugly. This version always draws the 3D border at fixed 2 + * pixel width. * * @author Ben Bederson */ public class P3DRect extends PNode { - private Color topLeftOuterColor; - private Color topLeftInnerColor; - private Color bottomRightInnerColor; - private Color bottomRightOuterColor; - private GeneralPath path; - private Stroke stroke; - private boolean raised; - - public P3DRect() { - raised = true; - stroke = new BasicStroke(0); - path = new GeneralPath(); - } - - public P3DRect(Rectangle2D bounds) { - this(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); - } - - public P3DRect(double x, double y, double width, double height) { - this(); - setBounds(x, y, width, height); - } - - public void setRaised(boolean raised) { - this.raised = raised; - setPaint(getPaint()); - } - - public boolean getRaised() { - return raised; - } - - protected void paint(PPaintContext paintContext) { - Graphics2D g2 = paintContext.getGraphics(); - - double x = getX(); - double y = getY(); - double width = getWidth(); - double height = getHeight(); - double magX = g2.getTransform().getScaleX(); - double magY = g2.getTransform().getScaleY(); - double dx = (float)(1.0 / magX); - double dy = (float)(1.0 / magY); - PBounds bounds = getBounds(); - - g2.setPaint(getPaint()); - g2.fill(bounds); - g2.setStroke(stroke); + private Color topLeftOuterColor; + private Color topLeftInnerColor; + private Color bottomRightInnerColor; + private Color bottomRightOuterColor; + private GeneralPath path; + private Stroke stroke; + private boolean raised; - path.reset(); - path.moveTo((float)(x+width), (float)y); - path.lineTo((float)x, (float)y); - path.lineTo((float)x, (float)(y+height)); - g2.setPaint(topLeftOuterColor); - g2.draw(path); + public P3DRect() { + raised = true; + stroke = new BasicStroke(0); + path = new GeneralPath(); + } - path.reset(); - path.moveTo((float)(x+width), (float)(y+dy)); - path.lineTo((float)(x+dx), (float)(y+dy)); - path.lineTo((float)(x+dx), (float)(y+height)); - g2.setPaint(topLeftInnerColor); - g2.draw(path); + public P3DRect(Rectangle2D bounds) { + this(bounds.getX(), bounds.getY(), bounds.getWidth(), bounds.getHeight()); + } - path.reset(); - path.moveTo((float)(x+width), (float)(y)); - path.lineTo((float)(x+width), (float)(y+height)); - path.lineTo((float)(x), (float)(y+height)); - g2.setPaint(bottomRightOuterColor); - g2.draw(path); + public P3DRect(double x, double y, double width, double height) { + this(); + setBounds(x, y, width, height); + } - path.reset(); - path.moveTo((float)(x+width-dx), (float)(y+dy)); - path.lineTo((float)(x+width-dx), (float)(y+height-dy)); - path.lineTo((float)(x), (float)(y+height-dy)); - g2.setPaint(bottomRightInnerColor); - g2.draw(path); - } + public void setRaised(boolean raised) { + this.raised = raised; + setPaint(getPaint()); + } - public void setPaint(Paint newPaint) { - super.setPaint(newPaint); - - if (newPaint instanceof Color) { - Color color = (Color)newPaint; - - if (raised) { - topLeftOuterColor = color.brighter(); - topLeftInnerColor = topLeftOuterColor.brighter(); - bottomRightInnerColor = color.darker(); - bottomRightOuterColor = bottomRightInnerColor.darker(); - } else { - topLeftOuterColor = color.darker(); - topLeftInnerColor = topLeftOuterColor.darker(); - bottomRightInnerColor = color.brighter(); - bottomRightOuterColor = bottomRightInnerColor.brighter(); - } - } else { - topLeftOuterColor = null; - topLeftInnerColor = null; - bottomRightInnerColor = null; - bottomRightOuterColor = null; - } - } + public boolean getRaised() { + return raised; + } - public static void main(String[] args) { - new PFrame() { - public void initialize() { - getCanvas().setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); + protected void paint(PPaintContext paintContext) { + Graphics2D g2 = paintContext.getGraphics(); - P3DRect rect1 = new P3DRect(50, 50, 100, 100); - rect1.setPaint(new Color(239, 235, 222)); + double x = getX(); + double y = getY(); + double width = getWidth(); + double height = getHeight(); + double magX = g2.getTransform().getScaleX(); + double magY = g2.getTransform().getScaleY(); + double dx = (float) (1.0 / magX); + double dy = (float) (1.0 / magY); + PBounds bounds = getBounds(); - P3DRect rect2 = new P3DRect(50, 50, 100, 100); - rect2.setPaint(new Color(239, 235, 222)); - rect2.translate(110, 0); - rect2.setRaised(false); - - getCanvas().getLayer().addChild(rect1); - getCanvas().getLayer().addChild(rect2); - } - }; - } + g2.setPaint(getPaint()); + g2.fill(bounds); + g2.setStroke(stroke); + + path.reset(); + path.moveTo((float) (x + width), (float) y); + path.lineTo((float) x, (float) y); + path.lineTo((float) x, (float) (y + height)); + g2.setPaint(topLeftOuterColor); + g2.draw(path); + + path.reset(); + path.moveTo((float) (x + width), (float) (y + dy)); + path.lineTo((float) (x + dx), (float) (y + dy)); + path.lineTo((float) (x + dx), (float) (y + height)); + g2.setPaint(topLeftInnerColor); + g2.draw(path); + + path.reset(); + path.moveTo((float) (x + width), (float) (y)); + path.lineTo((float) (x + width), (float) (y + height)); + path.lineTo((float) (x), (float) (y + height)); + g2.setPaint(bottomRightOuterColor); + g2.draw(path); + + path.reset(); + path.moveTo((float) (x + width - dx), (float) (y + dy)); + path.lineTo((float) (x + width - dx), (float) (y + height - dy)); + path.lineTo((float) (x), (float) (y + height - dy)); + g2.setPaint(bottomRightInnerColor); + g2.draw(path); + } + + public void setPaint(Paint newPaint) { + super.setPaint(newPaint); + + if (newPaint instanceof Color) { + Color color = (Color) newPaint; + + if (raised) { + topLeftOuterColor = color.brighter(); + topLeftInnerColor = topLeftOuterColor.brighter(); + bottomRightInnerColor = color.darker(); + bottomRightOuterColor = bottomRightInnerColor.darker(); + } + else { + topLeftOuterColor = color.darker(); + topLeftInnerColor = topLeftOuterColor.darker(); + bottomRightInnerColor = color.brighter(); + bottomRightOuterColor = bottomRightInnerColor.brighter(); + } + } + else { + topLeftOuterColor = null; + topLeftInnerColor = null; + bottomRightInnerColor = null; + bottomRightOuterColor = null; + } + } + + public static void main(String[] args) { + new PFrame() { + public void initialize() { + getCanvas().setDefaultRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); + + P3DRect rect1 = new P3DRect(50, 50, 100, 100); + rect1.setPaint(new Color(239, 235, 222)); + + P3DRect rect2 = new P3DRect(50, 50, 100, 100); + rect2.setPaint(new Color(239, 235, 222)); + rect2.translate(110, 0); + rect2.setRaised(false); + + getCanvas().getLayer().addChild(rect1); + getCanvas().getLayer().addChild(rect2); + } + }; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PCacheCamera.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PCacheCamera.java index 5697cb7..e741475 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PCacheCamera.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PCacheCamera.java @@ -20,146 +20,157 @@ import edu.umd.cs.piccolo.util.PUtil; /** - * An extension to PCamera that provides a fast image based animationToCenterBounds method + * An extension to PCamera that provides a fast image based + * animationToCenterBounds method * * @author Lance Good */ public class PCacheCamera extends PCamera { - - private BufferedImage paintBuffer; - private boolean imageAnimate; - private PBounds imageAnimateBounds; - - /** - * Get the buffer used to provide fast image based animation - */ - protected BufferedImage getPaintBuffer() { - PBounds fRef = getFullBoundsReference(); - if (paintBuffer == null || paintBuffer.getWidth() < fRef.getWidth() || paintBuffer.getHeight() < fRef.getHeight()) { - paintBuffer = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration().createCompatibleImage((int)Math.ceil(fRef.getWidth()),(int)Math.ceil(fRef.getHeight())); - } - return paintBuffer; - } - - /** - * Caches the information necessary to animate from the current view bounds to the - * specified centerBounds - */ - private AffineTransform cacheViewBounds(Rectangle2D centerBounds, boolean scaleToFit) { - PBounds viewBounds = getViewBounds(); - - // Initialize the image to the union of the current and destination bounds - PBounds imageBounds = new PBounds(viewBounds); - imageBounds.add(centerBounds); - animateViewToCenterBounds(imageBounds,scaleToFit,0); + private BufferedImage paintBuffer; + private boolean imageAnimate; + private PBounds imageAnimateBounds; + + /** + * Get the buffer used to provide fast image based animation + */ + protected BufferedImage getPaintBuffer() { + PBounds fRef = getFullBoundsReference(); + // TODO eclipse formatting made this ugly + if (paintBuffer == null || paintBuffer.getWidth() < fRef.getWidth() + || paintBuffer.getHeight() < fRef.getHeight()) { + paintBuffer = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice() + .getDefaultConfiguration().createCompatibleImage((int) Math.ceil(fRef.getWidth()), + (int) Math.ceil(fRef.getHeight())); + } + return paintBuffer; + } + + /** + * Caches the information necessary to animate from the current view bounds + * to the specified centerBounds + */ + private AffineTransform cacheViewBounds(Rectangle2D centerBounds, boolean scaleToFit) { + PBounds viewBounds = getViewBounds(); + + // Initialize the image to the union of the current and destination + // bounds + PBounds imageBounds = new PBounds(viewBounds); + imageBounds.add(centerBounds); + + animateViewToCenterBounds(imageBounds, scaleToFit, 0); imageAnimateBounds = getViewBounds(); - // Now create the actual cache image that we will use to animate fast - - BufferedImage buffer = getPaintBuffer(); - Paint fPaint = Color.white; - if (getPaint() != null) { - fPaint = getPaint(); - } - toImage(buffer,fPaint); + // Now create the actual cache image that we will use to animate fast - // Do this after the painting above! - imageAnimate = true; - - // Return the bounds to the previous viewbounds - animateViewToCenterBounds(viewBounds,scaleToFit,0); - - // The code below is just copied from animateViewToCenterBounds to create the - // correct transform to center the specified bounds - - PDimension delta = viewBounds.deltaRequiredToCenter(centerBounds); - PAffineTransform newTransform = getViewTransform(); - newTransform.translate(delta.width, delta.height); - - if (scaleToFit) { - double s = Math.min(viewBounds.getWidth() / centerBounds.getWidth(), viewBounds.getHeight() / centerBounds.getHeight()); - newTransform.scaleAboutPoint(s, centerBounds.getCenterX(), centerBounds.getCenterY()); - } - - return newTransform; - } - - /** - * Turns off the fast image animation and does any other applicable cleanup - */ - private void clearViewCache() { - imageAnimate = false; - imageAnimateBounds = null; - } - - /** - * Mimics the standard animateViewToCenterBounds but uses a cached image for performance - * rather than re-rendering the scene at each step - */ - public PTransformActivity animateStaticViewToCenterBoundsFast(Rectangle2D centerBounds, boolean shouldScaleToFit, long duration) { - if (duration == 0) { - return animateViewToCenterBounds(centerBounds,shouldScaleToFit,duration); - } - - AffineTransform newViewTransform = cacheViewBounds(centerBounds,shouldScaleToFit); + BufferedImage buffer = getPaintBuffer(); + Paint fPaint = Color.white; + if (getPaint() != null) { + fPaint = getPaint(); + } + toImage(buffer, fPaint); - return animateStaticViewToTransformFast(newViewTransform, duration); - } + // Do this after the painting above! + imageAnimate = true; - /** - * This copies the behavior of the standard animateViewToTransform but clears the cache - * when it is done - */ - protected PTransformActivity animateStaticViewToTransformFast(AffineTransform destination, long duration) { - if (duration == 0) { - setViewTransform(destination); - return null; - } - - PTransformActivity.Target t = new PTransformActivity.Target() { - public void setTransform(AffineTransform aTransform) { - PCacheCamera.this.setViewTransform(aTransform); - } - public void getSourceMatrix(double[] aSource) { - getViewTransformReference().getMatrix(aSource); - } - }; - - PTransformActivity ta = new PTransformActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destination) { + // Return the bounds to the previous viewbounds + animateViewToCenterBounds(viewBounds, scaleToFit, 0); + + // The code below is just copied from animateViewToCenterBounds to + // create the correct transform to center the specified bounds + + PDimension delta = viewBounds.deltaRequiredToCenter(centerBounds); + PAffineTransform newTransform = getViewTransform(); + newTransform.translate(delta.width, delta.height); + + if (scaleToFit) { + double s = Math.min(viewBounds.getWidth() / centerBounds.getWidth(), viewBounds.getHeight() + / centerBounds.getHeight()); + newTransform.scaleAboutPoint(s, centerBounds.getCenterX(), centerBounds.getCenterY()); + } + + return newTransform; + } + + /** + * Turns off the fast image animation and does any other applicable cleanup + */ + private void clearViewCache() { + imageAnimate = false; + imageAnimateBounds = null; + } + + /** + * Mimics the standard animateViewToCenterBounds but uses a cached image for + * performance rather than re-rendering the scene at each step + */ + public PTransformActivity animateStaticViewToCenterBoundsFast(Rectangle2D centerBounds, boolean shouldScaleToFit, + long duration) { + if (duration == 0) { + return animateViewToCenterBounds(centerBounds, shouldScaleToFit, duration); + } + + AffineTransform newViewTransform = cacheViewBounds(centerBounds, shouldScaleToFit); + + return animateStaticViewToTransformFast(newViewTransform, duration); + } + + /** + * This copies the behavior of the standard animateViewToTransform but + * clears the cache when it is done + */ + protected PTransformActivity animateStaticViewToTransformFast(AffineTransform destination, long duration) { + if (duration == 0) { + setViewTransform(destination); + return null; + } + + PTransformActivity.Target t = new PTransformActivity.Target() { + public void setTransform(AffineTransform aTransform) { + PCacheCamera.this.setViewTransform(aTransform); + } + + public void getSourceMatrix(double[] aSource) { + getViewTransformReference().getMatrix(aSource); + } + }; + + PTransformActivity ta = new PTransformActivity(duration, PUtil.DEFAULT_ACTIVITY_STEP_RATE, t, destination) { protected void activityFinished() { clearViewCache(); repaint(); super.activityFinished(); } - }; - - PRoot r = getRoot(); - if (r != null) { - r.getActivityScheduler().addActivity(ta); - } - - return ta; - } - - /** - * Overrides the camera's full paint method to do the fast rendering when possible - */ + }; + + PRoot r = getRoot(); + if (r != null) { + r.getActivityScheduler().addActivity(ta); + } + + return ta; + } + + /** + * Overrides the camera's full paint method to do the fast rendering when + * possible + */ public void fullPaint(PPaintContext paintContext) { - if (imageAnimate) { - PBounds fRef = getFullBoundsReference(); - PBounds viewBounds = getViewBounds(); - double scale = getFullBoundsReference().getWidth()/imageAnimateBounds.getWidth(); - double xOffset = (viewBounds.getX()-imageAnimateBounds.getX())*scale; - double yOffset = (viewBounds.getY()-imageAnimateBounds.getY())*scale; - double scaleW = viewBounds.getWidth()*scale; - double scaleH = viewBounds.getHeight()*scale; - paintContext.getGraphics().drawImage(paintBuffer,0,0,(int)Math.ceil(fRef.getWidth()),(int)Math.ceil(fRef.getHeight()), - (int)Math.floor(xOffset),(int)Math.floor(yOffset),(int)Math.ceil(xOffset+scaleW),(int)Math.ceil(yOffset+scaleH),null); - } - else { - super.fullPaint(paintContext); - } + if (imageAnimate) { + PBounds fRef = getFullBoundsReference(); + PBounds viewBounds = getViewBounds(); + double scale = getFullBoundsReference().getWidth() / imageAnimateBounds.getWidth(); + double xOffset = (viewBounds.getX() - imageAnimateBounds.getX()) * scale; + double yOffset = (viewBounds.getY() - imageAnimateBounds.getY()) * scale; + double scaleW = viewBounds.getWidth() * scale; + double scaleH = viewBounds.getHeight() * scale; + paintContext.getGraphics().drawImage(paintBuffer, 0, 0, (int) Math.ceil(fRef.getWidth()), + (int) Math.ceil(fRef.getHeight()), (int) Math.floor(xOffset), (int) Math.floor(yOffset), + (int) Math.ceil(xOffset + scaleW), (int) Math.ceil(yOffset + scaleH), null); + } + else { + super.fullPaint(paintContext); + } } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PClip.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PClip.java index 37300a3..f077b80 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PClip.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PClip.java @@ -40,78 +40,80 @@ import edu.umd.cs.piccolo.util.PPickPath; /** - * PClip is a simple node that applies a clip before rendering or picking its - * children. PClip is a subclass of PPath, the clip applies is the GeneralPath wrapped - * by its super class. See piccolo/examples ClipExample. - *

+ * PClip is a simple node that applies a clip before rendering or picking + * its children. PClip is a subclass of PPath, the clip applies is the + * GeneralPath wrapped by its super class. See piccolo/examples ClipExample. + * * @version 1.0 - * @author Jesse Grosjean + * @author Jesse Grosjean */ public class PClip extends PPath { - public PBounds computeFullBounds(PBounds dstBounds) { - if (dstBounds == null) dstBounds = new PBounds(); - dstBounds.reset(); - dstBounds.add(getBoundsReference()); - localToParent(dstBounds); - return dstBounds; - } + public PBounds computeFullBounds(PBounds dstBounds) { + if (dstBounds == null) + dstBounds = new PBounds(); + dstBounds.reset(); + dstBounds.add(getBoundsReference()); + localToParent(dstBounds); + return dstBounds; + } - public void repaintFrom(PBounds localBounds, PNode childOrThis) { - if (childOrThis != this) { - Rectangle2D.intersect(getBoundsReference(), localBounds, localBounds); - super.repaintFrom(localBounds, childOrThis); - } else { - super.repaintFrom(localBounds, childOrThis); - } - } + public void repaintFrom(PBounds localBounds, PNode childOrThis) { + if (childOrThis != this) { + Rectangle2D.intersect(getBoundsReference(), localBounds, localBounds); + super.repaintFrom(localBounds, childOrThis); + } + else { + super.repaintFrom(localBounds, childOrThis); + } + } - protected void paint(PPaintContext paintContext) { - Paint p = getPaint(); - if (p != null) { - Graphics2D g2 = paintContext.getGraphics(); - g2.setPaint(p); - g2.fill(getPathReference()); - } - paintContext.pushClip(getPathReference()); - } - - protected void paintAfterChildren(PPaintContext paintContext) { - paintContext.popClip(getPathReference()); - if (getStroke() != null && getStrokePaint() != null) { - Graphics2D g2 = paintContext.getGraphics(); - g2.setPaint(getStrokePaint()); - g2.setStroke(getStroke()); - g2.draw(getPathReference()); - } - } - - public boolean fullPick(PPickPath pickPath) { - if (getPickable() && fullIntersects(pickPath.getPickBounds())) { - pickPath.pushNode(this); - pickPath.pushTransform(getTransformReference(false)); - - if (pick(pickPath)) { - return true; - } - - if (getChildrenPickable() && getPathReference().intersects(pickPath.getPickBounds())) { - int count = getChildrenCount(); - for (int i = count - 1; i >= 0; i--) { - PNode each = getChild(i); - if (each.fullPick(pickPath)) - return true; - } - } + protected void paint(PPaintContext paintContext) { + Paint p = getPaint(); + if (p != null) { + Graphics2D g2 = paintContext.getGraphics(); + g2.setPaint(p); + g2.fill(getPathReference()); + } + paintContext.pushClip(getPathReference()); + } - if (pickAfterChildren(pickPath)) { - return true; - } + protected void paintAfterChildren(PPaintContext paintContext) { + paintContext.popClip(getPathReference()); + if (getStroke() != null && getStrokePaint() != null) { + Graphics2D g2 = paintContext.getGraphics(); + g2.setPaint(getStrokePaint()); + g2.setStroke(getStroke()); + g2.draw(getPathReference()); + } + } - pickPath.popTransform(getTransformReference(false)); - pickPath.popNode(this); - } + public boolean fullPick(PPickPath pickPath) { + if (getPickable() && fullIntersects(pickPath.getPickBounds())) { + pickPath.pushNode(this); + pickPath.pushTransform(getTransformReference(false)); - return false; - } + if (pick(pickPath)) { + return true; + } + + if (getChildrenPickable() && getPathReference().intersects(pickPath.getPickBounds())) { + int count = getChildrenCount(); + for (int i = count - 1; i >= 0; i--) { + PNode each = getChild(i); + if (each.fullPick(pickPath)) + return true; + } + } + + if (pickAfterChildren(pickPath)) { + return true; + } + + pickPath.popTransform(getTransformReference(false)); + pickPath.popNode(this); + } + + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PComposite.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PComposite.java index 6079c2e..a9f616b 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PComposite.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PComposite.java @@ -33,61 +33,54 @@ import edu.umd.cs.piccolo.util.PPickPath; /** - * PComposite is a simple node that makes a group of nodes appear to - * be a single node when picking and interacting. There is also partial - * (commented out) support for resizing the child node to fit when this - * nodes bounds are set. - *

+ * PComposite is a simple node that makes a group of nodes appear to be a + * single node when picking and interacting. There is also partial (commented + * out) support for resizing the child node to fit when this nodes bounds are + * set. + * * @version 1.0 * @author Jesse Grosjean */ public class PComposite extends PNode { - /* - public boolean setBounds(double x, double y, double width, double height) { - PBounds childBounds = getUnionOfChildrenBounds(null); - - double dx = x - childBounds.x; - double dy = y - childBounds.y; - double sx = width / childBounds.width; - double sy = height / childBounds.height; - double scale = sx > sy ? sx : sy; - - Iterator i = getChildrenIterator(); - while (i.hasNext()) { - PNode each = (PNode) i.next(); - each.offset(dx, dy); - each.scaleAboutPoint(scale, each.getBoundsReference().x, each.getBoundsReference().y); - } - - return super.setBounds(x, y, width, height); - } - - protected void layoutChildren() { - getBoundsReference().setRect(getUnionOfChildrenBounds(null)); - } - */ - - /** - * Return true if this node or any pickable descendends are picked. If - * a pick occurs the pickPath is modified so that this node is always returned - * as the picked node, event if it was a decendent node that initialy reported the - * pick. - */ - public boolean fullPick(PPickPath pickPath) { - if (super.fullPick(pickPath)) { - PNode picked = pickPath.getPickedNode(); - - // this code won't work with internal cameras, because it doesn't pop - // the cameras view transform. - while (picked != this) { - pickPath.popTransform(picked.getTransformReference(false)); - pickPath.popNode(picked); - picked = pickPath.getPickedNode(); - } - - return true; - } - return false; - } + /* + * public boolean setBounds(double x, double y, double width, double height) + * { PBounds childBounds = getUnionOfChildrenBounds(null); + * + * double dx = x - childBounds.x; double dy = y - childBounds.y; double sx = + * width / childBounds.width; double sy = height / childBounds.height; + * double scale = sx > sy ? sx : sy; + * + * Iterator i = getChildrenIterator(); while (i.hasNext()) { PNode each = + * (PNode) i.next(); each.offset(dx, dy); each.scaleAboutPoint(scale, + * each.getBoundsReference().x, each.getBoundsReference().y); } + * + * return super.setBounds(x, y, width, height); } + * + * protected void layoutChildren() { + * getBoundsReference().setRect(getUnionOfChildrenBounds(null)); } + */ + + /** + * Return true if this node or any pickable descendends are picked. If a + * pick occurs the pickPath is modified so that this node is always returned + * as the picked node, event if it was a decendent node that initialy + * reported the pick. + */ + public boolean fullPick(PPickPath pickPath) { + if (super.fullPick(pickPath)) { + PNode picked = pickPath.getPickedNode(); + + // this code won't work with internal cameras, because it doesn't + // pop the cameras view transform. + while (picked != this) { + pickPath.popTransform(picked.getTransformReference(false)); + pickPath.popNode(picked); + picked = pickPath.getPickedNode(); + } + + return true; + } + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLens.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLens.java index 249d7ea..5ae630a 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLens.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLens.java @@ -41,88 +41,94 @@ import edu.umd.cs.piccolo.nodes.PPath; /** - * PLens is a simple default lens implementation for Piccolo. See piccolo/examples - * LensExample for one possible use of this lens. Lens's are often application - * specific, it may be easiest to study this code, and then implement your own custom - * lens using the general principles illustrated here. - *

- * The basic design here is to add a PCamera as the child of a Pnode (the lens node). The camera is - * the viewing part of the lens, and the node is the title bar that can be used to - * move the lens around. Users of this lens will probably want to set up some lens - * specific event handler and attach it to the camera. - *

- * A lens also needs a layer that it will look at (it should not be the same as the layer - * that it's added to because then it will draw itself in a recursive loop. Last of all - * the PLens will need to be added to the PCanvas layer (so that it can be seen - * by the main camera). - *

+ * PLens is a simple default lens implementation for Piccolo. See + * piccolo/examples LensExample for one possible use of this lens. Lens's are + * often application specific, it may be easiest to study this code, and then + * implement your own custom lens using the general principles illustrated here. + *

+ * The basic design here is to add a PCamera as the child of a Pnode (the lens + * node). The camera is the viewing part of the lens, and the node is the title + * bar that can be used to move the lens around. Users of this lens will + * probably want to set up some lens specific event handler and attach it to the + * camera. + *

+ *

+ * A lens also needs a layer that it will look at (it should not be the same as + * the layer that it's added to because then it will draw itself in a recursive + * loop. Last of all the PLens will need to be added to the PCanvas layer (so + * that it can be seen by the main camera). + *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PLens extends PNode { - public static double LENS_DRAGBAR_HEIGHT = 20; - public static Paint DEFAULT_DRAGBAR_PAINT = Color.DARK_GRAY; - public static Paint DEFAULT_LENS_PAINT = Color.LIGHT_GRAY; - - private PPath dragBar; - private PCamera camera; - private PDragEventHandler lensDragger; - - public PLens() { - dragBar = PPath.createRectangle(0, 0, 100, 100); // Drag bar gets resized to fit the available space, so any rectangle will do here - dragBar.setPaint(DEFAULT_DRAGBAR_PAINT); - dragBar.setPickable(false); // This forces drag events to percolate up to PLens object - addChild(dragBar); - - camera = new PCamera(); - camera.setPaint(DEFAULT_LENS_PAINT); - addChild(camera); - - // create an event handler to drag the lens around. Note that this event - // handler consumes events in case another conflicting event handler has been - // installed higher up in the heirarchy. - lensDragger = new PDragEventHandler(); - lensDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); - addInputEventListener(lensDragger); + public static double LENS_DRAGBAR_HEIGHT = 20; + public static Paint DEFAULT_DRAGBAR_PAINT = Color.DARK_GRAY; + public static Paint DEFAULT_LENS_PAINT = Color.LIGHT_GRAY; - // When this PLens is dragged around adjust the cameras view transform. - addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - camera.setViewTransform(getInverseTransform()); - } - }); - } - - public PLens(PLayer layer) { - this(); - addLayer(0, layer); - } - - public PCamera getCamera() { - return camera; - } - - public PPath getDragBar() { - return dragBar; - } + private PPath dragBar; + private PCamera camera; + private PDragEventHandler lensDragger; - public PDragEventHandler getLensDraggerHandler() { - return lensDragger; - } - - public void addLayer(int index, PLayer layer) { - camera.addLayer(index, layer); - } - - public void removeLayer(PLayer layer) { - camera.removeLayer(layer); - } - - // when the lens is resized this method gives us a chance to layout the lenses - // camera child appropriately. - protected void layoutChildren() { - dragBar.setPathToRectangle((float)getX(), (float)getY(), (float)getWidth(), (float)LENS_DRAGBAR_HEIGHT); - camera.setBounds(getX(), getY() + LENS_DRAGBAR_HEIGHT, getWidth(), getHeight() - LENS_DRAGBAR_HEIGHT); - } + public PLens() { + // Drag bar gets resized to fit the available space, so any rectangle + // will do here + dragBar = PPath.createRectangle(0, 0, 100, 100); + dragBar.setPaint(DEFAULT_DRAGBAR_PAINT); + // This forces drag events to percolate up to PLens object + dragBar.setPickable(false); + addChild(dragBar); + + camera = new PCamera(); + camera.setPaint(DEFAULT_LENS_PAINT); + addChild(camera); + + // create an event handler to drag the lens around. Note that this event + // handler consumes events in case another conflicting event handler has + // been installed higher up in the heirarchy. + lensDragger = new PDragEventHandler(); + lensDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); + addInputEventListener(lensDragger); + + // When this PLens is dragged around adjust the cameras view transform. + addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + camera.setViewTransform(getInverseTransform()); + } + }); + } + + public PLens(PLayer layer) { + this(); + addLayer(0, layer); + } + + public PCamera getCamera() { + return camera; + } + + public PPath getDragBar() { + return dragBar; + } + + public PDragEventHandler getLensDraggerHandler() { + return lensDragger; + } + + public void addLayer(int index, PLayer layer) { + camera.addLayer(index, layer); + } + + public void removeLayer(PLayer layer) { + camera.removeLayer(layer); + } + + // when the lens is resized this method gives us a chance to layout the + // lenses camera child appropriately. + protected void layoutChildren() { + dragBar.setPathToRectangle((float) getX(), (float) getY(), (float) getWidth(), (float) LENS_DRAGBAR_HEIGHT); + camera.setBounds(getX(), getY() + LENS_DRAGBAR_HEIGHT, getWidth(), getHeight() - LENS_DRAGBAR_HEIGHT); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLine.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLine.java index 8e682c3..efdfa85 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLine.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PLine.java @@ -18,138 +18,142 @@ import edu.umd.cs.piccolo.util.PUtil; import edu.umd.cs.piccolox.util.LineShape; -/** - * PLine a class for drawing multisegment lines. - * Submitted by Hallvard Traetteberg. +/** + * PLine a class for drawing multisegment lines. Submitted by Hallvard + * Traetteberg. */ -public class PLine extends PNode { - - private static final PAffineTransform TEMP_TRANSFORM = new PAffineTransform(); - private static final BasicStroke DEFAULT_STROKE = new BasicStroke(1.0f); - private static final Color DEFAULT_STROKE_PAINT = Color.black; - - private transient LineShape line; - private transient Stroke stroke; - private Paint strokePaint; +public class PLine extends PNode { - public PLine(LineShape line) { - strokePaint = DEFAULT_STROKE_PAINT; - stroke = DEFAULT_STROKE; + private static final PAffineTransform TEMP_TRANSFORM = new PAffineTransform(); + private static final BasicStroke DEFAULT_STROKE = new BasicStroke(1.0f); + private static final Color DEFAULT_STROKE_PAINT = Color.black; + + private transient LineShape line; + private transient Stroke stroke; + private Paint strokePaint; + + public PLine(LineShape line) { + strokePaint = DEFAULT_STROKE_PAINT; + stroke = DEFAULT_STROKE; if (line == null) { line = new LineShape(null); } - this.line = line; - } + this.line = line; + } public PLine() { this(null); } - public PLine(LineShape line, Stroke aStroke) { - this(line); - stroke = aStroke; - } - - //**************************************************************** - // Stroke - //**************************************************************** - - public Paint getStrokePaint() { - return strokePaint; - } + public PLine(LineShape line, Stroke aStroke) { + this(line); + stroke = aStroke; + } - public void setStrokePaint(Paint aPaint) { - Paint old = strokePaint; - strokePaint = aPaint; - invalidatePaint(); - firePropertyChange(PPath.PROPERTY_CODE_STROKE_PAINT, PPath.PROPERTY_STROKE_PAINT, old, strokePaint); - } - - public Stroke getStroke() { - return stroke; - } + // **************************************************************** + // Stroke + // **************************************************************** - public void setStroke(Stroke aStroke) { - Stroke old = stroke; - stroke = aStroke; - updateBoundsFromLine(); - invalidatePaint(); - firePropertyChange(PPath.PROPERTY_CODE_STROKE, PPath.PROPERTY_STROKE, old, stroke); - } - - //**************************************************************** - // Bounds - //**************************************************************** + public Paint getStrokePaint() { + return strokePaint; + } - public boolean setBounds(double x, double y, double width, double height) { - if (line == null || !super.setBounds(x, y, width, height)) { - return false; - } + public void setStrokePaint(Paint aPaint) { + Paint old = strokePaint; + strokePaint = aPaint; + invalidatePaint(); + firePropertyChange(PPath.PROPERTY_CODE_STROKE_PAINT, PPath.PROPERTY_STROKE_PAINT, old, strokePaint); + } - Rectangle2D lineBounds = line.getBounds2D(); - Rectangle2D lineStrokeBounds = getLineBoundsWithStroke(); - double strokeOutset = Math.max(lineStrokeBounds.getWidth() - lineBounds.getWidth(), - lineStrokeBounds.getHeight() - lineBounds.getHeight()); - - x += strokeOutset / 2; - y += strokeOutset / 2; - width -= strokeOutset; - height -= strokeOutset; - - TEMP_TRANSFORM.setToIdentity(); - TEMP_TRANSFORM.translate(x, y); - TEMP_TRANSFORM.scale(width / lineBounds.getWidth(), height / lineBounds.getHeight()); - TEMP_TRANSFORM.translate(-lineBounds.getX(), -lineBounds.getY()); + public Stroke getStroke() { + return stroke; + } + + public void setStroke(Stroke aStroke) { + Stroke old = stroke; + stroke = aStroke; + updateBoundsFromLine(); + invalidatePaint(); + firePropertyChange(PPath.PROPERTY_CODE_STROKE, PPath.PROPERTY_STROKE, old, stroke); + } + + // **************************************************************** + // Bounds + // **************************************************************** + + public boolean setBounds(double x, double y, double width, double height) { + if (line == null || !super.setBounds(x, y, width, height)) { + return false; + } + + Rectangle2D lineBounds = line.getBounds2D(); + Rectangle2D lineStrokeBounds = getLineBoundsWithStroke(); + double strokeOutset = Math.max(lineStrokeBounds.getWidth() - lineBounds.getWidth(), lineStrokeBounds + .getHeight() + - lineBounds.getHeight()); + + x += strokeOutset / 2; + y += strokeOutset / 2; + width -= strokeOutset; + height -= strokeOutset; + + TEMP_TRANSFORM.setToIdentity(); + TEMP_TRANSFORM.translate(x, y); + TEMP_TRANSFORM.scale(width / lineBounds.getWidth(), height / lineBounds.getHeight()); + TEMP_TRANSFORM.translate(-lineBounds.getX(), -lineBounds.getY()); line.transformPoints(TEMP_TRANSFORM); - - return true; - } - public boolean intersects(Rectangle2D aBounds) { - if (super.intersects(aBounds)) { - if (line.intersects(aBounds)) { - return true; - } else if (stroke != null && strokePaint != null) { - return stroke.createStrokedShape(line).intersects(aBounds); - } - } - return false; - } - - public Rectangle2D getLineBoundsWithStroke() { - if (stroke != null) { - return stroke.createStrokedShape(line).getBounds2D(); - } else { - return line.getBounds2D(); - } - } - - public void updateBoundsFromLine() { - if (line.getPointCount() == 0) { - resetBounds(); - } else { - Rectangle2D b = getLineBoundsWithStroke(); - super.setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight()); - } - } - - //**************************************************************** - // Painting - //**************************************************************** - - protected void paint(PPaintContext paintContext) { - Graphics2D g2 = paintContext.getGraphics(); - - if (stroke != null && strokePaint != null) { - g2.setPaint(strokePaint); - g2.setStroke(stroke); - g2.draw(line); - } - } + return true; + } - public LineShape getLineReference() { - return line; - } + public boolean intersects(Rectangle2D aBounds) { + if (super.intersects(aBounds)) { + if (line.intersects(aBounds)) { + return true; + } + else if (stroke != null && strokePaint != null) { + return stroke.createStrokedShape(line).intersects(aBounds); + } + } + return false; + } + + public Rectangle2D getLineBoundsWithStroke() { + if (stroke != null) { + return stroke.createStrokedShape(line).getBounds2D(); + } + else { + return line.getBounds2D(); + } + } + + public void updateBoundsFromLine() { + if (line.getPointCount() == 0) { + resetBounds(); + } + else { + Rectangle2D b = getLineBoundsWithStroke(); + super.setBounds(b.getX(), b.getY(), b.getWidth(), b.getHeight()); + } + } + + // **************************************************************** + // Painting + // **************************************************************** + + protected void paint(PPaintContext paintContext) { + Graphics2D g2 = paintContext.getGraphics(); + + if (stroke != null && strokePaint != null) { + g2.setPaint(strokePaint); + g2.setStroke(stroke); + g2.draw(line); + } + } + + public LineShape getLineReference() { + return line; + } public int getPointCount() { return line.getPointCount(); @@ -167,11 +171,11 @@ updateBoundsFromLine(); invalidatePaint(); } - - public void setPoint(int i, double x, double y) { + + public void setPoint(int i, double x, double y) { line.setPoint(i, x, y); lineChanged(); - } + } public void addPoint(int i, double x, double y) { line.addPoint(i, x, y); @@ -183,22 +187,22 @@ lineChanged(); } - public void removeAllPoints() { + public void removeAllPoints() { line.removePoints(0, line.getPointCount()); lineChanged(); - } - - //**************************************************************** - // Serialization - //**************************************************************** - - private void writeObject(ObjectOutputStream out) throws IOException { - out.defaultWriteObject(); - PUtil.writeStroke(stroke, out); - } + } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - stroke = PUtil.readStroke(in); - } + // **************************************************************** + // Serialization + // **************************************************************** + + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + PUtil.writeStroke(stroke, out); + } + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + stroke = PUtil.readStroke(in); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PNodeCache.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PNodeCache.java index 8304aba..1cd34a4 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PNodeCache.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PNodeCache.java @@ -40,81 +40,81 @@ import edu.umd.cs.piccolo.util.PPickPath; /** - * PNodeCache caches a visual representation of it's children - * into an image and uses this cached image for painting instead of - * painting it's children directly. This is intended to be used in - * two ways. - *

- * First it can be used as a simple optimization technique. If a node - * has many descendents it may be faster to paint the cached image - * representation instead of painting each node. - *

- * Second PNodeCache provides a place where "image" effects such as - * blurring and drop shadows can be added to the Piccolo scene graph. - * This can be done by overriding the method createImageCache and - * returing an image with the desired effect applied. - *

+ * PNodeCache caches a visual representation of it's children into an + * image and uses this cached image for painting instead of painting it's + * children directly. This is intended to be used in two ways. + *

+ * First it can be used as a simple optimization technique. If a node has many + * descendents it may be faster to paint the cached image representation instead + * of painting each node. + *

+ *

+ * Second PNodeCache provides a place where "image" effects such as blurring and + * drop shadows can be added to the Piccolo scene graph. This can be done by + * overriding the method createImageCache and returing an image with the desired + * effect applied. + *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PNodeCache extends PNode { - - private transient Image imageCache; - private boolean validatingCache; - - /** - * Override this method to customize the image cache creation process. For - * example if you want to create a shadow effect you would do that here. Fill - * in the cacheOffsetRef if needed to make your image cache line up with the - * nodes children. - */ - public Image createImageCache(Dimension2D cacheOffsetRef) { - return toImage(); - } - - public Image getImageCache() { - if (imageCache == null) { - PDimension cacheOffsetRef = new PDimension(); - validatingCache = true; - resetBounds(); - imageCache = createImageCache(cacheOffsetRef); - PBounds b = getFullBoundsReference(); - setBounds(b.getX() + cacheOffsetRef.getWidth(), - b.getY() + cacheOffsetRef.getHeight(), - imageCache.getWidth(null), - imageCache.getHeight(null)); - validatingCache = false; - } - return imageCache; - } - - public void invalidateCache() { - imageCache = null; - } - - public void invalidatePaint() { - if (!validatingCache) { - super.invalidatePaint(); - } - } - - public void repaintFrom(PBounds localBounds, PNode childOrThis) { - if (!validatingCache) { - super.repaintFrom(localBounds, childOrThis); - invalidateCache(); - } - } - - public void fullPaint(PPaintContext paintContext) { - if (validatingCache) { - super.fullPaint(paintContext); - } else { - Graphics2D g2 = paintContext.getGraphics(); - g2.drawImage(getImageCache(), (int) getX(), (int) getY(), null); - } - } - - protected boolean pickAfterChildren(PPickPath pickPath) { - return false; - } + + private transient Image imageCache; + private boolean validatingCache; + + /** + * Override this method to customize the image cache creation process. For + * example if you want to create a shadow effect you would do that here. + * Fill in the cacheOffsetRef if needed to make your image cache line up + * with the nodes children. + */ + public Image createImageCache(Dimension2D cacheOffsetRef) { + return toImage(); + } + + public Image getImageCache() { + if (imageCache == null) { + PDimension cacheOffsetRef = new PDimension(); + validatingCache = true; + resetBounds(); + imageCache = createImageCache(cacheOffsetRef); + PBounds b = getFullBoundsReference(); + setBounds(b.getX() + cacheOffsetRef.getWidth(), b.getY() + cacheOffsetRef.getHeight(), imageCache + .getWidth(null), imageCache.getHeight(null)); + validatingCache = false; + } + return imageCache; + } + + public void invalidateCache() { + imageCache = null; + } + + public void invalidatePaint() { + if (!validatingCache) { + super.invalidatePaint(); + } + } + + public void repaintFrom(PBounds localBounds, PNode childOrThis) { + if (!validatingCache) { + super.repaintFrom(localBounds, childOrThis); + invalidateCache(); + } + } + + public void fullPaint(PPaintContext paintContext) { + if (validatingCache) { + super.fullPaint(paintContext); + } + else { + Graphics2D g2 = paintContext.getGraphics(); + g2.drawImage(getImageCache(), (int) getX(), (int) getY(), null); + } + } + + protected boolean pickAfterChildren(PPickPath pickPath) { + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java index b222041..31d6622 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/nodes/PStyledText.java @@ -61,620 +61,619 @@ */ public class PStyledText extends PNode { - protected static FontRenderContext SWING_FRC = new FontRenderContext(null,true,false); - protected static Line2D paintLine = new Line2D.Double(); + protected static FontRenderContext SWING_FRC = new FontRenderContext(null, true, false); + protected static Line2D paintLine = new Line2D.Double(); - protected Document document; - protected transient ArrayList stringContents; - protected transient LineInfo[] lines; + protected Document document; + protected transient ArrayList stringContents; + protected transient LineInfo[] lines; - protected boolean editing; - protected Insets insets = new Insets(0,0,0,0); - protected boolean constrainHeightToTextHeight = true; - protected boolean constrainWidthToTextWidth = true; + protected boolean editing; + protected Insets insets = new Insets(0, 0, 0, 0); + protected boolean constrainHeightToTextHeight = true; + protected boolean constrainWidthToTextWidth = true; - /** - * Constructor for PStyledText. - */ - public PStyledText() { - super(); - } + /** + * Constructor for PStyledText. + */ + public PStyledText() { + super(); + } - /** - * Controls whether this node changes its width to fit the width - * of its text. If flag is true it does; if flag is false it doesn't - */ - public void setConstrainWidthToTextWidth(boolean constrainWidthToTextWidth) { - this.constrainWidthToTextWidth = constrainWidthToTextWidth; - recomputeLayout(); - } + /** + * Controls whether this node changes its width to fit the width of its + * text. If flag is true it does; if flag is false it doesn't + */ + public void setConstrainWidthToTextWidth(boolean constrainWidthToTextWidth) { + this.constrainWidthToTextWidth = constrainWidthToTextWidth; + recomputeLayout(); + } - /** - * Controls whether this node changes its height to fit the height - * of its text. If flag is true it does; if flag is false it doesn't - */ - public void setConstrainHeightToTextHeight(boolean constrainHeightToTextHeight) { - this.constrainHeightToTextHeight = constrainHeightToTextHeight; - recomputeLayout(); - } + /** + * Controls whether this node changes its height to fit the height of its + * text. If flag is true it does; if flag is false it doesn't + */ + public void setConstrainHeightToTextHeight(boolean constrainHeightToTextHeight) { + this.constrainHeightToTextHeight = constrainHeightToTextHeight; + recomputeLayout(); + } - /** - * Controls whether this node changes its width to fit the width - * of its text. If flag is true it does; if flag is false it doesn't - */ - public boolean getConstrainWidthToTextWidth() { - return constrainWidthToTextWidth; - } + /** + * Controls whether this node changes its width to fit the width of its + * text. If flag is true it does; if flag is false it doesn't + */ + public boolean getConstrainWidthToTextWidth() { + return constrainWidthToTextWidth; + } - /** - * Controls whether this node changes its height to fit the height - * of its text. If flag is true it does; if flag is false it doesn't - */ - public boolean getConstrainHeightToTextHeight() { - return constrainHeightToTextHeight; - } + /** + * Controls whether this node changes its height to fit the height of its + * text. If flag is true it does; if flag is false it doesn't + */ + public boolean getConstrainHeightToTextHeight() { + return constrainHeightToTextHeight; + } - /** - * Get the document for this PStyledText - */ - public Document getDocument() { - return document; - } - - /** - * Set the document on this PStyledText - */ - public void setDocument(Document document) { - // Save the document - this.document = document; - - syncWithDocument(); - } - - - public void syncWithDocument() { - // The paragraph start and end indices - ArrayList pEnds = null; - - // The current position in the specified range - int pos = 0; - - // First get the actual text and stick it in an Attributed String - try { + /** + * Get the document for this PStyledText + */ + public Document getDocument() { + return document; + } - stringContents = new ArrayList(); - pEnds = new ArrayList(); - - String s = document.getText(0,document.getLength()); - StringTokenizer tokenizer = new StringTokenizer(s,"\n",true); - - // lastNewLine is used to detect the case when two newlines follow in direct succession - // & lastNewLine should be true to start in case the first character is a newline - boolean lastNewLine = true; - for(int i=0; tokenizer.hasMoreTokens(); i++) { - String token = tokenizer.nextToken(); - - // If the token - if (token.equals("\n")) { - if (lastNewLine) { - stringContents.add(new AttributedString(" ")); - pEnds.add(new RunInfo(pos,pos+1)); - - pos = pos + 1; + /** + * Set the document on this PStyledText + */ + public void setDocument(Document document) { + // Save the document + this.document = document; - lastNewLine = true; - } - else { - pos = pos + 1; - - lastNewLine = true; - } - } - // If the token is empty - create an attributed string with a single space - // since LineBreakMeasurers don't work with an empty string - // - note that this case should only arise if the document is empty - else if (token.equals("")) { - stringContents.add(new AttributedString(" ")); - pEnds.add(new RunInfo(pos,pos)); + syncWithDocument(); + } - lastNewLine = false; - } - // This is the normal case - where we have some text - else { - stringContents.add(new AttributedString(token)); - pEnds.add(new RunInfo(pos,pos+token.length())); + public void syncWithDocument() { + // The paragraph start and end indices + ArrayList pEnds = null; - // Increment the position - pos = pos+token.length(); - - lastNewLine = false; - } - } - - // Add one more newline if the last character was a newline - if (lastNewLine) { - stringContents.add(new AttributedString(" ")); - pEnds.add(new RunInfo(pos,pos+1)); - - lastNewLine = false; - } - } - catch (Exception e) { - e.printStackTrace(); - } + // The current position in the specified range + int pos = 0; - // The default style context - which will be reused - StyleContext style = StyleContext.getDefaultStyleContext(); + // First get the actual text and stick it in an Attributed String + try { - RunInfo pEnd = null; - for (int i = 0; i < stringContents.size(); i++) { - pEnd = (RunInfo)pEnds.get(i); - pos = pEnd.runStart; + stringContents = new ArrayList(); + pEnds = new ArrayList(); - // The current element will be used as a temp variable while searching - // for the leaf element at the current position - Element curElement = null; + String s = document.getText(0, document.getLength()); + StringTokenizer tokenizer = new StringTokenizer(s, "\n", true); - // Small assumption here that there is one root element - can fix - // for more general support later - Element rootElement = document.getDefaultRootElement(); + // lastNewLine is used to detect the case when two newlines follow + // in direct succession + // & lastNewLine should be true to start in case the first character + // is a newline + boolean lastNewLine = true; + for (int i = 0; tokenizer.hasMoreTokens(); i++) { + String token = tokenizer.nextToken(); - // If the string is length 0 then we just need to add the attributes once - if (pEnd.runStart != pEnd.runLimit) { - // OK, now we loop until we find all the leaf elements in the range - while (pos < pEnd.runLimit) { - - // Before each pass, start at the root - curElement = rootElement; - - // Now we descend the hierarchy until we get to a leaf - while (!curElement.isLeaf()) { - curElement = - curElement.getElement(curElement.getElementIndex(pos)); - } + // If the token + if (token.equals("\n")) { + if (lastNewLine) { + stringContents.add(new AttributedString(" ")); + pEnds.add(new RunInfo(pos, pos + 1)); - // These are the mandatory attributes + pos = pos + 1; - AttributeSet attributes = curElement.getAttributes(); - Color foreground = style.getForeground(attributes); + lastNewLine = true; + } + else { + pos = pos + 1; - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.FOREGROUND, - foreground, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - - Font font = (attributes.isDefined(StyleConstants.FontSize) || attributes.isDefined(StyleConstants.FontFamily)) ? style.getFont(attributes) : null; - if (font == null) { - if (document instanceof DefaultStyledDocument) { - font = style.getFont(((DefaultStyledDocument)document).getCharacterElement(pos).getAttributes()); - if (font == null) { - font = style.getFont(((DefaultStyledDocument)document).getParagraphElement(pos).getAttributes()); - } - if (font == null) { - font = style.getFont(rootElement.getAttributes()); - } - } - else { - font = style.getFont(rootElement.getAttributes()); - } - } - if (font != null) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.FONT, - font, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - // These are the optional attributes - - Color background = (attributes.isDefined(StyleConstants.Background)) ? style.getBackground(attributes) : null; - if (background != null) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.BACKGROUND, - background, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - boolean underline = StyleConstants.isUnderline(attributes); - if (underline) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.UNDERLINE, - Boolean.TRUE, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - boolean strikethrough = StyleConstants.isStrikeThrough(attributes); - if (strikethrough) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.STRIKETHROUGH, - Boolean.TRUE, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - // And set the position to the end of the given attribute - pos = curElement.getEndOffset(); - } - } - else { - // Before each pass, start at the root - curElement = rootElement; + lastNewLine = true; + } + } + // If the token is empty - create an attributed string with a + // single space + // since LineBreakMeasurers don't work with an empty string + // - note that this case should only arise if the document is + // empty + else if (token.equals("")) { + stringContents.add(new AttributedString(" ")); + pEnds.add(new RunInfo(pos, pos)); - // Now we descend the hierarchy until we get to a leaf - while (!curElement.isLeaf()) { - curElement = - curElement.getElement(curElement.getElementIndex(pos)); - } + lastNewLine = false; + } + // This is the normal case - where we have some text + else { + stringContents.add(new AttributedString(token)); + pEnds.add(new RunInfo(pos, pos + token.length())); - // These are the mandatory attributes - - AttributeSet attributes = curElement.getAttributes(); - Color foreground = style.getForeground(attributes); + // Increment the position + pos = pos + token.length(); - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.FOREGROUND, - foreground, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); + lastNewLine = false; + } + } - // These are the optional attributes + // Add one more newline if the last character was a newline + if (lastNewLine) { + stringContents.add(new AttributedString(" ")); + pEnds.add(new RunInfo(pos, pos + 1)); - Font font = (attributes.isDefined(StyleConstants.FontSize) || attributes.isDefined(StyleConstants.FontFamily)) ? style.getFont(attributes) : null; - if (font == null) { - if (document instanceof DefaultStyledDocument) { - font = style.getFont(((DefaultStyledDocument)document).getCharacterElement(pos).getAttributes()); - if (font == null) { - font = style.getFont(((DefaultStyledDocument)document).getParagraphElement(pos).getAttributes()); - } - if (font == null) { - font = style.getFont(rootElement.getAttributes()); - } - } - else { - font = style.getFont(rootElement.getAttributes()); - } - } - if (font != null) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.FONT, - font, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - Color background = (attributes.isDefined(StyleConstants.Background)) ? style.getBackground(attributes) : null; - if (background != null) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.BACKGROUND, - background, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - boolean underline = StyleConstants.isUnderline(attributes); - if (underline) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.UNDERLINE, - Boolean.TRUE, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - - boolean strikethrough = StyleConstants.isStrikeThrough(attributes); - if (strikethrough) { - ((AttributedString)stringContents.get(i)).addAttribute( - TextAttribute.STRIKETHROUGH, - Boolean.TRUE, - (int)Math.max(0,curElement.getStartOffset()-pEnd.runStart), - (int)Math.min(pEnd.runLimit-pEnd.runStart,curElement.getEndOffset()-pEnd.runStart)); - } - } - } + lastNewLine = false; + } + } + catch (Exception e) { + e.printStackTrace(); + } - recomputeLayout(); - } + // The default style context - which will be reused + StyleContext style = StyleContext.getDefaultStyleContext(); - /** - * Compute the bounds of the text wrapped by this node. The text layout - * is wrapped based on the bounds of this node. If the shrinkBoundsToFit parameter - * is true then after the text has been laid out the bounds of this node are shrunk - * to fit around those text bounds. - */ - public void recomputeLayout() { - if (stringContents == null) return; + RunInfo pEnd = null; + for (int i = 0; i < stringContents.size(); i++) { + pEnd = (RunInfo) pEnds.get(i); + pos = pEnd.runStart; - ArrayList linesList = new ArrayList(); + // The current element will be used as a temp variable while + // searching + // for the leaf element at the current position + Element curElement = null; - double textWidth = 0; - double textHeight = 0; - - for(int i=0; iPComboBox is used instead of a JComboBox in a Piccolo scene graph. - * This PComboBox won't work properly if it is located in an abnormal hierarchy of Cameras. - * Support is provided for only one (or zero) view transforms. - *

- * A ComboBox for use in Piccolo. This still has an associated JPopupMenu - * (which is always potentially heavyweight depending on component location - * relative to containing window borders.) However, this ComboBox places - * the PopupMenu component of the ComboBox in the appropriate position - * relative to the permanent part of the ComboBox. The PopupMenu is never - * transformed. - *

- * This class was not designed for subclassing. If different behavior - * is required, it seems more appropriate to subclass JComboBox directly - * using this class as a model. - *

- * NOTE: There is currently a known bug, namely, if the ComboBox receives - * focus through 'tab' focus traversal and the keyboard is used to interact - * with the ComboBox, there may be unexpected results. - *

- *

- * Warning: Serialized objects of this class will not be - * compatible with future Piccolo releases. The current serialization support is - * appropriate for short term storage or RMI between applications running the - * same version of Piccolo. A future release of Piccolo will provide support for long - * term persistence. - * + * This PComboBox won't work properly if it is located in an abnormal hierarchy + * of Cameras. Support is provided for only one (or zero) view transforms. + *

+ * A ComboBox for use in Piccolo. This still has an associated JPopupMenu (which + * is always potentially heavyweight depending on component location relative to + * containing window borders.) However, this ComboBox places the PopupMenu + * component of the ComboBox in the appropriate position relative to the + * permanent part of the ComboBox. The PopupMenu is never transformed. + *

+ *

+ * This class was not designed for subclassing. If different behavior is + * required, it seems more appropriate to subclass JComboBox directly using this + * class as a model. + *

+ *

+ * NOTE: There is currently a known bug, namely, if the ComboBox receives focus + * through 'tab' focus traversal and the keyboard is used to interact with the + * ComboBox, there may be unexpected results. + *

+ *

+ * Warning: Serialized objects of this class will not be compatible with + * future Piccolo releases. The current serialization support is appropriate for + * short term storage or RMI between applications running the same version of + * Piccolo. A future release of Piccolo will provide support for long term + * persistence. + *

+ * * @author Lance Good */ public class PComboBox extends JComboBox implements Serializable { @@ -51,31 +53,31 @@ /** * Creates a PComboBox that takes its items from an existing ComboBoxModel. - * + * * @param model The ComboBoxModel from which the list will be created */ - public PComboBox( ComboBoxModel model ) { - super( model ); + public PComboBox(ComboBoxModel model) { + super(model); init(); } /** * Creates a PComboBox that contains the elements in the specified array. - * + * * @param items The items to populate the PComboBox list */ - public PComboBox( final Object items[] ) { - super( items ); + public PComboBox(final Object items[]) { + super(items); init(); } /** * Creates a PComboBox that contains the elements in the specified Vector. - * + * * @param items The items to populate the PComboBox list */ - public PComboBox( Vector items ) { - super( items ); + public PComboBox(Vector items) { + super(items); init(); } @@ -91,24 +93,25 @@ * Substitue our UI for the default */ private void init() { - setUI( new PBasicComboBoxUI() ); + setUI(new PBasicComboBoxUI()); } /** - * Clients must set the PSwing and PSwingCanvas environment for this PComboBox to work properly. - * + * Clients must set the PSwing and PSwingCanvas environment for this + * PComboBox to work properly. + * * @param pSwing * @param canvas */ - public void setEnvironment( PSwing pSwing, PSwingCanvas canvas ) { + public void setEnvironment(PSwing pSwing, PSwingCanvas canvas) { this.pSwing = pSwing; this.canvas = canvas; } /** - * The substitute look and feel - used to capture the mouse - * events on the arrowButton and the component itself and - * to create our PopupMenu rather than the default + * The substitute look and feel - used to capture the mouse events on the + * arrowButton and the component itself and to create our PopupMenu rather + * than the default */ protected class PBasicComboBoxUI extends BasicComboBoxUI { @@ -116,66 +119,52 @@ * Create our Popup instead of theirs */ protected ComboPopup createPopup() { - PBasicComboPopup popup = new PBasicComboPopup( comboBox ); - popup.getAccessibleContext().setAccessibleParent( comboBox ); + PBasicComboPopup popup = new PBasicComboPopup(comboBox); + popup.getAccessibleContext().setAccessibleParent(comboBox); return popup; } } /** - * The substitute ComboPopupMenu that places itself correctly - * in Piccolo. + * The substitute ComboPopupMenu that places itself correctly in Piccolo. */ protected class PBasicComboPopup extends BasicComboPopup { /** * @param combo The parent ComboBox */ - public PBasicComboPopup( JComboBox combo ) { - super( combo ); + public PBasicComboPopup(JComboBox combo) { + super(combo); } - /** - * Computes the bounds for the Popup in Piccolo if a - * PMouseEvent has been received. Otherwise, it uses the - * default algorithm for placing the popup. - * + * Computes the bounds for the Popup in Piccolo if a PMouseEvent has + * been received. Otherwise, it uses the default algorithm for placing + * the popup. + * * @param px corresponds to the x coordinate of the popup * @param py corresponds to the y coordinate of the popup * @param pw corresponds to the width of the popup * @param ph corresponds to the height of the popup * @return The bounds for the PopupMenu */ - protected Rectangle computePopupBounds( int px, int py, int pw, int ph ) { + protected Rectangle computePopupBounds(int px, int py, int pw, int ph) { Rectangle2D r = getNodeBoundsInCanvas(); - Rectangle sup = super.computePopupBounds( px, py, pw, ph ); - return new Rectangle( (int)r.getX(), (int)r.getMaxY(), (int)sup.getWidth(), (int)sup.getHeight() ); + Rectangle sup = super.computePopupBounds(px, py, pw, ph); + return new Rectangle((int) r.getX(), (int) r.getMaxY(), (int) sup.getWidth(), (int) sup.getHeight()); } } private Rectangle2D getNodeBoundsInCanvas() { - if( pSwing == null || canvas == null ) { - throw new RuntimeException( "PComboBox.setEnvironment( swing, pCanvas );//has to be done manually at present" ); + if (pSwing == null || canvas == null) { + throw new RuntimeException( + "PComboBox.setEnvironment( swing, pCanvas );//has to be done manually at present"); } Rectangle2D r1c = pSwing.getBounds(); - pSwing.localToGlobal( r1c ); - canvas.getCamera().globalToLocal( r1c ); - r1c = canvas.getCamera().getViewTransform().createTransformedShape( r1c ).getBounds2D(); + pSwing.localToGlobal(r1c); + canvas.getCamera().globalToLocal(r1c); + r1c = canvas.getCamera().getViewTransform().createTransformedShape(r1c).getBounds2D(); return r1c; } } - - - - - - - - - - - - - diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java index 3bd2e74..096ce79 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwing.java @@ -112,7 +112,7 @@ /** * PSwing is used to add Swing Components to a Piccolo canvas. - *

+ *

* Example: adding a swing JButton to a PCanvas: *

  *     PSwingCanvas canvas = new PSwingCanvas();
@@ -120,14 +120,16 @@
  *     swing = new PSwing(canvas, button);
  *     canvas.getLayer().addChild(swing);
  * 
- * 

+ *

+ *

* NOTE: PSwing has the current limitation that it does not listen for * Container events. This is only an issue if you create a PSwing * and later add Swing components to the PSwing's component hierarchy * that do not have double buffering turned off or have a smaller font * size than the minimum font size of the original PSwing's component * hierarchy. - *

+ *

+ *

* For instance, the following bit of code will give unexpected * results: *

@@ -137,17 +139,21 @@
  *            newChild.setDoubleBuffered(true);
  *            panel.add(newChild);
  *       
- *

+ *

+ *

* NOTE: PSwing cannot be correctly interacted with through multiple cameras. * There is no support for it yet. - *

+ *

+ *

* NOTE: PSwing is java.io.Serializable. - *

+ *

+ *

* Warning: Serialized objects of this class will not be * compatible with future Piccolo releases. The current serialization support is * appropriate for short term storage or RMI between applications running the * same version of Piccolo. A future release of Piccolo will provide support for long * term persistence. + *

* * @author Sam R. Reid * @author Benjamin B. Bederson diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java index d7263f8..b050aae 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingCanvas.java @@ -16,8 +16,9 @@ import java.awt.*; /** - * The PSwingCanvas is a PCanvas that can display Swing components with the PSwing adapter. - * + * The PSwingCanvas is a PCanvas that can display Swing components with + * the PSwing adapter. + * * @author Benjamin B. Bederson * @author Sam R. Reid * @author Lance E. Good @@ -34,35 +35,36 @@ * Construct a new PSwingCanvas. */ public PSwingCanvas() { - swingWrapper = new SwingWrapper( this ); - add( swingWrapper ); - RepaintManager.setCurrentManager( pSwingRepaintManager ); - pSwingRepaintManager.addPSwingCanvas( this ); + swingWrapper = new SwingWrapper(this); + add(swingWrapper); + RepaintManager.setCurrentManager(pSwingRepaintManager); + pSwingRepaintManager.addPSwingCanvas(this); - swingEventHandler = new PSwingEventHandler( this, getCamera() );//todo or maybe getCameraLayer() or getRoot()? - swingEventHandler.setActive( true ); + // todo or maybe getCameraLayer() or getRoot()? + swingEventHandler = new PSwingEventHandler(this, getCamera()); + swingEventHandler.setActive(true); } JComponent getSwingWrapper() { return swingWrapper; } - public void addPSwing( PSwing pSwing ) { - swingWrapper.add( pSwing.getComponent() ); + public void addPSwing(PSwing pSwing) { + swingWrapper.add(pSwing.getComponent()); } - public void removePSwing( PSwing pSwing ) { - swingWrapper.remove( pSwing.getComponent() ); + public void removePSwing(PSwing pSwing) { + swingWrapper.remove(pSwing.getComponent()); } private static class SwingWrapper extends JComponent { private PSwingCanvas pSwingCanvas; - public SwingWrapper( PSwingCanvas pSwingCanvas ) { + public SwingWrapper(PSwingCanvas pSwingCanvas) { this.pSwingCanvas = pSwingCanvas; - setSize( new Dimension( 0, 0 ) ); - setPreferredSize( new Dimension( 0, 0 ) ); - putClientProperty( SWING_WRAPPER_KEY, SWING_WRAPPER_KEY ); + setSize(new Dimension(0, 0)); + setPreferredSize(new Dimension(0, 0)); + putClientProperty(SWING_WRAPPER_KEY, SWING_WRAPPER_KEY); } public PSwingCanvas getpSwingCanvas() { diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java index ee777c9..8d2123b 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingEventHandler.java @@ -19,18 +19,17 @@ import java.awt.geom.Point2D; /** - * Event handler to send MousePressed, MouseReleased, MouseMoved, - * MouseClicked, and MouseDragged events on Swing components within - * a PCanvas. - * + * Event handler to send MousePressed, MouseReleased, MouseMoved, MouseClicked, + * and MouseDragged events on Swing components within a PCanvas. + * * @author Ben Bederson * @author Lance Good * @author Sam Reid */ public class PSwingEventHandler implements PInputEventListener { - private PNode listenNode = null; //used to listen to for events - private boolean active = false; //True when event handlers are set active. + private PNode listenNode = null; // used to listen to for events + private boolean active = false; // True when event handlers are set active. // The previous component - used to generate mouseEntered and // mouseExited events @@ -40,7 +39,7 @@ private Point2D prevPoint = null; private Point2D prevOff = null; - private boolean recursing = false;//to avoid accidental recursive handling + private boolean recursing = false;// to avoid accidental recursive handling private ButtonData leftButtonData = new ButtonData(); private ButtonData rightButtonData = new ButtonData(); @@ -49,13 +48,13 @@ private PSwingCanvas canvas; /** - * Constructs a new PSwingEventHandler for the given canvas, - * and a node that will recieve the mouse events. - * + * Constructs a new PSwingEventHandler for the given canvas, and a node that + * will recieve the mouse events. + * * @param canvas the canvas associated with this PSwingEventHandler. - * @param node the node the mouse listeners will be attached to. + * @param node the node the mouse listeners will be attached to. */ - public PSwingEventHandler( PSwingCanvas canvas, PNode node ) { + public PSwingEventHandler(PSwingCanvas canvas, PNode node) { this.canvas = canvas; listenNode = node; } @@ -63,33 +62,33 @@ /** * Constructs a new PSwingEventHandler for the given canvas. */ - public PSwingEventHandler( PSwingCanvas canvas ) { + public PSwingEventHandler(PSwingCanvas canvas) { this.canvas = canvas; } /** * Sets whether this event handler can fire events. - * + * * @param active */ - void setActive( boolean active ) { - if( this.active && !active ) { - if( listenNode != null ) { + void setActive(boolean active) { + if (this.active && !active) { + if (listenNode != null) { this.active = false; - listenNode.removeInputEventListener( this ); + listenNode.removeInputEventListener(this); } } - else if( !this.active && active ) { - if( listenNode != null ) { + else if (!this.active && active) { + if (listenNode != null) { this.active = true; - listenNode.addInputEventListener( this ); + listenNode.addInputEventListener(this); } } } /** * Determines if this event handler is active. - * + * * @return True if active */ public boolean isActive() { @@ -98,33 +97,33 @@ /** * Finds the component at the specified location (must be showing). - * + * * @param c * @param x * @param y * @return the component at the specified location. */ - private Component findShowingComponentAt( Component c, int x, int y ) { - if( !c.contains( x, y ) ) { + private Component findShowingComponentAt(Component c, int x, int y) { + if (!c.contains(x, y)) { return null; } - if( c instanceof Container ) { - Container contain = ( (Container)c ); + if (c instanceof Container) { + Container contain = ((Container) c); int ncomponents = contain.getComponentCount(); Component component[] = contain.getComponents(); - for( int i = 0; i < ncomponents; i++ ) { + for (int i = 0; i < ncomponents; i++) { Component comp = component[i]; - if( comp != null ) { + if (comp != null) { Point p = comp.getLocation(); - if( comp instanceof Container ) { - comp = findShowingComponentAt( comp, x - (int)p.getX(), y - (int)p.getY() ); + if (comp instanceof Container) { + comp = findShowingComponentAt(comp, x - (int) p.getX(), y - (int) p.getY()); } else { - comp = comp.getComponentAt( x - (int)p.getX(), y - (int)p.getY() ); + comp = comp.getComponentAt(x - (int) p.getX(), y - (int) p.getY()); } - if( comp != null && comp.isShowing() ) { + if (comp != null && comp.isShowing()) { return comp; } } @@ -134,16 +133,15 @@ } /** - * Determines if any Swing components in Piccolo - * should receive the given MouseEvent and - * forwards the event to that component. - * However, mouseEntered and mouseExited are independent of the buttons. - * Also, notice the notes on mouseEntered and mouseExited. - * + * Determines if any Swing components in Piccolo should receive the given + * MouseEvent and forwards the event to that component. However, + * mouseEntered and mouseExited are independent of the buttons. Also, notice + * the notes on mouseEntered and mouseExited. + * * @param pSwingMouseEvent * @param aEvent */ - void dispatchEvent( PSwingMouseEvent pSwingMouseEvent, PInputEvent aEvent ) { + void dispatchEvent(PSwingMouseEvent pSwingMouseEvent, PInputEvent aEvent) { Component comp = null; Point2D pt = null; PNode pickedNode = pSwingMouseEvent.getPath().getPickedNode(); @@ -154,27 +152,27 @@ PNode currentNode = pSwingMouseEvent.getCurrentNode(); - if( currentNode instanceof PSwing ) { + if (currentNode instanceof PSwing) { - PSwing swing = (PSwing)currentNode; + PSwing swing = (PSwing) currentNode; PNode grabNode = pickedNode; - if( grabNode.isDescendentOf( canvas.getRoot() ) ) { - pt = new Point2D.Double( pSwingMouseEvent.getX(), pSwingMouseEvent.getY() ); - cameraToLocal( pSwingMouseEvent.getPath().getTopCamera(), pt, grabNode ); - prevPoint = new Point2D.Double( pt.getX(), pt.getY() ); + if (grabNode.isDescendentOf(canvas.getRoot())) { + pt = new Point2D.Double(pSwingMouseEvent.getX(), pSwingMouseEvent.getY()); + cameraToLocal(pSwingMouseEvent.getPath().getTopCamera(), pt, grabNode); + prevPoint = new Point2D.Double(pt.getX(), pt.getY()); // This is only partially fixed to find the deepest - // component at pt. It needs to do something like + // component at pt. It needs to do something like // package private method: // Container.getMouseEventTarget(int,int,boolean) - comp = findShowingComponentAt( swing.getComponent(), (int)pt.getX(), (int)pt.getY() ); + comp = findShowingComponentAt(swing.getComponent(), (int) pt.getX(), (int) pt.getY()); // We found the right component - but we need to // get the offset to put the event in the component's // coordinates - if( comp != null && comp != swing.getComponent() ) { - for( Component c = comp; c != swing.getComponent(); c = c.getParent() ) { + if (comp != null && comp != swing.getComponent()) { + for (Component c = comp; c != swing.getComponent(); c = c.getParent()) { offX += c.getLocation().getX(); offY += c.getLocation().getY(); } @@ -182,15 +180,15 @@ // Mouse Pressed gives focus - effects Mouse Drags and // Mouse Releases - if( comp != null && pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED ) { - if( SwingUtilities.isLeftMouseButton( pSwingMouseEvent ) ) { - leftButtonData.setState( swing, pickedNode, comp, offX, offY ); + if (comp != null && pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED) { + if (SwingUtilities.isLeftMouseButton(pSwingMouseEvent)) { + leftButtonData.setState(swing, pickedNode, comp, offX, offY); } - else if( SwingUtilities.isMiddleMouseButton( pSwingMouseEvent ) ) { - middleButtonData.setState( swing, pickedNode, comp, offX, offY ); + else if (SwingUtilities.isMiddleMouseButton(pSwingMouseEvent)) { + middleButtonData.setState(swing, pickedNode, comp, offX, offY); } - else if( SwingUtilities.isRightMouseButton( pSwingMouseEvent ) ) { - rightButtonData.setState( swing, pickedNode, comp, offX, offY ); + else if (SwingUtilities.isRightMouseButton(pSwingMouseEvent)) { + rightButtonData.setState(swing, pickedNode, comp, offX, offY); } } } @@ -199,219 +197,216 @@ // This first case we don't want to give events to just // any Swing component - but to the one that got the // original mousePressed - if( pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED || - pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED ) { + if (pSwingMouseEvent.getID() == MouseEvent.MOUSE_DRAGGED + || pSwingMouseEvent.getID() == MouseEvent.MOUSE_RELEASED) { // LEFT MOUSE BUTTON - if( SwingUtilities.isLeftMouseButton( pSwingMouseEvent ) && leftButtonData.getFocusedComponent() != null ) { - handleButton( pSwingMouseEvent, aEvent, leftButtonData ); + if (SwingUtilities.isLeftMouseButton(pSwingMouseEvent) && leftButtonData.getFocusedComponent() != null) { + handleButton(pSwingMouseEvent, aEvent, leftButtonData); } // MIDDLE MOUSE BUTTON - if( SwingUtilities.isMiddleMouseButton( pSwingMouseEvent ) && middleButtonData.getFocusedComponent() != null ) - { - handleButton( pSwingMouseEvent, aEvent, middleButtonData ); + if (SwingUtilities.isMiddleMouseButton(pSwingMouseEvent) && middleButtonData.getFocusedComponent() != null) { + handleButton(pSwingMouseEvent, aEvent, middleButtonData); } // RIGHT MOUSE BUTTON - if( SwingUtilities.isRightMouseButton( pSwingMouseEvent ) && rightButtonData.getFocusedComponent() != null ) - { - handleButton( pSwingMouseEvent, aEvent, rightButtonData ); + if (SwingUtilities.isRightMouseButton(pSwingMouseEvent) && rightButtonData.getFocusedComponent() != null) { + handleButton(pSwingMouseEvent, aEvent, rightButtonData); } } // This case covers the cases mousePressed, mouseClicked, // and mouseMoved events - else if( ( pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED || - pSwingMouseEvent.getID() == MouseEvent.MOUSE_CLICKED || - pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED ) && - ( comp != null ) ) { + else if ((pSwingMouseEvent.getID() == MouseEvent.MOUSE_PRESSED + || pSwingMouseEvent.getID() == MouseEvent.MOUSE_CLICKED || pSwingMouseEvent.getID() == MouseEvent.MOUSE_MOVED) + && (comp != null)) { - MouseEvent e_temp = new MouseEvent( comp, - pSwingMouseEvent.getID(), - pSwingMouseEvent.getWhen(), - pSwingMouseEvent.getModifiers(), - (int)pt.getX() - offX, - (int)pt.getY() - offY, - pSwingMouseEvent.getClickCount(), - pSwingMouseEvent.isPopupTrigger() ); + MouseEvent e_temp = new MouseEvent(comp, pSwingMouseEvent.getID(), pSwingMouseEvent.getWhen(), + pSwingMouseEvent.getModifiers(), (int) pt.getX() - offX, (int) pt.getY() - offY, pSwingMouseEvent + .getClickCount(), pSwingMouseEvent.isPopupTrigger()); - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( comp, e2 ); + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); + dispatchEvent(comp, e2); pSwingMouseEvent.consume(); } // Now we need to check if an exit or enter event needs to // be dispatched - this code is independent of the mouseButtons. // I tested in normal Swing to see the correct behavior. - if( prevComponent != null ) { + if (prevComponent != null) { // This means mouseExited // This shouldn't happen - since we're only getting node events - if( comp == null || pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { - MouseEvent e_temp = createExitEvent( pSwingMouseEvent ); + if (comp == null || pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED) { + MouseEvent e_temp = createExitEvent(pSwingMouseEvent); - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); - dispatchEvent( prevComponent, e2 ); + dispatchEvent(prevComponent, e2); prevComponent = null; - if( pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED ) { + if (pSwingMouseEvent.getID() == MouseEvent.MOUSE_EXITED) { pSwingMouseEvent.consume(); } } // This means mouseExited prevComponent and mouseEntered comp - else if( prevComponent != comp ) { - MouseEvent e_temp = createExitEvent( pSwingMouseEvent ); - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( prevComponent, e2 ); + else if (prevComponent != comp) { + MouseEvent e_temp = createExitEvent(pSwingMouseEvent); + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); + dispatchEvent(prevComponent, e2); - e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); - e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - comp.dispatchEvent( e2 ); + e_temp = createEnterEvent(comp, pSwingMouseEvent, offX, offY); + e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); + comp.dispatchEvent(e2); } } else { // This means mouseEntered - if( comp != null ) { - MouseEvent e_temp = createEnterEvent( comp, pSwingMouseEvent, offX, offY ); - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( comp, e2 ); + if (comp != null) { + MouseEvent e_temp = createEnterEvent(comp, pSwingMouseEvent, offX, offY); + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); + dispatchEvent(comp, e2); } } - //todo add cursors -// // We have to manager our own Cursors since this is normally -// // done on the native side -// if( comp != cursorComponent && -// focusNodeLeft == null && -// focusNodeMiddle == null && -// focusNodeRight == null ) { -// if( comp != null ) { -// cursorComponent = comp; -// canvas.setCursor( comp.getCursor(), false ); -// } -// else { -// cursorComponent = null; -// canvas.resetCursor(); -// } -// } + // todo add cursors + // // We have to manager our own Cursors since this is normally + // // done on the native side + // if( comp != cursorComponent && + // focusNodeLeft == null && + // focusNodeMiddle == null && + // focusNodeRight == null ) { + // if( comp != null ) { + // cursorComponent = comp; + // canvas.setCursor( comp.getCursor(), false ); + // } + // else { + // cursorComponent = null; + // canvas.resetCursor(); + // } + // } // Set the previous variables for next time prevComponent = comp; - if( comp != null ) { - prevOff = new Point2D.Double( offX, offY ); + if (comp != null) { + prevOff = new Point2D.Double(offX, offY); } } - private MouseEvent createEnterEvent( Component comp, PSwingMouseEvent e1, int offX, int offY ) { - return new MouseEvent( comp, MouseEvent.MOUSE_ENTERED, - e1.getWhen(), 0, - (int)prevPoint.getX() - offX, (int)prevPoint.getY() - offY, - e1.getClickCount(), e1.isPopupTrigger() ); + private MouseEvent createEnterEvent(Component comp, PSwingMouseEvent e1, int offX, int offY) { + return new MouseEvent(comp, MouseEvent.MOUSE_ENTERED, e1.getWhen(), 0, (int) prevPoint.getX() - offX, + (int) prevPoint.getY() - offY, e1.getClickCount(), e1.isPopupTrigger()); } - private MouseEvent createExitEvent( PSwingMouseEvent e1 ) { - return new MouseEvent( prevComponent, MouseEvent.MOUSE_EXITED, - e1.getWhen(), 0, - (int)prevPoint.getX() - (int)prevOff.getX(), (int)prevPoint.getY() - (int)prevOff.getY(), - e1.getClickCount(), e1.isPopupTrigger() ); + private MouseEvent createExitEvent(PSwingMouseEvent e1) { + return new MouseEvent(prevComponent, MouseEvent.MOUSE_EXITED, e1.getWhen(), 0, (int) prevPoint.getX() + - (int) prevOff.getX(), (int) prevPoint.getY() - (int) prevOff.getY(), e1.getClickCount(), e1 + .isPopupTrigger()); } - private void handleButton( PSwingMouseEvent e1, PInputEvent aEvent, ButtonData buttonData ) { + private void handleButton(PSwingMouseEvent e1, PInputEvent aEvent, ButtonData buttonData) { Point2D pt; - if( buttonData.getPNode().isDescendentOf( canvas.getRoot() ) ) { - pt = new Point2D.Double( e1.getX(), e1.getY() ); - cameraToLocal( e1.getPath().getTopCamera(), pt, buttonData.getPNode() ); - //todo this probably won't handle viewing through multiple cameras. - MouseEvent e_temp = new MouseEvent( buttonData.getFocusedComponent(), - e1.getID(), e1.getWhen(), e1.getModifiers(), - (int)pt.getX() - buttonData.getOffsetX(), - (int)pt.getY() - buttonData.getOffsetY(), - e1.getClickCount(), e1.isPopupTrigger() ); + if (buttonData.getPNode().isDescendentOf(canvas.getRoot())) { + pt = new Point2D.Double(e1.getX(), e1.getY()); + cameraToLocal(e1.getPath().getTopCamera(), pt, buttonData.getPNode()); + // todo this probably won't handle viewing through multiple cameras. + MouseEvent e_temp = new MouseEvent(buttonData.getFocusedComponent(), e1.getID(), e1.getWhen(), e1 + .getModifiers(), (int) pt.getX() - buttonData.getOffsetX(), (int) pt.getY() + - buttonData.getOffsetY(), e1.getClickCount(), e1.isPopupTrigger()); - PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent( e_temp.getID(), e_temp, aEvent ); - dispatchEvent( buttonData.getFocusedComponent(), e2 ); + PSwingMouseEvent e2 = PSwingMouseEvent.createMouseEvent(e_temp.getID(), e_temp, aEvent); + dispatchEvent(buttonData.getFocusedComponent(), e2); } else { - dispatchEvent( buttonData.getFocusedComponent(), e1 ); + dispatchEvent(buttonData.getFocusedComponent(), e1); } - //buttonData.getPSwing().repaint(); //Experiment with SliderExample (from Martin) suggests this line is unnecessary, and a serious problem in performance. + // buttonData.getPSwing().repaint(); //Experiment with SliderExample + // (from Martin) suggests this line is unnecessary, and a serious + // problem in performance. e1.consume(); - if( e1.getID() == MouseEvent.MOUSE_RELEASED ) { + if (e1.getID() == MouseEvent.MOUSE_RELEASED) { buttonData.mouseReleased(); } } - private void dispatchEvent( final Component target, final PSwingMouseEvent event ) { - SwingUtilities.invokeLater( new Runnable() { + private void dispatchEvent(final Component target, final PSwingMouseEvent event) { + SwingUtilities.invokeLater(new Runnable() { public void run() { - target.dispatchEvent( event ); + target.dispatchEvent(event); } - } ); + }); } - private void cameraToLocal( PCamera topCamera, Point2D pt, PNode node ) { + private void cameraToLocal(PCamera topCamera, Point2D pt, PNode node) { AffineTransform inverse = null; try { inverse = topCamera.getViewTransform().createInverse(); } - catch( NoninvertibleTransformException e ) { + catch (NoninvertibleTransformException e) { e.printStackTrace(); } - - /* Only apply the camera's view transform when this node is a descendant of PLayer */ + + /* + * Only apply the camera's view transform when this node is a descendant + * of PLayer + */ PNode searchNode = node; do { - searchNode = searchNode.getParent(); - if (searchNode instanceof PLayer) { - inverse.transform( pt, pt ); - break; - } - } while(searchNode != null); - - if( node != null ) { - node.globalToLocal( pt ); + searchNode = searchNode.getParent(); + if (searchNode instanceof PLayer) { + inverse.transform(pt, pt); + break; + } + } while (searchNode != null); + + if (node != null) { + node.globalToLocal(pt); } return; } /** - * Process a piccolo event and (if active) dispatch the corresponding Swing event. - * + * Process a piccolo event and (if active) dispatch the corresponding Swing + * event. + * * @param aEvent * @param type */ - public void processEvent( PInputEvent aEvent, int type ) { - if(aEvent.isMouseEvent()) { + public void processEvent(PInputEvent aEvent, int type) { + if (aEvent.isMouseEvent()) { InputEvent sourceSwingEvent = aEvent.getSourceSwingEvent(); if (sourceSwingEvent instanceof MouseEvent) { - MouseEvent swingMouseEvent = (MouseEvent) sourceSwingEvent; - PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( swingMouseEvent.getID(), swingMouseEvent, aEvent ); - if( !recursing ) { + MouseEvent swingMouseEvent = (MouseEvent) sourceSwingEvent; + PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent(swingMouseEvent.getID(), + swingMouseEvent, aEvent); + if (!recursing) { recursing = true; - dispatchEvent( pSwingMouseEvent, aEvent ); + dispatchEvent(pSwingMouseEvent, aEvent); recursing = false; } - } else { - new Exception("PInputEvent.getSourceSwingEvent was not a MouseEvent. Actual event: " + sourceSwingEvent + ", class=" + sourceSwingEvent.getClass().getName() ).printStackTrace(); + } + else { + new Exception("PInputEvent.getSourceSwingEvent was not a MouseEvent. Actual event: " + + sourceSwingEvent + ", class=" + sourceSwingEvent.getClass().getName()).printStackTrace(); } } - -/* if( !( EventQueue.getCurrentEvent() instanceof MouseEvent ) ) { - new Exception( "EventQueue.getCurrentEvent was not a MouseEvent, consider making PInputEvent.getSourceSwingEvent public. Actual event: " + EventQueue.getCurrentEvent() + ", class=" + EventQueue.getCurrentEvent().getClass().getName() ).printStackTrace(); - } - if( aEvent.isMouseEvent() && EventQueue.getCurrentEvent() instanceof MouseEvent ) { - MouseEvent sourceSwingEvent = (MouseEvent)EventQueue.getCurrentEvent(); - PSwingMouseEvent pSwingMouseEvent = PSwingMouseEvent.createMouseEvent( sourceSwingEvent.getID(), sourceSwingEvent, aEvent ); - if( !recursing ) { - recursing = true; - dispatchEvent( pSwingMouseEvent, aEvent ); - recursing = false; - } - } -*/ + + /* + * if( !( EventQueue.getCurrentEvent() instanceof MouseEvent ) ) { new + * Exception( + * "EventQueue.getCurrentEvent was not a MouseEvent, consider making PInputEvent.getSourceSwingEvent public. Actual event: " + * + EventQueue.getCurrentEvent() + ", class=" + + * EventQueue.getCurrentEvent().getClass().getName() + * ).printStackTrace(); } if( aEvent.isMouseEvent() && + * EventQueue.getCurrentEvent() instanceof MouseEvent ) { MouseEvent + * sourceSwingEvent = (MouseEvent)EventQueue.getCurrentEvent(); + * PSwingMouseEvent pSwingMouseEvent = + * PSwingMouseEvent.createMouseEvent( sourceSwingEvent.getID(), + * sourceSwingEvent, aEvent ); if( !recursing ) { recursing = true; + * dispatchEvent( pSwingMouseEvent, aEvent ); recursing = false; } } + */ } /** @@ -424,7 +419,7 @@ private int focusOffX = 0; private int focusOffY = 0; - public void setState( PSwing swing, PNode visualNode, Component comp, int offX, int offY ) { + public void setState(PSwing swing, PNode visualNode, Component comp, int offX, int offY) { focusPSwing = swing; focusComponent = comp; focusNode = visualNode; diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java index e9a49fc..be69302 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseEvent.java @@ -16,8 +16,9 @@ import java.io.Serializable; /** - * PMouseEvent is an event which indicates that a mouse action occurred in a node. - *

+ * PMouseEvent is an event which indicates that a mouse action occurred + * in a node. + *

* This low-level event is generated by a node object for: *

    *
  • Mouse Events @@ -28,21 +29,23 @@ *
  • the mouse cursor enters a node *
  • the mouse cursor exits a node *
- *

- * A PMouseEvent object is passed to every PMouseListener - * or PMouseAdapter object which registered to receive - * the "interesting" mouse events using the component's - * addMouseListener method. - * (PMouseAdapter objects implement the - * PMouseListener interface.) Each such listener object - * gets a PMouseEvent containing the mouse event. - *

- * Warning: Serialized objects of this class will not be - * compatible with future Piccolo releases. The current serialization support is - * appropriate for short term storage or RMI between applications running the - * same version of Piccolo. A future release of Piccolo will provide support for long - * term persistence. - * + *

+ *

+ * A PMouseEvent object is passed to every PMouseListener or + * PMouseAdapter object which registered to receive the + * "interesting" mouse events using the component's + * addMouseListener method. (PMouseAdapter objects + * implement the PMouseListener interface.) Each such listener + * object gets a PMouseEvent containing the mouse event. + *

+ *

+ * Warning: Serialized objects of this class will not be compatible with + * future Piccolo releases. The current serialization support is appropriate for + * short term storage or RMI between applications running the same version of + * Piccolo. A future release of Piccolo will provide support for long term + * persistence. + *

+ * * @author Benjamin B. Bederson * @author Sam R. Reid * @author Lance E. Good @@ -53,50 +56,50 @@ /** * Constructs a new PMouse event from a Java MouseEvent. - * - * @param id The event type (MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_CLICKED, MOUSE_ENTERED, MOUSE_EXITED) - * @param e The original Java mouse event - * when in MOUSE_RELEASED events. + * + * @param id The event type (MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_CLICKED, + * MOUSE_ENTERED, MOUSE_EXITED) + * @param e The original Java mouse event when in MOUSE_RELEASED events. */ - protected PSwingMouseEvent( int id, MouseEvent e, PInputEvent event ) { - super( (Component)e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e.getClickCount(), e.isPopupTrigger() ); + protected PSwingMouseEvent(int id, MouseEvent e, PInputEvent event) { + super((Component) e.getSource(), e.getID(), e.getWhen(), e.getModifiers(), e.getX(), e.getY(), e + .getClickCount(), e.isPopupTrigger()); this.id = id; this.event = event; } /** * Creates and returns a new PMouse event from a Java MouseEvent. - * - * @param id The event type (MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_CLICKED, MOUSE_ENTERED, MOUSE_EXITED, MOUSE_MOVED, MOUSE_DRAGGED) - * @param e The original Java mouse event - * when in MOUSE_DRAGGED and MOUSE_RELEASED events. + * + * @param id The event type (MOUSE_PRESSED, MOUSE_RELEASED, MOUSE_CLICKED, + * MOUSE_ENTERED, MOUSE_EXITED, MOUSE_MOVED, MOUSE_DRAGGED) + * @param e The original Java mouse event when in MOUSE_DRAGGED and + * MOUSE_RELEASED events. */ - public static PSwingMouseEvent createMouseEvent( int id, - MouseEvent e, - PInputEvent pEvent ) { - if( id == PSwingMouseEvent.MOUSE_MOVED || - id == PSwingMouseEvent.MOUSE_DRAGGED ) { - return new PSwingMouseMotionEvent( id, e, pEvent ); + public static PSwingMouseEvent createMouseEvent(int id, MouseEvent e, PInputEvent pEvent) { + if (id == PSwingMouseEvent.MOUSE_MOVED || id == PSwingMouseEvent.MOUSE_DRAGGED) { + return new PSwingMouseMotionEvent(id, e, pEvent); } else { - return new PSwingMouseEvent( id, e, pEvent ); + return new PSwingMouseEvent(id, e, pEvent); } } /** - * Returns the x,y position of the event in the local coordinate system of the node - * the event occurred on. - * - * @return a Point2D object containing the x and y coordinates local to the node. + * Returns the x,y position of the event in the local coordinate system of + * the node the event occurred on. + * + * @return a Point2D object containing the x and y coordinates local to the + * node. */ public Point2D getLocalPoint() { - return new Point2D.Double( getX(), getY() ); + return new Point2D.Double(getX(), getY()); } /** - * Returns the horizontal x position of the event in the local coordinate system - * of the node the event occurred on. - * + * Returns the horizontal x position of the event in the local coordinate + * system of the node the event occurred on. + * * @return x a double indicating horizontal position local to the node. */ public double getLocalX() { @@ -104,9 +107,9 @@ } /** - * Returns the vertical y position of the event in the local coordinate system - * of the node the event occurred on. - * + * Returns the vertical y position of the event in the local coordinate + * system of the node the event occurred on. + * * @return y a double indicating vertical position local to the node. */ public double getLocalY() { @@ -115,7 +118,7 @@ /** * Determine the event type. - * + * * @return the id */ public int getID() { @@ -123,13 +126,13 @@ } /** - * Determine the node the event originated at. If an event percolates - * up the tree and is handled by an event listener higher up in the - * tree than the original node that generated the event, this returns - * the original node. For mouse drag and release events, this is the - * node that the original matching press event went to - in other words, - * the event is 'grabbed' by the originating node. - * + * Determine the node the event originated at. If an event percolates up the + * tree and is handled by an event listener higher up in the tree than the + * original node that generated the event, this returns the original node. + * For mouse drag and release events, this is the node that the original + * matching press event went to - in other words, the event is 'grabbed' by + * the originating node. + * * @return the node */ public PNode getNode() { @@ -137,8 +140,9 @@ } /** - * Determine the path the event took from the PCanvas down to the visual component. - * + * Determine the path the event took from the PCanvas down to the visual + * component. + * * @return the path */ public PPickPath getPath() { @@ -146,13 +150,13 @@ } /** - * Determine the node the event originated at. If an event percolates - * up the tree and is handled by an event listener higher up in the - * tree than the original node that generated the event, this returns - * the original node. For mouse drag and release events, this is the - * node that the original matching press event went to - in other words, - * the event is 'grabbed' by the originating node. - * + * Determine the node the event originated at. If an event percolates up the + * tree and is handled by an event listener higher up in the tree than the + * original node that generated the event, this returns the original node. + * For mouse drag and release events, this is the node that the original + * matching press event went to - in other words, the event is 'grabbed' by + * the originating node. + * * @return the node */ public PNode getGrabNode() { @@ -161,7 +165,7 @@ /** * Return the path from the PCanvas down to the currently grabbed object. - * + * * @return the path */ public PPickPath getGrabPath() { @@ -169,9 +173,10 @@ } /** - * Get the current node that is under the cursor. This may return a different result then getGrabNode() when - * in a MOUSE_RELEASED or MOUSE_DRAGGED event. - * + * Get the current node that is under the cursor. This may return a + * different result then getGrabNode() when in a MOUSE_RELEASED or + * MOUSE_DRAGGED event. + * * @return the current node. */ public PNode getCurrentNode() { @@ -179,9 +184,10 @@ } /** - * Get the path from the PCanvas down to the visual component currently under the mouse.This may - * give a different result then getGrabPath() durring a MOUSE_DRAGGED or MOUSE_RELEASED operation. - * + * Get the path from the PCanvas down to the visual component currently + * under the mouse.This may give a different result then getGrabPath() + * durring a MOUSE_DRAGGED or MOUSE_RELEASED operation. + * * @return the current path. */ public PPickPath getCurrentPath() { @@ -190,54 +196,55 @@ /** * Calls appropriate method on the listener based on this events ID. - * + * * @param listener the MouseListener or MouseMotionListener to dispatch to. */ - public void dispatchTo( Object listener ) { - if( listener instanceof MouseListener ) { - MouseListener mouseListener = (MouseListener)listener; - switch( getID() ) { + public void dispatchTo(Object listener) { + if (listener instanceof MouseListener) { + MouseListener mouseListener = (MouseListener) listener; + switch (getID()) { case PSwingMouseEvent.MOUSE_CLICKED: - mouseListener.mouseClicked( this ); + mouseListener.mouseClicked(this); break; case PSwingMouseEvent.MOUSE_ENTERED: - mouseListener.mouseEntered( this ); + mouseListener.mouseEntered(this); break; case PSwingMouseEvent.MOUSE_EXITED: - mouseListener.mouseExited( this ); + mouseListener.mouseExited(this); break; case PSwingMouseEvent.MOUSE_PRESSED: - mouseListener.mousePressed( this ); + mouseListener.mousePressed(this); break; case PSwingMouseEvent.MOUSE_RELEASED: - mouseListener.mouseReleased( this ); + mouseListener.mouseReleased(this); break; default: - throw new RuntimeException( "PMouseEvent with bad ID" ); + throw new RuntimeException("PMouseEvent with bad ID"); } } else { - MouseMotionListener mouseMotionListener = (MouseMotionListener)listener; - switch( getID() ) { + MouseMotionListener mouseMotionListener = (MouseMotionListener) listener; + switch (getID()) { case PSwingMouseEvent.MOUSE_DRAGGED: - mouseMotionListener.mouseDragged( this ); + mouseMotionListener.mouseDragged(this); break; case PSwingMouseEvent.MOUSE_MOVED: - mouseMotionListener.mouseMoved( this ); + mouseMotionListener.mouseMoved(this); break; default: - throw new RuntimeException( "PMouseMotionEvent with bad ID" ); + throw new RuntimeException("PMouseMotionEvent with bad ID"); } } } /** - * Set the souce of this event. As the event is fired up the tree the source of the - * event will keep changing to reflect the scenegraph object that is firing the event. - * + * Set the souce of this event. As the event is fired up the tree the source + * of the event will keep changing to reflect the scenegraph object that is + * firing the event. + * * @param aSource */ - public void setSource( Object aSource ) { + public void setSource(Object aSource) { source = aSource; } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseMotionEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseMotionEvent.java index ac48daa..93cb2b1 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseMotionEvent.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingMouseMotionEvent.java @@ -10,31 +10,34 @@ import java.awt.event.MouseMotionListener; /** - * PMouseMotionEvent is an event which indicates that a mouse motion action occurred in a node. - *

+ * PMouseMotionEvent is an event which indicates that a mouse motion + * action occurred in a node. + *

* This low-level event is generated by a node object for: *

    - *
  • Mouse Motion Events + *
  • Mouse Motion Events *
      *
    • the mouse is moved *
    • the mouse is dragged *
    *
- *

- * A PMouseEvent object is passed to every PMouseMotionListener - * or PMouseMotionAdapter object which registered to receive - * mouse motion events using the component's addMouseMotionListener + *

+ *

+ * A PMouseEvent object is passed to every PMouseMotionListener or + * PMouseMotionAdapter object which registered to receive mouse + * motion events using the component's addMouseMotionListener * method. (PMouseMotionAdapter objects implement the - * PMouseMotionListener interface.) Each such listener object - * gets a PMouseEvent containing the mouse motion event. - *

- *

- * Warning: Serialized objects of this class will not be - * compatible with future Piccolo releases. The current serialization support is - * appropriate for short term storage or RMI between applications running the - * same version of Piccolo. A future release of Piccolo will provide support for long - * term persistence. - * + * PMouseMotionListener interface.) Each such listener object gets + * a PMouseEvent containing the mouse motion event. + *

+ *

+ * Warning: Serialized objects of this class will not be compatible with + * future Piccolo releases. The current serialization support is appropriate for + * short term storage or RMI between applications running the same version of + * Piccolo. A future release of Piccolo will provide support for long term + * persistence. + *

+ * * @author Benjamin B. Bederson * @author Sam R. Reid * @author Lance E. Good @@ -43,31 +46,30 @@ /** * Constructs a new PMouse event from a Java MouseEvent. - * + * * @param id The event type (MOUSE_MOVED, MOUSE_DRAGGED) - * @param e The original Java mouse event - * when in MOUSE_DRAGGED events. + * @param e The original Java mouse event when in MOUSE_DRAGGED events. */ - protected PSwingMouseMotionEvent( int id, MouseEvent e, PInputEvent event ) { - super( id, e, event ); + protected PSwingMouseMotionEvent(int id, MouseEvent e, PInputEvent event) { + super(id, e, event); } /** * Calls appropriate method on the listener based on this events ID. - * + * * @param listener the target for dispatch. */ - public void dispatchTo( Object listener ) { - MouseMotionListener mouseMotionListener = (MouseMotionListener)listener; - switch( getID() ) { + public void dispatchTo(Object listener) { + MouseMotionListener mouseMotionListener = (MouseMotionListener) listener; + switch (getID()) { case PSwingMouseEvent.MOUSE_DRAGGED: - mouseMotionListener.mouseDragged( this ); + mouseMotionListener.mouseDragged(this); break; case PSwingMouseEvent.MOUSE_MOVED: - mouseMotionListener.mouseMoved( this ); + mouseMotionListener.mouseMoved(this); break; default: - throw new RuntimeException( "PMouseMotionEvent with bad ID" ); + throw new RuntimeException("PMouseMotionEvent with bad ID"); } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java index 7b9a823..132f670 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/pswing/PSwingRepaintManager.java @@ -18,33 +18,35 @@ import java.util.Vector; /** - * This RepaintManager replaces the default Swing implementation, and - * is used to intercept and repaint dirty regions of PSwing components. - *

- * This is an internal class used by Piccolo to support Swing components - * in Piccolo. This should not be instantiated, though all the public - * methods of javax.swing.RepaintManager may still be called and - * perform in the expected manner. - *

- * PBasicRepaint Manager is an extension of RepaintManager that traps - * those repaints called by the Swing components that have been added - * to the PCanvas and passes these repaints to the - * SwingVisualComponent rather than up the component hierarchy as - * usually happens. - *

- * Also traps revalidate calls made by the Swing components added - * to the PCanvas to reshape the applicable Visual Component. - *

- * Also keeps a list of PSwings that are painting. This - * disables repaint until the component has finished painting. This is - * to address a problem introduced by Swing's CellRendererPane which is - * itself a work-around. The problem is that JTable's, JTree's, and - * JList's cell renderers need to be validated before repaint. Since - * we have to repaint the entire Swing component hierarchy (in the case - * of a Swing component group used as a Piccolo visual component). This - * causes an infinite loop. So we introduce the restriction that no + * This RepaintManager replaces the default Swing implementation, and is used to + * intercept and repaint dirty regions of PSwing components. + *

+ * This is an internal class used by Piccolo to support Swing components in + * Piccolo. This should not be instantiated, though all the public methods of + * javax.swing.RepaintManager may still be called and perform in the expected + * manner. + *

+ *

+ * PBasicRepaint Manager is an extension of RepaintManager that traps those + * repaints called by the Swing components that have been added to the PCanvas + * and passes these repaints to the SwingVisualComponent rather than up the + * component hierarchy as usually happens. + *

+ *

+ * Also traps revalidate calls made by the Swing components added to the PCanvas + * to reshape the applicable Visual Component. + *

+ *

+ * Also keeps a list of PSwings that are painting. This disables repaint until + * the component has finished painting. This is to address a problem introduced + * by Swing's CellRendererPane which is itself a work-around. The problem is + * that JTable's, JTree's, and JList's cell renderers need to be validated + * before repaint. Since we have to repaint the entire Swing component hierarchy + * (in the case of a Swing component group used as a Piccolo visual component). + * This causes an infinite loop. So we introduce the restriction that no * repaints can be triggered by a call to paint. - * + *

+ * * @author Benjamin B. Bederson * @author Lance E. Good * @author Sam R. Reid @@ -57,67 +59,64 @@ private Vector paintingComponents = new Vector(); /** - * Locks repaint for a particular (Swing) component displayed by - * PCanvas - * + * Locks repaint for a particular (Swing) component displayed by PCanvas + * * @param c The component for which the repaint is to be locked */ - public void lockRepaint( JComponent c ) { - paintingComponents.addElement( c ); + public void lockRepaint(JComponent c) { + paintingComponents.addElement(c); } /** - * Unlocks repaint for a particular (Swing) component displayed by - * PCanvas - * + * Unlocks repaint for a particular (Swing) component displayed by PCanvas + * * @param c The component for which the repaint is to be unlocked */ - public void unlockRepaint( JComponent c ) { - synchronized( paintingComponents ) { - paintingComponents.removeElementAt( paintingComponents.lastIndexOf( c ) ); + public void unlockRepaint(JComponent c) { + synchronized (paintingComponents) { + paintingComponents.removeElementAt(paintingComponents.lastIndexOf(c)); } } /** - * Returns true if repaint is currently locked for a component and - * false otherwise - * + * Returns true if repaint is currently locked for a component and false + * otherwise + * * @param c The component for which the repaint status is desired * @return Whether the component is currently painting */ - public boolean isPainting( JComponent c ) { - return paintingComponents.contains( c ); + public boolean isPainting(JComponent c) { + return paintingComponents.contains(c); } /** * This is the method "repaint" now calls in the Swing components. - * Overridden to capture repaint calls from those Swing components - * which are being used as Piccolo visual components and to call the Piccolo - * repaint mechanism rather than the traditional Component hierarchy - * repaint mechanism. Otherwise, behaves like the superclass. - * + * Overridden to capture repaint calls from those Swing components which are + * being used as Piccolo visual components and to call the Piccolo repaint + * mechanism rather than the traditional Component hierarchy repaint + * mechanism. Otherwise, behaves like the superclass. + * * @param c Component to be repainted * @param x X coordinate of the dirty region in the component * @param y Y coordinate of the dirty region in the component * @param w Width of the dirty region in the component * @param h Height of the dirty region in the component */ - public synchronized void addDirtyRegion( JComponent c, int x, int y, final int w, final int h ) { -// System.out.println( "PSwingCanvas$PBasicRepaintManager.addDirtyRegion, c="+c.getClass()+", rect=["+x+", "+y+", "+w+", " +", "+h+"], c="+c); + public synchronized void addDirtyRegion(JComponent c, int x, int y, final int w, final int h) { boolean captureRepaint = false; JComponent capturedComponent = null; int captureX = x, captureY = y; // We have to check to see if the PCanvas - // (ie. the SwingWrapper) is in the components ancestry. If so, - // we will want to capture that repaint. However, we also will + // (ie. the SwingWrapper) is in the components ancestry. If so, + // we will want to capture that repaint. However, we also will // need to translate the repaint request since the component may // be offset inside another component. - for( Component comp = c; comp != null && comp.isLightweight() && !captureRepaint; comp = comp.getParent() ) { - if( swingWrappers.contains( comp.getParent() ) ) { - if( comp instanceof JComponent ) { + for (Component comp = c; comp != null && comp.isLightweight() && !captureRepaint; comp = comp.getParent()) { + if (swingWrappers.contains(comp.getParent())) { + if (comp instanceof JComponent) { captureRepaint = true; - capturedComponent = (JComponent)comp; + capturedComponent = (JComponent) comp; } } else { @@ -129,58 +128,57 @@ // Now we check to see if we should capture the repaint and act // accordingly - if( captureRepaint ) { - if( !isPainting( capturedComponent ) ) { - final PSwing vis = (PSwing)capturedComponent.getClientProperty( PSwing.PSWING_PROPERTY ); - if( vis != null ) { + if (captureRepaint) { + if (!isPainting(capturedComponent)) { + final PSwing vis = (PSwing) capturedComponent.getClientProperty(PSwing.PSWING_PROPERTY); + if (vis != null) { final int repaintX = captureX; final int repaintY = captureY; Runnable repainter = new Runnable() { public void run() { - vis.repaint( new PBounds( (double)repaintX, (double)repaintY, (double)w, (double)h ) ); + vis.repaint(new PBounds((double) repaintX, (double) repaintY, (double) w, (double) h)); } }; - SwingUtilities.invokeLater( repainter ); + SwingUtilities.invokeLater(repainter); } } } else { - super.addDirtyRegion( c, x, y, w, h ); + super.addDirtyRegion(c, x, y, w, h); } } /** - * This is the method "revalidate" calls in the Swing components. - * Overridden to capture revalidate calls from those Swing components - * being used as Piccolo visual components and to update Piccolo's visual - * component wrapper bounds (these are stored separately from the - * Swing component). Otherwise, behaves like the superclass. - * + * This is the method "revalidate" calls in the Swing components. Overridden + * to capture revalidate calls from those Swing components being used as + * Piccolo visual components and to update Piccolo's visual component + * wrapper bounds (these are stored separately from the Swing component). + * Otherwise, behaves like the superclass. + * * @param invalidComponent The Swing component that needs validation */ - public synchronized void addInvalidComponent( JComponent invalidComponent ) { + public synchronized void addInvalidComponent(JComponent invalidComponent) { final JComponent capturedComponent = invalidComponent; - if( capturedComponent.getParent() != null && - capturedComponent.getParent() instanceof JComponent && - ( (JComponent)capturedComponent.getParent() ).getClientProperty( PSwingCanvas.SWING_WRAPPER_KEY ) != null ) - { + if (capturedComponent.getParent() != null + && capturedComponent.getParent() instanceof JComponent + && ((JComponent) capturedComponent.getParent()).getClientProperty(PSwingCanvas.SWING_WRAPPER_KEY) != null) { Runnable validater = new Runnable() { public void run() { capturedComponent.validate(); - PSwing swing = (PSwing)capturedComponent.getClientProperty( PSwing.PSWING_PROPERTY ); + PSwing swing = (PSwing) capturedComponent.getClientProperty(PSwing.PSWING_PROPERTY); swing.reshape(); } }; - SwingUtilities.invokeLater( validater ); + SwingUtilities.invokeLater(validater); } else { - super.addInvalidComponent( invalidComponent ); + super.addInvalidComponent(invalidComponent); } } - void addPSwingCanvas( PSwingCanvas swingWrapper ) { - swingWrappers.add( swingWrapper.getSwingWrapper() ); + void addPSwingCanvas(PSwingCanvas swingWrapper) { + swingWrappers.add(swingWrapper.getSwingWrapper()); } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PCacheCanvas.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PCacheCanvas.java index 8ab0bd1..9729f0b 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PCacheCanvas.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PCacheCanvas.java @@ -11,18 +11,19 @@ /** * An extension of PCanvas that automatically installs a PCacheCamera + * * @author Lance Good */ public class PCacheCanvas extends PCanvas { protected PCamera createDefaultCamera() { - PRoot r = new PRoot(); - PLayer l = new PLayer(); - PCamera c = new PCacheCamera(); - - r.addChild(c); - r.addChild(l); - c.addLayer(l); - - return c; + PRoot r = new PRoot(); + PLayer l = new PLayer(); + PCamera c = new PCacheCamera(); + + r.addChild(c); + r.addChild(l); + c.addLayer(l); + + return c; } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PDefaultScrollDirector.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PDefaultScrollDirector.java index e3c3177..1e7a89f 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PDefaultScrollDirector.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PDefaultScrollDirector.java @@ -32,255 +32,264 @@ * follows the widely accepted model of scrolling - namely the scrollbars * control the movement of the window over the document rather than the movement * of the document under the window. - * + * * @author Lance Good */ public class PDefaultScrollDirector implements PScrollDirector, PropertyChangeListener { - /** - * The viewport that signals this scroll director - */ - protected PViewport viewPort; + /** + * The viewport that signals this scroll director + */ + protected PViewport viewPort; - /** - * The scrollpane that contains the viewport - */ - protected PScrollPane scrollPane; + /** + * The scrollpane that contains the viewport + */ + protected PScrollPane scrollPane; - /** - * The canvas that this class directs - */ - protected PCanvas view; + /** + * The canvas that this class directs + */ + protected PCanvas view; - /** - * The canvas' camera - */ - protected PCamera camera; + /** + * The canvas' camera + */ + protected PCamera camera; - /** - * The canvas' root - */ - protected PRoot root; + /** + * The canvas' root + */ + protected PRoot root; - /** - * Flag to indicate when scrolling is currently in progress - */ - protected boolean scrollInProgress = false; + /** + * Flag to indicate when scrolling is currently in progress + */ + protected boolean scrollInProgress = false; - /** - * The default constructor - */ - public PDefaultScrollDirector() { - } + /** + * The default constructor + */ + public PDefaultScrollDirector() { + } - /** - * Installs the scroll director and adds the appropriate listeners - * @param viewPort The viewport on which this director directs - * @param view The ZCanvas that the viewport looks at - */ - public void install(PViewport viewPort, final PCanvas view) { - this.scrollPane = (PScrollPane) viewPort.getParent(); - this.viewPort = viewPort; - this.view = view; + /** + * Installs the scroll director and adds the appropriate listeners + * + * @param viewPort The viewport on which this director directs + * @param view The ZCanvas that the viewport looks at + */ + public void install(PViewport viewPort, final PCanvas view) { + this.scrollPane = (PScrollPane) viewPort.getParent(); + this.viewPort = viewPort; + this.view = view; - if (view != null) { - this.camera = view.getCamera(); - this.root = view.getRoot(); - } + if (view != null) { + this.camera = view.getCamera(); + this.root = view.getRoot(); + } - if (camera != null) { - camera.addPropertyChangeListener(this); - } - if (root != null) { - root.addPropertyChangeListener(this); - } + if (camera != null) { + camera.addPropertyChangeListener(this); + } + if (root != null) { + root.addPropertyChangeListener(this); + } - if (scrollPane != null) { - scrollPane.revalidate(); - } - } + if (scrollPane != null) { + scrollPane.revalidate(); + } + } - /** - * Uninstall the scroll director from the viewport - */ - public void unInstall() { - viewPort = null; - view = null; + /** + * Uninstall the scroll director from the viewport + */ + public void unInstall() { + viewPort = null; + view = null; - if (camera != null) { - camera.removePropertyChangeListener(this); - } - if (root != null) { - root.removePropertyChangeListener(this); - } + if (camera != null) { + camera.removePropertyChangeListener(this); + } + if (root != null) { + root.removePropertyChangeListener(this); + } - camera = null; - root = null; - } + camera = null; + root = null; + } - /** - * Get the View position given the specified camera bounds - * @param viewBounds The bounds for which the view position will be computed - * @return The view position - */ - public Point getViewPosition(Rectangle2D viewBounds) { - Point pos = new Point(); - if (camera != null) { - // First we compute the union of all the layers - PBounds layerBounds = new PBounds(); - List layers = camera.getLayersReference(); - for(Iterator i=layers.iterator(); i.hasNext();) { - PLayer layer = (PLayer)i.next(); - layerBounds.add(layer.getFullBoundsReference()); - } + /** + * Get the View position given the specified camera bounds + * + * @param viewBounds The bounds for which the view position will be computed + * @return The view position + */ + public Point getViewPosition(Rectangle2D viewBounds) { + Point pos = new Point(); + if (camera != null) { + // First we compute the union of all the layers + PBounds layerBounds = new PBounds(); + List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + layerBounds.add(layer.getFullBoundsReference()); + } - // Then we put the bounds into camera coordinates and - // union the camera bounds - camera.viewToLocal(layerBounds); - layerBounds.add(viewBounds); + // Then we put the bounds into camera coordinates and + // union the camera bounds + camera.viewToLocal(layerBounds); + layerBounds.add(viewBounds); - pos.setLocation((int) (viewBounds.getX() - layerBounds.getX() + 0.5), (int) (viewBounds.getY() - layerBounds.getY() + 0.5)); - } + pos.setLocation((int) (viewBounds.getX() - layerBounds.getX() + 0.5), (int) (viewBounds.getY() + - layerBounds.getY() + 0.5)); + } - return pos; - } + return pos; + } - /** - * Get the size of the view based on the specified camera bounds - * @param viewBounds The view bounds for which the view size will be computed - * @return The view size - */ - public Dimension getViewSize(Rectangle2D viewBounds) { - Dimension size = new Dimension(); - if (camera != null) { - // First we compute the union of all the layers - PBounds bounds = new PBounds(); - List layers = camera.getLayersReference(); - for(Iterator i=layers.iterator(); i.hasNext();) { - PLayer layer = (PLayer)i.next(); - bounds.add(layer.getFullBoundsReference()); - } + /** + * Get the size of the view based on the specified camera bounds + * + * @param viewBounds The view bounds for which the view size will be + * computed + * @return The view size + */ + public Dimension getViewSize(Rectangle2D viewBounds) { + Dimension size = new Dimension(); + if (camera != null) { + // First we compute the union of all the layers + PBounds bounds = new PBounds(); + List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + bounds.add(layer.getFullBoundsReference()); + } - // Then we put the bounds into camera coordinates and - // union the camera bounds - if (!bounds.isEmpty()) { - camera.viewToLocal(bounds); - } - bounds.add(viewBounds); + // Then we put the bounds into camera coordinates and + // union the camera bounds + if (!bounds.isEmpty()) { + camera.viewToLocal(bounds); + } + bounds.add(viewBounds); - size.setSize((int) (bounds.getWidth() + 0.5), (int) (bounds.getHeight() + 0.5)); - } + size.setSize((int) (bounds.getWidth() + 0.5), (int) (bounds.getHeight() + 0.5)); + } - return size; - } + return size; + } - /** - * Set the view position in a manner consistent with standardized scrolling - * @param x The new x position - * @param y The new y position - */ - public void setViewPosition(double x, double y) { - if (camera != null) { - // If a scroll is in progress - we ignore new scrolls - - // if we didn't, since the scrollbars depend on the camera location - // we can end up with an infinite loop - if (!scrollInProgress) { - scrollInProgress = true; + /** + * Set the view position in a manner consistent with standardized scrolling + * + * @param x The new x position + * @param y The new y position + */ + public void setViewPosition(double x, double y) { + if (camera != null) { + // If a scroll is in progress - we ignore new scrolls - + // if we didn't, since the scrollbars depend on the camera location + // we can end up with an infinite loop + if (!scrollInProgress) { + scrollInProgress = true; - // Get the union of all the layers' bounds - PBounds layerBounds = new PBounds(); - List layers = camera.getLayersReference(); - for(Iterator i=layers.iterator(); i.hasNext();) { - PLayer layer = (PLayer)i.next(); - layerBounds.add(layer.getFullBoundsReference()); - } - - PAffineTransform at = camera.getViewTransform(); - at.transform(layerBounds,layerBounds); + // Get the union of all the layers' bounds + PBounds layerBounds = new PBounds(); + List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + layerBounds.add(layer.getFullBoundsReference()); + } - // Union the camera bounds - PBounds viewBounds = camera.getBoundsReference(); - layerBounds.add(viewBounds); + PAffineTransform at = camera.getViewTransform(); + at.transform(layerBounds, layerBounds); - // Now find the new view position in view coordinates - Point2D newPoint = new Point2D.Double(layerBounds.getX() + x, layerBounds.getY() + y); + // Union the camera bounds + PBounds viewBounds = camera.getBoundsReference(); + layerBounds.add(viewBounds); - // Now transform the new view position into global coords - camera.localToView(newPoint); + // Now find the new view position in view coordinates + Point2D newPoint = new Point2D.Double(layerBounds.getX() + x, layerBounds.getY() + y); - // Compute the new matrix values to put the camera at the - // correct location - double newX = - (at.getScaleX() * newPoint.getX() + at.getShearX() * newPoint.getY()); - double newY = - (at.getShearY() * newPoint.getX() + at.getScaleY() * newPoint.getY()); + // Now transform the new view position into global coords + camera.localToView(newPoint); - at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), newX, newY); + // Compute the new matrix values to put the camera at the + // correct location + double newX = -(at.getScaleX() * newPoint.getX() + at.getShearX() * newPoint.getY()); + double newY = -(at.getShearY() * newPoint.getX() + at.getScaleY() * newPoint.getY()); - // Now actually set the camera's transform - camera.setViewTransform(at); - scrollInProgress = false; - } - } - } + at.setTransform(at.getScaleX(), at.getShearY(), at.getShearX(), at.getScaleY(), newX, newY); - /** - * Invoked when the camera's view changes, or the bounds of the root or camera changes - */ - public void propertyChange(PropertyChangeEvent pce) { - boolean isRelevantViewEvent = (PCamera.PROPERTY_VIEW_TRANSFORM == pce.getPropertyName()); - boolean isRelevantBoundsEvent = (PNode.PROPERTY_BOUNDS == pce.getPropertyName() || PNode.PROPERTY_FULL_BOUNDS == pce.getPropertyName()) && (pce.getSource() == camera || pce.getSource() == view.getRoot()); - if (isRelevantViewEvent || isRelevantBoundsEvent) { - if (shouldRevalidateScrollPane()) { - scrollPane.revalidate(); - } - else { - viewPort.fireStateChanged(); - } - } - } + // Now actually set the camera's transform + camera.setViewTransform(at); + scrollInProgress = false; + } + } + } - /** - * Should the ScrollPane be revalidated. This occurs when either the - * scrollbars are showing and should be remove or are not showing and should - * be added. - * - * @return Whether the scroll pane should be revalidated - */ - public boolean shouldRevalidateScrollPane() { - if (camera != null) { - if (scrollPane.getHorizontalScrollBarPolicy() != JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED - && scrollPane.getVerticalScrollBarPolicy() != JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED) { - return false; - } - - // Get the union of all the layers' bounds - PBounds layerBounds = new PBounds(); - List layers = camera.getLayersReference(); - for(Iterator i=layers.iterator(); i.hasNext();) { - PLayer layer = (PLayer)i.next(); - layerBounds.add(layer.getFullBoundsReference()); - } + /** + * Invoked when the camera's view changes, or the bounds of the root or + * camera changes + */ + public void propertyChange(PropertyChangeEvent pce) { + boolean isRelevantViewEvent = (PCamera.PROPERTY_VIEW_TRANSFORM == pce.getPropertyName()); + boolean isRelevantBoundsEvent = (PNode.PROPERTY_BOUNDS == pce.getPropertyName() || PNode.PROPERTY_FULL_BOUNDS == pce + .getPropertyName()) + && (pce.getSource() == camera || pce.getSource() == view.getRoot()); + if (isRelevantViewEvent || isRelevantBoundsEvent) { + if (shouldRevalidateScrollPane()) { + scrollPane.revalidate(); + } + else { + viewPort.fireStateChanged(); + } + } + } - // Put into camera coordinates - camera.viewToLocal(layerBounds); + /** + * Should the ScrollPane be revalidated. This occurs when either the + * scrollbars are showing and should be remove or are not showing and should + * be added. + * + * @return Whether the scroll pane should be revalidated + */ + public boolean shouldRevalidateScrollPane() { + if (camera != null) { + if (scrollPane.getHorizontalScrollBarPolicy() != JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED + && scrollPane.getVerticalScrollBarPolicy() != JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED) { + return false; + } - // And union with the camera bounds - PBounds cameraBounds = camera.getBoundsReference(); - layerBounds.add(cameraBounds); + // Get the union of all the layers' bounds + PBounds layerBounds = new PBounds(); + List layers = camera.getLayersReference(); + for (Iterator i = layers.iterator(); i.hasNext();) { + PLayer layer = (PLayer) i.next(); + layerBounds.add(layer.getFullBoundsReference()); + } - // Truncate these to ints before comparing since - // that's what the ScrollPane uses - int layerWidth = (int) (layerBounds.getWidth() + 0.5); - int layerHeight = (int) (layerBounds.getHeight() + 0.5); - int cameraWidth = (int) (cameraBounds.getWidth() + 0.5); - int cameraHeight = (int) (cameraBounds.getHeight() + 0.5); + // Put into camera coordinates + camera.viewToLocal(layerBounds); - if ((scrollPane.getHorizontalScrollBar().isShowing() && layerWidth <= cameraWidth) - || (!scrollPane.getHorizontalScrollBar().isShowing() && layerWidth > cameraWidth) - || (scrollPane.getVerticalScrollBar().isShowing() && layerHeight <= cameraHeight) - || (!scrollPane.getVerticalScrollBar().isShowing() && layerHeight > cameraHeight)) { - return true; - } - } - return false; - } + // And union with the camera bounds + PBounds cameraBounds = camera.getBoundsReference(); + layerBounds.add(cameraBounds); + + // Truncate these to ints before comparing since + // that's what the ScrollPane uses + int layerWidth = (int) (layerBounds.getWidth() + 0.5); + int layerHeight = (int) (layerBounds.getHeight() + 0.5); + int cameraWidth = (int) (cameraBounds.getWidth() + 0.5); + int cameraHeight = (int) (cameraBounds.getHeight() + 0.5); + + if ((scrollPane.getHorizontalScrollBar().isShowing() && layerWidth <= cameraWidth) + || (!scrollPane.getHorizontalScrollBar().isShowing() && layerWidth > cameraWidth) + || (scrollPane.getVerticalScrollBar().isShowing() && layerHeight <= cameraHeight) + || (!scrollPane.getVerticalScrollBar().isShowing() && layerHeight > cameraHeight)) { + return true; + } + } + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollDirector.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollDirector.java index 87c4f03..d31fa3a 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollDirector.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollDirector.java @@ -16,42 +16,47 @@ /** * The interface an application can implement to control scrolling in a * PScrollPane->PViewport->ZCanvas component hierarchy. + * * @see PDefaultScrollDirector * @author Lance Good */ public interface PScrollDirector { - /** - * Installs the scroll director - * @param viewport The viewport on which this director directs - * @param view The ZCanvas that the viewport looks at - */ - public void install(PViewport viewport, PCanvas view); + /** + * Installs the scroll director + * + * @param viewport The viewport on which this director directs + * @param view The ZCanvas that the viewport looks at + */ + public void install(PViewport viewport, PCanvas view); - /** - * Uninstall the scroll director - */ - public void unInstall(); + /** + * Uninstall the scroll director + */ + public void unInstall(); - /** - * Get the View position given the specified camera bounds - * @param viewBounds The bounds for which the view position will be computed - * @return The view position - */ - public Point getViewPosition(Rectangle2D viewBounds); + /** + * Get the View position given the specified camera bounds + * + * @param viewBounds The bounds for which the view position will be computed + * @return The view position + */ + public Point getViewPosition(Rectangle2D viewBounds); + /** + * Set the view position + * + * @param x The new x position + * @param y The new y position + */ + public void setViewPosition(double x, double y); - /** - * Set the view position - * @param x The new x position - * @param y The new y position - */ - public void setViewPosition(double x, double y); - - /** - * Get the size of the view based on the specified camera bounds - * @param viewBounds The view bounds for which the view size will be computed - * @return The view size - */ - public Dimension getViewSize(Rectangle2D viewBounds); + /** + * Get the size of the view based on the specified camera bounds + * + * @param viewBounds The view bounds for which the view size will be + * computed + * @return The view size + */ + public Dimension getViewSize(Rectangle2D viewBounds); } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPane.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPane.java index a14ba50..a4b1579 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPane.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPane.java @@ -23,277 +23,279 @@ import javax.swing.plaf.ScrollPaneUI; /** - * A simple extension to a standard scroll pane that uses the jazz version - * of the viewport by default. Also uses the jazz version of ScrollPaneLayout - * + * A simple extension to a standard scroll pane that uses the jazz version of + * the viewport by default. Also uses the jazz version of ScrollPaneLayout + * * @author Lance Good */ public class PScrollPane extends JScrollPane { - // A reusable null action - protected PNullAction nullAction = null; + // A reusable null action + protected PNullAction nullAction = null; - // Are key actions disabled on this component? - protected boolean disableKeyActions = false; + // Are key actions disabled on this component? + protected boolean disableKeyActions = false; - /** - * Pass on the constructor info to the super - */ - public PScrollPane(Component view, int vsbPolicy, int hsbPolicy) { - super(view, vsbPolicy, hsbPolicy); + /** + * Pass on the constructor info to the super + */ + public PScrollPane(Component view, int vsbPolicy, int hsbPolicy) { + super(view, vsbPolicy, hsbPolicy); - // Set the layout and sync it with the scroll pane - PScrollPaneLayout layout = new PScrollPaneLayout.UIResource(); - setLayout(layout); - layout.syncWithScrollPane(this); - } + // Set the layout and sync it with the scroll pane + PScrollPaneLayout layout = new PScrollPaneLayout.UIResource(); + setLayout(layout); + layout.syncWithScrollPane(this); + } - /** - * Pass on the constructor info to the super - */ - public PScrollPane(Component view) { - this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); - } + /** + * Pass on the constructor info to the super + */ + public PScrollPane(Component view) { + this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); + } - /** - * Pass on the constructor info to the super - */ - public PScrollPane(int vsbPolicy, int hsbPolicy) { - this(null, vsbPolicy, hsbPolicy); - } + /** + * Pass on the constructor info to the super + */ + public PScrollPane(int vsbPolicy, int hsbPolicy) { + this(null, vsbPolicy, hsbPolicy); + } - /** - * Pass on the constructor info to the super - */ - public PScrollPane() { - this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); - } + /** + * Pass on the constructor info to the super + */ + public PScrollPane() { + this(null, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); + } - /** - * Disable or enable key actions on this PScrollPane - * @param disable true disables key actions, false enables key actions - */ - public void setKeyActionsDisabled(boolean disable) { - if (disable && this.disableKeyActions != disable) { - this.disableKeyActions = disable; - disableKeyActions(); - } - else if (!disable && this.disableKeyActions != disable) { - this.disableKeyActions = disable; - installCustomKeyActions(); - } - } + /** + * Disable or enable key actions on this PScrollPane + * + * @param disable true disables key actions, false enables key actions + */ + public void setKeyActionsDisabled(boolean disable) { + if (disable && this.disableKeyActions != disable) { + this.disableKeyActions = disable; + disableKeyActions(); + } + else if (!disable && this.disableKeyActions != disable) { + this.disableKeyActions = disable; + installCustomKeyActions(); + } + } - /** - * Sets the UI - */ - public void setUI(ScrollPaneUI ui) { - super.setUI(ui); + /** + * Sets the UI + */ + public void setUI(ScrollPaneUI ui) { + super.setUI(ui); - if (!disableKeyActions) { - installCustomKeyActions(); - } - else { - disableKeyActions(); - } - } + if (!disableKeyActions) { + installCustomKeyActions(); + } + else { + disableKeyActions(); + } + } - /** - * Install custom key actions (in place of the Swing defaults) to - * correctly scroll the view - */ - protected void installCustomKeyActions() { - ActionMap map = getActionMap(); + /** + * Install custom key actions (in place of the Swing defaults) to correctly + * scroll the view + */ + protected void installCustomKeyActions() { + ActionMap map = getActionMap(); - map.put("scrollUp", new PScrollAction("scrollUp", SwingConstants.VERTICAL, -1, true)); - map.put("scrollDown", new PScrollAction("scrollDown", SwingConstants.VERTICAL, 1, true)); - map.put("scrollLeft", new PScrollAction("scrollLeft", SwingConstants.HORIZONTAL, -1, true)); + map.put("scrollUp", new PScrollAction("scrollUp", SwingConstants.VERTICAL, -1, true)); + map.put("scrollDown", new PScrollAction("scrollDown", SwingConstants.VERTICAL, 1, true)); + map.put("scrollLeft", new PScrollAction("scrollLeft", SwingConstants.HORIZONTAL, -1, true)); - map.put("scrollRight", new PScrollAction("ScrollRight", SwingConstants.HORIZONTAL, 1, true)); - map.put("unitScrollRight", new PScrollAction("UnitScrollRight", SwingConstants.HORIZONTAL, 1, false)); - map.put("unitScrollLeft", new PScrollAction("UnitScrollLeft", SwingConstants.HORIZONTAL, -1, false)); - map.put("unitScrollUp", new PScrollAction("UnitScrollUp", SwingConstants.VERTICAL, -1, false)); - map.put("unitScrollDown", new PScrollAction("UnitScrollDown", SwingConstants.VERTICAL, 1, false)); + map.put("scrollRight", new PScrollAction("ScrollRight", SwingConstants.HORIZONTAL, 1, true)); + map.put("unitScrollRight", new PScrollAction("UnitScrollRight", SwingConstants.HORIZONTAL, 1, false)); + map.put("unitScrollLeft", new PScrollAction("UnitScrollLeft", SwingConstants.HORIZONTAL, -1, false)); + map.put("unitScrollUp", new PScrollAction("UnitScrollUp", SwingConstants.VERTICAL, -1, false)); + map.put("unitScrollDown", new PScrollAction("UnitScrollDown", SwingConstants.VERTICAL, 1, false)); - map.put("scrollEnd", new PScrollEndAction("ScrollEnd")); - map.put("scrollHome", new PScrollHomeAction("ScrollHome")); - } + map.put("scrollEnd", new PScrollEndAction("ScrollEnd")); + map.put("scrollHome", new PScrollHomeAction("ScrollHome")); + } - /** - * Disables key actions on this PScrollPane - */ - protected void disableKeyActions() { - ActionMap map = getActionMap(); + /** + * Disables key actions on this PScrollPane + */ + protected void disableKeyActions() { + ActionMap map = getActionMap(); - if (nullAction == null) { - nullAction = new PNullAction(); - } + if (nullAction == null) { + nullAction = new PNullAction(); + } - map.put("scrollUp", nullAction); - map.put("scrollDown", nullAction); - map.put("scrollLeft", nullAction); - map.put("scrollRight", nullAction); - map.put("unitScrollRight", nullAction); - map.put("unitScrollLeft", nullAction); - map.put("unitScrollUp", nullAction); - map.put("unitScrollDown", nullAction); - map.put("scrollEnd", nullAction); - map.put("scrollHome", nullAction); - } + map.put("scrollUp", nullAction); + map.put("scrollDown", nullAction); + map.put("scrollLeft", nullAction); + map.put("scrollRight", nullAction); + map.put("unitScrollRight", nullAction); + map.put("unitScrollLeft", nullAction); + map.put("unitScrollUp", nullAction); + map.put("unitScrollDown", nullAction); + map.put("scrollEnd", nullAction); + map.put("scrollHome", nullAction); + } - /** - * Overridden to create the Jazz viewport - * @return The jazz version of the viewport - */ - protected JViewport createViewport() { - return new PViewport(); - } + /** + * Overridden to create the Jazz viewport + * + * @return The jazz version of the viewport + */ + protected JViewport createViewport() { + return new PViewport(); + } - /** - * Action to scroll left/right/up/down. - * Modified from javax.swing.plaf.basic.BasicScrollPaneUI.ScrollAction - * - * Gets the view parameters (position and size) from the Viewport - * rather than directly from the view - also only performs its actions - * when the relevant scrollbar is visible - */ - protected static class PScrollAction extends AbstractAction { - /** Direction to scroll. */ - protected int orientation; - /** 1 indicates scroll down, -1 up. */ - protected int direction; - /** True indicates a block scroll, otherwise a unit scroll. */ - private boolean block; + /** + * Action to scroll left/right/up/down. Modified from + * javax.swing.plaf.basic.BasicScrollPaneUI.ScrollAction + * + * Gets the view parameters (position and size) from the Viewport rather + * than directly from the view - also only performs its actions when the + * relevant scrollbar is visible + */ + protected static class PScrollAction extends AbstractAction { + /** Direction to scroll. */ + protected int orientation; + /** 1 indicates scroll down, -1 up. */ + protected int direction; + /** True indicates a block scroll, otherwise a unit scroll. */ + private boolean block; - protected PScrollAction(String name, int orientation, int direction, boolean block) { - super(name); - this.orientation = orientation; - this.direction = direction; - this.block = block; - } + protected PScrollAction(String name, int orientation, int direction, boolean block) { + super(name); + this.orientation = orientation; + this.direction = direction; + this.block = block; + } - public void actionPerformed(ActionEvent e) { - JScrollPane scrollpane = (JScrollPane) e.getSource(); - // LEG: Modification to only perform these actions if the relevant - // scrollbar is actually showing - if ((orientation == SwingConstants.VERTICAL && scrollpane.getVerticalScrollBar().isShowing()) - || (orientation == SwingConstants.HORIZONTAL && scrollpane.getHorizontalScrollBar().isShowing())) { + public void actionPerformed(ActionEvent e) { + JScrollPane scrollpane = (JScrollPane) e.getSource(); + // LEG: Modification to only perform these actions if the relevant + // scrollbar is actually showing + if ((orientation == SwingConstants.VERTICAL && scrollpane.getVerticalScrollBar().isShowing()) + || (orientation == SwingConstants.HORIZONTAL && scrollpane.getHorizontalScrollBar().isShowing())) { - JViewport vp = scrollpane.getViewport(); - Component view; - if (vp != null && (view = vp.getView()) != null) { - Rectangle visRect = vp.getViewRect(); - // LEG: Modification to query the viewport for the - // view size rather than going directly to the view - Dimension vSize = vp.getViewSize(); - int amount; + JViewport vp = scrollpane.getViewport(); + Component view; + if (vp != null && (view = vp.getView()) != null) { + Rectangle visRect = vp.getViewRect(); + // LEG: Modification to query the viewport for the + // view size rather than going directly to the view + Dimension vSize = vp.getViewSize(); + int amount; - if (view instanceof Scrollable) { - if (block) { - amount = ((Scrollable) view).getScrollableBlockIncrement(visRect, orientation, direction); - } - else { - amount = ((Scrollable) view).getScrollableUnitIncrement(visRect, orientation, direction); - } - } - else { - if (block) { - if (orientation == SwingConstants.VERTICAL) { - amount = visRect.height; - } - else { - amount = visRect.width; - } - } - else { - amount = 10; - } - } - if (orientation == SwingConstants.VERTICAL) { - visRect.y += (amount * direction); - if ((visRect.y + visRect.height) > vSize.height) { - visRect.y = Math.max(0, vSize.height - visRect.height); - } - else if (visRect.y < 0) { - visRect.y = 0; - } - } - else { - visRect.x += (amount * direction); - if ((visRect.x + visRect.width) > vSize.width) { - visRect.x = Math.max(0, vSize.width - visRect.width); - } - else if (visRect.x < 0) { - visRect.x = 0; - } - } - vp.setViewPosition(visRect.getLocation()); - } - } - } - } + if (view instanceof Scrollable) { + if (block) { + amount = ((Scrollable) view).getScrollableBlockIncrement(visRect, orientation, direction); + } + else { + amount = ((Scrollable) view).getScrollableUnitIncrement(visRect, orientation, direction); + } + } + else { + if (block) { + if (orientation == SwingConstants.VERTICAL) { + amount = visRect.height; + } + else { + amount = visRect.width; + } + } + else { + amount = 10; + } + } + if (orientation == SwingConstants.VERTICAL) { + visRect.y += (amount * direction); + if ((visRect.y + visRect.height) > vSize.height) { + visRect.y = Math.max(0, vSize.height - visRect.height); + } + else if (visRect.y < 0) { + visRect.y = 0; + } + } + else { + visRect.x += (amount * direction); + if ((visRect.x + visRect.width) > vSize.width) { + visRect.x = Math.max(0, vSize.width - visRect.width); + } + else if (visRect.x < 0) { + visRect.x = 0; + } + } + vp.setViewPosition(visRect.getLocation()); + } + } + } + } - /** - * Action to scroll to x,y location of 0,0. - * Modified from javax.swing.plaf.basic.BasicScrollPaneUI.ScrollEndAction - * - * Only performs the event if a scrollbar is visible - */ - private static class PScrollHomeAction extends AbstractAction { - protected PScrollHomeAction(String name) { - super(name); - } + /** + * Action to scroll to x,y location of 0,0. Modified from + * javax.swing.plaf.basic.BasicScrollPaneUI.ScrollEndAction + * + * Only performs the event if a scrollbar is visible + */ + private static class PScrollHomeAction extends AbstractAction { + protected PScrollHomeAction(String name) { + super(name); + } - public void actionPerformed(ActionEvent e) { - JScrollPane scrollpane = (JScrollPane) e.getSource(); - // LEG: Modification to only perform these actions if one of the - // scrollbars is actually showing - if (scrollpane.getVerticalScrollBar().isShowing() || scrollpane.getHorizontalScrollBar().isShowing()) { - JViewport vp = scrollpane.getViewport(); - if (vp != null && vp.getView() != null) { - vp.setViewPosition(new Point(0, 0)); - } - } - } - } + public void actionPerformed(ActionEvent e) { + JScrollPane scrollpane = (JScrollPane) e.getSource(); + // LEG: Modification to only perform these actions if one of the + // scrollbars is actually showing + if (scrollpane.getVerticalScrollBar().isShowing() || scrollpane.getHorizontalScrollBar().isShowing()) { + JViewport vp = scrollpane.getViewport(); + if (vp != null && vp.getView() != null) { + vp.setViewPosition(new Point(0, 0)); + } + } + } + } - /** - * Action to scroll to last visible location. - * Modified from javax.swing.plaf.basic.BasicScrollPaneUI.ScrollEndAction - * - * Gets the view size from the viewport rather than directly from the view - * - also only performs the event if a scrollbar is visible - */ - protected static class PScrollEndAction extends AbstractAction { - protected PScrollEndAction(String name) { - super(name); - } + /** + * Action to scroll to last visible location. Modified from + * javax.swing.plaf.basic.BasicScrollPaneUI.ScrollEndAction + * + * Gets the view size from the viewport rather than directly from the view - + * also only performs the event if a scrollbar is visible + */ + protected static class PScrollEndAction extends AbstractAction { + protected PScrollEndAction(String name) { + super(name); + } - public void actionPerformed(ActionEvent e) { - JScrollPane scrollpane = (JScrollPane) e.getSource(); - // LEG: Modification to only perform these actions if one of the - // scrollbars is actually showing - if (scrollpane.getVerticalScrollBar().isShowing() || scrollpane.getHorizontalScrollBar().isShowing()) { + public void actionPerformed(ActionEvent e) { + JScrollPane scrollpane = (JScrollPane) e.getSource(); + // LEG: Modification to only perform these actions if one of the + // scrollbars is actually showing + if (scrollpane.getVerticalScrollBar().isShowing() || scrollpane.getHorizontalScrollBar().isShowing()) { - JViewport vp = scrollpane.getViewport(); - if (vp != null && vp.getView() != null) { + JViewport vp = scrollpane.getViewport(); + if (vp != null && vp.getView() != null) { - Rectangle visRect = vp.getViewRect(); - // LEG: Modification to query the viewport for the - // view size rather than going directly to the view - Dimension size = vp.getViewSize(); - vp.setViewPosition(new Point(size.width - visRect.width, size.height - visRect.height)); - } - } - } - } + Rectangle visRect = vp.getViewRect(); + // LEG: Modification to query the viewport for the + // view size rather than going directly to the view + Dimension size = vp.getViewSize(); + vp.setViewPosition(new Point(size.width - visRect.width, size.height - visRect.height)); + } + } + } + } - /** - * An action to do nothing - put into an action map to keep it - * from looking to its parent - */ - protected static class PNullAction extends AbstractAction { - public void actionPerformed(ActionEvent e) { - } - } + /** + * An action to do nothing - put into an action map to keep it from looking + * to its parent + */ + protected static class PNullAction extends AbstractAction { + public void actionPerformed(ActionEvent e) { + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java index 346add8..f513f73 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PScrollPaneLayout.java @@ -21,309 +21,314 @@ /** * A subclass of ScrollPaneLayout that looks at the Viewport for sizing - * information rather than View. Also queries the Viewport for sizing + * information rather than View. Also queries the Viewport for sizing * information after each decision about scrollbar visiblity - * + * * @author Lance Good */ public class PScrollPaneLayout extends ScrollPaneLayout { - /** - * MODIFIED FROM javax.swing.ScrollPaneLayout.layoutContainer - * - * This is largely the same as ScrollPaneLayout.layoutContainer but - * obtains the preferred view size from the viewport rather than directly - * from the view so the viewport can get the preferred size from the - * PScrollDirector - * @param parent the Container to lay out - */ - public void layoutContainer(Container parent) { - /* Sync the (now obsolete) policy fields with the - * JScrollPane. - */ - JScrollPane scrollPane = (JScrollPane) parent; - vsbPolicy = scrollPane.getVerticalScrollBarPolicy(); - hsbPolicy = scrollPane.getHorizontalScrollBarPolicy(); + /** + * MODIFIED FROM javax.swing.ScrollPaneLayout.layoutContainer + * + * This is largely the same as ScrollPaneLayout.layoutContainer but obtains + * the preferred view size from the viewport rather than directly from the + * view so the viewport can get the preferred size from the PScrollDirector + * + * @param parent the Container to lay out + */ + public void layoutContainer(Container parent) { + /* + * Sync the (now obsolete) policy fields with the JScrollPane. + */ + JScrollPane scrollPane = (JScrollPane) parent; + vsbPolicy = scrollPane.getVerticalScrollBarPolicy(); + hsbPolicy = scrollPane.getHorizontalScrollBarPolicy(); - Rectangle availR = scrollPane.getBounds(); - availR.x = availR.y = 0; + Rectangle availR = scrollPane.getBounds(); + availR.x = availR.y = 0; - Insets insets = parent.getInsets(); - availR.x = insets.left; - availR.y = insets.top; - availR.width -= insets.left + insets.right; - availR.height -= insets.top + insets.bottom; + Insets insets = parent.getInsets(); + availR.x = insets.left; + availR.y = insets.top; + availR.width -= insets.left + insets.right; + availR.height -= insets.top + insets.bottom; - /* Get the scrollPane's orientation. - */ - boolean leftToRight = scrollPane.getComponentOrientation().isLeftToRight(); + /* + * Get the scrollPane's orientation. + */ + boolean leftToRight = scrollPane.getComponentOrientation().isLeftToRight(); - /* If there's a visible column header remove the space it - * needs from the top of availR. The column header is treated - * as if it were fixed height, arbitrary width. - */ + /* + * If there's a visible column header remove the space it needs from the + * top of availR. The column header is treated as if it were fixed + * height, arbitrary width. + */ + Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0); - Rectangle colHeadR = new Rectangle(0, availR.y, 0, 0); + if ((colHead != null) && (colHead.isVisible())) { + int colHeadHeight = colHead.getPreferredSize().height; + colHeadR.height = colHeadHeight; + availR.y += colHeadHeight; + availR.height -= colHeadHeight; + } - if ((colHead != null) && (colHead.isVisible())) { - int colHeadHeight = colHead.getPreferredSize().height; - colHeadR.height = colHeadHeight; - availR.y += colHeadHeight; - availR.height -= colHeadHeight; - } + /* + * If there's a visible row header remove the space it needs from the + * left or right of availR. The row header is treated as if it were + * fixed width, arbitrary height. + */ + Rectangle rowHeadR = new Rectangle(0, 0, 0, 0); - /* If there's a visible row header remove the space it needs - * from the left or right of availR. The row header is treated - * as if it were fixed width, arbitrary height. - */ + if ((rowHead != null) && (rowHead.isVisible())) { + int rowHeadWidth = rowHead.getPreferredSize().width; + rowHeadR.width = rowHeadWidth; + availR.width -= rowHeadWidth; + if (leftToRight) { + rowHeadR.x = availR.x; + availR.x += rowHeadWidth; + } + else { + rowHeadR.x = availR.x + availR.width; + } + } - Rectangle rowHeadR = new Rectangle(0, 0, 0, 0); + /* + * If there's a JScrollPane.viewportBorder, remove the space it occupies + * for availR. + */ + Border viewportBorder = scrollPane.getViewportBorder(); + Insets vpbInsets; + if (viewportBorder != null) { + vpbInsets = viewportBorder.getBorderInsets(parent); + availR.x += vpbInsets.left; + availR.y += vpbInsets.top; + availR.width -= vpbInsets.left + vpbInsets.right; + availR.height -= vpbInsets.top + vpbInsets.bottom; + } + else { + vpbInsets = new Insets(0, 0, 0, 0); + } - if ((rowHead != null) && (rowHead.isVisible())) { - int rowHeadWidth = rowHead.getPreferredSize().width; - rowHeadR.width = rowHeadWidth; - availR.width -= rowHeadWidth; - if (leftToRight) { - rowHeadR.x = availR.x; - availR.x += rowHeadWidth; - } - else { - rowHeadR.x = availR.x + availR.width; - } - } + /* + * At this point availR is the space available for the viewport and + * scrollbars. rowHeadR is correct except for its height and y and + * colHeadR is correct except for its width and x. Once we're through + * computing the dimensions of these three parts we can go back and set + * the dimensions of rowHeadR.height, rowHeadR.y, colHeadR.width, + * colHeadR.x and the bounds for the corners. + * + * We'll decide about putting up scrollbars by comparing the viewport + * views preferred size with the viewports extent size (generally just + * its size). Using the preferredSize is reasonable because layout + * proceeds top down - so we expect the viewport to be layed out next. + * And we assume that the viewports layout manager will give the view + * it's preferred size. + */ + Dimension extentSize = (viewport != null) ? viewport.toViewCoordinates(availR.getSize()) : new Dimension(0, 0); - /* If there's a JScrollPane.viewportBorder, remove the - * space it occupies for availR. - */ + PBounds cameraBounds = new PBounds(0, 0, extentSize.getWidth(), extentSize.getHeight()); - Border viewportBorder = scrollPane.getViewportBorder(); - Insets vpbInsets; - if (viewportBorder != null) { - vpbInsets = viewportBorder.getBorderInsets(parent); - availR.x += vpbInsets.left; - availR.y += vpbInsets.top; - availR.width -= vpbInsets.left + vpbInsets.right; - availR.height -= vpbInsets.top + vpbInsets.bottom; - } - else { - vpbInsets = new Insets(0, 0, 0, 0); - } + // LEG: Modification to ask the viewport for the view size rather + // than asking the view directly + Dimension viewPrefSize = (viewport != null) ? ((PViewport) viewport).getViewSize(cameraBounds) : new Dimension( + 0, 0); - /* At this point availR is the space available for the viewport - * and scrollbars. rowHeadR is correct except for its height and y - * and colHeadR is correct except for its width and x. Once we're - * through computing the dimensions of these three parts we can - * go back and set the dimensions of rowHeadR.height, rowHeadR.y, - * colHeadR.width, colHeadR.x and the bounds for the corners. - * - * We'll decide about putting up scrollbars by comparing the - * viewport views preferred size with the viewports extent - * size (generally just its size). Using the preferredSize is - * reasonable because layout proceeds top down - so we expect - * the viewport to be layed out next. And we assume that the - * viewports layout manager will give the view it's preferred - * size. - */ + /* + * If there's a vertical scrollbar and we need one, allocate space for + * it (we'll make it visible later). A vertical scrollbar is considered + * to be fixed width, arbitrary height. + */ + Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0); - Dimension extentSize = (viewport != null) ? viewport.toViewCoordinates(availR.getSize()) : new Dimension(0, 0); + boolean vsbNeeded; + if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) { + vsbNeeded = true; + } + else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) { + vsbNeeded = false; + } + else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED - PBounds cameraBounds = new PBounds(0, 0, extentSize.getWidth(), extentSize.getHeight()); + vsbNeeded = (viewPrefSize.height > extentSize.height); + } - // LEG: Modification to ask the viewport for the view size rather - // than asking the view directly - Dimension viewPrefSize = (viewport != null) ? ((PViewport) viewport).getViewSize(cameraBounds) : new Dimension(0, 0); + if ((vsb != null) && vsbNeeded) { + adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight); + extentSize = viewport.toViewCoordinates(availR.getSize()); - /* If there's a vertical scrollbar and we need one, allocate - * space for it (we'll make it visible later). A vertical - * scrollbar is considered to be fixed width, arbitrary height. - */ + // LEG: Modification because the view's preferred size needs to + // be recomputed because the extent may have changed + cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight()); + viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds); + } - Rectangle vsbR = new Rectangle(0, availR.y - vpbInsets.top, 0, 0); + /* + * If there's a horizontal scrollbar and we need one, allocate space for + * it (we'll make it visible later). A horizontal scrollbar is + * considered to be fixed height, arbitrary width. + */ + Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0); + boolean hsbNeeded; + if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) { + hsbNeeded = true; + } + else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) { + hsbNeeded = false; + } + else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED + hsbNeeded = (viewPrefSize.width > extentSize.width); + } - boolean vsbNeeded; - if (vsbPolicy == VERTICAL_SCROLLBAR_ALWAYS) { - vsbNeeded = true; - } - else if (vsbPolicy == VERTICAL_SCROLLBAR_NEVER) { - vsbNeeded = false; - } - else { // vsbPolicy == VERTICAL_SCROLLBAR_AS_NEEDED + if ((hsb != null) && hsbNeeded) { + adjustForHSB(true, availR, hsbR, vpbInsets); - vsbNeeded = (viewPrefSize.height > extentSize.height); - } + /* + * If we added the horizontal scrollbar then we've implicitly + * reduced the vertical space available to the viewport. As a + * consequence we may have to add the vertical scrollbar, if that + * hasn't been done so already. Ofcourse we don't bother with any of + * this if the vsbPolicy is NEVER. + */ + if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) { - if ((vsb != null) && vsbNeeded) { - adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight); - extentSize = viewport.toViewCoordinates(availR.getSize()); + extentSize = viewport.toViewCoordinates(availR.getSize()); - // LEG: Modification because the view's preferred size needs to - // be recomputed because the extent may have changed - cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight()); - viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds); - } + // LEG: Modification because the view's preferred size needs to + // be recomputed because the extent may have changed + cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight()); + viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds); - /* If there's a horizontal scrollbar and we need one, allocate - * space for it (we'll make it visible later). A horizontal - * scrollbar is considered to be fixed height, arbitrary width. - */ + vsbNeeded = viewPrefSize.height > extentSize.height; - Rectangle hsbR = new Rectangle(availR.x - vpbInsets.left, 0, 0, 0); - boolean hsbNeeded; - if (hsbPolicy == HORIZONTAL_SCROLLBAR_ALWAYS) { - hsbNeeded = true; - } - else if (hsbPolicy == HORIZONTAL_SCROLLBAR_NEVER) { - hsbNeeded = false; - } - else { // hsbPolicy == HORIZONTAL_SCROLLBAR_AS_NEEDED - hsbNeeded = (viewPrefSize.width > extentSize.width); - } + if (vsbNeeded) { + adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight); + } + } + } - if ((hsb != null) && hsbNeeded) { - adjustForHSB(true, availR, hsbR, vpbInsets); + /* + * Set the size of the viewport first, and then recheck the Scrollable + * methods. Some components base their return values for the Scrollable + * methods on the size of the Viewport, so that if we don't ask after + * resetting the bounds we may have gotten the wrong answer. + */ + if (viewport != null) { + viewport.setBounds(availR); + } - /* If we added the horizontal scrollbar then we've implicitly - * reduced the vertical space available to the viewport. - * As a consequence we may have to add the vertical scrollbar, - * if that hasn't been done so already. Ofcourse we - * don't bother with any of this if the vsbPolicy is NEVER. - */ + /* + * We now have the final size of the viewport: availR. Now fixup the + * header and scrollbar widths/heights. + */ + vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom; + hsbR.width = availR.width + vpbInsets.left + vpbInsets.right; + rowHeadR.height = availR.height + vpbInsets.top + vpbInsets.bottom; + rowHeadR.y = availR.y - vpbInsets.top; + colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right; + colHeadR.x = availR.x - vpbInsets.left; - if ((vsb != null) && !vsbNeeded && (vsbPolicy != VERTICAL_SCROLLBAR_NEVER)) { + /* + * Set the bounds of the remaining components. The scrollbars are made + * invisible if they're not needed. + */ + if (rowHead != null) { + rowHead.setBounds(rowHeadR); + } - extentSize = viewport.toViewCoordinates(availR.getSize()); + if (colHead != null) { + colHead.setBounds(colHeadR); + } - // LEG: Modification because the view's preferred size needs to - // be recomputed because the extent may have changed - cameraBounds.setRect(0, 0, extentSize.getWidth(), extentSize.getHeight()); - viewPrefSize = ((PViewport) viewport).getViewSize(cameraBounds); + if (vsb != null) { + if (vsbNeeded) { + vsb.setVisible(true); + vsb.setBounds(vsbR); + } + else { + vsb.setVisible(false); + } + } - vsbNeeded = viewPrefSize.height > extentSize.height; + if (hsb != null) { + if (hsbNeeded) { + hsb.setVisible(true); + hsb.setBounds(hsbR); + } + else { + hsb.setVisible(false); + } + } - if (vsbNeeded) { - adjustForVSB(true, availR, vsbR, vpbInsets, leftToRight); - } - } - } + if (lowerLeft != null) { + lowerLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x, hsbR.y, leftToRight ? rowHeadR.width : vsbR.width, + hsbR.height); + } - /* Set the size of the viewport first, and then recheck the Scrollable - * methods. Some components base their return values for the Scrollable - * methods on the size of the Viewport, so that if we don't - * ask after resetting the bounds we may have gotten the wrong - * answer. - */ + if (lowerRight != null) { + lowerRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x, hsbR.y, leftToRight ? vsbR.width : rowHeadR.width, + hsbR.height); + } - if (viewport != null) { - viewport.setBounds(availR); - } + if (upperLeft != null) { + upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x, colHeadR.y, leftToRight ? rowHeadR.width + : vsbR.width, colHeadR.height); + } - /* We now have the final size of the viewport: availR. - * Now fixup the header and scrollbar widths/heights. - */ - vsbR.height = availR.height + vpbInsets.top + vpbInsets.bottom; - hsbR.width = availR.width + vpbInsets.left + vpbInsets.right; - rowHeadR.height = availR.height + vpbInsets.top + vpbInsets.bottom; - rowHeadR.y = availR.y - vpbInsets.top; - colHeadR.width = availR.width + vpbInsets.left + vpbInsets.right; - colHeadR.x = availR.x - vpbInsets.left; + if (upperRight != null) { + upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x, colHeadR.y, leftToRight ? vsbR.width + : rowHeadR.width, colHeadR.height); + } + } - /* Set the bounds of the remaining components. The scrollbars - * are made invisible if they're not needed. - */ + /** + * Copied FROM javax.swing.ScrollPaneLayout.adjustForVSB + * + * This method is called from ScrollPaneLayout.layoutContainer and is + * private in ScrollPaneLayout so it was copied here + */ + protected void adjustForVSB(boolean wantsVSB, Rectangle available, Rectangle vsbR, Insets vpbInsets, + boolean leftToRight) { + int vsbWidth = vsb.getPreferredSize().width; + if (wantsVSB) { + available.width -= vsbWidth; + vsbR.width = vsbWidth; - if (rowHead != null) { - rowHead.setBounds(rowHeadR); - } + if (leftToRight) { + vsbR.x = available.x + available.width + vpbInsets.right; + } + else { + vsbR.x = available.x - vpbInsets.left; + available.x += vsbWidth; + } + } + else { + available.width += vsbWidth; + } + } - if (colHead != null) { - colHead.setBounds(colHeadR); - } + /** + * Copied FROM javax.swing.ScrollPaneLayout.adjustForHSB + * + * This method is called from ScrollPaneLayout.layoutContainer and is + * private in ScrollPaneLayout so it was copied here + */ + protected void adjustForHSB(boolean wantsHSB, Rectangle available, Rectangle hsbR, Insets vpbInsets) { + int hsbHeight = hsb.getPreferredSize().height; + if (wantsHSB) { + available.height -= hsbHeight; + hsbR.y = available.y + available.height + vpbInsets.bottom; + hsbR.height = hsbHeight; + } + else { + available.height += hsbHeight; + } + } - if (vsb != null) { - if (vsbNeeded) { - vsb.setVisible(true); - vsb.setBounds(vsbR); - } - else { - vsb.setVisible(false); - } - } - - if (hsb != null) { - if (hsbNeeded) { - hsb.setVisible(true); - hsb.setBounds(hsbR); - } - else { - hsb.setVisible(false); - } - } - - if (lowerLeft != null) { - lowerLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x, hsbR.y, leftToRight ? rowHeadR.width : vsbR.width, hsbR.height); - } - - if (lowerRight != null) { - lowerRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x, hsbR.y, leftToRight ? vsbR.width : rowHeadR.width, hsbR.height); - } - - if (upperLeft != null) { - upperLeft.setBounds(leftToRight ? rowHeadR.x : vsbR.x, colHeadR.y, leftToRight ? rowHeadR.width : vsbR.width, colHeadR.height); - } - - if (upperRight != null) { - upperRight.setBounds(leftToRight ? vsbR.x : rowHeadR.x, colHeadR.y, leftToRight ? vsbR.width : rowHeadR.width, colHeadR.height); - } - } - - /** - * Copied FROM javax.swing.ScrollPaneLayout.adjustForVSB - * - * This method is called from ScrollPaneLayout.layoutContainer and is - * private in ScrollPaneLayout so it was copied here - */ - protected void adjustForVSB(boolean wantsVSB, Rectangle available, Rectangle vsbR, Insets vpbInsets, boolean leftToRight) { - int vsbWidth = vsb.getPreferredSize().width; - if (wantsVSB) { - available.width -= vsbWidth; - vsbR.width = vsbWidth; - - if (leftToRight) { - vsbR.x = available.x + available.width + vpbInsets.right; - } - else { - vsbR.x = available.x - vpbInsets.left; - available.x += vsbWidth; - } - } - else { - available.width += vsbWidth; - } - } - - /** - * Copied FROM javax.swing.ScrollPaneLayout.adjustForHSB - * - * This method is called from ScrollPaneLayout.layoutContainer and is - * private in ScrollPaneLayout so it was copied here - */ - protected void adjustForHSB(boolean wantsHSB, Rectangle available, Rectangle hsbR, Insets vpbInsets) { - int hsbHeight = hsb.getPreferredSize().height; - if (wantsHSB) { - available.height -= hsbHeight; - hsbR.y = available.y + available.height + vpbInsets.bottom; - hsbR.height = hsbHeight; - } - else { - available.height += hsbHeight; - } - } - - /** - * The UI resource version of PScrollPaneLayout. It isn't clear why - * Swing does this in ScrollPaneLayout but we'll do it here too just - * to be safe. - */ - public static class UIResource extends PScrollPaneLayout implements javax.swing.plaf.UIResource { - } + /** + * The UI resource version of PScrollPaneLayout. It isn't clear why Swing + * does this in ScrollPaneLayout but we'll do it here too just to be safe. + */ + public static class UIResource extends PScrollPaneLayout implements javax.swing.plaf.UIResource { + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java b/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java index 0a735e8..d28469c 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swing/PViewport.java @@ -16,184 +16,188 @@ import edu.umd.cs.piccolo.util.PBounds; /** - * A subclass of JViewport that talks to the scroll director to negotiate - * the view positions and sizes. - * + * A subclass of JViewport that talks to the scroll director to negotiate the + * view positions and sizes. + * * @author Lance Good */ public class PViewport extends JViewport { - /** - * Controls what happens when scrolling occurs - */ - PScrollDirector scrollDirector; + /** + * Controls what happens when scrolling occurs + */ + PScrollDirector scrollDirector; - /** - * Pass constructor info to super - */ - public PViewport() { - super(); + /** + * Pass constructor info to super + */ + public PViewport() { + super(); - setScrollDirector(createScrollDirector()); - } + setScrollDirector(createScrollDirector()); + } - /** - * Subclassers can override this to install a different - * layout manager (or null) in the constructor. Returns - * a new ViewportLayout object. - * - * @return a LayoutManager - */ - protected LayoutManager createLayoutManager() { - return new PViewportLayout(); - } + /** + * Subclassers can override this to install a different layout manager (or + * null) in the constructor. Returns a new + * ViewportLayout object. + * + * @return a LayoutManager + */ + protected LayoutManager createLayoutManager() { + return new PViewportLayout(); + } - /** - * Subclassers can override this to install a different scroll director - * in the constructor. Returns a new PScrollDirector object. - * @return a PScrollDirector - */ - protected PScrollDirector createScrollDirector() { - return new PDefaultScrollDirector(); - } + /** + * Subclassers can override this to install a different scroll director in + * the constructor. Returns a new PScrollDirector object. + * + * @return a PScrollDirector + */ + protected PScrollDirector createScrollDirector() { + return new PDefaultScrollDirector(); + } - /** - * Set the scroll director on this viewport - * @param scrollDirector The new scroll director - */ - public void setScrollDirector(PScrollDirector scrollDirector) { - if (this.scrollDirector != null) { - this.scrollDirector.unInstall(); - } - this.scrollDirector = scrollDirector; - if (scrollDirector != null) { - this.scrollDirector.install(this, (PCanvas) getView()); - } - } + /** + * Set the scroll director on this viewport + * + * @param scrollDirector The new scroll director + */ + public void setScrollDirector(PScrollDirector scrollDirector) { + if (this.scrollDirector != null) { + this.scrollDirector.unInstall(); + } + this.scrollDirector = scrollDirector; + if (scrollDirector != null) { + this.scrollDirector.install(this, (PCanvas) getView()); + } + } - /** - * @return The scroll director on this viewport - */ - public PScrollDirector getScrollDirector() { - return scrollDirector; - } + /** + * @return The scroll director on this viewport + */ + public PScrollDirector getScrollDirector() { + return scrollDirector; + } - /** - * Overridden to throw an exception if the view is not a ZCanvas - * @param view The new view - it better be a ZCanvas! - */ - public void setView(Component view) { - if (!(view instanceof PCanvas)) { - throw new UnsupportedOperationException("PViewport only supports ZCanvas"); - } + /** + * Overridden to throw an exception if the view is not a ZCanvas + * + * @param view The new view - it better be a ZCanvas! + */ + public void setView(Component view) { + if (!(view instanceof PCanvas)) { + throw new UnsupportedOperationException("PViewport only supports ZCanvas"); + } - super.setView(view); + super.setView(view); - if (scrollDirector != null) { - scrollDirector.install(this, (PCanvas) view); - } - } + if (scrollDirector != null) { + scrollDirector.install(this, (PCanvas) view); + } + } - /** - * Sets the view coordinates that appear in the upper left - * hand corner of the viewport, does nothing if there's no view. - * - * @param p a Point object giving the upper left coordinates - */ - public void setViewPosition(Point p) { - if (getView() == null) { - return; - } + /** + * Sets the view coordinates that appear in the upper left hand corner of + * the viewport, does nothing if there's no view. + * + * @param p a Point object giving the upper left coordinates + */ + public void setViewPosition(Point p) { + if (getView() == null) { + return; + } - double oldX = 0, oldY = 0, x = p.x, y = p.y; + double oldX = 0, oldY = 0, x = p.x, y = p.y; - Point2D vp = getViewPosition(); - if (vp != null) { - oldX = vp.getX(); - oldY = vp.getY(); - } + Point2D vp = getViewPosition(); + if (vp != null) { + oldX = vp.getX(); + oldY = vp.getY(); + } - /** - * Send the scroll director the exact view position and let it - * interpret it as needed - */ - double newX = x; - double newY = y; + /** + * Send the scroll director the exact view position and let it interpret + * it as needed + */ + double newX = x; + double newY = y; - if ((oldX != newX) || (oldY != newY)) { - scrollUnderway = true; + if ((oldX != newX) || (oldY != newY)) { + scrollUnderway = true; - scrollDirector.setViewPosition(newX, newY); + scrollDirector.setViewPosition(newX, newY); - fireStateChanged(); - } - } + fireStateChanged(); + } + } - /** - * Gets the view position from the scroll director based on the current - * extent size - * @return The new view position - */ - public Point getViewPosition() { - if (scrollDirector != null) { - Dimension extent = getExtentSize(); - return scrollDirector.getViewPosition(new PBounds(0, 0, extent.getWidth(), extent.getHeight())); - } - else { - return null; - } - } + /** + * Gets the view position from the scroll director based on the current + * extent size + * + * @return The new view position + */ + public Point getViewPosition() { + if (scrollDirector != null) { + Dimension extent = getExtentSize(); + return scrollDirector.getViewPosition(new PBounds(0, 0, extent.getWidth(), extent.getHeight())); + } + else { + return null; + } + } - /** - * Gets the view size from the scroll director based on the current - * extent size - * @return The new view size - */ - public Dimension getViewSize() { - Dimension extent = getExtentSize(); - return scrollDirector.getViewSize(new PBounds(0, 0, extent.getWidth(), extent.getHeight())); - } + /** + * Gets the view size from the scroll director based on the current extent + * size + * + * @return The new view size + */ + public Dimension getViewSize() { + Dimension extent = getExtentSize(); + return scrollDirector.getViewSize(new PBounds(0, 0, extent.getWidth(), extent.getHeight())); + } - /** - * Gets the view size from the scroll director based on the specified - * extent size - * @param r The extent size from which the view is computed - * @return The new view size - */ - public Dimension getViewSize(Rectangle2D r) { - return scrollDirector.getViewSize(r); - } + /** + * Gets the view size from the scroll director based on the specified extent + * size + * + * @param r The extent size from which the view is computed + * @return The new view size + */ + public Dimension getViewSize(Rectangle2D r) { + return scrollDirector.getViewSize(r); + } - /** - * Notifies all ChangeListeners when the views - * size, position, or the viewports extent size has changed. - */ - public void fireStateChanged() { - super.fireStateChanged(); - } + /** + * Notifies all ChangeListeners when the views size, position, + * or the viewports extent size has changed. + */ + public void fireStateChanged() { + super.fireStateChanged(); + } - /** - * A simple layout manager to give the ZCanvas the same size as the - * Viewport - */ - public static class PViewportLayout extends ViewportLayout { - /** - * Called when the specified container needs to be laid out. - * - * @param parent the container to lay out - */ - public void layoutContainer(Container parent) { - JViewport vp = (JViewport) parent; - Component view = vp.getView(); + /** + * A simple layout manager to give the ZCanvas the same size as the Viewport + */ + public static class PViewportLayout extends ViewportLayout { + /** + * Called when the specified container needs to be laid out. + * + * @param parent the container to lay out + */ + public void layoutContainer(Container parent) { + JViewport vp = (JViewport) parent; + Component view = vp.getView(); - if (view == null) { - return; - } + if (view == null) { + return; + } - Dimension extentSize = vp.getSize(); + Dimension extentSize = vp.getSize(); - vp.setViewSize(extentSize); - } - - } + vp.setViewSize(extentSize); + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTBoundsHandle.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTBoundsHandle.java index a901e31..fb074cd 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTBoundsHandle.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTBoundsHandle.java @@ -48,296 +48,308 @@ /** * PBoundsHandle a handle for resizing the bounds of another node. If a * bounds handle is dragged such that the other node's width or height becomes - * negative then the each drag handle's locator assciated with that - * other node is "flipped" so that they are attached to and dragging a different - * corner of the nodes bounds. + * negative then the each drag handle's locator assciated with that other node + * is "flipped" so that they are attached to and dragging a different corner of + * the nodes bounds. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PSWTBoundsHandle extends PSWTHandle { - - private PBasicInputEventHandler handleCursorHandler; - - public static void addBoundsHandlesTo(PNode aNode) { - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createEastLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createWestLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); - aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); - } - public static void addStickyBoundsHandlesTo(PNode aNode, PCamera camera) { - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createEastLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createWestLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); - camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); - } - - public static void removeBoundsHandlesFrom(PNode aNode) { - ArrayList handles = new ArrayList(); + private PBasicInputEventHandler handleCursorHandler; - Iterator i = aNode.getChildrenIterator(); - while (i.hasNext()) { - PNode each = (PNode) i.next(); - if (each instanceof PSWTBoundsHandle) { - handles.add(each); - } - } - aNode.removeChildren(handles); - } - - public PSWTBoundsHandle(PBoundsLocator aLocator) { - super(aLocator); - } - - protected void installHandleEventHandlers() { - super.installHandleEventHandlers(); - handleCursorHandler = new PBasicInputEventHandler() { - boolean cursorPushed = false; - public void mouseEntered(PInputEvent aEvent) { - if (!cursorPushed) { - aEvent.pushCursor(getCursorFor(((PBoundsLocator)getLocator()).getSide())); - cursorPushed = true; - } - } - public void mouseExited(PInputEvent aEvent) { - PPickPath focus = aEvent.getInputManager().getMouseFocus(); - if (cursorPushed) { - if (focus == null || focus.getPickedNode() != PSWTBoundsHandle.this) { - aEvent.popCursor(); - cursorPushed = false; - } - } - } - public void mouseReleased(PInputEvent event) { - if (cursorPushed) { - event.popCursor(); - cursorPushed = false; - } - } - }; - addInputEventListener(handleCursorHandler); - } + public static void addBoundsHandlesTo(PNode aNode) { + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createEastLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createWestLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); + aNode.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); + } - /** - * Return the event handler that is responsible for setting the mouse - * cursor when it enters/exits this handle. - */ - public PBasicInputEventHandler getHandleCursorEventHandler() { - return handleCursorHandler; - } - - public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - l.getNode().startResizeBounds(); - } - - public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - - PNode n = l.getNode(); - PBounds b = n.getBounds(); + public static void addStickyBoundsHandlesTo(PNode aNode, PCamera camera) { + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createEastLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createWestLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthEastLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createNorthWestLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthEastLocator(aNode))); + camera.addChild(new PSWTBoundsHandle(PBoundsLocator.createSouthWestLocator(aNode))); + } - PNode parent = getParent(); - if (parent != n && parent instanceof PCamera) { - ((PCamera)parent).localToView(aLocalDimension); - } + public static void removeBoundsHandlesFrom(PNode aNode) { + ArrayList handles = new ArrayList(); - localToGlobal(aLocalDimension); - n.globalToLocal(aLocalDimension); - - double dx = aLocalDimension.getWidth(); - double dy = aLocalDimension.getHeight(); - - switch (l.getSide()) { - case SwingConstants.NORTH: - b.setRect(b.x, b.y + dy, b.width, b.height - dy); - break; - - case SwingConstants.SOUTH: - b.setRect(b.x, b.y, b.width, b.height + dy); - break; - - case SwingConstants.EAST: - b.setRect(b.x, b.y, b.width + dx, b.height); - break; - - case SwingConstants.WEST: - b.setRect(b.x + dx, b.y, b.width - dx, b.height); - break; - - case SwingConstants.NORTH_WEST: - b.setRect(b.x + dx, b.y + dy, b.width - dx, b.height - dy); - break; - - case SwingConstants.SOUTH_WEST: - b.setRect(b.x + dx, b.y, b.width - dx, b.height + dy); - break; - - case SwingConstants.NORTH_EAST: - b.setRect(b.x, b.y + dy, b.width + dx, b.height - dy); - break; - - case SwingConstants.SOUTH_EAST: - b.setRect(b.x, b.y, b.width + dx, b.height + dy); - break; - } - - boolean flipX = false; - boolean flipY = false; - - if (b.width < 0) { - flipX = true; - b.width = -b.width; - b.x -= b.width; - } - - if (b.height < 0) { - flipY = true; - b.height = -b.height; - b.y -= b.height; - } - - if (flipX || flipY) { - flipSiblingBoundsHandles(flipX, flipY); - } - - n.setBounds(b); - } - - public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - l.getNode().endResizeBounds(); - } - - public void flipSiblingBoundsHandles(boolean flipX, boolean flipY) { - Iterator i = getParent().getChildrenIterator(); - while (i.hasNext()) { - Object each = i.next(); - if (each instanceof PSWTBoundsHandle) { - ((PSWTBoundsHandle)each).flipHandleIfNeeded(flipX, flipY); - } - } - } - - public void flipHandleIfNeeded(boolean flipX, boolean flipY) { - PBoundsLocator l = (PBoundsLocator) getLocator(); - - if (flipX || flipY) { - switch (l.getSide()) { - case SwingConstants.NORTH: { - if (flipY) { - l.setSide(SwingConstants.SOUTH); - } - break; - } - - case SwingConstants.SOUTH: { - if (flipY) { - l.setSide(SwingConstants.NORTH); - } - break; - } - - case SwingConstants.EAST: { - if (flipX) { - l.setSide(SwingConstants.WEST); - } - break; - } - - case SwingConstants.WEST: { - if (flipX) { - l.setSide(SwingConstants.EAST); - } - break; - } - - case SwingConstants.NORTH_WEST: { - if (flipX && flipY) { - l.setSide(SwingConstants.SOUTH_EAST); - } else if (flipX) { - l.setSide(SwingConstants.NORTH_EAST); - } else if (flipY) { - l.setSide(SwingConstants.SOUTH_WEST); - } - - break; - } - - case SwingConstants.SOUTH_WEST: { - if (flipX && flipY) { - l.setSide(SwingConstants.NORTH_EAST); - } else if (flipX) { - l.setSide(SwingConstants.SOUTH_EAST); - } else if (flipY) { - l.setSide(SwingConstants.NORTH_WEST); - } - break; - } - - case SwingConstants.NORTH_EAST: { - if (flipX && flipY) { - l.setSide(SwingConstants.SOUTH_WEST); - } else if (flipX) { - l.setSide(SwingConstants.NORTH_WEST); - } else if (flipY) { - l.setSide(SwingConstants.SOUTH_EAST); - } - break; - } - - case SwingConstants.SOUTH_EAST: { - if (flipX && flipY) { - l.setSide(SwingConstants.NORTH_WEST); - } else if (flipX) { - l.setSide(SwingConstants.SOUTH_WEST); - } else if (flipY) { - l.setSide(SwingConstants.NORTH_EAST); - } - break; - } - } - } - - // reset locator to update layout - setLocator(l); - } - - public Cursor getCursorFor(int side) { - switch (side) { - case SwingConstants.NORTH: - return new Cursor(Cursor.N_RESIZE_CURSOR); + Iterator i = aNode.getChildrenIterator(); + while (i.hasNext()) { + PNode each = (PNode) i.next(); + if (each instanceof PSWTBoundsHandle) { + handles.add(each); + } + } + aNode.removeChildren(handles); + } - case SwingConstants.SOUTH: - return new Cursor(Cursor.S_RESIZE_CURSOR); - - case SwingConstants.EAST: - return new Cursor(Cursor.E_RESIZE_CURSOR); - - case SwingConstants.WEST: - return new Cursor(Cursor.W_RESIZE_CURSOR); - - case SwingConstants.NORTH_WEST: - return new Cursor(Cursor.NW_RESIZE_CURSOR); - - case SwingConstants.SOUTH_WEST: - return new Cursor(Cursor.SW_RESIZE_CURSOR); - - case SwingConstants.NORTH_EAST: - return new Cursor(Cursor.NE_RESIZE_CURSOR); - - case SwingConstants.SOUTH_EAST: - return new Cursor(Cursor.SE_RESIZE_CURSOR); - } - return null; - } + public PSWTBoundsHandle(PBoundsLocator aLocator) { + super(aLocator); + } + + protected void installHandleEventHandlers() { + super.installHandleEventHandlers(); + handleCursorHandler = new PBasicInputEventHandler() { + boolean cursorPushed = false; + + public void mouseEntered(PInputEvent aEvent) { + if (!cursorPushed) { + aEvent.pushCursor(getCursorFor(((PBoundsLocator) getLocator()).getSide())); + cursorPushed = true; + } + } + + public void mouseExited(PInputEvent aEvent) { + PPickPath focus = aEvent.getInputManager().getMouseFocus(); + if (cursorPushed) { + if (focus == null || focus.getPickedNode() != PSWTBoundsHandle.this) { + aEvent.popCursor(); + cursorPushed = false; + } + } + } + + public void mouseReleased(PInputEvent event) { + if (cursorPushed) { + event.popCursor(); + cursorPushed = false; + } + } + }; + addInputEventListener(handleCursorHandler); + } + + /** + * Return the event handler that is responsible for setting the mouse cursor + * when it enters/exits this handle. + */ + public PBasicInputEventHandler getHandleCursorEventHandler() { + return handleCursorHandler; + } + + public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + l.getNode().startResizeBounds(); + } + + public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + + PNode n = l.getNode(); + PBounds b = n.getBounds(); + + PNode parent = getParent(); + if (parent != n && parent instanceof PCamera) { + ((PCamera) parent).localToView(aLocalDimension); + } + + localToGlobal(aLocalDimension); + n.globalToLocal(aLocalDimension); + + double dx = aLocalDimension.getWidth(); + double dy = aLocalDimension.getHeight(); + + switch (l.getSide()) { + case SwingConstants.NORTH: + b.setRect(b.x, b.y + dy, b.width, b.height - dy); + break; + + case SwingConstants.SOUTH: + b.setRect(b.x, b.y, b.width, b.height + dy); + break; + + case SwingConstants.EAST: + b.setRect(b.x, b.y, b.width + dx, b.height); + break; + + case SwingConstants.WEST: + b.setRect(b.x + dx, b.y, b.width - dx, b.height); + break; + + case SwingConstants.NORTH_WEST: + b.setRect(b.x + dx, b.y + dy, b.width - dx, b.height - dy); + break; + + case SwingConstants.SOUTH_WEST: + b.setRect(b.x + dx, b.y, b.width - dx, b.height + dy); + break; + + case SwingConstants.NORTH_EAST: + b.setRect(b.x, b.y + dy, b.width + dx, b.height - dy); + break; + + case SwingConstants.SOUTH_EAST: + b.setRect(b.x, b.y, b.width + dx, b.height + dy); + break; + } + + boolean flipX = false; + boolean flipY = false; + + if (b.width < 0) { + flipX = true; + b.width = -b.width; + b.x -= b.width; + } + + if (b.height < 0) { + flipY = true; + b.height = -b.height; + b.y -= b.height; + } + + if (flipX || flipY) { + flipSiblingBoundsHandles(flipX, flipY); + } + + n.setBounds(b); + } + + public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + l.getNode().endResizeBounds(); + } + + public void flipSiblingBoundsHandles(boolean flipX, boolean flipY) { + Iterator i = getParent().getChildrenIterator(); + while (i.hasNext()) { + Object each = i.next(); + if (each instanceof PSWTBoundsHandle) { + ((PSWTBoundsHandle) each).flipHandleIfNeeded(flipX, flipY); + } + } + } + + public void flipHandleIfNeeded(boolean flipX, boolean flipY) { + PBoundsLocator l = (PBoundsLocator) getLocator(); + + if (flipX || flipY) { + switch (l.getSide()) { + case SwingConstants.NORTH: { + if (flipY) { + l.setSide(SwingConstants.SOUTH); + } + break; + } + + case SwingConstants.SOUTH: { + if (flipY) { + l.setSide(SwingConstants.NORTH); + } + break; + } + + case SwingConstants.EAST: { + if (flipX) { + l.setSide(SwingConstants.WEST); + } + break; + } + + case SwingConstants.WEST: { + if (flipX) { + l.setSide(SwingConstants.EAST); + } + break; + } + + case SwingConstants.NORTH_WEST: { + if (flipX && flipY) { + l.setSide(SwingConstants.SOUTH_EAST); + } + else if (flipX) { + l.setSide(SwingConstants.NORTH_EAST); + } + else if (flipY) { + l.setSide(SwingConstants.SOUTH_WEST); + } + + break; + } + + case SwingConstants.SOUTH_WEST: { + if (flipX && flipY) { + l.setSide(SwingConstants.NORTH_EAST); + } + else if (flipX) { + l.setSide(SwingConstants.SOUTH_EAST); + } + else if (flipY) { + l.setSide(SwingConstants.NORTH_WEST); + } + break; + } + + case SwingConstants.NORTH_EAST: { + if (flipX && flipY) { + l.setSide(SwingConstants.SOUTH_WEST); + } + else if (flipX) { + l.setSide(SwingConstants.NORTH_WEST); + } + else if (flipY) { + l.setSide(SwingConstants.SOUTH_EAST); + } + break; + } + + case SwingConstants.SOUTH_EAST: { + if (flipX && flipY) { + l.setSide(SwingConstants.NORTH_WEST); + } + else if (flipX) { + l.setSide(SwingConstants.SOUTH_WEST); + } + else if (flipY) { + l.setSide(SwingConstants.NORTH_EAST); + } + break; + } + } + } + + // reset locator to update layout + setLocator(l); + } + + public Cursor getCursorFor(int side) { + switch (side) { + case SwingConstants.NORTH: + return new Cursor(Cursor.N_RESIZE_CURSOR); + + case SwingConstants.SOUTH: + return new Cursor(Cursor.S_RESIZE_CURSOR); + + case SwingConstants.EAST: + return new Cursor(Cursor.E_RESIZE_CURSOR); + + case SwingConstants.WEST: + return new Cursor(Cursor.W_RESIZE_CURSOR); + + case SwingConstants.NORTH_WEST: + return new Cursor(Cursor.NW_RESIZE_CURSOR); + + case SwingConstants.SOUTH_WEST: + return new Cursor(Cursor.SW_RESIZE_CURSOR); + + case SwingConstants.NORTH_EAST: + return new Cursor(Cursor.NE_RESIZE_CURSOR); + + case SwingConstants.SOUTH_EAST: + return new Cursor(Cursor.SE_RESIZE_CURSOR); + } + return null; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java index db8fcd2..f9fc22b 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java @@ -63,541 +63,559 @@ import edu.umd.cs.piccolo.util.PStack; /** - * PCanvas is a simple Swing component that can be used to embed - * Piccolo into a Java Swing application. Canvas's view the Piccolo scene - * graph through a camera. The canvas manages screen updates coming from - * this camera, and forwards swing mouse and keyboard events to the camera. + * PCanvas is a simple Swing component that can be used to embed Piccolo + * into a Java Swing application. Canvas's view the Piccolo scene graph through + * a camera. The canvas manages screen updates coming from this camera, and + * forwards swing mouse and keyboard events to the camera. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PSWTCanvas extends Composite implements PComponent { - public static PSWTCanvas CURRENT_CANVAS = null; + public static PSWTCanvas CURRENT_CANVAS = null; - private Image backBuffer; - private boolean doubleBuffered = true; + private Image backBuffer; + private boolean doubleBuffered = true; - private PCamera camera; - private PStack cursorStack; - private Cursor curCursor; - private int interacting; - private int defaultRenderQuality; - private int animatingRenderQuality; - private int interactingRenderQuality; - private PPanEventHandler panEventHandler; - private PZoomEventHandler zoomEventHandler; - private boolean paintingImmediately; - private boolean animatingOnLastPaint; - - /** - * Construct a canvas with the basic scene graph consisting of a - * root, camera, and layer. Event handlers for zooming and panning - * are automatically installed. - */ - public PSWTCanvas(Composite parent, int style) { - super(parent,style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE); - - CURRENT_CANVAS = this; - cursorStack = new PStack(); - setCamera(createBasicSceneGraph()); - installInputSources(); - setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); - setAnimatingRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); - setInteractingRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); - panEventHandler = new PPanEventHandler(); - zoomEventHandler = new PZoomEventHandler(); - addInputEventListener(panEventHandler); - addInputEventListener(zoomEventHandler); - - // Add a paint listener to call paint - addPaintListener(new PaintListener() { - public void paintControl(PaintEvent pe) { - paintComponent(pe.gc,pe.x,pe.y,pe.width,pe.height); - } - }); - - // Keep track of the references so we can dispose of the Fonts and Colors - SWTGraphics2D.incrementGCCount(); - addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent de) { - getRoot().getActivityScheduler().removeAllActivities(); - SWTGraphics2D.decrementGCCount(); - } - }); - } - - //**************************************************************** - // Basic - Methods for accessing common piccolo nodes. - //**************************************************************** + private PCamera camera; + private PStack cursorStack; + private Cursor curCursor; + private int interacting; + private int defaultRenderQuality; + private int animatingRenderQuality; + private int interactingRenderQuality; + private PPanEventHandler panEventHandler; + private PZoomEventHandler zoomEventHandler; + private boolean paintingImmediately; + private boolean animatingOnLastPaint; - /** - * Get the pan event handler associated with this canvas. This event handler - * is set up to get events from the camera associated with this canvas by - * default. - */ - public PPanEventHandler getPanEventHandler() { - return panEventHandler; - } - - /** - * Get the zoom event handler associated with this canvas. This event handler - * is set up to get events from the camera associated with this canvas by - * default. - */ - public PZoomEventHandler getZoomEventHandler() { - return zoomEventHandler; - } + /** + * Construct a canvas with the basic scene graph consisting of a root, + * camera, and layer. Event handlers for zooming and panning are + * automatically installed. + */ + public PSWTCanvas(Composite parent, int style) { + super(parent, style | SWT.NO_BACKGROUND | SWT.NO_REDRAW_RESIZE); - /** - * Return the camera associated with this canvas. All input events from this canvas - * go through this camera. And this is the camera that paints this canvas. - */ - public PCamera getCamera() { - return camera; - } - - /** - * Set the camera associated with this canvas. All input events from this canvas - * go through this camera. And this is the camera that paints this canvas. - */ - public void setCamera(PCamera newCamera) { - if (camera != null) { - camera.setComponent(null); - } - - camera = newCamera; - - if (camera != null) { - camera.setComponent(this); - - Rectangle swtRect = getBounds(); - - camera.setBounds(new Rectangle2D.Double(swtRect.x,swtRect.y,swtRect.width,swtRect.height)); - } - } + CURRENT_CANVAS = this; + cursorStack = new PStack(); + setCamera(createBasicSceneGraph()); + installInputSources(); + setDefaultRenderQuality(PPaintContext.HIGH_QUALITY_RENDERING); + setAnimatingRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); + setInteractingRenderQuality(PPaintContext.LOW_QUALITY_RENDERING); + panEventHandler = new PPanEventHandler(); + zoomEventHandler = new PZoomEventHandler(); + addInputEventListener(panEventHandler); + addInputEventListener(zoomEventHandler); - /** - * Return root for this canvas. - */ - public PRoot getRoot() { - return camera.getRoot(); - } - - /** - * Return layer for this canvas. - */ - public PLayer getLayer() { - return camera.getLayer(0); - } + // Add a paint listener to call paint + addPaintListener(new PaintListener() { + public void paintControl(PaintEvent pe) { + paintComponent(pe.gc, pe.x, pe.y, pe.width, pe.height); + } + }); - /** - * Add an input listener to the camera associated with this canvas. - */ - public void addInputEventListener(PInputEventListener listener) { - getCamera().addInputEventListener(listener); - } - - /** - * Remove an input listener to the camera associated with this canvas. - */ - public void removeInputEventListener(PInputEventListener listener) { - getCamera().removeInputEventListener(listener); - } - - public PCamera createBasicSceneGraph() { - PRoot r = new PSWTRoot(this); - PLayer l = new PLayer(); - PCamera c = new PCamera(); + // Keep track of the references so we can dispose of the Fonts and + // Colors + SWTGraphics2D.incrementGCCount(); + addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent de) { + getRoot().getActivityScheduler().removeAllActivities(); + SWTGraphics2D.decrementGCCount(); + } + }); + } - r.addChild(c); - r.addChild(l); - c.addLayer(l); - - return c; - } - - //**************************************************************** - // Painting - //**************************************************************** + // **************************************************************** + // Basic - Methods for accessing common piccolo nodes. + // **************************************************************** - /** - * Return true if this canvas has been marked as interacting. If so - * the canvas will normally render at a lower quality that is faster. - */ - public boolean getInteracting() { - return interacting > 0; - } - - /** - * Return true if any activities that respond with true to the method - * isAnimating were run in the last PRoot.processInputs() loop. This - * values is used by this canvas to determine the render quality - * to use for the next paint. - */ - public boolean getAnimating() { - return getRoot().getActivityScheduler().getAnimating(); - } + /** + * Get the pan event handler associated with this canvas. This event handler + * is set up to get events from the camera associated with this canvas by + * default. + */ + public PPanEventHandler getPanEventHandler() { + return panEventHandler; + } - /** - * Set if this canvas is interacting. If so the canvas will normally - * render at a lower quality that is faster. - */ - public void setInteracting(boolean isInteracting) { - if (isInteracting) { - interacting++; - } else { - interacting--; - } - - if (!getInteracting()) { - repaint(); - } - } + /** + * Get the zoom event handler associated with this canvas. This event + * handler is set up to get events from the camera associated with this + * canvas by default. + */ + public PZoomEventHandler getZoomEventHandler() { + return zoomEventHandler; + } - /** - * Get whether this canvas should use double buffering - the default is no double buffering - */ - public boolean getDoubleBuffered() { - return doubleBuffered; - } + /** + * Return the camera associated with this canvas. All input events from this + * canvas go through this camera. And this is the camera that paints this + * canvas. + */ + public PCamera getCamera() { + return camera; + } - /** - * Set whether this canvas should use double buffering - the default is no double buffering - */ - public void setDoubleBuffered(boolean dBuffered) { - this.doubleBuffered = dBuffered; - } + /** + * Set the camera associated with this canvas. All input events from this + * canvas go through this camera. And this is the camera that paints this + * canvas. + */ + public void setCamera(PCamera newCamera) { + if (camera != null) { + camera.setComponent(null); + } - /** - * Set the render quality that should be used when rendering this canvas. - * The default value is PPaintContext.HIGH_QUALITY_RENDERING. - * - * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or PPaintContext.LOW_QUALITY_RENDERING - */ - public void setDefaultRenderQuality(int requestedQuality) { - defaultRenderQuality = requestedQuality; - repaint(); - } + camera = newCamera; - /** - * Set the render quality that should be used when rendering this canvas - * when it is animating. The default value is PPaintContext.LOW_QUALITY_RENDERING. - * - * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or PPaintContext.LOW_QUALITY_RENDERING - */ - public void setAnimatingRenderQuality(int requestedQuality) { - animatingRenderQuality = requestedQuality; - repaint(); - } + if (camera != null) { + camera.setComponent(this); - /** - * Set the render quality that should be used when rendering this canvas - * when it is interacting. The default value is PPaintContext.LOW_QUALITY_RENDERING. - * - * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or PPaintContext.LOW_QUALITY_RENDERING - */ - public void setInteractingRenderQuality(int requestedQuality) { - interactingRenderQuality = requestedQuality; - repaint(); - } - - /** - * Set the canvas cursor, and remember the previous cursor on the - * cursor stack. - */ - public void pushCursor(java.awt.Cursor cursor) { - Cursor aCursor = null; - if (cursor.getType() == java.awt.Cursor.N_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZEN); - } - else if (cursor.getType() == java.awt.Cursor.NE_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZENE); - } - else if (cursor.getType() == java.awt.Cursor.NW_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZENW); - } - else if (cursor.getType() == java.awt.Cursor.S_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZES); - } - else if (cursor.getType() == java.awt.Cursor.SE_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZESE); - } - else if (cursor.getType() == java.awt.Cursor.SW_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZESW); - } - else if (cursor.getType() == java.awt.Cursor.E_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZEE); - } - else if (cursor.getType() == java.awt.Cursor.W_RESIZE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZEW); - } - else if (cursor.getType() == java.awt.Cursor.TEXT_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_IBEAM); - } - else if (cursor.getType() == java.awt.Cursor.HAND_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_HAND); - } - else if (cursor.getType() == java.awt.Cursor.MOVE_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_SIZEALL); - } - else if (cursor.getType() == java.awt.Cursor.CROSSHAIR_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_CROSS); - } - else if (cursor.getType() == java.awt.Cursor.WAIT_CURSOR) { - aCursor = new Cursor(this.getDisplay(),SWT.CURSOR_WAIT); - } - - if (aCursor != null) { - if (curCursor != null) { - cursorStack.push(curCursor); - } - curCursor = aCursor; - setCursor(aCursor); - } - } - - /** - * Pop the cursor on top of the cursorStack and set it as the - * canvas cursor. - */ - public void popCursor() { - if (curCursor != null) { - // We must manually dispose of cursors under SWT - curCursor.dispose(); - } - - if (!cursorStack.isEmpty()) { - curCursor = (Cursor)cursorStack.pop(); - } - else { - curCursor = null; - } - - // This sets the cursor back to default - setCursor(curCursor); - } - - //**************************************************************** - // Code to manage connection to Swing. There appears to be a bug in - // swing where it will occasionally send to many mouse pressed or mouse - // released events. Below we attempt to filter out those cases before - // they get delivered to the Piccolo framework. - //**************************************************************** - - private boolean isButton1Pressed; - private boolean isButton2Pressed; - private boolean isButton3Pressed; - - /** - * This method installs mouse and key listeners on the canvas that forward - * those events to piccolo. - */ - protected void installInputSources() { - this.addMouseListener(new MouseListener() { - public void mouseDown(MouseEvent me) { - boolean shouldBalanceEvent = false; - - switch (me.button) { - case 1: - if (isButton1Pressed) { - shouldBalanceEvent = true; - } - isButton1Pressed = true; - break; - case 2: - if (isButton2Pressed) { - shouldBalanceEvent = true; - } - isButton2Pressed = true; - break; - case 3: - if (isButton3Pressed) { - shouldBalanceEvent = true; - } - isButton3Pressed = true; - break; - } - - if (shouldBalanceEvent) { - java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_RELEASED,1); - sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); - } - - java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_PRESSED,1); - sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); - } - - public void mouseUp(MouseEvent me) { - boolean shouldBalanceEvent = false; - - switch (me.button) { - case 1: - if (!isButton1Pressed) { - shouldBalanceEvent = true; - } - isButton1Pressed = false; - break; - case 2: - if (!isButton2Pressed) { - shouldBalanceEvent = true; - } - isButton2Pressed = false; - break; - case 3: - if (!isButton3Pressed) { - shouldBalanceEvent = true; - } - isButton3Pressed = false; - break; - } - - if (shouldBalanceEvent) { - java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_PRESSED,1); - sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); - } - - java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_RELEASED,1); - sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); - } - - public void mouseDoubleClick(final MouseEvent me) { - // This doesn't work with click event types for some reason - it has to do with how - // the click and release events are ordered, I think - java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_PRESSED,2); - sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); - inputEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_RELEASED,2); - sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); - } - }); + Rectangle swtRect = getBounds(); - this.addMouseMoveListener(new MouseMoveListener() { - public void mouseMove(MouseEvent me) { - if (isButton1Pressed || isButton2Pressed || isButton3Pressed) { - java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_DRAGGED,1); - sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_DRAGGED); - } - else { - java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me,java.awt.event.MouseEvent.MOUSE_MOVED,1); - sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_MOVED); - } - } - }); - - this.addKeyListener(new KeyListener() { - public void keyPressed(KeyEvent ke) { - java.awt.event.KeyEvent inputEvent = new PSWTKeyEvent(ke,java.awt.event.KeyEvent.KEY_PRESSED); - sendInputEventToInputManager(inputEvent, java.awt.event.KeyEvent.KEY_PRESSED); - } - - public void keyReleased(KeyEvent ke) { - java.awt.event.KeyEvent inputEvent = new PSWTKeyEvent(ke,java.awt.event.KeyEvent.KEY_RELEASED); - sendInputEventToInputManager(inputEvent, java.awt.event.KeyEvent.KEY_RELEASED); - } - }); + camera.setBounds(new Rectangle2D.Double(swtRect.x, swtRect.y, swtRect.width, swtRect.height)); + } + } - } + /** + * Return root for this canvas. + */ + public PRoot getRoot() { + return camera.getRoot(); + } - protected void sendInputEventToInputManager(InputEvent e, int type) { - getRoot().getDefaultInputManager().processEventFromCamera(e, type, getCamera()); - } - - public void setBounds(int x, int y, final int w, final int h) { - camera.setBounds(camera.getX(), camera.getY(), w, h); + /** + * Return layer for this canvas. + */ + public PLayer getLayer() { + return camera.getLayer(0); + } - if (backBuffer == null || backBuffer.getBounds().width < w || backBuffer.getBounds().height < h) { - backBuffer = new Image(getDisplay(),w,h); - } + /** + * Add an input listener to the camera associated with this canvas. + */ + public void addInputEventListener(PInputEventListener listener) { + getCamera().addInputEventListener(listener); + } - super.setBounds(x, y, w, h); - } + /** + * Remove an input listener to the camera associated with this canvas. + */ + public void removeInputEventListener(PInputEventListener listener) { + getCamera().removeInputEventListener(listener); + } - public void repaint() { - super.redraw(); - } - - public void repaint(PBounds bounds) { - bounds.expandNearestIntegerDimensions(); - bounds.inset(-1, -1); + public PCamera createBasicSceneGraph() { + PRoot r = new PSWTRoot(this); + PLayer l = new PLayer(); + PCamera c = new PCamera(); - redraw((int)bounds.x, - (int)bounds.y, - (int)bounds.width, - (int)bounds.height, - true); - } + r.addChild(c); + r.addChild(l); + c.addLayer(l); - public void paintComponent(GC gc, int x, int y, int w, int h) { - PDebug.startProcessingOutput(); + return c; + } - GC imageGC = null; - Graphics2D g2 = null; - if (doubleBuffered) { - imageGC = new GC(backBuffer); - g2 = new SWTGraphics2D(imageGC,getDisplay()); - } - else { - g2 = new SWTGraphics2D(gc,getDisplay()); - } + // **************************************************************** + // Painting + // **************************************************************** - g2.setColor(Color.white); - g2.setBackground(Color.white); - - Rectangle rect = getBounds(); - g2.fillRect(0,0,rect.width,rect.height); + /** + * Return true if this canvas has been marked as interacting. If so the + * canvas will normally render at a lower quality that is faster. + */ + public boolean getInteracting() { + return interacting > 0; + } - // This fixes a problem with standard debugging of region management in SWT - if (PDebug.debugRegionManagement) { - Rectangle r = gc.getClipping(); - Rectangle2D r2 = new Rectangle2D.Double(r.x,r.y,r.width,r.height); - g2.setBackground(PDebug.getDebugPaintColor()); - g2.fill(r2); - } - - // create new paint context and set render quality - PPaintContext paintContext = new PPaintContext(g2); - if (getInteracting() || getAnimating()) { - if (interactingRenderQuality > animatingRenderQuality) { - paintContext.setRenderQuality(interactingRenderQuality); - } else { - paintContext.setRenderQuality(animatingRenderQuality); - } - } else { - paintContext.setRenderQuality(defaultRenderQuality); - } - - // paint piccolo - camera.fullPaint(paintContext); - - // if switched state from animating to not animating invalidate the entire - // screen so that it will be drawn with the default instead of animating - // render quality. - if (!getAnimating() && animatingOnLastPaint) { - repaint(); - } - animatingOnLastPaint = getAnimating(); + /** + * Return true if any activities that respond with true to the method + * isAnimating were run in the last PRoot.processInputs() loop. This values + * is used by this canvas to determine the render quality to use for the + * next paint. + */ + public boolean getAnimating() { + return getRoot().getActivityScheduler().getAnimating(); + } - boolean region = PDebug.debugRegionManagement; - PDebug.debugRegionManagement = false; - PDebug.endProcessingOutput(g2); - PDebug.debugRegionManagement = region; - - if (doubleBuffered) { - gc.drawImage(backBuffer,0,0); - - // Dispose of the allocated image gc - imageGC.dispose(); - } - } - - public void paintImmediately() { - if (paintingImmediately) { - return; - } - - paintingImmediately = true; - redraw(); - update(); - paintingImmediately = false; - } + /** + * Set if this canvas is interacting. If so the canvas will normally render + * at a lower quality that is faster. + */ + public void setInteracting(boolean isInteracting) { + if (isInteracting) { + interacting++; + } + else { + interacting--; + } + + if (!getInteracting()) { + repaint(); + } + } + + /** + * Get whether this canvas should use double buffering - the default is no + * double buffering + */ + public boolean getDoubleBuffered() { + return doubleBuffered; + } + + /** + * Set whether this canvas should use double buffering - the default is no + * double buffering + */ + public void setDoubleBuffered(boolean dBuffered) { + this.doubleBuffered = dBuffered; + } + + /** + * Set the render quality that should be used when rendering this canvas. + * The default value is PPaintContext.HIGH_QUALITY_RENDERING. + * + * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or + * PPaintContext.LOW_QUALITY_RENDERING + */ + public void setDefaultRenderQuality(int requestedQuality) { + defaultRenderQuality = requestedQuality; + repaint(); + } + + /** + * Set the render quality that should be used when rendering this canvas + * when it is animating. The default value is + * PPaintContext.LOW_QUALITY_RENDERING. + * + * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or + * PPaintContext.LOW_QUALITY_RENDERING + */ + public void setAnimatingRenderQuality(int requestedQuality) { + animatingRenderQuality = requestedQuality; + repaint(); + } + + /** + * Set the render quality that should be used when rendering this canvas + * when it is interacting. The default value is + * PPaintContext.LOW_QUALITY_RENDERING. + * + * @param requestedQuality supports PPaintContext.HIGH_QUALITY_RENDERING or + * PPaintContext.LOW_QUALITY_RENDERING + */ + public void setInteractingRenderQuality(int requestedQuality) { + interactingRenderQuality = requestedQuality; + repaint(); + } + + /** + * Set the canvas cursor, and remember the previous cursor on the cursor + * stack. + */ + public void pushCursor(java.awt.Cursor cursor) { + Cursor aCursor = null; + if (cursor.getType() == java.awt.Cursor.N_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZEN); + } + else if (cursor.getType() == java.awt.Cursor.NE_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZENE); + } + else if (cursor.getType() == java.awt.Cursor.NW_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZENW); + } + else if (cursor.getType() == java.awt.Cursor.S_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZES); + } + else if (cursor.getType() == java.awt.Cursor.SE_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZESE); + } + else if (cursor.getType() == java.awt.Cursor.SW_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZESW); + } + else if (cursor.getType() == java.awt.Cursor.E_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZEE); + } + else if (cursor.getType() == java.awt.Cursor.W_RESIZE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZEW); + } + else if (cursor.getType() == java.awt.Cursor.TEXT_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_IBEAM); + } + else if (cursor.getType() == java.awt.Cursor.HAND_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_HAND); + } + else if (cursor.getType() == java.awt.Cursor.MOVE_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_SIZEALL); + } + else if (cursor.getType() == java.awt.Cursor.CROSSHAIR_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_CROSS); + } + else if (cursor.getType() == java.awt.Cursor.WAIT_CURSOR) { + aCursor = new Cursor(this.getDisplay(), SWT.CURSOR_WAIT); + } + + if (aCursor != null) { + if (curCursor != null) { + cursorStack.push(curCursor); + } + curCursor = aCursor; + setCursor(aCursor); + } + } + + /** + * Pop the cursor on top of the cursorStack and set it as the canvas cursor. + */ + public void popCursor() { + if (curCursor != null) { + // We must manually dispose of cursors under SWT + curCursor.dispose(); + } + + if (!cursorStack.isEmpty()) { + curCursor = (Cursor) cursorStack.pop(); + } + else { + curCursor = null; + } + + // This sets the cursor back to default + setCursor(curCursor); + } + + // **************************************************************** + // Code to manage connection to Swing. There appears to be a bug in + // swing where it will occasionally send to many mouse pressed or mouse + // released events. Below we attempt to filter out those cases before + // they get delivered to the Piccolo framework. + // **************************************************************** + + private boolean isButton1Pressed; + private boolean isButton2Pressed; + private boolean isButton3Pressed; + + /** + * This method installs mouse and key listeners on the canvas that forward + * those events to piccolo. + */ + protected void installInputSources() { + this.addMouseListener(new MouseListener() { + public void mouseDown(MouseEvent me) { + boolean shouldBalanceEvent = false; + + switch (me.button) { + case 1: + if (isButton1Pressed) { + shouldBalanceEvent = true; + } + isButton1Pressed = true; + break; + case 2: + if (isButton2Pressed) { + shouldBalanceEvent = true; + } + isButton2Pressed = true; + break; + case 3: + if (isButton3Pressed) { + shouldBalanceEvent = true; + } + isButton3Pressed = true; + break; + } + + if (shouldBalanceEvent) { + java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_RELEASED, 1); + sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); + } + + java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_PRESSED, 1); + sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); + } + + public void mouseUp(MouseEvent me) { + boolean shouldBalanceEvent = false; + + switch (me.button) { + case 1: + if (!isButton1Pressed) { + shouldBalanceEvent = true; + } + isButton1Pressed = false; + break; + case 2: + if (!isButton2Pressed) { + shouldBalanceEvent = true; + } + isButton2Pressed = false; + break; + case 3: + if (!isButton3Pressed) { + shouldBalanceEvent = true; + } + isButton3Pressed = false; + break; + } + + if (shouldBalanceEvent) { + java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_PRESSED, 1); + sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); + } + + java.awt.event.MouseEvent balanceEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_RELEASED, 1); + sendInputEventToInputManager(balanceEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); + } + + public void mouseDoubleClick(final MouseEvent me) { + // This doesn't work with click event types for some reason - it + // has to do with how the click and release events are ordered, + // I think + java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me, java.awt.event.MouseEvent.MOUSE_PRESSED, + 2); + sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_PRESSED); + inputEvent = new PSWTMouseEvent(me, java.awt.event.MouseEvent.MOUSE_RELEASED, 2); + sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_RELEASED); + } + }); + + this.addMouseMoveListener(new MouseMoveListener() { + public void mouseMove(MouseEvent me) { + if (isButton1Pressed || isButton2Pressed || isButton3Pressed) { + java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_DRAGGED, 1); + sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_DRAGGED); + } + else { + java.awt.event.MouseEvent inputEvent = new PSWTMouseEvent(me, + java.awt.event.MouseEvent.MOUSE_MOVED, 1); + sendInputEventToInputManager(inputEvent, java.awt.event.MouseEvent.MOUSE_MOVED); + } + } + }); + + this.addKeyListener(new KeyListener() { + public void keyPressed(KeyEvent ke) { + java.awt.event.KeyEvent inputEvent = new PSWTKeyEvent(ke, java.awt.event.KeyEvent.KEY_PRESSED); + sendInputEventToInputManager(inputEvent, java.awt.event.KeyEvent.KEY_PRESSED); + } + + public void keyReleased(KeyEvent ke) { + java.awt.event.KeyEvent inputEvent = new PSWTKeyEvent(ke, java.awt.event.KeyEvent.KEY_RELEASED); + sendInputEventToInputManager(inputEvent, java.awt.event.KeyEvent.KEY_RELEASED); + } + }); + + } + + protected void sendInputEventToInputManager(InputEvent e, int type) { + getRoot().getDefaultInputManager().processEventFromCamera(e, type, getCamera()); + } + + public void setBounds(int x, int y, final int w, final int h) { + camera.setBounds(camera.getX(), camera.getY(), w, h); + + if (backBuffer == null || backBuffer.getBounds().width < w || backBuffer.getBounds().height < h) { + backBuffer = new Image(getDisplay(), w, h); + } + + super.setBounds(x, y, w, h); + } + + public void repaint() { + super.redraw(); + } + + public void repaint(PBounds bounds) { + bounds.expandNearestIntegerDimensions(); + bounds.inset(-1, -1); + + redraw((int) bounds.x, (int) bounds.y, (int) bounds.width, (int) bounds.height, true); + } + + public void paintComponent(GC gc, int x, int y, int w, int h) { + PDebug.startProcessingOutput(); + + GC imageGC = null; + Graphics2D g2 = null; + if (doubleBuffered) { + imageGC = new GC(backBuffer); + g2 = new SWTGraphics2D(imageGC, getDisplay()); + } + else { + g2 = new SWTGraphics2D(gc, getDisplay()); + } + + g2.setColor(Color.white); + g2.setBackground(Color.white); + + Rectangle rect = getBounds(); + g2.fillRect(0, 0, rect.width, rect.height); + + // This fixes a problem with standard debugging of region management in + // SWT + if (PDebug.debugRegionManagement) { + Rectangle r = gc.getClipping(); + Rectangle2D r2 = new Rectangle2D.Double(r.x, r.y, r.width, r.height); + g2.setBackground(PDebug.getDebugPaintColor()); + g2.fill(r2); + } + + // create new paint context and set render quality + PPaintContext paintContext = new PPaintContext(g2); + if (getInteracting() || getAnimating()) { + if (interactingRenderQuality > animatingRenderQuality) { + paintContext.setRenderQuality(interactingRenderQuality); + } + else { + paintContext.setRenderQuality(animatingRenderQuality); + } + } + else { + paintContext.setRenderQuality(defaultRenderQuality); + } + + // paint piccolo + camera.fullPaint(paintContext); + + // if switched state from animating to not animating invalidate + // the entire screen so that it will be drawn with the default instead + // of animating render quality. + if (!getAnimating() && animatingOnLastPaint) { + repaint(); + } + animatingOnLastPaint = getAnimating(); + + boolean region = PDebug.debugRegionManagement; + PDebug.debugRegionManagement = false; + PDebug.endProcessingOutput(g2); + PDebug.debugRegionManagement = region; + + if (doubleBuffered) { + gc.drawImage(backBuffer, 0, 0); + + // Dispose of the allocated image gc + imageGC.dispose(); + } + } + + public void paintImmediately() { + if (paintingImmediately) { + return; + } + + paintingImmediately = true; + redraw(); + update(); + paintingImmediately = false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java index 0704363..cb1c37b 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java @@ -50,169 +50,174 @@ import edu.umd.cs.piccolox.util.PNodeLocator; /** - * PHandle is used to modify some aspect of Piccolo when it - * is dragged. Each handle has a PLocator that it uses to automatically position - * itself. See PBoundsHandle for an example of a handle that resizes the bounds - * of another node. + * PHandle is used to modify some aspect of Piccolo when it is dragged. + * Each handle has a PLocator that it uses to automatically position itself. See + * PBoundsHandle for an example of a handle that resizes the bounds of another + * node. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PSWTHandle extends PSWTPath { - public static float DEFAULT_HANDLE_SIZE = 8; - public static Shape DEFAULT_HANDLE_SHAPE = new Ellipse2D.Float(0f, 0f, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); - public static Color DEFAULT_COLOR = Color.white; - - private PLocator locator; - private PDragSequenceEventHandler handleDragger; + public static float DEFAULT_HANDLE_SIZE = 8; + public static Shape DEFAULT_HANDLE_SHAPE = new Ellipse2D.Float(0f, 0f, DEFAULT_HANDLE_SIZE, DEFAULT_HANDLE_SIZE); + public static Color DEFAULT_COLOR = Color.white; - /** - * Construct a new handle that will use the given locator - * to locate itself on its parent node. - */ - public PSWTHandle(PLocator aLocator) { - super(DEFAULT_HANDLE_SHAPE); - locator = aLocator; - setPaint(DEFAULT_COLOR); - installHandleEventHandlers(); - } + private PLocator locator; + private PDragSequenceEventHandler handleDragger; - protected void installHandleEventHandlers() { - handleDragger = new PDragSequenceEventHandler() { - protected void startDrag(PInputEvent event) { - super.startDrag(event); - startHandleDrag(event.getPositionRelativeTo(PSWTHandle.this), event); - } - protected void drag(PInputEvent event) { - super.drag(event); - PDimension aDelta = event.getDeltaRelativeTo(PSWTHandle.this); - if (aDelta.getWidth() != 0 || aDelta.getHeight() != 0) { - dragHandle(aDelta, event); - } - } - protected void endDrag(PInputEvent event) { - super.endDrag(event); - endHandleDrag(event.getPositionRelativeTo(PSWTHandle.this), event); - } - }; + /** + * Construct a new handle that will use the given locator to locate itself + * on its parent node. + */ + public PSWTHandle(PLocator aLocator) { + super(DEFAULT_HANDLE_SHAPE); + locator = aLocator; + setPaint(DEFAULT_COLOR); + installHandleEventHandlers(); + } - addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { - public void propertyChange(PropertyChangeEvent evt) { - relocateHandle(); - } - }); - - handleDragger.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); - handleDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); - handleDragger.getEventFilter().setAcceptsMouseEntered(false); - handleDragger.getEventFilter().setAcceptsMouseExited(false); - handleDragger.getEventFilter().setAcceptsMouseMoved(false); // no need for moved events for handle interaction, - // so reject them so we don't consume them - addInputEventListener(handleDragger); - } - - /** - * Return the event handler that is responsible for the drag handle - * interaction. - */ - public PDragSequenceEventHandler getHandleDraggerHandler() { - return handleDragger; - } + protected void installHandleEventHandlers() { + handleDragger = new PDragSequenceEventHandler() { + protected void startDrag(PInputEvent event) { + super.startDrag(event); + startHandleDrag(event.getPositionRelativeTo(PSWTHandle.this), event); + } - /** - * Get the locator that this handle uses to position itself on its - * parent node. - */ - public PLocator getLocator() { - return locator; - } - - /** - * Set the locator that this handle uses to position itself on its - * parent node. - */ - public void setLocator(PLocator aLocator) { - locator = aLocator; - invalidatePaint(); - relocateHandle(); - } - - //**************************************************************** - // Handle Dragging - These are the methods the subclasses should - // normally override to give a handle unique behavior. - //**************************************************************** - - /** - * Override this method to get notified when the handle starts to get dragged. - */ - public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - } - - /** - * Override this method to get notified as the handle is dragged. - */ - public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { - } - - /** - * Override this method to get notified when the handle stops getting dragged. - */ - public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { - } - - //**************************************************************** - // Layout - When a handle's parent's layout changes the handle - // invalidates its own layout and then repositions itself on its - // parents bounds using its locator to determine that new - // position. - //**************************************************************** - - public void setParent(PNode newParent) { - super.setParent(newParent); - relocateHandle(); - } - - public void parentBoundsChanged() { - relocateHandle(); - } - - /** - * Force this handle to relocate itself using its locator. - */ - public void relocateHandle() { - if (locator != null) { - PBounds b = getBoundsReference(); - Point2D aPoint = locator.locatePoint(null); - - if (locator instanceof PNodeLocator) { - PNode located = ((PNodeLocator)locator).getNode(); - PNode parent = getParent(); - - located.localToGlobal(aPoint); - globalToLocal(aPoint); - - if (parent != located && parent instanceof PCamera) { - ((PCamera)parent).viewToLocal(aPoint); - } - } - - double newCenterX = aPoint.getX(); - double newCenterY = aPoint.getY(); + protected void drag(PInputEvent event) { + super.drag(event); + PDimension aDelta = event.getDeltaRelativeTo(PSWTHandle.this); + if (aDelta.getWidth() != 0 || aDelta.getHeight() != 0) { + dragHandle(aDelta, event); + } + } - if (newCenterX != b.getCenterX() || - newCenterY != b.getCenterY()) { - centerBoundsOnPoint(newCenterX, newCenterY); - } - } - } - - //**************************************************************** - // Serialization - //**************************************************************** - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - in.defaultReadObject(); - installHandleEventHandlers(); - } + protected void endDrag(PInputEvent event) { + super.endDrag(event); + endHandleDrag(event.getPositionRelativeTo(PSWTHandle.this), event); + } + }; + + addPropertyChangeListener(PNode.PROPERTY_TRANSFORM, new PropertyChangeListener() { + public void propertyChange(PropertyChangeEvent evt) { + relocateHandle(); + } + }); + + handleDragger.setEventFilter(new PInputEventFilter(InputEvent.BUTTON1_MASK)); + handleDragger.getEventFilter().setMarksAcceptedEventsAsHandled(true); + handleDragger.getEventFilter().setAcceptsMouseEntered(false); + handleDragger.getEventFilter().setAcceptsMouseExited(false); + // no need for moved events for handle interaction, + handleDragger.getEventFilter().setAcceptsMouseMoved(false); + // so reject them so we don't consume them + addInputEventListener(handleDragger); + } + + /** + * Return the event handler that is responsible for the drag handle + * interaction. + */ + public PDragSequenceEventHandler getHandleDraggerHandler() { + return handleDragger; + } + + /** + * Get the locator that this handle uses to position itself on its parent + * node. + */ + public PLocator getLocator() { + return locator; + } + + /** + * Set the locator that this handle uses to position itself on its parent + * node. + */ + public void setLocator(PLocator aLocator) { + locator = aLocator; + invalidatePaint(); + relocateHandle(); + } + + // **************************************************************** + // Handle Dragging - These are the methods the subclasses should + // normally override to give a handle unique behavior. + // **************************************************************** + + /** + * Override this method to get notified when the handle starts to get + * dragged. + */ + public void startHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + } + + /** + * Override this method to get notified as the handle is dragged. + */ + public void dragHandle(PDimension aLocalDimension, PInputEvent aEvent) { + } + + /** + * Override this method to get notified when the handle stops getting + * dragged. + */ + public void endHandleDrag(Point2D aLocalPoint, PInputEvent aEvent) { + } + + // **************************************************************** + // Layout - When a handle's parent's layout changes the handle + // invalidates its own layout and then repositions itself on its + // parents bounds using its locator to determine that new + // position. + // **************************************************************** + + public void setParent(PNode newParent) { + super.setParent(newParent); + relocateHandle(); + } + + public void parentBoundsChanged() { + relocateHandle(); + } + + /** + * Force this handle to relocate itself using its locator. + */ + public void relocateHandle() { + if (locator != null) { + PBounds b = getBoundsReference(); + Point2D aPoint = locator.locatePoint(null); + + if (locator instanceof PNodeLocator) { + PNode located = ((PNodeLocator) locator).getNode(); + PNode parent = getParent(); + + located.localToGlobal(aPoint); + globalToLocal(aPoint); + + if (parent != located && parent instanceof PCamera) { + ((PCamera) parent).viewToLocal(aPoint); + } + } + + double newCenterX = aPoint.getX(); + double newCenterY = aPoint.getY(); + + if (newCenterX != b.getCenterX() || newCenterY != b.getCenterY()) { + centerBoundsOnPoint(newCenterX, newCenterY); + } + } + } + + // **************************************************************** + // Serialization + // **************************************************************** + + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + installHandleEventHandlers(); + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java index 2e5ee28..22f2f8c 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java @@ -40,124 +40,129 @@ import edu.umd.cs.piccolo.util.PPaintContext; /** - * PImage is a wrapper around a java.awt.Image. If this node is - * copied or serialized that image will be converted into a BufferedImage if - * it is not already one. + * PImage is a wrapper around a java.awt.Image. If this node is copied or + * serialized that image will be converted into a BufferedImage if it is not + * already one. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PSWTImage extends PNode { - - private transient PSWTCanvas canvas; - private transient Image image; + private transient PSWTCanvas canvas; - public PSWTImage(PSWTCanvas canvas) { - super(); - - this.canvas = canvas; - canvas.addDisposeListener(new DisposeListener() { - public void widgetDisposed(DisposeEvent de) { - if (image != null) { - image.dispose(); - } - } - }); - } - - public PSWTImage(PSWTCanvas canvas, Image newImage) { - this(canvas); - setImage(newImage); - } + private transient Image image; - public PSWTImage(PSWTCanvas canvas, String fileName) { - this(canvas); - setImage(fileName); - } - - /** - * Returns the image that is shown by this node. - * @return the image that is shown by this node - */ - public Image getImage() { - return image; - } + public PSWTImage(PSWTCanvas canvas) { + super(); - /** - * Set the image that is wrapped by this PImage node. This method will also load - * the image using a MediaTracker before returning. And if the this PImage is - * accelerated that I'm will be copied into an accelerated image if needed. Note - * that this may cause undesired results with images that have transparent regions, - * for those cases you may want to set the PImage to be not accelerated. - */ - public void setImage(String fileName) { - setImage(new Image(canvas.getDisplay(),fileName)); - } + this.canvas = canvas; + canvas.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent de) { + if (image != null) { + image.dispose(); + } + } + }); + } - /** - * Set the image that is wrapped by this PImage node. This method will also load - * the image using a MediaTracker before returning. And if the this PImage is - * accelerated that I'm will be copied into an accelerated image if needed. Note - * that this may cause undesired results with images that have transparent regions, - * for those cases you may want to set the PImage to be not accelerated. - */ - public void setImage(Image newImage) { - Image old = image; - image = newImage; - - if (image != null) { - Rectangle bounds = getImage().getBounds(); - setBounds(0, 0, bounds.width, bounds.height); - invalidatePaint(); - } else { - image = null; - } - - firePropertyChange(PImage.PROPERTY_CODE_IMAGE, PImage.PROPERTY_IMAGE, old, image); - } + public PSWTImage(PSWTCanvas canvas, Image newImage) { + this(canvas); + setImage(newImage); + } - protected void paint(PPaintContext paintContext) { - if (getImage() != null) { - Rectangle r = image.getBounds(); - double iw = r.width; - double ih = r.height; - PBounds b = getBoundsReference(); - SWTGraphics2D g2 = (SWTGraphics2D)paintContext.getGraphics(); + public PSWTImage(PSWTCanvas canvas, String fileName) { + this(canvas); + setImage(fileName); + } - if (b.x != 0 || b.y != 0 || b.width != iw || b.height != ih) { - g2.translate(b.x, b.y); - g2.scale(b.width / iw, b.height / ih); - g2.drawImage(image, 0, 0); - g2.scale(iw / b.width, ih / b.height); - g2.translate(-b.x, -b.y); - } else { - g2.drawImage(image, 0, 0); - } - } - } - - - //**************************************************************** - // Debugging - methods for debugging - //**************************************************************** + /** + * Returns the image that is shown by this node. + * + * @return the image that is shown by this node + */ + public Image getImage() { + return image; + } - /** - * Returns a string representing the state of this node. This method is - * intended to be used only for debugging purposes, and the content and - * format of the returned string may vary between implementations. The - * returned string may be empty but may not be null. - * - * @return a string representation of this node's state - */ - protected String paramString() { - StringBuffer result = new StringBuffer(); + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. And if the this + * PImage is accelerated that I'm will be copied into an accelerated image + * if needed. Note that this may cause undesired results with images that + * have transparent regions, for those cases you may want to set the PImage + * to be not accelerated. + */ + public void setImage(String fileName) { + setImage(new Image(canvas.getDisplay(), fileName)); + } - result.append("image=" + (image == null ? "null" : image.toString())); - - result.append(','); - result.append(super.paramString()); + /** + * Set the image that is wrapped by this PImage node. This method will also + * load the image using a MediaTracker before returning. And if the this + * PImage is accelerated that I'm will be copied into an accelerated image + * if needed. Note that this may cause undesired results with images that + * have transparent regions, for those cases you may want to set the PImage + * to be not accelerated. + */ + public void setImage(Image newImage) { + Image old = image; + image = newImage; - return result.toString(); - } + if (image != null) { + Rectangle bounds = getImage().getBounds(); + setBounds(0, 0, bounds.width, bounds.height); + invalidatePaint(); + } + else { + image = null; + } + + firePropertyChange(PImage.PROPERTY_CODE_IMAGE, PImage.PROPERTY_IMAGE, old, image); + } + + protected void paint(PPaintContext paintContext) { + if (getImage() != null) { + Rectangle r = image.getBounds(); + double iw = r.width; + double ih = r.height; + PBounds b = getBoundsReference(); + SWTGraphics2D g2 = (SWTGraphics2D) paintContext.getGraphics(); + + if (b.x != 0 || b.y != 0 || b.width != iw || b.height != ih) { + g2.translate(b.x, b.y); + g2.scale(b.width / iw, b.height / ih); + g2.drawImage(image, 0, 0); + g2.scale(iw / b.width, ih / b.height); + g2.translate(-b.x, -b.y); + } + else { + g2.drawImage(image, 0, 0); + } + } + } + + // **************************************************************** + // Debugging - methods for debugging + // **************************************************************** + + /** + * Returns a string representing the state of this node. This method is + * intended to be used only for debugging purposes, and the content and + * format of the returned string may vary between implementations. The + * returned string may be empty but may not be null. + * + * @return a string representation of this node's state + */ + protected String paramString() { + StringBuffer result = new StringBuffer(); + + result.append("image=" + (image == null ? "null" : image.toString())); + + result.append(','); + result.append(super.paramString()); + + return result.toString(); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java index 6eedfe4..b36f381 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java @@ -15,85 +15,86 @@ */ public class PSWTKeyEvent extends KeyEvent { - static Component fakeSrc = new Component() {}; + static Component fakeSrc = new Component() { + }; - org.eclipse.swt.events.KeyEvent swtEvent; - - public PSWTKeyEvent(org.eclipse.swt.events.KeyEvent ke, int eventType) { - super(fakeSrc, eventType, ke.time, 0, ke.keyCode, ke.character, KeyEvent.KEY_LOCATION_STANDARD); - - swtEvent = ke; - } + org.eclipse.swt.events.KeyEvent swtEvent; - public Object getSource() { - return swtEvent.getSource(); - } + public PSWTKeyEvent(org.eclipse.swt.events.KeyEvent ke, int eventType) { + super(fakeSrc, eventType, ke.time, 0, ke.keyCode, ke.character, KeyEvent.KEY_LOCATION_STANDARD); - public boolean isShiftDown() { - return (swtEvent.stateMask & SWT.SHIFT) != 0; - } + swtEvent = ke; + } - public boolean isControlDown() { - return (swtEvent.stateMask & SWT.CONTROL) != 0; - } - - public boolean isAltDown() { - return (swtEvent.stateMask & SWT.ALT) != 0; - } - - public int getModifiers() { - int modifiers = 0; - - if (swtEvent != null) { - if ((swtEvent.stateMask & SWT.ALT) != 0) { - modifiers = modifiers | InputEvent.ALT_MASK; - } - if ((swtEvent.stateMask & SWT.CONTROL) != 0) { - modifiers = modifiers | InputEvent.CTRL_MASK; - } - if ((swtEvent.stateMask & SWT.SHIFT) != 0) { - modifiers = modifiers | InputEvent.SHIFT_MASK; - } - } + public Object getSource() { + return swtEvent.getSource(); + } - return modifiers; - } - - public int getModifiersEx() { - int modifiers = 0; - - if (swtEvent != null) { - if ((swtEvent.stateMask & SWT.ALT) != 0) { - modifiers = modifiers | InputEvent.ALT_DOWN_MASK; - } - if ((swtEvent.stateMask & SWT.CONTROL) != 0) { - modifiers = modifiers | InputEvent.CTRL_DOWN_MASK; - } - if ((swtEvent.stateMask & SWT.SHIFT) != 0) { - modifiers = modifiers | InputEvent.SHIFT_DOWN_MASK; - } - } - - return modifiers; - } + public boolean isShiftDown() { + return (swtEvent.stateMask & SWT.SHIFT) != 0; + } - public boolean isActionKey() { - return false; - } + public boolean isControlDown() { + return (swtEvent.stateMask & SWT.CONTROL) != 0; + } - /////////////////////////// - // THE SWT SPECIFIC EVENTS - /////////////////////////// + public boolean isAltDown() { + return (swtEvent.stateMask & SWT.ALT) != 0; + } - public Widget getWidget() { - return swtEvent.widget; - } - - public Display getDisplay() { - return swtEvent.display; - } - - public Object getData() { - return swtEvent.data; - } + public int getModifiers() { + int modifiers = 0; + + if (swtEvent != null) { + if ((swtEvent.stateMask & SWT.ALT) != 0) { + modifiers = modifiers | InputEvent.ALT_MASK; + } + if ((swtEvent.stateMask & SWT.CONTROL) != 0) { + modifiers = modifiers | InputEvent.CTRL_MASK; + } + if ((swtEvent.stateMask & SWT.SHIFT) != 0) { + modifiers = modifiers | InputEvent.SHIFT_MASK; + } + } + + return modifiers; + } + + public int getModifiersEx() { + int modifiers = 0; + + if (swtEvent != null) { + if ((swtEvent.stateMask & SWT.ALT) != 0) { + modifiers = modifiers | InputEvent.ALT_DOWN_MASK; + } + if ((swtEvent.stateMask & SWT.CONTROL) != 0) { + modifiers = modifiers | InputEvent.CTRL_DOWN_MASK; + } + if ((swtEvent.stateMask & SWT.SHIFT) != 0) { + modifiers = modifiers | InputEvent.SHIFT_DOWN_MASK; + } + } + + return modifiers; + } + + public boolean isActionKey() { + return false; + } + + // ///////////////////////// + // THE SWT SPECIFIC EVENTS + // ///////////////////////// + + public Widget getWidget() { + return swtEvent.widget; + } + + public Display getDisplay() { + return swtEvent.display; + } + + public Object getData() { + return swtEvent.data; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java index 0117b25..8a31038 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java @@ -15,126 +15,120 @@ */ public class PSWTMouseEvent extends MouseEvent { - static Component fakeSrc = new Component() {}; + static Component fakeSrc = new Component() { + }; - protected org.eclipse.swt.events.MouseEvent swtEvent; - - protected int clickCount; + protected org.eclipse.swt.events.MouseEvent swtEvent; - public PSWTMouseEvent(org.eclipse.swt.events.MouseEvent me, int type, int clickCount) { - super(fakeSrc,type, me.time, 0, me.x, me.y, clickCount, (me.button == 3), me.button); - - this.swtEvent = me; - this.clickCount = clickCount; - } + protected int clickCount; - public Object getSource() { - return swtEvent.getSource(); - } + public PSWTMouseEvent(org.eclipse.swt.events.MouseEvent me, int type, int clickCount) { + super(fakeSrc, type, me.time, 0, me.x, me.y, clickCount, (me.button == 3), me.button); - public int getClickCount() { - return clickCount; - } + this.swtEvent = me; + this.clickCount = clickCount; + } - public int getButton() { - switch (swtEvent.button) { - case 1: - return MouseEvent.BUTTON1; - case 2: - return MouseEvent.BUTTON2; - case 3: - return MouseEvent.BUTTON3; - default: - return MouseEvent.NOBUTTON; - } - } - - public boolean isShiftDown() { - return (swtEvent.stateMask & SWT.SHIFT) != 0; - } + public Object getSource() { + return swtEvent.getSource(); + } - public boolean isControlDown() { - return (swtEvent.stateMask & SWT.CONTROL) != 0; - } - - public boolean isAltDown() { - return (swtEvent.stateMask & SWT.ALT) != 0; - } - - public int getModifiers() { - int modifiers = 0; - - if (swtEvent != null) { - if ((swtEvent.stateMask & SWT.ALT) != 0) { - modifiers = modifiers | InputEvent.ALT_MASK; - } - if ((swtEvent.stateMask & SWT.CONTROL) != 0) { - modifiers = modifiers | InputEvent.CTRL_MASK; - } - if ((swtEvent.stateMask & SWT.SHIFT) != 0) { - modifiers = modifiers | InputEvent.SHIFT_MASK; - } - if (swtEvent.button == 1 || - (swtEvent.stateMask & SWT.BUTTON1) != 0) { - modifiers = modifiers | InputEvent.BUTTON1_MASK; - } - if (swtEvent.button == 2 || - (swtEvent.stateMask & SWT.BUTTON2) != 0) { - modifiers = modifiers | InputEvent.BUTTON2_MASK; - } - if (swtEvent.button == 3 || - (swtEvent.stateMask & SWT.BUTTON3) != 0) { - modifiers = modifiers | InputEvent.BUTTON3_MASK; - } - } - - return modifiers; - } - - public int getModifiersEx() { - int modifiers = 0; - - if (swtEvent != null) { - if ((swtEvent.stateMask & SWT.ALT) != 0) { - modifiers = modifiers | InputEvent.ALT_DOWN_MASK; - } - if ((swtEvent.stateMask & SWT.CONTROL) != 0) { - modifiers = modifiers | InputEvent.CTRL_DOWN_MASK; - } - if ((swtEvent.stateMask & SWT.SHIFT) != 0) { - modifiers = modifiers | InputEvent.SHIFT_DOWN_MASK; - } - if (swtEvent.button == 1 || - (swtEvent.stateMask & SWT.BUTTON1) != 0) { - modifiers = modifiers | InputEvent.BUTTON1_DOWN_MASK; - } - if (swtEvent.button == 2 || - (swtEvent.stateMask & SWT.BUTTON2) != 0) { - modifiers = modifiers | InputEvent.BUTTON2_DOWN_MASK; - } - if (swtEvent.button == 3 || - (swtEvent.stateMask & SWT.BUTTON3) != 0) { - modifiers = modifiers | InputEvent.BUTTON3_DOWN_MASK; - } - } - - return modifiers; - } + public int getClickCount() { + return clickCount; + } + public int getButton() { + switch (swtEvent.button) { + case 1: + return MouseEvent.BUTTON1; + case 2: + return MouseEvent.BUTTON2; + case 3: + return MouseEvent.BUTTON3; + default: + return MouseEvent.NOBUTTON; + } + } - /////////////////////////// - // THE SWT SPECIFIC EVENTS - /////////////////////////// + public boolean isShiftDown() { + return (swtEvent.stateMask & SWT.SHIFT) != 0; + } - public Widget getWidget() { - return swtEvent.widget; - } - - public Display getDisplay() { - return swtEvent.display; - } - - public Object getData() { - return swtEvent.data; - } + public boolean isControlDown() { + return (swtEvent.stateMask & SWT.CONTROL) != 0; + } + + public boolean isAltDown() { + return (swtEvent.stateMask & SWT.ALT) != 0; + } + + public int getModifiers() { + int modifiers = 0; + + if (swtEvent != null) { + if ((swtEvent.stateMask & SWT.ALT) != 0) { + modifiers = modifiers | InputEvent.ALT_MASK; + } + if ((swtEvent.stateMask & SWT.CONTROL) != 0) { + modifiers = modifiers | InputEvent.CTRL_MASK; + } + if ((swtEvent.stateMask & SWT.SHIFT) != 0) { + modifiers = modifiers | InputEvent.SHIFT_MASK; + } + if (swtEvent.button == 1 || (swtEvent.stateMask & SWT.BUTTON1) != 0) { + modifiers = modifiers | InputEvent.BUTTON1_MASK; + } + if (swtEvent.button == 2 || (swtEvent.stateMask & SWT.BUTTON2) != 0) { + modifiers = modifiers | InputEvent.BUTTON2_MASK; + } + if (swtEvent.button == 3 || (swtEvent.stateMask & SWT.BUTTON3) != 0) { + modifiers = modifiers | InputEvent.BUTTON3_MASK; + } + } + + return modifiers; + } + + public int getModifiersEx() { + int modifiers = 0; + + if (swtEvent != null) { + if ((swtEvent.stateMask & SWT.ALT) != 0) { + modifiers = modifiers | InputEvent.ALT_DOWN_MASK; + } + if ((swtEvent.stateMask & SWT.CONTROL) != 0) { + modifiers = modifiers | InputEvent.CTRL_DOWN_MASK; + } + if ((swtEvent.stateMask & SWT.SHIFT) != 0) { + modifiers = modifiers | InputEvent.SHIFT_DOWN_MASK; + } + if (swtEvent.button == 1 || (swtEvent.stateMask & SWT.BUTTON1) != 0) { + modifiers = modifiers | InputEvent.BUTTON1_DOWN_MASK; + } + if (swtEvent.button == 2 || (swtEvent.stateMask & SWT.BUTTON2) != 0) { + modifiers = modifiers | InputEvent.BUTTON2_DOWN_MASK; + } + if (swtEvent.button == 3 || (swtEvent.stateMask & SWT.BUTTON3) != 0) { + modifiers = modifiers | InputEvent.BUTTON3_DOWN_MASK; + } + } + + return modifiers; + } + + // ///////////////////////// + // THE SWT SPECIFIC EVENTS + // ///////////////////////// + + public Widget getWidget() { + return swtEvent.widget; + } + + public Display getDisplay() { + return swtEvent.display; + } + + public Object getData() { + return swtEvent.data; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java index 3b9f750..cb8a559 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java @@ -49,387 +49,403 @@ import edu.umd.cs.piccolo.util.PPaintContext; /** - * PPath is a wrapper around a java.awt.geom.GeneralPath. The - * setBounds method works by scaling the path to fit into the specified - * bounds. This normally works well, but if the specified base bounds - * get too small then it is impossible to expand the path shape again since - * all its numbers have tended to zero, so application code may need to take - * this into consideration. + * PPath is a wrapper around a java.awt.geom.GeneralPath. The setBounds + * method works by scaling the path to fit into the specified bounds. This + * normally works well, but if the specified base bounds get too small then it + * is impossible to expand the path shape again since all its numbers have + * tended to zero, so application code may need to take this into consideration. *

- * One option that applications have is to call startResizeBounds before - * starting an interaction that may make the bounds very small, and calling - * endResizeBounds when this interaction is finished. When this is done - * PPath will use a copy of the original path to do the resizing so the numbers - * in the path wont loose resolution. + * One option that applications have is to call startResizeBounds + * before starting an interaction that may make the bounds very small, and + * calling endResizeBounds when this interaction is finished. When + * this is done PPath will use a copy of the original path to do the resizing so + * the numbers in the path wont loose resolution. *

- * This class also provides methods for constructing common shapes using a + * This class also provides methods for constructing common shapes using a * general path. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PSWTPath extends PNode { - - /** - * The property name that identifies a change of this node's path. - * In any property change event the new value will be a reference to - * this node's path, but old value will always be null. - */ - public static final String PROPERTY_SHAPE = "shape"; - private static final double BOUNDS_TOLERANCE = 0.01; - private static final Rectangle2D.Float TEMP_RECTANGLE = new Rectangle2D.Float(); - private static final RoundRectangle2D.Float TEMP_ROUNDRECTANGLE = new RoundRectangle2D.Float(); - private static final Ellipse2D.Float TEMP_ELLIPSE = new Ellipse2D.Float(); - private static final Color DEFAULT_STROKE_PAINT = Color.black; - private static final BasicStroke BASIC_STROKE = new BasicStroke(); - private static final float PEN_WIDTH = 1f; - - private Paint strokePaint; + /** + * The property name that identifies a change of this node's path. In any + * property change event the new value will be a reference to this node's + * path, but old value will always be null. + */ + public static final String PROPERTY_SHAPE = "shape"; - boolean updatingBoundsFromPath; - Shape origShape; - Shape shape; - - PAffineTransform internalXForm; - AffineTransform inverseXForm; - - double[] shapePts; + private static final double BOUNDS_TOLERANCE = 0.01; + private static final Rectangle2D.Float TEMP_RECTANGLE = new Rectangle2D.Float(); + private static final RoundRectangle2D.Float TEMP_ROUNDRECTANGLE = new RoundRectangle2D.Float(); + private static final Ellipse2D.Float TEMP_ELLIPSE = new Ellipse2D.Float(); + private static final Color DEFAULT_STROKE_PAINT = Color.black; + private static final BasicStroke BASIC_STROKE = new BasicStroke(); + private static final float PEN_WIDTH = 1f; - public static PSWTPath createRectangle(float x, float y, float width, float height) { - TEMP_RECTANGLE.setFrame(x, y, width, height); - PSWTPath result = new PSWTPath(TEMP_RECTANGLE); - result.setPaint(Color.white); - return result; - } - - public static PSWTPath createRoundRectangle(float x, float y, float width, float height, float arcWidth, float arcHeight) { - TEMP_ROUNDRECTANGLE.setRoundRect(x, y, width, height, arcWidth, arcHeight); - PSWTPath result = new PSWTPath(TEMP_ROUNDRECTANGLE); - result.setPaint(Color.white); - return result; - } - - public static PSWTPath createEllipse(float x, float y, float width, float height) { - TEMP_ELLIPSE.setFrame(x, y, width, height); - PSWTPath result = new PSWTPath(TEMP_ELLIPSE); - result.setPaint(Color.white); - return result; - } - - public static PSWTPath createPolyline(Point2D[] points) { - PSWTPath result = new PSWTPath(); - result.setPathToPolyline(points); - result.setPaint(Color.white); - return result; - } + private Paint strokePaint; - public static PSWTPath createPolyline(float[] xp, float[] yp) { - PSWTPath result = new PSWTPath(); - result.setPathToPolyline(xp, yp); - result.setPaint(Color.white); - return result; - } - - public PSWTPath() { - strokePaint = DEFAULT_STROKE_PAINT; - } + boolean updatingBoundsFromPath; + Shape origShape; + Shape shape; - public PSWTPath(Shape aShape) { - this(); - setShape(aShape); - } - - //**************************************************************** - // Stroke - //**************************************************************** - - public Paint getStrokePaint() { - return strokePaint; - } + PAffineTransform internalXForm; + AffineTransform inverseXForm; - public void setStrokeColor(Paint aPaint) { - Paint old = strokePaint; - strokePaint = aPaint; - invalidatePaint(); - firePropertyChange(PPath.PROPERTY_CODE_STROKE_PAINT, PPath.PROPERTY_STROKE_PAINT, old, strokePaint); - } - - /** - * Set the bounds of this path. This method works by scaling the path - * to fit into the specified bounds. This normally works well, but if - * the specified base bounds get too small then it is impossible to - * expand the path shape again since all its numbers have tended to zero, - * so application code may need to take this into consideration. - */ - protected void internalUpdateBounds(double x, double y, double width, double height) { - if (updatingBoundsFromPath) return; - if (origShape == null) return; - - Rectangle2D pathBounds = origShape.getBounds2D(); + double[] shapePts; - if (Math.abs(x-pathBounds.getX())/x < BOUNDS_TOLERANCE && - Math.abs(y-pathBounds.getY())/y < BOUNDS_TOLERANCE && - Math.abs(width-pathBounds.getWidth())/width < BOUNDS_TOLERANCE && - Math.abs(height-pathBounds.getHeight())/height < BOUNDS_TOLERANCE) { - return; - } - - if (internalXForm == null) { - internalXForm = new PAffineTransform(); - } - internalXForm.setToIdentity(); - internalXForm.translate(x, y); - internalXForm.scale(width / pathBounds.getWidth(), height / pathBounds.getHeight()); - internalXForm.translate(-pathBounds.getX(), -pathBounds.getY()); - - try { - inverseXForm = internalXForm.createInverse(); - } - catch (Exception e) { - } - } + public static PSWTPath createRectangle(float x, float y, float width, float height) { + TEMP_RECTANGLE.setFrame(x, y, width, height); + PSWTPath result = new PSWTPath(TEMP_RECTANGLE); + result.setPaint(Color.white); + return result; + } - - public boolean intersects(Rectangle2D aBounds) { - if (super.intersects(aBounds)) { - - if (internalXForm != null) { - aBounds = new PBounds(aBounds); - internalXForm.inverseTransform(aBounds,aBounds); - } - - if (getPaint() != null && shape.intersects(aBounds)) { - return true; - } else if (strokePaint != null) { - return BASIC_STROKE.createStrokedShape(shape).intersects(aBounds); - } - } - return false; - } - - public void updateBoundsFromPath() { - updatingBoundsFromPath = true; - - if (origShape == null) { - resetBounds(); - } else { - Rectangle2D b = origShape.getBounds2D(); - - // Note that this pen width code does not really work for SWT since it assumes - // that the pen width scales - in actuality it does not. However, the fix would - // be to have volatile bounds for all shapes which isn't a nice alternative - super.setBounds(b.getX()-PEN_WIDTH, - b.getY()-PEN_WIDTH, - b.getWidth()+2*PEN_WIDTH, - b.getHeight()+2*PEN_WIDTH); - } - updatingBoundsFromPath = false; - } - - //**************************************************************** - // Painting - //**************************************************************** - - protected void paint(PPaintContext paintContext) { - Paint p = getPaint(); - SWTGraphics2D g2 = (SWTGraphics2D)paintContext.getGraphics(); - - if (internalXForm != null) { - g2.transform(internalXForm); - } - - if (p != null) { - g2.setBackground((Color)p); + public static PSWTPath createRoundRectangle(float x, float y, float width, float height, float arcWidth, + float arcHeight) { + TEMP_ROUNDRECTANGLE.setRoundRect(x, y, width, height, arcWidth, arcHeight); + PSWTPath result = new PSWTPath(TEMP_ROUNDRECTANGLE); + result.setPaint(Color.white); + return result; + } - double lineWidth = g2.getTransformedLineWidth(); - if (shape instanceof Rectangle2D) { - g2.fillRect(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth); - } - else if (shape instanceof Ellipse2D) { - g2.fillOval(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth); - } - else if (shape instanceof Arc2D) { - g2.fillArc(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth,shapePts[4],shapePts[5]); - } - else if (shape instanceof RoundRectangle2D) { - g2.fillRoundRect(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth,shapePts[4],shapePts[5]); - } - else { - g2.fillPolygon(shapePts); - } - } - - if (strokePaint != null) { - g2.setColor((Color)strokePaint); - - double lineWidth = g2.getTransformedLineWidth(); - if (shape instanceof Rectangle2D) { - g2.drawRect(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth); - } - else if (shape instanceof Ellipse2D) { - g2.drawOval(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth); - } - else if (shape instanceof Arc2D) { - g2.drawArc(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth,shapePts[4],shapePts[5]); - } - else if (shape instanceof RoundRectangle2D) { - g2.drawRoundRect(shapePts[0]+lineWidth/2,shapePts[1]+lineWidth/2,shapePts[2]-lineWidth,shapePts[3]-lineWidth,shapePts[4],shapePts[5]); - } - else { - // TODO The bounds may be incorrect for polylines at the moment - resulting in graphics turds at some scales - g2.drawPolyline(shapePts); - } - } - - if (inverseXForm != null) { - g2.transform(inverseXForm); - } - } - - public void setShape(Shape aShape) { - this.shape = cloneShape(aShape); - this.origShape = shape; - updateShapePoints(aShape); - - firePropertyChange(PPath.PROPERTY_CODE_PATH, PPath.PROPERTY_PATH, null, shape); - updateBoundsFromPath(); - invalidatePaint(); - } + public static PSWTPath createEllipse(float x, float y, float width, float height) { + TEMP_ELLIPSE.setFrame(x, y, width, height); + PSWTPath result = new PSWTPath(TEMP_ELLIPSE); + result.setPaint(Color.white); + return result; + } - public void updateShapePoints(Shape aShape) { - if (aShape instanceof Rectangle2D) { - if (shapePts == null || shapePts.length < 4) { - shapePts = new double[4]; - } - - shapePts[0] = ((Rectangle2D)shape).getX(); - shapePts[1] = ((Rectangle2D)shape).getY(); - shapePts[2] = ((Rectangle2D)shape).getWidth(); - shapePts[3] = ((Rectangle2D)shape).getHeight(); - } - else if (aShape instanceof Ellipse2D) { - if (shapePts == null || shapePts.length < 4) { - shapePts = new double[4]; - } + public static PSWTPath createPolyline(Point2D[] points) { + PSWTPath result = new PSWTPath(); + result.setPathToPolyline(points); + result.setPaint(Color.white); + return result; + } - shapePts[0] = ((Ellipse2D)shape).getX(); - shapePts[1] = ((Ellipse2D)shape).getY(); - shapePts[2] = ((Ellipse2D)shape).getWidth(); - shapePts[3] = ((Ellipse2D)shape).getHeight(); - } - else if (aShape instanceof Arc2D) { - if (shapePts == null || shapePts.length < 6) { - shapePts = new double[6]; - } - - shapePts[0] = ((Arc2D)shape).getX(); - shapePts[1] = ((Arc2D)shape).getY(); - shapePts[2] = ((Arc2D)shape).getWidth(); - shapePts[3] = ((Arc2D)shape).getHeight(); - shapePts[4] = ((Arc2D)shape).getAngleStart(); - shapePts[5] = ((Arc2D)shape).getAngleExtent(); - } - else if (aShape instanceof RoundRectangle2D) { - if (shapePts == null || shapePts.length < 6) { - shapePts = new double[6]; - } + public static PSWTPath createPolyline(float[] xp, float[] yp) { + PSWTPath result = new PSWTPath(); + result.setPathToPolyline(xp, yp); + result.setPaint(Color.white); + return result; + } - shapePts[0] = ((RoundRectangle2D)shape).getX(); - shapePts[1] = ((RoundRectangle2D)shape).getY(); - shapePts[2] = ((RoundRectangle2D)shape).getWidth(); - shapePts[3] = ((RoundRectangle2D)shape).getHeight(); - shapePts[4] = ((RoundRectangle2D)shape).getArcWidth(); - shapePts[5] = ((RoundRectangle2D)shape).getArcHeight(); - } - else { - shapePts = SWTShapeManager.shapeToPolyline(shape); - } - } + public PSWTPath() { + strokePaint = DEFAULT_STROKE_PAINT; + } - public Shape cloneShape(Shape aShape) { - if (aShape instanceof Rectangle2D) { - return new PBounds((Rectangle2D)aShape); - } - else if (aShape instanceof Ellipse2D) { - Ellipse2D e2 = (Ellipse2D)aShape; - return new Ellipse2D.Double(e2.getX(),e2.getY(),e2.getWidth(),e2.getHeight()); - } - else if (aShape instanceof Arc2D) { - Arc2D a2 = (Arc2D)aShape; - return new Arc2D.Double(a2.getX(),a2.getY(),a2.getWidth(),a2.getHeight(),a2.getAngleStart(),a2.getAngleExtent(),a2.getArcType()); - } - else if (aShape instanceof RoundRectangle2D) { - RoundRectangle2D r2 = (RoundRectangle2D)aShape; - return new RoundRectangle2D.Double(r2.getX(),r2.getY(),r2.getWidth(),r2.getHeight(),r2.getArcWidth(),r2.getArcHeight()); - } - else if (aShape instanceof Line2D) { - Line2D l2 = (Line2D)aShape; - return new Line2D.Double(l2.getP1(),l2.getP2()); - } - else { - new Exception().printStackTrace(); - GeneralPath aPath = new GeneralPath(); - aPath.append(aShape,false); - return aPath; - } - } - - public void setPathToRectangle(float x, float y, float width, float height) { - TEMP_RECTANGLE.setFrame(x, y, width, height); - setShape(TEMP_RECTANGLE); - } - - public void setPathToRoundRectangle(float x, float y, float width, float height, float arcWidth, float arcHeight){ - TEMP_ROUNDRECTANGLE.setRoundRect(x, y, width, height, arcWidth, arcHeight); - setShape(TEMP_ROUNDRECTANGLE); - } + public PSWTPath(Shape aShape) { + this(); + setShape(aShape); + } - public void setPathToEllipse(float x, float y, float width, float height) { - TEMP_ELLIPSE.setFrame(x, y, width, height); - setShape(TEMP_ELLIPSE); - } + // **************************************************************** + // Stroke + // **************************************************************** - public void setPathToPolyline(Point2D[] points) { - GeneralPath path = new GeneralPath(); - path.reset(); - path.moveTo((float)points[0].getX(), (float)points[0].getY()); - for (int i = 1; i < points.length; i++) { - path.lineTo((float)points[i].getX(), (float)points[i].getY()); - } - setShape(path); - } + public Paint getStrokePaint() { + return strokePaint; + } - public void setPathToPolyline(float[] xp, float[] yp) { - GeneralPath path = new GeneralPath(); - path.reset(); - path.moveTo(xp[0], yp[0]); - for (int i = 1; i < xp.length; i++) { - path.lineTo(xp[i], yp[i]); - } - setShape(path); - } - - //**************************************************************** - // Debugging - methods for debugging - //**************************************************************** - - /** - * Returns a string representing the state of this node. This method is - * intended to be used only for debugging purposes, and the content and - * format of the returned string may vary between implementations. The - * returned string may be empty but may not be null. - * - * @return a string representation of this node's state - */ - protected String paramString() { - StringBuffer result = new StringBuffer(); + public void setStrokeColor(Paint aPaint) { + Paint old = strokePaint; + strokePaint = aPaint; + invalidatePaint(); + firePropertyChange(PPath.PROPERTY_CODE_STROKE_PAINT, PPath.PROPERTY_STROKE_PAINT, old, strokePaint); + } - result.append("path=" + (shape == null ? "null" : shape.toString())); - result.append(",strokePaint=" + (strokePaint == null ? "null" : strokePaint.toString())); - result.append(','); - result.append(super.paramString()); + /** + * Set the bounds of this path. This method works by scaling the path to fit + * into the specified bounds. This normally works well, but if the specified + * base bounds get too small then it is impossible to expand the path shape + * again since all its numbers have tended to zero, so application code may + * need to take this into consideration. + */ + protected void internalUpdateBounds(double x, double y, double width, double height) { + if (updatingBoundsFromPath) + return; + if (origShape == null) + return; - return result.toString(); - } + Rectangle2D pathBounds = origShape.getBounds2D(); + + if (Math.abs(x - pathBounds.getX()) / x < BOUNDS_TOLERANCE + && Math.abs(y - pathBounds.getY()) / y < BOUNDS_TOLERANCE + && Math.abs(width - pathBounds.getWidth()) / width < BOUNDS_TOLERANCE + && Math.abs(height - pathBounds.getHeight()) / height < BOUNDS_TOLERANCE) { + return; + } + + if (internalXForm == null) { + internalXForm = new PAffineTransform(); + } + internalXForm.setToIdentity(); + internalXForm.translate(x, y); + internalXForm.scale(width / pathBounds.getWidth(), height / pathBounds.getHeight()); + internalXForm.translate(-pathBounds.getX(), -pathBounds.getY()); + + try { + inverseXForm = internalXForm.createInverse(); + } + catch (Exception e) { + } + } + + public boolean intersects(Rectangle2D aBounds) { + if (super.intersects(aBounds)) { + + if (internalXForm != null) { + aBounds = new PBounds(aBounds); + internalXForm.inverseTransform(aBounds, aBounds); + } + + if (getPaint() != null && shape.intersects(aBounds)) { + return true; + } + else if (strokePaint != null) { + return BASIC_STROKE.createStrokedShape(shape).intersects(aBounds); + } + } + return false; + } + + public void updateBoundsFromPath() { + updatingBoundsFromPath = true; + + if (origShape == null) { + resetBounds(); + } + else { + Rectangle2D b = origShape.getBounds2D(); + + // Note that this pen width code does not really work for SWT since + // it assumes + // that the pen width scales - in actuality it does not. However, + // the fix would + // be to have volatile bounds for all shapes which isn't a nice + // alternative + super.setBounds(b.getX() - PEN_WIDTH, b.getY() - PEN_WIDTH, b.getWidth() + 2 * PEN_WIDTH, b.getHeight() + 2 + * PEN_WIDTH); + } + updatingBoundsFromPath = false; + } + + // **************************************************************** + // Painting + // **************************************************************** + + protected void paint(PPaintContext paintContext) { + Paint p = getPaint(); + SWTGraphics2D g2 = (SWTGraphics2D) paintContext.getGraphics(); + + if (internalXForm != null) { + g2.transform(internalXForm); + } + + if (p != null) { + g2.setBackground((Color) p); + + double lineWidth = g2.getTransformedLineWidth(); + if (shape instanceof Rectangle2D) { + g2.fillRect(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth); + } + else if (shape instanceof Ellipse2D) { + g2.fillOval(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth); + } + else if (shape instanceof Arc2D) { + g2.fillArc(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth, shapePts[4], shapePts[5]); + } + else if (shape instanceof RoundRectangle2D) { + g2.fillRoundRect(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth, shapePts[4], shapePts[5]); + } + else { + g2.fillPolygon(shapePts); + } + } + + if (strokePaint != null) { + g2.setColor((Color) strokePaint); + + double lineWidth = g2.getTransformedLineWidth(); + if (shape instanceof Rectangle2D) { + g2.drawRect(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth); + } + else if (shape instanceof Ellipse2D) { + g2.drawOval(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth); + } + else if (shape instanceof Arc2D) { + g2.drawArc(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth, shapePts[4], shapePts[5]); + } + else if (shape instanceof RoundRectangle2D) { + g2.drawRoundRect(shapePts[0] + lineWidth / 2, shapePts[1] + lineWidth / 2, shapePts[2] - lineWidth, + shapePts[3] - lineWidth, shapePts[4], shapePts[5]); + } + else { + // TODO The bounds may be incorrect for polylines at the moment + // - resulting in graphics turds at some scales + g2.drawPolyline(shapePts); + } + } + + if (inverseXForm != null) { + g2.transform(inverseXForm); + } + } + + public void setShape(Shape aShape) { + this.shape = cloneShape(aShape); + this.origShape = shape; + updateShapePoints(aShape); + + firePropertyChange(PPath.PROPERTY_CODE_PATH, PPath.PROPERTY_PATH, null, shape); + updateBoundsFromPath(); + invalidatePaint(); + } + + public void updateShapePoints(Shape aShape) { + if (aShape instanceof Rectangle2D) { + if (shapePts == null || shapePts.length < 4) { + shapePts = new double[4]; + } + + shapePts[0] = ((Rectangle2D) shape).getX(); + shapePts[1] = ((Rectangle2D) shape).getY(); + shapePts[2] = ((Rectangle2D) shape).getWidth(); + shapePts[3] = ((Rectangle2D) shape).getHeight(); + } + else if (aShape instanceof Ellipse2D) { + if (shapePts == null || shapePts.length < 4) { + shapePts = new double[4]; + } + + shapePts[0] = ((Ellipse2D) shape).getX(); + shapePts[1] = ((Ellipse2D) shape).getY(); + shapePts[2] = ((Ellipse2D) shape).getWidth(); + shapePts[3] = ((Ellipse2D) shape).getHeight(); + } + else if (aShape instanceof Arc2D) { + if (shapePts == null || shapePts.length < 6) { + shapePts = new double[6]; + } + + shapePts[0] = ((Arc2D) shape).getX(); + shapePts[1] = ((Arc2D) shape).getY(); + shapePts[2] = ((Arc2D) shape).getWidth(); + shapePts[3] = ((Arc2D) shape).getHeight(); + shapePts[4] = ((Arc2D) shape).getAngleStart(); + shapePts[5] = ((Arc2D) shape).getAngleExtent(); + } + else if (aShape instanceof RoundRectangle2D) { + if (shapePts == null || shapePts.length < 6) { + shapePts = new double[6]; + } + + shapePts[0] = ((RoundRectangle2D) shape).getX(); + shapePts[1] = ((RoundRectangle2D) shape).getY(); + shapePts[2] = ((RoundRectangle2D) shape).getWidth(); + shapePts[3] = ((RoundRectangle2D) shape).getHeight(); + shapePts[4] = ((RoundRectangle2D) shape).getArcWidth(); + shapePts[5] = ((RoundRectangle2D) shape).getArcHeight(); + } + else { + shapePts = SWTShapeManager.shapeToPolyline(shape); + } + } + + public Shape cloneShape(Shape aShape) { + if (aShape instanceof Rectangle2D) { + return new PBounds((Rectangle2D) aShape); + } + else if (aShape instanceof Ellipse2D) { + Ellipse2D e2 = (Ellipse2D) aShape; + return new Ellipse2D.Double(e2.getX(), e2.getY(), e2.getWidth(), e2.getHeight()); + } + else if (aShape instanceof Arc2D) { + Arc2D a2 = (Arc2D) aShape; + return new Arc2D.Double(a2.getX(), a2.getY(), a2.getWidth(), a2.getHeight(), a2.getAngleStart(), a2 + .getAngleExtent(), a2.getArcType()); + } + else if (aShape instanceof RoundRectangle2D) { + RoundRectangle2D r2 = (RoundRectangle2D) aShape; + return new RoundRectangle2D.Double(r2.getX(), r2.getY(), r2.getWidth(), r2.getHeight(), r2.getArcWidth(), + r2.getArcHeight()); + } + else if (aShape instanceof Line2D) { + Line2D l2 = (Line2D) aShape; + return new Line2D.Double(l2.getP1(), l2.getP2()); + } + else { + new Exception().printStackTrace(); + GeneralPath aPath = new GeneralPath(); + aPath.append(aShape, false); + return aPath; + } + } + + public void setPathToRectangle(float x, float y, float width, float height) { + TEMP_RECTANGLE.setFrame(x, y, width, height); + setShape(TEMP_RECTANGLE); + } + + public void setPathToRoundRectangle(float x, float y, float width, float height, float arcWidth, float arcHeight) { + TEMP_ROUNDRECTANGLE.setRoundRect(x, y, width, height, arcWidth, arcHeight); + setShape(TEMP_ROUNDRECTANGLE); + } + + public void setPathToEllipse(float x, float y, float width, float height) { + TEMP_ELLIPSE.setFrame(x, y, width, height); + setShape(TEMP_ELLIPSE); + } + + public void setPathToPolyline(Point2D[] points) { + GeneralPath path = new GeneralPath(); + path.reset(); + path.moveTo((float) points[0].getX(), (float) points[0].getY()); + for (int i = 1; i < points.length; i++) { + path.lineTo((float) points[i].getX(), (float) points[i].getY()); + } + setShape(path); + } + + public void setPathToPolyline(float[] xp, float[] yp) { + GeneralPath path = new GeneralPath(); + path.reset(); + path.moveTo(xp[0], yp[0]); + for (int i = 1; i < xp.length; i++) { + path.lineTo(xp[i], yp[i]); + } + setShape(path); + } + + // **************************************************************** + // Debugging - methods for debugging + // **************************************************************** + + /** + * Returns a string representing the state of this node. This method is + * intended to be used only for debugging purposes, and the content and + * format of the returned string may vary between implementations. The + * returned string may be empty but may not be null. + * + * @return a string representation of this node's state + */ + protected String paramString() { + StringBuffer result = new StringBuffer(); + + result.append("path=" + (shape == null ? "null" : shape.toString())); + result.append(",strokePaint=" + (strokePaint == null ? "null" : strokePaint.toString())); + result.append(','); + result.append(super.paramString()); + + return result.toString(); + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java index cb5e279..d4899cd 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java @@ -21,36 +21,37 @@ * thread. With the current setup only a single PSWTCanvas is expected to be * connected to a root. *

+ * * @version 1.1 * @author Jesse Grosjean */ public class PSWTRoot extends PRoot { - private Composite composite; - - public PSWTRoot(Composite composite) { - this.composite = composite; - } + private Composite composite; - public Timer createTimer(int delay, ActionListener listener) { - return new SWTTimer(composite.getDisplay(),delay,listener); - } + public PSWTRoot(Composite composite) { + this.composite = composite; + } - public void scheduleProcessInputsIfNeeded() { - if (!Thread.currentThread().equals(composite.getDisplay().getThread())) { - return; - } + public Timer createTimer(int delay, ActionListener listener) { + return new SWTTimer(composite.getDisplay(), delay, listener); + } - if (!processInputsScheduled && !processingInputs && - (getFullBoundsInvalid() || getChildBoundsInvalid() || getPaintInvalid() || getChildPaintInvalid())) { + public void scheduleProcessInputsIfNeeded() { + if (!Thread.currentThread().equals(composite.getDisplay().getThread())) { + return; + } - processInputsScheduled = true; - composite.getDisplay().asyncExec(new Runnable() { - public void run() { - processInputs(); - processInputsScheduled = false; - } - }); - } - } + if (!processInputsScheduled && !processingInputs + && (getFullBoundsInvalid() || getChildBoundsInvalid() || getPaintInvalid() || getChildPaintInvalid())) { + + processInputsScheduled = true; + composite.getDisplay().asyncExec(new Runnable() { + public void run() { + processInputs(); + processInputsScheduled = false; + } + }); + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java index ccfbb95..7d6d269 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java @@ -44,109 +44,113 @@ import edu.umd.cs.piccolox.event.PSelectionEventHandler; /** - * Modified to use SWT paths instead of normal paths + * Modified to use SWT paths instead of normal paths + * * @version 1.0 * @author Lance Good - */ + */ public class PSWTSelectionEventHandler extends PSelectionEventHandler { PSWTPath marquee; PNode marqueeParent; Point2D pressPt; Point2D canvasPressPt; - + /** - * Creates a selection event handler. - * @param marqueeParent The node to which the event handler dynamically adds a marquee - * (temporarily) to represent the area being selected. - * @param selectableParent The node whose children will be selected - * by this event handler. - */ - public PSWTSelectionEventHandler(PNode marqueeParent, PNode selectableParent) { - super(new PNode(),selectableParent); - this.marqueeParent = marqueeParent; - } + * Creates a selection event handler. + * + * @param marqueeParent The node to which the event handler dynamically adds + * a marquee (temporarily) to represent the area being selected. + * @param selectableParent The node whose children will be selected by this + * event handler. + */ + public PSWTSelectionEventHandler(PNode marqueeParent, PNode selectableParent) { + super(new PNode(), selectableParent); + this.marqueeParent = marqueeParent; + } - /** - * Creates a selection event handler. - * @param marqueeParent The node to which the event handler dynamically adds a marquee - * (temporarily) to represent the area being selected. - * @param selectableParents A list of nodes whose children will be selected - * by this event handler. - */ - public PSWTSelectionEventHandler(PNode marqueeParent, List selectableParents) { - super(new PNode(),selectableParents); - this.marqueeParent = marqueeParent; - } + /** + * Creates a selection event handler. + * + * @param marqueeParent The node to which the event handler dynamically adds + * a marquee (temporarily) to represent the area being selected. + * @param selectableParents A list of nodes whose children will be selected + * by this event handler. + */ + public PSWTSelectionEventHandler(PNode marqueeParent, List selectableParents) { + super(new PNode(), selectableParents); + this.marqueeParent = marqueeParent; + } - public void decorateSelectedNode(PNode node) { - PSWTBoundsHandle.addBoundsHandlesTo(node); - } + public void decorateSelectedNode(PNode node) { + PSWTBoundsHandle.addBoundsHandlesTo(node); + } - public void undecorateSelectedNode(PNode node) { - PSWTBoundsHandle.removeBoundsHandlesFrom(node); - } + public void undecorateSelectedNode(PNode node) { + PSWTBoundsHandle.removeBoundsHandlesFrom(node); + } - protected void initializeSelection(PInputEvent pie) { - super.initializeSelection(pie); - pressPt = pie.getPosition(); - canvasPressPt = pie.getCanvasPosition(); - } - - protected void initializeMarquee(PInputEvent e) { - super.initializeMarquee(e); - - marquee = new PSWTPath(new Rectangle2D.Float((float)pressPt.getX(), (float)pressPt.getY(), 0, 0)) { + protected void initializeSelection(PInputEvent pie) { + super.initializeSelection(pie); + pressPt = pie.getPosition(); + canvasPressPt = pie.getCanvasPosition(); + } + + protected void initializeMarquee(PInputEvent e) { + super.initializeMarquee(e); + + marquee = new PSWTPath(new Rectangle2D.Float((float) pressPt.getX(), (float) pressPt.getY(), 0, 0)) { protected void paint(PPaintContext paintContext) { - SWTGraphics2D s2g = (SWTGraphics2D)paintContext.getGraphics(); + SWTGraphics2D s2g = (SWTGraphics2D) paintContext.getGraphics(); s2g.gc.setLineStyle(SWT.LINE_DASH); super.paint(paintContext); s2g.gc.setLineStyle(SWT.LINE_SOLID); } - }; - marquee.setStrokeColor(Color.black); - marquee.setPaint(null); - marqueeParent.addChild(marquee); - } + }; + marquee.setStrokeColor(Color.black); + marquee.setPaint(null); + marqueeParent.addChild(marquee); + } - protected void updateMarquee(PInputEvent pie) { - super.updateMarquee(pie); - - PBounds b = new PBounds(); + protected void updateMarquee(PInputEvent pie) { + super.updateMarquee(pie); - if (marqueeParent instanceof PCamera) { - b.add(canvasPressPt); - b.add(pie.getCanvasPosition()); - } - else { - b.add(pressPt); - b.add(pie.getPosition()); - } + PBounds b = new PBounds(); - marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); - b.reset(); - b.add(pressPt); - b.add(pie.getPosition()); - } + if (marqueeParent instanceof PCamera) { + b.add(canvasPressPt); + b.add(pie.getCanvasPosition()); + } + else { + b.add(pressPt); + b.add(pie.getPosition()); + } - protected PBounds getMarqueeBounds() { - if (marquee != null) { - return marquee.getBounds(); - } - return new PBounds(); - } + marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); + b.reset(); + b.add(pressPt); + b.add(pie.getPosition()); + } - protected void endMarqueeSelection(PInputEvent e) { - super.endMarqueeSelection(e); - - // Remove marquee - marquee.removeFromParent(); - marquee = null; - } + protected PBounds getMarqueeBounds() { + if (marquee != null) { + return marquee.getBounds(); + } + return new PBounds(); + } - /** - * This gets called continuously during the drag, and is used to animate the marquee - */ - protected void dragActivityStep(PInputEvent aEvent) { - } + protected void endMarqueeSelection(PInputEvent e) { + super.endMarqueeSelection(e); + + // Remove marquee + marquee.removeFromParent(); + marquee = null; + } + + /** + * This gets called continuously during the drag, and is used to animate the + * marquee + */ + protected void dragActivityStep(PInputEvent aEvent) { + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java index 3740fbd..8c04056 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java @@ -35,54 +35,54 @@ import edu.umd.cs.piccolo.util.PPickPath; public class PSWTStickyHandleManager extends PNode { - - private PNode target; - private PCamera camera; - - public PSWTStickyHandleManager(PCamera newCamera, PNode newTarget) { - setCameraTarget(newCamera, newTarget); - PSWTBoundsHandle.addBoundsHandlesTo(this); - } - public void setCameraTarget(PCamera newCamera, PNode newTarget) { - camera = newCamera; - camera.addChild(this); - target = newTarget; - } - - public boolean setBounds(double x, double y, double width, double height) { - PBounds b = new PBounds(x, y, width, height); - camera.localToGlobal(b); - camera.localToView(b); - target.globalToLocal(b); - target.setBounds(b); - return super.setBounds(x, y, width, height); - } - - protected boolean getBoundsVolatile() { - return true; - } + private PNode target; + private PCamera camera; - public PBounds getBoundsReference() { - PBounds targetBounds = target.getFullBounds(); - camera.viewToLocal(targetBounds); - camera.globalToLocal(targetBounds); - PBounds bounds = super.getBoundsReference(); - bounds.setRect(targetBounds); - return super.getBoundsReference(); - } + public PSWTStickyHandleManager(PCamera newCamera, PNode newTarget) { + setCameraTarget(newCamera, newTarget); + PSWTBoundsHandle.addBoundsHandlesTo(this); + } - public void startResizeBounds() { - super.startResizeBounds(); - target.startResizeBounds(); - } + public void setCameraTarget(PCamera newCamera, PNode newTarget) { + camera = newCamera; + camera.addChild(this); + target = newTarget; + } - public void endResizeBounds() { - super.endResizeBounds(); - target.endResizeBounds(); - } + public boolean setBounds(double x, double y, double width, double height) { + PBounds b = new PBounds(x, y, width, height); + camera.localToGlobal(b); + camera.localToView(b); + target.globalToLocal(b); + target.setBounds(b); + return super.setBounds(x, y, width, height); + } - public boolean pickAfterChildren(PPickPath pickPath) { - return false; - } + protected boolean getBoundsVolatile() { + return true; + } + + public PBounds getBoundsReference() { + PBounds targetBounds = target.getFullBounds(); + camera.viewToLocal(targetBounds); + camera.globalToLocal(targetBounds); + PBounds bounds = super.getBoundsReference(); + bounds.setRect(targetBounds); + return super.getBoundsReference(); + } + + public void startResizeBounds() { + super.startResizeBounds(); + target.startResizeBounds(); + } + + public void endResizeBounds() { + super.endResizeBounds(); + target.endResizeBounds(); + } + + public boolean pickAfterChildren(PPickPath pickPath) { + return false; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java index 81eee7a..6e1c0d2 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java @@ -20,11 +20,11 @@ import edu.umd.cs.piccolo.util.PPaintContext; /** - * PSWTText creates a visual component to support text. Multiple lines can - * be entered, and basic editing is supported. A caret is drawn, - * and can be repositioned with mouse clicks. The text object is positioned - * so that its upper-left corner is at the origin, though this can be changed - * with the translate methods. + * PSWTText creates a visual component to support text. Multiple lines + * can be entered, and basic editing is supported. A caret is drawn, and can be + * repositioned with mouse clicks. The text object is positioned so that its + * upper-left corner is at the origin, though this can be changed with the + * translate methods. *

* Warning: Serialized and ZSerialized objects of this class will not be * compatible with future Jazz releases. The current serialization support is @@ -37,80 +37,78 @@ /** * Below this magnification render text as 'greek'. */ - static protected final double DEFAULT_GREEK_THRESHOLD = 5.5; + static protected final double DEFAULT_GREEK_THRESHOLD = 5.5; /** * Default color of text rendered as 'greek'. */ - static protected final Color DEFAULT_GREEK_COLOR = Color.gray; + static protected final Color DEFAULT_GREEK_COLOR = Color.gray; /** * Default font name of text. */ - static protected final String DEFAULT_FONT_NAME = "Helvetica"; + static protected final String DEFAULT_FONT_NAME = "Helvetica"; /** * Default font style for text. */ - static protected final int DEFAULT_FONT_STYLE = Font.PLAIN; + static protected final int DEFAULT_FONT_STYLE = Font.PLAIN; /** * Default font size for text. */ - static protected final int DEFAULT_FONT_SIZE = 12; + static protected final int DEFAULT_FONT_SIZE = 12; /** * Default font for text. */ - static protected final Font DEFAULT_FONT = new Font(DEFAULT_FONT_NAME, DEFAULT_FONT_STYLE, DEFAULT_FONT_SIZE); + static protected final Font DEFAULT_FONT = new Font(DEFAULT_FONT_NAME, DEFAULT_FONT_STYLE, DEFAULT_FONT_SIZE); /** * Default color for text. */ - static protected final Color DEFAULT_PEN_COLOR = Color.black; + static protected final Color DEFAULT_PEN_COLOR = Color.black; /** * Default text when new text area is created. */ - static protected final String DEFAULT_TEXT = ""; + static protected final String DEFAULT_TEXT = ""; /** * Default padding */ - static protected final int DEFAULT_PADDING = 2; - + static protected final int DEFAULT_PADDING = 2; + /** * Below this magnification text is rendered as greek. */ - protected double greekThreshold = DEFAULT_GREEK_THRESHOLD; + protected double greekThreshold = DEFAULT_GREEK_THRESHOLD; /** * Color for greek text. */ - protected Color greekColor = DEFAULT_GREEK_COLOR; + protected Color greekColor = DEFAULT_GREEK_COLOR; /** * Current pen color. */ - protected Color penColor = DEFAULT_PEN_COLOR; + protected Color penColor = DEFAULT_PEN_COLOR; /** * Current text font. */ - protected Font font = DEFAULT_FONT; + protected Font font = DEFAULT_FONT; /** * The amount of padding on each side of the text */ - protected int padding = DEFAULT_PADDING; + protected int padding = DEFAULT_PADDING; - /** * Each vector element is one line of text. */ - protected ArrayList lines = new ArrayList(); + protected ArrayList lines = new ArrayList(); - /** * Translation offset X. */ @@ -130,6 +128,7 @@ /** * PSWTTest constructor with initial text. + * * @param str The initial text. */ public PSWTText(String str) { @@ -138,6 +137,7 @@ /** * PSWTTest constructor with initial text and font. + * * @param str The initial text. * @param font The font for this PSWTText component. */ @@ -148,19 +148,24 @@ recomputeBounds(); } - //**************************************************************************** + //************************************************************************** + // ** // - // Get/Set and pairs + // Get/Set and pairs // - //*************************************************************************** + //************************************************************************** + // * /** * Returns the current pen color. */ - public Color getPenColor() {return penColor;} + public Color getPenColor() { + return penColor; + } /** * Sets the current pen color. + * * @param color use this color. */ public void setPenColor(Color color) { @@ -177,36 +182,41 @@ /** * Sets the current pen paint. + * * @param aPaint use this paint. */ public void setPenPaint(Paint aPaint) { - penColor = (Color)aPaint; + penColor = (Color) aPaint; } /** * Returns the current background color. */ public Color getBackgroundColor() { - return (Color)getPaint(); + return (Color) getPaint(); } /** * Sets the current background color. + * * @param color use this color. */ public void setBackgroundColor(Color color) { - super.setPaint(color); + super.setPaint(color); } /** - * Returns the current greek threshold. Below this magnification - * text is rendered as 'greek'. + * Returns the current greek threshold. Below this magnification text is + * rendered as 'greek'. */ - public double getGreekThreshold() {return greekThreshold;} + public double getGreekThreshold() { + return greekThreshold; + } /** - * Sets the current greek threshold. Below this magnification - * text is rendered as 'greek'. + * Sets the current greek threshold. Below this magnification text is + * rendered as 'greek'. + * * @param threshold compared to renderContext magnification. */ public void setGreekThreshold(double threshold) { @@ -217,12 +227,13 @@ /** * Returns the current font. */ - public Font getFont() {return font;} + public Font getFont() { + return font; + } /** - * Return the text within this text component. - * Multline text is returned as a single string - * where each line is separated by a newline character. + * Return the text within this text component. Multline text is returned as + * a single string where each line is separated by a newline character. * Single line text does not have any newline characters. */ public String getText() { @@ -230,11 +241,11 @@ String result = new String(); int lineNum = 0; - for (Iterator i = lines.iterator() ; i.hasNext() ; ) { + for (Iterator i = lines.iterator(); i.hasNext();) { if (lineNum > 0) { result += '\n'; } - line = (String)i.next(); + line = (String) i.next(); result += line; lineNum++; } @@ -245,23 +256,26 @@ /** * Sets the font for the text. *

- * Warning: Java has a serious bug in that it does not support very small - * fonts. In particular, fonts that are less than about a pixel high just don't work. - * Since in Jazz, it is common to create objects of arbitrary sizes, and then scale them, - * an application can easily create a text object with a very small font by accident. - * The workaround for this bug is to create a larger font for the text object, and - * then scale the node down correspondingly. + * Warning: Java has a serious bug in that it does not support very + * small fonts. In particular, fonts that are less than about a pixel high + * just don't work. Since in Jazz, it is common to create objects of + * arbitrary sizes, and then scale them, an application can easily create a + * text object with a very small font by accident. The workaround for this + * bug is to create a larger font for the text object, and then scale the + * node down correspondingly. + * * @param aFont use this font. */ public void setFont(Font aFont) { font = aFont; - recomputeBounds(); + recomputeBounds(); } /** - * Sets the text of this visual component to str. Multiple lines - * of text are separated by a newline character. + * Sets the text of this visual component to str. Multiple lines of text are + * separated by a newline character. + * * @param str use this string. */ public void setText(String str) { @@ -274,17 +288,19 @@ if (index == -1) { lines.add(str); done = true; - } else { + } + else { lines.add(str.substring(0, index)); str = str.substring(index + 1); } } while (!done); - recomputeBounds(); + recomputeBounds(); } /** * Set text translation offset X. + * * @param x the X translation. */ public void setTranslateX(double x) { @@ -293,6 +309,7 @@ /** * Get the X offset translation. + * * @return the X translation. */ public double getTranslateX() { @@ -301,6 +318,7 @@ /** * Set text translation offset Y. + * * @param y the Y translation. */ public void setTranslateY(double y) { @@ -309,6 +327,7 @@ /** * Get the Y offset translation. + * * @return the Y translation. */ public double getTranslateY() { @@ -317,6 +336,7 @@ /** * Set the text translation offset to the specified position. + * * @param x the X-coord of translation * @param y the Y-coord of translation */ @@ -324,11 +344,12 @@ translateX = x; translateY = y; - recomputeBounds(); + recomputeBounds(); } /** * Set the text translation offset to point p. + * * @param p The translation offset. */ public void setTranslation(Point2D p) { @@ -337,6 +358,7 @@ /** * Get the text translation offset. + * * @return The translation offset. */ public Point2D getTranslation() { @@ -347,12 +369,13 @@ /** * Renders the text object. *

- * The transform, clip, and composite will be set appropriately when this object - * is rendered. It is up to this object to restore the transform, clip, and composite of - * the Graphics2D if this node changes any of them. However, the color, font, and stroke are - * unspecified by Jazz. This object should set those things if they are used, but - * they do not need to be restored. - * + * The transform, clip, and composite will be set appropriately when this + * object is rendered. It is up to this object to restore the transform, + * clip, and composite of the Graphics2D if this node changes any of them. + * However, the color, font, and stroke are unspecified by Jazz. This object + * should set those things if they are used, but they do not need to be + * restored. + * * @param ppc Contains information about current render. */ public void paint(PPaintContext ppc) { @@ -367,17 +390,17 @@ translated = true; } - // If font too small and not antialiased, then greek + // If font too small and not antialiased, then greek double renderedFontSize = font.getSize() * ppc.getScale(); - // BBB: HACK ALERT - July 30, 1999 - // This is a workaround for a bug in Sun JDK 1.2.2 where - // fonts that are rendered at very small magnifications show up big! - // So, we render as greek if requested (that's normal) - // OR if the font is very small (that's the workaround) - if ((renderedFontSize < 0.5) || - (renderedFontSize < greekThreshold)) { + // BBB: HACK ALERT - July 30, 1999 + // This is a workaround for a bug in Sun JDK 1.2.2 where + // fonts that are rendered at very small magnifications show up big! + // So, we render as greek if requested (that's normal) + // OR if the font is very small (that's the workaround) + if ((renderedFontSize < 0.5) || (renderedFontSize < greekThreshold)) { paintAsGreek(ppc); - } else { + } + else { paintAsText(ppc); } if (translated) { @@ -388,47 +411,50 @@ /** * Paints this object as greek. + * * @param ppc The graphics context to paint into. */ public void paintAsGreek(PPaintContext ppc) { - Graphics2D g2 = ppc.getGraphics(); + Graphics2D g2 = ppc.getGraphics(); - if (greekColor != null) { - g2.setBackground(greekColor); - ((SWTGraphics2D)g2).fillRect(0,0,getWidth(),getHeight()); - } + if (greekColor != null) { + g2.setBackground(greekColor); + ((SWTGraphics2D) g2).fillRect(0, 0, getWidth(), getHeight()); + } } /** - * Paints this object normally (show it's text). - * Note that the entire text gets rendered so that it's upper - * left corner appears at the origin of this local object. + * Paints this object normally (show it's text). Note that the entire text + * gets rendered so that it's upper left corner appears at the origin of + * this local object. + * * @param ppc The graphics context to paint into. */ public void paintAsText(PPaintContext ppc) { - SWTGraphics2D sg2 = (SWTGraphics2D)ppc.getGraphics(); - - if (getPaint() != null) { - sg2.setBackground((Color)getPaint()); + SWTGraphics2D sg2 = (SWTGraphics2D) ppc.getGraphics(); + + if (getPaint() != null) { + sg2.setBackground((Color) getPaint()); Rectangle2D rect = new Rectangle2D.Double(0.0, 0.0, getWidth(), getHeight()); - sg2.fillRect(rect.getX(),rect.getY(),rect.getWidth(),rect.getHeight()); + sg2.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } + sg2.translate(padding, padding); - sg2.translate(padding,padding); + double scale = Math.min(sg2.getTransform().getScaleX(), sg2.getTransform().getScaleY()); + double dSize = scale * font.getSize(); + double fixupScale = Math.floor(dSize) / dSize; - double scale = Math.min(sg2.getTransform().getScaleX(),sg2.getTransform().getScaleY()); - double dSize = scale*font.getSize(); - double fixupScale = Math.floor(dSize)/dSize; - - // This moves the text size down to the next closest integer size - to help it stay in - // it's alloted bounds. This is because SWT only supports integer font metrics - sg2.scale(fixupScale,fixupScale); - - - // Render each line of text - // Note that the entire text gets rendered so that it's upper left corner - // appears at the origin of this local object. + // This moves the text size down to the next closest integer size - to + // help it stay in + // it's alloted bounds. This is because SWT only supports integer font + // metrics + sg2.scale(fixupScale, fixupScale); + + // Render each line of text + // Note that the entire text gets rendered so that it's upper left + // corner + // appears at the origin of this local object. sg2.setColor(penColor); sg2.setFont(font); @@ -436,88 +462,89 @@ String line; double y; - FontMetrics metrics = sg2.getSWTFontMetrics(); + FontMetrics metrics = sg2.getSWTFontMetrics(); - for (Iterator i = lines.iterator() ; i.hasNext() ; ) { - line = (String)i.next(); + for (Iterator i = lines.iterator(); i.hasNext();) { + line = (String) i.next(); - // ADDED BY LEG ON 2/25/03 - BUG CAUSING PROBLEMS AT CERTAIN - // SCALES WHEN LINE WAS EMPTY - line = (line.equals("")) ? " " : line; + // ADDED BY LEG ON 2/25/03 - BUG CAUSING PROBLEMS AT CERTAIN + // SCALES WHEN LINE WAS EMPTY + line = (line.equals("")) ? " " : line; y = (lineNum * metrics.getHeight()); - sg2.drawString(line, (double)0, (double)y); + sg2.drawString(line, (double) 0, (double) y); lineNum++; } - - sg2.scale(1/fixupScale,1/fixupScale); - - sg2.translate(-padding,-padding); + + sg2.scale(1 / fixupScale, 1 / fixupScale); + + sg2.translate(-padding, -padding); } /** - * Notifies this object that it has changed and that it - * should update its notion of its bounding box. + * Notifies this object that it has changed and that it should update its + * notion of its bounding box. */ protected void recomputeBounds() { - Point bds; + Point bds; double lineWidth; double maxWidth = 0.0; double height; - height = 0.0; + height = 0.0; boolean hasText = true; - if ((lines.size() == 1) && (((String)lines.get(0)).equals(""))) { + if ((lines.size() == 1) && (((String) lines.get(0)).equals(""))) { hasText = false; } - GC gc = new GC(Display.getDefault()); - SWTGraphics2D g2 = new SWTGraphics2D(gc,Display.getDefault()); - g2.setFont(font); - FontMetrics fm = g2.getSWTFontMetrics(); - + GC gc = new GC(Display.getDefault()); + SWTGraphics2D g2 = new SWTGraphics2D(gc, Display.getDefault()); + g2.setFont(font); + FontMetrics fm = g2.getSWTFontMetrics(); + if (!lines.isEmpty() && hasText) { String line; int lineNum = 0; - for (Iterator i = lines.iterator() ; i.hasNext() ; ) { - line = (String)i.next(); + for (Iterator i = lines.iterator(); i.hasNext();) { + line = (String) i.next(); - - // Find the longest line in the text - bds = gc.stringExtent(line); - lineWidth = bds.x; + // Find the longest line in the text + bds = gc.stringExtent(line); + lineWidth = bds.x; if (lineWidth > maxWidth) { maxWidth = lineWidth; } - // Find the heighest line in the text + // Find the heighest line in the text if (lineNum == 0) { - height += fm.getAscent()+fm.getDescent()+fm.getLeading(); - } else { + height += fm.getAscent() + fm.getDescent() + fm.getLeading(); + } + else { height += fm.getHeight(); } lineNum++; } - } else { - // If no text, then we want to have the bounds of a space character, - // so get those bounds here - bds = gc.stringExtent(" "); + } + else { + // If no text, then we want to have the bounds of a space character, + // so get those bounds here + bds = gc.stringExtent(" "); maxWidth = bds.x; height = bds.y; } - gc.dispose(); + gc.dispose(); - // Finally, set the bounds of this text - setBounds(translateX,translateY,maxWidth+2*DEFAULT_PADDING,height+2*DEFAULT_PADDING); + // Finally, set the bounds of this text + setBounds(translateX, translateY, maxWidth + 2 * DEFAULT_PADDING, height + 2 * DEFAULT_PADDING); } - protected void internalUpdateBounds(double x, double y, double width, double height) { - recomputeBounds(); - } - + protected void internalUpdateBounds(double x, double y, double width, double height) { + recomputeBounds(); + } + } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java index 821e236..0e7fef6 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java @@ -38,905 +38,924 @@ import org.eclipse.swt.graphics.GC; /** - * An extension to Graphics2D to support an SWT Piccolo Canvas with little modification to the current Piccolo architecture + * An extension to Graphics2D to support an SWT Piccolo Canvas with little + * modification to the current Piccolo architecture * - * There is an outstanding SWT bug request #33319 for more efficient polyline/polygon rendering methods. It also appears that - * most of the code below could be made obselete by bug fix #6490 + * There is an outstanding SWT bug request #33319 for more efficient + * polyline/polygon rendering methods. It also appears that most of the code + * below could be made obselete by bug fix #6490 * - * A lot of this may also be duplicated in GEF - the eclipse Graphical Editor Framework + * A lot of this may also be duplicated in GEF - the eclipse Graphical Editor + * Framework * * @author Lance Good */ public class SWTGraphics2D extends Graphics2D { - protected static int CACHE_COUNT = 0; - protected static HashMap FONT_CACHE = new HashMap(); - protected static HashMap COLOR_CACHE = new HashMap(); - protected static HashMap SHAPE_CACHE = new HashMap(); - protected static BufferedImage BUFFER = new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB); + protected static int CACHE_COUNT = 0; + protected static HashMap FONT_CACHE = new HashMap(); + protected static HashMap COLOR_CACHE = new HashMap(); + protected static HashMap SHAPE_CACHE = new HashMap(); + protected static BufferedImage BUFFER = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB); - static Point PT = new Point(); - static Rectangle2D RECT = new Rectangle2D.Double(); - static Rectangle2D LINE_RECT = new Rectangle2D.Double(); - static org.eclipse.swt.graphics.Rectangle SWT_RECT = new org.eclipse.swt.graphics.Rectangle(0,0,0,0); + static Point PT = new Point(); + static Rectangle2D RECT = new Rectangle2D.Double(); + static Rectangle2D LINE_RECT = new Rectangle2D.Double(); + static org.eclipse.swt.graphics.Rectangle SWT_RECT = new org.eclipse.swt.graphics.Rectangle(0, 0, 0, 0); - protected GC gc; - protected Device device; - protected AffineTransform transform = new AffineTransform(); - protected org.eclipse.swt.graphics.Font curFont; - protected double lineWidth = 1.0; + protected GC gc; + protected Device device; + protected AffineTransform transform = new AffineTransform(); + protected org.eclipse.swt.graphics.Font curFont; + protected double lineWidth = 1.0; - /** - * Constructor for SWTGraphics2D. - */ - public SWTGraphics2D(GC gc, Device device) { - super(); - - this.gc = gc; - this.device = device; - } + /** + * Constructor for SWTGraphics2D. + */ + public SWTGraphics2D(GC gc, Device device) { + super(); - //////////////////// - // GET CLIP - //////////////////// + this.gc = gc; + this.device = device; + } - /** - * @see java.awt.Graphics#getClipBounds() - */ - public Rectangle getClipBounds() { - org.eclipse.swt.graphics.Rectangle rect = gc.getClipping(); - Rectangle aRect = new Rectangle(rect.x,rect.y,rect.width,rect.height); - try { - SWTShapeManager.transform(aRect,transform.createInverse()); - } catch (Exception e) {e.printStackTrace();} - return aRect; - } + // ////////////////// + // GET CLIP + // ////////////////// - public void clipRect(int x, int y, int width, int height) { - RECT.setRect(x,y,width,height); - SWTShapeManager.transform(RECT,transform); - SWTShapeManager.awtToSWT(RECT,SWT_RECT); - - org.eclipse.swt.graphics.Rectangle clip = gc.getClipping(); - clip = clip.intersection(SWT_RECT); - - gc.setClipping(clip); - } + /** + * @see java.awt.Graphics#getClipBounds() + */ + public Rectangle getClipBounds() { + org.eclipse.swt.graphics.Rectangle rect = gc.getClipping(); + Rectangle aRect = new Rectangle(rect.x, rect.y, rect.width, rect.height); + try { + SWTShapeManager.transform(aRect, transform.createInverse()); + } + catch (Exception e) { + e.printStackTrace(); + } + return aRect; + } - public void setClip(int x, int y, int width, int height) { - RECT.setRect(x,y,width,height); - SWTShapeManager.transform(RECT,transform); - SWTShapeManager.awtToSWT(RECT,SWT_RECT); - - gc.setClipping(SWT_RECT); - } + public void clipRect(int x, int y, int width, int height) { + RECT.setRect(x, y, width, height); + SWTShapeManager.transform(RECT, transform); + SWTShapeManager.awtToSWT(RECT, SWT_RECT); - /** - * This method isn't really supported by SWT - so will use the shape bounds - */ - public void clip(Shape s) { - Rectangle2D clipBds = s.getBounds2D(); - SWTShapeManager.transform(clipBds,transform); - SWTShapeManager.awtToSWT(clipBds,SWT_RECT); + org.eclipse.swt.graphics.Rectangle clip = gc.getClipping(); + clip = clip.intersection(SWT_RECT); - org.eclipse.swt.graphics.Rectangle clip = gc.getClipping(); - clip = clip.intersection(SWT_RECT); - - gc.setClipping(SWT_RECT); - } + gc.setClipping(clip); + } - /** - * This method isn't really supported by SWT - so will use the shape bounds - */ - public void setClip(Shape clip) { - if (clip == null) { - gc.setClipping((org.eclipse.swt.graphics.Rectangle)null); - } - else { - Rectangle2D clipBds = clip.getBounds2D(); - SWTShapeManager.transform(clipBds,transform); - SWTShapeManager.awtToSWT(clipBds,SWT_RECT); - - gc.setClipping(SWT_RECT); - } - } - - public Shape getClip() { - org.eclipse.swt.graphics.Rectangle rect = gc.getClipping(); - Rectangle2D aRect = new Rectangle2D.Double(rect.x,rect.y,rect.width,rect.height); - try { - SWTShapeManager.transform(aRect,transform.createInverse()); - } catch (Exception e) {e.printStackTrace();} - return aRect; - } + public void setClip(int x, int y, int width, int height) { + RECT.setRect(x, y, width, height); + SWTShapeManager.transform(RECT, transform); + SWTShapeManager.awtToSWT(RECT, SWT_RECT); - ///////////////////// - // DEVICE SPECIFIC - ///////////////////// - + gc.setClipping(SWT_RECT); + } - public GraphicsConfiguration getDeviceConfiguration() { - return ((Graphics2D)BUFFER.getGraphics()).getDeviceConfiguration(); - } + /** + * This method isn't really supported by SWT - so will use the shape bounds + */ + public void clip(Shape s) { + Rectangle2D clipBds = s.getBounds2D(); + SWTShapeManager.transform(clipBds, transform); + SWTShapeManager.awtToSWT(clipBds, SWT_RECT); + org.eclipse.swt.graphics.Rectangle clip = gc.getClipping(); + clip = clip.intersection(SWT_RECT); - //////////////// - // COLOR METHODS - //////////////// + gc.setClipping(SWT_RECT); + } - public Paint getPaint() { - return getColor(); - } + /** + * This method isn't really supported by SWT - so will use the shape bounds + */ + public void setClip(Shape clip) { + if (clip == null) { + gc.setClipping((org.eclipse.swt.graphics.Rectangle) null); + } + else { + Rectangle2D clipBds = clip.getBounds2D(); + SWTShapeManager.transform(clipBds, transform); + SWTShapeManager.awtToSWT(clipBds, SWT_RECT); - public void setPaint(Paint paint) { - if (paint instanceof Color) { - setColor((Color)paint); - } - } + gc.setClipping(SWT_RECT); + } + } - public Color getColor() { - org.eclipse.swt.graphics.Color color = gc.getForeground(); - Color awtColor = new Color(color.getRed(),color.getGreen(),color.getBlue()); - return awtColor; - } + public Shape getClip() { + org.eclipse.swt.graphics.Rectangle rect = gc.getClipping(); + Rectangle2D aRect = new Rectangle2D.Double(rect.x, rect.y, rect.width, rect.height); + try { + SWTShapeManager.transform(aRect, transform.createInverse()); + } + catch (Exception e) { + e.printStackTrace(); + } + return aRect; + } - public void setColor(Color c) { - org.eclipse.swt.graphics.Color cachedColor = (org.eclipse.swt.graphics.Color)COLOR_CACHE.get(c); - if (cachedColor == null) { - cachedColor = new org.eclipse.swt.graphics.Color(device,c.getRed(),c.getGreen(),c.getBlue()); - COLOR_CACHE.put(c,cachedColor); - } - gc.setForeground(cachedColor); - } + // /////////////////// + // DEVICE SPECIFIC + // /////////////////// - public void setColor(org.eclipse.swt.graphics.Color c) { - gc.setForeground(c); - } + public GraphicsConfiguration getDeviceConfiguration() { + return ((Graphics2D) BUFFER.getGraphics()).getDeviceConfiguration(); + } - public void setBackground(Color c) { - org.eclipse.swt.graphics.Color cachedColor = (org.eclipse.swt.graphics.Color)COLOR_CACHE.get(c); - if (cachedColor == null) { - cachedColor = new org.eclipse.swt.graphics.Color(device,c.getRed(),c.getGreen(),c.getBlue()); - COLOR_CACHE.put(c,cachedColor); - } - gc.setBackground(cachedColor); - } + // ////////////// + // COLOR METHODS + // ////////////// - public void setBackground(org.eclipse.swt.graphics.Color c) { - gc.setBackground(c); - } + public Paint getPaint() { + return getColor(); + } - public Color getBackground() { - org.eclipse.swt.graphics.Color color = gc.getBackground(); - Color awtColor = new Color(color.getRed(),color.getGreen(),color.getBlue()); - return awtColor; - } + public void setPaint(Paint paint) { + if (paint instanceof Color) { + setColor((Color) paint); + } + } - //////////////// - // FONT METHODS - //////////////// + public Color getColor() { + org.eclipse.swt.graphics.Color color = gc.getForeground(); + Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue()); + return awtColor; + } - public org.eclipse.swt.graphics.Font getSWTFont() { - return curFont; - } - - public org.eclipse.swt.graphics.FontMetrics getSWTFontMetrics() { - gc.setFont(curFont); - return gc.getFontMetrics(); - } + public void setColor(Color c) { + org.eclipse.swt.graphics.Color cachedColor = (org.eclipse.swt.graphics.Color) COLOR_CACHE.get(c); + if (cachedColor == null) { + cachedColor = new org.eclipse.swt.graphics.Color(device, c.getRed(), c.getGreen(), c.getBlue()); + COLOR_CACHE.put(c, cachedColor); + } + gc.setForeground(cachedColor); + } - public Font getFont() { - if (curFont != null) { - int style = Font.PLAIN; - - FontData[] fd = curFont.getFontData(); - if (fd.length > 0) { - if ((fd[0].getStyle() & SWT.BOLD) != 0) { - style = style | Font.BOLD; - } - if ((fd[0].getStyle() & SWT.ITALIC) != 0) { - style = style | SWT.ITALIC; - } - - return new Font(fd[0].getName(),style,fd[0].height); - } - return null; - } - else { - return null; - } - } + public void setColor(org.eclipse.swt.graphics.Color c) { + gc.setForeground(c); + } - public void setFont(Font font) { - String fontString = "name="+font.getFamily()+";bold="+font.isBold()+";italic="+font.isItalic()+";size="+font.getSize(); - - curFont = getFont(fontString); - } + public void setBackground(Color c) { + org.eclipse.swt.graphics.Color cachedColor = (org.eclipse.swt.graphics.Color) COLOR_CACHE.get(c); + if (cachedColor == null) { + cachedColor = new org.eclipse.swt.graphics.Color(device, c.getRed(), c.getGreen(), c.getBlue()); + COLOR_CACHE.put(c, cachedColor); + } + gc.setBackground(cachedColor); + } - public void setFont(org.eclipse.swt.graphics.Font font) { - curFont = font; - } + public void setBackground(org.eclipse.swt.graphics.Color c) { + gc.setBackground(c); + } - public org.eclipse.swt.graphics.Font getFont(String fontString) { - org.eclipse.swt.graphics.Font cachedFont = (org.eclipse.swt.graphics.Font)FONT_CACHE.get(fontString); - if (cachedFont == null) { - int style = 0; - if (fontString.indexOf("bold=true") != -1) { - style = style | SWT.BOLD; - } - if (fontString.indexOf("italic=true") != -1) { - style = style | SWT.ITALIC; - } - - String name = fontString.substring(0,fontString.indexOf(";")); - String size = fontString.substring(fontString.lastIndexOf(";")+1,fontString.length()); - int sizeInt = 12; - try { - sizeInt = Integer.parseInt(size.substring(size.indexOf("=")+1,size.length())); - } - catch (Exception e) {e.printStackTrace();} - - cachedFont = new org.eclipse.swt.graphics.Font(device,name.substring(name.indexOf("=")+1,name.length()),sizeInt,style); - FONT_CACHE.put(fontString,cachedFont); - } - return cachedFont; - } + public Color getBackground() { + org.eclipse.swt.graphics.Color color = gc.getBackground(); + Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue()); + return awtColor; + } - protected org.eclipse.swt.graphics.Font getTransformedFont() { - if (curFont != null) { - FontData fontData = curFont.getFontData()[0]; - int height = fontData.getHeight(); - RECT.setRect(0,0,height,height); - SWTShapeManager.transform(RECT,transform); - height = (int)(RECT.getHeight()+0.5); - - String fontString = "name="+fontData.getName()+";bold="+((fontData.getStyle() & SWT.BOLD) != 0)+";italic="+((fontData.getStyle() & SWT.ITALIC) != 0)+";size="+height; - return getFont(fontString); - } - return null; - } + // ////////////// + // FONT METHODS + // ////////////// - /////////////////////////// - // AFFINE TRANSFORM METHODS - /////////////////////////// + public org.eclipse.swt.graphics.Font getSWTFont() { + return curFont; + } - public void translate(int x, int y) { - transform.translate(x,y); - } + public org.eclipse.swt.graphics.FontMetrics getSWTFontMetrics() { + gc.setFont(curFont); + return gc.getFontMetrics(); + } - public void translate(double tx, double ty) { - transform.translate(tx,ty); - } + public Font getFont() { + if (curFont != null) { + int style = Font.PLAIN; - public void rotate(double theta) { - transform.rotate(theta); - } + FontData[] fd = curFont.getFontData(); + if (fd.length > 0) { + if ((fd[0].getStyle() & SWT.BOLD) != 0) { + style = style | Font.BOLD; + } + if ((fd[0].getStyle() & SWT.ITALIC) != 0) { + style = style | SWT.ITALIC; + } - public void rotate(double theta, double x, double y) { - transform.rotate(theta,x,y); - } + return new Font(fd[0].getName(), style, fd[0].height); + } + return null; + } + else { + return null; + } + } - public void scale(double sx, double sy) { - transform.scale(sx,sy); - } + public void setFont(Font font) { + String fontString = "name=" + font.getFamily() + ";bold=" + font.isBold() + ";italic=" + font.isItalic() + + ";size=" + font.getSize(); - public void shear(double shx, double shy) { - transform.shear(shx,shy); - } + curFont = getFont(fontString); + } - public void transform(AffineTransform Tx) { - transform.concatenate(Tx); - } + public void setFont(org.eclipse.swt.graphics.Font font) { + curFont = font; + } - public void setTransform(AffineTransform Tx) { - transform = (AffineTransform)Tx.clone(); - } + public org.eclipse.swt.graphics.Font getFont(String fontString) { + org.eclipse.swt.graphics.Font cachedFont = (org.eclipse.swt.graphics.Font) FONT_CACHE.get(fontString); + if (cachedFont == null) { + int style = 0; + if (fontString.indexOf("bold=true") != -1) { + style = style | SWT.BOLD; + } + if (fontString.indexOf("italic=true") != -1) { + style = style | SWT.ITALIC; + } - public AffineTransform getTransform() { - return (AffineTransform)transform.clone(); - } + String name = fontString.substring(0, fontString.indexOf(";")); + String size = fontString.substring(fontString.lastIndexOf(";") + 1, fontString.length()); + int sizeInt = 12; + try { + sizeInt = Integer.parseInt(size.substring(size.indexOf("=") + 1, size.length())); + } + catch (Exception e) { + e.printStackTrace(); + } - /////////////////////////////// - // DRAWING AND FILLING METHODS - /////////////////////////////// - - public void clearRect(int x, int y, int width, int height) { - fillRect(x,y,width,height); - } - - public void draw(Shape s) { - if (s instanceof Rectangle2D) { - Rectangle2D r2 = (Rectangle2D)s; - drawRect(r2.getX(),r2.getY(),r2.getWidth(),r2.getHeight()); - } - else if (s instanceof Ellipse2D) { - Ellipse2D e2 = (Ellipse2D)s; - drawOval(e2.getX(),e2.getY(),e2.getWidth(),e2.getHeight()); - } - else if (s instanceof RoundRectangle2D) { - RoundRectangle2D r2 = (RoundRectangle2D)s; - drawRoundRect(r2.getX(),r2.getY(),r2.getWidth(),r2.getHeight(),r2.getArcWidth(),r2.getArcHeight()); - } - else if (s instanceof Arc2D) { - Arc2D a2 = (Arc2D)s; - drawArc(a2.getX(),a2.getY(),a2.getWidth(),a2.getHeight(),a2.getAngleStart(),a2.getAngleExtent()); - } - else { - double[] pts = (double[])SHAPE_CACHE.get(s); - - if (pts == null) { - pts = SWTShapeManager.shapeToPolyline(s); - SHAPE_CACHE.put(s,pts); - } - - drawPolyline(pts); - } - } + cachedFont = new org.eclipse.swt.graphics.Font(device, + name.substring(name.indexOf("=") + 1, name.length()), sizeInt, style); + FONT_CACHE.put(fontString, cachedFont); + } + return cachedFont; + } - public void fill(Shape s) { - if (s instanceof Rectangle2D) { - Rectangle2D r2 = (Rectangle2D)s; - fillRect(r2.getX(),r2.getY(),r2.getWidth(),r2.getHeight()); - } - else if (s instanceof Ellipse2D) { - Ellipse2D e2 = (Ellipse2D)s; - fillOval(e2.getX(),e2.getY(),e2.getWidth(),e2.getHeight()); - } - else if (s instanceof RoundRectangle2D) { - RoundRectangle2D r2 = (RoundRectangle2D)s; - fillRoundRect(r2.getX(),r2.getY(),r2.getWidth(),r2.getHeight(),r2.getArcWidth(),r2.getArcHeight()); - } - else if (s instanceof Arc2D) { - Arc2D a2 = (Arc2D)s; - fillArc(a2.getX(),a2.getY(),a2.getWidth(),a2.getHeight(),a2.getAngleStart(),a2.getAngleExtent()); - } - else { - double[] pts = (double[])SHAPE_CACHE.get(s); - - if (pts == null) { - pts = SWTShapeManager.shapeToPolyline(s); - SHAPE_CACHE.put(s,pts); - } - - fillPolygon(pts); - } - } + protected org.eclipse.swt.graphics.Font getTransformedFont() { + if (curFont != null) { + FontData fontData = curFont.getFontData()[0]; + int height = fontData.getHeight(); + RECT.setRect(0, 0, height, height); + SWTShapeManager.transform(RECT, transform); + height = (int) (RECT.getHeight() + 0.5); - public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { - int[] ptArray = new int[2*nPoints]; - for(int i=0; iTimer's initial delay. - * + * * @see #setInitialDelay * @see #setDelay */ @@ -158,47 +147,37 @@ return initialDelay; } - /** - * If flag is false, - * instructs the Timer to send only one - * action event to its listeners. - * - * @param flag specify false to make the timer - * stop after sending its first action event + * If flag is false, instructs the + * Timer to send only one action event to its listeners. + * + * @param flag specify false to make the timer stop after + * sending its first action event */ public void setRepeats(boolean flag) { repeats = flag; } - /** - * Returns true (the default) - * if the Timer will send - * an action event - * to its listeners multiple times. - * + * Returns true (the default) if the Timer will + * send an action event to its listeners multiple times. + * * @see #setRepeats */ public boolean isRepeats() { return repeats; } - /** * Sets whether the Timer coalesces multiple pending - * ActionEvent firings. - * A busy application may not be able - * to keep up with a Timer's event generation, - * causing multiple - * action events to be queued. When processed, - * the application sends these events one after the other, causing the - * Timer's listeners to receive a sequence of - * events with no delay between them. Coalescing avoids this situation - * by reducing multiple pending events to a single event. - * Timers - * coalesce events by default. - * + * ActionEvent firings. A busy application may not be able to + * keep up with a Timer's event generation, causing multiple + * action events to be queued. When processed, the application sends these + * events one after the other, causing the Timer's listeners to + * receive a sequence of events with no delay between them. Coalescing + * avoids this situation by reducing multiple pending events to a single + * event. Timers coalesce events by default. + * * @param flag specify false to turn off coalescing */ public void setCoalesce(boolean flag) { @@ -212,46 +191,39 @@ } } - /** - * Returns true if the Timer coalesces - * multiple pending action events. - * + * Returns true if the Timer coalesces multiple + * pending action events. + * * @see #setCoalesce */ public boolean isCoalesce() { return coalesce; } - /** - * Starts the Timer, - * causing it to start sending action events + * Starts the Timer, causing it to start sending action events * to its listeners. - * + * * @see #stop */ public void start() { - timerQueue().addTimer(this, - System.currentTimeMillis() + getInitialDelay()); + timerQueue().addTimer(this, System.currentTimeMillis() + getInitialDelay()); } - /** * Returns true if the Timer is running. - * + * * @see #start */ public boolean isRunning() { return timerQueue().containsTimer(this); } - /** - * Stops the Timer, - * causing it to stop sending action events - * to its listeners. - * + * Stops the Timer, causing it to stop sending action events to + * its listeners. + * * @see #start */ public void stop() { @@ -259,33 +231,29 @@ cancelEventOverride(); } - /** - * Restarts the Timer, - * canceling any pending firings and causing - * it to fire with its initial delay. + * Restarts the Timer, canceling any pending firings and + * causing it to fire with its initial delay. */ public void restart() { stop(); start(); } - /** - * Resets the internal state to indicate this Timer shouldn't notify - * any of its listeners. This does not stop a repeatable Timer from - * firing again, use stop for that. + * Resets the internal state to indicate this Timer shouldn't notify any of + * its listeners. This does not stop a repeatable Timer from firing again, + * use stop for that. */ synchronized void cancelEventOverride() { notify = false; } - synchronized void postOverride() { if (notify == false || !coalesce) { notify = true; - display.asyncExec(doPostEvent); + display.asyncExec(doPostEvent); } } - + } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java index cc158b2..1abfbfe 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java @@ -6,11 +6,11 @@ * @author Lance Good */ public class SWTTimerQueue implements Runnable { - static SWTTimerQueue instance; + static SWTTimerQueue instance; - Display display = null; + Display display = null; - SWTTimer firstTimer; + SWTTimer firstTimer; boolean running; /** @@ -19,31 +19,27 @@ public SWTTimerQueue(Display display) { super(); - this.display = display; + this.display = display; // Now start the TimerQueue thread. start(); } - public static SWTTimerQueue sharedInstance(Display display) { - if (instance == null) { - instance = new SWTTimerQueue(display); + if (instance == null) { + instance = new SWTTimerQueue(display); } return instance; } - synchronized void start() { if (running) { - throw new RuntimeException("Can't start a TimerQueue " + - "that is already running"); + throw new RuntimeException("Can't start a TimerQueue " + "that is already running"); } else { - Display.getDefault().asyncExec(new Runnable() { + Display.getDefault().asyncExec(new Runnable() { public void run() { - Thread timerThread = new Thread(SWTTimerQueue.this, - "TimerQueue"); + Thread timerThread = new Thread(SWTTimerQueue.this, "TimerQueue"); timerThread.setDaemon(true); timerThread.setPriority(Thread.NORM_PRIORITY); timerThread.start(); @@ -53,13 +49,11 @@ } } - synchronized void stop() { running = false; notify(); } - synchronized void addTimer(SWTTimer timer, long expirationTime) { SWTTimer previousTimer; SWTTimer nextTimer; @@ -73,11 +67,12 @@ nextTimer = firstTimer; // Insert the Timer into the linked list in the order they will - // expire. If two timers expire at the same time, put the newer entry + // expire. If two timers expire at the same time, put the newer entry // later so they expire in the order they came in. while (nextTimer != null) { - if (nextTimer.expirationTime > expirationTime) break; + if (nextTimer.expirationTime > expirationTime) + break; previousTimer = nextTimer; nextTimer = nextTimer.nextTimer; @@ -96,13 +91,13 @@ notify(); } - synchronized void removeTimer(SWTTimer timer) { - SWTTimer previousTimer; - SWTTimer nextTimer; + SWTTimer previousTimer; + SWTTimer nextTimer; boolean found; - if (!timer.running) return; + if (!timer.running) + return; previousTimer = null; nextTimer = firstTimer; @@ -118,7 +113,8 @@ nextTimer = nextTimer.nextTimer; } - if (!found) return; + if (!found) + return; if (previousTimer == null) { firstTimer = timer.nextTimer; @@ -132,35 +128,34 @@ timer.running = false; } - synchronized boolean containsTimer(SWTTimer timer) { return timer.running; } - /** - * If there are a ton of timers, this method may never return. It loops - * checking to see if the head of the Timer list has expired. If it has, - * it posts the Timer and reschedules it if necessary. + * If there are a ton of timers, this method may never return. It loops + * checking to see if the head of the Timer list has expired. If it has, it + * posts the Timer and reschedules it if necessary. */ synchronized long postExpiredTimers() { - SWTTimer timer; - long currentTime; - long timeToWait; + SWTTimer timer; + long currentTime; + long timeToWait; // The timeToWait we return should never be negative and only be zero // when we have no Timers to wait for. do { timer = firstTimer; - if (timer == null) return 0; + if (timer == null) + return 0; currentTime = System.currentTimeMillis(); timeToWait = timer.expirationTime - currentTime; if (timeToWait <= 0) { try { - timer.postOverride(); // have timer post an event + timer.postOverride(); // have timer post an event } catch (SecurityException e) { } @@ -175,7 +170,7 @@ } // Allow other threads to call addTimer() and removeTimer() - // even when we are posting Timers like mad. Since the wait() + // even when we are posting Timers like mad. Since the wait() // releases the lock, be sure not to maintain any state // between iterations of the loop. @@ -190,7 +185,6 @@ return timeToWait; } - public synchronized void run() { long timeToWait; @@ -212,12 +206,11 @@ timer.cancelEventOverride(); timer = timer.nextTimer; } - display.asyncExec(new SWTTimerQueueRestart(display)); + display.asyncExec(new SWTTimerQueueRestart(display)); throw td; } } - public synchronized String toString() { StringBuffer buf; SWTTimer nextTimer; @@ -230,39 +223,39 @@ buf.append(nextTimer.toString()); nextTimer = nextTimer.nextTimer; - if (nextTimer != null) buf.append(", "); + if (nextTimer != null) + buf.append(", "); } buf.append(")"); return buf.toString(); - } - + } /** - * Runnable that will message the shared instance of the Timer Queue - * to restart. + * Runnable that will message the shared instance of the Timer Queue to + * restart. */ protected static class SWTTimerQueueRestart implements Runnable { - boolean attemptedStart; - - Display display = null; - - public SWTTimerQueueRestart(Display display) { - this.display = display; - } - - public synchronized void run() { - // Only try and restart the q once. - if(!attemptedStart) { - SWTTimerQueue q = SWTTimerQueue.sharedInstance(display); - - synchronized(q) { - if(!q.running) - q.start(); - } - attemptedStart = true; - } - } + boolean attemptedStart; + + Display display = null; + + public SWTTimerQueueRestart(Display display) { + this.display = display; + } + + public synchronized void run() { + // Only try and restart the q once. + if (!attemptedStart) { + SWTTimerQueue q = SWTTimerQueue.sharedInstance(display); + + synchronized (q) { + if (!q.running) + q.start(); + } + attemptedStart = true; + } + } } - + } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/LineShape.java b/extras/src/main/java/edu/umd/cs/piccolox/util/LineShape.java index 272188f..c5b9538 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/LineShape.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/LineShape.java @@ -8,15 +8,14 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -public class LineShape implements Shape, MutablePoints -{ +public class LineShape implements Shape, MutablePoints { private MutablePoints points; - private Rectangle2D bounds = new Rectangle2D.Double(); + private Rectangle2D bounds = new Rectangle2D.Double(); public LineShape(MutablePoints points) { setPoints(points); } - + public void setPoints(MutablePoints points) { if (points == null) { points = new XYArray(); @@ -25,13 +24,18 @@ } // from Points - + public int getPointCount() { return points.getPointCount(); } - public double getX(int i) { return points.getX(i); } - public double getY(int i) { return points.getY(i); } + public double getX(int i) { + return points.getX(i); + } + + public double getY(int i) { + return points.getY(i); + } public Point2D getPoint(int i, Point2D dst) { return points.getPoint(i, dst); @@ -48,7 +52,7 @@ bounds.setRect(0.0d, 0.0d, 0.0d, 0.0d); points.getBounds(bounds); } - + public void setPoint(int i, double x, double y) { points.setPoint(i, x, y); updateBounds(); @@ -70,21 +74,20 @@ newPoints.transformPoints(trans); points = newPoints; } - + // - + public Rectangle getBounds() { - return new Rectangle((int)bounds.getX(), (int)bounds.getY(), (int)bounds.getWidth(), (int)bounds.getHeight()); + return new Rectangle((int) bounds.getX(), (int) bounds.getY(), (int) bounds.getWidth(), (int) bounds + .getHeight()); } public Rectangle2D getBounds2D() { return bounds; } - public static boolean contains(double x, double y, double x1, double y1, double x2, double y2, - boolean min, boolean max, - double d) - { + public static boolean contains(double x, double y, double x1, double y1, double x2, double y2, boolean min, + boolean max, double d) { double dx = x2 - x1, dy = y2 - y1; double dx2 = dx * dx, dy2 = dy * dy; double p; @@ -103,7 +106,8 @@ else if (min && p < 0.0) { return false; } - dx = (p * dx) + x1 - x; dy = (p * dy) + y1 - y; + dx = (p * dx) + x1 - x; + dy = (p * dy) + y1 - y; double len = dx * dx + dy * dy; return (len < d); } @@ -126,6 +130,7 @@ } return false; } + public boolean contains(double x, double y) { return contains(x, y, 2.0d); } @@ -134,11 +139,8 @@ return contains(p.getX(), p.getY()); } - public static boolean intersects(double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4, - boolean min1, boolean max1, - boolean min2, boolean max2) - { + public static boolean intersects(double x1, double y1, double x2, double y2, double x3, double y3, double x4, + double y4, boolean min1, boolean max1, boolean min2, boolean max2) { double dx1 = x2 - x1, dy1 = y2 - y1, dx2 = x4 - x3, dy2 = y4 - y3; double d, p2, p1; @@ -165,8 +167,7 @@ else { return false; } - return (((! min1) || (p1 >= 0.0)) && ((! max1) || (p1 <= 1.0)) && - ((! min2) || (p2 >= 0.0)) && ((! max2) || (p2 <= 1.0))); + return (((!min1) || (p1 >= 0.0)) && ((!max1) || (p1 <= 1.0)) && ((!min2) || (p2 >= 0.0)) && ((!max2) || (p2 <= 1.0))); } public boolean intersects(double x, double y, double w, double h) { @@ -181,10 +182,10 @@ y1 = y2; x2 = points.getX(i); y2 = points.getY(i); - if (intersects(x, y, x + w, y, x1, y1, x2, y2, true, true, true, true) || - intersects(x + w, y, x + w, y + h, x1, y1, x2, y2, true, true, true, true) || - intersects(x + w, y + h, x, y + h, x1, y1, x2, y2, true, true, true, true) || - intersects(x, y + h, x, y, x1, y1, x2, y2, true, true, true, true)) { + if (intersects(x, y, x + w, y, x1, y1, x2, y2, true, true, true, true) + || intersects(x + w, y, x + w, y + h, x1, y1, x2, y2, true, true, true, true) + || intersects(x + w, y + h, x, y + h, x1, y1, x2, y2, true, true, true, true) + || intersects(x, y + h, x, y, x1, y1, x2, y2, true, true, true, true)) { return true; } } @@ -204,9 +205,9 @@ } // - + // - + public PathIterator getPathIterator(AffineTransform at) { return new LinePathIterator(points, at); } @@ -214,13 +215,13 @@ public PathIterator getPathIterator(AffineTransform at, double flatness) { return new LinePathIterator(points, at); } - + private static class LinePathIterator implements PathIterator { private Points points; private AffineTransform trans; private int i = 0; - + public LinePathIterator(Points points, AffineTransform trans) { this.points = points; this.trans = trans; @@ -239,7 +240,7 @@ } private Point2D tempPoint = new Point2D.Double(); - + private void currentSegment() { tempPoint.setLocation(points.getX(i), points.getY(i)); if (trans != null) { @@ -249,8 +250,8 @@ public int currentSegment(float[] coords) { currentSegment(); - coords[0] = (float)tempPoint.getX(); - coords[1] = (float)tempPoint.getY(); + coords[0] = (float) tempPoint.getX(); + coords[1] = (float) tempPoint.getY(); return (i == 0 ? PathIterator.SEG_MOVETO : PathIterator.SEG_LINETO); } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/MutablePoints.java b/extras/src/main/java/edu/umd/cs/piccolox/util/MutablePoints.java index 42a6ed3..b14d97e 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/MutablePoints.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/MutablePoints.java @@ -2,10 +2,12 @@ import java.awt.geom.AffineTransform; -public interface MutablePoints extends Points -{ +public interface MutablePoints extends Points { public void setPoint(int i, double x, double y); + public void addPoint(int pos, double x, double y); + public void removePoints(int pos, int num); + public void transformPoints(AffineTransform t); } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/PBoundsLocator.java b/extras/src/main/java/edu/umd/cs/piccolox/util/PBoundsLocator.java index a27bd4e..0d2659d 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/PBoundsLocator.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/PBoundsLocator.java @@ -36,100 +36,101 @@ import edu.umd.cs.piccolo.PNode; /** - * PBoundsLocator is a locator that locates points on the - * bounds of a node. + * PBoundsLocator is a locator that locates points on the bounds of a + * node. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PBoundsLocator extends PNodeLocator { - private int side; - - public static PBoundsLocator createEastLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.EAST); - } + private int side; - public static PBoundsLocator createNorthEastLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.NORTH_EAST); - } + public static PBoundsLocator createEastLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.EAST); + } - public static PBoundsLocator createNorthWestLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.NORTH_WEST); - } + public static PBoundsLocator createNorthEastLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.NORTH_EAST); + } - public static PBoundsLocator createNorthLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.NORTH); - } + public static PBoundsLocator createNorthWestLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.NORTH_WEST); + } - public static PBoundsLocator createSouthLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.SOUTH); - } + public static PBoundsLocator createNorthLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.NORTH); + } - public static PBoundsLocator createWestLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.WEST); - } + public static PBoundsLocator createSouthLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.SOUTH); + } - public static PBoundsLocator createSouthWestLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.SOUTH_WEST); - } + public static PBoundsLocator createWestLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.WEST); + } - public static PBoundsLocator createSouthEastLocator(PNode node) { - return new PBoundsLocator(node, SwingConstants.SOUTH_EAST); - } + public static PBoundsLocator createSouthWestLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.SOUTH_WEST); + } - public PBoundsLocator(PNode node, int aSide) { - super(node); - side = aSide; - } + public static PBoundsLocator createSouthEastLocator(PNode node) { + return new PBoundsLocator(node, SwingConstants.SOUTH_EAST); + } - public int getSide() { - return side; - } - - public void setSide(int side) { - this.side = side; - } - - public double locateX() { - Rectangle2D aBounds = node.getBoundsReference(); + public PBoundsLocator(PNode node, int aSide) { + super(node); + side = aSide; + } - switch (side) { - case SwingConstants.NORTH_WEST : - case SwingConstants.SOUTH_WEST : - case SwingConstants.WEST : - return aBounds.getX(); + public int getSide() { + return side; + } - case SwingConstants.NORTH_EAST : - case SwingConstants.SOUTH_EAST : - case SwingConstants.EAST : - return aBounds.getX() + aBounds.getWidth(); + public void setSide(int side) { + this.side = side; + } - case SwingConstants.NORTH : - case SwingConstants.SOUTH : - return aBounds.getX() + (aBounds.getWidth() / 2); - } - return -1; - } + public double locateX() { + Rectangle2D aBounds = node.getBoundsReference(); - public double locateY() { - Rectangle2D aBounds = node.getBoundsReference(); + switch (side) { + case SwingConstants.NORTH_WEST: + case SwingConstants.SOUTH_WEST: + case SwingConstants.WEST: + return aBounds.getX(); - switch (side) { - case SwingConstants.EAST : - case SwingConstants.WEST : - return aBounds.getY() + (aBounds.getHeight() / 2); + case SwingConstants.NORTH_EAST: + case SwingConstants.SOUTH_EAST: + case SwingConstants.EAST: + return aBounds.getX() + aBounds.getWidth(); - case SwingConstants.SOUTH : - case SwingConstants.SOUTH_WEST : - case SwingConstants.SOUTH_EAST : - return aBounds.getY() + aBounds.getHeight(); + case SwingConstants.NORTH: + case SwingConstants.SOUTH: + return aBounds.getX() + (aBounds.getWidth() / 2); + } + return -1; + } - case SwingConstants.NORTH_WEST : - case SwingConstants.NORTH_EAST : - case SwingConstants.NORTH : - return aBounds.getY(); - } - return -1; - } + public double locateY() { + Rectangle2D aBounds = node.getBoundsReference(); + + switch (side) { + case SwingConstants.EAST: + case SwingConstants.WEST: + return aBounds.getY() + (aBounds.getHeight() / 2); + + case SwingConstants.SOUTH: + case SwingConstants.SOUTH_WEST: + case SwingConstants.SOUTH_EAST: + return aBounds.getY() + aBounds.getHeight(); + + case SwingConstants.NORTH_WEST: + case SwingConstants.NORTH_EAST: + case SwingConstants.NORTH: + return aBounds.getY(); + } + return -1; + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/PFixedWidthStroke.java b/extras/src/main/java/edu/umd/cs/piccolox/util/PFixedWidthStroke.java index d86ab8a..5df26ea 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/PFixedWidthStroke.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/PFixedWidthStroke.java @@ -50,361 +50,363 @@ import edu.umd.cs.piccolo.util.PPickPath; /** - * PFixedWidthStroke is the same as {@link java.awt.BasicStroke} except that PFixedWidthStroke - * has a fixed width on the screen so that even when the canvas view is zooming its - * width stays the same in canvas coordinates. Note that this stroke draws in the inside of - * the stroked shape, instead of the normal draw on center behavior. + * PFixedWidthStroke is the same as {@link java.awt.BasicStroke} except + * that PFixedWidthStroke has a fixed width on the screen so that even when the + * canvas view is zooming its width stays the same in canvas coordinates. Note + * that this stroke draws in the inside of the stroked shape, instead of the + * normal draw on center behavior. *

+ * * @see edu.umd.cs.piccolo.nodes.PPath * @version 1.0 * @author Jesse Grosjean */ public class PFixedWidthStroke implements Stroke, Serializable { - - private static PAffineTransform TEMP_TRANSFORM = new PAffineTransform(); - private static GeneralPath TEMP_PATH = new GeneralPath(GeneralPath.WIND_NON_ZERO); - - final static int JOIN_MITER = BasicStroke.JOIN_MITER; - final static int JOIN_ROUND = BasicStroke.JOIN_ROUND; - final static int JOIN_BEVEL = BasicStroke.JOIN_BEVEL; - final static int CAP_BUTT = BasicStroke.CAP_BUTT; - final static int CAP_ROUND = BasicStroke.CAP_ROUND; - final static int CAP_SQUARE = BasicStroke.CAP_SQUARE; - private float width; - private int join; - private int cap; - private float miterlimit; - private float dash[]; - private float dash_phase; + private static PAffineTransform TEMP_TRANSFORM = new PAffineTransform(); + private static GeneralPath TEMP_PATH = new GeneralPath(GeneralPath.WIND_NON_ZERO); - private static final int RasterizerCaps[] = { - Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE - }; + final static int JOIN_MITER = BasicStroke.JOIN_MITER; + final static int JOIN_ROUND = BasicStroke.JOIN_ROUND; + final static int JOIN_BEVEL = BasicStroke.JOIN_BEVEL; + final static int CAP_BUTT = BasicStroke.CAP_BUTT; + final static int CAP_ROUND = BasicStroke.CAP_ROUND; + final static int CAP_SQUARE = BasicStroke.CAP_SQUARE; - private static final int RasterizerCorners[] = { - Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL - }; + private float width; + private int join; + private int cap; + private float miterlimit; + private float dash[]; + private float dash_phase; - private class FillAdapter implements PathConsumer { - boolean closed; - GeneralPath path; + private static final int RasterizerCaps[] = { Rasterizer.BUTT, Rasterizer.ROUND, Rasterizer.SQUARE }; - public FillAdapter() { - path = TEMP_PATH; - path.reset(); - } + private static final int RasterizerCorners[] = { Rasterizer.MITER, Rasterizer.ROUND, Rasterizer.BEVEL }; - public Shape getShape() { - return path; - } + private class FillAdapter implements PathConsumer { + boolean closed; + GeneralPath path; - public void beginPath() {} + public FillAdapter() { + path = TEMP_PATH; + path.reset(); + } - public void beginSubpath(float x0, float y0) { - if (closed) { - path.closePath(); - closed = false; - } - path.moveTo(x0, y0); - } + public Shape getShape() { + return path; + } - public void appendLine(float x1, float y1) { - path.lineTo(x1, y1); - } + public void beginPath() { + } - public void appendQuadratic(float xm, float ym, float x1, float y1) { - path.quadTo(xm, ym, x1, y1); - } + public void beginSubpath(float x0, float y0) { + if (closed) { + path.closePath(); + closed = false; + } + path.moveTo(x0, y0); + } - public void appendCubic(float xm, float ym, - float xn, float yn, - float x1, float y1) { - path.curveTo(xm, ym, xn, yn, x1, y1); - } + public void appendLine(float x1, float y1) { + path.lineTo(x1, y1); + } - public void closedSubpath() { - closed = true; - } + public void appendQuadratic(float xm, float ym, float x1, float y1) { + path.quadTo(xm, ym, x1, y1); + } - public void endPath() { - if (closed) { - path.closePath(); - closed = false; - } - } + public void appendCubic(float xm, float ym, float xn, float yn, float x1, float y1) { + path.curveTo(xm, ym, xn, yn, x1, y1); + } - public void useProxy(FastPathProducer proxy) - throws PathException { - proxy.sendTo(this); - } + public void closedSubpath() { + closed = true; + } - public long getCPathConsumer() { - return 0; - } - - public void dispose() { - } + public void endPath() { + if (closed) { + path.closePath(); + closed = false; + } + } - public PathConsumer getConsumer() { - return null; - } - } - - public PFixedWidthStroke() { - this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); - } - - public PFixedWidthStroke(float width) { - this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); - } - - public PFixedWidthStroke(float width, int cap, int join) { - this(width, cap, join, 10.0f, null, 0.0f); - } - - public PFixedWidthStroke(float width, int cap, int join, float miterlimit) { - this(width, cap, join, miterlimit, null, 0.0f); - } - - public PFixedWidthStroke(float width, int cap, int join, float miterlimit, float dash[], float dash_phase) { - if (width < 0.0f) { - throw new IllegalArgumentException("negative width"); - } - if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { - throw new IllegalArgumentException("illegal end cap value"); - } - if (join == JOIN_MITER) { - if (miterlimit < 1.0f) { - throw new IllegalArgumentException("miter limit < 1"); - } - } else if (join != JOIN_ROUND && join != JOIN_BEVEL) { - throw new IllegalArgumentException("illegal line join value"); - } - if (dash != null) { - if (dash_phase < 0.0f) { - throw new IllegalArgumentException("negative dash phase"); - } - boolean allzero = true; - for (int i = 0; i < dash.length; i++) { - float d = dash[i]; - if (d > 0.0) { - allzero = false; - } else if (d < 0.0) { - throw new IllegalArgumentException("negative dash length"); - } - } - - if (allzero) { - throw new IllegalArgumentException("dash lengths all zero"); - } - } - this.width = width; - this.cap = cap; - this.join = join; - this.miterlimit = miterlimit; - if (dash != null) { - this.dash = (float []) dash.clone(); - } - this.dash_phase = dash_phase; - } - - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - e.printStackTrace(); - } - return null; - } - - public Shape createStrokedShape(Shape s) { - FillAdapter filler = new FillAdapter(); - PathStroker stroker = new PathStroker(filler); - PathConsumer consumer; + public void useProxy(FastPathProducer proxy) throws PathException { + proxy.sendTo(this); + } - // Fixed Width Additions, always stroke path inside shape. - // Also keeps dashes fixed when zooming (thanks to Shawn Castrianni - Dec 2006) - float fixedScale = 1.0f; + public long getCPathConsumer() { + return 0; + } - if (PDebug.getProcessingOutput()) { - if (PPaintContext.CURRENT_PAINT_CONTEXT != null) { - fixedScale = 1.0f / (float)PPaintContext.CURRENT_PAINT_CONTEXT.getScale(); - } - } else { - if (PPickPath.CURRENT_PICK_PATH != null) { - fixedScale = 1.0f / (float)PPickPath.CURRENT_PICK_PATH.getScale(); - } - } - float fixedWidth = width * fixedScale; + public void dispose() { + } - Rectangle2D bounds = s.getBounds2D(); - double scale = 1.0; + public PathConsumer getConsumer() { + return null; + } + } - if (bounds.getWidth() > bounds.getHeight()) { - if (bounds.getWidth() != 0) { - scale = (bounds.getWidth()-fixedWidth)/bounds.getWidth(); - } - } else { - if (bounds.getHeight() != 0) { - scale = (bounds.getHeight()-fixedWidth)/bounds.getHeight(); - } - } + public PFixedWidthStroke() { + this(1.0f, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } - TEMP_TRANSFORM.setToIdentity(); - TEMP_TRANSFORM.scaleAboutPoint(scale, bounds.getCenterX(), bounds.getCenterY()); - stroker.setPenDiameter(fixedWidth); - PathIterator pi = s.getPathIterator(TEMP_TRANSFORM); + public PFixedWidthStroke(float width) { + this(width, CAP_SQUARE, JOIN_MITER, 10.0f, null, 0.0f); + } - stroker.setPenT4(null); - stroker.setCaps(RasterizerCaps[cap]); - stroker.setCorners(RasterizerCorners[join], miterlimit); - if (dash != null) { - //Fixed Width Additions - float fixedDash[] = new float[dash.length]; - for (int i = 0; i < dash.length; i++) { - fixedDash[i] = dash[i] * fixedScale; - } - float fixedDashPhase = dash_phase * fixedScale; - PathDasher dasher = new PathDasher(stroker); - dasher.setDash(fixedDash, fixedDashPhase); - dasher.setDashT4(null); - consumer = dasher; - } else { - consumer = stroker; - } + public PFixedWidthStroke(float width, int cap, int join) { + this(width, cap, join, 10.0f, null, 0.0f); + } - try { - consumer.beginPath(); - boolean pathClosed = false; - float mx = 0.0f; - float my = 0.0f; - float point[] = new float[6]; + public PFixedWidthStroke(float width, int cap, int join, float miterlimit) { + this(width, cap, join, miterlimit, null, 0.0f); + } - while (!pi.isDone()) { - int type = pi.currentSegment(point); - if (pathClosed == true) { - pathClosed = false; - if (type != PathIterator.SEG_MOVETO) { - // Force current point back to last moveto point - consumer.beginSubpath(mx, my); - } - } - switch (type) { - case PathIterator.SEG_MOVETO: - mx = point[0]; - my = point[1]; - consumer.beginSubpath(point[0], point[1]); - break; - case PathIterator.SEG_LINETO: - consumer.appendLine(point[0], point[1]); - break; - case PathIterator.SEG_QUADTO: - // Quadratic curves take two points - consumer.appendQuadratic(point[0], point[1], - point[2], point[3]); - break; - case PathIterator.SEG_CUBICTO: - // Cubic curves take three points - consumer.appendCubic(point[0], point[1], - point[2], point[3], - point[4], point[5]); - break; - case PathIterator.SEG_CLOSE: - consumer.closedSubpath(); - pathClosed = true; - break; - } - pi.next(); - } + public PFixedWidthStroke(float width, int cap, int join, float miterlimit, float dash[], float dash_phase) { + if (width < 0.0f) { + throw new IllegalArgumentException("negative width"); + } + if (cap != CAP_BUTT && cap != CAP_ROUND && cap != CAP_SQUARE) { + throw new IllegalArgumentException("illegal end cap value"); + } + if (join == JOIN_MITER) { + if (miterlimit < 1.0f) { + throw new IllegalArgumentException("miter limit < 1"); + } + } + else if (join != JOIN_ROUND && join != JOIN_BEVEL) { + throw new IllegalArgumentException("illegal line join value"); + } + if (dash != null) { + if (dash_phase < 0.0f) { + throw new IllegalArgumentException("negative dash phase"); + } + boolean allzero = true; + for (int i = 0; i < dash.length; i++) { + float d = dash[i]; + if (d > 0.0) { + allzero = false; + } + else if (d < 0.0) { + throw new IllegalArgumentException("negative dash length"); + } + } - consumer.endPath(); + if (allzero) { + throw new IllegalArgumentException("dash lengths all zero"); + } + } + this.width = width; + this.cap = cap; + this.join = join; + this.miterlimit = miterlimit; + if (dash != null) { + this.dash = (float[]) dash.clone(); + } + this.dash_phase = dash_phase; + } - consumer.dispose(); // hack to fix memory leak, shouldn't be neccessary but is. - } catch (PathException e) { - throw new InternalError("Unable to Stroke shape ("+ - e.getMessage()+")"); - } + public Object clone() { + try { + return super.clone(); + } + catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return null; + } - return filler.getShape(); - } - - public boolean equals(Object obj) { - if (!(obj instanceof PFixedWidthStroke)) { - return false; - } + public Shape createStrokedShape(Shape s) { + FillAdapter filler = new FillAdapter(); + PathStroker stroker = new PathStroker(filler); + PathConsumer consumer; - PFixedWidthStroke bs = (PFixedWidthStroke) obj; - if (width != bs.width) { - return false; - } + // Fixed Width Additions, always stroke path inside shape. + // Also keeps dashes fixed when zooming (thanks to Shawn Castrianni - + // Dec 2006) + float fixedScale = 1.0f; - if (join != bs.join) { - return false; - } + if (PDebug.getProcessingOutput()) { + if (PPaintContext.CURRENT_PAINT_CONTEXT != null) { + fixedScale = 1.0f / (float) PPaintContext.CURRENT_PAINT_CONTEXT.getScale(); + } + } + else { + if (PPickPath.CURRENT_PICK_PATH != null) { + fixedScale = 1.0f / (float) PPickPath.CURRENT_PICK_PATH.getScale(); + } + } + float fixedWidth = width * fixedScale; - if (cap != bs.cap) { - return false; - } + Rectangle2D bounds = s.getBounds2D(); + double scale = 1.0; - if (miterlimit != bs.miterlimit) { - return false; - } + if (bounds.getWidth() > bounds.getHeight()) { + if (bounds.getWidth() != 0) { + scale = (bounds.getWidth() - fixedWidth) / bounds.getWidth(); + } + } + else { + if (bounds.getHeight() != 0) { + scale = (bounds.getHeight() - fixedWidth) / bounds.getHeight(); + } + } - if (dash != null) { - if (dash_phase != bs.dash_phase) { - return false; - } + TEMP_TRANSFORM.setToIdentity(); + TEMP_TRANSFORM.scaleAboutPoint(scale, bounds.getCenterX(), bounds.getCenterY()); + stroker.setPenDiameter(fixedWidth); + PathIterator pi = s.getPathIterator(TEMP_TRANSFORM); - if (!java.util.Arrays.equals(dash, bs.dash)) { - return false; - } - } else if (bs.dash != null) { - return false; - } + stroker.setPenT4(null); + stroker.setCaps(RasterizerCaps[cap]); + stroker.setCorners(RasterizerCorners[join], miterlimit); + if (dash != null) { + // Fixed Width Additions + float fixedDash[] = new float[dash.length]; + for (int i = 0; i < dash.length; i++) { + fixedDash[i] = dash[i] * fixedScale; + } + float fixedDashPhase = dash_phase * fixedScale; + PathDasher dasher = new PathDasher(stroker); + dasher.setDash(fixedDash, fixedDashPhase); + dasher.setDashT4(null); + consumer = dasher; + } + else { + consumer = stroker; + } - return true; - } - - private float[] getDashArray() { - if (dash == null) { - return null; - } + try { + consumer.beginPath(); + boolean pathClosed = false; + float mx = 0.0f; + float my = 0.0f; + float point[] = new float[6]; - return (float[]) dash.clone(); - } - - private float getDashPhase() { - return dash_phase; - } - - private int getEndCap() { - return cap; - } - - private int getLineJoin() { - return join; - } - - private float getLineWidth() { - return width; - } - - private float getMiterLimit() { - return miterlimit; - } - - public int hashCode() { - int hash = Float.floatToIntBits(width); - hash = hash * 31 + join; - hash = hash * 31 + cap; - hash = hash * 31 + Float.floatToIntBits(miterlimit); - if (dash != null) { - hash = hash * 31 + Float.floatToIntBits(dash_phase); - for (int i = 0; i < dash.length; i++) { - hash = hash * 31 + Float.floatToIntBits(dash[i]); - } - } - return hash; - } + while (!pi.isDone()) { + int type = pi.currentSegment(point); + if (pathClosed == true) { + pathClosed = false; + if (type != PathIterator.SEG_MOVETO) { + // Force current point back to last moveto point + consumer.beginSubpath(mx, my); + } + } + switch (type) { + case PathIterator.SEG_MOVETO: + mx = point[0]; + my = point[1]; + consumer.beginSubpath(point[0], point[1]); + break; + case PathIterator.SEG_LINETO: + consumer.appendLine(point[0], point[1]); + break; + case PathIterator.SEG_QUADTO: + // Quadratic curves take two points + consumer.appendQuadratic(point[0], point[1], point[2], point[3]); + break; + case PathIterator.SEG_CUBICTO: + // Cubic curves take three points + consumer.appendCubic(point[0], point[1], point[2], point[3], point[4], point[5]); + break; + case PathIterator.SEG_CLOSE: + consumer.closedSubpath(); + pathClosed = true; + break; + } + pi.next(); + } + + consumer.endPath(); + + consumer.dispose(); // hack to fix memory leak, shouldn't be + // neccessary but is. + } + catch (PathException e) { + throw new InternalError("Unable to Stroke shape (" + e.getMessage() + ")"); + } + + return filler.getShape(); + } + + public boolean equals(Object obj) { + if (!(obj instanceof PFixedWidthStroke)) { + return false; + } + + PFixedWidthStroke bs = (PFixedWidthStroke) obj; + if (width != bs.width) { + return false; + } + + if (join != bs.join) { + return false; + } + + if (cap != bs.cap) { + return false; + } + + if (miterlimit != bs.miterlimit) { + return false; + } + + if (dash != null) { + if (dash_phase != bs.dash_phase) { + return false; + } + + if (!java.util.Arrays.equals(dash, bs.dash)) { + return false; + } + } + else if (bs.dash != null) { + return false; + } + + return true; + } + + private float[] getDashArray() { + if (dash == null) { + return null; + } + + return (float[]) dash.clone(); + } + + private float getDashPhase() { + return dash_phase; + } + + private int getEndCap() { + return cap; + } + + private int getLineJoin() { + return join; + } + + private float getLineWidth() { + return width; + } + + private float getMiterLimit() { + return miterlimit; + } + + public int hashCode() { + int hash = Float.floatToIntBits(width); + hash = hash * 31 + join; + hash = hash * 31 + cap; + hash = hash * 31 + Float.floatToIntBits(miterlimit); + if (dash != null) { + hash = hash * 31 + Float.floatToIntBits(dash_phase); + for (int i = 0; i < dash.length; i++) { + hash = hash * 31 + Float.floatToIntBits(dash[i]); + } + } + return hash; + } } \ No newline at end of file diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/PLocator.java b/extras/src/main/java/edu/umd/cs/piccolox/util/PLocator.java index ee51de8..5365ce3 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/PLocator.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/PLocator.java @@ -37,23 +37,24 @@ * as PNodeLocator and PBoundsLocator specialize this behavior by locating * points on nodes, or on the bounds of nodes. *

+ * * @version 1.0 * @author Jesse Grosjean */ public abstract class PLocator implements Serializable { - public PLocator() { - } + public PLocator() { + } - public Point2D locatePoint(Point2D aDstPoint) { - if (aDstPoint == null) { - aDstPoint = new Point2D.Double(); - } - aDstPoint.setLocation(locateX(), locateY()); - return aDstPoint; - } + public Point2D locatePoint(Point2D aDstPoint) { + if (aDstPoint == null) { + aDstPoint = new Point2D.Double(); + } + aDstPoint.setLocation(locateX(), locateY()); + return aDstPoint; + } - public abstract double locateX(); + public abstract double locateX(); - public abstract double locateY(); + public abstract double locateY(); } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/PNodeLocator.java b/extras/src/main/java/edu/umd/cs/piccolox/util/PNodeLocator.java index b1a89ec..0d79527 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/PNodeLocator.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/PNodeLocator.java @@ -39,30 +39,31 @@ * many different nodes you will need to call setNode() before asking for each * location. *

+ * * @version 1.0 * @author Jesse Grosjean */ public class PNodeLocator extends PLocator { - - protected PNode node; - public PNodeLocator(PNode node) { - setNode(node); - } + protected PNode node; - public PNode getNode() { - return node; - } - - public void setNode(PNode node) { - this.node = node; - } + public PNodeLocator(PNode node) { + setNode(node); + } - public double locateX() { - return node.getBoundsReference().getCenterX(); - } + public PNode getNode() { + return node; + } - public double locateY() { - return node.getBoundsReference().getCenterY(); - } + public void setNode(PNode node) { + this.node = node; + } + + public double locateX() { + return node.getBoundsReference().getCenterX(); + } + + public double locateY() { + return node.getBoundsReference().getCenterY(); + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/POcclusionDetection.java b/extras/src/main/java/edu/umd/cs/piccolox/util/POcclusionDetection.java index e330740..1f96446 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/POcclusionDetection.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/POcclusionDetection.java @@ -40,46 +40,47 @@ */ public class POcclusionDetection { - /** - * Traverse from the bottom right of the scene graph (top visible node) - * up the tree determining which parent nodes are occluded by their children - * nodes. Note that this is only detecting a subset of occlusions (parent, child), - * others such as overlapping siblings or cousins are not detected. - */ - public void detectOccusions(PNode n, PBounds parentBounds) { - detectOcclusions(n, new PPickPath(null, parentBounds)); - } + /** + * Traverse from the bottom right of the scene graph (top visible node) up + * the tree determining which parent nodes are occluded by their children + * nodes. Note that this is only detecting a subset of occlusions (parent, + * child), others such as overlapping siblings or cousins are not detected. + */ + public void detectOccusions(PNode n, PBounds parentBounds) { + detectOcclusions(n, new PPickPath(null, parentBounds)); + } - public void detectOcclusions(PNode n, PPickPath pickPath) { - if (n.fullIntersects(pickPath.getPickBounds())) { - pickPath.pushTransform(n.getTransformReference(false)); - - int count = n.getChildrenCount(); - for (int i = count - 1; i >= 0; i--) { - PNode each = (PNode) n.getChild(i); - if (n.getOccluded()) { - // if n has been occuded by a previous decendent then - // this child must also be occuded - each.setOccluded(true); - } else { - // see if child each occludes n - detectOcclusions(each, pickPath); - } - } + public void detectOcclusions(PNode n, PPickPath pickPath) { + if (n.fullIntersects(pickPath.getPickBounds())) { + pickPath.pushTransform(n.getTransformReference(false)); - // see if n occudes it's parents - if (!n.getOccluded()) { - if (n.intersects(pickPath.getPickBounds())) { - if (n.isOpaque(pickPath.getPickBounds())) { - PNode p = n.getParent(); - while (p != null && !p.getOccluded()) { - p.setOccluded(true); - } - } - } - } - - pickPath.popTransform(n.getTransformReference(false)); - } - } + int count = n.getChildrenCount(); + for (int i = count - 1; i >= 0; i--) { + PNode each = (PNode) n.getChild(i); + if (n.getOccluded()) { + // if n has been occuded by a previous decendent then + // this child must also be occuded + each.setOccluded(true); + } + else { + // see if child each occludes n + detectOcclusions(each, pickPath); + } + } + + // see if n occudes it's parents + if (!n.getOccluded()) { + if (n.intersects(pickPath.getPickBounds())) { + if (n.isOpaque(pickPath.getPickBounds())) { + PNode p = n.getParent(); + while (p != null && !p.getOccluded()) { + p.setOccluded(true); + } + } + } + } + + pickPath.popTransform(n.getTransformReference(false)); + } + } } diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/Points.java b/extras/src/main/java/edu/umd/cs/piccolox/util/Points.java index 10180f7..0e8d9c8 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/Points.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/Points.java @@ -1,13 +1,15 @@ package edu.umd.cs.piccolox.util; + import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -public interface Points -{ +public interface Points { public int getPointCount(); public double getX(int i); + public double getY(int i); + public Point2D getPoint(int i, Point2D dst); public Rectangle2D getBounds(Rectangle2D dst); diff --git a/extras/src/main/java/edu/umd/cs/piccolox/util/XYArray.java b/extras/src/main/java/edu/umd/cs/piccolox/util/XYArray.java index d8410d7..8bfa502 100644 --- a/extras/src/main/java/edu/umd/cs/piccolox/util/XYArray.java +++ b/extras/src/main/java/edu/umd/cs/piccolox/util/XYArray.java @@ -4,8 +4,7 @@ import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; -public class XYArray implements MutablePoints -{ +public class XYArray implements MutablePoints { // the coordinates are stored as alternating x and y pairs private double[] points = null; @@ -15,11 +14,13 @@ private int numPoints = 0; - public int getPointCount() { return numPoints;} + public int getPointCount() { + return numPoints; + } // normalize an index, negative counts from end - private int i(int i) { + private int i(int i) { if (i < 0) { i = numPoints + i; } @@ -33,52 +34,47 @@ // from Points - public double getX(int i) - { + public double getX(int i) { i = i(i); - return points[i*2]; + return points[i * 2]; } - public double getY(int i) - { + + public double getY(int i) { i = i(i); - return points[i*2 + 1]; + return points[i * 2 + 1]; } + public Point2D getPoint(int i, Point2D dst) { i = i(i); - dst.setLocation(points[i*2], points[i*2 + 1]); + dst.setLocation(points[i * 2], points[i * 2 + 1]); return dst; } - public void setX(int i, double x) - { + public void setX(int i, double x) { i = i(i); - points[i*2] = x; - } - public void setY(int i, double y) - { - i = i(i); - points[i*2 + 1] = y; + points[i * 2] = x; } - public void setPoint(int i, double x, double y) - { + public void setY(int i, double y) { i = i(i); - points[i*2] = x; - points[i*2 + 1] = y; + points[i * 2 + 1] = y; } - public void setPoint(int i, Point2D pt) - { + public void setPoint(int i, double x, double y) { + i = i(i); + points[i * 2] = x; + points[i * 2 + 1] = y; + } + + public void setPoint(int i, Point2D pt) { setPoint(i, pt.getX(), pt.getY()); } - public void transformPoints(AffineTransform t) - { + public void transformPoints(AffineTransform t) { t.transform(points, 0, points, 0, numPoints); } - public Rectangle2D getBounds(Rectangle2D dst) - { + public Rectangle2D getBounds(Rectangle2D dst) { int i = 0; if (dst.isEmpty() && getPointCount() > 0) { dst.setRect(getX(i), getY(i), 1.0d, 1.0d); @@ -95,19 +91,17 @@ // initialization of points array - public static double[] initPoints(double[] points, int n, double[] old) - { + public static double[] initPoints(double[] points, int n, double[] old) { if (points == null || n * 2 > points.length) { points = new double[n * 2]; } if (old != null && points != old) { System.arraycopy(old, 0, points, 0, Math.min(old.length, n * 2)); } - return(points); + return (points); } - private void initPoints(double[] points, int n) - { + private void initPoints(double[] points, int n) { this.points = initPoints(points, n, this.points); numPoints = (points != null ? points.length / 2 : 0); } @@ -117,17 +111,18 @@ public XYArray(double[] points) { initPoints(points, points.length / 2); } + public XYArray(int n) { - initPoints(null, n); + initPoints(null, n); } + public XYArray() { this(0); } // adding points to points array - public void addPoints(int pos, Points pts, int start, int end) - { + public void addPoints(int pos, Points pts, int start, int end) { if (end < 0) { end = pts.getPointCount() + end + 1; } @@ -143,15 +138,16 @@ setPoint(pos + count, pts.getX(start), pts.getY(start)); } } + public void addPoints(int pos, Points pts) { addPoints(pos, pts, 0, pts.getPointCount()); } - public void appendPoints(Points pts) - { addPoints(numPoints, pts);} + public void appendPoints(Points pts) { + addPoints(numPoints, pts); + } - public static XYArray copyPoints(Points pts) - { + public static XYArray copyPoints(Points pts) { XYArray newList = new XYArray(pts.getPointCount()); newList.appendPoints(pts); return newList; @@ -159,39 +155,40 @@ // from MutablePoints - public void addPoint(int pos, double x, double y) - { + public void addPoint(int pos, double x, double y) { addPoints(pos, null, 0, 1); setPoint(pos, x, y); } - public void addPoint(int pos, Point2D pt) - { + public void addPoint(int pos, Point2D pt) { addPoint(pos, pt.getX(), pt.getY()); } - public void removePoints(int pos, int num) - { + public void removePoints(int pos, int num) { num = Math.min(num, numPoints - pos); if (num <= 0) return; System.arraycopy(points, (pos + num) * 2, points, pos * 2, (numPoints - (pos + num)) * 2); numPoints -= num; } - public void removeAllPoints() - { removePoints(0, numPoints);} + + public void removeAllPoints() { + removePoints(0, numPoints); + } // - public Object clone() - { - XYArray ps = null; - try { ps = (XYArray)(super.clone());} - catch (CloneNotSupportedException e) {} - if (ps != null) { - ps.points = initPoints(ps.points, numPoints, points); - ps.numPoints = numPoints; - } - return(ps); + public Object clone() { + XYArray ps = null; + try { + ps = (XYArray) (super.clone()); + } + catch (CloneNotSupportedException e) { + } + if (ps != null) { + ps.points = initPoints(ps.points, numPoints, points); + ps.numPoints = numPoints; + } + return (ps); } } diff --git a/extras/src/test/java/edu/umd/cs/piccolox/PFrameTest.java b/extras/src/test/java/edu/umd/cs/piccolox/PFrameTest.java index ee90198..1592423 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/PFrameTest.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/PFrameTest.java @@ -1,4 +1,5 @@ package edu.umd.cs.piccolox; + import java.awt.EventQueue; import java.awt.Rectangle; import java.lang.reflect.InvocationTargetException; @@ -23,6 +24,7 @@ }); Rectangle bounds = frame.getCanvas().getBounds(); assertEquals("Canvas width should match width of content pane", frame.getContentPane().getWidth(), bounds.width); - assertEquals("Canvas height should match height of content pane", frame.getContentPane().getHeight(), bounds.height); + assertEquals("Canvas height should match height of content pane", frame.getContentPane().getHeight(), + bounds.height); } } diff --git a/extras/src/test/java/edu/umd/cs/piccolox/event/PNotificationCenterTest.java b/extras/src/test/java/edu/umd/cs/piccolox/event/PNotificationCenterTest.java index bc0252f..cb8efa3 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/event/PNotificationCenterTest.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/event/PNotificationCenterTest.java @@ -1,55 +1,56 @@ package edu.umd.cs.piccolox.event; + import junit.framework.TestCase; public class PNotificationCenterTest extends TestCase { - boolean changed1; - boolean changed2; - boolean changed3; - boolean changed4; + boolean changed1; + boolean changed2; + boolean changed3; + boolean changed4; - public PNotificationCenterTest(String name) { - super(name); - } + public PNotificationCenterTest(String name) { + super(name); + } - public void testToString() { - PNotificationCenter center = PNotificationCenter.defaultCenter(); - - center.addListener(this, "changed1", "propertyChanged", this); - center.addListener(this, "changed2", null, this); - center.addListener(this, "changed3", "propertyChanged", null); - center.addListener(this, "changed4", null, null); - - center.postNotification("propertyChanged", this); - assertTrue(changed1 && changed2 && changed3 && changed4); - changed1 = changed2 = changed3 = changed4 = false; - - center.postNotification("propertyChanged", new Object()); - assertTrue(!changed1 && !changed2 && changed3 && changed4); - changed1 = changed2 = changed3 = changed4 = false; + public void testToString() { + PNotificationCenter center = PNotificationCenter.defaultCenter(); - center.postNotification("otherPropertyChanged", this); - assertTrue(!changed1 && changed2 && !changed3 && changed4); - changed1 = changed2 = changed3 = changed4 = false; + center.addListener(this, "changed1", "propertyChanged", this); + center.addListener(this, "changed2", null, this); + center.addListener(this, "changed3", "propertyChanged", null); + center.addListener(this, "changed4", null, null); - center.postNotification("otherPropertyChanged", new Object()); - assertTrue(!changed1 && !changed2 && !changed3 && changed4); - changed1 = changed2 = changed3 = changed4 = false; - } - - public void changed1(PNotification notification) { - changed1 = true; - } + center.postNotification("propertyChanged", this); + assertTrue(changed1 && changed2 && changed3 && changed4); + changed1 = changed2 = changed3 = changed4 = false; - public void changed2(PNotification notification) { - changed2 = true; - } - - public void changed3(PNotification notification) { - changed3 = true; - } + center.postNotification("propertyChanged", new Object()); + assertTrue(!changed1 && !changed2 && changed3 && changed4); + changed1 = changed2 = changed3 = changed4 = false; - public void changed4(PNotification notification) { - changed4 = true; - } + center.postNotification("otherPropertyChanged", this); + assertTrue(!changed1 && changed2 && !changed3 && changed4); + changed1 = changed2 = changed3 = changed4 = false; + + center.postNotification("otherPropertyChanged", new Object()); + assertTrue(!changed1 && !changed2 && !changed3 && changed4); + changed1 = changed2 = changed3 = changed4 = false; + } + + public void changed1(PNotification notification) { + changed1 = true; + } + + public void changed2(PNotification notification) { + changed2 = true; + } + + public void changed3(PNotification notification) { + changed3 = true; + } + + public void changed4(PNotification notification) { + changed4 = true; + } } diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwing.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwing.java index 7a4362e..a926262 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwing.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwing.java @@ -26,114 +26,112 @@ import edu.umd.cs.piccolo.nodes.PText; /** - * User: Sam Reid - * Date: Jul 11, 2005 - * Time: 12:15:55 PM + * User: Sam Reid Date: Jul 11, 2005 Time: 12:15:55 PM */ public class TestPSwing { - public static void main( String[] args ) { + public static void main(String[] args) { PSwingCanvas pCanvas = new PSwingCanvas(); - final PText pText = new PText( "PText" ); - pCanvas.getLayer().addChild( pText ); - JFrame frame = new JFrame( "Test Piccolo" ); + final PText pText = new PText("PText"); + pCanvas.getLayer().addChild(pText); + JFrame frame = new JFrame("Test Piccolo"); - frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); - frame.setContentPane( pCanvas ); - frame.setSize( 600, 800 ); - frame.setVisible( true ); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(pCanvas); + frame.setSize(600, 800); + frame.setVisible(true); - PText text2 = new PText( "Text2" ); - text2.setFont( new Font( "Lucida Sans", Font.BOLD, 18 ) ); - pCanvas.getLayer().addChild( text2 ); - text2.translate( 100, 100 ); - text2.addInputEventListener( new PZoomEventHandler() ); + PText text2 = new PText("Text2"); + text2.setFont(new Font("Lucida Sans", Font.BOLD, 18)); + pCanvas.getLayer().addChild(text2); + text2.translate(100, 100); + text2.addInputEventListener(new PZoomEventHandler()); - pCanvas.removeInputEventListener( pCanvas.getPanEventHandler() ); + pCanvas.removeInputEventListener(pCanvas.getPanEventHandler()); - JButton jButton = new JButton( "MyButton!" ); - jButton.addActionListener( new ActionListener() { - public void actionPerformed( ActionEvent e ) { - System.out.println( "TestZSwing.actionPerformed!!!!!!!!!!!!!!*********************" ); + JButton jButton = new JButton("MyButton!"); + jButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("TestZSwing.actionPerformed!!!!!!!!!!!!!!*********************"); } - } ); - final PSwing pSwing = new PSwing(jButton ); - pCanvas.getLayer().addChild( pSwing ); + }); + final PSwing pSwing = new PSwing(jButton); + pCanvas.getLayer().addChild(pSwing); pSwing.repaint(); JSpinner jSpinner = new JSpinner(); - jSpinner.setPreferredSize( new Dimension( 100, jSpinner.getPreferredSize().height ) ); - PSwing pSpinner = new PSwing(jSpinner ); - pCanvas.getLayer().addChild( pSpinner ); - pSpinner.translate( 0, 150 ); + jSpinner.setPreferredSize(new Dimension(100, jSpinner.getPreferredSize().height)); + PSwing pSpinner = new PSwing(jSpinner); + pCanvas.getLayer().addChild(pSpinner); + pSpinner.translate(0, 150); - JCheckBox jcb = new JCheckBox( "CheckBox", true ); - jcb.addActionListener( new ActionListener() { - public void actionPerformed( ActionEvent e ) { - System.out.println( "TestZSwing.JCheckBox.actionPerformed" ); + JCheckBox jcb = new JCheckBox("CheckBox", true); + jcb.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("TestZSwing.JCheckBox.actionPerformed"); } - } ); - jcb.addChangeListener( new ChangeListener() { - public void stateChanged( ChangeEvent e ) { - System.out.println( "TestPSwing.JChekbox.stateChanged@" + System.currentTimeMillis() ); + }); + jcb.addChangeListener(new ChangeListener() { + public void stateChanged(ChangeEvent e) { + System.out.println("TestPSwing.JChekbox.stateChanged@" + System.currentTimeMillis()); } - } ); - PSwing pCheckBox = new PSwing(jcb ); - pCanvas.getLayer().addChild( pCheckBox ); - pCheckBox.translate( 100, 0 ); + }); + PSwing pCheckBox = new PSwing(jcb); + pCanvas.getLayer().addChild(pCheckBox); + pCheckBox.translate(100, 0); // Growable JTextArea - JTextArea textArea = new JTextArea( "This is a growable TextArea.\nTry it out!" ); - textArea.setBorder( new LineBorder( Color.blue, 3 ) ); - PSwing swing = new PSwing(textArea ); - swing.translate( 150, 150 ); - pCanvas.getLayer().addChild( swing ); + JTextArea textArea = new JTextArea("This is a growable TextArea.\nTry it out!"); + textArea.setBorder(new LineBorder(Color.blue, 3)); + PSwing swing = new PSwing(textArea); + swing.translate(150, 150); + pCanvas.getLayer().addChild(swing); // A Slider JSlider slider = new JSlider(); - PSwing pSlider = new PSwing(slider ); - pSlider.translate( 200, 200 ); - pCanvas.getLayer().addChild( pSlider ); + PSwing pSlider = new PSwing(slider); + pSlider.translate(200, 200); + pCanvas.getLayer().addChild(pSlider); // A Scrollable JTree JTree tree = new JTree(); - tree.setEditable( true ); - JScrollPane p = new JScrollPane( tree ); - p.setPreferredSize( new Dimension( 150, 150 ) ); - PSwing pTree = new PSwing(p ); - pCanvas.getLayer().addChild( pTree ); - pTree.translate( 0, 250 ); + tree.setEditable(true); + JScrollPane p = new JScrollPane(tree); + p.setPreferredSize(new Dimension(150, 150)); + PSwing pTree = new PSwing(p); + pCanvas.getLayer().addChild(pTree); + pTree.translate(0, 250); // A JColorChooser - also demonstrates JTabbedPane JColorChooser chooser = new JColorChooser(); - PSwing pChooser = new PSwing(chooser ); - pCanvas.getLayer().addChild( pChooser ); - pChooser.translate( 100, 300 ); + PSwing pChooser = new PSwing(chooser); + pCanvas.getLayer().addChild(pChooser); + pChooser.translate(100, 300); JPanel myPanel = new JPanel(); - myPanel.setBorder( BorderFactory.createTitledBorder( "Titled Border" ) ); - myPanel.add( new JCheckBox( "CheckBox" ) ); - PSwing panelSwing = new PSwing(myPanel ); - pCanvas.getLayer().addChild( panelSwing ); - panelSwing.translate( 400, 50 ); + myPanel.setBorder(BorderFactory.createTitledBorder("Titled Border")); + myPanel.add(new JCheckBox("CheckBox")); + PSwing panelSwing = new PSwing(myPanel); + pCanvas.getLayer().addChild(panelSwing); + panelSwing.translate(400, 50); // A Slider JSlider slider2 = new JSlider(); - PSwing pSlider2 = new PSwing(slider2 ); - pSlider2.translate( 200, 200 ); + PSwing pSlider2 = new PSwing(slider2); + pSlider2.translate(200, 200); PNode root = new PNode(); - root.addChild( pSlider2 ); - root.scale( 1.5 ); - root.rotate( Math.PI / 4 ); - root.translate( 300, 200 ); - pCanvas.getLayer().addChild( root ); + root.addChild(pSlider2); + root.scale(1.5); + root.rotate(Math.PI / 4); + root.translate(300, 200); + pCanvas.getLayer().addChild(root); - String[] listItems = {"Summer Teeth", "Mermaid Avenue", "Being There", "A.M."}; - PComboBox box = new PComboBox( listItems ); - swing = new PSwing(box ); - swing.translate( 200, 250 ); - pCanvas.getLayer().addChild( swing ); - box.setEnvironment( swing, pCanvas );//has to be done manually at present + String[] listItems = { "Summer Teeth", "Mermaid Avenue", "Being There", "A.M." }; + PComboBox box = new PComboBox(listItems); + swing = new PSwing(box); + swing.translate(200, 250); + pCanvas.getLayer().addChild(swing); + box.setEnvironment(swing, pCanvas);// has to be done manually at present // Revalidate and repaint pCanvas.revalidate(); diff --git a/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwingFull.java b/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwingFull.java index ccfd848..70ae13d 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwingFull.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/pswing/TestPSwingFull.java @@ -43,25 +43,23 @@ import edu.umd.cs.piccolo.PNode; /** - * User: Sam Reid - * Date: Jul 11, 2005 - * Time: 12:15:55 PM + * User: Sam Reid Date: Jul 11, 2005 Time: 12:15:55 PM */ public class TestPSwingFull extends JFrame { public TestPSwingFull() { - setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ClassLoader loader; PSwingCanvas canvas; // Set up basic frame - setBounds( 50, 50, 750, 750 ); - setResizable( true ); - setBackground( null ); - setVisible( true ); + setBounds(50, 50, 750, 750); + setResizable(true); + setBackground(null); + setVisible(true); canvas = new PSwingCanvas(); - canvas.setPanEventHandler( null ); - getContentPane().add( canvas ); + canvas.setPanEventHandler(null); + getContentPane().add(canvas); validate(); loader = getClass().getClassLoader(); @@ -71,369 +69,369 @@ PSwing swing2; // JButton - JButton button = new JButton( "Button" ); - button.setCursor( Cursor.getPredefinedCursor( Cursor.CROSSHAIR_CURSOR ) ); - swing = new PSwing(button ); - leaf = new ZVisualLeaf( swing ); + JButton button = new JButton("Button"); + button.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + swing = new PSwing(button); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -500, -500 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-500, -500); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // JButton - JSpinner spinner = new JSpinner( new SpinnerNumberModel( 0, 0, 10, 1 ) ); - spinner.setCursor( Cursor.getPredefinedCursor( Cursor.CROSSHAIR_CURSOR ) ); - swing = new PSwing(spinner ); - leaf = new ZVisualLeaf( swing ); + JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0, 10, 1)); + spinner.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); + swing = new PSwing(spinner); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -800, -500 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-800, -500); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // 2nd Copy of JButton - leaf = new ZVisualLeaf( swing ); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -450, -450 ); - transform.rotate( Math.PI / 2 ); - transform.scale( 0.5 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-450, -450); + transform.rotate(Math.PI / 2); + transform.scale(0.5); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // Growable JTextArea - JTextArea textArea = new JTextArea( "This is a growable TextArea.\nTry it out!" ); - textArea.setBorder( new LineBorder( Color.blue, 3 ) ); - swing = new PSwing(textArea ); - leaf = new ZVisualLeaf( swing ); + JTextArea textArea = new JTextArea("This is a growable TextArea.\nTry it out!"); + textArea.setBorder(new LineBorder(Color.blue, 3)); + swing = new PSwing(textArea); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -250, -500 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-250, -500); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // Growable JTextField - JTextField textField = new JTextField( "A growable text field" ); - swing = new PSwing(textField ); - leaf = new ZVisualLeaf( swing ); + JTextField textField = new JTextField("A growable text field"); + swing = new PSwing(textField); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 0, -500 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(0, -500); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // A Slider JSlider slider = new JSlider(); - swing = new PSwing(slider ); - leaf = new ZVisualLeaf( swing ); + swing = new PSwing(slider); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 250, -500 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(250, -500); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // A Scrollable JTree JTree tree = new JTree(); - tree.setEditable( true ); - JScrollPane p = new JScrollPane( tree ); - p.setPreferredSize( new Dimension( 150, 150 ) ); - swing = new PSwing(p ); - leaf = new ZVisualLeaf( swing ); + tree.setEditable(true); + JScrollPane p = new JScrollPane(tree); + p.setPreferredSize(new Dimension(150, 150)); + swing = new PSwing(p); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -500, -250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-500, -250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // A Scrollable JTextArea - JScrollPane pane = new JScrollPane( new JTextArea( "A Scrollable Text Area\nTry it out!" ) ); - pane.setPreferredSize( new Dimension( 150, 150 ) ); - swing = new PSwing(pane ); - leaf = new ZVisualLeaf( swing ); + JScrollPane pane = new JScrollPane(new JTextArea("A Scrollable Text Area\nTry it out!")); + pane.setPreferredSize(new Dimension(150, 150)); + swing = new PSwing(pane); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -250, -250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-250, -250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); swing2 = swing; // A non-scrollable JTextField // A panel MUST be created with double buffering off - JPanel panel = new JPanel( false ); - textField = new JTextField( "A fixed-size text field" ); - panel.setLayout( new BorderLayout() ); - panel.add( textField ); - swing = new PSwing(panel ); - leaf = new ZVisualLeaf( swing ); + JPanel panel = new JPanel(false); + textField = new JTextField("A fixed-size text field"); + panel.setLayout(new BorderLayout()); + panel.add(textField); + swing = new PSwing(panel); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 0, -250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(0, -250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); -// // A JComboBox -// String[] listItems = {"Summer Teeth", "Mermaid Avenue", "Being There", "A.M."}; -// ZComboBox box = new ZComboBox( listItems ); -// swing = new PSwing( canvas, box ); -// leaf = new ZVisualLeaf( swing ); -// transform = new PNode(); -// transform.translate( 0, -150 ); -// transform.addChild( leaf ); -// canvas.getLayer().addChild( transform ); + // // A JComboBox + // String[] listItems = {"Summer Teeth", "Mermaid Avenue", + // "Being There", "A.M."}; + // ZComboBox box = new ZComboBox( listItems ); + // swing = new PSwing( canvas, box ); + // leaf = new ZVisualLeaf( swing ); + // transform = new PNode(); + // transform.translate( 0, -150 ); + // transform.addChild( leaf ); + // canvas.getLayer().addChild( transform ); // A panel with TitledBorder and JList - panel = new JPanel( false ); - panel.setBackground( Color.lightGray ); - panel.setLayout( new BorderLayout() ); - panel.setBorder( new TitledBorder( new EtchedBorder( EtchedBorder.RAISED ), "A JList", TitledBorder.LEFT, TitledBorder.TOP ) ); - panel.setPreferredSize( new Dimension( 200, 200 ) ); + panel = new JPanel(false); + panel.setBackground(Color.lightGray); + panel.setLayout(new BorderLayout()); + panel.setBorder(new TitledBorder(new EtchedBorder(EtchedBorder.RAISED), "A JList", TitledBorder.LEFT, + TitledBorder.TOP)); + panel.setPreferredSize(new Dimension(200, 200)); Vector data = new Vector(); - data.addElement( "Choice 1" ); - data.addElement( "Choice 2" ); - data.addElement( "Choice 3" ); - data.addElement( "Choice 4" ); - data.addElement( "Choice 5" ); - JList list = new JList( data ); - list.setBackground( Color.lightGray ); - panel.add( list ); - swing = new PSwing(panel ); - leaf = new ZVisualLeaf( swing ); + data.addElement("Choice 1"); + data.addElement("Choice 2"); + data.addElement("Choice 3"); + data.addElement("Choice 4"); + data.addElement("Choice 5"); + JList list = new JList(data); + list.setBackground(Color.lightGray); + panel.add(list); + swing = new PSwing(panel); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 250, -250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(250, -250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // A JLabel - JLabel label = new JLabel( "A JLabel", SwingConstants.CENTER ); + JLabel label = new JLabel("A JLabel", SwingConstants.CENTER); - swing = new PSwing(label ); - leaf = new ZVisualLeaf( swing ); + swing = new PSwing(label); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -500, 0 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-500, 0); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // Rotated copy of the Scrollable JTextArea - leaf = new ZVisualLeaf( swing2 ); + leaf = new ZVisualLeaf(swing2); transform = new PNode(); - transform.translate( -100, 0 ); - transform.rotate( Math.PI / 2 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-100, 0); + transform.rotate(Math.PI / 2); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // A panel with layout // A panel MUST be created with double buffering off - panel = new JPanel( false ); - panel.setLayout( new BorderLayout() ); - JButton button1 = new JButton( "Button 1" ); - JButton button2 = new JButton( "Button 2" ); - label = new JLabel( "A Panel with Layout" ); - label.setHorizontalAlignment( SwingConstants.CENTER ); - label.setForeground( Color.white ); - panel.setBackground( Color.red ); - panel.setPreferredSize( new Dimension( 150, 150 ) ); - panel.setBorder( new EmptyBorder( 5, 5, 5, 5 ) ); - panel.add( button1, "North" ); - panel.add( button2, "South" ); - panel.add( label, "Center" ); + panel = new JPanel(false); + panel.setLayout(new BorderLayout()); + JButton button1 = new JButton("Button 1"); + JButton button2 = new JButton("Button 2"); + label = new JLabel("A Panel with Layout"); + label.setHorizontalAlignment(SwingConstants.CENTER); + label.setForeground(Color.white); + panel.setBackground(Color.red); + panel.setPreferredSize(new Dimension(150, 150)); + panel.setBorder(new EmptyBorder(5, 5, 5, 5)); + panel.add(button1, "North"); + panel.add(button2, "South"); + panel.add(label, "Center"); panel.revalidate(); - swing = new PSwing(panel ); - leaf = new ZVisualLeaf( swing ); + swing = new PSwing(panel); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 0, 0 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(0, 0); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // JTable Example Vector columns = new Vector(); - columns.addElement( "Check Number" ); - columns.addElement( "Description" ); - columns.addElement( "Amount" ); + columns.addElement("Check Number"); + columns.addElement("Description"); + columns.addElement("Amount"); Vector rows = new Vector(); Vector row = new Vector(); - row.addElement( "101" ); - row.addElement( "Sandwich" ); - row.addElement( "$20.00" ); - rows.addElement( row ); + row.addElement("101"); + row.addElement("Sandwich"); + row.addElement("$20.00"); + rows.addElement(row); row = new Vector(); - row.addElement( "102" ); - row.addElement( "Monkey Wrench" ); - row.addElement( "$100.00" ); - rows.addElement( row ); + row.addElement("102"); + row.addElement("Monkey Wrench"); + row.addElement("$100.00"); + rows.addElement(row); row = new Vector(); - row.addElement( "214" ); - row.addElement( "Ant farm" ); - row.addElement( "$55.00" ); - rows.addElement( row ); + row.addElement("214"); + row.addElement("Ant farm"); + row.addElement("$55.00"); + rows.addElement(row); row = new Vector(); - row.addElement( "215" ); - row.addElement( "Self-esteem tapes" ); - row.addElement( "$37.99" ); - rows.addElement( row ); + row.addElement("215"); + row.addElement("Self-esteem tapes"); + row.addElement("$37.99"); + rows.addElement(row); row = new Vector(); - row.addElement( "216" ); - row.addElement( "Tube Socks" ); - row.addElement( "$7.45" ); - rows.addElement( row ); + row.addElement("216"); + row.addElement("Tube Socks"); + row.addElement("$7.45"); + rows.addElement(row); row = new Vector(); - row.addElement( "220" ); - row.addElement( "Ab Excerciser" ); - row.addElement( "$56.95" ); - rows.addElement( row ); + row.addElement("220"); + row.addElement("Ab Excerciser"); + row.addElement("$56.95"); + rows.addElement(row); row = new Vector(); - row.addElement( "319" ); - row.addElement( "Y2K Supplies" ); - row.addElement( "$4624.33" ); - rows.addElement( row ); + row.addElement("319"); + row.addElement("Y2K Supplies"); + row.addElement("$4624.33"); + rows.addElement(row); row = new Vector(); - row.addElement( "332" ); - row.addElement( "Tie Rack" ); - row.addElement( "$15.20" ); - rows.addElement( row ); + row.addElement("332"); + row.addElement("Tie Rack"); + row.addElement("$15.20"); + rows.addElement(row); row = new Vector(); - row.addElement( "344" ); - row.addElement( "Swing Set" ); - row.addElement( "$146.59" ); - rows.addElement( row ); - JTable table = new JTable( rows, columns ); - table.setAutoResizeMode( JTable.AUTO_RESIZE_OFF ); - table.setRowHeight( 30 ); - TableColumn c = table.getColumn( table.getColumnName( 0 ) ); - c.setPreferredWidth( 150 ); - c = table.getColumn( table.getColumnName( 1 ) ); - c.setPreferredWidth( 150 ); - c = table.getColumn( table.getColumnName( 2 ) ); - c.setPreferredWidth( 150 ); - pane = new JScrollPane( table ); - pane.setPreferredSize( new Dimension( 200, 200 ) ); - table.setDoubleBuffered( false ); - swing = new PSwing(pane ); - leaf = new ZVisualLeaf( swing ); + row.addElement("344"); + row.addElement("Swing Set"); + row.addElement("$146.59"); + rows.addElement(row); + JTable table = new JTable(rows, columns); + table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + table.setRowHeight(30); + TableColumn c = table.getColumn(table.getColumnName(0)); + c.setPreferredWidth(150); + c = table.getColumn(table.getColumnName(1)); + c.setPreferredWidth(150); + c = table.getColumn(table.getColumnName(2)); + c.setPreferredWidth(150); + pane = new JScrollPane(table); + pane.setPreferredSize(new Dimension(200, 200)); + table.setDoubleBuffered(false); + swing = new PSwing(pane); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 250, 0 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(250, 0); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // JEditorPane - HTML example try { - - final JEditorPane editorPane = new JEditorPane( loader.getResource( "csdept.html" ) ); - editorPane.setDoubleBuffered( false ); - editorPane.setEditable( false ); - pane = new JScrollPane( editorPane ); - pane.setDoubleBuffered( false ); - pane.setPreferredSize( new Dimension( 400, 400 ) ); - editorPane.addHyperlinkListener( new HyperlinkListener() { - public void hyperlinkUpdate( HyperlinkEvent e ) { - if( e.getEventType() == HyperlinkEvent.EventType.ACTIVATED ) { + final JEditorPane editorPane = new JEditorPane(loader.getResource("csdept.html")); + editorPane.setDoubleBuffered(false); + editorPane.setEditable(false); + pane = new JScrollPane(editorPane); + pane.setDoubleBuffered(false); + pane.setPreferredSize(new Dimension(400, 400)); + editorPane.addHyperlinkListener(new HyperlinkListener() { + public void hyperlinkUpdate(HyperlinkEvent e) { + if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) { try { - editorPane.setPage( e.getURL() ); + editorPane.setPage(e.getURL()); } - catch( IOException ioe ) { - System.out.println( "Couldn't Load Web Page" ); + catch (IOException ioe) { + System.out.println("Couldn't Load Web Page"); } } } - } ); - swing = new PSwing(pane ); - leaf = new ZVisualLeaf( swing ); + }); + swing = new PSwing(pane); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -500, 250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-500, 250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); } - catch( IOException ioe ) { - System.out.println( "Couldn't Load Web Page" ); + catch (IOException ioe) { + System.out.println("Couldn't Load Web Page"); } // A JInternalFrame with a JSplitPane - a JOptionPane - and a // JToolBar - JInternalFrame iframe = new JInternalFrame( "JInternalFrame" ); - iframe.getRootPane().setDoubleBuffered( false ); - ( (JComponent)iframe.getContentPane() ).setDoubleBuffered( false ); - iframe.setPreferredSize( new Dimension( 500, 500 ) ); + JInternalFrame iframe = new JInternalFrame("JInternalFrame"); + iframe.getRootPane().setDoubleBuffered(false); + ((JComponent) iframe.getContentPane()).setDoubleBuffered(false); + iframe.setPreferredSize(new Dimension(500, 500)); JTabbedPane tabby = new JTabbedPane(); - tabby.setDoubleBuffered( false ); - iframe.getContentPane().setLayout( new BorderLayout() ); - JOptionPane options = new JOptionPane( "This is a JOptionPane!", - JOptionPane.INFORMATION_MESSAGE, - JOptionPane.DEFAULT_OPTION ); - options.setDoubleBuffered( false ); - options.setMinimumSize( new Dimension( 50, 50 ) ); - options.setPreferredSize( new Dimension( 225, 225 ) ); - JPanel tools = new JPanel( false ); - tools.setMinimumSize( new Dimension( 150, 150 ) ); - tools.setPreferredSize( new Dimension( 225, 225 ) ); + tabby.setDoubleBuffered(false); + iframe.getContentPane().setLayout(new BorderLayout()); + JOptionPane options = new JOptionPane("This is a JOptionPane!", JOptionPane.INFORMATION_MESSAGE, + JOptionPane.DEFAULT_OPTION); + options.setDoubleBuffered(false); + options.setMinimumSize(new Dimension(50, 50)); + options.setPreferredSize(new Dimension(225, 225)); + JPanel tools = new JPanel(false); + tools.setMinimumSize(new Dimension(150, 150)); + tools.setPreferredSize(new Dimension(225, 225)); JToolBar bar = new JToolBar(); - Action letter = new AbstractAction( "Big A!" ) { + Action letter = new AbstractAction("Big A!") { - public void actionPerformed( ActionEvent e ) { + public void actionPerformed(ActionEvent e) { } }; - Action hand = new AbstractAction( "Hi!" ) { - public void actionPerformed( ActionEvent e ) { + Action hand = new AbstractAction("Hi!") { + public void actionPerformed(ActionEvent e) { } }; - Action select = new AbstractAction( "There!" ) { - public void actionPerformed( ActionEvent e ) { + Action select = new AbstractAction("There!") { + public void actionPerformed(ActionEvent e) { } }; - label = new JLabel( "A Panel with a JToolBar" ); - label.setHorizontalAlignment( SwingConstants.CENTER ); - bar.add( letter ); - bar.add( hand ); - bar.add( select ); - bar.setFloatable( false ); - bar.setBorder( new LineBorder( Color.black, 2 ) ); - tools.setLayout( new BorderLayout() ); - tools.add( bar, "North" ); - tools.add( label, "Center" ); + label = new JLabel("A Panel with a JToolBar"); + label.setHorizontalAlignment(SwingConstants.CENTER); + bar.add(letter); + bar.add(hand); + bar.add(select); + bar.setFloatable(false); + bar.setBorder(new LineBorder(Color.black, 2)); + tools.setLayout(new BorderLayout()); + tools.add(bar, "North"); + tools.add(label, "Center"); - JSplitPane split = new JSplitPane( JSplitPane.HORIZONTAL_SPLIT, options, tools ); - split.setDoubleBuffered( false ); - iframe.getContentPane().add( split ); - swing = new PSwing(iframe ); - leaf = new ZVisualLeaf( swing ); + JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, options, tools); + split.setDoubleBuffered(false); + iframe.getContentPane().add(split); + swing = new PSwing(iframe); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( 0, 250 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(0, 250); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); -// JMenuBar menuBar = new JMenuBar(); -// ZMenu menu = new ZMenu( "File" ); -// ZMenu sub = new ZMenu( "Export" ); -// JMenuItem gif = new JMenuItem( "Funds" ); -// sub.add( gif ); -// menu.add( sub ); -// menuBar.add( menu ); -// iframe.setJMenuBar( menuBar ); + // JMenuBar menuBar = new JMenuBar(); + // ZMenu menu = new ZMenu( "File" ); + // ZMenu sub = new ZMenu( "Export" ); + // JMenuItem gif = new JMenuItem( "Funds" ); + // sub.add( gif ); + // menu.add( sub ); + // menuBar.add( menu ); + // iframe.setJMenuBar( menuBar ); - iframe.setVisible( true ); + iframe.setVisible(true); // A JColorChooser - also demonstrates JTabbedPane -// JColorChooser chooser = new JColorChooser(); - JCheckBox chooser = new JCheckBox( "Check Box" ); - swing = new PSwing(chooser ); - leaf = new ZVisualLeaf( swing ); + // JColorChooser chooser = new JColorChooser(); + JCheckBox chooser = new JCheckBox("Check Box"); + swing = new PSwing(chooser); + leaf = new ZVisualLeaf(swing); transform = new PNode(); - transform.translate( -250, 850 ); - transform.addChild( leaf ); - canvas.getLayer().addChild( transform ); + transform.translate(-250, 850); + transform.addChild(leaf); + canvas.getLayer().addChild(transform); // Revalidate and repaint canvas.revalidate(); canvas.repaint(); - PSwing message = new PSwing(new JTextArea( "Click-drag to zoom in and out." ) ); - message.translate( 0, -50 ); - canvas.getLayer().addChild( message ); + PSwing message = new PSwing(new JTextArea("Click-drag to zoom in and out.")); + message.translate(0, -50); + canvas.getLayer().addChild(message); - canvas.getCamera().animateViewToCenterBounds( message.getFullBounds(), false, 1200 ); + canvas.getCamera().animateViewToCenterBounds(message.getFullBounds(), false, 1200); } - public static void main( String[] args ) { - new TestPSwingFull().setVisible( true ); + public static void main(String[] args) { + new TestPSwingFull().setVisible(true); } public static class ZVisualLeaf extends PNode { - public ZVisualLeaf( PNode node ) { - addChild( node ); + public ZVisualLeaf(PNode node) { + addChild(node); } } diff --git a/extras/src/test/java/edu/umd/cs/piccolox/util/PFixedWidthStrokeTest.java b/extras/src/test/java/edu/umd/cs/piccolox/util/PFixedWidthStrokeTest.java index e9fd380..e21390c 100644 --- a/extras/src/test/java/edu/umd/cs/piccolox/util/PFixedWidthStrokeTest.java +++ b/extras/src/test/java/edu/umd/cs/piccolox/util/PFixedWidthStrokeTest.java @@ -5,12 +5,12 @@ import junit.framework.TestCase; public class PFixedWidthStrokeTest extends TestCase { - public void testContants() { - assertEquals(PFixedWidthStroke.CAP_BUTT, BasicStroke.CAP_BUTT); - assertEquals(PFixedWidthStroke.CAP_ROUND, BasicStroke.CAP_ROUND); - assertEquals(PFixedWidthStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE); - assertEquals(PFixedWidthStroke.JOIN_BEVEL, BasicStroke.JOIN_BEVEL); - assertEquals(PFixedWidthStroke.JOIN_MITER, BasicStroke.JOIN_MITER); - assertEquals(PFixedWidthStroke.JOIN_ROUND, BasicStroke.JOIN_ROUND); - } + public void testContants() { + assertEquals(PFixedWidthStroke.CAP_BUTT, BasicStroke.CAP_BUTT); + assertEquals(PFixedWidthStroke.CAP_ROUND, BasicStroke.CAP_ROUND); + assertEquals(PFixedWidthStroke.CAP_SQUARE, BasicStroke.CAP_SQUARE); + assertEquals(PFixedWidthStroke.JOIN_BEVEL, BasicStroke.JOIN_BEVEL); + assertEquals(PFixedWidthStroke.JOIN_MITER, BasicStroke.JOIN_MITER); + assertEquals(PFixedWidthStroke.JOIN_ROUND, BasicStroke.JOIN_ROUND); + } }