actionMap) {
public void mouseDragged(MouseEvent e) {
super.mouseDragged(e);
- if (isDraggingDrawings) {
+ if (isDraggingDrawings && selectedTool.equals(TemplatePointerTool.class)) {
ZonePoint dragTargetCell = getCellAtMouse(e);
if (!dragWorkingCell.equals(dragTargetCell)) {
-
for (DrawnElement de : draggedDrawnElementSet) {
- // Currently drag templates only
Drawable d = de.getDrawable();
if (d instanceof AbstractTemplate at) {
updateDraggedDrawnElements(e, at);
@@ -272,6 +274,26 @@ public void mouseDragged(MouseEvent e) {
dragWorkingCell = dragTargetCell;
renderer.repaint();
}
+
+ } else if (isDraggingDrawings && selectedTool.equals(DrawingPointerTool.class)) {
+ ZonePoint dragTargetZonePoint =
+ new ScreenPoint(e.getX(), e.getY()).convertToZone(renderer.getViewModel().getZoneScale());
+ if (e.isControlDown()) {
+ dragTargetZonePoint = renderer.getZone().getGrid().getNearestVertex(dragTargetZonePoint);
+ }
+ for (DrawnElement de : draggedDrawnElementSet) {
+ Drawable d = de.getDrawable();
+ if (d instanceof DrawablesGroup dg) {
+ updateDraggedDrawnElements(e, dg);
+ } else if (d instanceof ShapeDrawable sd) {
+ updateDraggedDrawnElements(e, sd);
+ } else if (d instanceof LineSegment ls) {
+ updateDraggedDrawnElements(e, ls);
+ }
+ }
+ dragWorkingZonePoint = dragTargetZonePoint;
+ renderer.repaint();
+
} else if (isDraggingSelectionBox) {
int x1 = dragStartPoint.x;
int y1 = dragStartPoint.y;
@@ -452,25 +474,24 @@ public void mouseReleased(MouseEvent e) {
for (DrawnElement de : drawableList) {
Drawable d = de.getDrawable();
- // Only select drawing types relevant to the tool
- // Object selectedTool = MapTool.getFrame().getToolbox().getSelectedTool().getClass();
+ // Only select drawn element types relevant to the tool
boolean isTemplate = isTemplate(de);
if (selectedTool == TemplatePointerTool.class && isTemplate
|| selectedTool == DrawingPointerTool.class && !isTemplate) {
GUID id = d.getId();
- // Check if the template bounds is within the bounds of the selection box
+ // Check if the drawable bounds is within the bounds of the selection box
if (zoneTemplateSelectionBox.contains(d.getBounds(zone))) {
boolean isControlCheck = true;
boolean isAltCheck = true;
- // CTRL key - check if the template border color matches the color picker
+ // CTRL key - check if the border color matches the color picker
if (e.isControlDown()) {
isControlCheck =
drawablePaintToString(de.getPen().getPaint())
.equals(drawablePaintToString(getPen().getPaint()));
}
- // ALT key - check if the template fill color matches the color picker
+ // ALT key - check if the fill color matches the color picker
if (e.isAltDown()) {
isAltCheck =
drawablePaintToString(de.getPen().getBackgroundPaint())
@@ -609,17 +630,20 @@ public void paintOverlay(ZoneRenderer renderer, Graphics2D g) {
*/
private void dragDrawnElementsStart(MouseEvent e) {
- if (isTemplate(drawnElementAtMouse)) {
- renderer.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
- }
+ renderer.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
isDraggingDrawings = true;
isDraggingSelectionBox = false;
dragStartPoint = new Point(e.getX(), e.getY());
dragWorkingCell = getCellAtMouse(e);
+ dragWorkingZonePoint =
+ new ScreenPoint(e.getX(), e.getY()).convertToZone(renderer.getViewModel().getZoneScale());
if (drawnElementAtMouse.getDrawable() instanceof AbstractTemplate at) {
dragStartVertex = new ZonePoint(at.getVertex());
+ } else {
+ dragStartVertex = renderer.getZone().getGrid().getNearestVertex(dragWorkingZonePoint);
}
+
setDraggedDrawnElementsSet();
}
@@ -851,8 +875,11 @@ void onZoneActivated(ZoneActivated event) {
}
/**
- * Paints the drawings which are being changed via dragging. This could be a change in position,
- * path, radius, direction, etc.
+ * Paints the drawables which are being changed via dragging.
+ *
+ * For templates this could be a change in position, path, radius, direction, etc.
+ *
+ *
For drawings this is just a change in position
*
* @param g where to paint.
*/
@@ -862,8 +889,9 @@ private void paintDraggedDrawings(Graphics2D g) {
for (DrawnElement de : draggedDrawnElementSet) {
if (de != null) {
- // Templates only
if (de.getDrawable() instanceof AbstractTemplate at) {
+ // i.e. templates only
+
Pen pen = de.getPen();
AffineTransform oldTransform = g.getTransform();
AffineTransform newTransform = g.getTransform();
@@ -890,6 +918,36 @@ private void paintDraggedDrawings(Graphics2D g) {
if (drawnElementAtMouse.getDrawable().getId() == at.getId()) {
paintTemplateMovementLabel(g, dragStartVertex, at);
}
+
+ } else if (de.getDrawable() instanceof LineSegment ls) {
+ // e.g. points and lines
+
+ AffineTransform oldTransform = g.getTransform();
+ AffineTransform newTransform = g.getTransform();
+ newTransform.concatenate(getPaintTransform(renderer));
+ g.setTransform(newTransform);
+ ls.draw(getZone(), g, de.getPen());
+ g.setTransform(oldTransform);
+
+ } else if (de.getDrawable() instanceof ShapeDrawable sd) {
+ // e.g. rectangles, ellipses, etc
+
+ AffineTransform oldTransform = g.getTransform();
+ AffineTransform newTransform = g.getTransform();
+ newTransform.concatenate(getPaintTransform(renderer));
+ g.setTransform(newTransform);
+ sd.draw(getZone(), g, de.getPen());
+ g.setTransform(oldTransform);
+
+ } else if (de.getDrawable() instanceof DrawablesGroup dg) {
+ // groups of drawables (inc. other groups)
+
+ AffineTransform oldTransform = g.getTransform();
+ AffineTransform newTransform = g.getTransform();
+ newTransform.concatenate(getPaintTransform(renderer));
+ g.setTransform(newTransform);
+ dg.draw(getZone(), g, de.getPen());
+ g.setTransform(oldTransform);
}
}
} // end for
@@ -1134,9 +1192,12 @@ private void paintTemplateRadiusLabel(Graphics2D g, ZonePoint zp, AbstractTempla
}
/**
- * Creates a copy of the {@link DrawnElement}s being dragged. This {@link Set} is used for
- * displaying the dragged drawings. e.g. for templates this could be either a change in position,
- * path, direction, and/or size.
+ * Creates a copy of the {@link DrawnElement}s being dragged and stores their pre-drag bounds.
+ *
+ *
The {@link Set} is used for displaying the dragged drawings. e.g. for templates this could
+ * be either a change in position, path, direction, and/or size.
+ *
+ *
The {@link Map} is used when snapping drawings to grid whilst dragging.
*
*
In the event of the Escape key being pressed while dragging, any changes to
* dragged drawings will not be applied to the original drawings.
@@ -1145,20 +1206,41 @@ private void setDraggedDrawnElementsSet() {
List drawableList = getDrawnElementsOnLayerList(false);
draggedDrawnElementSet.clear();
+ draggedStartBoundsMap.clear();
if (!selectedDrawableIdSet.isEmpty()) {
for (DrawnElement de : drawableList) {
Drawable d = de.getDrawable();
GUID id = d.getId();
if (selectedDrawableIdSet.contains(id)) {
- if (d instanceof AbstractTemplate) {
- DrawnElement deCopy = new DrawnElement(de);
- draggedDrawnElementSet.add(deCopy);
+ DrawnElement deCopy = new DrawnElement(de);
+ draggedDrawnElementSet.add(deCopy);
+ draggedStartBoundsMap.put(id, de.getDrawable().getBounds(getZone()));
+ if (d instanceof DrawablesGroup dg) {
+ setGroupDraggedStartBoundsMap(dg);
}
}
}
}
}
+ /**
+ * Get the bounds of the drawables group contents, recursively if there are child groups.
+ *
+ * @param dg the drawables group
+ */
+ private void setGroupDraggedStartBoundsMap(DrawablesGroup dg) {
+
+ for (DrawnElement de : dg.getDrawableList()) {
+ if (de.getDrawable() instanceof DrawablesGroup dg2) {
+ setGroupDraggedStartBoundsMap(dg2);
+ } else if (de.getDrawable() instanceof LineSegment ls) {
+ draggedStartBoundsMap.put(ls.getId(), ls.getBounds(getZone()));
+ } else if (de.getDrawable() instanceof ShapeDrawable sd) {
+ draggedStartBoundsMap.put(sd.getId(), sd.getBounds(getZone()));
+ }
+ }
+ }
+
/**
* Helper method that sets the path vertex for the template (for known template types that have
* them), but prevents setting it where it would equal the vertex.
@@ -1198,6 +1280,96 @@ private void updateDrawablesPanel() {
}
}
+ private void updateDraggedDrawnElements(MouseEvent e, DrawablesGroup dg) {
+
+ if (!MapTool.getPlayer().isGM() && MapTool.getServerPolicy().isMovementLocked()) {
+ // i.e. not allowed
+ return;
+ }
+
+ for (DrawnElement de : dg.getDrawableList()) {
+ if (de.getDrawable() instanceof DrawablesGroup dg2) {
+ updateDraggedDrawnElements(e, dg2);
+ } else if (de.getDrawable() instanceof LineSegment ls) {
+ updateDraggedDrawnElements(e, ls);
+ } else if (de.getDrawable() instanceof ShapeDrawable sd) {
+ updateDraggedDrawnElements(e, sd);
+ }
+ }
+ }
+
+ private void updateDraggedDrawnElements(MouseEvent e, LineSegment ls) {
+
+ if (!MapTool.getPlayer().isGM() && MapTool.getServerPolicy().isMovementLocked()) {
+ // i.e. not allowed
+ return;
+ }
+
+ ZonePoint dragPointOffset =
+ new ScreenPoint(e.getX(), e.getY()).convertToZone(renderer.getViewModel().getZoneScale());
+
+ if (e.isControlDown()) {
+ // Snap to grid based on the drawing's original (i.e. pre-dragged) position.
+ ZonePoint dragNearestVertex = renderer.getZone().getGrid().getNearestVertex(dragPointOffset);
+ dragPointOffset.x =
+ dragStartVertex.x
+ - draggedStartBoundsMap.get(ls.getId()).getBounds().x
+ - dragNearestVertex.x
+ + ls.getBounds(getZone()).x;
+ dragPointOffset.y =
+ dragStartVertex.y
+ - draggedStartBoundsMap.get(ls.getId()).getBounds().y
+ - dragNearestVertex.y
+ + ls.getBounds(getZone()).y;
+ } else {
+ // Not snapping to grid
+ dragPointOffset.x = dragWorkingZonePoint.x - dragPointOffset.x;
+ dragPointOffset.y = dragWorkingZonePoint.y - dragPointOffset.y;
+ }
+
+ ls.translate(-dragPointOffset.x, -dragPointOffset.y);
+ }
+
+ private void updateDraggedDrawnElements(MouseEvent e, ShapeDrawable sd) {
+
+ if (!MapTool.getPlayer().isGM() && MapTool.getServerPolicy().isMovementLocked()) {
+ // i.e. not allowed
+ return;
+ }
+
+ ZonePoint dragPointOffset =
+ new ScreenPoint(e.getX(), e.getY()).convertToZone(renderer.getViewModel().getZoneScale());
+
+ if (e.isControlDown()) {
+ // Snap to grid based on the drawing's original (i.e. pre-dragged) position.
+ ZonePoint dragNearestVertex = renderer.getZone().getGrid().getNearestVertex(dragPointOffset);
+ dragPointOffset.x =
+ dragStartVertex.x
+ - draggedStartBoundsMap.get(sd.getId()).getBounds().x
+ - dragNearestVertex.x
+ + sd.getBounds().x;
+ dragPointOffset.y =
+ dragStartVertex.y
+ - draggedStartBoundsMap.get(sd.getId()).getBounds().y
+ - dragNearestVertex.y
+ + sd.getBounds().y;
+ } else {
+ // Not snapping to grid
+ dragPointOffset.x = dragWorkingZonePoint.x - dragPointOffset.x;
+ dragPointOffset.y = dragWorkingZonePoint.y - dragPointOffset.y;
+ }
+
+ if (sd.getShape() instanceof RectangularShape rs) {
+ rs.setFrame(
+ rs.getBounds().x - dragPointOffset.x,
+ rs.getBounds().y - dragPointOffset.y,
+ rs.getWidth(),
+ rs.getHeight());
+ } else if (sd.getShape() instanceof Polygon p) {
+ p.translate(-dragPointOffset.x, -dragPointOffset.y);
+ }
+ }
+
/**
* Handles moving the template by moving the vertex and (if relevant) the pathVertex.
*
@@ -1289,30 +1461,11 @@ private void updateOriginalDrawnElements() {
for (DrawnElement deDragged : draggedDrawnElementSet) {
GUID id = deDragged.getDrawable().getId();
if (id == deOriginal.getDrawable().getId()) {
- if (deOriginal.getDrawable() instanceof AbstractTemplate atOriginal
- && deDragged.getDrawable() instanceof AbstractTemplate atDragged) {
-
- // Update the radius and vertex (all templates have these)
- atOriginal.setVertex(atDragged.getVertex());
- atOriginal.setRadius(atDragged.getRadius());
-
- // Update the path vertex (if applicable to the template type)
- setTemplatePathVertex(atOriginal, getTemplatePathVertex(atDragged));
-
- // Update other special things (applicable to specific template types)
- String templateType = getTemplateType(atOriginal);
- if (templateType.equals("BlastTemplate")) {
- int OffsetX = ((BlastTemplate) atDragged).getOffsetX();
- int OffsetY = ((BlastTemplate) atDragged).getOffsetY();
- ((BlastTemplate) atOriginal).setControlCellOffset(OffsetX, OffsetY);
- } else if (templateType.equals("ConeTemplate")) {
- ((ConeTemplate) atOriginal).setDirection(((ConeTemplate) atDragged).getDirection());
- }
+ deOriginal.setDrawable(deDragged.getDrawable());
- // Server drawing update
- MapTool.serverCommand().updateDrawing(zone.getId(), deOriginal.getPen(), deOriginal);
- renderer.getZone().updateDrawable(deOriginal, deOriginal.getPen());
- }
+ // Server drawing update
+ MapTool.serverCommand().updateDrawing(zone.getId(), deOriginal.getPen(), deOriginal);
+ renderer.getZone().updateDrawable(deOriginal, deOriginal.getPen());
}
} // end for
} // end for
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 dd6fee0e50..e36125fae9 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
@@ -92,9 +92,7 @@ public DrawPanelPopupMenu(
add(new SetPropertiesAction());
add(new SetDrawingName());
add(new GetDrawingId());
- if (isDrawnElementTemplate(elementUnderMouse)) {
- add(new DuplicateDrawingAction(selectedDrawSet));
- }
+ add(new DuplicateDrawingAction(selectedDrawSet));
addGMItem(new JSeparator());
add(createPathVblMenu());
add(createShapeVblMenu());
@@ -178,11 +176,7 @@ public void actionPerformed(ActionEvent e) {
}
}
- /**
- * Duplicates selected drawings...
- *
- * ... but currently limited to templates only as we can drag and manipulate those
- */
+ /** Duplicates selected drawings... */
public static class DuplicateDrawingAction extends AbstractAction {
public DuplicateDrawingAction() {
@@ -208,18 +202,15 @@ public void actionPerformed(ActionEvent e) {
return;
}
- // check to see if this is the required action
for (GUID id : selectedDrawings) {
DrawnElement de = renderer.getZone().getDrawnElement(id);
Drawable d = de.getDrawable();
- if (de.getDrawable() instanceof AbstractTemplate) {
- AbstractTemplate at = (AbstractTemplate) d.copy();
- at.setId(new GUID());
- // Draw it
- MapTool.serverCommand().draw(renderer.getZone().getId(), de.getPen(), at);
- // Allow it to be undone
- renderer.getZone().addDrawable(de.getPen(), at);
- }
+ AbstractDrawing ad = (AbstractDrawing) d.copy();
+ ad.setId(new GUID());
+ // Draw it
+ MapTool.serverCommand().draw(renderer.getZone().getId(), de.getPen(), ad);
+ // Allow it to be undone
+ renderer.getZone().addDrawable(de.getPen(), ad);
}
renderer.repaint();
MapTool.getFrame().updateDrawTree();
diff --git a/src/main/java/net/rptools/maptool/model/drawing/LineSegment.java b/src/main/java/net/rptools/maptool/model/drawing/LineSegment.java
index 7b01a4c000..18e615e63d 100644
--- a/src/main/java/net/rptools/maptool/model/drawing/LineSegment.java
+++ b/src/main/java/net/rptools/maptool/model/drawing/LineSegment.java
@@ -130,6 +130,19 @@ public List getPoints() {
return Collections.unmodifiableList(points);
}
+ /**
+ * Translate the line segment
+ *
+ * @param deltaX offset in the X axis
+ * @param deltaY offset in the Y axis
+ */
+ public void translate(int deltaX, int deltaY) {
+ points.replaceAll(point1 -> new Point(point1.x + deltaX, point1.y + deltaY));
+ if (cachedBounds != null) {
+ cachedBounds.translate(deltaX, deltaY);
+ }
+ }
+
@Override
public @Nonnull Area getArea(Zone zone) {
if (area == null) {