From fba49bb87663b0ccb2dc572f77455c807b2928ae Mon Sep 17 00:00:00 2001 From: "honfika@gmail.com" Date: Sun, 18 Dec 2016 12:14:38 +0100 Subject: [PATCH] use dropdown control for enum type values in raw editor --- .../flash/tags/DefineBitsLossless2Tag.java | 11 +- .../flash/tags/DefineBitsLosslessTag.java | 12 +- .../flash/tags/DefineEditTextTag.java | 21 +- .../flash/tags/DefineFontAlignZonesTag.java | 4 + .../decompiler/flash/tags/DefineSoundTag.java | 13 + .../flash/tags/SoundStreamHeadTag.java | 11 + .../decompiler/flash/types/FILLSTYLE.java | 9 + .../decompiler/flash/types/LINESTYLE2.java | 12 +- .../flash/types/MORPHFILLSTYLE.java | 9 + .../flash/types/annotations/Conditional.java | 9 +- .../flash/types/annotations/EnumValue.java | 40 +++ .../flash/types/annotations/EnumValues.java | 33 +++ .../flash/gui/GenericTagTreePanel.java | 35 ++- .../gui/generictageditors/EnumEditor.java | 235 ++++++++++++++++++ 14 files changed, 426 insertions(+), 28 deletions(-) create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValue.java create mode 100644 libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValues.java create mode 100644 src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java index 78a6f16b5..a03fab9db 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLossless2Tag.java @@ -28,6 +28,7 @@ import com.jpexs.decompiler.flash.types.ALPHABITMAPDATA; import com.jpexs.decompiler.flash.types.ALPHACOLORMAPDATA; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -54,6 +55,8 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { public static final String NAME = "DefineBitsLossless2"; @SWFType(BasicType.UI8) + @EnumValue(value = FORMAT_8BIT_COLORMAPPED, text = "8-bit colormapped") + @EnumValue(value = FORMAT_32BIT_ARGB, text = "32-bit ARGB") public int bitmapFormat; @SWFType(BasicType.UI16) @@ -241,10 +244,10 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { ALPHACOLORMAPDATA colorMapData = null; ALPHABITMAPDATA bitmapData = null; - if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED) { + if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) { colorMapData = getColorMapData(); } - if (bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB) { + if (bitmapFormat == FORMAT_32BIT_ARGB) { bitmapData = getBitmapData(); } int pos32aligned = 0; @@ -252,13 +255,13 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag { for (int y = 0; y < bitmapHeight; y++) { for (int x = 0; x < bitmapWidth; x++) { int c = 0; - if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_8BIT_COLORMAPPED)) { + if ((bitmapFormat == FORMAT_8BIT_COLORMAPPED)) { int colorTableIndex = colorMapData.colorMapPixelData[pos32aligned] & 0xff; if (colorTableIndex < colorMapData.colorTableRGB.length) { c = colorMapData.colorTableRGB[colorTableIndex]; } } - if ((bitmapFormat == DefineBitsLossless2Tag.FORMAT_32BIT_ARGB)) { + if ((bitmapFormat == FORMAT_32BIT_ARGB)) { c = bitmapData.bitmapPixelData[pos]; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java index b9b03f25f..f8a191a9d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineBitsLosslessTag.java @@ -28,6 +28,7 @@ import com.jpexs.decompiler.flash.types.BITMAPDATA; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.COLORMAPDATA; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -54,6 +55,9 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { public static final String NAME = "DefineBitsLossless"; @SWFType(BasicType.UI8) + @EnumValue(value = FORMAT_8BIT_COLORMAPPED, text = "8-bit colormapped") + @EnumValue(value = FORMAT_15BIT_RGB, text = "15-bit RGB") + @EnumValue(value = FORMAT_24BIT_RGB, text = "24-bit RGB") public int bitmapFormat; @SWFType(BasicType.UI16) @@ -232,7 +236,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { @Override protected SerializableImage getImage() { int[] pixels = new int[bitmapWidth * bitmapHeight]; - if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) { + if (bitmapFormat == FORMAT_8BIT_COLORMAPPED) { COLORMAPDATA colorMapData = getColorMapData(); int pos32aligned = 0; int pos = 0; @@ -252,13 +256,13 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag { pos32aligned++; } } - } else if ((bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) || (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB)) { + } else if ((bitmapFormat == FORMAT_15BIT_RGB) || (bitmapFormat == FORMAT_24BIT_RGB)) { BITMAPDATA bitmapData = getBitmapData(); int pos = 0; int[] bitmapPixelData = null; - if (bitmapFormat == DefineBitsLosslessTag.FORMAT_15BIT_RGB) { + if (bitmapFormat == FORMAT_15BIT_RGB) { bitmapPixelData = bitmapData.bitmapPixelDataPix15; - } else if (bitmapFormat == DefineBitsLosslessTag.FORMAT_24BIT_RGB) { + } else if (bitmapFormat == FORMAT_24BIT_RGB) { bitmapPixelData = bitmapData.bitmapPixelDataPix24; } 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 3cf0a48d4..0577310ca 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 @@ -52,6 +52,7 @@ import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.TEXTRECORD; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.helpers.ByteArrayRange; @@ -146,6 +147,10 @@ public class DefineEditTextTag extends TextTag { @SWFType(BasicType.UI8) @Conditional("hasLayout") + @EnumValue(value = ALIGN_LEFT, text = "Left") + @EnumValue(value = ALIGN_RIGHT, text = "Right") + @EnumValue(value = ALIGN_CENTER, text = "Center") + @EnumValue(value = ALIGN_JUSTIFY, text = "Justify") public int align; @SWFType(BasicType.UI16) @@ -169,6 +174,14 @@ public class DefineEditTextTag extends TextTag { @Conditional("hasText") public String initialText; + public static final int ALIGN_LEFT = 0; + + public static final int ALIGN_RIGHT = 1; + + public static final int ALIGN_CENTER = 2; + + public static final int ALIGN_JUSTIFY = 3; + /** * Constructor * @@ -1103,16 +1116,16 @@ public class DefineEditTextTag extends TextTag { yOffset += currentOffset; int alignOffset = 0; switch (align) { - case 0: // left + case ALIGN_LEFT: alignOffset = 0; break; - case 1: // right + case ALIGN_RIGHT: alignOffset = bounds.getWidth() - width; break; - case 2: // center + case ALIGN_CENTER: alignOffset = (bounds.getWidth() - width) / 2; break; - case 3: // justify + case ALIGN_JUSTIFY: // todo; break; } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java index 870e845d2..eb125b89d 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineFontAlignZonesTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.base.CharacterIdTag; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.ZONERECORD; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFArray; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -46,6 +47,9 @@ public class DefineFontAlignZonesTag extends Tag implements CharacterIdTag { public int fontID; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = 0, text = "Thin") + @EnumValue(value = 1, text = "Medium") + @EnumValue(value = 2, text = "Thick") public int CSMTableHint; @Reserved diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java index 50f248601..4e1271fe7 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/DefineSoundTag.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.SWFOutputStream; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.base.SoundTag; import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; import com.jpexs.decompiler.flash.types.sound.MP3FRAME; @@ -57,9 +58,21 @@ public class DefineSoundTag extends CharacterTag implements SoundTag { public int soundId; @SWFType(value = BasicType.UB, count = 4) + @EnumValue(value = SoundFormat.FORMAT_UNCOMPRESSED_NATIVE_ENDIAN, text = "Uncompressed, native-endian") + @EnumValue(value = SoundFormat.FORMAT_ADPCM, text = "ADPCM") + @EnumValue(value = SoundFormat.FORMAT_MP3, text = "MP3", minSwfVersion = 4) + @EnumValue(value = SoundFormat.FORMAT_UNCOMPRESSED_LITTLE_ENDIAN, text = "Uncompressed, little-endian", minSwfVersion = 4) + @EnumValue(value = SoundFormat.FORMAT_NELLYMOSER16KHZ, text = "Nellymoser 16 kHz", minSwfVersion = 10) + @EnumValue(value = SoundFormat.FORMAT_NELLYMOSER8KHZ, text = "Nellymoser 8 kHz", minSwfVersion = 10) + @EnumValue(value = SoundFormat.FORMAT_NELLYMOSER, text = "Nellymoser", minSwfVersion = 6) + @EnumValue(value = SoundFormat.FORMAT_SPEEX, text = "Speex", minSwfVersion = 10) public int soundFormat; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = 0, text = "5.5 kHz") + @EnumValue(value = 1, text = "11 kHz") + @EnumValue(value = 2, text = "22 kHz") + @EnumValue(value = 3, text = "44 kHz") public int soundRate; public boolean soundSize; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java index 6f37e83d0..ca689c815 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/tags/SoundStreamHeadTag.java @@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.tags.base.SoundStreamHeadTypeTag; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFType; @@ -51,6 +52,10 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { public int reserved; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = 0, text = "5.5 kHz") + @EnumValue(value = 1, text = "11 kHz") + @EnumValue(value = 2, text = "22 kHz") + @EnumValue(value = 3, text = "44 kHz") public int playBackSoundRate; public boolean playBackSoundSize; @@ -58,9 +63,15 @@ public class SoundStreamHeadTag extends Tag implements SoundStreamHeadTypeTag { public boolean playBackSoundType; @SWFType(value = BasicType.UB, count = 4) + @EnumValue(value = SoundFormat.FORMAT_ADPCM, text = "ADPCM") + @EnumValue(value = SoundFormat.FORMAT_MP3, text = "MP3", minSwfVersion = 4) public int streamSoundCompression; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = 0, text = "5.5 kHz") + @EnumValue(value = 1, text = "11 kHz") + @EnumValue(value = 2, text = "22 kHz") + @EnumValue(value = 3, text = "44 kHz") public int streamSoundRate; public boolean streamSoundSize; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java index b150ca458..4d305e6ca 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/FILLSTYLE.java @@ -20,6 +20,7 @@ import com.jpexs.decompiler.flash.tags.DefineShape3Tag; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.ConditionalType; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.decompiler.flash.types.annotations.SWFVersion; @@ -33,6 +34,14 @@ import java.util.Set; public class FILLSTYLE implements NeedsCharacters, Serializable { @SWFType(BasicType.UI8) + @EnumValue(value = SOLID, text = "Solid") + @EnumValue(value = LINEAR_GRADIENT, text = "Linear gradient") + @EnumValue(value = RADIAL_GRADIENT, text = "Radial gradient") + @EnumValue(value = FOCAL_RADIAL_GRADIENT, text = "Focal radial gradient", minSwfVersion = 8) + @EnumValue(value = REPEATING_BITMAP, text = "Repeating bitmap") + @EnumValue(value = CLIPPED_BITMAP, text = "Clipped bitmap") + @EnumValue(value = NON_SMOOTHED_REPEATING_BITMAP, text = "Non smoothed repeating bitmap") + @EnumValue(value = NON_SMOOTHED_CLIPPED_BITMAP, text = "Non smoothed clipped bitmap") public int fillStyleType; public static final int SOLID = 0x0; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java index 74712b7fc..a680daeff 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/LINESTYLE2.java @@ -17,6 +17,7 @@ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.Reserved; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.Serializable; @@ -29,9 +30,15 @@ import java.util.Set; public class LINESTYLE2 extends LINESTYLE implements Serializable { @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = ROUND_CAP, text = "Round cap") + @EnumValue(value = NO_CAP, text = "No cap") + @EnumValue(value = SQUARE_CAP, text = "Square cap") public int startCapStyle; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = ROUND_JOIN, text = "Round join") + @EnumValue(value = BEVEL_JOIN, text = "Bevel join") + @EnumValue(value = MITER_JOIN, text = "Miter join") public int joinStyle; public static final int ROUND_CAP = 0; @@ -61,10 +68,13 @@ public class LINESTYLE2 extends LINESTYLE implements Serializable { public boolean noClose; @SWFType(value = BasicType.UB, count = 2) + @EnumValue(value = ROUND_CAP, text = "Round cap") + @EnumValue(value = NO_CAP, text = "No cap") + @EnumValue(value = SQUARE_CAP, text = "Square cap") public int endCapStyle; @SWFType(BasicType.FIXED8) - @Conditional(value = "joinStyle", options = MITER_JOIN) + @Conditional(value = "joinStyle", options = {MITER_JOIN}) public float miterLimitFactor; public FILLSTYLE fillType; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java index 309843a4b..3b54c80a9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/MORPHFILLSTYLE.java @@ -18,6 +18,7 @@ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.tags.base.NeedsCharacters; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.io.Serializable; import java.util.Set; @@ -29,6 +30,14 @@ import java.util.Set; public class MORPHFILLSTYLE implements NeedsCharacters, Serializable { @SWFType(BasicType.UI8) + @EnumValue(value = SOLID, text = "Solid") + @EnumValue(value = LINEAR_GRADIENT, text = "Linear gradient") + @EnumValue(value = RADIAL_GRADIENT, text = "Radial gradient") + @EnumValue(value = FOCAL_RADIAL_GRADIENT, text = "Focal radial gradient", minSwfVersion = 8) + @EnumValue(value = REPEATING_BITMAP, text = "Repeating bitmap") + @EnumValue(value = CLIPPED_BITMAP, text = "Clipped bitmap") + @EnumValue(value = NON_SMOOTHED_REPEATING_BITMAP, text = "Non smoothed repeating bitmap") + @EnumValue(value = NON_SMOOTHED_CLIPPED_BITMAP, text = "Non smoothed clipped bitmap") public int fillStyleType; public static final int SOLID = 0x0; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/Conditional.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/Conditional.java index 04bb2880a..33479585b 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/Conditional.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/Conditional.java @@ -1,18 +1,19 @@ /* * Copyright (C) 2010-2016 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.types.annotations; import java.lang.annotation.ElementType; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValue.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValue.java new file mode 100644 index 000000000..69a00fbf8 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValue.java @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010-2016 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.types.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author JPEXS + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +@Repeatable(EnumValues.class) +public @interface EnumValue { + + int value(); + + String text(); + + // todo: check in generic tag editor + int minSwfVersion() default 1; +} diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValues.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValues.java new file mode 100644 index 000000000..3b8080937 --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/types/annotations/EnumValues.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2010-2016 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.types.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * @author JPEXS + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface EnumValues { + + EnumValue[] value(); +} diff --git a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java index 863774627..53a22d829 100644 --- a/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java +++ b/src/com/jpexs/decompiler/flash/gui/GenericTagTreePanel.java @@ -22,6 +22,7 @@ import com.jpexs.decompiler.flash.gui.generictageditors.Amf3ValueEditor; import com.jpexs.decompiler.flash.gui.generictageditors.BinaryDataEditor; import com.jpexs.decompiler.flash.gui.generictageditors.BooleanEditor; import com.jpexs.decompiler.flash.gui.generictageditors.ColorEditor; +import com.jpexs.decompiler.flash.gui.generictageditors.EnumEditor; import com.jpexs.decompiler.flash.gui.generictageditors.FullSized; import com.jpexs.decompiler.flash.gui.generictageditors.GenericTagEditor; import com.jpexs.decompiler.flash.gui.generictageditors.NumberEditor; @@ -33,6 +34,8 @@ import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.annotations.Conditional; +import com.jpexs.decompiler.flash.types.annotations.EnumValue; +import com.jpexs.decompiler.flash.types.annotations.EnumValues; import com.jpexs.decompiler.flash.types.annotations.HideInRawEdit; import com.jpexs.decompiler.flash.types.annotations.Internal; import com.jpexs.decompiler.flash.types.annotations.Multiline; @@ -109,13 +112,11 @@ public class GenericTagTreePanel extends GenericTagPanel { public MyTree() { setBackground(Color.white); setUI(new BasicTreeUI() { - @Override public void paint(Graphics g, JComponent c) { setHashColor(Color.gray); super.paint(g, c); } - }); setCellRenderer(new MyTreeCellRenderer()); setCellEditor(new MyTreeCellEditor(this)); @@ -163,7 +164,15 @@ public class GenericTagTreePanel extends GenericTagPanel { GenericTagEditor editor = null; SWFType swfType = field.getAnnotation(SWFType.class); Multiline multiline = field.getAnnotation(Multiline.class); - if (type.equals(int.class) || type.equals(Integer.class) + EnumValues enumValues = field.getAnnotation(EnumValues.class); + if (enumValues != null && (type.equals(int.class) || type.equals(Integer.class))) { + Map values = new HashMap<>(); + for (EnumValue enumValue : enumValues.value()) { + values.put(enumValue.value(), enumValue.text()); + } + + editor = new EnumEditor(field.getName(), obj, field, index, type, swfType, values); + } else if (type.equals(int.class) || type.equals(Integer.class) || type.equals(short.class) || type.equals(Short.class) || type.equals(long.class) || type.equals(Long.class) || type.equals(double.class) || type.equals(Double.class) @@ -191,7 +200,6 @@ public class GenericTagTreePanel extends GenericTagPanel { fl.setAlignOnBaseline(true); pan.setLayout(fl); JLabel nameLabel = new JLabel(fnode.getNameType(i) + " = ") { - @Override public BaselineResizeBehavior getBaselineResizeBehavior() { return Component.BaselineResizeBehavior.CONSTANT_ASCENT; @@ -201,7 +209,6 @@ public class GenericTagTreePanel extends GenericTagPanel { public int getBaseline(int width, int height) { return 0; } - }; pan.setOpaque(false); nameLabel.setAlignmentY(TOP_ALIGNMENT); @@ -374,7 +381,6 @@ public class GenericTagTreePanel extends GenericTagPanel { mi = new JMenuItem(AppStrings.translate("generictag.array.insertbeginning").replace("%item%", itemStr)); mi.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { addItem(fnode.obj, fnode.fieldSet.get(FIELD_INDEX), 0, null); @@ -388,7 +394,6 @@ public class GenericTagTreePanel extends GenericTagPanel { if (fnode.index > -1) { mi = new JMenuItem(AppStrings.translate("generictag.array.insertbefore").replace("%item%", itemStr)); mi.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { addItem(fnode.obj, fnode.fieldSet.get(FIELD_INDEX), fnode.index, null); @@ -401,7 +406,6 @@ public class GenericTagTreePanel extends GenericTagPanel { mi = new JMenuItem(AppStrings.translate("generictag.array.remove").replace("%item%", itemStr)); mi.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { removeItem(fnode.obj, fnode.fieldSet.get(FIELD_INDEX), fnode.index); @@ -411,7 +415,6 @@ public class GenericTagTreePanel extends GenericTagPanel { mi = new JMenuItem(AppStrings.translate("generictag.array.insertafter").replace("%item%", itemStr)); mi.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { addItem(fnode.obj, fnode.fieldSet.get(FIELD_INDEX), fnode.index + 1, null); @@ -425,7 +428,6 @@ public class GenericTagTreePanel extends GenericTagPanel { mi = new JMenuItem(AppStrings.translate("generictag.array.insertend").replace("%item%", itemStr)); mi.addActionListener(new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { addItem(fnode.obj, fnode.fieldSet.get(FIELD_INDEX), ReflectionTools.getFieldSubSize(fnode.obj, fnode.fieldSet.get(FIELD_INDEX)), null); @@ -558,12 +560,23 @@ public class GenericTagTreePanel extends GenericTagPanel { colorAdd = "\u25cf "; } + EnumValues enumValues = field.getAnnotation(EnumValues.class); + String enumAdd = ""; + if (enumValues != null && val instanceof Integer) { + Map values = new HashMap<>(); + for (EnumValue enumValue : enumValues.value()) { + values.put(enumValue.value(), enumValue.text()); + } + + enumAdd = " - " + values.get(val); + } + if (val instanceof byte[]) { valStr += " = " + ((byte[]) val).length + " byte"; } else if (val instanceof ByteArrayRange) { valStr += " = " + ((ByteArrayRange) val).getLength() + " byte"; } else { - valStr += " = " + colorAdd + val.toString(); + valStr += " = " + colorAdd + val.toString() + enumAdd; } } return getNameType(fieldIndex) + valStr; diff --git a/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java b/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java new file mode 100644 index 000000000..77d606399 --- /dev/null +++ b/src/com/jpexs/decompiler/flash/gui/generictageditors/EnumEditor.java @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2010-2016 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.generictageditors; + +import com.jpexs.decompiler.flash.gui.ComboBoxItem; +import com.jpexs.decompiler.flash.types.BasicType; +import com.jpexs.decompiler.flash.types.annotations.SWFType; +import com.jpexs.helpers.ReflectionTools; +import java.awt.Component; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.Map; +import javax.swing.JComboBox; +import javax.swing.SpinnerModel; +import javax.swing.SpinnerNumberModel; + +/** + * + * @author JPEXS + */ +public class EnumEditor extends JComboBox> implements GenericTagEditor { + + private final Object obj; + + private final Field field; + + private final int index; + + private final Class type; + + private final SWFType swfType; + + private String fieldName; + + private Map values; + + @Override + public BaselineResizeBehavior getBaselineResizeBehavior() { + return Component.BaselineResizeBehavior.CONSTANT_ASCENT; + } + + @Override + public int getBaseline(int width, int height) { + return 0; + } + + @Override + public void added() { + + } + + public EnumEditor(String fieldName, Object obj, Field field, int index, Class type, SWFType swfType, Map values) { + setSize(100, getSize().height); + setMaximumSize(getSize()); + this.obj = obj; + this.field = field; + this.index = index; + this.type = type; + this.swfType = swfType; + this.fieldName = fieldName; + this.values = values; + + Integer[] valuesArray = new Integer[values.size()]; + values.keySet().toArray(valuesArray); + Arrays.sort(valuesArray); + for (int value : valuesArray) { + addItem(new ComboBoxItem<>(value + " - " + values.get(value), value)); + } + + reset(); + } + + @Override + public void reset() { + try { + int value = (int) (Integer) ReflectionTools.getValue(obj, field, index); + setSelectedItem(values.get(value)); + } catch (IllegalArgumentException | IllegalAccessException ex) { + // ignore + } + } + + @Override + public void save() { + try { + Object value = getChangedValue(); + if (value != null) { + ReflectionTools.setValue(obj, field, index, value); + } + } catch (IllegalArgumentException | IllegalAccessException ex) { + // ignore + } + } + + private SpinnerModel getModel(SWFType swfType, Object value) { + SpinnerNumberModel m = null; + BasicType basicType = swfType == null ? BasicType.NONE : swfType.value(); + switch (basicType) { + case UI8: + m = new SpinnerNumberModel(toInt(value), 0, 0xff, 1); + break; + case UI16: + m = new SpinnerNumberModel(toInt(value), 0, 0xffff, 1); + break; + case UB: { + long max = 1; + if (swfType.count() > 0) { + max <<= swfType.count(); + } else { + max <<= 31; + } + m = new SpinnerNumberModel((Number) toLong(value), 0L, (long) max - 1, 1L); + } + break; + case UI32: + case EncodedU32: + case NONE: + m = new SpinnerNumberModel((Number) toLong(value), 0L, 0xffffffffL, 1L); + break; + case SI8: + m = new SpinnerNumberModel(toInt(value), -0x80, 0x7f, 1); + break; + case SI16: + case FLOAT16: + m = new SpinnerNumberModel(toInt(value), -0x8000, 0x7fff, 1); + break; + case FB: + case SB: { + long max = 1; + if (swfType.count() > 0) { + max <<= (swfType.count() - 1); + } else { + max <<= 30; + } + m = new SpinnerNumberModel((Number) toLong(value), (long) (-max), (long) max - 1, 1L); + } + break; + case SI32: + m = new SpinnerNumberModel(toDouble(value), -0x80000000, 0x7fffffff, 1); + break; + case FLOAT: + case FIXED: + case FIXED8: + m = new SpinnerNumberModel(toDouble(value), -0x80000000, 0x7fffffff, 0.01); + break; + } + return m; + } + + private double toDouble(Object value) { + if (value instanceof Float) { + return (double) (Float) value; + } + if (value instanceof Double) { + return (double) (Double) value; + } + return 0; + } + + private int toInt(Object value) { + if (value instanceof Short) { + return (int) (Short) value; + } + if (value instanceof Integer) { + return (int) (Integer) value; + } + return 0; + } + + private long toLong(Object value) { + if (value instanceof Short) { + return (long) (Short) value; + } + if (value instanceof Integer) { + return (long) (Integer) value; + } + if (value instanceof Long) { + return (long) (Long) value; + } + return 0; + } + + @Override + public void addChangeListener(final ChangeListener l) { + final GenericTagEditor t = this; + addFocusListener(new FocusAdapter() { + @Override + public void focusLost(FocusEvent e) { + l.change(t); + } + }); + } + + @Override + public void validateValue() { + } + + @Override + public Object getChangedValue() { + ComboBoxItem item = (ComboBoxItem) getSelectedItem(); + int value = item.getValue(); + return value; + } + + @Override + public String getFieldName() { + return fieldName; + } + + @Override + public Field getField() { + return field; + } + + @Override + public String getReadOnlyValue() { + return getChangedValue().toString(); + } +}