/*
* Copyright (C) 2022-2024 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 .
*/
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.configuration.Configuration;
import com.jpexs.decompiler.flash.gui.tagtree.TagTree;
import com.jpexs.decompiler.flash.tags.DefineSpriteTag;
import com.jpexs.decompiler.flash.tags.DoInitActionTag;
import com.jpexs.decompiler.flash.tags.FrameLabelTag;
import com.jpexs.decompiler.flash.tags.ShowFrameTag;
import com.jpexs.decompiler.flash.tags.Tag;
import com.jpexs.decompiler.flash.timeline.Timelined;
import com.jpexs.decompiler.flash.treeitems.TreeItem;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.geom.GeneralPath;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
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;
/**
* @author JPEXS
*/
public class SelectFramePositionDialog extends AppDialog {
private final JButton okButton = new JButton(translate("button.ok"));
private final JButton cancelButton = new JButton(translate("button.cancel"));
private JTree positionTree;
private PreviewPanel previewPanel;
private final SWF swf;
private int result = ERROR_OPTION;
private int selectedFrame = -1;
private Timelined selectedTimelined = null;
private boolean selectNext;
private static class MyTreeNode implements TreeNode {
private final List children = new ArrayList<>();
private TreeNode parent;
private Object data;
@Override
public String toString() {
if (data instanceof DoInitActionTag) {
DoInitActionTag doinit = (DoInitActionTag) data;
String exportName = doinit.getSwf().getExportName(doinit.spriteId);
if (exportName != null && !exportName.isEmpty()) {
return DoInitActionTag.NAME + " (" + doinit.spriteId + ") : " + exportName;
}
}
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 extends TreeNode> children() {
return Collections.enumeration(children);
}
}
private static class MyTimelineEnd {
@Override
public String toString() {
return AppDialog.translateForDialog("timeline.end", SelectFramePositionDialog.class);
}
}
private static class MySprites {
@Override
public String toString() {
return AppStrings.translate("node.sprites");
}
}
private static class MyFrame {
private final int frame;
private boolean invalid;
private List labels;
public MyFrame(int frame, List labels) {
this.frame = frame;
this.labels = labels;
}
public int getFrame() {
return frame;
}
public void setInvalid(boolean invalid) {
this.invalid = invalid;
}
public boolean isInvalid() {
return invalid;
}
@Override
public String toString() {
String name = "frame " + frame;
if (!labels.isEmpty()) {
name += " (" + String.join(", ", labels) + ")";
}
return name;
}
}
private void populateSprites(MyTreeNode root, Timelined tim) {
for (Tag t : tim.getTags()) {
if (t instanceof DefineSpriteTag) {
MyTreeNode node = new MyTreeNode();
node.setData(t);
root.addChild(node);
populateSprites(root, (DefineSpriteTag) t);
DefineSpriteTag sprite = (DefineSpriteTag) t;
populateFrames(node, sprite);
}
}
}
private void populateFrames(MyTreeNode parent, Timelined tim) {
MyTreeNode frameNode = new MyTreeNode();
List labels = new ArrayList<>();
frameNode.setData(new MyFrame(1, labels));
frameNode.setParent(parent);
int f = 1;
parent.addChild(frameNode);
int numtags = 0;
for (Tag t : tim.getTags()) {
if (t instanceof FrameLabelTag) {
labels.add(((FrameLabelTag) t).name);
}
numtags++;
if (t instanceof ShowFrameTag) {
f++;
frameNode = new MyTreeNode();
labels = new ArrayList<>();
frameNode.setData(new MyFrame(f, labels));
frameNode.setParent(parent);
parent.addChild(frameNode);
numtags = 0;
}
}
if (numtags == 0) {
parent.children.remove(parent.children.size() - 1);
}
MyTimelineEnd end = new MyTimelineEnd();
MyTreeNode endNode = new MyTreeNode();
endNode.setData(end);
parent.addChild(endNode);
}
private void populateNodes(MyTreeNode root, Timelined tim) {
MyTreeNode spritesNode = new MyTreeNode();
spritesNode.setData(new MySprites());
root.addChild(spritesNode);
populateSprites(spritesNode, tim);
populateFrames(root, tim);
}
private void selectPath(List