From 02285cbf278b0c07ac1a720031b2dfc7536b5fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sun, 4 May 2025 10:46:48 +0200 Subject: [PATCH] Added: #2370 Snap to guides --- CHANGELOG.md | 1 + .../decompiler/flash/gui/ImagePanel.java | 109 +++++++++++++----- 2 files changed, 82 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f8617b4c..605f2a782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - [#2370] Objects display - Option to show horizontal and vertical rulers - [#2370] Objects display - Create guides by dragging from a ruler - Objects dragging - show touch point and snap it to 9 important points around object rectangle +- [#2370] Snap to guides ### Fixed - [#2424] DefineEditText handling of letterSpacing, font size on incorrect values diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index cb90c3f3c..7a88c0aa4 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -294,7 +294,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private RegistrationPointPosition registrationPointPosition = RegistrationPointPosition.CENTER; private DepthState depthStateUnderCursor = null; - + private List allDepthStatesUnderCursor = null; private List placeObjectSelectedListeners = new ArrayList<>(); @@ -302,11 +302,18 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private Point[] hilightedEdge = null; private List hilightedPoints = null; - + private DisplayPoint touchPointOffset = null; - + private static final int TOUCH_POINT_DISTANCE = 15; + private DisplayPoint snapOffset = new DisplayPoint(0, 0); + + private static final int SNAP_DISTANCE = 10; + + //TODO: Move this to config + private static final boolean SNAP_TO_GUIDES = true; + //private DisplayPoint closestPoint = null; private List pointsUnderCursor = new ArrayList<>(); private List selectedPoints = new ArrayList<>(); @@ -1125,15 +1132,16 @@ public final class ImagePanel extends JPanel implements MediaDisplay { g2.draw(new Rectangle2D.Double(selectionRect.getX(), selectionRect.getY(), selectionRect.getWidth(), selectionRect.getHeight())); g2.setComposite(AlphaComposite.SrcOver); } - + if (touchPointOffset != null) { double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - g2.setStroke(new BasicStroke((float) (1 / zoomDouble))); - DisplayPoint p = new DisplayPoint(lastMouseEvent.getX() + touchPointOffset.x, lastMouseEvent.getY() + touchPointOffset.y); - double pointSize = 3 / zoomDouble; + boolean snapped = snapOffset.x != 0 || snapOffset.y != 0; + g2.setStroke(new BasicStroke((float) ((snapped ? 2 : 1) / zoomDouble))); + DisplayPoint p = new DisplayPoint(lastMouseEvent.getX() + touchPointOffset.x + snapOffset.x, lastMouseEvent.getY() + touchPointOffset.y + snapOffset.y); + double pointSize = (snapped ? 4 : 3) / zoomDouble; Shape pointShape = new Ellipse2D.Double(p.x - pointSize, p.y - pointSize, pointSize * 2, pointSize * 2); g2.setPaint(Color.black); - g2.draw(pointShape); + g2.draw(pointShape); } } } catch (InternalError ie) { @@ -1436,35 +1444,32 @@ public final class ImagePanel extends JPanel implements MediaDisplay { matrix = matrix.preConcatenate(new Matrix(ds.matrix)); } } - + Matrix scaleMatrix = Matrix.getScaleInstance(getRealZoom() / SWF.unitDivisor); - - matrix = matrix.preConcatenate(scaleMatrix); + + matrix = matrix.preConcatenate(scaleMatrix); matrix = matrix.preConcatenate(Matrix.getTranslateInstance(offsetPoint.getX(), offsetPoint.getY())); - + Point2D cursorPos = new Point2D.Double(e.getX(), e.getY()); - + DepthState lastDs = allDepthStatesUnderCursor.get(0); - CharacterTag ch = lastDs.getCharacter(); + CharacterTag ch = lastDs.getCharacter(); if (ch != null) { if (ch instanceof BoundedTag) { BoundedTag bt = (BoundedTag) ch; RECT rect = bt.getRect(); - - Point2D[] importantPoints = new Point2D[] { + + Point2D[] importantPoints = new Point2D[]{ new Point2D.Double(rect.Xmin, rect.Ymin), new Point2D.Double((rect.Xmin + rect.Xmax) / 2.0, rect.Ymin), new Point2D.Double(rect.Xmax, rect.Ymin), - new Point2D.Double(rect.Xmin, (rect.Ymin + rect.Ymax) / 2.0), new Point2D.Double((rect.Xmin + rect.Xmax) / 2.0, (rect.Ymin + rect.Ymax) / 2.0), new Point2D.Double(rect.Xmax, (rect.Ymin + rect.Ymax) / 2.0), - new Point2D.Double(rect.Xmin, rect.Ymax), new Point2D.Double((rect.Xmin + rect.Xmax) / 2.0, rect.Ymax), - new Point2D.Double(rect.Xmax, rect.Ymax), - }; - + new Point2D.Double(rect.Xmax, rect.Ymax),}; + Point2D nearestPoint = null; double distance = Double.MAX_VALUE; for (Point2D p : importantPoints) { @@ -1475,9 +1480,9 @@ public final class ImagePanel extends JPanel implements MediaDisplay { nearestPoint = windowPoint; } } - + if (distance < TOUCH_POINT_DISTANCE) { - touchPointOffset = new DisplayPoint((int) Math.round(nearestPoint.getX() - cursorPos.getX()), (int) Math.round(nearestPoint.getY() - cursorPos.getY())); + touchPointOffset = new DisplayPoint((int) Math.round(nearestPoint.getX() - cursorPos.getX()), (int) Math.round(nearestPoint.getY() - cursorPos.getY())); } else { touchPointOffset = new DisplayPoint(0, 0); } @@ -1558,8 +1563,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { }*/ } } - - + if (!autoPlayed) { Configuration.autoPlayPreviews.set(true); autoPlayed = true; @@ -1705,6 +1709,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { if (mode != MODE_GUIDE_X && mode != MODE_GUIDE_Y) { mode = Cursor.DEFAULT_CURSOR; } + snapOffset = new DisplayPoint(0, 0); } } @@ -1752,7 +1757,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { repaint(); return; } - } + } if (dragStart != null && allowMove && mode == Cursor.DEFAULT_CURSOR) { Point2D dragEnd = e.getPoint(); Point2D delta = new Point2D.Double(dragEnd.getX() - dragStart.getX(), dragEnd.getY() - dragStart.getY()); @@ -1765,7 +1770,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { iconPanel.calcRect(); _viewRect = getViewRect(); - double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; + double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; synchronized (lock) { @@ -1798,6 +1803,54 @@ public final class ImagePanel extends JPanel implements MediaDisplay { return; } + //snapping + if (dragStart != null && selectionMode && !doFreeTransform) { + Point2D touchPointPos = new Point2D.Double(e.getX(), e.getY()); + if (touchPointOffset != null) { + touchPointPos = new Point2D.Double(e.getX() + touchPointOffset.x, e.getY() + touchPointOffset.y); + } + + int snapOffsetX = 0; + int snapOffsetY = 0; + + if (SNAP_TO_GUIDES) { + Double nearestGuideX = null; + double distance = Double.MAX_VALUE; + double zoomDouble = getRealZoom(); + + for (Double gx : guidesX) { + gx = gx * zoomDouble + offsetPoint.getX(); + double d = Math.abs(gx - touchPointPos.getX()); + if (d < distance) { + distance = d; + nearestGuideX = gx; + } + } + + if (distance < SNAP_DISTANCE) { + snapOffsetX = (int) Math.round(nearestGuideX - touchPointPos.getX()); + } + Double nearestGuideY = null; + distance = Double.MAX_VALUE; + + for (Double gy : guidesY) { + gy = gy * zoomDouble + offsetPoint.getY(); + + double d = Math.abs(gy - touchPointPos.getY()); + if (d < distance) { + distance = d; + nearestGuideY = gy; + } + } + + if (distance < SNAP_DISTANCE) { + snapOffsetY = (int) Math.round(nearestGuideY - touchPointPos.getY()); + } + } + + snapOffset = new DisplayPoint(snapOffsetX, snapOffsetY); + } + //move in selection mode if (dragStart != null && selectionMode && !doFreeTransform) { if (transform == null) { @@ -1805,7 +1858,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } Matrix parentMatrix = getParentMatrix(); - Point2D mouseTransPoint = toTransformPoint(new Point2D.Double(e.getX(), e.getY())); + Point2D mouseTransPoint = toTransformPoint(new Point2D.Double(e.getX() + snapOffset.x, e.getY() + snapOffset.y)); double ex = mouseTransPoint.getX(); double ey = mouseTransPoint.getY(); Point2D dragStartTransPoint = toTransformPoint(dragStart);