- * - * @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(); - - 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); - } - - /** - * 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 deleted file mode 100644 index 0e14e50..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org - * Copyright (c) 1998-2008, University of Maryland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its - * contributors may be used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package edu.umd.cs.piccolox.swt; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.event.InputEvent; -import java.awt.geom.Rectangle2D; - -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.MouseEvent; -import org.eclipse.swt.events.MouseListener; -import org.eclipse.swt.events.MouseMoveListener; -import org.eclipse.swt.events.PaintEvent; -import org.eclipse.swt.events.PaintListener; -import org.eclipse.swt.graphics.Cursor; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; -import org.eclipse.swt.widgets.Composite; - -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PComponent; -import edu.umd.cs.piccolo.PLayer; -import edu.umd.cs.piccolo.PRoot; -import edu.umd.cs.piccolo.event.PInputEventListener; -import edu.umd.cs.piccolo.event.PPanEventHandler; -import edu.umd.cs.piccolo.event.PZoomEventHandler; -import edu.umd.cs.piccolo.util.PBounds; -import edu.umd.cs.piccolo.util.PDebug; -import edu.umd.cs.piccolo.util.PPaintContext; -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. - *
- * - * @version 1.0 - * @author Jesse Grosjean - */ -public class PSWTCanvas extends Composite implements PComponent { - - public static PSWTCanvas CURRENT_CANVAS = null; - - 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. - // **************************************************************** - - /** - * 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; - } - - /** - * 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)); - } - } - - /** - * Return root for this canvas. - */ - public PRoot getRoot() { - return camera.getRoot(); - } - - /** - * Return layer for this canvas. - */ - public PLayer getLayer() { - return camera.getLayer(0); - } - - /** - * 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(); - - r.addChild(c); - r.addChild(l); - c.addLayer(l); - - return c; - } - - // **************************************************************** - // Painting - // **************************************************************** - - /** - * 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(); - } - - /** - * 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 deleted file mode 100644 index 5799e04..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org - * Copyright (c) 1998-2008, University of Maryland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its - * contributors may be used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package edu.umd.cs.piccolox.swt; - -import java.awt.Color; -import java.awt.Shape; -import java.awt.event.InputEvent; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Point2D; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.io.ObjectInputStream; - -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.event.PDragSequenceEventHandler; -import edu.umd.cs.piccolo.event.PInputEvent; -import edu.umd.cs.piccolo.event.PInputEventFilter; -import edu.umd.cs.piccolo.util.PBounds; -import edu.umd.cs.piccolo.util.PDimension; -import edu.umd.cs.piccolox.util.PLocator; -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. - *
- * - * @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; - - /** - * 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(); - } - - 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); - } - }; - - 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 deleted file mode 100644 index a3d4dd6..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org - * Copyright (c) 1998-2008, University of Maryland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its - * contributors may be used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package edu.umd.cs.piccolox.swt; - -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.Rectangle; - -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.nodes.PImage; -import edu.umd.cs.piccolo.util.PBounds; -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. - *
- *
- * @version 1.0
- * @author Jesse Grosjean
- */
-public class PSWTImage extends PNode {
-
- private transient PSWTCanvas canvas;
-
- private transient Image image;
-
- 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);
- }
-
- 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;
- }
-
- /**
- * 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));
- }
-
- /**
- * 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);
- }
-
- 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
deleted file mode 100644
index 4a1b0b1..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.Component;
-import java.awt.event.InputEvent;
-import java.awt.event.KeyEvent;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Overridden to wrap an SWT KeyEvent
- *
- * @author Lance Good
- */
-public class PSWTKeyEvent extends KeyEvent {
-
- 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;
- }
-
- public Object getSource() {
- return swtEvent.getSource();
- }
-
- public boolean isShiftDown() {
- return (swtEvent.stateMask & SWT.SHIFT) != 0;
- }
-
- 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;
- }
- }
-
- 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
deleted file mode 100644
index 2a45dbc..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.Component;
-import java.awt.event.InputEvent;
-import java.awt.event.MouseEvent;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.widgets.Display;
-import org.eclipse.swt.widgets.Widget;
-
-/**
- * Overridden to wrap an SWT MouseEvent
- *
- * @author Lance Good
- */
-public class PSWTMouseEvent extends MouseEvent {
-
- static Component fakeSrc = new Component() {
- };
-
- protected org.eclipse.swt.events.MouseEvent swtEvent;
-
- protected int clickCount;
-
- 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;
- }
-
- public Object getSource() {
- return swtEvent.getSource();
- }
-
- 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;
- }
- }
-
- public boolean isShiftDown() {
- return (swtEvent.stateMask & SWT.SHIFT) != 0;
- }
-
- 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
deleted file mode 100644
index 5253f7d..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java
+++ /dev/null
@@ -1,450 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Paint;
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.Line2D;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-
-import edu.umd.cs.piccolo.PNode;
-import edu.umd.cs.piccolo.nodes.PPath;
-import edu.umd.cs.piccolo.util.PAffineTransform;
-import edu.umd.cs.piccolo.util.PBounds;
-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.
- *
- * 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 - * 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;
-
- boolean updatingBoundsFromPath;
- Shape origShape;
- Shape shape;
-
- PAffineTransform internalXForm;
- AffineTransform inverseXForm;
-
- double[] shapePts;
-
- 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;
- }
-
- 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;
- }
-
- public PSWTPath(Shape aShape) {
- this();
- setShape(aShape);
- }
-
- // ****************************************************************
- // Stroke
- // ****************************************************************
-
- public Paint getStrokePaint() {
- return strokePaint;
- }
-
- 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();
-
- 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
deleted file mode 100644
index 5b27d25..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.event.ActionListener;
-import javax.swing.Timer;
-
-import org.eclipse.swt.widgets.Composite;
-
-import edu.umd.cs.piccolo.PRoot;
-
-/**
- * PSWTRoot is a subclass of PRoot that is designed to work in the SWT
- * environment. In particular it uses SWTTimers and the SWT event dispatch
- * 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; - } - - public Timer createTimer(int delay, ActionListener listener) { - return new SWTTimer(composite.getDisplay(), delay, listener); - } - - public void scheduleProcessInputsIfNeeded() { - if (!Thread.currentThread().equals(composite.getDisplay().getThread())) { - return; - } - - 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 deleted file mode 100644 index 9f67a3e..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org - * Copyright (c) 1998-2008, University of Maryland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its - * contributors may be used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package edu.umd.cs.piccolox.swt; - -import java.awt.Color; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.List; - -import org.eclipse.swt.SWT; - -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.event.PInputEvent; -import edu.umd.cs.piccolo.util.PBounds; -import edu.umd.cs.piccolo.util.PPaintContext; -import edu.umd.cs.piccolox.event.PSelectionEventHandler; - -/** - * 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 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 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 paint(PPaintContext paintContext) { - 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); - } - - protected void updateMarquee(PInputEvent pie) { - super.updateMarquee(pie); - - PBounds b = new PBounds(); - - if (marqueeParent instanceof PCamera) { - b.add(canvasPressPt); - b.add(pie.getCanvasPosition()); - } - else { - b.add(pressPt); - b.add(pie.getPosition()); - } - - marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); - b.reset(); - b.add(pressPt); - b.add(pie.getPosition()); - } - - protected PBounds getMarqueeBounds() { - if (marquee != null) { - return marquee.getBounds(); - } - return new PBounds(); - } - - 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 deleted file mode 100644 index 1734398..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org - * Copyright (c) 1998-2008, University of Maryland - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided - * that the following conditions are met: - * - * Redistributions of source code must retain the above copyright notice, this list of conditions - * and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions - * and the following disclaimer in the documentation and/or other materials provided with the - * distribution. - * - * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its - * contributors may be used to endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -package edu.umd.cs.piccolox.swt; - -import edu.umd.cs.piccolo.PCamera; -import edu.umd.cs.piccolo.PNode; -import edu.umd.cs.piccolo.util.PBounds; -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; - } - - 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 deleted file mode 100644 index 6e1c0d2..0000000 --- a/extras/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java +++ /dev/null @@ -1,550 +0,0 @@ -/** - * Copyright (C) 1998-1999 by University of Maryland, College Park, MD 20742, USA - * All rights reserved. - */ -package edu.umd.cs.piccolox.swt; - -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Paint; -import java.awt.geom.*; -import java.util.*; - -import org.eclipse.swt.graphics.FontMetrics; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.graphics.Point; -import org.eclipse.swt.widgets.Display; - -import edu.umd.cs.piccolo.PNode; -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. - *
- * Warning: Serialized and ZSerialized objects of this class will not be - * compatible with future Jazz releases. The current serialization support is - * appropriate for short term storage or RMI between applications running the - * same version of Jazz. A future release of Jazz will provide support for long - * term persistence. - */ -public class PSWTText extends PNode { - - /** - * Below this magnification render text as 'greek'. - */ - 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; - - /** - * Default font name of text. - */ - static protected final String DEFAULT_FONT_NAME = "Helvetica"; - - /** - * Default font style for text. - */ - static protected final int DEFAULT_FONT_STYLE = Font.PLAIN; - - /** - * Default font size for text. - */ - 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); - - /** - * Default color for text. - */ - static protected final Color DEFAULT_PEN_COLOR = Color.black; - - /** - * Default text when new text area is created. - */ - static protected final String DEFAULT_TEXT = ""; - - /** - * Default padding - */ - static protected final int DEFAULT_PADDING = 2; - - /** - * Below this magnification text is rendered as greek. - */ - protected double greekThreshold = DEFAULT_GREEK_THRESHOLD; - - /** - * Color for greek text. - */ - protected Color greekColor = DEFAULT_GREEK_COLOR; - - /** - * Current pen color. - */ - protected Color penColor = DEFAULT_PEN_COLOR; - - /** - * Current text font. - */ - protected Font font = DEFAULT_FONT; - - /** - * The amount of padding on each side of the text - */ - protected int padding = DEFAULT_PADDING; - - /** - * Each vector element is one line of text. - */ - protected ArrayList lines = new ArrayList(); - - /** - * Translation offset X. - */ - protected double translateX = 0.0; - - /** - * Translation offset Y. - */ - protected double translateY = 0.0; - - /** - * Default constructor for PSWTTest. - */ - public PSWTText() { - this("", DEFAULT_FONT); - } - - /** - * PSWTTest constructor with initial text. - * - * @param str The initial text. - */ - public PSWTText(String str) { - this(str, DEFAULT_FONT); - } - - /** - * PSWTTest constructor with initial text and font. - * - * @param str The initial text. - * @param font The font for this PSWTText component. - */ - public PSWTText(String str, Font font) { - setText(str); - this.font = font; - - recomputeBounds(); - } - - //************************************************************************** - // ** - // - // Get/Set and pairs - // - //************************************************************************** - // * - - /** - * Returns the current pen color. - */ - public Color getPenColor() { - return penColor; - } - - /** - * Sets the current pen color. - * - * @param color use this color. - */ - public void setPenColor(Color color) { - penColor = color; - repaint(); - } - - /** - * Returns the current pen paint. - */ - public Paint getPenPaint() { - return penColor; - } - - /** - * Sets the current pen paint. - * - * @param aPaint use this paint. - */ - public void setPenPaint(Paint aPaint) { - penColor = (Color) aPaint; - } - - /** - * Returns the current background color. - */ - public Color getBackgroundColor() { - return (Color) getPaint(); - } - - /** - * Sets the current background color. - * - * @param color use this color. - */ - public void setBackgroundColor(Color color) { - super.setPaint(color); - } - - /** - * Returns the current greek threshold. Below this magnification text is - * rendered as 'greek'. - */ - public double getGreekThreshold() { - return greekThreshold; - } - - /** - * Sets the current greek threshold. Below this magnification text is - * rendered as 'greek'. - * - * @param threshold compared to renderContext magnification. - */ - public void setGreekThreshold(double threshold) { - greekThreshold = threshold; - repaint(); - } - - /** - * Returns the current 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. - * Single line text does not have any newline characters. - */ - public String getText() { - String line; - String result = new String(); - int lineNum = 0; - - for (Iterator i = lines.iterator(); i.hasNext();) { - if (lineNum > 0) { - result += '\n'; - } - line = (String) i.next(); - result += line; - lineNum++; - } - - return result; - } - - /** - * 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. - * - * @param aFont use this font. - */ - public void setFont(Font aFont) { - font = aFont; - - recomputeBounds(); - } - - /** - * 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) { - int pos = 0; - int index; - boolean done = false; - lines = new ArrayList(); - do { - index = str.indexOf('\n', pos); - if (index == -1) { - lines.add(str); - done = true; - } - else { - lines.add(str.substring(0, index)); - str = str.substring(index + 1); - } - } while (!done); - - recomputeBounds(); - } - - /** - * Set text translation offset X. - * - * @param x the X translation. - */ - public void setTranslateX(double x) { - setTranslation(x, translateY); - } - - /** - * Get the X offset translation. - * - * @return the X translation. - */ - public double getTranslateX() { - return translateX; - } - - /** - * Set text translation offset Y. - * - * @param y the Y translation. - */ - public void setTranslateY(double y) { - setTranslation(translateX, y); - } - - /** - * Get the Y offset translation. - * - * @return the Y translation. - */ - public double getTranslateY() { - return translateY; - } - - /** - * Set the text translation offset to the specified position. - * - * @param x the X-coord of translation - * @param y the Y-coord of translation - */ - public void setTranslation(double x, double y) { - translateX = x; - translateY = y; - - recomputeBounds(); - } - - /** - * Set the text translation offset to point p. - * - * @param p The translation offset. - */ - public void setTranslation(Point2D p) { - setTranslation(p.getX(), p.getY()); - } - - /** - * Get the text translation offset. - * - * @return The translation offset. - */ - public Point2D getTranslation() { - Point2D p = new Point2D.Double(translateX, translateY); - return p; - } - - /** - * 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.
- *
- * @param ppc Contains information about current render.
- */
- public void paint(PPaintContext ppc) {
- Graphics2D g2 = ppc.getGraphics();
- AffineTransform at = null;
- boolean translated = false;
- if (!lines.isEmpty()) {
-
- if ((translateX != 0.0) || (translateY != 0.0)) {
- at = g2.getTransform(); // save transform
- g2.translate(translateX, translateY);
- translated = true;
- }
-
- // 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)) {
- paintAsGreek(ppc);
- }
- else {
- paintAsText(ppc);
- }
- if (translated) {
- g2.setTransform(at); // restore transform
- }
- }
- }
-
- /**
- * Paints this object as greek.
- *
- * @param ppc The graphics context to paint into.
- */
- public void paintAsGreek(PPaintContext ppc) {
- Graphics2D g2 = ppc.getGraphics();
-
- 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.
- *
- * @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());
- Rectangle2D rect = new Rectangle2D.Double(0.0, 0.0, getWidth(), getHeight());
- sg2.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
- }
-
- 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;
-
- // 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);
-
- int lineNum = 0;
- String line;
- double y;
-
- FontMetrics metrics = sg2.getSWTFontMetrics();
-
- 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;
-
- y = (lineNum * metrics.getHeight());
-
- sg2.drawString(line, (double) 0, (double) y);
-
- lineNum++;
- }
-
- 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.
- */
- protected void recomputeBounds() {
- Point bds;
- double lineWidth;
- double maxWidth = 0.0;
- double height;
-
- height = 0.0;
-
- boolean hasText = true;
- 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();
-
- if (!lines.isEmpty() && hasText) {
- String line;
- int lineNum = 0;
- 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;
-
- if (lineWidth > maxWidth) {
- maxWidth = lineWidth;
- }
- // Find the heighest line in the text
- if (lineNum == 0) {
- 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(" ");
- maxWidth = bds.x;
- height = bds.y;
- }
-
- gc.dispose();
-
- // 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();
- }
-
-}
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
deleted file mode 100644
index e21350c..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java
+++ /dev/null
@@ -1,989 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Font;
-import java.awt.FontMetrics;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.GraphicsConfiguration;
-import java.awt.Image;
-import java.awt.Paint;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.Shape;
-import java.awt.Stroke;
-import java.awt.RenderingHints.Key;
-import java.awt.font.FontRenderContext;
-import java.awt.font.GlyphVector;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Arc2D;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.Rectangle2D;
-import java.awt.geom.RoundRectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.BufferedImageOp;
-import java.awt.image.ImageObserver;
-import java.awt.image.RenderedImage;
-import java.awt.image.renderable.RenderableImage;
-import java.text.AttributedCharacterIterator;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.graphics.Device;
-import org.eclipse.swt.graphics.FontData;
-import org.eclipse.swt.graphics.GC;
-
-/**
- * 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
- *
- * 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);
-
- 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;
-
- /**
- * Constructor for SWTGraphics2D.
- */
- public SWTGraphics2D(GC gc, Device device) {
- super();
-
- this.gc = gc;
- this.device = device;
- }
-
- // //////////////////
- // GET 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 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);
- }
-
- 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);
- }
-
- /**
- * 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);
-
- gc.setClipping(SWT_RECT);
- }
-
- /**
- * 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;
- }
-
- // ///////////////////
- // DEVICE SPECIFIC
- // ///////////////////
-
- public GraphicsConfiguration getDeviceConfiguration() {
- return ((Graphics2D) BUFFER.getGraphics()).getDeviceConfiguration();
- }
-
- // //////////////
- // COLOR METHODS
- // //////////////
-
- public Paint getPaint() {
- return getColor();
- }
-
- public void setPaint(Paint paint) {
- if (paint instanceof Color) {
- setColor((Color) paint);
- }
- }
-
- public Color getColor() {
- org.eclipse.swt.graphics.Color color = gc.getForeground();
- Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue());
- return awtColor;
- }
-
- 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 void setColor(org.eclipse.swt.graphics.Color c) {
- gc.setForeground(c);
- }
-
- 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 setBackground(org.eclipse.swt.graphics.Color c) {
- gc.setBackground(c);
- }
-
- public Color getBackground() {
- org.eclipse.swt.graphics.Color color = gc.getBackground();
- Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue());
- return awtColor;
- }
-
- // //////////////
- // FONT METHODS
- // //////////////
-
- public org.eclipse.swt.graphics.Font getSWTFont() {
- return curFont;
- }
-
- public org.eclipse.swt.graphics.FontMetrics getSWTFontMetrics() {
- gc.setFont(curFont);
- return gc.getFontMetrics();
- }
-
- 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 setFont(Font font) {
- String fontString = "name=" + font.getFamily() + ";bold=" + font.isBold() + ";italic=" + font.isItalic()
- + ";size=" + font.getSize();
-
- curFont = getFont(fontString);
- }
-
- public void setFont(org.eclipse.swt.graphics.Font font) {
- curFont = font;
- }
-
- 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;
- }
-
- 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;
- }
-
- // /////////////////////////
- // AFFINE TRANSFORM METHODS
- // /////////////////////////
-
- public void translate(int x, int y) {
- transform.translate(x, y);
- }
-
- public void translate(double tx, double ty) {
- transform.translate(tx, ty);
- }
-
- public void rotate(double theta) {
- transform.rotate(theta);
- }
-
- public void rotate(double theta, double x, double y) {
- transform.rotate(theta, x, y);
- }
-
- public void scale(double sx, double sy) {
- transform.scale(sx, sy);
- }
-
- public void shear(double shx, double shy) {
- transform.shear(shx, shy);
- }
-
- public void transform(AffineTransform Tx) {
- transform.concatenate(Tx);
- }
-
- public void setTransform(AffineTransform Tx) {
- transform = (AffineTransform) Tx.clone();
- }
-
- public AffineTransform getTransform() {
- return (AffineTransform) transform.clone();
- }
-
- // /////////////////////////////
- // 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);
- }
- }
-
- 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);
- }
- }
-
- public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
- int[] ptArray = new int[2 * nPoints];
- for (int i = 0; i < nPoints; i++) {
- PT.setLocation(xPoints[i], yPoints[i]);
- transform.transform(PT, PT);
- ptArray[2 * i] = xPoints[i];
- ptArray[2 * i + 1] = yPoints[i];
- }
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawPolyline(ptArray);
- }
-
- public void drawPolyline(double[] pts) {
- int[] intPts = SWTShapeManager.transform(pts, transform);
- gc.drawPolyline(intPts);
- }
-
- public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
- int[] ptArray = new int[2 * nPoints];
- for (int i = 0; i < nPoints; i++) {
- PT.setLocation(xPoints[i], yPoints[i]);
- transform.transform(PT, PT);
- ptArray[2 * i] = xPoints[i];
- ptArray[2 * i + 1] = yPoints[i];
- }
-
- gc.drawPolygon(ptArray);
- }
-
- public void fillPolygon(double[] pts) {
- int[] intPts = SWTShapeManager.transform(pts, transform);
- gc.fillPolygon(intPts);
- }
-
- public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
- int[] ptArray = new int[2 * nPoints];
- for (int i = 0; i < nPoints; i++) {
- PT.setLocation(xPoints[i], yPoints[i]);
- transform.transform(PT, PT);
- ptArray[2 * i] = xPoints[i];
- ptArray[2 * i + 1] = yPoints[i];
- }
-
- gc.fillPolygon(ptArray);
- }
-
- public void drawLine(int x1, int y1, int x2, int y2) {
- drawLine((double) x1, (double) y1, (double) x2, (double) y2);
- }
-
- public void drawLine(double x1, double y1, double x2, double y2) {
- PT.setLocation(x1, y1);
- transform.transform(PT, PT);
- x1 = (int) PT.getX();
- y1 = (int) PT.getY();
- PT.setLocation(x2, y2);
- transform.transform(PT, PT);
- x2 = (int) PT.getX();
- y2 = (int) PT.getY();
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawLine((int) (x1 + 0.5), (int) (y1 + 0.5), (int) (x2 + 0.5), (int) (y2 + 0.5));
- }
-
- //**************************************************************************
- // *
- // FOR NOW - ASSUME NO ROTATION ON THE TRANSFORM FOR THE FOLLOWING CALLS!
- //**************************************************************************
- // *
-
- public void copyArea(org.eclipse.swt.graphics.Image img, double x, double y) {
- PT.setLocation(x, y);
- transform.transform(PT, PT);
-
- gc.copyArea(img, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5));
- }
-
- public void copyArea(int x, int y, int width, int height, int dx, int dy) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
-
- PT.setLocation(dx, dy);
- transform.transform(PT, PT);
- gc.copyArea((int) RECT.getX(), (int) RECT.getY(), (int) RECT.getWidth(), (int) RECT.getHeight(), (int) PT
- .getX(), (int) PT.getY());
- }
-
- public void drawString(String str, double x, double y) {
- PT.setLocation(x, y);
- transform.transform(PT, PT);
- gc.setFont(getTransformedFont());
- gc.drawString(str, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), true);
- }
-
- public void drawString(String str, int x, int y) {
- drawString(str, (double) x, (double) y);
- }
-
- public void drawString(String str, float x, float y) {
- drawString(str, (double) x, (double) y);
- }
-
- public void drawText(String s, double x, double y) {
- PT.setLocation(x, y);
- transform.transform(PT, PT);
- gc.setFont(getTransformedFont());
- gc.drawText(s, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), true);
- }
-
- public void drawText(String s, double x, double y, int flags) {
- PT.setLocation(x, y);
- transform.transform(PT, PT);
- gc.setFont(getTransformedFont());
- gc.drawText(s, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), flags);
- }
-
- public void drawRect(int x, int y, int width, int height) {
- drawRect((double) x, (double) y, (double) width, (double) height);
- }
-
- public void drawRect(double x, double y, double width, double height) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
- SWTShapeManager.awtToSWT(RECT, SWT_RECT);
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawRectangle(SWT_RECT);
- }
-
- public void fillRect(int x, int y, int width, int height) {
- fillRect((double) x, (double) y, (double) width, (double) height);
- }
-
- public void fillRect(double x, double y, double width, double height) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
- SWTShapeManager.awtToSWT(RECT, SWT_RECT);
-
- gc.fillRectangle(SWT_RECT);
- }
-
- public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
- drawRoundRect((double) x, (double) y, (double) width, (double) height, (double) arcWidth, (double) arcHeight);
- }
-
- public void drawRoundRect(double x, double y, double width, double height, double arcWidth, double arcHeight) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
- x = RECT.getX();
- y = RECT.getY();
- width = RECT.getWidth();
- height = RECT.getHeight();
-
- RECT.setRect(0, 0, arcWidth, arcHeight);
- SWTShapeManager.transform(RECT, transform);
- arcWidth = RECT.getWidth();
- arcHeight = RECT.getHeight();
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawRoundRectangle((int) (x + 0.5), (int) (y + 0.5), (int) (width + 0.5), (int) (height + 0.5),
- (int) (arcWidth + 0.5), (int) (arcHeight + 0.5));
- }
-
- public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
- fillRoundRect((double) x, (double) y, (double) width, (double) height, (double) arcWidth, (double) arcHeight);
- }
-
- public void fillRoundRect(double x, double y, double width, double height, double arcWidth, double arcHeight) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
- x = RECT.getX();
- y = RECT.getY();
- width = RECT.getWidth();
- height = RECT.getHeight();
-
- RECT.setRect(0, 0, arcWidth, arcHeight);
- SWTShapeManager.transform(RECT, transform);
- arcWidth = RECT.getWidth();
- arcHeight = RECT.getHeight();
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.fillRoundRectangle((int) (x + 0.5), (int) (y + 0.5), (int) (width + 0.5), (int) (height + 0.5),
- (int) (arcWidth + 0.5), (int) (arcHeight + 0.5));
- }
-
- public void drawOval(int x, int y, int width, int height) {
- drawOval((double) x, (double) y, (double) width, (double) height);
- }
-
- public void drawOval(double x, double y, double width, double height) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawOval((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
- .getHeight() + 0.5));
- }
-
- public void fillOval(int x, int y, int width, int height) {
- fillOval((double) x, (double) y, (double) width, (double) height);
- }
-
- public void fillOval(double x, double y, double width, double height) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
-
- gc.fillOval((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
- .getHeight() + 0.5));
- }
-
- public void drawArc(int x, int y, int width, int height, int startAngle, int extent) {
- drawArc((double) x, (double) y, (double) width, (double) height, (double) startAngle, (double) extent);
- }
-
- public void drawArc(double x, double y, double width, double height, double startAngle, double extent) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
-
- gc.setLineWidth(getTransformedLineWidth());
- gc.drawArc((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
- .getHeight() + 0.5), (int) (startAngle + 0.5), (int) (startAngle + extent + 0.5));
- }
-
- public void fillArc(int x, int y, int width, int height, int startAngle, int extent) {
- drawArc((double) x, (double) y, (double) width, (double) height, (double) startAngle, (double) extent);
- }
-
- public void fillArc(double x, double y, double width, double height, double startAngle, double extent) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
-
- gc.drawArc((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
- .getHeight() + 0.5), (int) (startAngle + 0.5), (int) (startAngle + extent + 0.5));
- }
-
- // ////////////////////////
- // SWT IMAGE METHODS
- // ////////////////////////
-
- public void drawImage(org.eclipse.swt.graphics.Image image, double x, double y) {
- org.eclipse.swt.graphics.Rectangle bounds = image.getBounds();
- RECT.setRect(x, y, bounds.width, bounds.height);
- SWTShapeManager.transform(RECT, transform);
- SWTShapeManager.awtToSWT(RECT, SWT_RECT);
-
- gc.drawImage(image, 0, 0, bounds.width, bounds.height, SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height);
- }
-
- public void drawImage(org.eclipse.swt.graphics.Image image, int srcX, int srcY, int srcW, int srcH, double destX,
- double destY, double destW, double destH) {
- RECT.setRect(destX, destY, destW, destH);
- SWTShapeManager.transform(RECT, transform);
- SWTShapeManager.awtToSWT(RECT, SWT_RECT);
-
- gc.drawImage(image, srcX, srcY, srcW, srcH, SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height);
- }
-
- // ////////////////////////////
- // OTHER SWT SPECIFIC METHODS
- // ////////////////////////////
-
- public void setLineWidth(double lineWidth) {
- this.lineWidth = lineWidth;
- }
-
- protected int getTransformedLineWidth() {
- LINE_RECT.setRect(0, 0, lineWidth, lineWidth);
- SWTShapeManager.transform(LINE_RECT, transform);
-
- return (int) (Math.max(LINE_RECT.getWidth(), 1) + 0.5);
- }
-
- public void fillGradientRectangle(double x, double y, double width, double height, boolean vertical) {
- RECT.setRect(x, y, width, height);
- SWTShapeManager.transform(RECT, transform);
- SWTShapeManager.awtToSWT(RECT, SWT_RECT);
-
- gc.fillGradientRectangle(SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height, vertical);
- }
-
- public void setXORMode(boolean xOr) {
- gc.setXORMode(xOr);
- }
-
- public int getAdvanceWidth(char ch) {
- org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
- gc.setFont(curFont);
- int width = gc.getAdvanceWidth(ch);
- gc.setFont(scaledFont);
- return width;
- }
-
- public int getCharWidth(char ch) {
- org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
- gc.setFont(curFont);
- int width = gc.getCharWidth(ch);
- gc.setFont(scaledFont);
- return width;
- }
-
- public org.eclipse.swt.graphics.Point stringExtent(String str) {
- org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
- gc.setFont(curFont);
- org.eclipse.swt.graphics.Point extent = gc.stringExtent(str);
- gc.setFont(scaledFont);
- return extent;
- }
-
- public org.eclipse.swt.graphics.Point textExtent(String str) {
- org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
- gc.setFont(curFont);
- org.eclipse.swt.graphics.Point extent = gc.textExtent(str);
- gc.setFont(scaledFont);
- return extent;
- }
-
- public org.eclipse.swt.graphics.Point textExtent(String str, int flags) {
- org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
- gc.setFont(curFont);
- org.eclipse.swt.graphics.Point extent = gc.textExtent(str, flags);
- gc.setFont(scaledFont);
- return extent;
- }
-
- // ///////////////////////////////
- // CURRENTLY UNSUPPORTED METHODS
- // ///////////////////////////////
-
- /**
- * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int)
- */
- public void drawString(AttributedCharacterIterator iterator, int x, int y) {
- }
-
- /**
- * @see java.awt.Graphics2D#drawString(AttributedCharacterIterator, float,
- * float)
- */
- public void drawString(AttributedCharacterIterator iterator, float x, float y) {
- }
-
- /**
- * @see java.awt.Graphics2D#drawGlyphVector(GlyphVector, float, float)
- */
- public void drawGlyphVector(GlyphVector g, float x, float y) {
- }
-
- /**
- * @see java.awt.Graphics2D#hit(Rectangle, Shape, boolean)
- */
- public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics2D#setComposite(Composite)
- */
- public void setComposite(Composite comp) {
- }
-
- /**
- * @see java.awt.Graphics2D#setStroke(Stroke)
- */
- public void setStroke(Stroke s) {
- }
-
- public void setRenderingHint(Key hintKey, Object hintValue) {
- }
-
- public Object getRenderingHint(Key hintKey) {
- return null;
- }
-
- /**
- * @see java.awt.Graphics2D#setRenderingHints(Map)
- */
- public void setRenderingHints(Map hints) {
- }
-
- /**
- * @see java.awt.Graphics2D#addRenderingHints(Map)
- */
- public void addRenderingHints(Map hints) {
- }
-
- /**
- * @see java.awt.Graphics2D#getRenderingHints()
- */
- public RenderingHints getRenderingHints() {
- return null;
- }
-
- /**
- * @see java.awt.Graphics2D#getComposite()
- */
- public Composite getComposite() {
- return null;
- }
-
- /**
- * @see java.awt.Graphics2D#getStroke()
- */
- public Stroke getStroke() {
- return null;
- }
-
- /**
- * @see java.awt.Graphics2D#getFontRenderContext()
- */
- public FontRenderContext getFontRenderContext() {
- return null;
- }
-
- /**
- * @see java.awt.Graphics#create()
- */
- public Graphics create() {
- return null;
- }
-
- /**
- * @see java.awt.Graphics#setPaintMode()
- */
- public void setPaintMode() {
- }
-
- /**
- * @see java.awt.Graphics#setXORMode(Color)
- */
- public void setXORMode(Color c1) {
- }
-
- /**
- * @see java.awt.Graphics#getFontMetrics(Font)
- */
- public FontMetrics getFontMetrics(Font f) {
- return null;
- }
-
- /**
- * @see java.awt.Graphics2D#drawImage(Image, AffineTransform, ImageObserver)
- */
- public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics2D#drawImage(BufferedImage, BufferedImageOp, int,
- * int)
- */
- public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
- }
-
- /**
- * @see java.awt.Graphics2D#drawRenderedImage(RenderedImage,
- * AffineTransform)
- */
- public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
- }
-
- /**
- * @see java.awt.Graphics2D#drawRenderableImage(RenderableImage,
- * AffineTransform)
- */
- public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, int, int,
- * ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, Color, ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, int, int, Color,
- * ImageObserver)
- */
- public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, int, int, int, int,
- * int, int, ImageObserver)
- */
- public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
- ImageObserver observer) {
- return false;
- }
-
- /**
- * @see java.awt.Graphics#drawImage(Image, int, int, int, int, int, int,
- * int, int, Color, ImageObserver)
- */
- public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
- Color bgcolor, ImageObserver observer) {
- return false;
- }
-
- /**
- * DO NOTHING - DISPOSED IN RENDERING CLASS
- */
- public void dispose() {
- }
-
- // ///////////////////////////////
- // CLEAN-UP METHODS
- // ///////////////////////////////
-
- public static void incrementGCCount() {
- CACHE_COUNT++;
- }
-
- public static void decrementGCCount() {
- CACHE_COUNT--;
-
- if (CACHE_COUNT == 0) {
- for (Iterator i = FONT_CACHE.values().iterator(); i.hasNext();) {
- org.eclipse.swt.graphics.Font font = (org.eclipse.swt.graphics.Font) i.next();
- font.dispose();
- }
- for (Iterator i = COLOR_CACHE.values().iterator(); i.hasNext();) {
- org.eclipse.swt.graphics.Color color = (org.eclipse.swt.graphics.Color) i.next();
- color.dispose();
- }
- }
- }
-}
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java
deleted file mode 100644
index 22126b9..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-
-import org.eclipse.swt.graphics.Rectangle;
-
-/**
- * @author Lance Good
- */
-public class SWTShapeManager {
-
- static AffineTransform IDENTITY_XFORM = new AffineTransform();
- static Point2D aPoint = new Point2D.Double();
- static ArrayList segList = new ArrayList();
- static double[] pts = new double[8];
-
- /**
- * Apply the specified transform to the specified rectangle, modifying the
- * rect.
- *
- * @param rect The rectangle to be transformed
- * @param at The transform to use to transform the rectangle
- */
- public static void transform(Rectangle2D rect, AffineTransform at) {
- // First, transform all 4 corners of the rectangle
- pts[0] = rect.getX(); // top left corner
- pts[1] = rect.getY();
- pts[2] = rect.getX() + rect.getWidth(); // top right corner
- pts[3] = rect.getY();
- pts[4] = rect.getX() + rect.getWidth(); // bottom right corner
- pts[5] = rect.getY() + rect.getHeight();
- pts[6] = rect.getX(); // bottom left corner
- pts[7] = rect.getY() + rect.getHeight();
- at.transform(pts, 0, pts, 0, 4);
-
- // Then, find the bounds of those 4 transformed points.
- double minX = pts[0];
- double minY = pts[1];
- double maxX = pts[0];
- double maxY = pts[1];
- int i;
- for (i = 1; i < 4; i++) {
- if (pts[2 * i] < minX) {
- minX = pts[2 * i];
- }
- if (pts[2 * i + 1] < minY) {
- minY = pts[2 * i + 1];
- }
- if (pts[2 * i] > maxX) {
- maxX = pts[2 * i];
- }
- if (pts[2 * i + 1] > maxY) {
- maxY = pts[2 * i + 1];
- }
- }
- rect.setRect(minX, minY, maxX - minX, maxY - minY);
- }
-
- public static void awtToSWT(Rectangle2D aRect, Rectangle sRect) {
- sRect.x = (int) (aRect.getX() + 0.5);
- sRect.y = (int) (aRect.getY() + 0.5);
- sRect.width = (int) (aRect.getWidth() + 0.5);
- sRect.height = (int) (aRect.getHeight() + 0.5);
- }
-
- public static double[] shapeToPolyline(Shape s) {
- segList.clear();
- aPoint.setLocation(0, 0);
-
- PathIterator pi = s.getPathIterator(IDENTITY_XFORM, 0.000000001);
- while (!pi.isDone()) {
- int segType = pi.currentSegment(pts);
- switch (segType) {
- case PathIterator.SEG_MOVETO:
- aPoint.setLocation(pts[0], pts[1]);
- segList.add(new Point2D.Double(pts[0], pts[1]));
- break;
- case PathIterator.SEG_LINETO:
- segList.add(new Point2D.Double(pts[0], pts[1]));
- break;
- case PathIterator.SEG_CLOSE:
- segList.add(new Point2D.Double(aPoint.getX(), aPoint.getY()));
- break;
- }
- pi.next();
- }
-
- double[] polyObj = new double[2 * segList.size()];
- for (int i = 0; i < segList.size(); i++) {
- Point2D p2 = (Point2D) segList.get(i);
- polyObj[2 * i] = (int) (p2.getX() + 0.5);
- polyObj[2 * i + 1] = (int) (p2.getY() + 0.5);
- }
-
- return polyObj;
- }
-
- public static int[] transform(double[] pts, AffineTransform at) {
- int[] intPts = new int[pts.length];
- for (int i = 0; i < pts.length / 2; i++) {
- aPoint.setLocation(pts[2 * i], pts[2 * i + 1]);
- at.transform(aPoint, aPoint);
- intPts[2 * i] = (int) (aPoint.getX() + 0.5);
- intPts[2 * i + 1] = (int) (aPoint.getY() + 0.5);
- }
- return intPts;
- }
-}
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java b/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
deleted file mode 100644
index 8b0881e..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.Timer;
-
-import org.eclipse.swt.widgets.Display;
-
-/**
- * @author Lance Good
- */
-public class SWTTimer extends Timer {
-
- private boolean notify = false;
-
- int initialDelay, delay;
- boolean repeats = true, coalesce = true;
-
- Runnable doPostEvent = null;
-
- Display display = null;
-
- // These fields are maintained by TimerQueue.
- // eventQueued can also be reset by the TimerQueue, but will only ever
- // happen in applet case when TimerQueues thread is destroyed.
- long expirationTime;
- SWTTimer nextTimer;
- boolean running;
-
- /**
- * DoPostEvent is a runnable class that fires actionEvents to the listeners
- * on the EventDispatchThread, via invokeLater.
- *
- * @see #post
- */
- class SWTDoPostEvent implements Runnable {
- public void run() {
-
- if (notify) {
- fireActionPerformed(new ActionEvent(SWTTimer.this, 0, null, System.currentTimeMillis(), 0));
- if (coalesce) {
- cancelEventOverride();
- }
- }
- }
-
- SWTTimer getTimer() {
- return SWTTimer.this;
- }
- }
-
- /**
- * Constructor for SWTTimer.
- *
- * @param delay
- * @param listener
- */
- public SWTTimer(Display display, int delay, ActionListener listener) {
- super(delay, listener);
- this.delay = delay;
- this.initialDelay = delay;
-
- doPostEvent = new SWTDoPostEvent();
- this.display = display;
- }
-
- /**
- * Notifies all listeners that have registered interest for notification on
- * this event type.
- *
- * @param e the action event to fire
- */
- protected void fireActionPerformed(ActionEvent e) {
- // Guaranteed to return a non-null array
- Object[] listeners = listenerList.getListenerList();
-
- // Process the listeners last to first, notifying
- // those that are interested in this event
- for (int i = listeners.length - 2; i >= 0; i -= 2) {
- if (listeners[i] == ActionListener.class) {
- ((ActionListener) listeners[i + 1]).actionPerformed(e);
- }
- }
- }
-
- /**
- * Returns the timer queue.
- */
- SWTTimerQueue timerQueue() {
- return SWTTimerQueue.sharedInstance(display);
- }
-
- /**
- * Sets the Timer
's delay, the number of milliseconds between
- * successive action events.
- *
- * @param delay the delay in milliseconds
- * @see #setInitialDelay
- */
- public void setDelay(int delay) {
- if (delay < 0) {
- throw new IllegalArgumentException("Invalid delay: " + delay);
- }
- else {
- this.delay = delay;
- }
- }
-
- /**
- * Returns the delay, in milliseconds, between firings of action events.
- *
- * @see #setDelay
- * @see #getInitialDelay
- */
- public int getDelay() {
- return delay;
- }
-
- /**
- * Sets the Timer
's initial delay, which by default is the same
- * as the between-event delay. This is used only for the first action event.
- * Subsequent action events are spaced using the delay property.
- *
- * @param initialDelay the delay, in milliseconds, between the invocation of
- * the start
method and the first action event fired
- * by this timer
- *
- * @see #setDelay
- */
- public void setInitialDelay(int initialDelay) {
- if (initialDelay < 0) {
- throw new IllegalArgumentException("Invalid initial delay: " + initialDelay);
- }
- else {
- this.initialDelay = initialDelay;
- }
- }
-
- /**
- * Returns the Timer
's initial delay.
- *
- * @see #setInitialDelay
- * @see #setDelay
- */
- public int getInitialDelay() {
- 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
- */
- public void setRepeats(boolean flag) {
- repeats = flag;
- }
-
- /**
- * 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. Timer
s coalesce events by default.
- *
- * @param flag specify false
to turn off coalescing
- */
- public void setCoalesce(boolean flag) {
- boolean old = coalesce;
- coalesce = flag;
- if (!old && coalesce) {
- // We must do this as otherwise if the Timer once notified
- // in !coalese mode notify will be stuck to true and never
- // become false.
- cancelEventOverride();
- }
- }
-
- /**
- * 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
- * to its listeners.
- *
- * @see #stop
- */
- public void start() {
- 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.
- *
- * @see #start
- */
- public void stop() {
- timerQueue().removeTimer(this);
- cancelEventOverride();
- }
-
- /**
- * 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.
- */
- synchronized void cancelEventOverride() {
- notify = false;
- }
-
- synchronized void postOverride() {
- if (notify == false || !coalesce) {
- notify = true;
- 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
deleted file mode 100644
index a4092ab..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
+++ /dev/null
@@ -1,289 +0,0 @@
-/*
- * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
- * Copyright (c) 1998-2008, University of Maryland
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided
- * that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this list of conditions
- * and the following disclaimer.
- *
- * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
- * and the following disclaimer in the documentation and/or other materials provided with the
- * distribution.
- *
- * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
- * contributors may be used to endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
- * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package edu.umd.cs.piccolox.swt;
-
-import org.eclipse.swt.widgets.Display;
-
-/**
- * @author Lance Good
- */
-public class SWTTimerQueue implements Runnable {
- static SWTTimerQueue instance;
-
- Display display = null;
-
- SWTTimer firstTimer;
- boolean running;
-
- /**
- * Constructor for TimerQueue.
- */
- public SWTTimerQueue(Display display) {
- super();
-
- this.display = display;
-
- // Now start the TimerQueue thread.
- start();
- }
-
- public static SWTTimerQueue sharedInstance(Display 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");
- }
- else {
- Display.getDefault().asyncExec(new Runnable() {
- public void run() {
- Thread timerThread = new Thread(SWTTimerQueue.this, "TimerQueue");
- timerThread.setDaemon(true);
- timerThread.setPriority(Thread.NORM_PRIORITY);
- timerThread.start();
- }
- });
- running = true;
- }
- }
-
- synchronized void stop() {
- running = false;
- notify();
- }
-
- synchronized void addTimer(SWTTimer timer, long expirationTime) {
- SWTTimer previousTimer;
- SWTTimer nextTimer;
-
- // If the Timer is already in the queue, then ignore the add.
- if (timer.running) {
- return;
- }
-
- previousTimer = null;
- 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
- // later so they expire in the order they came in.
-
- while (nextTimer != null) {
- if (nextTimer.expirationTime > expirationTime)
- break;
-
- previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
- }
-
- if (previousTimer == null) {
- firstTimer = timer;
- }
- else {
- previousTimer.nextTimer = timer;
- }
-
- timer.expirationTime = expirationTime;
- timer.nextTimer = nextTimer;
- timer.running = true;
- notify();
- }
-
- synchronized void removeTimer(SWTTimer timer) {
- SWTTimer previousTimer;
- SWTTimer nextTimer;
- boolean found;
-
- if (!timer.running)
- return;
-
- previousTimer = null;
- nextTimer = firstTimer;
- found = false;
-
- while (nextTimer != null) {
- if (nextTimer == timer) {
- found = true;
- break;
- }
-
- previousTimer = nextTimer;
- nextTimer = nextTimer.nextTimer;
- }
-
- if (!found)
- return;
-
- if (previousTimer == null) {
- firstTimer = timer.nextTimer;
- }
- else {
- previousTimer.nextTimer = timer.nextTimer;
- }
-
- timer.expirationTime = 0;
- timer.nextTimer = null;
- 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.
- */
- synchronized long postExpiredTimers() {
- 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;
-
- currentTime = System.currentTimeMillis();
- timeToWait = timer.expirationTime - currentTime;
-
- if (timeToWait <= 0) {
- try {
- timer.postOverride(); // have timer post an event
- }
- catch (SecurityException e) {
- }
-
- // Remove the timer from the queue
- removeTimer(timer);
-
- // This tries to keep the interval uniform at
- // the cost of drift.
- if (timer.isRepeats()) {
- addTimer(timer, currentTime + timer.getDelay());
- }
-
- // Allow other threads to call addTimer() and removeTimer()
- // 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.
-
- try {
- wait(1);
- }
- catch (InterruptedException e) {
- }
- }
- } while (timeToWait <= 0);
-
- return timeToWait;
- }
-
- public synchronized void run() {
- long timeToWait;
-
- try {
- while (running) {
- timeToWait = postExpiredTimers();
- try {
- wait(timeToWait);
- }
- catch (InterruptedException e) {
- }
- }
- }
- catch (ThreadDeath td) {
- running = false;
- // Mark all the timers we contain as not being queued.
- SWTTimer timer = firstTimer;
- while (timer != null) {
- timer.cancelEventOverride();
- timer = timer.nextTimer;
- }
- display.asyncExec(new SWTTimerQueueRestart(display));
- throw td;
- }
- }
-
- public synchronized String toString() {
- StringBuffer buf;
- SWTTimer nextTimer;
-
- buf = new StringBuffer();
- buf.append("TimerQueue (");
-
- nextTimer = firstTimer;
- while (nextTimer != null) {
- buf.append(nextTimer.toString());
-
- nextTimer = nextTimer.nextTimer;
- if (nextTimer != null)
- buf.append(", ");
- }
-
- buf.append(")");
- return buf.toString();
- }
-
- /**
- * 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;
- }
- }
- }
-
-}
diff --git a/extras/src/main/java/edu/umd/cs/piccolox/swt/package.html b/extras/src/main/java/edu/umd/cs/piccolox/swt/package.html
deleted file mode 100644
index 1af36f5..0000000
--- a/extras/src/main/java/edu/umd/cs/piccolox/swt/package.html
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
This package provides a SWT implementation of the core Piccolo library.
- - diff --git a/pom.xml b/pom.xml index 2be4ab5..f3888e1 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@+ * + * @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(); + + 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); + } + + /** + * 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java new file mode 100644 index 0000000..0e14e50 --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTCanvas.java @@ -0,0 +1,620 @@ +/* + * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolox.swt; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.event.InputEvent; +import java.awt.geom.Rectangle2D; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.events.PaintEvent; +import org.eclipse.swt.events.PaintListener; +import org.eclipse.swt.graphics.Cursor; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; + +import edu.umd.cs.piccolo.PCamera; +import edu.umd.cs.piccolo.PComponent; +import edu.umd.cs.piccolo.PLayer; +import edu.umd.cs.piccolo.PRoot; +import edu.umd.cs.piccolo.event.PInputEventListener; +import edu.umd.cs.piccolo.event.PPanEventHandler; +import edu.umd.cs.piccolo.event.PZoomEventHandler; +import edu.umd.cs.piccolo.util.PBounds; +import edu.umd.cs.piccolo.util.PDebug; +import edu.umd.cs.piccolo.util.PPaintContext; +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. + *
+ * + * @version 1.0 + * @author Jesse Grosjean + */ +public class PSWTCanvas extends Composite implements PComponent { + + public static PSWTCanvas CURRENT_CANVAS = null; + + 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. + // **************************************************************** + + /** + * 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; + } + + /** + * 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)); + } + } + + /** + * Return root for this canvas. + */ + public PRoot getRoot() { + return camera.getRoot(); + } + + /** + * Return layer for this canvas. + */ + public PLayer getLayer() { + return camera.getLayer(0); + } + + /** + * 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(); + + r.addChild(c); + r.addChild(l); + c.addLayer(l); + + return c; + } + + // **************************************************************** + // Painting + // **************************************************************** + + /** + * 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(); + } + + /** + * 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java new file mode 100644 index 0000000..5799e04 --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTHandle.java @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolox.swt; + +import java.awt.Color; +import java.awt.Shape; +import java.awt.event.InputEvent; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Point2D; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.io.ObjectInputStream; + +import edu.umd.cs.piccolo.PCamera; +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.event.PDragSequenceEventHandler; +import edu.umd.cs.piccolo.event.PInputEvent; +import edu.umd.cs.piccolo.event.PInputEventFilter; +import edu.umd.cs.piccolo.util.PBounds; +import edu.umd.cs.piccolo.util.PDimension; +import edu.umd.cs.piccolox.util.PLocator; +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. + *
+ * + * @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; + + /** + * 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(); + } + + 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); + } + }; + + 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java new file mode 100644 index 0000000..a3d4dd6 --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTImage.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolox.swt; + +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Rectangle; + +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.nodes.PImage; +import edu.umd.cs.piccolo.util.PBounds; +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. + *
+ *
+ * @version 1.0
+ * @author Jesse Grosjean
+ */
+public class PSWTImage extends PNode {
+
+ private transient PSWTCanvas canvas;
+
+ private transient Image image;
+
+ 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);
+ }
+
+ 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;
+ }
+
+ /**
+ * 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));
+ }
+
+ /**
+ * 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);
+ }
+
+ 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java
new file mode 100644
index 0000000..4a1b0b1
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTKeyEvent.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.Component;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Overridden to wrap an SWT KeyEvent
+ *
+ * @author Lance Good
+ */
+public class PSWTKeyEvent extends KeyEvent {
+
+ 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;
+ }
+
+ public Object getSource() {
+ return swtEvent.getSource();
+ }
+
+ public boolean isShiftDown() {
+ return (swtEvent.stateMask & SWT.SHIFT) != 0;
+ }
+
+ 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;
+ }
+ }
+
+ 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java
new file mode 100644
index 0000000..2a45dbc
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTMouseEvent.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.Component;
+import java.awt.event.InputEvent;
+import java.awt.event.MouseEvent;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Widget;
+
+/**
+ * Overridden to wrap an SWT MouseEvent
+ *
+ * @author Lance Good
+ */
+public class PSWTMouseEvent extends MouseEvent {
+
+ static Component fakeSrc = new Component() {
+ };
+
+ protected org.eclipse.swt.events.MouseEvent swtEvent;
+
+ protected int clickCount;
+
+ 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;
+ }
+
+ public Object getSource() {
+ return swtEvent.getSource();
+ }
+
+ 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;
+ }
+ }
+
+ public boolean isShiftDown() {
+ return (swtEvent.stateMask & SWT.SHIFT) != 0;
+ }
+
+ 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java
new file mode 100644
index 0000000..5253f7d
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTPath.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Paint;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Line2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+
+import edu.umd.cs.piccolo.PNode;
+import edu.umd.cs.piccolo.nodes.PPath;
+import edu.umd.cs.piccolo.util.PAffineTransform;
+import edu.umd.cs.piccolo.util.PBounds;
+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.
+ *
+ * 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 + * 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;
+
+ boolean updatingBoundsFromPath;
+ Shape origShape;
+ Shape shape;
+
+ PAffineTransform internalXForm;
+ AffineTransform inverseXForm;
+
+ double[] shapePts;
+
+ 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;
+ }
+
+ 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;
+ }
+
+ public PSWTPath(Shape aShape) {
+ this();
+ setShape(aShape);
+ }
+
+ // ****************************************************************
+ // Stroke
+ // ****************************************************************
+
+ public Paint getStrokePaint() {
+ return strokePaint;
+ }
+
+ 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();
+
+ 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java
new file mode 100644
index 0000000..5b27d25
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTRoot.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.event.ActionListener;
+import javax.swing.Timer;
+
+import org.eclipse.swt.widgets.Composite;
+
+import edu.umd.cs.piccolo.PRoot;
+
+/**
+ * PSWTRoot is a subclass of PRoot that is designed to work in the SWT
+ * environment. In particular it uses SWTTimers and the SWT event dispatch
+ * 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; + } + + public Timer createTimer(int delay, ActionListener listener) { + return new SWTTimer(composite.getDisplay(), delay, listener); + } + + public void scheduleProcessInputsIfNeeded() { + if (!Thread.currentThread().equals(composite.getDisplay().getThread())) { + return; + } + + if (!processInputsScheduled && !processingInputs + && (getFullBoundsInvalid() || getChildBoundsInvalid() || getPaintInvalid() || getChildPaintInvalid())) { + + processInputsScheduled = true; + composite.getDisplay().asyncExec(new Runnable() { + public void run() { + processInputs(); + processInputsScheduled = false; + } + }); + } + } +} diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java new file mode 100644 index 0000000..9f67a3e --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTSelectionEventHandler.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolox.swt; + +import java.awt.Color; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.List; + +import org.eclipse.swt.SWT; + +import edu.umd.cs.piccolo.PCamera; +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.event.PInputEvent; +import edu.umd.cs.piccolo.util.PBounds; +import edu.umd.cs.piccolo.util.PPaintContext; +import edu.umd.cs.piccolox.event.PSelectionEventHandler; + +/** + * 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 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 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 paint(PPaintContext paintContext) { + 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); + } + + protected void updateMarquee(PInputEvent pie) { + super.updateMarquee(pie); + + PBounds b = new PBounds(); + + if (marqueeParent instanceof PCamera) { + b.add(canvasPressPt); + b.add(pie.getCanvasPosition()); + } + else { + b.add(pressPt); + b.add(pie.getPosition()); + } + + marquee.setPathToRectangle((float) b.x, (float) b.y, (float) b.width, (float) b.height); + b.reset(); + b.add(pressPt); + b.add(pie.getPosition()); + } + + protected PBounds getMarqueeBounds() { + if (marquee != null) { + return marquee.getBounds(); + } + return new PBounds(); + } + + 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java new file mode 100644 index 0000000..1734398 --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTStickyHandleManager.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org + * Copyright (c) 1998-2008, University of Maryland + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this list of conditions + * and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + * and the following disclaimer in the documentation and/or other materials provided with the + * distribution. + * + * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its + * contributors may be used to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package edu.umd.cs.piccolox.swt; + +import edu.umd.cs.piccolo.PCamera; +import edu.umd.cs.piccolo.PNode; +import edu.umd.cs.piccolo.util.PBounds; +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; + } + + 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/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java new file mode 100644 index 0000000..6e1c0d2 --- /dev/null +++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/PSWTText.java @@ -0,0 +1,550 @@ +/** + * Copyright (C) 1998-1999 by University of Maryland, College Park, MD 20742, USA + * All rights reserved. + */ +package edu.umd.cs.piccolox.swt; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.geom.*; +import java.util.*; + +import org.eclipse.swt.graphics.FontMetrics; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; + +import edu.umd.cs.piccolo.PNode; +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. + *
+ * Warning: Serialized and ZSerialized objects of this class will not be + * compatible with future Jazz releases. The current serialization support is + * appropriate for short term storage or RMI between applications running the + * same version of Jazz. A future release of Jazz will provide support for long + * term persistence. + */ +public class PSWTText extends PNode { + + /** + * Below this magnification render text as 'greek'. + */ + 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; + + /** + * Default font name of text. + */ + static protected final String DEFAULT_FONT_NAME = "Helvetica"; + + /** + * Default font style for text. + */ + static protected final int DEFAULT_FONT_STYLE = Font.PLAIN; + + /** + * Default font size for text. + */ + 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); + + /** + * Default color for text. + */ + static protected final Color DEFAULT_PEN_COLOR = Color.black; + + /** + * Default text when new text area is created. + */ + static protected final String DEFAULT_TEXT = ""; + + /** + * Default padding + */ + static protected final int DEFAULT_PADDING = 2; + + /** + * Below this magnification text is rendered as greek. + */ + protected double greekThreshold = DEFAULT_GREEK_THRESHOLD; + + /** + * Color for greek text. + */ + protected Color greekColor = DEFAULT_GREEK_COLOR; + + /** + * Current pen color. + */ + protected Color penColor = DEFAULT_PEN_COLOR; + + /** + * Current text font. + */ + protected Font font = DEFAULT_FONT; + + /** + * The amount of padding on each side of the text + */ + protected int padding = DEFAULT_PADDING; + + /** + * Each vector element is one line of text. + */ + protected ArrayList lines = new ArrayList(); + + /** + * Translation offset X. + */ + protected double translateX = 0.0; + + /** + * Translation offset Y. + */ + protected double translateY = 0.0; + + /** + * Default constructor for PSWTTest. + */ + public PSWTText() { + this("", DEFAULT_FONT); + } + + /** + * PSWTTest constructor with initial text. + * + * @param str The initial text. + */ + public PSWTText(String str) { + this(str, DEFAULT_FONT); + } + + /** + * PSWTTest constructor with initial text and font. + * + * @param str The initial text. + * @param font The font for this PSWTText component. + */ + public PSWTText(String str, Font font) { + setText(str); + this.font = font; + + recomputeBounds(); + } + + //************************************************************************** + // ** + // + // Get/Set and pairs + // + //************************************************************************** + // * + + /** + * Returns the current pen color. + */ + public Color getPenColor() { + return penColor; + } + + /** + * Sets the current pen color. + * + * @param color use this color. + */ + public void setPenColor(Color color) { + penColor = color; + repaint(); + } + + /** + * Returns the current pen paint. + */ + public Paint getPenPaint() { + return penColor; + } + + /** + * Sets the current pen paint. + * + * @param aPaint use this paint. + */ + public void setPenPaint(Paint aPaint) { + penColor = (Color) aPaint; + } + + /** + * Returns the current background color. + */ + public Color getBackgroundColor() { + return (Color) getPaint(); + } + + /** + * Sets the current background color. + * + * @param color use this color. + */ + public void setBackgroundColor(Color color) { + super.setPaint(color); + } + + /** + * Returns the current greek threshold. Below this magnification text is + * rendered as 'greek'. + */ + public double getGreekThreshold() { + return greekThreshold; + } + + /** + * Sets the current greek threshold. Below this magnification text is + * rendered as 'greek'. + * + * @param threshold compared to renderContext magnification. + */ + public void setGreekThreshold(double threshold) { + greekThreshold = threshold; + repaint(); + } + + /** + * Returns the current 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. + * Single line text does not have any newline characters. + */ + public String getText() { + String line; + String result = new String(); + int lineNum = 0; + + for (Iterator i = lines.iterator(); i.hasNext();) { + if (lineNum > 0) { + result += '\n'; + } + line = (String) i.next(); + result += line; + lineNum++; + } + + return result; + } + + /** + * 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. + * + * @param aFont use this font. + */ + public void setFont(Font aFont) { + font = aFont; + + recomputeBounds(); + } + + /** + * 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) { + int pos = 0; + int index; + boolean done = false; + lines = new ArrayList(); + do { + index = str.indexOf('\n', pos); + if (index == -1) { + lines.add(str); + done = true; + } + else { + lines.add(str.substring(0, index)); + str = str.substring(index + 1); + } + } while (!done); + + recomputeBounds(); + } + + /** + * Set text translation offset X. + * + * @param x the X translation. + */ + public void setTranslateX(double x) { + setTranslation(x, translateY); + } + + /** + * Get the X offset translation. + * + * @return the X translation. + */ + public double getTranslateX() { + return translateX; + } + + /** + * Set text translation offset Y. + * + * @param y the Y translation. + */ + public void setTranslateY(double y) { + setTranslation(translateX, y); + } + + /** + * Get the Y offset translation. + * + * @return the Y translation. + */ + public double getTranslateY() { + return translateY; + } + + /** + * Set the text translation offset to the specified position. + * + * @param x the X-coord of translation + * @param y the Y-coord of translation + */ + public void setTranslation(double x, double y) { + translateX = x; + translateY = y; + + recomputeBounds(); + } + + /** + * Set the text translation offset to point p. + * + * @param p The translation offset. + */ + public void setTranslation(Point2D p) { + setTranslation(p.getX(), p.getY()); + } + + /** + * Get the text translation offset. + * + * @return The translation offset. + */ + public Point2D getTranslation() { + Point2D p = new Point2D.Double(translateX, translateY); + return p; + } + + /** + * 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.
+ *
+ * @param ppc Contains information about current render.
+ */
+ public void paint(PPaintContext ppc) {
+ Graphics2D g2 = ppc.getGraphics();
+ AffineTransform at = null;
+ boolean translated = false;
+ if (!lines.isEmpty()) {
+
+ if ((translateX != 0.0) || (translateY != 0.0)) {
+ at = g2.getTransform(); // save transform
+ g2.translate(translateX, translateY);
+ translated = true;
+ }
+
+ // 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)) {
+ paintAsGreek(ppc);
+ }
+ else {
+ paintAsText(ppc);
+ }
+ if (translated) {
+ g2.setTransform(at); // restore transform
+ }
+ }
+ }
+
+ /**
+ * Paints this object as greek.
+ *
+ * @param ppc The graphics context to paint into.
+ */
+ public void paintAsGreek(PPaintContext ppc) {
+ Graphics2D g2 = ppc.getGraphics();
+
+ 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.
+ *
+ * @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());
+ Rectangle2D rect = new Rectangle2D.Double(0.0, 0.0, getWidth(), getHeight());
+ sg2.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
+ }
+
+ 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;
+
+ // 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);
+
+ int lineNum = 0;
+ String line;
+ double y;
+
+ FontMetrics metrics = sg2.getSWTFontMetrics();
+
+ 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;
+
+ y = (lineNum * metrics.getHeight());
+
+ sg2.drawString(line, (double) 0, (double) y);
+
+ lineNum++;
+ }
+
+ 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.
+ */
+ protected void recomputeBounds() {
+ Point bds;
+ double lineWidth;
+ double maxWidth = 0.0;
+ double height;
+
+ height = 0.0;
+
+ boolean hasText = true;
+ 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();
+
+ if (!lines.isEmpty() && hasText) {
+ String line;
+ int lineNum = 0;
+ 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;
+
+ if (lineWidth > maxWidth) {
+ maxWidth = lineWidth;
+ }
+ // Find the heighest line in the text
+ if (lineNum == 0) {
+ 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(" ");
+ maxWidth = bds.x;
+ height = bds.y;
+ }
+
+ gc.dispose();
+
+ // 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();
+ }
+
+}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java
new file mode 100644
index 0000000..e21350c
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTGraphics2D.java
@@ -0,0 +1,989 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GraphicsConfiguration;
+import java.awt.Image;
+import java.awt.Paint;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.RenderingHints.Key;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Device;
+import org.eclipse.swt.graphics.FontData;
+import org.eclipse.swt.graphics.GC;
+
+/**
+ * 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
+ *
+ * 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);
+
+ 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;
+
+ /**
+ * Constructor for SWTGraphics2D.
+ */
+ public SWTGraphics2D(GC gc, Device device) {
+ super();
+
+ this.gc = gc;
+ this.device = device;
+ }
+
+ // //////////////////
+ // GET 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 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);
+ }
+
+ 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);
+ }
+
+ /**
+ * 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);
+
+ gc.setClipping(SWT_RECT);
+ }
+
+ /**
+ * 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;
+ }
+
+ // ///////////////////
+ // DEVICE SPECIFIC
+ // ///////////////////
+
+ public GraphicsConfiguration getDeviceConfiguration() {
+ return ((Graphics2D) BUFFER.getGraphics()).getDeviceConfiguration();
+ }
+
+ // //////////////
+ // COLOR METHODS
+ // //////////////
+
+ public Paint getPaint() {
+ return getColor();
+ }
+
+ public void setPaint(Paint paint) {
+ if (paint instanceof Color) {
+ setColor((Color) paint);
+ }
+ }
+
+ public Color getColor() {
+ org.eclipse.swt.graphics.Color color = gc.getForeground();
+ Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue());
+ return awtColor;
+ }
+
+ 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 void setColor(org.eclipse.swt.graphics.Color c) {
+ gc.setForeground(c);
+ }
+
+ 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 setBackground(org.eclipse.swt.graphics.Color c) {
+ gc.setBackground(c);
+ }
+
+ public Color getBackground() {
+ org.eclipse.swt.graphics.Color color = gc.getBackground();
+ Color awtColor = new Color(color.getRed(), color.getGreen(), color.getBlue());
+ return awtColor;
+ }
+
+ // //////////////
+ // FONT METHODS
+ // //////////////
+
+ public org.eclipse.swt.graphics.Font getSWTFont() {
+ return curFont;
+ }
+
+ public org.eclipse.swt.graphics.FontMetrics getSWTFontMetrics() {
+ gc.setFont(curFont);
+ return gc.getFontMetrics();
+ }
+
+ 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 setFont(Font font) {
+ String fontString = "name=" + font.getFamily() + ";bold=" + font.isBold() + ";italic=" + font.isItalic()
+ + ";size=" + font.getSize();
+
+ curFont = getFont(fontString);
+ }
+
+ public void setFont(org.eclipse.swt.graphics.Font font) {
+ curFont = font;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ // /////////////////////////
+ // AFFINE TRANSFORM METHODS
+ // /////////////////////////
+
+ public void translate(int x, int y) {
+ transform.translate(x, y);
+ }
+
+ public void translate(double tx, double ty) {
+ transform.translate(tx, ty);
+ }
+
+ public void rotate(double theta) {
+ transform.rotate(theta);
+ }
+
+ public void rotate(double theta, double x, double y) {
+ transform.rotate(theta, x, y);
+ }
+
+ public void scale(double sx, double sy) {
+ transform.scale(sx, sy);
+ }
+
+ public void shear(double shx, double shy) {
+ transform.shear(shx, shy);
+ }
+
+ public void transform(AffineTransform Tx) {
+ transform.concatenate(Tx);
+ }
+
+ public void setTransform(AffineTransform Tx) {
+ transform = (AffineTransform) Tx.clone();
+ }
+
+ public AffineTransform getTransform() {
+ return (AffineTransform) transform.clone();
+ }
+
+ // /////////////////////////////
+ // 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);
+ }
+ }
+
+ 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);
+ }
+ }
+
+ public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
+ int[] ptArray = new int[2 * nPoints];
+ for (int i = 0; i < nPoints; i++) {
+ PT.setLocation(xPoints[i], yPoints[i]);
+ transform.transform(PT, PT);
+ ptArray[2 * i] = xPoints[i];
+ ptArray[2 * i + 1] = yPoints[i];
+ }
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawPolyline(ptArray);
+ }
+
+ public void drawPolyline(double[] pts) {
+ int[] intPts = SWTShapeManager.transform(pts, transform);
+ gc.drawPolyline(intPts);
+ }
+
+ public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+ int[] ptArray = new int[2 * nPoints];
+ for (int i = 0; i < nPoints; i++) {
+ PT.setLocation(xPoints[i], yPoints[i]);
+ transform.transform(PT, PT);
+ ptArray[2 * i] = xPoints[i];
+ ptArray[2 * i + 1] = yPoints[i];
+ }
+
+ gc.drawPolygon(ptArray);
+ }
+
+ public void fillPolygon(double[] pts) {
+ int[] intPts = SWTShapeManager.transform(pts, transform);
+ gc.fillPolygon(intPts);
+ }
+
+ public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+ int[] ptArray = new int[2 * nPoints];
+ for (int i = 0; i < nPoints; i++) {
+ PT.setLocation(xPoints[i], yPoints[i]);
+ transform.transform(PT, PT);
+ ptArray[2 * i] = xPoints[i];
+ ptArray[2 * i + 1] = yPoints[i];
+ }
+
+ gc.fillPolygon(ptArray);
+ }
+
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ drawLine((double) x1, (double) y1, (double) x2, (double) y2);
+ }
+
+ public void drawLine(double x1, double y1, double x2, double y2) {
+ PT.setLocation(x1, y1);
+ transform.transform(PT, PT);
+ x1 = (int) PT.getX();
+ y1 = (int) PT.getY();
+ PT.setLocation(x2, y2);
+ transform.transform(PT, PT);
+ x2 = (int) PT.getX();
+ y2 = (int) PT.getY();
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawLine((int) (x1 + 0.5), (int) (y1 + 0.5), (int) (x2 + 0.5), (int) (y2 + 0.5));
+ }
+
+ //**************************************************************************
+ // *
+ // FOR NOW - ASSUME NO ROTATION ON THE TRANSFORM FOR THE FOLLOWING CALLS!
+ //**************************************************************************
+ // *
+
+ public void copyArea(org.eclipse.swt.graphics.Image img, double x, double y) {
+ PT.setLocation(x, y);
+ transform.transform(PT, PT);
+
+ gc.copyArea(img, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5));
+ }
+
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+
+ PT.setLocation(dx, dy);
+ transform.transform(PT, PT);
+ gc.copyArea((int) RECT.getX(), (int) RECT.getY(), (int) RECT.getWidth(), (int) RECT.getHeight(), (int) PT
+ .getX(), (int) PT.getY());
+ }
+
+ public void drawString(String str, double x, double y) {
+ PT.setLocation(x, y);
+ transform.transform(PT, PT);
+ gc.setFont(getTransformedFont());
+ gc.drawString(str, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), true);
+ }
+
+ public void drawString(String str, int x, int y) {
+ drawString(str, (double) x, (double) y);
+ }
+
+ public void drawString(String str, float x, float y) {
+ drawString(str, (double) x, (double) y);
+ }
+
+ public void drawText(String s, double x, double y) {
+ PT.setLocation(x, y);
+ transform.transform(PT, PT);
+ gc.setFont(getTransformedFont());
+ gc.drawText(s, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), true);
+ }
+
+ public void drawText(String s, double x, double y, int flags) {
+ PT.setLocation(x, y);
+ transform.transform(PT, PT);
+ gc.setFont(getTransformedFont());
+ gc.drawText(s, (int) (PT.getX() + 0.5), (int) (PT.getY() + 0.5), flags);
+ }
+
+ public void drawRect(int x, int y, int width, int height) {
+ drawRect((double) x, (double) y, (double) width, (double) height);
+ }
+
+ public void drawRect(double x, double y, double width, double height) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+ SWTShapeManager.awtToSWT(RECT, SWT_RECT);
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawRectangle(SWT_RECT);
+ }
+
+ public void fillRect(int x, int y, int width, int height) {
+ fillRect((double) x, (double) y, (double) width, (double) height);
+ }
+
+ public void fillRect(double x, double y, double width, double height) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+ SWTShapeManager.awtToSWT(RECT, SWT_RECT);
+
+ gc.fillRectangle(SWT_RECT);
+ }
+
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ drawRoundRect((double) x, (double) y, (double) width, (double) height, (double) arcWidth, (double) arcHeight);
+ }
+
+ public void drawRoundRect(double x, double y, double width, double height, double arcWidth, double arcHeight) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+ x = RECT.getX();
+ y = RECT.getY();
+ width = RECT.getWidth();
+ height = RECT.getHeight();
+
+ RECT.setRect(0, 0, arcWidth, arcHeight);
+ SWTShapeManager.transform(RECT, transform);
+ arcWidth = RECT.getWidth();
+ arcHeight = RECT.getHeight();
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawRoundRectangle((int) (x + 0.5), (int) (y + 0.5), (int) (width + 0.5), (int) (height + 0.5),
+ (int) (arcWidth + 0.5), (int) (arcHeight + 0.5));
+ }
+
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) {
+ fillRoundRect((double) x, (double) y, (double) width, (double) height, (double) arcWidth, (double) arcHeight);
+ }
+
+ public void fillRoundRect(double x, double y, double width, double height, double arcWidth, double arcHeight) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+ x = RECT.getX();
+ y = RECT.getY();
+ width = RECT.getWidth();
+ height = RECT.getHeight();
+
+ RECT.setRect(0, 0, arcWidth, arcHeight);
+ SWTShapeManager.transform(RECT, transform);
+ arcWidth = RECT.getWidth();
+ arcHeight = RECT.getHeight();
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.fillRoundRectangle((int) (x + 0.5), (int) (y + 0.5), (int) (width + 0.5), (int) (height + 0.5),
+ (int) (arcWidth + 0.5), (int) (arcHeight + 0.5));
+ }
+
+ public void drawOval(int x, int y, int width, int height) {
+ drawOval((double) x, (double) y, (double) width, (double) height);
+ }
+
+ public void drawOval(double x, double y, double width, double height) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawOval((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
+ .getHeight() + 0.5));
+ }
+
+ public void fillOval(int x, int y, int width, int height) {
+ fillOval((double) x, (double) y, (double) width, (double) height);
+ }
+
+ public void fillOval(double x, double y, double width, double height) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+
+ gc.fillOval((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
+ .getHeight() + 0.5));
+ }
+
+ public void drawArc(int x, int y, int width, int height, int startAngle, int extent) {
+ drawArc((double) x, (double) y, (double) width, (double) height, (double) startAngle, (double) extent);
+ }
+
+ public void drawArc(double x, double y, double width, double height, double startAngle, double extent) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+
+ gc.setLineWidth(getTransformedLineWidth());
+ gc.drawArc((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
+ .getHeight() + 0.5), (int) (startAngle + 0.5), (int) (startAngle + extent + 0.5));
+ }
+
+ public void fillArc(int x, int y, int width, int height, int startAngle, int extent) {
+ drawArc((double) x, (double) y, (double) width, (double) height, (double) startAngle, (double) extent);
+ }
+
+ public void fillArc(double x, double y, double width, double height, double startAngle, double extent) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+
+ gc.drawArc((int) (RECT.getX() + 0.5), (int) (RECT.getY() + 0.5), (int) (RECT.getWidth() + 0.5), (int) (RECT
+ .getHeight() + 0.5), (int) (startAngle + 0.5), (int) (startAngle + extent + 0.5));
+ }
+
+ // ////////////////////////
+ // SWT IMAGE METHODS
+ // ////////////////////////
+
+ public void drawImage(org.eclipse.swt.graphics.Image image, double x, double y) {
+ org.eclipse.swt.graphics.Rectangle bounds = image.getBounds();
+ RECT.setRect(x, y, bounds.width, bounds.height);
+ SWTShapeManager.transform(RECT, transform);
+ SWTShapeManager.awtToSWT(RECT, SWT_RECT);
+
+ gc.drawImage(image, 0, 0, bounds.width, bounds.height, SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height);
+ }
+
+ public void drawImage(org.eclipse.swt.graphics.Image image, int srcX, int srcY, int srcW, int srcH, double destX,
+ double destY, double destW, double destH) {
+ RECT.setRect(destX, destY, destW, destH);
+ SWTShapeManager.transform(RECT, transform);
+ SWTShapeManager.awtToSWT(RECT, SWT_RECT);
+
+ gc.drawImage(image, srcX, srcY, srcW, srcH, SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height);
+ }
+
+ // ////////////////////////////
+ // OTHER SWT SPECIFIC METHODS
+ // ////////////////////////////
+
+ public void setLineWidth(double lineWidth) {
+ this.lineWidth = lineWidth;
+ }
+
+ protected int getTransformedLineWidth() {
+ LINE_RECT.setRect(0, 0, lineWidth, lineWidth);
+ SWTShapeManager.transform(LINE_RECT, transform);
+
+ return (int) (Math.max(LINE_RECT.getWidth(), 1) + 0.5);
+ }
+
+ public void fillGradientRectangle(double x, double y, double width, double height, boolean vertical) {
+ RECT.setRect(x, y, width, height);
+ SWTShapeManager.transform(RECT, transform);
+ SWTShapeManager.awtToSWT(RECT, SWT_RECT);
+
+ gc.fillGradientRectangle(SWT_RECT.x, SWT_RECT.y, SWT_RECT.width, SWT_RECT.height, vertical);
+ }
+
+ public void setXORMode(boolean xOr) {
+ gc.setXORMode(xOr);
+ }
+
+ public int getAdvanceWidth(char ch) {
+ org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
+ gc.setFont(curFont);
+ int width = gc.getAdvanceWidth(ch);
+ gc.setFont(scaledFont);
+ return width;
+ }
+
+ public int getCharWidth(char ch) {
+ org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
+ gc.setFont(curFont);
+ int width = gc.getCharWidth(ch);
+ gc.setFont(scaledFont);
+ return width;
+ }
+
+ public org.eclipse.swt.graphics.Point stringExtent(String str) {
+ org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
+ gc.setFont(curFont);
+ org.eclipse.swt.graphics.Point extent = gc.stringExtent(str);
+ gc.setFont(scaledFont);
+ return extent;
+ }
+
+ public org.eclipse.swt.graphics.Point textExtent(String str) {
+ org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
+ gc.setFont(curFont);
+ org.eclipse.swt.graphics.Point extent = gc.textExtent(str);
+ gc.setFont(scaledFont);
+ return extent;
+ }
+
+ public org.eclipse.swt.graphics.Point textExtent(String str, int flags) {
+ org.eclipse.swt.graphics.Font scaledFont = gc.getFont();
+ gc.setFont(curFont);
+ org.eclipse.swt.graphics.Point extent = gc.textExtent(str, flags);
+ gc.setFont(scaledFont);
+ return extent;
+ }
+
+ // ///////////////////////////////
+ // CURRENTLY UNSUPPORTED METHODS
+ // ///////////////////////////////
+
+ /**
+ * @see java.awt.Graphics#drawString(AttributedCharacterIterator, int, int)
+ */
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawString(AttributedCharacterIterator, float,
+ * float)
+ */
+ public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawGlyphVector(GlyphVector, float, float)
+ */
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#hit(Rectangle, Shape, boolean)
+ */
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#setComposite(Composite)
+ */
+ public void setComposite(Composite comp) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#setStroke(Stroke)
+ */
+ public void setStroke(Stroke s) {
+ }
+
+ public void setRenderingHint(Key hintKey, Object hintValue) {
+ }
+
+ public Object getRenderingHint(Key hintKey) {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#setRenderingHints(Map)
+ */
+ public void setRenderingHints(Map hints) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#addRenderingHints(Map)
+ */
+ public void addRenderingHints(Map hints) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#getRenderingHints()
+ */
+ public RenderingHints getRenderingHints() {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#getComposite()
+ */
+ public Composite getComposite() {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#getStroke()
+ */
+ public Stroke getStroke() {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#getFontRenderContext()
+ */
+ public FontRenderContext getFontRenderContext() {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics#create()
+ */
+ public Graphics create() {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics#setPaintMode()
+ */
+ public void setPaintMode() {
+ }
+
+ /**
+ * @see java.awt.Graphics#setXORMode(Color)
+ */
+ public void setXORMode(Color c1) {
+ }
+
+ /**
+ * @see java.awt.Graphics#getFontMetrics(Font)
+ */
+ public FontMetrics getFontMetrics(Font f) {
+ return null;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawImage(Image, AffineTransform, ImageObserver)
+ */
+ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawImage(BufferedImage, BufferedImageOp, int,
+ * int)
+ */
+ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawRenderedImage(RenderedImage,
+ * AffineTransform)
+ */
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ }
+
+ /**
+ * @see java.awt.Graphics2D#drawRenderableImage(RenderableImage,
+ * AffineTransform)
+ */
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, int, int,
+ * ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, Color, ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, int, int, Color,
+ * ImageObserver)
+ */
+ public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, int, int, int, int,
+ * int, int, ImageObserver)
+ */
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+ ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * @see java.awt.Graphics#drawImage(Image, int, int, int, int, int, int,
+ * int, int, Color, ImageObserver)
+ */
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2,
+ Color bgcolor, ImageObserver observer) {
+ return false;
+ }
+
+ /**
+ * DO NOTHING - DISPOSED IN RENDERING CLASS
+ */
+ public void dispose() {
+ }
+
+ // ///////////////////////////////
+ // CLEAN-UP METHODS
+ // ///////////////////////////////
+
+ public static void incrementGCCount() {
+ CACHE_COUNT++;
+ }
+
+ public static void decrementGCCount() {
+ CACHE_COUNT--;
+
+ if (CACHE_COUNT == 0) {
+ for (Iterator i = FONT_CACHE.values().iterator(); i.hasNext();) {
+ org.eclipse.swt.graphics.Font font = (org.eclipse.swt.graphics.Font) i.next();
+ font.dispose();
+ }
+ for (Iterator i = COLOR_CACHE.values().iterator(); i.hasNext();) {
+ org.eclipse.swt.graphics.Color color = (org.eclipse.swt.graphics.Color) i.next();
+ color.dispose();
+ }
+ }
+ }
+}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java
new file mode 100644
index 0000000..22126b9
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTShapeManager.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+
+import org.eclipse.swt.graphics.Rectangle;
+
+/**
+ * @author Lance Good
+ */
+public class SWTShapeManager {
+
+ static AffineTransform IDENTITY_XFORM = new AffineTransform();
+ static Point2D aPoint = new Point2D.Double();
+ static ArrayList segList = new ArrayList();
+ static double[] pts = new double[8];
+
+ /**
+ * Apply the specified transform to the specified rectangle, modifying the
+ * rect.
+ *
+ * @param rect The rectangle to be transformed
+ * @param at The transform to use to transform the rectangle
+ */
+ public static void transform(Rectangle2D rect, AffineTransform at) {
+ // First, transform all 4 corners of the rectangle
+ pts[0] = rect.getX(); // top left corner
+ pts[1] = rect.getY();
+ pts[2] = rect.getX() + rect.getWidth(); // top right corner
+ pts[3] = rect.getY();
+ pts[4] = rect.getX() + rect.getWidth(); // bottom right corner
+ pts[5] = rect.getY() + rect.getHeight();
+ pts[6] = rect.getX(); // bottom left corner
+ pts[7] = rect.getY() + rect.getHeight();
+ at.transform(pts, 0, pts, 0, 4);
+
+ // Then, find the bounds of those 4 transformed points.
+ double minX = pts[0];
+ double minY = pts[1];
+ double maxX = pts[0];
+ double maxY = pts[1];
+ int i;
+ for (i = 1; i < 4; i++) {
+ if (pts[2 * i] < minX) {
+ minX = pts[2 * i];
+ }
+ if (pts[2 * i + 1] < minY) {
+ minY = pts[2 * i + 1];
+ }
+ if (pts[2 * i] > maxX) {
+ maxX = pts[2 * i];
+ }
+ if (pts[2 * i + 1] > maxY) {
+ maxY = pts[2 * i + 1];
+ }
+ }
+ rect.setRect(minX, minY, maxX - minX, maxY - minY);
+ }
+
+ public static void awtToSWT(Rectangle2D aRect, Rectangle sRect) {
+ sRect.x = (int) (aRect.getX() + 0.5);
+ sRect.y = (int) (aRect.getY() + 0.5);
+ sRect.width = (int) (aRect.getWidth() + 0.5);
+ sRect.height = (int) (aRect.getHeight() + 0.5);
+ }
+
+ public static double[] shapeToPolyline(Shape s) {
+ segList.clear();
+ aPoint.setLocation(0, 0);
+
+ PathIterator pi = s.getPathIterator(IDENTITY_XFORM, 0.000000001);
+ while (!pi.isDone()) {
+ int segType = pi.currentSegment(pts);
+ switch (segType) {
+ case PathIterator.SEG_MOVETO:
+ aPoint.setLocation(pts[0], pts[1]);
+ segList.add(new Point2D.Double(pts[0], pts[1]));
+ break;
+ case PathIterator.SEG_LINETO:
+ segList.add(new Point2D.Double(pts[0], pts[1]));
+ break;
+ case PathIterator.SEG_CLOSE:
+ segList.add(new Point2D.Double(aPoint.getX(), aPoint.getY()));
+ break;
+ }
+ pi.next();
+ }
+
+ double[] polyObj = new double[2 * segList.size()];
+ for (int i = 0; i < segList.size(); i++) {
+ Point2D p2 = (Point2D) segList.get(i);
+ polyObj[2 * i] = (int) (p2.getX() + 0.5);
+ polyObj[2 * i + 1] = (int) (p2.getY() + 0.5);
+ }
+
+ return polyObj;
+ }
+
+ public static int[] transform(double[] pts, AffineTransform at) {
+ int[] intPts = new int[pts.length];
+ for (int i = 0; i < pts.length / 2; i++) {
+ aPoint.setLocation(pts[2 * i], pts[2 * i + 1]);
+ at.transform(aPoint, aPoint);
+ intPts[2 * i] = (int) (aPoint.getX() + 0.5);
+ intPts[2 * i + 1] = (int) (aPoint.getY() + 0.5);
+ }
+ return intPts;
+ }
+}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
new file mode 100644
index 0000000..8b0881e
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimer.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Timer;
+
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * @author Lance Good
+ */
+public class SWTTimer extends Timer {
+
+ private boolean notify = false;
+
+ int initialDelay, delay;
+ boolean repeats = true, coalesce = true;
+
+ Runnable doPostEvent = null;
+
+ Display display = null;
+
+ // These fields are maintained by TimerQueue.
+ // eventQueued can also be reset by the TimerQueue, but will only ever
+ // happen in applet case when TimerQueues thread is destroyed.
+ long expirationTime;
+ SWTTimer nextTimer;
+ boolean running;
+
+ /**
+ * DoPostEvent is a runnable class that fires actionEvents to the listeners
+ * on the EventDispatchThread, via invokeLater.
+ *
+ * @see #post
+ */
+ class SWTDoPostEvent implements Runnable {
+ public void run() {
+
+ if (notify) {
+ fireActionPerformed(new ActionEvent(SWTTimer.this, 0, null, System.currentTimeMillis(), 0));
+ if (coalesce) {
+ cancelEventOverride();
+ }
+ }
+ }
+
+ SWTTimer getTimer() {
+ return SWTTimer.this;
+ }
+ }
+
+ /**
+ * Constructor for SWTTimer.
+ *
+ * @param delay
+ * @param listener
+ */
+ public SWTTimer(Display display, int delay, ActionListener listener) {
+ super(delay, listener);
+ this.delay = delay;
+ this.initialDelay = delay;
+
+ doPostEvent = new SWTDoPostEvent();
+ this.display = display;
+ }
+
+ /**
+ * Notifies all listeners that have registered interest for notification on
+ * this event type.
+ *
+ * @param e the action event to fire
+ */
+ protected void fireActionPerformed(ActionEvent e) {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length - 2; i >= 0; i -= 2) {
+ if (listeners[i] == ActionListener.class) {
+ ((ActionListener) listeners[i + 1]).actionPerformed(e);
+ }
+ }
+ }
+
+ /**
+ * Returns the timer queue.
+ */
+ SWTTimerQueue timerQueue() {
+ return SWTTimerQueue.sharedInstance(display);
+ }
+
+ /**
+ * Sets the Timer
's delay, the number of milliseconds between
+ * successive action events.
+ *
+ * @param delay the delay in milliseconds
+ * @see #setInitialDelay
+ */
+ public void setDelay(int delay) {
+ if (delay < 0) {
+ throw new IllegalArgumentException("Invalid delay: " + delay);
+ }
+ else {
+ this.delay = delay;
+ }
+ }
+
+ /**
+ * Returns the delay, in milliseconds, between firings of action events.
+ *
+ * @see #setDelay
+ * @see #getInitialDelay
+ */
+ public int getDelay() {
+ return delay;
+ }
+
+ /**
+ * Sets the Timer
's initial delay, which by default is the same
+ * as the between-event delay. This is used only for the first action event.
+ * Subsequent action events are spaced using the delay property.
+ *
+ * @param initialDelay the delay, in milliseconds, between the invocation of
+ * the start
method and the first action event fired
+ * by this timer
+ *
+ * @see #setDelay
+ */
+ public void setInitialDelay(int initialDelay) {
+ if (initialDelay < 0) {
+ throw new IllegalArgumentException("Invalid initial delay: " + initialDelay);
+ }
+ else {
+ this.initialDelay = initialDelay;
+ }
+ }
+
+ /**
+ * Returns the Timer
's initial delay.
+ *
+ * @see #setInitialDelay
+ * @see #setDelay
+ */
+ public int getInitialDelay() {
+ 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
+ */
+ public void setRepeats(boolean flag) {
+ repeats = flag;
+ }
+
+ /**
+ * 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. Timer
s coalesce events by default.
+ *
+ * @param flag specify false
to turn off coalescing
+ */
+ public void setCoalesce(boolean flag) {
+ boolean old = coalesce;
+ coalesce = flag;
+ if (!old && coalesce) {
+ // We must do this as otherwise if the Timer once notified
+ // in !coalese mode notify will be stuck to true and never
+ // become false.
+ cancelEventOverride();
+ }
+ }
+
+ /**
+ * 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
+ * to its listeners.
+ *
+ * @see #stop
+ */
+ public void start() {
+ 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.
+ *
+ * @see #start
+ */
+ public void stop() {
+ timerQueue().removeTimer(this);
+ cancelEventOverride();
+ }
+
+ /**
+ * 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.
+ */
+ synchronized void cancelEventOverride() {
+ notify = false;
+ }
+
+ synchronized void postOverride() {
+ if (notify == false || !coalesce) {
+ notify = true;
+ display.asyncExec(doPostEvent);
+ }
+ }
+
+}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
new file mode 100644
index 0000000..a4092ab
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/SWTTimerQueue.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (c) 2008, Piccolo2D project, http://piccolo2d.org
+ * Copyright (c) 1998-2008, University of Maryland
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions
+ * and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
+ * and the following disclaimer in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * None of the name of the University of Maryland, the name of the Piccolo2D project, or the names of its
+ * contributors may be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package edu.umd.cs.piccolox.swt;
+
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * @author Lance Good
+ */
+public class SWTTimerQueue implements Runnable {
+ static SWTTimerQueue instance;
+
+ Display display = null;
+
+ SWTTimer firstTimer;
+ boolean running;
+
+ /**
+ * Constructor for TimerQueue.
+ */
+ public SWTTimerQueue(Display display) {
+ super();
+
+ this.display = display;
+
+ // Now start the TimerQueue thread.
+ start();
+ }
+
+ public static SWTTimerQueue sharedInstance(Display 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");
+ }
+ else {
+ Display.getDefault().asyncExec(new Runnable() {
+ public void run() {
+ Thread timerThread = new Thread(SWTTimerQueue.this, "TimerQueue");
+ timerThread.setDaemon(true);
+ timerThread.setPriority(Thread.NORM_PRIORITY);
+ timerThread.start();
+ }
+ });
+ running = true;
+ }
+ }
+
+ synchronized void stop() {
+ running = false;
+ notify();
+ }
+
+ synchronized void addTimer(SWTTimer timer, long expirationTime) {
+ SWTTimer previousTimer;
+ SWTTimer nextTimer;
+
+ // If the Timer is already in the queue, then ignore the add.
+ if (timer.running) {
+ return;
+ }
+
+ previousTimer = null;
+ 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
+ // later so they expire in the order they came in.
+
+ while (nextTimer != null) {
+ if (nextTimer.expirationTime > expirationTime)
+ break;
+
+ previousTimer = nextTimer;
+ nextTimer = nextTimer.nextTimer;
+ }
+
+ if (previousTimer == null) {
+ firstTimer = timer;
+ }
+ else {
+ previousTimer.nextTimer = timer;
+ }
+
+ timer.expirationTime = expirationTime;
+ timer.nextTimer = nextTimer;
+ timer.running = true;
+ notify();
+ }
+
+ synchronized void removeTimer(SWTTimer timer) {
+ SWTTimer previousTimer;
+ SWTTimer nextTimer;
+ boolean found;
+
+ if (!timer.running)
+ return;
+
+ previousTimer = null;
+ nextTimer = firstTimer;
+ found = false;
+
+ while (nextTimer != null) {
+ if (nextTimer == timer) {
+ found = true;
+ break;
+ }
+
+ previousTimer = nextTimer;
+ nextTimer = nextTimer.nextTimer;
+ }
+
+ if (!found)
+ return;
+
+ if (previousTimer == null) {
+ firstTimer = timer.nextTimer;
+ }
+ else {
+ previousTimer.nextTimer = timer.nextTimer;
+ }
+
+ timer.expirationTime = 0;
+ timer.nextTimer = null;
+ 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.
+ */
+ synchronized long postExpiredTimers() {
+ 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;
+
+ currentTime = System.currentTimeMillis();
+ timeToWait = timer.expirationTime - currentTime;
+
+ if (timeToWait <= 0) {
+ try {
+ timer.postOverride(); // have timer post an event
+ }
+ catch (SecurityException e) {
+ }
+
+ // Remove the timer from the queue
+ removeTimer(timer);
+
+ // This tries to keep the interval uniform at
+ // the cost of drift.
+ if (timer.isRepeats()) {
+ addTimer(timer, currentTime + timer.getDelay());
+ }
+
+ // Allow other threads to call addTimer() and removeTimer()
+ // 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.
+
+ try {
+ wait(1);
+ }
+ catch (InterruptedException e) {
+ }
+ }
+ } while (timeToWait <= 0);
+
+ return timeToWait;
+ }
+
+ public synchronized void run() {
+ long timeToWait;
+
+ try {
+ while (running) {
+ timeToWait = postExpiredTimers();
+ try {
+ wait(timeToWait);
+ }
+ catch (InterruptedException e) {
+ }
+ }
+ }
+ catch (ThreadDeath td) {
+ running = false;
+ // Mark all the timers we contain as not being queued.
+ SWTTimer timer = firstTimer;
+ while (timer != null) {
+ timer.cancelEventOverride();
+ timer = timer.nextTimer;
+ }
+ display.asyncExec(new SWTTimerQueueRestart(display));
+ throw td;
+ }
+ }
+
+ public synchronized String toString() {
+ StringBuffer buf;
+ SWTTimer nextTimer;
+
+ buf = new StringBuffer();
+ buf.append("TimerQueue (");
+
+ nextTimer = firstTimer;
+ while (nextTimer != null) {
+ buf.append(nextTimer.toString());
+
+ nextTimer = nextTimer.nextTimer;
+ if (nextTimer != null)
+ buf.append(", ");
+ }
+
+ buf.append(")");
+ return buf.toString();
+ }
+
+ /**
+ * 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;
+ }
+ }
+ }
+
+}
diff --git a/swt/src/main/java/edu/umd/cs/piccolox/swt/package.html b/swt/src/main/java/edu/umd/cs/piccolox/swt/package.html
new file mode 100644
index 0000000..1af36f5
--- /dev/null
+++ b/swt/src/main/java/edu/umd/cs/piccolox/swt/package.html
@@ -0,0 +1,34 @@
+
+
+
This package provides a SWT implementation of the core Piccolo library.
+ + diff --git a/swt/src/main/java/overview.html b/swt/src/main/java/overview.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/swt/src/main/java/overview.html