diff --git a/CHANGELOG.md b/CHANGELOG.md index 6af66cf10..53dce9a7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -73,6 +73,8 @@ All notable changes to this project will be documented in this file. - [#1646] Scrolling in Error log frame inside log texts - JLayer stripping last byte of MP3 data - [#2469] Converting shape type did not convert gradient colors transparency +- [#2470] Transform - paste matrix, edit current matrix not working +- Do not allow to switch PlaceObjects in transform mode ## [23.0.1] - 2025-05-16 ### Fixed @@ -3876,6 +3878,7 @@ Major version of SWF to XML export changed to 2. [#2405]: https://www.free-decompiler.com/flash/issues/2405 [#1646]: https://www.free-decompiler.com/flash/issues/1646 [#2469]: https://www.free-decompiler.com/flash/issues/2469 +[#2470]: https://www.free-decompiler.com/flash/issues/2470 [#2427]: https://www.free-decompiler.com/flash/issues/2427 [#1826]: https://www.free-decompiler.com/flash/issues/1826 [#2448]: https://www.free-decompiler.com/flash/issues/2448 diff --git a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java index 46cf30aff..3f2efadc3 100644 --- a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java +++ b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java @@ -548,7 +548,7 @@ public class EasySwfPanel extends JPanel { if (obj instanceof Tag) { Tag t = (Tag) obj; libraryPreviewPanel.setTimelined(TimelinedMaker.makeTimelined(t), t.getSwf(), - -1, false, true, true, true, true, false, true, true, true); + -1, false, true, true, true, true, false, true, true, true, new Matrix()); libraryPreviewPanel.zoomFit(); } else { libraryPreviewPanel.clearAll(); @@ -600,7 +600,7 @@ public class EasySwfPanel extends JPanel { libraryTreeTable.setSwf(swf); libraryPreviewPanel.clearAll(); if (updateStage) { - stagePanel.setTimelined(timelined, swf, 0, true, true, true, true, true, false, true, true, true); + stagePanel.setTimelined(timelined, swf, 0, true, true, true, true, true, false, true, true, true, new Matrix()); if (timelined instanceof CharacterTag) { stagePanel.setGuidesCharacter(swf, ((CharacterTag) timelined).getCharacterId()); } else { diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index c632af620..9ef973160 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -220,6 +220,8 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private Matrix transform; private AffineTransform transformUpdated; + + private Matrix originalMatrix = new Matrix(); private final double LQ_FACTOR = 2; @@ -710,8 +712,15 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } public Matrix getNewMatrix() { + if (transform == null) { + return new Matrix(); + } return transform; } + + public Matrix getOriginalMatrix() { + return originalMatrix; + } public synchronized void selectDepth(int depth) { List depths = new ArrayList<>(); @@ -1563,7 +1572,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { freeTransformDepths(newSelectedDepths); firePlaceObjectSelected(); } - } else if ((altDown && !selectionMode) || selectionMode) { + } else if ((altDown && !selectionMode && !doFreeTransform) || selectionMode) { selectDepths(newSelectedDepths); firePlaceObjectSelected(); } @@ -4365,7 +4374,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { private Timer setTimelinedTimer = null; - public void setTimelined(final Timelined drawable, final SWF swf, int frame, boolean showObjectsUnderCursor, boolean autoPlay, boolean frozen, boolean alwaysDisplay, boolean muted, boolean mutable, boolean allowZoom, boolean frozenButtons, boolean canHaveRuler) { + public void setTimelined(final Timelined drawable, final SWF swf, int frame, boolean showObjectsUnderCursor, boolean autoPlay, boolean frozen, boolean alwaysDisplay, boolean muted, boolean mutable, boolean allowZoom, boolean frozenButtons, boolean canHaveRuler, Matrix originalMatrix) { Stage stage = new Stage(drawable) { @Override public void callFrame(int frame) { @@ -4432,6 +4441,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { bounds = null; displayObjectCache.clear(); this.timelined = drawable; + this.originalMatrix = originalMatrix; this.parentTimelineds.clear(); this.parentFrames.clear(); this.parentDepths.clear(); @@ -4664,6 +4674,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { pointEditPanel.setVisible(false); iconPanel.setImg(image); drawReady = true; + originalMatrix = new Matrix(); horizontalScrollBar.setVisible(false); verticalScrollBar.setVisible(false); @@ -5476,7 +5487,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { newCursor = guideXCursor; } else if (mode == MODE_GUIDE_Y) { newCursor = guideYCursor; - } else if (iconPanel.isAltDown() && !selectionMode) { + } else if (iconPanel.isAltDown() && !selectionMode && !doFreeTransform) { if (depthStateUnderCursor == null) { newCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); } else { @@ -5948,8 +5959,15 @@ public final class ImagePanel extends JPanel implements MediaDisplay { redraw(); fireBoundsChange(getTransformBounds(), registrationPoint, position); } - - public void applyTransformMatrix(Matrix matrix) { + + public void applyTransformMatrix(Matrix matrix) { + applyTransformMatrixInternal(matrix); + redraw(); + fireBoundsChange(getTransformBounds(), registrationPoint, registrationPointPosition); + fireTransformChanged(); + } + + private void applyTransformMatrixInternal(Matrix matrix) { Matrix parentMatrix = getParentMatrix(); transform = transform.preConcatenate(matrix); transform = parentMatrix.concatenate(transform).concatenate(parentMatrix.inverse()); @@ -5957,10 +5975,13 @@ public final class ImagePanel extends JPanel implements MediaDisplay { Point2D newRegistrationPoint = new Point2D.Double(); matrix.toTransform().transform(registrationPoint, newRegistrationPoint); registrationPoint = newRegistrationPoint; - - redraw(); - fireBoundsChange(getTransformBounds(), registrationPoint, registrationPointPosition); - fireTransformChanged(); + } + + public void setFullTransformMatrix(Matrix matrix) { + Matrix deltaMatrix = getOriginalMatrix().inverse().concatenate(getNewMatrix().inverse()).concatenate(matrix); + applyTransformMatrixInternal(deltaMatrix); + Matrix errorCorrectionMatrix = matrix.inverse().concatenate(getNewMatrix().concatenate(getOriginalMatrix())); + applyTransformMatrix(errorCorrectionMatrix.inverse()); } private Point2D toTransformPoint(Point2D point) { @@ -6111,5 +6132,5 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } return timelined; } - } + } } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 941d5f16d..45564b1e0 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -1722,7 +1722,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } imageTransformSaveButton.setVisible(false); imageTransformCancelButton.setVisible(false); - imagePanel.setTimelined(timelined, swf, frame, showObjectsUnderCursor, autoPlay, frozen, alwaysDisplay, muted, mutable, allowZoom, frozenButtons, canHaveRuler); + imagePanel.setTimelined(timelined, swf, frame, showObjectsUnderCursor, autoPlay, frozen, alwaysDisplay, muted, mutable, allowZoom, frozenButtons, canHaveRuler, new Matrix()); if (canHaveRuler) { if (timelined instanceof Tag) { imagePanel.setGuidesCharacter(swf, ((CharacterTag) timelined).getCharacterId()); @@ -2055,18 +2055,18 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel displayEditImagePanel.selectDepth(-1); if (tag instanceof ShapeTag) { Timelined tim = TimelinedMaker.makeTimelined(tag); - displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true, new Matrix()); displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tag).getCharacterId()); } if (tag instanceof MorphShapeTag) { Timelined tim = TimelinedMaker.makeTimelined(tag); - displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setTimelined(tim, ((Tag) tag).getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true, new Matrix()); displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tag).getCharacterId()); morphDisplayMode = MORPH_ANIMATE; displayEditShowAnimationButton.setSelected(true); } if (tag instanceof PlaceObjectTypeTag) { - displayEditImagePanel.setTimelined(((Tag) tag).getTimelined(), ((Tag) tag).getSwf(), frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, true, true, true); + displayEditImagePanel.setTimelined(((Tag) tag).getTimelined(), ((Tag) tag).getSwf(), frame, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), true, true, true, true, new Matrix(((PlaceObjectTypeTag) tag).getMatrix())); Timelined tim = ((Tag) tag).getTimelined(); if (tim instanceof Tag) { displayEditImagePanel.setGuidesCharacter(tag.getSwf(), ((CharacterTag) tim).getCharacterId()); @@ -2724,21 +2724,21 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel private void showAnimationDisplayEditTagButtonActionPerformed(ActionEvent evt) { morphDisplayMode = MORPH_ANIMATE; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); - displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), -1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true, new Matrix()); displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } private void showStartDisplayEditTagButtonActionPerformed(ActionEvent evt) { morphDisplayMode = MORPH_START; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); - displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), 0, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true, new Matrix()); displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } private void showEndDisplayEditTagButtonActionPerformed(ActionEvent evt) { morphDisplayMode = MORPH_END; Timelined tim = TimelinedMaker.makeTimelined(displayEditTag); - displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), tim.getFrameCount() - 1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true); + displayEditImagePanel.setTimelined(tim, displayEditTag.getSwf(), tim.getFrameCount() - 1, true, Configuration.autoPlayPreviews.get(), !Configuration.animateSubsprites.get(), false, !Configuration.playFrameSounds.get(), false, true, true, true, new Matrix()); displayEditImagePanel.setGuidesCharacter(displayEditTag.getSwf(), ((CharacterTag) displayEditTag).getCharacterId()); } @@ -3097,7 +3097,7 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel } }; - imagePanel.setTimelined(tim, origSwf, 0, true, true, true, true, true, false, true, true, true); + imagePanel.setTimelined(tim, origSwf, 0, true, true, true, true, true, false, true, true, true, new Matrix()); imagePanel.setGuidesCharacter(displayedCharacter.getSwf(), ((CharacterTag) displayedCharacter).getCharacterId()); imagePanel.selectDepth(-1); @@ -3209,14 +3209,14 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel FontTag fontTag = fontPanel.getFontTag(); int pageCount = getFontPageCount(fontTag); fontPageNum = (fontPageNum + pageCount - 1) % pageCount; - imagePanel.setTimelined(TimelinedMaker.makeTimelined(fontTag, fontPageNum), fontTag.getSwf(), 0, true, true, true, true, true, false, false, true, false); + imagePanel.setTimelined(TimelinedMaker.makeTimelined(fontTag, fontPageNum), fontTag.getSwf(), 0, true, true, true, true, true, false, false, true, false, new Matrix()); } private void nextFontsButtonActionPerformed(ActionEvent evt) { FontTag fontTag = fontPanel.getFontTag(); int pageCount = getFontPageCount(fontTag); fontPageNum = (fontPageNum + 1) % pageCount; - imagePanel.setTimelined(TimelinedMaker.makeTimelined(fontTag, fontPageNum), fontTag.getSwf(), 0, true, true, true, true, true, false, false, true, false); + imagePanel.setTimelined(TimelinedMaker.makeTimelined(fontTag, fontPageNum), fontTag.getSwf(), 0, true, true, true, true, true, false, false, true, false, new Matrix()); } @Override diff --git a/src/com/jpexs/decompiler/flash/gui/TransformPanel.java b/src/com/jpexs/decompiler/flash/gui/TransformPanel.java index f4997dfd1..526cdf28a 100644 --- a/src/com/jpexs/decompiler/flash/gui/TransformPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/TransformPanel.java @@ -425,7 +425,7 @@ public class TransformPanel extends JPanel { @Override public void itemStateChanged(ItemEvent e) { if (matrixEditCurrentCheckBox.isSelected()) { - Matrix matrix = imagePanel.getNewMatrix(); + Matrix matrix = imagePanel.getOriginalMatrix().concatenate(imagePanel.getNewMatrix()); matrixATextField.setText(formatDouble(matrix.scaleX)); matrixBTextField.setText(formatDouble(matrix.rotateSkew0)); matrixCTextField.setText(formatDouble(matrix.rotateSkew1)); @@ -491,7 +491,7 @@ public class TransformPanel extends JPanel { } } if (matrixEditCurrentCheckBox.isSelected()) { - Matrix matrix = imagePanel.getNewMatrix(); + Matrix matrix = imagePanel.getOriginalMatrix().concatenate(imagePanel.getNewMatrix()); matrixATextField.setText(formatDouble(matrix.scaleX)); matrixBTextField.setText(formatDouble(matrix.rotateSkew0)); matrixCTextField.setText(formatDouble(matrix.rotateSkew1)); @@ -527,7 +527,7 @@ public class TransformPanel extends JPanel { } private void copyClipboardActionPerformed(ActionEvent e) { - Matrix matrix = imagePanel.getNewMatrix(); + Matrix matrix = imagePanel.getOriginalMatrix().concatenate(imagePanel.getNewMatrix()); String copyString = "MATRIX[" + matrix.scaleX + "," + matrix.rotateSkew0 + "," + matrix.rotateSkew1 + "," + matrix.scaleY + "," + matrix.translateX + "," + matrix.translateY + "]"; StringSelection stringSelection = new StringSelection(copyString); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -552,8 +552,7 @@ public class TransformPanel extends JPanel { matrix.translateX = Double.parseDouble(matcher.group("translateX")); matrix.translateY = Double.parseDouble(matcher.group("translateY")); - matrix = imagePanel.getNewMatrix().inverse().concatenate(matrix); - imagePanel.applyTransformMatrix(matrix); + imagePanel.setFullTransformMatrix(matrix); } } } @@ -688,9 +687,10 @@ public class TransformPanel extends JPanel { matrix.translateX = parseDouble(matrixETextField.getText()); matrix.translateY = parseDouble(matrixFTextField.getText()); if (matrixEditCurrentCheckBox.isSelected()) { - matrix = imagePanel.getNewMatrix().inverse().concatenate(matrix); + imagePanel.setFullTransformMatrix(matrix); + } else { + imagePanel.applyTransformMatrix(matrix); } - imagePanel.applyTransformMatrix(matrix); } catch (NumberFormatException nfe) { //ignored }