/* * This software copyright by various authors including the RPTools.net * development team, and licensed under the LGPL Version 3 or, at your option, * any later version. * * Portions of this software were originally covered under the Apache Software * License, Version 1.1 or Version 2.0. * * See the file LICENSE elsewhere in this distribution for license details. */ package net.rptools.maptool.client.ui.adjustgrid; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.SwingUtilities; import net.rptools.lib.swing.SwingUtil; import net.rptools.maptool.client.AppActions; import net.rptools.maptool.client.ui.Scale; public class AdjustGridPanel extends JComponent implements MouseListener, MouseMotionListener, MouseWheelListener { private static final int MINIMUM_GRID_SIZE = 5; private static enum Direction { Increase, Decrease }; public static final String PROPERTY_GRID_OFFSET_X = "gridOffsetX"; public static final String PROPERTY_GRID_OFFSET_Y = "gridOffsetY"; public static final String PROPERTY_GRID_SIZE = "gridSize"; public static final String PROPERTY_ZOOM = "zoom"; private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); private int gridOffsetX = 0; private int gridOffsetY = 0; private int gridSize = 40; private boolean showGrid = true; private int mouseX; private int mouseY; private int dragStartX; private int dragStartY; private int dragOffsetX; private int dragOffsetY; private Color gridColor = Color.darkGray; private BufferedImage image; private Scale scale; public AdjustGridPanel() { setOpaque(false); addMouseListener(this); addMouseMotionListener(this); addMouseWheelListener(this); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(AppActions.ZOOM_OUT.getKeyStroke(), "zoomOut"); getActionMap().put("zoomOut", new AbstractAction() { public void actionPerformed(ActionEvent e) { zoomOut(); } }); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(AppActions.ZOOM_IN.getKeyStroke(), "zoomIn"); getActionMap().put("zoomIn", new AbstractAction() { public void actionPerformed(ActionEvent e) { zoomIn(); } }); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(AppActions.ZOOM_RESET.getKeyStroke(), "zoomReset"); getActionMap().put("zoomReset", new AbstractAction() { public void actionPerformed(ActionEvent e) { zoomReset(); } }); } public void setZoneImage(BufferedImage image) { this.image = image; scale = new Scale(image.getWidth(), image.getHeight()); } public void setZoomIndex(int index) { scale.setScale(index); repaint(); } @Override protected void paintComponent(Graphics g) { if (image == null) { return; } Dimension size = getSize(); if (scale.initialize(size.width, size.height)) { propertyChangeSupport.firePropertyChange(PROPERTY_ZOOM, 0, (int) scale.getScale()); } // CALCULATIONS Dimension imageSize = getScaledImageSize(); Point imagePosition = getScaledImagePosition(); double imgRatio = scale.getScale(); // SETUP Graphics2D g2d = (Graphics2D) g; // BG FILL g2d.setColor(getBackground()); g2d.fillRect(0, 0, size.width, size.height); // IMAGE g2d.drawImage(image, imagePosition.x, imagePosition.y, imageSize.width, imageSize.height, null); g2d.setColor(Color.black); g2d.drawRect(imagePosition.x, imagePosition.y, imageSize.width, imageSize.height); // GRID g2d.setColor(gridColor); double gridSize = this.gridSize * imgRatio; // across int x = imagePosition.x + (int) (gridOffsetX * imgRatio); for (double i = gridSize; i <= imageSize.width; i += gridSize) { g2d.drawLine(x + (int) i, imagePosition.y, x + (int) i, imagePosition.y + imageSize.height - 1); } // down int y = imagePosition.y + (int) (gridOffsetY * imgRatio); for (double i = gridSize; i <= imageSize.height; i += gridSize) { g2d.drawLine(imagePosition.x, y + (int) i, imagePosition.x + imageSize.width - 1, y + (int) i); } } public void setGridColor(Color color) { gridColor = color; } @Override public boolean isFocusable() { return true; } public void setGridOffset(int offsetX, int offsetY) { gridOffsetX = offsetX; gridOffsetY = offsetY; repaint(); } public int getGridSize() { return gridSize; } public int getGridOffsetX() { return gridOffsetX; } public int getGridOffsetY() { return gridOffsetY; } public void setGridSize(int size) { gridSize = Math.max(MINIMUM_GRID_SIZE, size); repaint(); } private Dimension getScaledImageSize() { Dimension imageSize = new Dimension(image.getWidth(), image.getHeight()); imageSize.width *= scale.getScale(); imageSize.height *= scale.getScale(); return imageSize; } private Point getScaledImagePosition() { int imgX = scale.getOffsetX(); int imgY = scale.getOffsetY(); return new Point(imgX, imgY); } public void zoomIn() { scale.zoomIn(mouseX, mouseY); repaint(); } public void zoomOut() { scale.zoomOut(mouseX, mouseY); repaint(); } public void zoomReset() { scale.reset(); repaint(); } public void moveGridBy(int dx, int dy) { int oldOffsetX = gridOffsetX; int oldOffsetY = gridOffsetY; gridOffsetX += dx; gridOffsetY += dy; gridOffsetX %= gridSize; gridOffsetY %= gridSize; if (gridOffsetY > 0) { gridOffsetY = gridOffsetY - gridSize; } if (gridOffsetX > 0) { gridOffsetX = gridOffsetX - gridSize; } repaint(); propertyChangeSupport.firePropertyChange(PROPERTY_GRID_OFFSET_X, oldOffsetX, gridOffsetX); propertyChangeSupport.firePropertyChange(PROPERTY_GRID_OFFSET_Y, oldOffsetY, gridOffsetY); } public void adjustGridSize(int delta) { int oldSize = gridSize; gridSize = Math.max(MINIMUM_GRID_SIZE, gridSize + delta); repaint(); propertyChangeSupport.firePropertyChange(PROPERTY_GRID_SIZE, oldSize, gridSize); } private void adjustGridSize(Direction direction) { Point imagePosition = getScaledImagePosition(); double gridSize = this.gridSize * scale.getScale(); int cellX = (int) ((mouseX - imagePosition.x - gridOffsetX) / gridSize); int cellY = (int) ((mouseY - imagePosition.y - gridOffsetY) / gridSize); switch (direction) { case Increase: adjustGridSize(1); if (this.gridSize != gridSize) { moveGridBy(-cellX, -cellY); } break; case Decrease: adjustGridSize(-1); if (this.gridSize != gridSize) { moveGridBy(cellX, cellY); } break; } } //// // MOUSE LISTENER public void mouseClicked(MouseEvent e) { } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { mouseX = e.getX(); mouseY = e.getY(); dragStartX = e.getX(); dragStartY = e.getY(); Point imagePosition = getScaledImagePosition(); int x = (int) ((e.getX() - imagePosition.x) / scale.getScale() - gridOffsetX); int y = (int) ((e.getY() - imagePosition.y) / scale.getScale() - gridOffsetY); dragOffsetX = x % gridSize; dragOffsetY = y % gridSize; } public void mouseReleased(MouseEvent e) { } //// // MOUSE MOTION LISTENER public void mouseDragged(MouseEvent e) { if (SwingUtilities.isLeftMouseButton(e)) { Point imagePosition = getScaledImagePosition(); int x = (int) ((e.getX() - imagePosition.x) / scale.getScale() - dragOffsetX); int y = (int) ((e.getY() - imagePosition.y) / scale.getScale() - dragOffsetY); int oldOffsetX = gridOffsetX; int oldOffsetY = gridOffsetY; gridOffsetX = x % gridSize; gridOffsetY = y % gridSize; if (gridOffsetY > 0) { gridOffsetY = gridOffsetY - gridSize; } if (gridOffsetX > 0) { gridOffsetX = gridOffsetX - gridSize; } repaint(); propertyChangeSupport.firePropertyChange(PROPERTY_GRID_OFFSET_X, oldOffsetX, gridOffsetX); propertyChangeSupport.firePropertyChange(PROPERTY_GRID_OFFSET_Y, oldOffsetY, gridOffsetY); } else { int offsetX = scale.getOffsetX() + e.getX() - dragStartX; int offsetY = scale.getOffsetY() + e.getY() - dragStartY; scale.setOffset(offsetX, offsetY); dragStartX = e.getX(); dragStartY = e.getY(); repaint(); } } public void mouseMoved(MouseEvent e) { Dimension imgSize = getScaledImageSize(); Point imgPos = getScaledImagePosition(); boolean insideMap = e.getX() > imgPos.x && e.getX() < imgPos.x + imgSize.width && e.getY() > imgPos.y && e.getY() < imgPos.y + imgSize.height; if ((insideMap && showGrid) || (!insideMap && !showGrid)) { showGrid = !insideMap; repaint(); } mouseX = e.getX(); mouseY = e.getY(); } //// // MOUSE WHEEL LISTENER public void mouseWheelMoved(MouseWheelEvent e) { if (SwingUtil.isControlDown(e)) { double oldScale = scale.getScale(); if (e.getWheelRotation() > 0) { scale.zoomOut(e.getX(), e.getY()); } else { scale.zoomIn(e.getX(), e.getY()); } propertyChangeSupport.firePropertyChange(PROPERTY_ZOOM, oldScale, scale.getScale()); } else { if (e.getWheelRotation() > 0) { adjustGridSize(Direction.Increase); } else { adjustGridSize(Direction.Decrease); } } repaint(); } //// // PROPERTY CHANGE SUPPORT @Override public void addPropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(listener); } @Override public void addPropertyChangeListener(String name, PropertyChangeListener listener) { propertyChangeSupport.addPropertyChangeListener(name, listener); } @Override public void removePropertyChangeListener(String name, PropertyChangeListener listener) { propertyChangeSupport.removePropertyChangeListener(name, listener); } /* * private final Map<KeyStroke, Action> KEYSTROKES = new HashMap<KeyStroke, Action>() { { * put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK), new GridSizeAction(Size.Decrease)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK), new GridSizeAction(Size.Decrease)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK), new GridSizeAction(Size.Increase)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK), new GridSizeAction(Size.Increase)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), new GridOffsetAction(GridOffsetAction.Direction.Up)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), new GridOffsetAction(GridOffsetAction.Direction.Left)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), new GridOffsetAction(GridOffsetAction.Direction.Down)); * put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), new GridOffsetAction(GridOffsetAction.Direction.Right)); } }; * protected Map<KeyStroke, Action> getKeyActionMap() { return KEYSTROKES; } * * private final class GridSizeAction extends AbstractAction { private final Size size; public GridSizeAction(Size * size) { this.size = size; } * * public void actionPerformed(ActionEvent e) { ZoneRenderer renderer = (ZoneRenderer) e.getSource(); * adjustGridSize(renderer, size); } } * * private static final class GridOffsetAction extends AbstractAction { private static enum Direction { Left, Right, * Up, Down }; private final Direction direction; * * public GridOffsetAction(Direction direction) { this.direction = direction; } * * public void actionPerformed(ActionEvent e) { ZoneRenderer renderer = (ZoneRenderer) e.getSource(); switch * (direction) { case Left: renderer.moveGridBy(-1, 0); break; case Right: renderer.moveGridBy(1, 0); break; case * Up: renderer.moveGridBy(0, -1); break; case Down: renderer.moveGridBy(0, 1); break; } } } */ }