Mega Code Archive

 
Categories / Java / SWT Jface Eclipse
 

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);   } }