diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e9b43abf..60b7d00dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to this project will be documented in this file. - #1202 Check for modifications outside FFDec and ask user to reload - #1155, #1602 AS3 remove trait button - #1260, #1438 AS1/2 direct editing on(xxx), onClipEvent(xxx) handlers -- AS1/2 Add new frame script +- AS1/2 Add new script ### Fixed - #1298 AS1/2 properly decompiled setProperty/getProperty diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java index 63bc8547d..5e4b2b58b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/BUTTONCONDACTION.java @@ -63,6 +63,12 @@ public class BUTTONCONDACTION implements ASMSource, Serializable { actionBytes = new ByteArrayRange(SWFInputStream.BYTE_ARRAY_EMPTY); } + public BUTTONCONDACTION(SWF swf, Tag tag) { + this.swf = swf; + this.tag = tag; + actionBytes = new ByteArrayRange(SWFInputStream.BYTE_ARRAY_EMPTY); + } + @Override public void setScriptName(String scriptName) { this.scriptName = scriptName; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java index 80b106456..199aae3ed 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONRECORD.java @@ -128,6 +128,13 @@ public class CLIPACTIONRECORD implements ASMSource, Serializable { actionBytes = ByteArrayRange.EMPTY; } + public CLIPACTIONRECORD(SWF swf, Tag tag) { + this.swf = swf; + this.tag = tag; + eventFlags = new CLIPEVENTFLAGS(); + actionBytes = ByteArrayRange.EMPTY; + } + @Override public void setScriptName(String scriptName) { this.scriptName = scriptName; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONS.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONS.java index f703e3ec9..6ee18faf6 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONS.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CLIPACTIONS.java @@ -48,7 +48,8 @@ public class CLIPACTIONS implements Serializable { public void calculateAllEventFlags() { - Field[] fields = allEventFlags.getClass().getDeclaredFields(); + allEventFlags = new CLIPEVENTFLAGS(); + Field[] fields = CLIPEVENTFLAGS.class.getDeclaredFields(); try { for (Field f : fields) { if (!f.getName().startsWith("clipEvent")) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CXFORMWITHALPHA.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CXFORMWITHALPHA.java index ca278c83f..f99fcfbd8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CXFORMWITHALPHA.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/CXFORMWITHALPHA.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.types.annotations.Calculated; @@ -140,6 +141,17 @@ public class CXFORMWITHALPHA extends ColorTransform { public CXFORMWITHALPHA() { } + public CXFORMWITHALPHA(CXFORM cxform) { + redMultTerm = cxform.redMultTerm; + greenMultTerm = cxform.greenMultTerm; + blueMultTerm = cxform.blueMultTerm; + redAddTerm = cxform.redAddTerm; + greenAddTerm = cxform.greenAddTerm; + blueAddTerm = cxform.blueAddTerm; + alphaAddTerm = 0; + alphaMultTerm = 255; + } + public CXFORMWITHALPHA(ColorTransform colorTransform) { redMultTerm = colorTransform.getRedMulti(); greenMultTerm = colorTransform.getGreenMulti(); diff --git a/src/com/jpexs/decompiler/flash/gui/AppDialog.java b/src/com/jpexs/decompiler/flash/gui/AppDialog.java index bb1100e6d..eb598e0ff 100644 --- a/src/com/jpexs/decompiler/flash/gui/AppDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/AppDialog.java @@ -55,7 +55,7 @@ public abstract class AppDialog extends JDialog { return resourceBundle; } - public String translate(String key) { + public final String translate(String key) { return resourceBundle.getString(key); } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index bd171f06b..143528451 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -758,4 +758,8 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel || (genericSaveButton.isVisible() && genericSaveButton.isEnabled()) || (metadataSaveButton.isVisible() && metadataSaveButton.isEnabled()); } + + public void selectImageDepth(int depth) { + imagePanel.selectDepth(depth); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/action/AddScriptDialog.java b/src/com/jpexs/decompiler/flash/gui/action/AddScriptDialog.java index 87101a22e..efd7514f4 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/AddScriptDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/action/AddScriptDialog.java @@ -16,20 +16,56 @@ */ package com.jpexs.decompiler.flash.gui.action; +import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.gui.AppDialog; import com.jpexs.decompiler.flash.gui.Main; +import com.jpexs.decompiler.flash.gui.MainPanel; +import com.jpexs.decompiler.flash.gui.PreviewPanel; import com.jpexs.decompiler.flash.gui.View; +import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; +import com.jpexs.decompiler.flash.tags.ShowFrameTag; +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.timeline.Timelined; import java.awt.BorderLayout; +import java.awt.CardLayout; +import java.awt.Color; +import java.awt.Component; import java.awt.Container; +import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import javax.swing.DefaultListCellRenderer; +import javax.swing.ImageIcon; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JLabel; -import javax.swing.JOptionPane; +import javax.swing.JList; import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JSplitPane; import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.ListSelectionModel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; +import javax.swing.plaf.basic.BasicLabelUI; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeNode; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; /** * @@ -41,15 +77,36 @@ public class AddScriptDialog extends AppDialog { private final JButton cancelButton = new JButton(translate("button.cancel")); private JTextField frameTextField; + private JTextField spriteFrameTextField; + private PreviewPanel spritePreviewPanel; + private PreviewPanel buttonPreviewPanel; + private PreviewPanel instancePreviewPanel; + + private JTree instanceTree; + + private JList spriteList; + + private JList buttonList; private int frame = -1; private int result = ERROR_OPTION; - public AddScriptDialog() { + private JPanel centerPanel; + + public static final int TYPE_FRAME = 0; + public static final int TYPE_SPRITE_FRAME = 1; + public static final int TYPE_BUTTON_EVENT = 2; + public static final int TYPE_INSTANCE_EVENT = 3; + private final SWF swf; + + private JComboBox typeComboBox; + + public AddScriptDialog(SWF swf) { setDefaultCloseOperation(HIDE_ON_CLOSE); setTitle(translate("dialog.title")); + this.swf = swf; Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); @@ -59,13 +116,44 @@ public class AddScriptDialog extends AppDialog { panButtons.add(okButton); panButtons.add(cancelButton); - JPanel centerPanel = new JPanel(new FlowLayout()); - JLabel frameLabel = new JLabel(translate("framenum")); - frameTextField = new JTextField(4); - frameTextField.addActionListener(this::okButtonActionPerformed); - frameLabel.setLabelFor(frameTextField); - centerPanel.add(frameLabel); - centerPanel.add(frameTextField); + JPanel topPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + JLabel typeLabel = new JLabel(translate("type")); + typeComboBox = new JComboBox<>(new String[]{ + translate("type.frame"), + translate("type.sprite.frame"), + translate("type.button.event"), + translate("type.instance.event") + }); + typeComboBox.addActionListener(this::typeChangedActionPerformed); + typeLabel.setLabelFor(typeComboBox); + topPanel.add(typeLabel); + topPanel.add(typeComboBox); + + cnt.add(topPanel, BorderLayout.NORTH); + + DocumentListener checkEnabledDocumentListener = new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + checkEnabled(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + checkEnabled(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + checkEnabled(); + } + }; + + centerPanel = new JPanel(new CardLayout()); + centerPanel.add(createFramePanel(checkEnabledDocumentListener), "" + TYPE_FRAME); + centerPanel.add(createSpritePanel(checkEnabledDocumentListener), "" + TYPE_SPRITE_FRAME); + centerPanel.add(createButtonPanel(), "" + TYPE_BUTTON_EVENT); + centerPanel.add(createInstancePanel(), "" + TYPE_INSTANCE_EVENT); cnt.add(centerPanel, BorderLayout.CENTER); cnt.add(panButtons, BorderLayout.SOUTH); @@ -73,34 +161,458 @@ public class AddScriptDialog extends AppDialog { setModal(true); setResizable(true); pack(); + View.setWindowIcon(this); View.centerScreen(this); + checkEnabled(); + } + + private JPanel createFramePanel(DocumentListener checkEnabledDocumentListener) { + JPanel framePanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + JLabel frameLabel = new JLabel(translate("framenum")); + frameTextField = new JTextField(4); + frameTextField.addActionListener(this::okButtonActionPerformed); + + frameTextField.getDocument().addDocumentListener(checkEnabledDocumentListener); + frameLabel.setLabelFor(frameTextField); + framePanel.add(frameLabel); + framePanel.add(frameTextField); + return framePanel; + } + + private JPanel createSpritePanel(DocumentListener checkEnabledDocumentListener) { + + JPanel spriteFramePanel = new JPanel(new BorderLayout()); + JLabel spriteFrameLabel = new JLabel(translate("framenum")); + spriteFrameTextField = new JTextField(4); + spriteFrameTextField.addActionListener(this::okButtonActionPerformed); + spriteFrameTextField.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + checkEnabled(); + } + }); + spriteFrameTextField.getDocument().addDocumentListener(checkEnabledDocumentListener); + + List sprites = new ArrayList<>(); + for (Tag t : swf.getTags()) { + if (t instanceof DefineSpriteTag) { + sprites.add((DefineSpriteTag) t); + } + } + spriteList = new JList<>(sprites.toArray(new DefineSpriteTag[sprites.size()])); + final ImageIcon spriteIcon = View.getIcon("sprite16"); + spriteList.setCellRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component renderer = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (renderer instanceof JLabel) { + ((JLabel) renderer).setIcon(spriteIcon); + } + return renderer; + } + }); + spriteList.addListSelectionListener(this::spriteValueChanged); + spriteList.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + spriteFrameLabel.setLabelFor(spriteFrameTextField); + + JPanel spriteFrameTopPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + spriteFrameTopPanel.add(spriteFrameLabel); + spriteFrameTopPanel.add(spriteFrameTextField); + + spriteFramePanel.add(spriteFrameTopPanel, BorderLayout.NORTH); + + spritePreviewPanel = new PreviewPanel(Main.getMainFrame().getPanel(), null); + spritePreviewPanel.setReadOnly(true); + spritePreviewPanel.setPreferredSize(new Dimension(300, 1)); + spritePreviewPanel.showEmpty(); + spritePreviewPanel.setParametersPanelVisible(false); + + JScrollPane spriteListScrollPane = new JScrollPane(spriteList); + spriteListScrollPane.setMinimumSize(new Dimension(400, 1)); + JSplitPane spriteSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, spriteListScrollPane, spritePreviewPanel); + spriteSplitPane.setDividerLocation(0.7); + spriteFramePanel.add(spriteSplitPane, BorderLayout.CENTER); + return spriteFramePanel; + } + + private JPanel createButtonPanel() { + List buttons = new ArrayList<>(); + for (Tag t : swf.getTags()) { + if (t instanceof ButtonTag) { + buttons.add((ButtonTag) t); + } + } + buttonList = new JList<>(buttons.toArray(new DefineButton2Tag[buttons.size()])); + final ImageIcon buttonIcon = View.getIcon("button16"); + buttonList.setCellRenderer(new DefaultListCellRenderer() { + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + Component renderer = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (renderer instanceof JLabel) { + ((JLabel) renderer).setIcon(buttonIcon); + } + return renderer; + } + }); + buttonList.addListSelectionListener(this::buttonValueChanged); + buttonList.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + buttonPreviewPanel = new PreviewPanel(Main.getMainFrame().getPanel(), null); + buttonPreviewPanel.setReadOnly(true); + buttonPreviewPanel.setPreferredSize(new Dimension(300, 1)); + buttonPreviewPanel.showEmpty(); + + JPanel buttonPanel = new JPanel(new BorderLayout()); + JScrollPane buttonListScrollPane = new JScrollPane(buttonList); + buttonListScrollPane.setMinimumSize(new Dimension(400, 1)); + JSplitPane buttonSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, buttonListScrollPane, buttonPreviewPanel); + buttonSplitPane.setDividerLocation(0.7); + buttonPanel.add(buttonSplitPane, BorderLayout.CENTER); + return buttonPanel; + } + + private static class MyTreeNode implements TreeNode { + + private List children = new ArrayList<>(); + private TreeNode parent; + private Object data; + + @Override + public String toString() { + return data.toString(); + } + + public void setData(Object data) { + this.data = data; + } + + public Object getData() { + return data; + } + + public void addChild(TreeNode node) { + children.add(node); + } + + public void setParent(TreeNode parent) { + this.parent = parent; + } + + @Override + public TreeNode getChildAt(int childIndex) { + return children.get(childIndex); + } + + @Override + public int getChildCount() { + return children.size(); + } + + @Override + public TreeNode getParent() { + return parent; + } + + @Override + public int getIndex(TreeNode node) { + return children.indexOf(node); + } + + @Override + public boolean getAllowsChildren() { + return true; + } + + @Override + public boolean isLeaf() { + return children.isEmpty(); + } + + @Override + public Enumeration children() { + return Collections.enumeration(children); + } + + } + + private static class MyFrame { + + private int frame; + + public MyFrame(int frame) { + this.frame = frame; + } + + public int getFrame() { + return frame; + } + + @Override + public String toString() { + return "frame " + frame; + } + + + } + + private void nodesFromTimelined(MyTreeNode root, Timelined tim) { + int frame = 1; + List currentFramePlaces = new ArrayList<>(); + for (Tag t : tim.getTags()) { + if (t instanceof DefineSpriteTag) { + MyTreeNode sprite = new MyTreeNode(); + sprite.setParent(root); + sprite.setData(t); + nodesFromTimelined(sprite, (DefineSpriteTag) t); + if (sprite.getChildCount() > 0) { + root.addChild(sprite); + } + } + } + for (Tag t : tim.getTags()) { + if (t instanceof ShowFrameTag) { + if (!currentFramePlaces.isEmpty()) { + MyTreeNode frameNode = new MyTreeNode(); + frameNode.setData(new MyFrame(frame)); + frameNode.setParent(root); + for (MyTreeNode p : currentFramePlaces) { + p.setParent(frameNode); + frameNode.addChild(p); + } + root.addChild(frameNode); + currentFramePlaces.clear(); + } + frame++; + } + if (t instanceof PlaceObjectTypeTag) { + MyTreeNode place = new MyTreeNode(); + place.setData(t); + currentFramePlaces.add(place); + } + } + } + + private JPanel createInstancePanel() { + MyTreeNode root = new MyTreeNode(); + root.setData("root"); + nodesFromTimelined(root, swf); + instanceTree = new JTree(root); + instanceTree.setRootVisible(false); + instanceTree.setShowsRootHandles(true); + instanceTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); + final ImageIcon placeIcon = View.getIcon("placeobject16"); + final ImageIcon spriteIcon = View.getIcon("sprite16"); + final ImageIcon frameIcon = View.getIcon("frame16"); + + instanceTree.setCellRenderer(new DefaultTreeCellRenderer() { + { + setUI(new BasicLabelUI()); + setOpaque(false); + setBackgroundNonSelectionColor(Color.white); + } + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { + Component renderer = super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); + if (renderer instanceof JLabel) { + JLabel lab = (JLabel) renderer; + Object subValue = value; + if (value instanceof MyTreeNode) { + subValue = ((MyTreeNode) value).getData(); + } + if (subValue instanceof PlaceObjectTypeTag) { + lab.setIcon(placeIcon); + } else if (subValue instanceof DefineSpriteTag) { + lab.setIcon(spriteIcon); + } else if (subValue instanceof MyFrame) { + lab.setIcon(frameIcon); + } + } + return renderer; + } + }); + + instanceTree.addTreeSelectionListener(this::instanceValueChanged); + instanceTree.setBackground(Color.white); + + instancePreviewPanel = new PreviewPanel(Main.getMainFrame().getPanel(), null); + instancePreviewPanel.setReadOnly(true); + instancePreviewPanel.setPreferredSize(new Dimension(300, 1)); + instancePreviewPanel.showEmpty(); + instancePreviewPanel.setParametersPanelVisible(false); + + JPanel instancePanel = new JPanel(new BorderLayout()); + JScrollPane instanceTreeScrollPane = new JScrollPane(instanceTree); + instanceTreeScrollPane.setMinimumSize(new Dimension(400, 1)); + JSplitPane instanceSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, instanceTreeScrollPane, instancePreviewPanel); + instanceSplitPane.setDividerLocation(0.7); + instancePanel.add(instanceSplitPane, BorderLayout.CENTER); + return instancePanel; + } + + private void instanceValueChanged(TreeSelectionEvent e) { + TreePath selection = instanceTree.getSelectionPath(); + if (selection == null) { + return; + } + MyTreeNode tnode = (MyTreeNode) selection.getLastPathComponent(); + if (tnode.getData() instanceof PlaceObjectTypeTag) { + + PlaceObjectTypeTag place = (PlaceObjectTypeTag) tnode.getData(); + instancePreviewPanel.selectImageDepth(place.getDepth()); + int frame = ((MyFrame) ((MyTreeNode) tnode.getParent()).getData()).frame; + Object parent = ((MyTreeNode) tnode.getParent().getParent()).getData(); + if (parent instanceof DefineSpriteTag) { + instancePreviewPanel.showImagePanel((DefineSpriteTag) parent, swf, frame - 1); + } else { + instancePreviewPanel.showImagePanel(swf, swf, frame - 1); + } + + } else if (tnode.getData() instanceof DefineSpriteTag) { + instancePreviewPanel.selectImageDepth(-1); + instancePreviewPanel.showImagePanel((DefineSpriteTag) tnode.getData(), swf, -1); + } else if (tnode.getData() instanceof MyFrame) { + instancePreviewPanel.selectImageDepth(-1); + int frame = ((MyFrame) tnode.getData()).frame; + Object parent = ((MyTreeNode) tnode.getParent()).getData(); + if (parent instanceof DefineSpriteTag) { + instancePreviewPanel.showImagePanel((DefineSpriteTag) parent, swf, frame - 1); + } else { + instancePreviewPanel.showImagePanel(swf, swf, frame - 1); + } + } + checkEnabled(); + } + + private void buttonValueChanged(ListSelectionEvent e) { + buttonPreviewPanel.showEmpty(); + buttonPreviewPanel.showImagePanel(MainPanel.makeTimelined(buttonList.getSelectedValue()), swf, -1); + checkEnabled(); + } + + private void spriteValueChanged(ListSelectionEvent e) { + spritePreviewPanel.showEmpty(); + spritePreviewPanel.showImagePanel(spriteList.getSelectedValue(), swf, -1); + checkEnabled(); + } + + private void typeChangedActionPerformed(ActionEvent evt) { + int selectedType = ((JComboBox) evt.getSource()).getSelectedIndex(); + ((CardLayout) centerPanel.getLayout()).show(centerPanel, "" + selectedType); + pack(); + checkEnabled(); + } + + private void checkEnabled() { + okButton.setEnabled(true); + int type = typeComboBox.getSelectedIndex(); + if (type == TYPE_SPRITE_FRAME) { + if (spriteList.getSelectedIndex() == -1) { + okButton.setEnabled(false); + } + boolean invalid = false; + try { + frame = Integer.parseInt(spriteFrameTextField.getText()); + if (frame <= 0) { + invalid = true; + } + + } catch (NumberFormatException nfe) { + invalid = true; + } + if (invalid) { + okButton.setEnabled(false); + } + } + if (type == TYPE_FRAME) { + boolean invalid = false; + try { + frame = Integer.parseInt(frameTextField.getText()); + if (frame <= 0) { + invalid = true; + } + + } catch (NumberFormatException nfe) { + invalid = true; + } + if (invalid) { + okButton.setEnabled(false); + } + } + + if (type == TYPE_BUTTON_EVENT) { + if (buttonList.getSelectedIndex() < 0) { + okButton.setEnabled(false); + } + } + + if (type == TYPE_INSTANCE_EVENT) { + TreePath selection = instanceTree.getSelectionPath(); + if (selection == null) { + okButton.setEnabled(false); + return; + } + MyTreeNode tnode = (MyTreeNode) selection.getLastPathComponent(); + okButton.setEnabled(false); + if (tnode.getData() instanceof PlaceObjectTypeTag) { + okButton.setEnabled(true); + } + } + } private void okButtonActionPerformed(ActionEvent evt) { - boolean invalid = false; - try { + int type = getScriptType(); + frame = -1; + if (type == TYPE_FRAME) { frame = Integer.parseInt(frameTextField.getText()); - if (frame <= 0) { - invalid = true; - } - - } catch (NumberFormatException nfe) { - invalid = true; - } - - if (invalid) { - View.showMessageDialog(this, translate("message.framenum.invalid"), Main.getMainFrame().translate("error"), JOptionPane.ERROR_MESSAGE); - frame = -1; - } else { - result = OK_OPTION; - setVisible(false); + } else if (type == TYPE_SPRITE_FRAME) { + frame = Integer.parseInt(spriteFrameTextField.getText()); + } else if (type == TYPE_INSTANCE_EVENT) { + MyTreeNode placeNode = (MyTreeNode) instanceTree.getSelectionPath().getLastPathComponent(); + frame = ((MyFrame) ((MyTreeNode) placeNode.getParent()).getData()).frame; } + result = OK_OPTION; + setVisible(false); } public int getFrame() { return frame; } + public int getScriptType() { + return typeComboBox.getSelectedIndex(); + } + + public DefineSpriteTag getSprite() { + if (getScriptType() == TYPE_SPRITE_FRAME) { + return spriteList.getSelectedValue(); + } + if (getScriptType() == TYPE_INSTANCE_EVENT) { + MyTreeNode tnode = (MyTreeNode) instanceTree.getSelectionPath().getLastPathComponent(); + Object parent = ((MyTreeNode) tnode.getParent().getParent()).getData(); + if (parent instanceof DefineSpriteTag) { + return (DefineSpriteTag) parent; + } else { + return null; + } + } + return null; + } + + public PlaceObjectTypeTag getPlaceObject() { + if (getScriptType() == TYPE_INSTANCE_EVENT) { + return (PlaceObjectTypeTag) ((MyTreeNode) instanceTree.getSelectionPath().getLastPathComponent()).getData(); + } + return null; + } + + public DefineButton2Tag getButton() { + if (getScriptType() == TYPE_BUTTON_EVENT) { + return buttonList.getSelectedValue(); + } + return null; + } private void cancelButtonActionPerformed(ActionEvent evt) { result = CANCEL_OPTION; diff --git a/src/com/jpexs/decompiler/flash/gui/locales/action/AddScriptDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/action/AddScriptDialog.properties index 0dfa5d2f8..ec8443e3d 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/action/AddScriptDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/action/AddScriptDialog.properties @@ -1,6 +1,14 @@ -framenum = Frame # +framenum = Frame #: dialog.title = Add new script button.ok = OK button.cancel = Cancel message.framenum.invalid = Invalid Frame # -message.alreadyhasscript = The selected frame already contains a script \ No newline at end of file +message.alreadyhasscript = The selected frame already contains a script +type = Script type: +type.frame = Main movie frame script +type.sprite.frame = Sprite frame script +type.button.event = Button event +type.instance.event = Instance event + +sprite = Sprite: +instance = Instance: \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java index f5dadee9b..d56ce8d3f 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -25,21 +25,33 @@ import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog; import com.jpexs.decompiler.flash.gui.View; import com.jpexs.decompiler.flash.gui.action.AddScriptDialog; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineButton2Tag; import com.jpexs.decompiler.flash.tags.DefineSoundTag; +import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DoActionTag; import com.jpexs.decompiler.flash.tags.DoInitActionTag; +import com.jpexs.decompiler.flash.tags.PlaceObject2Tag; +import com.jpexs.decompiler.flash.tags.PlaceObject3Tag; +import com.jpexs.decompiler.flash.tags.PlaceObject4Tag; +import com.jpexs.decompiler.flash.tags.PlaceObjectTag; import com.jpexs.decompiler.flash.tags.ShowFrameTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.ImageTag; +import com.jpexs.decompiler.flash.tags.base.PlaceObjectTypeTag; import com.jpexs.decompiler.flash.tags.base.ShapeTag; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.FrameScript; import com.jpexs.decompiler.flash.timeline.TagScript; +import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.treeitems.FolderItem; import com.jpexs.decompiler.flash.treeitems.SWFList; import com.jpexs.decompiler.flash.treeitems.TreeItem; +import com.jpexs.decompiler.flash.types.BUTTONCONDACTION; +import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD; +import com.jpexs.decompiler.flash.types.CLIPACTIONS; +import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA; import com.jpexs.helpers.Helper; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; @@ -341,7 +353,11 @@ public class TagTreeContextMenu extends JPopupMenu { boolean singleSelect = items.size() == 1; Predicate> canReplace = p -> { - for (TreeItem ti : items) if (!p.test(ti)) return false; + for (TreeItem ti : items) { + if (!p.test(ti)) { + return false; + } + } return true; }; @@ -707,69 +723,217 @@ public class TagTreeContextMenu extends JPopupMenu { } private void addScriptActionPerformed(ActionEvent evt) { - AddScriptDialog addScriptDialog = new AddScriptDialog(); - if (addScriptDialog.showDialog() == JOptionPane.OK_OPTION) { - int targetFrame = addScriptDialog.getFrame(); - List sel = tagTree.getSelected(); - if (!sel.isEmpty()) { - if (sel.get(0) instanceof FolderItem) { + List sel = tagTree.getSelected(); + if (!sel.isEmpty()) { + if (sel.get(0) instanceof FolderItem) { - FolderItem folder = (FolderItem) sel.get(0); - SWF swf = folder.getSwf(); + FolderItem folder = (FolderItem) sel.get(0); + SWF swf = folder.getSwf(); - DoActionTag doAction = new DoActionTag(swf); + AddScriptDialog addScriptDialog = new AddScriptDialog(swf); + if (addScriptDialog.showDialog() == JOptionPane.OK_OPTION) { + if ((addScriptDialog.getScriptType() == AddScriptDialog.TYPE_FRAME) + || (addScriptDialog.getScriptType() == AddScriptDialog.TYPE_SPRITE_FRAME)) { - ReadOnlyTagList tagList = swf.getTags(); - int frame = 1; - boolean frameFound = false; - for (int i = 0; i < tagList.size(); i++) { - Tag t = tagList.get(i); - if (frame == targetFrame && t instanceof DoActionTag) { - View.showMessageDialog(mainPanel, AppDialog.translateForDialog("message.alreadyhasscript", AddScriptDialog.class), - mainPanel.getMainFrame().translate("error"), JOptionPane.ERROR_MESSAGE - ); - addScriptActionPerformed(evt); - return; + Timelined tim = swf; + if (addScriptDialog.getScriptType() == AddScriptDialog.TYPE_SPRITE_FRAME) { + tim = addScriptDialog.getSprite(); } - if (t instanceof ShowFrameTag) { - if (frame == targetFrame) { - swf.addTag(i, doAction); - frameFound = true; - break; + + int targetFrame = addScriptDialog.getFrame(); + + DoActionTag doAction = new DoActionTag(swf); + + ReadOnlyTagList tagList = tim.getTags(); + int frame = 1; + boolean frameFound = false; + for (int i = 0; i < tagList.size(); i++) { + Tag t = tagList.get(i); + if (frame == targetFrame && t instanceof DoActionTag) { + View.showMessageDialog(mainPanel, AppDialog.translateForDialog("message.alreadyhasscript", AddScriptDialog.class), + mainPanel.getMainFrame().translate("error"), JOptionPane.ERROR_MESSAGE + ); + addScriptActionPerformed(evt); + return; + } + if (t instanceof ShowFrameTag) { + if (frame == targetFrame) { + tim.addTag(i, doAction); + frameFound = true; + break; + } + frame++; } - frame++; } - } - if (!frameFound) { - for (; frame < targetFrame; frame++) { - swf.addTag(new ShowFrameTag(swf)); + if (!frameFound) { + for (; frame < targetFrame; frame++) { + tim.addTag(new ShowFrameTag(swf)); + } + tim.addTag(doAction); + tim.addTag(new ShowFrameTag(swf)); } - swf.addTag(doAction); - swf.addTag(new ShowFrameTag(swf)); - } - TreePath selection = mainPanel.tagTree.getSelectionPath(); - TreePath swfPath = selection.getParentPath(); - swf.resetTimeline(); - mainPanel.refreshTree(swf); + TreePath selection = mainPanel.tagTree.getSelectionPath(); + TreePath swfPath = selection.getParentPath(); + tim.resetTimeline(); + mainPanel.refreshTree(swf); - FolderItem scriptsNode = (FolderItem) mainPanel.tagTree.getModel().getScriptsNode(swf); - TreePath scriptsPath = swfPath.pathByAddingChild(scriptsNode); - for (TreeItem subItem : scriptsNode.subItems) { - if (subItem instanceof FrameScript) { - if (((FrameScript) subItem).getFrame().frame + 1 == targetFrame) { - TreePath framePath = scriptsPath.pathByAddingChild(subItem); - TreeItem doActionTag = mainPanel.tagTree.getModel().getChild(subItem, 0); - TreePath doActionPath = framePath.pathByAddingChild(doActionTag); - mainPanel.tagTree.setSelectionPath(doActionPath); - break; + FolderItem scriptsNode = (FolderItem) mainPanel.tagTree.getModel().getScriptsNode(swf); + TreePath scriptsPath = swfPath.pathByAddingChild(scriptsNode); + + if (addScriptDialog.getScriptType() == AddScriptDialog.TYPE_FRAME) { + for (TreeItem subItem : scriptsNode.subItems) { + if (subItem instanceof FrameScript) { + if (((FrameScript) subItem).getFrame().frame + 1 == targetFrame) { + TreePath framePath = scriptsPath.pathByAddingChild(subItem); + TreeItem doActionTag = mainPanel.tagTree.getModel().getChild(subItem, 0); + TreePath doActionPath = framePath.pathByAddingChild(doActionTag); + mainPanel.tagTree.setSelectionPath(doActionPath); + break; + } + } + } + } else { //sprite + for (TreeItem subItem : scriptsNode.subItems) { + if (subItem instanceof TagScript) { + if (((TagScript) subItem).getTag() == tim) { + TreePath spritePath = scriptsPath.pathByAddingChild(subItem); + TagScript ts = (TagScript) subItem; + for (TreeItem f : ts.getFrames()) { + if (f instanceof FrameScript) { + FrameScript fs = (FrameScript) f; + if (fs.getFrame().frame + 1 == targetFrame) { + TreePath framePath = spritePath.pathByAddingChild(fs); + TreeItem doActionTag = mainPanel.tagTree.getModel().getChild(fs, 0); + TreePath doActionPath = framePath.pathByAddingChild(doActionTag); + mainPanel.tagTree.setSelectionPath(doActionPath); + break; + } + } + } + break; + } + } + } + } + } else if (addScriptDialog.getScriptType() == AddScriptDialog.TYPE_BUTTON_EVENT) { + DefineButton2Tag button = addScriptDialog.getButton(); + BUTTONCONDACTION bca = new BUTTONCONDACTION(swf, button); + bca.condOverUpToOverDown = true; //press + button.actions.add(bca); + button.setModified(true); + + button.resetTimeline(); + mainPanel.refreshTree(swf); + + FolderItem scriptsNode = (FolderItem) mainPanel.tagTree.getModel().getScriptsNode(swf); + TreePath selection = mainPanel.tagTree.getSelectionPath(); + TreePath swfPath = selection.getParentPath(); + TreePath scriptsPath = swfPath.pathByAddingChild(scriptsNode); + for (TreeItem subItem : scriptsNode.subItems) { + if (subItem instanceof TagScript) { + if (((TagScript) subItem).getTag() == button) { + TreePath buttonPath = scriptsPath.pathByAddingChild(subItem); + TreePath buttonCondPath = buttonPath.pathByAddingChild(bca); + mainPanel.tagTree.setSelectionPath(buttonCondPath); + break; + } + } + } + } else if (addScriptDialog.getScriptType() == AddScriptDialog.TYPE_INSTANCE_EVENT) { + DefineSpriteTag sprite = addScriptDialog.getSprite(); + int frame = addScriptDialog.getFrame(); + PlaceObjectTypeTag placeType = addScriptDialog.getPlaceObject(); + CLIPACTIONS clipActions = null; + + Timelined tim = swf; + if (sprite != null) { + tim = sprite; + } + + if (placeType instanceof PlaceObjectTag) { + ReadOnlyTagList tags = tim.getTags(); + PlaceObjectTag place = (PlaceObjectTag) placeType; + clipActions = new CLIPACTIONS(); + for (int i = 0; i < tags.size(); i++) { + if (tags.get(i) == placeType) { + PlaceObject2Tag place2 = new PlaceObject2Tag(swf, false, place.depth, place.characterId, place.matrix, + new CXFORMWITHALPHA(place.colorTransform), -1, null, -1, clipActions); + tim.replaceTag(i, place2); + placeType = place2; + break; + } + } + } + if (placeType instanceof PlaceObject2Tag) { + PlaceObject2Tag place2 = (PlaceObject2Tag) placeType; + if (!place2.placeFlagHasClipActions) { + clipActions = place2.clipActions = new CLIPACTIONS(); + place2.placeFlagHasClipActions = true; + } + } + if (placeType instanceof PlaceObject3Tag) { + PlaceObject3Tag place3 = (PlaceObject3Tag) placeType; + if (!place3.placeFlagHasClipActions) { + clipActions = place3.clipActions = new CLIPACTIONS(); + place3.placeFlagHasClipActions = true; + } + } + if (placeType instanceof PlaceObject4Tag) { + PlaceObject4Tag place4 = (PlaceObject4Tag) placeType; + if (!place4.placeFlagHasClipActions) { + clipActions = place4.clipActions = new CLIPACTIONS(); + place4.placeFlagHasClipActions = true; + } + } + CLIPACTIONRECORD clipActionRecord = new CLIPACTIONRECORD(swf, (Tag) placeType); + clipActionRecord.setParentClipActions(clipActions); + clipActionRecord.eventFlags.clipEventPress = true; + + clipActions.clipActionRecords.add(clipActionRecord); + clipActions.calculateAllEventFlags(); + + ((Tag) placeType).setModified(true); + + TreePath selection = mainPanel.tagTree.getSelectionPath(); + TreePath swfPath = selection.getParentPath(); + tim.resetTimeline(); + mainPanel.refreshTree(swf); + + FolderItem scriptsNode = (FolderItem) mainPanel.tagTree.getModel().getScriptsNode(swf); + TreePath scriptsPath = swfPath.pathByAddingChild(scriptsNode); + + for (TreeItem subItem : scriptsNode.subItems) { + if (sprite != null) { + if (subItem instanceof TagScript) { + if (((TagScript) subItem).getTag() == sprite) { + TreePath spritePaths = scriptsPath.pathByAddingChild(subItem); + List frames = ((TagScript) subItem).getFrames(); + loopframes: + for (TreeItem f : frames) { + if (f instanceof FrameScript) { + FrameScript fs = (FrameScript) f; + if (fs.getFrame().frame + 1 == frame) { + TreePath framePath = spritePaths.pathByAddingChild(f); + List subs = mainPanel.tagTree.getModel().getAllChildren(fs); + for (TreeItem t : subs) { + if (t instanceof TagScript) { + if (((TagScript) t).getTag() == placeType) { + TreePath placePath = framePath.pathByAddingChild(t); + TreePath clipActionRecordPath = placePath.pathByAddingChild(clipActionRecord); + mainPanel.tagTree.setSelectionPath(clipActionRecordPath); + break loopframes; + } + } + } + } + } + } + } + } } } } - //tagTree.getSelectionPath(); - /*mainPanel.tagTree.setSelectionPath(new TreePath(new Object[]{ - mainPanel.tagTree.getModel().getRoot() - }));*/ } } }