From acc048705558ce970e8556feec3992da545a9250 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jindra=20Pet=C5=99=C3=ADk?= Date: Thu, 22 Dec 2022 09:11:11 +0100 Subject: [PATCH] Added #1910 Copy/paste transform matrix to/from the clipboard --- CHANGELOG.md | 2 + .../decompiler/flash/gui/TransformPanel.java | 104 ++++++++++++++++-- .../flash/gui/locales/MainFrame.properties | 4 + .../flash/gui/locales/MainFrame_cs.properties | 3 + 4 files changed, 104 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2154dd0e9..356157f0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - [#1460] Commandline import of text, images, shapes, symbol-class - [#1909] Export/import DefineBitsJPEG3/4s alpha channel to/from separate file ("PNG/GIF/JPEG+alpha" option in GUI, "-format image:png_gif_jpeg_alpha" for commandline) +- [#1910] Copy/paste transform matrix to/from the clipboard ### Fixed - [#1904] NullPointerException when renaming invalid identifiers in AS1/2 files caused by missing charset @@ -2778,6 +2779,7 @@ All notable changes to this project will be documented in this file. [#1690]: https://www.free-decompiler.com/flash/issues/1690 [#1460]: https://www.free-decompiler.com/flash/issues/1460 [#1909]: https://www.free-decompiler.com/flash/issues/1909 +[#1910]: https://www.free-decompiler.com/flash/issues/1910 [#1904]: https://www.free-decompiler.com/flash/issues/1904 [#595]: https://www.free-decompiler.com/flash/issues/595 [#1908]: https://www.free-decompiler.com/flash/issues/1908 diff --git a/src/com/jpexs/decompiler/flash/gui/TransformPanel.java b/src/com/jpexs/decompiler/flash/gui/TransformPanel.java index c11c6254e..83e4c4c85 100644 --- a/src/com/jpexs/decompiler/flash/gui/TransformPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/TransformPanel.java @@ -21,7 +21,6 @@ import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.helpers.Reference; import java.awt.BasicStroke; import java.awt.BorderLayout; -import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; @@ -33,6 +32,14 @@ import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.FlavorEvent; +import java.awt.datatransfer.FlavorListener; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; @@ -45,20 +52,16 @@ import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; +import java.io.IOException; import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Locale; import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; @@ -109,6 +112,11 @@ public class TransformPanel extends JPanel { private JTextField matrixFTextField = new JTextField(formatDouble(0), NUMBER_COLS); private JCheckBox matrixEditCurrentCheckBox = new JCheckBox(AppStrings.translate("transform.matrix.editCurrent")); + private JButton pasteClipboardButton; + + private static final String doublePatternString = "[-+]?([0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?|[0-9]+)"; + private static final Pattern matrixPattern = Pattern.compile("^MATRIX\\[(?" + doublePatternString + "),(?" + doublePatternString + "),(?" + doublePatternString + "),(?" + doublePatternString + "),(?" + doublePatternString + "),(?" + doublePatternString + ")\\]$"); + private ImagePanel imagePanel; private Rectangle2D bounds = new Rectangle2D.Double(0, 0, 1, 1); @@ -429,6 +437,18 @@ public class TransformPanel extends JPanel { } } }); + + JPanel clipboardPanel = new JPanel(new FlowLayout()); + JButton copyClipboardButton = new JButton(AppStrings.translate("transform.clipboard.copy"), View.getIcon("copy16")); + copyClipboardButton.addActionListener(this::copyClipboardActionPerformed); + pasteClipboardButton = new JButton(AppStrings.translate("transform.clipboard.paste"), View.getIcon("paste16")); + pasteClipboardButton.addActionListener(this::pasteClipboardActionPerformed); + clipboardPanel.add(copyClipboardButton); + clipboardPanel.add(pasteClipboardButton); + Toolkit.getDefaultToolkit().getSystemClipboard().addFlavorListener(this::clipBoardflavorsChanged); + + add(makeCard("clipboard", "clipboard16", clipboardPanel)); + add(Box.createVerticalGlue()); /*JPanel finalPanel = new JPanel(); //finalPanel.setPreferredSize(new Dimension(1, Integer.MAX_VALUE)); @@ -476,11 +496,77 @@ public class TransformPanel extends JPanel { } } + public void clipBoardflavorsChanged(FlavorEvent e) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable contents = clipboard.getContents(null); + boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor); + if (hasTransferableText) { + try { + String result = (String) contents.getTransferData(DataFlavor.stringFlavor); + if (result != null) { + Matcher matcher = matrixPattern.matcher(result); + if (matcher.matches()) { + pasteClipboardButton.setEnabled(true); + } else { + pasteClipboardButton.setEnabled(false); + } + } else { + pasteClipboardButton.setEnabled(false); + } + + } catch (UnsupportedFlavorException | IOException ex) { + pasteClipboardButton.setEnabled(false); + } + } else { + pasteClipboardButton.setEnabled(false); + } + } + + private void copyClipboardActionPerformed(ActionEvent e) { + Matrix matrix = imagePanel.getNewMatrix(); + String copyString = "MATRIX[" + matrix.scaleX + "," + matrix.rotateSkew0 + "," + matrix.rotateSkew1 + "," + matrix.scaleY + "," + matrix.translateX + "," + matrix.translateY + "]"; + StringSelection stringSelection = new StringSelection(copyString); + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + clipboard.setContents(stringSelection, null); + } + + private void pasteClipboardActionPerformed(ActionEvent e) { + Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); + Transferable contents = clipboard.getContents(null); + boolean hasTransferableText = (contents != null) && contents.isDataFlavorSupported(DataFlavor.stringFlavor); + if (hasTransferableText) { + try { + String result = (String) contents.getTransferData(DataFlavor.stringFlavor); + if (result != null) { + Matcher matcher = matrixPattern.matcher(result); + if (matcher.matches()) { + Matrix matrix = new Matrix(); + try { + matrix.scaleX = Double.parseDouble(matcher.group("scaleX")); + matrix.rotateSkew0 = Double.parseDouble(matcher.group("rotateSkew0")); + matrix.rotateSkew1 = Double.parseDouble(matcher.group("rotateSkew1")); + matrix.scaleY = Double.parseDouble(matcher.group("scaleY")); + matrix.translateX = Double.parseDouble(matcher.group("translateX")); + matrix.translateY = Double.parseDouble(matcher.group("translateY")); + + matrix = imagePanel.getNewMatrix().inverse().concatenate(matrix); + imagePanel.applyTransformMatrix(matrix); + } catch (NumberFormatException nfe) { + //ignore + } + } + } + } catch (UnsupportedFlavorException | IOException ex) { + //ignore + } + } + } + private void clearMoveActionPerformed(ActionEvent e) { moveUnitComboBox.setSelectedItem(Unit.PX); moveRelativeCheckBox.setSelected(false); moveHorizontalTextField.setText(formatDouble(convertUnit(bounds.getX(), Unit.TWIP, Unit.PX))); - moveVerticalTextField.setText(formatDouble(convertUnit(bounds.getY(), Unit.TWIP, Unit.PX))); + moveVerticalTextField.setText(formatDouble(convertUnit(bounds.getY(), Unit.TWIP, Unit.PX))); } private void applyMoveActionPerformed(ActionEvent e) { diff --git a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties index 2170abe0c..4dfbd14c7 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame.properties @@ -1077,3 +1077,7 @@ message.info.importImages2 = During importing images, you need to select a FOLDE Filenames inside the folder must match existing images in current selected SWF.\r\n \ If there exist "images" folder inside, it is selected instead.\r\n \ The best way to get the structure right is to export images in current SWF file first. + +transform.clipboard = Clipboard +transform.clipboard.copy = Copy matrix to clipboard +transform.clipboard.paste = Paste matrix from clipboard \ 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 7c04b8f98..04941ab9c 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/MainFrame_cs.properties @@ -1063,3 +1063,6 @@ message.info.importImages2 = B\u011bhem importu text\u016f mus\u00edte vybrat SL Pokud je uvnit\u0159 slo\u017eka "images", pak je vybr\u00e1na m\u00edsto n\u00ed.\r\n \ Nejlep\u0161\u00ed zp\u016fsob jak m\u00edt tuto strukturu spr\u00e1vn\u011b je nejprve exportovat obr\u00e1zky v aktu\u00e1ln\u00edm SWF souboru. +transform.clipboard = Schr\u00e1nka +transform.clipboard.copy = Kop\u00edrovat matici do schr\u00e1nky +transform.clipboard.paste = Vlo\u017eit matici ze schr\u00e1nky \ No newline at end of file