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 java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.util.Collection; import java.util.IdentityHashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Vector; import com.kreative.paint.Canvas; import com.kreative.paint.Layer; import com.kreative.paint.datatransfer.ClipboardUtilities; import com.kreative.paint.document.draw.DrawObject; import com.kreative.paint.document.draw.DrawSurface; import com.kreative.paint.document.draw.ImageDrawObject; import com.kreative.paint.document.draw.PaintSettings; import com.kreative.paint.document.draw.TextDrawObject; import com.kreative.paint.util.CursorUtils; import com.kreative.paint.util.ImageUtils; public class PaintDrawMarqueeTool extends AbstractPaintDrawSelectionTool implements ToolOptions.DrawSquare, ToolOptions.DrawFromCenter { private static final int K = 0xFF000000; private static final Image icon = ToolUtilities.makeIcon( 16, 16, new int[] { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K, 0,K,0,0,0,0,0,0,0,0,0,0,0,0,0,K, 0,0,0,K,K,0,0,K,K,K,0,0,K,K,0,0, 0,0,0,K,0,0,0,0,0,0,0,0,0,K,0,0, 0,K,0,0,0,0,0,0,0,0,0,0,0,K,0,K, 0,K,0,0,0,0,0,0,0,0,0,0,0,0,0,K, 0,K,0,K,0,0,0,0,0,0,0,0,0,0,0,K, 0,0,0,K,0,0,0,0,0,0,0,0,0,K,0,0, 0,0,0,K,K,0,0,K,K,K,0,0,K,K,0,0, 0,K,0,0,0,0,0,0,0,0,0,0,0,0,0,K, 0,K,K,K,0,0,0,K,K,K,0,0,0,K,K,K, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, } ); protected Image getBWIcon() { return icon; } private boolean definingSelection = false; private boolean draggingSelection = false; private Rectangle2D makeShape(ToolEvent e, float sx, float sy, float x, float y) { return new Rectangle2D.Float(Math.min(x,sx), Math.min(y,sy), Math.abs(x-sx), Math.abs(y-sy)); } private Rectangle2D makeShape1(ToolEvent e) { float sx = e.getCanvasPreviousClickedX(); float sy = e.getCanvasPreviousClickedY(); float x = e.getCanvasX(); float y = e.getCanvasY(); if (e.isShiftDown() != e.tc().drawSquare()) { float w = Math.abs(x-sx); float h = Math.abs(y-sy); float s = Math.max(w, h); if (y > sy) y = sy+s; else y = sy-s; if (x > sx) x = sx+s; else x = sx-s; } if (e.tc().drawFromCenter()) { sx -= (x-sx); sy -= (y-sy); } return makeShape(e, sx, sy, x, y); } private Rectangle2D makeShape2(ToolEvent e) { float sx = e.getPreviousClickedX(); float sy = e.getPreviousClickedY(); float x = e.getX(); float y = e.getY(); if (e.isShiftDown() != e.tc().drawSquare()) { float w = Math.abs(x-sx); float h = Math.abs(y-sy); float s = Math.max(w, h); if (y > sy) y = sy+s; else y = sy-s; if (x > sx) x = sx+s; else x = sx-s; } if (e.tc().drawFromCenter()) { sx -= (x-sx); sy -= (y-sy); } return makeShape(e, sx, sy, x, y); } public boolean toolDoubleClicked(ToolEvent e) { e.beginTransaction(ToolUtilities.messages.getString("marquee.SelectAll")); e.getCanvas().pushPaintSelection(); e.getCanvas().setPaintSelection(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight())); e.getCanvas().pushPaintSelection(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(true); } e.commitTransaction(); return true; } public boolean mousePressed(ToolEvent e) { if (isInSelection(e)) { if (e.isAltDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); e.getCanvas().popPaintSelection(false, true); DrawSurface d = e.getDrawSurface(); List<DrawObject> sel = new Vector<DrawObject>(); for (DrawObject o : d) { if (o.isSelected()) { o.setSelected(false); o = o.clone(); o.setSelected(true); o.setVisible(true); o.setLocked(false); sel.add(o); } } d.addAll(sel); } else { e.beginTransaction(ToolUtilities.messages.getString("marquee.Move")); if (!e.getCanvas().isPaintSelectionPopped()) { e.getCanvas().popPaintSelection(false, false); } } definingSelection = false; draggingSelection = true; return true; } else { e.beginTransaction(ToolUtilities.messages.getString("marquee.Select")); e.getCanvas().pushPaintSelection(); definingSelection = true; draggingSelection = false; return true; } } public boolean mouseDragged(ToolEvent e) { if (draggingSelection) { e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(e.getCanvasX()-e.getCanvasPreviousX(), e.getCanvasY()-e.getCanvasPreviousY())); DrawSurface d = e.getDrawSurface(); for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) { Point2D p = o.getLocation(); p = new Point2D.Double( p.getX()+e.getCanvasX()-e.getCanvasPreviousX(), p.getY()+e.getCanvasY()-e.getCanvasPreviousY() ); o.setLocation(p); } } return true; } else { return false; } } public boolean mouseReleased(ToolEvent e) { if (draggingSelection) { e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(e.getCanvasX()-e.getCanvasPreviousX(), e.getCanvasY()-e.getCanvasPreviousY())); DrawSurface d = e.getDrawSurface(); for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) { Point2D p = o.getLocation(); p = new Point2D.Double( p.getX()+e.getCanvasX()-e.getCanvasPreviousX(), p.getY()+e.getCanvasY()-e.getCanvasPreviousY() ); o.setLocation(p); } } e.commitTransaction(); definingSelection = false; draggingSelection = false; return true; } else if (definingSelection) { Shape s = makeShape1(e); 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(); DrawSurface d = e.getDrawSurface(); Point2D.Float p = new Point2D.Float(e.getX(), e.getY()); Rectangle2D r = makeShape2(e); if (r.isEmpty()) { if (e.isCtrlDown() && e.isAltDown()) { ListIterator<DrawObject> oi = d.listIterator(d.size()); while (oi.hasPrevious()) { DrawObject o = oi.previous(); if (o.contains(p)) { o.setSelected(!o.isSelected()); break; } } } else if (e.isCtrlDown()) { ListIterator<DrawObject> oi = d.listIterator(d.size()); while (oi.hasPrevious()) { DrawObject o = oi.previous(); if (o.contains(p)) { o.setSelected(true); break; } } } else if (e.isAltDown()) { ListIterator<DrawObject> oi = d.listIterator(d.size()); while (oi.hasPrevious()) { DrawObject o = oi.previous(); if (o.contains(p)) { o.setSelected(false); break; } } } else { for (DrawObject o : d) { o.setSelected(o.contains(p)); } } } else { if (e.isCtrlDown() && e.isAltDown()) { for (DrawObject o : d) { if (o.intersects(r)) { o.setSelected(!o.isSelected()); } } } else if (e.isCtrlDown()) { for (DrawObject o : d) { if (o.intersects(r)) { o.setSelected(true); } } } else if (e.isAltDown()) { for (DrawObject o : d) { if (o.intersects(r)) { o.setSelected(false); } } } else { for (DrawObject o : d) { o.setSelected(o.intersects(r)); } } } e.commitTransaction(); definingSelection = false; draggingSelection = false; return true; } else { return false; } } public boolean paintIntermediate(ToolEvent e, Graphics2D g) { if (definingSelection) { ToolUtilities.fillSelectionShape(e, g, makeShape1(e)); return true; } else { return false; } } public boolean keyPressed(ToolEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_ESCAPE: case KeyEvent.VK_CLEAR: e.beginTransaction(ToolUtilities.messages.getString("marquee.DeselectAll")); e.getCanvas().clearPaintSelection(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(false); } e.commitTransaction(); return true; case KeyEvent.VK_BACK_SPACE: case KeyEvent.VK_DELETE: { e.beginTransaction(ToolUtilities.messages.getString("marquee.Clear")); e.getCanvas().deletePaintSelection(false); if (!e.isCtrlDown() && !e.isAltDown()) e.getCanvas().clearPaintSelection(); DrawSurface d = e.getDrawSurface(); Map<DrawObject,DrawObject> sel = new IdentityHashMap<DrawObject,DrawObject>(); for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) sel.put(o,o); } for (DrawObject o : sel.values()) { d.remove(o); } e.commitTransaction(); } return true; case KeyEvent.VK_LEFT: case KeyEvent.VK_RIGHT: case KeyEvent.VK_UP: case KeyEvent.VK_DOWN: if (e.isAltDown()) { e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); e.getCanvas().popPaintSelection(false, true); DrawSurface d = e.getDrawSurface(); List<DrawObject> sel = new Vector<DrawObject>(); for (DrawObject o : d) { if (o.isSelected()) { o.setSelected(false); o = o.clone(); o.setSelected(true); o.setVisible(true); o.setLocked(false); Point2D p = o.getLocation(); p = new Point2D.Double(p.getX()+8, p.getY()+8); o.setLocation(p); sel.add(o); } } d.addAll(sel); } else { e.beginTransaction(ToolUtilities.messages.getString("marquee.Move")); if (!e.getCanvas().isPaintSelectionPopped()) { e.getCanvas().popPaintSelection(false, false); } } nudge(e); e.commitTransaction(); return true; default: return false; } } public 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 boolean enableCommand(ToolEvent e) { switch (e.getCommand()) { case CUT: case COPY: case CLEAR: case DUPLICATE: return isSelection(e); case PASTE: return ClipboardUtilities.clipboardHasDrawObjects() || ClipboardUtilities.clipboardHasImage() || ClipboardUtilities.clipboardHasString(); case SELECT_ALL: case DESELECT_ALL: case INVERT_SELECTION: return true; default: return false; } } public boolean doCommand(ToolEvent e) { switch (e.getCommand()) { case CUT: { e.beginTransaction(ToolUtilities.messages.getString("marquee.Cut")); copy(e); e.getCanvas().deletePaintSelection(false); e.getCanvas().clearPaintSelection(); DrawSurface d = e.getDrawSurface(); Map<DrawObject,DrawObject> sel = new IdentityHashMap<DrawObject,DrawObject>(); for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) sel.put(o,o); } for (DrawObject o : sel.values()) { d.remove(o); } e.commitTransaction(); } return true; case COPY: copy(e); return true; case PASTE: e.beginTransaction(ToolUtilities.messages.getString("marquee.Paste")); paste(e); e.commitTransaction(); return true; case CLEAR: { e.beginTransaction(ToolUtilities.messages.getString("marquee.Clear")); e.getCanvas().deletePaintSelection(false); e.getCanvas().clearPaintSelection(); DrawSurface d = e.getDrawSurface(); Map<DrawObject,DrawObject> sel = new IdentityHashMap<DrawObject,DrawObject>(); for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) sel.put(o,o); } for (DrawObject o : sel.values()) { d.remove(o); } e.commitTransaction(); } return true; case DUPLICATE: { e.beginTransaction(ToolUtilities.messages.getString("marquee.Duplicate")); e.getCanvas().popPaintSelection(false, true); DrawSurface d = e.getDrawSurface(); List<DrawObject> sel = new Vector<DrawObject>(); for (DrawObject o : d) { if (o.isSelected()) { o.setSelected(false); o = o.clone(); o.setSelected(true); o.setVisible(true); o.setLocked(false); sel.add(o); } } d.addAll(sel); e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(8, 8)); for (DrawObject o : sel) { Point2D p = o.getLocation(); p = new Point2D.Double(p.getX()+8, p.getY()+8); o.setLocation(p); } e.commitTransaction(); } return true; case SELECT_ALL: e.beginTransaction(ToolUtilities.messages.getString("marquee.SelectAll")); e.getCanvas().pushPaintSelection(); e.getCanvas().setPaintSelection(new Rectangle(0, 0, e.getCanvas().getWidth(), e.getCanvas().getHeight())); e.getCanvas().pushPaintSelection(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(true); } e.commitTransaction(); return true; case DESELECT_ALL: e.beginTransaction(ToolUtilities.messages.getString("marquee.DeselectAll")); e.getCanvas().clearPaintSelection(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(false); } e.commitTransaction(); return true; case INVERT_SELECTION: e.beginTransaction(ToolUtilities.messages.getString("marquee.InvertSelection")); 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(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(!o.isSelected()); } e.commitTransaction(); return true; default: return false; } } public boolean shiftConstrainsCoordinates() { return draggingSelection; } private boolean isSelection(ToolEvent e) { if (e.getCanvas().getPaintSelection() != null) return true; DrawSurface d = e.getDrawSurface(); if (d == null) return false; for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) return true; } return false; } private boolean isInSelection(ToolEvent e) { Shape ps = e.getCanvas().getPaintSelection(); if (ps != null && ps.contains(e.getCanvasX(), e.getCanvasY())) { return true; } else { DrawSurface d = e.getDrawSurface(); ListIterator<DrawObject> oi; oi = d.listIterator(d.size()); while (oi.hasPrevious()) { DrawObject o = oi.previous(); if (o.isSelected() && o.contains(e.getCanvasX(), e.getCanvasY())) { return true; } } return false; } } 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)); nudge(e.getDrawSurface(), -n, 0); break; case KeyEvent.VK_RIGHT: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(n, 0)); nudge(e.getDrawSurface(), n, 0); break; case KeyEvent.VK_UP: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(0, -n)); nudge(e.getDrawSurface(), 0, -n); break; case KeyEvent.VK_DOWN: e.getCanvas().transformPaintSelection(AffineTransform.getTranslateInstance(0, n)); nudge(e.getDrawSurface(), 0, n); break; } } private void nudge(DrawSurface d, float dx, float dy) { for (DrawObject o : d) { if (o.isSelected() && !o.isLocked()) { Point2D p = o.getLocation(); o.setLocation(new Point2D.Double(p.getX()+dx, p.getY()+dy)); } } } private void copy(ToolEvent e) { Canvas c = e.getCanvas(); Layer l = e.getLayer(); List<DrawObject> sel = new Vector<DrawObject>(); if (c.getPaintSelection() != null) { AffineTransform lx = AffineTransform.getTranslateInstance(-l.getX(), -l.getY()); sel.add(l.copyImageObject(lx.createTransformedShape(c.getPaintSelection()))); } for (DrawObject o : e.getDrawSurface()) { if (o.isSelected()) sel.add(o); } ClipboardUtilities.setClipboardDrawObjects(sel); } private void paste(ToolEvent e) { e.getCanvas().clearPaintSelection(); for (DrawObject o : e.getDrawSurface()) { o.setSelected(false); } if (ClipboardUtilities.clipboardHasDrawObjects()) { Collection<? extends DrawObject> c = ClipboardUtilities.getClipboardDrawObjects(); boolean first = true; for (DrawObject o : c) { if (first && o instanceof ImageDrawObject) { ImageDrawObject ido = (ImageDrawObject)o; e.getCanvas().pastePaintSelection(ido.getImage(), ido.getTransform()); } else { DrawObject oo = o.clone(); oo.setSelected(true); e.getDrawSurface().add(oo); } first = false; } } else if (ClipboardUtilities.clipboardHasImage()) { Image i = ClipboardUtilities.getClipboardImage(); if (ImageUtils.prepImage(i)) { int w = i.getWidth(null); int h = i.getHeight(null); if (e.isInPaintMode()) { AffineTransform tx = AffineTransform.getTranslateInstance( (int)(e.getPreviousClickedX() - w / 2), (int)(e.getPreviousClickedY() - h / 2)); e.getCanvas().pastePaintSelection(i, tx); } else { PaintSettings ps = new PaintSettings(null, null); ImageDrawObject ido = ImageDrawObject.forGraphicsDrawImage( ps, i, (int)(e.getPreviousClickedX() - w / 2), (int)(e.getPreviousClickedY() - h / 2)); ido.setSelected(true); e.getDrawSurface().add(ido); } } else { System.err.println("Error: Failed to paste image."); } } else if (ClipboardUtilities.clipboardHasString()) { TextDrawObject tdo = new TextDrawObject( e.getPaintSettings(), e.getPreviousClickedX(), e.getPreviousClickedY(), Integer.MAX_VALUE, ClipboardUtilities.getClipboardString() ); tdo.setSelected(true); e.getDrawSurface().add(tdo); } } public Cursor getCursor(ToolEvent e) { if (isInSelection(e)) { if (e.isAltDown()) { return CursorUtils.CURSOR_ARROW_HALF_DOUBLE_HALLOW; } else { return CursorUtils.CURSOR_MOVE; } } else { return CursorUtils.CURSOR_SELECT; } } }