package ini.trakem2.display; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Shape; import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.util.HashMap; public class Overlay { private HashMap<Shape,OverlayShape> oshapes = null; /** Add a new Shape to be painted above all other elements in the canvas. * The color and stroke may be null, defaulting to Color.yellow and a line of width 1. */ synchronized public void add(Shape shape, Color color, Stroke stroke) { add(shape, color, stroke, false, false, 1.0f); } synchronized public void add(Shape shape, Color color, Stroke stroke, boolean as_XOR_color) { add(shape, color, stroke, false, as_XOR_color, 1.0f); } synchronized public void add(Shape shape, Color color, Stroke stroke, boolean fill, boolean as_XOR_color, float alpha) { if (null == shape) return; if (null == oshapes) oshapes = new HashMap<Shape,OverlayShape>(); oshapes.put(shape, new OverlayShape(shape, color, stroke, fill, as_XOR_color, alpha)); } synchronized public void remove(Shape shape) { if (null == oshapes || null == shape) return; oshapes.remove(shape); } synchronized public void clear() { oshapes = null; } public void paint(Graphics2D g, Rectangle srcRect, double mag) { if (null == oshapes) return; AffineTransform original = g.getTransform(); // Clear transform, so stroke is magnification-invariant g.setTransform(new AffineTransform()); // Compute pan/zoom transform AffineTransform sm = new AffineTransform(); sm.scale(mag, mag); sm.translate(-srcRect.x, -srcRect.y); // Ensure stroke of line thickness 1 g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER)); for (OverlayShape o : oshapes.values()) { o.paint(g, sm); } // Restore g.setTransform(original); } private class OverlayShape { Shape shape; Color color; Stroke stroke; boolean fill; boolean as_XOR_color; float alpha; OverlayShape(Shape shape, Color color, Stroke stroke, boolean fill, boolean as_XOR_color, float alpha) { this.shape = shape; this.color = color; this.stroke = stroke; this.fill = fill; this.as_XOR_color = as_XOR_color; this.alpha = alpha; } void paint(Graphics2D g, AffineTransform sm) { Composite c = g.getComposite(); if (as_XOR_color) { g.setXORMode(null == color ? Color.yellow : color); } else { g.setColor(null == color ? Color.yellow : color); if (alpha < 1.0f && alpha > 0.0f) { g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha)); } } Stroke s = null; if (null != stroke) { s = g.getStroke(); g.setStroke(stroke); } if (fill) g.fill(sm.createTransformedShape(shape)); else g.draw(sm.createTransformedShape(shape)); if (null != stroke) g.setStroke(s); if (null != c) g.setComposite(c); } } }