SWT Paint Example

 

SWT Paint Example : 2D « SWT JFace Eclipse « Java

 

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


      

 

경축! 아무것도 안하여 에스천사게임즈가 새로운 모습으로 재오픈 하였습니다.
어린이용이며, 설치가 필요없는 브라우저 게임입니다.
https://s1004games.com

 

[출처] http://www.java2s.com/Code/Java/SWT-JFace-Eclipse/SWTPaintExample.htm

본 웹사이트는 광고를 포함하고 있습니다.
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.
대표 김성준 주소 : 경기 용인 분당수지 U타워 등록번호 : 142-07-27414
통신판매업 신고 : 제2012-용인수지-0185호 출판업 신고 : 수지구청 제 123호 개인정보보호최고책임자 : 김성준 sjkim70@stechstar.com
대표전화 : 010-4589-2193 [fax] 02-6280-1294 COPYRIGHT(C) stechstar.com ALL RIGHTS RESERVED