diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java index 19d61af64..13d276322 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFInputStream.java @@ -2868,9 +2868,9 @@ public class SWFInputStream implements AutoCloseable { ret.textHeight = readUI16("textHeight"); } int glyphCount = readUI8("glyphCount"); - ret.glyphEntries = new GLYPHENTRY[glyphCount]; + ret.glyphEntries = new ArrayList<>(glyphCount); for (int i = 0; i < glyphCount; i++) { - ret.glyphEntries[i] = readGLYPHENTRY(glyphBits, advanceBits, "glyphEntry"); + ret.glyphEntries.add(readGLYPHENTRY(glyphBits, advanceBits, "glyphEntry")); } alignByte(); endDumpLevel(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java index 1e050e143..e739f8361 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWFOutputStream.java @@ -1471,7 +1471,7 @@ public class SWFOutputStream extends OutputStream { if (value.styleFlagsHasFont) { writeUI16(value.textHeight); } - writeUI8(value.glyphEntries.length); + writeUI8(value.glyphEntries.size()); for (GLYPHENTRY ge : value.glyphEntries) { writeGLYPHENTRY(ge, glyphBits, advanceBits); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java index fc874e854..cd203075e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/ActionList.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2015 JPEXS, All rights reserved. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. - * + * * This library 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 * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.action; import com.jpexs.decompiler.flash.DisassemblyListener; @@ -81,10 +82,9 @@ public class ActionList extends ArrayList { } public Iterator getReferencesFor(final Action target) { - final ActionList diz = this; return new Iterator() { - private final Iterator iterator = diz.iterator(); + private final Iterator iterator = ActionList.this.iterator(); private Action action = getNext(); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java index 8b62c5977..9195ede82 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/swf/SwfXmlExporter.java @@ -16,7 +16,9 @@ */ package com.jpexs.decompiler.flash.exporters.swf; +import com.jpexs.decompiler.flash.ApplicationInfo; import com.jpexs.decompiler.flash.SWF; +import com.jpexs.decompiler.flash.helpers.InternalClass; import com.jpexs.decompiler.flash.helpers.LazyObject; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.helpers.ByteArrayRange; @@ -148,7 +150,12 @@ public class SwfXmlExporter { ((LazyObject) obj).load(); } - String className = obj.getClass().getSimpleName(); + Class clazz = obj.getClass(); + if (obj instanceof InternalClass) { + clazz = clazz.getSuperclass(); + } + + String className = clazz.getSimpleName(); List fields = ReflectionTools.getSwfFields(obj.getClass()); Element objNode = doc.createElement(name); objNode.setAttribute("type", className); @@ -156,6 +163,7 @@ public class SwfXmlExporter { if (level == 0) { objNode.appendChild(doc.createComment("WARNING: The structure of this XML is not final. In later versions of FFDec it can be changed.")); + objNode.appendChild(doc.createComment(ApplicationInfo.applicationVerName)); } for (Field f : fields) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/InternalClass.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/InternalClass.java new file mode 100644 index 000000000..0bf387a94 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/InternalClass.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.helpers; + +/** + * + * @author JPEXS + */ +public interface InternalClass { +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java index 3d4356cb9..4e417837f 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineEditTextTag.java @@ -29,6 +29,7 @@ import com.jpexs.decompiler.flash.tags.base.RenderContext; import com.jpexs.decompiler.flash.tags.base.TextTag; import com.jpexs.decompiler.flash.tags.dynamictext.CharacterWithStyle; import com.jpexs.decompiler.flash.tags.dynamictext.DynamicTextModel; +import com.jpexs.decompiler.flash.tags.dynamictext.GlyphCharacter; import com.jpexs.decompiler.flash.tags.dynamictext.Paragraph; import com.jpexs.decompiler.flash.tags.dynamictext.SameStyleTextRecord; import com.jpexs.decompiler.flash.tags.dynamictext.TextStyle; @@ -1017,9 +1018,9 @@ public class DefineEditTextTag extends TextTag { tr2.styleFlagsHasYOffset = true; tr2.yOffset = yOffset; } - tr2.glyphEntries = new GLYPHENTRY[tr.glyphEntries.size()]; - for (int i = 0; i < tr2.glyphEntries.length; i++) { - tr2.glyphEntries[i] = tr.glyphEntries.get(i).glyphEntry; + tr2.glyphEntries = new ArrayList<>(tr.glyphEntries.size()); + for (GlyphCharacter ge : tr.glyphEntries) { + tr2.glyphEntries.add(ge.glyphEntry); } allTextRecords.add(tr2); } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java index c89ab1489..4b7f1f694 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineText2Tag.java @@ -391,7 +391,7 @@ public class DefineText2Tag extends TextTag { tr.styleFlagsHasYOffset = true; y = null; } - tr.glyphEntries = new GLYPHENTRY[txt.length()]; + tr.glyphEntries = new ArrayList<>(txt.length()); for (int i = 0; i < txt.length(); i++) { char c = txt.charAt(i); Character nextChar = null; @@ -399,8 +399,8 @@ public class DefineText2Tag extends TextTag { nextChar = txt.charAt(i + 1); } - tr.glyphEntries[i] = new GLYPHENTRY(); - tr.glyphEntries[i].glyphIndex = font.charToGlyph(c); + GLYPHENTRY ge = new GLYPHENTRY(); + ge.glyphIndex = font.charToGlyph(c); int advance; if (font.hasLayout()) { @@ -408,11 +408,13 @@ public class DefineText2Tag extends TextTag { if (nextChar != null) { kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); } - advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); + advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); } else { advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor), c, nextChar)); } - tr.glyphEntries[i].glyphAdvance = advance; + + ge.glyphAdvance = advance; + tr.glyphEntries.add(ge); currentX += advance; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java index eec2b4fe3..fd25f7e44 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineTextTag.java @@ -397,7 +397,7 @@ public class DefineTextTag extends TextTag { tr.styleFlagsHasYOffset = true; y = null; } - tr.glyphEntries = new GLYPHENTRY[txt.length()]; + tr.glyphEntries = new ArrayList<>(txt.length()); for (int i = 0; i < txt.length(); i++) { char c = txt.charAt(i); Character nextChar = null; @@ -405,8 +405,8 @@ public class DefineTextTag extends TextTag { nextChar = txt.charAt(i + 1); } - tr.glyphEntries[i] = new GLYPHENTRY(); - tr.glyphEntries[i].glyphIndex = font.charToGlyph(c); + GLYPHENTRY ge = new GLYPHENTRY(); + ge.glyphIndex = font.charToGlyph(c); int advance; if (font.hasLayout()) { @@ -414,11 +414,13 @@ public class DefineTextTag extends TextTag { if (nextChar != null) { kerningAdjustment = font.getCharKerningAdjustment(c, nextChar); } - advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(tr.glyphEntries[i].glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); + advance = (int) Math.round(((double) textHeight * (font.getGlyphAdvance(ge.glyphIndex) + kerningAdjustment)) / (font.getDivider() * 1024.0)); } else { advance = (int) Math.round(SWF.unitDivisor * FontTag.getSystemFontAdvance(fontName, font.getFontStyle(), (int) (textHeight / SWF.unitDivisor), c, nextChar)); } - tr.glyphEntries[i].glyphAdvance = advance; + + ge.glyphAdvance = advance; + tr.glyphEntries.add(ge); currentX += advance; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java index 24f60b1d7..6461b5345 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/base/TextTag.java @@ -27,6 +27,7 @@ import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; import com.jpexs.decompiler.flash.importers.TextImportResizeTextBoundsMode; +import com.jpexs.decompiler.flash.tags.text.JustifyAlignGlyphEntry; import com.jpexs.decompiler.flash.tags.text.TextAlign; import com.jpexs.decompiler.flash.tags.text.TextParseException; import com.jpexs.decompiler.flash.types.ColorTransform; @@ -121,6 +122,20 @@ public abstract class TextTag extends CharacterTag implements DrawableTag { } public static void alignText(SWF swf, List textRecords, TextAlign textAlign) { + // Remove Justify align entries + for (TEXTRECORD tr : textRecords) { + for (int i = 0; i < tr.glyphEntries.size(); i++) { + GLYPHENTRY ge = tr.glyphEntries.get(i); + if (ge instanceof JustifyAlignGlyphEntry) { + JustifyAlignGlyphEntry jge = (JustifyAlignGlyphEntry) ge; + ge = new GLYPHENTRY(); + ge.glyphAdvance = jge.originalAdvance; + ge.glyphIndex = jge.glyphIndex; + tr.glyphEntries.set(i, ge); + } + } + } + int xMin = Integer.MAX_VALUE; int maxWidth = 0; for (TEXTRECORD tr : textRecords) { @@ -146,16 +161,6 @@ public abstract class TextTag extends CharacterTag implements DrawableTag { } } - /*if (tr.justified) { - // Text record was aligned in Justify mode earier - // restore the advances - for (GLYPHENTRY ge : tr.glyphEntries) { - char ch = font.glyphToChar(ge.glyphIndex); - if (Character.isWhitespace(ch)) { - ge.glyphAdvance = ge.originalAdvance; - } - } - }*/ int width = tr.getTotalAdvance(); switch (textAlign) { case LEFT: @@ -205,7 +210,7 @@ public abstract class TextTag extends CharacterTag implements DrawableTag { } } - if (spaces > 0) { + if (spaces > 0 && glyphEntries.size() > 0) { int fix = diff / spaces; int remaining = diff - fix * spaces; for (GLYPHENTRY ge : glyphEntries) { @@ -214,11 +219,13 @@ public abstract class TextTag extends CharacterTag implements DrawableTag { diff2++; } - //ge.originalAdvance = ge.glyphAdvance; - ge.glyphAdvance += diff2; + JustifyAlignGlyphEntry jge = new JustifyAlignGlyphEntry(); + jge.originalAdvance = ge.glyphAdvance; + jge.glyphAdvance = ge.glyphAdvance + diff2; + jge.glyphIndex = ge.glyphIndex; + int idx = tr.glyphEntries.indexOf(ge); + tr.glyphEntries.set(idx, jge); } - - //tr.justified = true; } } } @@ -295,11 +302,11 @@ public abstract class TextTag extends CharacterTag implements DrawableTag { firstLine = false; allLeftMargins.add(currentLeftMargin); int letterSpacing = 0; - for (int e = 0; e < rec.glyphEntries.length; e++) { - GLYPHENTRY entry = rec.glyphEntries[e]; + for (int e = 0; e < rec.glyphEntries.size(); e++) { + GLYPHENTRY entry = rec.glyphEntries.get(e); GLYPHENTRY nextEntry = null; - if (e < rec.glyphEntries.length - 1) { - nextEntry = rec.glyphEntries[e + 1]; + if (e < rec.glyphEntries.size() - 1) { + nextEntry = rec.glyphEntries.get(e + 1); } RECT rect = SHAPERECORD.getBounds(glyphs.get(entry.glyphIndex).shapeRecords); rect.Xmax = (int) Math.round(((double) rect.Xmax * textHeight) / (font.getDivider() * 1024)); diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/JustifyAlignGlyphEntry.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/JustifyAlignGlyphEntry.java new file mode 100644 index 000000000..4c1388789 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/text/JustifyAlignGlyphEntry.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010-2015 JPEXS, All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3.0 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. + */ +package com.jpexs.decompiler.flash.tags.text; + +import com.jpexs.decompiler.flash.helpers.InternalClass; +import com.jpexs.decompiler.flash.types.GLYPHENTRY; +import com.jpexs.decompiler.flash.types.annotations.Internal; + +/** + * + * @author JPEXS + */ +public class JustifyAlignGlyphEntry extends GLYPHENTRY implements InternalClass { + + @Internal + public int originalAdvance; +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java index 412045b7e..700021473 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/TEXTRECORD.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.Serializable; +import java.util.List; /** * @@ -61,7 +62,7 @@ public class TEXTRECORD implements Serializable { public int textHeight; @SWFArray(countField = "glyphCount") - public GLYPHENTRY[] glyphEntries; + public List glyphEntries; public String getText(FontTag font) { StringBuilder ret = new StringBuilder(); diff --git a/src/com/jpexs/decompiler/flash/gui/MainPanel.java b/src/com/jpexs/decompiler/flash/gui/MainPanel.java index cae2a59ec..0f4506ec7 100644 --- a/src/com/jpexs/decompiler/flash/gui/MainPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/MainPanel.java @@ -661,11 +661,10 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec private void ensureActionPanel() { if (actionPanel == null) { - final MainPanel diz = this; View.execInEventDispatch(new Runnable() { @Override public void run() { - actionPanel = new ActionPanel(diz); + actionPanel = new ActionPanel(MainPanel.this); displayPanel.add(actionPanel, CARDACTIONSCRIPTPANEL); } }); @@ -1570,7 +1569,6 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { String selFile = Helper.fixDialogFile(chooser.getSelectedFile()).getAbsolutePath(); File textsFile = new File(Path.combine(selFile, TextExporter.TEXT_EXPORT_FOLDER, TextExporter.TEXT_EXPORT_FILENAME_FORMATTED)); - final MainPanel diz = this; TextImporter textImporter = new TextImporter(getMissingCharacterHandler(), new TextImportErrorHandler() { // "configuration items" for the current replace only @@ -1591,14 +1589,14 @@ public final class MainPanel extends JPanel implements ActionListener, TreeSelec public boolean handle(TextTag textTag) { String msg = translate("error.text.import"); logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); - return View.showConfirmDialog(diz, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; + return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainImportError, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; } @Override public boolean handle(TextTag textTag, String message, long line) { String msg = translate("error.text.invalid.continue").replace("%text%", message).replace("%line%", Long.toString(line)); logger.log(Level.SEVERE, msg + getTextTagInfo(textTag)); - return View.showConfirmDialog(diz, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; + return View.showConfirmDialog(MainPanel.this, msg, translate("error"), JOptionPane.OK_CANCEL_OPTION, showAgainInvalidText, JOptionPane.OK_OPTION) != JOptionPane.OK_OPTION; } }); diff --git a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java index 066ee13b8..6db0c78d5 100644 --- a/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/PreviewPanel.java @@ -755,16 +755,17 @@ public class PreviewPanel extends JSplitPane implements ActionListener { tr.yOffset = 0; tr.styleFlagsHasXOffset = true; tr.styleFlagsHasYOffset = true; - tr.glyphEntries = new GLYPHENTRY[1]; + tr.glyphEntries = new ArrayList<>(1); tr.styleFlagsHasColor = true; tr.textColor = new RGB(0, 0, 0); - tr.glyphEntries[0] = new GLYPHENTRY(); + GLYPHENTRY ge = new GLYPHENTRY(); double ga = ft.getGlyphAdvance(f); int cw = ga == -1 ? w : (int) (ga / ft.getDivider() * textHeight / 1024.0); - tr.glyphEntries[0].glyphAdvance = 0; - tr.glyphEntries[0].glyphIndex = f; + ge.glyphAdvance = 0; + ge.glyphIndex = f; + tr.glyphEntries.add(ge); rec.add(tr); tmat.translateX = x * width / cols + width / cols / 2 - w / 2; diff --git a/src/com/jpexs/decompiler/flash/gui/TextPanel.java b/src/com/jpexs/decompiler/flash/gui/TextPanel.java index 5b0d5fab1..9b0827d46 100644 --- a/src/com/jpexs/decompiler/flash/gui/TextPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/TextPanel.java @@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.gui; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.gui.abc.LineMarkedEditorPane; +import com.jpexs.decompiler.flash.gui.controls.JRepeatButton; import com.jpexs.decompiler.flash.tags.DefineEditTextTag; import com.jpexs.decompiler.flash.tags.base.FontTag; import com.jpexs.decompiler.flash.tags.base.MissingCharacterHandler; @@ -117,8 +118,8 @@ public class TextPanel extends JPanel { textAlignCenterButton = createButton(null, "textaligncenter16", "text.align.center", e -> textAlign(TextAlign.CENTER)); textAlignRightButton = createButton(null, "textalignright16", "text.align.right", e -> textAlign(TextAlign.RIGHT)); textAlignJustifyButton = createButton(null, "textalignjustify16", "text.align.justify", e -> textAlign(TextAlign.JUSTIFY)); - decreaseTranslateXButton = createButton(null, "textunindent16", "text.align.translatex.decrease", e -> translateX(-(int) SWF.unitDivisor)); - increaseTranslateXButton = createButton(null, "textindent16", "text.align.translatex.increase", e -> translateX((int) SWF.unitDivisor)); + decreaseTranslateXButton = createButton(null, "textunindent16", "text.align.translatex.decrease", e -> translateX(-(int) SWF.unitDivisor, ((JRepeatButton) e.getSource()).getRepeatCount()), true); + increaseTranslateXButton = createButton(null, "textindent16", "text.align.translatex.increase", e -> translateX((int) SWF.unitDivisor, ((JRepeatButton) e.getSource()).getRepeatCount()), true); undoChangesButton = createButton(null, "reload16", "text.undo", e -> undoChanges()); textButtonsPanel.add(textAlignLeftButton); @@ -145,8 +146,12 @@ public class TextPanel extends JPanel { } private JButton createButton(String textResource, String iconName, String toolTipResource, ActionListener actionListener) { + return createButton(textResource, iconName, toolTipResource, actionListener, false); + } + + private JButton createButton(String textResource, String iconName, String toolTipResource, ActionListener actionListener, boolean repeat) { String text = textResource == null ? "" : mainPanel.translate(textResource); - JButton button = new JButton(text, View.getIcon(iconName)); + JButton button = repeat ? new JRepeatButton(text, View.getIcon(iconName)) : new JButton(text, View.getIcon(iconName)); button.setMargin(new Insets(3, 3, 3, 10)); button.addActionListener(actionListener); if (toolTipResource != null) { @@ -243,8 +248,8 @@ public class TextPanel extends JPanel { } } - private void translateX(int delta) { - if (mainPanel.translateText(textTag, delta)) { + private void translateX(int delta, int repeatCount) { + if (mainPanel.translateText(textTag, delta * repeatCount)) { updateButtonsVisibility(); textTag.getSwf().clearImageCache(); mainPanel.refreshTree(); diff --git a/src/com/jpexs/decompiler/flash/gui/controls/JRepeatButton.java b/src/com/jpexs/decompiler/flash/gui/controls/JRepeatButton.java new file mode 100644 index 000000000..36d77f3a6 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/controls/JRepeatButton.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010-2015 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui.controls; + +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.SwingUtilities; + +/** + * + * @author JPEXS + */ +public class JRepeatButton extends JButton { + + final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + + private int repeatCount; + + public JRepeatButton(String text, ImageIcon icon) { + super(text, icon); + addMouseListener(new MouseAdapter() { + int counter = 0; + + ScheduledFuture future; + + @Override + public void mousePressed(MouseEvent e) { + Runnable runnable = new Runnable() { + private int cnt = 0; + + @Override + public void run() { + SwingUtilities.invokeLater(() -> { + cnt++; + JRepeatButton button = JRepeatButton.this; + repeatCount = cnt; + fireActionPerformed(new ActionEvent(button, ActionEvent.ACTION_PERFORMED, button.getActionCommand(), e.getWhen(), e.getModifiers())); + }); + } + }; + + future = executor.scheduleAtFixedRate(runnable, 200, 200, TimeUnit.MILLISECONDS); + } + + @Override + public void mouseReleased(MouseEvent e) { + if (future != null) { + future.cancel(true); + } + } + + @Override + public void mouseExited(MouseEvent e) { + if (future != null) { + future.cancel(true); + } + } + + }); + } + + public int getRepeatCount() { + return repeatCount; + } +}