One of ftNone, ftOutline, ftSolid.
*/ public int commonFillType = ftNone; /** * commonLineStyle: current line type */ public int commonLineStyle = SWT.LINE_SOLID; /** * airbrushRadius: coverage radius in pixels */ public int airbrushRadius = 10; /** * airbrushIntensity: average surface area coverage in region defined by radius per "jot" */ public int airbrushIntensity = 30; /** * roundedRectangleCornerDiameter: the diameter of curvature of corners in a rounded rectangle */ public int roundedRectangleCornerDiameter = 16; } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ class Tool { public int id; public String name; public String group; public int type; public Runnable action; public Image image = null; public Object data; public Tool(int id, String name, String group, int type) { super(); this.id = id; this.name = name; this.group = group; this.type = type; } public Tool(int id, String name, String group, int type, Object data) { this(id, name, group, type); this.data = data; } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A text drawing tool. */ class TextTool extends BasicPaintSession implements PaintTool { private ToolSettings settings; private String drawText = PaintExample.getResourceString("tool.Text.settings.defaulttext"); /** * Constructs a PaintTool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public TextTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.Text.label"); } /** * Activates the tool. */ public void beginSession() { getPaintSurface().setStatusMessage(PaintExample.getResourceString( "session.Text.message")); } /** * Deactivates the tool. */ public void endSession() { getPaintSurface().clearRubberbandSelection(); } /** * Aborts the current operation. */ public void resetSession() { getPaintSurface().clearRubberbandSelection(); } /** * Handles a mouseDown event. * * @param event the mouse event detail information */ public void mouseDown(MouseEvent event) { if (event.button == 1) { // draw with left mouse button getPaintSurface().commitRubberbandSelection(); } else { // set text with right mouse button getPaintSurface().clearRubberbandSelection(); Shell shell = getPaintSurface().getShell(); final Shell dialog = new Shell(shell, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL); dialog.setText(PaintExample.getResourceString("tool.Text.dialog.title")); dialog.setLayout(new GridLayout()); Label label = new Label(dialog, SWT.NONE); label.setText(PaintExample.getResourceString("tool.Text.dialog.message")); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); final Text field = new Text(dialog, SWT.SINGLE | SWT.BORDER); field.setText(drawText); field.selectAll(); field.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); Composite buttons = new Composite(dialog, SWT.NONE); GridLayout layout = new GridLayout(2, true); layout.marginWidth = 0; buttons.setLayout(layout); buttons.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); Button ok = new Button(buttons, SWT.PUSH); ok.setText(PaintExample.getResourceString("OK")); ok.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false)); ok.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { drawText = field.getText(); dialog.dispose(); } }); Button cancel = new Button(buttons, SWT.PUSH); cancel.setText(PaintExample.getResourceString("Cancel")); cancel.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent e) { dialog.dispose(); } }); dialog.setDefaultButton(ok); dialog.pack(); dialog.open(); Display display = dialog.getDisplay(); while (! shell.isDisposed() && ! dialog.isDisposed()) { if (! display.readAndDispatch()) display.sleep(); } } } /** * Handles a mouseDoubleClick event. * * @param event the mouse event detail information */ public void mouseDoubleClick(MouseEvent event) { } /** * Handles a mouseUp event. * * @param event the mouse event detail information */ public void mouseUp(MouseEvent event) { } /** * Handles a mouseMove event. * * @param event the mouse event detail information */ public void mouseMove(MouseEvent event) { final PaintSurface ps = getPaintSurface(); ps.setStatusCoord(ps.getCurrentPosition()); ps.clearRubberbandSelection(); ps.addRubberbandSelection( new TextFigure(settings.commonForegroundColor, settings.commonFont, drawText, event.x, event.y)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Rectangle object */ class TextFigure extends Figure { private Color color; private Font font; private String text; private int x, y; /** * Constructs a TextFigure * * @param color the color for this object * @param font the font for this object * @param text the text to draw, tab and new-line expansion is performed * @param x the virtual X coordinate of the top-left corner of the text bounding box * @param y the virtual Y coordinate of the top-left corner of the text bounding box */ public TextFigure(Color color, Font font, String text, int x, int y) { this.color = color; this.font = font; this.text = text; this.x = x; this.y = y; } public void draw(FigureDrawContext fdc) { Point p = fdc.toClientPoint(x, y); fdc.gc.setFont(font); fdc.gc.setForeground(color); fdc.gc.drawText(text, p.x, p.y, true); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { Font oldFont = fdc.gc.getFont(); fdc.gc.setFont(font); Point textExtent = fdc.gc.textExtent(text); fdc.gc.setFont(oldFont); region.add(fdc.toClientRectangle(x, y, x + textExtent.x, y + textExtent.y)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D SolidRectangle object */ class SolidRoundedRectangleFigure extends Figure { private Color color; private int x1, y1, x2, y2, diameter; /** * Constructs a SolidRectangle * These objects are defined by any two diametrically opposing corners. * * @param color the color for this object * @param x1 the virtual X coordinate of the first corner * @param y1 the virtual Y coordinate of the first corner * @param x2 the virtual X coordinate of the second corner * @param y2 the virtual Y coordinate of the second corner * @param diameter the diameter of curvature of all four corners */ public SolidRoundedRectangleFigure(Color color, int x1, int y1, int x2, int y2, int diameter) { this.color = color; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.diameter = diameter; } public void draw(FigureDrawContext fdc) { Rectangle r = fdc.toClientRectangle(x1, y1, x2, y2); fdc.gc.setBackground(color); fdc.gc.fillRoundRectangle(r.x, r.y, r.width, r.height, diameter, diameter); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D SolidRectangle object */ class SolidRectangleFigure extends Figure { private Color color; private int x1, y1, x2, y2; /** * Constructs a SolidRectangle * These objects are defined by any two diametrically opposing corners. * * @param color the color for this object * @param x1 the virtual X coordinate of the first corner * @param y1 the virtual Y coordinate of the first corner * @param x2 the virtual X coordinate of the second corner * @param y2 the virtual Y coordinate of the second corner */ public SolidRectangleFigure(Color color, int x1, int y1, int x2, int y2) { this.color = color; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public void draw(FigureDrawContext fdc) { Rectangle r = fdc.toClientRectangle(x1, y1, x2, y2); fdc.gc.setBackground(color); fdc.gc.fillRectangle(r.x, r.y, r.width, r.height); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Line object */ class SolidPolygonFigure extends Figure { private Color color; private int[] points; /** * Constructs a SolidPolygon * These objects are defined by a sequence of vertices. * * @param color the color for this object * @param vertices the array of vertices making up the polygon * @param numPoint the number of valid points in the array (n >= 3) */ public SolidPolygonFigure(Color color, Point[] vertices, int numPoints) { this.color = color; this.points = new int[numPoints * 2]; for (int i = 0; i < numPoints; ++i) { points[i * 2] = vertices[i].x; points[i * 2 + 1] = vertices[i].y; } } public void draw(FigureDrawContext fdc) { int[] drawPoints = new int[points.length]; for (int i = 0; i < points.length; i += 2) { drawPoints[i] = points[i] * fdc.xScale - fdc.xOffset; drawPoints[i + 1] = points[i + 1] * fdc.yScale - fdc.yOffset; } fdc.gc.setBackground(color); fdc.gc.fillPolygon(drawPoints); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { int xmin = Integer.MAX_VALUE, ymin = Integer.MAX_VALUE; int xmax = Integer.MIN_VALUE, ymax = Integer.MIN_VALUE; for (int i = 0; i < points.length; i += 2) { if (points[i] < xmin) xmin = points[i]; if (points[i] > xmax) xmax = points[i]; if (points[i+1] < ymin) ymin = points[i+1]; if (points[i+1] > ymax) ymax = points[i+1]; } region.add(fdc.toClientRectangle(xmin, ymin, xmax, ymax)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Solid Ellipse object */ class SolidEllipseFigure extends Figure { private Color color; private int x1, y1, x2, y2; /** * Constructs a SolidEllipse * These objects are defined by any two diametrically opposing corners of a box * bounding the ellipse. * * @param color the color for this object * @param x1 the virtual X coordinate of the first corner * @param y1 the virtual Y coordinate of the first corner * @param x2 the virtual X coordinate of the second corner * @param y2 the virtual Y coordinate of the second corner */ public SolidEllipseFigure(Color color, int x1, int y1, int x2, int y2) { this.color = color; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public void draw(FigureDrawContext fdc) { Rectangle r = fdc.toClientRectangle(x1, y1, x2, y2); fdc.gc.setBackground(color); fdc.gc.fillOval(r.x, r.y, r.width, r.height); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * The superclass for paint tools that contruct objects from individually * picked segments. */ abstract class SegmentedPaintSession extends BasicPaintSession { /** * The set of control points making up the segmented selection */ private Vector /* of Point */ controlPoints = new Vector(); /** * The previous figure (so that we can abort with right-button) */ private Figure previousFigure = null; /** * The current figure (so that we can abort with right-button) */ private Figure currentFigure = null; /** * Constructs a PaintSession. * * @param paintSurface the drawing surface to use */ protected SegmentedPaintSession(PaintSurface paintSurface) { super(paintSurface); } /** * Activates the tool. */ public void beginSession() { getPaintSurface().setStatusMessage(PaintExample.getResourceString( "session.SegmentedInteractivePaint.message.anchorMode")); previousFigure = null; currentFigure = null; controlPoints.clear(); } /** * Deactivates the tool. */ public void endSession() { getPaintSurface().clearRubberbandSelection(); if (previousFigure != null) getPaintSurface().drawFigure(previousFigure); } /** * Resets the tool. * Aborts any operation in progress. */ public void resetSession() { getPaintSurface().clearRubberbandSelection(); if (previousFigure != null) getPaintSurface().drawFigure(previousFigure); getPaintSurface().setStatusMessage(PaintExample.getResourceString( "session.SegmentedInteractivePaint.message.anchorMode")); previousFigure = null; currentFigure = null; controlPoints.clear(); } /** * Handles a mouseDown event. * * @param event the mouse event detail information */ public void mouseDown(MouseEvent event) { if (event.button != 1) return; getPaintSurface().setStatusMessage(PaintExample.getResourceString( "session.SegmentedInteractivePaint.message.interactiveMode")); previousFigure = currentFigure; if (controlPoints.size() > 0) { final Point lastPoint = (Point) controlPoints.elementAt(controlPoints.size() - 1); if (lastPoint.x == event.x || lastPoint.y == event.y) return; // spurious event } controlPoints.add(new Point(event.x, event.y)); } /** * Handles a mouseDoubleClick event. * * @param event the mouse event detail information */ public void mouseDoubleClick(MouseEvent event) { if (event.button != 1) return; if (controlPoints.size() >= 2) { getPaintSurface().clearRubberbandSelection(); previousFigure = createFigure( (Point[]) controlPoints.toArray(new Point[controlPoints.size()]), controlPoints.size(), true); } resetSession(); } /** * Handles a mouseUp event. * * @param event the mouse event detail information */ public void mouseUp(MouseEvent event) { if (event.button != 1) { resetSession(); // abort if right or middle mouse button pressed return; } } /** * Handles a mouseMove event. * * @param event the mouse event detail information */ public void mouseMove(MouseEvent event) { final PaintSurface ps = getPaintSurface(); if (controlPoints.size() == 0) { ps.setStatusCoord(ps.getCurrentPosition()); return; // spurious event } else { ps.setStatusCoordRange((Point) controlPoints.elementAt(controlPoints.size() - 1), ps.getCurrentPosition()); } ps.clearRubberbandSelection(); Point[] points = (Point[]) controlPoints.toArray(new Point[controlPoints.size() + 1]); points[controlPoints.size()] = ps.getCurrentPosition(); currentFigure = createFigure(points, points.length, false); ps.addRubberbandSelection(currentFigure); } /** * Template Method: Creates a Figure for drawing rubberband entities and the final product * * @param points the array of control points * @param numPoints the number of valid points in the array (n >= 2) * @param closed true if the user double-clicked on the final control point */ protected abstract Figure createFigure(Point[] points, int numPoints, boolean closed); } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A drawing tool. */ class RoundedRectangleTool extends DragPaintSession implements PaintTool { private ToolSettings settings; /** * Constructs a RoundedRectangleTool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public RoundedRectangleTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.RoundedRectangle.label"); } /* * Template methods for drawing */ protected Figure createFigure(Point a, Point b) { ContainerFigure container = new ContainerFigure(); if (settings.commonFillType != ToolSettings.ftNone) container.add(new SolidRoundedRectangleFigure(settings.commonBackgroundColor, a.x, a.y, b.x, b.y, settings.roundedRectangleCornerDiameter)); if (settings.commonFillType != ToolSettings.ftSolid) container.add(new RoundedRectangleFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y, settings.roundedRectangleCornerDiameter)); return container; } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Rectangle object */ class RoundedRectangleFigure extends Figure { private Color foregroundColor, backgroundColor; private int lineStyle, x1, y1, x2, y2, diameter; /** * Constructs a Rectangle * These objects are defined by any two diametrically opposing corners. * * @param color the color for this object * @param lineStyle the line style for this object * @param x1 the virtual X coordinate of the first corner * @param y1 the virtual Y coordinate of the first corner * @param x2 the virtual X coordinate of the second corner * @param y2 the virtual Y coordinate of the second corner * @param diameter the diameter of curvature of all four corners */ public RoundedRectangleFigure(Color foregroundColor, Color backgroundColor, int lineStyle, int x1, int y1, int x2, int y2, int diameter) { this.foregroundColor = foregroundColor; this.backgroundColor = backgroundColor; this.lineStyle = lineStyle; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; this.diameter = diameter; } public void draw(FigureDrawContext fdc) { Rectangle r = fdc.toClientRectangle(x1, y1, x2, y2); fdc.gc.setForeground(foregroundColor); fdc.gc.setBackground(backgroundColor); fdc.gc.setLineStyle(lineStyle); fdc.gc.drawRoundRectangle(r.x, r.y, r.width - 1, r.height - 1, diameter, diameter); fdc.gc.setLineStyle(SWT.LINE_SOLID); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A drawing tool. */ class RectangleTool extends DragPaintSession implements PaintTool { private ToolSettings settings; /** * Constructs a RectangleTool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public RectangleTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.Rectangle.label"); } /* * Template method for drawing */ protected Figure createFigure(Point a, Point b) { switch (settings.commonFillType) { default: case ToolSettings.ftNone: return new RectangleFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y); case ToolSettings.ftSolid: return new SolidRectangleFigure(settings.commonBackgroundColor, a.x, a.y, b.x, b.y); case ToolSettings.ftOutline: { ContainerFigure container = new ContainerFigure(); container.add(new SolidRectangleFigure(settings.commonBackgroundColor, a.x, a.y, b.x, b.y)); container.add(new RectangleFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y)); return container; } } } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Rectangle object */ class RectangleFigure extends Figure { private Color foregroundColor, backgroundColor; private int lineStyle, x1, y1, x2, y2; /** * Constructs a Rectangle * These objects are defined by any two diametrically opposing corners. * * @param color the color for this object * @param lineStyle the line style for this object * @param x1 the virtual X coordinate of the first corner * @param y1 the virtual Y coordinate of the first corner * @param x2 the virtual X coordinate of the second corner * @param y2 the virtual Y coordinate of the second corner */ public RectangleFigure(Color foregroundColor, Color backgroundColor, int lineStyle, int x1, int y1, int x2, int y2) { this.foregroundColor = foregroundColor; this.backgroundColor = backgroundColor; this.lineStyle = lineStyle; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public void draw(FigureDrawContext fdc) { Rectangle r = fdc.toClientRectangle(x1, y1, x2, y2); fdc.gc.setForeground(foregroundColor); fdc.gc.setBackground(backgroundColor); fdc.gc.setLineStyle(lineStyle); fdc.gc.drawRectangle(r.x, r.y, r.width - 1, r.height - 1); fdc.gc.setLineStyle(SWT.LINE_SOLID); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A polyline drawing tool. */ class PolyLineTool extends SegmentedPaintSession implements PaintTool { private ToolSettings settings; /** * Constructs a PolyLineTool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public PolyLineTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns the name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.PolyLine.label"); } /* * Template methods for drawing */ protected Figure createFigure(Point[] points, int numPoints, boolean closed) { ContainerFigure container = new ContainerFigure(); if (closed && settings.commonFillType != ToolSettings.ftNone && numPoints >= 3) { container.add(new SolidPolygonFigure(settings.commonBackgroundColor, points, numPoints)); } if (! closed || settings.commonFillType != ToolSettings.ftSolid || numPoints < 3) { for (int i = 0; i < numPoints - 1; ++i) { final Point a = points[i]; final Point b = points[i + 1]; container.add(new LineFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y)); } if (closed) { final Point a = points[points.length - 1]; final Point b = points[0]; container.add(new LineFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y)); } } return container; } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Point object */ class PointFigure extends Figure { private Color color; private int x, y; /** * Constructs a Point * * @param color the color for this object * @param x the virtual X coordinate of the first end-point * @param y the virtual Y coordinate of the first end-point */ public PointFigure(Color color, int x, int y) { this.color = color; this.x = x; this.y = y; } public void draw(FigureDrawContext fdc) { Point p = fdc.toClientPoint(x, y); fdc.gc.setBackground(color); fdc.gc.fillRectangle(p.x, p.y, 1, 1); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x, y, x, y)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A pencil tool. */ class PencilTool extends ContinuousPaintSession implements PaintTool { private ToolSettings settings; /** * Constructs a pencil tool. * * @param toolSettings the new tool settings * @param getPaintSurface() the PaintSurface we will render on. */ public PencilTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns the name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.Pencil.label"); } /* * Template method for drawing */ public void render(final Point point) { final PaintSurface ps = getPaintSurface(); ps.drawFigure(new PointFigure(settings.commonForegroundColor, point.x, point.y)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ interface PaintTool extends PaintSession { /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings); } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * Manages a simple drawing surface. */ class PaintSurface { private Point currentPosition = new Point(0, 0); private Canvas paintCanvas; private PaintSession paintSession; private Image image; private Image paintImage; // buffer for refresh blits private int imageWidth, imageHeight; private int visibleWidth, visibleHeight; private FigureDrawContext displayFDC = new FigureDrawContext(); private FigureDrawContext imageFDC = new FigureDrawContext(); private FigureDrawContext paintFDC = new FigureDrawContext(); /* Rubberband */ private ContainerFigure rubberband = new ContainerFigure(); // the active rubberband selection private int rubberbandHiddenNestingCount = 0; // always >= 0, if > 0 rubberband has been hidden /* Status */ private Text statusText; private String statusActionInfo, statusMessageInfo, statusCoordInfo; /** * Constructs a PaintSurface. ** paintCanvas must have SWT.NO_REDRAW_RESIZE and SWT.NO_BACKGROUND styles, * and may have SWT.V_SCROLL and/or SWT.H_SCROLL. *
* @param paintCanvas the Canvas object in which to render * @param paintStatus the PaintStatus object to use for providing user feedback * @param fillColor the color to fill the canvas with initially */ public PaintSurface(Canvas paintCanvas, Text statusText, Color fillColor) { this.paintCanvas = paintCanvas; this.statusText = statusText; clearStatus(); /* Set up the drawing surface */ Rectangle displayRect = paintCanvas.getDisplay().getClientArea(); imageWidth = displayRect.width; imageHeight = displayRect.height; image = new Image(paintCanvas.getDisplay(), imageWidth, imageHeight); imageFDC.gc = new GC(image); imageFDC.gc.setBackground(fillColor); imageFDC.gc.fillRectangle(0, 0, imageWidth, imageHeight); displayFDC.gc = new GC(paintCanvas); /* Initialize the session */ setPaintSession(null); /* Add our listeners */ paintCanvas.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { displayFDC.gc.dispose(); } }); paintCanvas.addMouseListener(new MouseAdapter() { public void mouseDown(MouseEvent event) { processMouseEventCoordinates(event); if (paintSession != null) paintSession.mouseDown(event); } public void mouseUp(MouseEvent event) { processMouseEventCoordinates(event); if (paintSession != null) paintSession.mouseUp(event); } public void mouseDoubleClick(MouseEvent event) { processMouseEventCoordinates(event); if (paintSession != null) paintSession.mouseDoubleClick(event); } }); paintCanvas.addMouseMoveListener(new MouseMoveListener() { public void mouseMove(MouseEvent event) { processMouseEventCoordinates(event); if (paintSession != null) paintSession.mouseMove(event); } }); paintCanvas.addPaintListener(new PaintListener() { public void paintControl(PaintEvent event) { if (rubberband.isEmpty()) { // Nothing to merge, so we just refresh event.gc.drawImage(image, displayFDC.xOffset + event.x, displayFDC.yOffset + event.y, event.width, event.height, event.x, event.y, event.width, event.height); } else { /* * Avoid flicker when merging overlayed objects by constructing the image on * a backbuffer first, then blitting it to the screen. */ // Check that the backbuffer is large enough if (paintImage != null) { Rectangle rect = paintImage.getBounds(); if ((event.width + event.x > rect.width) || (event.height + event.y > rect.height)) { paintFDC.gc.dispose(); paintImage.dispose(); paintImage = null; } } if (paintImage == null) { Display display = getDisplay(); Rectangle rect = display.getClientArea(); paintImage = new Image(display, Math.max(rect.width, event.width + event.x), Math.max(rect.height, event.height + event.y)); paintFDC.gc = new GC(paintImage); } // Setup clipping and the FDC Region clipRegion = new Region(); event.gc.getClipping(clipRegion); paintFDC.gc.setClipping(clipRegion); clipRegion.dispose(); paintFDC.xOffset = displayFDC.xOffset; paintFDC.yOffset = displayFDC.yOffset; paintFDC.xScale = displayFDC.xScale; paintFDC.yScale = displayFDC.yScale; // Merge the overlayed objects into the image, then blit paintFDC.gc.drawImage(image, displayFDC.xOffset + event.x, displayFDC.yOffset + event.y, event.width, event.height, event.x, event.y, event.width, event.height); rubberband.draw(paintFDC); event.gc.drawImage(paintImage, event.x, event.y, event.width, event.height, event.x, event.y, event.width, event.height); } } }); paintCanvas.addControlListener(new ControlAdapter() { public void controlResized(ControlEvent event) { handleResize(); } }); /* Set up the paint canvas scroll bars */ ScrollBar horizontal = paintCanvas.getHorizontalBar(); horizontal.setVisible(true); horizontal.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { scrollHorizontally((ScrollBar)event.widget); } }); ScrollBar vertical = paintCanvas.getVerticalBar(); vertical.setVisible(true); vertical.addSelectionListener(new SelectionAdapter() { public void widgetSelected(SelectionEvent event) { scrollVertically((ScrollBar)event.widget); } }); handleResize(); } /** * Disposes of the PaintSurface's resources. */ public void dispose() { imageFDC.gc.dispose(); image.dispose(); if (paintImage != null) { paintImage.dispose(); paintFDC.gc.dispose(); } currentPosition = null; paintCanvas = null; paintSession = null; image = null; paintImage = null; displayFDC = null; imageFDC = null; paintFDC = null; rubberband = null; statusText = null; statusActionInfo = null; statusMessageInfo = null; statusCoordInfo = null; } /** * Called when we must grab focus. */ public void setFocus() { paintCanvas.setFocus(); } /** * Returns the Display on which the PaintSurface resides. * @return the Display */ public Display getDisplay() { return paintCanvas.getDisplay(); } /** * Returns the Shell in which the PaintSurface resides. * @return the Shell */ public Shell getShell() { return paintCanvas.getShell(); } /** * Sets the current paint session. ** If oldPaintSession != paintSession calls oldPaintSession.end() * and paintSession.begin() *
* * @param paintSession the paint session to activate; null to disable all sessions */ public void setPaintSession(PaintSession paintSession) { if (this.paintSession != null) { if (this.paintSession == paintSession) return; this.paintSession.endSession(); } this.paintSession = paintSession; clearStatus(); if (paintSession != null) { setStatusAction(paintSession.getDisplayName()); paintSession.beginSession(); } else { setStatusAction(PaintExample.getResourceString("tool.Null.label")); setStatusMessage(PaintExample.getResourceString("session.Null.message")); } } /** * Returns the current paint session. * * @return the current paint session, null if none is active */ public PaintSession getPaintSession() { return paintSession; } /** * Returns the current paint tool. * * @return the current paint tool, null if none is active (though some other session * might be) */ public PaintTool getPaintTool() { return (paintSession != null && paintSession instanceof PaintTool) ? (PaintTool)paintSession : null; } /** * Returns the current position in an interactive operation. * * @return the last known position of the pointer */ public Point getCurrentPosition() { return currentPosition; } /** * Draws a Figure object to the screen and to the backing store permanently. * * @param object the object to draw onscreen */ public void drawFigure(Figure object) { object.draw(imageFDC); object.draw(displayFDC); } /** * Adds a Figure object to the active rubberband selection. ** This object will be drawn to the screen as a preview and refreshed appropriately * until the selection is either cleared or committed. *
* * @param object the object to add to the selection */ public void addRubberbandSelection(Figure object) { rubberband.add(object); if (! isRubberbandHidden()) object.draw(displayFDC); } /** * Clears the active rubberband selection. ** Erases any rubberband objects on the screen then clears the selection. *
*/ public void clearRubberbandSelection() { if (! isRubberbandHidden()) { Region region = new Region(); rubberband.addDamagedRegion(displayFDC, region); Rectangle r = region.getBounds(); paintCanvas.redraw(r.x, r.y, r.width, r.height, true); region.dispose(); } rubberband.clear(); } /** * Commits the active rubberband selection. ** Redraws any rubberband objects on the screen as permanent objects then clears the selection. *
*/ public void commitRubberbandSelection() { rubberband.draw(imageFDC); if (isRubberbandHidden()) rubberband.draw(displayFDC); rubberband.clear(); } /** * Hides the rubberband (but does not eliminate it). ** Increments by one the rubberband "hide" nesting count. The rubberband * is hidden from view (but remains active) if it wasn't already hidden. *
*/ public void hideRubberband() { if (rubberbandHiddenNestingCount++ <= 0) { Region region = new Region(); rubberband.addDamagedRegion(displayFDC, region); Rectangle r = region.getBounds(); paintCanvas.redraw(r.x, r.y, r.width, r.height, true); region.dispose(); } } /** * Shows (un-hides) the rubberband. ** Decrements by one the rubberband "hide" nesting count. The rubberband * is only made visible when showRubberband() has been called once for each * previous hideRubberband(). It is not permitted to call showRubberband() if * the rubber band is not presently hidden. *
*/ public void showRubberband() { if (rubberbandHiddenNestingCount <= 0) throw new IllegalStateException("rubberbandHiddenNestingCount > 0"); if (--rubberbandHiddenNestingCount == 0) { rubberband.draw(displayFDC); } } /** * Determines if the rubberband is hidden. * * @return true iff the rubber is hidden */ public boolean isRubberbandHidden() { return rubberbandHiddenNestingCount > 0; } /** * Handles a horizontal scroll event * * @param scrollbar the horizontal scroll bar that posted this event */ public void scrollHorizontally(ScrollBar scrollBar) { if (image == null) return; if (imageWidth > visibleWidth) { final int oldOffset = displayFDC.xOffset; final int newOffset = Math.min(scrollBar.getSelection(), imageWidth - visibleWidth); if (oldOffset != newOffset) { paintCanvas.update(); displayFDC.xOffset = newOffset; paintCanvas.scroll(Math.max(oldOffset - newOffset, 0), 0, Math.max(newOffset - oldOffset, 0), 0, visibleWidth, visibleHeight, false); } } } /** * Handles a vertical scroll event * * @param scrollbar the vertical scroll bar that posted this event */ public void scrollVertically(ScrollBar scrollBar) { if (image == null) return; if (imageHeight > visibleHeight) { final int oldOffset = displayFDC.yOffset; final int newOffset = Math.min(scrollBar.getSelection(), imageHeight - visibleHeight); if (oldOffset != newOffset) { paintCanvas.update(); displayFDC.yOffset = newOffset; paintCanvas.scroll(0, Math.max(oldOffset - newOffset, 0), 0, Math.max(newOffset - oldOffset, 0), visibleWidth, visibleHeight, false); } } } /** * Handles resize events */ private void handleResize() { paintCanvas.update(); Rectangle visibleRect = paintCanvas.getClientArea(); visibleWidth = visibleRect.width; visibleHeight = visibleRect.height; ScrollBar horizontal = paintCanvas.getHorizontalBar(); if (horizontal != null) { displayFDC.xOffset = Math.min(horizontal.getSelection(), imageWidth - visibleWidth); if (imageWidth <= visibleWidth) { horizontal.setEnabled(false); horizontal.setSelection(0); } else { horizontal.setEnabled(true); horizontal.setValues(displayFDC.xOffset, 0, imageWidth, visibleWidth, 8, visibleWidth); } } ScrollBar vertical = paintCanvas.getVerticalBar(); if (vertical != null) { displayFDC.yOffset = Math.min(vertical.getSelection(), imageHeight - visibleHeight); if (imageHeight <= visibleHeight) { vertical.setEnabled(false); vertical.setSelection(0); } else { vertical.setEnabled(true); vertical.setValues(displayFDC.yOffset, 0, imageHeight, visibleHeight, 8, visibleHeight); } } } /** * Virtualizes MouseEvent coordinates and stores the current position. */ private void processMouseEventCoordinates(MouseEvent event) { currentPosition.x = event.x = Math.min(Math.max(event.x, 0), visibleWidth - 1) + displayFDC.xOffset; currentPosition.y = event.y = Math.min(Math.max(event.y, 0), visibleHeight - 1) + displayFDC.yOffset; } /** * Clears the status bar. */ public void clearStatus() { statusActionInfo = ""; statusMessageInfo = ""; statusCoordInfo = ""; updateStatus(); } /** * Sets the status bar action text. * * @param action the action in progress, null to clear */ public void setStatusAction(String action) { statusActionInfo = (action != null) ? action : ""; updateStatus(); } /** * Sets the status bar message text. * * @param message the message to display, null to clear */ public void setStatusMessage(String message) { statusMessageInfo = (message != null) ? message : ""; updateStatus(); } /** * Sets the coordinates in the status bar. * * @param coord the coordinates to display, null to clear */ public void setStatusCoord(Point coord) { statusCoordInfo = (coord != null) ? PaintExample.getResourceString("status.Coord.format", new Object[] { new Integer(coord.x), new Integer(coord.y)}) : ""; updateStatus(); } /** * Sets the coordinate range in the status bar. * * @param a the "from" coordinate, must not be null * @param b the "to" coordinate, must not be null */ public void setStatusCoordRange(Point a, Point b) { statusCoordInfo = PaintExample.getResourceString("status.CoordRange.format", new Object[] { new Integer(a.x), new Integer(a.y), new Integer(b.x), new Integer(b.y)}); updateStatus(); } /** * Updates the display. */ private void updateStatus() { statusText.setText( PaintExample.getResourceString("status.Bar.format", new Object[] { statusActionInfo, statusMessageInfo, statusCoordInfo })); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * Manages an interactive paint session. * Note that the coordinates received via the listener interfaces are virtualized to zero-origin * relative to the painting surface. */ interface PaintSession extends MouseListener, MouseMoveListener { /** * Returns the paint surface associated with this paint session * * @return the associated PaintSurface */ public PaintSurface getPaintSurface(); /** * Activates the session. * * Note: When overriding this method, call super.beginSession() at method start. */ public abstract void beginSession(); /** * Deactivates the session. * * Note: When overriding this method, call super.endSession() at method exit. */ public abstract void endSession(); /** * Resets the session. * Aborts any operation in progress. * * Note: When overriding this method, call super.resetSession() at method exit. */ public abstract void resetSession(); /** * Returns the name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName(); } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * A line drawing tool */ class LineTool extends DragPaintSession implements PaintTool { private ToolSettings settings; /** * Constructs a LineTool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public LineTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { settings = toolSettings; } /** * Returns name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.Line.label"); } /* * Template methods for drawing */ protected Figure createFigure(Point a, Point b) { return new LineFigure(settings.commonForegroundColor, settings.commonBackgroundColor, settings.commonLineStyle, a.x, a.y, b.x, b.y); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * 2D Line object */ class LineFigure extends Figure { private Color foregroundColor, backgroundColor; private int lineStyle, x1, y1, x2, y2; /** * Constructs a Line * These objects are defined by their two end-points. * * @param color the color for this object * @param lineStyle the line style for this object * @param x1 the virtual X coordinate of the first end-point * @param y1 the virtual Y coordinate of the first end-point * @param x2 the virtual X coordinate of the second end-point * @param y2 the virtual Y coordinate of the second end-point */ public LineFigure(Color foregroundColor, Color backgroundColor, int lineStyle, int x1, int y1, int x2, int y2) { this.foregroundColor = foregroundColor; this.backgroundColor = backgroundColor; this.lineStyle = lineStyle; this.x1 = x1; this.y1 = y1; this.x2 = x2; this.y2 = y2; } public void draw(FigureDrawContext fdc) { Point p1 = fdc.toClientPoint(x1, y1); Point p2 = fdc.toClientPoint(x2, y2); fdc.gc.setForeground(foregroundColor); fdc.gc.setBackground(backgroundColor); fdc.gc.setLineStyle(lineStyle); fdc.gc.drawLine(p1.x, p1.y, p2.x, p2.y); fdc.gc.setLineStyle(SWT.LINE_SOLID); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { region.add(fdc.toClientRectangle(x1, y1, x2, y2)); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ class FigureDrawContext { /* ** The GC must be set up as follows * (it will be returned to this state upon completion of drawing operations) *
* After the timer elapses, if the mouse is still hovering over the same point with the * drag button pressed, a new render order is issued and the timer is restarted. *
* @param interval the time in milliseconds to wait between retriggers, 0 to disable */ public void setRetriggerTimer(int interval) { retriggerInterval = interval; } /** * Activates the tool. */ public void beginSession() { getPaintSurface(). setStatusMessage(PaintExample.getResourceString("session.ContinuousPaint.message")); dragInProgress = false; } /** * Deactivates the tool. */ public void endSession() { abortRetrigger(); } /** * Aborts the current operation. */ public void resetSession() { abortRetrigger(); } /** * Handles a mouseDown event. * * @param event the mouse event detail information */ public final void mouseDown(MouseEvent event) { if (event.button != 1) return; if (dragInProgress) return; // spurious event dragInProgress = true; points[0].x = event.x; points[0].y = event.y; render(points[0]); prepareRetrigger(); } /** * Handles a mouseDoubleClick event. * * @param event the mouse event detail information */ public final void mouseDoubleClick(MouseEvent event) { } /** * Handles a mouseUp event. * * @param event the mouse event detail information */ public final void mouseUp(MouseEvent event) { if (event.button != 1) return; if (! dragInProgress) return; // spurious event abortRetrigger(); mouseSegmentFinished(event); dragInProgress = false; } /** * Handles a mouseMove event. * * @param event the mouse event detail information */ public final void mouseMove(MouseEvent event) { final PaintSurface ps = getPaintSurface(); ps.setStatusCoord(ps.getCurrentPosition()); if (! dragInProgress) return; mouseSegmentFinished(event); prepareRetrigger(); } /** * Handle a rendering segment * * @param event the mouse event detail information */ private final void mouseSegmentFinished(MouseEvent event) { if (points[0].x == -1) return; // spurious event if (points[0].x != event.x || points[0].y != event.y) { // draw new segment points[1].x = event.x; points[1].y = event.y; renderContinuousSegment(); } } /** * Draws a continuous segment from points[0] to points[1]. * Assumes points[0] has been drawn already. * * @post points[0] will refer to the same point as points[1] */ protected void renderContinuousSegment() { /* A lazy but effective line drawing algorithm */ final int dX = points[1].x - points[0].x; final int dY = points[1].y - points[0].y; int absdX = Math.abs(dX); int absdY = Math.abs(dY); if ((dX == 0) && (dY == 0)) return; if (absdY > absdX) { final int incfpX = (dX << 16) / absdY; final int incY = (dY > 0) ? 1 : -1; int fpX = points[0].x << 16; // X in fixedpoint format while (--absdY >= 0) { points[0].y += incY; points[0].x = (fpX += incfpX) >> 16; render(points[0]); } if (points[0].x == points[1].x) return; points[0].x = points[1].x; } else { final int incfpY = (dY << 16) / absdX; final int incX = (dX > 0) ? 1 : -1; int fpY = points[0].y << 16; // Y in fixedpoint format while (--absdX >= 0) { points[0].x += incX; points[0].y = (fpY += incfpY) >> 16; render(points[0]); } if (points[0].y == points[1].y) return; points[0].y = points[1].y; } render(points[0]); } /** * Prepare the retrigger timer */ private final void prepareRetrigger() { if (retriggerInterval > 0) { /* * timerExec() provides a lightweight mechanism for running code at intervals from within * the event loop when timing accuracy is not important. * * Since it is not possible to cancel a timerExec(), we remember the Runnable that is * active in order to distinguish the valid one from the stale ones. In practice, * if the interval is 1/100th of a second, then creating a few hundred new RetriggerHandlers * each second will not cause a significant performance hit. */ Display display = getPaintSurface().getDisplay(); retriggerHandler = new Runnable() { public void run() { if (retriggerHandler == this) { render(points[0]); prepareRetrigger(); } } }; display.timerExec(retriggerInterval, retriggerHandler); } } /** * Aborts the retrigger timer */ private final void abortRetrigger() { retriggerHandler = null; } /** * Template method: Renders a point. * @param point, the point to render */ protected abstract void render(Point point); } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * Container for Figure objects with stacking preview mechanism. */ class ContainerFigure extends Figure { private static final int INITIAL_ARRAY_SIZE = 16; Figure[] objectStack = null; int nextIndex = 0; /** * Constructs an empty Container */ public ContainerFigure() { } /** * Adds an object to the container for later drawing. * * @param object the object to add to the drawing list */ public void add(Figure object) { if (objectStack == null) { objectStack = new Figure[INITIAL_ARRAY_SIZE]; } else if (objectStack.length <= nextIndex) { Figure[] newObjectStack = new Figure[objectStack.length * 2]; System.arraycopy(objectStack, 0, newObjectStack, 0, objectStack.length); objectStack = newObjectStack; } objectStack[nextIndex] = object; ++nextIndex; } /** * Determines if the container is empty. * @return true if the container is empty */ public boolean isEmpty() { return nextIndex == 0; } /** * Adds an object to the container and draws its preview then updates the supplied preview state. * * @param object the object to add to the drawing list * @param gc the GC to draw on * @param offset the offset to add to virtual coordinates to get display coordinates * @param rememberedState the state returned by a previous drawPreview() or addAndPreview() * using this Container, may be null if there was no such previous call * @return object state that must be passed to erasePreview() later to erase this object */ // public Object addAndPreview(Figure object, GC gc, Point offset, Object rememberedState) { // Object[] stateStack = (Object[]) rememberedState; // if (stateStack == null) { // stateStack = new Object[INITIAL_ARRAY_SIZE]; // } else if (stateStack.length <= nextIndex) { // Object[] newStateStack = new Object[stateStack.length * 2]; // System.arraycopy(stateStack, 0, newStateStack, 0, stateStack.length); // stateStack = newStateStack; // } // add(object); // stateStack[nextIndex - 1] = object.drawPreview(gc, offset); // return stateStack; // } /** * Clears the container. ** Note that erasePreview() cannot be called after this point to erase any previous * drawPreview()'s. *
*/ public void clear() { while (--nextIndex > 0) objectStack[nextIndex] = null; nextIndex = 0; } public void draw(FigureDrawContext fdc) { for (int i = 0; i < nextIndex; ++i) objectStack[i].draw(fdc); } public void addDamagedRegion(FigureDrawContext fdc, Region region) { for (int i = 0; i < nextIndex; ++i) objectStack[i].addDamagedRegion(fdc, region); } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ abstract class BasicPaintSession implements PaintSession { /** * The paint surface */ private PaintSurface paintSurface; /** * Constructs a PaintSession. * * @param paintSurface the drawing surface to use */ protected BasicPaintSession(PaintSurface paintSurface) { this.paintSurface = paintSurface; } /** * Returns the paint surface associated with this paint session. * * @return the associated PaintSurface */ public PaintSurface getPaintSurface() { return paintSurface; } } /******************************************************************************* * Copyright (c) 2000, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ /** * An airbrush tool. */ class AirbrushTool extends ContinuousPaintSession implements PaintTool { private ToolSettings settings; private Random random; private int cachedRadiusSquared; private int cachedNumPoints; /** * Constructs a Tool. * * @param toolSettings the new tool settings * @param paintSurface the PaintSurface we will render on. */ public AirbrushTool(ToolSettings toolSettings, PaintSurface paintSurface) { super(paintSurface); random = new Random(); setRetriggerTimer(10); set(toolSettings); } /** * Sets the tool's settings. * * @param toolSettings the new tool settings */ public void set(ToolSettings toolSettings) { // compute things we need to know for drawing settings = toolSettings; cachedRadiusSquared = settings.airbrushRadius * settings.airbrushRadius; cachedNumPoints = 314 * settings.airbrushIntensity * cachedRadiusSquared / 250000; if (cachedNumPoints == 0 && settings.airbrushIntensity != 0) cachedNumPoints = 1; } /** * Returns the name associated with this tool. * * @return the localized name of this tool */ public String getDisplayName() { return PaintExample.getResourceString("tool.Airbrush.label"); } /* * Template method for drawing */ protected void render(Point point) { // Draws a bunch (cachedNumPoints) of random pixels within a specified circle (cachedRadiusSquared). ContainerFigure cfig = new ContainerFigure(); for (int i = 0; i < cachedNumPoints; ++i) { int randX, randY; do { randX = (int) ((random.nextDouble() - 0.5) * settings.airbrushRadius * 2.0); randY = (int) ((random.nextDouble() - 0.5) * settings.airbrushRadius * 2.0); } while (randX * randX + randY * randY > cachedRadiusSquared); cfig.add(new PointFigure(settings.commonForegroundColor, point.x + randX, point.y + randY)); } getPaintSurface().drawFigure(cfig); } }