Main concept working

This commit is contained in:
Exund
2023-06-26 21:34:13 +02:00
committed by Jindra Petřík
parent 6db690e25a
commit a2f585ba5c
4 changed files with 309 additions and 2 deletions

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2010-2023 JPEXS
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jpexs.decompiler.flash.gui;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListSelectionModel;
/**
*
* @author JPEXS
*/
public class CollectDepthAsSpritesDialogue extends AppDialog {
private final JButton okButton = new JButton(translate("button.ok"));
private final JButton cancelButton = new JButton(translate("button.cancel"));
private final JList<Integer> depthsList;
private final JCheckBox replaceCheckBox;
private final JCheckBox offsetCheckBox;
private int result = ERROR_OPTION;
public CollectDepthAsSpritesDialogue(Window owner) {
super(owner);
setSize(400, 150);
setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
Container cnt = getContentPane();
cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS));
cnt.add(new JLabel(translate("collect.depths")));
depthsList = new JList<>();
depthsList.setVisibleRowCount(7);
depthsList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
JScrollPane listScroller = new FasterScrollPane(depthsList);
listScroller.setPreferredSize(new Dimension(400, 200));
cnt.add(listScroller);
replaceCheckBox = new JCheckBox(translate("collect.replace"));
cnt.add(replaceCheckBox);
offsetCheckBox = new JCheckBox(translate("collect.offset"));
cnt.add(offsetCheckBox);
JPanel panButtons = new JPanel(new FlowLayout());
okButton.addActionListener(this::okButtonActionPerformed);
cancelButton.addActionListener(this::cancelButtonActionPerformed);
panButtons.add(okButton);
panButtons.add(cancelButton);
add(panButtons, BorderLayout.SOUTH);
setModalityType(ModalityType.APPLICATION_MODAL);
View.setWindowIcon(this);
setTitle(translate("dialog.title"));
getRootPane().setDefaultButton(okButton);
pack();
View.centerScreen(this);
}
private void okButtonActionPerformed(ActionEvent evt) {
result = OK_OPTION;
setVisible(false);
}
private void cancelButtonActionPerformed(ActionEvent evt) {
result = CANCEL_OPTION;
setVisible(false);
}
public List<Integer> getDepths() {
if (result == ERROR_OPTION) {
return null;
}
return depthsList.getSelectedValuesList();
}
public boolean getReplace() {
return replaceCheckBox.isSelected();
}
public boolean getOffset() {
return offsetCheckBox.isSelected();
}
public int showDialog(Collection<Integer> depths) {
depthsList.setListData(depths.toArray(new Integer[depths.size()]));
depthsList.setVisibleRowCount(7);
setVisible(true);
return result;
}
}

View File

@@ -0,0 +1,22 @@
# Copyright (C) 2010-2016 JPEXS
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
dialog.title = Collect options
collect.depths = Depths to collect:
collect.replace = Replace original tags with sprite
collect.offset = Offset top left corner to (0,0)
button.ok = OK
button.cancel = Cancel

View File

@@ -1256,4 +1256,5 @@ node.scenes = scenes
contextmenu.showInFramesFolder = Show in frames folder
#after 20.1.0
contextmenu.collapseAll = Collapse all
contextmenu.collapseAll = Collapse all
contextmenu.collectDepthAsSprites = Collect items at same depth as sprites

View File

