diff --git a/src/main/java/net/rptools/maptool/client/tool/PointerTool.java b/src/main/java/net/rptools/maptool/client/tool/PointerTool.java index 26c6263030..b153bf9aca 100644 --- a/src/main/java/net/rptools/maptool/client/tool/PointerTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/PointerTool.java @@ -1859,36 +1859,13 @@ public void dragTo(int mouseX, int mouseY) { } ZonePoint zonePoint = new ScreenPoint(mouseX, mouseY).convertToZone(renderer); - - zonePoint.x = this.dragAnchor.x + zonePoint.x - tokenDragStart.x; - zonePoint.y = this.dragAnchor.y + zonePoint.y - tokenDragStart.y; - - var grid = renderer.getZone().getGrid(); - if (tokenBeingDragged.isSnapToGrid() - && grid.getCapabilities().isSnapToGridSupported() - && AppPreferences.tokensSnapWhileDragging.get()) { - // Snap to grid point. - zonePoint = grid.convert(grid.convert(zonePoint)); - - if (debugEnabled) { - renderer.setShape(new Rectangle2D.Double(zonePoint.x - 5, zonePoint.y - 5, 10, 10)); - } - - // Adjust given offet from grid to anchor point. - zonePoint.x += this.snapOffsetX; - zonePoint.y += this.snapOffsetY; - } + zonePoint.x += dragAnchor.x - tokenDragStart.x; + zonePoint.y += dragAnchor.y - tokenDragStart.y; if (debugEnabled) { renderer.setShape2(new Rectangle2D.Double(zonePoint.x - 5, zonePoint.y - 5, 10, 10)); } - - @Nullable ZonePoint previous = renderer.getLastWaypoint(tokenBeingDragged.getId()); - if (previous == null) { - doDragTo(zonePoint, 0, 0); - } else { - doDragTo(zonePoint, zonePoint.x - previous.x, zonePoint.y - previous.y); - } + doDragTo(zonePoint); } public void moveByKey(double dx, double dy) { @@ -1904,9 +1881,6 @@ public void moveByKey(double dx, double dy) { zp.x += snapOffsetX; zp.y += snapOffsetY; - - dx = zp.x - tokenBeingDragged.getX(); - dy = zp.y - tokenBeingDragged.getY(); } else { // Scalar for dx/dy in zone space. Defaulting to essentially 1 pixel. int moveFactor = 1; @@ -1920,22 +1894,45 @@ public void moveByKey(double dx, double dy) { zp = new ZonePoint(x, y); } - doDragTo(zp, (int) dx, (int) dy); + doDragTo(zp); } - private void doDragTo(ZonePoint newAnchorPoint, int dirx, int diry) { + private void doDragTo(ZonePoint newAnchorPoint) { + + // For snapped tokens, validation is done snapped as well, even if the "snap token while + // dragging preference" if disabled. + var validationAnchorPoint = newAnchorPoint; + var grid = renderer.getZone().getGrid(); + ZonePoint previousAnchorPoint = tokenDragCurrent; + if (tokenBeingDragged.isSnapToGrid() && grid.getCapabilities().isSnapToGridSupported()) { + // Snap to grid point. + validationAnchorPoint = grid.convert(grid.convert(validationAnchorPoint)); + + // Adjust given offset from grid to anchor point. + validationAnchorPoint.x += this.snapOffsetX; + validationAnchorPoint.y += this.snapOffsetY; + + previousAnchorPoint = grid.convert(grid.convert(previousAnchorPoint)); + previousAnchorPoint.x += this.snapOffsetX; + previousAnchorPoint.y += this.snapOffsetY; + } + if (AppPreferences.tokensSnapWhileDragging.get()) { + newAnchorPoint = validationAnchorPoint; + } + // Don't bother if there isn't any movement if (!renderer.hasMoveSelectionSetMoved(tokenBeingDragged.getId(), newAnchorPoint)) { return; } - // Make sure it's a valid move + // Make sure it's a valid move. + int dirx = validationAnchorPoint.x - previousAnchorPoint.x; + int diry = validationAnchorPoint.y - previousAnchorPoint.y; boolean isValid = - (renderer.getZone().getGrid().getSize() >= 9) - ? validateMove( - tokenBeingDragged, renderer.getSelectedTokenSet(), newAnchorPoint, dirx, diry) - : validateMove_legacy( - tokenBeingDragged, renderer.getSelectedTokenSet(), newAnchorPoint); + previousAnchorPoint.equals(validationAnchorPoint) + || ((renderer.getZone().getGrid().getSize() >= 9) + ? validateMove(renderer.getSelectedTokenSet(), validationAnchorPoint, dirx, diry) + : validateMove_legacy(renderer.getSelectedTokenSet(), validationAnchorPoint)); if (!isValid) { return; } @@ -2001,7 +1998,7 @@ private void exposeFoW(ZonePoint p) { } private boolean validateMove( - Token leadToken, Set tokenSet, ZonePoint point, int dirx, int diry) { + Set tokenSet, ZonePoint leadTokenNewAnchor, int dirx, int diry) { if (MapTool.getPlayer().isGM()) { return true; } @@ -2014,8 +2011,8 @@ private boolean validateMove( boolean useTokenExposedArea = MapTool.getServerPolicy().isUseIndividualFOW() && zone.getVisionType() != VisionType.OFF; - int deltaX = point.x - leadToken.getX(); - int deltaY = point.y - leadToken.getY(); + int deltaX = leadTokenNewAnchor.x - this.dragAnchor.x; + int deltaY = leadTokenNewAnchor.y - this.dragAnchor.y; Grid grid = zone.getGrid(); // Loop through all tokens. As soon as one of them is blocked, stop processing and // return @@ -2054,7 +2051,7 @@ private boolean validateMove( return !isBlocked; } - private boolean validateMove_legacy(Token leadToken, Set tokenSet, ZonePoint point) { + private boolean validateMove_legacy(Set tokenSet, ZonePoint leadTokenNewAnchor) { Zone zone = renderer.getZone(); if (MapTool.getPlayer().isGM()) { return true; @@ -2068,8 +2065,8 @@ private boolean validateMove_legacy(Token leadToken, Set tokenSet, ZonePoi } isVisible = false; int fudgeSize = Math.max(Math.min((zone.getGrid().getSize() - 2) / 3 - 1, 8), 0); - int deltaX = point.x - leadToken.getX(); - int deltaY = point.y - leadToken.getY(); + int deltaX = leadTokenNewAnchor.x - this.dragAnchor.x; + int deltaY = leadTokenNewAnchor.y - this.dragAnchor.y; Rectangle bounds = new Rectangle(); for (GUID tokenGUID : tokenSet) { Token token = zone.getToken(tokenGUID); diff --git a/src/main/java/net/rptools/maptool/client/tool/StampTool.java b/src/main/java/net/rptools/maptool/client/tool/StampTool.java index 4995f79de4..5cc6f53e07 100644 --- a/src/main/java/net/rptools/maptool/client/tool/StampTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/StampTool.java @@ -1195,23 +1195,8 @@ public void dragTo(int mouseX, int mouseY) { } ZonePoint zonePoint = new ScreenPoint(mouseX, mouseY).convertToZone(renderer); - - zonePoint.x = this.dragAnchor.x + zonePoint.x - tokenDragStart.x; - zonePoint.y = this.dragAnchor.y + zonePoint.y - tokenDragStart.y; - - var grid = renderer.getZone().getGrid(); - if (tokenBeingDragged.isSnapToGrid() && grid.getCapabilities().isSnapToGridSupported()) { - // Snap to grid point. - zonePoint = grid.convert(grid.convert(zonePoint)); - - if (debugEnabled) { - renderer.setShape(new Rectangle2D.Double(zonePoint.x - 5, zonePoint.y - 5, 10, 10)); - } - - // Adjust given offet from grid to anchor point. - zonePoint.x += this.snapOffsetX; - zonePoint.y += this.snapOffsetY; - } + zonePoint.x += dragAnchor.x - tokenDragStart.x; + zonePoint.y += dragAnchor.y - tokenDragStart.y; if (debugEnabled) { renderer.setShape2(new Rectangle2D.Double(zonePoint.x - 5, zonePoint.y - 5, 10, 10)); @@ -1244,13 +1229,23 @@ public void moveByKey(int dx, int dy, boolean micro) { } private void doDragTo(ZonePoint newAnchorPoint) { - tokenDragCurrent = new ZonePoint(newAnchorPoint); - // Don't bother if there isn't any movement if (!renderer.hasMoveSelectionSetMoved(tokenBeingDragged.getId(), newAnchorPoint)) { return; } + tokenDragCurrent = new ZonePoint(newAnchorPoint); + + var grid = renderer.getZone().getGrid(); + if (tokenBeingDragged.isSnapToGrid() && grid.getCapabilities().isSnapToGridSupported()) { + // Snap to grid point. + newAnchorPoint = grid.convert(grid.convert(newAnchorPoint)); + + // Adjust given offset from grid to anchor point. + newAnchorPoint.x += this.snapOffsetX; + newAnchorPoint.y += this.snapOffsetY; + } + renderer.updateMoveSelectionSet(tokenBeingDragged.getId(), newAnchorPoint); MapTool.serverCommand() .updateTokenMove( diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingLikeTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingLikeTool.java index 28570bb0c0..200083b673 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingLikeTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingLikeTool.java @@ -22,11 +22,31 @@ import net.rptools.maptool.client.tool.ToolHelper; import net.rptools.maptool.client.ui.zone.ZoneOverlay; import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer; +import net.rptools.maptool.language.I18N; import net.rptools.maptool.model.ZonePoint; public abstract class AbstractDrawingLikeTool extends DefaultTool implements ZoneOverlay { + private final String instructionKey; + private final String tooltipKey; private boolean isEraser; + protected AbstractDrawingLikeTool(String instructionKey, String tooltipKey) { + this.instructionKey = instructionKey; + this.tooltipKey = tooltipKey; + + setToolTipText(I18N.getText(tooltipKey)); + } + + @Override + public String getInstructions() { + return instructionKey; + } + + @Override + public String getTooltip() { + return tooltipKey; + } + protected void setIsEraser(boolean eraser) { isEraser = eraser; } diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractTemplateTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractTemplateTool.java index f794433fad..2a91a2a379 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractTemplateTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractTemplateTool.java @@ -22,6 +22,7 @@ import net.rptools.maptool.client.MapToolUtil; import net.rptools.maptool.client.swing.SwingUtil; import net.rptools.maptool.client.swing.colorpicker.ColorPicker; +import net.rptools.maptool.client.tool.DefaultTool; import net.rptools.maptool.client.ui.zone.ZoneOverlay; import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer; import net.rptools.maptool.model.Zone.Layer; @@ -29,12 +30,13 @@ import net.rptools.maptool.model.drawing.Pen; /** Base class for tools that draw templates. */ -public abstract class AbstractTemplateTool extends AbstractDrawingLikeTool implements ZoneOverlay { +public abstract class AbstractTemplateTool extends DefaultTool implements ZoneOverlay { private static final long serialVersionUID = 9121558405484986225L; private boolean isSnapToGridSelected; private boolean isEraseSelected; + private boolean isEraser; protected AffineTransform getPaintTransform(ZoneRenderer renderer) { AffineTransform transform = new AffineTransform(); @@ -69,6 +71,14 @@ protected void detachFrom(ZoneRenderer renderer) { super.detachFrom(renderer); } + protected void setIsEraser(boolean eraser) { + isEraser = eraser; + } + + protected boolean isEraser() { + return isEraser; + } + protected boolean isEraser(MouseEvent e) { boolean defaultValue = MapTool.getFrame().getColorPicker().isEraseSelected(); if (SwingUtil.isShiftDown(e)) { @@ -78,15 +88,6 @@ protected boolean isEraser(MouseEvent e) { return defaultValue; } - protected boolean isSnapToGrid(MouseEvent e) { - boolean defaultValue = MapTool.getFrame().getColorPicker().isSnapSelected(); - if (SwingUtil.isControlDown(e)) { - // Invert from the color panel - defaultValue = !defaultValue; - } - return defaultValue; - } - protected Pen getPen() { Pen pen = new Pen(MapTool.getFrame().getPen()); pen.setEraser(isEraser()); diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/DrawingTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/DrawingTool.java index 21c06d772c..6568721e55 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/DrawingTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/DrawingTool.java @@ -36,8 +36,6 @@ import net.rptools.maptool.model.drawing.ShapeDrawable; public final class DrawingTool extends AbstractDrawingLikeTool { - private final String instructionKey; - private final String tooltipKey; private final Strategy strategy; /** The current state of the tool. If {@code null}, nothing is being drawn right now. */ @@ -47,19 +45,9 @@ public final class DrawingTool extends AbstractDrawingLikeTool { private boolean centerOnOrigin = false; public DrawingTool(String instructionKey, String tooltipKey, Strategy strategy) { - this.instructionKey = instructionKey; - this.tooltipKey = tooltipKey; - this.strategy = strategy; - } - - @Override - public String getInstructions() { - return instructionKey; - } + super(instructionKey, tooltipKey); - @Override - public String getTooltip() { - return tooltipKey; + this.strategy = strategy; } @Override @@ -291,5 +279,7 @@ public void mouseReleased(MouseEvent e) { submit(result.shape()); } } + + super.mouseReleased(e); } } diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/ExposeTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/ExposeTool.java index 5d3b1876cc..ae9a37fed0 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/ExposeTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/ExposeTool.java @@ -30,8 +30,6 @@ import net.rptools.maptool.model.ZonePoint; public final class ExposeTool extends AbstractDrawingLikeTool { - private final String instructionKey; - private final String tooltipKey; private final Strategy strategy; /** The current state of the tool. If {@code null}, nothing is being drawn right now. */ @@ -41,19 +39,9 @@ public final class ExposeTool extends AbstractDrawingLikeTool { private boolean centerOnOrigin = false; public ExposeTool(String instructionKey, String tooltipKey, Strategy strategy) { - this.instructionKey = instructionKey; - this.tooltipKey = tooltipKey; - this.strategy = strategy; - } - - @Override - public String getInstructions() { - return instructionKey; - } + super(instructionKey, tooltipKey); - @Override - public String getTooltip() { - return tooltipKey; + this.strategy = strategy; } @Override @@ -200,5 +188,7 @@ public void mouseReleased(MouseEvent e) { submit(result.shape()); } } + + super.mouseReleased(e); } } diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/TopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/TopologyTool.java index ae8d537188..8e5e6fc232 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/TopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/TopologyTool.java @@ -32,8 +32,6 @@ import net.rptools.maptool.model.ZonePoint; public final class TopologyTool extends AbstractDrawingLikeTool { - private final String instructionKey; - private final String tooltipKey; private final boolean isFilled; private final Strategy strategy; private final TopologyModeSelectionPanel topologyModeSelectionPanel; @@ -54,8 +52,8 @@ public TopologyTool( boolean isFilled, Strategy strategy, TopologyModeSelectionPanel topologyModeSelectionPanel) { - this.instructionKey = instructionKey; - this.tooltipKey = tooltipKey; + super(instructionKey, tooltipKey); + this.isFilled = isFilled; this.strategy = strategy; // Consistency with topology tools before refactoring. Can be updated as part of #5002. @@ -65,16 +63,6 @@ public TopologyTool( this.maskOverlay = new MaskOverlay(); } - @Override - public String getInstructions() { - return instructionKey; - } - - @Override - public String getTooltip() { - return tooltipKey; - } - @Override public boolean isAvailable() { return MapTool.getPlayer().isGM(); diff --git a/src/main/java/net/rptools/maptool/model/Grid.java b/src/main/java/net/rptools/maptool/model/Grid.java index e54e7c4dda..3a398615ff 100644 --- a/src/main/java/net/rptools/maptool/model/Grid.java +++ b/src/main/java/net/rptools/maptool/model/Grid.java @@ -1035,18 +1035,29 @@ protected Area getGridAreaFromCache(int gridRadius) { } public static Grid fromDto(GridDto dto) { - Grid grid = null; - switch (dto.getTypeCase()) { - case GRIDLESS_GRID -> grid = new GridlessGrid(); - case HEX_GRID -> { - grid = HexGrid.fromDto(dto.getHexGrid()); - } - case SQUARE_GRID -> grid = new SquareGrid(); - case ISOMETRIC_GRID -> grid = new IsometricGrid(); - } + Runnable postProcess = () -> {}; + Grid grid = + switch (dto.getTypeCase()) { + case GRIDLESS_GRID -> new GridlessGrid(); + case HEX_GRID -> { + var hexDto = dto.getHexGrid(); + var hexGrid = hexDto.getVertical() ? new HexGridVertical() : new HexGridHorizontal(); + postProcess = () -> hexGrid.readDto(hexDto); + yield hexGrid; + } + case SQUARE_GRID -> new SquareGrid(); + case ISOMETRIC_GRID -> new IsometricGrid(); + default -> { + log.error("Unrecognized Grid DTO: {}. Defaulting to square grid", dto.getTypeCase()); + yield new SquareGrid(); + } + }; + grid.offsetX = dto.getOffsetX(); grid.offsetY = dto.getOffsetY(); grid.size = dto.getSize(); + postProcess.run(); + grid.cellShape = grid.createCellShape(); return grid; diff --git a/src/main/java/net/rptools/maptool/model/HexGrid.java b/src/main/java/net/rptools/maptool/model/HexGrid.java index 47dad64c1f..746266e9f9 100644 --- a/src/main/java/net/rptools/maptool/model/HexGrid.java +++ b/src/main/java/net/rptools/maptool/model/HexGrid.java @@ -603,17 +603,9 @@ protected Area getScaledGridArea(Token token, int gridRadius) { protected abstract OffsetTranslator getOffsetTranslator(); - public static HexGrid fromDto(HexGridDto dto) { - HexGrid grid = null; - if (dto.getVertical()) { - grid = new HexGridVertical(); - } else { - grid = new HexGridHorizontal(); - } - - // Exact values do not matter, just the proportions. Grid itself will scale to the right size. - grid.setDimensions(100, 100 / grid.hexRatio); - return grid; + protected void readDto(HexGridDto dto) { + hexRatio = dto.getHexRatio(); + setDimensions(getSize(), getSize() / hexRatio); } protected void fillDto(GridDto.Builder dto) { diff --git a/src/main/java/net/rptools/maptool/model/drawing/AbstractTemplate.java b/src/main/java/net/rptools/maptool/model/drawing/AbstractTemplate.java index 2c5ce25992..2a8c3d9cfe 100644 --- a/src/main/java/net/rptools/maptool/model/drawing/AbstractTemplate.java +++ b/src/main/java/net/rptools/maptool/model/drawing/AbstractTemplate.java @@ -41,6 +41,13 @@ public abstract class AbstractTemplate extends AbstractDrawing { /** The location of the vertex where painting starts. */ private ZonePoint vertex = new ZonePoint(0, 0); + /** + * @deprecated This used to indicate the zone where this drawable is painted. We no longer track + * this in the drawing, but old campaign files may keep a reference to this field. So we have + * to keep this around so XStream can find the value if it needs it. + */ + @Deprecated private GUID zoneId; + protected AbstractTemplate() {} protected AbstractTemplate(GUID id) { @@ -53,6 +60,11 @@ protected AbstractTemplate(AbstractTemplate other) { this.vertex = new ZonePoint(other.vertex); } + public Object readResolve() { + zoneId = null; + return this; + } + /*--------------------------------------------------------------------------------------------- * Class Variables *-------------------------------------------------------------------------------------------*/