diff --git a/CHANGELOG.md b/CHANGELOG.md index 68e3bbb66..bd3a151db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file. - Support for DefineShape4 nonzero winding rule - display, svg (import, export), canvas export - Generic tag editor - MORPHLINESTYLE2 has enum selection for cap and join style - Generic tag editor - Default values for filters +- AS1/2 P-code actions inline documentation ### Fixed - Close action on SWF inside DefineBinaryData @@ -47,6 +48,7 @@ All notable changes to this project will be documented in this file. ### Changed - AS1/2 P-code action parameters are now separated by commas, code without commas is still accepted +- AS1/2 P-code Action GetURL2 as swithed parameters - sendVarsMethod is first, older code is still accepted ## [19.0.0] - 2023-10-01 ### Added diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParsedSymbol.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParsedSymbol.java index dfcebbcd7..958a2a1f8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParsedSymbol.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/parser/pcode/ASMParsedSymbol.java @@ -73,6 +73,6 @@ public class ASMParsedSymbol { @Override public String toString() { - return "symbol[type="+type+", value="+value+"]"; + return "symbol[type=" + type + ", value=" + value + "]"; } } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionGetURL2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionGetURL2.java index 7417a7441..edb2f1b4a 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionGetURL2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/action/swf4/ActionGetURL2.java @@ -35,6 +35,7 @@ import com.jpexs.decompiler.flash.action.model.PrintNumActionItem; import com.jpexs.decompiler.flash.action.model.UnLoadMovieActionItem; import com.jpexs.decompiler.flash.action.model.UnLoadMovieNumActionItem; import com.jpexs.decompiler.flash.action.parser.ActionParseException; +import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol; import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; import com.jpexs.decompiler.flash.ecma.EcmaScript; import com.jpexs.decompiler.flash.types.annotations.Reserved; @@ -86,7 +87,7 @@ public class ActionGetURL2 extends Action { @Override public String toString() { - return "GetURL2 " + loadVariablesFlag + ", " + loadTargetFlag + ", " + sendVarsMethod; + return "GetURL2 " + sendVarsMethod + ", " + loadVariablesFlag + ", " + loadTargetFlag; } @Override @@ -109,11 +110,24 @@ public class ActionGetURL2 extends Action { public ActionGetURL2(FlasmLexer lexer, String charset) throws IOException, ActionParseException { super(0x9A, -1, charset); + + ASMParsedSymbol symb = lexer.lex(); + boolean sendVarsMethodLast = false; + if (symb.type == ASMParsedSymbol.TYPE_BOOLEAN) { //backwards compatibility + sendVarsMethodLast = true; + } + lexer.pushback(symb); + if (!sendVarsMethodLast) { + sendVarsMethod = (int) lexLong(lexer); + lexOptionalComma(lexer); + } loadVariablesFlag = lexBoolean(lexer); lexOptionalComma(lexer); - loadTargetFlag = lexBoolean(lexer); - lexOptionalComma(lexer); - sendVarsMethod = (int) lexLong(lexer); + loadTargetFlag = lexBoolean(lexer); + if (sendVarsMethodLast) { + lexOptionalComma(lexer); + sendVarsMethod = (int) lexLong(lexer); + } } @Override diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java index 25ab5c3a5..9794f9a1e 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java @@ -927,6 +927,15 @@ public final class Configuration { @ConfigurationCategory("ui") public static ConfigurationItem showImportSpriteInfo = null; + @ConfigurationDefaultBoolean(true) + @ConfigurationCategory("ui") + public static ConfigurationItem displayAs12PCodeDocsPanel = null; + + @ConfigurationDefaultDouble(0.85) + @ConfigurationName("gui.action.splitPane.docs.dividerLocationPercent") + @ConfigurationInternal + public static ConfigurationItem guiActionDocsSplitPaneDividerLocationPercent = null; + private enum OSId { WINDOWS, OSX, UNIX } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As12PCodeDocs.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As12PCodeDocs.java new file mode 100644 index 000000000..f9d717950 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/docs/As12PCodeDocs.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2010-2023 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.docs; + +import com.jpexs.decompiler.flash.ApplicationInfo; +import com.jpexs.helpers.Helper; +import com.jpexs.helpers.utf8.Utf8Helper; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TreeSet; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Generator for AVM2 instruction set documentation. + * + * @author JPEXS + */ +public class As12PCodeDocs extends AbstractDocs { + + static ResourceBundle prop; + private static List allInstructionNames = Arrays.asList("gotoframe", + "geturl", + "nextframe", + "prevframe", + "play", + "stop", + "togglequality", + "stopsounds", + "waitforframe", + "settarget", + "gotolabel", + "push", + "pop", + "add", + "subtract", + "multiply", + "divide", + "equals", + "less", + "and", + "or", + "not", + "stringequals", + "stringlength", + "stringadd", + "stringextract", + "stringless", + "mbstringlength", + "mbstringextract", + "tointeger", + "chartoascii", + "asciitochar", + "mbchartoascii", + "mbasciitochar", + "jump", + "if", + "call", + "getvariable", + "setvariable", + "geturl2", + "gotoframe2", + "settarget2", + "getproperty", + "setproperty", + "clonesprite", + "removesprite", + "startdrag", + "enddrag", + "waitforframe2", + "trace", + "gettime", + "randomnumber", + "callfunction", + "callmethod", + "constantpool", + "definefunction", + "definelocal", + "definelocal2", + "delete", + "delete2", + "enumerate", + "equals2", + "getmember", + "initarray", + "initobject", + "newmethod", + "newobject", + "setmember", + "targetpath", + "with", + "tonumber", + "tostring", + "typeof", + "add2", + "less2", + "modulo", + "bitand", + "bitlshift", + "bitor", + "bitrshift", + "biturshift", + "bitxor", + "decrement", + "increment", + "pushduplicate", + "return", + "stackswap", + "storeregister", + "instanceof", + "enumerate2", + "strictequals", + "greater", + "stringgreater", + "definefunction2", + "extends", + "castop", + "implementsop", + "try", + "throw" + ); + + static { + prop = ResourceBundle.getBundle("com.jpexs.decompiler.flash.locales.docs.pcode.AS2"); + } + + static final String NEWLINE = "\r\n"; + + private static String makeIdent(String name) { + StringBuilder identName = new StringBuilder(); + boolean cap = false; + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (c == '_') { + cap = true; + continue; + } + if (cap) { + identName.append(c); + cap = false; + } else { + identName.append(Character.toLowerCase(c)); + } + } + return identName.toString(); + } + + public static String getDocsForIns(String insName, boolean ui, boolean standalone, boolean nightMode) { + insName = insName.toLowerCase(); + if (!allInstructionNames.contains(insName)) { + return null; + } + final String cacheKey = insName + "|" + (ui ? 1 : 0) + "|" + (standalone ? 1 : 0); + String v = docsCache.get(cacheKey); + if (v != null) { + return v; + } + + StringBuilder sb = new StringBuilder(); + if (standalone) { + sb.append(htmlHeader("", getStyle(), nightMode)); + } + + String insShortDescription = getProperty("action." + insName + ".shortDescription"); + String insDescription = getProperty("action." + insName + ".description"); + String stackBefore = getProperty("action." + insName + ".stackBefore"); + String stackAfter = getProperty("action." + insName + ".stackAfter"); + String instructionCode = getProperty("action." + insName + ".code"); + String swfVersion = getProperty("action." + insName + ".swfVersion"); + String insRealName = getProperty("action." + insName + ".name"); + + if (stackBefore.trim().isEmpty()) { + stackBefore = getProperty("ui.stack.before.empty"); + } else { + stackBefore = getProperty("ui.stack.before") + stackBefore; + } + if (stackAfter.trim().isEmpty()) { + stackAfter = getProperty("ui.stack.before.empty"); + } else { + stackAfter = getProperty("ui.stack.before") + stackAfter; + } + stackBefore = "" + stackBefore + ""; + stackAfter = "" + stackAfter + ""; + + String stack = stackBefore + "" + getProperty("ui.stack.to") + "" + stackAfter; + String operandsDoc = getProperty("action." + insName + ".operands"); + + if (standalone) { + sb.append(""); + } + + sb.append("
"); + + sb.append("
").append(instructionCode).append(" ").append(insRealName).append(""); + + if (!operandsDoc.isEmpty()) { + sb.append(" "); + } + sb.append(operandsDoc); + sb.append("
").append(NEWLINE); + + sb.append("
").append(insShortDescription).append("
").append(NEWLINE); + + if (!insDescription.trim().isEmpty()) { + sb.append("
").append("").append(getProperty("ui.description")).append("").append(insDescription).append("
").append(NEWLINE); + } + sb.append("
").append(getProperty("ui.stack")).append("").append(stack).append("").append("
").append(NEWLINE); + sb.append("
").append(getProperty("ui.swfVersion")).append("").append(swfVersion).append("").append("
").append(NEWLINE); + sb.append("
").append(NEWLINE); //.instruction + if (standalone) { + sb.append(""); + sb.append(htmlFooter()); + } + String r = sb.toString(); + docsCache.put(cacheKey, r); + return r; + } + + public static String getJs() { + String cached = docsCache.get("__js"); + if (cached != null) { + return cached; + } + String js = ""; + InputStream is = As12PCodeDocs.class.getResourceAsStream("/com/jpexs/decompiler/flash/docs/docs.js"); + if (is == null) { + Logger.getLogger(As12PCodeDocs.class.getName()).log(Level.SEVERE, "docs.js needed for documentation not found"); + } else { + js = new String(Helper.readStream(is), Utf8Helper.charset); + } + + docsCache.put("__js", js); + return js; + } + + public static String getAllInstructionDocs(boolean nightMode) { + + String jsData = ""; + jsData += "var txt_filter_hide = \"" + getProperty("ui.filter.hide") + "\";" + NEWLINE; + jsData += "var txt_filter_byname = \"" + getProperty("ui.filter.byname") + "\";" + NEWLINE; + jsData += "var txt_filter_order = \"" + getProperty("ui.filter.order") + "\";" + NEWLINE; + jsData += "var txt_filter_order_code = \"" + getProperty("ui.filter.order.code") + "\";" + NEWLINE; + jsData += "var txt_filter_order_name = \"" + getProperty("ui.filter.order.name") + "\";" + NEWLINE; + + jsData += "var order_set = \"name\";"; + StringBuilder sb = new StringBuilder(); + sb.append(htmlHeader(jsData + getJs(), getStyle(), nightMode)); + sb.append(""); + sb.append("\t\t

").append(getProperty("ui.list.heading")).append("

").append(NEWLINE); + sb.append(""); + sb.append("\t\t
    ").append(NEWLINE); + Set s = new TreeSet<>(allInstructionNames); + for (String name : s) { + sb.append("\t\t\t
  • ").append(NEWLINE); + sb.append("\t\t\t\t").append(getDocsForIns(name, false, false, nightMode).trim().replace(NEWLINE, NEWLINE + "\t\t\t\t")).append(NEWLINE); + sb.append("\t\t\t
  • ").append(NEWLINE); + } + sb.append("\t\t
").append(NEWLINE); + sb.append("\t").append(NEWLINE); + sb.append(htmlFooter()); + return sb.toString(); + } + + public static void main(String[] args) throws UnsupportedEncodingException { + System.out.println(getAllInstructionDocs(false)); + } + + protected static String htmlHeader(String js, String style, boolean nightMode) { + Date dateGenerated = new Date(); + StringBuilder sb = new StringBuilder(); + sb.append("").append(NEWLINE) + .append("").append(NEWLINE) + .append("\t").append(NEWLINE); + if (style != null && !style.isEmpty()) { + sb.append("\t\t").append(NEWLINE); + } + if (js != null && !js.isEmpty()) { + sb.append("\t\t").append(NEWLINE); + } + sb.append("\t\t").append(NEWLINE) + .append(meta("generator", ApplicationInfo.applicationVerName)) + .append(meta("description", getProperty("ui.list.pageDescription"))) + .append(metaProp("og:title", getProperty("ui.list.pageTitle"))) + .append(metaProp("og:type", "article")) + .append(metaProp("og:description", getProperty("ui.list.pageDescription"))) + .append(meta("date", dateGenerated)) + .append("\t\t").append(getProperty("ui.list.documentTitle")).append("").append(NEWLINE) + .append("\t").append(NEWLINE); + return sb.toString(); + } + + protected static String getProperty(String name) { + if (prop.containsKey(name)) { + return Helper.escapeHTML(prop.getString(name)); + } + return null; + } +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS2.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS2.properties new file mode 100644 index 000000000..b7de05165 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS2.properties @@ -0,0 +1,925 @@ +#String for whole list generation + +ui.list.heading = AVM2 Instruction list +ui.list.pageTitle = AVM2 Instruction list +ui.list.documentTitle = AVM2 Instruction list +ui.list.pageDescription = List of all known ActionScript 3 - AVM2 instructions with their operands and stack values + +#various strings in UI: +ui.unknown = ??? +ui.stack = Stack: +ui.stack.before = ..., +ui.stack.before.empty = ... +ui.stack.to = \ \u279e +ui.flags = Flags: +ui.description = Description: +ui.filter.hide = Hide: +ui.filter.byname = Find by name: +ui.filter.order = Order by: +ui.filter.order.code = code +ui.filter.order.name = name +ui.swfVersion = Since SWF version: + +#----------------------- Actions + +action.gotoframe.name = GotoFrame +action.gotoframe.code = 0x81 +action.gotoframe.swfVersion = 3 +action.gotoframe.shortDescription = Go to frame +action.gotoframe.description = +action.gotoframe.stackBefore = +action.gotoframe.stackAfter = +action.gotoframe.operands = frame:UI16 + +action.geturl.name = GetURL +action.geturl.code = 0x83 +action.geturl.swfVersion = 3 +action.geturl.shortDescription = Get URL +action.geturl.description = +action.geturl.stackBefore = +action.geturl.stackAfter = +action.geturl.operands = urlString:STRING, targetString:STRING + +action.nextframe.name = NextFrame +action.nextframe.code = 0x04 +action.nextframe.swfVersion = 3 +action.nextframe.shortDescription = Go to next frame +action.nextframe.description = +action.nextframe.stackBefore = +action.nextframe.stackAfter = +action.nextframe.operands = + +action.prevframe.name = PrevFrame +action.prevframe.code = 0x05 +action.prevframe.swfVersion = 3 +action.prevframe.shortDescription = Go to previous frame +action.prevframe.description = +action.prevframe.stackBefore = +action.prevframe.stackAfter = +action.prevframe.operands = + +action.play.name = Play +action.play.code = 0x06 +action.play.swfVersion = 3 +action.play.shortDescription = Play +action.play.description = Start playing at current frame +action.play.stackBefore = +action.play.stackAfter = +action.play.operands = + +action.stop.name = Stop +action.stop.code = 0x07 +action.stop.swfVersion = 3 +action.stop.shortDescription = Stop +action.stop.description = Stop playing at current frame +action.stop.stackBefore = +action.stop.stackAfter = +action.stop.operands = + +action.togglequality.name = ToggleQuality +action.togglequality.code = 0x08 +action.togglequality.swfVersion = 3 +action.togglequality.shortDescription = Toggle quality +action.togglequality.description = Toggles display quality between high and low +action.togglequality.stackBefore = +action.togglequality.stackAfter = +action.togglequality.operands = + +action.stopsounds.name = StopSounds +action.stopsounds.code = 0x09 +action.stopsounds.swfVersion = 3 +action.stopsounds.shortDescription = Stop sounds +action.stopsounds.description = Stop playing all sounds +action.stopsounds.stackBefore = +action.stopsounds.stackAfter = +action.stopsounds.operands = + +action.waitforframe.name = WaitForFrame +action.waitforframe.code = 0x8A +action.waitforframe.swfVersion = 3 +action.waitforframe.shortDescription = Wait for frame +action.waitforframe.description = +action.waitforframe.stackBefore = +action.waitforframe.stackAfter = +action.waitforframe.operands = frame:UI16, skipCount:UI8 + +action.settarget.name = SetTarget +action.settarget.code = 0x8B +action.settarget.swfVersion = 3 +action.settarget.shortDescription = Set target +action.settarget.description = Changes context of subsequent actions +action.settarget.stackBefore = +action.settarget.stackAfter = +action.settarget.operands = targetName:STRING + +action.gotolabel.name = GoToLabel +action.gotolabel.code = 0x8C +action.gotolabel.swfVersion = 3 +action.gotolabel.shortDescription = Go to label +action.gotolabel.description = Go to frame associated with specified label +action.gotolabel.stackBefore = +action.gotolabel.stackAfter = +action.gotolabel.operands = label:STRING + +action.push.name = Push +action.push.code = 0x96 +action.push.swfVersion = 4 +action.push.shortDescription = Push value(s) +action.push.description = Pushes one or more values to the stack +action.push.stackBefore = +action.push.stackAfter = values +action.push.operands = value1:*, value2:*, ... + +action.pop.name = Pop +action.pop.code = 0x17 +action.pop.swfVersion = 4 +action.pop.shortDescription = Pop value +action.pop.description = Pops value from the stack and discards it +action.pop.stackBefore = value +action.pop.stackAfter = +action.pop.operands = + +action.add.name = Add +action.add.code = 0x0A +action.add.swfVersion = 4 +action.add.shortDescription = Add two values +action.add.description = Adds two numbers and pushes the result back to the stack +action.add.stackBefore = value1, value2 +action.add.stackAfter = result +action.add.operands = + +action.subtract.name = Subtract +action.subtract.code = 0x0B +action.subtract.swfVersion = 4 +action.subtract.shortDescription = Subtract two values +action.subtract.description = Subtracts two numbers and pushes the result back to the stack +action.subtract.stackBefore = value1, value2 +action.subtract.stackAfter = result +action.subtract.operands = + +action.multiply.name = Multiply +action.multiply.code = 0x0C +action.multiply.swfVersion = 4 +action.multiply.shortDescription = Multiply two values +action.multiply.description = Multiplies two numbers and pushes the result back to the stack +action.multiply.stackBefore = value1, value2 +action.multiply.stackAfter = result +action.multiply.operands = + +action.divide.name = Divide +action.divide.code = 0x0D +action.divide.swfVersion = 4 +action.divide.shortDescription = Divide two values +action.divide.description = Divides two numbers and pushes the result back to the stack +action.divide.stackBefore = value1, value2 +action.divide.stackAfter = result +action.divide.operands = + +action.equals.name = Equals +action.equals.code = 0x0E +action.equals.swfVersion = 4 +action.equals.shortDescription = Check that two values are equal +action.equals.description = +action.equals.stackBefore = value1, value2 +action.equals.stackAfter = booleanResult +action.equals.operands = + +action.less.name = Less +action.less.code = 0x0F +action.less.swfVersion = 4 +action.less.shortDescription = Check that value is less than other value +action.less.description = +action.less.stackBefore = value1, value2 +action.less.stackAfter = booleanResult +action.less.operands = + +action.and.name = And +action.and.code = 0x10 +action.and.swfVersion = 4 +action.and.shortDescription = Logical AND +action.and.description = Performs a logical AND of two numbers +action.and.stackBefore = value1, value2 +action.and.stackAfter = booleanResult +action.and.operands = + +action.or.name = Or +action.or.code = 0x11 +action.or.swfVersion = 4 +action.or.shortDescription = Logical OR +action.or.description = Performs a logical OR of two numbers +action.or.stackBefore = value1, value2 +action.or.stackAfter = booleanResult +action.or.operands = + +action.not.name = Not +action.not.code = 0x12 +action.not.swfVersion = 4 +action.not.shortDescription = Logical NOT +action.not.description = Performs a logical NOT of a number +action.not.stackBefore = value +action.not.stackAfter = booleanResult +action.not.operands = + +action.stringequals.name = StringEquals +action.stringequals.code = 0x13 +action.stringequals.swfVersion = 4 +action.stringequals.shortDescription = Check that two strings are equal +action.stringequals.description = +action.stringequals.stackBefore = value1, value2 +action.stringequals.stackAfter = booleanResult +action.stringequals.operands = + +action.stringlength.name = StringLength +action.stringlength.code = 0x14 +action.stringlength.swfVersion = 4 +action.stringlength.shortDescription = Length of the string +action.stringlength.description = Computes the length of a string +action.stringlength.stackBefore = value +action.stringlength.stackAfter = result +action.stringlength.operands = + +action.stringadd.name = StringAdd +action.stringadd.code = 0x21 +action.stringadd.swfVersion = 4 +action.stringadd.shortDescription = Concatenate two strings +action.stringadd.description = +action.stringadd.stackBefore = value1, value2 +action.stringadd.stackAfter = result +action.stringadd.operands = + +action.stringextract.name = StringExtract +action.stringextract.code = 0x15 +action.stringextract.swfVersion = 4 +action.stringextract.shortDescription = Extract a substring from a string +action.stringextract.description = +action.stringextract.stackBefore = count, index, string +action.stringextract.stackAfter = result +action.stringextract.operands = + +action.stringless.name = StringLess +action.stringless.code = 0x29 +action.stringless.swfVersion = 4 +action.stringless.shortDescription = Check that string is less than other string +action.stringless.description = +action.stringless.stackBefore = value1, value2 +action.stringless.stackAfter = booleanResult +action.stringless.operands = + +action.mbstringlength.name = MBStringLength +action.mbstringlength.code = 0x31 +action.mbstringlength.swfVersion = 4 +action.mbstringlength.shortDescription = Length of the string multi-byte aware +action.mbstringlength.description = Computes the length of a string multi-byte aware +action.mbstringlength.stackBefore = value +action.mbstringlength.stackAfter = result +action.mbstringlength.operands = + +action.mbstringextract.name = MBStringExtract +action.mbstringextract.code = 0x35 +action.mbstringextract.swfVersion = 4 +action.mbstringextract.shortDescription = Extract a substring from a string multi-byte aware +action.mbstringextract.description = +action.mbstringextract.stackBefore = count, index, string +action.mbstringextract.stackAfter = result +action.mbstringextract.operands = + +action.tointeger.name = ToInteger +action.tointeger.code = 0x18 +action.tointeger.swfVersion = 4 +action.tointeger.shortDescription = Convert a value to an integer +action.tointeger.description = +action.tointeger.stackBefore = value +action.tointeger.stackAfter = result +action.tointeger.operands = + +action.chartoascii.name = CharToAscii +action.chartoascii.code = 0x32 +action.chartoascii.swfVersion = 4 +action.chartoascii.shortDescription = Convert character code to ASCII +action.chartoascii.description = +action.chartoascii.stackBefore = value +action.chartoascii.stackAfter = result +action.chartoascii.operands = + +action.asciitochar.name = AsciiToChar +action.asciitochar.code = 0x33 +action.asciitochar.swfVersion = 4 +action.asciitochar.shortDescription = Converts a value to an ASCII character code +action.asciitochar.description = +action.asciitochar.stackBefore = value +action.asciitochar.stackAfter = result +action.asciitochar.operands = + +action.mbchartoascii.name = MBCharToAscii +action.mbchartoascii.code = 0x36 +action.mbchartoascii.swfVersion = 4 +action.mbchartoascii.shortDescription = Convert character code to ASCII multi-byte aware +action.mbchartoascii.description = +action.mbchartoascii.stackBefore = value +action.mbchartoascii.stackAfter = result +action.mbchartoascii.operands = + +action.mbasciitochar.name = MBAsciiToChar +action.mbasciitochar.code = 0x37 +action.mbasciitochar.swfVersion = 4 +action.mbasciitochar.shortDescription = Converts a value to an ASCII character code multi-byte aware +action.mbasciitochar.description = +action.mbasciitochar.stackBefore = value +action.mbasciitochar.stackAfter = result +action.mbasciitochar.operands = + +action.jump.name = Jump +action.jump.code = 0x99 +action.jump.swfVersion = 4 +action.jump.shortDescription = Jump to location +action.jump.description = +action.jump.stackBefore = +action.jump.stackAfter = +action.jump.operands = location:identifier + +action.if.name = If +action.if.code = 0x9D +action.if.swfVersion = 4 +action.if.shortDescription = If branch +action.if.description = Creates a conditional test and branch +action.if.stackBefore = condition +action.if.stackAfter = +action.if.operands = branchTarget:identifier + +action.call.name = Call +action.call.code = 0x9E +action.call.swfVersion = 4 +action.call.shortDescription = Call a subroutine +action.call.description = +action.call.stackBefore = value +action.call.stackAfter = +action.call.operands = + +action.getvariable.name = GetVariable +action.getvariable.code = 0x1C +action.getvariable.swfVersion = 4 +action.getvariable.shortDescription = Get variable value +action.getvariable.description = +action.getvariable.stackBefore = name +action.getvariable.stackAfter = value +action.getvariable.operands = + +action.setvariable.name = SetVariable +action.setvariable.code = 0x1D +action.setvariable.swfVersion = 4 +action.setvariable.shortDescription = Set variable value +action.setvariable.description = +action.setvariable.stackBefore = value, name +action.setvariable.stackAfter = +action.setvariable.operands = + +action.geturl2.name = GetURL2 +action.geturl2.code = 0x9A +action.geturl2.swfVersion = 4 +action.geturl2.shortDescription = Get a URL (stack based) +action.geturl2.description = +action.geturl2.stackBefore = target, url +action.geturl2.stackAfter = +action.geturl2.operands = sendVarsMethod:integer, loadTargetFlag:boolean, loadVariablesFlag:boolean + +action.gotoframe2.name = GotoFrame2 +action.gotoframe2.code = 0x9F +action.gotoframe2.swfVersion = 4 +action.gotoframe2.shortDescription = Go to frame (stack based) +action.gotoframe2.description = +action.gotoframe2.stackBefore = frame +action.gotoframe2.stackAfter = +action.gotoframe2.operands = sceneBiasFlag:boolean, playFlag:boolean, [sceneBias:UI16] + +action.settarget2.name = SetTarget2 +action.settarget2.code = 0x20 +action.settarget2.swfVersion = 4 +action.settarget2.shortDescription = Set the current context (stack based) +action.settarget2.description = +action.settarget2.stackBefore = target +action.settarget2.stackAfter = +action.settarget2.operands = + +action.getproperty.name = GetProperty +action.getproperty.code = 0x22 +action.getproperty.swfVersion = 4 +action.getproperty.shortDescription = Get property value +action.getproperty.description = +action.getproperty.stackBefore = index, target +action.getproperty.stackAfter = value +action.getproperty.operands = + +action.setproperty.name = SetProperty +action.setproperty.code = 0x23 +action.setproperty.swfVersion = 4 +action.setproperty.shortDescription = Set property value +action.setproperty.description = +action.setproperty.stackBefore = value, index, target +action.setproperty.stackAfter = +action.setproperty.operands = + +action.clonesprite.name = CloneSprite +action.clonesprite.code = 0x24 +action.clonesprite.swfVersion = 4 +action.clonesprite.shortDescription = Clone a sprite +action.clonesprite.description = +action.clonesprite.stackBefore = depth, target, source +action.clonesprite.stackAfter = +action.clonesprite.operands = + +action.removesprite.name = RemoveSprite +action.removesprite.code = 0x25 +action.removesprite.swfVersion = 4 +action.removesprite.shortDescription = Remove sprite +action.removesprite.description = +action.removesprite.stackBefore = target +action.removesprite.stackAfter = +action.removesprite.operands = + +action.startdrag.name = StartDrag +action.startdrag.code = 0x27 +action.startdrag.swfVersion = 4 +action.startdrag.shortDescription = Start dragging a movie clip +action.startdrag.description = +action.startdrag.stackBefore = target, lockcenter, constrain, [y2, x2, y1, x1] +action.startdrag.stackAfter = +action.startdrag.operands = + +action.enddrag.name = EndDrag +action.enddrag.code = 0x28 +action.enddrag.swfVersion = 4 +action.enddrag.shortDescription = End drag operation +action.enddrag.description = +action.enddrag.stackBefore = +action.enddrag.stackAfter = +action.enddrag.operands = + +action.waitforframe2.name = WaitForFrame2 +action.waitforframe2.code = 0x8D +action.waitforframe2.swfVersion = 4 +action.waitforframe2.shortDescription = Wait for a frame (stack based) +action.waitforframe2.description = +action.waitforframe2.stackBefore = frame +action.waitforframe2.stackAfter = +action.waitforframe2.operands = skipCount:UI8 + +action.trace.name = Trace +action.trace.code = 0x26 +action.trace.swfVersion = 4 +action.trace.shortDescription = Send debugging output string +action.trace.description = +action.trace.stackBefore = value +action.trace.stackAfter = +action.trace.operands = + +action.gettime.name = GetTime +action.gettime.code = 0x34 +action.gettime.swfVersion = 4 +action.gettime.shortDescription = Get milliseconds since FP start +action.gettime.description = +action.gettime.stackBefore = +action.gettime.stackAfter = value +action.gettime.operands = + +action.randomnumber.name = RandomNumber +action.randomnumber.code = 0x30 +action.randomnumber.swfVersion = 4 +action.randomnumber.shortDescription = Calculate random number +action.randomnumber.description = +action.randomnumber.stackBefore = maximum +action.randomnumber.stackAfter = result +action.randomnumber.operands = + +action.callfunction.name = CallFunction +action.callfunction.code = 0x3D +action.callfunction.swfVersion = 5 +action.callfunction.shortDescription = Execute a function +action.callfunction.description = +action.callfunction.stackBefore = functionName, numArgs, [argument1, argument2, ...] +action.callfunction.stackAfter = result +action.callfunction.operands = + +action.callmethod.name = CallMethod +action.callmethod.code = 0x52 +action.callmethod.swfVersion = 5 +action.callmethod.shortDescription = Execute a method on an object +action.callmethod.description = +action.callmethod.stackBefore = methodName, object, numArgs, [argument1, argument2, ...] +action.callmethod.stackAfter = result +action.callmethod.operands = + +action.constantpool.name = ConstantPool +action.constantpool.code = 0x88 +action.constantpool.swfVersion = 5 +action.constantpool.shortDescription = Create a new constant pool +action.constantpool.description = +action.constantpool.stackBefore = +action.constantpool.stackAfter = +action.constantpool.operands = constant1:STRING, constant2:STRING, ... + +action.definefunction.name = DefineFunction +action.definefunction.code = 0x9B +action.definefunction.swfVersion = 5 +action.definefunction.shortDescription = Define a function +action.definefunction.description = +action.definefunction.stackBefore = +action.definefunction.stackAfter = result +action.definefunction.operands = functionName:STRING, numParams:UI16, [paramName1, paramName2, ...] + +action.definelocal.name = DefineLocal +action.definelocal.code = 0x3C +action.definelocal.swfVersion = 5 +action.definelocal.shortDescription = Define local variable and set its value +action.definelocal.description = +action.definelocal.stackBefore = value, name +action.definelocal.stackAfter = +action.definelocal.operands = + +action.definelocal2.name = DefineLocal2 +action.definelocal2.code = 0x41 +action.definelocal2.swfVersion = 5 +action.definelocal2.shortDescription = Define local variable without setting its value +action.definelocal2.description = +action.definelocal2.stackBefore = name +action.definelocal2.stackAfter = +action.definelocal2.operands = + +action.delete.name = Delete +action.delete.code = 0x3A +action.delete.swfVersion = 5 +action.delete.shortDescription = Delete named property from a scriptObject +action.delete.description = +action.delete.stackBefore = name, object +action.delete.stackAfter = +action.delete.operands = + +action.delete2.name = Delete2 +action.delete2.code = 0x3B +action.delete2.swfVersion = 5 +action.delete2.shortDescription = Delete named property +action.delete2.description = +action.delete2.stackBefore = name +action.delete2.stackAfter = +action.delete2.operands = + +action.enumerate.name = Enumerate +action.enumerate.code = 0x46 +action.enumerate.swfVersion = 5 +action.enumerate.shortDescription = Obtain names of all slots from an object +action.enumerate.description = +action.enumerate.stackBefore = objectName +action.enumerate.stackAfter = null, [slotName1, slotName2, ...] +action.enumerate.operands = + +action.equals2.name = Equals2 +action.equals2.code = 0x49 +action.equals2.swfVersion = 5 +action.equals2.shortDescription = Check that two values are equal, based on types +action.equals2.description = +action.equals2.stackBefore = value1, value2 +action.equals2.stackAfter = result +action.equals2.operands = + +action.getmember.name = GetMember +action.getmember.code = 0x4E +action.getmember.swfVersion = 5 +action.getmember.shortDescription = Get named property from an object +action.getmember.description = +action.getmember.stackBefore = propertyName, object +action.getmember.stackAfter = result +action.getmember.operands = + +action.initarray.name = InitArray +action.initarray.code = 0x42 +action.initarray.swfVersion = 5 +action.initarray.shortDescription = Initialize array +action.initarray.description = +action.initarray.stackBefore = numArgs, [argument1, argument2, ...] +action.initarray.stackAfter = result +action.initarray.operands = + +action.initobject.name = InitObject +action.initobject.code = 0x43 +action.initobject.swfVersion = 5 +action.initobject.shortDescription = Initialize object +action.initobject.description = +action.initobject.stackBefore = numProps, [value1, name1, value2, name2, ...] +action.initobject.stackAfter = result +action.initobject.operands = + +action.newmethod.name = NewMethod +action.newmethod.code = 0x53 +action.newmethod.swfVersion = 5 +action.newmethod.shortDescription = Invoke constructor method and create new object +action.newmethod.description = +action.newmethod.stackBefore = methodName, object, numArgs, [argument1, argument2, ...] +action.newmethod.stackAfter = result +action.newmethod.operands = + +action.newobject.name = NewObject +action.newobject.code = 0x40 +action.newobject.swfVersion = 5 +action.newobject.shortDescription = Invoke constructor function and create new object +action.newobject.description = +action.newobject.stackBefore = objectName, numArgs, [argument1, argument2, ...] +action.newobject.stackAfter = result +action.newobject.operands = + +action.setmember.name = SetMember +action.setmember.code = 0x4F +action.setmember.swfVersion = 5 +action.setmember.shortDescription = Set named property of an object +action.setmember.description = +action.setmember.stackBefore = value, propertyName, object +action.setmember.stackAfter = +action.setmember.operands = + +action.targetpath.name = TargetPath +action.targetpath.code = 0x45 +action.targetpath.swfVersion = 5 +action.targetpath.shortDescription = Get object target path +action.targetpath.description = +action.targetpath.stackBefore = object +action.targetpath.stackAfter = result +action.targetpath.operands = + +action.with.name = With +action.with.code = 0x94 +action.with.swfVersion = 5 +action.with.shortDescription = Define with block +action.with.description = +action.with.stackBefore = object +action.with.stackAfter = +action.with.operands = + +action.tonumber.name = ToNumber +action.tonumber.code = 0x4A +action.tonumber.swfVersion = 5 +action.tonumber.shortDescription = Convert value to a number +action.tonumber.description = +action.tonumber.stackBefore = value +action.tonumber.stackAfter = result +action.tonumber.operands = + +action.tostring.name = ToString +action.tostring.code = 0x4B +action.tostring.swfVersion = 5 +action.tostring.shortDescription = Convert value to a string +action.tostring.description = +action.tostring.stackBefore = value +action.tostring.stackAfter = result +action.tostring.operands = + +action.typeof.name = TypeOf +action.typeof.code = 0x44 +action.typeof.swfVersion = 5 +action.typeof.shortDescription = Get object type +action.typeof.description = +action.typeof.stackBefore = value +action.typeof.stackAfter = result +action.typeof.operands = + +action.add2.name = Add2 +action.add2.code = 0x47 +action.add2.swfVersion = 5 +action.add2.shortDescription = Add two values, based on types +action.add2.description = +action.add2.stackBefore = value1, value2 +action.add2.stackAfter = result +action.add2.operands = + +action.less2.name = Less2 +action.less2.code = 0x48 +action.less2.swfVersion = 5 +action.less2.shortDescription = Check that value is less than other value, based on types +action.less2.description = +action.less2.stackBefore = value1, value2 +action.less2.stackAfter = booleanResult +action.less2.operands = + +action.modulo.name = Modulo +action.modulo.code = 0x3F +action.modulo.swfVersion = 5 +action.modulo.shortDescription = Calculate modulo of two numbers +action.modulo.description = Calculates modulo of two numbers and pushes the result back to the stack +action.modulo.stackBefore = value1, value2 +action.modulo.stackAfter = result +action.modulo.operands = + +action.bitand.name = BitAnd +action.bitand.code = 0x60 +action.bitand.swfVersion = 5 +action.bitand.shortDescription = Bitwise AND +action.bitand.description = Performs a bitwise AND of two numbers +action.bitand.stackBefore = value1, value2 +action.bitand.stackAfter = result +action.bitand.operands = + +action.bitlshift.name = BitLShift +action.bitlshift.code = 0x63 +action.bitlshift.swfVersion = 5 +action.bitlshift.shortDescription = Left bit shift +action.bitlshift.description = +action.bitlshift.stackBefore = shiftCount, value +action.bitlshift.stackAfter = result +action.bitlshift.operands = + +action.bitor.name = BitOr +action.bitor.code = 0x61 +action.bitor.swfVersion = 5 +action.bitor.shortDescription = Bitwise OR +action.bitor.description = Performs a bitwise OR of two numbers +action.bitor.stackBefore = value1, value2 +action.bitor.stackAfter = result +action.bitor.operands = + +action.bitrshift.name = BitRShift +action.bitrshift.code = 0x64 +action.bitrshift.swfVersion = 5 +action.bitrshift.shortDescription = Right bit shift +action.bitrshift.description = +action.bitrshift.stackBefore = shiftCount, value +action.bitrshift.stackAfter = result +action.bitrshift.operands = + +action.biturshift.name = BitURShift +action.biturshift.code = 0x65 +action.biturshift.swfVersion = 5 +action.biturshift.shortDescription = Unsigned right bit shift +action.biturshift.description = +action.biturshift.stackBefore = shiftCount, value +action.biturshift.stackAfter = result +action.biturshift.operands = + +action.bitxor.name = BitXor +action.bitxor.code = 0x62 +action.bitxor.swfVersion = 5 +action.bitxor.shortDescription = Bitwise XOR +action.bitxor.description = Performs a bitwise XOR of two numbers +action.bitxor.stackBefore = value1, value2 +action.bitxor.stackAfter = result +action.bitxor.operands = + +action.decrement.name = Decrement +action.decrement.code = 0x51 +action.decrement.swfVersion = 5 +action.decrement.shortDescription = Decrement value +action.decrement.description = +action.decrement.stackBefore = value +action.decrement.stackAfter = result +action.decrement.operands = + +action.increment.name = Increment +action.increment.code = 0x50 +action.increment.swfVersion = 5 +action.increment.shortDescription = Increment value +action.increment.description = +action.increment.stackBefore = value +action.increment.stackAfter = result +action.increment.operands = + +action.pushduplicate.name = PushDuplicate +action.pushduplicate.code = 0x4C +action.pushduplicate.swfVersion = 5 +action.pushduplicate.shortDescription = Duplicate top of the stack +action.pushduplicate.description = +action.pushduplicate.stackBefore = value +action.pushduplicate.stackAfter = value, value +action.pushduplicate.operands = + +action.return.name = Return +action.return.code = 0x3E +action.return.swfVersion = 5 +action.return.shortDescription = Return value +action.return.description = +action.return.stackBefore = value +action.return.stackAfter = +action.return.operands = + +action.stackswap.name = StackSwap +action.stackswap.code = 0x4D +action.stackswap.swfVersion = 5 +action.stackswap.shortDescription = Swap top two values on the stack +action.stackswap.description = +action.stackswap.stackBefore = value1, value2 +action.stackswap.stackAfter = value2, value1 +action.stackswap.operands = + +action.storeregister.name = StoreRegister +action.storeregister.code = 0x87 +action.storeregister.swfVersion = 5 +action.storeregister.shortDescription = Store value to a register +action.storeregister.description = +action.storeregister.stackBefore = value +action.storeregister.stackAfter = value +action.storeregister.operands = registerNumber:UI8 + +action.instanceof.name = InstanceOf +action.instanceof.code = 0x54 +action.instanceof.swfVersion = 6 +action.instanceof.shortDescription = Object is instance of class +action.instanceof.description = +action.instanceof.stackBefore = constructor, object +action.instanceof.stackAfter = booleanResult +action.instanceof.operands = + +action.enumerate2.name = Enumerate2 +action.enumerate2.code = 0x55 +action.enumerate2.swfVersion = 6 +action.enumerate2.shortDescription = Obtain names of all slots from an object (stack argument is object type) +action.enumerate2.description = +action.enumerate2.stackBefore = object +action.enumerate2.stackAfter = null, [slotName1, slotName2, ...] +action.enumerate2.operands = + +action.strictequals.name = StrictEquals +action.strictequals.code = 0x66 +action.strictequals.swfVersion = 6 +action.strictequals.shortDescription = Check that two values are equal and have same type +action.strictequals.description = +action.strictequals.stackBefore = value1, value2 +action.strictequals.stackAfter = booleanResult +action.strictequals.operands = + +action.greater.name = Greater +action.greater.code = 0x67 +action.greater.swfVersion = 6 +action.greater.shortDescription = Check that value is greater than other value +action.greater.description = +action.greater.stackBefore = value1, value2 +action.greater.stackAfter = booleanResult +action.greater.operands = + +action.stringgreater.name = StringGreater +action.stringgreater.code = 0x68 +action.stringgreater.swfVersion = 6 +action.stringgreater.shortDescription = Check that string is greater than other value +action.stringgreater.description = +action.stringgreater.stackBefore = value1, value2 +action.stringgreater.stackAfter = booleanResult +action.stringgreater.operands = + +action.definefunction2.name = DefineFunction2 +action.definefunction2.code = 0x8E +action.definefunction2.swfVersion = 7 +action.definefunction2.shortDescription = Define a function (additional features) +action.definefunction2.description = +action.definefunction2.stackBefore = +action.definefunction2.stackAfter = result +action.definefunction2.operands = functionName:STRING, numParams:UI16, \ + registerCount:UI8, \ + preloadParentFlag:boolean, \ + preloadRootFlag:boolean, \ + suppressSuperFlag:boolean, \ + preloadSuperFlag:boolean, \ + suppressArgumentsFlag:boolean, \ + preloadArgumentsFlag:boolean, \ + suppressThisFlag:boolean, \ + preloadThisFlag:boolean, \ + preloadGlobalFlag:boolean, \ + [register1:UI8, paramName1:STRING, register2:UI8, paramName2:STRING, ...] + +action.extends.name = Extends +action.extends.code = 0x69 +action.extends.swfVersion = 7 +action.extends.shortDescription = Create inheritance relationship +action.extends.description = +action.extends.stackBefore = superClassConstructor, subClassConstructor +action.extends.stackAfter = +action.extends.operands = + +action.castop.name = CastOp +action.castop.code = 0x2B +action.castop.swfVersion = 7 +action.castop.shortDescription = Cast data type +action.castop.description = +action.castop.stackBefore = object, constructor +action.castop.stackAfter = result +action.castop.operands = + +action.implementsop.name = ImplementsOp +action.implementsop.code = 0x2C +action.implementsop.swfVersion = 7 +action.implementsop.shortDescription = Specify interfaces that a class implements +action.implementsop.description = +action.implementsop.stackBefore = classConstructor, numInterfaces, [interfaceConstructor1, interfaceConstructor2, ...] +action.implementsop.stackAfter = +action.implementsop.operands = + +action.try.name = Try +action.try.code = 0x8F +action.try.swfVersion = 7 +action.try.shortDescription = Define handler for exceptional conditions +action.try.description = +action.try.stackBefore = +action.try.stackAfter = +action.try.operands = catchTarget:register|STRING + +action.throw.name = Throw +action.throw.code = 0x2A +action.throw.swfVersion = 7 +action.throw.shortDescription = Throw exceptional condition +action.throw.description = +action.throw.stackBefore = value +action.throw.stackAfter = +action.throw.operands = diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties index 074befcb0..d796cff8b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/locales/docs/pcode/AS3.properties @@ -1162,7 +1162,7 @@ instruction.lessequals.stackBefore = value1, value2 instruction.lessequals.stackAfter = booleanResult instruction.lessequals.operands = booleanResult -instruction.greaterthan.shortDescription = Check that value is greater or equal than other value +instruction.greaterthan.shortDescription = Check that value is greater than other value instruction.greaterthan.description = instruction.greaterthan.stackBefore = value1, value2 instruction.greaterthan.stackAfter = booleanResult diff --git a/src/com/jpexs/decompiler/flash/gui/ScrollablePanel.java b/src/com/jpexs/decompiler/flash/gui/ScrollablePanel.java new file mode 100644 index 000000000..943631729 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/ScrollablePanel.java @@ -0,0 +1,353 @@ +/* + * Copyright (C) 2023 JPEXS + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.jpexs.decompiler.flash.gui; + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import javax.swing.JPanel; +import javax.swing.JViewport; +import javax.swing.Scrollable; +import javax.swing.SwingConstants; + +/* + * Taken from https://github.com/tips4java/tips4java/blob/main/source/ScrollablePanel.java + */ + +/** + * A panel that implements the Scrollable interface. This class allows you to + * customize the scrollable features by using newly provided setter methods so + * you don't have to extend this class every time. + * + * Scrollable amounts can be specifed as a percentage of the viewport size or as + * an actual pixel value. The amount can be changed for both unit and block + * scrolling for both horizontal and vertical scrollbars. + * + * The Scrollable interface only provides a boolean value for determining + * whether or not the viewport size (width or height) should be used by the + * scrollpane when determining if scrollbars should be made visible. This class + * supports the concept of dynamically changing this value based on the size of + * the viewport. In this case the viewport size will only be used when it is + * larger than the panels size. This has the effect of ensuring the viewport is + * always full as components added to the panel will be size to fill the area + * available, based on the rules of the applicable layout manager of course. + */ +public class ScrollablePanel extends JPanel implements Scrollable, SwingConstants { + + public enum ScrollableSizeHint { + NONE, + FIT, + STRETCH; + } + + public enum IncrementType { + PERCENT, + PIXELS; + } + + private ScrollableSizeHint scrollableHeight = ScrollableSizeHint.NONE; + private ScrollableSizeHint scrollableWidth = ScrollableSizeHint.NONE; + + private IncrementInfo horizontalBlock; + private IncrementInfo horizontalUnit; + private IncrementInfo verticalBlock; + private IncrementInfo verticalUnit; + + /** + * Default constructor that uses a FlowLayout + */ + public ScrollablePanel() { + this(new FlowLayout()); + } + + /** + * Constuctor for specifying the LayoutManager of the panel. + * + * @param layout the LayountManger for the panel + */ + public ScrollablePanel(LayoutManager layout) { + super(layout); + + IncrementInfo block = new IncrementInfo(IncrementType.PERCENT, 100); + IncrementInfo unit = new IncrementInfo(IncrementType.PERCENT, 10); + + setScrollableBlockIncrement(HORIZONTAL, block); + setScrollableBlockIncrement(VERTICAL, block); + setScrollableUnitIncrement(HORIZONTAL, unit); + setScrollableUnitIncrement(VERTICAL, unit); + } + + /** + * Get the height ScrollableSizeHint enum + * + * @return the ScrollableSizeHint enum for the height + */ + public ScrollableSizeHint getScrollableHeight() { + return scrollableHeight; + } + + /** + * Set the ScrollableSizeHint enum for the height. The enum is used to + * determine the boolean value that is returned by the + * getScrollableTracksViewportHeight() method. The valid values are: + * + * ScrollableSizeHint.NONE - return "false", which causes the height of the + * panel to be used when laying out the children ScrollableSizeHint.FIT - + * return "true", which causes the height of the viewport to be used when + * laying out the children ScrollableSizeHint.STRETCH - return "true" when + * the viewport height is greater than the height of the panel, "false" + * otherwise. + * + * @param scrollableHeight as represented by the ScrollableSizeHint enum. + */ + public void setScrollableHeight(ScrollableSizeHint scrollableHeight) { + this.scrollableHeight = scrollableHeight; + revalidate(); + } + + /** + * Get the width ScrollableSizeHint enum + * + * @return the ScrollableSizeHint enum for the width + */ + public ScrollableSizeHint getScrollableWidth() { + return scrollableWidth; + } + + /** + * Set the ScrollableSizeHint enum for the width. The enum is used to + * determine the boolean value that is returned by the + * getScrollableTracksViewportWidth() method. The valid values are: + * + * ScrollableSizeHint.NONE - return "false", which causes the width of the + * panel to be used when laying out the children ScrollableSizeHint.FIT - + * return "true", which causes the width of the viewport to be used when + * laying out the children ScrollableSizeHint.STRETCH - return "true" when + * the viewport width is greater than the width of the panel, "false" + * otherwise. + * + * @param scrollableWidth as represented by the ScrollableSizeHint enum. + */ + public void setScrollableWidth(ScrollableSizeHint scrollableWidth) { + this.scrollableWidth = scrollableWidth; + revalidate(); + } + + /** + * Get the block IncrementInfo for the specified orientation + * + * @param orientation + * @return the block IncrementInfo for the specified orientation + */ + public IncrementInfo getScrollableBlockIncrement(int orientation) { + return orientation == SwingConstants.HORIZONTAL ? horizontalBlock : verticalBlock; + } + + @Override + public int getScrollableBlockIncrement( + Rectangle visible, int orientation, int direction) { + switch (orientation) { + case SwingConstants.HORIZONTAL: + return getScrollableIncrement(horizontalBlock, visible.width); + case SwingConstants.VERTICAL: + return getScrollableIncrement(verticalBlock, visible.height); + default: + throw new IllegalArgumentException("Invalid orientation: " + orientation); + } + } + + /** + * Specify the information needed to do block scrolling. + * + * @param orientation specify the scrolling orientation. Must be either: + * SwingContants.HORIZONTAL or SwingContants.VERTICAL. + * @param type + * @paran type specify how the amount parameter in the calculation of the + * scrollable amount. Valid values are: IncrementType.PERCENT - treat the + * amount as a % of the viewport size IncrementType.PIXEL - treat the amount + * as the scrollable amount + * @param amount a value used with the IncrementType to determine the + * scrollable amount + */ + public void setScrollableBlockIncrement(int orientation, IncrementType type, int amount) { + IncrementInfo info = new IncrementInfo(type, amount); + setScrollableBlockIncrement(orientation, info); + } + + /** + * Specify the information needed to do block scrolling. + * + * @param orientation specify the scrolling orientation. Must be either: + * SwingContants.HORIZONTAL or SwingContants.VERTICAL. + * @param info An IncrementInfo object containing information of how to + * calculate the scrollable amount. + */ + public void setScrollableBlockIncrement(int orientation, IncrementInfo info) { + switch (orientation) { + case SwingConstants.HORIZONTAL: + horizontalBlock = info; + break; + case SwingConstants.VERTICAL: + verticalBlock = info; + break; + default: + throw new IllegalArgumentException("Invalid orientation: " + orientation); + } + } + + /** + * Get the unit IncrementInfo for the specified orientation + * + * @param orientation + * @return the unit IncrementInfo for the specified orientation + */ + public IncrementInfo getScrollableUnitIncrement(int orientation) { + return orientation == SwingConstants.HORIZONTAL ? horizontalUnit : verticalUnit; + } + + @Override + public int getScrollableUnitIncrement( + Rectangle visible, int orientation, int direction) { + switch (orientation) { + case SwingConstants.HORIZONTAL: + return getScrollableIncrement(horizontalUnit, visible.width); + case SwingConstants.VERTICAL: + return getScrollableIncrement(verticalUnit, visible.height); + default: + throw new IllegalArgumentException("Invalid orientation: " + orientation); + } + } + + /** + * Specify the information needed to do unit scrolling. + * + * @param orientation specify the scrolling orientation. Must be either: + * SwingContants.HORIZONTAL or SwingContants.VERTICAL. + * @paran type specify how the amount parameter in the calculation of the + * scrollable amount. Valid values are: IncrementType.PERCENT - treat the + * amount as a % of the viewport size IncrementType.PIXEL - treat the amount + * as the scrollable amount + * @param amount a value used with the IncrementType to determine the + * scrollable amount + */ + public void setScrollableUnitIncrement(int orientation, IncrementType type, int amount) { + IncrementInfo info = new IncrementInfo(type, amount); + setScrollableUnitIncrement(orientation, info); + } + + /** + * Specify the information needed to do unit scrolling. + * + * @param orientation specify the scrolling orientation. Must be either: + * SwingContants.HORIZONTAL or SwingContants.VERTICAL. + * @param info An IncrementInfo object containing information of how to + * calculate the scrollable amount. + */ + public void setScrollableUnitIncrement(int orientation, IncrementInfo info) { + switch (orientation) { + case SwingConstants.HORIZONTAL: + horizontalUnit = info; + break; + case SwingConstants.VERTICAL: + verticalUnit = info; + break; + default: + throw new IllegalArgumentException("Invalid orientation: " + orientation); + } + } + + // Implement Scrollable interface + @Override + public Dimension getPreferredScrollableViewportSize() { + return getPreferredSize(); + } + + protected int getScrollableIncrement(IncrementInfo info, int distance) { + if (info.getIncrement() == IncrementType.PIXELS) { + return info.getAmount(); + } else { + return distance * info.getAmount() / 100; + } + } + + @Override + public boolean getScrollableTracksViewportWidth() { + if (scrollableWidth == ScrollableSizeHint.NONE) { + return false; + } + + if (scrollableWidth == ScrollableSizeHint.FIT) { + return true; + } + + // STRETCH sizing, use the greater of the panel or viewport width + if (getParent() instanceof JViewport) { + return (((JViewport) getParent()).getWidth() > getPreferredSize().width); + } + + return false; + } + + @Override + public boolean getScrollableTracksViewportHeight() { + if (scrollableHeight == ScrollableSizeHint.NONE) { + return false; + } + + if (scrollableHeight == ScrollableSizeHint.FIT) { + return true; + } + + // STRETCH sizing, use the greater of the panel or viewport height + if (getParent() instanceof JViewport) { + return (((JViewport) getParent()).getHeight() > getPreferredSize().height); + } + + return false; + } + + /** + * Helper class to hold the information required to calculate the scroll + * amount. + */ + static class IncrementInfo { + + private final IncrementType type; + private final int amount; + + public IncrementInfo(IncrementType type, int amount) { + this.type = type; + this.amount = amount; + } + + public IncrementType getIncrement() { + return type; + } + + public int getAmount() { + return amount; + } + + @Override + public String toString() { + return "ScrollablePanel[" + + type + ", " + + amount + "]"; + } + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java index 9383bcf52..4bd1d42a8 100644 --- a/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java +++ b/src/com/jpexs/decompiler/flash/gui/action/ActionPanel.java @@ -25,7 +25,9 @@ import com.jpexs.decompiler.flash.action.ActionList; import com.jpexs.decompiler.flash.action.ConstantPoolTooBigException; import com.jpexs.decompiler.flash.action.deobfuscation.BrokenScriptDetector; import com.jpexs.decompiler.flash.action.parser.ActionParseException; +import com.jpexs.decompiler.flash.action.parser.pcode.ASMParsedSymbol; import com.jpexs.decompiler.flash.action.parser.pcode.ASMParser; +import com.jpexs.decompiler.flash.action.parser.pcode.FlasmLexer; import com.jpexs.decompiler.flash.action.parser.script.ActionScript2Parser; import com.jpexs.decompiler.flash.action.parser.script.ActionScriptLexer; import com.jpexs.decompiler.flash.action.parser.script.ParsedSymbol; @@ -34,15 +36,18 @@ import com.jpexs.decompiler.flash.action.swf4.ActionPush; import com.jpexs.decompiler.flash.action.swf4.ConstantIndex; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.configuration.ConfigurationItemChangeListener; +import com.jpexs.decompiler.flash.docs.As12PCodeDocs; import com.jpexs.decompiler.flash.exporters.modes.ScriptExportMode; import com.jpexs.decompiler.flash.gui.AppStrings; import com.jpexs.decompiler.flash.gui.DebugPanel; import com.jpexs.decompiler.flash.gui.DebuggerHandler; +import com.jpexs.decompiler.flash.gui.DocsPanel; import com.jpexs.decompiler.flash.gui.FasterScrollPane; import com.jpexs.decompiler.flash.gui.GraphDialog; import com.jpexs.decompiler.flash.gui.HeaderLabel; import com.jpexs.decompiler.flash.gui.Main; import com.jpexs.decompiler.flash.gui.MainPanel; +import com.jpexs.decompiler.flash.gui.ScrollablePanel; import com.jpexs.decompiler.flash.gui.SearchListener; import com.jpexs.decompiler.flash.gui.SearchPanel; import com.jpexs.decompiler.flash.gui.TagEditorPanel; @@ -72,6 +77,7 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Insets; +import java.awt.Point; import java.awt.event.ActionEvent; import java.io.IOException; import java.io.StringReader; @@ -94,6 +100,8 @@ import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import javax.swing.JToggleButton; import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.border.BevelBorder; import javax.swing.border.EmptyBorder; import javax.swing.event.CaretEvent; @@ -751,7 +759,53 @@ public class ActionPanel extends JPanel implements SearchListener