From 85ba45cbb38fe8c43c4de2bb61353f80aead31b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Fri, 29 Dec 2023 18:40:23 +0100 Subject: [PATCH] Added Scenes folder with (readonly) display of scene frames --- CHANGELOG.md | 1 + .../decompiler/flash/timeline/Scene.java | 92 ++++++++++++++++++ .../decompiler/flash/timeline/SceneFrame.java | 87 +++++++++++++++++ .../decompiler/flash/timeline/Timeline.java | 27 +++++ .../flash/gui/FolderPreviewPanel.java | 8 ++ .../jpexs/decompiler/flash/gui/MainPanel.java | 35 +++++-- .../decompiler/flash/gui/TreeNodeType.java | 1 + .../flash/gui/graphics/folderscenes16.png | Bin 0 -> 664 bytes .../decompiler/flash/gui/graphics/scene16.png | Bin 0 -> 602 bytes .../decompiler/flash/gui/graphics/scene32.png | Bin 0 -> 1654 bytes .../flash/gui/locales/MainFrame.properties | 5 +- .../flash/gui/locales/MainFrame_cs.properties | 5 +- .../flash/gui/tagtree/AbstractTagTree.java | 9 +- .../flash/gui/tagtree/TagTreeContextMenu.java | 42 +++++++- .../flash/gui/tagtree/TagTreeModel.java | 31 ++++++ 15 files changed, 333 insertions(+), 10 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Scene.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SceneFrame.java create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/folderscenes16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/scene16.png create mode 100644 src/com/jpexs/decompiler/flash/gui/graphics/scene32.png diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e059c566..6d9cb9944 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ All notable changes to this project will be documented in this file. - FLA export - show export time - [#2138] Morphshapes - detect classic easing - FLA export - option to disable fixing of shapes +- Scenes folder with (readonly) display of scene frames ### Fixed - [#2021], [#2000] Caret position in editors when using tabs and / or unicode diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Scene.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Scene.java new file mode 100644 index 000000000..4e7a9c099 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Scene.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2010-2023 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.timeline; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import java.util.Objects; + +/** + * + * @author JPEXS + */ +public class Scene implements TreeItem { + private SWF swf; + public int startFrame; + public int endFrame; + public String name; + + public Scene(SWF swf, int startFrame, int endFrame, String name) { + this.swf = swf; + this.startFrame = startFrame; + this.endFrame = endFrame; + this.name = name; + } + + public int getSceneFrameCount() { + return endFrame - startFrame + 1; + } + + public SceneFrame getSceneFrame(int sceneFrameIndex) { + if (sceneFrameIndex >= getSceneFrameCount()) { + throw new IndexOutOfBoundsException("Invalid sceneframe index"); + } + return new SceneFrame(swf, this, startFrame + sceneFrameIndex); + } + + @Override + public Openable getOpenable() { + return swf; + } + + @Override + public boolean isModified() { + return false; //?? + } + + @Override + public int hashCode() { + int hash = 7; + hash = 97 * hash + Objects.hashCode(this.swf); + hash = 97 * hash + this.startFrame; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Scene other = (Scene) obj; + if (this.startFrame != other.startFrame) { + return false; + } + return Objects.equals(this.swf, other.swf); + } + + @Override + public String toString() { + return name; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SceneFrame.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SceneFrame.java new file mode 100644 index 000000000..efa62f1c5 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/SceneFrame.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010-2023 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.timeline; + +import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.treeitems.Openable; +import com.jpexs.decompiler.flash.treeitems.TreeItem; +import java.util.Objects; + +/** + * + * @author JPEXS + */ +public class SceneFrame implements TreeItem { + private final SWF swf; + private final Scene scene; + private final int realFrameIndex; + + public SceneFrame(SWF swf, Scene scene, int realFrameIndex) { + this.swf = swf; + this.scene = scene; + this.realFrameIndex = realFrameIndex; + } + + public int getSceneFrameIndex() { + return realFrameIndex - scene.startFrame; + } + + public Frame getFrame() { + return swf.getTimeline().getFrame(realFrameIndex); + } + + @Override + public String toString() { + return "scene frame " + (getSceneFrameIndex() + 1); + } + + @Override + public Openable getOpenable() { + return swf; + } + + @Override + public boolean isModified() { + return getFrame().isModified(); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 47 * hash + Objects.hashCode(this.scene); + hash = 47 * hash + this.realFrameIndex; + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final SceneFrame other = (SceneFrame) obj; + if (this.realFrameIndex != other.realFrameIndex) { + return false; + } + return Objects.equals(this.scene, other.scene); + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java index 241957034..4adb30ce1 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/timeline/Timeline.java @@ -128,6 +128,8 @@ public class Timeline { private boolean initialized = false; private Map labelToFrame = new HashMap<>(); + + private List scenes = new ArrayList<>(); public static final int DRAW_MODE_ALL = 0; public static final int DRAW_MODE_SHAPES = 1; @@ -282,6 +284,8 @@ public class Timeline { Frame frame = new Frame(this, frameIdx++); frame.layersChanged = true; boolean newFrameNeeded = false; + scenes = new ArrayList<>(); + Scene prevScene = null; for (Tag t : timelined.getTags()) { newFrameNeeded = true; boolean isNested = ShowFrameTag.isNestedTagType(t.getId()); @@ -290,6 +294,20 @@ public class Timeline { } frame.allInnerTags.add(t); + if (id == 0 && (t instanceof DefineSceneAndFrameLabelDataTag)) { + DefineSceneAndFrameLabelDataTag sceneData = (DefineSceneAndFrameLabelDataTag) t; + scenes = new ArrayList<>(); + for (int i = 0; i < sceneData.sceneNames.length; i++) { + int ioffset = (int) sceneData.sceneOffsets[i]; + Scene currentScene = new Scene(swf, ioffset, -1, sceneData.sceneNames[i]); + scenes.add(currentScene); + if (prevScene != null) { + prevScene.endFrame = ioffset - 1; + } + prevScene = currentScene; + } + } + if (t instanceof ASMSourceContainer) { ASMSourceContainer asmSourceContainer = (ASMSourceContainer) t; if (!asmSourceContainer.getSubItems().isEmpty()) { @@ -445,6 +463,10 @@ public class Timeline { if (newFrameNeeded) { frames.add(frame); } + + if (prevScene != null) { + prevScene.endFrame = frames.size() - 1; + } maxDepth = getMaxDepthInternal(); @@ -1521,4 +1543,9 @@ public class Timeline { return false; } + + public List getScenes() { + ensureInitialized(); + return new ArrayList<>(scenes); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java index 50ceb9f82..08b18ab8a 100644 --- a/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FolderPreviewPanel.java @@ -27,6 +27,8 @@ import com.jpexs.decompiler.flash.tags.base.DrawableTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Scene; +import com.jpexs.decompiler.flash.timeline.SceneFrame; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.treeitems.TreeItem; import com.jpexs.decompiler.flash.types.RECT; @@ -294,6 +296,12 @@ public class FolderPreviewPanel extends JPanel { Matrix m = new Matrix(); double ow = 1; double oh = 1; + if (treeItem instanceof Scene) { + treeItem = ((Scene) treeItem).getSceneFrame(0); + } + if (treeItem instanceof SceneFrame) { + treeItem = ((SceneFrame) treeItem).getFrame(); + } if (treeItem instanceof Frame) { Frame fn = (Frame) treeItem; RECT rect = swf.displayRect; diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index 1a237d98c..89438052c 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -192,6 +192,8 @@ import com.jpexs.decompiler.flash.tags.text.TextParseException; import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; +import com.jpexs.decompiler.flash.timeline.Scene; +import com.jpexs.decompiler.flash.timeline.SceneFrame; import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange; import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.timeline.Timeline; @@ -5737,6 +5739,14 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se boolean internalViewer = !isAdobeFlashPlayerEnabled(); + Frame frameTreeItem = null; + if (treeItem instanceof Frame) { + frameTreeItem = (Frame) treeItem; + } + if (treeItem instanceof SceneFrame) { + frameTreeItem = ((SceneFrame) treeItem).getFrame(); + } + if ((treeItem instanceof AS3Package) && ((AS3Package) treeItem).isCompoundScript()) { final ScriptPack scriptLeaf = ((AS3Package) treeItem).getCompoundInitializerPack(); if (Main.isInited() && (!Main.isWorking() || Main.isDebugging())) { @@ -5810,8 +5820,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else { showDetail(DETAILCARDEMPTYPANEL); } - } else if (treeItem instanceof Frame) { - Frame frame = (Frame) treeItem; + } else if (frameTreeItem != null) { + Frame frame = frameTreeItem; Set needed = new LinkedHashSet<>(); frame.getNeededCharacters(needed); @@ -5850,6 +5860,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else if (treeItem instanceof SWF) { showPreview(treeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); + } else if (treeItem instanceof Scene) { + showFolderPreviewList(treePath); } else if (treeItem instanceof MetadataTag) { showPreview(treeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); @@ -5874,8 +5886,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else if ((treeItem instanceof TextTag) && internalViewer) { showPreview(treeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); - } else if (treeItem instanceof Frame && internalViewer) { - showPreview(treeItem, previewPanel, -1, null); + } else if (frameTreeItem != null && internalViewer) { + showPreview(frameTreeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); } else if (treeItem instanceof ShowFrameTag && internalViewer) { showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), getTimelinedForTreeItem(treeItem)); @@ -5883,9 +5895,11 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } else if ((treeItem instanceof SoundTag)) { //&& isInternalFlashViewerSelected() && (Arrays.asList("mp3", "wav").contains(((SoundTag) tagObj).getExportFormat())))) { showPreview(treeItem, previewPanel, -1, null); showCard(CARDPREVIEWPANEL); - } else if ((treeItem instanceof Frame) || (treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { + } else if (frameTreeItem != null) { + showPreview(frameTreeItem, previewPanel, -1, null); + showCard(CARDPREVIEWPANEL); + } else if ((treeItem instanceof CharacterTag) || (treeItem instanceof FontTag) || (treeItem instanceof SoundStreamHeadTypeTag)) { showPreview(treeItem, previewPanel, -1, null); - showCard(CARDPREVIEWPANEL); } else if (treeItem instanceof PlaceObjectTypeTag) { showPreview(treeItem, previewPanel, getFrameForTreeItem(treeItem), null); @@ -6027,6 +6041,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } break; + case TagTreeModel.FOLDER_SCENES: + folderPreviewItems.addAll(timelined.getTimeline().getScenes()); + break; } } @@ -6044,6 +6061,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se folderPreviewPanel.setItems(folderPreviewItems); showCard(CARDFOLDERPREVIEWPANEL); } + + private void showFolderPreviewList(TreePath path) { + List items = new ArrayList<>(getCurrentTree().getFullModel().getAllChildren((TreeItem) path.getLastPathComponent())); + folderPreviewPanel.setItems(items); + showCard(CARDFOLDERPREVIEWPANEL); + } private void showFolderList(TreePath path) { List items = new ArrayList<>(getCurrentTree().getFullModel().getAllChildren((TreeItem) path.getLastPathComponent())); diff --git a/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java b/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java index 200d28f1b..85df9727b 100644 --- a/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java +++ b/src/com/jpexs/decompiler/flash/gui/TreeNodeType.java @@ -44,6 +44,7 @@ public enum TreeNodeType { AS_INIT, PACKAGE, FRAME, + SCENE, SHOW_FRAME, MOVIE, SOUND, diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/folderscenes16.png b/src/com/jpexs/decompiler/flash/gui/graphics/folderscenes16.png new file mode 100644 index 0000000000000000000000000000000000000000..61a6a29ea398b578e657d773bb9b885d13efa0d0 GIT binary patch literal 664 zcmV;J0%!e+P)p~XdnxVjZA@0Hq8|A2I|qmy+ITaBj=IfSTxmWT3(eTe%X@$%5+_Uh{4tj^8N$@hIpQn_4~B>BEC-}m)r|6d)ru1gq( z1VKQlR3Zohc6N3ED3{9`Ud{dRZ1U~rmwr;)oKI?-^U0khcj4S=Yl9#l3_}3IFr-u} z9Yn{`VDQJMQ?a#1l9jBLtWl*>Q7)HLu~?MndGZS5^1OmP&y(Z0TDp1T%V32}F*c#I zeV^8+2efKcj;KZP#7T-1MK(4zh#GZPRw_hMMBXbfmNOH5zzC`1$|jg3hpe#e8o%mI zzJL2l61SP1oy9ARv$l2*&+}+T4Wd1p8vq=Q+N@2|0ww#TyG<@$ILrCTOJv6M+QjQO z??}^>ndxcT+t2Ng1DBCwMG9vY0Sgj~GZvd{lQmu-6QL|(;o2xN8KbAJu=V6oS{VQ& znHbx8-)%O#C~IKTIx-Ptjb6Qp%s!|C>EOvn=pfk)oBlvq)SKAo<#m)bd*UuY%Ahk0 zNF)b?vR^%6yel0An+F|7rUN9%?MBBnm^hXa y+Zh1j&fTr`>r;rUIOPBNQ3N=z609EgOTPi!EM=k^grtlB0000gQD2Hu(?%w=t*clMLvQ(#AXQ|QZIsd@!-*(ECeK#_7wEi zyF$J}l0%_;?FW!-8UpnNcV>2HdN8IYwk6Pk2cBnUe*fo%nGAERYPI@lcJK7`^c{dZ zCsdy~{(SGa|Hv{0)oL|<3yMSX1HDlr<3{^|o?!!SGpU~_Zxix48sX0tY*&rb}P z@*moL1uj66Bv-!gUl)tTWzX|4CMA}VXDchjN+M&)(()22R!AlBJnw312G-id7&F$k zD6P>-qqIgTjaF(Lt2@YX?4uz%?h`EbH>A}BPSTXs=c`zI#|iH#j~Muc9NU-_TGE$dG0ySIrr9pf5g0E#mb&QFzD1& z^*4jTP(|&RP$*P)TCCp&vun%!=9R#cSZ_U+qwEiJx0pYH*hoA1M9GC>H@ zNXx2?Mxz8(S9f_}GyxbVPoA>c?RH}*5WuvY9K<^u=)WwSzu0tLtA_o1N@=@u!27?e88vWpt7p*M9_|)-8&qzmV zYAQ~jI*pT+mCOYczh8{vl46kCISjDctmL)hIC$s~CQKNQ&vx#_?Af!WN6cn3nwpw$ z?bOIH^sh=1NFRbmZnv&r3>5^4RT;c_yRL&2V`$ zmQ}0Y!;<`bu(t>cZRW>;1K-fbe;{kpBy8XQDKf}Ad`62k4t{?-zW??+33Tq9!n5o5cDD<${^xqC@)`SECHGO)XE7|2Ca?T?qHvvRSN(!3q-j(1A zmldM4v{aHD{B(+yk6Y9caKupS4BDjea;oW^`0I3p9!wGoA^e}L2J#EPOKQZ`638EBK5a~IJ2 z_%UYBnSvmbGc**CshLcKTs}-kRRu2BUP5p0FdYJ}7)?}J**3a$0Md=-=;=*F zkiC2NVf}^;GG9A7x`;^am@;)Ls;a87Y2zjwJAMM)-My549q8-plRA5z)9LKyx# zvtbjC9y^Y%uI>oiBewq1i7zEBKYxi}>FIqe%F8Ro!iDdMwQD~Xf42KYM`xF8++VkD zy__pQQ7PB@J38gJqT=Mg>MWT5wz$>MC~f5DFXdRI4JTOI;>AnlaUIioX6QVki(4VO0}>KuB!ex=k!vv{+PCoe{xMSOkKhm+EZUvQ-ooE|=?g&2Ru* zh|&rQ3c7ae*nvHJ_94zDLgORpFd=#E zu3evF|Nbv<{`|S|IuD|kkx`aaCy|K_Fnd{qYGFyvTt+(Kh=l;?O{pO2-(eU5!N ztU`zwx1n4>2m zK(w%oHUJJQ+YlHb1mREw!0`Bwb_m!;%n)!@VdHkjSi;DJ3);d0+lWe1~A(0A07s_5iB-0Ps7_M2}26{TX?oRE?JK8$mHiTQ2}$=Kpx;ApI%PfHAVqsbw@6<@NpCFp{ZF z(Z8=l`lz+)UkSjXzu(NS2|!4H4F&OkkiP{O0L92lkcj@I&j0`b07*qoM6N<$f;9#V AUjP6A 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 9542b1ac5..e9113a9af 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1250,4 +1250,7 @@ error.wrong.packer = %item%\r\nCannot unpack binary data with %packer%.\r\nThe d contextmenu.copyTagToReplaceByClass = Copy tag to (replace by class name) contextmenu.copyTagToReplaceByExportName = Copy tag to (replace by export name) -button.breakpointList = Show breakpoint list \ No newline at end of file +button.breakpointList = Show breakpoint list + +node.scenes = scenes +contextmenu.showInFramesFolder = Show in frames folder \ 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 b9bfa3d08..bef7a988f 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1225,4 +1225,7 @@ error.wrong.packer = %item%\r\nNelze rozbalit bin\u00e1rn\u00ed data pomoc\u00ed contextmenu.copyTagToReplaceByClass = Kop\u00edrovat tag do (nahradit podle n\u00e1zvu t\u0159\u00eddy) contextmenu.copyTagToReplaceByExportName = Kop\u00edrovat tag do (nahradit podle exportovan\u00e9ho n\u00e1zvu) -button.breakpointList = Zobrazit seznam breakpoint\u016f \ No newline at end of file +button.breakpointList = Zobrazit seznam breakpoint\u016f + +node.scenes = sc\u00e9ny +contextmenu.showInFramesFolder = Zobrazit ve slo\u017ece sn\u00edmk\u016f \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java index a067b7c6a..25d21962f 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/AbstractTagTree.java @@ -90,6 +90,8 @@ import com.jpexs.decompiler.flash.timeline.AS2Package; import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; +import com.jpexs.decompiler.flash.timeline.Scene; +import com.jpexs.decompiler.flash.timeline.SceneFrame; import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange; import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.treeitems.FolderItem; @@ -376,8 +378,13 @@ public abstract class AbstractTagTree extends JTree { } if ((t instanceof Frame) - || (t instanceof FrameScript)) { + || (t instanceof FrameScript) + || (t instanceof SceneFrame)) { return TreeNodeType.FRAME; + } + + if (t instanceof Scene) { + return TreeNodeType.SCENE; } if (t instanceof ShowFrameTag) { diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index 81c0aec25..8aa34b7f2 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -95,6 +95,8 @@ import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; +import com.jpexs.decompiler.flash.timeline.Scene; +import com.jpexs.decompiler.flash.timeline.SceneFrame; import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.timeline.Timelined; @@ -275,6 +277,8 @@ public class TagTreeContextMenu extends JPopupMenu { private JMenuItem showInTagListViewTagMenuItem; private JMenuItem showInHexDumpViewTagMenuItem; + + private JMenuItem showInFramesFolderMenuItem; private JMenuItem addFramesMenuItem; @@ -501,6 +505,11 @@ public class TagTreeContextMenu extends JPopupMenu { importSymbolClassMenuItem.setIcon(View.getIcon("importsymbolclass16")); add(importSymbolClassMenuItem); + showInFramesFolderMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInFramesFolder")); + showInFramesFolderMenuItem.addActionListener(this::showInFramesFolderActionPerformed); + showInFramesFolderMenuItem.setIcon(View.getIcon("frame16")); + add(showInFramesFolderMenuItem); + showInResourcesViewTagMenuItem = new JMenuItem(mainPanel.translate("contextmenu.showInResources")); showInResourcesViewTagMenuItem.addActionListener(this::showInResourcesViewActionPerformed); showInResourcesViewTagMenuItem.setIcon(View.getIcon("folder16")); @@ -515,7 +524,7 @@ public class TagTreeContextMenu extends JPopupMenu { showInHexDumpViewTagMenuItem.addActionListener(this::showInHexDumpViewActionPerformed); showInHexDumpViewTagMenuItem.setIcon(View.getIcon("viewhex16")); add(showInHexDumpViewTagMenuItem); - + addTagInsideMenu = new JMenu(mainPanel.translate("contextmenu.addTagInside")); addTagInsideMenu.setIcon(View.getIcon("addtag16")); add(addTagInsideMenu); @@ -1130,6 +1139,7 @@ public class TagTreeContextMenu extends JPopupMenu { showInResourcesViewTagMenuItem.setVisible(false); showInTagListViewTagMenuItem.setVisible(false); showInHexDumpViewTagMenuItem.setVisible(false); + showInFramesFolderMenuItem.setVisible(false); addFramesMenuItem.setVisible(false); addFramesBeforeMenuItem.setVisible(false); addFramesAfterMenuItem.setVisible(false); @@ -1369,6 +1379,10 @@ public class TagTreeContextMenu extends JPopupMenu { || (firstItem instanceof TagScript)) { showInHexDumpViewTagMenuItem.setVisible(true); } + + if ((firstItem instanceof Scene) || (firstItem instanceof SceneFrame)) { + showInFramesFolderMenuItem.setVisible(true); + } if (firstItem instanceof SWF) { importImagesMenuItem.setVisible(true); @@ -1695,6 +1709,14 @@ public class TagTreeContextMenu extends JPopupMenu { if (item instanceof SWF) { return; } + + if (item instanceof Scene) { + return; + } + + if (item instanceof SceneFrame) { + return; + } if (item instanceof Frame) { insideFrame = true; @@ -3563,6 +3585,18 @@ public class TagTreeContextMenu extends JPopupMenu { logger.log(Level.SEVERE, null, ex); } } + + private void showInFramesFolderActionPerformed(ActionEvent evt) { + TreeItem item = getCurrentItem(); + if (item instanceof SceneFrame) { + item = ((SceneFrame) item).getFrame(); + } + if (item instanceof Scene) { + item = ((Scene) item).getSceneFrame(0).getFrame(); + } + mainPanel.setTagTreeSelectedNode(mainPanel.tagTree, item); + mainPanel.updateMenu(); + } private void showInResourcesViewActionPerformed(ActionEvent evt) { TreeItem item = getCurrentItem(); @@ -3578,6 +3612,12 @@ public class TagTreeContextMenu extends JPopupMenu { if (item instanceof TagScript) { item = ((TagScript) item).getTag(); } + if (item instanceof SceneFrame) { + item = ((SceneFrame) item).getFrame(); + } + if (item instanceof Scene) { + item = ((Scene) item).getSceneFrame(0).getFrame(); + } mainPanel.setTagTreeSelectedNode(mainPanel.tagListTree, item); mainPanel.updateMenu(); } diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java index 2a20ed879..81fa87f4b 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeModel.java @@ -40,6 +40,8 @@ import com.jpexs.decompiler.flash.timeline.AS2Package; import com.jpexs.decompiler.flash.timeline.AS3Package; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; +import com.jpexs.decompiler.flash.timeline.Scene; +import com.jpexs.decompiler.flash.timeline.SceneFrame; import com.jpexs.decompiler.flash.timeline.SoundStreamFrameRange; import com.jpexs.decompiler.flash.timeline.TagScript; import com.jpexs.decompiler.flash.timeline.Timeline; @@ -91,6 +93,8 @@ public class TagTreeModel extends AbstractTagTreeModel { public static final String FOLDER_OTHERS = "others"; public static final String FOLDER_SCRIPTS = "scripts"; + + public static final String FOLDER_SCENES = "scenes"; private final List listeners = new ArrayList<>(); @@ -261,6 +265,10 @@ public class TagTreeModel extends AbstractTagTreeModel { for (int i = 0; i < frameCount; i++) { frames.add(timeline.getFrame(i)); } + List scenes = new ArrayList<>(); + + List sceneList = timeline.getScenes(); + scenes.addAll(sceneList); for (int i = sounds.size() - 1; i >= 0; i--) { TreeItem sound = sounds.get(i); @@ -285,6 +293,7 @@ public class TagTreeModel extends AbstractTagTreeModel { addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.fonts"), FOLDER_FONTS, swf, fonts); addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.binaryData"), FOLDER_BINARY_DATA, swf, binaryData); addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.frames"), FOLDER_FRAMES, swf, frames); + addFolderItem(nodeList, emptyFolders, addAllFolders, translate("node.scenes"), FOLDER_SCENES, swf, scenes); addFolderItem(nodeList, emptyFolders, true /*always add*/, translate("node.others"), FOLDER_OTHERS, swf, others); Map currentTagScriptCache = new HashMap<>(); @@ -418,6 +427,15 @@ public class TagTreeModel extends AbstractTagTreeModel { } } + if (obj instanceof SceneFrame && n instanceof SceneFrame) { + // SceneFrames are always recreated, so compare them by frame and swf + SceneFrame nds = (SceneFrame) n; + SceneFrame objs = (SceneFrame) obj; + if (objs.getFrame().frame == nds.getFrame().frame && objs.getOpenable() == nds.getOpenable()) { + return newPath; + } + } + if (obj instanceof FolderItem && n instanceof FolderItem) { // FolderItems are always recreated, so compare them by name and swf FolderItem nds = (FolderItem) n; @@ -521,6 +539,13 @@ public class TagTreeModel extends AbstractTagTreeModel { return ((OpenableList) parentNode).items; } else if (parentNode instanceof SWF) { return getSwfFolders((SWF) parentNode); + } else if (parentNode instanceof Scene) { + Scene scene = (Scene) parentNode; + List sceneFrames = new ArrayList<>(); + for (int i = 0; i < scene.getSceneFrameCount(); i++) { + sceneFrames.add(scene.getSceneFrame(i)); + } + return sceneFrames; } else if (parentNode instanceof FolderItem) { return ((FolderItem) parentNode).subItems; } else if (parentNode instanceof Frame) { @@ -614,6 +639,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return ((OpenableList) parentNode).items.get(index); } else if (parentNode instanceof SWF) { return getSwfFolders((SWF) parentNode).get(index); + } else if (parentNode instanceof Scene) { + return ((Scene) parentNode).getSceneFrame(index); } else if (parentNode instanceof FolderItem) { return ((FolderItem) parentNode).subItems.get(index); } else if (parentNode instanceof Frame) { @@ -687,6 +714,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return mappedSize + ((OpenableList) parentNode).items.size(); } else if (parentNode instanceof SWF) { return mappedSize + getSwfFolders((SWF) parentNode).size(); + } else if (parentNode instanceof Scene) { + return mappedSize + ((Scene) parentNode).getSceneFrameCount(); } else if (parentNode instanceof HeaderItem) { return mappedSize + 0; } else if (parentNode instanceof FolderItem) { @@ -763,6 +792,8 @@ public class TagTreeModel extends AbstractTagTreeModel { return indexOfAdd(baseIndex, ((OpenableList) parentNode).items.indexOf(childNode)); } else if (parentNode instanceof SWF) { return indexOfAdd(baseIndex, getSwfFolders((SWF) parentNode).indexOf(childNode)); + } else if (parentNode instanceof Scene) { + return getAllChildren(parentNode).indexOf(childNode); } else if (parentNode instanceof FolderItem) { return indexOfAdd(baseIndex, ((FolderItem) parentNode).subItems.indexOf(childNode)); } else if (parentNode instanceof Frame) {