From a995252a96a13f574877f94309bab7dbb8ea9e26 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Wed, 28 Aug 2024 18:47:30 +0930 Subject: [PATCH 01/21] Beginnings of Token Footprints as Campaign Properties. --- .../client/MapToolExpressionParser.java | 2 + .../client/functions/FootprintFunctions.java | 159 ++++++++++++++++++ .../maptool/model/CampaignProperties.java | 24 +++ .../rptools/maptool/model/GridlessGrid.java | 11 +- .../maptool/model/HexGridHorizontal.java | 11 +- .../maptool/model/HexGridVertical.java | 11 +- .../rptools/maptool/model/IsometricGrid.java | 11 +- .../net/rptools/maptool/model/SquareGrid.java | 11 +- src/main/proto/data_transfer_objects.proto | 11 ++ 9 files changed, 241 insertions(+), 10 deletions(-) create mode 100644 src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java diff --git a/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java b/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java index 1a7d432bcd..4b99e74b39 100644 --- a/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java +++ b/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java @@ -19,6 +19,7 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import main.java.net.rptools.maptool.client.functions.FootprintFunctions; // why import net.rptools.dicelib.expression.ExpressionParser; import net.rptools.maptool.client.functions.*; import net.rptools.maptool.client.functions.json.JSONMacroFunctions; @@ -105,6 +106,7 @@ public class MapToolExpressionParser extends ExpressionParser { TestFunctions.getInstance(), TextLabelFunctions.getInstance(), TokenSpeechNameFunction.getInstance(), + FootprintFunctions.getInstance(), new MarkDownFunctions(), new PlayerFunctions(), new LibraryFunctions(), diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java new file mode 100644 index 0000000000..dfbd7155fc --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -0,0 +1,159 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package main.java.net.rptools.maptool.client.functions; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import java.util.List; +import java.util.Objects; +import java.util.regex.PatternSyntaxException; +import net.rptools.maptool.client.functions.exceptions.*; +import net.rptools.maptool.model.CellPoint; +import net.rptools.maptool.model.Grid; +import net.rptools.maptool.model.GridFactory; +import net.rptools.maptool.model.TokenFootprint; +import net.rptools.parser.Parser; +import net.rptools.parser.ParserException; +import net.rptools.parser.VariableResolver; +import net.rptools.parser.function.AbstractFunction; + +/** + * functions for dealing with token footprint retrieval and modification. + * + * @author cold_ankles + */ +public class FootprintFunctions extends AbstractFunction { + public FootprintFunctions() { + super(0, 2, "getTokenFootprint", "setTokenFootprint", "getFootprintNames", "getGridTypes"); + } + + /** The singleton instance. */ + private static final FootprintFunctions instance = new FootprintFunctions(); + + /** + * Gets the instance. + * + * @return the instance. + */ + public static FootprintFunctions getInstance() { + return instance; + } + + @Override + public Object childEvaluate( + Parser parser, VariableResolver resolver, String functionName, List parameters) + throws ParserException { + + String result = ""; + + try { + if (functionName.equalsIgnoreCase("getTokenFootprint")) { + if (parameters.isEmpty() + || (parameters.size() >= 2 + && !(parameters.get(0) instanceof String) + && !(parameters.get(1) instanceof String))) { + throw new ParserException( + net.rptools.maptool.language.I18N.getText( + "macro.function.general.argumentTypeN", + functionName, + 0, + parameters.get(0).toString(), + parameters.get(1).toString())); + } else if (parameters.size() > 1) { + result = getTokenFootPrints(parameters.get(0).toString(), parameters.get(1).toString()); + } else { + result = getTokenFootPrints(parameters.get(0).toString(), null); + } + } else if (functionName.equalsIgnoreCase("setTokenFootprint")) { + + } else if (functionName.equalsIgnoreCase("getFootprintNames")) { + if (parameters.isEmpty() + || (parameters.size() >= 1 && !(parameters.get(0) instanceof String))) { + throw new ParserException( + net.rptools.maptool.language.I18N.getText( + "macro.function.general.argumentTypeN", + functionName, + 0, + parameters.get(0).toString())); + } else { + result = getFootprintNames(parameters.get(0).toString()); + } + } else if (functionName.equalsIgnoreCase("getGridTypes")) { + result = + "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"Isometric\",\"Isometric Hex\",\"Isometric Hex\",\"None\"]"; + } else { + throw new ParserException( + net.rptools.maptool.language.I18N.getText( + "macro.function.general.unknownFunction", functionName)); + } + } catch (PatternSyntaxException e) { + throw new ParserException(e.getMessage()); + } + + return result; + } + + String getFootprintNames(String gridType) { + Grid grid = GridFactory.createGrid(gridType, true, false); + var allFootprints = grid.getFootprints().toArray(); + JsonArray footprintNames = new JsonArray(); + for (int i = 0; i < allFootprints.length; i++) { + TokenFootprint footprint = (TokenFootprint) allFootprints[i]; + footprintNames.add(footprint.getName()); + } + return footprintNames.toString(); + } + + String getTokenFootPrints(String gridType, String footprintName) { + Grid grid = GridFactory.createGrid(gridType, true, false); + var allFootprints = grid.getFootprints().toArray(); + if (footprintName == null) { + // Get all footprints + JsonObject asJSON = new JsonObject(); + for (int i = 0; i < allFootprints.length; i++) { + TokenFootprint footprint = (TokenFootprint) allFootprints[i]; + var occupiedCells = footprint.getOccupiedCells(new CellPoint(0, 0)).toArray(); + JsonArray occupiedString = new JsonArray(); + for (int j = 0; j < occupiedCells.length; j++) { + CellPoint currentCell = (CellPoint) occupiedCells[j]; + JsonObject jsonPoint = new JsonObject(); + jsonPoint.addProperty("x", currentCell.x); + jsonPoint.addProperty("y", currentCell.y); + occupiedString.add(jsonPoint); + } + asJSON.add(footprint.getName(), occupiedString); + } + return asJSON.toString(); + } else { + for (int i = 0; i < allFootprints.length; i++) { + TokenFootprint footprint = (TokenFootprint) allFootprints[i]; + if (!Objects.equals(footprint.getName(), footprintName)) { + continue; + } + JsonArray asJSON = new JsonArray(); + var occupiedCells = footprint.getOccupiedCells(new CellPoint(0, 0)).toArray(); + for (int j = 0; j < occupiedCells.length; j++) { + CellPoint currentCell = (CellPoint) occupiedCells[j]; + JsonObject jsonPoint = new JsonObject(); + jsonPoint.addProperty("x", currentCell.x); + jsonPoint.addProperty("y", currentCell.y); + asJSON.add(jsonPoint); + } + return asJSON.toString(); + } + return null; + } + } +} diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index 4560ef0f9c..853e632694 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -77,6 +77,8 @@ public class CampaignProperties { private Map tokenBars = new LinkedHashMap<>(); private Map characterSheets = new HashMap<>(); + private Map> gridFootprints = new HashMap<>(); + /** Flag indicating that owners have special permissions */ private boolean initiativeOwnerPermissions = AppPreferences.getInitOwnerPermissions(); @@ -144,6 +146,9 @@ public CampaignProperties(CampaignProperties properties) { characterSheets.put(type, properties.characterSheets.get(type)); } defaultTokenPropertyType = properties.defaultTokenPropertyType; + if (properties.gridFootprints != null) { + gridFootprints = properties.gridFootprints; + } } public void mergeInto(CampaignProperties properties) { @@ -163,6 +168,11 @@ public void mergeInto(CampaignProperties properties) { properties.tokenStates.putAll(tokenStates); properties.tokenBars.putAll(tokenBars); properties.defaultTokenPropertyType = defaultTokenPropertyType; + if (properties.gridFootprints != null) { + properties.gridFootprints.putAll(gridFootprints); + } else { + properties.gridFootprints = gridFootprints; + } } public Map> getTokenTypeMap() { @@ -465,6 +475,14 @@ public void setCharacterSheets(Map characterSheets) { this.characterSheets.putAll(characterSheets); } + public Map> getGridFootprints() { + return gridFootprints; + } + + public void setGridFootprints(String gridType, List footprintList) { + gridFootprints.put(gridType, footprintList); + } + protected Object readResolve() { if (tokenTypeMap == null) { tokenTypeMap = new HashMap<>(); @@ -571,6 +589,11 @@ public static CampaignProperties fromDto(CampaignPropertiesDto dto) { } else { props.defaultTokenPropertyType = FALLBACK_DEFAULT_TOKEN_PROPERTY_TYPE; } + dto.getGridFootprints() + .forEach( + (k, v) -> { + // TODO Finish DTO Import for Footprints + }); return props; } @@ -618,6 +641,7 @@ public CampaignPropertiesDto toDto() { dto.addAllSightTypes( sightTypeMap.values().stream().map(SightType::toDto).collect(Collectors.toList())); dto.setDefaultTokenPropertyType(StringValue.of(defaultTokenPropertyType)); + //TODO Finish DTO Export for Footprints return dto.build(); } } diff --git a/src/main/java/net/rptools/maptool/model/GridlessGrid.java b/src/main/java/net/rptools/maptool/model/GridlessGrid.java index aa79e7ff0e..8e509bc9b1 100644 --- a/src/main/java/net/rptools/maptool/model/GridlessGrid.java +++ b/src/main/java/net/rptools/maptool/model/GridlessGrid.java @@ -63,12 +63,19 @@ public boolean isCoordinatesSupported() { @Override public List getFootprints() { - if (footprintList == null) { + Map> campaignFootprints = + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + if (campaignFootprints.containsKey("None")) { + return campaignFootprints.get("None"); + } else { try { footprintList = loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml"); } catch (IOException ioe) { - MapTool.showError("GridlessGrid.error.notLoaded", ioe); + MapTool.showError("Could not load Gridless Grid footprints", ioe); } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("None", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java index 26911c5ca3..4d5b8b4510 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java +++ b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java @@ -185,14 +185,21 @@ public void uninstallMovementKeys(Map actionMap) { @Override public List getFootprints() { - if (footprintList == null) { + Map> campaignFootprints = + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + if (campaignFootprints.containsKey("Horizontal Hex")) { + return campaignFootprints.get("Horizontal Hex"); + } else { try { footprintList = loadFootprints( "net/rptools/maptool/model/hexGridHorizFootprints.xml", getOffsetTranslator()); } catch (IOException ioe) { - MapTool.showError("Could not load Hex Grid footprints", ioe); + MapTool.showError("Could not load HHex Grid footprints", ioe); } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Horizontal Hex", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/HexGridVertical.java b/src/main/java/net/rptools/maptool/model/HexGridVertical.java index a1f6dbfed5..7eb359aef5 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridVertical.java +++ b/src/main/java/net/rptools/maptool/model/HexGridVertical.java @@ -172,14 +172,21 @@ public void uninstallMovementKeys(Map actionMap) { @Override public List getFootprints() { - if (footprintList == null) { + Map> campaignFootprints = + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + if (campaignFootprints.containsKey("Vertical Hex")) { + return campaignFootprints.get("Vertical Hex"); + } else { try { footprintList = loadFootprints( "net/rptools/maptool/model/hexGridVertFootprints.xml", getOffsetTranslator()); } catch (IOException ioe) { - MapTool.showError("Could not load Hex Grid footprints", ioe); + MapTool.showError("Could not load VHex Grid footprints", ioe); } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Vertical Hex", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/IsometricGrid.java b/src/main/java/net/rptools/maptool/model/IsometricGrid.java index b79c26bfc3..096bdcb320 100644 --- a/src/main/java/net/rptools/maptool/model/IsometricGrid.java +++ b/src/main/java/net/rptools/maptool/model/IsometricGrid.java @@ -177,12 +177,19 @@ public boolean isCoordinatesSupported() { @Override public List getFootprints() { - if (footprintList == null) { + Map> campaignFootprints = + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + if (campaignFootprints.containsKey("Square")) { + return campaignFootprints.get("Square"); + } else { try { footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); } catch (IOException ioe) { - MapTool.showError("SquareGrid.error.squareGridNotLoaded", ioe); + MapTool.showError("Could not load Square Grid footprints", ioe); } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Square", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/SquareGrid.java b/src/main/java/net/rptools/maptool/model/SquareGrid.java index f0e3650b92..0d4261ca23 100644 --- a/src/main/java/net/rptools/maptool/model/SquareGrid.java +++ b/src/main/java/net/rptools/maptool/model/SquareGrid.java @@ -222,12 +222,19 @@ public void drawCoordinatesOverlay(Graphics2D g, ZoneRenderer renderer) { @Override public List getFootprints() { - if (footprintList == null) { + Map> campaignFootprints = + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + if (campaignFootprints.containsKey("Square")) { + return campaignFootprints.get("Square"); + } else { try { footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); } catch (IOException ioe) { - MapTool.showError("SquareGrid.error.squareGridNotLoaded", ioe); + MapTool.showError("Could not load Square Grid footprints", ioe); } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Square", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } return footprintList; } diff --git a/src/main/proto/data_transfer_objects.proto b/src/main/proto/data_transfer_objects.proto index 61cb023e51..0340f9169d 100644 --- a/src/main/proto/data_transfer_objects.proto +++ b/src/main/proto/data_transfer_objects.proto @@ -133,6 +133,17 @@ message CampaignPropertiesDto { repeated SightTypeDto sight_types = 13; map token_type_stat_sheet = 14; google.protobuf.StringValue default_token_property_type = 15; + map gridFootprints = 16; +} + +message FootprintListDto { + string gridName = 1; + map footprintList = 2; +} + +message FootprintDto { + string name = 1; + repeated IntPointDto points = 2; } message SightTypeDto { From 754d4334e321638c8d7e76687ca3d7f23f2b8ef9 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Thu, 29 Aug 2024 18:20:59 +0930 Subject: [PATCH 02/21] CampaignPropertiesDto Includes Footprints (To and From) Macro Functions Improved (Get All Footprints for All Grids, Get All Footprints for One Grid, Get One Footprint from One Grid) Campaign Properties Initialise Default Footprints on New Campaign --- .../client/functions/FootprintFunctions.java | 99 ++++++++++++------- .../maptool/model/CampaignProperties.java | 71 ++++++++++++- .../rptools/maptool/model/TokenFootprint.java | 19 ++++ src/main/proto/data_transfer_objects.proto | 7 +- 4 files changed, 151 insertions(+), 45 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index dfbd7155fc..cc6e1f711e 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -17,12 +17,10 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.regex.PatternSyntaxException; import net.rptools.maptool.client.functions.exceptions.*; -import net.rptools.maptool.model.CellPoint; -import net.rptools.maptool.model.Grid; -import net.rptools.maptool.model.GridFactory; import net.rptools.maptool.model.TokenFootprint; import net.rptools.parser.Parser; import net.rptools.parser.ParserException; @@ -36,7 +34,14 @@ */ public class FootprintFunctions extends AbstractFunction { public FootprintFunctions() { - super(0, 2, "getTokenFootprint", "setTokenFootprint", "getFootprintNames", "getGridTypes"); + super( + 0, + 3, + "getTokenFootprints", + "setTokenFootprint", + "removeTokenFootprint", + "getFootprintNames", + "getGridTypes"); } /** The singleton instance. */ @@ -59,11 +64,10 @@ public Object childEvaluate( String result = ""; try { - if (functionName.equalsIgnoreCase("getTokenFootprint")) { - if (parameters.isEmpty() - || (parameters.size() >= 2 - && !(parameters.get(0) instanceof String) - && !(parameters.get(1) instanceof String))) { + if (functionName.equalsIgnoreCase("getTokenFootprints")) { + if ((parameters.size() >= 2 + && !(parameters.get(0) instanceof String) + && !(parameters.get(1) instanceof String))) { throw new ParserException( net.rptools.maptool.language.I18N.getText( "macro.function.general.argumentTypeN", @@ -71,22 +75,27 @@ public Object childEvaluate( 0, parameters.get(0).toString(), parameters.get(1).toString())); + } else if (parameters.isEmpty()) { + result = getTokenFootPrints(null, null); } else if (parameters.size() > 1) { result = getTokenFootPrints(parameters.get(0).toString(), parameters.get(1).toString()); } else { result = getTokenFootPrints(parameters.get(0).toString(), null); } } else if (functionName.equalsIgnoreCase("setTokenFootprint")) { - + // TODO Set Token Footprint Function setTokenFootprint(name, scale, points) + } else if (functionName.equalsIgnoreCase("removeTokenFootprint")) { + // TODO Remove Token Footprint Function removeTokenFootprint(grid, name) } else if (functionName.equalsIgnoreCase("getFootprintNames")) { - if (parameters.isEmpty() - || (parameters.size() >= 1 && !(parameters.get(0) instanceof String))) { + if ((parameters.size() >= 1 && !(parameters.get(0) instanceof String))) { throw new ParserException( net.rptools.maptool.language.I18N.getText( "macro.function.general.argumentTypeN", functionName, 0, parameters.get(0).toString())); + } else if (parameters.isEmpty()) { + result = getFootprintNames(null); } else { result = getFootprintNames(parameters.get(0).toString()); } @@ -106,8 +115,25 @@ public Object childEvaluate( } String getFootprintNames(String gridType) { - Grid grid = GridFactory.createGrid(gridType, true, false); - var allFootprints = grid.getFootprints().toArray(); + Map> campaignFootprints = + net.rptools.maptool.client.MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints(); + if (gridType == null) { + JsonObject asJSON = new JsonObject(); + for (var entry : campaignFootprints.entrySet()) { + JsonArray footprintNames = new JsonArray(); + for (TokenFootprint footprint : entry.getValue()) { + footprintNames.add(footprint.getName()); + } + asJSON.add(entry.getKey(), footprintNames); + } + return asJSON.toString(); + } + if (!campaignFootprints.containsKey(gridType)) { + return "null"; + } + var allFootprints = campaignFootprints.get(gridType).toArray(); JsonArray footprintNames = new JsonArray(); for (int i = 0; i < allFootprints.length; i++) { TokenFootprint footprint = (TokenFootprint) allFootprints[i]; @@ -117,23 +143,31 @@ String getFootprintNames(String gridType) { } String getTokenFootPrints(String gridType, String footprintName) { - Grid grid = GridFactory.createGrid(gridType, true, false); - var allFootprints = grid.getFootprints().toArray(); + Map> campaignFootprints = + net.rptools.maptool.client.MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints(); + if (gridType == null) { + JsonObject asJSON = new JsonObject(); + for (var entry : campaignFootprints.entrySet()) { + JsonObject footprintListJSON = new JsonObject(); + for (TokenFootprint f : entry.getValue()) { + footprintListJSON.add(f.getName(), f.toJson()); + } + asJSON.add(entry.getKey(), footprintListJSON); + } + return asJSON.toString(); + } + if (!campaignFootprints.containsKey(gridType)) { + return "null"; + } + var allFootprints = campaignFootprints.get(gridType).toArray(); if (footprintName == null) { // Get all footprints JsonObject asJSON = new JsonObject(); for (int i = 0; i < allFootprints.length; i++) { TokenFootprint footprint = (TokenFootprint) allFootprints[i]; - var occupiedCells = footprint.getOccupiedCells(new CellPoint(0, 0)).toArray(); - JsonArray occupiedString = new JsonArray(); - for (int j = 0; j < occupiedCells.length; j++) { - CellPoint currentCell = (CellPoint) occupiedCells[j]; - JsonObject jsonPoint = new JsonObject(); - jsonPoint.addProperty("x", currentCell.x); - jsonPoint.addProperty("y", currentCell.y); - occupiedString.add(jsonPoint); - } - asJSON.add(footprint.getName(), occupiedString); + asJSON.add(footprint.getName(), footprint.toJson()); } return asJSON.toString(); } else { @@ -142,18 +176,9 @@ String getTokenFootPrints(String gridType, String footprintName) { if (!Objects.equals(footprint.getName(), footprintName)) { continue; } - JsonArray asJSON = new JsonArray(); - var occupiedCells = footprint.getOccupiedCells(new CellPoint(0, 0)).toArray(); - for (int j = 0; j < occupiedCells.length; j++) { - CellPoint currentCell = (CellPoint) occupiedCells[j]; - JsonObject jsonPoint = new JsonObject(); - jsonPoint.addProperty("x", currentCell.x); - jsonPoint.addProperty("y", currentCell.y); - asJSON.add(jsonPoint); - } - return asJSON.toString(); + return footprint.toJson().toString(); } - return null; + return "null"; } } } diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index 853e632694..6cb1d897d8 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -50,6 +50,7 @@ import net.rptools.maptool.model.sheet.stats.StatSheetManager; import net.rptools.maptool.model.sheet.stats.StatSheetProperties; import net.rptools.maptool.server.proto.CampaignPropertiesDto; +import net.rptools.maptool.server.proto.FootprintListDto; import net.rptools.maptool.server.proto.LightSourceListDto; import net.rptools.maptool.server.proto.TokenPropertyListDto; @@ -281,6 +282,7 @@ public void initDefaultProperties() { initTokenStatesMap(); initTokenBarsMap(); initCharacterSheetsMap(); + initTokenFootprints(); } private void initLightSourcesMap() { @@ -362,6 +364,56 @@ private void initTokenTypeMap() { tokenTypeMap.put(getDefaultTokenPropertyType(), list); } + // Undesired reimplementation from Grid.java + protected List loadFootprints( + String path, net.rptools.maptool.model.TokenFootprint.OffsetTranslator... translators) { + List result = null; + try { + Object obj = net.rptools.lib.FileUtil.objFromResource(path); + @SuppressWarnings("unchecked") + List footprintList = (List) obj; + for (TokenFootprint footprint : footprintList) { + for (net.rptools.maptool.model.TokenFootprint.OffsetTranslator ot : translators) { + footprint.addOffsetTranslator(ot); + } + } + result = footprintList; + } catch (IOException ioe) { + MapTool.showError("Could not load VHex Grid footprints", ioe); + } + return result; + } + + private void initTokenFootprints() { + if (!gridFootprints.isEmpty()) { + return; + } + // Potential for importing defaults from app preferences instead. + + setGridFootprints( + "Horizontal Hex", + loadFootprints( + "net/rptools/maptool/model/hexGridHorizFootprints.xml", + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + offsetPoint.x++; + } + })); + setGridFootprints( + "Vertical Hex", + loadFootprints( + "net/rptools/maptool/model/hexGridVertFootprints.xml", + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + offsetPoint.y++; + } + })); + setGridFootprints( + "None", loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml")); + setGridFootprints( + "Square", loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml")); + } + private void initTokenStatesMap() { tokenStates.clear(); tokenStates.put("Dead", (new XTokenOverlay("Dead", Color.RED, 5))); @@ -592,7 +644,14 @@ public static CampaignProperties fromDto(CampaignPropertiesDto dto) { dto.getGridFootprints() .forEach( (k, v) -> { - // TODO Finish DTO Import for Footprints + List newList = new ArrayList<>(); + v.getFootprintList() + .forEach( + (ik, iv) -> { + TokenFootprint newPrint = TokenFootprint.fromDto(iv); + newList.add(newPrint); + }); + props.gridFootprints.put(k, newList); }); return props; @@ -641,7 +700,15 @@ public CampaignPropertiesDto toDto() { dto.addAllSightTypes( sightTypeMap.values().stream().map(SightType::toDto).collect(Collectors.toList())); dto.setDefaultTokenPropertyType(StringValue.of(defaultTokenPropertyType)); - //TODO Finish DTO Export for Footprints + gridFootprints.forEach( + (k, v) -> { + var subDTO = FootprintListDto.newBuilder(); + v.forEach( + (f) -> { + subDTO.putFootprintList(f.getName(), f.toDto()); + }); + dto.putGridFootprints(k, subDTO.build()); + }); return dto.build(); } } diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index 80199c5ae4..ac0dff3020 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -14,6 +14,8 @@ */ package net.rptools.maptool.model; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import java.awt.Point; import java.awt.Rectangle; import java.util.*; @@ -76,6 +78,23 @@ public String toString() { return getLocalizedName(); } + public JsonObject toJson() { + JsonObject jsonRep = new JsonObject(); + JsonArray occupiedString = new JsonArray(); + var cellArray = getOccupiedCells(new CellPoint(0, 0)).toArray(); + for (int j = 0; j < cellArray.length; j++) { + CellPoint currentCell = (CellPoint) cellArray[j]; + JsonObject jsonPoint = new JsonObject(); + jsonPoint.addProperty("x", currentCell.x); + jsonPoint.addProperty("y", currentCell.y); + occupiedString.add(jsonPoint); + } + jsonRep.addProperty("name", name); + jsonRep.add("cells", occupiedString); + jsonRep.addProperty("scale", scale); + return jsonRep; + } + public void addOffsetTranslator(OffsetTranslator translator) { translatorList.add(translator); } diff --git a/src/main/proto/data_transfer_objects.proto b/src/main/proto/data_transfer_objects.proto index 0340f9169d..66614873bc 100644 --- a/src/main/proto/data_transfer_objects.proto +++ b/src/main/proto/data_transfer_objects.proto @@ -138,12 +138,7 @@ message CampaignPropertiesDto { message FootprintListDto { string gridName = 1; - map footprintList = 2; -} - -message FootprintDto { - string name = 1; - repeated IntPointDto points = 2; + map footprintList = 2; } message SightTypeDto { From 7b57c420da423ae3f8ba0bc7e398c5a09915d550 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Fri, 30 Aug 2024 19:01:25 +0930 Subject: [PATCH 03/21] Footprint Modifications and Resets Adding and Removing new Footprints Resetting Footprints to Default Localized Footprint Name for Token --- .../client/functions/FootprintFunctions.java | 51 ++++++++++++++-- .../maptool/model/CampaignProperties.java | 60 +++++++++++++++---- .../rptools/maptool/model/TokenFootprint.java | 18 +++++- src/main/proto/data_transfer_objects.proto | 1 + 4 files changed, 112 insertions(+), 18 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index cc6e1f711e..bee2763aca 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -16,12 +16,16 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; +import java.awt.Point; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.regex.PatternSyntaxException; +import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.functions.exceptions.*; +import net.rptools.maptool.model.CampaignProperties; import net.rptools.maptool.model.TokenFootprint; +import net.rptools.maptool.util.FunctionUtil; import net.rptools.parser.Parser; import net.rptools.parser.ParserException; import net.rptools.parser.VariableResolver; @@ -41,7 +45,8 @@ public FootprintFunctions() { "setTokenFootprint", "removeTokenFootprint", "getFootprintNames", - "getGridTypes"); + "getGridTypes", + "resetFootprintsToDefault"); } /** The singleton instance. */ @@ -83,9 +88,14 @@ public Object childEvaluate( result = getTokenFootPrints(parameters.get(0).toString(), null); } } else if (functionName.equalsIgnoreCase("setTokenFootprint")) { - // TODO Set Token Footprint Function setTokenFootprint(name, scale, points) + FunctionUtil.checkNumberParam(functionName, parameters, 3, 3); + setTokenFootprint( + parameters.get(0).toString(), + parameters.get(1).toString(), + net.rptools.maptool.util.FunctionUtil.paramAsJsonObject(functionName, parameters, 2)); } else if (functionName.equalsIgnoreCase("removeTokenFootprint")) { - // TODO Remove Token Footprint Function removeTokenFootprint(grid, name) + FunctionUtil.checkNumberParam(functionName, parameters, 2, 2); + removeTokenFootprint(parameters.get(0).toString(), parameters.get(1).toString()); } else if (functionName.equalsIgnoreCase("getFootprintNames")) { if ((parameters.size() >= 1 && !(parameters.get(0) instanceof String))) { throw new ParserException( @@ -102,6 +112,8 @@ public Object childEvaluate( } else if (functionName.equalsIgnoreCase("getGridTypes")) { result = "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"Isometric\",\"Isometric Hex\",\"Isometric Hex\",\"None\"]"; + } else if (functionName.equalsIgnoreCase("resetFootprintsToDefault")) { + resetFootprintsToDefault(); } else { throw new ParserException( net.rptools.maptool.language.I18N.getText( @@ -144,9 +156,7 @@ String getFootprintNames(String gridType) { String getTokenFootPrints(String gridType, String footprintName) { Map> campaignFootprints = - net.rptools.maptool.client.MapTool.getCampaign() - .getCampaignProperties() - .getGridFootprints(); + MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (gridType == null) { JsonObject asJSON = new JsonObject(); for (var entry : campaignFootprints.entrySet()) { @@ -181,4 +191,33 @@ String getTokenFootPrints(String gridType, String footprintName) { return "null"; } } + + void setTokenFootprint(String name, String gridtype, JsonObject data) { + var cellList = data.get("cells").getAsJsonArray(); + Point[] newCells = new Point[cellList.size()]; + for (var i = 0; i < cellList.size(); i++) { + var cell = cellList.get(i).getAsJsonObject(); + newCells[i] = new Point(cell.get("x").getAsInt(), cell.get("y").getAsInt()); + } + TokenFootprint newPrint = + new TokenFootprint(name, false, data.get("scale").getAsDouble(), newCells); + if (data.has("localizedName")) { + newPrint.setLocalizedName(data.get("localizedName").getAsString()); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprint(name, gridtype, newPrint); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); + } + + void removeTokenFootprint(String name, String gridtype) { + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.removeGridFootprint(name, gridtype); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); + } + + void resetFootprintsToDefault() { + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.resetTokenFootprints(); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); + } } diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index 6cb1d897d8..80c0ae33d5 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -17,16 +17,8 @@ import com.google.protobuf.StringValue; import java.awt.Color; import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; import java.util.stream.Collectors; import net.rptools.lib.MD5Key; import net.rptools.maptool.client.AppPreferences; @@ -384,9 +376,19 @@ protected List loadFootprints( return result; } + public void resetTokenFootprints() { + initTokenFootprints(true); + } + private void initTokenFootprints() { - if (!gridFootprints.isEmpty()) { + initTokenFootprints(false); + } + + private void initTokenFootprints(boolean reset) { + if (!gridFootprints.isEmpty() && !reset) { return; + } else if (!gridFootprints.isEmpty()) { + gridFootprints.clear(); } // Potential for importing defaults from app preferences instead. @@ -535,6 +537,44 @@ public void setGridFootprints(String gridType, List footprintLis gridFootprints.put(gridType, footprintList); } + public void setGridFootprint(String footprintName, String gridType, TokenFootprint newPrint) { + if (!gridFootprints.containsKey(gridType)) { + gridFootprints.put(gridType, new ArrayList()); + } + List allFootprints = new ArrayList(gridFootprints.get(gridType)); + if (!allFootprints.isEmpty()) { + for (var i = 0; i < allFootprints.size(); i++) { + String testName = allFootprints.get(i).getName(); + if (Objects.equals(testName, footprintName)) { + allFootprints.set(i, newPrint); + return; + } + } + } + allFootprints.add(newPrint); + setGridFootprints(gridType, allFootprints); + } + + public void removeGridFootprint(String gridtype, String name) { + if (!gridFootprints.containsKey(gridtype) || gridFootprints.get(gridtype).isEmpty()) { + return; + } else { + List allFootprints = new ArrayList(gridFootprints.get(gridtype)); + int removeIndex = -1; + for (var i = 0; i < allFootprints.size(); i++) { + String testName = allFootprints.get(i).getName(); + if (Objects.equals(testName, name)) { + removeIndex = i; + break; + } + } + if (removeIndex != -1) { + allFootprints.remove(removeIndex); + setGridFootprints(gridtype, allFootprints); + } + } + } + protected Object readResolve() { if (tokenTypeMap == null) { tokenTypeMap = new HashMap<>(); diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index ac0dff3020..6e3145993a 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -33,6 +33,7 @@ public class TokenFootprint { private final Set cellSet = new HashSet(); private String name; + private String localizedName = null; private GUID id; private boolean isDefault; private double scale = 1; @@ -60,6 +61,7 @@ public static TokenFootprint fromDto(TokenFootPrintDto dto) { footPrint.id = GUID.valueOf(dto.getId()); footPrint.isDefault = dto.getIsDefault(); footPrint.scale = dto.getScale(); + footPrint.localizedName = dto.getLocalizedName(); return footPrint; } @@ -70,6 +72,9 @@ public TokenFootPrintDto toDto() { dto.setId(id.toString()); dto.setIsDefault(isDefault); dto.setScale(scale); + if (localizedName != null) { + dto.setLocalizedName(localizedName); + } return dto.build(); } @@ -92,6 +97,7 @@ public JsonObject toJson() { jsonRep.addProperty("name", name); jsonRep.add("cells", occupiedString); jsonRep.addProperty("scale", scale); + jsonRep.addProperty("localizedName", localizedName); return jsonRep; } @@ -103,6 +109,7 @@ public Set getOccupiedCells(CellPoint centerPoint) { Set occupiedSet = new HashSet(); // Implied + // Not a centre point on square grid, in fact is top-left?? occupiedSet.add(centerPoint); // Relative @@ -139,12 +146,19 @@ public String getName() { /** Returns the localized name of the footprint */ public String getLocalizedName() { - if (localizeName) { - return I18N.getString("TokenFootprint.name." + name.toLowerCase()); + if (localizeName && localizedName == null) { + localizedName = I18N.getString("TokenFootprint.name." + name.toLowerCase()); + return localizedName; + } else if (localizedName != null) { + return localizedName; } return name; } + public void setLocalizedName(String text) { + localizedName = text; + } + public Rectangle getBounds(Grid grid) { return getBounds(grid, null); } diff --git a/src/main/proto/data_transfer_objects.proto b/src/main/proto/data_transfer_objects.proto index 66614873bc..842d15876c 100644 --- a/src/main/proto/data_transfer_objects.proto +++ b/src/main/proto/data_transfer_objects.proto @@ -716,4 +716,5 @@ message TokenFootPrintDto { bool is_default = 4;; double scale = 5; bool localize_name = 6; + string localized_name = 7; } \ No newline at end of file From 3c6dcb35b512b6f29d000cf953b55aefaebe7b9f Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sat, 31 Aug 2024 10:25:48 +0930 Subject: [PATCH 04/21] Make (0,0) explicitly part of default footprints --- .../rptools/maptool/model/TokenFootprint.java | 5 +- .../maptool/model/hexGridFootprints.xml | 50 ++++++++++++++--- .../maptool/model/hexGridHorizFootprints.xml | 54 ++++++++++++++++--- .../maptool/model/hexGridVertFootprints.xml | 54 ++++++++++++++++--- .../maptool/model/squareGridFootprints.xml | 51 ++++++++++++++++-- 5 files changed, 188 insertions(+), 26 deletions(-) diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index 6e3145993a..8573071446 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -108,9 +108,8 @@ public void addOffsetTranslator(OffsetTranslator translator) { public Set getOccupiedCells(CellPoint centerPoint) { Set occupiedSet = new HashSet(); - // Implied - // Not a centre point on square grid, in fact is top-left?? - occupiedSet.add(centerPoint); + // not implied any more, explicitly part of footprint data + // occupiedSet.add(centerPoint); // Relative for (Point offset : cellSet) { diff --git a/src/main/resources/net/rptools/maptool/model/hexGridFootprints.xml b/src/main/resources/net/rptools/maptool/model/hexGridFootprints.xml index 3caf1724ed..e02fe8a16d 100644 --- a/src/main/resources/net/rptools/maptool/model/hexGridFootprints.xml +++ b/src/main/resources/net/rptools/maptool/model/hexGridFootprints.xml @@ -13,7 +13,12 @@ --> - + + + 0 + 0 + + 1/6 wKgPDgy5+1YBAAAAQKgJDA== @@ -22,7 +27,12 @@ 0.408 - + + + 0 + 0 + + 1/4 wKgPDgy5+1YCAAAAQKgJDA== @@ -31,7 +41,12 @@ 0.500 - + + + 0 + 0 + + 1/3 wKgPDgy5+1YDAAAAQKgJDA== @@ -40,7 +55,12 @@ 0.577 - + + + 0 + 0 + + 1/2 wKgPDgy5+1YEAAAAQKgJDA== @@ -49,7 +69,12 @@ 0.707 - + + + 0 + 0 + + 2/3 wKgPDgy5+1YFAAAAQKgJDA== @@ -58,7 +83,12 @@ 0.816 - + + + 0 + 0 + + Medium fwABAQllXDgBAAAAOAABAQ== @@ -69,6 +99,10 @@ + + 0 + 0 + 1 0 @@ -88,6 +122,10 @@ + + 0 + 0 + 1 -1 diff --git a/src/main/resources/net/rptools/maptool/model/hexGridHorizFootprints.xml b/src/main/resources/net/rptools/maptool/model/hexGridHorizFootprints.xml index d9af547c1e..945a05c07f 100644 --- a/src/main/resources/net/rptools/maptool/model/hexGridHorizFootprints.xml +++ b/src/main/resources/net/rptools/maptool/model/hexGridHorizFootprints.xml @@ -13,7 +13,12 @@ --> - + + + 0 + 0 + + 1/6 wKgPDgy5+1YBAAAAQKgJDA== @@ -22,7 +27,12 @@ 0.408 - + + + 0 + 0 + + 1/4 wKgPDgy5+1YCAAAAQKgJDA== @@ -31,7 +41,12 @@ 0.5 - + + + 0 + 0 + + 1/3 wKgPDgy5+1YDAAAAQKgJDA== @@ -40,7 +55,12 @@ 0.577 - + + + 0 + 0 + + 1/2 wKgPDgy5+1YEAAAAQKgJDA== @@ -49,7 +69,12 @@ 0.707 - + + + 0 + 0 + + 2/3 wKgPDgy5+1YFAAAAQKgJDA== @@ -58,7 +83,12 @@ 0.816 - + + + 0 + 0 + + Medium fwABAQllXDgBAAAAOAABAQ== @@ -69,6 +99,10 @@ + + 0 + 0 + 1 0 @@ -88,6 +122,10 @@ + + 0 + 0 + -1 1 @@ -123,6 +161,10 @@ + + 0 + 0 + -1 2 diff --git a/src/main/resources/net/rptools/maptool/model/hexGridVertFootprints.xml b/src/main/resources/net/rptools/maptool/model/hexGridVertFootprints.xml index 9fc056c759..8375745c74 100644 --- a/src/main/resources/net/rptools/maptool/model/hexGridVertFootprints.xml +++ b/src/main/resources/net/rptools/maptool/model/hexGridVertFootprints.xml @@ -13,7 +13,12 @@ --> - + + + 0 + 0 + + 1/6 wKgPDgy5+1YBAAAAQKgJDA== @@ -22,7 +27,12 @@ 0.408 - + + + 0 + 0 + + 1/4 wKgPDgy5+1YCAAAAQKgJDA== @@ -31,7 +41,12 @@ 0.5 - + + + 0 + 0 + + 1/3 wKgPDgy5+1YDAAAAQKgJDA== @@ -40,7 +55,12 @@ 0.577 - + + + 0 + 0 + + 1/2 wKgPDgy5+1YEAAAAQKgJDA== @@ -49,7 +69,12 @@ 0.707 - + + + 0 + 0 + + 2/3 wKgPDgy5+1YFAAAAQKgJDA== @@ -58,7 +83,12 @@ 0.816 - + + + 0 + 0 + + Medium fwABAQllXDgBAAAAOAABAQ== @@ -69,6 +99,10 @@ + + 0 + 0 + 1 0 @@ -88,6 +122,10 @@ + + 0 + 0 + 1 -1 @@ -123,6 +161,10 @@ + + 0 + 0 + 1 -2 diff --git a/src/main/resources/net/rptools/maptool/model/squareGridFootprints.xml b/src/main/resources/net/rptools/maptool/model/squareGridFootprints.xml index d6f2caea4f..74a91532bb 100644 --- a/src/main/resources/net/rptools/maptool/model/squareGridFootprints.xml +++ b/src/main/resources/net/rptools/maptool/model/squareGridFootprints.xml @@ -13,7 +13,12 @@ --> - + + + 0 + 0 + + Fine fwABAc1lFSoBAAAAKgABAQ== @@ -22,7 +27,12 @@ true - + + + 0 + 0 + + Diminutive fwABAc1lFSoCAAAAKgABAQ== @@ -31,7 +41,12 @@ true - + + + 0 + 0 + + Tiny fwABAc5lFSoDAAAAKgABAA== @@ -40,7 +55,12 @@ true - + + + 0 + 0 + + Small fwABAc5lFSoEAAAAKgABAA== @@ -49,7 +69,12 @@ true - + + + 0 + 0 + + Medium fwABAc9lFSoFAAAAKgABAQ== @@ -60,6 +85,10 @@ + + 0 + 0 + 1 1 @@ -82,6 +111,10 @@ + + 0 + 0 + 2 2 @@ -124,6 +157,10 @@ + + 0 + 0 + 3 0 @@ -194,6 +231,10 @@ + + 0 + 0 + 2 4 From 605eb62ec3ceb76bb788e93398e32a0145e5e76d Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:18:49 +0930 Subject: [PATCH 05/21] Corrected actual grid list, better error reporting Comments --- .../client/functions/FootprintFunctions.java | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index bee2763aca..99f0dfb22e 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -17,6 +17,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import java.awt.Point; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; @@ -68,6 +69,12 @@ public Object childEvaluate( String result = ""; + ArrayList gridTypes = new ArrayList<>(); + gridTypes.add("Vertical Hex"); + gridTypes.add("Horizontal Hex"); + gridTypes.add("Square"); + gridTypes.add("None"); + try { if (functionName.equalsIgnoreCase("getTokenFootprints")) { if ((parameters.size() >= 2 @@ -83,18 +90,34 @@ public Object childEvaluate( } else if (parameters.isEmpty()) { result = getTokenFootPrints(null, null); } else if (parameters.size() > 1) { + if(!gridTypes.contains(parameters.get(0).toString())){ + throw new ParserException( + net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + } result = getTokenFootPrints(parameters.get(0).toString(), parameters.get(1).toString()); } else { + if(!gridTypes.contains(parameters.get(0).toString())){ + throw new ParserException( + net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + } result = getTokenFootPrints(parameters.get(0).toString(), null); } } else if (functionName.equalsIgnoreCase("setTokenFootprint")) { FunctionUtil.checkNumberParam(functionName, parameters, 3, 3); + if(!gridTypes.contains(parameters.get(0).toString())){ + throw new ParserException( + net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + } setTokenFootprint( parameters.get(0).toString(), parameters.get(1).toString(), net.rptools.maptool.util.FunctionUtil.paramAsJsonObject(functionName, parameters, 2)); } else if (functionName.equalsIgnoreCase("removeTokenFootprint")) { FunctionUtil.checkNumberParam(functionName, parameters, 2, 2); + if(!gridTypes.contains(parameters.get(0).toString())){ + throw new ParserException( + net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + } removeTokenFootprint(parameters.get(0).toString(), parameters.get(1).toString()); } else if (functionName.equalsIgnoreCase("getFootprintNames")) { if ((parameters.size() >= 1 && !(parameters.get(0) instanceof String))) { @@ -107,11 +130,15 @@ public Object childEvaluate( } else if (parameters.isEmpty()) { result = getFootprintNames(null); } else { + if(!gridTypes.contains(parameters.get(0).toString())){ + throw new ParserException( + net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + } result = getFootprintNames(parameters.get(0).toString()); } } else if (functionName.equalsIgnoreCase("getGridTypes")) { result = - "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"Isometric\",\"Isometric Hex\",\"Isometric Hex\",\"None\"]"; + "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"None\"]"; } else if (functionName.equalsIgnoreCase("resetFootprintsToDefault")) { resetFootprintsToDefault(); } else { @@ -126,6 +153,9 @@ public Object childEvaluate( return result; } + /* Returns a String representing the JSON object containing footprints within the given grid type + * or if gridType is null it returns a JSON object containing all of the above JSON objects for all grids. + * */ String getFootprintNames(String gridType) { Map> campaignFootprints = net.rptools.maptool.client.MapTool.getCampaign() @@ -154,6 +184,10 @@ String getFootprintNames(String gridType) { return footprintNames.toString(); } + /* Gets string representation of JSON object containing footprint data for given gridType and footprintName + if footprint name omitted, it returns a JSON object containing all footprints for given gridType + if gridType also omitted, it returns all the above JSON Objects for all existing gridtypes + */ String getTokenFootPrints(String gridType, String footprintName) { Map> campaignFootprints = MapTool.getCampaign().getCampaignProperties().getGridFootprints(); @@ -192,7 +226,8 @@ String getTokenFootPrints(String gridType, String footprintName) { } } - void setTokenFootprint(String name, String gridtype, JsonObject data) { + /* sets token footprint under given name/gridtype to the footprint represented in data */ + void setTokenFootprint(String gridtype, String name, JsonObject data) { var cellList = data.get("cells").getAsJsonArray(); Point[] newCells = new Point[cellList.size()]; for (var i = 0; i < cellList.size(); i++) { @@ -209,12 +244,14 @@ void setTokenFootprint(String name, String gridtype, JsonObject data) { MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } - void removeTokenFootprint(String name, String gridtype) { + /* removes the footprint named "name" under gridType*/ + void removeTokenFootprint(String gridtype, String name) { CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.removeGridFootprint(name, gridtype); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } + /* Resets all footprints to default, discarding any/all custom or edited footprints */ void resetFootprintsToDefault() { CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.resetTokenFootprints(); From 4b49f4c8617dd815331278ff2539111129eda685 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:19:08 +0930 Subject: [PATCH 06/21] Corrected actual grid list, better error reporting Comments --- .../client/functions/FootprintFunctions.java | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index 99f0dfb22e..54f23b6028 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -90,23 +90,29 @@ public Object childEvaluate( } else if (parameters.isEmpty()) { result = getTokenFootPrints(null, null); } else if (parameters.size() > 1) { - if(!gridTypes.contains(parameters.get(0).toString())){ + if (!gridTypes.contains(parameters.get(0).toString())) { throw new ParserException( - net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + net.rptools.maptool.language.I18N.getText( + "macro.function.footprintFunctions.unknownGridType", + parameters.get(0).toString())); } result = getTokenFootPrints(parameters.get(0).toString(), parameters.get(1).toString()); } else { - if(!gridTypes.contains(parameters.get(0).toString())){ + if (!gridTypes.contains(parameters.get(0).toString())) { throw new ParserException( - net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + net.rptools.maptool.language.I18N.getText( + "macro.function.footprintFunctions.unknownGridType", + parameters.get(0).toString())); } result = getTokenFootPrints(parameters.get(0).toString(), null); } } else if (functionName.equalsIgnoreCase("setTokenFootprint")) { FunctionUtil.checkNumberParam(functionName, parameters, 3, 3); - if(!gridTypes.contains(parameters.get(0).toString())){ + if (!gridTypes.contains(parameters.get(0).toString())) { throw new ParserException( - net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + net.rptools.maptool.language.I18N.getText( + "macro.function.footprintFunctions.unknownGridType", + parameters.get(0).toString())); } setTokenFootprint( parameters.get(0).toString(), @@ -114,9 +120,11 @@ public Object childEvaluate( net.rptools.maptool.util.FunctionUtil.paramAsJsonObject(functionName, parameters, 2)); } else if (functionName.equalsIgnoreCase("removeTokenFootprint")) { FunctionUtil.checkNumberParam(functionName, parameters, 2, 2); - if(!gridTypes.contains(parameters.get(0).toString())){ + if (!gridTypes.contains(parameters.get(0).toString())) { throw new ParserException( - net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + net.rptools.maptool.language.I18N.getText( + "macro.function.footprintFunctions.unknownGridType", + parameters.get(0).toString())); } removeTokenFootprint(parameters.get(0).toString(), parameters.get(1).toString()); } else if (functionName.equalsIgnoreCase("getFootprintNames")) { @@ -130,15 +138,16 @@ public Object childEvaluate( } else if (parameters.isEmpty()) { result = getFootprintNames(null); } else { - if(!gridTypes.contains(parameters.get(0).toString())){ + if (!gridTypes.contains(parameters.get(0).toString())) { throw new ParserException( - net.rptools.maptool.language.I18N.getText("macro.function.footprintFunctions.unknownGridType", parameters.get(0).toString())); + net.rptools.maptool.language.I18N.getText( + "macro.function.footprintFunctions.unknownGridType", + parameters.get(0).toString())); } result = getFootprintNames(parameters.get(0).toString()); } } else if (functionName.equalsIgnoreCase("getGridTypes")) { - result = - "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"None\"]"; + result = "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"None\"]"; } else if (functionName.equalsIgnoreCase("resetFootprintsToDefault")) { resetFootprintsToDefault(); } else { @@ -154,8 +163,8 @@ public Object childEvaluate( } /* Returns a String representing the JSON object containing footprints within the given grid type - * or if gridType is null it returns a JSON object containing all of the above JSON objects for all grids. - * */ + * or if gridType is null it returns a JSON object containing all of the above JSON objects for all grids. + * */ String getFootprintNames(String gridType) { Map> campaignFootprints = net.rptools.maptool.client.MapTool.getCampaign() From 2a2a80839b4e16c46eedc825e8079e0a338266f1 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sun, 1 Sep 2024 13:21:45 +0930 Subject: [PATCH 07/21] New i18n string --- src/main/resources/net/rptools/maptool/language/i18n.properties | 2 ++ .../resources/net/rptools/maptool/language/i18n_en.properties | 2 ++ .../net/rptools/maptool/language/i18n_en_AU.properties | 2 ++ .../net/rptools/maptool/language/i18n_en_GB.properties | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/main/resources/net/rptools/maptool/language/i18n.properties b/src/main/resources/net/rptools/maptool/language/i18n.properties index 4ebff9e42d..211e2f2ef1 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n.properties @@ -2130,6 +2130,8 @@ macro.function.html5.invalidURI = Invalid URI {0}. macro.function.html5.unknownType = Unknown HTML5 Container specified. macro.function.jsevalURI.invalidURI = Can not access JavaScript from URI {0}. +macro.function.footprintFunctions.unknownGridType = Unknown Grid Type. + macro.setAllowsURIAccess.notLibToken = {0} is not a valid lib:token name, URI access can only be set on lib:tokens. macro.setAllowsURIAccess.reservedPrefix = Can not set URI access on lib:tokens starting with {0} macro.setAllowsURIAccess.reserved = Can not set URI access on lib:token named {0} diff --git a/src/main/resources/net/rptools/maptool/language/i18n_en.properties b/src/main/resources/net/rptools/maptool/language/i18n_en.properties index 00142e12aa..7ee122dd5b 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n_en.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n_en.properties @@ -1947,6 +1947,8 @@ macro.function.html5.invalidURI = Invalid URI {0}. macro.function.html5.unknownType = Unknown HTML5 Container specified. macro.function.jsevalURI.invalidURI = Can not access JavaScript from URI {0}. +macro.function.footprintFunctions.unknownGridType = Unknown Grid Type. + macro.setAllowsURIAccess.notLibToken = {0} is not a valid lib\:token name, URI access can only be set on lib\:tokens. macro.setAllowsURIAccess.reservedPrefix = Can not set URI access on lib\:tokens starting with {0} macro.setAllowsURIAccess.reserved = Can not set URI access on lib\:token named {0} diff --git a/src/main/resources/net/rptools/maptool/language/i18n_en_AU.properties b/src/main/resources/net/rptools/maptool/language/i18n_en_AU.properties index 45f9774099..dd712483c0 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n_en_AU.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n_en_AU.properties @@ -1994,6 +1994,8 @@ macro.function.html5.invalidURI = Invalid URI {0}. macro.function.html5.unknownType = Unknown HTML5 Container specified. macro.function.jsevalURI.invalidURI = Can not access JavaScript from URI {0}. +macro.function.footprintFunctions.unknownGridType = Unknown Grid Type. + macro.setAllowsURIAccess.notLibToken = {0} is not a valid lib\:token name, URI access can only be set on lib\:tokens. macro.setAllowsURIAccess.reservedPrefix = Can not set URI access on lib\:tokens starting with {0} macro.setAllowsURIAccess.reserved = Can not set URI access on lib\:token named {0} diff --git a/src/main/resources/net/rptools/maptool/language/i18n_en_GB.properties b/src/main/resources/net/rptools/maptool/language/i18n_en_GB.properties index c019dc0d33..e5ea84185d 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n_en_GB.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n_en_GB.properties @@ -1994,6 +1994,8 @@ macro.function.html5.invalidURI = Invalid URI {0}. macro.function.html5.unknownType = Unknown HTML5 Container specified. macro.function.jsevalURI.invalidURI = Can not access JavaScript from URI {0}. +macro.function.footprintFunctions.unknownGridType = Unknown Grid Type. + macro.setAllowsURIAccess.notLibToken = {0} is not a valid lib\:token name, URI access can only be set on lib\:tokens. macro.setAllowsURIAccess.reservedPrefix = Can not set URI access on lib\:tokens starting with {0} macro.setAllowsURIAccess.reserved = Can not set URI access on lib\:token named {0} From 40ad58de03c5342a00fc20c67ee32264ac7e98c2 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:55:29 +0930 Subject: [PATCH 08/21] Fixes and Cleaning Up Remove Grid.loadFootprints (commented for now) Remove uses of Grid.loadFootprints (commented for now) Move FootprintToJSON Comment Cleanup Fixed Dev Env Mistakes Attempted fix of #4856 --- .../client/MapToolExpressionParser.java | 1 - .../client/functions/FootprintFunctions.java | 31 ++++++++++++++--- .../maptool/model/CampaignProperties.java | 6 ++-- .../java/net/rptools/maptool/model/Grid.java | 2 ++ .../rptools/maptool/model/GridlessGrid.java | 4 ++- .../maptool/model/HexGridHorizontal.java | 3 +- .../maptool/model/HexGridVertical.java | 4 +-- .../rptools/maptool/model/IsometricGrid.java | 3 +- .../net/rptools/maptool/model/SquareGrid.java | 4 +-- .../java/net/rptools/maptool/model/Token.java | 4 +++ .../rptools/maptool/model/TokenFootprint.java | 34 +++++-------------- 11 files changed, 55 insertions(+), 41 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java b/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java index 4b99e74b39..2a728d5291 100644 --- a/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java +++ b/src/main/java/net/rptools/maptool/client/MapToolExpressionParser.java @@ -19,7 +19,6 @@ import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; -import main.java.net.rptools.maptool.client.functions.FootprintFunctions; // why import net.rptools.dicelib.expression.ExpressionParser; import net.rptools.maptool.client.functions.*; import net.rptools.maptool.client.functions.json.JSONMacroFunctions; diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index 54f23b6028..b94176bb48 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -12,7 +12,7 @@ * and specifically the Affero license * text at . */ -package main.java.net.rptools.maptool.client.functions; +package net.rptools.maptool.client.functions; import com.google.gson.JsonArray; import com.google.gson.JsonObject; @@ -31,6 +31,7 @@ import net.rptools.parser.ParserException; import net.rptools.parser.VariableResolver; import net.rptools.parser.function.AbstractFunction; +import net.rptools.maptool.model.CellPoint; /** * functions for dealing with token footprint retrieval and modification. @@ -205,7 +206,7 @@ String getTokenFootPrints(String gridType, String footprintName) { for (var entry : campaignFootprints.entrySet()) { JsonObject footprintListJSON = new JsonObject(); for (TokenFootprint f : entry.getValue()) { - footprintListJSON.add(f.getName(), f.toJson()); + footprintListJSON.add(f.getName(), FootprintToJsonObject(f)); } asJSON.add(entry.getKey(), footprintListJSON); } @@ -220,7 +221,7 @@ String getTokenFootPrints(String gridType, String footprintName) { JsonObject asJSON = new JsonObject(); for (int i = 0; i < allFootprints.length; i++) { TokenFootprint footprint = (TokenFootprint) allFootprints[i]; - asJSON.add(footprint.getName(), footprint.toJson()); + asJSON.add(footprint.getName(), FootprintToJsonObject(footprint)); } return asJSON.toString(); } else { @@ -229,7 +230,7 @@ String getTokenFootPrints(String gridType, String footprintName) { if (!Objects.equals(footprint.getName(), footprintName)) { continue; } - return footprint.toJson().toString(); + return FootprintToJsonObject(footprint).toString(); } return "null"; } @@ -248,6 +249,9 @@ void setTokenFootprint(String gridtype, String name, JsonObject data) { if (data.has("localizedName")) { newPrint.setLocalizedName(data.get("localizedName").getAsString()); } + if (data.has("isDefault")) { + newPrint.setDefault(data.get("isDefault").getAsBoolean()); + } CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.setGridFootprint(name, gridtype, newPrint); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); @@ -266,4 +270,23 @@ void resetFootprintsToDefault() { ModifiedProperties.resetTokenFootprints(); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } + + public JsonObject FootprintToJsonObject(TokenFootprint footprint) { + JsonObject jsonRep = new JsonObject(); + JsonArray occupiedString = new JsonArray(); + var cellArray = footprint.getOccupiedCells(new CellPoint(0, 0)).toArray(); + for (int j = 0; j < cellArray.length; j++) { + CellPoint currentCell = (CellPoint) cellArray[j]; + JsonObject jsonPoint = new JsonObject(); + jsonPoint.addProperty("x", currentCell.x); + jsonPoint.addProperty("y", currentCell.y); + occupiedString.add(jsonPoint); + } + jsonRep.addProperty("name", footprint.getName()); + jsonRep.add("cells", occupiedString); + jsonRep.addProperty("scale", footprint.getScale()); + jsonRep.addProperty("localizedName", footprint.getLocalizedName()); + jsonRep.addProperty("isDefault", footprint.isDefault()); + return jsonRep; + } } diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index 80c0ae33d5..f59ffe28eb 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -140,7 +140,8 @@ public CampaignProperties(CampaignProperties properties) { } defaultTokenPropertyType = properties.defaultTokenPropertyType; if (properties.gridFootprints != null) { - gridFootprints = properties.gridFootprints; + gridFootprints.clear(); + gridFootprints.putAll(properties.gridFootprints); } } @@ -164,7 +165,7 @@ public void mergeInto(CampaignProperties properties) { if (properties.gridFootprints != null) { properties.gridFootprints.putAll(gridFootprints); } else { - properties.gridFootprints = gridFootprints; + properties.gridFootprints = new HashMap<>(gridFootprints); } } @@ -356,7 +357,6 @@ private void initTokenTypeMap() { tokenTypeMap.put(getDefaultTokenPropertyType(), list); } - // Undesired reimplementation from Grid.java protected List loadFootprints( String path, net.rptools.maptool.model.TokenFootprint.OffsetTranslator... translators) { List result = null; diff --git a/src/main/java/net/rptools/maptool/model/Grid.java b/src/main/java/net/rptools/maptool/model/Grid.java index bf11e27508..51e643f574 100644 --- a/src/main/java/net/rptools/maptool/model/Grid.java +++ b/src/main/java/net/rptools/maptool/model/Grid.java @@ -137,6 +137,7 @@ public int[] getFacingAngles() { */ public abstract Point2D.Double getCellCenter(CellPoint cell); + /* protected List loadFootprints(String path, OffsetTranslator... translators) throws IOException { Object obj = FileUtil.objFromResource(path); @@ -149,6 +150,7 @@ protected List loadFootprints(String path, OffsetTranslator... t } return footprintList; } + */ public TokenFootprint getDefaultFootprint() { for (TokenFootprint footprint : getFootprints()) { diff --git a/src/main/java/net/rptools/maptool/model/GridlessGrid.java b/src/main/java/net/rptools/maptool/model/GridlessGrid.java index 8e509bc9b1..459e0b7df5 100644 --- a/src/main/java/net/rptools/maptool/model/GridlessGrid.java +++ b/src/main/java/net/rptools/maptool/model/GridlessGrid.java @@ -67,7 +67,8 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("None")) { return campaignFootprints.get("None"); - } else { + } + /*else { try { footprintList = loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml"); } catch (IOException ioe) { @@ -77,6 +78,7 @@ public List getFootprints() { ModifiedProperties.setGridFootprints("None", footprintList); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } + */ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java index 4d5b8b4510..0aa584d08c 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java +++ b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java @@ -189,7 +189,7 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Horizontal Hex")) { return campaignFootprints.get("Horizontal Hex"); - } else { + } /*else { try { footprintList = loadFootprints( @@ -201,6 +201,7 @@ public List getFootprints() { ModifiedProperties.setGridFootprints("Horizontal Hex", footprintList); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } + */ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/HexGridVertical.java b/src/main/java/net/rptools/maptool/model/HexGridVertical.java index 7eb359aef5..db91b17ece 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridVertical.java +++ b/src/main/java/net/rptools/maptool/model/HexGridVertical.java @@ -176,7 +176,7 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Vertical Hex")) { return campaignFootprints.get("Vertical Hex"); - } else { + } /*else { try { footprintList = loadFootprints( @@ -187,7 +187,7 @@ public List getFootprints() { CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.setGridFootprints("Vertical Hex", footprintList); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } + }*/ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/IsometricGrid.java b/src/main/java/net/rptools/maptool/model/IsometricGrid.java index 096bdcb320..7db284c42b 100644 --- a/src/main/java/net/rptools/maptool/model/IsometricGrid.java +++ b/src/main/java/net/rptools/maptool/model/IsometricGrid.java @@ -181,7 +181,7 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); - } else { + } /*else { try { footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); } catch (IOException ioe) { @@ -191,6 +191,7 @@ public List getFootprints() { ModifiedProperties.setGridFootprints("Square", footprintList); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } + */ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/SquareGrid.java b/src/main/java/net/rptools/maptool/model/SquareGrid.java index 0d4261ca23..a7bd4b0e06 100644 --- a/src/main/java/net/rptools/maptool/model/SquareGrid.java +++ b/src/main/java/net/rptools/maptool/model/SquareGrid.java @@ -226,7 +226,7 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); - } else { + } /*else { try { footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); } catch (IOException ioe) { @@ -235,7 +235,7 @@ public List getFootprints() { CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.setGridFootprints("Square", footprintList); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } + }*/ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/Token.java b/src/main/java/net/rptools/maptool/model/Token.java index 59d5a3baca..284e619356 100644 --- a/src/main/java/net/rptools/maptool/model/Token.java +++ b/src/main/java/net/rptools/maptool/model/Token.java @@ -1308,6 +1308,10 @@ public boolean isSnapToScale() { */ public void setSnapToScale(boolean snapScale) { this.snapToScale = snapScale; + if (!snapScale){ //Reset to default footprint when set to native size + var grid = getZoneRenderer().getZone().getGrid(); + setFootprint(grid,grid.getDefaultFootprint()); + } } public void setVisible(boolean visible) { diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index 8573071446..c08365efb9 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -14,8 +14,6 @@ */ package net.rptools.maptool.model; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; import java.awt.Point; import java.awt.Rectangle; import java.util.*; @@ -83,39 +81,23 @@ public String toString() { return getLocalizedName(); } - public JsonObject toJson() { - JsonObject jsonRep = new JsonObject(); - JsonArray occupiedString = new JsonArray(); - var cellArray = getOccupiedCells(new CellPoint(0, 0)).toArray(); - for (int j = 0; j < cellArray.length; j++) { - CellPoint currentCell = (CellPoint) cellArray[j]; - JsonObject jsonPoint = new JsonObject(); - jsonPoint.addProperty("x", currentCell.x); - jsonPoint.addProperty("y", currentCell.y); - occupiedString.add(jsonPoint); - } - jsonRep.addProperty("name", name); - jsonRep.add("cells", occupiedString); - jsonRep.addProperty("scale", scale); - jsonRep.addProperty("localizedName", localizedName); - return jsonRep; - } - public void addOffsetTranslator(OffsetTranslator translator) { translatorList.add(translator); } - public Set getOccupiedCells(CellPoint centerPoint) { + /* TokenFootprint is a list of cells relative to the (0,0) + This function returns the actual points when the (0,0) of the footprint is located at the reference point. + For Square Grids, the reference point is at the top left + For Hex Grids, the reference point is at the centre + */ + public Set getOccupiedCells(CellPoint referencePoint) { Set occupiedSet = new HashSet(); - // not implied any more, explicitly part of footprint data - // occupiedSet.add(centerPoint); - // Relative for (Point offset : cellSet) { - CellPoint cp = new CellPoint(centerPoint.x + offset.x, centerPoint.y + offset.y); + CellPoint cp = new CellPoint(referencePoint.x + offset.x, referencePoint.y + offset.y); for (OffsetTranslator translator : translatorList) { - translator.translate(centerPoint, cp); + translator.translate(referencePoint, cp); } occupiedSet.add(cp); } From cc69bd3d13763aa8177e58fe76442e23637184e6 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Mon, 2 Sep 2024 16:57:34 +0930 Subject: [PATCH 09/21] Spotless Apply --- .../client/functions/FootprintFunctions.java | 2 +- .../java/net/rptools/maptool/model/Grid.java | 3 --- .../rptools/maptool/model/GridlessGrid.java | 3 +-- .../maptool/model/HexGridHorizontal.java | 23 +++++++++---------- .../maptool/model/HexGridVertical.java | 23 +++++++++---------- .../rptools/maptool/model/IsometricGrid.java | 19 ++++++++------- .../net/rptools/maptool/model/SquareGrid.java | 19 ++++++++------- .../java/net/rptools/maptool/model/Token.java | 4 ++-- 8 files changed, 44 insertions(+), 52 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index b94176bb48..54177d1553 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -25,13 +25,13 @@ import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.functions.exceptions.*; import net.rptools.maptool.model.CampaignProperties; +import net.rptools.maptool.model.CellPoint; import net.rptools.maptool.model.TokenFootprint; import net.rptools.maptool.util.FunctionUtil; import net.rptools.parser.Parser; import net.rptools.parser.ParserException; import net.rptools.parser.VariableResolver; import net.rptools.parser.function.AbstractFunction; -import net.rptools.maptool.model.CellPoint; /** * functions for dealing with token footprint retrieval and modification. diff --git a/src/main/java/net/rptools/maptool/model/Grid.java b/src/main/java/net/rptools/maptool/model/Grid.java index 51e643f574..4d1ee3d9da 100644 --- a/src/main/java/net/rptools/maptool/model/Grid.java +++ b/src/main/java/net/rptools/maptool/model/Grid.java @@ -18,7 +18,6 @@ import java.awt.*; import java.awt.geom.*; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -28,7 +27,6 @@ import javax.annotation.Nonnull; import javax.swing.Action; import javax.swing.KeyStroke; -import net.rptools.lib.FileUtil; import net.rptools.maptool.client.AppPreferences; import net.rptools.maptool.client.DeveloperOptions; import net.rptools.maptool.client.MapTool; @@ -37,7 +35,6 @@ import net.rptools.maptool.client.walker.WalkerMetric; import net.rptools.maptool.client.walker.ZoneWalker; import net.rptools.maptool.events.MapToolEventBus; -import net.rptools.maptool.model.TokenFootprint.OffsetTranslator; import net.rptools.maptool.model.zones.GridChanged; import net.rptools.maptool.server.proto.GridDto; import net.rptools.maptool.util.GraphicsUtil; diff --git a/src/main/java/net/rptools/maptool/model/GridlessGrid.java b/src/main/java/net/rptools/maptool/model/GridlessGrid.java index 459e0b7df5..b59b8064df 100644 --- a/src/main/java/net/rptools/maptool/model/GridlessGrid.java +++ b/src/main/java/net/rptools/maptool/model/GridlessGrid.java @@ -18,7 +18,6 @@ import java.awt.event.KeyEvent; import java.awt.geom.Area; import java.awt.geom.Point2D; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -68,7 +67,7 @@ public List getFootprints() { if (campaignFootprints.containsKey("None")) { return campaignFootprints.get("None"); } - /*else { + /*else { try { footprintList = loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml"); } catch (IOException ioe) { diff --git a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java index 0aa584d08c..2f1a34649f 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java +++ b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java @@ -22,7 +22,6 @@ import java.awt.geom.GeneralPath; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -190,18 +189,18 @@ public List getFootprints() { if (campaignFootprints.containsKey("Horizontal Hex")) { return campaignFootprints.get("Horizontal Hex"); } /*else { - try { - footprintList = - loadFootprints( - "net/rptools/maptool/model/hexGridHorizFootprints.xml", getOffsetTranslator()); - } catch (IOException ioe) { - MapTool.showError("Could not load HHex Grid footprints", ioe); + try { + footprintList = + loadFootprints( + "net/rptools/maptool/model/hexGridHorizFootprints.xml", getOffsetTranslator()); + } catch (IOException ioe) { + MapTool.showError("Could not load HHex Grid footprints", ioe); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Horizontal Hex", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Horizontal Hex", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } - */ + */ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/HexGridVertical.java b/src/main/java/net/rptools/maptool/model/HexGridVertical.java index db91b17ece..58b8f22709 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridVertical.java +++ b/src/main/java/net/rptools/maptool/model/HexGridVertical.java @@ -21,7 +21,6 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -177,17 +176,17 @@ public List getFootprints() { if (campaignFootprints.containsKey("Vertical Hex")) { return campaignFootprints.get("Vertical Hex"); } /*else { - try { - footprintList = - loadFootprints( - "net/rptools/maptool/model/hexGridVertFootprints.xml", getOffsetTranslator()); - } catch (IOException ioe) { - MapTool.showError("Could not load VHex Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Vertical Hex", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - }*/ + try { + footprintList = + loadFootprints( + "net/rptools/maptool/model/hexGridVertFootprints.xml", getOffsetTranslator()); + } catch (IOException ioe) { + MapTool.showError("Could not load VHex Grid footprints", ioe); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Vertical Hex", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); + }*/ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/IsometricGrid.java b/src/main/java/net/rptools/maptool/model/IsometricGrid.java index 7db284c42b..8f13239f59 100644 --- a/src/main/java/net/rptools/maptool/model/IsometricGrid.java +++ b/src/main/java/net/rptools/maptool/model/IsometricGrid.java @@ -18,7 +18,6 @@ import java.awt.event.KeyEvent; import java.awt.geom.*; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -182,16 +181,16 @@ public List getFootprints() { if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); } /*else { - try { - footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); - } catch (IOException ioe) { - MapTool.showError("Could not load Square Grid footprints", ioe); + try { + footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); + } catch (IOException ioe) { + MapTool.showError("Could not load Square Grid footprints", ioe); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Square", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Square", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } - */ + */ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/SquareGrid.java b/src/main/java/net/rptools/maptool/model/SquareGrid.java index a7bd4b0e06..cea3231d16 100644 --- a/src/main/java/net/rptools/maptool/model/SquareGrid.java +++ b/src/main/java/net/rptools/maptool/model/SquareGrid.java @@ -24,7 +24,6 @@ import java.awt.geom.Area; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; -import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -227,15 +226,15 @@ public List getFootprints() { if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); } /*else { - try { - footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); - } catch (IOException ioe) { - MapTool.showError("Could not load Square Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Square", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - }*/ + try { + footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); + } catch (IOException ioe) { + MapTool.showError("Could not load Square Grid footprints", ioe); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); + ModifiedProperties.setGridFootprints("Square", footprintList); + MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); + }*/ return footprintList; } diff --git a/src/main/java/net/rptools/maptool/model/Token.java b/src/main/java/net/rptools/maptool/model/Token.java index 284e619356..7ae853c214 100644 --- a/src/main/java/net/rptools/maptool/model/Token.java +++ b/src/main/java/net/rptools/maptool/model/Token.java @@ -1308,9 +1308,9 @@ public boolean isSnapToScale() { */ public void setSnapToScale(boolean snapScale) { this.snapToScale = snapScale; - if (!snapScale){ //Reset to default footprint when set to native size + if (!snapScale) { // Reset to default footprint when set to native size var grid = getZoneRenderer().getZone().getGrid(); - setFootprint(grid,grid.getDefaultFootprint()); + setFootprint(grid, grid.getDefaultFootprint()); } } From b36510efd52d81975418703ccc386c16e14c3ade Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:40:24 +0930 Subject: [PATCH 10/21] Localized Name Edge Case and TokenFootprintCreator Updates --- .../client/functions/FootprintFunctions.java | 2 +- .../maptool/model/CampaignProperties.java | 47 +------- .../rptools/maptool/model/TokenFootprint.java | 13 +- .../maptool/tool/TokenFootprintCreator.java | 114 ++++++------------ 4 files changed, 55 insertions(+), 121 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index 54177d1553..5d50ccce7f 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -285,7 +285,7 @@ public JsonObject FootprintToJsonObject(TokenFootprint footprint) { jsonRep.addProperty("name", footprint.getName()); jsonRep.add("cells", occupiedString); jsonRep.addProperty("scale", footprint.getScale()); - jsonRep.addProperty("localizedName", footprint.getLocalizedName()); + jsonRep.addProperty("localizedName", footprint.getLocalizedName(true)); jsonRep.addProperty("isDefault", footprint.isDefault()); return jsonRep; } diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index f59ffe28eb..b922c7a4f3 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -45,6 +45,7 @@ import net.rptools.maptool.server.proto.FootprintListDto; import net.rptools.maptool.server.proto.LightSourceListDto; import net.rptools.maptool.server.proto.TokenPropertyListDto; +import net.rptools.maptool.tool.TokenFootprintCreator; public class CampaignProperties { @@ -357,25 +358,6 @@ private void initTokenTypeMap() { tokenTypeMap.put(getDefaultTokenPropertyType(), list); } - protected List loadFootprints( - String path, net.rptools.maptool.model.TokenFootprint.OffsetTranslator... translators) { - List result = null; - try { - Object obj = net.rptools.lib.FileUtil.objFromResource(path); - @SuppressWarnings("unchecked") - List footprintList = (List) obj; - for (TokenFootprint footprint : footprintList) { - for (net.rptools.maptool.model.TokenFootprint.OffsetTranslator ot : translators) { - footprint.addOffsetTranslator(ot); - } - } - result = footprintList; - } catch (IOException ioe) { - MapTool.showError("Could not load VHex Grid footprints", ioe); - } - return result; - } - public void resetTokenFootprints() { initTokenFootprints(true); } @@ -392,28 +374,10 @@ private void initTokenFootprints(boolean reset) { } // Potential for importing defaults from app preferences instead. - setGridFootprints( - "Horizontal Hex", - loadFootprints( - "net/rptools/maptool/model/hexGridHorizFootprints.xml", - (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { - offsetPoint.x++; - } - })); - setGridFootprints( - "Vertical Hex", - loadFootprints( - "net/rptools/maptool/model/hexGridVertFootprints.xml", - (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { - offsetPoint.y++; - } - })); - setGridFootprints( - "None", loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml")); - setGridFootprints( - "Square", loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml")); + setGridFootprints("Horizontal Hex", TokenFootprintCreator.makeHorizHex()); + setGridFootprints("Vertical Hex", TokenFootprintCreator.makeVertHex()); + setGridFootprints("None", TokenFootprintCreator.makeGridless()); + setGridFootprints("Square", TokenFootprintCreator.makeSquare()); } private void initTokenStatesMap() { @@ -547,6 +511,7 @@ public void setGridFootprint(String footprintName, String gridType, TokenFootpri String testName = allFootprints.get(i).getName(); if (Objects.equals(testName, footprintName)) { allFootprints.set(i, newPrint); + setGridFootprints(gridType, allFootprints); return; } } diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index c08365efb9..d5ec68dd61 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -59,7 +59,9 @@ public static TokenFootprint fromDto(TokenFootPrintDto dto) { footPrint.id = GUID.valueOf(dto.getId()); footPrint.isDefault = dto.getIsDefault(); footPrint.scale = dto.getScale(); - footPrint.localizedName = dto.getLocalizedName(); + if (!dto.getLocalizedName().equals("")) { + footPrint.localizedName = dto.getLocalizedName(); + } return footPrint; } @@ -127,13 +129,20 @@ public String getName() { /** Returns the localized name of the footprint */ public String getLocalizedName() { + return getLocalizedName(false); + } + + public String getLocalizedName(boolean actual) { if (localizeName && localizedName == null) { localizedName = I18N.getString("TokenFootprint.name." + name.toLowerCase()); return localizedName; } else if (localizedName != null) { return localizedName; + } else if (!actual) { + return name; + } else { + return localizedName; } - return name; } public void setLocalizedName(String text) { diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index 01abf46193..4e87d69596 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -14,24 +14,22 @@ */ package net.rptools.maptool.tool; -import com.thoughtworks.xstream.XStream; import java.awt.Point; import java.util.Arrays; import java.util.List; -import net.rptools.lib.FileUtil; import net.rptools.maptool.model.TokenFootprint; public class TokenFootprintCreator { public static void main(String[] args) { // List footprintList = makeHorizHex(); - List footprintList = makeVertHex(); + // List footprintList = makeVertHex(); // List footprintList = makeSquare(); // List footprintList = makeGridless(); - XStream xstream = FileUtil.getConfiguredXStream(); - System.out.println(xstream.toXML(footprintList)); + // XStream xstream = FileUtil.getConfiguredXStream(); + // System.out.println(xstream.toXML(footprintList)); } - private static Point[] points(int[][] points) { + public static Point[] points(int[][] points) { Point[] pa = new Point[points.length]; for (int i = 0; i < points.length; i++) { pa[i] = new Point(points[i][0], points[i][1]); @@ -39,15 +37,12 @@ private static Point[] points(int[][] points) { return pa; } - private static Point[] squarePoints(int size) { - Point[] pa = new Point[size * size - 1]; + public static Point[] squarePoints(int size) { + Point[] pa = new Point[size * size]; int indx = 0; for (int y = 0; y < size; y++) { for (int x = 0; x < size; x++) { - if (y == 0 && x == 0) { - continue; - } pa[indx] = new Point(x, y); indx++; } @@ -55,11 +50,15 @@ private static Point[] squarePoints(int size) { return pa; } - private static List makeSquare() { + public static List makeSquare() { List footprintList = Arrays.asList( // SQUARE - new TokenFootprint("Medium", true, 1.0), + new TokenFootprint("Diminutive", false, 0.5, squarePoints(1)), + new TokenFootprint("Fine", false, 0.5, squarePoints(1)), + new TokenFootprint("Tiny", false, 0.5, squarePoints(1)), + new TokenFootprint("Small", false, 0.75, squarePoints(1)), + new TokenFootprint("Medium", true, 1.0, squarePoints(1)), new TokenFootprint("Large", squarePoints(2)), new TokenFootprint("Huge", squarePoints(3)), new TokenFootprint("Gargantuan", squarePoints(4)), @@ -67,81 +66,57 @@ private static List makeSquare() { return footprintList; } - private static List makeVertHex() { + public static List makeVertHex() { List footprintList = Arrays.asList( // HEXES - new TokenFootprint("1/6", false, .408), - new TokenFootprint("1/4", false, .500), - new TokenFootprint("1/3", false, .577), - new TokenFootprint("1/2", false, .707), - new TokenFootprint("2/3", false, .816), - new TokenFootprint("Medium", true, 1.0), + new TokenFootprint("1/6", false, .408, points(new int[][] {{0, 0}})), + new TokenFootprint("1/4", false, .500, points(new int[][] {{0, 0}})), + new TokenFootprint("1/3", false, .577, points(new int[][] {{0, 0}})), + new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), + new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), + new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), new TokenFootprint( "Large", points( new int[][] { - {0, 1}, - {1, 0}, + {0, 0}, {0, 1}, {1, 0}, })), new TokenFootprint( "Huge", - points( - new int[][] { - {-1, -1}, - {-1, 0}, - {0, -1}, - {0, 1}, - {1, -1}, - {1, 0} - })), + points(new int[][] {{0, 0}, {-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, -1}, {1, 0}})), new TokenFootprint( "Humongous", points( new int[][] { - {-2, -1}, - {-2, 0}, - {-2, 1}, - {-1, -2}, - {-1, -1}, - {-1, 0}, - {-1, 1}, - {0, -2}, - {0, -1}, - {0, 1}, - {0, 2}, - {1, -2}, - {1, -1}, - {1, 0}, - {1, 1}, - {2, -1}, - {2, 0}, - {2, 1} + {0, 0}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, -2}, {-1, -1}, {-1, 0}, {-1, 1}, + {0, -2}, {0, -1}, {0, 1}, {0, 2}, {1, -2}, {1, -1}, {1, 0}, {1, 1}, {2, -1}, + {2, 0}, {2, 1} }))); return footprintList; } - private static List makeHorizHex() { + public static List makeHorizHex() { List footprintList = Arrays.asList( // Horizontal Hex Grid - Flipped x <> y from Vert grid - new TokenFootprint("1/6", false, .408), - new TokenFootprint("1/4", false, .500), - new TokenFootprint("1/3", false, .577), - new TokenFootprint("1/2", false, .707), - new TokenFootprint("2/3", false, .816), - new TokenFootprint("Medium", true, 1.0), + new TokenFootprint("1/6", false, .408, points(new int[][] {{0, 0}})), + new TokenFootprint("1/4", false, .500, points(new int[][] {{0, 0}})), + new TokenFootprint("1/3", false, .577, points(new int[][] {{0, 0}})), + new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), + new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), + new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), new TokenFootprint( "Large", points( new int[][] { - {1, 0}, - {0, 1}, + {0, 0}, {1, 0}, {0, 1}, })), new TokenFootprint( "Huge", points( new int[][] { + {0, 0}, {0, 1}, {1, 0}, {-1, 0}, @@ -153,29 +128,14 @@ private static List makeHorizHex() { "Humongous", points( new int[][] { - {-1, -2}, - {0, -2}, - {1, -2}, - {-2, -1}, - {-1, -1}, - {0, -1}, - {1, -1}, - {-2, 0}, - {-1, 0}, - {1, 0}, - {2, 0}, - {-2, 1}, - {-1, 1}, - {0, 1}, - {1, 1}, - {-1, 2}, - {0, 2}, - {1, 2} + {0, 0}, {-1, -2}, {0, -2}, {1, -2}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, + {-2, 0}, {-1, 0}, {1, 0}, {2, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}, {-1, 2}, + {0, 2}, {1, 2} }))); return footprintList; } - private static List makeGridless() { + public static List makeGridless() { List footprintList = Arrays.asList( new TokenFootprint("-11", false, 0.086), From 3a53f0bcfca0cc46328abe7565aaef2fa0b45b01 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sat, 7 Sep 2024 10:08:00 +0930 Subject: [PATCH 11/21] Cleanup --- .../java/net/rptools/maptool/model/Grid.java | 15 ------------ .../rptools/maptool/model/GridlessGrid.java | 15 ++---------- .../maptool/model/HexGridHorizontal.java | 17 +++----------- .../maptool/model/HexGridVertical.java | 16 +++---------- .../rptools/maptool/model/IsometricGrid.java | 16 +++---------- .../net/rptools/maptool/model/SquareGrid.java | 16 +++---------- .../maptool/tool/TokenFootprintCreator.java | 23 +++---------------- 7 files changed, 17 insertions(+), 101 deletions(-) diff --git a/src/main/java/net/rptools/maptool/model/Grid.java b/src/main/java/net/rptools/maptool/model/Grid.java index 4d1ee3d9da..e716fec160 100644 --- a/src/main/java/net/rptools/maptool/model/Grid.java +++ b/src/main/java/net/rptools/maptool/model/Grid.java @@ -134,21 +134,6 @@ public int[] getFacingAngles() { */ public abstract Point2D.Double getCellCenter(CellPoint cell); - /* - protected List loadFootprints(String path, OffsetTranslator... translators) - throws IOException { - Object obj = FileUtil.objFromResource(path); - @SuppressWarnings("unchecked") - List footprintList = (List) obj; - for (TokenFootprint footprint : footprintList) { - for (OffsetTranslator ot : translators) { - footprint.addOffsetTranslator(ot); - } - } - return footprintList; - } - */ - public TokenFootprint getDefaultFootprint() { for (TokenFootprint footprint : getFootprints()) { if (footprint.isDefault()) { diff --git a/src/main/java/net/rptools/maptool/model/GridlessGrid.java b/src/main/java/net/rptools/maptool/model/GridlessGrid.java index b59b8064df..575ea662be 100644 --- a/src/main/java/net/rptools/maptool/model/GridlessGrid.java +++ b/src/main/java/net/rptools/maptool/model/GridlessGrid.java @@ -18,6 +18,7 @@ import java.awt.event.KeyEvent; import java.awt.geom.Area; import java.awt.geom.Point2D; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -31,7 +32,6 @@ import net.rptools.maptool.util.GraphicsUtil; public class GridlessGrid extends Grid { - private static List footprintList; // @formatter:off private static final GridCapabilities GRID_CAPABILITIES = @@ -67,18 +67,7 @@ public List getFootprints() { if (campaignFootprints.containsKey("None")) { return campaignFootprints.get("None"); } - /*else { - try { - footprintList = loadFootprints("net/rptools/maptool/model/gridlessGridFootprints.xml"); - } catch (IOException ioe) { - MapTool.showError("Could not load Gridless Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("None", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } - */ - return footprintList; + return new ArrayList<>(); } @Override diff --git a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java index 2f1a34649f..fea0588442 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java +++ b/src/main/java/net/rptools/maptool/model/HexGridHorizontal.java @@ -22,6 +22,7 @@ import java.awt.geom.GeneralPath; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -188,20 +189,8 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Horizontal Hex")) { return campaignFootprints.get("Horizontal Hex"); - } /*else { - try { - footprintList = - loadFootprints( - "net/rptools/maptool/model/hexGridHorizFootprints.xml", getOffsetTranslator()); - } catch (IOException ioe) { - MapTool.showError("Could not load HHex Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Horizontal Hex", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } - */ - return footprintList; + } + return new ArrayList<>(); } @Override diff --git a/src/main/java/net/rptools/maptool/model/HexGridVertical.java b/src/main/java/net/rptools/maptool/model/HexGridVertical.java index 58b8f22709..56bdd5e2c7 100644 --- a/src/main/java/net/rptools/maptool/model/HexGridVertical.java +++ b/src/main/java/net/rptools/maptool/model/HexGridVertical.java @@ -21,6 +21,7 @@ import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -175,19 +176,8 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Vertical Hex")) { return campaignFootprints.get("Vertical Hex"); - } /*else { - try { - footprintList = - loadFootprints( - "net/rptools/maptool/model/hexGridVertFootprints.xml", getOffsetTranslator()); - } catch (IOException ioe) { - MapTool.showError("Could not load VHex Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Vertical Hex", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - }*/ - return footprintList; + } + return new ArrayList<>(); } @Override diff --git a/src/main/java/net/rptools/maptool/model/IsometricGrid.java b/src/main/java/net/rptools/maptool/model/IsometricGrid.java index 8f13239f59..9048c948b8 100644 --- a/src/main/java/net/rptools/maptool/model/IsometricGrid.java +++ b/src/main/java/net/rptools/maptool/model/IsometricGrid.java @@ -18,6 +18,7 @@ import java.awt.event.KeyEvent; import java.awt.geom.*; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -47,7 +48,6 @@ public class IsometricGrid extends Grid { private static final int[] ALL_ANGLES = new int[] {-135, -90, -45, 0, 45, 90, 135, 180}; private static int[] FACING_ANGLES; - private static List footprintList; private static BufferedImage pathHighlight = RessourceManager.getImage(Images.GRID_BORDER_ISOMETRIC); @@ -180,18 +180,8 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); - } /*else { - try { - footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); - } catch (IOException ioe) { - MapTool.showError("Could not load Square Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Square", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - } - */ - return footprintList; + } + return new ArrayList<>(); } @Override diff --git a/src/main/java/net/rptools/maptool/model/SquareGrid.java b/src/main/java/net/rptools/maptool/model/SquareGrid.java index cea3231d16..c6fc0ae5a9 100644 --- a/src/main/java/net/rptools/maptool/model/SquareGrid.java +++ b/src/main/java/net/rptools/maptool/model/SquareGrid.java @@ -24,6 +24,7 @@ import java.awt.geom.Area; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,8 +53,6 @@ public class SquareGrid extends Grid { private static BufferedImage pathHighlightAlt = RessourceManager.getImage(Images.GRID_BORDER_SQUARE_RED); - private static List footprintList; - // @formatter:off private static final GridCapabilities CAPABILITIES = new GridCapabilities() { @@ -225,17 +224,8 @@ public List getFootprints() { MapTool.getCampaign().getCampaignProperties().getGridFootprints(); if (campaignFootprints.containsKey("Square")) { return campaignFootprints.get("Square"); - } /*else { - try { - footprintList = loadFootprints("net/rptools/maptool/model/squareGridFootprints.xml"); - } catch (IOException ioe) { - MapTool.showError("Could not load Square Grid footprints", ioe); - } - CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); - ModifiedProperties.setGridFootprints("Square", footprintList); - MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); - }*/ - return footprintList; + } + return new ArrayList<>(); } @Override diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index 4e87d69596..ad41a3b4ff 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -20,14 +20,7 @@ import net.rptools.maptool.model.TokenFootprint; public class TokenFootprintCreator { - public static void main(String[] args) { - // List footprintList = makeHorizHex(); - // List footprintList = makeVertHex(); - // List footprintList = makeSquare(); - // List footprintList = makeGridless(); - // XStream xstream = FileUtil.getConfiguredXStream(); - // System.out.println(xstream.toXML(footprintList)); - } + public static void main(String[] args) {} public static Point[] points(int[][] points) { Point[] pa = new Point[points.length]; @@ -76,12 +69,7 @@ public static List makeVertHex() { new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), - new TokenFootprint( - "Large", - points( - new int[][] { - {0, 0}, {0, 1}, {1, 0}, - })), + new TokenFootprint("Large", points(new int[][] {{0, 0}, {0, 1}, {1, 0}})), new TokenFootprint( "Huge", points(new int[][] {{0, 0}, {-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, -1}, {1, 0}})), @@ -106,12 +94,7 @@ public static List makeHorizHex() { new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), - new TokenFootprint( - "Large", - points( - new int[][] { - {0, 0}, {1, 0}, {0, 1}, - })), + new TokenFootprint("Large", points(new int[][] {{0, 0}, {1, 0}, {0, 1}})), new TokenFootprint( "Huge", points( From dd7ea52ad944a94720f504f490548f42a0070484 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Mon, 16 Sep 2024 18:34:39 +0930 Subject: [PATCH 12/21] Sorted Offset Problems --- .../client/functions/FootprintFunctions.java | 18 ++++++++++++++++++ .../maptool/tool/TokenFootprintCreator.java | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index 5d50ccce7f..ebe4bcc7ce 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -252,6 +252,24 @@ void setTokenFootprint(String gridtype, String name, JsonObject data) { if (data.has("isDefault")) { newPrint.setDefault(data.get("isDefault").getAsBoolean()); } + + /* Needs Update if Grid Coordinate System Changes */ + if (gridtype == "Horizontal Hex") { + newPrint.addOffsetTranslator( + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + offsetPoint.x++; + } + }); + } else if (gridtype == "Vertical Hex") { + newPrint.addOffsetTranslator( + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + offsetPoint.y++; + } + }); + } + CampaignProperties ModifiedProperties = MapTool.getCampaign().getCampaignProperties(); ModifiedProperties.setGridFootprint(name, gridtype, newPrint); MapTool.getCampaign().mergeCampaignProperties(ModifiedProperties); diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index ad41a3b4ff..7eee37a9e4 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -81,6 +81,15 @@ public static List makeVertHex() { {0, -2}, {0, -1}, {0, 1}, {0, 2}, {1, -2}, {1, -1}, {1, 0}, {1, 1}, {2, -1}, {2, 0}, {2, 1} }))); + /* Needs Update if Grid Coordinate System Changes */ + for (var footprint : footprintList) { + footprint.addOffsetTranslator( + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + offsetPoint.y++; + } + }); + } return footprintList; } @@ -115,6 +124,15 @@ public static List makeHorizHex() { {-2, 0}, {-1, 0}, {1, 0}, {2, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}, {-1, 2}, {0, 2}, {1, 2} }))); + /* Needs Update if Grid Coordinate System Changes */ + for (var footprint : footprintList) { + footprint.addOffsetTranslator( + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + offsetPoint.x++; + } + }); + } return footprintList; } From 3b4319c9d60460a6eee69451c017dfd30401373d Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Tue, 17 Sep 2024 08:17:48 +0930 Subject: [PATCH 13/21] Footprint Creator Update --- .../rptools/maptool/model/TokenFootprint.java | 23 +++- .../maptool/tool/TokenFootprintCreator.java | 119 ++++++++++++------ 2 files changed, 100 insertions(+), 42 deletions(-) diff --git a/src/main/java/net/rptools/maptool/model/TokenFootprint.java b/src/main/java/net/rptools/maptool/model/TokenFootprint.java index d5ec68dd61..021da46af1 100644 --- a/src/main/java/net/rptools/maptool/model/TokenFootprint.java +++ b/src/main/java/net/rptools/maptool/model/TokenFootprint.java @@ -36,7 +36,6 @@ public class TokenFootprint { private boolean isDefault; private double scale = 1; private boolean localizeName = false; - private transient List translatorList = new LinkedList(); public TokenFootprint() { @@ -110,10 +109,32 @@ public TokenFootprint(String name, Point... points) { this(name, false, 1, points); } + public TokenFootprint( + String name, boolean isDefault, Double scale, boolean localizeName, Point... points) { + this(name, isDefault, scale, points); + this.localizeName = localizeName; + } + + public TokenFootprint( + String name, + boolean isDefault, + Double scale, + boolean localizeName, + OffsetTranslator translator, + Point... points) { + this(name, isDefault, scale, points); + this.localizeName = localizeName; + this.addOffsetTranslator(translator); + } + public void setDefault(boolean isDefault) { this.isDefault = isDefault; } + public void setLocalizeName(boolean localize) { + this.localizeName = localize; + } + public boolean isDefault() { return isDefault; } diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index 7eee37a9e4..88fd47ffa1 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -47,65 +47,107 @@ public static List makeSquare() { List footprintList = Arrays.asList( // SQUARE - new TokenFootprint("Diminutive", false, 0.5, squarePoints(1)), - new TokenFootprint("Fine", false, 0.5, squarePoints(1)), - new TokenFootprint("Tiny", false, 0.5, squarePoints(1)), - new TokenFootprint("Small", false, 0.75, squarePoints(1)), - new TokenFootprint("Medium", true, 1.0, squarePoints(1)), - new TokenFootprint("Large", squarePoints(2)), - new TokenFootprint("Huge", squarePoints(3)), - new TokenFootprint("Gargantuan", squarePoints(4)), - new TokenFootprint("Colossal", squarePoints(6))); + new TokenFootprint("Diminutive", false, 0.5, true, squarePoints(1)), + new TokenFootprint("Fine", false, 0.5, true, squarePoints(1)), + new TokenFootprint("Tiny", false, 0.5, true, squarePoints(1)), + new TokenFootprint("Small", false, 0.75, true, squarePoints(1)), + new TokenFootprint("Medium", true, 1.0, true, squarePoints(1)), + new TokenFootprint("Large", false, 1.0, true, squarePoints(2)), + new TokenFootprint("Huge", false, 1.0, true, squarePoints(3)), + new TokenFootprint("Gargantuan", false, 1.0, true, squarePoints(4)), + new TokenFootprint("Colossal", false, 1.0, true, squarePoints(6))); return footprintList; } public static List makeVertHex() { + + /* Needs Update if Grid Coordinate System Changes */ + TokenFootprint.OffsetTranslator vertOffsetTranslator = + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + offsetPoint.y++; + } + }; List footprintList = Arrays.asList( // HEXES - new TokenFootprint("1/6", false, .408, points(new int[][] {{0, 0}})), - new TokenFootprint("1/4", false, .500, points(new int[][] {{0, 0}})), - new TokenFootprint("1/3", false, .577, points(new int[][] {{0, 0}})), - new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), - new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), - new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), - new TokenFootprint("Large", points(new int[][] {{0, 0}, {0, 1}, {1, 0}})), + new TokenFootprint( + "1/6", false, .408, false, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/4", false, .500, false, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/3", false, .577, false, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/2", false, .707, false, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "2/3", false, .816, false, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "Medium", true, 1.0, true, vertOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "Large", + false, + 1.0, + true, + vertOffsetTranslator, + points(new int[][] {{0, 0}, {0, 1}, {1, 0}})), new TokenFootprint( "Huge", + false, + 1.0, + true, + vertOffsetTranslator, points(new int[][] {{0, 0}, {-1, -1}, {-1, 0}, {0, -1}, {0, 1}, {1, -1}, {1, 0}})), new TokenFootprint( "Humongous", + false, + 1.0, + true, + vertOffsetTranslator, points( new int[][] { {0, 0}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, -2}, {-1, -1}, {-1, 0}, {-1, 1}, {0, -2}, {0, -1}, {0, 1}, {0, 2}, {1, -2}, {1, -1}, {1, 0}, {1, 1}, {2, -1}, {2, 0}, {2, 1} }))); - /* Needs Update if Grid Coordinate System Changes */ - for (var footprint : footprintList) { - footprint.addOffsetTranslator( - (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { - offsetPoint.y++; - } - }); - } return footprintList; } public static List makeHorizHex() { + /* Needs Update if Grid Coordinate System Changes */ + TokenFootprint.OffsetTranslator horizOffsetTranslator = + (originPoint, offsetPoint) -> { + if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + offsetPoint.x++; + } + }; List footprintList = Arrays.asList( // Horizontal Hex Grid - Flipped x <> y from Vert grid - new TokenFootprint("1/6", false, .408, points(new int[][] {{0, 0}})), - new TokenFootprint("1/4", false, .500, points(new int[][] {{0, 0}})), - new TokenFootprint("1/3", false, .577, points(new int[][] {{0, 0}})), - new TokenFootprint("1/2", false, .707, points(new int[][] {{0, 0}})), - new TokenFootprint("2/3", false, .816, points(new int[][] {{0, 0}})), - new TokenFootprint("Medium", true, 1.0, points(new int[][] {{0, 0}})), - new TokenFootprint("Large", points(new int[][] {{0, 0}, {1, 0}, {0, 1}})), + new TokenFootprint( + "1/6", false, .408, false, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/4", false, .500, false, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/3", false, .577, false, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "1/2", false, .707, false, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "2/3", false, .816, false, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "Medium", true, 1.0, true, horizOffsetTranslator, points(new int[][] {{0, 0}})), + new TokenFootprint( + "Large", + false, + 1.0, + true, + horizOffsetTranslator, + points(new int[][] {{0, 0}, {1, 0}, {0, 1}})), new TokenFootprint( "Huge", + false, + 1.0, + true, + horizOffsetTranslator, points( new int[][] { {0, 0}, @@ -118,21 +160,16 @@ public static List makeHorizHex() { })), new TokenFootprint( "Humongous", + false, + 1.0, + true, + horizOffsetTranslator, points( new int[][] { {0, 0}, {-1, -2}, {0, -2}, {1, -2}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-2, 0}, {-1, 0}, {1, 0}, {2, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}, {-1, 2}, {0, 2}, {1, 2} }))); - /* Needs Update if Grid Coordinate System Changes */ - for (var footprint : footprintList) { - footprint.addOffsetTranslator( - (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { - offsetPoint.x++; - } - }); - } return footprintList; } From db899ee2cccd0acbcaaaa88b7238774833d552cd Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:32:31 +0930 Subject: [PATCH 14/21] Add Isometric Size List and Bitwise And instead of Mod for even check. --- .../rptools/maptool/client/functions/FootprintFunctions.java | 4 ++-- .../java/net/rptools/maptool/model/CampaignProperties.java | 5 ++++- .../java/net/rptools/maptool/tool/TokenFootprintCreator.java | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index ebe4bcc7ce..9510035c08 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -257,14 +257,14 @@ void setTokenFootprint(String gridtype, String name, JsonObject data) { if (gridtype == "Horizontal Hex") { newPrint.addOffsetTranslator( (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + if ((originPoint.y & 1 ) == 1 && (offsetPoint.y & 1) == 0) { offsetPoint.x++; } }); } else if (gridtype == "Vertical Hex") { newPrint.addOffsetTranslator( (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + if ((originPoint.x & 1 ) == 1 && (offsetPoint.x & 1) == 0) { offsetPoint.y++; } }); diff --git a/src/main/java/net/rptools/maptool/model/CampaignProperties.java b/src/main/java/net/rptools/maptool/model/CampaignProperties.java index b922c7a4f3..1cfaa68aab 100644 --- a/src/main/java/net/rptools/maptool/model/CampaignProperties.java +++ b/src/main/java/net/rptools/maptool/model/CampaignProperties.java @@ -374,10 +374,13 @@ private void initTokenFootprints(boolean reset) { } // Potential for importing defaults from app preferences instead. + var squareFP = TokenFootprintCreator.makeSquare(); + setGridFootprints("Horizontal Hex", TokenFootprintCreator.makeHorizHex()); setGridFootprints("Vertical Hex", TokenFootprintCreator.makeVertHex()); setGridFootprints("None", TokenFootprintCreator.makeGridless()); - setGridFootprints("Square", TokenFootprintCreator.makeSquare()); + setGridFootprints("Square", new ArrayList<>(squareFP)); + setGridFootprints("Isometric", new ArrayList<>(squareFP)); } private void initTokenStatesMap() { diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index 88fd47ffa1..bfea818529 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -64,7 +64,7 @@ public static List makeVertHex() { /* Needs Update if Grid Coordinate System Changes */ TokenFootprint.OffsetTranslator vertOffsetTranslator = (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.x) % 2 == 1 && Math.abs(offsetPoint.x) % 2 == 0) { + if ((originPoint.x & 1 ) == 1 && (offsetPoint.x & 1) == 0) { offsetPoint.y++; } }; @@ -116,7 +116,7 @@ public static List makeHorizHex() { /* Needs Update if Grid Coordinate System Changes */ TokenFootprint.OffsetTranslator horizOffsetTranslator = (originPoint, offsetPoint) -> { - if (Math.abs(originPoint.y) % 2 == 1 && Math.abs(offsetPoint.y) % 2 == 0) { + if ((originPoint.y & 1 ) == 1 && (offsetPoint.y & 1) == 0) { offsetPoint.x++; } }; From ef60b313830ddc6b43552d780d592bdae65b96b9 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Sat, 21 Sep 2024 10:11:01 +0930 Subject: [PATCH 15/21] Forgotten Isometric Stuff and Formatting --- .../maptool/client/functions/FootprintFunctions.java | 7 ++++--- src/main/java/net/rptools/maptool/model/IsometricGrid.java | 4 ++-- .../net/rptools/maptool/tool/TokenFootprintCreator.java | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java index 9510035c08..f41df2c90a 100644 --- a/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java +++ b/src/main/java/net/rptools/maptool/client/functions/FootprintFunctions.java @@ -74,6 +74,7 @@ public Object childEvaluate( gridTypes.add("Vertical Hex"); gridTypes.add("Horizontal Hex"); gridTypes.add("Square"); + gridTypes.add("Isometric"); gridTypes.add("None"); try { @@ -148,7 +149,7 @@ public Object childEvaluate( result = getFootprintNames(parameters.get(0).toString()); } } else if (functionName.equalsIgnoreCase("getGridTypes")) { - result = "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"None\"]"; + result = "[\"Vertical Hex\",\"Horizontal Hex\",\"Square\",\"Isometric\",\"None\"]"; } else if (functionName.equalsIgnoreCase("resetFootprintsToDefault")) { resetFootprintsToDefault(); } else { @@ -257,14 +258,14 @@ void setTokenFootprint(String gridtype, String name, JsonObject data) { if (gridtype == "Horizontal Hex") { newPrint.addOffsetTranslator( (originPoint, offsetPoint) -> { - if ((originPoint.y & 1 ) == 1 && (offsetPoint.y & 1) == 0) { + if ((originPoint.y & 1) == 1 && (offsetPoint.y & 1) == 0) { offsetPoint.x++; } }); } else if (gridtype == "Vertical Hex") { newPrint.addOffsetTranslator( (originPoint, offsetPoint) -> { - if ((originPoint.x & 1 ) == 1 && (offsetPoint.x & 1) == 0) { + if ((originPoint.x & 1) == 1 && (offsetPoint.x & 1) == 0) { offsetPoint.y++; } }); diff --git a/src/main/java/net/rptools/maptool/model/IsometricGrid.java b/src/main/java/net/rptools/maptool/model/IsometricGrid.java index 9048c948b8..e51d2d5cf4 100644 --- a/src/main/java/net/rptools/maptool/model/IsometricGrid.java +++ b/src/main/java/net/rptools/maptool/model/IsometricGrid.java @@ -178,8 +178,8 @@ public boolean isCoordinatesSupported() { public List getFootprints() { Map> campaignFootprints = MapTool.getCampaign().getCampaignProperties().getGridFootprints(); - if (campaignFootprints.containsKey("Square")) { - return campaignFootprints.get("Square"); + if (campaignFootprints.containsKey("Isometric")) { + return campaignFootprints.get("Isometric"); } return new ArrayList<>(); } diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index bfea818529..e93d3b9f2b 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -64,7 +64,7 @@ public static List makeVertHex() { /* Needs Update if Grid Coordinate System Changes */ TokenFootprint.OffsetTranslator vertOffsetTranslator = (originPoint, offsetPoint) -> { - if ((originPoint.x & 1 ) == 1 && (offsetPoint.x & 1) == 0) { + if ((originPoint.x & 1) == 1 && (offsetPoint.x & 1) == 0) { offsetPoint.y++; } }; @@ -116,7 +116,7 @@ public static List makeHorizHex() { /* Needs Update if Grid Coordinate System Changes */ TokenFootprint.OffsetTranslator horizOffsetTranslator = (originPoint, offsetPoint) -> { - if ((originPoint.y & 1 ) == 1 && (offsetPoint.y & 1) == 0) { + if ((originPoint.y & 1) == 1 && (offsetPoint.y & 1) == 0) { offsetPoint.x++; } }; From a76b072f228f0f012e1d12b1e7cfb2b3858b93f2 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Thu, 26 Sep 2024 18:51:47 +0930 Subject: [PATCH 16/21] Centre the origin for square footprints --- .../java/net/rptools/maptool/tool/TokenFootprintCreator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java index e93d3b9f2b..01d92851fa 100644 --- a/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java +++ b/src/main/java/net/rptools/maptool/tool/TokenFootprintCreator.java @@ -34,8 +34,8 @@ public static Point[] squarePoints(int size) { Point[] pa = new Point[size * size]; int indx = 0; - for (int y = 0; y < size; y++) { - for (int x = 0; x < size; x++) { + for (int y = -Math.floorDiv(size, 2); y < Math.ceilDiv(size, 2); y++) { + for (int x = -Math.floorDiv(size, 2); x < Math.ceilDiv(size, 2); x++) { pa[indx] = new Point(x, y); indx++; } From 3ed5186bff4c56c795910adf56a260a2ffa57bdc Mon Sep 17 00:00:00 2001 From: bubblobill <45483160+bubblobill@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:29:40 +0800 Subject: [PATCH 17/21] UI and assorted supporting classes. Can be consolidated once the code settles down. --- .../rptools/maptool/client/AppActions.java | 18 + .../rptools/maptool/client/ui/AppMenuBar.java | 1 + .../footprintEditor/FootPrintEditorView.form | 515 +++++++++++ .../footprintEditor/FootPrintEditorView.java | 25 + .../FootprintEditingPanel.java | 251 +++++ .../FootprintEditorDialog.java | 864 ++++++++++++++++++ .../maptool/model/FootprintManager.java | 192 ++++ .../maptool/util/FootPrintToolbox.java | 95 ++ .../rptools/maptool/language/i18n.properties | 6 + 9 files changed, 1967 insertions(+) create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.java create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java create mode 100644 src/main/java/net/rptools/maptool/model/FootprintManager.java create mode 100644 src/main/java/net/rptools/maptool/util/FootPrintToolbox.java diff --git a/src/main/java/net/rptools/maptool/client/AppActions.java b/src/main/java/net/rptools/maptool/client/AppActions.java index c49300c1b7..2cdc55684c 100644 --- a/src/main/java/net/rptools/maptool/client/AppActions.java +++ b/src/main/java/net/rptools/maptool/client/AppActions.java @@ -55,6 +55,7 @@ import net.rptools.maptool.client.ui.connecttoserverdialog.ConnectToServerDialog; import net.rptools.maptool.client.ui.connecttoserverdialog.ConnectToServerDialogPreferences; import net.rptools.maptool.client.ui.exportdialog.ExportDialog; +import net.rptools.maptool.client.ui.footprintEditor.FootprintEditorDialog; import net.rptools.maptool.client.ui.htmlframe.HTMLOverlayManager; import net.rptools.maptool.client.ui.io.*; import net.rptools.maptool.client.ui.io.FTPTransferObject.Direction; @@ -3011,6 +3012,23 @@ protected void process(List list) { } } + public static final Action CAMPAIGN_FOOTPRINTS = + new DefaultClientAction() { + { + init("action.campaignFootprints"); + } + + @Override + public boolean isAvailable() { + return MapTool.getPlayer().isGM(); + } + + @Override + protected void executeAction() { + FootprintEditorDialog dialog = new FootprintEditorDialog(MapTool.getFrame()); + dialog.setVisible(true); + } + }; public static final Action CAMPAIGN_PROPERTIES = new DefaultClientAction() { { diff --git a/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java b/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java index 27f457b2ff..1344211633 100644 --- a/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java +++ b/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java @@ -212,6 +212,7 @@ protected JMenu createEditMenu() { menu.addSeparator(); + menu.add(new JMenuItem(AppActions.CAMPAIGN_FOOTPRINTS)); menu.add(new JMenuItem(AppActions.CAMPAIGN_PROPERTIES)); if (!AppUtil.MAC_OS_X) menu.add(new JMenuItem(AppActions.SHOW_PREFERENCES)); diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form new file mode 100644 index 0000000000..2419085beb --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form @@ -0,0 +1,515 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.java new file mode 100644 index 0000000000..9fce2c449d --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.java @@ -0,0 +1,25 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.footprintEditor; + +import javax.swing.*; + +public class FootPrintEditorView { + private JPanel mainPanel; + + public JComponent getRootComponent() { + return mainPanel; + } +} diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java new file mode 100644 index 0000000000..0185cd9d50 --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java @@ -0,0 +1,251 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.footprintEditor; + +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.geom.Point2D; +import java.awt.image.BufferedImage; +import java.util.HashSet; +import java.util.Set; +import javax.swing.*; +import net.rptools.maptool.client.MapTool; +import net.rptools.maptool.client.ScreenPoint; +import net.rptools.maptool.client.ui.Scale; +import net.rptools.maptool.client.ui.theme.Images; +import net.rptools.maptool.client.ui.theme.RessourceManager; +import net.rptools.maptool.client.ui.zone.PlayerView; +import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer; +import net.rptools.maptool.client.walker.ZoneWalker; +import net.rptools.maptool.events.MapToolEventBus; +import net.rptools.maptool.model.*; +import net.rptools.maptool.model.player.Player; +import net.rptools.maptool.model.zones.GridChanged; +import net.rptools.maptool.util.FootPrintToolbox; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FootprintEditingPanel extends JPanel { + private final Logger log = LoggerFactory.getLogger(this.getClass().getName()); + private static final CellPoint ORIGIN = new CellPoint(0, 0); + private static final BufferedImage ORIGIN_MARKER = + RessourceManager.getImage(Images.ZONE_RENDERER_CELL_WAYPOINT); + final HexGridHorizontal HV = new HexGridHorizontal(); + final HexGridVertical HH = new HexGridVertical(); + final IsometricGrid ISO_S = new IsometricGrid(); + final HexGridHorizontal ISO_H = new HexGridHorizontal(); + final SquareGrid SQ = new SquareGrid(); + final GridlessGrid GG = new GridlessGrid(); + private ScreenPoint pointUnderMouse = new ScreenPoint(0, 0); + private final PlayerView playerView = new PlayerView(Player.Role.GM); + private static volatile Set cellSet = new HashSet<>(); + private static volatile Grid currentGrid; + private BufferedImage cellHighlight; + ZoneRenderer renderer; + ZoneWalker walker; + Zone zone; + static volatile Scale zoneScale; + static volatile float tokenScale = 1; + TokenFootprint footprint = FootprintManager.getGlobalDefaultFootprint(); + + public FootprintEditingPanel() { + log.info("new FootprintEditingPanel"); + this.setFocusable(true); + this.setEnabled(true); + this.setBorder(BorderFactory.createLoweredBevelBorder()); + this.setPreferredSize(new Dimension(700, 500)); + zone = ZoneFactory.createZone(); + zone.setHasFog(false); + zone.setLightingStyle(Zone.LightingStyle.ENVIRONMENTAL); + zone.setVisionType(Zone.VisionType.DAY); + zone.setVisible(true); + zone.setGridColor(Color.WHITE.hashCode()); + renderer = new ZoneRenderer(zone); + renderer.setSize(this.getSize()); + zoneScale = renderer.getZoneScale(); + zoneScale.setScale(0.7f); + if (footprint != null) { + cellSet = footprint.getOccupiedCells(ORIGIN); + } else { + cellSet.add(ORIGIN); + } + addListeners(); + } + + private void addListeners() { + addMouseListener( + new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + modifyFootprintCells(renderer.getCellAt(pointUnderMouse)); + } + }); + addMouseMotionListener( + new MouseAdapter() { + @Override + public void mouseMoved(MouseEvent e) { + pointUnderMouse = new ScreenPoint(e.getX(), e.getY()); + } + }); + } + + public Set getCellSet() { + log.info("getCellSet"); + return cellSet; + } + + private void setTokenFootprint(TokenFootprint tokenFootprint) { + this.footprint = tokenFootprint; + this.setCellSet(tokenFootprint.getOccupiedCells(ORIGIN)); + } + + public void setTokenFootprint( + String gridTypeName, TokenFootprint tokenFootprint, Set cells) { + log.info("setTokenFootprint - " + gridTypeName + " : " + tokenFootprint + " : " + cells); + if (gridTypeName != null) { + setGrid(gridTypeName); + } + setTokenFootprint(tokenFootprint); + setScale(tokenFootprint.getScale()); + this.footprint.addOffsetTranslator(FootprintManager.createOffsetTranslator(gridTypeName)); + if (cells != null) { + setCellSet(cells); + } + walker = currentGrid.createZoneWalker(); + walker.setWaypoints(ORIGIN, ORIGIN); + repaint(); + } + + private void setCellSet(Set cells) { + if (!cells.equals(cellSet)) { + footprint = + new TokenFootprint(footprint.getName(), FootPrintToolbox.cellSetToPointArray(cells)); + cellSet = cells; + repaint(); + } + } + + public void setScale(double scale) { + tokenScale = (float) scale; + repaint(); + } + + public void setGrid(String gridName) { + log.info("setGrid: " + gridName); + Grid tmpGrid; + switch (gridName) { + case "Vertical Hex" -> tmpGrid = HV; + case "Horizontal Hex" -> tmpGrid = HH; + case "Isometric Hex" -> tmpGrid = ISO_H; + case "Isometric" -> tmpGrid = ISO_S; + case "None" -> tmpGrid = GG; + case "Square" -> tmpGrid = SQ; + default -> tmpGrid = null; + } + if (tmpGrid == null || tmpGrid == currentGrid) { + return; + } + currentGrid = tmpGrid; + cellHighlight = currentGrid.getCellHighlight(); + zone.setGrid(currentGrid); + + walker = currentGrid.createZoneWalker(); + walker.setWaypoints(ORIGIN, ORIGIN); + renderer.flush(); + renderer.setScale(0.7f); + new MapToolEventBus().getMainEventBus().post(new GridChanged(zone)); + + repaint(); + log.info("grid changed"); + } + + void modifyFootprintCells(CellPoint cp) { + if (cp.equals(ORIGIN)) { + return; + } + if (cellSet.contains(cp)) { + cellSet.remove(cp); + walker = currentGrid.createZoneWalker(); + walker.setWaypoints(ORIGIN, ORIGIN); + log.info("modifyFootprintCells: - remove " + cp); + } else { + log.info("modifyFootprintCells: - add " + cp); + cellSet.add(cp); + walker.addWaypoints(cp); + } + + cellSet.addAll(walker.getPath().getCellPath()); + footprint = + new TokenFootprint(footprint.getName(), FootPrintToolbox.cellSetToPointArray(cellSet)); + repaint(); + } + + @Override + protected void paintComponent(Graphics graphics) { + super.paintComponent(graphics); + Graphics2D g = (Graphics2D) graphics; + renderer.setSize(this.getSize()); + renderer.centerOn(FootPrintToolbox.zonePointFromCellCentre(currentGrid.getCellCenter(ORIGIN))); + renderer.renderZone(g, playerView); + if (currentGrid != null) { + renderFootprint(g); + } + g.dispose(); + } + + public void zoomIn() { + renderer.zoomIn(0, 0); + repaint(); + } + + public void zoomOut() { + renderer.zoomOut(0, 0); + repaint(); + } + + public void zoomReset() { + renderer.zoomReset(0, 0); + repaint(); + } + + @Override + public void setVisible(boolean aFlag) { + super.setVisible(aFlag); + if (!aFlag) { + renderer.flush(); + MapTool.removeZone(zone); + } + } + + /** + * Relevant bits stolen from ZoneRenderer.renderPath + * + * @param g graphics + */ + public void renderFootprint(Graphics2D g) { + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + Point2D cellCentre; + ZonePoint zp; + for (CellPoint p : cellSet) { + zp = FootPrintToolbox.zonePointFromCellCentre(currentGrid.getCellCenter(p)); + renderer.highlightCell(g, zp, cellHighlight, tokenScale); + } + log.info("renderFootprint - cellSet: " + cellSet.toString()); + cellCentre = currentGrid.getCellCenter(ORIGIN); + zp = new ZonePoint((int) cellCentre.getX(), (int) cellCentre.getY()); + renderer.highlightCell(g, zp, ORIGIN_MARKER, tokenScale / 3f); + } +} diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java new file mode 100644 index 0000000000..9c19c66d4b --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java @@ -0,0 +1,864 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.footprintEditor; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.List; +import javax.swing.*; +import net.rptools.maptool.client.AppPreferences; +import net.rptools.maptool.client.AppState; +import net.rptools.maptool.client.MapTool; +import net.rptools.maptool.client.swing.AbeillePanel; +import net.rptools.maptool.client.swing.SwingUtil; +import net.rptools.maptool.client.ui.theme.Icons; +import net.rptools.maptool.client.ui.theme.RessourceManager; +import net.rptools.maptool.language.I18N; +import net.rptools.maptool.model.CellPoint; +import net.rptools.maptool.model.FootprintManager; +import net.rptools.maptool.model.GridFactory; +import net.rptools.maptool.model.TokenFootprint; +import net.rptools.maptool.util.FootPrintToolbox; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Tool for visually editing the token footprints associated with each grid type + * + *

