From 5fecb497b428498fecf3fc817a376dca55594f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Sat, 17 May 2025 13:38:53 +0200 Subject: [PATCH] Added: Simple editor - edit parameters of items inside buttons --- CHANGELOG.md | 1 + .../flash/tags/DefineButton2Tag.java | 7 +- .../decompiler/flash/tags/base/ButtonTag.java | 123 +++++++++++++++++- .../decompiler/flash/types/BUTTONRECORD.java | 13 ++ .../flash/easygui/EasySwfPanel.java | 35 +++-- .../panels/InstancePropertiesPanel.java | 29 +++-- .../decompiler/flash/gui/ImagePanel.java | 2 +- 7 files changed, 187 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ec2810fa..64029cde6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [Unreleased] ### Added - "Starting Flash content debugger" in status bar when debugging starts +- Simple editor - edit parameters of items inside buttons ### Fixed - Resize export dialogs labels to match localized strings diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java index b8e182ff8..5b3a8c4a6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineButton2Tag.java @@ -200,6 +200,9 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { @Override public RECT getRect(Set added) { + if (swf == null) { + return null; + } Cache cache = swf == null ? null : swf.getRectCache(); RECT ret = cache == null ? null : cache.get(this); if (ret != null) { @@ -267,6 +270,8 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { layer.filters = r.filterList; layer.matrix = r.placeMatrix; layer.characterId = r.characterId; + layer.depth = r.placeDepth; + if (r.placeDepth > maxDepth) { maxDepth = r.placeDepth; } @@ -313,7 +318,7 @@ public class DefineButton2Tag extends ButtonTag implements ASMSourceContainer { @Override public void setFrameCount(int frameCount) { - throw new UnsupportedOperationException("Not supported yet."); + } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java index 5b00b7829..d2be8b594 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/ButtonTag.java @@ -48,22 +48,22 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { /** * Frame up */ - public static int FRAME_UP = 0; + public static final int FRAME_UP = 0; /** * Frame over */ - public static int FRAME_OVER = 1; + public static final int FRAME_OVER = 1; /** * Frame down */ - public static int FRAME_DOWN = 2; + public static final int FRAME_DOWN = 2; /** * Frame hit test */ - public static int FRAME_HITTEST = 3; + public static final int FRAME_HITTEST = 3; private transient Timeline timeline; @@ -85,12 +85,14 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { /** * Gets button records. + * * @return Button records */ public abstract List getRecords(); /** * Checks if the button is tracked as a menu. + * * @return True if the button is tracked as a menu, otherwise false */ public abstract boolean trackAsMenu(); @@ -134,6 +136,7 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { /** * Gets the sounds. + * * @return Sounds */ public DefineButtonSoundTag getSounds() { @@ -184,6 +187,7 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { /** * Initializes the timeline. + * * @param timeline Timeline */ protected abstract void initTimeline(Timeline timeline); @@ -244,4 +248,115 @@ public abstract class ButtonTag extends DrawableTag implements Timelined { record.setModified(value); } } + + public BUTTONRECORD getButtonRecordAt(int frame, int depth, boolean addIfNotExists) { + for (BUTTONRECORD rec : getRecords()) { + if (rec.placeDepth != depth) { + continue; + } + + switch (frame) { + case FRAME_UP: + if (rec.buttonStateUp) { + return rec; + } + break; + case FRAME_OVER: + if (rec.buttonStateOver) { + return rec; + } + break; + case FRAME_DOWN: + if (rec.buttonStateDown) { + return rec; + } + break; + case FRAME_HITTEST: + if (rec.buttonStateHitTest) { + return rec; + } + break; + } + } + + if (addIfNotExists) { + BUTTONRECORD newRecord = new BUTTONRECORD(swf, this); + switch (frame) { + case FRAME_UP: + newRecord.buttonStateUp = true; + break; + case FRAME_OVER: + newRecord.buttonStateOver = true; + break; + case FRAME_DOWN: + newRecord.buttonStateDown = true; + break; + case FRAME_HITTEST: + newRecord.buttonStateHitTest = true; + break; + } + getRecords().add(newRecord); + return newRecord; + } + + return null; + } + + public void setRecordFromPlaceObject(int frame, PlaceObjectTypeTag placeTag) { + BUTTONRECORD selectedRecord = null; + List records = getRecords(); + loopRecords: + for (BUTTONRECORD rec : records) { + if (rec.placeDepth != placeTag.getDepth()) { + continue; + } + + switch (frame) { + case FRAME_UP: + if (rec.buttonStateUp) { + selectedRecord = rec; + break loopRecords; + } + break; + case FRAME_OVER: + if (rec.buttonStateOver) { + selectedRecord = rec; + break loopRecords; + } + break; + case FRAME_DOWN: + if (rec.buttonStateDown) { + selectedRecord = rec; + break loopRecords; + } + break; + case FRAME_HITTEST: + if (rec.buttonStateHitTest) { + selectedRecord = rec; + break loopRecords; + } + break; + } + } + + if (selectedRecord == null) { + selectedRecord = new BUTTONRECORD(swf, this); + switch (frame) { + case FRAME_UP: + selectedRecord.buttonStateUp = true; + break; + case FRAME_OVER: + selectedRecord.buttonStateOver = true; + break; + case FRAME_DOWN: + selectedRecord.buttonStateDown = true; + break; + case FRAME_HITTEST: + selectedRecord.buttonStateHitTest = true; + break; + } + records.add(selectedRecord); + } + selectedRecord.fromPlaceObject(placeTag); + } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java index 2fcfad3e7..e1b419b81 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONRECORD.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.tags.DefineButtonTag; import com.jpexs.decompiler.flash.tags.PlaceObject3Tag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ButtonTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.treeitems.Openable; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.annotations.Conditional; @@ -210,6 +211,18 @@ public class BUTTONRECORD implements Serializable, TreeItem, HasSwfAndTag, HasCh this.characterId = characterId; } + public void fromPlaceObject(PlaceObjectTypeTag placeObject) { + placeDepth = placeObject.getDepth(); + characterId = placeObject.getCharacterId(); + ColorTransform importedColorTrans = placeObject.getColorTransform(); + colorTransform = importedColorTrans == null ? null : new CXFORMWITHALPHA(placeObject.getColorTransform()); + placeMatrix = placeObject.getMatrix(); + blendMode = placeObject.getBlendMode(); + buttonHasBlendMode = blendMode > 0; + filterList = placeObject.getFilters(); + buttonHasFilterList = filterList != null && !filterList.isEmpty(); + } + /** * Converts this BUTTONRECORD to a place tag. * @return Place tag diff --git a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java index 16eba63a6..ce5efb672 100644 --- a/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java +++ b/src/com/jpexs/decompiler/flash/easygui/EasySwfPanel.java @@ -49,6 +49,7 @@ import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.decompiler.flash.types.BUTTONRECORD; import com.jpexs.decompiler.flash.types.MATRIX; import java.awt.BorderLayout; import java.awt.CardLayout; @@ -187,13 +188,19 @@ public class EasySwfPanel extends JPanel { for (int i = 0; i < depths.size(); i++) { int depth = depths.get(i); DepthState ds = stagePanel.getTimelined().getTimeline().getFrame(frame).layers.get(depth); - wasModified.add(ds.placeObjectTag.isModified()); + wasModified.add(ds.placeObjectTag == null ? false : ds.placeObjectTag.isModified()); Matrix contMat = newMatrix.concatenate(new Matrix(fpreviousMatrices.get(i))); - ds.placeObjectTag.setMatrix(contMat.toMATRIX()); - ds.placeObjectTag.setPlaceFlagHasMatrix(newMatrix != null); - ds.placeObjectTag.setModified(true); + if (timelined instanceof ButtonTag) { + ButtonTag button = (ButtonTag) timelined; + BUTTONRECORD rec = button.getButtonRecordAt(frame, depth, true); + rec.placeMatrix = contMat.toMATRIX(); + } else { + ds.placeObjectTag.setMatrix(contMat.toMATRIX()); + ds.placeObjectTag.setPlaceFlagHasMatrix(newMatrix != null); + ds.placeObjectTag.setModified(true); + } } timelined.resetTimeline(); stagePanel.repaint(); @@ -216,10 +223,16 @@ public class EasySwfPanel extends JPanel { for (int i = 0; i < depths.size(); i++) { int depth = depths.get(i); DepthState ds = stagePanel.getTimelined().getTimeline().getFrame(frame).layers.get(depth); - ds.placeObjectTag.setMatrix(fpreviousMatrices.get(i)); - ds.placeObjectTag.setPlaceFlagHasMatrix(fpreviousMatrices != null); - if (!wasModified.get(i)) { - ds.placeObjectTag.setModified(false); + if (timelined instanceof ButtonTag) { + ButtonTag button = (ButtonTag) timelined; + BUTTONRECORD rec = button.getButtonRecordAt(frame, depth, true); + rec.placeMatrix = fpreviousMatrices.get(i); + } else { + ds.placeObjectTag.setMatrix(fpreviousMatrices.get(i)); + ds.placeObjectTag.setPlaceFlagHasMatrix(fpreviousMatrices != null); + if (ds.placeObjectTag != null && !wasModified.get(i)) { + ds.placeObjectTag.setModified(false); + } } } stagePanel.getTimelined().resetTimeline(); @@ -675,7 +688,11 @@ public class EasySwfPanel extends JPanel { if (ds == null) { ret.add(null); } else { - ret.add(ds.placeObjectTag); + if (ds.placeObjectTag == null) { + ret.add(ds.toPlaceObjectTag(ds.depth)); + } else { + ret.add(ds.placeObjectTag); + } } } return ret; diff --git a/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java b/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java index 9849d34c7..7ad1c6623 100644 --- a/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java +++ b/src/com/jpexs/decompiler/flash/easygui/properties/panels/InstancePropertiesPanel.java @@ -33,6 +33,7 @@ import com.jpexs.decompiler.flash.gui.PopupButton; import com.jpexs.decompiler.flash.gui.RegistrationPointPosition; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.ViewMessages; +import com.jpexs.decompiler.flash.tags.base.ButtonTag; import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.converters.PlaceObjectTypeConverter; import com.jpexs.decompiler.flash.timeline.DepthState; @@ -1093,13 +1094,20 @@ public class InstancePropertiesPanel extends AbstractPropertiesPanel { for (int i = 0; i < fdepths.size(); i++) { PlaceObjectTypeTag placeObjectBefore = placeObjectsBefore.get(i); PlaceObjectTypeTag placeObjectAfter = placeObjectsAfter.get(i); - - int index = timelined.indexOfTag(placeObjectBefore); - timelined.removeTag(index); - timelined.addTag(index, placeObjectAfter); - timelined.setModified(true); + + if (!(timelined instanceof ButtonTag)) { + int index = timelined.indexOfTag(placeObjectBefore); + timelined.removeTag(index); + timelined.addTag(index, placeObjectAfter); + timelined.setModified(true); + } DepthState depthStateBefore = depthStatesBefore.get(i); doPlaceOperation(placeObjectAfter, depthStateBefore); + + if (timelined instanceof ButtonTag) { + ButtonTag button = (ButtonTag) timelined; + button.setRecordFromPlaceObject(fframe, placeObjectAfter); + } } timelined.resetTimeline(); @@ -1113,9 +1121,14 @@ public class InstancePropertiesPanel extends AbstractPropertiesPanel { for (int i = 0; i < placeObjectsAfter.size(); i++) { PlaceObjectTypeTag placeObjectAfter = placeObjectsAfter.get(i); PlaceObjectTypeTag placeObjectBefore = placeObjectsBefore.get(i); - int index = timelined.indexOfTag(placeObjectAfter); - timelined.removeTag(index); - timelined.addTag(index, placeObjectBefore); + if (timelined instanceof ButtonTag) { + ButtonTag button = (ButtonTag) timelined; + button.setRecordFromPlaceObject(fframe, placeObjectBefore); + } else { + int index = timelined.indexOfTag(placeObjectAfter); + timelined.removeTag(index); + timelined.addTag(index, placeObjectBefore); + } } if (!timelinedModifiedBefore) { timelined.setModified(false); diff --git a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java index ed7c1038e..e37157b7f 100644 --- a/src/com/jpexs/decompiler/flash/gui/ImagePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/ImagePanel.java @@ -5394,7 +5394,7 @@ public final class ImagePanel extends JPanel implements MediaDisplay { } else { depthStateUnderCursor = null; } - + if (showObjectsUnderCursor && autoPlayed) { boolean first = true; for (int i = renderContext.stateUnderCursor.size() - 1; i >= 0; i--) {