Timeline view with preview and object hilighting.

Embedded timeline view instead of new window.
code formatting
This commit is contained in:
Jindra Petřík
2014-09-02 20:25:56 +02:00
parent 9a47517d94
commit bd04ffba49
17 changed files with 2181 additions and 2002 deletions
@@ -17,12 +17,14 @@
package com.jpexs.decompiler.flash.gui;
import com.jpexs.decompiler.flash.SWF;
import com.jpexs.decompiler.flash.exporters.ShapeExporter;
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
import com.jpexs.decompiler.flash.gui.player.MediaDisplay;
import com.jpexs.decompiler.flash.tags.DefineButtonSoundTag;
import com.jpexs.decompiler.flash.tags.base.BoundedTag;
import com.jpexs.decompiler.flash.tags.base.ButtonTag;
import com.jpexs.decompiler.flash.tags.base.CharacterTag;
import com.jpexs.decompiler.flash.tags.base.DrawableTag;
import com.jpexs.decompiler.flash.tags.base.SoundTag;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Timeline;
@@ -85,6 +87,14 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
private final List<SoundTagPlayer> soundPlayers = new ArrayList<>();
private final IconPanel iconPanel;
private int time = 0;
private int selectedDepth = -1;
public void selectDepth(int depth) {
if (depth != selectedDepth) {
this.selectedDepth = depth;
}
hideMouseSelection();
}
private class IconPanel extends JPanel {
@@ -271,6 +281,26 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
}
private void showSelectedName() {
if (selectedDepth > -1 && frame > -1) {
DepthState ds = timelined.getTimeline().frames.get(frame).layers.get(selectedDepth);
if (ds != null) {
CharacterTag cht = timelined.getTimeline().swf.characters.get(ds.characterId);
if (cht != null) {
debugLabel.setText(cht.getName());
}
}
}
}
public void hideMouseSelection() {
if (selectedDepth > -1) {
showSelectedName();
} else {
debugLabel.setText(" - ");
}
}
public ImagePanel() {
super(new BorderLayout());
//iconPanel.setHorizontalAlignment(JLabel.CENTER);
@@ -301,8 +331,9 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
@Override
public void mouseExited(MouseEvent e) {
stateUnderCursor = null;
lastMouseEvent = null;
drawFrame();
debugLabel.setText(" - ");
hideMouseSelection();
}
@Override
@@ -489,8 +520,8 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
}
}
private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton) {
String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode());
private static SerializableImage getFrame(SWF swf, int frame, int time, Timelined drawable, DepthState stateUnderCursor, int mouseButton, int selectedDepth) {
String key = "drawable_" + frame + "_" + drawable.hashCode() + "_" + mouseButton + "_depth" + selectedDepth + "_" + (stateUnderCursor == null ? "out" : stateUnderCursor.hashCode());
SerializableImage img = SWF.getFromCache(key);
if (img == null) {
if (drawable instanceof BoundedTag) {
@@ -514,6 +545,30 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
gg.setTransform(AffineTransform.getTranslateInstance(0, 0));
List<DepthState> dss = new ArrayList<>();
List<Shape> os = new ArrayList<>();
DepthState ds = drawable.getTimeline().frames.get(frame).layers.get(selectedDepth);
if (ds != null) {
CharacterTag cht = swf.characters.get(ds.characterId);
if (cht != null) {
if (cht instanceof DrawableTag) {
DrawableTag dt = (DrawableTag) cht;
Shape outline = dt.getOutline(0, ds.time, ds.ratio, stateUnderCursor, mouseButton, new Matrix(ds.matrix));
Rectangle bounds = outline.getBounds();
bounds.x /= 20;
bounds.y /= 20;
bounds.width /= 20;
bounds.height /= 20;
bounds.x -= rect.Xmin / 20;
bounds.y -= rect.Ymin / 20;
//SHAPERECORD.resizeSHAPE(outline, 1/20)
gg.setStroke(new BasicStroke(2.0f,
BasicStroke.CAP_BUTT,
BasicStroke.JOIN_MITER,
10.0f, new float[]{10.0f}, 0.0f));
gg.setPaint(Color.red);
gg.draw(bounds);
}
}
}
/*drawable.getTimeline().getObjectsOutlines(frame, frame, stateUnderCursor, mouseButton, m, dss, os);
//gg.setTransform(AffineTransform.getTranslateInstance(0, 0));
@@ -544,7 +599,7 @@ public final class ImagePanel extends JPanel implements ActionListener, MediaDis
mat.translateX = swf.displayRect.Xmin;
mat.translateY = swf.displayRect.Ymin;
updatePos(lastMouseEvent, false);
SerializableImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton);
SerializableImage img = getFrame(swf, frame, time, timelined, stateUnderCursor, mouseButton, selectedDepth);
List<Integer> sounds = new ArrayList<>();
List<String> soundClasses = new ArrayList<>();
timeline.getSounds(frame, time, stateUnderCursor, mouseButton, sounds, soundClasses);
@@ -48,6 +48,7 @@ import javax.swing.JDialog;
import javax.swing.JEditorPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.SwingUtilities;
import org.pushingpixels.flamingo.api.common.AbstractCommandButton;
import org.pushingpixels.flamingo.api.common.CommandButtonDisplayState;
@@ -122,6 +123,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
static final String ACTION_CHECK_RESOURCES = "CHECKRESOURCES";
static final String ACTION_VIEWMODE_RESOURCES = "VIEWMODERESOURCES";
static final String ACTION_VIEWMODE_HEX = "VIEWMODEHEX";
static final String ACTION_VIEWMODE_TIMELINE = "VIEWMODETIMELINE";
static final String ACTION_DEOBFUSCATION_MODE_OLD = "DEOBFUSCATIONMODEOLD";
static final String ACTION_DEOBFUSCATION_MODE_NEW = "DEOBFUSCATIONMODENEW";
@@ -153,10 +155,13 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
private JCommandButton globalrenameCommandButton;
private JCommandButton deobfuscationCommandButton;
private JCommandButton searchCommandButton;
private JCommandButton timeLineCommandButton;
private JCommandToggleButton timeLineToggleButton;
private CommandToggleButtonGroup timeLineToggleGroup;
private JCommandButton gotoDocumentClassCommandButton;
private JCommandButton clearRecentFilesCommandButton;
private CommandToggleButtonGroup viewModeToggleGroup;
RibbonApplicationMenuEntryPrimary exportFlaMenu;
RibbonApplicationMenuEntryPrimary exportAllMenu;
RibbonApplicationMenuEntryPrimary exportSelMenu;
@@ -280,7 +285,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
resizePolicies.add(new BaseRibbonBandResizePolicy<AbstractBandControlPanel>(ribbonBand.getControlPanel()) {
@Override
public int getPreferredWidth(int i, int i1) {
return ribbonBand.getGraphics().getFontMetrics(ribbonBand.getFont()).stringWidth(ribbonBand.getTitle())+20;
return ribbonBand.getGraphics().getFontMetrics(ribbonBand.getFont()).stringWidth(ribbonBand.getTitle()) + 20;
}
@Override
@@ -357,7 +362,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
JRibbonBand viewBand = new JRibbonBand(translate("menu.view"), null);
viewBand.setResizePolicies(getResizePolicies(viewBand));
CommandToggleButtonGroup grpViewMode = new CommandToggleButtonGroup();
viewModeToggleGroup = new CommandToggleButtonGroup();
viewModeResourcesToggleButton = new JCommandToggleButton(fixCommandTitle(translate("menu.file.view.resources")), View.getResizableIcon("viewresources16"));
assignListener(viewModeResourcesToggleButton, ACTION_VIEWMODE_RESOURCES);
@@ -365,13 +370,13 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
viewModeHexToggleButton = new JCommandToggleButton(fixCommandTitle(translate("menu.file.view.hex")), View.getResizableIcon("viewhex16"));
assignListener(viewModeHexToggleButton, ACTION_VIEWMODE_HEX);
grpViewMode.add(viewModeResourcesToggleButton);
grpViewMode.add(viewModeHexToggleButton);
viewModeToggleGroup.add(viewModeResourcesToggleButton);
viewModeToggleGroup.add(viewModeHexToggleButton);
if (Configuration.dumpView.get()) {
grpViewMode.setSelected(viewModeHexToggleButton, true);
viewModeToggleGroup.setSelected(viewModeHexToggleButton, true);
} else {
grpViewMode.setSelected(viewModeResourcesToggleButton, true);
viewModeToggleGroup.setSelected(viewModeResourcesToggleButton, true);
}
viewBand.addCommandButton(viewModeResourcesToggleButton, RibbonElementPriority.MEDIUM);
@@ -389,8 +394,11 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
searchCommandButton = new JCommandButton(fixCommandTitle(translate("menu.tools.search")), View.getResizableIcon("search32"));
assignListener(searchCommandButton, ACTION_SEARCH);
timeLineCommandButton = new JCommandButton(fixCommandTitle(translate("menu.tools.timeline")), View.getResizableIcon("timeline32"));
assignListener(timeLineCommandButton, ACTION_TIMELINE);
timeLineToggleButton = new JCommandToggleButton(fixCommandTitle(translate("menu.tools.timeline")), View.getResizableIcon("timeline32"));
assignListener(timeLineToggleButton, ACTION_TIMELINE);
timeLineToggleGroup = new CommandToggleButtonGroup();
timeLineToggleGroup.add(timeLineToggleButton);
gotoDocumentClassCommandButton = new JCommandButton(fixCommandTitle(translate("menu.tools.gotodocumentclass")), View.getResizableIcon("gotomainclass32"));
assignListener(gotoDocumentClassCommandButton, ACTION_GOTO_DOCUMENT_CLASS);
@@ -405,7 +413,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
assignListener(loadCacheCommandButton, ACTION_LOAD_CACHE);
toolsBand.addCommandButton(searchCommandButton, RibbonElementPriority.TOP);
toolsBand.addCommandButton(timeLineCommandButton, RibbonElementPriority.TOP);
toolsBand.addCommandButton(timeLineToggleButton, RibbonElementPriority.TOP);
toolsBand.addCommandButton(gotoDocumentClassCommandButton, RibbonElementPriority.TOP);
toolsBand.addCommandButton(proxyCommandButton, RibbonElementPriority.MEDIUM);
toolsBand.addCommandButton(loadMemoryCommandButton, RibbonElementPriority.MEDIUM);
@@ -614,7 +622,7 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
globalrenameCommandButton.setEnabled(swfLoaded);
deobfuscationCommandButton.setEnabled(swfLoaded);
searchCommandButton.setEnabled(swfLoaded);
timeLineCommandButton.setEnabled(swfLoaded);
timeLineToggleButton.setEnabled(swfLoaded);
gotoDocumentClassCommandButton.setEnabled(hasAbc);
deobfuscationCommandButton.setEnabled(hasAbc);
@@ -705,11 +713,13 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
case ACTION_VIEWMODE_RESOURCES:
Configuration.dumpView.set(false);
mainFrame.panel.showDumpView(false);
mainFrame.panel.showView(MainPanel.VIEW_RESOURCES);
timeLineToggleGroup.setSelected(timeLineToggleButton, false);
break;
case ACTION_VIEWMODE_HEX:
Configuration.dumpView.set(true);
mainFrame.panel.showDumpView(true);
mainFrame.panel.showView(MainPanel.VIEW_DUMP);
timeLineToggleGroup.setSelected(timeLineToggleButton, false);
break;
case ACTION_DEOBFUSCATION_MODE_OLD:
Configuration.deobfuscationMode.set(0);
@@ -719,15 +729,28 @@ public class MainFrameRibbonMenu implements MainFrameMenu, ActionListener {
Configuration.deobfuscationMode.set(1);
mainFrame.panel.autoDeobfuscateChanged();
break;
case ACTION_DUMP_VIEW_SWITCH:
Configuration.dumpView.set(miDumpView.isSelected());
mainFrame.panel.showDumpView(miDumpView.isSelected());
break;
case ACTION_SEARCH:
mainFrame.panel.searchAs();
break;
case ACTION_TIMELINE:
mainFrame.panel.timeline();
timeLineToggleGroup.setSelected(timeLineToggleButton, timeLineToggleGroup.getSelected() == timeLineToggleButton);
if (timeLineToggleGroup.getSelected() == timeLineToggleButton) {
if (!mainFrame.panel.showView(MainPanel.VIEW_TIMELINE)) {
timeLineToggleGroup.setSelected(timeLineToggleButton, false);
} else {
viewModeToggleGroup.setSelected(viewModeHexToggleButton, false);
viewModeToggleGroup.setSelected(viewModeResourcesToggleButton, false);
}
} else {
if (Configuration.dumpView.get()) {
viewModeToggleGroup.setSelected(viewModeHexToggleButton, true);
mainFrame.panel.showView(MainPanel.VIEW_DUMP);
} else {
viewModeToggleGroup.setSelected(viewModeResourcesToggleButton, true);
mainFrame.panel.showView(MainPanel.VIEW_RESOURCES);
}
}
break;
case ACTION_AUTO_DEOBFUSCATE:
if (View.showConfirmDialog(mainFrame.panel, translate("message.confirm.autodeobfuscate") + "\r\n" + (miAutoDeobfuscation.isSelected() ? translate("message.confirm.on") : translate("message.confirm.off")), translate("message.confirm"), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
@@ -63,7 +63,8 @@ import com.jpexs.decompiler.flash.gui.dumpview.DumpTree;
import com.jpexs.decompiler.flash.gui.dumpview.DumpTreeModel;
import com.jpexs.decompiler.flash.gui.dumpview.DumpViewPanel;
import com.jpexs.decompiler.flash.gui.player.FlashPlayerPanel;
import com.jpexs.decompiler.flash.gui.timeline.TimelineFrame;
import com.jpexs.decompiler.flash.gui.timeline.TimelineViewPanel;
import com.jpexs.decompiler.flash.gui.timeline.TimelinePanel;
import com.jpexs.decompiler.flash.gui.treenodes.SWFBundleNode;
import com.jpexs.decompiler.flash.gui.treenodes.SWFNode;
import com.jpexs.decompiler.flash.gui.treenodes.StringNode;
@@ -219,6 +220,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
private ABCPanel abcPanel;
private ActionPanel actionPanel;
private final JPanel welcomePanel;
private final TimelineViewPanel timelineViewPanel;
private final MainFrameStatusPanel statusPanel;
private final MainFrameMenu mainMenu;
private final JProgressBar progressBar = new JProgressBar(0, 100);
@@ -241,6 +243,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
private static final String DETAILCARDEMPTYPANEL = "Empty card";
private static final String SPLIT_PANE1 = "SPLITPANE1";
private static final String WELCOME_PANEL = "WELCOMEPANEL";
private static final String TIMELINE_PANEL = "TIMELINEPANEL";
private final JSplitPane splitPane1;
private final JSplitPane splitPane2;
private boolean splitsInited = false;
@@ -560,10 +563,13 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
}
});
timelineViewPanel = new TimelineViewPanel();
CardLayout cl3 = new CardLayout();
contentPanel = new JPanel(cl3);
contentPanel.add(welcomePanel, WELCOME_PANEL);
contentPanel.add(splitPane1, SPLIT_PANE1);
contentPanel.add(timelineViewPanel, TIMELINE_PANEL);
add(contentPanel);
cl3.show(contentPanel, WELCOME_PANEL);
@@ -578,7 +584,7 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
});
detailPanel.setVisible(false);
showDumpView(Configuration.dumpView.get());
showView(Configuration.dumpView.get() ? VIEW_DUMP : VIEW_RESOURCES);
updateUi();
//Opening files with drag&drop to main window
@@ -2143,19 +2149,52 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
return mainMenu.isInternalFlashViewerSelected();
}
public void showDumpView(boolean show) {
treePanel.removeAll();
if (show) {
treePanel.add(new JScrollPane(dumpTree), BorderLayout.CENTER);
treePanelMode = TreePanelMode.DUMP_TREE;
showDetail(DETAILCARDEMPTYPANEL);
} else {
treePanel.add(new JScrollPane(tagTree), BorderLayout.CENTER);
treePanel.add(searchPanel, BorderLayout.SOUTH);
treePanelMode = TreePanelMode.TAG_TREE;
public static final int VIEW_RESOURCES = 0;
public static final int VIEW_DUMP = 1;
public static final int VIEW_TIMELINE = 2;
public boolean showView(int view) {
CardLayout cl = (CardLayout) (contentPanel.getLayout());
switch (view) {
case VIEW_DUMP:
if (!isWelcomeScreen) {
cl.show(contentPanel, SPLIT_PANE1);
}
treePanel.removeAll();
treePanel.add(new JScrollPane(dumpTree), BorderLayout.CENTER);
treePanelMode = TreePanelMode.DUMP_TREE;
showDetail(DETAILCARDEMPTYPANEL);
reload(true);
treePanel.revalidate();
return true;
case VIEW_RESOURCES:
if (!isWelcomeScreen) {
cl.show(contentPanel, SPLIT_PANE1);
}
treePanel.removeAll();
treePanel.add(new JScrollPane(tagTree), BorderLayout.CENTER);
treePanel.add(searchPanel, BorderLayout.SOUTH);
treePanelMode = TreePanelMode.TAG_TREE;
reload(true);
treePanel.revalidate();
return true;
case VIEW_TIMELINE:
final SWF swf = getCurrentSwf();
if (swf != null) {
TreeItem item = tagTree.getCurrentTreeItem();
if (item instanceof DefineSpriteTag) {
timelineViewPanel.setTimelined((DefineSpriteTag) item);
} else {
timelineViewPanel.setTimelined(swf);
}
cl.show(contentPanel, TIMELINE_PANEL);
return true;
}
return false;
}
reload(true);
treePanel.revalidate();
return false;
}
private void dumpViewReload(boolean forceReload) {
@@ -2499,21 +2538,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec
statusPanel.setErrorState(errorState);
}
public void timeline() {
final SWF swf = getCurrentSwf();
if (swf != null) {
TreeItem item = tagTree.getCurrentTreeItem();
if (item instanceof DefineSpriteTag) {
TimelineFrame tf = new TimelineFrame((DefineSpriteTag) item);
tf.setVisible(true);
return;
}
TimelineFrame tf = new TimelineFrame(swf);
tf.setVisible(true);
}
}
public static Timelined makeTimelined(final Tag tag) {
return new Timelined() {
@@ -141,7 +141,7 @@ public class NewVersionDialog extends AppDialog implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand() == ACTION_OK) {
String url;
String url;
if (latestVersion.updateLink != null) {
url = latestVersion.updateLink;
} else {
+1 -2
View File
@@ -537,8 +537,7 @@ public class View {
}
}
}
return false;
}
}
@@ -49,7 +49,7 @@ public class DumpViewPanel extends JPanel {
super(new BorderLayout());
this.dumpTree = dumpTree;
selectedByteInfo = new JLabel();
selectedByteInfo.setMinimumSize(new Dimension(100, 20));
selectedByteInfo.setText("-");
@@ -64,13 +64,13 @@ public class DumpViewPanel extends JPanel {
dumpViewHexTable.addListener(new HexViewListener() {
private int lastAddressUnderCursor = -1;
@Override
public void byteValueChanged(int address, byte b) {
if (skipValueChange) {
return;
}
if (address != -1) {
TreeModel model = dumpTree.getModel();
DumpInfo di = DumpInfoSwfNode.getSwfNode(selectedDumpInfo);
@@ -100,7 +100,7 @@ public class DumpViewPanel extends JPanel {
dumpTree.setSelectionPath(tp);
dumpTree.scrollPathToVisible(tp);
}
byte[] data = dumpViewHexTable.getData();
byteMouseMoved(lastAddressUnderCursor, lastAddressUnderCursor == -1 ? 0 : data[lastAddressUnderCursor]);
}
@@ -115,20 +115,20 @@ public class DumpViewPanel extends JPanel {
b = data[address];
}
}
if (address != -1) {
int b2 = b & 0xff;
selectedByteInfo.setText("Addr: " + Helper.padZeros(address, 8) +
" Hex: " + Helper.padZeros(Integer.toHexString(b2), 2) +
" Dec: " + b2 +
" Bin: " + Helper.padZeros(Integer.toBinaryString(b2), 8) +
" Ascii: " + (char) b2);
selectedByteInfo.setText("Addr: " + Helper.padZeros(address, 8)
+ " Hex: " + Helper.padZeros(Integer.toHexString(b2), 2)
+ " Dec: " + b2
+ " Bin: " + Helper.padZeros(Integer.toBinaryString(b2), 8)
+ " Ascii: " + (char) b2);
} else {
selectedByteInfo.setText("-");
}
}
});
add(new JScrollPane(dumpViewHexTable), BorderLayout.CENTER);
}
@@ -137,7 +137,7 @@ public class DumpViewPanel extends JPanel {
skipNextScroll = false;
return;
}
this.selectedDumpInfo = dumpInfo;
byte[] data = DumpInfoSwfNode.getSwfNode(dumpInfo).getSwf().originalUncompressedData;
List<DumpInfo> dumpInfos = new ArrayList<>();
@@ -50,11 +50,11 @@ public class HexView extends JTable {
private final Color bgColorAlternate = Color.decode("#EDEDED");
private int mouseOverIdx = -1;
private HexViewListener listener;
private class HighlightCellRenderer extends DefaultTableCellRenderer {
public int byteIndex;
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col) {
@@ -81,7 +81,7 @@ public class HexView extends JTable {
foreground = Color.black;
background = row % 2 == 0 ? bgColor : bgColorAlternate;
}
if (idx != -1 && idx == mouseOverIdx) {
foreground = new Color(255 - foreground.getRed(), 255 - foreground.getGreen(), 255 - foreground.getBlue());
background = new Color(255 - background.getRed(), 255 - background.getGreen(), 255 - background.getBlue());
@@ -92,18 +92,18 @@ public class HexView extends JTable {
return l;
}
}
private class HexViewSelectionListener implements ListSelectionListener {
private final HexView table;
public HexViewSelectionListener(HexView table) {
this.table = table;
}
@Override
public void valueChanged(ListSelectionEvent e) {
int col = table.getSelectedColumn();
int row = table.getSelectedRow();
@@ -118,7 +118,7 @@ public class HexView extends JTable {
@Override
public void mouseExited(MouseEvent e) {
HexView table = (HexView) e.getSource();
HexView table = (HexView) e.getSource();
Point point = e.getPoint();
int col = table.columnAtPoint(point);
int row = table.rowAtPoint(point);
@@ -131,17 +131,17 @@ public class HexView extends JTable {
}
private class HexViewMouseMotionAdapter extends MouseMotionAdapter {
@Override
public void mouseMoved(MouseEvent e) {
HexView table = (HexView) e.getSource();
HexView table = (HexView) e.getSource();
Point point = e.getPoint();
int col = table.columnAtPoint(point);
int row = table.rowAtPoint(point);
int idx = getIdxByColAndRow(row, col);
mouseOverIdx = idx;
getModel().fireTableCellUpdated(row, col);
if (listener != null) {
listener.byteMouseMoved(idx, idx == -1 ? 0 : getModel().getData()[idx]);
}
@@ -182,7 +182,7 @@ public class HexView extends JTable {
column.setMaxWidth(10);
column.setCellRenderer(cellRenderer);
}
addMouseListener(new HexViewMouseAdapter());
addMouseMotionListener(new HexViewMouseMotionAdapter());
ListSelectionModel rowSelModel = getSelectionModel();
@@ -195,9 +195,9 @@ public class HexView extends JTable {
@Override
public HexViewTableModel getModel() {
TableModel model = super.getModel();
return (HexViewTableModel) model;
return (HexViewTableModel) model;
}
public void setData(byte[] data, long[] highlightStarts, long[] highlightEnds) {
if ((highlightStarts == null) ^ (highlightEnds == null)) {
@@ -216,7 +216,7 @@ public class HexView extends JTable {
public byte[] getData() {
return getModel().getData();
}
public void scrollToByte(long byteNum) {
int row = (int) (byteNum / bytesInRow);
@@ -237,7 +237,7 @@ public class HexView extends JTable {
}
return idx;
}
public int getFocusedByteIdx() {
int col = getSelectedColumn();
int row = getSelectedRow();
@@ -245,7 +245,7 @@ public class HexView extends JTable {
int idx = getIdxByColAndRow(row, col);
return idx;
}
public void scrollToByte(long[] byteNumStarts, long[] byteNumEnds) {
for (int i = 0; i < byteNumStarts.length; i++) {
scrollToByte(byteNumStarts[i]);
@@ -253,7 +253,7 @@ public class HexView extends JTable {
scrollToByte(byteNumStarts[i]);
}
}
public void addListener(HexViewListener listener) {
this.listener = listener;
}
@@ -23,7 +23,7 @@ import javax.swing.table.AbstractTableModel;
* @author JPEXS
*/
public class HexViewTableModel extends AbstractTableModel {
private byte[] data;
private final int bytesInRow;
@@ -79,15 +79,15 @@ public class HexViewTableModel extends AbstractTableModel {
return null;
}
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
@Override
public void fireTableCellUpdated(int row, int columnd) {
super.fireTableCellUpdated(bytesInRow, bytesInRow);
@@ -369,9 +369,9 @@ public class ProxyFrame extends AppFrame implements ActionListener, CatchedListe
if ((!sniffOSCheckBox.isSelected()) && (contentType.equals("application/octet-stream"))) {
return null;
}
byte[] result = null;
if (!listModel.contains(url)) {
try {
byte[] hdr = new byte[3];
@@ -387,16 +387,16 @@ public class ProxyFrame extends AppFrame implements ActionListener, CatchedListe
try (FileOutputStream fos = new FileOutputStream(new File(tempFilePath))) {
fos.write(dataArray);
}
result = SWFDecompilerPlugin.fireProxyFileCatched(dataArray);
Replacement r = new Replacement(url, tempFilePath);
r.lastAccess = Calendar.getInstance();
listModel.addURL(r);
} catch (IOException e) {
}
}
return result;
}
@@ -1,273 +1,311 @@
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Timeline;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
/**
*
* @author JPEXS
*/
public class TimelineBodyPanel extends JPanel implements MouseListener {
private final Timeline timeLine;
public static Color frameColor = Color.lightGray;
public static Color emptyFrameColor = Color.white;
public static Color emptyFrameSecondColor = new Color(0xed, 0xed, 0xed);
public static Color borderColor = Color.black;
public static Color emptyBorderColor = Color.lightGray;
public static Color keyColor = Color.black;
public static Color aColor = Color.black;
public static Color stopColor = Color.white;
public static Color stopBorderColor = Color.black;
public static Color borderLinesColor = new Color(0xde, 0xde, 0xde);
public static Color selectedColor = new Color(113, 174, 235);
public static final int borderLinesLength = 2;
public static final float fontSize = 10.0f;
private final List<FrameSelectionListener> listeners = new ArrayList<>();
public Point cursor = null;
public void addFrameSelectionListener(FrameSelectionListener l) {
listeners.add(l);
}
public void removeFrameSelectionListener(FrameSelectionListener l) {
listeners.remove(l);
}
public TimelineBodyPanel(Timeline timeLine) {
this.timeLine = timeLine;
Dimension dim = new Dimension(TimelinePanel.FRAME_WIDTH * timeLine.getFrameCount() + 1, TimelinePanel.FRAME_HEIGHT * timeLine.getMaxDepth());
setSize(dim);
setPreferredSize(dim);
addMouseListener(this);
}
@Override
protected void paintComponent(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(TimelinePanel.backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
Rectangle clip = g.getClipBounds();
int start_f = clip.x / TimelinePanel.FRAME_WIDTH;
int start_d = clip.y / TimelinePanel.FRAME_HEIGHT;
int end_f = (clip.x + clip.width) / TimelinePanel.FRAME_WIDTH;
int end_d = (clip.y + clip.height) / TimelinePanel.FRAME_HEIGHT;
int max_d = timeLine.getMaxDepth();
if (max_d < end_d) {
end_d = max_d;
}
int max_f = timeLine.getFrameCount() - 1;
if (max_f < end_f) {
end_f = max_f;
}
if (end_d - start_d + 1 < 0) {
return;
}
boolean keyfound[] = new boolean[end_d - start_d + 1];
for (int f = start_f; f <= end_f; f++) {
for (int d = start_d; d <= end_d; d++) {
DepthState fl = timeLine.frames.get(f).layers.get(d);
if (fl == null) {
if ((f + 1) % 5 == 0) {
g.setColor(emptyFrameSecondColor);
} else {
g.setColor(emptyFrameColor);
}
g.fillRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
g.setColor(emptyBorderColor);
g.drawRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
}
}
}
for (int f = start_f; f <= end_f; f++) {
for (int d = start_d; d <= end_d; d++) {
DepthState fl = timeLine.frames.get(f).layers.get(d);
DepthState flNext = null;
if (f < max_f) {
flNext = timeLine.frames.get(f + 1).layers.get(d);
}
boolean selected = false;
if (cursor != null) {
if (f == cursor.x && d == cursor.y) {
selected = true;
}
}
if (selected) {
if (!(fl != null && (flNext == null || flNext.key))) {
g.setColor(selectedColor);
g.fillRect(f * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1);
}
}
if (fl == null) {
if (d == 0) {
if (timeLine.frames.get(f).action != null) {
g.setColor(aColor);
g.setFont(getFont().deriveFont(fontSize));
int awidth = g.getFontMetrics().stringWidth("a");
g.drawString("a", f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2 - awidth / 2, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 + fontSize / 2);
}
}
continue;
} else {
int draw_f = 0;
if (fl.key) {
draw_f = f;
keyfound[d - start_d] = true;
} else if (!keyfound[d - start_d]) {
for (int k = f - 1; k >= 0; k--) {
fl = timeLine.frames.get(k).layers.get(d);
if (fl == null) {
break;
}
if (fl.key) {
keyfound[d - start_d] = true;
draw_f = k;
break;
}
}
} else {
continue;
}
int num_frames = 1;
for (int n = draw_f + 1; n < timeLine.getFrameCount(); n++) {
fl = timeLine.frames.get(n).layers.get(d);
if (fl == null) {
break;
}
if (fl.key) {
break;
}
num_frames++;
}
g.setColor(frameColor);
g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
if (selected) {
g.setColor(selectedColor);
g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
}
g.setColor(borderColor);
g.drawRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
g.setColor(keyColor);
g.fillOval(draw_f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - TimelinePanel.FRAME_WIDTH / 2 / 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_WIDTH / 2);
if (num_frames > 1) {
if (cursor != null && cursor.y == d && cursor.x == f + num_frames - 1) {
g.setColor(selectedColor);
g.fillRect((f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1);
}
g.setColor(stopColor);
g.fillRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2);
g.setColor(stopBorderColor);
g.drawRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2);
g.setColor(borderLinesColor);
for (int n = draw_f + 1; n < draw_f + num_frames; n++) {
g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + borderLinesLength);
g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - borderLinesLength);
}
}
}
}
}
if (cursor != null && cursor.x >= start_f && cursor.x <= end_f) {
g.setColor(TimelinePanel.selectedBorderColor);
g.drawLine(cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, 0, cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, getHeight());
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
public void frameSelect(int frame, int depth) {
if (cursor != null && cursor.x == frame && (cursor.y == depth || depth == -1)) {
return;
}
if (depth == -1 && cursor != null) {
depth = cursor.y;
}
cursor = new Point(frame, depth);
for (FrameSelectionListener l : listeners) {
l.frameSelected(frame, -1);
}
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
p.x = p.x / TimelinePanel.FRAME_WIDTH;
p.y = p.y / TimelinePanel.FRAME_HEIGHT;
if (p.x >= timeLine.getFrameCount()) {
p.x = timeLine.getFrameCount() - 1;
}
int maxDepth = timeLine.getMaxDepth();
if (p.y > maxDepth) {
p.y = maxDepth;
}
frameSelect(p.x, p.y);
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.timeline.DepthState;
import com.jpexs.decompiler.flash.timeline.Timeline;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
/**
*
* @author JPEXS
*/
public class TimelineBodyPanel extends JPanel implements MouseListener, KeyListener {
private final Timeline timeLine;
public static Color frameColor = new Color(0xbd, 0xd8, 0xfc);
public static Color emptyFrameColor = Color.white;
public static Color emptyFrameSecondColor = new Color(0xea, 0xf2, 0xfc);
public static Color borderColor = Color.black;
public static Color emptyBorderColor = new Color(0xbd, 0xd8, 0xfc);
public static Color keyColor = Color.black;
public static Color aColor = Color.black;
public static Color stopColor = Color.white;
public static Color stopBorderColor = Color.black;
public static Color borderLinesColor = new Color(0xde, 0xde, 0xde);
public static Color selectedColor = new Color(113, 174, 235);
public static final int borderLinesLength = 2;
public static final float fontSize = 10.0f;
private final List<FrameSelectionListener> listeners = new ArrayList<>();
public Point cursor = null;
public void addFrameSelectionListener(FrameSelectionListener l) {
listeners.add(l);
}
public void removeFrameSelectionListener(FrameSelectionListener l) {
listeners.remove(l);
}
public TimelineBodyPanel(Timeline timeLine) {
this.timeLine = timeLine;
Dimension dim = new Dimension(TimelinePanel.FRAME_WIDTH * timeLine.getFrameCount() + 1, TimelinePanel.FRAME_HEIGHT * timeLine.getMaxDepth());
setSize(dim);
setPreferredSize(dim);
addMouseListener(this);
addKeyListener(this);
setFocusable(true);
}
@Override
protected void paintComponent(Graphics g1) {
Graphics2D g = (Graphics2D) g1;
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(TimelinePanel.backgroundColor);
g.fillRect(0, 0, getWidth(), getHeight());
Rectangle clip = g.getClipBounds();
int start_f = clip.x / TimelinePanel.FRAME_WIDTH;
int start_d = clip.y / TimelinePanel.FRAME_HEIGHT;
int end_f = (clip.x + clip.width) / TimelinePanel.FRAME_WIDTH;
int end_d = (clip.y + clip.height) / TimelinePanel.FRAME_HEIGHT;
int max_d = timeLine.getMaxDepth();
if (max_d < end_d) {
end_d = max_d;
}
int max_f = timeLine.getFrameCount() - 1;
if (max_f < end_f) {
end_f = max_f;
}
if (end_d - start_d + 1 < 0) {
return;
}
boolean keyfound[] = new boolean[end_d - start_d + 1];
for (int f = start_f; f <= end_f; f++) {
for (int d = start_d; d <= end_d; d++) {
DepthState fl = timeLine.frames.get(f).layers.get(d);
if (fl == null) {
if ((f + 1) % 5 == 0) {
g.setColor(emptyFrameSecondColor);
} else {
g.setColor(emptyFrameColor);
}
g.fillRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
g.setColor(emptyBorderColor);
g.drawRect(f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
}
}
}
for (int f = start_f; f <= end_f; f++) {
for (int d = start_d; d <= end_d; d++) {
DepthState fl = timeLine.frames.get(f).layers.get(d);
DepthState flNext = null;
if (f < max_f) {
flNext = timeLine.frames.get(f + 1).layers.get(d);
}
boolean selected = false;
if (cursor != null) {
if (f == cursor.x && d == cursor.y) {
selected = true;
}
}
if (selected) {
if (!(fl != null && (flNext == null || flNext.key))) {
g.setColor(selectedColor);
g.fillRect(f * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1);
}
}
if (fl == null) {
if (d == 0) {
if (timeLine.frames.get(f).action != null) {
g.setColor(aColor);
g.setFont(getFont().deriveFont(fontSize));
int awidth = g.getFontMetrics().stringWidth("a");
g.drawString("a", f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2 - awidth / 2, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 + fontSize / 2);
}
}
continue;
} else {
int draw_f = 0;
if (fl.key) {
draw_f = f;
keyfound[d - start_d] = true;
} else if (!keyfound[d - start_d]) {
for (int k = f - 1; k >= 0; k--) {
fl = timeLine.frames.get(k).layers.get(d);
if (fl == null) {
break;
}
if (fl.key) {
keyfound[d - start_d] = true;
draw_f = k;
break;
}
}
} else {
continue;
}
int num_frames = 1;
for (int n = draw_f + 1; n < timeLine.getFrameCount(); n++) {
fl = timeLine.frames.get(n).layers.get(d);
if (fl == null) {
break;
}
if (fl.key) {
break;
}
num_frames++;
}
g.setColor(frameColor);
g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
if (selected) {
g.setColor(selectedColor);
g.fillRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
}
g.setColor(borderColor);
g.drawRect(draw_f * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT, num_frames * TimelinePanel.FRAME_WIDTH, TimelinePanel.FRAME_HEIGHT);
g.setColor(keyColor);
g.fillOval(draw_f * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT * 3 / 4 - TimelinePanel.FRAME_WIDTH / 2 / 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_WIDTH / 2);
if (num_frames > 1) {
if (cursor != null && cursor.y == d && cursor.x == f + num_frames - 1) {
g.setColor(selectedColor);
g.fillRect((f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + 1, d * TimelinePanel.FRAME_HEIGHT + 1, TimelinePanel.FRAME_WIDTH - 1, TimelinePanel.FRAME_HEIGHT - 1);
}
g.setColor(stopColor);
g.fillRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2);
g.setColor(stopBorderColor);
g.drawRect((draw_f + num_frames - 1) * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 4, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT / 2 - 2, TimelinePanel.FRAME_WIDTH / 2, TimelinePanel.FRAME_HEIGHT / 2);
g.setColor(borderLinesColor);
for (int n = draw_f + 1; n < draw_f + num_frames; n++) {
g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + borderLinesLength);
g.drawLine(n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - 1, n * TimelinePanel.FRAME_WIDTH, d * TimelinePanel.FRAME_HEIGHT + TimelinePanel.FRAME_HEIGHT - borderLinesLength);
}
}
}
}
}
if (cursor != null && cursor.x >= start_f && cursor.x <= end_f) {
g.setColor(TimelinePanel.selectedBorderColor);
g.drawLine(cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, 0, cursor.x * TimelinePanel.FRAME_WIDTH + TimelinePanel.FRAME_WIDTH / 2, getHeight());
}
}
@Override
public void mouseClicked(MouseEvent e) {
}
public void frameSelect(int frame, int depth) {
if (cursor != null && cursor.x == frame && (cursor.y == depth || depth == -1)) {
return;
}
if (depth == -1 && cursor != null) {
depth = cursor.y;
}
cursor = new Point(frame, depth);
for (FrameSelectionListener l : listeners) {
l.frameSelected(frame, depth);
}
repaint();
}
@Override
public void mousePressed(MouseEvent e) {
Point p = e.getPoint();
p.x = p.x / TimelinePanel.FRAME_WIDTH;
p.y = p.y / TimelinePanel.FRAME_HEIGHT;
if (p.x >= timeLine.getFrameCount()) {
p.x = timeLine.getFrameCount() - 1;
}
int maxDepth = timeLine.getMaxDepth();
if (p.y > maxDepth) {
p.y = maxDepth;
}
frameSelect(p.x, p.y);
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case 37: //left
if (cursor.x > 0) {
frameSelect(cursor.x - 1, cursor.y);
}
break;
case 39: //right
if (cursor.x < timeLine.frames.size() - 1) {
frameSelect(cursor.x + 1, cursor.y);
}
break;
case 38: //up
if (cursor.y > 0) {
frameSelect(cursor.x, cursor.y - 1);
}
break;
case 40: //down
if (cursor.y < timeLine.getMaxDepth()) {
frameSelect(cursor.x, cursor.y + 1);
}
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
}
}
@@ -1,50 +0,0 @@
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.gui.AppFrame;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.timeline.Timelined;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Image;
import java.util.ArrayList;
import java.util.List;
/**
*
* @author JPEXS
*/
public class TimelineFrame extends AppFrame {
public TimelinePanel timeline;
public TimelineFrame(Timelined timelined) {
setSize(800, 600);
View.setWindowIcon(this);
View.centerScreen(this);
setTitle(translate("dialog.title"));
Container cnt = getContentPane();
cnt.setLayout(new BorderLayout());
cnt.add(timeline = new TimelinePanel(timelined), BorderLayout.CENTER);
List<Image> images = new ArrayList<>();
images.add(View.loadImage("timeline16"));
images.add(View.loadImage("timeline32"));
setIconImages(images);
}
}
@@ -1,106 +1,124 @@
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.timeline.Timelined;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* @author JPEXS
*/
public class TimelinePanel extends JPanel {
public TimelineBodyPanel timelineBodyPanel;
public TimelineTimePanel timePanel;
public TimelineDepthPanel depthPanel;
public Timeline timeline;
public static final int FRAME_WIDTH = 8;
public static final int FRAME_HEIGHT = 18;
public static Color selectedColor = new Color(0xff, 0x99, 0x99);
public static Color selectedBorderColor = new Color(0xcc, 0, 0);
public static Color backgroundColor = new Color(0xee, 0xee, 0xee);
public TimelinePanel(Timelined timelined) {
timeline = timelined.getTimeline();
timelineBodyPanel = new TimelineBodyPanel(timeline);
setLayout(new BorderLayout());
JScrollPane sp = new JScrollPane(timelineBodyPanel);
depthPanel = new TimelineDepthPanel(timeline);
timePanel = new TimelineTimePanel();
JPanel row1Panel = new JPanel();
row1Panel.setLayout(new BorderLayout());
JPanel sepPanel = new JPanel();
sepPanel.setBackground(TimelinePanel.backgroundColor);
sepPanel.setPreferredSize(new Dimension(depthPanel.getWidth(), timePanel.getHeight()));
row1Panel.add(sepPanel, BorderLayout.WEST);
row1Panel.add(timePanel, BorderLayout.CENTER);
JPanel row2Panel = new JPanel();
row2Panel.setLayout(new BorderLayout());
row2Panel.add(depthPanel, BorderLayout.WEST);
row2Panel.add(sp, BorderLayout.CENTER);
add(row1Panel, BorderLayout.NORTH);
add(row2Panel, BorderLayout.CENTER);
sp.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
timePanel.scroll(e.getValue());
}
});
sp.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
depthPanel.scroll(e.getValue());
}
});
final TimelineTimePanel ftime = timePanel;
timelineBodyPanel.addFrameSelectionListener(new FrameSelectionListener() {
@Override
public void frameSelected(int frame, int depth) {
ftime.frameSelect(frame);
}
});
final TimelineBodyPanel ftimeline = timelineBodyPanel;
timePanel.addFrameSelectionListener(new FrameSelectionListener() {
@Override
public void frameSelected(int frame, int depth) {
ftimeline.frameSelect(frame, depth);
}
});
}
}
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.timeline.Timeline;
import com.jpexs.decompiler.flash.timeline.Timelined;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
*
* @author JPEXS
*/
public class TimelinePanel extends JPanel {
private TimelineBodyPanel timelineBodyPanel;
private TimelineTimePanel timePanel;
private TimelineDepthPanel depthPanel;
private Timeline timeline;
public static final int FRAME_WIDTH = 8;
public static final int FRAME_HEIGHT = 18;
public static Color selectedColor = new Color(0xff, 0x99, 0x99);
public static Color selectedBorderColor = new Color(0xcc, 0, 0);
public static Color backgroundColor = new Color(0xd9, 0xe7, 0xfa);
public Timeline getTimeline() {
return timeline;
}
public void addFrameSelectionListener(FrameSelectionListener l) {
timelineBodyPanel.addFrameSelectionListener(l);
}
public void removeFrameSelectionListener(FrameSelectionListener l) {
timelineBodyPanel.removeFrameSelectionListener(l);
}
public void setTimelined(Timelined timelined) {
this.removeAll();
if (timelined == null) {
this.revalidate();
return;
}
timeline = timelined.getTimeline();
timelineBodyPanel = new TimelineBodyPanel(timeline);
setLayout(new BorderLayout());
JScrollPane sp = new JScrollPane(timelineBodyPanel);
depthPanel = new TimelineDepthPanel(timeline);
timePanel = new TimelineTimePanel();
JPanel row1Panel = new JPanel();
row1Panel.setLayout(new BorderLayout());
JPanel sepPanel = new JPanel();
sepPanel.setBackground(TimelinePanel.backgroundColor);
sepPanel.setPreferredSize(new Dimension(depthPanel.getWidth(), timePanel.getHeight()));
row1Panel.add(sepPanel, BorderLayout.WEST);
row1Panel.add(timePanel, BorderLayout.CENTER);
JPanel row2Panel = new JPanel();
row2Panel.setLayout(new BorderLayout());
row2Panel.add(depthPanel, BorderLayout.WEST);
row2Panel.add(sp, BorderLayout.CENTER);
add(row1Panel, BorderLayout.NORTH);
add(row2Panel, BorderLayout.CENTER);
sp.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
timePanel.scroll(e.getValue());
}
});
sp.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
@Override
public void adjustmentValueChanged(AdjustmentEvent e) {
depthPanel.scroll(e.getValue());
}
});
final TimelineTimePanel ftime = timePanel;
timelineBodyPanel.addFrameSelectionListener(new FrameSelectionListener() {
@Override
public void frameSelected(int frame, int depth) {
ftime.frameSelect(frame);
}
});
final TimelineBodyPanel ftimeline = timelineBodyPanel;
timePanel.addFrameSelectionListener(new FrameSelectionListener() {
@Override
public void frameSelected(int frame, int depth) {
ftimeline.frameSelect(frame, depth);
}
});
this.revalidate();
}
}
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010-2014 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.timeline;
import com.jpexs.decompiler.flash.gui.AppFrame;
import com.jpexs.decompiler.flash.gui.ImagePanel;
import com.jpexs.decompiler.flash.gui.View;
import com.jpexs.decompiler.flash.timeline.Timelined;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Image;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
/**
*
* @author JPEXS
*/
public class TimelineViewPanel extends JPanel {
public TimelinePanel timeline;
public ImagePanel previewPanel;
public TimelineViewPanel() {
}
public void setTimelined(Timelined timelined) {
removeAll();
if (timelined == null) {
revalidate();
return;
}
setLayout(new BorderLayout());
timeline = new TimelinePanel();
timeline.setTimelined(timelined);
add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, timeline, previewPanel = new ImagePanel()));
previewPanel.setTimelined(timelined, timelined.getTimeline().swf, 0);
//previewPanel.setPreferredSize(new Dimension(400,300));
previewPanel.pause();
previewPanel.gotoFrame(0);
timeline.addFrameSelectionListener(new FrameSelectionListener() {
@Override
public void frameSelected(int frame, int depth) {
previewPanel.selectDepth(depth);
previewPanel.pause();
previewPanel.gotoFrame(frame);
}
});
revalidate();
}
}