blob: 19a10a4597441ed77af17aab22cb75679fa4dafe [file] [log] [blame]
/*******************************************************************************
* 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
*******************************************************************************/
package org.eclipse.swt.examples.paint;
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 static ResourceBundle resourceBundle =
ResourceBundle.getBundle("examples_paint");
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) {
try {
return resourceBundle.getString(key);
} catch (MissingResourceException e) {
return key;
} catch (NullPointerException e) {
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;
if (resourceBundle != null) {
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 = (resourceBundle != null) ?
getResourceString("error.CouldNotLoadResources") :
"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();
}
}