@@ -36,6 +36,7 @@ import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
import com.jpexs.decompiler.flash.gui.AppDialog;
import com.jpexs.decompiler.flash.gui.AppStrings;
import com.jpexs.decompiler.flash.gui.ClipboardType;
import com.jpexs.decompiler.flash.gui.CollectDepthAsSpritesDialogue;
import com.jpexs.decompiler.flash.gui.Main;
import com.jpexs.decompiler.flash.gui.MainPanel;
import com.jpexs.decompiler.flash.gui.ReplaceCharacterDialog;
@@ -118,6 +119,7 @@ import com.jpexs.decompiler.flash.types.CLIPACTIONRECORD;
import com.jpexs.decompiler.flash.types.CLIPACTIONS;
import com.jpexs.decompiler.flash.types.CXFORMWITHALPHA;
import com.jpexs.decompiler.flash.types.HasCharacterId;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.graph.CompilationException;
import com.jpexs.decompiler.graph.DottedChain;
import com.jpexs.helpers.ByteArrayRange;
@@ -143,6 +145,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
@@ -308,6 +311,8 @@ public class TagTreeContextMenu extends JPopupMenu {
private JMenuItem replaceWithGifMenuItem;
private JMenuItem collectDepthAsSpritesItem;
private List<TreeItem> items = new ArrayList<>();
private static final int KIND_TAG_MOVETO = 0;
@@ -637,6 +642,10 @@ public class TagTreeContextMenu extends JPopupMenu {
pasteInsideMenuItem.addActionListener(this::pasteInsideActionPerformed);
add(pasteInsideMenuItem);
collectDepthAsSpritesItem = new JMenuItem(mainPanel.translate("contextmenu.collectDepthAsSprites"));
collectDepthAsSpritesItem.addActionListener(this::collectDepthAsSprites);
add(collectDepthAsSpritesItem);
applyUnpackerMenu = new JMenu(mainPanel.translate("contextmenu.applyUnpacker"));
applyUnpackerMenu.setIcon(View.getIcon("openinside16"));
@@ -1083,6 +1092,14 @@ public class TagTreeContextMenu extends JPopupMenu {
}
}
boolean allSelectedIsFrame = true;
for (TreeItem item : items) {
if (!(item instanceof Frame)) {
allSelectedIsFrame = false;
break;
}
}
boolean hasExportableNodes = tree.hasExportableNodes();
expandRecursiveMenuItem.setVisible(false);
@@ -1140,6 +1157,7 @@ public class TagTreeContextMenu extends JPopupMenu {
pasteAfterMenuItem.setVisible(false);
pasteBeforeMenuItem.setVisible(false);
pasteInsideMenuItem.setVisible(false);
collectDepthAsSpritesItem.setVisible(allSelectedIsFrame && allSelectedSameParent);
applyUnpackerMenu.setVisible(false);
openSWFInsideTagMenuItem.setVisible(false);
addAs12ScriptMenuItem.setVisible(false);
@@ -4088,6 +4106,146 @@ public class TagTreeContextMenu extends JPopupMenu {
}
}
private void collectDepthAsSprites(ActionEvent e) {
List<TreeItem> frames = getSelectedItems();
Timelined timelined = ((Frame) frames.get(0)).timeline.timelined;
SWF swf = timelined instanceof SWF ? (SWF) timelined : ((DefineSpriteTag) timelined).getSwf();
Set<Integer> originalDepths = new HashSet<>();
for (TreeItem item : frames) {
Frame f = (Frame) item;
for (Tag t : f.innerTags) {
if (t instanceof RemoveTag) {
originalDepths.add(((RemoveTag) t).getDepth());
} else if (t instanceof PlaceObjectTypeTag) {
originalDepths.add(((PlaceObjectTypeTag) t).getDepth());
}
}
}
CollectDepthAsSpritesDialogue dialog = new CollectDepthAsSpritesDialogue(Main.getDefaultDialogsOwner());
if (dialog.showDialog(originalDepths) == CollectDepthAsSpritesDialogue.OK_OPTION) {
List<Integer> depths = dialog.getDepths();
boolean replace = dialog.getReplace();
boolean offset = dialog.getOffset();
Map<Integer, DefineSpriteTag> sprites = new HashMap<>();
for (int d : depths) {
DefineSpriteTag sprite = new DefineSpriteTag(swf);
sprite.frameCount = frames.size();
for (int i = 0; i < frames.size(); i++) {
Tag showFrame = new ShowFrameTag(swf);
showFrame.setTimelined(sprite);
sprite.addTag(showFrame);
}
swf.addTag(sprite);
sprites.put(d, sprite);
}
try {
for (int i = frames.size() - 1; i > -1; i--) {
Frame f = (Frame) frames.get(i);
for (int j = 0; j < f.innerTags.size(); j++) {
Tag t = f.innerTags.get(j);
int depth = -1;
if (t instanceof RemoveTag) {
depth = ((RemoveTag) t).getDepth();
} else if (t instanceof PlaceObjectTypeTag) {
depth = ((PlaceObjectTypeTag) t).getDepth();
}
if (depth != -1) {
DefineSpriteTag sprite = sprites.get(depth);
Tag clone = t.cloneTag();
clone.setTimelined(sprite);
sprite.addTag(i, clone);
if (replace) {
f.innerTags.remove(t);
t.getTimelined().removeTag(t);
swf.removeTag(t);
j--;
}
}
}
}
Frame first = (Frame) frames.get(0);
for (Entry<Integer, DefineSpriteTag> entry : sprites.entrySet()) {
DefineSpriteTag sprite = entry.getValue();
if (offset || replace) {
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
for (Tag t : sprite.getTags()) {
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag placeTag = (PlaceObjectTypeTag) t;
MATRIX m = placeTag.getMatrix();
if (m != null) {
if (m.translateX < minX) {
minX = m.translateX;
}
if (m.translateY < minY) {
minY = m.translateY;
}
}
}
}
if (offset) {
for (Tag t : sprite.getTags()) {
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag placeTag = (PlaceObjectTypeTag) t;
MATRIX m = placeTag.getMatrix();
if (m != null) {
m.translateX -= minX;
m.translateY -= minY;
}
}
}
}
if (replace) {
PlaceObject3Tag place = new PlaceObject3Tag(swf);
place.placeFlagHasCharacter = true;
place.characterId = sprite.getCharacterId();
place.depth = entry.getKey();
if (offset) {
place.placeFlagHasMatrix = true;
place.placeFlagMove = true;
place.matrix = new MATRIX();
place.matrix.translateX = minX;
place.matrix.translateY = minY;
}
place.setTimelined(first.timeline.timelined);
first.innerTags.add(place);
}
}
}
swf.updateCharacters();
if(replace) {
swf.computeDependentCharacters();
swf.computeDependentFrames();
}
mainPanel.refreshTree(swf);
} catch (InterruptedException | IOException ex) {
Logger.getLogger(TagTreeContextMenu.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
*
* @param items
@@ -4852,7 +5010,7 @@ public class TagTreeContextMenu extends JPopupMenu {
}
}
try (FileOutputStream fos = new FileOutputStream(fileName)) {
try ( FileOutputStream fos = new FileOutputStream(fileName)) {
container.getABC().saveTo(fos);
}