From 24e5078fe34401a0b3a9375b28b19c349e2cf1ad Mon Sep 17 00:00:00 2001 From: Jamz Date: Mon, 27 Jan 2020 18:26:26 -0600 Subject: [PATCH 1/2] Add new drawing layer that only blocks token movement. * Same tools used as VBL with extra button that defines which layer(s) the polygons are drawn on. Signed-off-by: JamzTheMan --- .../maptool/client/AppPreferences.java | 25 ++++- .../net/rptools/maptool/client/AppStyle.java | 4 + .../tool/drawing/AbstractDrawingTool.java | 87 +++++++++++++++++- .../tool/drawing/CrossTopologyTool.java | 39 +------- .../tool/drawing/DiamondTopologyTool.java | 37 +------- .../drawing/HollowDiamondTopologyTool.java | 40 +------- .../tool/drawing/HollowOvalTopologyTool.java | 44 +-------- .../drawing/HollowRectangleTopologyTool.java | 39 +------- .../client/tool/drawing/OvalTopologyTool.java | 37 +------- .../tool/drawing/PolygonTopologyTool.java | 19 +--- .../tool/drawing/RectangleTopologyTool.java | 37 +------- .../maptool/client/ui/ToolbarPanel.java | 77 ++++++++++++++-- .../walker/astar/AbstractAStarWalker.java | 3 + .../java/net/rptools/maptool/model/Zone.java | 47 +++++++++- .../maptool/client/image/tool/mbl-only.png | Bin 0 -> 2751 bytes .../maptool/client/image/tool/mbl-vbl-on.png | Bin 0 -> 2835 bytes .../maptool/client/image/tool/vbl-only.png | Bin 0 -> 2748 bytes 17 files changed, 234 insertions(+), 301 deletions(-) create mode 100644 src/main/resources/net/rptools/maptool/client/image/tool/mbl-only.png create mode 100644 src/main/resources/net/rptools/maptool/client/image/tool/mbl-vbl-on.png create mode 100644 src/main/resources/net/rptools/maptool/client/image/tool/vbl-only.png diff --git a/src/main/java/net/rptools/maptool/client/AppPreferences.java b/src/main/java/net/rptools/maptool/client/AppPreferences.java index fe35ce0a55..f220da7a8b 100644 --- a/src/main/java/net/rptools/maptool/client/AppPreferences.java +++ b/src/main/java/net/rptools/maptool/client/AppPreferences.java @@ -27,10 +27,12 @@ import net.rptools.maptool.model.GridFactory; import net.rptools.maptool.model.Token; import net.rptools.maptool.model.Zone; +import net.rptools.maptool.model.Zone.TopologyMode; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class AppPreferences { + private static final Logger log = LogManager.getLogger(AppPreferences.class); private static Preferences prefs = Preferences.userRoot().node(AppConstants.APP_NAME + "/prefs"); @@ -178,6 +180,9 @@ public class AppPreferences { private static final String MACRO_EDITOR_THEME = "macroEditorTheme"; private static final String DEFAULT_MACRO_EDITOR_THEME = "default"; + private static final String KEY_TOPOLOGY_DRAWING_MODE = "topologyDrawingMode"; + private static final String DEFAULT_TOPOLOGY_DRAWING_MODE = "VBL"; + public static void setFillSelectionBox(boolean fill) { prefs.putBoolean(KEY_FILL_SELECTION_BOX, fill); } @@ -1021,8 +1026,9 @@ public static void setMruCampaigns(List mruCampaigns) { path = file.getCanonicalPath(); } catch (IOException e) { // Probably pretty rare, but we want to know about it - if (log.isInfoEnabled()) + if (log.isInfoEnabled()) { log.info("unexpected during file.getCanonicalPath()", e); // $NON-NLS-1$ + } path = file.getPath(); } // It's important that '%3A' is done last. Note that the pathSeparator may not be a colon on @@ -1042,7 +1048,9 @@ public static List getMruCampaigns() { // It's important that '%3A' is done first combined = combined.replaceAll("%3A", File.pathSeparator).replaceAll("%25", "%"); String[] all = combined.split(File.pathSeparator); - for (int i = 0; i < all.length; i++) mruCampaigns.add(new File(all[i])); + for (int i = 0; i < all.length; i++) { + mruCampaigns.add(new File(all[i])); + } } return mruCampaigns; } @@ -1061,7 +1069,9 @@ public static List getSavedPaintTextures() { String combined = prefs.get(KEY_SAVED_PAINT_TEXTURES, null); if (combined != null) { String[] all = combined.split(File.pathSeparator); - for (int i = 0; i < all.length; i++) savedTextures.add(new File(all[i])); + for (int i = 0; i < all.length; i++) { + savedTextures.add(new File(all[i])); + } } return savedTextures; } @@ -1195,4 +1205,13 @@ public static String getDefaultMacroEditorTheme() { public static void setDefaultMacroEditorTheme(String type) { prefs.put(MACRO_EDITOR_THEME, type); } + + public static TopologyMode getTopologyDrawingMode() { + return TopologyMode.valueOf( + prefs.get(KEY_TOPOLOGY_DRAWING_MODE, DEFAULT_TOPOLOGY_DRAWING_MODE)); + } + + public static void setTopologyDrawingMode(TopologyMode mode) { + prefs.put(KEY_TOPOLOGY_DRAWING_MODE, mode.toString()); + } } diff --git a/src/main/java/net/rptools/maptool/client/AppStyle.java b/src/main/java/net/rptools/maptool/client/AppStyle.java index 994e8453d1..104064289c 100644 --- a/src/main/java/net/rptools/maptool/client/AppStyle.java +++ b/src/main/java/net/rptools/maptool/client/AppStyle.java @@ -62,6 +62,10 @@ public class AppStyle { public static Color topologyAddColor = new Color(255, 0, 0, 128); public static Color topologyRemoveColor = new Color(255, 255, 255, 128); + public static Color topologyTerrainColor = new Color(255, 0, 255, 128); + public static Color topologyTerrainAddColor = new Color(255, 0, 0, 128); + public static Color topologyTerrainRemoveColor = new Color(255, 255, 255, 128); + public static Color tokenTopologyColor = new Color(255, 255, 0, 128); public static Color tokenTopologyAddColor = new Color(255, 0, 0, 128); public static Color tokenTopologyRemoveColor = new Color(255, 255, 255, 128); diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingTool.java index 386c66d621..f078936386 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/AbstractDrawingTool.java @@ -27,6 +27,7 @@ import java.util.List; import net.rptools.lib.swing.ColorPicker; import net.rptools.lib.swing.SwingUtil; +import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.MapToolUtil; import net.rptools.maptool.client.ScreenPoint; @@ -41,10 +42,13 @@ import net.rptools.maptool.model.Zone.Layer; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Drawable; +import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Pen; +import net.rptools.maptool.model.drawing.ShapeDrawable; /** Tool for drawing freehand lines. */ public abstract class AbstractDrawingTool extends DefaultTool implements ZoneOverlay { + private static final long serialVersionUID = 9121558405484986225L; private boolean isEraser; @@ -238,6 +242,78 @@ protected Area getTokenTopology() { public abstract void paintOverlay(ZoneRenderer renderer, Graphics2D g); + protected void paintTopologyOverlay(Graphics2D g, Drawable drawable) { + paintTopologyOverlay(g, drawable, Pen.MODE_SOLID); + } + + protected void paintTopologyOverlay(Graphics2D g, Shape shape) { + ShapeDrawable drawable = null; + + if (shape != null) { + drawable = new ShapeDrawable(shape, false); + } + + paintTopologyOverlay(g, drawable, Pen.MODE_SOLID); + } + + protected void paintTopologyOverlay(Graphics2D g, Shape shape, int penMode) { + ShapeDrawable drawable = null; + + if (shape != null) { + drawable = new ShapeDrawable(shape, false); + } + + paintTopologyOverlay(g, drawable, penMode); + } + + protected void paintTopologyOverlay(Graphics2D g) { + Rectangle rectangle = null; + paintTopologyOverlay(g, rectangle, Pen.MODE_SOLID); + } + + protected void paintTopologyOverlay(Graphics2D g, Drawable drawable, int penMode) { + if (MapTool.getPlayer().isGM()) { + Zone zone = renderer.getZone(); + Area topology = zone.getTopology(); + + Graphics2D g2 = (Graphics2D) g.create(); + g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); + g2.scale(renderer.getScale(), renderer.getScale()); + + g2.setColor(AppStyle.tokenTopologyColor); + g2.fill(getTokenTopology()); + + g2.setColor(AppStyle.topologyTerrainColor); + g2.fill(zone.getTopologyTerrain()); + + g2.setColor(AppStyle.topologyColor); + g2.fill(topology); + + g2.dispose(); + } + + if (drawable != null) { + Pen pen = new Pen(); + pen.setEraser(getPen().isEraser()); + pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); + pen.setBackgroundMode(penMode); + + if (penMode == Pen.MODE_TRANSPARENT) { + pen.setThickness(3.0f); + } + + if (pen.isEraser()) { + pen.setEraser(false); + } + if (isEraser()) { + pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); + } else { + pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); + } + paintTransformed(g, renderer, drawable, pen); + } + } + /** * Render a drawable on a zone. This method consolidates all of the calls to the server in one * place so that it is easier to keep them in sync. @@ -250,10 +326,15 @@ protected void completeDrawable(GUID zoneId, Pen pen, Drawable drawable) { if (!hasPaint(pen)) { return; } - if (drawable.getBounds() == null) return; + if (drawable.getBounds() == null) { + return; + } drawable.setLayer(selectedLayer); - if (MapTool.getPlayer().isGM()) drawable.setLayer(selectedLayer); - else drawable.setLayer(Layer.TOKEN); + if (MapTool.getPlayer().isGM()) { + drawable.setLayer(selectedLayer); + } else { + drawable.setLayer(Layer.TOKEN); + } // Send new textures MapToolUtil.uploadTexture(pen.getPaint()); diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java index 23a3f0bca4..635337158e 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java @@ -23,13 +23,10 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Cross; -import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.util.GraphicsUtil; @@ -79,41 +76,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - // Color oldColor = g.getColor(); - - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (cross != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_TRANSPARENT); - pen.setThickness(3.0f); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, cross, pen); - } + paintTopologyOverlay(g, cross, Pen.MODE_TRANSPARENT); } @Override diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java index 2a71770b26..19b708be7b 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java @@ -23,13 +23,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; -import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.model.drawing.ShapeDrawable; public class DiamondTopologyTool extends AbstractDrawingTool implements MouseMotionListener { @@ -78,38 +74,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (diamond != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_SOLID); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, new ShapeDrawable(diamond, false), pen); - } + paintTopologyOverlay(g, diamond); } @Override diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java index e77ff8dad5..de7fb143f4 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java @@ -23,14 +23,10 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Pen; -import net.rptools.maptool.model.drawing.ShapeDrawable; public class HollowDiamondTopologyTool extends AbstractDrawingTool implements MouseMotionListener { private static final long serialVersionUID = 7227397975734203085L; @@ -77,41 +73,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - // Color oldColor = g.getColor(); - - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (diamond != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_TRANSPARENT); - pen.setThickness(3.0f); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, new ShapeDrawable(diamond, false), pen); - } + paintTopologyOverlay(g, diamond, Pen.MODE_TRANSPARENT); } @Override diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java index 7eff5150d4..f3bdc4baee 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java @@ -22,12 +22,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Oval; import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.util.GraphicsUtil; @@ -78,46 +75,7 @@ public String getTooltip() { } public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - - // Color oldColor = g.getColor(); - - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - - if (oval != null) { - - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_TRANSPARENT); - pen.setThickness(3.0f); - - if (pen.isEraser()) { - pen.setEraser(false); - } - - if (isEraser()) { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - - paintTransformed(g, renderer, oval, pen); - } + paintTopologyOverlay(g, oval, Pen.MODE_TRANSPARENT); } public void mousePressed(MouseEvent e) { diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java index 68fb295978..df91ce0e68 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java @@ -22,12 +22,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.model.drawing.Rectangle; @@ -78,41 +75,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - // Color oldColor = g.getColor(); - - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (rectangle != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_TRANSPARENT); - pen.setThickness(3.0f); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, rectangle, pen); - } + paintTopologyOverlay(g, rectangle, Pen.MODE_TRANSPARENT); } @Override diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java index a05f02b47e..dc70f7c2a0 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java @@ -22,14 +22,10 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.Oval; -import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.util.GraphicsUtil; public class OvalTopologyTool extends AbstractDrawingTool implements MouseMotionListener { @@ -79,38 +75,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (oval != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_SOLID); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, oval, pen); - } + paintTopologyOverlay(g, oval); } @Override diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java index b64ed68eed..aff4362df7 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java @@ -29,7 +29,6 @@ import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; import net.rptools.maptool.model.GUID; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.drawing.Drawable; import net.rptools.maptool.model.drawing.DrawableColorPaint; import net.rptools.maptool.model.drawing.LineSegment; @@ -38,6 +37,7 @@ /** Tool for drawing freehand lines. */ public class PolygonTopologyTool extends LineTool implements MouseMotionListener { + private static final long serialVersionUID = 3258132466219627316L; public PolygonTopologyTool() { @@ -148,22 +148,7 @@ protected Polygon getPolygon(LineSegment line) { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } + paintTopologyOverlay(g); super.paintOverlay(renderer, g); } } diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java index 4927079cea..7e1acca8dc 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java @@ -22,13 +22,9 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; -import net.rptools.maptool.client.AppStyle; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.ui.zone.ZoneRenderer; -import net.rptools.maptool.model.Zone; import net.rptools.maptool.model.ZonePoint; -import net.rptools.maptool.model.drawing.DrawableColorPaint; -import net.rptools.maptool.model.drawing.Pen; import net.rptools.maptool.model.drawing.Rectangle; /** @author drice */ @@ -77,38 +73,7 @@ public String getTooltip() { @Override public void paintOverlay(ZoneRenderer renderer, Graphics2D g) { - if (MapTool.getPlayer().isGM()) { - Zone zone = renderer.getZone(); - Area topology = zone.getTopology(); - - Graphics2D g2 = (Graphics2D) g.create(); - g2.translate(renderer.getViewOffsetX(), renderer.getViewOffsetY()); - g2.scale(renderer.getScale(), renderer.getScale()); - - g2.setColor(AppStyle.tokenTopologyColor); - g2.fill(getTokenTopology()); - - g2.setColor(AppStyle.topologyColor); - g2.fill(topology); - - g2.dispose(); - } - if (rectangle != null) { - Pen pen = new Pen(); - pen.setEraser(getPen().isEraser()); - pen.setOpacity(AppStyle.topologyRemoveColor.getAlpha() / 255.0f); - pen.setBackgroundMode(Pen.MODE_SOLID); - - if (pen.isEraser()) { - pen.setEraser(false); - } - if (isEraser()) { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyRemoveColor)); - } else { - pen.setBackgroundPaint(new DrawableColorPaint(AppStyle.topologyAddColor)); - } - paintTransformed(g, renderer, rectangle, pen); - } + paintTopologyOverlay(g, rectangle); } @Override diff --git a/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java b/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java index dee796e352..e0989eeb9a 100644 --- a/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java @@ -23,7 +23,17 @@ import java.io.IOException; import java.util.Hashtable; import javax.imageio.ImageIO; -import javax.swing.*; +import javax.swing.Box; +import javax.swing.ButtonGroup; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSeparator; +import javax.swing.JSlider; +import javax.swing.JToggleButton; +import javax.swing.JToolBar; +import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.plaf.basic.BasicToolBarUI; @@ -68,8 +78,14 @@ import net.rptools.maptool.language.I18N; import net.rptools.maptool.model.Campaign; import net.rptools.maptool.model.Zone.TokenSelection; +import net.rptools.maptool.model.Zone.TopologyMode; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; public class ToolbarPanel extends JToolBar { + + private static final Logger log = LogManager.getLogger(ToolbarPanel.class); + private final ButtonGroup buttonGroup = new ButtonGroup(); private final ButtonGroup tokenSelectionbuttonGroup = new ButtonGroup(); private final JPanel optionPanel; @@ -327,6 +343,13 @@ private OptionPanel createTopologyPanel() { panel.add(DiamondTopologyTool.class); panel.add(HollowDiamondTopologyTool.class); + panel.add( + createTopologyModeButton( + "net/rptools/maptool/client/image/tool/vbl-only.png", + "net/rptools/maptool/client/image/tool/mbl-only.png", + "net/rptools/maptool/client/image/tool/mbl-vbl-on.png", + I18N.getText("tools.vbl_mbl_selector.tooltip"))); + // panel.add(FillTopologyTool.class); return panel; } @@ -355,18 +378,44 @@ public void actionPerformed(ActionEvent e) { return button; } - public void getTest() {} + private JToggleButton createTopologyModeButton( + final String vblIcon, final String mblIcon, final String combinedIcon, String tooltip) { - private JToggleButton createAiButton(final String icon, final String offIcon, String tooltip) { final JToggleButton button = new JToggleButton(); button.setToolTipText(tooltip); + button.addActionListener( - new ActionListener() { - public void actionPerformed(ActionEvent e) { - AppPreferences.setUseAstarPathfinding(button.isSelected()); + e -> { + if (button.isSelected()) { + AppPreferences.setTopologyDrawingMode(TopologyMode.MBL); + } else { + AppPreferences.setTopologyDrawingMode(TopologyMode.VBL); } }); + try { + button.setIcon(new ImageIcon(ImageUtil.getImage(vblIcon))); + button.setSelectedIcon(new ImageIcon(ImageUtil.getImage(mblIcon))); + + // storing icons for third state usage + // button.setDisabledIcon(new ImageIcon(ImageUtil.getImage(mblIcon))); + // button.setDisabledSelectedIcon(new ImageIcon(ImageUtil.getImage(combinedIcon))); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + + if (AppPreferences.getTopologyDrawingMode().equals(TopologyMode.MBL)) { + button.doClick(); + } + + return button; + } + + private JToggleButton createAiButton(final String icon, final String offIcon, String tooltip) { + final JToggleButton button = new JToggleButton(); + button.setToolTipText(tooltip); + button.addActionListener(e -> AppPreferences.setUseAstarPathfinding(button.isSelected())); + try { button.setIcon(new ImageIcon(ImageUtil.getImage(offIcon))); button.setSelectedIcon(new ImageIcon(ImageUtil.getImage(icon))); @@ -374,7 +423,9 @@ public void actionPerformed(ActionEvent e) { ioe.printStackTrace(); } - if (AppPreferences.isUsingAstarPathfinding()) button.doClick(); + if (AppPreferences.isUsingAstarPathfinding()) { + button.doClick(); + } return button; } @@ -387,8 +438,11 @@ private JToggleButton createMuteButton( new ActionListener() { public void actionPerformed(ActionEvent e) { MediaPlayerAdapter.setGlobalMute(button.isSelected()); - if (button.isSelected()) button.setToolTipText(unmutetooltip); - else button.setToolTipText(mutetooltip); + if (button.isSelected()) { + button.setToolTipText(unmutetooltip); + } else { + button.setToolTipText(mutetooltip); + } } }); @@ -399,7 +453,9 @@ public void actionPerformed(ActionEvent e) { ioe.printStackTrace(); } - if (MediaPlayerAdapter.getGlobalMute()) button.doClick(); + if (MediaPlayerAdapter.getGlobalMute()) { + button.doClick(); + } return button; } @@ -461,6 +517,7 @@ public void setVisible(boolean visible) { } private class OptionPanel extends JToolBar { + private Class firstTool; private Class currentTool; diff --git a/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java b/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java index bb10abeb8c..fa6f349af9 100644 --- a/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java +++ b/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java @@ -155,6 +155,9 @@ protected List calculatePath(CellPoint start, CellPoint goal) { if (tokenVBL != null) { vbl.subtract(tokenVBL); } + + // Finally, add the Move Blocking Layer! + vbl.add((zone.getTopologyTerrain())); } if (!vbl.isEmpty()) { diff --git a/src/main/java/net/rptools/maptool/model/Zone.java b/src/main/java/net/rptools/maptool/model/Zone.java index 55d118e01b..4f2f5dc7fe 100644 --- a/src/main/java/net/rptools/maptool/model/Zone.java +++ b/src/main/java/net/rptools/maptool/model/Zone.java @@ -31,6 +31,7 @@ import java.util.Map; import java.util.Set; import net.rptools.lib.MD5Key; +import net.rptools.maptool.client.AppPreferences; import net.rptools.maptool.client.AppUtil; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.tool.drawing.UndoPerZone; @@ -133,6 +134,13 @@ public enum AStarRoundingOptions { INTEGER } + // Control what topology layer(s) to add/get drawing to/from + public enum TopologyMode { + VBL, + MBL, + COMBINED + } + public static final int DEFAULT_TOKEN_VISION_DISTANCE = 250; // In units public static final int DEFAULT_PIXELS_CELL = 50; public static final int DEFAULT_UNITS_PER_CELL = 5; @@ -185,6 +193,9 @@ public enum AStarRoundingOptions { /** The VBL topology of the zone. Does not include token VBL. */ private Area topology = new Area(); + // New topology to hold Movement Blocking Only + private Area topologyTerrain = new Area(); + // The 'board' layer, at the very bottom of the layer stack. // Itself has two sub-layers: // The top one is an optional texture, typically a pre-drawn map. @@ -730,7 +741,19 @@ public void clearTopology() { * @param area the area */ public void addTopology(Area area) { - topology.add(area); + switch (AppPreferences.getTopologyDrawingMode()) { + case VBL: + topology.add(area); + break; + case MBL: + topologyTerrain.add(area); + break; + case COMBINED: + topology.add(area); + topologyTerrain.add(area); + break; + } + fireModelChangeEvent(new ModelChangeEvent(this, Event.TOPOLOGY_CHANGED)); } @@ -740,7 +763,19 @@ public void addTopology(Area area) { * @param area the area */ public void removeTopology(Area area) { - topology.subtract(area); + switch (AppPreferences.getTopologyDrawingMode()) { + case VBL: + topology.subtract(area); + break; + case MBL: + topologyTerrain.subtract(area); + break; + case COMBINED: + topology.subtract(area); + topologyTerrain.subtract(area); + break; + } + fireModelChangeEvent(new ModelChangeEvent(this, Event.TOPOLOGY_CHANGED)); } @@ -754,6 +789,14 @@ public Area getTopology() { return topology; } + /** @return the terrain topology of the zone */ + public Area getTopologyTerrain() { + if (topologyTerrain == null) { + topologyTerrain = new Area(); + } + return topologyTerrain; + } + /** * Fire the event TOKEN_CHANGED * diff --git a/src/main/resources/net/rptools/maptool/client/image/tool/mbl-only.png b/src/main/resources/net/rptools/maptool/client/image/tool/mbl-only.png new file mode 100644 index 0000000000000000000000000000000000000000..3faba6ff2e824b0a8052ad967bb5f425f38f6a28 GIT binary patch literal 2751 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 W(5VBs7g)Len@Xd&lIw`U3I72gc&-2d literal 0 HcmV?d00001 diff --git a/src/main/resources/net/rptools/maptool/client/image/tool/vbl-only.png b/src/main/resources/net/rptools/maptool/client/image/tool/vbl-only.png new file mode 100644 index 0000000000000000000000000000000000000000..157cf94db234c3d33b44324d077d681d7bc9adaf GIT binary patch literal 2748 zcmbVOc|6p4AD>08q=;-evu$jC@=Bm&G69D~4YZEe>$;BZTYhNUoyE24`nxkA%*1_DdS z5U}|oHjfKjW27JDg^MsCg{PlG;P72s{vzfIza&bLGKiSYhrqy42#2#4*C%bEh|2n} z8-J@Uq($*r5GqT^3l}gH^$0Xw2P<;-&xY0%72crT1Z+i7=%EB2Bb>wHiW~_Tkm3Z) zWHZq)ERkSkg+ij>L@d!72E!7pZBckA39CpZ3WtNPbNn6F)&@tyK@lVb32Fs{5wTbj z0*}YyNm!H>6op6N*RhUVp@`09u-5Ie6?VU1iT{X2;{`0bh$o=&c%kbZ;2y*i@q|G< zJ`nGT1b*wy<}!Ja!rg1-`5Y~QC16Lem?Qy@1N@XG@d^oHi-5sFU$D&oCub0aGmy3B_@8E3-%@no+VZc~R|tO%4~wgq7=dCmz*E1$ z007kqM*@~6ekStrJ#9qZu~NB|S2%W~WuQQeY3`SXg;sl;)oN&VR0VuvmZh&(rk<#x zo3+)XEFfN-K1AHrLbOv!Q&SnbdrG%V#W!&mr4^^w|Esp)=+lfdn3jRt7v?4oV=z5E za@n#Bvk^(|>ZNrZke!GfoL`kqbpNzjC)q@gh;?(*2C37ZBTwB`vckku+22GhFVJ3& zm6GR;^X*VCqc~D_LuKZx!(hGWmB%&mIhjo0{C0JDX2bAI)cMQtBRSzBv_0yW`?P}u zsQ$){8}@oi-f)#46#Pe$vLgaMWZVfzX@cg*W1hd1|VjCQmo(Wnmcu~gr|?b=&b za&I-~yW<{bC0?0=yL=>b$+m(yr(66ud$#{Auiqv&skIv8`cMMjt0!uL4op0|U}uNU zI^G6-#@ppGX>+=k$WD>dbLAS|;9Qa!2NURf&<$h`hDdcJW^UcDTq z)5ukWW*bo1N%>GVrm#6i$?cbj4G&v+ua;U$F^hMekj>xwM0L%anAjNRFZp4be<2>{ zap*_eLg~m6)CVqmp0~>1dE^{^cGm0%sp0QvVySX;0@kME2LoJdoeDW3Jz3<{-hC)_ zYjqAZ?nbS{Mc9$LthSm;K}Ds~K?^4jpPSW@(%LK(Ha_hMA^l44me($kvy4EW{JFy z=$}2_ykj^deDhwotB$i{c34utt7t9n=E)K&r{r)1C}mYLu*CxFIAp@z(p48(I#kS# zi8@r1U88YbGG3MC-qu?|WvL3nD(;A-#~WJT7I}qXgVX3QS`uSZ{KSkx=J#B(`;@K$ z>-@nuhZdIHM2K=@-+7zG;w+*gG_H`uYj=z6Nt##H$&riJd*u~HPQD$k2di$17v~WRW1HJy=yTYfX;b{4 zdEZr#ozkyq4864|&M69=^1i3BP1)qNxN6eRqyF8{f`sN?-CJAZ9`CH<{3qoWWy`er zU~BwLuG7MZaP!fiN54I+-8*1={q&Jl?zUuF>C^iOr)0{}e`>aoXlI6FiXR8%iouQb zq^#KSl@IslF!Sc7YOUKz+A3)#=dKn+KZ5u#smEb7TIM<#sQDFxB@>>1cX4|z5GJqB~ zzW4(_7TTHM?-|xF>}^*Gc+Gul+BwYp_ l-gLt^b@fe%eEgD<79e{vGu=6X;Jfxe=}2@XNN@oO{{b9Bqh0_2 literal 0 HcmV?d00001 From d114c8af3c7e394e72ff0f24b0d99ad4a5691745 Mon Sep 17 00:00:00 2001 From: Jamz Date: Fri, 31 Jan 2020 22:41:10 -0600 Subject: [PATCH 2/2] Add new drawing layer that only blocks token movement. * Same tools used as VBL with extra button that defines which layer(s) the polygons are drawn on. * Changes included (and to be tested) include client/server commands to properly send VBL/MBL to other clients * AppPreferences persist last ToolbarPanel presses * TODO: Make AI buttons for GM persist over to Player clients and disable buttons on Player clients when server is running Signed-off-by: JamzTheMan --- .../maptool/client/AppPreferences.java | 28 ++---- .../maptool/client/ClientMethodHandler.java | 8 +- .../net/rptools/maptool/client/MapTool.java | 29 ++++-- .../client/ServerCommandClientImpl.java | 9 +- .../tool/drawing/CrossTopologyTool.java | 9 +- .../tool/drawing/DiamondTopologyTool.java | 9 +- .../drawing/HollowDiamondTopologyTool.java | 9 +- .../tool/drawing/HollowOvalTopologyTool.java | 9 +- .../drawing/HollowRectangleTopologyTool.java | 9 +- .../client/tool/drawing/OvalTopologyTool.java | 9 +- .../tool/drawing/PolygonTopologyTool.java | 8 +- .../tool/drawing/RectangleTopologyTool.java | 9 +- .../maptool/client/ui/ToolbarPanel.java | 95 +++++++++++++++--- .../ui/drawpanel/DrawPanelPopupMenu.java | 6 +- .../maptool/client/ui/zone/vbl/TokenVBL.java | 6 +- .../walker/astar/AbstractAStarWalker.java | 17 ++-- .../java/net/rptools/maptool/model/Zone.java | 48 ++++++--- .../rptools/maptool/server/ServerCommand.java | 5 +- .../maptool/server/ServerMethodHandler.java | 13 +-- .../client/image/tool/ignore-vbl-on-move.png | Bin 0 -> 3011 bytes .../client/image/tool/use-vbl-on-move.png | Bin 0 -> 2979 bytes 21 files changed, 226 insertions(+), 109 deletions(-) create mode 100644 src/main/resources/net/rptools/maptool/client/image/tool/ignore-vbl-on-move.png create mode 100644 src/main/resources/net/rptools/maptool/client/image/tool/use-vbl-on-move.png diff --git a/src/main/java/net/rptools/maptool/client/AppPreferences.java b/src/main/java/net/rptools/maptool/client/AppPreferences.java index f220da7a8b..6d08886bc6 100644 --- a/src/main/java/net/rptools/maptool/client/AppPreferences.java +++ b/src/main/java/net/rptools/maptool/client/AppPreferences.java @@ -177,6 +177,9 @@ public class AppPreferences { private static final String KEY_USE_ASTAR_PATHFINDING = "useAstarPathfinding"; private static final boolean DEFAULT_USE_ASTAR_PATHFINDING = true; + private static final String KEY_VBL_BLOCKS_MOVE = "vblBlocksMove"; + private static final boolean DEFAULT_VBL_BLOCKS_MOVE = true; + private static final String MACRO_EDITOR_THEME = "macroEditorTheme"; private static final String DEFAULT_MACRO_EDITOR_THEME = "default"; @@ -1076,15 +1079,6 @@ public static List getSavedPaintTextures() { return savedTextures; } - // Jamz: Disabling Initiative Panel server sync prevents panel updates to other clients. - // Effectively, only the GM now has access to the initiative panel. This greatly increases - // performance and - // prevents the updates from getting out of sync as they can today. - // Note: This is a HACK to fix a broken system, but we're not going to invest anymore time into - // the current classes. REWRITE ME! - // private static final String INIT_ENABLE_SERVER_SYNC = "initEnableServerSync"; - // private static final boolean DEFAULT_INIT_ENABLE_SERVER_SYNC = true; - private static final String INIT_SHOW_TOKENS = "initShowTokens"; private static final boolean DEFAULT_INIT_SHOW_TOKENS = true; @@ -1106,14 +1100,6 @@ public static List getSavedPaintTextures() { private static final String INIT_LOCK_MOVEMENT = "initLockMovement"; private static final boolean DEFAULT_INIT_LOCK_MOVEMENT = false; - // public static boolean getInitEnableServerSync() { - // return prefs.getBoolean(INIT_ENABLE_SERVER_SYNC, DEFAULT_INIT_ENABLE_SERVER_SYNC); - // } - // - // public static void setInitEnableServerSync(boolean enableSync) { - // prefs.putBoolean(INIT_ENABLE_SERVER_SYNC, enableSync); - // } - public static boolean getInitShowTokens() { return prefs.getBoolean(INIT_SHOW_TOKENS, DEFAULT_INIT_SHOW_TOKENS); } @@ -1198,6 +1184,14 @@ public static void setUseAstarPathfinding(boolean show) { prefs.putBoolean(KEY_USE_ASTAR_PATHFINDING, show); } + public static boolean getVblBlocksMove() { + return prefs.getBoolean(KEY_VBL_BLOCKS_MOVE, DEFAULT_VBL_BLOCKS_MOVE); + } + + public static void setVblBlocksMove(boolean use) { + prefs.putBoolean(KEY_VBL_BLOCKS_MOVE, use); + } + public static String getDefaultMacroEditorTheme() { return prefs.get(MACRO_EDITOR_THEME, DEFAULT_MACRO_EDITOR_THEME); } diff --git a/src/main/java/net/rptools/maptool/client/ClientMethodHandler.java b/src/main/java/net/rptools/maptool/client/ClientMethodHandler.java index 40719e995d..ffbd0e9d08 100644 --- a/src/main/java/net/rptools/maptool/client/ClientMethodHandler.java +++ b/src/main/java/net/rptools/maptool/client/ClientMethodHandler.java @@ -18,7 +18,6 @@ import java.awt.Point; import java.awt.geom.Area; import java.io.IOException; -import java.lang.reflect.*; import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -48,6 +47,7 @@ import net.rptools.maptool.model.TextMessage; import net.rptools.maptool.model.Token; import net.rptools.maptool.model.Zone; +import net.rptools.maptool.model.Zone.TopologyMode; import net.rptools.maptool.model.Zone.VisionType; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Drawable; @@ -485,9 +485,10 @@ public void run() { case addTopology: zoneGUID = (GUID) parameters[0]; area = (Area) parameters[1]; + TopologyMode topologyMode = (TopologyMode) parameters[2]; zone = MapTool.getCampaign().getZone(zoneGUID); - zone.addTopology(area); + zone.addTopology(area, topologyMode); MapTool.getFrame().getZoneRenderer(zoneGUID).repaint(); return; @@ -495,9 +496,10 @@ public void run() { case removeTopology: zoneGUID = (GUID) parameters[0]; area = (Area) parameters[1]; + topologyMode = (TopologyMode) parameters[2]; zone = MapTool.getCampaign().getZone(zoneGUID); - zone.removeTopology(area); + zone.removeTopology(area, topologyMode); MapTool.getFrame().getZoneRenderer(zoneGUID).repaint(); return; diff --git a/src/main/java/net/rptools/maptool/client/MapTool.java b/src/main/java/net/rptools/maptool/client/MapTool.java index 33971db589..e9cd63e6a6 100644 --- a/src/main/java/net/rptools/maptool/client/MapTool.java +++ b/src/main/java/net/rptools/maptool/client/MapTool.java @@ -258,7 +258,7 @@ public static void showMessage( * window (formatted using params) * @param messageType one of JOptionPane.ERROR_MESSAGE, * JOptionPane.WARNING_MESSAGE, JOptionPane.INFORMATION_MESSAGE - * + * * @param params optional parameters to use when formatting the title text from the properties * file */ @@ -1330,6 +1330,18 @@ private static void postInitialize() { // Jamz: After preferences are loaded, Asset Tree and ImagePanel are out of sync, // so after frame is all done loading we sync them back up. MapTool.getFrame().getAssetPanel().getAssetTree().initialize(); + + // Set the Topology drawing mode to the last mode used for convenience + MapTool.getFrame() + .getCurrentZoneRenderer() + .getZone() + .setTopologyMode(AppPreferences.getTopologyDrawingMode()); + + // Set the Topology drawing mode to the last mode used for convenience + MapTool.getFrame() + .getCurrentZoneRenderer() + .getZone() + .setTopologyMode(AppPreferences.getTopologyDrawingMode()); } /** @@ -1421,13 +1433,12 @@ public void run() { * *

Examples: -version=1.4.0.1 -user=Jamz * - * @param options {@link org.apache.commons.cli.Options} + * @param cmd {@link org.apache.commons.cli.Options} * @param searchValue Option string to search for, ie -version * @param defaultValue A default value to return if option is not found - * @param args String array of passed in args * @return Option value found as a String, or defaultValue if not found * @author Jamz - * @since 1.4.0.1 + * @since 1.5.12 */ private static String getCommandLineOption( CommandLine cmd, String searchValue, String defaultValue) { @@ -1439,12 +1450,11 @@ private static String getCommandLineOption( * *

Examples: -x or -fullscreen * - * @param options {@link org.apache.commons.cli.Options} + * @param cmd {@link org.apache.commons.cli.Options} * @param searchValue Option string to search for, ie -version - * @param args String array of passed in args * @return A boolean value of true if option parameter found * @author Jamz - * @since 1.4.0.1 + * @since 1.5.12 */ private static boolean getCommandLineOption(CommandLine cmd, String searchValue) { return cmd.hasOption(searchValue); @@ -1456,13 +1466,12 @@ private static boolean getCommandLineOption(CommandLine cmd, String searchValue) * *

Examples: -monitor=1 -x=0 -y=0 -w=1200 -h=960 * - * @param options {@link org.apache.commons.cli.Options} + * @param cmd {@link org.apache.commons.cli.Options} * @param searchValue Option string to search for, ie -version * @param defaultValue A default value to return if option is not found - * @param args String array of passed in args * @return Int value of the matching option parameter if found * @author Jamz - * @since 1.4.0.1 + * @since 1.5.12 */ private static int getCommandLineOption(CommandLine cmd, String searchValue, int defaultValue) { return StringUtil.parseInteger(cmd.getOptionValue(searchValue), defaultValue); diff --git a/src/main/java/net/rptools/maptool/client/ServerCommandClientImpl.java b/src/main/java/net/rptools/maptool/client/ServerCommandClientImpl.java index 92c525d924..956941e9bf 100644 --- a/src/main/java/net/rptools/maptool/client/ServerCommandClientImpl.java +++ b/src/main/java/net/rptools/maptool/client/ServerCommandClientImpl.java @@ -34,6 +34,7 @@ import net.rptools.maptool.model.TextMessage; import net.rptools.maptool.model.Token; import net.rptools.maptool.model.Zone; +import net.rptools.maptool.model.Zone.TopologyMode; import net.rptools.maptool.model.Zone.VisionType; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Drawable; @@ -261,12 +262,12 @@ public void toggleTokenMoveWaypoint(GUID zoneGUID, GUID tokenGUID, ZonePoint cp) makeServerCall(COMMAND.toggleTokenMoveWaypoint, zoneGUID, tokenGUID, cp); } - public void addTopology(GUID zoneGUID, Area area) { - makeServerCall(COMMAND.addTopology, zoneGUID, area); + public void addTopology(GUID zoneGUID, Area area, TopologyMode topologyMode) { + makeServerCall(COMMAND.addTopology, zoneGUID, area, topologyMode); } - public void removeTopology(GUID zoneGUID, Area area) { - makeServerCall(COMMAND.removeTopology, zoneGUID, area); + public void removeTopology(GUID zoneGUID, Area area, TopologyMode topologyMode) { + makeServerCall(COMMAND.removeTopology, zoneGUID, area, topologyMode); } public void exposePCArea(GUID zoneGUID) { diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java index 635337158e..28730e304c 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/CrossTopologyTool.java @@ -106,11 +106,12 @@ public void mousePressed(MouseEvent e) { GraphicsUtil.createLine(1, new Point2D.Double(x1, y2), new Point2D.Double(x2, y1))); if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); // TODO: send this to the server diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java index 19b708be7b..d5c986082d 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/DiamondTopologyTool.java @@ -95,11 +95,12 @@ public void mousePressed(MouseEvent e) { } Area area = new ShapeDrawable(diamond, false).getArea(); if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); // TODO: send this to the server diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java index de7fb143f4..af64d93960 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowDiamondTopologyTool.java @@ -94,11 +94,12 @@ public void mousePressed(MouseEvent e) { } Area area = new Area(diamond); if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); // TODO: send this to the server diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java index f3bdc4baee..2c68fa1171 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowOvalTopologyTool.java @@ -111,11 +111,12 @@ public void mousePressed(MouseEvent e) { } if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java index df91ce0e68..6ce24be6fb 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/HollowRectangleTopologyTool.java @@ -103,11 +103,12 @@ public void mousePressed(MouseEvent e) { area.subtract(innerArea); } if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); // TODO: send this to the server diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java index dc70f7c2a0..a2f90ac2fe 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/OvalTopologyTool.java @@ -99,11 +99,12 @@ public void mousePressed(MouseEvent e) { 10); if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); oval = null; diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java index aff4362df7..4ce2703a29 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/PolygonTopologyTool.java @@ -114,11 +114,11 @@ protected void completeDrawable(GUID zoneGUID, Pen pen, Drawable drawable) { area = new Area(((ShapeDrawable) drawable).getShape()); } if (pen.isEraser()) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand().removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); } diff --git a/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java b/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java index 7e1acca8dc..ae20ad9da8 100644 --- a/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java +++ b/src/main/java/net/rptools/maptool/client/tool/drawing/RectangleTopologyTool.java @@ -94,11 +94,12 @@ public void mousePressed(MouseEvent e) { Area area = new Area(new java.awt.Rectangle(x1, y1, x2 - x1, y2 - y1)); if (isEraser(e)) { - renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + getZone().removeTopology(area); + MapTool.serverCommand() + .removeTopology(getZone().getId(), area, getZone().getTopologyMode()); } else { - renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + getZone().addTopology(area); + MapTool.serverCommand().addTopology(getZone().getId(), area, getZone().getTopologyMode()); } renderer.repaint(); // TODO: send this to the server diff --git a/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java b/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java index e0989eeb9a..84af702430 100644 --- a/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java +++ b/src/main/java/net/rptools/maptool/client/ui/ToolbarPanel.java @@ -90,6 +90,9 @@ public class ToolbarPanel extends JToolBar { private final ButtonGroup tokenSelectionbuttonGroup = new ButtonGroup(); private final JPanel optionPanel; private final Toolbox toolbox; + private ImageIcon vblImageIcon; + private ImageIcon combinedImageIcon; + private ImageIcon mblImageIcon; public ToolbarPanel(Toolbox tbox) { setRollover(true); @@ -187,6 +190,11 @@ public void stateChanged(ChangeEvent e) { "net/rptools/maptool/client/image/tool/ai-blue-green.png", "net/rptools/maptool/client/image/tool/ai-blue-off.png", I18N.getText("tools.ai_selector.tooltip"))); + add( + createUseVBLonMoveButton( + "net/rptools/maptool/client/image/tool/use-vbl-on-move.png", + "net/rptools/maptool/client/image/tool/ignore-vbl-on-move.png", + I18N.getText("tools.ignore_vbl_on_move.tooltip"))); add(Box.createHorizontalStrut(10)); add(new JSeparator(JSeparator.VERTICAL)); @@ -381,40 +389,101 @@ public void actionPerformed(ActionEvent e) { private JToggleButton createTopologyModeButton( final String vblIcon, final String mblIcon, final String combinedIcon, String tooltip) { + try { + vblImageIcon = new ImageIcon(ImageUtil.getImage(vblIcon)); + mblImageIcon = new ImageIcon(ImageUtil.getImage(mblIcon)); + combinedImageIcon = new ImageIcon(ImageUtil.getImage(combinedIcon)); + } catch (IOException ioe) { + ioe.printStackTrace(); + } + final JToggleButton button = new JToggleButton(); button.setToolTipText(tooltip); + button.setSelectedIcon(combinedImageIcon); + + switch (AppPreferences.getTopologyDrawingMode()) { + case VBL: + button.setActionCommand(TopologyMode.VBL.toString()); + button.setIcon(vblImageIcon); + break; + case MBL: + button.setActionCommand(TopologyMode.MBL.toString()); + button.setIcon(mblImageIcon); + break; + case COMBINED: + button.setActionCommand(TopologyMode.VBL.toString()); + button.setIcon(vblImageIcon); + button.setSelected(true); + break; + } button.addActionListener( e -> { + TopologyMode currentTopologyMode; + + // Not a huge fan of this code but needed a TriStateButton and TriStateCheckbox from JIDE + // doesn't handle custom images very well. Also, trying to avoid JIDE were possible + // in case we move to FX in the future. if (button.isSelected()) { - AppPreferences.setTopologyDrawingMode(TopologyMode.MBL); + if (button.getActionCommand().equals(TopologyMode.MBL.toString())) { + currentTopologyMode = TopologyMode.VBL; + button.setActionCommand(TopologyMode.VBL.toString()); + button.setSelected(false); + button.setIcon(vblImageIcon); + } else { + currentTopologyMode = TopologyMode.COMBINED; + } } else { - AppPreferences.setTopologyDrawingMode(TopologyMode.VBL); + // Toggle unselected button between VBL/MBL + if (button.getActionCommand().equals(TopologyMode.VBL.toString())) { + currentTopologyMode = TopologyMode.MBL; + button.setActionCommand(TopologyMode.MBL.toString()); + button.setIcon(mblImageIcon); + } else { + currentTopologyMode = TopologyMode.VBL; + button.setActionCommand(TopologyMode.VBL.toString()); + button.setIcon(vblImageIcon); + } } + + AppPreferences.setTopologyDrawingMode(currentTopologyMode); + + MapTool.getFrame() + .getCurrentZoneRenderer() + .getZone() + .setTopologyMode(currentTopologyMode); }); - try { - button.setIcon(new ImageIcon(ImageUtil.getImage(vblIcon))); - button.setSelectedIcon(new ImageIcon(ImageUtil.getImage(mblIcon))); + return button; + } - // storing icons for third state usage - // button.setDisabledIcon(new ImageIcon(ImageUtil.getImage(mblIcon))); - // button.setDisabledSelectedIcon(new ImageIcon(ImageUtil.getImage(combinedIcon))); + private JToggleButton createAiButton(final String icon, final String offIcon, String tooltip) { + final JToggleButton button = new JToggleButton(); + button.setToolTipText(tooltip); + button.addActionListener(e -> AppPreferences.setUseAstarPathfinding(button.isSelected())); + + try { + button.setIcon(new ImageIcon(ImageUtil.getImage(offIcon))); + button.setSelectedIcon(new ImageIcon(ImageUtil.getImage(icon))); } catch (IOException ioe) { ioe.printStackTrace(); } - if (AppPreferences.getTopologyDrawingMode().equals(TopologyMode.MBL)) { + if (AppPreferences.isUsingAstarPathfinding()) { button.doClick(); } return button; } - private JToggleButton createAiButton(final String icon, final String offIcon, String tooltip) { + private JToggleButton createUseVBLonMoveButton( + final String icon, final String offIcon, String tooltip) { final JToggleButton button = new JToggleButton(); button.setToolTipText(tooltip); - button.addActionListener(e -> AppPreferences.setUseAstarPathfinding(button.isSelected())); + button.addActionListener( + e -> { + AppPreferences.setVblBlocksMove(button.isSelected()); + }); try { button.setIcon(new ImageIcon(ImageUtil.getImage(offIcon))); @@ -423,8 +492,8 @@ private JToggleButton createAiButton(final String icon, final String offIcon, St ioe.printStackTrace(); } - if (AppPreferences.isUsingAstarPathfinding()) { - button.doClick(); + if (AppPreferences.getVblBlocksMove()) { + button.setSelected(true); } return button; diff --git a/src/main/java/net/rptools/maptool/client/ui/drawpanel/DrawPanelPopupMenu.java b/src/main/java/net/rptools/maptool/client/ui/drawpanel/DrawPanelPopupMenu.java index ec43f1a2bb..7d1a4d633c 100644 --- a/src/main/java/net/rptools/maptool/client/ui/drawpanel/DrawPanelPopupMenu.java +++ b/src/main/java/net/rptools/maptool/client/ui/drawpanel/DrawPanelPopupMenu.java @@ -570,10 +570,12 @@ private void VblTool(Drawable drawable, boolean pathOnly, boolean isEraser) { } if (isEraser) { renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + MapTool.serverCommand() + .removeTopology(renderer.getZone().getId(), area, renderer.getZone().getTopologyMode()); } else { renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + MapTool.serverCommand() + .addTopology(renderer.getZone().getId(), area, renderer.getZone().getTopologyMode()); } renderer.repaint(); } diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/vbl/TokenVBL.java b/src/main/java/net/rptools/maptool/client/ui/zone/vbl/TokenVBL.java index becff5517e..c360585199 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/vbl/TokenVBL.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/vbl/TokenVBL.java @@ -69,10 +69,12 @@ public static Area renderVBL(ZoneRenderer renderer, Area area, boolean erase) { if (erase) { renderer.getZone().removeTopology(area); - MapTool.serverCommand().removeTopology(renderer.getZone().getId(), area); + MapTool.serverCommand() + .removeTopology(renderer.getZone().getId(), area, renderer.getZone().getTopologyMode()); } else { renderer.getZone().addTopology(area); - MapTool.serverCommand().addTopology(renderer.getZone().getId(), area); + MapTool.serverCommand() + .addTopology(renderer.getZone().getId(), area, renderer.getZone().getTopologyMode()); } MapTool.getFrame().getCurrentZoneRenderer().getZone().tokenTopologyChanged(); diff --git a/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java b/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java index fa6f349af9..a8278ef07c 100644 --- a/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java +++ b/src/main/java/net/rptools/maptool/client/walker/astar/AbstractAStarWalker.java @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import net.rptools.maptool.client.AppPreferences; import net.rptools.maptool.client.MapTool; import net.rptools.maptool.client.walker.AbstractZoneWalker; import net.rptools.maptool.model.CellPoint; @@ -150,14 +151,18 @@ protected List calculatePath(CellPoint start, CellPoint goal) { // Render VBL to Geometry class once and store. // Note: zoneRenderer will be null if map is not visible to players. if (MapTool.getFrame().getCurrentZoneRenderer() != null) { - vbl = MapTool.getFrame().getCurrentZoneRenderer().getZoneView().getTopologyTree().getArea(); + if (AppPreferences.getVblBlocksMove()) { + vbl = MapTool.getFrame().getCurrentZoneRenderer().getZoneView().getTopologyTree().getArea(); - if (tokenVBL != null) { - vbl.subtract(tokenVBL); - } + if (tokenVBL != null) { + vbl.subtract(tokenVBL); + } - // Finally, add the Move Blocking Layer! - vbl.add((zone.getTopologyTerrain())); + // Finally, add the Move Blocking Layer! + vbl.add((zone.getTopologyTerrain())); + } else { + vbl = zone.getTopologyTerrain(); + } } if (!vbl.isEmpty()) { diff --git a/src/main/java/net/rptools/maptool/model/Zone.java b/src/main/java/net/rptools/maptool/model/Zone.java index 4f2f5dc7fe..df1518fb1a 100644 --- a/src/main/java/net/rptools/maptool/model/Zone.java +++ b/src/main/java/net/rptools/maptool/model/Zone.java @@ -166,6 +166,7 @@ public enum TopologyMode { private double unitsPerCell = DEFAULT_UNITS_PER_CELL; private AStarRoundingOptions aStarRounding = AStarRoundingOptions.NONE; + private TopologyMode topologyMode = TopologyMode.VBL; private List drawables = new LinkedList(); private List gmDrawables = new LinkedList(); @@ -440,6 +441,9 @@ public Zone(Zone zone, boolean keepIds) { boardPosition = (Point) zone.boardPosition.clone(); exposedArea = (Area) zone.exposedArea.clone(); topology = (Area) zone.topology.clone(); + topologyTerrain = (Area) zone.topologyTerrain.clone(); + aStarRounding = zone.aStarRounding; + topologyMode = zone.topologyMode; isVisible = zone.isVisible; hasFog = zone.hasFog; } @@ -740,45 +744,53 @@ public void clearTopology() { * * @param area the area */ - public void addTopology(Area area) { - switch (AppPreferences.getTopologyDrawingMode()) { + public void addTopology(Area area, TopologyMode topologyMode) { + switch (topologyMode) { case VBL: - topology.add(area); + getTopology().add(area); break; case MBL: - topologyTerrain.add(area); + getTopologyTerrain().add(area); break; case COMBINED: - topology.add(area); - topologyTerrain.add(area); + getTopology().add(area); + getTopologyTerrain().add(area); break; } fireModelChangeEvent(new ModelChangeEvent(this, Event.TOPOLOGY_CHANGED)); } + public void addTopology(Area area) { + addTopology(area, getTopologyMode()); + } + /** * Subtract the area from the topology, and fire the event TOPOLOGY_CHANGED * * @param area the area */ - public void removeTopology(Area area) { - switch (AppPreferences.getTopologyDrawingMode()) { + public void removeTopology(Area area, TopologyMode topologyMode) { + switch (topologyMode) { case VBL: - topology.subtract(area); + getTopology().subtract(area); break; case MBL: - topologyTerrain.subtract(area); + getTopologyTerrain().subtract(area); break; case COMBINED: - topology.subtract(area); - topologyTerrain.subtract(area); + getTopology().subtract(area); + getTopologyTerrain().subtract(area); break; } fireModelChangeEvent(new ModelChangeEvent(this, Event.TOPOLOGY_CHANGED)); } + public void removeTopology(Area area) { + removeTopology(area, getTopologyMode()); + } + /** Fire the event TOPOLOGY_CHANGED. */ public void tokenTopologyChanged() { fireModelChangeEvent(new ModelChangeEvent(this, Event.TOPOLOGY_CHANGED)); @@ -1082,6 +1094,18 @@ public void setAStarRounding(AStarRoundingOptions aStarRounding) { this.aStarRounding = aStarRounding; } + public TopologyMode getTopologyMode() { + if (topologyMode == null) { + topologyMode = AppPreferences.getTopologyDrawingMode(); + } + + return topologyMode; + } + + public void setTopologyMode(TopologyMode topologyMode) { + this.topologyMode = topologyMode; + } + public int getLargestZOrder() { return tokenOrderedList.size() > 0 ? tokenOrderedList.get(tokenOrderedList.size() - 1).getZOrder() diff --git a/src/main/java/net/rptools/maptool/server/ServerCommand.java b/src/main/java/net/rptools/maptool/server/ServerCommand.java index 43f82727c4..2a709119fe 100644 --- a/src/main/java/net/rptools/maptool/server/ServerCommand.java +++ b/src/main/java/net/rptools/maptool/server/ServerCommand.java @@ -30,6 +30,7 @@ import net.rptools.maptool.model.TextMessage; import net.rptools.maptool.model.Token; import net.rptools.maptool.model.Zone; +import net.rptools.maptool.model.Zone.TopologyMode; import net.rptools.maptool.model.Zone.VisionType; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Drawable; @@ -111,9 +112,9 @@ public static enum COMMAND { public void setFoW(GUID zoneGUID, Area area, Set selectedToks); - public void addTopology(GUID zoneGUID, Area area); + public void addTopology(GUID zoneGUID, Area area, TopologyMode topologyMode); - public void removeTopology(GUID zoneGUID, Area area); + public void removeTopology(GUID zoneGUID, Area area, TopologyMode topologyMode); public void enforceZoneView(GUID zoneGUID, int x, int y, double scale, int width, int height); diff --git a/src/main/java/net/rptools/maptool/server/ServerMethodHandler.java b/src/main/java/net/rptools/maptool/server/ServerMethodHandler.java index 0cd66376fb..251b9e4da4 100644 --- a/src/main/java/net/rptools/maptool/server/ServerMethodHandler.java +++ b/src/main/java/net/rptools/maptool/server/ServerMethodHandler.java @@ -41,6 +41,7 @@ import net.rptools.maptool.model.TextMessage; import net.rptools.maptool.model.Token; import net.rptools.maptool.model.Zone; +import net.rptools.maptool.model.Zone.TopologyMode; import net.rptools.maptool.model.Zone.VisionType; import net.rptools.maptool.model.ZonePoint; import net.rptools.maptool.model.drawing.Drawable; @@ -221,10 +222,10 @@ public void handleMethod(String id, String method, Object... parameters) { setServerPolicy((ServerPolicy) context.get(0)); break; case addTopology: - addTopology(context.getGUID(0), (Area) context.get(1)); + addTopology(context.getGUID(0), (Area) context.get(1), (TopologyMode) context.get(2)); break; case removeTopology: - removeTopology(context.getGUID(0), (Area) context.get(1)); + removeTopology(context.getGUID(0), (Area) context.get(1), (TopologyMode) context.get(2)); break; case renameZone: renameZone(context.getGUID(0), context.getString(1)); @@ -777,15 +778,15 @@ public void setServerPolicy(ServerPolicy policy) { forwardToClients(); } - public void addTopology(GUID zoneGUID, Area area) { + public void addTopology(GUID zoneGUID, Area area, TopologyMode topologyMode) { Zone zone = server.getCampaign().getZone(zoneGUID); - zone.addTopology(area); + zone.addTopology(area, topologyMode); forwardToClients(); } - public void removeTopology(GUID zoneGUID, Area area) { + public void removeTopology(GUID zoneGUID, Area area, TopologyMode topologyMode) { Zone zone = server.getCampaign().getZone(zoneGUID); - zone.removeTopology(area); + zone.removeTopology(area, topologyMode); forwardToClients(); } diff --git a/src/main/resources/net/rptools/maptool/client/image/tool/ignore-vbl-on-move.png b/src/main/resources/net/rptools/maptool/client/image/tool/ignore-vbl-on-move.png new file mode 100644 index 0000000000000000000000000000000000000000..fa25af47177cb2ceb05305eb5c66458023b56417 GIT binary patch literal 3011 zcmbVOc|4T)AD@t$lv*02#vm%k+{VOc&Ws}WXi3J*gNZrJOlBw@q;YQgxmL=NjgGC= zAt5$LCb^Z(xk6S&p_GcUqpkh@{@B<4@q1p+@%?x-{qm)*s<<~kPhc$zVyd6miytDEFogh!$mRzFP&$_x3U~rcc64Mj-~a+Chj6_8 z#D1>3@GL&phPkX`BjpMdXb{N3Nh)Bn!T~Wf7zpL?9AVSdzrvs#wj+#zafQ1I$Uqp! zIYtP0#khI1V!~PWY?u=P>LA4{2)KZl36*jqcp|*i5%z@_uUIc{+rpq=3*s zh4$5!LUM$KiNylEt*t~Nv5}x`_`*uC9L*^F&`0rAV2rlqs-9*uZVM+~v5wXp6+2z<=HN zM{SXJv;eU61VsD;LYAT)A*SEJiroFXp=CvdH~8H`j-n{c2nwHdfD7=%bc!QP@y3SD zVdD`*Dg}+kVR1+*k%~beh!l)Hjtr*}70JYrNbqkQ|AZxxY4#|jy&W2DM?xT|L>vu6 zwI`7=G&q$?rqRgXuymeC%;d3vZ+1BfyI--`f5qa-LVzje3%&XLh;JR>9>y2*MPYma zlx>YBAwdBEDPrTuJsdU{s68eOU)Q(0r-7E$o>;49Jf zG>vwA!T3V$(!%^gY-^fP8{AbNBCj8#%Sv7(HY1*n1Mw3pwFw#@k9JdM^pdv^Yb7|*O2=v)d@PdctdQpY)n&O=^Q z>1La+Ak6`_gM;G(!-IR;g}(DO3#(0X9~ow2bS{TocDvuCsTz{kU;^=2HrafB(F05pv#*>|zl6ujJBPy0RhMowE!F@ZrK8Nu+L}cl2r20DfGw6= z%k9*o#;f+Ok(3=jb6VW!P`-FG0MZ?xd%1-(40CQzv*WkC%aF%(MOtY3oZsy4cN&kX z%<1pc`PeB=RDxfrPo}2aSZx_Z3ucXNs~>61my?S>vMUV*o7GM*e{yN;dpWvWrMc#9 z>$QQw(gi1~j7tbOw@x>yq&0(X@rb;|y#dZyQeV6B_8<-3eQ2$14RUC2P1pk)A0zDC z3f8LfaHRH7&VF3W^_$G@E!9Ic&l{Tq-C|kB*p0(+)Vfv7Sr0Ue0;tZ!Y7OJ~Xi!x%e_Oc69c3dd8Ub+l4o`Dt=G)I|&Js z#Xd86&8f!j>yuF@B-@#sr%JA}GI$t!Q$zhz^Ty|MJ$r}JxCTdLAoZU{h=-y^SG*#0 z1|%Gwe&U^P)tyiurDb%Sb!c?fx zT~B;>M7t-ESR`o(t)7Vy=~K#ZXBo%lb86#PlOwSjxV`95acoBDQrSzC>EUKd@j zz*eMAY;M5o_P`zsM9nybOEyAZfd7#uPQ;F@f`bf?fS9|wF^$KvA&X9cMCIS za_T{comkeYrn=fI8>EkZIfsVAI^++TESt{!bOWHzGMr;vlwo=_4wQ6lo2B3#^iC9p z@S)#E8id>6GPU`ZtfwSA}^oyNnwkJ{sAD=%EV zNRIvFzy^TP=Jcf5$TpIRXGVRJkB1=zz|ZuPt2>aP%W@vw%-6ZQ*mVU zb-5v}VRI?3my#dHC{4$h23TcJvF)w5%HRB$w{6I652Go|Xd->G+@xiq>F4-RM0NPu zE%)l0%@d@9eliRBKv(ah6IC0MQ+mQ@LuSEqZ%gYQ08r~8O$_ty2;3w&)upd8OG{Pl zB<`UD2DsNgXB)E?LKu#}y098|2mf0dnrY58BRfrJ8;p9oS@*sHld{3$tk=C=J#qIW zuST;vO{Q{h>FDBflh6EE2-&BrmbZ>|nuiue+8_Qsr{&#uD@)q?kCZ8si^01XAW{G4 z#PL8PF z2+I5fTfua(Ug-BR20h10k~Qt97mdJ?!Nj?Z((otK=@;Ui07lSsX4;cJnEG$Q4;bh5 zxRrwIQHQ)2l^0EZ;l;Jv4R4c0*KKMPYi-$THDlmuqjZq+xR+4BCh%la=1E81*yl?= zgv^5*#^lBaN4n8x+~%3{nL2uVj8wde_IMyr7(ECO;h77M>{2Vp4s^s0rOIs-Z0Y+yiII!nGS>Q+AzNV9M_M z$36`E?~ZgF-}!N%u=Q;v7ks_G?Kb2+@-^6?II6_QO%xKbRz+@}LRArccu=kpTL>|g zI=VP*vpO5F_fAihT>}N(R;v1w7HF#4g(+B(@P0@7Y*tQ2VmI$SVo@tU=kZo2#{Jo%=amCq z9>l08zW!^uFOeVByi<1^2m|*>f4EDxxS!Jy?4ofJ=0rU4xcik5n9`PwlP_Hg%cygZ zq`%*{S@C6kx1r@4qh`Z9BP|15c3ZxA)^QSDZ5-z2qjTvexVaI!xt$W>+f7tInA+ZK zaeREht8X+{zeTj;96c1R+Ypgve$%%)-pT#@{J`g6$kKkRH3b??H@nPNpGeP3&UPr> plcEZc#&)*>T6*V~jCFa}{cGO&LcrW(LDt=3pF~qO>GM!fKJ&lueE$ zAtFZyNwtVo$Zn<7B1cj@qs>0gAN$%rp5OWXe1D(!`*Xiuzhw8lyVN%sYytoP>MqU{ zPsLk*Pu~q~rl_B*K21}!uVh(`F76x%ZE_`MP$CJZkM@QV{-~j-oU@n~@ zWzhEESVBIOxuOG=^F<0Y0DyOriI|;6EE~fN9%f=yy zR0 z;6$`70)-;2VqF9hDO14WtlH%&?0&^!{}qcPi#bfGP)rvJd8-}Z9x9XyC80tQi0p*{ zS$cB?Y+;ndYNb4XMN8p`xse?9PO*>=`jTH9_aE$|?8rzv3K0%Rp>|S~= zP>6K-AbWo_Pj_B#=|%oPUSne424S`{cij2s^x%+Z z^NMq^$yhS(3G?q?|3LCRg;cR;n-Am!r}JGR$T=tfWbZ`$=i2*D3sc?qHSraNt#C=c zKeV6^U1s5H;P}IRV4_#$LJnvWXw;;Bb69iVY~Xgs<8jXbomC?d5B347`P&R{_f=l` z%;r$rvj`3Iw&EK)O@yp0>C+%=w@i277xQxa-}JBd$2pE);$oMpY+^4=es1iKKhpDN z#;Fy4qu*MX&7SI&8t}=jE<-?B#MlenE!oqVhj;5$@tR?ioz_&Lq^LHm*LBt}BW&hU zKs4-jmBqWYh=bIn6sXaW^KKiJfAwY$EI#TDcbP46V*x*cRUa2;P}5vP-W}SF;2jra zsr#(;&DF(EiS$dup0?9*4R$}=xk*6PvWI^j&*ZTm2Y)*WQN%vZ{I@u&jhTCDRCQH*wug3ctXt>G-$Y(_8!wN(@$!$ zM*ld54a=EtC^d*%_;A;13HIlyZ_k8yc$R{+w9d<;RgjGqdWYhsx_8?UUTU3AWQ5|< z{2Zc2qg2Za-^7tT8t*yYbQ?5vpCH9K>TKMSdjn~3a$>yUN4g^(zww-}o*5u5WE5$b z1LKNQ_Qee__5#k$kL+w8Zhkv>qF0aZF^w|BU03=ky)RHkyK5wKbO`nB2JSYibi7$* zdp2^LhViytIMt&?MsP#TR&yLrscs0290wvVBiLR=J;>UT;tZhrC#AXW;qwWAo%Po4 zpIc&kO2Q*b!;NxZTrIi0m}ELVGB))gB_p&m>Z<>N?U;eB?#Zzl0~0#HD5JFwn&p{C zZMJEx&wgh}kt1^6lICLLn^XS4B*82LhvT$=SZ{1zh3M*<`rvyeH7$~R?#;AC=%pvS z(D!|M`)@jDI@8yzVRv|FrxXhG2|BXOtjm*~m~|b8ZDJ}ni|UR9|CTN z=;7qKrG0X|wW$|$I%boMGxlUkYGL5_+e1n8Vb_R2_7+jziy2REr{GT6s|Ti9&qL2V zs4nt~)4kRPD&5~xL2ov87tQ&n{(gtLos;~~a@ga^=5{!cjaI5KudGBRBwdTVer=s~ zb_wsrh^YnK!8WaKA-XMUAhc04=f*_)SS3W|Y58f_9B0!t?P~%RA_loWVCHZR=B8^7U-d5u!y-} z=9%c6oN`r?J=roEAeDtwW~wBzS|{(IpI@O_zqz=;+i(0r{__<)vQ-$mY4o$huI9N+ zR@va;j~#%)(*1?Y!JF#u1qsNo@725Vp~U-a)bkd#n58(45ZFcS0uSfMVcIHp;qNu# znr@jQ%`Z!wj8D*vXE%Vqq4hrOnfhck#EagL^0Z59=vp*e zykjoVpyMqbn?LPvNwiC*&Tk>2?&nGaKn1C%_VK53F(ftnkd zSGqL+t4VFVo${e2uc7+aWLAjIn`beaXCb>8Ip)-F{8h6|-Xdh!i$s8iRqN9c-wvxs zGj|eoNW{^UvB`pn>e!+8PVytwcXRCapuGLwE}B~m4oz;g%IWtzpLgJte)yKrUN4n& z;hsl3u*OcRSr_Wt9Ln5VTvg@8e2rT~4L>{UR}4t_q4@FL8NWMNry#EzH&*=e#PV@< zd3w(J{be)H{+xn$y=CYO=o|MmYELz(RO=<)QG+Ck4sG`DJIwN$Yb(f)Dtzfr&zyQv z<VQbJGKBA$e&M3B$5`~JdS~!(F}3XS7{ACoMmE!;Tz*x*Eb+AhcqG*McgGwbt5Y@87QE>={+(Oo)!9Cn%`3-8;Adz8 zTP$icVg#IZiPeq#{>rFH=Pe5x3$-ok@A5ZyE`O7pQlh%HsADeV{r;P;H)~wwsnsZ# zc%2G)To-9zrrDSg%$TcUj+gAo)32b-?L3l2>TCDvAoRzt0|I7E^2@X9r_5J=n_Z}T KDOX8>3I74HnfH4D literal 0 HcmV?d00001