package rescuecore2.misc.gui; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelListener; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.awt.Point; import java.awt.Insets; import javax.swing.JComponent; /** A mouse listener that will handle panning and zooming in conjunction with a ScreenTransform. */ public class PanZoomListener implements MouseListener, MouseMotionListener, MouseWheelListener { private static final int DEFAULT_MOUSE_ZOOM_THRESHOLD = 100; private double mouseDownX; private double mouseDownY; private int zoomMouseDownY; private boolean dragging; private boolean zooming; private ScreenTransform transform; private JComponent component; private boolean enabled; private int panTriggerModifiers; private int zoomTriggerModifiers; private int zoomThreshold; /** Construct a PanZoomListener that listens for events on a JComponent. @param component The component to listen for mouse events on. */ public PanZoomListener(JComponent component) { this.component = component; component.addMouseListener(this); component.addMouseMotionListener(this); component.addMouseWheelListener(this); panTriggerModifiers = InputEvent.BUTTON1_DOWN_MASK; zoomTriggerModifiers = InputEvent.BUTTON2_DOWN_MASK; zoomThreshold = DEFAULT_MOUSE_ZOOM_THRESHOLD; enabled = true; } /** Set the screen transform. @param t The screen transform. */ public void setScreenTransform(ScreenTransform t) { this.transform = t; } /** Enable or disable this PanZoomListener. @param b Whether to process events or not. */ public void setEnabled(boolean b) { enabled = b; if (!enabled) { dragging = false; zooming = false; } } /** Set the modifiers that will trigger zooming. @param modifiers The modifiers mask that must be set for zooming to begin. */ public void setZoomTriggerModifiers(int modifiers) { zoomTriggerModifiers = modifiers; zooming = false; } /** Set the modifiers that will trigger panning. @param modifiers The modifiers mask that must be set for panning to begin. */ public void setPanTriggerModifiers(int modifiers) { panTriggerModifiers = modifiers; dragging = false; } /** Set the pan trigger modifiers so that pressing the left mouse button triggers panning. */ public void setPanOnLeftMouse() { setPanTriggerModifiers(InputEvent.BUTTON1_DOWN_MASK); } /** Set the pan trigger modifiers so that pressing the right mouse button triggers panning. */ public void setPanOnRightMouse() { setPanTriggerModifiers(InputEvent.BUTTON3_DOWN_MASK); } @Override public void mousePressed(MouseEvent e) { if (!enabled) { return; } if (transform == null) { return; } if ((e.getModifiersEx() & panTriggerModifiers) == panTriggerModifiers) { Point p = fixEventPoint(e.getPoint()); mouseDownX = transform.screenToX(p.x); mouseDownY = transform.screenToY(p.y); dragging = true; } if ((e.getModifiersEx() & zoomTriggerModifiers) == zoomTriggerModifiers) { zoomMouseDownY = e.getPoint().y; zooming = true; } } @Override public void mouseReleased(MouseEvent e) { if (!enabled) { return; } if ((e.getModifiersEx() & panTriggerModifiers) != panTriggerModifiers) { dragging = false; } if ((e.getModifiersEx() & zoomTriggerModifiers) != zoomTriggerModifiers) { zooming = false; } } @Override public void mouseDragged(MouseEvent e) { if (!enabled) { return; } if (transform == null) { return; } if (dragging) { Point p = fixEventPoint(e.getPoint()); transform.makeCentreRelativeTo(mouseDownX, mouseDownY, p.x, p.y); component.repaint(); } if (zooming) { int newY = e.getPoint().y; if (newY < zoomMouseDownY - zoomThreshold) { transform.zoomIn(); zoomMouseDownY = newY; component.repaint(); } else if (newY > zoomMouseDownY + zoomThreshold) { transform.zoomOut(); zoomMouseDownY = newY; component.repaint(); } } } @Override public void mouseWheelMoved(MouseWheelEvent e) { if (!enabled) { return; } if (transform == null) { return; } if (e.getWheelRotation() < 0) { Point p = fixEventPoint(e.getPoint()); double x = transform.screenToX(p.x); double y = transform.screenToY(p.y); transform.zoomIn(); transform.makeCentreRelativeTo(x, y, p.x, p.y); component.repaint(); } if (e.getWheelRotation() > 0) { Point p = fixEventPoint(e.getPoint()); double x = transform.screenToX(p.x); double y = transform.screenToY(p.y); transform.zoomOut(); transform.makeCentreRelativeTo(x, y, p.x, p.y); component.repaint(); } } @Override public void mouseClicked(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) {} private Point fixEventPoint(Point p) { Insets insets = component.getInsets(); return new Point(p.x - insets.left, p.y - insets.top); } }