Horizontal Hex = Pointy hat + * + *

Iso Hex = not yet implemented + * + *

Gridless = not yet implemented + */ +public class FootprintEditorDialog extends JDialog { + private final Logger log = LoggerFactory.getLogger(this.getClass().getName()); + + public FootprintEditorDialog(JFrame owner) { + super(owner, I18N.getText("FootprintEditorDialog.label.title"), false); + initialise(); + pack(); + } + + // form elements + private FootprintEditingPanel editor; + AbeillePanel formPanel; + private JSpinner scaleSpinner; + private JCheckBox defaultCheckbox; + public JRadioButton hexHorizontalRadio; + public JRadioButton hexVerticalRadio; + public JRadioButton squareRadio; + public JRadioButton noGridRadio; + public JRadioButton isoRadio; + public JRadioButton isoHexRadio; + public JLabel hexHorizontalIcon; + public JLabel hexVerticalIcon; + public JLabel isoIcon; + public JLabel isoHexIcon; + public JLabel noGridIcon; + public JLabel squareIcon; + public JTextField nameField; + public JComboBox footprintCombo; + public JButton okButton; + public JButton cancelButton; + public JButton addButton; + public JButton deleteButton; + public JButton revertButton; + public JButton saveButton; + public JButton listOrderButton; + public JPanel footprintDisplayContainer; + // variables + final boolean oldShowGrid = AppState.isShowGrid(); + private ComboBoxManager comboBoxManager; + String currentGridType; + private FPManager fpManager; + private final ChangeTracking changeTrack = new ChangeTracking(); + Changes changes; + private static final CellPoint ZERO_POINT = new CellPoint(0, 0); + JLayeredPane layeredPane = new JLayeredPane(); + + /** set up all the controls and variables prior to display */ + private void initialise() { + // RevsIconViewer riv = new RevsIconViewer(MapTool.getFrame()); + // riv.setVisible(true); + + log.info("initialise"); + setLayout(new GridLayout()); + formPanel = new AbeillePanel<>(new FootPrintEditorView().getRootComponent()); + getRootPane().setDefaultButton(okButton); + + AppState.setShowGrid(true); + currentGridType = FootPrintToolbox.getCurrentMapGridType(); + connectControls(); + initRadioButtons(); + + fpManager = new FPManager(); + comboBoxManager = new ComboBoxManager(); + + editor = new FootprintEditingPanel(); + footprintDisplayContainer.add(editor); + editor.setGrid(currentGridType); + + addMiscellaneousListeners(); + fpManager.selectionChanged((TokenFootprint) footprintCombo.getSelectedItem(), null, null); + add(formPanel); + this.pack(); + } + + /** + * add listeners to: + * + *

    + *
  • reset the the grid visibility to its original state on window closing + *
  • link escape key to cancel action + *
  • link +/- pgUp/pgDown to editor zoom level + */ + // spotless:off + private void addMiscellaneousListeners() { + log.info("addMiscellaneousListeners"); + // reset grid visibility + this.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { AppState.setShowGrid(oldShowGrid);}}); + // Escape key + formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); + formPanel.getActionMap().put("cancel", new AbstractAction() { + public void actionPerformed(ActionEvent e) {cancel();}}); + + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "zoomOut"); + formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut"); + formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "zoomIn"); + formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn"); + formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + .put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0), "zoomReset"); + formPanel.getActionMap().put("zoomOut", new AbstractAction() { + public void actionPerformed(ActionEvent e) { editor.zoomOut();}}); + formPanel.getActionMap().put("zoomIn", new AbstractAction() { + public void actionPerformed(ActionEvent e) { editor.zoomIn(); }}); + formPanel.getActionMap().put("zoomReset", new AbstractAction() { + public void actionPerformed(ActionEvent e) {editor.zoomReset();}}); + } +// spotless:on + /** connect variables to their associated controls */ + private void connectControls() { + log.info("connectControls"); + // editor panel + footprintDisplayContainer = (JPanel) formPanel.getComponent("footprintDisplayContainer"); + // default checkbox + defaultCheckbox = formPanel.getCheckBox("defaultCheckbox"); + defaultCheckbox.addActionListener(l -> fpManager.setAsDefault(defaultCheckbox.isSelected())); + // radio button icons + hexHorizontalIcon = (JLabel) formPanel.getComponent("hexHoriIcon"); + hexVerticalIcon = (JLabel) formPanel.getComponent("hexVertIcon"); + isoIcon = (JLabel) formPanel.getComponent("isoIcon"); + isoHexIcon = (JLabel) formPanel.getComponent("isoHexIcon"); + noGridIcon = (JLabel) formPanel.getComponent("noGridIcon"); + squareIcon = (JLabel) formPanel.getComponent("squareIcon"); + + // radio buttons + hexHorizontalRadio = formPanel.getRadioButton("hexHoriRadio"); + hexVerticalRadio = formPanel.getRadioButton("hexVertRadio"); + squareRadio = formPanel.getRadioButton("squareRadio"); + noGridRadio = formPanel.getRadioButton("noGridRadio"); + noGridRadio.setEnabled(false); // not yet implemented + isoRadio = formPanel.getRadioButton("isoRadio"); + isoHexRadio = formPanel.getRadioButton("isoHexRadio"); + isoHexRadio.setEnabled(false); // not yet implemented + + // editable text field + nameField = formPanel.getTextField("footprintName"); + nameField.addFocusListener( + new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + super.focusLost(e); + fpManager.setCurrentFootprintName(); + } + }); + nameField.addActionListener(e -> fpManager.setCurrentFootprintName()); + nameField.addKeyListener( + new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + super.keyPressed(e); + fpManager.setCurrentFootprintName(); + } + }); + + // scale slider + scaleSpinner = formPanel.getSpinner("scaleSpinner"); + + SpinnerNumberModel spinnerModel = new SpinnerNumberModel(1.0, 0.2, 1.0, 0.05); + scaleSpinner.setModel(spinnerModel); + JSpinner.NumberEditor numberEditor = new JSpinner.NumberEditor(scaleSpinner, "0.###"); + scaleSpinner.setEditor(numberEditor); + + scaleSpinner.addChangeListener( + e -> + fpManager.setScale( + ((SpinnerNumberModel) scaleSpinner.getModel()).getNumber().doubleValue())); + + // editing buttons + addButton = (JButton) formPanel.getButton("addButton"); + deleteButton = (JButton) formPanel.getButton("deleteButton"); + revertButton = (JButton) formPanel.getButton("revertButton"); + saveButton = (JButton) formPanel.getButton("saveButton"); + listOrderButton = (JButton) formPanel.getButton("listOrderButton"); + listOrderButton.setIcon(RessourceManager.getSmallIcon(Icons.PROPERTIES_TABLE_EXPAND)); + // add listeners assigning button actions to footprint manager functions + addButton.addActionListener(e -> fpManager.addFootprint()); + deleteButton.addActionListener(e -> fpManager.deleteFootprint()); + revertButton.addActionListener(e -> fpManager.revertFootprint()); + saveButton.addActionListener(e -> fpManager.saveFootprint()); + listOrderButton.addActionListener(e -> fpManager.reorderList()); + + // form buttons + okButton = (JButton) formPanel.getButton("okButton"); + cancelButton = (JButton) formPanel.getButton("okButton"); + + okButton.addActionListener(e -> okay()); + cancelButton.addActionListener(e -> cancel()); + } + + // spotless: on + /** + * set up the radio buttons: + * + *
      + *
    • assign action commands with grid types + *
    • assign icons to their labels + *
    • collect them into a group + *
    • add listener to control the footprint manager + */ + private void initRadioButtons() { + log.info("initRadioButtons"); + hexHorizontalRadio.setActionCommand("Horizontal Hex"); + hexVerticalRadio.setActionCommand("Vertical Hex"); + isoHexRadio.setActionCommand("Isometric Hex"); + isoRadio.setActionCommand("Isometric"); + noGridRadio.setActionCommand("None"); + squareRadio.setActionCommand("Square"); + + // set icons //TODO: make iso hex icon + isoIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_ISOMETRIC)); + isoHexIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_NONE)); + hexHorizontalIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_HEX_HORIZONTAL)); + hexVerticalIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_HEX_VERTICAL)); + noGridIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_NONE)); + squareIcon.setIcon(RessourceManager.getBigIcon(Icons.GRID_SQUARE)); + + // add to group and add listeners + ButtonGroup gridRadios = new ButtonGroup(); + gridRadios.add(hexHorizontalRadio); + gridRadios.add(hexVerticalRadio); + gridRadios.add(isoHexRadio); + gridRadios.add(isoRadio); + gridRadios.add(noGridRadio); + gridRadios.add(squareRadio); + + ActionListener radioListener = + e -> { + currentGridType = e.getActionCommand(); + fpManager.changeCurrentGridType(currentGridType); + }; + + hexHorizontalRadio.addActionListener(radioListener); + hexVerticalRadio.addActionListener(radioListener); + isoHexRadio.addActionListener(radioListener); + isoRadio.addActionListener(radioListener); + noGridRadio.addActionListener(radioListener); + squareRadio.addActionListener(radioListener); + // set initial selection to default grid + switch (currentGridType) { + case GridFactory.HEX_VERT -> hexVerticalRadio.setSelected(true); + case GridFactory.HEX_HORI -> hexHorizontalRadio.setSelected(true); + case GridFactory.ISOMETRIC -> isoRadio.setSelected(true); + case GridFactory.ISOMETRIC_HEX -> isoHexRadio.setSelected(false); + case GridFactory.SQUARE -> squareRadio.setSelected(true); + case GridFactory.NONE -> noGridRadio.setSelected(false); + } + } + + /** close dialogue accepting all changes */ + void okay() { + fpManager.writeUpdates(); + setVisible(false); + this.dispose(); + } + + /** close dialogue rejecting all changes */ + void cancel() { + setVisible(false); + this.dispose(); + } + + /** + * As all fields of a footprint cannot be modified on-the-fly, this class is used to store the + * current state of footprint fields + */ + private static class Changes { + double scale; + String name; + boolean asDefault; + Set cells; + + Changes(double scale, String name, Set cells) { + this.scale = scale; + this.name = name; + this.cells = cells; + } + + Changes(TokenFootprint footprint) { + this(footprint.getScale(), footprint.getName(), footprint.getOccupiedCells(ZERO_POINT)); + } + + void put(String fieldName, Object value) { + switch (fieldName) { + case "scale" -> this.scale = (double) value; + case "name" -> this.name = (String) value; + case "cells" -> { + if (value instanceof Set) { + if (((Set) value).stream().toList().getFirst() instanceof CellPoint) { + cells.clear(); + cells.addAll((Set) value); + } + } + } + } + } + + double getScale() { + return this.scale; + } + + String getName() { + return this.name; + } + + Set getCells() { + return this.cells; + } + + public String toString() { + return "scale: " + + this.scale + + ", name: " + + this.name + + ", default: " + + this.asDefault + + ", cells: " + + this.cells; + } + } + + /** + * A class to store the changes linked to each footprint. just a glorified HashMap with a couple + * of utility functions + */ + private static class ChangeTracking { + private final Map changeTrack = new HashMap<>(); + + public void put(TokenFootprint fp, Changes changeMap) { + changeTrack.put(fp, changeMap); + } + + public Changes getChanges(TokenFootprint fp) { + return changeTrack.get(fp); + } + + public void addChange(TokenFootprint footprint, String field, Object value) { + Changes changes = getChanges(footprint); + changes.put(field, value); + changeTrack.put(footprint, changes); + } + + public void remove(TokenFootprint footprint) { + changeTrack.remove(footprint); + } + } + + /** + * A manager class for keeping track of footprints - extends FootprintManager: + * + *
        + *
      • the current footprint being worked on "currentFootprint" + *
      • If there is one, the original version of the footprint to allow reversion + * "originalFootprint" + *
      • originals are stored in "originalMap" + *
      • a list of all the footprints mapped to grid type "gridFootprintListMap" + *
      • the list of footprints for the currently selected grid type "currentFootprintList" + *
      + * + * Contains methods for: + * + *
        + *
      • footprint editing control actions, i.e. setScale, changeName, etc. + *
      • updating editing controls from the change track + *
      • identifying if the footprint has changed + *
      • writing footprints to the campaign + *
      • etc. + *
      + */ + private class FPManager extends FootprintManager { + protected TokenFootprint currentFootprint; + protected List currentGridFootprintList = new LinkedList<>(); + protected Map> gridMapToFootprintList = new HashMap<>(); + protected Map gridDefaultFootprint = new HashMap<>(); + protected Map originalsMap = new HashMap<>(); + protected TokenFootprint originalFootprint; + + public FPManager() { + super(false); + log.info("new FPManager"); + addAllFootprintsFromCampaign(); + if (currentFootprint == null) { + currentFootprint = FootprintManager.getGlobalDefaultFootprint(); + } + originalFootprint = currentFootprint; + } + + private void addAllFootprintsFromCampaign() { + for (String gridType : campaignFootprints.keySet()) { + List gridList = new LinkedList<>(); + for (TokenFootprint fp : campaignFootprints.get(gridType)) { + changeTrack.put(fp, new Changes(fp)); + originalsMap.put(fp, fp); + gridList.add(fp); + if (fp.isDefault()) { + gridDefaultFootprint.put(gridType, fp); + } + if (currentGridType.equalsIgnoreCase(gridType)) { + currentFootprint = fp; + } + } + gridMapToFootprintList.put(gridType, gridList); + if (currentGridType.equalsIgnoreCase(gridType)) { + currentGridFootprintList = gridList; + } + } + } + + /** + * Actions to take when the combo box selection changes + * + * @param toFootprint the newly selected footprint + * @param fromFootprint the previously selected footprint(where available) + */ + private void selectionChanged( + TokenFootprint toFootprint, TokenFootprint fromFootprint, Changes changeUpdate) { + log.info( + "selectionChanged - " + + FootPrintToolbox.stringifyFootprint(toFootprint) + + " : " + + FootPrintToolbox.stringifyFootprint(fromFootprint) + + " : " + + changes); + if (fromFootprint != null && changeUpdate != null) { + // apply all control values to the change track on the last footprint + changeTrack.put(fromFootprint, changeUpdate); + } + // apply all values from the change track to the controls + changes = changeTrack.getChanges(toFootprint); + if (changes != null) { + nameField.setText( + changes.getName().isBlank() || changes.getName().isEmpty() + ? ((TokenFootprint) footprintCombo.getSelectedItem()).getLocalizedName() + : changes.getName()); + scaleSpinner.setValue(changes.getScale()); + editor.setTokenFootprint(currentGridType, toFootprint, changes.getCells()); + } else { + nameField.setText(((TokenFootprint) footprintCombo.getSelectedItem()).getLocalizedName()); + editor.setTokenFootprint(currentGridType, toFootprint, null); + } + log.info( + "Selection isDefault: " + getGridDefaultFootprint(currentGridType).equals(toFootprint)); + defaultCheckbox.setSelected(getGridDefaultFootprint(currentGridType).equals(toFootprint)); + setCurrentFootprint(toFootprint); + } + + TokenFootprint getGridDefaultFootprint(String gridType) { + return gridDefaultFootprint.get(gridType.equals("Isometric") ? "Square" : gridType); + } + + List getCurrentGridFootprintList() { + return currentGridFootprintList; + } + + /** + * Compares a footprint against the stored changes + * + * @param fp TokenFootprint + * @return boolean + */ + public boolean hasChanged(TokenFootprint fp) { + changes = changeTrack.getChanges(fp); + boolean result = false; + if (originalsMap.containsKey(fp)) { + result = + originalsMap.get(fp).isDefault() != getGridDefaultFootprint(currentGridType).equals(fp); + } + return result + || fp.getScale() != changes.getScale() + || !fp.getName().equals(changes.getName()) + || !fp.getOccupiedCells(ZERO_POINT).equals(changes.getCells()) + || !fp.getLocalizedName().equals(fp.getLocalizedName()); + } + + void writeUpdate(TokenFootprint fp, String gridType) { + log.info("writeUpdate - " + gridType + fp); + writeFootprintToCampaign(fp, gridType); + } + + void writeUpdates() { + writeAllFootprintsToCampaign(gridMapToFootprintList); + } + + private void setScale(double s) { + log.info("setScale: " + s); + if (currentFootprint.getScale() != s) { + changeTrack.addChange(currentFootprint, "scale", s); + } + editor.setScale(s); + // TODO: check validity and update editor + } + + @Override + public void changeCurrentGridType(String gridType) { + log.info("setCurrentGridFootprints"); + // store the old + gridMapToFootprintList.put(currentGridType, getCurrentGridFootprintList()); + // replace with the new + currentGridType = gridType; + currentGridFootprintList = gridMapToFootprintList.get(currentGridType); + // update the ui + comboBoxManager.setVisibleComboBox(); + selectionChanged((TokenFootprint) footprintCombo.getSelectedItem(), null, null); + } + + private void setCurrentFootprint(TokenFootprint footprint) { + log.info("setCurrentFootprint - " + footprint.toString()); + currentFootprint = footprint; + boolean exists = originalsMap.containsKey(footprint); + revertButton.setEnabled(exists); + if (exists) { + originalFootprint = originalsMap.get(footprint); + } else { + originalFootprint = null; + } + } + + void FPMReplace(TokenFootprint fp1, TokenFootprint fp2) { + if (getCurrentGridFootprintList().contains(fp1)) { + int idx = currentGridFootprintList.indexOf(fp1); + currentGridFootprintList.remove(idx); + currentGridFootprintList.add(idx, fp2); + changeTrack.remove(fp1); + changeTrack.put(fp2, new Changes(fp2)); + comboBoxManager.comboReplace(fp1, fp2); + } + } + + public void setCurrentFootprintName() { + log.info("setCurrentFootprintName"); + String name = nameField.getText(); + changeTrack.addChange(currentFootprint, "name", name); + currentFootprint.setLocalizedName(name); + } + + public TokenFootprint buildNewFootprint(TokenFootprint footprint) { + changes = changeTrack.getChanges(footprint); + String name = newName(changes.getName()); + return createTokenFootprint( + currentGridType, + name, + getGridDefaultFootprint(currentGridType).equals(footprint), + changes.getScale(), + true, + name, + changes.getCells()); + } + + public TokenFootprint buildNewFootprint() { + log.info("buildNewFootprint"); + changeTrack.addChange(currentFootprint, "name", nameField.getText()); + changeTrack.addChange( + currentFootprint, + "scale", + ((SpinnerNumberModel) scaleSpinner.getModel()).getNumber().doubleValue()); + changeTrack.addChange(currentFootprint, "cells", editor.getCellSet()); + return buildNewFootprint(currentFootprint); + } + + void setAsDefault(boolean value) { + if (value) { + gridDefaultFootprint.replace(currentGridType, currentFootprint); + } else { + gridDefaultFootprint.replace(currentGridType, currentGridFootprintList.getFirst()); + } + } + + void addFootprint() { + log.info("addFootprint"); + TokenFootprint newFp = buildNewFootprint(); + changeTrack.put(newFp, new Changes(newFp)); + currentGridFootprintList.add(newFp); + setCurrentFootprint(newFp); + setAsDefault(defaultCheckbox.isSelected()); + comboBoxManager.addToComboBox(newFp); + } + + void deleteFootprint() { + log.info("deleteFootprint"); + currentGridFootprintList.remove(currentFootprint); + changeTrack.remove(currentFootprint); + comboBoxManager.remove(currentFootprint); + } + + String newName(String text) { + List useList = getCurrentGridFootprintList(); + text = text.isEmpty() ? "new_footprint" : text; + boolean test; + do { + test = useList.stream().map(TokenFootprint::getName).toList().contains(text); + if (!test) { + test = useList.stream().map(TokenFootprint::getLocalizedName).toList().contains(text); + } + text = test ? text + "_" : text; + } while (test); + return text; + } + + void saveFootprint() { + log.info("saveFootprint"); + if (hasChanged(currentFootprint)) { + TokenFootprint newFP = buildNewFootprint(currentFootprint); + FPMReplace(currentFootprint, newFP); + writeUpdate(newFP, currentGridType); + } + } + + void revertFootprint() { + log.info("revertFootprint"); + if (originalFootprint != null) { + currentFootprint = originalFootprint; + changeTrack.remove(currentFootprint); + changes = new Changes(originalFootprint); + changeTrack.put(originalFootprint, changes); + + setAsDefault(originalFootprint.isDefault()); + scaleSpinner.setValue(changes.getScale()); + nameField.setText(changes.getName()); + editor.setTokenFootprint(currentGridType, originalFootprint, null); + } + } + + public void reorderList() { + log.info("reorderList"); + JOptionPane.showMessageDialog(formPanel, "Whole lotta nuthin"); + // TODO: Token list order - update comboBox model + } + } + + /** + * A class for juggling multiple combo boxes where only one is visible. + * + *

      To reflect that footprints are stored against a type of grid, each unique grid type has its + * own combo box stored in a Card Layout. When the type of grid is changed the relevant combo box + * is made visible. + * + *

      As a convenience measure the visible combo box is assigned to "footprintCombo". + * + *

      Contains additional methods for edit actions such as adding/removing footprints from the + * list. + */ + private class ComboBoxManager { + public JPanel comboBoxPanel; + JComboBox activeCombo = footprintCombo; + static TokenFootprint lastSelectedFootprint = null; + + JComboBox createComboBox(List footprints) { + JComboBox combo = new JComboBox<>(); + MutableComboBoxModel comboModel = new DefaultComboBoxModel<>(); + for (TokenFootprint footprint : footprints) { + comboModel.addElement(footprint); + if (footprint.isDefault()) { + comboModel.setSelectedItem(footprint); + } + } + combo.setModel(comboModel); + combo.addItemListener(comboListener); + return combo; + } + + ComboBoxManager() { + log.info("ComboBoxManager"); + footprintCombo = (JComboBox) formPanel.getComboBox("footprintCombo"); + comboBoxPanel = (JPanel) formPanel.getComponent("comboBoxPanel"); + initFootprintCombo(); + setVisibleComboBox(); + } + + private void setVisibleComboBox() { + log.info("setVisibleComboBox"); + lastSelectedFootprint = null; + CardLayout cl = (CardLayout) (comboBoxPanel.getLayout()); + String useGrid = currentGridType.equalsIgnoreCase("Isometric") ? "Square" : currentGridType; + cl.show(comboBoxPanel, useGrid + "Combo"); + + for (Component comp : comboBoxPanel.getComponents()) { + if ((useGrid + "Combo").equalsIgnoreCase(comp.getName())) { + activeCombo = (JComboBox) comp; + } + } + footprintCombo = activeCombo; + activeCombo.requestFocus(); + } + + void remove(TokenFootprint footprint) { + if (footprintCombo.getModel().getSize() > 1) { + MutableComboBoxModel model = + (MutableComboBoxModel) footprintCombo.getModel(); + model.removeElement(footprint); + } + } + + void comboReplace(TokenFootprint fp1, TokenFootprint fp2) { + MutableComboBoxModel model = + (MutableComboBoxModel) footprintCombo.getModel(); + int i = 0; + boolean finished = false; + while (i < model.getSize() && !finished) { + if (model.getElementAt(i).equals(fp1)) { + model.removeElementAt(i); + model.insertElementAt(fp2, i); + finished = true; + } + i++; + } + } + + ItemListener comboListener = + new ItemListener() { + private Changes lastChangeRecord; + + @Override + public void itemStateChanged(ItemEvent e) { + log.info("Combo box event: " + e); + TokenFootprint item = (TokenFootprint) e.getItem(); + if (e.getStateChange() == ItemEvent.DESELECTED) { + // store the state of the outgoing footprint + lastChangeRecord = + new Changes( + ((SpinnerNumberModel) scaleSpinner.getModel()).getNumber().doubleValue(), + nameField.getText(), + editor.getCellSet()); + // store the identity of the outgoing footprint + lastSelectedFootprint = item; + } + if (e.getStateChange() == ItemEvent.SELECTED) { + // advise the footprint manager of the selection change with the state at the point of + // change + fpManager.selectionChanged(item, lastSelectedFootprint, lastChangeRecord); + lastChangeRecord = null; + } + } + }; + + private void initFootprintCombo() { + log.info("initFootprintCombo"); + footprintCombo.setVisible(false); + Map> useCampaignFootprints = + FootprintManager.getCampaignFootprints(); + + for (String key : useCampaignFootprints.keySet()) { + List footPrints = useCampaignFootprints.get(key); + JComboBox comboBox = createComboBox(footPrints); + comboBox.setEnabled(true); + comboBox.setFocusable(true); + comboBox.setRequestFocusEnabled(true); + comboBox.setActionCommand(footprintCombo.getActionCommand()); + comboBox.setName(key + "Combo"); + comboBox.addItemListener(comboListener); + comboBoxPanel.add(comboBox, comboBox.getName()); + } + } + + public void addToComboBox(TokenFootprint newFp) { + log.info("addToComboBox - " + newFp); + ((MutableComboBoxModel) footprintCombo.getModel()).addElement(newFp); + footprintCombo.setSelectedItem(newFp); + } + } + + // spotless:off + private void createZoomButtons() { + layeredPane = this.getLayeredPane(); + JPanel buttonHolder = new JPanel(); + // buttonHolder.setPreferredSize(layeredPane.getPreferredSize()); + buttonHolder.setBackground(new Color(80, 180, 80)); + buttonHolder.setBorder(BorderFactory.createLineBorder(Color.BLUE, 3, true)); + String oldTheme = AppPreferences.getIconTheme(); + AppPreferences.setIconTheme(RessourceManager.ROD_TAKEHARA); + JButton zInButton = new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_HIDE_OFF)); + JButton zOutButton = new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_HIDE_ON)); + JButton zResetButton = + new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_TOPOLOGY_OVAL_HOLLOW)); + AppPreferences.setIconTheme(oldTheme); + Dimension buttonSize = new Dimension(36, 36); + Color bg = new Color(0, 0, 0, 0); + zInButton.setBackground(bg); + zOutButton.setBackground(bg); + zResetButton.setBackground(bg); + zInButton.setPreferredSize(buttonSize); + zInButton.setPreferredSize(buttonSize); + zOutButton.setPreferredSize(buttonSize); + zResetButton.setPreferredSize(buttonSize); + zInButton.addActionListener(e -> editor.zoomIn()); + zOutButton.addActionListener(e -> editor.zoomOut()); + zResetButton.addActionListener(e -> editor.zoomReset()); + + zInButton.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + zOutButton.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + zResetButton.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4)); + buttonHolder.setLayout(new BoxLayout(buttonHolder, BoxLayout.Y_AXIS)); + buttonHolder.add(zInButton); + buttonHolder.add(zResetButton); + buttonHolder.add(zOutButton); + buttonHolder.validate(); + buttonHolder.setBounds(8, 70, 40, 120); + layeredPane.add(buttonHolder, Integer.valueOf(450)); + } + + @Override + public void setVisible(boolean b) { + if (b) { + SwingUtil.centerOver(this, MapTool.getFrame()); + } + super.setVisible(b); + editor.requestFocusInWindow(); + } + + @Override + public void dispose() { + AppState.setShowGrid(oldShowGrid); + super.dispose(); + } +} diff --git a/src/main/java/net/rptools/maptool/model/FootprintManager.java b/src/main/java/net/rptools/maptool/model/FootprintManager.java new file mode 100644 index 0000000000..878f91e16e --- /dev/null +++ b/src/main/java/net/rptools/maptool/model/FootprintManager.java @@ -0,0 +1,192 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.model; + +import static java.util.Map.entry; + +import java.awt.*; +import java.util.*; +import java.util.List; +import net.rptools.maptool.client.AppPreferences; +import net.rptools.maptool.client.MapTool; +import net.rptools.maptool.tool.TokenFootprintCreator; +import net.rptools.maptool.util.FootPrintToolbox; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FootprintManager { + public static final Map GRID_FOOTPRINT_TYPE = + Map.ofEntries( + entry(GridFactory.HEX_HORI, GridFactory.HEX_HORI), + entry(GridFactory.HEX_VERT, GridFactory.HEX_VERT), + entry(GridFactory.ISOMETRIC, GridFactory.SQUARE), + entry(GridFactory.ISOMETRIC_HEX, GridFactory.NONE), + entry(GridFactory.NONE, GridFactory.NONE), + entry(GridFactory.SQUARE, GridFactory.SQUARE)); + protected static final String DEFAULT_GRID_TYPE = AppPreferences.getDefaultGridType(); + private static final Logger log = LoggerFactory.getLogger(FootprintManager.class); + protected static boolean useAppDefaults = false; + protected static String currentGridType = DEFAULT_GRID_TYPE; + protected static Map> campaignFootprints = new HashMap<>(); + protected static List currentGridFootprints = new ArrayList<>(); + protected TokenFootprint defaultFootprint; + + public FootprintManager(boolean useAppDefaults) { + load(useAppDefaults); + } + + public static TokenFootprint getGlobalDefaultFootprint() { + return MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints() + .get(AppPreferences.getDefaultGridType()) + .stream() + .filter(TokenFootprint::isDefault) + .findAny() + .orElse( + MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints() + .get(AppPreferences.getDefaultGridType()) + .getFirst()); + } + + public static Map getGridFootprintType() { + return GRID_FOOTPRINT_TYPE; + } + + public static Map> getCampaignFootprints() { + return campaignFootprints; + } + + public static List getGridFootprints(String gridTypeName) { + return getCampaignFootprints().get(GRID_FOOTPRINT_TYPE.get(gridTypeName)); + } + + public static TokenFootprint.OffsetTranslator createOffsetTranslator(String gridTypeName) { + gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); + if (gridTypeName.equals(GridFactory.HEX_HORI)) { + return (originPoint, offsetPoint) -> { + if ((originPoint.y & 1) == 1 && (offsetPoint.y & 1) == 0) { + offsetPoint.x++; + } + }; + } else if (gridTypeName.equals(GridFactory.HEX_VERT)) { + return (originPoint, offsetPoint) -> { + if ((originPoint.x & 1) == 1 && (offsetPoint.x & 1) == 0) { + offsetPoint.y++; + } + }; + } else { + return (originPoint, offsetPoint) -> offsetPoint = originPoint; + } + } + + public static TokenFootprint createTokenFootprint( + String gridTypeName, + String name, + boolean isDefault, + Double scale, + boolean localiseName, + String localisedName, + Set cellPoints) { + Point[] pointArray = + FootPrintToolbox.cellPointListToPointArray(FootPrintToolbox.cellPointSetToList(cellPoints)); + TokenFootprint newPrint = new TokenFootprint(name, isDefault, scale, localiseName, pointArray); + if (!localisedName.isEmpty()) { + newPrint.setLocalizedName(localisedName); + } + newPrint.addOffsetTranslator(createOffsetTranslator(gridTypeName)); + return newPrint; + } + + public static void writeAllFootprintsToCampaign(Map> footprints) { + CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); + for (String key : footprints.keySet()) { + props.setGridFootprints(key, footprints.get(key)); + } + MapTool.getCampaign().mergeCampaignProperties(props); + } + + public static void writeGridFootprintsToCampaign( + List footprints, String gridTypeName) { + gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); + CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); + props.setGridFootprints(gridTypeName, footprints); + MapTool.getCampaign().mergeCampaignProperties(props); + } + + public static void writeFootprintToCampaign(TokenFootprint footprint, String gridTypeName) { + log.debug("writeFootprintToCampaign - " + footprint + " - " + gridTypeName); + gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); + List list = getGridFootprints(gridTypeName); + list.add(footprint); + CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); + props.setGridFootprints(gridTypeName, list); + MapTool.getCampaign().mergeCampaignProperties(props); + } + + void load(boolean useDefaults) { + setUseAppDefaults(useDefaults); + load(); + } + + void load() { + if (useAppDefaults) { + load(DEFAULT_GRID_TYPE); + } else { + setCurrentGrid(MapTool.getFrame().getCurrentZoneRenderer().getZone().getGrid()); + } + } + + void load(String gridType) { + log.debug("gridType" + gridType); + log.debug("useAppDefaults:" + useAppDefaults); + currentGridType = gridType; + if (useAppDefaults) { + campaignFootprints = + Map.ofEntries( + entry(GridFactory.HEX_HORI, TokenFootprintCreator.makeHorizHex()), + entry(GridFactory.HEX_VERT, TokenFootprintCreator.makeVertHex()), + entry(GridFactory.NONE, TokenFootprintCreator.makeGridless()), + entry(GridFactory.SQUARE, TokenFootprintCreator.makeSquare())); + } else { + campaignFootprints = MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + } + currentGridFootprints = campaignFootprints.get(GRID_FOOTPRINT_TYPE.get(currentGridType)); + defaultFootprint = + currentGridFootprints.stream().filter(TokenFootprint::isDefault).toList().getFirst(); + } + + boolean isUseAppDefaults() { + return useAppDefaults; + } + + void setUseAppDefaults(boolean value) { + useAppDefaults = value; + } + + void setCurrentGrid(Grid grid) { + setCurrentGridType(GridFactory.getGridType(grid)); + } + + void setCurrentGridType(String gridType) { + load(gridType); + } + + public void changeCurrentGridType(String gridType) { + currentGridFootprints = campaignFootprints.get(GRID_FOOTPRINT_TYPE.get(gridType)); + } +} diff --git a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java new file mode 100644 index 0000000000..6f8d00bbfd --- /dev/null +++ b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java @@ -0,0 +1,95 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.util; + +import java.awt.Point; +import java.awt.geom.Point2D; +import java.util.*; +import java.util.stream.Collectors; +import net.rptools.maptool.client.MapTool; +import net.rptools.maptool.model.*; + +public class FootPrintToolbox { + public static final CellPoint ZERO_CELLPOINT = new CellPoint(0, 0); + + public static List getGridFootprints(String gridType) { + return FootprintManager.getCampaignFootprints() + .getOrDefault(FootprintManager.getGridFootprintType().get(gridType), null); + } + + public static Grid getCurrentMapGrid() { + return MapTool.getFrame().getCurrentZoneRenderer().getZone().getGrid(); + } + + public static String getCurrentMapGridType() { + return getGridType(getCurrentMapGrid()); + } + + public static String getGridType(Grid grid) { + return GridFactory.getGridType(grid); + } + + public static ZonePoint zonePointFromCellCentre(Point2D pt) { + return new ZonePoint((int) pt.getX(), (int) pt.getY()); + } + + public static List cellPointsToZonePoints(Grid grid, List cellPoints) { + return cellPoints.stream().map(grid::convert).collect(Collectors.toSet()).stream().toList(); + } + + public static Point[] cellSetToPointArray(Set set) { + return cellPointListToPointArray(cellPointSetToList(set)); + } + + public static Point[] cellPointListToPointArray(List cellPoints) { + return cellPoints.stream().map(cp -> new Point(cp.x, cp.y)).toList().toArray(new Point[0]); + } + + public static List cellPointSetToList(Set cellPoints) { + return cellPoints.stream().toList(); + } + + public static List getGridFootprints() { + return getGridFootprints(getGridType(getCurrentMapGrid())); + } + + public static List sortCellList(List cellList) { + cellList.sort(Comparator.comparingInt(o -> o.x)); + cellList.sort(Comparator.comparingInt(o -> o.y)); + return cellList; + } + + public static TokenFootprint getDefaultFootprint(List list) { + return list.stream().filter(TokenFootprint::isDefault).findFirst().orElseGet(list::getFirst); + } + + public static String stringifyFootprint(TokenFootprint footprint) { + if (footprint == null) { + return "null"; + } + return "\n---TokenFootprint---\nName:\t\t\t" + + footprint.getName() + + "\nLocalizedName:\t" + + footprint.getLocalizedName() + + "\nDefault:\t\t" + + footprint.isDefault() + + "\nScale:\t\t\t" + + footprint.getScale() + + "\nCells:\t\t\t" + + footprint.getOccupiedCells(ZERO_CELLPOINT) + + "\nGUID:\t\t\t" + + footprint.getId(); + } +} diff --git a/src/main/resources/net/rptools/maptool/language/i18n.properties b/src/main/resources/net/rptools/maptool/language/i18n.properties index 2010556c13..dd9d198244 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n.properties @@ -128,6 +128,8 @@ Button.install = Install Button.runmacro = RUN MACRO Button.hide = Hide +Button.rearrange.tooltip = Rearrange content + Label.lights = Vision: Label.name = Name: Label.gmname = GM Name: @@ -371,6 +373,8 @@ EditTokenDialog.button.hero.refresh.tooltip.off = Refresh data from Hero L EditTokenDialog.libTokenURI.error.notLibToken = {0} is not a valid name for a lib:Token. EditTokenDialog.libTokenURI.error.reserved = lib:Tokens can not be named {0} if you want to enable URI access. +FootprintEditorDialog.label.title = Edit Campaign Footprints + MapPropertiesDialog.label.playerMapAlias = Display Name: MapPropertiesDialog.label.playerMapAlias.tooltip = This is how players will see the map identified. Must be unique within campaign. MapPropertiesDialog.label.Name.tooltip = This is how the map is referred to in macros and is only visible to the GM. @@ -1279,6 +1283,8 @@ action.autohideNewMaps.description = New maps start invisible to play # necessary code for localization. action.bootConnectedPlayer = Boot... action.campaignProperties = Campaign Properties... +action.campaignFootprints = Token Footprints +action.campaignFootprints.description = Opens a dialog for editing the token sizes and the space they occupy in a campaign. action.campaignProperties.description = Opens dialog for setting Campaign Properties. action.cancelCommand = Not used (action.cancelCommand) action.clearDrawing = Clear All Drawings From d46505e924d7cdde3209dd8dd9ba968609ea0dce Mon Sep 17 00:00:00 2001 From: bubblobill <45483160+bubblobill@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:20:11 +0800 Subject: [PATCH 18/21] Deleting default now resets default. Sort button now allows reordering list. Took out the cell selecting cleverness. --- .../footprintEditor/FootPrintEditorView.form | 4 +- .../FootprintEditingPanel.java | 28 +--- .../FootprintEditorDialog.java | 117 +++++++++----- .../ui/footprintEditor/ListSorterView.form | 109 +++++++++++++ .../ui/footprintEditor/ListSorterView.java | 25 +++ .../ui/footprintEditor/ListSortingDialog.java | 153 ++++++++++++++++++ 6 files changed, 377 insertions(+), 59 deletions(-) create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.form create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.java create mode 100644 src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSortingDialog.java diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form index 2419085beb..6977dbdb3e 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootPrintEditorView.form @@ -464,9 +464,9 @@ - diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java index 0185cd9d50..b466fbc005 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java @@ -29,7 +29,6 @@ import net.rptools.maptool.client.ui.theme.RessourceManager; import net.rptools.maptool.client.ui.zone.PlayerView; import net.rptools.maptool.client.ui.zone.renderer.ZoneRenderer; -import net.rptools.maptool.client.walker.ZoneWalker; import net.rptools.maptool.events.MapToolEventBus; import net.rptools.maptool.model.*; import net.rptools.maptool.model.player.Player; @@ -55,14 +54,13 @@ public class FootprintEditingPanel extends JPanel { private static volatile Grid currentGrid; private BufferedImage cellHighlight; ZoneRenderer renderer; - ZoneWalker walker; Zone zone; static volatile Scale zoneScale; static volatile float tokenScale = 1; TokenFootprint footprint = FootprintManager.getGlobalDefaultFootprint(); public FootprintEditingPanel() { - log.info("new FootprintEditingPanel"); + log.debug("new FootprintEditingPanel"); this.setFocusable(true); this.setEnabled(true); this.setBorder(BorderFactory.createLoweredBevelBorder()); @@ -103,7 +101,7 @@ public void mouseMoved(MouseEvent e) { } public Set getCellSet() { - log.info("getCellSet"); + log.debug("getCellSet"); return cellSet; } @@ -114,7 +112,7 @@ private void setTokenFootprint(TokenFootprint tokenFootprint) { public void setTokenFootprint( String gridTypeName, TokenFootprint tokenFootprint, Set cells) { - log.info("setTokenFootprint - " + gridTypeName + " : " + tokenFootprint + " : " + cells); + log.debug("setTokenFootprint - " + gridTypeName + " : " + tokenFootprint + " : " + cells); if (gridTypeName != null) { setGrid(gridTypeName); } @@ -124,8 +122,6 @@ public void setTokenFootprint( if (cells != null) { setCellSet(cells); } - walker = currentGrid.createZoneWalker(); - walker.setWaypoints(ORIGIN, ORIGIN); repaint(); } @@ -144,7 +140,7 @@ public void setScale(double scale) { } public void setGrid(String gridName) { - log.info("setGrid: " + gridName); + log.debug("setGrid: " + gridName); Grid tmpGrid; switch (gridName) { case "Vertical Hex" -> tmpGrid = HV; @@ -161,15 +157,12 @@ public void setGrid(String gridName) { currentGrid = tmpGrid; cellHighlight = currentGrid.getCellHighlight(); zone.setGrid(currentGrid); - - walker = currentGrid.createZoneWalker(); - walker.setWaypoints(ORIGIN, ORIGIN); renderer.flush(); renderer.setScale(0.7f); new MapToolEventBus().getMainEventBus().post(new GridChanged(zone)); repaint(); - log.info("grid changed"); + log.debug("grid changed"); } void modifyFootprintCells(CellPoint cp) { @@ -178,16 +171,11 @@ void modifyFootprintCells(CellPoint cp) { } if (cellSet.contains(cp)) { cellSet.remove(cp); - walker = currentGrid.createZoneWalker(); - walker.setWaypoints(ORIGIN, ORIGIN); - log.info("modifyFootprintCells: - remove " + cp); + log.debug("modifyFootprintCells: - remove " + cp); } else { - log.info("modifyFootprintCells: - add " + cp); + log.debug("modifyFootprintCells: - add " + cp); cellSet.add(cp); - walker.addWaypoints(cp); } - - cellSet.addAll(walker.getPath().getCellPath()); footprint = new TokenFootprint(footprint.getName(), FootPrintToolbox.cellSetToPointArray(cellSet)); repaint(); @@ -243,7 +231,7 @@ public void renderFootprint(Graphics2D g) { zp = FootPrintToolbox.zonePointFromCellCentre(currentGrid.getCellCenter(p)); renderer.highlightCell(g, zp, cellHighlight, tokenScale); } - log.info("renderFootprint - cellSet: " + cellSet.toString()); + log.debug("renderFootprint - cellSet: " + cellSet.toString()); cellCentre = currentGrid.getCellCenter(ORIGIN); zp = new ZonePoint((int) cellCentre.getX(), (int) cellCentre.getY()); renderer.highlightCell(g, zp, ORIGIN_MARKER, tokenScale / 3f); diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java index 9c19c66d4b..3b9dc6d50b 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java @@ -18,6 +18,7 @@ import java.awt.event.*; import java.util.*; import java.util.List; +import java.util.stream.Collectors; import javax.swing.*; import net.rptools.maptool.client.AppPreferences; import net.rptools.maptool.client.AppState; @@ -92,10 +93,7 @@ public FootprintEditorDialog(JFrame owner) { /** set up all the controls and variables prior to display */ private void initialise() { - // RevsIconViewer riv = new RevsIconViewer(MapTool.getFrame()); - // riv.setVisible(true); - - log.info("initialise"); + log.debug("initialise"); setLayout(new GridLayout()); formPanel = new AbeillePanel<>(new FootPrintEditorView().getRootComponent()); getRootPane().setDefaultButton(okButton); @@ -115,6 +113,7 @@ private void initialise() { addMiscellaneousListeners(); fpManager.selectionChanged((TokenFootprint) footprintCombo.getSelectedItem(), null, null); add(formPanel); + createZoomButtons(); this.pack(); } @@ -128,7 +127,7 @@ private void initialise() { */ // spotless:off private void addMiscellaneousListeners() { - log.info("addMiscellaneousListeners"); + log.debug("addMiscellaneousListeners"); // reset grid visibility this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { AppState.setShowGrid(oldShowGrid);}}); @@ -159,7 +158,7 @@ private void addMiscellaneousListeners() { // spotless:on /** connect variables to their associated controls */ private void connectControls() { - log.info("connectControls"); + log.debug("connectControls"); // editor panel footprintDisplayContainer = (JPanel) formPanel.getComponent("footprintDisplayContainer"); // default checkbox @@ -249,7 +248,7 @@ public void keyPressed(KeyEvent e) { *

    • add listener to control the footprint manager */ private void initRadioButtons() { - log.info("initRadioButtons"); + log.debug("initRadioButtons"); hexHorizontalRadio.setActionCommand("Horizontal Hex"); hexVerticalRadio.setActionCommand("Vertical Hex"); isoHexRadio.setActionCommand("Isometric Hex"); @@ -427,7 +426,7 @@ private class FPManager extends FootprintManager { public FPManager() { super(false); - log.info("new FPManager"); + log.debug("new FPManager"); addAllFootprintsFromCampaign(); if (currentFootprint == null) { currentFootprint = FootprintManager.getGlobalDefaultFootprint(); @@ -464,7 +463,7 @@ private void addAllFootprintsFromCampaign() { */ private void selectionChanged( TokenFootprint toFootprint, TokenFootprint fromFootprint, Changes changeUpdate) { - log.info( + log.debug( "selectionChanged - " + FootPrintToolbox.stringifyFootprint(toFootprint) + " : " @@ -488,7 +487,7 @@ private void selectionChanged( nameField.setText(((TokenFootprint) footprintCombo.getSelectedItem()).getLocalizedName()); editor.setTokenFootprint(currentGridType, toFootprint, null); } - log.info( + log.debug( "Selection isDefault: " + getGridDefaultFootprint(currentGridType).equals(toFootprint)); defaultCheckbox.setSelected(getGridDefaultFootprint(currentGridType).equals(toFootprint)); setCurrentFootprint(toFootprint); @@ -523,7 +522,7 @@ public boolean hasChanged(TokenFootprint fp) { } void writeUpdate(TokenFootprint fp, String gridType) { - log.info("writeUpdate - " + gridType + fp); + log.debug("writeUpdate - " + gridType + fp); writeFootprintToCampaign(fp, gridType); } @@ -532,7 +531,7 @@ void writeUpdates() { } private void setScale(double s) { - log.info("setScale: " + s); + log.debug("setScale: " + s); if (currentFootprint.getScale() != s) { changeTrack.addChange(currentFootprint, "scale", s); } @@ -542,7 +541,7 @@ private void setScale(double s) { @Override public void changeCurrentGridType(String gridType) { - log.info("setCurrentGridFootprints"); + log.debug("setCurrentGridFootprints"); // store the old gridMapToFootprintList.put(currentGridType, getCurrentGridFootprintList()); // replace with the new @@ -554,7 +553,7 @@ public void changeCurrentGridType(String gridType) { } private void setCurrentFootprint(TokenFootprint footprint) { - log.info("setCurrentFootprint - " + footprint.toString()); + log.debug("setCurrentFootprint - " + footprint.toString()); currentFootprint = footprint; boolean exists = originalsMap.containsKey(footprint); revertButton.setEnabled(exists); @@ -577,7 +576,7 @@ void FPMReplace(TokenFootprint fp1, TokenFootprint fp2) { } public void setCurrentFootprintName() { - log.info("setCurrentFootprintName"); + log.debug("setCurrentFootprintName"); String name = nameField.getText(); changeTrack.addChange(currentFootprint, "name", name); currentFootprint.setLocalizedName(name); @@ -597,7 +596,7 @@ public TokenFootprint buildNewFootprint(TokenFootprint footprint) { } public TokenFootprint buildNewFootprint() { - log.info("buildNewFootprint"); + log.debug("buildNewFootprint"); changeTrack.addChange(currentFootprint, "name", nameField.getText()); changeTrack.addChange( currentFootprint, @@ -616,7 +615,7 @@ void setAsDefault(boolean value) { } void addFootprint() { - log.info("addFootprint"); + log.debug("addFootprint"); TokenFootprint newFp = buildNewFootprint(); changeTrack.put(newFp, new Changes(newFp)); currentGridFootprintList.add(newFp); @@ -626,7 +625,10 @@ void addFootprint() { } void deleteFootprint() { - log.info("deleteFootprint"); + log.debug("deleteFootprint"); + if (defaultCheckbox.isSelected()) { + setAsDefault(false); + } currentGridFootprintList.remove(currentFootprint); changeTrack.remove(currentFootprint); comboBoxManager.remove(currentFootprint); @@ -647,7 +649,7 @@ String newName(String text) { } void saveFootprint() { - log.info("saveFootprint"); + log.debug("saveFootprint"); if (hasChanged(currentFootprint)) { TokenFootprint newFP = buildNewFootprint(currentFootprint); FPMReplace(currentFootprint, newFP); @@ -656,7 +658,7 @@ void saveFootprint() { } void revertFootprint() { - log.info("revertFootprint"); + log.debug("revertFootprint"); if (originalFootprint != null) { currentFootprint = originalFootprint; changeTrack.remove(currentFootprint); @@ -671,9 +673,21 @@ void revertFootprint() { } public void reorderList() { - log.info("reorderList"); - JOptionPane.showMessageDialog(formPanel, "Whole lotta nuthin"); - // TODO: Token list order - update comboBox model + log.debug("reorderList"); + log.debug("list out - " + currentGridFootprintList); + ListSortingDialog sortingDialog = + new ListSortingDialog( + MapTool.getFrame(), + currentGridFootprintList.stream().map(o -> (Object) o).collect(Collectors.toList())); + + List sortedList = sortingDialog.showDialog(); + log.debug("list in - " + sortedList); + if (sortedList != null) { + currentGridFootprintList = + sortedList.stream().map(o -> (TokenFootprint) o).collect(Collectors.toList()); + } + comboBoxManager.replaceComboBox( + comboBoxManager.createComboBox(currentGridType, currentGridFootprintList)); } } @@ -691,11 +705,14 @@ public void reorderList() { */ private class ComboBoxManager { public JPanel comboBoxPanel; - JComboBox activeCombo = footprintCombo; + Map> comboMap = new HashMap<>(); static TokenFootprint lastSelectedFootprint = null; - JComboBox createComboBox(List footprints) { + JComboBox createComboBox(String gridType, List footprints) { + log.debug("createComboBox - " + gridType + " - " + footprints); JComboBox combo = new JComboBox<>(); + String useGrid = gridType.equalsIgnoreCase("Isometric") ? "Square" : gridType; + combo.setName(useGrid + "Combo"); MutableComboBoxModel comboModel = new DefaultComboBoxModel<>(); for (TokenFootprint footprint : footprints) { comboModel.addElement(footprint); @@ -705,31 +722,58 @@ JComboBox createComboBox(List footprints) { } combo.setModel(comboModel); combo.addItemListener(comboListener); + if (comboMap.containsKey(useGrid)) { + comboMap.replace(useGrid, combo); + comboBoxPanel.add(combo); + setVisibleComboBox(); + } else { + comboMap.put(useGrid, combo); + } return combo; } ComboBoxManager() { - log.info("ComboBoxManager"); + log.debug("ComboBoxManager"); footprintCombo = (JComboBox) formPanel.getComboBox("footprintCombo"); comboBoxPanel = (JPanel) formPanel.getComponent("comboBoxPanel"); initFootprintCombo(); setVisibleComboBox(); } + private void replaceComboBox(JComboBox replacement) { + log.debug("replaceComboBox - replacement - " + replacement.getName()); + for (Component comp : comboBoxPanel.getComponents()) { + if (comp.getName().equalsIgnoreCase(replacement.getName())) { + log.debug("replaceComboBox - replacing"); + comboBoxPanel.remove(comp); + comboBoxPanel.add(replacement); + break; + } + } + setVisibleComboBox(); + } + private void setVisibleComboBox() { - log.info("setVisibleComboBox"); + log.debug("setVisibleComboBox"); lastSelectedFootprint = null; - CardLayout cl = (CardLayout) (comboBoxPanel.getLayout()); String useGrid = currentGridType.equalsIgnoreCase("Isometric") ? "Square" : currentGridType; - cl.show(comboBoxPanel, useGrid + "Combo"); + CardLayout cl = (CardLayout) (comboBoxPanel.getLayout()); for (Component comp : comboBoxPanel.getComponents()) { if ((useGrid + "Combo").equalsIgnoreCase(comp.getName())) { - activeCombo = (JComboBox) comp; + comp.setVisible(true); + cl.show(comboBoxPanel, useGrid + "Combo"); + footprintCombo = (JComboBox) comp; + String s = ""; + for (int i = 0; i < footprintCombo.getItemCount(); i++) { + s += " " + footprintCombo.getModel().getElementAt(i); + } + log.debug(s); + } else { + comp.setVisible(false); } } - footprintCombo = activeCombo; - activeCombo.requestFocus(); + footprintCombo.requestFocus(); } void remove(TokenFootprint footprint) { @@ -761,7 +805,7 @@ void comboReplace(TokenFootprint fp1, TokenFootprint fp2) { @Override public void itemStateChanged(ItemEvent e) { - log.info("Combo box event: " + e); + log.debug("Combo box event: " + e); TokenFootprint item = (TokenFootprint) e.getItem(); if (e.getStateChange() == ItemEvent.DESELECTED) { // store the state of the outgoing footprint @@ -783,26 +827,25 @@ public void itemStateChanged(ItemEvent e) { }; private void initFootprintCombo() { - log.info("initFootprintCombo"); + log.debug("initFootprintCombo"); footprintCombo.setVisible(false); Map> useCampaignFootprints = FootprintManager.getCampaignFootprints(); for (String key : useCampaignFootprints.keySet()) { List footPrints = useCampaignFootprints.get(key); - JComboBox comboBox = createComboBox(footPrints); + JComboBox comboBox = createComboBox(key, footPrints); comboBox.setEnabled(true); comboBox.setFocusable(true); comboBox.setRequestFocusEnabled(true); comboBox.setActionCommand(footprintCombo.getActionCommand()); - comboBox.setName(key + "Combo"); comboBox.addItemListener(comboListener); comboBoxPanel.add(comboBox, comboBox.getName()); } } public void addToComboBox(TokenFootprint newFp) { - log.info("addToComboBox - " + newFp); + log.debug("addToComboBox - " + newFp); ((MutableComboBoxModel) footprintCombo.getModel()).addElement(newFp); footprintCombo.setSelectedItem(newFp); } diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.form b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.form new file mode 100644 index 0000000000..d08df9d92b --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.form @@ -0,0 +1,109 @@ + +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.java new file mode 100644 index 0000000000..1803a16a13 --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSorterView.java @@ -0,0 +1,25 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.footprintEditor; + +import javax.swing.*; + +public class ListSorterView { + private JPanel mainPanel; + + public JComponent getRootComponent() { + return mainPanel; + } +} diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSortingDialog.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSortingDialog.java new file mode 100644 index 0000000000..9fe7675533 --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/ListSortingDialog.java @@ -0,0 +1,153 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.footprintEditor; + +import com.jidesoft.list.ListTransferHandler; +import java.awt.*; +import java.awt.event.ActionListener; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import javax.swing.*; +import net.rptools.maptool.client.MapTool; +import net.rptools.maptool.client.swing.AbeillePanel; +import net.rptools.maptool.client.swing.SwingUtil; +import net.rptools.maptool.language.I18N; + +public class ListSortingDialog extends JDialog { + AbeillePanel formPanel = new AbeillePanel<>(new ListSorterView().getRootComponent()); + private List sortList = new LinkedList<>(); + + public ListSortingDialog(JFrame owner, List listToSort) { + super(owner, I18N.getText("initPanel.sort"), true); + sortList.addAll(listToSort); + initialise(); + pack(); + } + + JButton okButton; + JButton cancelButton; + JButton upButton; + JButton downButton; + JList sortingList; + JPanel listHolder; + DefaultListModel listModel; + + private void initialise() { + setLayout(new GridLayout()); + formPanel = new AbeillePanel<>(new ListSorterView().getRootComponent()); + getRootPane().setDefaultButton(okButton); + + setOkButton((JButton) formPanel.getButton("okButton")); + setCancelButton((JButton) formPanel.getButton("cancelButton")); + setUpButton((JButton) formPanel.getButton("upButton")); + setDownButton((JButton) formPanel.getButton("downButton")); + setListHolder((JPanel) formPanel.getComponent("listHolder")); + setSortingList(); + + add(formPanel); + this.pack(); + } + + public List showDialog() { + setVisible(true); + Object[] tmp = new Object[listModel.getSize()]; + listModel.copyInto(tmp); + return Arrays.stream(tmp).toList(); + } + + void cancel() { + sortList = null; + closeDialog(); + } + + public void setSortingList() { + listModel = new DefaultListModel<>(); + sortingList = new JList<>(listModel); + listModel.addAll(sortList); + sortingList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + sortingList.setTransferHandler(new ListTransferHandler(null)); + sortingList.setDragEnabled(true); + sortingList.setVisibleRowCount(sortList.size()); + listHolder.add(new JScrollPane(this.sortingList), BorderLayout.CENTER); + listHolder.invalidate(); + } + + public void setListHolder(JPanel listHolder) { + this.listHolder = listHolder; + } + + void moveItem(boolean up) { + int selectedIndex = sortingList.getSelectedIndex(); + if ((up && selectedIndex == 0) + || (!up && selectedIndex == sortList.size() - 1) + || selectedIndex == -1) { + return; + } + int targetIndex = up ? selectedIndex - 1 : selectedIndex + 1; + + Object selectedElement = listModel.getElementAt(selectedIndex); + listModel.removeElementAt(selectedIndex); + listModel.insertElementAt(selectedElement, targetIndex); + sortingList.setSelectedIndex(targetIndex); + } + + private final ActionListener buttonListener = + e -> { + switch (e.getActionCommand()) { + case "up" -> moveItem(true); + case "down" -> moveItem(false); + case "ok" -> closeDialog(); + case "cancel" -> cancel(); + } + }; + + private void setDownButton(JButton downButton) { + this.downButton = downButton; + this.downButton.setActionCommand("down"); + this.downButton.addActionListener(buttonListener); + } + + private void setUpButton(JButton upButton) { + this.upButton = upButton; + this.upButton.setActionCommand("up"); + this.upButton.addActionListener(buttonListener); + } + + private void setOkButton(JButton okButton) { + this.okButton = okButton; + this.okButton.setActionCommand("ok"); + this.okButton.addActionListener(buttonListener); + } + + private void setCancelButton(JButton cancelButton) { + this.cancelButton = cancelButton; + this.cancelButton.setActionCommand("cancel"); + this.cancelButton.addActionListener(buttonListener); + } + + void closeDialog() { + setVisible(false); + dispose(); + } + + @Override + public void setVisible(boolean b) { + if (b) { + SwingUtil.centerOver(this, MapTool.getFrame()); + } + super.setVisible(b); + } +} From fb64c1ebfedcddec430a342eede75293ad19c6d7 Mon Sep 17 00:00:00 2001 From: bubblobill <45483160+bubblobill@users.noreply.github.com> Date: Sat, 28 Sep 2024 16:14:51 +0800 Subject: [PATCH 19/21] Repaint zone renderer on close to remove artifacts when turning off grid visibility. A bunch of refactoring such as moving FootprintManager into the dialog code and its utility methods to FootPrintToolbox Added zoom control buttons back in to layered pane --- .../FootprintEditingPanel.java | 4 +- .../FootprintEditorDialog.java | 336 ++++++++++-------- .../maptool/model/FootprintManager.java | 192 ---------- .../maptool/util/FootPrintToolbox.java | 154 +++++++- 4 files changed, 330 insertions(+), 356 deletions(-) delete mode 100644 src/main/java/net/rptools/maptool/model/FootprintManager.java diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java index b466fbc005..c35a4800d9 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditingPanel.java @@ -57,7 +57,7 @@ public class FootprintEditingPanel extends JPanel { Zone zone; static volatile Scale zoneScale; static volatile float tokenScale = 1; - TokenFootprint footprint = FootprintManager.getGlobalDefaultFootprint(); + TokenFootprint footprint = FootPrintToolbox.getGlobalDefaultFootprint(); public FootprintEditingPanel() { log.debug("new FootprintEditingPanel"); @@ -118,7 +118,7 @@ public void setTokenFootprint( } setTokenFootprint(tokenFootprint); setScale(tokenFootprint.getScale()); - this.footprint.addOffsetTranslator(FootprintManager.createOffsetTranslator(gridTypeName)); + this.footprint.addOffsetTranslator(FootPrintToolbox.createOffsetTranslator(gridTypeName)); if (cells != null) { setCellSet(cells); } diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java index 3b9dc6d50b..da58c23845 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java @@ -29,7 +29,6 @@ import net.rptools.maptool.client.ui.theme.RessourceManager; import net.rptools.maptool.language.I18N; import net.rptools.maptool.model.CellPoint; -import net.rptools.maptool.model.FootprintManager; import net.rptools.maptool.model.GridFactory; import net.rptools.maptool.model.TokenFootprint; import net.rptools.maptool.util.FootPrintToolbox; @@ -85,7 +84,7 @@ public FootprintEditorDialog(JFrame owner) { final boolean oldShowGrid = AppState.isShowGrid(); private ComboBoxManager comboBoxManager; String currentGridType; - private FPManager fpManager; + private FootprintManager fpManager; private final ChangeTracking changeTrack = new ChangeTracking(); Changes changes; private static final CellPoint ZERO_POINT = new CellPoint(0, 0); @@ -103,7 +102,7 @@ private void initialise() { connectControls(); initRadioButtons(); - fpManager = new FPManager(); + fpManager = new FootprintManager(); comboBoxManager = new ComboBoxManager(); editor = new FootprintEditingPanel(); @@ -125,37 +124,73 @@ private void initialise() { *
    • link escape key to cancel action *
    • link +/- pgUp/pgDown to editor zoom level */ - // spotless:off private void addMiscellaneousListeners() { log.debug("addMiscellaneousListeners"); // reset grid visibility - this.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent e) { AppState.setShowGrid(oldShowGrid);}}); + this.addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + AppState.setShowGrid(oldShowGrid); + } + }); // Escape key - formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "cancel"); - formPanel.getActionMap().put("cancel", new AbstractAction() { - public void actionPerformed(ActionEvent e) {cancel();}}); + formPanel + .getActionMap() + .put( + "cancel", + new AbstractAction() { + public void actionPerformed(ActionEvent e) { + cancel(); + } + }); formPanel .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0), "zoomOut"); - formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0), "zoomOut"); - formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0), "zoomIn"); - formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, 0), "zoomIn"); - formPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) + formPanel + .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0), "zoomReset"); - formPanel.getActionMap().put("zoomOut", new AbstractAction() { - public void actionPerformed(ActionEvent e) { editor.zoomOut();}}); - formPanel.getActionMap().put("zoomIn", new AbstractAction() { - public void actionPerformed(ActionEvent e) { editor.zoomIn(); }}); - formPanel.getActionMap().put("zoomReset", new AbstractAction() { - public void actionPerformed(ActionEvent e) {editor.zoomReset();}}); + formPanel + .getActionMap() + .put( + "zoomOut", + new AbstractAction() { + public void actionPerformed(ActionEvent e) { + editor.zoomOut(); + } + }); + formPanel + .getActionMap() + .put( + "zoomIn", + new AbstractAction() { + public void actionPerformed(ActionEvent e) { + editor.zoomIn(); + } + }); + formPanel + .getActionMap() + .put( + "zoomReset", + new AbstractAction() { + public void actionPerformed(ActionEvent e) { + editor.zoomReset(); + } + }); } -// spotless:on + /** connect variables to their associated controls */ private void connectControls() { log.debug("connectControls"); @@ -231,13 +266,12 @@ public void keyPressed(KeyEvent e) { // form buttons okButton = (JButton) formPanel.getButton("okButton"); - cancelButton = (JButton) formPanel.getButton("okButton"); + cancelButton = (JButton) formPanel.getButton("cancelButton"); okButton.addActionListener(e -> okay()); cancelButton.addActionListener(e -> cancel()); } - // spotless: on /** * set up the radio buttons: * @@ -416,7 +450,11 @@ public void remove(TokenFootprint footprint) { *
    • etc. * */ - private class FPManager extends FootprintManager { + private class FootprintManager { + private static final Logger FPM_LOG = LoggerFactory.getLogger(FootprintManager.class); + private static final Map> CAMPAIGN_FOOTPRINTS = + FootPrintToolbox.getCampaignFootprints(); + protected static String currentGridType = AppPreferences.getDefaultGridType(); protected TokenFootprint currentFootprint; protected List currentGridFootprintList = new LinkedList<>(); protected Map> gridMapToFootprintList = new HashMap<>(); @@ -424,28 +462,40 @@ private class FPManager extends FootprintManager { protected Map originalsMap = new HashMap<>(); protected TokenFootprint originalFootprint; - public FPManager() { - super(false); - log.debug("new FPManager"); + public FootprintManager() { + FPM_LOG.debug("new FPManager"); addAllFootprintsFromCampaign(); if (currentFootprint == null) { - currentFootprint = FootprintManager.getGlobalDefaultFootprint(); + currentFootprint = FootPrintToolbox.getGlobalDefaultFootprint(); } originalFootprint = currentFootprint; } + List getCurrentGridFootprintList() { + return currentGridFootprintList; + } + + public static Map> getCampaignFootprints() { + return CAMPAIGN_FOOTPRINTS; + } + + TokenFootprint getGridDefaultFootprint(String gridType) { + return gridDefaultFootprint.get(FootPrintToolbox.lookupGridType(gridType)); + } + + /** Copies all footprints to local map sets originals and current instances to defaults */ private void addAllFootprintsFromCampaign() { - for (String gridType : campaignFootprints.keySet()) { + for (String gridType : CAMPAIGN_FOOTPRINTS.keySet()) { List gridList = new LinkedList<>(); - for (TokenFootprint fp : campaignFootprints.get(gridType)) { + for (TokenFootprint fp : CAMPAIGN_FOOTPRINTS.get(gridType)) { changeTrack.put(fp, new Changes(fp)); originalsMap.put(fp, fp); gridList.add(fp); if (fp.isDefault()) { gridDefaultFootprint.put(gridType, fp); - } - if (currentGridType.equalsIgnoreCase(gridType)) { - currentFootprint = fp; + if (currentGridType.equalsIgnoreCase(gridType)) { + currentFootprint = fp; + } } } gridMapToFootprintList.put(gridType, gridList); @@ -463,7 +513,7 @@ private void addAllFootprintsFromCampaign() { */ private void selectionChanged( TokenFootprint toFootprint, TokenFootprint fromFootprint, Changes changeUpdate) { - log.debug( + FPM_LOG.debug( "selectionChanged - " + FootPrintToolbox.stringifyFootprint(toFootprint) + " : " @@ -479,69 +529,24 @@ private void selectionChanged( if (changes != null) { nameField.setText( changes.getName().isBlank() || changes.getName().isEmpty() - ? ((TokenFootprint) footprintCombo.getSelectedItem()).getLocalizedName() + ? ((TokenFootprint) Objects.requireNonNull(footprintCombo.getSelectedItem())) + .getLocalizedName() : changes.getName()); scaleSpinner.setValue(changes.getScale()); editor.setTokenFootprint(currentGridType, toFootprint, changes.getCells()); } else { - nameField.setText(((TokenFootprint) footprintCombo.getSelectedItem()).getLocalizedName()); + nameField.setText( + ((TokenFootprint) Objects.requireNonNull(footprintCombo.getSelectedItem())).getName()); editor.setTokenFootprint(currentGridType, toFootprint, null); } - log.debug( + FPM_LOG.debug( "Selection isDefault: " + getGridDefaultFootprint(currentGridType).equals(toFootprint)); defaultCheckbox.setSelected(getGridDefaultFootprint(currentGridType).equals(toFootprint)); setCurrentFootprint(toFootprint); } - TokenFootprint getGridDefaultFootprint(String gridType) { - return gridDefaultFootprint.get(gridType.equals("Isometric") ? "Square" : gridType); - } - - List getCurrentGridFootprintList() { - return currentGridFootprintList; - } - - /** - * Compares a footprint against the stored changes - * - * @param fp TokenFootprint - * @return boolean - */ - public boolean hasChanged(TokenFootprint fp) { - changes = changeTrack.getChanges(fp); - boolean result = false; - if (originalsMap.containsKey(fp)) { - result = - originalsMap.get(fp).isDefault() != getGridDefaultFootprint(currentGridType).equals(fp); - } - return result - || fp.getScale() != changes.getScale() - || !fp.getName().equals(changes.getName()) - || !fp.getOccupiedCells(ZERO_POINT).equals(changes.getCells()) - || !fp.getLocalizedName().equals(fp.getLocalizedName()); - } - - void writeUpdate(TokenFootprint fp, String gridType) { - log.debug("writeUpdate - " + gridType + fp); - writeFootprintToCampaign(fp, gridType); - } - - void writeUpdates() { - writeAllFootprintsToCampaign(gridMapToFootprintList); - } - - private void setScale(double s) { - log.debug("setScale: " + s); - if (currentFootprint.getScale() != s) { - changeTrack.addChange(currentFootprint, "scale", s); - } - editor.setScale(s); - // TODO: check validity and update editor - } - - @Override public void changeCurrentGridType(String gridType) { - log.debug("setCurrentGridFootprints"); + FPM_LOG.debug("changeCurrentGridType"); // store the old gridMapToFootprintList.put(currentGridType, getCurrentGridFootprintList()); // replace with the new @@ -552,8 +557,17 @@ public void changeCurrentGridType(String gridType) { selectionChanged((TokenFootprint) footprintCombo.getSelectedItem(), null, null); } + private void setScale(double s) { + FPM_LOG.debug("setScale: " + s); + if (currentFootprint.getScale() != s) { + changeTrack.addChange(currentFootprint, "scale", s); + } + editor.setScale(s); + // TODO: check validity and update editor + } + private void setCurrentFootprint(TokenFootprint footprint) { - log.debug("setCurrentFootprint - " + footprint.toString()); + FPM_LOG.debug("setCurrentFootprint - " + footprint.toString()); currentFootprint = footprint; boolean exists = originalsMap.containsKey(footprint); revertButton.setEnabled(exists); @@ -564,28 +578,25 @@ private void setCurrentFootprint(TokenFootprint footprint) { } } - void FPMReplace(TokenFootprint fp1, TokenFootprint fp2) { - if (getCurrentGridFootprintList().contains(fp1)) { - int idx = currentGridFootprintList.indexOf(fp1); - currentGridFootprintList.remove(idx); - currentGridFootprintList.add(idx, fp2); - changeTrack.remove(fp1); - changeTrack.put(fp2, new Changes(fp2)); - comboBoxManager.comboReplace(fp1, fp2); - } - } - public void setCurrentFootprintName() { - log.debug("setCurrentFootprintName"); + FPM_LOG.debug("setCurrentFootprintName"); String name = nameField.getText(); changeTrack.addChange(currentFootprint, "name", name); currentFootprint.setLocalizedName(name); } + void setAsDefault(boolean value) { + if (value) { + gridDefaultFootprint.replace(currentGridType, currentFootprint); + } else { + gridDefaultFootprint.replace(currentGridType, currentGridFootprintList.getFirst()); + } + } + public TokenFootprint buildNewFootprint(TokenFootprint footprint) { changes = changeTrack.getChanges(footprint); - String name = newName(changes.getName()); - return createTokenFootprint( + String name = newName(); + return FootPrintToolbox.createTokenFootprint( currentGridType, name, getGridDefaultFootprint(currentGridType).equals(footprint), @@ -595,8 +606,19 @@ public TokenFootprint buildNewFootprint(TokenFootprint footprint) { changes.getCells()); } + void FPMReplace(TokenFootprint fp1, TokenFootprint fp2) { + if (getCurrentGridFootprintList().contains(fp1)) { + int idx = currentGridFootprintList.indexOf(fp1); + currentGridFootprintList.remove(idx); + currentGridFootprintList.add(idx, fp2); + changeTrack.remove(fp1); + changeTrack.put(fp2, new Changes(fp2)); + comboBoxManager.comboReplace(fp1, fp2); + } + } + public TokenFootprint buildNewFootprint() { - log.debug("buildNewFootprint"); + FPM_LOG.debug("buildNewFootprint"); changeTrack.addChange(currentFootprint, "name", nameField.getText()); changeTrack.addChange( currentFootprint, @@ -606,16 +628,23 @@ public TokenFootprint buildNewFootprint() { return buildNewFootprint(currentFootprint); } - void setAsDefault(boolean value) { - if (value) { - gridDefaultFootprint.replace(currentGridType, currentFootprint); - } else { - gridDefaultFootprint.replace(currentGridType, currentGridFootprintList.getFirst()); - } + /** returns "new_footprint" with as many underscores as necessary to make it unique */ + String newName() { + List useList = getCurrentGridFootprintList(); + String text = "new_footprint"; + boolean test; + do { + test = useList.stream().map(TokenFootprint::getName).toList().contains(text); + if (!test) { + test = useList.stream().map(TokenFootprint::getLocalizedName).toList().contains(text); + } + text = test ? text + "_" : text; + } while (test); + return text; } void addFootprint() { - log.debug("addFootprint"); + FPM_LOG.debug("addFootprint"); TokenFootprint newFp = buildNewFootprint(); changeTrack.put(newFp, new Changes(newFp)); currentGridFootprintList.add(newFp); @@ -625,40 +654,17 @@ void addFootprint() { } void deleteFootprint() { - log.debug("deleteFootprint"); + FPM_LOG.debug("deleteFootprint"); if (defaultCheckbox.isSelected()) { setAsDefault(false); } currentGridFootprintList.remove(currentFootprint); changeTrack.remove(currentFootprint); - comboBoxManager.remove(currentFootprint); - } - - String newName(String text) { - List useList = getCurrentGridFootprintList(); - text = text.isEmpty() ? "new_footprint" : text; - boolean test; - do { - test = useList.stream().map(TokenFootprint::getName).toList().contains(text); - if (!test) { - test = useList.stream().map(TokenFootprint::getLocalizedName).toList().contains(text); - } - text = test ? text + "_" : text; - } while (test); - return text; - } - - void saveFootprint() { - log.debug("saveFootprint"); - if (hasChanged(currentFootprint)) { - TokenFootprint newFP = buildNewFootprint(currentFootprint); - FPMReplace(currentFootprint, newFP); - writeUpdate(newFP, currentGridType); - } + comboBoxManager.removeFootprint(currentFootprint); } void revertFootprint() { - log.debug("revertFootprint"); + FPM_LOG.debug("revertFootprint"); if (originalFootprint != null) { currentFootprint = originalFootprint; changeTrack.remove(currentFootprint); @@ -672,16 +678,45 @@ void revertFootprint() { } } + /** + * Compares a footprint against the stored changes + * + * @param fp TokenFootprint + * @return boolean + */ + public boolean hasChanged(TokenFootprint fp) { + changes = changeTrack.getChanges(fp); + boolean result = false; + if (originalsMap.containsKey(fp)) { + result = + originalsMap.get(fp).isDefault() != getGridDefaultFootprint(currentGridType).equals(fp); + } + return result + || fp.getScale() != changes.getScale() + || !fp.getName().equals(changes.getName()) + || !fp.getOccupiedCells(ZERO_POINT).equals(changes.getCells()) + || !fp.getLocalizedName().equals(fp.getLocalizedName()); + } + + void saveFootprint() { + FPM_LOG.debug("saveFootprint"); + if (hasChanged(currentFootprint)) { + TokenFootprint newFP = buildNewFootprint(currentFootprint); + FPMReplace(currentFootprint, newFP); + writeUpdate(newFP, currentGridType); + } + } + public void reorderList() { - log.debug("reorderList"); - log.debug("list out - " + currentGridFootprintList); + FPM_LOG.debug("reorderList"); + FPM_LOG.debug("list out - " + currentGridFootprintList); ListSortingDialog sortingDialog = new ListSortingDialog( MapTool.getFrame(), currentGridFootprintList.stream().map(o -> (Object) o).collect(Collectors.toList())); List sortedList = sortingDialog.showDialog(); - log.debug("list in - " + sortedList); + FPM_LOG.debug("list in - " + sortedList); if (sortedList != null) { currentGridFootprintList = sortedList.stream().map(o -> (TokenFootprint) o).collect(Collectors.toList()); @@ -689,6 +724,15 @@ public void reorderList() { comboBoxManager.replaceComboBox( comboBoxManager.createComboBox(currentGridType, currentGridFootprintList)); } + + void writeUpdate(TokenFootprint fp, String gridType) { + FPM_LOG.info("writeUpdate - " + gridType + fp); + FootPrintToolbox.writeFootprintToCampaign(fp, gridType); + } + + void writeUpdates() { + FootPrintToolbox.writeAllFootprintsToCampaign(gridMapToFootprintList); + } } /** @@ -711,7 +755,7 @@ private class ComboBoxManager { JComboBox createComboBox(String gridType, List footprints) { log.debug("createComboBox - " + gridType + " - " + footprints); JComboBox combo = new JComboBox<>(); - String useGrid = gridType.equalsIgnoreCase("Isometric") ? "Square" : gridType; + String useGrid = FootPrintToolbox.lookupGridType(gridType); combo.setName(useGrid + "Combo"); MutableComboBoxModel comboModel = new DefaultComboBoxModel<>(); for (TokenFootprint footprint : footprints) { @@ -756,19 +800,14 @@ private void replaceComboBox(JComboBox replacement) { private void setVisibleComboBox() { log.debug("setVisibleComboBox"); lastSelectedFootprint = null; - String useGrid = currentGridType.equalsIgnoreCase("Isometric") ? "Square" : currentGridType; - - CardLayout cl = (CardLayout) (comboBoxPanel.getLayout()); + String useGrid = FootPrintToolbox.lookupGridType(currentGridType); + // comboBoxPanel uses a card layout - it was set to just show the appropriate combo box + // but I couldn't get it to work with replaced combo boxes so I just set the visibility + // instead. for (Component comp : comboBoxPanel.getComponents()) { if ((useGrid + "Combo").equalsIgnoreCase(comp.getName())) { comp.setVisible(true); - cl.show(comboBoxPanel, useGrid + "Combo"); footprintCombo = (JComboBox) comp; - String s = ""; - for (int i = 0; i < footprintCombo.getItemCount(); i++) { - s += " " + footprintCombo.getModel().getElementAt(i); - } - log.debug(s); } else { comp.setVisible(false); } @@ -776,7 +815,7 @@ private void setVisibleComboBox() { footprintCombo.requestFocus(); } - void remove(TokenFootprint footprint) { + void removeFootprint(TokenFootprint footprint) { if (footprintCombo.getModel().getSize() > 1) { MutableComboBoxModel model = (MutableComboBoxModel) footprintCombo.getModel(); @@ -851,7 +890,6 @@ public void addToComboBox(TokenFootprint newFp) { } } - // spotless:off private void createZoomButtons() { layeredPane = this.getLayeredPane(); JPanel buttonHolder = new JPanel(); @@ -896,12 +934,12 @@ public void setVisible(boolean b) { SwingUtil.centerOver(this, MapTool.getFrame()); } super.setVisible(b); - editor.requestFocusInWindow(); } @Override public void dispose() { AppState.setShowGrid(oldShowGrid); + MapTool.getFrame().getCurrentZoneRenderer().repaint(); super.dispose(); } } diff --git a/src/main/java/net/rptools/maptool/model/FootprintManager.java b/src/main/java/net/rptools/maptool/model/FootprintManager.java deleted file mode 100644 index 878f91e16e..0000000000 --- a/src/main/java/net/rptools/maptool/model/FootprintManager.java +++ /dev/null @@ -1,192 +0,0 @@ -/* - * This software Copyright by the RPTools.net development team, and - * licensed under the Affero GPL Version 3 or, at your option, any later - * version. - * - * MapTool Source Code is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public - * License * along with this source Code. If not, please visit - * and specifically the Affero license - * text at . - */ -package net.rptools.maptool.model; - -import static java.util.Map.entry; - -import java.awt.*; -import java.util.*; -import java.util.List; -import net.rptools.maptool.client.AppPreferences; -import net.rptools.maptool.client.MapTool; -import net.rptools.maptool.tool.TokenFootprintCreator; -import net.rptools.maptool.util.FootPrintToolbox; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class FootprintManager { - public static final Map GRID_FOOTPRINT_TYPE = - Map.ofEntries( - entry(GridFactory.HEX_HORI, GridFactory.HEX_HORI), - entry(GridFactory.HEX_VERT, GridFactory.HEX_VERT), - entry(GridFactory.ISOMETRIC, GridFactory.SQUARE), - entry(GridFactory.ISOMETRIC_HEX, GridFactory.NONE), - entry(GridFactory.NONE, GridFactory.NONE), - entry(GridFactory.SQUARE, GridFactory.SQUARE)); - protected static final String DEFAULT_GRID_TYPE = AppPreferences.getDefaultGridType(); - private static final Logger log = LoggerFactory.getLogger(FootprintManager.class); - protected static boolean useAppDefaults = false; - protected static String currentGridType = DEFAULT_GRID_TYPE; - protected static Map> campaignFootprints = new HashMap<>(); - protected static List currentGridFootprints = new ArrayList<>(); - protected TokenFootprint defaultFootprint; - - public FootprintManager(boolean useAppDefaults) { - load(useAppDefaults); - } - - public static TokenFootprint getGlobalDefaultFootprint() { - return MapTool.getCampaign() - .getCampaignProperties() - .getGridFootprints() - .get(AppPreferences.getDefaultGridType()) - .stream() - .filter(TokenFootprint::isDefault) - .findAny() - .orElse( - MapTool.getCampaign() - .getCampaignProperties() - .getGridFootprints() - .get(AppPreferences.getDefaultGridType()) - .getFirst()); - } - - public static Map getGridFootprintType() { - return GRID_FOOTPRINT_TYPE; - } - - public static Map> getCampaignFootprints() { - return campaignFootprints; - } - - public static List getGridFootprints(String gridTypeName) { - return getCampaignFootprints().get(GRID_FOOTPRINT_TYPE.get(gridTypeName)); - } - - public static TokenFootprint.OffsetTranslator createOffsetTranslator(String gridTypeName) { - gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); - if (gridTypeName.equals(GridFactory.HEX_HORI)) { - return (originPoint, offsetPoint) -> { - if ((originPoint.y & 1) == 1 && (offsetPoint.y & 1) == 0) { - offsetPoint.x++; - } - }; - } else if (gridTypeName.equals(GridFactory.HEX_VERT)) { - return (originPoint, offsetPoint) -> { - if ((originPoint.x & 1) == 1 && (offsetPoint.x & 1) == 0) { - offsetPoint.y++; - } - }; - } else { - return (originPoint, offsetPoint) -> offsetPoint = originPoint; - } - } - - public static TokenFootprint createTokenFootprint( - String gridTypeName, - String name, - boolean isDefault, - Double scale, - boolean localiseName, - String localisedName, - Set cellPoints) { - Point[] pointArray = - FootPrintToolbox.cellPointListToPointArray(FootPrintToolbox.cellPointSetToList(cellPoints)); - TokenFootprint newPrint = new TokenFootprint(name, isDefault, scale, localiseName, pointArray); - if (!localisedName.isEmpty()) { - newPrint.setLocalizedName(localisedName); - } - newPrint.addOffsetTranslator(createOffsetTranslator(gridTypeName)); - return newPrint; - } - - public static void writeAllFootprintsToCampaign(Map> footprints) { - CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); - for (String key : footprints.keySet()) { - props.setGridFootprints(key, footprints.get(key)); - } - MapTool.getCampaign().mergeCampaignProperties(props); - } - - public static void writeGridFootprintsToCampaign( - List footprints, String gridTypeName) { - gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); - CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); - props.setGridFootprints(gridTypeName, footprints); - MapTool.getCampaign().mergeCampaignProperties(props); - } - - public static void writeFootprintToCampaign(TokenFootprint footprint, String gridTypeName) { - log.debug("writeFootprintToCampaign - " + footprint + " - " + gridTypeName); - gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); - List list = getGridFootprints(gridTypeName); - list.add(footprint); - CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); - props.setGridFootprints(gridTypeName, list); - MapTool.getCampaign().mergeCampaignProperties(props); - } - - void load(boolean useDefaults) { - setUseAppDefaults(useDefaults); - load(); - } - - void load() { - if (useAppDefaults) { - load(DEFAULT_GRID_TYPE); - } else { - setCurrentGrid(MapTool.getFrame().getCurrentZoneRenderer().getZone().getGrid()); - } - } - - void load(String gridType) { - log.debug("gridType" + gridType); - log.debug("useAppDefaults:" + useAppDefaults); - currentGridType = gridType; - if (useAppDefaults) { - campaignFootprints = - Map.ofEntries( - entry(GridFactory.HEX_HORI, TokenFootprintCreator.makeHorizHex()), - entry(GridFactory.HEX_VERT, TokenFootprintCreator.makeVertHex()), - entry(GridFactory.NONE, TokenFootprintCreator.makeGridless()), - entry(GridFactory.SQUARE, TokenFootprintCreator.makeSquare())); - } else { - campaignFootprints = MapTool.getCampaign().getCampaignProperties().getGridFootprints(); - } - currentGridFootprints = campaignFootprints.get(GRID_FOOTPRINT_TYPE.get(currentGridType)); - defaultFootprint = - currentGridFootprints.stream().filter(TokenFootprint::isDefault).toList().getFirst(); - } - - boolean isUseAppDefaults() { - return useAppDefaults; - } - - void setUseAppDefaults(boolean value) { - useAppDefaults = value; - } - - void setCurrentGrid(Grid grid) { - setCurrentGridType(GridFactory.getGridType(grid)); - } - - void setCurrentGridType(String gridType) { - load(gridType); - } - - public void changeCurrentGridType(String gridType) { - currentGridFootprints = campaignFootprints.get(GRID_FOOTPRINT_TYPE.get(gridType)); - } -} diff --git a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java index 6f8d00bbfd..aa54717858 100644 --- a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java +++ b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java @@ -14,31 +14,132 @@ */ package net.rptools.maptool.util; +import static java.util.Map.entry; + import java.awt.Point; import java.awt.geom.Point2D; import java.util.*; import java.util.stream.Collectors; +import net.rptools.maptool.client.AppPreferences; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.model.*; +import net.rptools.maptool.tool.TokenFootprintCreator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class FootPrintToolbox { + protected static final String DEFAULT_GRID_TYPE = AppPreferences.getDefaultGridType(); + private static final Logger log = LoggerFactory.getLogger(FootPrintToolbox.class); public static final CellPoint ZERO_CELLPOINT = new CellPoint(0, 0); + /** Map between grid type constants pointing to the one holding its footprints */ + public static final Map GRID_FOOTPRINT_TYPE = + Map.ofEntries( + entry(GridFactory.HEX_HORI, GridFactory.HEX_HORI), + entry(GridFactory.HEX_VERT, GridFactory.HEX_VERT), + entry(GridFactory.ISOMETRIC, GridFactory.SQUARE), + entry(GridFactory.ISOMETRIC_HEX, GridFactory.NONE), + entry(GridFactory.NONE, GridFactory.NONE), + entry(GridFactory.SQUARE, GridFactory.SQUARE)); + + // spotless:off + public static Map getGridFootprintType() { return GRID_FOOTPRINT_TYPE; } public static List getGridFootprints(String gridType) { - return FootprintManager.getCampaignFootprints() - .getOrDefault(FootprintManager.getGridFootprintType().get(gridType), null); + return getCampaignFootprints().getOrDefault(lookupGridType(gridType), null); + } + public static String lookupGridType(String gridType){ return getGridFootprintType().get(gridType); } + public static String getGridType(Grid grid) { + return GridFactory.getGridType(grid); } - public static Grid getCurrentMapGrid() { return MapTool.getFrame().getCurrentZoneRenderer().getZone().getGrid(); } - public static String getCurrentMapGridType() { return getGridType(getCurrentMapGrid()); } + public static Map> getCampaignFootprints() { + return MapTool.getCampaign().getCampaignProperties().getGridFootprints(); + } + public static List getCurrentGridFootprints() { + return getGridFootprints(getGridType(getCurrentMapGrid())); + } - public static String getGridType(Grid grid) { - return GridFactory.getGridType(grid); + /** + * Generate default footprints from the TokenFootprintCreator + * @return map of grids to footprints + */ + public static Map> getDefaultCampaignFootprints() { + return Map.ofEntries( + entry(GridFactory.HEX_HORI, TokenFootprintCreator.makeHorizHex()), + entry(GridFactory.HEX_VERT, TokenFootprintCreator.makeVertHex()), + entry(GridFactory.NONE, TokenFootprintCreator.makeGridless()), + entry(GridFactory.SQUARE, TokenFootprintCreator.makeSquare())); + } + + /** + * Find the default footprint in the list + * @param list list of token footprints + * @return the default footprint + */ + public static TokenFootprint getDefaultFootprint(List list) { + return list.stream().filter(TokenFootprint::isDefault).findFirst().orElseGet(list::getFirst); + } + + /** Get the default footprint for the default grid type in preferences */ + public static TokenFootprint getGlobalDefaultFootprint() { + return MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints() + .get(AppPreferences.getDefaultGridType()) + .stream() + .filter(TokenFootprint::isDefault) + .findAny() + .orElse( + MapTool.getCampaign() + .getCampaignProperties() + .getGridFootprints() + .get(AppPreferences.getDefaultGridType()) + .getFirst()); + } + + /** + * Write list of footprints to campaign for specified grid type + * + * @param footprints list of footprints + * @param gridTypeName grid type to store them under + */ + public static void writeGridFootprintsToCampaign( + List footprints, String gridTypeName) { + gridTypeName = lookupGridType(gridTypeName); + CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); + props.setGridFootprints(gridTypeName, footprints); + MapTool.getCampaign().mergeCampaignProperties(props); + } + + /** + * Write map of footprints to campaign + * + * @param footprints Lists of footprints mapped to grid type name + */ + public static void writeAllFootprintsToCampaign(Map> footprints) { + CampaignProperties props = MapTool.getCampaign().getCampaignProperties(); + for (String key : footprints.keySet()) { + props.setGridFootprints(key, footprints.get(key)); + } + MapTool.getCampaign().mergeCampaignProperties(props); + } + + /** + * Write single footprint to campaign list for grid type + * @param footprint token footprint + * @param gridTypeName list name to store under + */ + public static void writeFootprintToCampaign(TokenFootprint footprint, String gridTypeName) { + log.info("writeFootprintToCampaign - " + footprint + " - " + gridTypeName); + List list = getGridFootprints(gridTypeName); + List replacement = new ArrayList<>(list); + replacement.add(footprint); + writeGridFootprintsToCampaign(replacement, gridTypeName); } public static ZonePoint zonePointFromCellCentre(Point2D pt) { @@ -61,20 +162,46 @@ public static List cellPointSetToList(Set cellPoints) { return cellPoints.stream().toList(); } - public static List getGridFootprints() { - return getGridFootprints(getGridType(getCurrentMapGrid())); - } - public static List sortCellList(List cellList) { cellList.sort(Comparator.comparingInt(o -> o.x)); cellList.sort(Comparator.comparingInt(o -> o.y)); return cellList; } - public static TokenFootprint getDefaultFootprint(List list) { - return list.stream().filter(TokenFootprint::isDefault).findFirst().orElseGet(list::getFirst); + public static TokenFootprint createTokenFootprint( + String gridTypeName, + String name, + boolean isDefault, + Double scale, + boolean localiseName, + String localisedName, + Set cellPoints) { + Point[] pointArray = cellPointListToPointArray(cellPointSetToList(cellPoints)); + TokenFootprint newPrint = new TokenFootprint(name, isDefault, scale, localiseName, pointArray); + if (!(localisedName.isEmpty() || localisedName.isBlank())) { + newPrint.setLocalizedName(localisedName); + } + newPrint.addOffsetTranslator(createOffsetTranslator(gridTypeName)); + return newPrint; + } + public static TokenFootprint.OffsetTranslator createOffsetTranslator(String gridTypeName) { + gridTypeName = GRID_FOOTPRINT_TYPE.get(gridTypeName); + if (gridTypeName.equals(GridFactory.HEX_HORI)) { + return (originPoint, offsetPoint) -> { + if ((originPoint.y & 1) == 1 && (offsetPoint.y & 1) == 0) { + offsetPoint.x++; + } + }; + } else if (gridTypeName.equals(GridFactory.HEX_VERT)) { + return (originPoint, offsetPoint) -> { + if ((originPoint.x & 1) == 1 && (offsetPoint.x & 1) == 0) { + offsetPoint.y++; + } + }; + } else { + return (originPoint, offsetPoint) -> offsetPoint = originPoint; + } } - public static String stringifyFootprint(TokenFootprint footprint) { if (footprint == null) { return "null"; @@ -92,4 +219,5 @@ public static String stringifyFootprint(TokenFootprint footprint) { + "\nGUID:\t\t\t" + footprint.getId(); } + // spotless:on } From ad823e4976167cbb5d910492a90d7927421e5a3c Mon Sep 17 00:00:00 2001 From: bubblobill <45483160+bubblobill@users.noreply.github.com> Date: Sun, 29 Sep 2024 21:51:59 +0800 Subject: [PATCH 20/21] Added some code docs --- .../net/rptools/maptool/util/FootPrintToolbox.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java index aa54717858..7c227e4023 100644 --- a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java +++ b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java @@ -27,6 +27,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Collection of static methods useful for dealing with token footprints + */ public class FootPrintToolbox { protected static final String DEFAULT_GRID_TYPE = AppPreferences.getDefaultGridType(); private static final Logger log = LoggerFactory.getLogger(FootPrintToolbox.class); @@ -168,6 +171,17 @@ public static List sortCellList(List cellList) { return cellList; } + /** + * Convenience constructor for TokenFootprint that allows creation with all writable fields and the grid type. + * @param gridTypeName Grid type cell points is relevant to + * @param name Name + * @param isDefault Default footprint to use + * @param scale cell size + * @param localiseName Should name be localised + * @param localisedName The localised name (string key?) + * @param cellPoints Set of points relative to 0,0 that make up the footprint + * @return new TokenFootprint + */ public static TokenFootprint createTokenFootprint( String gridTypeName, String name, From 078918808a3014d5e64608bddd4509b42e8e5324 Mon Sep 17 00:00:00 2001 From: ColdAnkles <13864745+ColdAnkles@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:52:05 +1030 Subject: [PATCH 21/21] fixes for develop changes --- .../ui/footprintEditor/FootprintEditorDialog.java | 8 ++++---- .../net/rptools/maptool/util/FootPrintToolbox.java | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java index da58c23845..ea528e50a2 100644 --- a/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/footprintEditor/FootprintEditorDialog.java @@ -454,7 +454,7 @@ private class FootprintManager { private static final Logger FPM_LOG = LoggerFactory.getLogger(FootprintManager.class); private static final Map> CAMPAIGN_FOOTPRINTS = FootPrintToolbox.getCampaignFootprints(); - protected static String currentGridType = AppPreferences.getDefaultGridType(); + protected static String currentGridType = AppPreferences.defaultGridType.get(); protected TokenFootprint currentFootprint; protected List currentGridFootprintList = new LinkedList<>(); protected Map> gridMapToFootprintList = new HashMap<>(); @@ -896,13 +896,13 @@ private void createZoomButtons() { // buttonHolder.setPreferredSize(layeredPane.getPreferredSize()); buttonHolder.setBackground(new Color(80, 180, 80)); buttonHolder.setBorder(BorderFactory.createLineBorder(Color.BLUE, 3, true)); - String oldTheme = AppPreferences.getIconTheme(); - AppPreferences.setIconTheme(RessourceManager.ROD_TAKEHARA); + String oldTheme = AppPreferences.iconTheme.get(); + AppPreferences.iconTheme.set(RessourceManager.ROD_TAKEHARA); JButton zInButton = new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_HIDE_OFF)); JButton zOutButton = new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_HIDE_ON)); JButton zResetButton = new JButton(RessourceManager.getBigIcon(Icons.TOOLBAR_TOPOLOGY_OVAL_HOLLOW)); - AppPreferences.setIconTheme(oldTheme); + AppPreferences.iconTheme.set(oldTheme); Dimension buttonSize = new Dimension(36, 36); Color bg = new Color(0, 0, 0, 0); zInButton.setBackground(bg); diff --git a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java index 7c227e4023..c93afef50a 100644 --- a/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java +++ b/src/main/java/net/rptools/maptool/util/FootPrintToolbox.java @@ -27,11 +27,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -/** - * Collection of static methods useful for dealing with token footprints - */ +/** Collection of static methods useful for dealing with token footprints */ public class FootPrintToolbox { - protected static final String DEFAULT_GRID_TYPE = AppPreferences.getDefaultGridType(); + protected static final String DEFAULT_GRID_TYPE = AppPreferences.defaultGridType.get(); private static final Logger log = LoggerFactory.getLogger(FootPrintToolbox.class); public static final CellPoint ZERO_CELLPOINT = new CellPoint(0, 0); @@ -93,7 +91,7 @@ public static TokenFootprint getGlobalDefaultFootprint() { return MapTool.getCampaign() .getCampaignProperties() .getGridFootprints() - .get(AppPreferences.getDefaultGridType()) + .get(AppPreferences.defaultGridType.get()) .stream() .filter(TokenFootprint::isDefault) .findAny() @@ -101,7 +99,7 @@ public static TokenFootprint getGlobalDefaultFootprint() { MapTool.getCampaign() .getCampaignProperties() .getGridFootprints() - .get(AppPreferences.getDefaultGridType()) + .get(AppPreferences.defaultGridType.get()) .getFirst()); }