package com.kreative.paint.tool; import java.awt.Cursor; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.KeyEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import com.kreative.paint.Layer; import com.kreative.paint.datatransfer.ClipboardUtilities; import com.kreative.paint.document.draw.DrawObject; import com.kreative.paint.geom.BitmapShape; import com.kreative.paint.util.CursorUtils; import com.kreative.paint.util.ImageUtils; public abstract class MarqueeTool extends AbstractPaintSelectionTool { private boolean definingSelection = false; private boolean draggingSelection = false; // interface to implementing classes protected boolean selectAllLasso() { return false; } protected boolean toolSelectedImpl(ToolEvent e) { return false; } protected boolean toolDeselectedImpl(ToolEvent e) { return false; } protected boolean mousePressedImpl(ToolEvent e) { return false; } protected boolean mouseHeldImpl(ToolEvent e) { return false; } protected boolean mouseClickedImpl(ToolEvent e) { return false; } protected boolean mouseDraggedImpl(ToolEvent e) { return false; } protected boolean mouseReleasedImpl(ToolEvent e) { return false; } protected boolean keyPressedImpl(ToolEvent e) { return false; } protected boolean keyTypedImpl(ToolEvent e) { return false; } protected boolean keyReleasedImpl(ToolEvent e) { return false; } protected boolean paintIntermediateImpl(ToolEvent e, Graphics2D g) { return false; } protected boolean shiftConstrainsCoordinatesImpl() { return false; } protected Cursor getDefaultCursor() { return CursorUtils.CURSOR_SELECT; } protected final void beginSelection(ToolEvent e) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Select")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); definingSelection = true; } protected final void commitSelection(ToolEvent e, Shape s) { if (e.isCtrlDown() && e.isAltDown()) e.getCanvas().xorPaintSelection(s); else if (e.isCtrlDown()) e.getCanvas().addPaintSelection(s); else if (e.isAltDown()) e.getCanvas().subtractPaintSelection(s); else e.getCanvas().setPaintSelection(s); e.getCanvas().pushPaintSelection(); e.commitTransaction(); definingSelection = false; } protected final void rollbackSelection(ToolEvent e) { e.rollbackTransaction(); definingSelection = false; } protected final boolean isSelectionInProgress() { return definingSelection; } // interface to Tool public final boolean paintIntermediateUsesCanvasCoordinates() { return true; } public final boolean toolSelected(ToolEvent e) { return toolSelectedImpl(e); } public final boolean toolDeselected(ToolEvent e) { return toolDeselectedImpl(e); } public final boolean toolDoubleClicked(ToolEvent e) { if (!definingSelection && !draggingSelection) { e.beginTransaction(ToolUtilities.messages.getString("marquee.SelectAll")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); if (selectAllLasso()) { Layer l = e.getLayer(); if (l == null) { e.getCanvas().setPaintSelection(null); } else { Rectangle r = new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight()); boolean empty = true; int[] rgb = new int[r.width * r.height]; l.getRGB(r.x-l.getX(), r.y-l.getY(), r.width, r.height, rgb, 0, r.width); for (int ay = 0; ay < rgb.length; ay += r.width) { for (int ax = 0; ax < r.width; ax++) { if ((rgb[ay+ax] & 0xFF000000) != 0) { empty = false; rgb[ay+ax] = 0xFF000000; } else { rgb[ay+ax] = 0; } } } if (empty) { e.getCanvas().setPaintSelection(null); } else { e.getCanvas().setPaintSelection(new BitmapShape(rgb, r.x, r.y, r.width, r.height)); } } } else { e.getCanvas().setPaintSelection(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight())); } e.getCanvas().pushPaintSelection(); e.commitTransaction(); return true; } else { return false; } } public final boolean toolSettingsChanged(ToolEvent e) { return false; } public final boolean paintSettingsChanged(ToolEvent e) { return false; } public final boolean mouseEntered(ToolEvent e) { return false; } public final boolean mouseMoved(ToolEvent e) { return false; } public final boolean mouseExited(ToolEvent e) { return false; } public final boolean mousePressed(ToolEvent e) { if (definingSelection) { return mousePressedImpl(e); } else if (draggingSelection) { return false; } else { Shape ps = e.getCanvas().getPaintSelection(); if (ps != null && ps.contains(e.getCanvasX(), e.getCanvasY())) { if (e.isCtrlDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Select")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); } else if (e.isAltDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().popPaintSelection(false, true); } else { e.beginTransaction(ToolUtilities.messages.getString("marquee.Move")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } if (!e.getCanvas().isPaintSelectionPopped()) { e.getCanvas().popPaintSelection(false, false); } } draggingSelection = true; return true; } else { return mousePressedImpl(e); } } } public final boolean mouseHeld(ToolEvent e) { if (definingSelection) { return mouseHeldImpl(e); } else if (draggingSelection) { return false; } else { return mouseHeldImpl(e); } } public final boolean mouseClicked(ToolEvent e) { if (definingSelection) { return mouseClickedImpl(e); } else if (draggingSelection) { return false; } else { return mouseClickedImpl(e); } } public final boolean mouseDragged(ToolEvent e) { if (definingSelection) { return mouseDraggedImpl(e); } else if (draggingSelection) { e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(e.getCanvasX()-e.getCanvasPreviousX(), e.getCanvasY()-e.getCanvasPreviousY())); return true; } else { return mouseDraggedImpl(e); } } public final boolean mouseReleased(ToolEvent e) { if (definingSelection) { return mouseReleasedImpl(e); } else if (draggingSelection) { e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(e.getCanvasX()-e.getCanvasPreviousX(), e.getCanvasY()-e.getCanvasPreviousY())); e.commitTransaction(); draggingSelection = false; return true; } else { return mouseReleasedImpl(e); } } public final boolean keyPressed(ToolEvent e) { if (definingSelection) { return keyPressedImpl(e); } else if (draggingSelection) { return false; } else { switch (e.getKeyCode()) { case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: e.beginTransaction(ToolUtilities.messages.getString("marquee.Clear")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().deletePaintSelection(false); if (!e.isCtrlDown() && !e.isAltDown()) e.getCanvas().clearPaintSelection(); e.commitTransaction(); return true; case KeyEvent.VK_ESCAPE: case KeyEvent.VK_CLEAR: e.beginTransaction(ToolUtilities.messages.getString("marquee.DeselectAll")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().clearPaintSelection(); e.commitTransaction(); return true; case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: if (e.isCtrlDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Select")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); } else if (e.isAltDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().popPaintSelection(false, true); } else { e.beginTransaction(ToolUtilities.messages.getString("marquee.Move")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } if (!e.getCanvas().isPaintSelectionPopped()) { e.getCanvas().popPaintSelection(false, false); } } nudge(e); e.commitTransaction(); return true; default: return keyPressedImpl(e); } } } public final boolean keyTyped(ToolEvent e) { if (definingSelection) { return keyTypedImpl(e); } else if (draggingSelection) { return false; } else { return keyTypedImpl(e); } } public final boolean keyReleased(ToolEvent e) { if (definingSelection) { return keyReleasedImpl(e); } else if (draggingSelection) { return false; } else { return keyReleasedImpl(e); } } public final boolean respondsToCommand(ToolEvent e) { switch (e.getCommand()) { case CUT: case COPY: case PASTE: case CLEAR: case DUPLICATE: case SELECT_ALL: case DESELECT_ALL: case INVERT_SELECTION: return true; default: return false; } } public final boolean enableCommand(ToolEvent e) { switch (e.getCommand()) { case CUT: case COPY: case CLEAR: case DUPLICATE: return (e.getCanvas().getPaintSelection() != null); case PASTE: return ClipboardUtilities.clipboardHasImage(); case SELECT_ALL: case DESELECT_ALL: case INVERT_SELECTION: return true; default: return false; } } public final boolean doCommand(ToolEvent e) { switch (e.getCommand()) { case CUT: e.beginTransaction(ToolUtilities.messages.getString("marquee.Cut")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } ClipboardUtilities.setClipboardImage(e.getCanvas().copyPaintSelection()); e.getCanvas().deletePaintSelection(false); e.getCanvas().clearPaintSelection(); e.commitTransaction(); return true; case COPY: ClipboardUtilities.setClipboardImage(e.getCanvas().copyPaintSelection()); return false; case PASTE: Image pasteImage = ClipboardUtilities.getClipboardImage(); if (ImageUtils.prepImage(pasteImage)) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Paste")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pastePaintSelection(pasteImage, AffineTransform.getTranslateInstance(Math.round(e.getCanvasPreviousClickedX()-pasteImage.getWidth(null)/2.0), Math.round(e.getCanvasPreviousClickedY()-pasteImage.getHeight(null)/2.0))); e.commitTransaction(); } else { System.err.println("Error: Failed to paste image."); } return true; case CLEAR: e.beginTransaction(ToolUtilities.messages.getString("marquee.Clear")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().deletePaintSelection(false); e.getCanvas().clearPaintSelection(); e.commitTransaction(); return true; case DUPLICATE: e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().popPaintSelection(false, true); e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(8, 8)); e.commitTransaction(); return true; case SELECT_ALL: e.beginTransaction(ToolUtilities.messages.getString("marquee.SelectAll")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); e.getCanvas().setPaintSelection(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight())); e.getCanvas().pushPaintSelection(); e.commitTransaction(); return true; case DESELECT_ALL: e.beginTransaction(ToolUtilities.messages.getString("marquee.DeselectAll")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().clearPaintSelection(); e.commitTransaction(); return true; case INVERT_SELECTION: e.beginTransaction(ToolUtilities.messages.getString("marquee.InvertSelection")); for (Layer l : e.getCanvas()) { for (DrawObject o : l) { if (o.isSelected()) o.setSelected(false); } } e.getCanvas().pushPaintSelection(); Area invertSelection = new Area(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight())); invertSelection.exclusiveOr(new Area(e.getCanvas().getPaintSelection())); e.getCanvas().setPaintSelection(invertSelection); e.getCanvas().pushPaintSelection(); e.commitTransaction(); return true; default: return false; } } public final boolean paintIntermediate(ToolEvent e, Graphics2D g) { return paintIntermediateImpl(e,g); } public final boolean shiftConstrainsCoordinates() { return draggingSelection || shiftConstrainsCoordinatesImpl(); } private void nudge(ToolEvent e) { float n = e.isShiftDown() ? 8 : 1; switch (e.getKeyCode()) { case KeyEvent.VK_LEFT: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(-n, 0)); break; case KeyEvent.VK_RIGHT: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(n, 0)); break; case KeyEvent.VK_UP: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(0, -n)); break; case KeyEvent.VK_DOWN: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(0, n)); break; } } public final Cursor getCursor(ToolEvent e) { if (definingSelection) { return getDefaultCursor(); } else if (draggingSelection) { if (e.isCtrlDown()) { return CursorUtils.CURSOR_MOVE_SELECT; } else if (e.isAltDown()) { return CursorUtils.CURSOR_ARROW_HALF_DOUBLE_HALLOW; } else { return CursorUtils.CURSOR_MOVE; } } else { Shape ps = e.getCanvas().getPaintSelection(); if (ps != null && ps.contains(e.getCanvasX(), e.getCanvasY())) { if (e.isCtrlDown()) { return CursorUtils.CURSOR_MOVE_SELECT; } else if (e.isAltDown()) { return CursorUtils.CURSOR_ARROW_HALF_DOUBLE_HALLOW; } else { return CursorUtils.CURSOR_MOVE; } } else { return getDefaultCursor(); } } } }