package ie.dcu.apps.ist.controllers; import ie.dcu.segment.annotate.*; import ie.dcu.swt.*; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.graphics.*; import org.eclipse.swt.widgets.Canvas; public class AnnotationTool extends MouseMotionAdapter { private final AnnotationManager manager; private ImageControl view; private Canvas canvas; private Annotation current; private AnnotationType type; private int lineWidth; private Point last; private boolean invert; public AnnotationTool(AnnotationManager manager) { this (manager, null); } /** * * @param manager * @param view */ public AnnotationTool(AnnotationManager manager, ImageControl view) { assert (manager != null); this.manager = manager; this.current = null; this.lineWidth = 1; this.type = AnnotationType.Foreground; attach(view); } /** * * @param view */ public void attach(ImageControl view) { detach(); if (view != null) { this.view = view; canvas = view.getCanvas(); canvas.addMouseListener(this); canvas.addMouseMoveListener(this); } } public void detach() { if (view != null) { canvas.removeMouseListener(this); canvas.removeMouseMoveListener(this); view = null; canvas = null; current = null; } } /** * Returns the image control associated with the annotation tool. */ public ImageControl getView() { return view; } /** * @return the line width */ public int getLineWidth() { return lineWidth; } /** * @param width the line width to set */ public void setLineWidth(int width) { assert (width > 0); this.lineWidth = width; } /** * @return the annotation type */ public AnnotationType getType() { return type; } /** * @param type the annotation type to set */ public void setType(AnnotationType type) { assert (type != null); this.type = type; } public void begin(Point pt) { // Create a new annotation current = new Annotation(getTypeForUse(), lineWidth, view.canvasToImage(pt)); // Give immediate visual feedback feedback(pt); // Set last last = pt; } public void append(Point pt) { // Update the annotation current.add(view.canvasToImage(pt)); // Give immediate visual feedback feedback(last, pt); // Set last last = pt; } public void commit(Point pt) { // Clip points to image bounds clip(last, pt); // Add point to annotation current.add(view.canvasToImage(pt)); // Add annotation to annotation manager manager.add(current); // Give immediate visual feedback feedback(last, pt); // Mark current annotation as null current = null; } public void cancel() { // Repaint dirty area view.repaint(current.getBounds()); // Discard annotation current = null; } @Override public void mouseDown(MouseEvent e) { if (view == null || !view.isEnabled()) { current = null; return; } ObservableImage image = view.getImage(); if (image != null) { if (e.button == 1 || e.button == 3) { Point pt = new Point(e.x, e.y); if (view.imageContains(pt)) { // Check for right mouse button or ctrl modifier if (e.button == 3 || (e.stateMask & SWT.CTRL) != 0) { // Invert type invert = true; } else { invert = false; } if (current != null) { // Cancel last action cancel(); } begin(pt); } } } return; } @Override public void mouseMove(MouseEvent e) { if (view == null || !view.isEnabled()) { current = null; return; } if (current != null) { Point pt = new Point(e.x, e.y); if (view.imageContains(pt)) { // Normal case: append append(pt); } else { // Line drawn outside image if (view.getImage() != null) { commit(pt); } else { // No image: cancel cancel(); } } } } @Override public void mouseUp(MouseEvent e) { if (view == null || !view.isEnabled()) { current = null; return; } if (current != null) { Point pt = new Point(e.x, e.y); if (view.imageContains(pt)) { // Normal case: commit commit(pt); } else { // Line drawn outside image if (view.getImage() != null) { commit(pt); } else { // No image cancel(); } } } } private void clip(Point p, Point q) { SwtUtils.clip(view.getCanvasImageBounds(), p, q); } private GC createFeedbackGC() { GC gc = new GC(canvas); gc.setAntialias(SWT.ON); gc.setLineCap(SWT.CAP_ROUND); gc.setLineJoin(SWT.JOIN_ROUND); gc.setLineWidth((int) Math.floor(lineWidth * view.getZoom())); gc.setForeground(getTypeForUse().getColor()); return gc; } private void feedback(Point p1) { feedback(p1, new Point(p1.x+1, p1.y)); } private void feedback(Point p1, Point p2) { GC gc = createFeedbackGC(); gc.setClipping(getClip(p1, p2)); gc.drawLine(p1.x, p1.y, p2.x, p2.y); gc.dispose(); } private Rectangle getClip(Point p1, Point p2) { int x1 = Math.min(p1.x, p2.x) - lineWidth; int x2 = Math.max(p1.x, p2.x) + lineWidth; int y1 = Math.min(p1.y, p2.y) - lineWidth; int y2 = Math.max(p1.y, p2.y) + lineWidth; Rectangle r = new Rectangle(x1, y1, x2 - x1, y2 - y1); return r.intersection(view.getCanvasImageBounds()); } private AnnotationType getTypeForUse() { return (invert) ? type.invert() : type; } }