SWT Paint Example
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.accessibility.*;
import java.io.*;
import java.text.*;
import java.util.*;
public class PaintExample {
private Composite mainComposite;
private Canvas activeForegroundColorCanvas;
private Canvas activeBackgroundColorCanvas;
private Color paintColorBlack, paintColorWhite; // alias for paintColors[0] and [1]
private Color[] paintColors;
private Font paintDefaultFont; // do not free
private static final int numPaletteRows = 3;
private static final int numPaletteCols = 50;
private ToolSettings toolSettings; // current active settings
private PaintSurface paintSurface; // paint surface for drawing
static final int Pencil_tool = 0;
static final int Airbrush_tool = 1;
static final int Line_tool = 2;
static final int PolyLine_tool = 3;
static final int Rectangle_tool = 4;
static final int RoundedRectangle_tool = 5;
static final int Ellipse_tool = 6;
static final int Text_tool = 7;
static final int None_fill = 8;
static final int Outline_fill = 9;
static final int Solid_fill = 10;
static final int Solid_linestyle = 11;
static final int Dash_linestyle = 12;
static final int Dot_linestyle = 13;
static final int DashDot_linestyle = 14;
static final int Font_options = 15;
static final int Default_tool = Pencil_tool;
static final int Default_fill = None_fill;
static final int Default_linestyle = Solid_linestyle;
public static final Tool[] tools = {
new Tool(Pencil_tool, "Pencil", "tool", SWT.RADIO),
new Tool(Airbrush_tool, "Airbrush", "tool", SWT.RADIO),
new Tool(Line_tool, "Line", "tool", SWT.RADIO),
new Tool(PolyLine_tool, "PolyLine", "tool", SWT.RADIO),
new Tool(Rectangle_tool, "Rectangle", "tool", SWT.RADIO),
new Tool(RoundedRectangle_tool, "RoundedRectangle", "tool", SWT.RADIO),
new Tool(Ellipse_tool, "Ellipse", "tool", SWT.RADIO),
new Tool(Text_tool, "Text", "tool", SWT.RADIO),
new Tool(None_fill, "None", "fill", SWT.RADIO, new Integer(ToolSettings.ftNone)),
new Tool(Outline_fill, "Outline", "fill", SWT.RADIO, new Integer(ToolSettings.ftOutline)),
new Tool(Solid_fill, "Solid", "fill", SWT.RADIO, new Integer(ToolSettings.ftSolid)),
new Tool(Solid_linestyle, "Solid", "linestyle", SWT.RADIO, new Integer(SWT.LINE_SOLID)),
new Tool(Dash_linestyle, "Dash", "linestyle", SWT.RADIO, new Integer(SWT.LINE_DASH)),
new Tool(Dot_linestyle, "Dot", "linestyle", SWT.RADIO, new Integer(SWT.LINE_DOT)),
new Tool(DashDot_linestyle, "DashDot", "linestyle", SWT.RADIO, new Integer(SWT.LINE_DASHDOT)),
new Tool(Font_options, "Font", "options", SWT.PUSH)
};
/**
* Creates an instance of a PaintExample embedded inside
* the supplied parent Composite.
*
* @param parent the container of the example
*/
public PaintExample(Composite parent) {
mainComposite = parent;
initResources();
initActions();
init();
}
/**
* Invokes as a standalone program.
*/
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setText(getResourceString("window.title"));
shell.setLayout(new GridLayout());
PaintExample instance = new PaintExample(shell);
instance.createToolBar(shell);
Composite composite = new Composite(shell, SWT.NONE);
composite.setLayout(new FillLayout());
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
instance.createGUI(composite);
instance.setDefaults();
setShellSize(display, shell);
shell.open();
while (! shell.isDisposed()) {
if (! display.readAndDispatch()) display.sleep();
}
instance.dispose();
}
/**
* Creates the toolbar.
* Note: Only called by standalone.
*/
private void createToolBar(Composite parent) {
ToolBar toolbar = new ToolBar (parent, SWT.NONE);
String group = null;
for (int i = 0; i < tools.length; i++) {
Tool tool = tools[i];
if (group != null && !tool.group.equals(group)) {
new ToolItem (toolbar, SWT.SEPARATOR);
}
group = tool.group;
ToolItem item = addToolItem(toolbar, tool);
if (i == Default_tool || i == Default_fill || i == Default_linestyle) item.setSelection(true);
}
}
/**
* Adds a tool item to the toolbar.
* Note: Only called by standalone.
*/
private ToolItem addToolItem(final ToolBar toolbar, final Tool tool) {
final String id = tool.group + '.' + tool.name;
ToolItem item = new ToolItem (toolbar, tool.type);
item.setText (getResourceString(id + ".label"));
item.setToolTipText(getResourceString(id + ".tooltip"));
item.setImage(tool.image);
item.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
tool.action.run();
}
});
final int childID = toolbar.indexOf(item);
toolbar.getAccessible().addAccessibleListener(new AccessibleAdapter() {
public void getName(org.eclipse.swt.accessibility.AccessibleEvent e) {
if (e.childID == childID) {
e.result = getResourceString(id + ".description");
}
}
});
return item;
}
/**
* Sets the default tool item states.
*/
public void setDefaults() {
setPaintTool(Default_tool);
setFillType(Default_fill);
setLineStyle(Default_linestyle);
setForegroundColor(paintColorBlack);
setBackgroundColor(paintColorWhite);
}
/**
* Creates the GUI.
*/
public void createGUI(Composite parent) {
GridLayout gridLayout;
GridData gridData;
/*** Create principal GUI layout elements ***/
Composite displayArea = new Composite(parent, SWT.NONE);
gridLayout = new GridLayout();
gridLayout.numColumns = 1;
displayArea.setLayout(gridLayout);
// Creating these elements here avoids the need to instantiate the GUI elements
// in strict layout order. The natural layout ordering is an artifact of using
// SWT layouts, but unfortunately it is not the same order as that required to
// instantiate all of the non-GUI application elements to satisfy referential
// dependencies. It is possible to reorder the initialization to some extent, but
// this can be very tedious.
// paint canvas
final Canvas paintCanvas = new Canvas(displayArea, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL |
SWT.NO_REDRAW_RESIZE | SWT.NO_BACKGROUND);
gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.FILL_VERTICAL);
paintCanvas.setLayoutData(gridData);
paintCanvas.setBackground(paintColorWhite);
// color selector frame
final Composite colorFrame = new Composite(displayArea, SWT.NONE);
gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
colorFrame.setLayoutData(gridData);
// tool settings frame
final Composite toolSettingsFrame = new Composite(displayArea, SWT.NONE);
gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
toolSettingsFrame.setLayoutData(gridData);
// status text
final Text statusText = new Text(displayArea, SWT.BORDER | SWT.SINGLE | SWT.READ_ONLY);
gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL);
statusText.setLayoutData(gridData);
/*** Create the remaining application elements inside the principal GUI layout elements ***/
// paintSurface
paintSurface = new PaintSurface(paintCanvas, statusText, paintColorWhite);
// finish initializing the tool data
tools[Pencil_tool].data = new PencilTool(toolSettings, paintSurface);
tools[Airbrush_tool].data = new AirbrushTool(toolSettings, paintSurface);
tools[Line_tool].data = new LineTool(toolSettings, paintSurface);
tools[PolyLine_tool].data = new PolyLineTool(toolSettings, paintSurface);
tools[Rectangle_tool].data = new RectangleTool(toolSettings, paintSurface);
tools[RoundedRectangle_tool].data = new RoundedRectangleTool(toolSettings, paintSurface);
tools[Ellipse_tool].data = new EllipseTool(toolSettings, paintSurface);
tools[Text_tool].data = new TextTool(toolSettings, paintSurface);
// colorFrame
gridLayout = new GridLayout();
gridLayout.numColumns = 3;
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
colorFrame.setLayout(gridLayout);
// activeForegroundColorCanvas, activeBackgroundColorCanvas
activeForegroundColorCanvas = new Canvas(colorFrame, SWT.BORDER);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.heightHint = 24;
gridData.widthHint = 24;
activeForegroundColorCanvas.setLayoutData(gridData);
activeBackgroundColorCanvas = new Canvas(colorFrame, SWT.BORDER);
gridData = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
gridData.heightHint = 24;
gridData.widthHint = 24;
activeBackgroundColorCanvas.setLayoutData(gridData);
// paletteCanvas
final Canvas paletteCanvas = new Canvas(colorFrame, SWT.BORDER | SWT.NO_BACKGROUND);
gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.heightHint = 24;
paletteCanvas.setLayoutData(gridData);
paletteCanvas.addListener(SWT.MouseDown, new Listener() {
public void handleEvent(Event e) {
Rectangle bounds = paletteCanvas.getClientArea();
Color color = getColorAt(bounds, e.x, e.y);
if (e.button == 1) setForegroundColor(color);
else setBackgroundColor(color);
}
private Color getColorAt(Rectangle bounds, int x, int y) {
if (bounds.height <= 1 && bounds.width <= 1) return paintColorWhite;
final int row = (y - bounds.y) * numPaletteRows / bounds.height;
final int col = (x - bounds.x) * numPaletteCols / bounds.width;
return paintColors[Math.min(Math.max(row * numPaletteCols + col, 0), paintColors.length - 1)];
}
});
Listener refreshListener = new Listener() {
public void handleEvent(Event e) {
if (e.gc == null) return;
Rectangle bounds = paletteCanvas.getClientArea();
for (int row = 0; row < numPaletteRows; ++row) {
for (int col = 0; col < numPaletteCols; ++col) {
final int x = bounds.width * col / numPaletteCols;
final int y = bounds.height * row / numPaletteRows;
final int width = Math.max(bounds.width * (col + 1) / numPaletteCols - x, 1);
final int height = Math.max(bounds.height * (row + 1) / numPaletteRows - y, 1);
e.gc.setBackground(paintColors[row * numPaletteCols + col]);
e.gc.fillRectangle(bounds.x + x, bounds.y + y, width, height);
}
}
}
};
paletteCanvas.addListener(SWT.Resize, refreshListener);
paletteCanvas.addListener(SWT.Paint, refreshListener);
//paletteCanvas.redraw();
// toolSettingsFrame
gridLayout = new GridLayout();
gridLayout.numColumns = 4;
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
toolSettingsFrame.setLayout(gridLayout);
Label label = new Label(toolSettingsFrame, SWT.NONE);
label.setText(getResourceString("settings.AirbrushRadius.text"));
final Scale airbrushRadiusScale = new Scale(toolSettingsFrame, SWT.HORIZONTAL);
airbrushRadiusScale.setMinimum(5);
airbrushRadiusScale.setMaximum(50);
airbrushRadiusScale.setSelection(toolSettings.airbrushRadius);
airbrushRadiusScale.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL));
airbrushRadiusScale.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
toolSettings.airbrushRadius = airbrushRadiusScale.getSelection();
updateToolSettings();
}
});
label = new Label(toolSettingsFrame, SWT.NONE);
label.setText(getResourceString("settings.AirbrushIntensity.text"));
final Scale airbrushIntensityScale = new Scale(toolSettingsFrame, SWT.HORIZONTAL);
airbrushIntensityScale.setMinimum(1);
airbrushIntensityScale.setMaximum(100);
airbrushIntensityScale.setSelection(toolSettings.airbrushIntensity);
airbrushIntensityScale.setLayoutData(new GridData(GridData.FILL_HORIZONTAL | GridData.VERTICAL_ALIGN_FILL));
airbrushIntensityScale.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
toolSettings.airbrushIntensity = airbrushIntensityScale.getSelection();
updateToolSettings();
}
});
}
/**
* Disposes of all resources associated with a particular
* instance of the PaintExample.
*/
public void dispose() {
if (paintSurface != null) paintSurface.dispose();
if (paintColors != null) {
for (int i = 0; i < paintColors.length; ++i) {
final Color color = paintColors[i];
if (color != null) color.dispose();
}
}
paintDefaultFont = null;
paintColors = null;
paintSurface = null;
freeResources();
}
/**
* Frees the resource bundle resources.
*/
public void freeResources() {
for (int i = 0; i < tools.length; ++i) {
Tool tool = tools[i];
final Image image = tool.image;
if (image != null) image.dispose();
tool.image = null;
}
}
/**
* Returns the Display.
*
* @return the display we're using
*/
public Display getDisplay() {
return mainComposite.getDisplay();
}
/**
* Gets a string from the resource bundle.
* We don't want to crash because of a missing String.
* Returns the key if not found.
*/
public static String getResourceString(String key) {
return key;
}
/**
* Gets a string from the resource bundle and binds it
* with the given arguments. If the key is not found,
* return the key.
*/
public static String getResourceString(String key, Object[] args) {
try {
return MessageFormat.format(getResourceString(key), args);
} catch (MissingResourceException e) {
return key;
} catch (NullPointerException e) {
return "!" + key + "!";
}
}
/**
* Initialize colors, fonts, and tool settings.
*/
private void init() {
Display display = mainComposite.getDisplay();
paintColorWhite = new Color(display, 255, 255, 255);
paintColorBlack = new Color(display, 0, 0, 0);
paintDefaultFont = display.getSystemFont();
paintColors = new Color[numPaletteCols * numPaletteRows];
paintColors[0] = paintColorBlack;
paintColors[1] = paintColorWhite;
for (int i = 2; i < paintColors.length; i++) {
paintColors[i] = new Color(display,
((i*7)%255),((i*23)%255), ((i*51)%255));
}
toolSettings = new ToolSettings();
toolSettings.commonForegroundColor = paintColorBlack;
toolSettings.commonBackgroundColor = paintColorWhite;
toolSettings.commonFont = paintDefaultFont;
}
/**
* Sets the action field of the tools
*/
private void initActions() {
for (int i = 0; i < tools.length; ++i) {
final Tool tool = tools[i];
String group = tool.group;
if (group.equals("tool")) {
tool.action = new Runnable() {
public void run() {
setPaintTool(tool.id);
}
};
} else if (group.equals("fill")) {
tool.action = new Runnable() {
public void run() {
setFillType(tool.id);
}
};
} else if (group.equals("linestyle")) {
tool.action = new Runnable() {
public void run() {
setLineStyle(tool.id);
}
};
} else if (group.equals("options")) {
tool.action = new Runnable() {
public void run() {
FontDialog fontDialog = new FontDialog(paintSurface.getShell(), SWT.PRIMARY_MODAL);
FontData[] fontDatum = toolSettings.commonFont.getFontData();
if (fontDatum != null && fontDatum.length > 0) {
fontDialog.setFontList(fontDatum);
}
fontDialog.setText(getResourceString("options.Font.dialog.title"));
paintSurface.hideRubberband();
FontData fontData = fontDialog.open();
paintSurface.showRubberband();
if (fontData != null) {
try {
Font font = new Font(mainComposite.getDisplay(), fontData);
toolSettings.commonFont = font;
updateToolSettings();
} catch (SWTException ex) {
}
}
}
};
}
}
}
/**
* Loads the image resources.
*/
public void initResources() {
final Class clazz = PaintExample.class;
try {
for (int i = 0; i < tools.length; ++i) {
Tool tool = tools[i];
String id = tool.group + '.' + tool.name;
InputStream sourceStream = clazz.getResourceAsStream(getResourceString(id + ".image"));
ImageData source = new ImageData(sourceStream);
ImageData mask = source.getTransparencyMask();
tool.image = new Image(null, source, mask);
try {
sourceStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return;
} catch (Throwable t) {
}
String error = "Unable to load resources";
freeResources();
throw new RuntimeException(error);
}
/**
* Grabs input focus.
*/
public void setFocus() {
mainComposite.setFocus();
}
/**
* Sets the tool foreground color.
*
* @param color the new color to use
*/
public void setForegroundColor(Color color) {
if (activeForegroundColorCanvas != null)
activeForegroundColorCanvas.setBackground(color);
toolSettings.commonForegroundColor = color;
updateToolSettings();
}
/**
* Set the tool background color.
*
* @param color the new color to use
*/
public void setBackgroundColor(Color color) {
if (activeBackgroundColorCanvas != null)
activeBackgroundColorCanvas.setBackground(color);
toolSettings.commonBackgroundColor = color;
updateToolSettings();
}
/**
* Selects a tool given its ID.
*/
public void setPaintTool(int id) {
PaintTool paintTool = (PaintTool) tools[id].data;
paintSurface.setPaintSession(paintTool);
updateToolSettings();
}
/**
* Selects a filltype given its ID.
*/
public void setFillType(int id) {
Integer fillType = (Integer) tools[id].data;
toolSettings.commonFillType = fillType.intValue();
updateToolSettings();
}
/**
* Selects line type given its ID.
*/
public void setLineStyle(int id) {
Integer lineType = (Integer) tools[id].data;
toolSettings.commonLineStyle = lineType.intValue();
updateToolSettings();
}
/**
* Sets the size of the shell to it's "packed" size,
* unless that makes it bigger than the display,
* in which case set it to 9/10 of display size.
*/
private static void setShellSize (Display display, Shell shell) {
Rectangle bounds = display.getBounds();
Point size = shell.computeSize (SWT.DEFAULT, SWT.DEFAULT);
if (size.x > bounds.width) size.x = bounds.width * 9 / 10;
if (size.y > bounds.height) size.y = bounds.height * 9 / 10;
shell.setSize (size);
}
/**
* Notifies the tool that its settings have changed.
*/
private void updateToolSettings() {
final PaintTool activePaintTool = paintSurface.getPaintTool();
if (activePaintTool == null) return;
activePaintTool.endSession();
activePaintTool.set(toolSettings);
activePaintTool.beginSession();
}
}
/*******************************************************************************
* 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
*******************************************************************************/
/**
* Tool Settings objects group tool-related configuration information.
*/
class ToolSettings {
public static final int ftNone = 0, ftOutline = 1, ftSolid = 2;
/**
* commonForegroundColor: current tool foreground colour
*/
public Color commonForegroundColor;
/**
* commonBackgroundColor: current tool background colour
*/
public Color commonBackgroundColor;
/**
* commonFont: current font
*/
public Font commonFont;
/**
* commonFillType: current fill type
* <p>One of ftNone, ftOutline, ftSolid.</p>
*/
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.
* <p>
* paintCanvas must have SWT.NO_REDRAW_RESIZE and SWT.NO_BACKGROUND styles,
* and may have SWT.V_SCROLL and/or SWT.H_SCROLL.
* </p>
* @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.
* <p>
* If oldPaintSession != paintSession calls oldPaintSession.end()
* and paintSession.begin()
* </p>
*
* @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.
* <p>
* This object will be drawn to the screen as a preview and refreshed appropriately
* until the selection is either cleared or committed.
* </p>
*
* @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.
* <p>
* Erases any rubberband objects on the screen then clears the selection.
* </p>
*/
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.
* <p>
* Redraws any rubberband objects on the screen as permanent objects then clears the selection.
* </p>
*/
public void commitRubberbandSelection() {
rubberband.draw(imageFDC);
if (isRubberbandHidden()) rubberband.draw(displayFDC);
rubberband.clear();
}
/**
* Hides the rubberband (but does not eliminate it).
* <p>
* Increments by one the rubberband "hide" nesting count. The rubberband
* is hidden from view (but remains active) if it wasn't already hidden.
* </p>
*/
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.
* <p>
* 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.
* </p>
*/
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 {
/*
* <p>
* The GC must be set up as follows
* (it will be returned to this state upon completion of drawing operations)
* <ul>
* <li>setXORMode(false)
* </ul>
* </p>
*/
public GC gc = null;
public int xOffset = 0, yOffset = 0; // substract to get GC coords
public int xScale = 1, yScale = 1;
public Rectangle toClientRectangle(int x1, int y1, int x2, int y2) {
return new Rectangle(
Math.min(x1, x2) * xScale - xOffset,
Math.min(y1, y2) * yScale - yOffset,
(Math.abs(x2 - x1) + 1) * xScale,
(Math.abs(y2 - y1) + 1) * yScale);
}
public Point toClientPoint(int x, int y) {
return new Point(x * xScale - xOffset, y * yScale - yOffset);
}
}
/*******************************************************************************
* 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
*******************************************************************************/
/**
* Superinterface for all drawing objects.
* All drawing objects know how to render themselved to the screen and can draw a
* temporary version of themselves for previewing the general appearance of the
* object onscreen before it gets committed.
*/
abstract class Figure {
/**
* Draws this object.
*
* @param fdc a parameter block specifying drawing-related information
*/
public abstract void draw(FigureDrawContext fdc);
/**
* Computes the damaged screen region caused by drawing this object (imprecise), then
* appends it to the supplied region.
*
* @param fdc a parameter block specifying drawing-related information
* @param region a region to which additional damage areas will be added
*/
public abstract void addDamagedRegion(FigureDrawContext fdc, Region 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
*******************************************************************************/
/**
* A drawing tool.
*/
class EllipseTool extends DragPaintSession implements PaintTool {
private ToolSettings settings;
/**
* Constructs a EllipseTool.
*
* @param toolSettings the new tool settings
* @param paintSurface the PaintSurface we will render on.
*/
public EllipseTool(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.Ellipse.label");
}
/*
* Template methods for drawing
*/
protected Figure createFigure(Point a, Point b) {
ContainerFigure container = new ContainerFigure();
if (settings.commonFillType != ToolSettings.ftNone)
container.add(new SolidEllipseFigure(settings.commonBackgroundColor, a.x, a.y, b.x, b.y));
if (settings.commonFillType != ToolSettings.ftSolid)
container.add(new EllipseFigure(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 Ellipse object
*/
class EllipseFigure extends Figure {
private Color foregroundColor, backgroundColor;
private int lineStyle, x1, y1, x2, y2;
/**
* Constructs an Ellipse
* These objects are defined by any two diametrically opposing corners of a box
* bounding the ellipse.
*
* @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 EllipseFigure(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.drawOval(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
*******************************************************************************/
/**
* The superclass for paint tools that use click-drag-release motions to
* draw objects.
*/
abstract class DragPaintSession extends BasicPaintSession {
/**
* True if a click-drag is in progress
*/
private boolean dragInProgress = false;
/**
* The position of the first click in a click-drag
*/
private Point anchorPosition = new Point(-1, -1);
/**
* A temporary point
*/
private Point tempPosition = new Point(-1, -1);
/**
* Constructs a PaintSession.
*
* @param getPaintSurface() the drawing surface to use
*/
protected DragPaintSession(PaintSurface paintSurface) {
super(paintSurface);
}
/**
* Activates the tool.
*/
public void beginSession() {
getPaintSurface().
setStatusMessage(PaintExample.getResourceString("session.DragInteractivePaint.message"));
anchorPosition.x = -1;
dragInProgress = false;
}
/**
* Deactivates the tool.
*/
public void endSession() {
}
/**
* Resets the tool.
* Aborts any operation in progress.
*/
public void resetSession() {
getPaintSurface().clearRubberbandSelection();
anchorPosition.x = -1;
dragInProgress = false;
}
/**
* Handles a mouseDown event.
*
* @param event the mouse event detail information
*/
public void mouseDown(MouseEvent event) {
if (event.button != 1) return;
if (dragInProgress) return; // spurious event
dragInProgress = true;
anchorPosition.x = event.x;
anchorPosition.y = event.y;
}
/**
* 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) {
if (event.button != 1) {
resetSession(); // abort if right or middle mouse button pressed
return;
}
if (! dragInProgress) return; // spurious event
dragInProgress = false;
if (anchorPosition.x == -1) return; // spurious event
getPaintSurface().commitRubberbandSelection();
}
/**
* Handles a mouseMove event.
*
* @param event the mouse event detail information
*/
public void mouseMove(MouseEvent event) {
final PaintSurface ps = getPaintSurface();
if (! dragInProgress) {
ps.setStatusCoord(ps.getCurrentPosition());
return;
}
ps.setStatusCoordRange(anchorPosition, ps.getCurrentPosition());
ps.clearRubberbandSelection();
tempPosition.x = event.x;
tempPosition.y = event.y;
ps.addRubberbandSelection(createFigure(anchorPosition, tempPosition));
}
/**
* Template Method: Creates a Figure for drawing rubberband entities and the final product
*
* @param anchor the anchor point
* @param cursor the point marking the current pointer location
*/
protected abstract Figure createFigure(Point anchor, Point cursor);
}
/*******************************************************************************
* 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 draw continuously along the path
* traced by the mouse's movement while the button is depressed
*/
abstract class ContinuousPaintSession extends BasicPaintSession {
/**
* True if a click-drag is in progress.
*/
private boolean dragInProgress = false;
/**
* A cached Point array for drawing.
*/
private Point[] points = new Point[] { new Point(-1, -1), new Point(-1, -1) };
/**
* The time to wait between retriggers in milliseconds.
*/
private int retriggerInterval = 0;
/**
* The currently valid RetriggerHandler
*/
protected Runnable retriggerHandler = null;
/**
* Constructs a ContinuousPaintSession.
*
* @param paintSurface the drawing surface to use
*/
protected ContinuousPaintSession(PaintSurface paintSurface) {
super(paintSurface);
}
/**
* Sets the retrigger timer.
* <p>
* 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.
* </p>
* @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.
* <p>
* Note that erasePreview() cannot be called after this point to erase any previous
* drawPreview()'s.
* </p>
*/
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);
}
}
Related examples in the same category