From 040ee8e0117297240fc3360108bcab43d3a6eeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Thu, 29 Dec 2022 19:40:52 +0100 Subject: [PATCH] Basic points moving --- .../decompiler/flash/gui/DisplayPoint.java | 46 +++++ .../decompiler/flash/gui/ImagePanel.java | 193 ++++++++++++++---- .../flash/gui/PointUpdateListener.java | 31 +++ .../decompiler/flash/gui/PreviewPanel.java | 162 +++++++++++++-- .../flash/gui/graphics/cursors/default.png | Bin 0 -> 6244 bytes .../flash/gui/graphics/cursors/move_point.png | Bin 0 -> 6272 bytes .../flash/gui/locales/MainFrame.properties | 5 +- .../flash/gui/locales/MainFrame_cs.properties | 5 +- 8 files changed, 380 insertions(+), 62 deletions(-) create mode 100644 src/com/jpexs/decompiler/flash/gui/DisplayPoint.java create mode 100644 src/com/jpexs/decompiler/flash/gui/PointUpdateListener.java create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/cursors/default.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/cursors/move_point.png diff --git a/src/com/jpexs/decompiler/flash/gui/DisplayPoint.java b/src/com/jpexs/decompiler/flash/gui/DisplayPoint.java new file mode 100644 index 000000000..fb928ff08 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/DisplayPoint.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +/** + * + * @author JPEXS + */ +public class DisplayPoint { + public int x; + public int y; + public boolean onPath; + + public DisplayPoint(DisplayPoint src) { + this(src.x, src.y, src.onPath); + } + + public DisplayPoint(int x, int y) { + this(x, y, true); + } + public DisplayPoint(int x, int y, boolean onPath) { + this.x = x; + this.y = y; + this.onPath = onPath; + } + + @Override + public String toString() { + return "["+x+","+y+"]"; + } + +} diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index 19c189b14..89e146cca 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -231,6 +231,8 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private static Cursor selectCursor; private static Cursor shearXCursor; private static Cursor shearYCursor; + private static Cursor movePointCursor; + private static Cursor defaultCursor; private Point2D offsetPoint = new Point2D.Double(0, 0); @@ -253,9 +255,14 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private DepthState depthStateUnderCursor = null; private List placeObjectSelectedListeners = new ArrayList<>(); - + private Point[] hilightedEdge = null; + + private List hilightedPoints = null; + private List pointsUnderCursor = new ArrayList<>(); + private List pointsUnderCursorValues = new ArrayList<>(); + private int hilightEdgeColorStep = 10; private int hilightEdgeColor = 0; @@ -268,21 +275,44 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private SerializableImage imgPlay = null; private List boundsChangeListeners = new ArrayList<>(); + + private List pointUpdateListeners = new ArrayList<>(); + + public void addPointUpdateListener(PointUpdateListener listener) { + pointUpdateListeners.add(listener); + } + public void removePointUpdateListener(PointUpdateListener listener) { + pointUpdateListeners.remove(listener); + } + + private void firePointsUpdated(List points) { + for(PointUpdateListener listener:pointUpdateListeners) { + listener.pointsUpdated(points); + } + } + + private void firePointAdded(int position, DisplayPoint point) { + for(PointUpdateListener listener:pointUpdateListeners) { + listener.pointAdded(position, point); + } + } + + private void firePointRemoved(int position) { + for(PointUpdateListener listener:pointUpdateListeners) { + listener.pointRemoved(position); + } + } + + public void setHilightedPoints(List hilightedPoints) { + this.hilightedPoints = hilightedPoints; + redraw(); + } public void setHilightedEdge(Point[] hilightedEdge) { this.hilightedEdge = hilightedEdge; hilightEdgeColor = 255; - /*if (hilightedEdge == null) { - System.out.println("set no hilight edge"); - } else { - String s = ""; - for(Point p:hilightedEdge) { - s+="["+p.x+","+p.y+"]"; - } - System.out.println("set hilight edge " + s); - }*/ redraw(); - } + } public void addBoundsChangeListener(BoundsChangeListener listener) { boundsChangeListeners.add(listener); @@ -371,7 +401,9 @@ public final class ImagePanel extends JPanel implements MediaDisplay { selectCursor = loadCursor("select", 0, 0); shearXCursor = loadCursor("shear_x", 9, 5); shearYCursor = loadCursor("shear_y", 5, 9); - + movePointCursor = loadCursor("move_point", 0, 0); + defaultCursor = loadCursor("default", 0, 0); + } catch (IOException ex) { Logger.getLogger(MainPanel.class.getName()).log(Level.SEVERE, null, ex); } @@ -481,6 +513,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { this.freeTransformDepth = depth; } hilightedEdge = null; + hilightedPoints = null; registrationPoint = null; calculateFreeTransform(); hideMouseSelection(); @@ -637,7 +670,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { g2.drawImage(img.getBufferedImage(), x, y, x + img.getWidth(), y + img.getHeight(), 0, 0, img.getWidth(), img.getHeight(), null); - if (hilightedEdge != null) { + if (hilightedEdge != null || hilightedPoints != null) { hilightEdgeColor += hilightEdgeColorStep; if (hilightEdgeColor < 100 || hilightEdgeColor > 255) { hilightEdgeColorStep = -hilightEdgeColorStep; @@ -645,43 +678,59 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } RECT timRect = timelined.getRect(); double zoomDouble = zoom.fit ? getZoomToFit() : zoom.value; - AffineTransform t = new AffineTransform(); - t.translate(offsetPoint.getX() - (int) (timRect.Xmin * zoomDouble / SWF.unitDivisor) - , offsetPoint.getY() - (int) (timRect.Ymin * zoomDouble / SWF.unitDivisor)); - t.scale(1/SWF.unitDivisor, 1/SWF.unitDivisor); + AffineTransform t = new AffineTransform(); + t.translate(offsetPoint.getX() - (int) (timRect.Xmin * zoomDouble / SWF.unitDivisor), + offsetPoint.getY() - (int) (timRect.Ymin * zoomDouble / SWF.unitDivisor)); + t.scale(1 / SWF.unitDivisor, 1 / SWF.unitDivisor); t.scale(zoomDouble, zoomDouble); AffineTransform oldTransform = g2.getTransform(); g2.setTransform(t); - g2.setStroke(new BasicStroke((float) (SWF.unitDivisor * 6 / zoomDouble))); - g2.setPaint(new Color(hilightEdgeColor, hilightEdgeColor, hilightEdgeColor)); - Point[] edge = hilightedEdge; - GeneralPath path = new GeneralPath(); - if (edge.length == 2) { - path.moveTo(edge[0].x, edge[0].y); - path.lineTo(edge[1].x, edge[1].y); + + if (hilightedEdge != null) { + g2.setStroke(new BasicStroke((float) (SWF.unitDivisor * 6 / zoomDouble))); + g2.setPaint(new Color(hilightEdgeColor, hilightEdgeColor, hilightEdgeColor)); + Point[] edge = hilightedEdge; + GeneralPath path = new GeneralPath(); + if (edge.length == 2) { + path.moveTo(edge[0].x, edge[0].y); + path.lineTo(edge[1].x, edge[1].y); + } + if (edge.length == 3) { + path.moveTo(edge[0].x, edge[0].y); + path.quadTo(edge[1].x, edge[1].y, edge[2].x, edge[2].y); + } + if (edge.length == 1) { + double crossSize = (SWF.unitDivisor * 10 / zoomDouble); + path.moveTo(edge[0].x - crossSize, edge[0].y); + path.lineTo(edge[0].x + crossSize, edge[0].y); + path.moveTo(edge[0].x, edge[0].y - crossSize); + path.lineTo(edge[0].x, edge[0].y + crossSize); + } + g2.draw(path); + + double pointSize = SWF.unitDivisor * 4 / zoomDouble; + + g2.setPaint(Color.red); + g2.fill(new Ellipse2D.Double(edge[edge.length - 1].x - pointSize, edge[edge.length - 1].y - pointSize, pointSize * 2, pointSize * 2)); + g2.setPaint(Color.green); + g2.fill(new Ellipse2D.Double(edge[0].x - pointSize, edge[0].y - pointSize, pointSize * 2, pointSize * 2)); } - if (edge.length == 3) { - path.moveTo(edge[0].x, edge[0].y); - path.quadTo(edge[1].x, edge[1].y, edge[2].x, edge[2].y); - } - if (edge.length == 1) { - double crossSize = (SWF.unitDivisor * 10 / zoomDouble); - path.moveTo(edge[0].x - crossSize, edge[0].y); - path.lineTo(edge[0].x + crossSize, edge[0].y); - path.moveTo(edge[0].x, edge[0].y - crossSize); - path.lineTo(edge[0].x, edge[0].y + crossSize); - } - g2.draw(path); - double pointSize = SWF.unitDivisor * 4 / zoomDouble; - - g2.setPaint(Color.red); - g2.fill(new Ellipse2D.Double(edge[edge.length - 1].x - pointSize, edge[edge.length - 1].y - pointSize, pointSize * 2, pointSize * 2)); - g2.setPaint(Color.green); - g2.fill(new Ellipse2D.Double(edge[0].x - pointSize, edge[0].y - pointSize, pointSize * 2, pointSize * 2)); + List points = hilightedPoints; + if (points != null) { + g2.setStroke(new BasicStroke((float) (SWF.unitDivisor * 1 / zoomDouble))); + double pointSize = SWF.unitDivisor * 4 / zoomDouble; + for (DisplayPoint p:points) { + Rectangle2D pointRect = new Rectangle2D.Double(p.x - pointSize, p.y - pointSize, pointSize * 2, pointSize * 2); + g2.setPaint(Color.white); + g2.fill(pointRect); + g2.setPaint(Color.black); + g2.draw(pointRect); + } + } g2.setTransform(oldTransform); } - if (!(timelined instanceof SWF) && freeTransformDepth > -1) { + if (!(timelined instanceof SWF) && (freeTransformDepth > -1 || hilightedPoints != null)) { int axisX = 0; int axisY = 0; @@ -800,6 +849,14 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } mouseMoved(e); //to correctly calculate mode, because moseMoved event is not called during dragging setDragStart(e.getPoint()); + + List newPointsUnderCursorValues = new ArrayList<>(); + for (int i:pointsUnderCursor) { + newPointsUnderCursorValues.add(new DisplayPoint(hilightedPoints.get(i))); + } + + pointsUnderCursorValues = newPointsUnderCursorValues; + if (!autoPlayed) { Configuration.autoPlayPreviews.set(true); @@ -858,6 +915,26 @@ public final class ImagePanel extends JPanel implements MediaDisplay { @Override public void mouseDragged(MouseEvent e) { + List points = hilightedPoints; + if (dragStart != null && points != null) { + if (!pointsUnderCursor.isEmpty()) { + + for (int i = 0; i < pointsUnderCursor.size(); i++) { + int pointIndex = pointsUnderCursor.get(i); + DisplayPoint pointStart = pointsUnderCursorValues.get(i); + Point2D dragEnd = e.getPoint(); + Point2D startTransformPoint = toTransformPoint(dragStart); + Point2D endTransformPoint = toTransformPoint(dragEnd); + Point2D delta = new Point2D.Double(endTransformPoint.getX() - startTransformPoint.getX(), endTransformPoint.getY() - startTransformPoint.getY()); + //System.out.println("delta = "+delta); + DisplayPoint newPoint = new DisplayPoint((int)Math.round(pointStart.x + delta.getX()), (int)Math.round(pointStart.y + delta.getY()), pointStart.onPath); + points.set(pointIndex, newPoint); + } + firePointsUpdated(points); + 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()); @@ -1347,6 +1424,32 @@ public final class ImagePanel extends JPanel implements MediaDisplay { @Override public void mouseMoved(MouseEvent e) { + List points = hilightedPoints; + if (points != null) { + Cursor cursor = defaultCursor; + int maxDistance = 5; + List newPointsUnderCursor = new ArrayList<>(); + for (int i = 0; i < points.size(); i++) { + DisplayPoint p = points.get(i); + Point2D ip = toImagePoint(new Point2D.Double(p.x,p.y)); + int ex = e.getX(); + int ey = e.getY(); + if (ex > ip.getX() - maxDistance && ex < ip.getX() + maxDistance) { + if (ey > ip.getY() - maxDistance && ey < ip.getY() + maxDistance) { + cursor = movePointCursor; + newPointsUnderCursor.add(i); + } + } + } + if (dragStart == null) { + pointsUnderCursor = newPointsUnderCursor; + } + + if (getCursor() != cursor) { + setCursor(cursor); + } + return; + } if (freeTransformDepth > -1) { if (bounds == null) { return; @@ -1983,6 +2086,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { this.mutable = mutable; depthStateUnderCursor = null; hilightedEdge = null; + hilightedPoints = null; this.showObjectsUnderCursor = showObjectsUnderCursor; this.registrationPointPosition = RegistrationPointPosition.CENTER; centerImage(); @@ -2019,6 +2123,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { stillFrame = true; zoomAvailable = false; hilightedEdge = null; + hilightedPoints = null; iconPanel.setImg(image); drawReady = true; @@ -2690,7 +2795,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } else { debugLabel.setText(ret.toString()); } - if (freeTransformDepth == -1) { + if (freeTransformDepth == -1 && hilightedPoints == null) { Cursor newCursor; if (iconPanel.isAltDown()) { if (depthStateUnderCursor == null) { diff --git a/src/com/jpexs/decompiler/flash/gui/PointUpdateListener.java b/src/com/jpexs/decompiler/flash/gui/PointUpdateListener.java new file mode 100644 index 000000000..a46a094a6 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/PointUpdateListener.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2022 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import java.util.List; + +/** + * + * @author JPEXS + */ +public interface PointUpdateListener { + public void pointsUpdated(List points); + + public void pointAdded(int position, DisplayPoint point); + + public void pointRemoved(int position); +} diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 35b51e4e9..a76f9e7fd 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -64,6 +64,7 @@ import com.jpexs.decompiler.flash.types.shaperecords.CurvedEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.SHAPERECORD; import com.jpexs.decompiler.flash.types.shaperecords.StraightEdgeRecord; import com.jpexs.decompiler.flash.types.shaperecords.StyleChangeRecord; +import com.jpexs.helpers.Helper; import com.jpexs.helpers.SerializableImage; import java.awt.BorderLayout; import java.awt.CardLayout; @@ -220,6 +221,8 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel private JButton displayEditSaveButton; private JButton displayEditCancelButton; + + private JButton displayEditEditPointsButton; private JPanel parametersPanel; @@ -241,9 +244,12 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel private HexView unknownHexView; - private final int PLACE_EDIT_TRANSFORM = 1; - private final int PLACE_EDIT_RAW = 2; - private int placeEditMode = PLACE_EDIT_RAW; + private final int EDIT_TRANSFORM = 1; + private final int EDIT_RAW = 2; + private final int EDIT_POINTS = 3; + private int displayEditMode = EDIT_RAW; + + private List oldShapeRecords; //used only for flash player private TreeItem currentItem; @@ -731,6 +737,58 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } }); } + + displayEditImagePanel.addPointUpdateListener(new PointUpdateListener() { + @Override + public void pointsUpdated(List points) { + ShapeTag shape = (ShapeTag) displayEditTag; + int pointsPos = 0; + int x = 0; + int y = 0; + for(int i = 0; i < shape.shapes.shapeRecords.size(); i++) { + SHAPERECORD rec = shape.shapes.shapeRecords.get(i); + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateMoveTo) { + scr.moveDeltaX = points.get(pointsPos).x; + scr.moveDeltaY = points.get(pointsPos).y; + pointsPos++; + } + } + if (rec instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) rec; + ser.generalLineFlag = true; + ser.deltaX = points.get(pointsPos).x - x; + ser.deltaY = points.get(pointsPos).y - y; + pointsPos += 1; + ser.simplify(); + } + if (rec instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) rec; + cer.controlDeltaX = points.get(pointsPos).x - x; + cer.controlDeltaY = points.get(pointsPos).y - y; + cer.anchorDeltaX = points.get(pointsPos + 1).x - points.get(pointsPos).x; + cer.anchorDeltaY = points.get(pointsPos + 1).y - points.get(pointsPos).y; + pointsPos += 2; + } + x = rec.changeX(x); + y = rec.changeY(y); + } + shape.getSwf().clearShapeCache(); + displayEditImagePanel.repaint(); + } + + @Override + public void pointAdded(int position, DisplayPoint point) { + } + + @Override + public void pointRemoved(int position) { + + } + + }); + displayEditTransformPanel = new TransformPanel(displayEditImagePanel); //imagePanel.setLoop(Configuration.loopMedia.get()); previewCnt.add(displayEditTransformSplitPane = new JPersistentSplitPane( @@ -837,6 +895,10 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditCancelButton.setMargin(new Insets(3, 3, 3, 10)); displayEditCancelButton.addActionListener(this::cancelDisplayEditTagButtonActionPerformed); + displayEditEditPointsButton = new JButton(mainPanel.translate("button.edit.points"), View.getIcon("edit16")); + displayEditEditPointsButton.setMargin(new Insets(3, 3, 3, 10)); + displayEditEditPointsButton.addActionListener(this::editPointsDisplayEditTagButtonActionPerformed); + replaceShapeButton = new JButton(mainPanel.translate("button.replace"), View.getIcon("replaceshape16")); replaceShapeButton.setMargin(new Insets(3, 3, 3, 10)); replaceShapeButton.addActionListener(new ActionListener() { @@ -874,6 +936,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel placeTagButtonsPanel.add(displayEditEditButton); placeTagButtonsPanel.add(displayEditSaveButton); placeTagButtonsPanel.add(displayEditCancelButton); + placeTagButtonsPanel.add(displayEditEditPointsButton); placeTagButtonsPanel.add(replaceShapeButton); placeTagButtonsPanel.add(replaceShapeUpdateBoundsButton); return placeTagButtonsPanel; @@ -1225,6 +1288,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel replaceImageButton.setVisible(showImage); replaceImageAlphaButton.setVisible(showAlpha); replaceShapeButton.setVisible(showShape); + displayEditEditPointsButton.setVisible(showShape); replaceShapeUpdateBoundsButton.setVisible(showShape); replaceSoundButton.setVisible(showSound); replaceMovieButton.setVisible(showMovie); @@ -1460,7 +1524,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } private void saveDisplayEditTag(boolean refreshTree) { - if (placeEditMode == PLACE_EDIT_TRANSFORM) { + if (displayEditMode == EDIT_TRANSFORM) { Matrix matrix = displayEditImagePanel.getNewMatrix(); if (displayEditTag instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag placeTag = (PlaceObjectTypeTag) displayEditTag; @@ -1550,9 +1614,14 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditTransformScrollPane.setVisible(false); displayEditGenericPanel.setVisible(true); } + if (displayEditMode == EDIT_POINTS) { + displayEditImagePanel.setHilightedPoints(null); + displayEditTag.setModified(true); + oldShapeRecords = null; + } Tag hilightTag = null; SWF swf = null; - if (placeEditMode == PLACE_EDIT_RAW) { + if (displayEditMode == EDIT_RAW) { if (displayEditGenericPanel.save()) { Tag tag = displayEditGenericPanel.getTag(); swf = tag.getSwf(); @@ -1565,6 +1634,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (displayEditTag instanceof ShapeTag) { replaceShapeButton.setVisible(true); replaceShapeUpdateBoundsButton.setVisible(true); + displayEditEditPointsButton.setVisible(true); } displayEditTransformButton.setVisible(true); @@ -1581,7 +1651,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditCancelButton.setVisible(false); } - if (placeEditMode == PLACE_EDIT_RAW && refreshTree && swf != null) { + if (displayEditMode == EDIT_RAW && refreshTree && swf != null) { mainPanel.refreshTree(swf); } mainPanel.clearEditingStatus(); @@ -1589,8 +1659,8 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (hilightTag != null) { mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), hilightTag); } - if (placeEditMode == PLACE_EDIT_TRANSFORM) { - placeEditMode = PLACE_EDIT_RAW; + if (displayEditMode == EDIT_TRANSFORM) { + displayEditMode = EDIT_RAW; } } @@ -1599,7 +1669,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } private void editDisplayEditTagButtonActionPerformed(ActionEvent evt) { - placeEditMode = PLACE_EDIT_RAW; + displayEditMode = EDIT_RAW; displayEditGenericPanel.setEditMode(true, displayEditTag); displayEditEditButton.setVisible(false); displayEditTransformButton.setVisible(false); @@ -1607,6 +1677,55 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditCancelButton.setVisible(true); replaceShapeButton.setVisible(false); replaceShapeUpdateBoundsButton.setVisible(false); + displayEditEditPointsButton.setVisible(false); + mainPanel.setEditingStatus(); + } + + private void editPointsDisplayEditTagButtonActionPerformed(ActionEvent evt) { + displayEditMode = EDIT_POINTS; + displayEditGenericPanel.setVisible(false); + displayEditEditButton.setVisible(false); + displayEditTransformButton.setVisible(false); + displayEditSaveButton.setVisible(true); + displayEditCancelButton.setVisible(true); + replaceShapeButton.setVisible(false); + replaceShapeUpdateBoundsButton.setVisible(false); + displayEditEditPointsButton.setVisible(false); + + + ShapeTag shape = (ShapeTag) displayEditTag; + + oldShapeRecords = Helper.deepCopy(shape.shapes.shapeRecords); + int x = 0; + int y = 0; + + List points = new ArrayList<>(); + for (SHAPERECORD rec:shape.shapes.shapeRecords) { + if (rec instanceof StraightEdgeRecord) { + StraightEdgeRecord ser = (StraightEdgeRecord) rec; + DisplayPoint point = new DisplayPoint(x + ser.deltaX, y + ser.deltaY); + points.add(point); + } + if (rec instanceof CurvedEdgeRecord) { + CurvedEdgeRecord cer = (CurvedEdgeRecord) rec; + DisplayPoint controlPoint = new DisplayPoint(x + cer.controlDeltaX, y + cer.controlDeltaY, false); + DisplayPoint anchorPoint = new DisplayPoint(x + cer.controlDeltaX + cer.anchorDeltaX, y + cer.controlDeltaY + cer.anchorDeltaY); + points.add(controlPoint); + points.add(anchorPoint); + } + if (rec instanceof StyleChangeRecord) { + StyleChangeRecord scr = (StyleChangeRecord) rec; + if (scr.stateMoveTo) { + DisplayPoint point = new DisplayPoint(scr.moveDeltaX, scr.moveDeltaY); + points.add(point); + } + } + + x = rec.changeX(x); + y = rec.changeY(y); + } + displayEditImagePanel.setHilightedPoints(points); + mainPanel.setEditingStatus(); } @@ -1615,7 +1734,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (item == null) { return; } - placeEditMode = PLACE_EDIT_TRANSFORM; + displayEditMode = EDIT_TRANSFORM; displayEditGenericPanel.setVisible(false); displayEditImagePanel.selectDepth(-1); @@ -1628,6 +1747,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel replaceShapeButton.setVisible(false); replaceShapeUpdateBoundsButton.setVisible(false); + displayEditEditPointsButton.setVisible(false); if (Configuration.editorMode.get()) { displayEditSaveButton.setEnabled(false); @@ -1869,7 +1989,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } private void cancelDisplayEditTagButtonActionPerformed(ActionEvent evt) { - if (placeEditMode == PLACE_EDIT_TRANSFORM) { + if (displayEditMode == EDIT_TRANSFORM) { if (displayEditTag instanceof PlaceObjectTypeTag) { PlaceObjectTypeTag place = (PlaceObjectTypeTag) displayEditTag; displayEditImagePanel.selectDepth(place.getDepth()); @@ -1879,9 +1999,18 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditTransformScrollPane.setVisible(false); displayEditGenericPanel.setVisible(true); } + + if (displayEditMode == EDIT_POINTS) { + displayEditImagePanel.setHilightedPoints(null); + ShapeTag shape = (ShapeTag) displayEditTag; + shape.shapes.shapeRecords = oldShapeRecords; + shape.getSwf().clearShapeCache(); + displayEditImagePanel.repaint(); + displayEditGenericPanel.setVisible(true); + } if (Configuration.editorMode.get()) { - if (placeEditMode == PLACE_EDIT_RAW) { + if (displayEditMode == EDIT_RAW) { displayEditGenericPanel.setEditMode(true, null); } displayEditEditButton.setVisible(false); @@ -1890,7 +2019,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditCancelButton.setVisible(true); displayEditCancelButton.setEnabled(false); } else { - if (placeEditMode == PLACE_EDIT_RAW) { + if (displayEditMode == EDIT_RAW) { displayEditGenericPanel.setEditMode(false, null); } displayEditEditButton.setVisible(true); @@ -1900,14 +2029,15 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (displayEditTag instanceof ShapeTag) { replaceShapeButton.setVisible(true); - replaceShapeUpdateBoundsButton.setVisible(true); + replaceShapeUpdateBoundsButton.setVisible(true); + displayEditEditPointsButton.setVisible(true); } mainPanel.clearEditingStatus(); displayEditTransformButton.setVisible(true); - if (placeEditMode == PLACE_EDIT_TRANSFORM) { - placeEditMode = PLACE_EDIT_RAW; + if (displayEditMode == EDIT_TRANSFORM) { + displayEditMode = EDIT_RAW; } } diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/cursors/default.png b/src/com/jpexs/decompiler/flash/gui/graphics/cursors/default.png new file mode 100644 index 0000000000000000000000000000000000000000..a1adae238bb25e31434a40ce6382ba8d95c73b2a GIT binary patch literal 6244 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 literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/cursors/move_point.png b/src/com/jpexs/decompiler/flash/gui/graphics/cursors/move_point.png new file mode 100644 index 0000000000000000000000000000000000000000..df67227a9fda001f407dc43a8f3d8e61dd762e5b GIT binary patch literal 6272 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 literal 0 HcmV?d00001 diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index c92268376..54b9da5d2 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1107,4 +1107,7 @@ message.info.importSounds2 = During importing sounds, you need to select a FOLDE If there exist "sounds" folder inside, it is selected instead.\r\n \ The best way to get the structure right is to export sounds in current SWF file first. -import.sound.result = %count% sounds imported. \ No newline at end of file +import.sound.result = %count% sounds imported. + +#after 18.2.1 +button.edit.points = Edit points \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index 7c6c35b58..b6f44da28 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1092,4 +1092,7 @@ message.info.importSounds2 = B\u011bhem importu zvuk\u016f mus\u00edte vybrat SL Pokud je uvnit\u0159 slo\u017eka "sounds", pak je vybr\u00e1na m\u00edsto n\u00ed.\r\n \ Nejlep\u0161\u00ed zp\u016fsob jak m\u00edt tuto strukturu spr\u00e1vn\u011b je nejprve exportovat zvuky v aktu\u00e1ln\u00edm SWF souboru. -import.sound.result = %count% zvuk\u016f importov\u00e1no. \ No newline at end of file +import.sound.result = %count% zvuk\u016f importov\u00e1no. + +#after 18.2.1 +button.edit.points = Editovat body \ No newline at end of file