diff --git a/CHANGELOG.md b/CHANGELOG.md index 3dfa6d2fa..3b55edd51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to this project will be documented in this file. - ActionScript Debugger - Call stack frames switching - view variables around call stack - ActionScript Debugger - Highlight lines of callstack - [#2105] GFX - Basic tag info +- Context menu items to create new tags (shape, sprite, image, movie, sound, binaryData) from files + and using font embed dialog for fonts ### Fixed - [#1306], [#1768] Maximizing window on other than main monitor diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java index 596e60019..ddc6dbc3b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/ImageImporter.java @@ -53,8 +53,16 @@ public class ImageImporter extends TagImporter { return importImage(it, newData, 0); } + /** + * + * @param it + * @param newData + * @param tagType 0 = can change for defineBits, -1 = detect based on data + * @return + * @throws IOException + */ public Tag importImage(ImageTag it, byte[] newData, int tagType) throws IOException { - if (newData[0] == 'B' && newData[1] == 'M') { + if (newData.length >= 2 && newData[0] == 'B' && newData[1] == 'M') { BufferedImage b = ImageHelper.read(newData); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageHelper.write(b, ImageFormat.PNG, baos); @@ -69,6 +77,18 @@ public class ImageImporter extends TagImporter { tagType = it.getId(); } } + if (tagType == -1) { + if (newData.length >= 4 + && newData[0] == (byte) 0xff + && newData[1] == (byte) 0xd8 + && newData[2] == (byte) 0xff + && newData[3] == (byte) 0xe0 + ) { + tagType = DefineBitsJPEG2Tag.ID; + } else { + tagType = DefineBitsLosslessTag.ID; + } + } if (it.getId() == tagType) { it.setImage(newData); @@ -108,6 +128,7 @@ public class ImageImporter extends TagImporter { imageTag.setModified(true); it.getTimelined().replaceTag(it, imageTag); + imageTag.setTimelined(it.getTimelined()); swf.updateCharacters(); swf.resetTimelines(swf); return imageTag; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/MovieImporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/MovieImporter.java index 31181b1e0..77dcd6384 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/MovieImporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/importers/MovieImporter.java @@ -261,9 +261,13 @@ public class MovieImporter { if (timelined != null) { timelined.resetTimeline(); } + if (timelined == null) { + timelined = movie.getTimelined(); + } int startFrame = 0; int placeDepth = -1; + int maxPlaceDepth = 0; if (timelined != null) { for (Tag t : timelined.getTags()) { if (t instanceof ShowFrameTag) { @@ -275,13 +279,47 @@ public class MovieImporter { placeDepth = pt.getDepth(); break; } + if (pt.getDepth() > -1) { + if (pt.getDepth() > maxPlaceDepth) { + maxPlaceDepth = pt.getDepth(); + } + } } } } + if (placeDepth == -1) { + placeDepth = maxPlaceDepth + 1; + startFrame = 0; + } int numTimelineFrames = timelined == null ? 0 : timelined.getFrameCount(); int importLastFrame = -1; if (timelined != null) { + + boolean placeWithCharacterIdFound = false; + ReadOnlyTagList tagList1 = timelined.getTags(); + for (int p = 0; p < tagList1.size(); p++) { + Tag t = tagList1.get(p); + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag place = (PlaceObjectTypeTag) t; + if (place.getCharacterId() == movie.characterID) { + placeWithCharacterIdFound = true; + } + } + if (t instanceof ShowFrameTag) { + if (!placeWithCharacterIdFound) { + PlaceObject2Tag placeObject = new PlaceObject2Tag(swf); + placeObject.setTimelined(timelined); + placeObject.placeFlagHasCharacter = true; + placeObject.characterId = movie.characterID; + placeObject.depth = placeDepth; + placeObject.placeFlagMove = false; + timelined.addTag(p, placeObject); + break; + } + } + } + VideoFrameTag lastVideoFrame = null; for (FLVTAG ftag : videoTags) { videoData = ((VIDEODATA) ftag.data); @@ -322,10 +360,28 @@ public class MovieImporter { ReadOnlyTagList tagList = timelined.getTags(); int p = 0; boolean found = false; + boolean placeFound = false; for (; p < tagList.size(); p++) { Tag t = tagList.get(p); - if (t instanceof ShowFrameTag) { + if (t instanceof PlaceObjectTypeTag) { + PlaceObjectTypeTag place = (PlaceObjectTypeTag) t; + if (place.getDepth() == placeDepth) { + placeFound = true; + } + } + if (t instanceof ShowFrameTag) { swfFrameNum++; + if (!placeFound) { + PlaceObject2Tag placeObject = new PlaceObject2Tag(swf); + placeObject.setTimelined(timelined); + placeObject.depth = placeDepth; + placeObject.placeFlagMove = true; + placeObject.placeFlagHasRatio = true; + placeObject.ratio = swfFrameNum - startFrame; + timelined.addTag(p, placeObject); + p++; + } + placeFound = false; if (swfFrameNum == idealFrame) { found = true; break; diff --git a/src/com/jpexs/decompiler/flash/gui/FontEmbedDialog.java b/src/com/jpexs/decompiler/flash/gui/FontEmbedDialog.java index fe4a170b6..5bf1fe9a1 100644 --- a/src/com/jpexs/decompiler/flash/gui/FontEmbedDialog.java +++ b/src/com/jpexs/decompiler/flash/gui/FontEmbedDialog.java @@ -81,13 +81,33 @@ public class FontEmbedDialog extends AppDialog { private final JCheckBox allCheckbox; private final JCheckBox importAscentDescentLeadingCheckBox; + + private final JTextField fontNameTextField; + public String getCreateFontName() { + return fontNameTextField.getText(); + } + public Font getSelectedFont() { if (ttfFileRadio.isSelected() && customFont != null) { return customFont; } return ((FontFace) faceSelection.getSelectedItem()).font; } + + public boolean isBold() { + if (ttfFileRadio.isSelected() && customFont != null) { + return customFont.isBold(); + } + return ((FontFace) faceSelection.getSelectedItem()).isBold(); + } + + public boolean isItalic() { + if (ttfFileRadio.isSelected() && customFont != null) { + return customFont.isItalic(); + } + return ((FontFace) faceSelection.getSelectedItem()).isItalic(); + } public boolean isImportAscentDescentLeading() { return importAscentDescentLeadingCheckBox.isSelected(); @@ -134,15 +154,27 @@ public class FontEmbedDialog extends AppDialog { faceSelection.setModel(FontPanel.getFaceModel((FontFamily) familyNamesSelection.getSelectedItem())); } - public FontEmbedDialog(Window owner, boolean hasLayout, FontFace selectedFace, String selectedChars) { + public FontEmbedDialog(Window owner, boolean hasLayout, FontFace selectedFace, String selectedChars, boolean create) { super(owner); setSize(900, 600); setDefaultCloseOperation(HIDE_ON_CLOSE); setTitle(translate("dialog.title")); - + + Container cnt = getContentPane(); cnt.setLayout(new BoxLayout(cnt, BoxLayout.Y_AXIS)); + + fontNameTextField = new JTextField(30); + fontNameTextField.setText(translate("font.name.default")); + fontNameTextField.selectAll(); + if (create) { + JPanel fontNamePanel = new JPanel(new FlowLayout()); + fontNamePanel.add(new JLabel(translate("font.name"))); + fontNamePanel.add(fontNameTextField); + cnt.add(fontNamePanel); + } + JPanel selFontPanel = new JPanel(new FlowLayout()); installedRadio = new JRadioButton(translate("installed")); @@ -163,6 +195,7 @@ public class FontEmbedDialog extends AppDialog { JButton loadFromDiskButton = new JButton(View.getIcon("open16")); loadFromDiskButton.setToolTipText(translate("button.loadfont")); loadFromDiskButton.addActionListener(this::loadFromDiscButtonActionPerformed); + selFontPanel.add(new JLabel(translate("font.source"))); selFontPanel.add(installedRadio); selFontPanel.add(familyNamesSelection); selFontPanel.add(faceSelection); @@ -257,9 +290,12 @@ public class FontEmbedDialog extends AppDialog { importAscentDescentLeadingCheckBox = new JCheckBox(translate("ascentdescentleading")); importAscentDescentLeadingCheckBox.setAlignmentX(Component.CENTER_ALIGNMENT); - if (hasLayout) { + if (hasLayout && !create) { cnt.add(importAscentDescentLeadingCheckBox); } + if (create) { + importAscentDescentLeadingCheckBox.setSelected(true); + } JPanel buttonsPanel = new JPanel(new FlowLayout()); JButton okButton = new JButton(AppStrings.translate("button.ok")); diff --git a/src/com/jpexs/decompiler/flash/gui/FontFace.java b/src/com/jpexs/decompiler/flash/gui/FontFace.java index dc616b3fb..9127df614 100644 --- a/src/com/jpexs/decompiler/flash/gui/FontFace.java +++ b/src/com/jpexs/decompiler/flash/gui/FontFace.java @@ -44,6 +44,14 @@ public class FontFace implements Comparable { return face; } + public boolean isBold() { + return toString().toLowerCase().contains("bold"); + } + + public boolean isItalic() { + return toString().toLowerCase().contains("italic"); + } + @Override public int hashCode() { int hash = 7; diff --git a/src/com/jpexs/decompiler/flash/gui/FontPanel.java b/src/com/jpexs/decompiler/flash/gui/FontPanel.java index f43e507f6..835ccc757 100644 --- a/src/com/jpexs/decompiler/flash/gui/FontPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/FontPanel.java @@ -615,37 +615,51 @@ public class FontPanel extends JPanel implements TagEditorPanel { } } } + + public boolean fontEmbed(TreeItem item, boolean create) { + if (item == null) { + return false; + } + FontTag ft = (FontTag) item; + FontEmbedDialog fed = new FontEmbedDialog(Main.getDefaultDialogsOwner(), ft.hasLayout() || ft.getCharacterCount() == 0, (FontFace) fontFaceSelection.getSelectedItem(), fontAddCharactersField.getText(), create); + if (fed.showDialog() == AppDialog.OK_OPTION) { + Set selChars = fed.getSelectedChars(); + if (!selChars.isEmpty() || fed.isImportAscentDescentLeading()) { + if (ft.getCharacterCount() == 0) { + ft.setHasLayout(true); + } + Font selFont = fed.getSelectedFont(); + fontFamilyNameSelection.setSelectedItem(new FontFamily(selFont)); + fontFaceSelection.setSelectedItem(new FontFace(selFont)); + fontAddChars(ft, selChars, selFont); + if (fed.isImportAscentDescentLeading()) { + Font adlFont = selFont; + if (selFont.getSize() != 1024) { + adlFont = selFont.deriveFont(1024f); + } + ft.setAscent((int) (ft.getDivider() * this.getFontMetrics(adlFont).getAscent())); + ft.setDescent((int) (ft.getDivider() * this.getFontMetrics(adlFont).getDescent())); + int leading = this.getFontMetrics(adlFont).getAscent() + this.getFontMetrics(adlFont).getDescent() - 1024; + ft.setLeading((int) (ft.getDivider() * leading)); + } + if (create) { + ft.setFontNameIntag(fed.getCreateFontName()); + ft.setBold(fed.isBold()); + ft.setItalic(fed.isItalic()); + } + fontAddCharactersField.setText(""); + ft.setModified(true); + mainPanel.reload(true); + return true; + } + } + return false; + } private void fontEmbedButtonActionPerformed(ActionEvent evt) { TreeItem item = mainPanel.getCurrentTree().getCurrentTreeItem(); if (item instanceof FontTag) { - FontTag ft = (FontTag) item; - FontEmbedDialog fed = new FontEmbedDialog(Main.getDefaultDialogsOwner(), ft.hasLayout() || ft.getCharacterCount() == 0, (FontFace) fontFaceSelection.getSelectedItem(), fontAddCharactersField.getText()); - if (fed.showDialog() == AppDialog.OK_OPTION) { - Set selChars = fed.getSelectedChars(); - if (!selChars.isEmpty() || fed.isImportAscentDescentLeading()) { - if (ft.getCharacterCount() == 0) { - ft.setHasLayout(true); - } - Font selFont = fed.getSelectedFont(); - fontFamilyNameSelection.setSelectedItem(new FontFamily(selFont)); - fontFaceSelection.setSelectedItem(new FontFace(selFont)); - fontAddChars(ft, selChars, selFont); - if (fed.isImportAscentDescentLeading()) { - Font adlFont = selFont; - if (selFont.getSize() != 1024) { - adlFont = selFont.deriveFont(1024f); - } - ft.setAscent((int) (ft.getDivider() * this.getFontMetrics(adlFont).getAscent())); - ft.setDescent((int) (ft.getDivider() * this.getFontMetrics(adlFont).getDescent())); - int leading = this.getFontMetrics(adlFont).getAscent() + this.getFontMetrics(adlFont).getDescent() - 1024; - ft.setLeading((int) (ft.getDivider() * leading)); - } - fontAddCharactersField.setText(""); - ft.setModified(true); - mainPanel.reload(true); - } - } + fontEmbed(item, false); } } diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index c88ca5801..003e03c8d 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -4422,8 +4422,12 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } public void replaceButtonActionPerformed(List items) { - if (items.size() == 0) { - return; + replace(items, false); + } + + public boolean replace(List items, boolean create) { + if (items.isEmpty()) { + return false; } TreeItem ti0 = items.get(0); @@ -4446,12 +4450,16 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se if (ti0 instanceof UnknownTag) { file = showImportFileChooser("", false); } - for (TreeItem ti : items) { - doReplaceAction(ti, file); + if (file == null) { + return false; } + for (TreeItem ti : items) { + doReplaceAction(ti, file, create); + } + return true; } - private void doReplaceAction(TreeItem item, File selectedFile) { + private void doReplaceAction(TreeItem item, File selectedFile, boolean create) { if (selectedFile == null) { return; } @@ -4496,7 +4504,7 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se File selfile = Helper.fixDialogFile(selectedFile); byte[] data = Helper.readFile(selfile.getAbsolutePath()); try { - Tag newTag = new ImageImporter().importImage(it, data); + Tag newTag = new ImageImporter().importImage(it, data, create ? -1 : 0); SWF swf = it.getSwf(); if (newTag != null) { refreshTree(swf); @@ -4572,9 +4580,9 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } } - public void replaceSpriteWithGifButtonActionPerformed(TreeItem item) { + public boolean replaceSpriteWithGif(TreeItem item) { if (item == null) { - return; + return false; } if (item instanceof DefineSpriteTag) { String filter = "filter.images|*.gif"; @@ -4595,13 +4603,23 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } reload(true); refreshTree(swf); + return true; } } + return false; + } + + public void replaceSpriteWithGifButtonActionPerformed(TreeItem item) { + replaceSpriteWithGif(item); } public void replaceNoFillButtonActionPerformed(TreeItem item) { + replaceNoFill(item); + } + + public boolean replaceNoFill(TreeItem item) { if (item == null) { - return; + return false; } if (item instanceof ShapeTag) { @@ -4633,8 +4651,10 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se ViewMessages.showMessageDialog(this, translate("error.image.invalid"), translate("error"), JOptionPane.ERROR_MESSAGE); } reload(true); + return true; } } + return false; } private void showSvgImportWarning() { @@ -6250,4 +6270,8 @@ public final class MainPanel extends JPanel implements TreeSelectionListener, Se } return dialog; } + + public boolean fontEmbed(TreeItem item, boolean create) { + return previewPanel.getFontPanel().fontEmbed(item, create); + } } diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 229c87159..efe30e35d 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -317,8 +317,8 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel if (readOnly) { parametersPanel.setVisible(false); } - } - + } + public PreviewPanel(MainPanel mainPanel, FlashPlayerPanel flashPanel) { super(JSplitPane.HORIZONTAL_SPLIT, Configuration.guiPreviewSplitPaneDividerLocationPercent); this.mainPanel = mainPanel; @@ -351,6 +351,10 @@ public class PreviewPanel extends JPersistentSplitPane implements TagEditorPanel return ret; } + public FontPanel getFontPanel() { + return fontPanel; + } + private void createParametersPanel() { displayWithPreview = new JPanel(new CardLayout()); diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata16.png new file mode 100644 index 000000000..834facf2e Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata32.png new file mode 100644 index 000000000..1cbf5436d Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importbinarydata32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importfont16.png b/src/com/jpexs/decompiler/flash/gui/graphics/importfont16.png new file mode 100644 index 000000000..11c4d0b77 Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importfont16.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/graphics/importfont32.png b/src/com/jpexs/decompiler/flash/gui/graphics/importfont32.png new file mode 100644 index 000000000..8d411d20b Binary files /dev/null and b/src/com/jpexs/decompiler/flash/gui/graphics/importfont32.png differ diff --git a/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog.properties index 90c83fd00..8fb83fa92 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog.properties @@ -26,3 +26,8 @@ ttffile.selection = TTF file: %fontname% (%filename%) allcharacters = All characters (%available% characters) #after 14.0.0 ascentdescentleading = Set ascent, descent and leading + +#after 19.1.2 +font.name = Font name: +font.name.default = My font +font.source = Source: \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog_cs.properties index a275a5455..64c54d4d7 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/FontEmbedDialog_cs.properties @@ -25,3 +25,8 @@ ttffile.noselection = TTF soubor: ttffile.selection = TTF soubor: %fontname% (%filename%) allcharacters = V\u0161echny znaky (%available% znak\u016f) ascentdescentleading = Nastavit ascent, descent a leading + +#after 19.1.2 +font.name = N\u00e1zev fontu: +font.name.default = Muj font +font.source = Zdroj: \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 39bace7cb..908841773 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1195,4 +1195,12 @@ tagInfo.textureFormat = Texture format tagInfo.padPixels = Pad pixels tagInfo.nominalGlyphSz = Nominal glyph size tagInfo.glyphCount = Glyph count -tagInfo.fontCount = Font count \ No newline at end of file +tagInfo.fontCount = Font count + +tag.shape.create = create shape from file... +tag.image.create = create image from file... +tag.sprite.create = create sprite from GIF file... +tag.movie.create = create movie from file... +tag.sound.create = create sound from file... +tag.font.create = create font using dialog... +tag.binaryData.create = create binary data from file... \ No newline at end of file diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties index b58dc3d9a..7d4c6ea9e 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1172,4 +1172,12 @@ tagInfo.textureFormat = Form\u00e1t textury tagInfo.padPixels = Zarovn\u00e1n\u00ed pixel\u016f tagInfo.nominalGlyphSz = Nomin\u00e1ln\u00ed velikost glyfu tagInfo.glyphCount = Po\u010det glyf\u016f -tagInfo.fontCount = Po\u010det p\u00edsem \ No newline at end of file +tagInfo.fontCount = Po\u010det p\u00edsem + +tag.shape.create = vytvo\u0159it tvar ze souboru... +tag.image.create = vytvo\u0159it obr\u00e1zek ze souboru... +tag.sprite.create = vytvo\u0159it sprite z GIF souboru... +tag.movie.create = vytvo\u0159it video ze souboru... +tag.sound.create = vytvo\u0159it zvuk ze souboru... +tag.font.create = vytvo\u0159it p\u00edsmo pomoc\u00ed dialogu... +tag.binaryData.create = vytvo\u0159it bin\u00e1rn\u00ed data ze souboru... \ 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 2bc0544e8..12de08bd9 100644 --- a/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java +++ b/src/com/jpexs/decompiler/flash/gui/tagtree/TagTreeContextMenu.java @@ -47,7 +47,11 @@ import com.jpexs.decompiler.flash.gui.action.AddScriptDialog; import com.jpexs.decompiler.flash.helpers.GraphTextWriter; import com.jpexs.decompiler.flash.tags.ABCContainerTag; import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag; +import com.jpexs.decompiler.flash.tags.DefineBitsLossless2Tag; import com.jpexs.decompiler.flash.tags.DefineButton2Tag; +import com.jpexs.decompiler.flash.tags.DefineFont3Tag; +import com.jpexs.decompiler.flash.tags.DefineShape4Tag; +import com.jpexs.decompiler.flash.tags.DefineSoundTag; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.DefineVideoStreamTag; import com.jpexs.decompiler.flash.tags.DoABC2Tag; @@ -1396,8 +1400,7 @@ public class TagTreeContextMenu extends JPopupMenu { } private interface AddTagActionListener { - - void call(ActionEvent evt, TreeItem item, Class cl); + void call(ActionEvent evt, TreeItem item, Class cl, TreeNodeType createNodeType); } private void addAddTagMenuFolder(JMenu addTagMenu, String folder, boolean gfx, TreeItem item, AddTagActionListener listener) { @@ -1415,11 +1418,11 @@ public class TagTreeContextMenu extends JPopupMenu { if (allowedTagTypes.isEmpty() && mappedTagTypes.isEmpty()) { return; } - addAddTagMenuItems(allowedTagTypes, folderMenu, item, listener); + addAddTagMenuItems(allowedTagTypes, folderMenu, item, listener, folder); if (!allowedTagTypes.isEmpty() && !mappedTagTypes.isEmpty()) { folderMenu.addSeparator(); } - addAddTagMenuItems(new ArrayList(mappedTagTypes), folderMenu, item, listener); + addAddTagMenuItems(new ArrayList(mappedTagTypes), folderMenu, item, listener, null); addTagMenu.add(folderMenu); } @@ -1427,7 +1430,7 @@ public class TagTreeContextMenu extends JPopupMenu { private void addAttachTagMenuItems(TreeItem item) { AddTagActionListener listener = this::attachTagActionPerformed; List mapped = AbstractTagTree.getMappedTagIdsForClass(item.getClass()); - addAddTagMenuItems(mapped, attachTagMenu, item, listener); + addAddTagMenuItems(mapped, attachTagMenu, item, listener, null); } private void addAddTagInsideMenuItems(TreeItem item) { @@ -1440,12 +1443,12 @@ public class TagTreeContextMenu extends JPopupMenu { boolean gfx = currentSwf.gfx; if (item instanceof SWF) { - addAddTagMenuItems(null, addTagInsideMenu, item, listener); + addAddTagMenuItems(null, addTagInsideMenu, item, listener, null); return; } if (item instanceof DefineSpriteTag) { - addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagInsideMenu, item, listener); + addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagInsideMenu, item, listener, TagTreeModel.FOLDER_FRAMES); addTagInsideMenu.addSeparator(); addTagInsideMenu.add(createOthersMenu(item, listener)); return; @@ -1455,10 +1458,10 @@ public class TagTreeContextMenu extends JPopupMenu { Frame frame = (Frame) item; boolean insideSprite = frame.timeline.timelined instanceof DefineSpriteTag; if (mainPanel.getCurrentView() == MainPanel.VIEW_TAGLIST) { - addAddTagMenuItems(null, addTagInsideMenu, item, listener); + addAddTagMenuItems(null, addTagInsideMenu, item, listener, TagTreeModel.FOLDER_FRAMES); return; } else { - addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagInsideMenu, item, listener); + addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagInsideMenu, item, listener, TagTreeModel.FOLDER_FRAMES); addTagInsideMenu.addSeparator(); addTagInsideMenu.add(createOthersMenu(item, listener)); } @@ -1467,7 +1470,7 @@ public class TagTreeContextMenu extends JPopupMenu { if (item instanceof FolderItem) { List allowedTagTypes = new ArrayList<>(TagTree.getSwfFolderItemNestedTagIds(((FolderItem) item).getName(), gfx)); - addAddTagMenuItems(allowedTagTypes, addTagInsideMenu, item, listener); + addAddTagMenuItems(allowedTagTypes, addTagInsideMenu, item, listener, ((FolderItem) item).getName()); return; } @@ -1513,11 +1516,11 @@ public class TagTreeContextMenu extends JPopupMenu { if (insideFrame) { if (mainPanel.getCurrentView() == MainPanel.VIEW_TAGLIST && !insideSprite) { - addAddTagMenuItems(null, addTagMenu, item, listener); + addAddTagMenuItems(null, addTagMenu, item, listener, TagTreeModel.FOLDER_FRAMES); return; } - addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagMenu, item, listener); + addAddTagMenuItems(AbstractTagTree.getFrameNestedTagIds(), addTagMenu, item, listener, TagTreeModel.FOLDER_FRAMES); addTagMenu.addSeparator(); addTagMenu.add(createOthersMenu(item, listener)); @@ -1527,25 +1530,25 @@ public class TagTreeContextMenu extends JPopupMenu { if (parent instanceof FolderItem) { List allowedTagTypes = new ArrayList<>(TagTree.getSwfFolderItemNestedTagIds(((FolderItem) parent).getName(), gfx)); - addAddTagMenuItems(allowedTagTypes, addTagMenu, item, listener); + addAddTagMenuItems(allowedTagTypes, addTagMenu, item, listener, ((FolderItem) parent).getName()); addTagMenu.addSeparator(); addTagMenu.add(createOthersMenu(item, listener)); return; } if ((item instanceof HeaderItem) && !before) { - addAddTagMenuItems(null, addTagMenu, item, listener); + addAddTagMenuItems(null, addTagMenu, item, listener, null); } } private JMenu createOthersMenu(TreeItem item, AddTagActionListener listener) { JMenu othersMenu = new JMenu(AppStrings.translate("node.others")); othersMenu.setIcon(View.getIcon("folder16")); - addAddTagMenuItems(null, othersMenu, item, listener); + addAddTagMenuItems(null, othersMenu, item, listener, TagTreeModel.FOLDER_OTHERS); return othersMenu; } - private void addAddTagMenuItems(List allowedTagTypes, JMenu addTagMenu, TreeItem item, AddTagActionListener listener) { + private void addAddTagMenuItems(List allowedTagTypes, JMenu addTagMenu, TreeItem item, AddTagActionListener listener, String parentFolder) { if (allowedTagTypes == null) { boolean gfx = mainPanel.getCurrentSwf().gfx; @@ -1580,13 +1583,82 @@ public class TagTreeContextMenu extends JPopupMenu { TreeNodeType type = AbstractTagTree.getTagNodeTypeFromTagClass(cl); tagItem.setIcon(TagTree.getIconForType(type)); tagItem.addActionListener((ActionEvent ae) -> { - listener.call(ae, item, cl); + listener.call(ae, item, cl, null); }); addTagMenu.add(tagItem); } + + if (parentFolder == null) { + return; + } + switch (parentFolder) { + case TagTreeModel.FOLDER_SHAPES: + addTagMenu.addSeparator(); + JMenuItem createShapeItem = new JMenuItem(AppStrings.translate("tag.shape.create")); + createShapeItem.setIcon(View.getIcon("importshape16")); + createShapeItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineShape4Tag.class, TreeNodeType.SHAPE); + }); + addTagMenu.add(createShapeItem); + break; + case TagTreeModel.FOLDER_IMAGES: + addTagMenu.addSeparator(); + JMenuItem createImageItem = new JMenuItem(AppStrings.translate("tag.image.create")); + createImageItem.setIcon(View.getIcon("importimage16")); + createImageItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineBitsLossless2Tag.class, TreeNodeType.IMAGE); + }); + addTagMenu.add(createImageItem); + break; + case TagTreeModel.FOLDER_SPRITES: + addTagMenu.addSeparator(); + JMenuItem createSpriteItem = new JMenuItem(AppStrings.translate("tag.sprite.create")); + createSpriteItem.setIcon(View.getIcon("importsprite16")); + createSpriteItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineSpriteTag.class, TreeNodeType.SPRITE); + }); + addTagMenu.add(createSpriteItem); + break; + case TagTreeModel.FOLDER_MOVIES: + addTagMenu.addSeparator(); + JMenuItem createMovieItem = new JMenuItem(AppStrings.translate("tag.movie.create")); + createMovieItem.setIcon(View.getIcon("importmovie16")); + createMovieItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineVideoStreamTag.class, TreeNodeType.MOVIE); + }); + addTagMenu.add(createMovieItem); + break; + case TagTreeModel.FOLDER_SOUNDS: + addTagMenu.addSeparator(); + JMenuItem createSoundItem = new JMenuItem(AppStrings.translate("tag.sound.create")); + createSoundItem.setIcon(View.getIcon("importsound16")); + createSoundItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineSoundTag.class, TreeNodeType.SOUND); + }); + addTagMenu.add(createSoundItem); + break; + case TagTreeModel.FOLDER_FONTS: + addTagMenu.addSeparator(); + JMenuItem createFontItem = new JMenuItem(AppStrings.translate("tag.font.create")); + createFontItem.setIcon(View.getIcon("importfont16")); + createFontItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineFont3Tag.class, TreeNodeType.FONT); + }); + addTagMenu.add(createFontItem); + break; + case TagTreeModel.FOLDER_BINARY_DATA: + addTagMenu.addSeparator(); + JMenuItem createBinaryDataItem = new JMenuItem(AppStrings.translate("tag.binaryData.create")); + createBinaryDataItem.setIcon(View.getIcon("importbinarydata16")); + createBinaryDataItem.addActionListener((ActionEvent ae) -> { + listener.call(ae, item, DefineBinaryDataTag.class, TreeNodeType.BINARY_DATA); + }); + addTagMenu.add(createBinaryDataItem); + break; + } } - private void addTagInsideActionPerformed(ActionEvent evt, TreeItem item, Class cl) { + private void addTagInsideActionPerformed(ActionEvent evt, TreeItem item, Class cl, TreeNodeType createNodeType) { int id = -1; try { id = cl.getDeclaredField("ID").getInt(null); @@ -1629,13 +1701,14 @@ public class TagTreeContextMenu extends JPopupMenu { swf.updateCharacters(); mainPanel.refreshTree(swf); mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), t); + handleCreateFromFile(t, createNodeType); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { logger.log(Level.SEVERE, null, ex); } } } - private void addTagBeforeActionPerformed(ActionEvent evt, TreeItem item, Class cl) { + private void addTagBeforeActionPerformed(ActionEvent evt, TreeItem item, Class cl, TreeNodeType createNodeType) { try { SWF swf = (SWF) item.getOpenable(); Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf}); @@ -1669,12 +1742,13 @@ public class TagTreeContextMenu extends JPopupMenu { swf.updateCharacters(); mainPanel.refreshTree(swf); mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), t); + handleCreateFromFile(t, createNodeType); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { logger.log(Level.SEVERE, null, ex); } } - private void addTagAfterActionPerformed(ActionEvent evt, TreeItem item, Class cl) { + private void addTagAfterActionPerformed(ActionEvent evt, TreeItem item, Class cl, TreeNodeType createNodeType) { try { SWF swf = (SWF) item.getOpenable(); Tag t = (Tag) cl.getDeclaredConstructor(SWF.class).newInstance(new Object[]{swf}); @@ -1711,6 +1785,7 @@ public class TagTreeContextMenu extends JPopupMenu { swf.updateCharacters(); mainPanel.refreshTree(swf); mainPanel.setTagTreeSelectedNode(mainPanel.getCurrentTree(), t); + handleCreateFromFile(t, createNodeType); } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException ex) { logger.log(Level.SEVERE, null, ex); } @@ -3277,7 +3352,7 @@ public class TagTreeContextMenu extends JPopupMenu { } } - private void attachTagActionPerformed(ActionEvent evt, TreeItem item, Class cl) { + private void attachTagActionPerformed(ActionEvent evt, TreeItem item, Class cl, TreeNodeType createNodeType) { int id = -1; try { id = cl.getDeclaredField("ID").getInt(null); @@ -3726,4 +3801,31 @@ public class TagTreeContextMenu extends JPopupMenu { } } } + + private void handleCreateFromFile(Tag tag, TreeNodeType createNodeType) { + if (createNodeType == null) { + return; + } + boolean remove; + switch (createNodeType) { + case SPRITE: + remove = !mainPanel.replaceSpriteWithGif(tag); + break; + case SHAPE: + remove = !mainPanel.replaceNoFill(tag); + break; + case FONT: + remove = !mainPanel.fontEmbed(tag, true); + break; + default: + List sel = new ArrayList<>(); + sel.add(tag); + remove = !mainPanel.replace(sel, true); + break; + } + if (remove) { + tag.getTimelined().removeTag(tag); + mainPanel.refreshTree(); + } + } }