From d9a44511e00a1bea37b5f868da9fb965927247dd Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Sun, 25 Jun 2023 18:24:16 +0200 Subject: [PATCH 01/28] Preferences dialog: Link Syntax Highlighting with Color Scheme Selected state of "Syntax Highlighting" controls enabled state of associated "Color Scheme". --- src/org/infinity/gui/PreferencesDialog.java | 96 ++++++++++++++++++- .../infinity/gui/options/OptionCheckBox.java | 12 +-- .../gui/options/OptionElementBase.java | 44 ++++++++- .../infinity/gui/options/OptionGroupBox.java | 17 ++-- 4 files changed, 147 insertions(+), 22 deletions(-) diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java index eaba73182..b2c801d78 100644 --- a/src/org/infinity/gui/PreferencesDialog.java +++ b/src/org/infinity/gui/PreferencesDialog.java @@ -255,7 +255,8 @@ public String toString() { 0, OptionsMenuItem.getBcsColorSchemes().toArray(new OptionsMenuItem.ColorScheme[0]), AppOption.BCS_COLOR_SCHEME), OptionCheckBox.create(AppOption.BCS_SYNTAX_HIGHLIGHTING.getName(), AppOption.BCS_SYNTAX_HIGHLIGHTING.getLabel(), - "Enables syntax highlighting for BCS script sources.", AppOption.BCS_SYNTAX_HIGHLIGHTING), + "Enables syntax highlighting for BCS script sources.", AppOption.BCS_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::bcsSyntaxHighlightingOnCreated).setOnAction(this::bcsSyntaxHighlightingOnAction), OptionCheckBox.create(AppOption.BCS_CODE_FOLDING.getName(), AppOption.BCS_CODE_FOLDING.getLabel(), "Enables code folding for BCS script sources.", AppOption.BCS_CODE_FOLDING), OptionCheckBox.create(AppOption.BCS_AUTO_INDENT.getName(), AppOption.BCS_AUTO_INDENT.getLabel(), @@ -277,7 +278,8 @@ public String toString() { 0, OptionsMenuItem.getColorSchemes().toArray(new OptionsMenuItem.ColorScheme[0]), AppOption.GLSL_COLOR_SCHEME), OptionCheckBox.create(AppOption.GLSL_SYNTAX_HIGHLIGHTING.getName(), AppOption.GLSL_SYNTAX_HIGHLIGHTING.getLabel(), - "Enables syntax highlighting for GLSL resources.", AppOption.GLSL_SYNTAX_HIGHLIGHTING), + "Enables syntax highlighting for GLSL resources.", AppOption.GLSL_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::glslSyntaxHighlightingOnCreated).setOnAction(this::glslSyntaxHighlightingOnAction), OptionCheckBox.create(AppOption.GLSL_CODE_FOLDING.getName(), AppOption.GLSL_CODE_FOLDING.getLabel(), "Enables code folding for GLSL resources.", AppOption.GLSL_CODE_FOLDING) ), @@ -295,6 +297,7 @@ public String toString() { AppOption.INI_COLOR_SCHEME), OptionCheckBox.create(AppOption.INI_SYNTAX_HIGHLIGHTING.getName(), AppOption.INI_SYNTAX_HIGHLIGHTING.getLabel(), "Enables syntax highlighting for INI resources.", AppOption.INI_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::iniSyntaxHighlightingOnCreated).setOnAction(this::iniSyntaxHighlightingOnAction) ), OptionGroup.create("LUA", OptionGroupBox.create(AppOption.LUA_COLOR_SCHEME.getName(), AppOption.LUA_COLOR_SCHEME.getLabel(), @@ -310,6 +313,7 @@ public String toString() { AppOption.LUA_COLOR_SCHEME), OptionCheckBox.create(AppOption.LUA_SYNTAX_HIGHLIGHTING.getName(), AppOption.LUA_SYNTAX_HIGHLIGHTING.getLabel(), "Enables syntax highlighting for LUA resources.", AppOption.LUA_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::luaSyntaxHighlightingOnCreated).setOnAction(this::luaSyntaxHighlightingOnAction) ), OptionGroup.create("SQL", OptionGroupBox.create(AppOption.SQL_COLOR_SCHEME.getName(), AppOption.SQL_COLOR_SCHEME.getLabel(), @@ -325,6 +329,7 @@ public String toString() { AppOption.SQL_COLOR_SCHEME), OptionCheckBox.create(AppOption.SQL_SYNTAX_HIGHLIGHTING.getName(), AppOption.SQL_SYNTAX_HIGHLIGHTING.getLabel(), "Enables syntax highlighting for SQL resources.", AppOption.SQL_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::sqlSyntaxHighlightingOnCreated).setOnAction(this::sqlSyntaxHighlightingOnAction) ), OptionGroup.create("Dialog.tlk", OptionGroupBox.create(AppOption.TLK_COLOR_SCHEME.getName(), AppOption.TLK_COLOR_SCHEME.getLabel(), @@ -340,6 +345,7 @@ public String toString() { AppOption.TLK_COLOR_SCHEME), OptionCheckBox.create(AppOption.TLK_SYNTAX_HIGHLIGHTING.getName(), AppOption.TLK_SYNTAX_HIGHLIGHTING.getLabel(), "Enables syntax highlighting for Dialog.tlk strings.", AppOption.TLK_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::tlkSyntaxHighlightingOnCreated).setOnAction(this::tlkSyntaxHighlightingOnAction) ), OptionGroup.create("WeiDU.log", OptionGroupBox.create(AppOption.WEIDU_COLOR_SCHEME.getName(), AppOption.WEIDU_COLOR_SCHEME.getLabel(), @@ -355,6 +361,7 @@ public String toString() { AppOption.WEIDU_COLOR_SCHEME), OptionCheckBox.create(AppOption.WEIDU_SYNTAX_HIGHLIGHTING.getName(), AppOption.WEIDU_SYNTAX_HIGHLIGHTING.getLabel(), "Enables syntax highlighting for WeiDU.log content.", AppOption.WEIDU_SYNTAX_HIGHLIGHTING) + .setOnCreated(this::weiduSyntaxHighlightingOnCreated).setOnAction(this::weiduSyntaxHighlightingOnAction) ) ), OptionGroup.createDefault( @@ -1158,6 +1165,91 @@ private void launchGameAllowedOnCreated(OptionCheckBox cb) { cb.setEnabled(BrowserMenuBar.getInstance().getOptions().isLaunchGameMenuEnabled()); } + /** onCreated() function for {@link AppOption#BCS_SYNTAX_HIGHLIGHTING}. */ + private void bcsSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.BCS_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#BCS_SYNTAX_HIGHLIGHTING}. */ + private boolean bcsSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.BCS_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#GLSL_SYNTAX_HIGHLIGHTING}. */ + private void glslSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.GLSL_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#GLSL_SYNTAX_HIGHLIGHTING}. */ + private boolean glslSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.GLSL_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#INI_SYNTAX_HIGHLIGHTING}. */ + private void iniSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.INI_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#INI_SYNTAX_HIGHLIGHTING}. */ + private boolean iniSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.INI_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#LUA_SYNTAX_HIGHLIGHTING}. */ + private void luaSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.LUA_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#LUA_SYNTAX_HIGHLIGHTING}. */ + private boolean luaSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.LUA_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#SQL_SYNTAX_HIGHLIGHTING}. */ + private void sqlSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.SQL_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#SQL_SYNTAX_HIGHLIGHTING}. */ + private boolean sqlSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.SQL_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#TLK_SYNTAX_HIGHLIGHTING}. */ + private void tlkSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.TLK_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#TLK_SYNTAX_HIGHLIGHTING}. */ + private boolean tlkSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.TLK_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** onCreated() function for {@link AppOption#WEIDU_SYNTAX_HIGHLIGHTING}. */ + private void weiduSyntaxHighlightingOnCreated(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.WEIDU_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + } + + /** onAction() function for {@link AppOption#WEIDU_SYNTAX_HIGHLIGHTING}. */ + private boolean weiduSyntaxHighlightingOnAction(OptionCheckBox cb) { + setOptionUiEnabled(AppOption.WEIDU_COLOR_SCHEME.getName(), cb.getUiCheckBox().isSelected()); + return true; + } + + /** Helper method for setting the enabled state of a given option component. */ + private void setOptionUiEnabled(String optionName, boolean enable) { + OptionBase option = optionRoot.findOption(optionName); + if (option instanceof OptionElementBase) { + ((OptionElementBase) option).setEnabled(enable); + } + } + /** onInit() function for {@link AppOption#TEXT_TAB_SIZE}. */ private void textTabSizeOnInit(OptionGroupBox gb) { final String[] items = { "Expand by 2 Spaces", "Expand by 4 Spaces", "Expand by 8 Spaces" }; diff --git a/src/org/infinity/gui/options/OptionCheckBox.java b/src/org/infinity/gui/options/OptionCheckBox.java index dee582eeb..e3ac2524f 100644 --- a/src/org/infinity/gui/options/OptionCheckBox.java +++ b/src/org/infinity/gui/options/OptionCheckBox.java @@ -66,14 +66,6 @@ public OptionCheckBox setValue(boolean value) { return this; } - @Override - protected OptionCheckBox setUiEnabled(boolean enable) { - if (checkBox != null) { - checkBox.setEnabled(enable); - } - return this; - } - /** * Returns the function that will be executed right before the UI elements for the option are created. */ @@ -154,6 +146,8 @@ public OptionCheckBox updateUi() { checkBox.setText(getLabel()); checkBox.setSelected(getValue()); checkBox.setEnabled(isEnabled()); + addUiComponent(checkBox); + return this; } @@ -164,7 +158,9 @@ public JCheckBox getUiCheckBox() { /** Sets the {@code JCheckBox} component of the OptionCheckBox UI. */ public OptionCheckBox setUiCheckBox(JCheckBox checkBox) { + removeUiComponent(this.checkBox); this.checkBox = checkBox; + addUiComponent(this.checkBox); return this; } diff --git a/src/org/infinity/gui/options/OptionElementBase.java b/src/org/infinity/gui/options/OptionElementBase.java index 10c8dc994..946d77969 100644 --- a/src/org/infinity/gui/options/OptionElementBase.java +++ b/src/org/infinity/gui/options/OptionElementBase.java @@ -4,6 +4,7 @@ package org.infinity.gui.options; +import java.awt.Component; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -20,6 +21,7 @@ */ public abstract class OptionElementBase extends OptionBase { private final List secondaryOptions = new ArrayList<>(); + private final List uiComponents = new ArrayList<>(); private final AppOption option; private String description; @@ -71,7 +73,10 @@ public OptionElementBase setEnabled(boolean enable) { /** * Sets the enabled state of the associated UI elements. The method is used internally by {@link #setEnabled(boolean)}. */ - protected abstract OptionElementBase setUiEnabled(boolean enable); + protected OptionElementBase setUiEnabled(boolean enable) { + uiComponents.forEach(c -> c.setEnabled(enable)); + return this; + } @Override public OptionGroup getParent() { @@ -88,6 +93,43 @@ protected OptionBase setParent(OptionBase parent) { } } + /** Returns a list of all UI {@link Component} instances associated with the Option. */ + public List getUiComponents() { + return Collections.unmodifiableList(uiComponents); + } + + /** Returns the number of available UI {@link Component} instances associated with the Option. */ + public int getUiComponentCount() { + return uiComponents.size(); + } + + /** Returns the {@link Component} at the specified index. */ + public Component getUiComponent(int index) throws IndexOutOfBoundsException { + return uiComponents.get(index); + } + + /** Adds a new {@link Component} to the list of associated UI components. */ + protected OptionElementBase addUiComponent(Component comp) throws NullPointerException { + if (comp != null) { + uiComponents.add(comp); + } + return this; + } + + /** Removes the UI {@link Component} at the specified index from the list of UI components. */ + protected OptionElementBase removeUiComponent(int index) throws IndexOutOfBoundsException { + uiComponents.remove(index); + return this; + } + + /** Removes the specified UI {@link Component} from the list of UI components. */ + protected OptionElementBase removeUiComponent(Component comp) { + if (comp != null) { + uiComponents.remove(comp); + } + return this; + } + /** * This method is called right before the associated UI elements are initialized and can therefore be used * to update option properties. diff --git a/src/org/infinity/gui/options/OptionGroupBox.java b/src/org/infinity/gui/options/OptionGroupBox.java index 3e0ced9a0..c769f26b2 100644 --- a/src/org/infinity/gui/options/OptionGroupBox.java +++ b/src/org/infinity/gui/options/OptionGroupBox.java @@ -160,17 +160,6 @@ public OptionGroupBox setSelectedDesc(String desc) { return this; } - @Override - protected OptionGroupBox setUiEnabled(boolean enable) { - if (label != null) { - label.setEnabled(enable); - } - if (comboBox != null) { - comboBox.setEnabled(enable); - } - return this; - } - /** * Returns the function that will be executed right before the UI elements for the option are created. */ @@ -250,6 +239,7 @@ public OptionGroupBox updateUi() { } label.setText(getLabel() + ":"); label.setEnabled(isEnabled()); + addUiComponent(label); if (comboBox == null) { comboBox = new JComboBox<>(); @@ -259,6 +249,7 @@ public OptionGroupBox updateUi() { int newIndex = Math.max(-1, Math.min(items.size() - 1, index)); comboBox.setSelectedIndex(newIndex); comboBox.setEnabled(isEnabled()); + addUiComponent(comboBox); return this; } @@ -270,7 +261,9 @@ public JLabel getUiLabel() { /** Sets the {@code JLabel} component of the OptionGroupBox UI. */ public OptionGroupBox setUiLabel(JLabel label) { + removeUiComponent(this.label); this.label = label; + addUiComponent(this.label); return this; } @@ -281,7 +274,9 @@ public JComboBox getUiComboBox() { /** Sets the {@code JComboBox} component of the OptionGroupBox UI. */ public OptionGroupBox setUiComboBox(JComboBox comboBox) { + removeUiComponent(this.comboBox); this.comboBox = comboBox; + addUiComponent(this.comboBox); return this; } From a728a2d91499f36b2b958235ed30cfd838e5bdbb Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:01:42 +0200 Subject: [PATCH 02/28] Update various opcode labels --- .../infinity/resource/effects/Opcode020.java | 13 ++++++++++++- .../infinity/resource/effects/Opcode053.java | 17 ++++++++++++++++- .../infinity/resource/effects/Opcode110.java | 10 +++++++++- .../infinity/resource/effects/Opcode113.java | 13 +------------ .../infinity/resource/effects/Opcode114.java | 8 +------- .../infinity/resource/effects/Opcode121.java | 13 +------------ .../infinity/resource/effects/Opcode172.java | 15 ++++++++++++++- .../infinity/resource/effects/Opcode207.java | 7 +++++-- .../infinity/resource/effects/Opcode209.java | 17 ++--------------- .../infinity/resource/effects/Opcode211.java | 17 ++--------------- .../infinity/resource/effects/Opcode212.java | 9 ++------- .../infinity/resource/effects/Opcode213.java | 7 +++++-- .../infinity/resource/effects/Opcode214.java | 11 +++++++---- .../infinity/resource/effects/Opcode215.java | 7 +++++-- .../infinity/resource/effects/Opcode216.java | 7 +++++-- .../infinity/resource/effects/Opcode217.java | 9 ++------- .../infinity/resource/effects/Opcode219.java | 9 +++++++-- .../infinity/resource/effects/Opcode220.java | 8 ++++++-- .../infinity/resource/effects/Opcode221.java | 8 ++++++-- .../infinity/resource/effects/Opcode222.java | 7 +++++-- .../infinity/resource/effects/Opcode223.java | 8 ++++++-- .../infinity/resource/effects/Opcode224.java | 9 ++------- .../infinity/resource/effects/Opcode225.java | 9 ++------- .../infinity/resource/effects/Opcode226.java | 8 ++++++-- .../infinity/resource/effects/Opcode227.java | 8 ++++++-- .../infinity/resource/effects/Opcode228.java | 8 ++++++-- .../infinity/resource/effects/Opcode229.java | 8 ++++++-- .../infinity/resource/effects/Opcode230.java | 8 ++++++-- .../infinity/resource/effects/Opcode231.java | 9 ++------- 29 files changed, 155 insertions(+), 132 deletions(-) diff --git a/src/org/infinity/resource/effects/Opcode020.java b/src/org/infinity/resource/effects/Opcode020.java index 5a52ae952..ae672141e 100644 --- a/src/org/infinity/resource/effects/Opcode020.java +++ b/src/org/infinity/resource/effects/Opcode020.java @@ -11,6 +11,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.resource.AbstractStruct; +import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; /** @@ -23,7 +24,11 @@ public class Opcode020 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { - return "Invisibility"; + if (Profile.getEngine() == Profile.Engine.IWD2) { + return null; + } else { + return "Invisibility"; + } } public Opcode020() { @@ -51,4 +56,10 @@ protected String makeEffectParamsPST(Datatype parent, ByteBuffer buffer, int off boolean isVersion1) { return makeEffectParamsBG1(parent, buffer, offset, list, isVersion1); } + + @Override + protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, + boolean isVersion1) { + return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + } } diff --git a/src/org/infinity/resource/effects/Opcode053.java b/src/org/infinity/resource/effects/Opcode053.java index e996124f2..26eed19b8 100644 --- a/src/org/infinity/resource/effects/Opcode053.java +++ b/src/org/infinity/resource/effects/Opcode053.java @@ -10,6 +10,9 @@ import org.infinity.datatype.AnimateBitmap; import org.infinity.datatype.Bitmap; import org.infinity.datatype.Datatype; +import org.infinity.datatype.DecNumber; +import org.infinity.resource.AbstractStruct; +import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; /** @@ -23,7 +26,11 @@ public class Opcode053 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { - return "Animation change"; + if (Profile.getEngine() == Profile.Engine.IWD) { + return AbstractStruct.COMMON_UNUSED; + } else { + return "Animation change"; + } } public Opcode053() { @@ -37,4 +44,12 @@ protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int list.add(new Bitmap(buffer, offset + 4, 4, EFFECT_MORPH_TYPE, TYPES)); return null; } + + @Override + protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, + boolean isVersion1) { + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; + } } diff --git a/src/org/infinity/resource/effects/Opcode110.java b/src/org/infinity/resource/effects/Opcode110.java index 6c74b9df8..fc1ed7338 100644 --- a/src/org/infinity/resource/effects/Opcode110.java +++ b/src/org/infinity/resource/effects/Opcode110.java @@ -26,7 +26,7 @@ private static String getOpcodeName() { case PST: return "Retreat from"; default: - return null; + return AbstractStruct.COMMON_UNUSED; } } @@ -34,6 +34,14 @@ public Opcode110() { super(110, getOpcodeName()); } + @Override + protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int offset, List list, + boolean isVersion1) { + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; + } + @Override protected String makeEffectParamsPST(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { diff --git a/src/org/infinity/resource/effects/Opcode113.java b/src/org/infinity/resource/effects/Opcode113.java index 408dfb644..a68070a51 100644 --- a/src/org/infinity/resource/effects/Opcode113.java +++ b/src/org/infinity/resource/effects/Opcode113.java @@ -10,7 +10,6 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.resource.AbstractStruct; -import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; /** @@ -19,11 +18,7 @@ public class Opcode113 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { - if (Profile.getEngine() == Profile.Engine.IWD) { - return null; - } else { - return "Equip weapon"; - } + return AbstractStruct.COMMON_UNUSED; } public Opcode113() { @@ -37,10 +32,4 @@ protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); return null; } - - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } } diff --git a/src/org/infinity/resource/effects/Opcode114.java b/src/org/infinity/resource/effects/Opcode114.java index 1fed530cc..e21ac3b3e 100644 --- a/src/org/infinity/resource/effects/Opcode114.java +++ b/src/org/infinity/resource/effects/Opcode114.java @@ -20,7 +20,7 @@ public class Opcode114 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { if (Profile.getEngine() == Profile.Engine.IWD) { - return null; + return AbstractStruct.COMMON_UNUSED; } else { return "Dither"; } @@ -37,10 +37,4 @@ protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); return null; } - - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } } diff --git a/src/org/infinity/resource/effects/Opcode121.java b/src/org/infinity/resource/effects/Opcode121.java index f129bdae3..4833e5fdb 100644 --- a/src/org/infinity/resource/effects/Opcode121.java +++ b/src/org/infinity/resource/effects/Opcode121.java @@ -10,7 +10,6 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.resource.AbstractStruct; -import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; /** @@ -19,11 +18,7 @@ public class Opcode121 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { - if (Profile.getEngine() == Profile.Engine.IWD) { - return null; - } else { - return "Visual animation effect"; - } + return AbstractStruct.COMMON_UNUSED; } public Opcode121() { @@ -37,10 +32,4 @@ protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); return null; } - - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } } diff --git a/src/org/infinity/resource/effects/Opcode172.java b/src/org/infinity/resource/effects/Opcode172.java index cf1c57183..6e54dbe0e 100644 --- a/src/org/infinity/resource/effects/Opcode172.java +++ b/src/org/infinity/resource/effects/Opcode172.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.resource.AbstractStruct; +import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; /** @@ -20,7 +21,11 @@ public class Opcode172 extends BaseOpcode { /** Returns the opcode name for the current game variant. */ private static String getOpcodeName() { - return "Remove spell"; + if (Profile.getEngine() == Profile.Engine.IWD) { + return AbstractStruct.COMMON_UNUSED; + } else { + return "Remove spell"; + } } public Opcode172() { @@ -34,4 +39,12 @@ protected String makeEffectParamsGeneric(Datatype parent, ByteBuffer buffer, int list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); return RES_TYPE; } + + @Override + protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, + boolean isVersion1) { + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; + } } diff --git a/src/org/infinity/resource/effects/Opcode207.java b/src/org/infinity/resource/effects/Opcode207.java index aafb4c37f..593979c11 100644 --- a/src/org/infinity/resource/effects/Opcode207.java +++ b/src/org/infinity/resource/effects/Opcode207.java @@ -26,9 +26,10 @@ public class Opcode207 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; case PST: return "Stop all actions"; default: @@ -57,7 +58,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode209.java b/src/org/infinity/resource/effects/Opcode209.java index e4d2b4e09..c4fd1c010 100644 --- a/src/org/infinity/resource/effects/Opcode209.java +++ b/src/org/infinity/resource/effects/Opcode209.java @@ -21,9 +21,10 @@ public class Opcode209 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; case PST: return "Soul exodus"; default: @@ -49,23 +50,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - - @Override - protected String makeEffectParamsPST(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); - list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); - return null; - } } diff --git a/src/org/infinity/resource/effects/Opcode211.java b/src/org/infinity/resource/effects/Opcode211.java index 92fd09a19..36c571cf7 100644 --- a/src/org/infinity/resource/effects/Opcode211.java +++ b/src/org/infinity/resource/effects/Opcode211.java @@ -21,9 +21,10 @@ public class Opcode211 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; case PST: return "Induce hiccups"; default: @@ -49,23 +50,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - - @Override - protected String makeEffectParamsPST(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); - list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); - return null; - } } diff --git a/src/org/infinity/resource/effects/Opcode212.java b/src/org/infinity/resource/effects/Opcode212.java index e8e7813d2..58d016959 100644 --- a/src/org/infinity/resource/effects/Opcode212.java +++ b/src/org/infinity/resource/effects/Opcode212.java @@ -21,9 +21,10 @@ public class Opcode212 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; case PST: return "Speak with dead"; default: @@ -49,12 +50,6 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { diff --git a/src/org/infinity/resource/effects/Opcode213.java b/src/org/infinity/resource/effects/Opcode213.java index 4a90cc72b..b4722210b 100644 --- a/src/org/infinity/resource/effects/Opcode213.java +++ b/src/org/infinity/resource/effects/Opcode213.java @@ -24,10 +24,11 @@ public class Opcode213 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Maze"; } @@ -54,7 +55,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode214.java b/src/org/infinity/resource/effects/Opcode214.java index 7340b6dcf..11bf9e96d 100644 --- a/src/org/infinity/resource/effects/Opcode214.java +++ b/src/org/infinity/resource/effects/Opcode214.java @@ -30,10 +30,11 @@ public class Opcode214 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: - case IWD2: case PST: return null; + case IWD: + case IWD2: + return AbstractStruct.COMMON_UNUSED; default: return "Select spell"; } @@ -68,13 +69,15 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + return makeEffectParamsIWD(parent, buffer, offset, list, isVersion1); } @Override diff --git a/src/org/infinity/resource/effects/Opcode215.java b/src/org/infinity/resource/effects/Opcode215.java index b1a9e3760..0dc3e76e2 100644 --- a/src/org/infinity/resource/effects/Opcode215.java +++ b/src/org/infinity/resource/effects/Opcode215.java @@ -29,10 +29,11 @@ public class Opcode215 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Play visual effect"; } @@ -59,7 +60,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode216.java b/src/org/infinity/resource/effects/Opcode216.java index 33382e973..dcbb133be 100644 --- a/src/org/infinity/resource/effects/Opcode216.java +++ b/src/org/infinity/resource/effects/Opcode216.java @@ -23,10 +23,11 @@ public class Opcode216 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Level drain"; } @@ -53,7 +54,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode217.java b/src/org/infinity/resource/effects/Opcode217.java index 54ceada8f..0002c780b 100644 --- a/src/org/infinity/resource/effects/Opcode217.java +++ b/src/org/infinity/resource/effects/Opcode217.java @@ -21,10 +21,11 @@ public class Opcode217 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Power word, sleep"; } @@ -48,12 +49,6 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { diff --git a/src/org/infinity/resource/effects/Opcode219.java b/src/org/infinity/resource/effects/Opcode219.java index 3709669aa..38706f0bb 100644 --- a/src/org/infinity/resource/effects/Opcode219.java +++ b/src/org/infinity/resource/effects/Opcode219.java @@ -9,7 +9,9 @@ import java.util.List; import org.infinity.datatype.Datatype; +import org.infinity.datatype.DecNumber; import org.infinity.datatype.IdsTargetType; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -25,10 +27,11 @@ public class Opcode219 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Attack and Saving Throw roll penalty"; } @@ -66,7 +69,9 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode220.java b/src/org/infinity/resource/effects/Opcode220.java index b14588447..e88e18a98 100644 --- a/src/org/infinity/resource/effects/Opcode220.java +++ b/src/org/infinity/resource/effects/Opcode220.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.PriTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -24,10 +25,11 @@ public class Opcode220 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Remove spell school protections"; } @@ -54,7 +56,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode221.java b/src/org/infinity/resource/effects/Opcode221.java index f8391f2f0..32b71b7ba 100644 --- a/src/org/infinity/resource/effects/Opcode221.java +++ b/src/org/infinity/resource/effects/Opcode221.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.SecTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -24,10 +25,11 @@ public class Opcode221 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Remove spell type protections"; } @@ -54,7 +56,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode222.java b/src/org/infinity/resource/effects/Opcode222.java index 5b8a94dc7..419f37384 100644 --- a/src/org/infinity/resource/effects/Opcode222.java +++ b/src/org/infinity/resource/effects/Opcode222.java @@ -23,10 +23,11 @@ public class Opcode222 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Teleport field"; } @@ -53,7 +54,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode223.java b/src/org/infinity/resource/effects/Opcode223.java index c28562f0d..740d96960 100644 --- a/src/org/infinity/resource/effects/Opcode223.java +++ b/src/org/infinity/resource/effects/Opcode223.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.PriTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -26,10 +27,11 @@ public class Opcode223 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Spell school deflection"; } @@ -64,7 +66,9 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode224.java b/src/org/infinity/resource/effects/Opcode224.java index 9d9f0dd51..e4aade971 100644 --- a/src/org/infinity/resource/effects/Opcode224.java +++ b/src/org/infinity/resource/effects/Opcode224.java @@ -21,10 +21,11 @@ public class Opcode224 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Restoration"; } @@ -48,12 +49,6 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { diff --git a/src/org/infinity/resource/effects/Opcode225.java b/src/org/infinity/resource/effects/Opcode225.java index 79abac63d..68fb22c15 100644 --- a/src/org/infinity/resource/effects/Opcode225.java +++ b/src/org/infinity/resource/effects/Opcode225.java @@ -21,10 +21,11 @@ public class Opcode225 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Detect magic"; } @@ -48,12 +49,6 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { diff --git a/src/org/infinity/resource/effects/Opcode226.java b/src/org/infinity/resource/effects/Opcode226.java index 84d94018c..e5f52f9f0 100644 --- a/src/org/infinity/resource/effects/Opcode226.java +++ b/src/org/infinity/resource/effects/Opcode226.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.SecTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -26,10 +27,11 @@ public class Opcode226 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Spell type deflection"; } @@ -64,7 +66,9 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode227.java b/src/org/infinity/resource/effects/Opcode227.java index af9b5e6b5..a52a233da 100644 --- a/src/org/infinity/resource/effects/Opcode227.java +++ b/src/org/infinity/resource/effects/Opcode227.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.PriTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -26,10 +27,11 @@ public class Opcode227 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Spell school turning"; } @@ -64,7 +66,9 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode228.java b/src/org/infinity/resource/effects/Opcode228.java index 80442f042..d3e56d32d 100644 --- a/src/org/infinity/resource/effects/Opcode228.java +++ b/src/org/infinity/resource/effects/Opcode228.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.SecTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -26,10 +27,11 @@ public class Opcode228 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Spell type turning"; } @@ -64,7 +66,9 @@ protected String makeEffectParamsEE(Datatype parent, ByteBuffer buffer, int offs @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode229.java b/src/org/infinity/resource/effects/Opcode229.java index 041fadf22..dbd1fc993 100644 --- a/src/org/infinity/resource/effects/Opcode229.java +++ b/src/org/infinity/resource/effects/Opcode229.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.PriTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -24,10 +25,11 @@ public class Opcode229 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Remove protection by school"; } @@ -54,7 +56,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode230.java b/src/org/infinity/resource/effects/Opcode230.java index 34a37de44..a9a7cc708 100644 --- a/src/org/infinity/resource/effects/Opcode230.java +++ b/src/org/infinity/resource/effects/Opcode230.java @@ -10,6 +10,7 @@ import org.infinity.datatype.Datatype; import org.infinity.datatype.DecNumber; import org.infinity.datatype.SecTypeBitmap; +import org.infinity.resource.AbstractStruct; import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; @@ -24,10 +25,11 @@ public class Opcode230 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Remove protection by type"; } @@ -54,7 +56,9 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off @Override protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); + list.add(new DecNumber(buffer, offset, 4, AbstractStruct.COMMON_UNUSED)); + list.add(new DecNumber(buffer, offset + 4, 4, AbstractStruct.COMMON_UNUSED)); + return null; } @Override diff --git a/src/org/infinity/resource/effects/Opcode231.java b/src/org/infinity/resource/effects/Opcode231.java index 73759cceb..d3918d475 100644 --- a/src/org/infinity/resource/effects/Opcode231.java +++ b/src/org/infinity/resource/effects/Opcode231.java @@ -21,10 +21,11 @@ public class Opcode231 extends BaseOpcode { private static String getOpcodeName() { switch (Profile.getEngine()) { case BG1: - case IWD: case IWD2: case PST: return null; + case IWD: + return AbstractStruct.COMMON_UNUSED; default: return "Time stop"; } @@ -48,12 +49,6 @@ protected String makeEffectParamsBG1(Datatype parent, ByteBuffer buffer, int off return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); } - @Override - protected String makeEffectParamsIWD(Datatype parent, ByteBuffer buffer, int offset, List list, - boolean isVersion1) { - return super.makeEffectParamsGeneric(parent, buffer, offset, list, isVersion1); - } - @Override protected String makeEffectParamsIWD2(Datatype parent, ByteBuffer buffer, int offset, List list, boolean isVersion1) { From 14cc301253be938b66792a2ebfea8318a1db7cbb Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Mon, 3 Jul 2023 13:42:41 +0200 Subject: [PATCH 03/28] Area Viewer: Add new sublayers for regions, doors and containers to visualize launch points Different types of launch points are labeled with letters. --- .../resource/are/viewer/AreaViewer.java | 260 +++++++++++++++--- .../resource/are/viewer/BasicTargetLayer.java | 68 +++++ .../resource/are/viewer/LayerActor.java | 67 +++-- .../resource/are/viewer/LayerAmbient.java | 8 +- .../resource/are/viewer/LayerAnimation.java | 60 ++-- .../resource/are/viewer/LayerContainer.java | 5 +- .../resource/are/viewer/LayerDoor.java | 24 +- .../resource/are/viewer/LayerDoorPoly.java | 4 +- .../resource/are/viewer/LayerManager.java | 20 +- .../resource/are/viewer/LayerObject.java | 12 +- .../resource/are/viewer/LayerObjectActor.java | 7 +- .../are/viewer/LayerObjectAmbient.java | 18 +- .../are/viewer/LayerObjectAnimation.java | 7 +- .../are/viewer/LayerObjectAutomap.java | 7 +- .../are/viewer/LayerObjectAutomapPST.java | 7 +- .../are/viewer/LayerObjectContainer.java | 92 ++++++- .../resource/are/viewer/LayerObjectDoor.java | 256 ++++++++++++++--- .../are/viewer/LayerObjectDoorPoly.java | 46 +++- .../are/viewer/LayerObjectEntrance.java | 7 +- .../are/viewer/LayerObjectProTrap.java | 7 +- .../are/viewer/LayerObjectRegion.java | 131 ++++++++- .../are/viewer/LayerObjectSpawnPoint.java | 7 +- .../are/viewer/LayerObjectTransition.java | 7 +- .../are/viewer/LayerObjectWallPoly.java | 7 +- .../resource/are/viewer/LayerRegion.java | 2 +- .../resource/are/viewer/Settings.java | 123 ++++++--- .../resource/are/viewer/SettingsDialog.java | 135 +++++---- .../resource/are/viewer/ViewerConstants.java | 101 +++++-- .../resource/are/viewer/icon/ViewerIcons.java | 16 ++ .../are/viewer/icon/itm_Container1.png | Bin 0 -> 992 bytes .../are/viewer/icon/itm_Container2.png | Bin 0 -> 1001 bytes .../are/viewer/icon/itm_ContainerLaunch1.png | Bin 0 -> 1042 bytes .../are/viewer/icon/itm_ContainerLaunch2.png | Bin 0 -> 1051 bytes .../are/viewer/icon/itm_DoorClosed1.png | Bin 0 -> 1182 bytes .../are/viewer/icon/itm_DoorClosed2.png | Bin 0 -> 1182 bytes .../are/viewer/icon/itm_DoorLaunch1.png | Bin 0 -> 1044 bytes .../are/viewer/icon/itm_DoorLaunch2.png | Bin 0 -> 1055 bytes .../are/viewer/icon/itm_DoorOpen1.png | Bin 0 -> 1192 bytes .../are/viewer/icon/itm_DoorOpen2.png | Bin 0 -> 1197 bytes .../resource/are/viewer/icon/itm_Region1.png | Bin 0 -> 963 bytes .../resource/are/viewer/icon/itm_Region2.png | Bin 0 -> 975 bytes .../are/viewer/icon/itm_RegionActivation1.png | Bin 0 -> 1108 bytes .../are/viewer/icon/itm_RegionActivation2.png | Bin 0 -> 1126 bytes .../are/viewer/icon/itm_RegionSpeaker1.png | Bin 0 -> 1172 bytes .../are/viewer/icon/itm_RegionSpeaker2.png | Bin 0 -> 1177 bytes 45 files changed, 1166 insertions(+), 345 deletions(-) create mode 100644 src/org/infinity/resource/are/viewer/BasicTargetLayer.java create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_Container1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_Container2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorClosed1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorClosed2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorOpen1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_DoorOpen2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_Region1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_Region2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_RegionActivation1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_RegionActivation2.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker1.png create mode 100644 src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker2.png diff --git a/src/org/infinity/resource/are/viewer/AreaViewer.java b/src/org/infinity/resource/are/viewer/AreaViewer.java index fab0ecb1b..c718f592c 100644 --- a/src/org/infinity/resource/are/viewer/AreaViewer.java +++ b/src/org/infinity/resource/are/viewer/AreaViewer.java @@ -164,6 +164,9 @@ public class AreaViewer extends ChildFrame { private JCheckBox cbEnableSchedules; private JComboBox cbZoomLevel; private JCheckBox cbLayerAmbientRange; + private JCheckBox cbLayerRegionTarget; + private JCheckBox cbLayerContainerTarget; + private JCheckBox cbLayerDoorTarget; private JLabel lPosX; private JLabel lPosY; private JTextArea taInfo; @@ -416,6 +419,24 @@ private void init() { cbLayerRealAnimation[1].addActionListener(getListeners()); t3 = new DefaultMutableTreeNode(cbLayerRealAnimation[1]); t2.add(t3); + } else if (i == LayerManager.getLayerTypeIndex(LayerType.CONTAINER)) { + // Initializing container target locations checkbox + cbLayerContainerTarget = new JCheckBox("Show target locations"); + cbLayerContainerTarget.addActionListener(getListeners()); + t3 = new DefaultMutableTreeNode(cbLayerContainerTarget); + t2.add(t3); + } else if (i == LayerManager.getLayerTypeIndex(LayerType.DOOR)) { + // Initializing door target locations checkbox + cbLayerDoorTarget = new JCheckBox("Show target locations"); + cbLayerDoorTarget.addActionListener(getListeners()); + t3 = new DefaultMutableTreeNode(cbLayerDoorTarget); + t2.add(t3); + } else if (i == LayerManager.getLayerTypeIndex(LayerType.REGION)) { + // Initializing region target locations checkbox + cbLayerRegionTarget = new JCheckBox("Show target locations"); + cbLayerRegionTarget.addActionListener(getListeners()); + t3 = new DefaultMutableTreeNode(cbLayerRegionTarget); + t2.add(t3); } } @@ -769,7 +790,9 @@ private void initGuiSettings() { } cbLayers[i].setEnabled(count > 0); cbLayers[i].setSelected(isChecked); - updateLayerItems(Settings.layerToStacking(layer)); + for (final LayerStackingType lst : Settings.layerToStacking(layer)) { + updateLayerItems(lst); + } showLayer(LayerManager.getLayerType(i), cbLayers[i].isSelected()); } @@ -792,6 +815,18 @@ private void initGuiSettings() { cbLayerAmbientRange.setSelected(Settings.ShowAmbientRanges); updateAmbientRange(); + // Setting up container target locations + cbLayerContainerTarget.setSelected(Settings.ShowContainerTargets); + updateContainerTargets(); + + // Setting up door target locations + cbLayerDoorTarget.setSelected(Settings.ShowDoorTargets); + updateDoorTargets(); + + // Setting up region target locations + cbLayerRegionTarget.setSelected(Settings.ShowRegionTargets); + updateRegionTargets(); + // initializing background animation display // Disabling animated frames for performance and safety reasons if (Settings.ShowRealAnimations == ViewerConstants.ANIM_SHOW_ANIMATED) { @@ -1298,7 +1333,17 @@ private boolean updateItemPopup(Point canvasCoords) { && ((LayerObjectAmbient) obj).isLocal()) { // skipped: will be handled in AmbientRange layer break; + } else if (stacking == LayerStackingType.CONTAINER_TARGET) { + // skipped: will be handled in ContainerTarget layer + break; + } else if (stacking == LayerStackingType.DOOR_TARGET) { + // skipped: will be handled in DoorTarget layer + break; + } else if (stacking == LayerStackingType.REGION_TARGET) { + // skipped: will be handled in RegionTarget layer + break; } + if (stacking == LayerStackingType.AMBIENT_RANGE) { if (((LayerObjectAmbient) obj).isLocal() && i == ViewerConstants.AMBIENT_ITEM_ICON) { // considering ranged item only @@ -1387,14 +1432,12 @@ private void reloadAreLayers(boolean order) { if (layerManager != null) { for (int i = 0, ltCount = LayerManager.getLayerTypeCount(); i < ltCount; i++) { LayerType layer = LayerManager.getLayerType(i); - LayerStackingType layer2 = Settings.layerToStacking(layer); - if (layer != LayerType.DOOR_POLY && layer != LayerType.WALL_POLY) { + LayerStackingType[] layerStacking = Settings.layerToStacking(layer); + if (layer.isAre()) { layerManager.reload(layer); - updateLayerItems(layer2); - addLayerItems(layer2); - if (layer == LayerType.AMBIENT) { - updateLayerItems(LayerStackingType.AMBIENT_RANGE); - addLayerItems(LayerStackingType.AMBIENT_RANGE); + for (final LayerStackingType lst : layerStacking) { + updateLayerItems(lst); + addLayerItems(lst); } showLayer(layer, cbLayers[i].isSelected()); } @@ -1403,6 +1446,9 @@ private void reloadAreLayers(boolean order) { updateRealActors(); updateRealActorsLighting(getVisualState()); updateAmbientRange(); + updateContainerTargets(); + updateDoorTargets(); + updateRegionTargets(); updateRealAnimation(); updateRealAnimationsLighting(getVisualState()); if (order) { @@ -1586,6 +1632,63 @@ private void updateAmbientRange() { } } + /** Updates the visibility state of region target locations. */ + private void updateRegionTargets() { + if (layerManager != null) { + LayerRegion layer = (LayerRegion) layerManager.getLayer(LayerType.REGION); + if (layer != null) { + JCheckBox cb = cbLayers[LayerManager.getLayerTypeIndex(LayerType.REGION)]; + cbLayerRegionTarget.setEnabled(cb.isSelected() && cb.isEnabled()); + boolean state = cbLayerRegionTarget.isEnabled() && cbLayerRegionTarget.isSelected(); + layer.setIconLayerEnabled(state); + } else { + cbLayerRegionTarget.setEnabled(false); + } + updateTreeNode(cbLayerRegionTarget); + + // Storing settings + Settings.ShowRegionTargets = cbLayerRegionTarget.isSelected(); + } + } + + /** Updates the visibility state of container target locations. */ + private void updateContainerTargets() { + if (layerManager != null) { + LayerContainer layer = (LayerContainer) layerManager.getLayer(LayerType.CONTAINER); + if (layer != null) { + JCheckBox cb = cbLayers[LayerManager.getLayerTypeIndex(LayerType.CONTAINER)]; + cbLayerContainerTarget.setEnabled(cb.isSelected() && cb.isEnabled()); + boolean state = cbLayerContainerTarget.isEnabled() && cbLayerContainerTarget.isSelected(); + layer.setIconLayerEnabled(state); + } else { + cbLayerContainerTarget.setEnabled(false); + } + updateTreeNode(cbLayerContainerTarget); + + // Storing settings + Settings.ShowContainerTargets = cbLayerContainerTarget.isSelected(); + } + } + + /** Updates the visibility state of door target locations. */ + private void updateDoorTargets() { + if (layerManager != null) { + LayerDoor layer = (LayerDoor) layerManager.getLayer(LayerType.DOOR); + if (layer != null) { + JCheckBox cb = cbLayers[LayerManager.getLayerTypeIndex(LayerType.DOOR)]; + cbLayerDoorTarget.setEnabled(cb.isSelected() && cb.isEnabled()); + boolean state = cbLayerDoorTarget.isEnabled() && cbLayerDoorTarget.isSelected(); + layer.setIconLayerEnabled(state); + } else { + cbLayerDoorTarget.setEnabled(false); + } + updateTreeNode(cbLayerDoorTarget); + + // Storing settings + Settings.ShowDoorTargets = cbLayerDoorTarget.isSelected(); + } + } + /** Applies the specified lighting condition to real actor items. */ private void updateRealActorsLighting(int visualState) { if (layerManager != null) { @@ -1723,21 +1826,41 @@ private void addLayerItems(LayerStackingType layer) { /** Adds items of a single layer object to the map canvas. */ private void addLayerItem(LayerStackingType layer, LayerObject object) { + int type = -1; if (object != null) { - // Dealing with ambient icons and ambient ranges separately - if (layer == LayerStackingType.AMBIENT) { - AbstractLayerItem item = object.getLayerItem(ViewerConstants.AMBIENT_ITEM_ICON); - if (item != null) { - rcCanvas.add(item); - } - } else if (layer == LayerStackingType.AMBIENT_RANGE) { - AbstractLayerItem item = object.getLayerItem(ViewerConstants.AMBIENT_ITEM_RANGE); - if (item != null) { + switch (layer) { + case AMBIENT: + type = ViewerConstants.AMBIENT_ITEM_ICON; + break; + case AMBIENT_RANGE: + type = ViewerConstants.AMBIENT_ITEM_RANGE; + break; + case CONTAINER: + case REGION: + type = ViewerConstants.LAYER_ITEM_POLY; + break; + case DOOR: + type = ViewerConstants.DOOR_ANY | ViewerConstants.LAYER_ITEM_POLY; + break; + case CONTAINER_TARGET: + case DOOR_TARGET: + case REGION_TARGET: + type = ViewerConstants.LAYER_ITEM_ICON; + break; + default: + } + + if (type >= 0) { + // dealing with components of composed layers individually + final AbstractLayerItem[] items = object.getLayerItems(type); + for (final AbstractLayerItem item : items) { rcCanvas.add(item); } } else { for (final AbstractLayerItem item : object.getLayerItems()) { - rcCanvas.add(item); + if (item != null) { + rcCanvas.add(item); + } } } } @@ -1764,19 +1887,39 @@ private void removeLayerItems(LayerStackingType layer) { /** Removes items of a single layer object from the map canvas. */ private void removeLayerItem(LayerStackingType layer, LayerObject object) { - if (object != null) { - if (layer == LayerStackingType.AMBIENT) { - AbstractLayerItem item = object.getLayerItem(ViewerConstants.AMBIENT_ITEM_ICON); + int type = -1; + switch (layer) { + case AMBIENT: + type = ViewerConstants.AMBIENT_ITEM_ICON; + break; + case AMBIENT_RANGE: + type = ViewerConstants.AMBIENT_ITEM_RANGE; + break; + case CONTAINER: + case REGION: + type = ViewerConstants.LAYER_ITEM_POLY; + break; + case DOOR: + type = ViewerConstants.DOOR_ANY | ViewerConstants.LAYER_ITEM_POLY; + break; + case CONTAINER_TARGET: + case DOOR_TARGET: + case REGION_TARGET: + type = ViewerConstants.LAYER_ITEM_ICON; + break; + default: + } + + if (type >= 0) { + final AbstractLayerItem[] items = object.getLayerItems(type); + for (final AbstractLayerItem item : items) { rcCanvas.remove(item); - } else if (layer == LayerStackingType.AMBIENT_RANGE) { - AbstractLayerItem item = object.getLayerItem(ViewerConstants.AMBIENT_ITEM_RANGE); + } + } else { + for (final AbstractLayerItem item : object.getLayerItems()) { if (item != null) { rcCanvas.remove(item); } - } else { - for (final AbstractLayerItem item : object.getLayerItems()) { - rcCanvas.remove(item); - } } } } @@ -1785,25 +1928,43 @@ private void removeLayerItem(LayerStackingType layer, LayerObject object) { private void orderLayerItems() { if (layerManager != null) { int index = 0; - for (final LayerStackingType type : Settings.LIST_LAYER_ORDER) { - final List list = layerManager.getLayerObjects(Settings.stackingToLayer(type)); + for (final LayerStackingType layer : Settings.LIST_LAYER_ORDER) { + final List list = layerManager.getLayerObjects(Settings.stackingToLayer(layer)); if (list == null) { continue; } for (final LayerObject obj : list) { - if (type == LayerStackingType.AMBIENT_RANGE) { - // Special: process ambient ranges only - AbstractLayerItem item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_RANGE); - if (item != null) { + int type = -1; + switch (layer) { + case AMBIENT: + type = ViewerConstants.AMBIENT_ITEM_ICON; + break; + case AMBIENT_RANGE: + type = ViewerConstants.AMBIENT_ITEM_RANGE; + break; + case CONTAINER: + case REGION: + type = ViewerConstants.LAYER_ITEM_POLY; + break; + case DOOR: + type = ViewerConstants.DOOR_ANY | ViewerConstants.LAYER_ITEM_POLY; + break; + case CONTAINER_TARGET: + case DOOR_TARGET: + case REGION_TARGET: + type = ViewerConstants.LAYER_ITEM_ICON; + break; + default: + } + + if (type >= 0) { + // process components of composed layers individually + final AbstractLayerItem[] items = obj.getLayerItems(type); + for (final AbstractLayerItem item : items) { rcCanvas.setComponentZOrder(item, index); index++; } - } else if (type == LayerStackingType.AMBIENT) { - // Special: process ambient icons only - AbstractLayerItem item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_ICON); - rcCanvas.setComponentZOrder(item, index); - index++; } else { for (final AbstractLayerItem item : obj.getLayerItems()) { if (item.getParent() != null) { @@ -1934,6 +2095,7 @@ private void viewSettings() { private void applySettings() { // applying layer stacking order orderLayerItems(); + // applying interpolation settings to map switch (Settings.InterpolationMap) { case ViewerConstants.FILTERING_AUTO: @@ -1948,6 +2110,7 @@ private void applySettings() { rcCanvas.setForcedInterpolation(true); break; } + // applying minimap alpha rcCanvas.setMiniMapTransparency((int) (Settings.MiniMapAlpha * 255.0)); @@ -1973,6 +2136,10 @@ private void applySettings() { // applying animation active override settings ((LayerAnimation) layerManager.getLayer(LayerType.ANIMATION)) .setRealAnimationActiveIgnored(Settings.OverrideAnimVisibility); + ((LayerContainer) layerManager.getLayer(LayerType.CONTAINER)).setIconLayerEnabled(Settings.ShowContainerTargets); + ((LayerDoor) layerManager.getLayer(LayerType.DOOR)).setIconLayerEnabled(Settings.ShowDoorTargets); + ((LayerRegion) layerManager.getLayer(LayerType.REGION)).setIconLayerEnabled(Settings.ShowRegionTargets); + // applying interpolation settings to animations switch (Settings.InterpolationAnim) { case ViewerConstants.FILTERING_AUTO: @@ -1987,11 +2154,13 @@ private void applySettings() { layerManager.setRealAnimationForcedInterpolation(true); break; } + // applying frame rate to animated overlays int interval = (int) (1000.0 / Settings.FrameRateOverlays); if (interval != timerOverlays.getDelay()) { timerOverlays.setDelay(interval); } + // applying frame rate to actor sprites and background animations layerManager.setRealAnimationFrameRate(Settings.FrameRateAnimations); } @@ -2074,6 +2243,15 @@ public void actionPerformed(ActionEvent event) { } else if (layer == LayerType.ANIMATION) { // Taking care of real animation display updateRealAnimation(); + } else if (layer == LayerType.CONTAINER) { + // Taking care of container target locations + updateContainerTargets(); + } else if (layer == LayerType.DOOR) { + // Taking care of door target locations + updateDoorTargets(); + } else if (layer == LayerType.REGION) { + // Taking care of region target locations + updateRegionTargets(); } updateScheduledItems(); } else if (cb == cbLayerRealActor[0]) { @@ -2098,6 +2276,12 @@ public void actionPerformed(ActionEvent event) { cbLayerRealAnimation[0].setSelected(false); } updateRealAnimation(); + } else if (cb == cbLayerContainerTarget) { + updateContainerTargets(); + } else if (cb == cbLayerDoorTarget) { + updateDoorTargets(); + } else if (cb == cbLayerRegionTarget) { + updateRegionTargets(); } else if (cb == cbEnableSchedules) { WindowBlocker.blockWindow(AreaViewer.this, true); try { diff --git a/src/org/infinity/resource/are/viewer/BasicTargetLayer.java b/src/org/infinity/resource/are/viewer/BasicTargetLayer.java new file mode 100644 index 000000000..09eeb3cc9 --- /dev/null +++ b/src/org/infinity/resource/are/viewer/BasicTargetLayer.java @@ -0,0 +1,68 @@ +// Near Infinity - An Infinity Engine Browser and Editor +// Copyright (C) 2001 Jon Olav Hauglid +// See LICENSE.txt for license information + +package org.infinity.resource.are.viewer; + +import org.infinity.gui.layeritem.AbstractLayerItem; +import org.infinity.resource.AbstractStruct; +import org.infinity.resource.are.viewer.ViewerConstants.LayerType; + +/** + * + */ +public abstract class BasicTargetLayer extends BasicLayer { + private boolean polyEnabled = true; + private boolean iconsEnabled; + + public BasicTargetLayer(R parent, LayerType type, AreaViewer viewer) { + super(parent, type, viewer); + } + + @Override + public void setLayerVisible(boolean visible) { + setVisibilityState(visible); + + getLayerObjects().stream().forEach(obj -> { + AbstractLayerItem[] items = obj.getLayerItems(ViewerConstants.LAYER_ITEM_POLY); + for (final AbstractLayerItem item : items) { + item.setVisible(isPolyLayerVisible() && isPolyLayerEnabled()); + } + + items = obj.getLayerItems(ViewerConstants.LAYER_ITEM_ICON); + for (final AbstractLayerItem item : items) { + item.setVisible(isIconsLayerVisible() && isIconsLayerEnabled()); + } + }); + } + + public boolean isPolyLayerVisible() { + return isLayerVisible() && polyEnabled; + } + + public boolean isIconsLayerVisible() { + return isLayerVisible() && iconsEnabled; + } + + public boolean isPolyLayerEnabled() { + return polyEnabled; + } + + public void setPolyLayerEnabled(boolean enable) { + if (enable != polyEnabled) { + polyEnabled = enable; + setLayerVisible(isPolyLayerVisible()); + } + } + + public boolean isIconsLayerEnabled() { + return iconsEnabled; + } + + public void setIconLayerEnabled(boolean enable) { + if (enable != iconsEnabled) { + iconsEnabled = enable; + setLayerVisible(isPolyLayerVisible() || isIconsLayerVisible()); + } + } +} diff --git a/src/org/infinity/resource/are/viewer/LayerActor.java b/src/org/infinity/resource/are/viewer/LayerActor.java index 295e3e889..ae90bdbf7 100644 --- a/src/org/infinity/resource/are/viewer/LayerActor.java +++ b/src/org/infinity/resource/are/viewer/LayerActor.java @@ -18,7 +18,6 @@ import org.infinity.gui.WindowBlocker; import org.infinity.gui.layeritem.AbstractLayerItem; import org.infinity.gui.layeritem.AnimatedLayerItem; -import org.infinity.gui.layeritem.IconLayerItem; import org.infinity.resource.Profile; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; @@ -162,13 +161,14 @@ public Void doInBackground() { boolean state = isLayerVisible() && (!isScheduleEnabled() || isScheduled(i)); LayerObjectActor loa = list.get(i); - IconLayerItem iconItem = (IconLayerItem) loa.getLayerItem(ViewerConstants.ITEM_ICON); - if (iconItem != null) { + AbstractLayerItem[] iconItems = loa.getLayerItems(ViewerConstants.ITEM_ICON); + for (AbstractLayerItem iconItem : iconItems) { iconItem.setVisible(state && !realEnabled); } - AnimatedLayerItem animItem = (AnimatedLayerItem) loa.getLayerItem(ViewerConstants.ITEM_REAL); - if (animItem != null) { + AbstractLayerItem[] animItems = loa.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item: animItems) { + final AnimatedLayerItem animItem = (AnimatedLayerItem) item; if (animItem.getAnimation() == AbstractAnimationProvider.DEFAULT_ANIMATION_PROVIDER && state && realEnabled) { // real actor animations loaded on demand @@ -240,9 +240,9 @@ public void setRealActorInterpolation(Object interpolationType) { if (interpolationType != this.interpolationType) { this.interpolationType = interpolationType; for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setInterpolationType(interpolationType); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setInterpolationType(interpolationType); } } } @@ -264,9 +264,9 @@ public void setRealActorForcedInterpolation(boolean forced) { if (forced != forcedInterpolation) { forcedInterpolation = forced; for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setForcedInterpolation(forced); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setForcedInterpolation(forced); } } } @@ -357,10 +357,13 @@ public void setRealActorSelectionCircleEnabled(boolean enable) { if (enable != selectionCircleEnabled) { selectionCircleEnabled = enable; for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item.getAnimation() instanceof ActorAnimationProvider) { - ActorAnimationProvider aap = (ActorAnimationProvider) item.getAnimation(); - aap.setSelectionCircleEnabled(selectionCircleEnabled); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + final AnimatedLayerItem animItem = (AnimatedLayerItem) item; + if (animItem.getAnimation() instanceof ActorAnimationProvider) { + ActorAnimationProvider aap = (ActorAnimationProvider) animItem.getAnimation(); + aap.setSelectionCircleEnabled(selectionCircleEnabled); + } } } } @@ -380,10 +383,13 @@ public void setRealActorPersonalSpaceEnabled(boolean enable) { if (enable != personalSpaceEnabled) { personalSpaceEnabled = enable; for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item.getAnimation() instanceof ActorAnimationProvider) { - ActorAnimationProvider aap = (ActorAnimationProvider) item.getAnimation(); - aap.setPersonalSpaceEnabled(personalSpaceEnabled); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + final AnimatedLayerItem animItem = (AnimatedLayerItem) item; + if (animItem.getAnimation() instanceof ActorAnimationProvider) { + ActorAnimationProvider aap = (ActorAnimationProvider) animItem.getAnimation(); + aap.setPersonalSpaceEnabled(personalSpaceEnabled); + } } } } @@ -408,9 +414,9 @@ public void setRealActorFrameRate(double frameRate) { if (frameRate != this.frameRate) { this.frameRate = frameRate; for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setFrameRate(frameRate); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setFrameRate(frameRate); } } } @@ -418,20 +424,21 @@ public void setRealActorFrameRate(double frameRate) { private void updateFrameState() { for (final LayerObjectActor layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + final AnimatedLayerItem animItem = (AnimatedLayerItem) item; switch (frameState) { case ViewerConstants.FRAME_NEVER: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, false); break; case ViewerConstants.FRAME_AUTO: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); break; case ViewerConstants.FRAME_ALWAYS: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, true); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); break; } } diff --git a/src/org/infinity/resource/are/viewer/LayerAmbient.java b/src/org/infinity/resource/are/viewer/LayerAmbient.java index 347be84e2..4f2835354 100644 --- a/src/org/infinity/resource/are/viewer/LayerAmbient.java +++ b/src/org/infinity/resource/are/viewer/LayerAmbient.java @@ -66,13 +66,13 @@ public void setLayerVisible(boolean visible) { for (int i = 0, size = list.size(); i < size; i++) { LayerObjectAmbient obj = list.get(i); state = isLayerVisible(ViewerConstants.AMBIENT_ITEM_ICON) && (!isScheduleEnabled() || isScheduled(i)); - AbstractLayerItem item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_ICON); - if (item != null) { + AbstractLayerItem[] items = obj.getLayerItems(ViewerConstants.AMBIENT_ITEM_ICON); + for (final AbstractLayerItem item : items) { item.setVisible(state && iconEnabled); } state = isLayerVisible(ViewerConstants.AMBIENT_ITEM_RANGE) && (!isScheduleEnabled() || isScheduled(i)); - item = obj.getLayerItem(ViewerConstants.AMBIENT_ITEM_RANGE); - if (item != null) { + items = obj.getLayerItems(ViewerConstants.AMBIENT_ITEM_RANGE); + for (final AbstractLayerItem item : items) { item.setVisible(state && rangeEnabled); } } diff --git a/src/org/infinity/resource/are/viewer/LayerAnimation.java b/src/org/infinity/resource/are/viewer/LayerAnimation.java index 1f6941451..b868fcf5a 100644 --- a/src/org/infinity/resource/are/viewer/LayerAnimation.java +++ b/src/org/infinity/resource/are/viewer/LayerAnimation.java @@ -13,7 +13,6 @@ import org.infinity.datatype.Flag; import org.infinity.gui.layeritem.AbstractLayerItem; import org.infinity.gui.layeritem.AnimatedLayerItem; -import org.infinity.gui.layeritem.IconLayerItem; import org.infinity.resource.are.Animation; import org.infinity.resource.are.AreResource; @@ -78,16 +77,17 @@ public String getAvailability() { @Override public void setLayerVisible(boolean visible) { setVisibilityState(visible); - List list = getLayerObjects(); + final List list = getLayerObjects(); for (int i = 0, size = list.size(); i < size; i++) { boolean state = isLayerVisible() && (!isScheduleEnabled() || isScheduled(i)); - LayerObjectAnimation obj = list.get(i); - IconLayerItem iconItem = (IconLayerItem) obj.getLayerItem(ViewerConstants.ITEM_ICON); - if (iconItem != null) { - iconItem.setVisible(state && !realEnabled); + final LayerObjectAnimation obj = list.get(i); + final AbstractLayerItem[] iconItems = obj.getLayerItems(ViewerConstants.ITEM_ICON); + for (final AbstractLayerItem item : iconItems) { + item.setVisible(state && !realEnabled); } - AnimatedLayerItem animItem = (AnimatedLayerItem) obj.getLayerItem(ViewerConstants.ITEM_REAL); - if (animItem != null) { + final AbstractLayerItem[] animItems = obj.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : animItems) { + AnimatedLayerItem animItem = (AnimatedLayerItem) item; animItem.setVisible(state && realEnabled); if (isRealAnimationEnabled() && isRealAnimationPlaying()) { animItem.play(); @@ -118,9 +118,9 @@ public void setRealAnimationInterpolation(Object interpolationType) { if (interpolationType != this.interpolationType) { this.interpolationType = interpolationType; for (final LayerObjectAnimation layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setInterpolationType(interpolationType); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setInterpolationType(interpolationType); } } } @@ -142,9 +142,9 @@ public void setRealAnimationForcedInterpolation(boolean forced) { if (forced != forcedInterpolation) { forcedInterpolation = forced; for (final LayerObjectAnimation layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setForcedInterpolation(forced); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setForcedInterpolation(forced); } } } @@ -242,9 +242,9 @@ public void setRealAnimationFrameRate(double frameRate) { if (frameRate != this.frameRate) { this.frameRate = frameRate; for (final LayerObjectAnimation layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - item.setFrameRate(frameRate); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + ((AnimatedLayerItem) item).setFrameRate(frameRate); } } } @@ -265,10 +265,11 @@ public boolean isRealAnimationActiveIgnored() { public void setRealAnimationActiveIgnored(boolean set) { isAnimActiveIgnored = set; for (final LayerObjectAnimation layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { - if (item.getAnimation() instanceof AbstractAnimationProvider) { - ((AbstractAnimationProvider) item.getAnimation()).setActiveIgnored(set); + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + AnimatedLayerItem animItem = (AnimatedLayerItem) item; + if (animItem.getAnimation() instanceof AbstractAnimationProvider) { + ((AbstractAnimationProvider) animItem.getAnimation()).setActiveIgnored(set); } } } @@ -276,20 +277,21 @@ public void setRealAnimationActiveIgnored(boolean set) { private void updateFrameState() { for (final LayerObjectAnimation layer : getLayerObjects()) { - final AnimatedLayerItem item = (AnimatedLayerItem) layer.getLayerItem(ViewerConstants.ITEM_REAL); - if (item != null) { + final AbstractLayerItem[] items = layer.getLayerItems(ViewerConstants.ITEM_REAL); + for (final AbstractLayerItem item : items) { + final AnimatedLayerItem animItem = (AnimatedLayerItem) item; switch (frameState) { case ViewerConstants.FRAME_NEVER: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, false); break; case ViewerConstants.FRAME_AUTO: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, false); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); break; case ViewerConstants.FRAME_ALWAYS: - item.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, true); - item.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.NORMAL, true); + animItem.setFrameEnabled(AbstractLayerItem.ItemState.HIGHLIGHTED, true); break; } } diff --git a/src/org/infinity/resource/are/viewer/LayerContainer.java b/src/org/infinity/resource/are/viewer/LayerContainer.java index e53b1bf08..10fb1f78c 100644 --- a/src/org/infinity/resource/are/viewer/LayerContainer.java +++ b/src/org/infinity/resource/are/viewer/LayerContainer.java @@ -13,7 +13,7 @@ /** * Manages container layer objects. */ -public class LayerContainer extends BasicLayer { +public class LayerContainer extends BasicTargetLayer { private static final String AVAILABLE_FMT = "Containers: %d"; public LayerContainer(AreResource are, AreaViewer viewer) { @@ -23,8 +23,7 @@ public LayerContainer(AreResource are, AreaViewer viewer) { @Override protected void loadLayer() { - loadLayerItems(ARE_OFFSET_CONTAINERS, ARE_NUM_CONTAINERS, Container.class, - c -> new LayerObjectContainer(parent, c)); + loadLayerItems(ARE_OFFSET_CONTAINERS, ARE_NUM_CONTAINERS, Container.class, c -> new LayerObjectContainer(parent, c)); } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerDoor.java b/src/org/infinity/resource/are/viewer/LayerDoor.java index 25414bdf8..94b4dfa06 100644 --- a/src/org/infinity/resource/are/viewer/LayerDoor.java +++ b/src/org/infinity/resource/are/viewer/LayerDoor.java @@ -7,13 +7,14 @@ import static org.infinity.resource.are.AreResource.ARE_NUM_DOORS; import static org.infinity.resource.are.AreResource.ARE_OFFSET_DOORS; +import org.infinity.gui.layeritem.AbstractLayerItem; import org.infinity.resource.are.AreResource; import org.infinity.resource.are.Door; /** * Manages door layer objects. */ -public class LayerDoor extends BasicLayer { +public class LayerDoor extends BasicTargetLayer { private static final String AVAILABLE_FMT = "Doors: %d"; private boolean doorClosed; @@ -37,10 +38,23 @@ public String getAvailability() { @Override public void setLayerVisible(boolean visible) { setVisibilityState(visible); - for (final LayerObjectDoor obj : getLayerObjects()) { - obj.getLayerItem(ViewerConstants.DOOR_OPEN).setVisible(isLayerVisible() && !doorClosed); - obj.getLayerItem(ViewerConstants.DOOR_CLOSED).setVisible(isLayerVisible() && doorClosed); - } + + getLayerObjects().stream().forEach(obj -> { + AbstractLayerItem[] items = obj.getLayerItems(ViewerConstants.DOOR_OPEN | ViewerConstants.LAYER_ITEM_POLY); + for (final AbstractLayerItem item : items) { + item.setVisible(isPolyLayerVisible() && isPolyLayerEnabled() && !doorClosed); + } + + items = obj.getLayerItems(ViewerConstants.DOOR_CLOSED | ViewerConstants.LAYER_ITEM_POLY); + for (final AbstractLayerItem item : items) { + item.setVisible(isPolyLayerVisible() && isPolyLayerEnabled() && doorClosed); + } + + items = obj.getLayerItems(ViewerConstants.LAYER_ITEM_ICON); + for (final AbstractLayerItem item : items) { + item.setVisible(isIconsLayerVisible() && isIconsLayerEnabled()); + } + }); } /** diff --git a/src/org/infinity/resource/are/viewer/LayerDoorPoly.java b/src/org/infinity/resource/are/viewer/LayerDoorPoly.java index 2a921e639..6494d5d9d 100644 --- a/src/org/infinity/resource/are/viewer/LayerDoorPoly.java +++ b/src/org/infinity/resource/are/viewer/LayerDoorPoly.java @@ -40,14 +40,14 @@ public void setLayerVisible(boolean visible) { setVisibilityState(visible); for (final LayerObjectDoorPoly obj : getLayerObjects()) { // processing open door items - AbstractLayerItem[] items = obj.getLayerItems(ViewerConstants.DOOR_OPEN); + AbstractLayerItem[] items = obj.getLayerItemsByState(ViewerConstants.DOOR_OPEN); if (items != null) { for (final AbstractLayerItem item : items) { item.setVisible(isLayerVisible() && !doorClosed); } } // processing open door items - items = obj.getLayerItems(ViewerConstants.DOOR_CLOSED); + items = obj.getLayerItemsByState(ViewerConstants.DOOR_CLOSED); if (items != null) { for (final AbstractLayerItem item : items) { item.setVisible(isLayerVisible() && doorClosed); diff --git a/src/org/infinity/resource/are/viewer/LayerManager.java b/src/org/infinity/resource/are/viewer/LayerManager.java index d452e4543..f24bad590 100644 --- a/src/org/infinity/resource/are/viewer/LayerManager.java +++ b/src/org/infinity/resource/are/viewer/LayerManager.java @@ -32,24 +32,6 @@ public final class LayerManager { LayerType.WALL_POLY }; - private static final EnumMap LAYER_LABELS = new EnumMap<>(LayerType.class); - - static { - LAYER_LABELS.put(LayerType.ACTOR, "Actors"); - LAYER_LABELS.put(LayerType.REGION, "Regions"); - LAYER_LABELS.put(LayerType.ENTRANCE, "Entrances"); - LAYER_LABELS.put(LayerType.CONTAINER, "Containers"); - LAYER_LABELS.put(LayerType.AMBIENT, "Ambient Sounds"); - LAYER_LABELS.put(LayerType.DOOR, "Doors"); - LAYER_LABELS.put(LayerType.ANIMATION, "Background Animations"); - LAYER_LABELS.put(LayerType.AUTOMAP, "Automap Notes"); - LAYER_LABELS.put(LayerType.SPAWN_POINT, "Spawn Points"); - LAYER_LABELS.put(LayerType.TRANSITION, "Map Transitions"); - LAYER_LABELS.put(LayerType.PRO_TRAP, "Projectile Traps"); - LAYER_LABELS.put(LayerType.DOOR_POLY, "Door Polygons"); - LAYER_LABELS.put(LayerType.WALL_POLY, "Wall Polygons"); - } - private final EnumMap> layers = new EnumMap<>(LayerType.class); private final AreaViewer viewer; @@ -96,7 +78,7 @@ public static int getLayerTypeIndex(LayerType layer) { * Returns the label associated with the specified layer. */ public static String getLayerTypeLabel(LayerType layer) { - String s = LAYER_LABELS.get(layer); + String s = layer.getLabel(); if (s != null) { return s; } else { diff --git a/src/org/infinity/resource/are/viewer/LayerObject.java b/src/org/infinity/resource/are/viewer/LayerObject.java index a1f4d9551..3873c274d 100644 --- a/src/org/infinity/resource/are/viewer/LayerObject.java +++ b/src/org/infinity/resource/are/viewer/LayerObject.java @@ -128,13 +128,13 @@ public void setVisible(boolean state) { public abstract Viewable getViewable(); /** - * Returns the specified layer item. {@code type} is layer type specific, usually defined as an identifier in - * {@code ViewerConstants}. + * Returns the layer items of the specified type. {@code type} is layer type specific, usually defined as an + * identifier in {@code ViewerConstants}. * * @param type A layer-specific type to identify the item to return. - * @return The desired layer item, or {@code null} if not available. + * @return The desired layer items as array. Returns an empty array items are not available. */ - public abstract AbstractLayerItem getLayerItem(int type); + public abstract AbstractLayerItem[] getLayerItems(int type); /** * Returns all layer items associated with the layer object. This method is useful for layer objects consisting of @@ -273,7 +273,7 @@ protected static Image[] getIcons(Image[] defIcons) { return icons; } - protected static void addResResDesc(StringBuilder sb, AbstractStruct struct, String resRefAttr, String desc) { + protected static void addResRefDesc(StringBuilder sb, AbstractStruct struct, String resRefAttr, String desc) { final ResourceRef res = (ResourceRef) struct.getAttribute(resRefAttr, false); if (res != null && !res.isEmpty()) { if (sb.length() > 1) { @@ -295,6 +295,6 @@ protected static void addTrappedDesc(StringBuilder sb, AbstractStruct struct, St sb.append("Trapped (").append(v).append(')'); } } - addResResDesc(sb, struct, scriptAttr, "Script: "); + addResRefDesc(sb, struct, scriptAttr, "Script: "); } } diff --git a/src/org/infinity/resource/are/viewer/LayerObjectActor.java b/src/org/infinity/resource/are/viewer/LayerObjectActor.java index 0e47af6ef..8bfb72f56 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectActor.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectActor.java @@ -117,9 +117,12 @@ public void close() { * @return The desired layer item, or {@code null} if not available. */ @Override - public AbstractLayerItem getLayerItem(int type) { + public AbstractLayerItem[] getLayerItems(int type) { type = (type == ViewerConstants.ITEM_REAL) ? ViewerConstants.ITEM_REAL : ViewerConstants.ITEM_ICON; - return items[type]; + if (items[type] != null) { + return new AbstractLayerItem[] { items[type] }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectAmbient.java b/src/org/infinity/resource/are/viewer/LayerObjectAmbient.java index b4d87a2ad..8bd53c5a2 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectAmbient.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectAmbient.java @@ -10,6 +10,8 @@ import java.awt.Rectangle; import java.awt.Shape; import java.awt.geom.Ellipse2D; +import java.util.ArrayList; +import java.util.List; import org.infinity.datatype.Flag; import org.infinity.datatype.IsNumeric; @@ -122,14 +124,18 @@ public Viewable getViewable() { * @return The layer item of specified type. */ @Override - public AbstractLayerItem getLayerItem(int type) { - if (type == ViewerConstants.AMBIENT_ITEM_RANGE) { - return itemShape; + public AbstractLayerItem[] getLayerItems(int type) { + final List list = new ArrayList<>(); + + if ((type & ViewerConstants.AMBIENT_ITEM_RANGE) == ViewerConstants.AMBIENT_ITEM_RANGE && itemShape != null) { + list.add(itemShape); } - if (type == ViewerConstants.AMBIENT_ITEM_ICON) { - return itemIcon; + + if ((type & ViewerConstants.AMBIENT_ITEM_ICON) == ViewerConstants.AMBIENT_ITEM_ICON) { + list.add(itemIcon); } - return null; + + return list.toArray(new AbstractLayerItem[0]); } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectAnimation.java b/src/org/infinity/resource/are/viewer/LayerObjectAnimation.java index 7f34683f0..b53ec5252 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectAnimation.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectAnimation.java @@ -233,9 +233,12 @@ public Viewable getViewable() { * @return The desired layer item, or {@code null} if not available. */ @Override - public AbstractLayerItem getLayerItem(int type) { + public AbstractLayerItem[] getLayerItems(int type) { type = (type == ViewerConstants.ITEM_REAL) ? ViewerConstants.ITEM_REAL : ViewerConstants.ITEM_ICON; - return items[type]; + if (items[type] != null) { + return new AbstractLayerItem[] { items[type] }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectAutomap.java b/src/org/infinity/resource/are/viewer/LayerObjectAutomap.java index ce63454a5..e9a32ad85 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectAutomap.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectAutomap.java @@ -134,8 +134,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectAutomapPST.java b/src/org/infinity/resource/are/viewer/LayerObjectAutomapPST.java index 7f078b0bf..2e198c240 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectAutomapPST.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectAutomapPST.java @@ -61,8 +61,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectContainer.java b/src/org/infinity/resource/are/viewer/LayerObjectContainer.java index 9aa9ee966..f3bc49963 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectContainer.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectContainer.java @@ -5,23 +5,35 @@ package org.infinity.resource.are.viewer; import java.awt.Color; +import java.awt.Image; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; +import java.util.Arrays; import org.infinity.datatype.Flag; import org.infinity.datatype.IsNumeric; import org.infinity.gui.layeritem.AbstractLayerItem; +import org.infinity.gui.layeritem.IconLayerItem; import org.infinity.gui.layeritem.ShapedLayerItem; import org.infinity.resource.Viewable; import org.infinity.resource.are.AreResource; import org.infinity.resource.are.Container; +import org.infinity.resource.are.viewer.icon.ViewerIcons; import org.infinity.resource.vertex.Vertex; /** * Handles specific layer type: ARE/Container */ public class LayerObjectContainer extends LayerObject { + private static final Image[] ICONS = { ViewerIcons.ICON_ITM_CONTAINER_TARGET_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_CONTAINER_TARGET_2.getIcon().getImage() }; + + private static final Image[] ICONS_LAUNCH = { ViewerIcons.ICON_ITM_CONTAINER_TARGET_L_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_CONTAINER_TARGET_L_2.getIcon().getImage() }; + + private static final Point CENTER = new Point(13, 29); + private static final Color[] COLOR = { new Color(0xFF004040, true), new Color(0xFF004040, true), new Color(0xC0008080, true), new Color(0xC000C0C0, true) }; @@ -31,9 +43,16 @@ public class LayerObjectContainer extends LayerObject { private final ShapedLayerItem item; private Point[] shapeCoords; + private final IconLayerItem itemIconAccess; + private final Point accessPoint = new Point(); + + private final IconLayerItem itemIconLaunch; + private final Point launchPoint = new Point(); + public LayerObjectContainer(AreResource parent, Container container) { super("Container", Container.class, parent); this.container = container; + String label = null; String msg = null; try { int type = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_TYPE)).getValue(); @@ -47,6 +66,12 @@ public LayerObjectContainer(AreResource parent, Container container) { int vNum = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_NUM_VERTICES)).getValue(); int vOfs = ((IsNumeric) parent.getAttribute(AreResource.ARE_OFFSET_VERTICES)).getValue(); shapeCoords = loadVertices(container, vOfs, 0, vNum, Vertex.class); + + label = container.getAttribute(Container.ARE_CONTAINER_NAME).toString(); + accessPoint.x = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_LOCATION_X)).getValue(); + accessPoint.y = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_LOCATION_Y)).getValue(); + launchPoint.x = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_LAUNCH_POINT_X)).getValue(); + launchPoint.y = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_LAUNCH_POINT_Y)).getValue(); } catch (Exception e) { e.printStackTrace(); } @@ -64,6 +89,9 @@ public LayerObjectContainer(AreResource parent, Container container) { item.setStroked(true); item.setFilled(true); item.setVisible(isVisible()); + + itemIconAccess = createValidatedLayerItem(accessPoint, label, getIcons(ICONS)); + itemIconLaunch = createValidatedLayerItem(launchPoint, label, getIcons(ICONS_LAUNCH)); } @Override @@ -72,13 +100,45 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + switch (type) { + case ViewerConstants.LAYER_ITEM_POLY: + if (item != null) { + return new AbstractLayerItem[] { item }; + } + break; + case ViewerConstants.LAYER_ITEM_ICON: + if (itemIconAccess != null && itemIconLaunch != null) { + return new AbstractLayerItem[] { itemIconAccess, itemIconLaunch }; + } else if (itemIconAccess != null) { + return new AbstractLayerItem[] { itemIconAccess }; + } else if (itemIconLaunch != null) { + return new AbstractLayerItem[] { itemIconLaunch }; + } + break; + } + return new AbstractLayerItem[0]; } @Override public AbstractLayerItem[] getLayerItems() { - return new AbstractLayerItem[] { item }; + final AbstractLayerItem[] retVal = new AbstractLayerItem[] { item, itemIconAccess, itemIconLaunch }; + int size = retVal.length; + + if (itemIconAccess == null) { + retVal[1] = retVal[size - 1]; + size--; + } + + if (itemIconLaunch == null) { + size--; + } + + if (size < 3) { + return Arrays.copyOf(retVal, size); + } else { + return retVal; + } } @Override @@ -91,6 +151,16 @@ public void update(double zoomFactor) { normalizePolygon(poly); item.setShape(poly); } + + if (itemIconAccess != null) { + itemIconAccess.setItemLocation((int) (accessPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (accessPoint.y * zoomFactor + (zoomFactor / 2.0))); + } + + if (itemIconLaunch != null) { + itemIconLaunch.setItemLocation((int) (launchPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (launchPoint.y * zoomFactor + (zoomFactor / 2.0))); + } } private String getAttributes() { @@ -102,7 +172,7 @@ private String getAttributes() { int v = ((IsNumeric) container.getAttribute(Container.ARE_CONTAINER_LOCK_DIFFICULTY)).getValue(); if (v > 0) { sb.append("Locked (").append(v).append(')'); - addResResDesc(sb, container, Container.ARE_CONTAINER_KEY, "Key: "); + addResRefDesc(sb, container, Container.ARE_CONTAINER_KEY, "Key: "); } } @@ -115,4 +185,18 @@ private String getAttributes() { sb.append(']'); return sb.toString(); } + + private IconLayerItem createValidatedLayerItem(Point pt, String label, Image[] icons) { + IconLayerItem retVal = null; + + if (pt.x > 0 && pt.y > 0) { + retVal = new IconLayerItem(container, label, icons[0], CENTER); + retVal.setLabelEnabled(Settings.ShowLabelContainerTargets); + retVal.setName(getCategory()); + retVal.setImage(AbstractLayerItem.ItemState.HIGHLIGHTED, icons[1]); + retVal.setVisible(isVisible()); + } + + return retVal; + } } diff --git a/src/org/infinity/resource/are/viewer/LayerObjectDoor.java b/src/org/infinity/resource/are/viewer/LayerObjectDoor.java index ce95c4457..838859dbd 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectDoor.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectDoor.java @@ -5,18 +5,26 @@ package org.infinity.resource.are.viewer; import java.awt.Color; +import java.awt.Image; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; import org.infinity.datatype.Flag; import org.infinity.datatype.IsNumeric; import org.infinity.gui.layeritem.AbstractLayerItem; +import org.infinity.gui.layeritem.IconLayerItem; import org.infinity.gui.layeritem.ShapedLayerItem; import org.infinity.resource.Profile; import org.infinity.resource.Viewable; import org.infinity.resource.are.AreResource; import org.infinity.resource.are.Door; +import org.infinity.resource.are.viewer.icon.ViewerIcons; import org.infinity.resource.vertex.ClosedVertex; import org.infinity.resource.vertex.OpenVertex; @@ -24,52 +32,86 @@ * Handles specific layer type: ARE/Door */ public class LayerObjectDoor extends LayerObject { + private static final Image[] ICONS_CLOSE = { ViewerIcons.ICON_ITM_DOOR_TARGET_C_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_DOOR_TARGET_C_2.getIcon().getImage() }; + + private static final Image[] ICONS_OPEN = { ViewerIcons.ICON_ITM_DOOR_TARGET_O_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_DOOR_TARGET_O_2.getIcon().getImage() }; + + private static final Image[] ICONS_LAUNCH = { ViewerIcons.ICON_ITM_DOOR_TARGET_L_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_DOOR_TARGET_L_2.getIcon().getImage() }; + + private static final Point CENTER = new Point(13, 29); + private static final Color[] COLOR = { new Color(0xFF400040, true), new Color(0xFF400040, true), new Color(0xC0800080, true), new Color(0xC0C000C0, true) }; + private final HashMap doorMap = new HashMap<>(4); private final Door door; - private final Point[] location = { new Point(), new Point() }; - private final ShapedLayerItem[] items = new ShapedLayerItem[2]; - private final Point[][] shapeCoords = new Point[2][]; + + private final IconLayerItem itemIconClose; + private final Point closePoint = new Point(); + + private final IconLayerItem itemIconOpen; + private final Point openPoint = new Point(); + + private final IconLayerItem itemIconLaunch; + private final Point launchPoint = new Point(); public LayerObjectDoor(AreResource parent, Door door) { super("Door", Door.class, parent); this.door = door; - final String[] msg = new String[2]; + final DoorInfo doorOpen = new DoorInfo(); + doorMap.put(Integer.valueOf(ViewerConstants.DOOR_OPEN), doorOpen); + final DoorInfo doorClosed = new DoorInfo(); + doorMap.put(Integer.valueOf(ViewerConstants.DOOR_CLOSED), doorClosed); + String label = null; try { String attr = getAttributes(); final String name = door.getAttribute(Door.ARE_DOOR_NAME).toString(); final int vOfs = ((IsNumeric) parent.getAttribute(AreResource.ARE_OFFSET_VERTICES)).getValue(); // processing opened state door - msg[ViewerConstants.DOOR_OPEN] = String.format("%s (Open) %s", name, attr); + doorOpen.setMessage(String.format("%s (Open) %s", name, attr)); int vNum = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_NUM_VERTICES_OPEN)).getValue(); - shapeCoords[ViewerConstants.DOOR_OPEN] = loadVertices(door, vOfs, 0, vNum, OpenVertex.class); + doorOpen.setCoords(loadVertices(door, vOfs, 0, vNum, OpenVertex.class)); // processing closed state door - msg[ViewerConstants.DOOR_CLOSED] = String.format("%s (Closed) %s", name, attr); + doorClosed.setMessage(String.format("%s (Closed) %s", name, attr)); vNum = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_NUM_VERTICES_CLOSED)).getValue(); - shapeCoords[ViewerConstants.DOOR_CLOSED] = loadVertices(door, vOfs, 0, vNum, ClosedVertex.class); + doorClosed.setCoords(loadVertices(door, vOfs, 0, vNum, ClosedVertex.class)); + + label = door.getAttribute(Door.ARE_DOOR_NAME).toString(); + closePoint.x = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LOCATION_CLOSE_X)).getValue(); + closePoint.y = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LOCATION_CLOSE_Y)).getValue(); + openPoint.x = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LOCATION_OPEN_X)).getValue(); + openPoint.y = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LOCATION_OPEN_Y)).getValue(); + launchPoint.x = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LAUNCH_POINT_X)).getValue(); + launchPoint.y = ((IsNumeric) door.getAttribute(Door.ARE_DOOR_LAUNCH_POINT_Y)).getValue(); } catch (Exception e) { e.printStackTrace(); } - for (int i = 0; i < 2; i++) { - final Polygon poly = createPolygon(shapeCoords[i], 1.0); + for (final DoorInfo info: getDoors()) { + final Polygon poly = createPolygon(info.getCoords(), 1.0); final Rectangle bounds = normalizePolygon(poly); - location[i].x = bounds.x; - location[i].y = bounds.y; - items[i] = new ShapedLayerItem(door, msg[i], poly); - items[i].setName(getCategory()); - items[i].setStrokeColor(AbstractLayerItem.ItemState.NORMAL, COLOR[0]); - items[i].setStrokeColor(AbstractLayerItem.ItemState.HIGHLIGHTED, COLOR[1]); - items[i].setFillColor(AbstractLayerItem.ItemState.NORMAL, COLOR[2]); - items[i].setFillColor(AbstractLayerItem.ItemState.HIGHLIGHTED, COLOR[3]); - items[i].setStroked(true); - items[i].setFilled(true); - items[i].setVisible(isVisible()); + info.setLocation(new Point(bounds.x, bounds.y)); + final ShapedLayerItem item = new ShapedLayerItem(door, info.getMessage(), poly); + item.setName(getCategory()); + item.setStrokeColor(AbstractLayerItem.ItemState.NORMAL, COLOR[0]); + item.setStrokeColor(AbstractLayerItem.ItemState.HIGHLIGHTED, COLOR[1]); + item.setFillColor(AbstractLayerItem.ItemState.NORMAL, COLOR[2]); + item.setFillColor(AbstractLayerItem.ItemState.HIGHLIGHTED, COLOR[3]); + item.setStroked(true); + item.setFilled(true); + item.setVisible(isVisible()); + info.setItem(item); } + + itemIconClose = createValidatedLayerItem(closePoint, label, getIcons(ICONS_CLOSE)); + itemIconOpen = createValidatedLayerItem(openPoint, label, getIcons(ICONS_OPEN)); + itemIconLaunch = createValidatedLayerItem(launchPoint, label, getIcons(ICONS_LAUNCH)); } @Override @@ -84,29 +126,95 @@ public Viewable getViewable() { * @return The layer item of the specified state. */ @Override - public AbstractLayerItem getLayerItem(int type) { + public AbstractLayerItem[] getLayerItems(int type) { + boolean isClosed = (type & ViewerConstants.DOOR_CLOSED) == ViewerConstants.DOOR_CLOSED; + boolean isOpen = (type & ViewerConstants.DOOR_OPEN) == ViewerConstants.DOOR_OPEN; + boolean isIcon = (type & ViewerConstants.LAYER_ITEM_ICON) == ViewerConstants.LAYER_ITEM_ICON; + boolean isPoly = (type & ViewerConstants.LAYER_ITEM_POLY) == ViewerConstants.LAYER_ITEM_POLY; + if (Profile.getEngine() == Profile.Engine.PST) { // open/closed states are inverted for PST - type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_CLOSED : ViewerConstants.DOOR_OPEN; - } else { - type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_OPEN : ViewerConstants.DOOR_CLOSED; + boolean tmp = isClosed; + isClosed = isOpen; + isOpen = tmp; + } + + List list = new ArrayList<>(); + + if (isIcon) { + if (itemIconClose != null) { + list.add(itemIconClose); + } + if (itemIconOpen != null) { + list.add(itemIconOpen); + } + if (itemIconLaunch != null) { + list.add(itemIconLaunch); + } } - return items[type]; + + if (isPoly) { + if (isOpen) { + final DoorInfo info = getDoor(ViewerConstants.DOOR_OPEN); + if (info != null && info.getItem() != null) { + list.add(info.getItem()); + } + } + if (isClosed) { + final DoorInfo info = getDoor(ViewerConstants.DOOR_CLOSED); + if (info != null && info.getItem() != null) { + list.add(info.getItem()); + } + } + } + + return list.toArray(new AbstractLayerItem[0]); } @Override public AbstractLayerItem[] getLayerItems() { - return items; + List list = new ArrayList<>(); + + for (final AbstractLayerItem item : getDoorItems()) { + if (item != null) { + list.add(item); + } + } + + if (itemIconClose != null) { + list.add(itemIconClose); + } + if (itemIconOpen != null) { + list.add(itemIconOpen); + } + if (itemIconLaunch != null) { + list.add(itemIconLaunch); + } + + return list.toArray(new AbstractLayerItem[0]); } @Override public void update(double zoomFactor) { - for (int i = 0; i < items.length; i++) { - items[i].setItemLocation((int) (location[i].x * zoomFactor + (zoomFactor / 2.0)), - (int) (location[i].y * zoomFactor + (zoomFactor / 2.0))); - Polygon poly = createPolygon(shapeCoords[i], zoomFactor); + for (final DoorInfo info : getDoors()) { + info.getItem().setItemLocation((int) (info.getLocation().x * zoomFactor + (zoomFactor / 2.0)), + (int) (info.getLocation().y * zoomFactor + (zoomFactor / 2.0))); + Polygon poly = createPolygon(info.getCoords(), zoomFactor); normalizePolygon(poly); - items[i].setShape(poly); + info.getItem().setShape(poly); + } + + if (itemIconClose != null) { + itemIconClose.setItemLocation((int) (closePoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (closePoint.y * zoomFactor + (zoomFactor / 2.0))); + } + if (itemIconOpen != null) { + itemIconOpen.setItemLocation((int) (openPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (openPoint.y * zoomFactor + (zoomFactor / 2.0))); + } + if (itemIconLaunch != null) { + itemIconLaunch.setItemLocation((int) (launchPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (launchPoint.y * zoomFactor + (zoomFactor / 2.0))); } } @@ -122,7 +230,7 @@ private String getAttributes() { int bit = (Profile.getEngine() == Profile.Engine.IWD2) ? 14 : 10; boolean usesKey = ((Flag) door.getAttribute(Door.ARE_DOOR_FLAGS)).isFlagSet(bit); if (usesKey) { - addResResDesc(sb, door, Door.ARE_DOOR_KEY, "Key: "); + addResRefDesc(sb, door, Door.ARE_DOOR_KEY, "Key: "); } } } @@ -143,4 +251,86 @@ private String getAttributes() { sb.append(']'); return sb.toString(); } + + private IconLayerItem createValidatedLayerItem(Point pt, String label, Image[] icons) { + IconLayerItem retVal = null; + + if (pt.x > 0 && pt.y > 0) { + retVal = new IconLayerItem(door, label, icons[0], CENTER); + retVal.setLabelEnabled(Settings.ShowLabelDoorTargets); + retVal.setName(getCategory()); + retVal.setImage(AbstractLayerItem.ItemState.HIGHLIGHTED, icons[1]); + retVal.setVisible(isVisible()); + } + + return retVal; + } + + private Collection getDoors() { + return doorMap.values(); + } + + private Collection getDoorItems() { + return doorMap.values().stream().map(di -> di.getItem()).filter(item -> item != null).collect(Collectors.toList()); + } + + private DoorInfo getDoor(int id) { + return doorMap.get(Integer.valueOf(id)); + } + + // ----------------------------- INNER CLASSES ----------------------------- + + /** Storage for open/close-based door information. */ + private static class DoorInfo { + private String message; + private ShapedLayerItem item; + private Point location; + private Point[] coords; + + private DoorInfo() {} + + /** Returns a message or label associated with the door. */ + public String getMessage() { + return message; + } + + /** Defines a message or label associated with the door. */ + public DoorInfo setMessage(String msg) { + this.message = msg; + return this; + } + + /** Returns the layer item for the door. */ + public ShapedLayerItem getItem() { + return item; + } + + /** Defines the layer item for the door. */ + public DoorInfo setItem(ShapedLayerItem newItem) { + this.item = newItem; + return this; + } + + /** Returns the origin of the door shape. */ + public Point getLocation() { + return location; + } + + /** Defines the origin of the door shape. */ + public DoorInfo setLocation(Point newLocation) { + this.location = newLocation; + return this; + } + + /** Returns the vertices of the door shape. */ + public Point[] getCoords() { + return coords; + } + + /** Defines the vertices of the door shape. */ + public DoorInfo setCoords(Point[] newCoords) { + this.coords = newCoords; + return this; + } + } } diff --git a/src/org/infinity/resource/are/viewer/LayerObjectDoorPoly.java b/src/org/infinity/resource/are/viewer/LayerObjectDoorPoly.java index a9463a640..b5430e23c 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectDoorPoly.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectDoorPoly.java @@ -8,7 +8,9 @@ import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.infinity.datatype.Flag; import org.infinity.datatype.IsNumeric; @@ -92,18 +94,29 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { + public AbstractLayerItem[] getLayerItems(int type) { + boolean isClosed = (type & ViewerConstants.DOOR_CLOSED) == ViewerConstants.DOOR_CLOSED; + boolean isOpen = (type & ViewerConstants.DOOR_OPEN) == ViewerConstants.DOOR_OPEN; + if (Profile.getEngine() == Profile.Engine.PST) { // open/closed states are inverted for PST - type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_CLOSED : ViewerConstants.DOOR_OPEN; - } else { - type = (type == ViewerConstants.DOOR_OPEN) ? ViewerConstants.DOOR_OPEN : ViewerConstants.DOOR_CLOSED; + boolean tmp = isClosed; + isClosed = isOpen; + isOpen = tmp; + } + + List list = new ArrayList<>(); + if (isOpen) { + if (openCount > 0 && items[0] != null) { + list.add(items[0]); + } } - if (type == ViewerConstants.DOOR_OPEN) { - return (openCount > 0) ? items[0] : null; - } else { - return (items.length - openCount > 0) ? items[openCount] : null; + if (isClosed) { + if (items.length - openCount > 0 && items[openCount] != null) { + list.add(items[openCount]); + } } + return list.toArray(new AbstractLayerItem[0]); } @Override @@ -129,11 +142,22 @@ public void update(double zoomFactor) { * @param state The state of the layer items ({@code Open} or {@code Closed}). * @return An array of layer items. */ - public AbstractLayerItem[] getLayerItems(int state) { - if (state == ViewerConstants.DOOR_OPEN) { + public AbstractLayerItem[] getLayerItemsByState(int state) { + boolean isClosed = (state == ViewerConstants.DOOR_CLOSED); + boolean isOpen = (state == ViewerConstants.DOOR_OPEN); + + if (Profile.getEngine() == Profile.Engine.PST) { + // open/closed states are inverted for PST + boolean tmp = isClosed; + isClosed = isOpen; + isOpen = tmp; + } + + if (isOpen) { return Arrays.copyOf(items, openCount); } - if (state == ViewerConstants.DOOR_CLOSED) { + + if (isClosed) { return Arrays.copyOfRange(items, openCount, items.length); } return new AbstractLayerItem[0]; diff --git a/src/org/infinity/resource/are/viewer/LayerObjectEntrance.java b/src/org/infinity/resource/are/viewer/LayerObjectEntrance.java index be211c46a..23cbee50a 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectEntrance.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectEntrance.java @@ -65,8 +65,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectProTrap.java b/src/org/infinity/resource/are/viewer/LayerObjectProTrap.java index 35a15adb0..721e7b88d 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectProTrap.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectProTrap.java @@ -67,8 +67,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectRegion.java b/src/org/infinity/resource/are/viewer/LayerObjectRegion.java index 960c617be..bb9d5ed52 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectRegion.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectRegion.java @@ -5,24 +5,41 @@ package org.infinity.resource.are.viewer; import java.awt.Color; +import java.awt.Image; import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.List; import org.infinity.datatype.IsNumeric; import org.infinity.datatype.IsTextual; import org.infinity.datatype.ResourceRef; import org.infinity.gui.layeritem.AbstractLayerItem; +import org.infinity.gui.layeritem.IconLayerItem; import org.infinity.gui.layeritem.ShapedLayerItem; +import org.infinity.resource.Profile; import org.infinity.resource.Viewable; import org.infinity.resource.are.AreResource; import org.infinity.resource.are.ITEPoint; +import org.infinity.resource.are.viewer.icon.ViewerIcons; import org.infinity.resource.vertex.Vertex; /** * Handles specific layer type: ARE/Region */ public class LayerObjectRegion extends LayerObject { + private static final Image[] ICONS = { ViewerIcons.ICON_ITM_REGION_TARGET_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_REGION_TARGET_2.getIcon().getImage() }; + + private static final Image[] ICONS_ALT = { ViewerIcons.ICON_ITM_REGION_TARGET_A_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_REGION_TARGET_A_2.getIcon().getImage() }; + + private static final Image[] ICONS_SPEAKER = { ViewerIcons.ICON_ITM_REGION_TARGET_S_1.getIcon().getImage(), + ViewerIcons.ICON_ITM_REGION_TARGET_S_2.getIcon().getImage() }; + + private static final Point CENTER = new Point(13, 29); + private static final Color[][] COLOR = { { new Color(0xFF400000, true), new Color(0xFF400000, true), new Color(0xC0800000, true), new Color(0xC0C00000, true) }, { new Color(0xFF400000, true), new Color(0xFF400000, true), new Color(0xC0804040, true), new Color(0xC0C06060, true) }, @@ -31,13 +48,29 @@ public class LayerObjectRegion extends LayerObject { private final ITEPoint region; private final Point location = new Point(); + private final Point launchPoint = new Point(); + private final Point alternatePoint = new Point(); + private final Point speakerPoint = new Point(); + /** Region area */ private final ShapedLayerItem item; + + /** Launch point of the region. */ + private final IconLayerItem itemIcon; + + /** Optional alternate/activation point of the region. */ + private final IconLayerItem itemIconAlternate; + + /** Optional speaker location of the region (PST/PSTEE). */ + private final IconLayerItem itemIconSpeaker; + private Point[] shapeCoords; + private boolean alternateEnabled; public LayerObjectRegion(AreResource parent, ITEPoint region) { super("Region", ITEPoint.class, parent); this.region = region; + String label = null; String msg = null; int type = 0; try { @@ -56,6 +89,28 @@ ITEPoint.TYPE_ARRAY[type], getAttributes(), final int vNum = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_NUM_VERTICES)).getValue(); final int vOfs = ((IsNumeric) parent.getAttribute(AreResource.ARE_OFFSET_VERTICES)).getValue(); shapeCoords = loadVertices(region, vOfs, 0, vNum, Vertex.class); + + label = region.getAttribute(ITEPoint.ARE_TRIGGER_NAME).toString(); + int flags = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_FLAGS)).getValue(); + alternateEnabled = (flags & (1 << 10)) != 0; + if (alternateEnabled) { + if (Profile.getEngine() == Profile.Engine.IWD || Profile.getEngine() == Profile.Engine.IWD2) { + alternatePoint.x = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_ALTERNATE_POINT_X)).getValue(); + alternatePoint.y = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_ALTERNATE_POINT_Y)).getValue(); + } else if (Profile.getEngine() != Profile.Engine.PST) { + alternatePoint.x = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_ACTIVATION_POINT_X)).getValue(); + alternatePoint.y = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_ACTIVATION_POINT_Y)).getValue(); + } + } else { + launchPoint.x = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_LAUNCH_POINT_X)).getValue(); + launchPoint.y = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_LAUNCH_POINT_Y)).getValue(); + } + if (Profile.getEngine() == Profile.Engine.PST || Profile.getGame() == Profile.Game.PSTEE) { + if (!((ResourceRef) region.getAttribute(ITEPoint.ARE_TRIGGER_DIALOG)).isEmpty()) { + speakerPoint.x = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_SPEAKER_POINT_X)).getValue(); + speakerPoint.y = ((IsNumeric) region.getAttribute(ITEPoint.ARE_TRIGGER_SPEAKER_POINT_Y)).getValue(); + } + } } catch (Exception e) { e.printStackTrace(); } @@ -74,6 +129,15 @@ ITEPoint.TYPE_ARRAY[type], getAttributes(), item.setStroked(true); item.setFilled(true); item.setVisible(isVisible()); + + itemIconSpeaker = createValidatedLayerItem(speakerPoint, label, getIcons(ICONS_SPEAKER)); + if (alternateEnabled) { + itemIcon = null; + itemIconAlternate = createValidatedLayerItem(alternatePoint, label, getIcons(ICONS_ALT)); + } else { + itemIcon = createValidatedLayerItem(launchPoint, label, getIcons(ICONS)); + itemIconAlternate = null; + } } @Override @@ -82,13 +146,45 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + switch (type) { + case ViewerConstants.LAYER_ITEM_POLY: + if (item != null) { + return new AbstractLayerItem[] { item }; + } + break; + case ViewerConstants.LAYER_ITEM_ICON: + final List list = new ArrayList<>(); + if (itemIcon != null) { + list.add(itemIcon); + } + if (itemIconAlternate != null) { + list.add(itemIconAlternate); + } + if (itemIconSpeaker != null) { + list.add(itemIconSpeaker); + } + return list.toArray(new AbstractLayerItem[0]); + } + return new AbstractLayerItem[0]; } @Override public AbstractLayerItem[] getLayerItems() { - return new AbstractLayerItem[] { item }; + final List retVal = new ArrayList<>(); + if (item != null) { + retVal.add(item); + } + if (itemIcon != null) { + retVal.add(itemIcon); + } + if (itemIconAlternate != null) { + retVal.add(itemIconAlternate); + } + if (itemIconSpeaker != null) { + retVal.add(itemIconSpeaker); + } + return retVal.toArray(new AbstractLayerItem[0]); } @Override @@ -100,6 +196,21 @@ public void update(double zoomFactor) { normalizePolygon(poly); item.setShape(poly); } + + if (itemIcon != null) { + itemIcon.setItemLocation((int) (launchPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (launchPoint.y * zoomFactor + (zoomFactor / 2.0))); + } + + if (itemIconAlternate != null) { + itemIconAlternate.setItemLocation((int) (alternatePoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (alternatePoint.y * zoomFactor + (zoomFactor / 2.0))); + } + + if (itemIconSpeaker != null) { + itemIconSpeaker.setItemLocation((int) (speakerPoint.x * zoomFactor + (zoomFactor / 2.0)), + (int) (speakerPoint.y * zoomFactor + (zoomFactor / 2.0))); + } } private String getAttributes() { @@ -130,4 +241,18 @@ private String getAttributes() { sb.append(']'); return sb.toString(); } + + private IconLayerItem createValidatedLayerItem(Point pt, String label, Image[] icons) { + IconLayerItem retVal = null; + + if (pt.x > 0 && pt.y > 0) { + retVal = new IconLayerItem(region, label, icons[0], CENTER); + retVal.setLabelEnabled(Settings.ShowLabelRegionTargets); + retVal.setName(getCategory()); + retVal.setImage(AbstractLayerItem.ItemState.HIGHLIGHTED, icons[1]); + retVal.setVisible(isVisible()); + } + + return retVal; + } } diff --git a/src/org/infinity/resource/are/viewer/LayerObjectSpawnPoint.java b/src/org/infinity/resource/are/viewer/LayerObjectSpawnPoint.java index ce9acba36..da58e3381 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectSpawnPoint.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectSpawnPoint.java @@ -62,8 +62,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectTransition.java b/src/org/infinity/resource/are/viewer/LayerObjectTransition.java index d9877432b..6d63f86c0 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectTransition.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectTransition.java @@ -67,8 +67,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerObjectWallPoly.java b/src/org/infinity/resource/are/viewer/LayerObjectWallPoly.java index 3b141209a..148569a1d 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectWallPoly.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectWallPoly.java @@ -69,8 +69,11 @@ public Viewable getViewable() { } @Override - public AbstractLayerItem getLayerItem(int type) { - return (type == 0) ? item : null; + public AbstractLayerItem[] getLayerItems(int type) { + if (type == 0 && item != null) { + return new AbstractLayerItem[] { item }; + } + return new AbstractLayerItem[0]; } @Override diff --git a/src/org/infinity/resource/are/viewer/LayerRegion.java b/src/org/infinity/resource/are/viewer/LayerRegion.java index d07213c3b..a32f0d4f8 100644 --- a/src/org/infinity/resource/are/viewer/LayerRegion.java +++ b/src/org/infinity/resource/are/viewer/LayerRegion.java @@ -13,7 +13,7 @@ /** * Manages region layer objects. */ -public class LayerRegion extends BasicLayer { +public class LayerRegion extends BasicTargetLayer { private static final String AVAILABLE_FMT = "Regions: %d"; public LayerRegion(AreResource are, AreaViewer viewer) { diff --git a/src/org/infinity/resource/are/viewer/Settings.java b/src/org/infinity/resource/are/viewer/Settings.java index 3020e2423..254a48613 100644 --- a/src/org/infinity/resource/are/viewer/Settings.java +++ b/src/org/infinity/resource/are/viewer/Settings.java @@ -19,6 +19,9 @@ public class Settings { // Default layer order on map public static final ViewerConstants.LayerStackingType[] DEFAULT_LAYER_ORDER = { + ViewerConstants.LayerStackingType.CONTAINER_TARGET, + ViewerConstants.LayerStackingType.REGION_TARGET, + ViewerConstants.LayerStackingType.DOOR_TARGET, ViewerConstants.LayerStackingType.ACTOR, ViewerConstants.LayerStackingType.ENTRANCE, ViewerConstants.LayerStackingType.AMBIENT, @@ -62,6 +65,12 @@ public class Settings { public static boolean DrawGrid = getDefaultDrawGrid(); // Current visibility state of ambient range items public static boolean ShowAmbientRanges = getDefaultAmbientRanges(); + // Current visibility state of container target locations + public static boolean ShowContainerTargets = getDefaultShowContainerTargets(); + // Current visibility state of door target locations + public static boolean ShowDoorTargets = getDefaultShowDoorTargets(); + // Current visibility state of region target locations + public static boolean ShowRegionTargets = getDefaultShowRegionTargets(); // Defines whether to ignore time schedules on layer items public static boolean EnableSchedules = getDefaultEnableSchedules(); // Defines whether to ignore the "Is shown" flag of background animations @@ -104,6 +113,9 @@ public class Settings { public static boolean ShowLabelActorsAre = getDefaultLabelActorsAre(); public static boolean ShowLabelActorsIni = getDefaultLabelActorsIni(); // public static boolean ShowLabelRegions = getDefaultLabelRegions(); + public static boolean ShowLabelContainerTargets = getDefaultLabelRegionTargets(); + public static boolean ShowLabelDoorTargets = getDefaultLabelRegionTargets(); + public static boolean ShowLabelRegionTargets = getDefaultLabelRegionTargets(); public static boolean ShowLabelEntrances = getDefaultLabelEntrances(); // public static boolean ShowLabelContainers = getDefaultLabelContainers(); public static boolean ShowLabelSounds = getDefaultLabelSounds(); @@ -132,6 +144,9 @@ public class Settings { private static final String PREFS_LAYERFLAGS = "LayerFlags"; private static final String PREFS_SHOWREALACTORS = "ShowRealActors"; private static final String PREFS_SHOWREALANIMS = "ShowRealAnimations"; + private static final String PREFS_SHOWCONTAINERTARGETS = "ShowContainerTargets"; + private static final String PREFS_SHOWDOORTARGETS = "ShowDoorTargets"; + private static final String PREFS_SHOWREGIONTARGETS = "ShowRegionTargets"; private static final String PREFS_TIMEOFDAY = "TimeOfDay"; private static final String PREFS_ZOOMFACTOR = "ZoomFactor"; private static final String PREFS_LAYERZORDER_FMT = "LayerZOrder%d"; @@ -143,13 +158,13 @@ public class Settings { private static final String PREFS_MINIMAP = "MiniMap"; private static final String PREFS_LABEL_ACTOR_ARE = "LabelActorAre"; private static final String PREFS_LABEL_ACTOR_INI = "LabelActorIni"; -// private static final String PREFS_LABEL_REGIONS = "LabelRegions"; - private static final String PREFS_LABEL_ENTRANCES = "LabelEntrances"; -// private static final String PREFS_LABEL_CONTAINERS = "LabelContainers"; - private static final String PREFS_LABEL_SOUNDS = "LabelSounds"; -// private static final String PREFS_LABEL_DOORS = "LabelDoors"; private static final String PREFS_LABEL_ANIMATIONS = "LabelAnimations"; + private static final String PREFS_LABEL_CONTAINER_TARGETS = "LabelContainerTargets"; + private static final String PREFS_LABEL_DOOR_TARGETS = "LabelDoorTargets"; + private static final String PREFS_LABEL_ENTRANCES = "LabelEntrances"; private static final String PREFS_LABEL_MAPNOTES = "LabelMapNotes"; + private static final String PREFS_LABEL_REGION_TARGETS = "LabelRegionTargets"; + private static final String PREFS_LABEL_SOUNDS = "LabelSounds"; private static final String PREFS_LABEL_SPAWNPOINTS = "LabelSpawnPoints"; private static boolean SettingsLoaded = false; @@ -181,13 +196,13 @@ public static void loadSettings(boolean force) { MiniMapAlpha = prefs.getDouble(PREFS_MINIMAP_ALPHA, getDefaultMiniMapAlpha()); ShowLabelActorsAre = prefs.getBoolean(PREFS_LABEL_ACTOR_ARE, getDefaultLabelActorsAre()); ShowLabelActorsIni = prefs.getBoolean(PREFS_LABEL_ACTOR_INI, getDefaultLabelActorsIni()); - // ShowLabelRegions = prefs.getBoolean(PREFS_LABEL_REGIONS, getDefaultLabelRegions()); - ShowLabelEntrances = prefs.getBoolean(PREFS_LABEL_ENTRANCES, getDefaultLabelEntrances()); - // ShowLabelContainers = prefs.getBoolean(PREFS_LABEL_CONTAINERS, getDefaultLabelContainers()); - ShowLabelSounds = prefs.getBoolean(PREFS_LABEL_SOUNDS, getDefaultLabelSounds()); - // ShowLabelDoors = prefs.getBoolean(PREFS_LABEL_DOORS, getDefaultLabelDoors()); ShowLabelAnimations = prefs.getBoolean(PREFS_LABEL_ANIMATIONS, getDefaultLabelAnimations()); + ShowLabelContainerTargets = prefs.getBoolean(PREFS_LABEL_CONTAINER_TARGETS, getDefaultLabelContainerTargets()); + ShowLabelDoorTargets = prefs.getBoolean(PREFS_LABEL_DOOR_TARGETS, getDefaultLabelDoorTargets()); + ShowLabelEntrances = prefs.getBoolean(PREFS_LABEL_ENTRANCES, getDefaultLabelEntrances()); ShowLabelMapNotes = prefs.getBoolean(PREFS_LABEL_MAPNOTES, getDefaultLabelMapNotes()); + ShowLabelRegionTargets = prefs.getBoolean(PREFS_LABEL_REGION_TARGETS, getDefaultLabelRegionTargets()); + ShowLabelSounds = prefs.getBoolean(PREFS_LABEL_SOUNDS, getDefaultLabelSounds()); ShowLabelSpawnPoints = prefs.getBoolean(PREFS_LABEL_SPAWNPOINTS, getDefaultLabelSpawnPoints()); // loading layer z-order @@ -208,6 +223,9 @@ public static void loadSettings(boolean force) { DrawOverlays = prefs.getBoolean(PREFS_DRAWOVERLAYS, getDefaultDrawOverlays()); DrawGrid = prefs.getBoolean(PREFS_DRAWGRID, getDefaultDrawGrid()); ShowAmbientRanges = prefs.getBoolean(PREFS_SHOWAMBIENT, getDefaultAmbientRanges()); + ShowContainerTargets = prefs.getBoolean(PREFS_SHOWCONTAINERTARGETS, getDefaultShowContainerTargets()); + ShowDoorTargets = prefs.getBoolean(PREFS_SHOWDOORTARGETS, getDefaultShowDoorTargets()); + ShowRegionTargets = prefs.getBoolean(PREFS_SHOWREGIONTARGETS, getDefaultShowRegionTargets()); SidebarControls = prefs.getInt(PREFS_SIDEBARCONTROLS, getDefaultSidebarControls()); LayerFlags = prefs.getInt(PREFS_LAYERFLAGS, getDefaultLayerFlags()); ShowActorSprites = prefs.getInt(PREFS_SHOWREALACTORS, getDefaultShowRealActors()); @@ -248,13 +266,13 @@ public static void storeSettings(boolean force) { prefs.putDouble(PREFS_MINIMAP_ALPHA, MiniMapAlpha); prefs.putBoolean(PREFS_LABEL_ACTOR_ARE, ShowLabelActorsAre); prefs.putBoolean(PREFS_LABEL_ACTOR_INI, ShowLabelActorsIni); - // prefs.putBoolean(PREFS_LABEL_REGIONS, ShowLabelRegions); - prefs.putBoolean(PREFS_LABEL_ENTRANCES, ShowLabelEntrances); - // prefs.putBoolean(PREFS_LABEL_CONTAINERS, ShowLabelContainers); - prefs.putBoolean(PREFS_LABEL_SOUNDS, ShowLabelSounds); - // prefs.putBoolean(PREFS_LABEL_DOORS, ShowLabelDoors); prefs.putBoolean(PREFS_LABEL_ANIMATIONS, ShowLabelAnimations); + prefs.putBoolean(PREFS_LABEL_CONTAINER_TARGETS, ShowLabelContainerTargets); + prefs.putBoolean(PREFS_LABEL_DOOR_TARGETS, ShowLabelDoorTargets); + prefs.putBoolean(PREFS_LABEL_ENTRANCES, ShowLabelEntrances); prefs.putBoolean(PREFS_LABEL_MAPNOTES, ShowLabelMapNotes); + prefs.putBoolean(PREFS_LABEL_REGION_TARGETS, ShowLabelRegionTargets); + prefs.putBoolean(PREFS_LABEL_SOUNDS, ShowLabelSounds); prefs.putBoolean(PREFS_LABEL_SPAWNPOINTS, ShowLabelSpawnPoints); // storing layer z-order @@ -269,6 +287,9 @@ public static void storeSettings(boolean force) { prefs.putBoolean(PREFS_DRAWOVERLAYS, DrawOverlays); prefs.putBoolean(PREFS_DRAWGRID, DrawGrid); prefs.putBoolean(PREFS_SHOWAMBIENT, ShowAmbientRanges); + prefs.putBoolean(PREFS_SHOWCONTAINERTARGETS, ShowContainerTargets); + prefs.putBoolean(PREFS_SHOWDOORTARGETS, ShowDoorTargets); + prefs.putBoolean(PREFS_SHOWREGIONTARGETS, ShowRegionTargets); prefs.putInt(PREFS_SIDEBARCONTROLS, SidebarControls); prefs.putInt(PREFS_LAYERFLAGS, LayerFlags); prefs.putInt(PREFS_SHOWREALACTORS, ShowActorSprites); @@ -367,6 +388,18 @@ public static boolean getDefaultAmbientRanges() { return false; } + public static boolean getDefaultShowContainerTargets() { + return false; + } + + public static boolean getDefaultShowDoorTargets() { + return false; + } + + public static boolean getDefaultShowRegionTargets() { + return false; + } + public static boolean getDefaultEnableSchedules() { return false; } @@ -483,29 +516,26 @@ public static boolean getDefaultLabelActorsIni() { return true; } - // public static boolean getDefaultLabelRegions() - // { - // return false; - // } + public static boolean getDefaultLabelContainerTargets() { + return true; + } + + public static boolean getDefaultLabelDoorTargets() { + return true; + } + + public static boolean getDefaultLabelRegionTargets() { + return true; + } public static boolean getDefaultLabelEntrances() { return false; } - // public static boolean getDefaultLabelContainers() - // { - // return false; - // } - public static boolean getDefaultLabelSounds() { return false; } - // public static boolean getDefaultLabelDoors() - // { - // return false; - // } - public static boolean getDefaultLabelAnimations() { return false; } @@ -531,8 +561,10 @@ public static LayerType stackingToLayer(LayerStackingType type) { case AUTOMAP: return LayerType.AUTOMAP; case CONTAINER: + case CONTAINER_TARGET: return LayerType.CONTAINER; case DOOR: + case DOOR_TARGET: return LayerType.DOOR; case DOOR_POLY: return LayerType.DOOR_POLY; @@ -541,6 +573,7 @@ public static LayerType stackingToLayer(LayerStackingType type) { case PRO_TRAP: return LayerType.PRO_TRAP; case REGION: + case REGION_TARGET: return LayerType.REGION; case SPAWN_POINT: return LayerType.SPAWN_POINT; @@ -553,37 +586,37 @@ public static LayerType stackingToLayer(LayerStackingType type) { } } - // Converts values from LayerType to LayerStackingType (ignoring AmbientRange) - public static LayerStackingType layerToStacking(LayerType type) { + // Converts values from LayerType to LayerStackingType(s) + public static LayerStackingType[] layerToStacking(LayerType type) { switch (type) { case ACTOR: - return LayerStackingType.ACTOR; + return new LayerStackingType[] { LayerStackingType.ACTOR }; case AMBIENT: - return LayerStackingType.AMBIENT; + return new LayerStackingType[] { LayerStackingType.AMBIENT, LayerStackingType.AMBIENT_RANGE }; case ANIMATION: - return LayerStackingType.ANIMATION; + return new LayerStackingType[] { LayerStackingType.ANIMATION }; case AUTOMAP: - return LayerStackingType.AUTOMAP; + return new LayerStackingType[] { LayerStackingType.AUTOMAP }; case CONTAINER: - return LayerStackingType.CONTAINER; + return new LayerStackingType[] { LayerStackingType.CONTAINER, LayerStackingType.CONTAINER_TARGET }; case DOOR: - return LayerStackingType.DOOR; + return new LayerStackingType[] { LayerStackingType.DOOR, LayerStackingType.DOOR_TARGET }; case DOOR_POLY: - return LayerStackingType.DOOR_POLY; + return new LayerStackingType[] { LayerStackingType.DOOR_POLY }; case ENTRANCE: - return LayerStackingType.ENTRANCE; + return new LayerStackingType[] { LayerStackingType.ENTRANCE }; case PRO_TRAP: - return LayerStackingType.PRO_TRAP; + return new LayerStackingType[] { LayerStackingType.PRO_TRAP }; case REGION: - return LayerStackingType.REGION; + return new LayerStackingType[] { LayerStackingType.REGION, LayerStackingType.REGION_TARGET }; case SPAWN_POINT: - return LayerStackingType.SPAWN_POINT; + return new LayerStackingType[] { LayerStackingType.SPAWN_POINT }; case TRANSITION: - return LayerStackingType.TRANSITION; + return new LayerStackingType[] { LayerStackingType.TRANSITION }; case WALL_POLY: - return LayerStackingType.WALL_POLY; + return new LayerStackingType[] { LayerStackingType.WALL_POLY }; default: - return null; + return new LayerStackingType[0]; } } diff --git a/src/org/infinity/resource/are/viewer/SettingsDialog.java b/src/org/infinity/resource/are/viewer/SettingsDialog.java index e54a98d41..7c64a29ab 100644 --- a/src/org/infinity/resource/are/viewer/SettingsDialog.java +++ b/src/org/infinity/resource/are/viewer/SettingsDialog.java @@ -17,6 +17,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; +import java.util.EnumMap; import java.util.Hashtable; import java.util.List; @@ -57,24 +58,21 @@ public class SettingsDialog extends JDialog implements ActionListener, ListSelec "Always use nearest neighbor filtering", "Always use bilinear filtering" }; - private static final String[] LayerDesc = { "Actors", "Regions", "Entrances", "Containers", "Ambient Sounds", - "Ambient Sound Ranges", "Doors", "Background Animations", "Automap Notes", - "Spawn Points", "Map Transitions", "Projectile Traps", "Door Polygons", - "Wall Polygons" }; - - private static final int INDEX_LABEL_ACTORS_ARE = 0; - private static final int INDEX_LABEL_ACTORS_INI = 1; -// private static final int INDEX_LABEL_REGIONS = 2; - private static final int INDEX_LABEL_ENTRANCES = 2; -// private static final int INDEX_LABEL_CONTAINERS = 4; - private static final int INDEX_LABEL_SOUNDS = 3; -// private static final int INDEX_LABEL_DOORS = 6; - private static final int INDEX_LABEL_ANIMATIONS = 4; - private static final int INDEX_LABEL_MAPNOTES = 5; - private static final int INDEX_LABEL_SPAWNPOINTS = 6; - private static final int INDEX_LABEL_COUNT = 7; - - private JCheckBox[] cbLabels; + private enum LabelIndex { + ActorsAre, + ActorsIni, + RegionTargets, + Entrances, + ContainerTargets, + Sounds, + DoorTargets, + Animations, + MapNotes, + SpawnPoints, + } + + private final EnumMap labelsMap = new EnumMap<>(LabelIndex.class); + private SimpleListModel modelLayers; private JList listLayers; private JButton bUp; @@ -149,16 +147,16 @@ private void updateSettings() { Settings.LIST_LAYER_ORDER.set(i, lt.layer); } - Settings.ShowLabelActorsAre = cbLabels[INDEX_LABEL_ACTORS_ARE].isSelected(); - Settings.ShowLabelActorsIni = cbLabels[INDEX_LABEL_ACTORS_INI].isSelected(); - // Settings.ShowLabelRegions = cbLabels[INDEX_LABEL_REGIONS].isSelected(); - Settings.ShowLabelEntrances = cbLabels[INDEX_LABEL_ENTRANCES].isSelected(); - // Settings.ShowLabelContainers = cbLabels[INDEX_LABEL_CONTAINERS].isSelected(); - Settings.ShowLabelSounds = cbLabels[INDEX_LABEL_SOUNDS].isSelected(); - // Settings.ShowLabelDoors = cbLabels[INDEX_LABEL_DOORS].isSelected(); - Settings.ShowLabelAnimations = cbLabels[INDEX_LABEL_ANIMATIONS].isSelected(); - Settings.ShowLabelMapNotes = cbLabels[INDEX_LABEL_MAPNOTES].isSelected(); - Settings.ShowLabelSpawnPoints = cbLabels[INDEX_LABEL_SPAWNPOINTS].isSelected(); + Settings.ShowLabelActorsAre = labelsMap.get(LabelIndex.ActorsAre).isSelected(); + Settings.ShowLabelActorsIni = labelsMap.get(LabelIndex.ActorsIni).isSelected(); + Settings.ShowLabelAnimations = labelsMap.get(LabelIndex.Animations).isSelected(); + Settings.ShowLabelContainerTargets = labelsMap.get(LabelIndex.ContainerTargets).isSelected(); + Settings.ShowLabelDoorTargets = labelsMap.get(LabelIndex.DoorTargets).isSelected(); + Settings.ShowLabelEntrances = labelsMap.get(LabelIndex.Entrances).isSelected(); + Settings.ShowLabelMapNotes = labelsMap.get(LabelIndex.MapNotes).isSelected(); + Settings.ShowLabelRegionTargets = labelsMap.get(LabelIndex.RegionTargets).isSelected(); + Settings.ShowLabelSounds = labelsMap.get(LabelIndex.Sounds).isSelected(); + Settings.ShowLabelSpawnPoints = labelsMap.get(LabelIndex.SpawnPoints).isSelected(); Settings.ShowActorFrame = cbActorFrames.getSelectedIndex(); Settings.ShowActorSelectionCircle = cbShowActorSelectionCircle.isSelected(); @@ -191,7 +189,7 @@ private void resetLayerOrder() { modelLayers.clear(); List list = Settings.getDefaultLayerOrder(); for (LayerStackingType layer : list) { - String desc = LayerDesc[Settings.getLayerStackingTypeIndex(layer)]; + String desc = layer.getLabel(); modelLayers.addElement(new LayerEntry(layer, desc)); } list.clear(); @@ -204,16 +202,16 @@ private void resetLayerOrder() { private void resetDialogSettings() { resetLayerOrder(); - cbLabels[INDEX_LABEL_ACTORS_ARE].setSelected(Settings.getDefaultLabelActorsAre()); - cbLabels[INDEX_LABEL_ACTORS_INI].setSelected(Settings.getDefaultLabelActorsIni()); - // cbLabels[INDEX_LABEL_REGIONS].setSelected(Settings.getDefaultLabelRegions()); - cbLabels[INDEX_LABEL_ENTRANCES].setSelected(Settings.getDefaultLabelEntrances()); - // cbLabels[INDEX_LABEL_CONTAINERS].setSelected(Settings.getDefaultLabelContainers()); - cbLabels[INDEX_LABEL_SOUNDS].setSelected(Settings.getDefaultLabelSounds()); - // cbLabels[INDEX_LABEL_DOORS].setSelected(Settings.getDefaultLabelDoors()); - cbLabels[INDEX_LABEL_ANIMATIONS].setSelected(Settings.getDefaultLabelAnimations()); - cbLabels[INDEX_LABEL_MAPNOTES].setSelected(Settings.getDefaultLabelMapNotes()); - cbLabels[INDEX_LABEL_SPAWNPOINTS].setSelected(Settings.getDefaultLabelSpawnPoints()); + labelsMap.get(LabelIndex.ActorsAre).setSelected(Settings.getDefaultLabelActorsAre()); + labelsMap.get(LabelIndex.ActorsIni).setSelected(Settings.getDefaultLabelActorsIni()); + labelsMap.get(LabelIndex.Animations).setSelected(Settings.getDefaultLabelAnimations()); + labelsMap.get(LabelIndex.ContainerTargets).setSelected(Settings.getDefaultLabelContainerTargets()); + labelsMap.get(LabelIndex.DoorTargets).setSelected(Settings.getDefaultLabelDoorTargets()); + labelsMap.get(LabelIndex.Entrances).setSelected(Settings.getDefaultLabelEntrances()); + labelsMap.get(LabelIndex.MapNotes).setSelected(Settings.getDefaultLabelMapNotes()); + labelsMap.get(LabelIndex.RegionTargets).setSelected(Settings.getDefaultLabelRegionTargets()); + labelsMap.get(LabelIndex.Sounds).setSelected(Settings.getDefaultLabelSounds()); + labelsMap.get(LabelIndex.SpawnPoints).setSelected(Settings.getDefaultLabelSpawnPoints()); cbActorFrames.setSelectedIndex(Settings.getDefaultShowActorFrame()); cbShowActorSelectionCircle.setSelected(Settings.getDefaultActorSelectionCircle()); @@ -277,7 +275,7 @@ private void init() { listLayers.setBorder(BorderFactory.createLineBorder(getForeground())); // filling list with layer entries for (LayerStackingType layer : Settings.LIST_LAYER_ORDER) { - String desc = LayerDesc[Settings.getLayerStackingTypeIndex(layer)]; + String desc = layer.getLabel(); modelLayers.addElement(new LayerEntry(layer, desc)); } Dimension d = listLayers.getPreferredSize(); @@ -341,41 +339,36 @@ private void init() { // Icon labels JPanel pShowLabels = new JPanel(new GridBagLayout()); pShowLabels.setBorder(BorderFactory.createTitledBorder("Show icon labels for: ")); - cbLabels = new JCheckBox[INDEX_LABEL_COUNT]; - cbLabels[INDEX_LABEL_ACTORS_ARE] = new JCheckBox("Actors (ARE)"); - cbLabels[INDEX_LABEL_ACTORS_ARE].setSelected(Settings.ShowLabelActorsAre); - cbLabels[INDEX_LABEL_ACTORS_INI] = new JCheckBox("Actors (INI)"); - cbLabels[INDEX_LABEL_ACTORS_INI].setSelected(Settings.ShowLabelActorsIni); - // cbLabels[INDEX_LABEL_REGIONS] = new JCheckBox("Regions"); - // cbLabels[INDEX_LABEL_REGIONS].setEnabled(false); - // cbLabels[INDEX_LABEL_REGIONS].setToolTipText("Not yet supported"); - // cbLabels[INDEX_LABEL_REGIONS].setSelected(Settings.ShowLabelRegions); - cbLabels[INDEX_LABEL_ENTRANCES] = new JCheckBox("Entrances"); - cbLabels[INDEX_LABEL_ENTRANCES].setSelected(Settings.ShowLabelEntrances); - // cbLabels[INDEX_LABEL_CONTAINERS] = new JCheckBox("Containers"); - // cbLabels[INDEX_LABEL_CONTAINERS].setEnabled(false); - // cbLabels[INDEX_LABEL_CONTAINERS].setToolTipText("Not yet supported"); - // cbLabels[INDEX_LABEL_CONTAINERS].setSelected(Settings.ShowLabelContainers); - cbLabels[INDEX_LABEL_SOUNDS] = new JCheckBox("Ambient Sounds"); - cbLabels[INDEX_LABEL_SOUNDS].setSelected(Settings.ShowLabelSounds); - // cbLabels[INDEX_LABEL_DOORS] = new JCheckBox("Doors"); - // cbLabels[INDEX_LABEL_DOORS].setEnabled(false); - // cbLabels[INDEX_LABEL_DOORS].setToolTipText("Not yet supported"); - // cbLabels[INDEX_LABEL_DOORS].setSelected(Settings.ShowLabelDoors); - cbLabels[INDEX_LABEL_ANIMATIONS] = new JCheckBox("Background Animations"); - cbLabels[INDEX_LABEL_ANIMATIONS].setSelected(Settings.ShowLabelAnimations); - cbLabels[INDEX_LABEL_MAPNOTES] = new JCheckBox("Automap Notes"); - cbLabels[INDEX_LABEL_MAPNOTES].setSelected(Settings.ShowLabelMapNotes); - cbLabels[INDEX_LABEL_SPAWNPOINTS] = new JCheckBox("Spawn Points"); - cbLabels[INDEX_LABEL_SPAWNPOINTS].setSelected(Settings.ShowLabelSpawnPoints); - for (int idx = 0; idx < cbLabels.length; idx++) { - // spread entries over two columns + labelsMap.put(LabelIndex.ActorsAre, new JCheckBox("Actors (ARE)")); + labelsMap.get(LabelIndex.ActorsAre).setSelected(Settings.ShowLabelActorsAre); + labelsMap.put(LabelIndex.ActorsIni, new JCheckBox("Actors (INI)")); + labelsMap.get(LabelIndex.ActorsIni).setSelected(Settings.ShowLabelActorsIni); + labelsMap.put(LabelIndex.Animations, new JCheckBox("Background Animations")); + labelsMap.get(LabelIndex.Animations).setSelected(Settings.ShowLabelAnimations); + labelsMap.put(LabelIndex.ContainerTargets, new JCheckBox("Container targets")); + labelsMap.get(LabelIndex.ContainerTargets).setSelected(Settings.ShowLabelContainerTargets); + labelsMap.put(LabelIndex.DoorTargets, new JCheckBox("Door targets")); + labelsMap.get(LabelIndex.DoorTargets).setSelected(Settings.ShowLabelDoorTargets); + labelsMap.put(LabelIndex.Entrances, new JCheckBox("Entrances")); + labelsMap.get(LabelIndex.Entrances).setSelected(Settings.ShowLabelEntrances); + labelsMap.put(LabelIndex.MapNotes, new JCheckBox("Automap Notes")); + labelsMap.get(LabelIndex.MapNotes).setSelected(Settings.ShowLabelMapNotes); + labelsMap.put(LabelIndex.RegionTargets, new JCheckBox("Region targets")); + labelsMap.get(LabelIndex.RegionTargets).setSelected(Settings.ShowLabelRegionTargets); + labelsMap.put(LabelIndex.Sounds, new JCheckBox("Ambient Sounds")); + labelsMap.get(LabelIndex.Sounds).setSelected(Settings.ShowLabelSounds); + labelsMap.put(LabelIndex.SpawnPoints, new JCheckBox("Spawn Points")); + labelsMap.get(LabelIndex.SpawnPoints).setSelected(Settings.ShowLabelSpawnPoints); + + // spread entries over two columns + for (int idx = 0, len = LabelIndex.values().length; idx < len; idx++) { + final LabelIndex li = LabelIndex.values()[idx]; int x = idx & 1; int y = idx / 2; - int bottom = (idx == cbLabels.length - 1 || (idx == cbLabels.length - 2 && x == 0)) ? 4 : 0; + int bottom = (idx == len - 1 || (idx == len - 2 && x == 0)) ? 4 : 0; c = ViewerUtil.setGBC(c, x, y, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 4, bottom, 4), 0, 0); - pShowLabels.add(cbLabels[idx], c); + pShowLabels.add(labelsMap.get(li), c); } // Actor animation options diff --git a/src/org/infinity/resource/are/viewer/ViewerConstants.java b/src/org/infinity/resource/are/viewer/ViewerConstants.java index 24bb5821a..8f34b92b9 100644 --- a/src/org/infinity/resource/are/viewer/ViewerConstants.java +++ b/src/org/infinity/resource/are/viewer/ViewerConstants.java @@ -14,14 +14,74 @@ public final class ViewerConstants { * Supported layer types. */ public static enum LayerType { - ACTOR, REGION, ENTRANCE, CONTAINER, AMBIENT, DOOR, ANIMATION, AUTOMAP, SPAWN_POINT, TRANSITION, PRO_TRAP, DOOR_POLY, - WALL_POLY + ACTOR("Actors", true), + REGION("Regions", true), + ENTRANCE("Entrances", true), + CONTAINER("Containers", true), + AMBIENT("Ambient Sounds", true), + DOOR("Doors", true), + ANIMATION("Background Animations", true), + AUTOMAP("Automap Notes", true), + SPAWN_POINT("Spawn Points", true), + TRANSITION("Map Transitions", true), + PRO_TRAP("Projectile Traps", true), + DOOR_POLY("Door Polygons", false), + WALL_POLY("Wall Polygons", false), + ; + + private final boolean isAre; + private final String label; + private LayerType(String label, boolean isAre) { + this.label = label; + this.isAre = isAre; + } + + /** Returns a label associated with the layer type. */ + public String getLabel() { + return label; + } + + /** Returns whether the layer type is defined in ARE resources. */ + public boolean isAre() { + return isAre; + } + + /** Returns whether the layer type is defined in WED resources. */ + public boolean isWed() { + return !isAre; + } } // Used for setting stacking order on map public static enum LayerStackingType { - ACTOR, REGION, ENTRANCE, CONTAINER, AMBIENT, AMBIENT_RANGE, DOOR, ANIMATION, AUTOMAP, SPAWN_POINT, TRANSITION, - PRO_TRAP, DOOR_POLY, WALL_POLY + ACTOR("Actors"), + REGION_TARGET("Region targets"), + CONTAINER_TARGET("Container targets"), + DOOR_TARGET("Door targets"), + REGION("Regions"), + ENTRANCE("Entrances"), + CONTAINER("Containers"), + AMBIENT("Ambient Sounds"), + AMBIENT_RANGE("Ambient Sound Ranges"), + DOOR("Doors"), + ANIMATION("Background Animations"), + AUTOMAP("Automap Notes"), + SPAWN_POINT("Spawn Points"), + TRANSITION("Map Transitions"), + PRO_TRAP("Projectile Traps"), + DOOR_POLY("Door Polygons"), + WALL_POLY("Wall Polygons"), + ; + + private final String label; + private LayerStackingType(String label) { + this.label = label; + } + + /** Returns a label associated with the layer stacking type. */ + public String getLabel() { + return label; + } } // Flags that identify the different control sections in the sidebar @@ -68,13 +128,20 @@ public static enum LayerStackingType { public static final int ANIM_SHOW_STILL = 1; public static final int ANIM_SHOW_ANIMATED = 2; - // Door state indices (LayerObjectDoor) - public static final int DOOR_OPEN = 0; - public static final int DOOR_CLOSED = 1; + // The layer item types used (LayerObjectContainer, LayerObjectDoor, LayerObjectRegion) + public static final int LAYER_ITEM_POLY = 1 << 0; + public static final int LAYER_ITEM_ICON = 1 << 1; + public static final int LAYER_ITEM_ANY = LAYER_ITEM_POLY | LAYER_ITEM_ICON; + + // Door state indices (LayerObjectDoor, LayerObjectDoorPoly) + public static final int DOOR_OPEN = 1 << 4; + public static final int DOOR_CLOSED = 1 << 5; + public static final int DOOR_ANY = DOOR_OPEN | DOOR_CLOSED; // The layer item types used (LayerObjectAmbient) - public static final int AMBIENT_ITEM_ICON = 0; - public static final int AMBIENT_ITEM_RANGE = 1; + public static final int AMBIENT_ITEM_ICON = 1 << 0; + public static final int AMBIENT_ITEM_RANGE = 1 << 1; + public static final int AMBIENT_ITEM_ANY = AMBIENT_ITEM_ICON | AMBIENT_ITEM_RANGE; // The ambient sound type public static final int AMBIENT_TYPE_GLOBAL = 1 << 0; @@ -139,12 +206,12 @@ public static int getDayTime(int hour) { case 5: case 22: case 23: - return ViewerConstants.LIGHTING_NIGHT; + return LIGHTING_NIGHT; case 6: case 21: - return ViewerConstants.LIGHTING_TWILIGHT; + return LIGHTING_TWILIGHT; default: - return ViewerConstants.LIGHTING_DAY; + return LIGHTING_DAY; } } @@ -156,12 +223,12 @@ public static int getDayTime(int hour) { */ public static int getHourOf(int dayTime) { switch (dayTime) { - case ViewerConstants.LIGHTING_TWILIGHT: - return ViewerConstants.TIME_TWILIGHT; - case ViewerConstants.LIGHTING_NIGHT: - return ViewerConstants.TIME_NIGHT; + case LIGHTING_TWILIGHT: + return TIME_TWILIGHT; + case LIGHTING_NIGHT: + return TIME_NIGHT; default: - return ViewerConstants.TIME_DAY; + return TIME_DAY; } } } diff --git a/src/org/infinity/resource/are/viewer/icon/ViewerIcons.java b/src/org/infinity/resource/are/viewer/icon/ViewerIcons.java index ebf90497e..8511929df 100644 --- a/src/org/infinity/resource/are/viewer/icon/ViewerIcons.java +++ b/src/org/infinity/resource/are/viewer/icon/ViewerIcons.java @@ -60,6 +60,16 @@ public enum ViewerIcons { ICON_ITM_ARE_ACTOR_R_2("itm_AreActorR2.png"), ICON_ITM_AUTOMAP_1("itm_Automap1.png"), ICON_ITM_AUTOMAP_2("itm_Automap2.png"), + ICON_ITM_CONTAINER_TARGET_1("itm_Container1.png"), + ICON_ITM_CONTAINER_TARGET_2("itm_Container2.png"), + ICON_ITM_CONTAINER_TARGET_L_1("itm_ContainerLaunch1.png"), + ICON_ITM_CONTAINER_TARGET_L_2("itm_ContainerLaunch2.png"), + ICON_ITM_DOOR_TARGET_C_1("itm_DoorClosed1.png"), + ICON_ITM_DOOR_TARGET_C_2("itm_DoorClosed2.png"), + ICON_ITM_DOOR_TARGET_O_1("itm_DoorOpen1.png"), + ICON_ITM_DOOR_TARGET_O_2("itm_DoorOpen2.png"), + ICON_ITM_DOOR_TARGET_L_1("itm_DoorLaunch1.png"), + ICON_ITM_DOOR_TARGET_L_2("itm_DoorLaunch2.png"), ICON_ITM_ENTRANCE_1("itm_Entrance1.png"), ICON_ITM_ENTRANCE_2("itm_Entrance2.png"), ICON_ITM_GAM_ACTOR_B_1("itm_GamActorB1.png"), @@ -76,6 +86,12 @@ public enum ViewerIcons { ICON_ITM_INI_ACTOR_R_2("itm_IniActorR2.png"), ICON_ITM_PRO_TRAP_1("itm_ProTrap1.png"), ICON_ITM_PRO_TRAP_2("itm_ProTrap2.png"), + ICON_ITM_REGION_TARGET_1("itm_Region1.png"), + ICON_ITM_REGION_TARGET_2("itm_Region2.png"), + ICON_ITM_REGION_TARGET_A_1("itm_RegionActivation1.png"), + ICON_ITM_REGION_TARGET_A_2("itm_RegionActivation2.png"), + ICON_ITM_REGION_TARGET_S_1("itm_RegionSpeaker1.png"), + ICON_ITM_REGION_TARGET_S_2("itm_RegionSpeaker2.png"), ICON_ITM_SPAWN_POINT_1("itm_SpawnPoint1.png"), ICON_ITM_SPAWN_POINT_2("itm_SpawnPoint2.png"), ICON_ITM_VERTEX_1("itm_Vertex1.png"), diff --git a/src/org/infinity/resource/are/viewer/icon/itm_Container1.png b/src/org/infinity/resource/are/viewer/icon/itm_Container1.png new file mode 100644 index 0000000000000000000000000000000000000000..e6c3c7b717051822107e747bf3a072b95ac4b9cf GIT binary patch literal 992 zcmV<610Vc}P)6#Rn^jq9BN3yPL-BG|hJ1x@oGr zvkCKcedtt5vYDCP1M_fa&b`0+-*fJ{M{LdK3A1*oG=^=z4eUczw+KbK3s9u*cksNw zrIf!4U4PBUWG;oRBf>!KLg51viRTi#b_sQK6eXDiT}KFkv~7IL!fQ5huUx@zwLUd+ zxu<#twa=dYO5d~Rke*7R3=W2>_ALu%ZVsnh{?3@1I@rxe>GrZ!ES}JI?mUzjACH6p zD9I!Pd-tO6-hH55D4dK95<)z$r&0(_qZiXtDNxlT?NTWb32GIKC$#O`N7RuKdNpNe z2z|$nA#D52Xhpt%pdZNp3l0y1l>4JWLZsrvWnIwb%}61}B0)lk4MNxZ1_@n)*K1KWJ$Q0Y647(zMfVqw%j?S?PV-Y#X;;?~q7*90@Yg={BzWo7-sg4DuQcr0f1} zq|>ot1gcu_u3hUHXr$BazCcDU zcigE~t8PeQc+Dox%uHj`)YLPfRXwsA3-Ml%jeY_H{|%6mTE#Gw?O=6L5V^ z<5DP8H%v^Vlw^|5g$r%qK_ip7yvl79*atiYJOq@1qZ)7qSOE4%CWfNCKIhJeEHkZ(W9q=!^5b(y=}dA?%&7CWH4uEe=sH|Pi(bE*%C56eL));ITacm z^@IQ@J9iQu8$&yC%qP!d&8bSnvbYj}@FsSP3dNQebf@;qkNh_5}9r zqf=9N??xLM+9gf%T~Cm7oa5@=y>x48UmsG+W1b)(#Gs$NYzyk`MF=tAog+ngWJAK; zn9wv3BJ4*DQcBr1NJ_TBpXxe9vug8srajPs`^zkpYIrC7Yd*#w|o~>t_Nv@n~6?<{9Y{X*k z`LEvp->2(VF6aOH<)@zQ-fM#q zi(RspmVPtS>4zZ;3s~9gq7jR|(Jd$hJPDk3d(4aG?CiQztv-|+5eU5LE}sXUa?iE} z9R%J1W`G;OIp74)r$?hXX<1)9D0efRrdcZes83AH)RV~`;A!Bzdv*qR8yIi(U7CTkZpJ5x6G$Q>l62IUwVw0@S9a{t&@nzdk;0_$(TS zfExkeb>M5@OCSN<^%y?JrQ`S+`W^$~zze{+joJGUa26N<{sHoCIJ3ZCKowX8ETFX! zNLOJ!z%Jl%H_!dRAkYgGfDeJp<{@7Lo^fTm2QYvgfB>A$&TU$+0yUrl`~;-j9|Pb& XtH5YR`mKw+00000NkvXXu0mjfF3Z)Z literal 0 HcmV?d00001 diff --git a/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch1.png b/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch1.png new file mode 100644 index 0000000000000000000000000000000000000000..a4a378d4f577102596d3d391a5d6f1978c47df92 GIT binary patch literal 1042 zcmV+t1nv8YP)FGWB6G$m+Qtf-v*ALs=I}vYy%YOx^*1q zA1URpLepN=lgU5*_7Q%dY9{jm(de_$0|$iK*@+U1fuGV@u230R!{7O4?Xi$sCQCeGlRlBts*31l6KL4FQJUp`cRx35F(=wPd+ zw6&r2^t54`Zv-oH-Q&$b?rzxL4pJTs1_=>wyqA&QUKU43SsWc@psULtv}+eqi0(j; z5MsN~w5AmaO@p;u^9MvI0_;!{pK5 zZmrfd$gR~ti22}PP}OhUTeq4AEiWVB$Hw{fsUL})w@alr*)bt zJfFY&)qZ9diwH%z9J;9LLqqS|^YgRL@^bjQsZ_A$<`(r->aEZq&$6~*ga%oL0gm(K zrlo1K7kWDVqBS#9be5LFshOU>Em~S$*fPjV-cPI$sw~4m+ICh?B&tn;^mO{PRVWnf zg@w%{tz5>Mnkwxa9)8-lss~nMA>Q*-Wf=w%#sdFSK@NH4IQ##Y8jkIY90ZWtEmVgjar77{j zLf?E7ER|)G?nZnOL5RgK>IZ`OV4*e%V$*6Q54Kc_zW5MCQ4}OgTG!o8BaPm;2)LN5tTsMk&#bCUEQE|xZ zy1QK=0Lspt)c5qD9X;Bc9T~ac8HA#|=x=XF`2AF4T1N+{>Y3cwnC1$~j*gz!4j$a= z+rOV`P2IBxt-XDhEEL{x1xefPRrl?qR#TgrkWwCV1qmVA%HwjnxtUa7AE~}RdUx-x z3~Fpd2+`^uBSm>+BZX@*p=lsQy_aN=Qp%b^Qc4iQL)J;ThH2Ie!Zbn3f80T~owoD& znmP9BD$=&oUR;;5bGh08WiQ{^7pyL#E~ZlN%C$9J zG&F2l=*zCI|BZ(d3C0%}AB4A1z)B|9gruEmp!Q|+`gR=_4O}T4RTbCnX#BRHI{Wv z4+QcxfsAnYoEeYLS$FPipJ_`=6sD(_jlsczidEQy`#-WOsIp=)kn&U4a_=_52!$?M zb928HB9YCInHkJjY}N>cUau8Y2RsR!aca!z!qn8doyly9jqv&2aE8wTPdWcq1U(MC z4NL&nfg#`o(4+^0acP=gJe=-@NQC0T!jJmEz(j6rtN}OaJE09*jBik8XA1n?{n^>PDbhlhU`et(PJ-*0%lG!6sT zeZXtL*T6V10^D_JKKi9?dujTbfiUnqFtpKo9|m3pT7kcTdB>eG;7=d}tO6!b+Hj~e8s<5eIFq=BD+NoQjK{0sk* VcEsJn&JO?p002ovPDHLkV1gd8_cQAGEVYqbA4*lZ~H+6~@K_bp}n@w7K%golz zleFu(eg0UM^^)eKdm(VX@4WB(eDCGF`9$ZcPRdD7u4kQz`3|r}MO~o?WeK3T(w%g0 z{*_Yxt_kh+s2=^RoF7pRl*lDM^y7biy??z}sjeib1kunCLSRahyqhQMWEr#vFzp((V#QAGv92~HnxPdFd-#WHtM{aXTTbu&+7Z3L+@xVrK6PE>@vCzH~1P_8vTu) z5P+Z(WOHCM8?+5O61l|Dia|n%7s6T?pYX9532R|g)V)2q9=|83%ji11*0;8{R;^{R zQms@|uhmzZm~VN4T-+V^1Gy_TN(~aZb?*MW+z3RtR9zzbB1B$_5C{bT$R@KSk0nW+ zOU=?-t}I7LvCcChA;eNmXtVa34mHtqsHq46sEyRJ^OK!4Jkc;qR}&fv$`a3rkVuIv zF01ORi0q3Lqv+n%O&}Ct_nF;P)mIUy4$L)Yru~8-iJY{gRa~!bUR``n9!ml+eQTQT zUEL*XWJwE&obpVaL}n-DWJxE}x28RtVM22;Nt#^ z#X|sOoD8ZENRXkMN^tKO1?2(}f zXQJZKW4H#x*6?_{-u`yQpu6)mZKo>+rL8m$&esdQUl0`2W3LQY17p{n>lHCz4FMx*jbf49C z+i;C}(Wt1e6_!r|j}~mpf*uCm1Wp5IfdfD@up+8Q`%TyUVrB~a&3-aY=EpX@?Q~DB zXBn^^I9RYf4ZHz7H1l2;1Wo{(fM0=cfnR`Y^DdM|BDHPlws24ha(?oB4tON0N3YCL zTM29d9tWC$KHxd+RrpK<7P`d`4EBpYC0;fdhs?N(m z6u4B$1V|W(KUJZw*`x0XRX8*nfwMl~RiGRA68IPxD`({szPO9~Km~w0;5pza;K1Fx zcO$SLSO;7O(uH*P0e=HGfjnRWPI1WJ>9A!$HSl1e&TD`$Py-AB?*W(QUh@6GV}&-Y w1wud&5P&=H3OMIq9JmE!fuDfy3I_w=e{rs)g9sj`TL1t607*qoM6N<$f{_s>uK)l5 literal 0 HcmV?d00001 diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed2.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed2.png new file mode 100644 index 0000000000000000000000000000000000000000..0b791e50f3c1354abf4da7b9090e5eef75d91dc5 GIT binary patch literal 1182 zcmV;P1Y!G$P)4q24|v)B{6mhHbkw8Pza_a2K&%J zN+0@GNJtS)Tx(xSp`f8(q_ioNJ~WUIr8Fk}z=tNJr0q)|Oo^nlAd04TS5q~+mY8VC z?rPMXnVs8*tXn_Uoz(*i_ue_@{O6qif9@X9Q_@2wyBxdhTa=5R0JW-6ixiYxflv}8 z<`Xh8Es+D7(B5y<8~@6bM`Qx(h<2RM5jibYT9w%C*^QwXXhH+PlqOLp%2Z;C5p#ry z6ZzV2_+Q^J(1qxQpKEezj+A@LDO3wHRz2&?GHedhAMd}_VzeAe=cA-M?2LAvuFxuu z?9bWn3IdR?CPv@Al+C z9lJcc*r;t+w^OE-ZHvqJN3KAQbn14hJK3xisYOUB53D}-tWk#$d(!dZYxUu4_2Ds| zgv<`j5;`AZ`p4-NeuZiwLI|I0MGDH6B?&KCX?rQ9?WHLYfc)xwDlb%0^h(hRUrlHT zL~b@>kW$LjW{YnNzE)qVikna0q_?V<*`ZnNsEya~t`0^ZaBZDL&YPI2eL-D8Y8^Ts z0>F;i^u64dmLn4riCl0O1J2BxGnY1r9kpG>@Ys2bBb}LSS{IHvv9w8+bF`ktoEQlH zaRpLQf1OVJucSw}9;MdBM~hSIn(u0;57$$CtawHIOkxHFDBq2F+mBKtVHzgY(mR&({U=8~(S4&EfkG5)ZPf=1%-h zBv<6VwPB!SRb2rykX1Dn*3|~RVQy1Ee#3t%Xa>jcS@+iUnX;!Cj1N9&F^RIeZ_zuI102a z&EA#3JAe=P7nn%4GXVSzM1aSD2_#aTe4?;CU>opElIId&4^Rk%fX{&8)kD4pyqJ{f w4!{7m0s?SWkASPk1t1E{0Jnjj literal 0 HcmV?d00001 diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch1.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch1.png new file mode 100644 index 0000000000000000000000000000000000000000..f9bc13e5661a079a106d07ac21b230d0d861176b GIT binary patch literal 1044 zcmV+v1nc{WP)#v*u8)sw<)duXnJT5u><{c89SRP4 zLI6Tah{J7%Ij9{xo-8NN`UVLho(pSX0wO>&7S_V3s1xaOI_L>Xl~QN+1@`sys68}m zT}l@N+CZ0y`GzOR#Xa5%WW&0ZZY1)kCrBW|o4?E8#2}N)lT0p8(l^rA5Y(Y`Af)K` z1_`l46I#oPG@+rOw0j4GL`r1KAX$4nK@wTDq}4LWk`@xV<_A=)%4*A?HMxdF7X93# zzbbB}Wl+VfAP_lEkSf$~Z@af!2CcfQAoy`}f1ti2aK2y{-dvaK9qpnnco_YB^ndNE zC$Ey3$^c+Wlf0d;1_^%bsVJgH$~N|I1-sC+nu1fnmiD!X9w~Y%0#H$tOU}}<0c`+) z%v9#?t{Yk2&Z7wBvhSoirjNa!vvUip&Z=)UCAY+)wYVJ9V{iEeZRA(OHhhB&%fP|; za=YnV`bJ$ZmCX$(td4j2S}2EGP<0&dk6l%-^L zc*k%!q=dLqy;24qit5oDo7{SVBfw+8!$1ajJ^)+*7J;Ll=PZ0#V?)pA3*JC4X0iy7z>BqSI&67y>Q@fR}(TfX{%BfPAA_ z0TGyVaqsg1=mVYso&Zj5)ZRnDNuVEC0gT#lW`I9|J3s|60q1U#|1ZLJ0$srUweP$a z2m{@~0`M+yeRGi?1Rkx0X%El|ga84!btT}Yzc}y@Py~JezNu{tfPVqr0&)w&cL$yT O0000R7l62mR)EZRTRg6cV>4IQ##Y8jkIY90ZWtEmVgjar77{j zLf?E7ER|)G?ne4j1R)l`s2>R8gN528h)t`JJlIkx`r<qThq?FM^Sl3Z&)hj;vSpG=b|rVEbzQE%5A>))ZBkI`1wtuN zS}V!YibPIpLVGi)2mh!PM^plhWJf-!6Lo`!v_oQ_Zy$zYpa~5CQ<`M$EK8*&;%1zT zo%uX$gkP!}bSZo3+pfB<6CM5z8r8;%s_)zPiI@?l3R6D}8iU6+^HDY%9LIza&9(z#2wU{O}1ft$cF-R$8%^)cy0^weD61iq#)(kQ+k;s4Civc^G zxAQfFR_#@6X{WuUE|s%$HG^_?4g`O>f>hM+S4t~2gVLom3d+yrD98dyE4ii#?K4+J0X>knq&2f(EmW;0RZL-G-U{e} zw5uW~eP1PtiK7R!0{|?JFFxFLB}-aK6qK8uFV)k=>5mguB3aE@W$X-d*4$Fa2)*YS z9bT^Vx};&JZKCKREni|NdHGsYim_eD~d#Z>K4Qm6f!~= z=dJnQrVG;>=4P!~qGoh1WQ1O?6;ua24V-fRF(;=AQ|lQ!v*B!f!uN*r`U3Ebv$i7W zN#Jc@0=Nzg0mp!*pdO5w(){Ala-S|tvrt_4aX=rK7|V?{07rpy&e{p!Euiz!zHS?E z5$FJZ1-=7*0q$+mP|hE3INqi!Iydq+@ zgTQqk@EY(nFb<3WcU_u~ep}jJn!aWr47>;oJ?Om;0~4YiyFR#`cKfrl=HbF{SD1^Bd>8@`b$@0LaF&B#tBi zs18z5gu09kSa^R9DM#)F2PVG#V{3G(4P zl(8~*?#X*@0c2xYw=i~G-$DDib~n58d(XSEhBO$o21oq(zwiV#>&`I!+WZFtk>yx#!TsALf z+N#^0FSnQC^|eBXkIQA1GE*Sw^xDT0)T*~07_bL^OBjhs@A|ENl2-C+Yjx}H2L)9D z8-Wf04ei;u8NZiva+9)AQQs=6PXkXBW6Odb1KtIW0>^=!KohVatcMeZV|+FK2opwv zjGg(ZMQ=IUlkb@WYyx%_V~+yw0FREJ>jJ<5U^Vb7@I7!2xG`y<%tezMXKxGzlmKT& z&g6l|!+QA21h<92df+Kw9S{dz@d1Z{YrqE2a~8^nDKqt1KnY-B9g66YD^s}L08SJi zfPKJW(YdJeG7ttXRnh^Xx#*v&P#164x7SqIG#Y^8KHyED8~7Ud92hJYXcLA8br21mvK0000C^D^_rzh(g2e zvLHLNJGT$c4j;nK;z>5S=ghh1f6qDpd-sUe@>X)mxx~59l$`n$sP+k8se)1{5K4y3 zWJYF2B(hT#>IZdN-QT(5h+IHT@upJ+qM&iJx>>C8uR&LIRG|W3N|U%9XE-y=ZSyuU zJN9i@55KW!pwscw*R~XF*;5&)q{LT}GwX4CoF21>j#Nimqu#i4J|AU1V{^Ru_(pZ( zo^1u&JV5}8lp?ANtEp0}YMSCrC-MeTP!3lFDhP-Gi;+sT5+A+;Er}M@6R0`fe0;sS ze&uTaY8ERid@HC>E0(8Z>SIqJTiP|Ne5-g`DfN{irQAN(?tg+ELad#yFQGR>tUJ2S z)yLY#FisncwT;d4EAf>ega~;8DJa1#g|o8t+E$9Hie}l0Yl~yHzPlexOP>j z2t;8%WROxyS1H?H=7J1e7~=Y~*Jz2o15&K&Mw=JU?@o0{xbIPG8AU<) z!xJbV0%r%(1BppF=@MYPYuqKqu7O=t|5oj0l`%MNz9IM$GS7zpf`MyH;{9mE=A2~-at_^ijDo#Lf;nz3hUu_ zdd!~t4>Aw(%H~$;R;*AIzP)H5C##l-8ObXf3+qy?R-1e(ps*f37B!=N_pEyh`V6Os zxtY58piytE&lO9_qx@e+tcA0RSP>-hYp)=lKn;4s$v&&Ey))JM#J66nmxvj;)1WuJ z_q0F-z)QdZ=RanDN2+5gX2+iBjbHfRchuK`mz}*ifnESU0xklVfg`|9ptMe_i<;8> zZYJG3Q=JT^2Y;>C>Myn=T9yDifMd?yi@=A##+h^7Qs5*|3H$~84EzZ^oM)iy+r4D> zT20ZolDv`>LcCa~)%DJCdj_ZmUIn%R5#TL9a2^;0wtLmthwt;K89k#Z8fnsJ!&)uK_*zyZ~q7XSxF-P<~K5sOR};YyvL(fuq0=zy+WQxSwm6 zD%69vwDTGI%78Gi4>*#Yy*B~x0wLf(px-HH1o#Jt0TX};WZX(VX4n#7IqXLj#y)15V;#4bvWTl_!_eG#Nqtl)zW zeF@Pd3QB#kV8s^^1Qqq6q6p%Hg^EJ3QWeA|f+>pNgNmXk2%^{~wQbheG)7Zfy?3`| zXYPy-xlx;sy>~Z%7%rEYIlnn)X3iWLtyE~Gi74u8!VAFm99*tMHUP?b--zK4@BR0I z$g_i5A8TbtT7kx*=+y%3y|z%0&AA*Ur3e5Kq3Jz!=U9kiezBI&xwnS3exPm8;VAm( z`XJa<4FbBAYUy>|IZheFq%mKNXnp%?V^*~=9)|n2=JUJy3x!k&KuIaK6^mRK1Utu~ zXn$sqh&)^k0`elXqiPV4gWVHRR7eGlhvB}f^7-E0T#k0tqZC&MK~EE&O9eUD*$HGx zo0P)CEvX=ZYLmuF|8YR;OnXEQ#?HiX+n_mXQ6fh&C)K;Per49$nR9Kx zLgzSb%x^Lort2116tn(Y+Zb$ z34vq4d&w6WtyD_Dfdud^@Coou0=cxH48!RiU0v0ZQhe5EM8HjhTK~Lk*k)ima3^px zFbO=82Mz(JS*4&@5oeJXYsS1*QVI(PhgU*K7I-9S0Q-SMGFqt|2L^$oSu(&_82*$K z*>acG-5HZcKk$AYcoO&kcn5eLm}@mFFY=&+D>4AC1RetJ1D;r_z59X3fj;0YP)ou& z37iDZ19hMY#Q!CEioiyo2e>BL=Pf`L*aXY~F9AoF7x@L?j^vp30^L9(AX|gZ?{sEgvQ2V$3O*?G z%_jw=64IKD_##4~O6x;K5yS@z)uxDzRYAmxQWU|5Ac~?O4OP?Kwvw1cn%W3E+fD4; znZ4JCj(-w|z^YkO~1<>o^P+i`?UR z+s1<6KxU8w&u+@+$tP~gDg&N}3p>W^buSfkI0*LN;d$#f=5ll@H@YsHJa1iS?JKDu zW9_z^Gq`It+2FcZYqzF?M5Mp>IzYXyi-`24f*iQP>o7J~izk9WF-tO7Yi-vcYb}x` z>ntp5x)*&}$G_>x0E-P{x&|#7gRyooi|gj<*8!><10sK=f?W9aLbKU5XtCMEfge*r zd66S?aa>>SA|XO+nT?`lPvpH+(2(ypB5P01M^VS1xj06{uS33{DMq;P=}a7V44RE1 z95|l2s6M0ATQgBK+exfy#&9-@7DkkMH8Uu=Psge{`;Dq1|9>ZvQ&UWLGXKCq_orbRmP&R8Tc#*ya;>&d<2XE=Te4`oyOXY834BcW#CC* z&;PUcW?(na2mAxfB<`#Le*iULDH#cxS3F4p=mFLNwy$3;R#1?$; zp$|EtNh&DuB?T1=iXf;|A1aCoD7m;7K@hTZvn=J#j6Gh!f>qLz)=c5?~d1a^erWK}l=oJdc9wGU+&2o;TPd<&$d$ z9kcCk?ljHat)@xBFlt6U=Xso0iZP{r>XmX=wQs6=7`ChfZQ=0l_DCcU0uVC{wnwAf zVVXOKZ2Mr{AR)vvt)@v>2-ae)rb!6;Mr=D02pYDm1Gk35$z&+RTCK@2Xfe&E61*M= z@?htBAd9xqFwk&+AV@&#YIWH&I!b>&Pk%no)?HO=&P|4a(7HJoBt)ZGr8dcQns`e~ zdEVC9SrudofdLJ{&7if`RUEWsG639|oh{F!iA3dce*}Uw6jc?}U44B3WDgwzAeu;2 zO`p;l4cF@d6^biBZJnLv-H#6rQpjePMY+_jFMta5{6`n&Jg;in3fU|-W@ou{;zY#; zma2q+=|E6Oh#&u50*WRQ<-#Y^Y5Mbd();#Rq;%1)dL9VzOCTr=M`j%7zj;4>D;=%Y zBmgC?x$HQ_2z(p}%1CKDkezWH0B-RMZcR?|(dNzNF*Z0@jxw1}12E&dI9mUnk+M*i zdLOs#=eC5y?{+jatVtD4&CheearSph`9@u$`lyueO*_uiRoAT>VtF1HmC9FxtO{Dx z*PNfedMu|DE_}V(`&B_bQoe9rsmoXDh|2Oj&M9>*D#Y_^2KhhlCpo3+ipJ4;I3uOK zE>Mq@uS_U4aj8ZM3$DvqrDl5L@x8Tt1)kGFh<9p5l~W3|9tiRi2^VSLt%qc|(UiGJs0T1|VsiHV#y9d|<+zrG5 z2lyNKwoA(KW0v)4PN}`yqYHkpO4t~hK!UC0&NS2G!}3M_`-i822!aQ zaM%Z&0=@%AeaP|)rDaWYG&Z)z41*tvMH{%cOUgf2e6|VL0Xz)c2aEyFhJmBNMXFpV zD)KDETREjZh#3YB9OMYO&oUTU!hAiukkPzD*kup)IXtV>z z!@$eHm%wMhhrs1ptHMI`d$6Srz*gWX;BnxkMfGk6UIdzfD?rXq=NRx8a1EFPO2DEf zh5QcN05k!&`E}j~v;rG}Dd273^vYu*0zBlmX%a{PF~5_%$}8aVQyiFO;lA)Q@V&n= a0R9J(6^I%X*N}N@SS z40_MDzqv0S-_a6_(GZE$jC#)V7*~o@jx*9H+P+AWa?n@w|# zqxEZnAW!S|TSLgToHa%wXsx#ef`kyw%jKo@q<#FI{_%#HUR58JBdnJZ89QE)oCcGDg!s} z+66$izaN08lvU+Z3qGy}7X!@9dtOB}i>tpdG{oH4*g{lQXGu$r0f1R>NpkO&bcmWr6zi$+<&v6IPd_l+uvh$opPLOvt>OnqZCmg zUhy9v2Ojk2R@jXPgL{C-fEJ)0C<6Zg-*#J8X27;T$tbnAHLGkj@c!Go#dD%P=Uy(cVf3{sO=9FMxxo&_ES z#=~@g!?yiLOo-$j%aS3R#uni7DDV>SB`^dG02gb`GKJXVX}uu?U?b2AJORA8*uA#^ zF91!zzrcB4&NT2RFbiDqj|8RbN)iX^fHlCKex8#+GtdBJfwzG1@@>Kd9`?(09Uy_# sekFP3TTJ<{907*qoM6N<$g1B4?PXGV_ literal 0 HcmV?d00001 diff --git a/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker1.png b/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker1.png new file mode 100644 index 0000000000000000000000000000000000000000..21a8ba68a44d248d6bd48194113dbaa87d129777 GIT binary patch literal 1172 zcmV;F1Z(?=P)b)(nbMGA=db_f_W$%`gOm1fG%=zZbIdkTS?&@kv$x+*0n}t__jUl+v5Mmi%cv{c7 z@VD0b7gLCrnxs5gN{=W7>b32+BJjj*k%(9o3Q=Jgn1B$1tk%qW9@DPNnB!o1UQe@> zk1ZK=*tS2r!!)C~5Vq=W#|UhL!qumy}x=>)J7W@4M!$4@gHW(zta*^vJkLQh>LSVqM;9$^N>w=-1{hdz_4RN5RhU4w+07T<)>KYsK zm-{Ucq+w1KpvL?Ab5^uvGQ<)I22&{x)YLHC(~~z>X^nD?x+A*8qr zYonCYix^NWA?TfO-OUNp%vm*y9mCOp0j)NgYU)f3ZK`GxHcbu~qT(|7hV|gCu zl*;Us@|Chd3;8vD)$s*MS}9!k^jiO~32K(|nKMdFo-e~H%kwy`)WxU}PcIqdU*7l9 zN|j}eqxF$SDedb5HB0%zs8XX7C5~{~bvdQf)UH@;cPU+g@3au&jZ#*nl>)81gY*P~ zc1pQ_+;x8*$!3fGopl^W9q07USS)$HpeV2jXaz9gkzu7STLn2VtrQ`6(eFM4+~cpM z)P=nhXaUv%F~9--0={UHa^$dOy`NTU_lD@ao{?;pDcAjOmy{nKwe1y+Qf>z7<{xP+ z;3V*o|3!3HS62Z0eZY^vm%xAz$uB4^Yjo4{<+T-t!Pj$hHgH#yl)o2DTLo+c?gJWt zVc@ASa0ocZA_Ya!IScVxTB)}y3B^E$g?C z5NjTgGG1oVSPy(02A&5#0X_iU0VYeW3JcNZ!A)fVRs)X%4+GCF)ZXiXXMwfAc_8f{ z=P>XGa1odVvVi-4k|zqR04jl7eLt@OYJru&S>ScxL}8I10q*s~vx7xtk* zxDS0QP>e&(`_q>Qf;OrTMqLnnNN~@SNV9~9j6#&44`-Yj1)=%pyj4@%wbZ=uW<5{m zo!NQ&;I!WEojaos48!}pe}41)ndg1PU^-1b`Mgxh+|c?1pw$#&o&gO4j517=wZ5$3 zuqDL1Yi;{Py>mo8(17FQQbKe;W?AC?L;`6TSV91xw8jYnE|$xjREn`6_@Yb7m+u(V z?>KuOPo-8aNhXX!1E>DCz2DYrV##z!n`<+4;N5&|&OFlcRP zV5w!b4>-=I*dPOX7AKP=LpQ~hC6{9S?#kT_KmF zkjquZi?Uf3WwW#%I6z~jIvm%6fI#cfIIb&}YCu56g5OuIsz4hv85XQwUA3+h1R%s; zksuR(x?C<-#tA7anby+Z&y}Ge3b`D<<5cD+%V@cb0Y68Al0s}N`hIC5ObFj`DshjDp z84ChVd)~zjQobJ>6#h@U@=C=9<&`3UJ-3^`EvQS%*N2t5a4CjWV?n?%*BxsR;1?rOWt-Mla|D2S8wQ|w-IpVsPx}{uS?<^yR`#&D30~+x> zG<+I$NF->3l$+0b-fxFpcgox;&tpWX(;K9G`))xg;3;5Dc*m?h+p>jOs8i6n?t~_z>mN$A*8mUJo|i8(?Z)Y_-=fBTnO>RTH8KV zvur-l3Oola14e*X6TlAOJg_{<&nA4BS89uG82GTQYbu2B19x+)6m0@_h{1IFB=7<- z9H#;wjY3-xwcLaYn4UJwItAJ7G?0^a<;_ih2+ z05ZV8z`4+!BfuZP7;r6Y3Cg!TNeXBJW&sa|aZUpZfjK|{_y`!TZSpPP*)UD#0uq=J rW>W3_Ufb+k0~}x!I0y`e9|pjGf#0ygd({vk00000NkvXXu0mjfJIx%N literal 0 HcmV?d00001 From 8f86180f461dd80dfaa4cd7340620f12f86fab93 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Mon, 3 Jul 2023 21:11:32 +0200 Subject: [PATCH 04/28] Update GitHub Action with an option to provide a nightly build - Generates a debug build - Updates version NI information to include current date and hash of latest commit - Adds generated JAR file to the "nightly" release entry of the project --- .github/workflows/ant.yml | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ant.yml b/.github/workflows/ant.yml index 8418d09d8..1fead9138 100644 --- a/.github/workflows/ant.yml +++ b/.github/workflows/ant.yml @@ -2,9 +2,9 @@ name: Java CI with Apache Ant on: push: - branches: [ devel, master ] + branches: [ devel ] pull_request: - branches: [ devel, master ] + branches: [ devel ] jobs: build: @@ -17,4 +17,15 @@ jobs: distribution: 'temurin' java-version: '8' - name: Build with Ant - run: ant -noinput -buildfile build.xml + run: | + hash=$(echo "${{ github.sha }}" | sed -e 's/\(.\{7\}\).*/\1/') + sed -i "s/\(VERSION *= *\"v\?[0-9]\+\.[0-9]\+\(\.[0-9]\+\)\?\)[^\"]*\"/\1-$(date +%Y%m%d) (${hash})\"/" src/org/infinity/NearInfinity.java + sed -i 's/debug="false"/debug="true"/' build.xml + ant -noinput -buildfile build.xml + - name: Upload artifact + uses: pyTooling/Actions/releaser@r0 + with: + tag: nightly + rm: true + token: ${{ secrets.GITHUB_TOKEN }} + files: NearInfinity.jar From 2a64bf1a9da2cdc434178c3936a22260fb269e49 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Mon, 3 Jul 2023 22:10:17 +0200 Subject: [PATCH 05/28] Add README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7c3d15237..eb285212e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Argent77/NearInfinity?color=darkred&include_prereleases&label=latest%20release)](https://GitHub.com/Argent77/NearInfinity/releases/latest) +[![GitHub release (latest by date)](https://img.shields.io/github/v/release/Argent77/NearInfinity?color=darkred&label=latest%20release)](https://GitHub.com/Argent77/NearInfinity/releases/latest) [![GitHub release date (latest by date)](https://img.shields.io/github/release-date/Argent77/NearInfinity?color=gold)](https://GitHub.com/Argent77/NearInfinity/releases/latest) [![Github downloads (total)](https://img.shields.io/github/downloads/Argent77/NearInfinity/total.svg?color=blueviolet)](https://GitHub.com/Argent77/NearInfinity/releases) From d12cf2f0aa824c789d80a2e2ba09a19495aed7ee Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 10:33:13 +0200 Subject: [PATCH 06/28] Display "Area Type" flags in ARE View tab --- src/org/infinity/resource/are/Viewer.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/org/infinity/resource/are/Viewer.java b/src/org/infinity/resource/are/Viewer.java index 1d80a82b6..985758b60 100644 --- a/src/org/infinity/resource/are/Viewer.java +++ b/src/org/infinity/resource/are/Viewer.java @@ -13,6 +13,7 @@ import java.awt.event.ActionListener; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JPanel; @@ -60,6 +61,24 @@ private JComponent makeFieldPanel() { return scrollPane; } + private JComponent makeFlagsPanel() { + JPanel panel = new JPanel(); + panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); + + JPanel areaTypePanel = ViewerUtil.makeCheckPanel((Flag) are.getAttribute(AreResource.ARE_AREA_TYPE), 1); + panel.add(areaTypePanel); + + JPanel locationPanel = ViewerUtil.makeCheckPanel((Flag) are.getAttribute(AreResource.ARE_LOCATION), 1); + panel.add(locationPanel); + + JScrollPane scrollPane = new JScrollPane(panel); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.setBorder(BorderFactory.createEmptyBorder()); + scrollPane.setPreferredSize(scrollPane.getMinimumSize()); + + return scrollPane; + } + Viewer(AreResource are) { this.are = are; @@ -70,7 +89,7 @@ private JComponent makeFieldPanel() { // row 0, column 2 JPanel containerPanel = ViewerUtil.makeListPanel("Containers", are, Container.class, Container.ARE_CONTAINER_NAME); // row 1, column 0 - JPanel boxPanel = ViewerUtil.makeCheckPanel((Flag) are.getAttribute(AreResource.ARE_LOCATION), 1); + JComponent boxPanel = makeFlagsPanel(); // row 1, column 1 JPanel doorPanel = ViewerUtil.makeListPanel("Doors", are, Door.class, Door.ARE_DOOR_NAME); // row 1, column 2 From 022c37fde64b89ea2324e7171337b6b4cf6e87b6 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:22:40 +0200 Subject: [PATCH 07/28] Display item usability flags in ITM View tab --- src/org/infinity/gui/ViewerUtil.java | 2 +- src/org/infinity/resource/itm/Viewer.java | 74 ++++++++++++++++++++--- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/org/infinity/gui/ViewerUtil.java b/src/org/infinity/gui/ViewerUtil.java index b36c1573f..5a72b6aad 100644 --- a/src/org/infinity/gui/ViewerUtil.java +++ b/src/org/infinity/gui/ViewerUtil.java @@ -240,7 +240,7 @@ public static JPanel makeCheckPanel(Flag flag, int rows) { JPanel panel = new JPanel(new GridLayout(0, rows, 8, 4)); for (int i = 0; i < flag.getSize() << 3; i++) { final String label = flag.getString(i); - if (label != null) { + if (label != null && !label.isEmpty()) { final JLabel check = new JLabel(label); final Icons icon = flag.isFlagSet(i) ? Icons.ICON_CHECK_16 : Icons.ICON_CHECK_NOT_16; check.setIcon(icon.getIcon()); diff --git a/src/org/infinity/resource/itm/Viewer.java b/src/org/infinity/resource/itm/Viewer.java index 38c0b97ab..99ce23572 100644 --- a/src/org/infinity/resource/itm/Viewer.java +++ b/src/org/infinity/resource/itm/Viewer.java @@ -13,6 +13,7 @@ import java.nio.ByteBuffer; import javax.swing.BorderFactory; +import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; @@ -36,28 +37,85 @@ final class Viewer extends JPanel { Viewer(ItmResource itm) { // row 0, column 0 - JComponent iconPanel = ViewerUtil.makeBamPanel((ResourceRef) itm.getAttribute(ItmResource.ITM_ICON), 1, 1); + // top region + // Properties panel + JPanel propertiesPanel = makeFieldPanel(itm); + + // Icons panel + JComponent itemIconPanel = ViewerUtil.makeBamPanel((ResourceRef) itm.getAttribute(ItmResource.ITM_ICON), 1, 1); JComponent groundIconPanel = ViewerUtil.makeBamPanel((ResourceRef) itm.getAttribute(ItmResource.ITM_ICON_GROUND), 1); JPanel iconsPanel = new JPanel(new GridLayout(2, 1, 0, 6)); - iconsPanel.add(iconPanel); + iconsPanel.add(itemIconPanel); iconsPanel.add(groundIconPanel); + // laying out properties and icons + JPanel iconsPropertiesPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = ViewerUtil.setGBC(null, 0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0); + iconsPropertiesPanel.add(propertiesPanel, gbc); + gbc = ViewerUtil.setGBC(null, 1, 0, 1, 1, 1.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH, + new Insets(0, 0, 0, 0), 0, 0); + iconsPropertiesPanel.add(iconsPanel, gbc); + + // bottom region + // Flag panel JPanel flagsPanel = ViewerUtil.makeCheckPanel((Flag) itm.getAttribute(ItmResource.ITM_FLAGS), 1); - JPanel propertiesPanel = makeFieldPanel(itm); + // General usability flags panel + JPanel usabilityPanel = ViewerUtil.makeCheckPanel((Flag) itm.getAttribute(ItmResource.ITM_UNUSABLE_BY), 1); + + // Kit-specific usability flags panel + JPanel kitUsabilityPanel = new JPanel(); + kitUsabilityPanel.setLayout(new BoxLayout(kitUsabilityPanel, BoxLayout.Y_AXIS)); + + int kitPanelCount = 0; + JPanel kitUsabilityPanel1 = null; + StructEntry unusableEntry = itm.getAttribute(ItmResource.ITM_UNUSABLE_BY_1); + if (unusableEntry != null) { + kitUsabilityPanel1 = ViewerUtil.makeCheckPanel((Flag) unusableEntry, 1); + kitUsabilityPanel.add(kitUsabilityPanel1); + kitPanelCount++; + } + JPanel kitUsabilityPanel2 = null; + unusableEntry = itm.getAttribute(ItmResource.ITM_UNUSABLE_BY_2); + if (unusableEntry != null) { + kitUsabilityPanel2 = ViewerUtil.makeCheckPanel((Flag) unusableEntry, 1); + kitUsabilityPanel.add(kitUsabilityPanel2); + kitPanelCount++; + } + JPanel kitUsabilityPanel3 = null; + unusableEntry = itm.getAttribute(ItmResource.ITM_UNUSABLE_BY_3); + if (unusableEntry != null) { + kitUsabilityPanel3 = ViewerUtil.makeCheckPanel((Flag) unusableEntry, 1); + kitUsabilityPanel.add(kitUsabilityPanel3); + kitPanelCount++; + } + JPanel kitUsabilityPanel4 = null; + unusableEntry = itm.getAttribute(ItmResource.ITM_UNUSABLE_BY_4); + if (unusableEntry != null) { + kitUsabilityPanel4 = ViewerUtil.makeCheckPanel((Flag) unusableEntry, 1); + kitUsabilityPanel.add(kitUsabilityPanel4); + kitPanelCount++; + } - JPanel iconsFlagsPanel = new JPanel(new BorderLayout(3, 0)); - iconsFlagsPanel.add(iconsPanel, BorderLayout.CENTER); - iconsFlagsPanel.add(flagsPanel, BorderLayout.WEST); + // laying out item and usability flags + JPanel flagsUsabilityPanel = new JPanel(); + flagsUsabilityPanel.setLayout(new BoxLayout(flagsUsabilityPanel, BoxLayout.X_AXIS)); + flagsUsabilityPanel.add(flagsPanel); + flagsUsabilityPanel.add(usabilityPanel); + if (kitPanelCount > 0) { + flagsUsabilityPanel.add(kitUsabilityPanel); + } JPanel leftPanel = new JPanel(new BorderLayout()); - leftPanel.add(propertiesPanel, BorderLayout.NORTH); - leftPanel.add(iconsFlagsPanel, BorderLayout.CENTER); + leftPanel.add(iconsPropertiesPanel, BorderLayout.NORTH); + leftPanel.add(flagsUsabilityPanel, BorderLayout.CENTER); JScrollPane scrollPane = new JScrollPane(leftPanel); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); + scrollPane.getVerticalScrollBar().setUnitIncrement(16); // row 0, column 1 StructEntry descGeneral = itm.getAttribute(ItmResource.ITM_DESCRIPTION_GENERAL); From 1cb72f5855cbb146cb2de52febdb451cbbc5162e Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:31:42 +0200 Subject: [PATCH 08/28] Fix incorrect function parameter name --- src/org/infinity/gui/ViewerUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/infinity/gui/ViewerUtil.java b/src/org/infinity/gui/ViewerUtil.java index 5a72b6aad..43d4b1965 100644 --- a/src/org/infinity/gui/ViewerUtil.java +++ b/src/org/infinity/gui/ViewerUtil.java @@ -236,8 +236,8 @@ public static JComponent makeCheckLabel(StructEntry entry, String yes) { return check; } - public static JPanel makeCheckPanel(Flag flag, int rows) { - JPanel panel = new JPanel(new GridLayout(0, rows, 8, 4)); + public static JPanel makeCheckPanel(Flag flag, int cols) { + JPanel panel = new JPanel(new GridLayout(0, cols, 8, 4)); for (int i = 0; i < flag.getSize() << 3; i++) { final String label = flag.getString(i); if (label != null && !label.isEmpty()) { From b58399bf4ebac07d73231fd1ed22d6e634c07a12 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:32:39 +0200 Subject: [PATCH 09/28] Display "Exclusion Flags" in SPL View tab --- src/org/infinity/resource/spl/Viewer.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/org/infinity/resource/spl/Viewer.java b/src/org/infinity/resource/spl/Viewer.java index cf45f7ef4..8f6188d44 100644 --- a/src/org/infinity/resource/spl/Viewer.java +++ b/src/org/infinity/resource/spl/Viewer.java @@ -18,6 +18,7 @@ import javax.swing.JScrollPane; import org.infinity.datatype.EffectType; +import org.infinity.datatype.Flag; import org.infinity.datatype.ResourceRef; import org.infinity.gui.ViewerUtil; import org.infinity.resource.AbstractAbility; @@ -140,13 +141,18 @@ private static JPanel makeFieldPanel(SplResource spl) { // row 0, column 0 JComponent iconPanel = ViewerUtil.makeBamPanel((ResourceRef) spl.getAttribute(SplResource.SPL_ICON), 0, 0); JPanel fieldPanel = makeFieldPanel(spl); + JPanel exclusionFlagsPanel = ViewerUtil.makeCheckPanel((Flag) spl.getAttribute(SplResource.SPL_EXCLUSION_FLAGS), 4); + JPanel infoPanel = new JPanel(new BorderLayout()); infoPanel.add(iconPanel, BorderLayout.NORTH); infoPanel.add(fieldPanel, BorderLayout.CENTER); + infoPanel.add(exclusionFlagsPanel, BorderLayout.SOUTH); + JScrollPane scrollPane = new JScrollPane(infoPanel); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); + scrollPane.getVerticalScrollBar().setUnitIncrement(16); // row 0, column 1 JPanel globaleffectsPanel = ViewerUtil.makeListPanel("Global effects", spl, Effect.class, EffectType.EFFECT_TYPE); From b0fe19d0bcf542ed48b7ac8a99cb6fe044f17c84 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:40:57 +0200 Subject: [PATCH 10/28] Display "Storage Capacity" in STO View tab --- src/org/infinity/resource/sto/Viewer.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/org/infinity/resource/sto/Viewer.java b/src/org/infinity/resource/sto/Viewer.java index fee7abbf2..5ad5301e9 100644 --- a/src/org/infinity/resource/sto/Viewer.java +++ b/src/org/infinity/resource/sto/Viewer.java @@ -13,8 +13,10 @@ import javax.swing.JPanel; import org.infinity.datatype.Flag; +import org.infinity.datatype.IsNumeric; import org.infinity.gui.ViewerUtil; import org.infinity.resource.AbstractStruct; +import org.infinity.resource.StructEntry; public final class Viewer extends JPanel { private static JPanel makeFieldPanel(StoResource sto) { @@ -31,6 +33,10 @@ private static JPanel makeFieldPanel(StoResource sto) { ViewerUtil.addLabelFieldPair(fieldPanel, sto.getAttribute(StoResource.STO_COST_TO_IDENTIFY), gbl, gbc, true); ViewerUtil.addLabelFieldPair(fieldPanel, sto.getAttribute(StoResource.STO_STEALING_DIFFICULTY), gbl, gbc, true); ViewerUtil.addLabelFieldPair(fieldPanel, sto.getAttribute(StoResource.STO_DEPRECIATION_RATE), gbl, gbc, true); + final StructEntry capacityEntry = sto.getAttribute(StoResource.STO_STORAGE_CAPACITY); + if (capacityEntry != null && ((IsNumeric) sto.getAttribute(StoResource.STO_STORAGE_CAPACITY)).getValue() > 0) { + ViewerUtil.addLabelFieldPair(fieldPanel, sto.getAttribute(StoResource.STO_STORAGE_CAPACITY), gbl, gbc, true); + } return fieldPanel; } From 2fd83bf6192ce1d67f6ebceb9fe4dc1ec5f9cd03 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 4 Jul 2023 11:58:16 +0200 Subject: [PATCH 11/28] Update README.md --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eb285212e..455a2ddbe 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,13 @@ # Near Infinity -A file browser and editor for the Infinity Engine. You can find out more in -the [Near Infinity Wiki](https://github.com/NearInfinityBrowser/NearInfinity/wiki), or download it directly from the -[Releases section](https://github.com/Argent77/NearInfinity/releases). +A file browser and editor for the Infinity Engine. + +Find out more in the [Near Infinity Wiki](https://github.com/NearInfinityBrowser/NearInfinity/wiki). + +Download Near Infinity directly from the [Releases section](https://github.com/Argent77/NearInfinity/releases) +or use [Nightly Releases](https://github.com/Argent77/NearInfinity/releases/tag/nightly) for the latest features +and bugfixes. **Discuss Near Infinity on:** - [GitHub Discussions](https://github.com/NearInfinityBrowser/NearInfinity/discussions) From 7b09798874461001a7a54a6d4432bee7d3766e40 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:18:31 +0200 Subject: [PATCH 12/28] BAM Converter: Fix enabled state of transparency threshold component in Options dialog Enable only if "Use alpha channel" is set to 'Never', or 'in EE Only' for non-EE games. --- src/org/infinity/gui/converter/BamOptionsDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/org/infinity/gui/converter/BamOptionsDialog.java b/src/org/infinity/gui/converter/BamOptionsDialog.java index 0a619bdfd..0a99f935b 100644 --- a/src/org/infinity/gui/converter/BamOptionsDialog.java +++ b/src/org/infinity/gui/converter/BamOptionsDialog.java @@ -371,9 +371,9 @@ public void focusLost(FocusEvent event) { @Override public void itemStateChanged(ItemEvent e) { if (e.getSource() == cbUseAlpha) { - boolean b = cbUseAlpha.getSelectedIndex() == ConvertToBam.ALPHA_ALWAYS - || (!Profile.isEnhancedEdition() && cbUseAlpha.getSelectedIndex() == ConvertToBam.ALPHA_AUTO); - sTransparency.setEnabled(b); + boolean bUseAlpha = cbUseAlpha.getSelectedIndex() == ConvertToBam.ALPHA_ALWAYS + || (Profile.isEnhancedEdition() && cbUseAlpha.getSelectedIndex() == ConvertToBam.ALPHA_AUTO); + sTransparency.setEnabled(!bUseAlpha); } } From 8c8a0bb97ed4ade668a51592dbd3568973c8a278 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:25:57 +0200 Subject: [PATCH 13/28] BAM Converter: Fix incorrect color mapping under certain conditions --- .../gui/converter/BamOptionsDialog.java | 6 +++ .../gui/converter/BamPaletteDialog.java | 38 +++++++++++-------- .../infinity/gui/converter/ConvertToBam.java | 8 +--- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/org/infinity/gui/converter/BamOptionsDialog.java b/src/org/infinity/gui/converter/BamOptionsDialog.java index 0a99f935b..72142a67e 100644 --- a/src/org/infinity/gui/converter/BamOptionsDialog.java +++ b/src/org/infinity/gui/converter/BamOptionsDialog.java @@ -90,6 +90,8 @@ class BamOptionsDialog extends JDialog implements ActionListener, FocusListener, private static int pvrzIndex = DEFAULT_PVRZ_INDEX; private static List recentSessions = new ArrayList<>(); + private final ConvertToBam converter; + private JButton bOK; private JButton bCancel; private JButton bDefaults; @@ -309,6 +311,7 @@ public BamOptionsDialog(ConvertToBam parent) { if (parent == null) { throw new NullPointerException(); } + this.converter = parent; init(); } @@ -575,5 +578,8 @@ private void updateSettings() { compressionType = cbCompressionType.getSelectedIndex(); pvrzIndex = (Integer) sPvrzIndex.getValue(); validateSettings(); + + // transparency options may have changed: force palette generation + converter.getPaletteDialog().setPaletteModified(); } } \ No newline at end of file diff --git a/src/org/infinity/gui/converter/BamPaletteDialog.java b/src/org/infinity/gui/converter/BamPaletteDialog.java index 20c021399..f0862a092 100644 --- a/src/org/infinity/gui/converter/BamPaletteDialog.java +++ b/src/org/infinity/gui/converter/BamPaletteDialog.java @@ -26,6 +26,8 @@ import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import javax.swing.AbstractAction; import javax.swing.BorderFactory; @@ -49,6 +51,7 @@ import org.infinity.icon.Icons; import org.infinity.resource.Profile; import org.infinity.resource.graphics.ColorConvert; +import org.infinity.resource.graphics.PseudoBamDecoder; import org.infinity.resource.graphics.PseudoBamDecoder.PseudoBamFrameEntry; import org.infinity.util.io.FileEx; import org.infinity.util.io.StreamUtils; @@ -72,7 +75,8 @@ class BamPaletteDialog extends JDialog private final LinkedHashMap colorMap = new LinkedHashMap<>(); private final int[][] palettes = new int[2][]; - private ConvertToBam converter; + private final ConvertToBam converter; + private ColorGrid cgPalette; private JLabel lInfoType; private JLabel lInfoIndex; @@ -362,25 +366,27 @@ public void updateGeneratedPalette() { } } else { // reducing color count to max. 256 - - // medianCut() should not consider the special transparent green color, workaround to keep it preserved - final Integer savedGreen = colorMap.remove(Green); - final int[] pixels = new int[colorMap.size()]; - final Iterator iter = colorMap.keySet().iterator(); - int idx = 0; - while (idx < pixels.length && iter.hasNext()) { - pixels[idx] = iter.next(); - idx++; - } - final int desiredColors = savedGreen != null ? 255 : 256; + int threshold = ConvertToBam.getUseAlpha() ? -1 : ConvertToBam.getTransparencyThreshold(); + int alpha = threshold >= 0 ? 0xff000000 : 0; + Set colors = colorMap + .keySet() + .stream() + .map(color -> PseudoBamDecoder.isTransparentColor(color, threshold) ? Green : color | alpha) + .collect(Collectors.toSet()); + + // medianCut() should not consider the special transparent "green" color, workaround to keep it preserved + boolean hasGreen = colors.remove(Green); + + final int[] pixels = colors.stream().mapToInt(Integer::intValue).toArray(); + final int desiredColors = hasGreen ? 255 : 256; ColorConvert.medianCut(pixels, desiredColors, palettes[TYPE_GENERATED], false); - if (savedGreen != null) { - colorMap.put(Green, savedGreen); + + if (hasGreen) { palettes[TYPE_GENERATED][255] = Green; } } - // moving special "green" to the first index + // moving special "green" color to the first index if ((palettes[TYPE_GENERATED][0] & 0x00ffffff) != 0x0000ff00) { for (int i = 1; i < palettes[TYPE_GENERATED].length; i++) { if ((palettes[TYPE_GENERATED][i] & 0x00ffffff) == 0x0000ff00) { @@ -394,7 +400,7 @@ public void updateGeneratedPalette() { if (colorMap.size() > 256) { boolean ignoreAlpha = !(Boolean) Profile.getProperty(Profile.Key.IS_SUPPORTED_BAM_V1_ALPHA); - int startIdx = (palettes[TYPE_GENERATED][0] & 0xffffff) == 0x00ff00 ? 1 : 0; + int startIdx = (palettes[TYPE_GENERATED][0] | 0xff000000) == Green ? 1 : 0; ColorConvert.sortPalette(palettes[TYPE_GENERATED], startIdx, BamOptionsDialog.getSortPalette(), ignoreAlpha); } diff --git a/src/org/infinity/gui/converter/ConvertToBam.java b/src/org/infinity/gui/converter/ConvertToBam.java index 14cdfc0a7..aefe0a0ff 100644 --- a/src/org/infinity/gui/converter/ConvertToBam.java +++ b/src/org/infinity/gui/converter/ConvertToBam.java @@ -4146,15 +4146,11 @@ private void updateFinalBamDecoder(int bamVersion) throws Exception { } else { Byte colIdx = colorCache.get(Integer.valueOf(c)); if (colIdx != null) { - int ci = colIdx.intValue() & 0xff; - if (ci >= transIndex) { - ci++; - } - dstBuf[ofs] = colIdx;// (byte)ci; + dstBuf[ofs] = colIdx; } else { double weight = getUseAlpha() ? 1.0 : 0.0; byte color = (byte) ColorConvert.getNearestColor(srcBuf[ofs], palette, weight, null, true); - dstBuf[ofs] = color;// (byte)ci; + dstBuf[ofs] = color; colorCache.put(c, color); } } From fbee4bd52e24e0ab8f9ff801d49c201d5f7d5bf2 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Thu, 6 Jul 2023 11:12:27 +0200 Subject: [PATCH 14/28] BAM Converter: Various optimizations --- .../gui/converter/BamFilterColorSwap.java | 44 ++++++++-- .../converter/BamFilterTransformResize.java | 69 +++++++++------ .../converter/BamFilterTransformRotate.java | 51 +++++++---- .../gui/converter/BamFilterTransformTrim.java | 86 +++++++++++-------- .../infinity/gui/converter/ConvertToBam.java | 77 ++++++++--------- 5 files changed, 203 insertions(+), 124 deletions(-) diff --git a/src/org/infinity/gui/converter/BamFilterColorSwap.java b/src/org/infinity/gui/converter/BamFilterColorSwap.java index 9b6888107..2a54b20cc 100644 --- a/src/org/infinity/gui/converter/BamFilterColorSwap.java +++ b/src/org/infinity/gui/converter/BamFilterColorSwap.java @@ -34,13 +34,39 @@ public class BamFilterColorSwap extends BamFilterBaseColor implements ChangeList private static final String FILTER_DESC = "This filter provides controls for swapping color " + "channels in any desired order."; - // Supported swap combinations - private static final String[] SWAP_TYPE_ITEMS = { "RBG", "GRB", "GBR", "BGR", "BRG" }; - private static final int[][] SWAP_TYPE_SHIFT = { - { 0, -8, 8 }, { -8, 8, 0 }, { -16, 8, 8 }, { -16, 0, 16 }, { -8, -8, 16 }, - }; + /** Definition of supported swap combinations. */ + private enum SwapType { + RBG("RBG", new int[] { 0, -8, 8}), + GRB("GRB", new int[] { -8, 8, 0}), + GBR("GBR", new int[] {-16, 8, 8}), + BGR("BGR", new int[] {-16, 0, 16}), + BRG("BRG", new int[] { -8, -8, 16}), + ; + + private final String label; + private final int[] shift; + + private SwapType(String label, int[] shift) { + this.label = label; + this.shift = shift; + } + + public String getLabel() { + return label; + } + + /** Returns the number of bits to shift for each color channel to get the resulting order. */ + public int[] getShift() { + return shift; + } + + @Override + public String toString() { + return getLabel(); + } + } - private JComboBox cbSwapType; + private JComboBox cbSwapType; private ButtonPopupWindow bpwExclude; private BamFilterBaseColor.ExcludeColorsPanel pExcludeColors; @@ -142,7 +168,7 @@ protected JPanel loadControls() { pExclude.add(new JPanel(), c); JLabel l = new JLabel("RGB =>"); - cbSwapType = new JComboBox<>(SWAP_TYPE_ITEMS); + cbSwapType = new JComboBox<>(SwapType.values()); cbSwapType.addActionListener(this); JPanel p = new JPanel(new GridBagLayout()); @@ -219,8 +245,8 @@ private BufferedImage applyEffect(BufferedImage srcImage) { } // shift contains shift values for r, g, b - int idx = cbSwapType.getSelectedIndex(); - int[] shift = SWAP_TYPE_SHIFT[idx]; + final SwapType type = (SwapType) cbSwapType.getSelectedItem(); + final int[] shift = type.getShift(); for (int i = 0; i < buffer.length; i++) { if ((cm == null || (cm != null && !pExcludeColors.isSelectedIndex(i))) && (buffer[i] & 0xff000000) != 0) { diff --git a/src/org/infinity/gui/converter/BamFilterTransformResize.java b/src/org/infinity/gui/converter/BamFilterTransformResize.java index bb5e46d7c..4ee0a93ec 100644 --- a/src/org/infinity/gui/converter/BamFilterTransformResize.java +++ b/src/org/infinity/gui/converter/BamFilterTransformResize.java @@ -45,13 +45,30 @@ public class BamFilterTransformResize extends BamFilterBaseTransform implements private static final String FILTER_NAME = "Resize BAM frames"; private static final String FILTER_DESC = "This filter allows you to adjust the size of each BAM frame."; - private static final int TYPE_NEAREST_NEIGHBOR = 0; - private static final int TYPE_BILINEAR = 1; - private static final int TYPE_BICUBIC = 2; - private static final int TYPE_SCALEX = 3; - private static final String[] SCALING_TYPE_ITEMS = { "Nearest neighbor", "Bilinear", "Bicubic", "Scale2x/3x/4x" }; + private enum ScalingType { + Nearest("Nearest Neighbor"), + Bilinear("Bilinear"), + Bicubic("Bicubic"), + ScaleX("Scale2x/3x/4x"), + ; - private JComboBox cbType; + private final String label; + + private ScalingType(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public String toString() { + return getLabel(); + } + } + + private JComboBox cbType; private JCheckBox cbAdjustCenter; private JRadioButton rbScaleBoth; private JRadioButton rbScaleIndividually; @@ -190,11 +207,13 @@ public boolean setConfiguration(String config) { @Override protected JPanel loadControls() { /* - * Possible scaling algorithms: - nearest neighbor (BamV1, BamV2) -> use Java's internal filters - bilinear (BamV2) - * -> use Java's internal filters - bicubic (BamV2) -> use Java's internal filters - scale2x/scale3x (BamV1, BamV2) - * -> http://en.wikipedia.org/wiki/Image_scaling - [?] lanczos (BamV2) -> - * http://en.wikipedia.org/wiki/Lanczos_resampling - [?] xBR (BamV1, BamV2) -> - * http://board.byuu.org/viewtopic.php?f=10&t=2248 + * Possible scaling algorithms: + * - nearest neighbor (BamV1, BamV2) -> use Java's internal filters + * - bilinear (BamV2) -> use Java's internal filters + * - bicubic (BamV2) -> use Java's internal filters + * - scale2x/scale3x (BamV1, BamV2) -> http://en.wikipedia.org/wiki/Image_scaling + * - [?] lanczos (BamV2) -> http://en.wikipedia.org/wiki/Lanczos_resampling + * - [?] xBR (BamV1, BamV2) -> http://board.byuu.org/viewtopic.php?f=10&t=2248 */ GridBagConstraints c = new GridBagConstraints(); @@ -204,7 +223,7 @@ protected JPanel loadControls() { lFactorX.setEnabled(false); lFactorY = new JLabel("Factor Y:"); lFactorY.setEnabled(false); - cbType = new JComboBox<>(SCALING_TYPE_ITEMS); + cbType = new JComboBox<>(ScalingType.values()); cbType.addActionListener(this); rbScaleBoth = new JRadioButton("Scale uniformly"); rbScaleIndividually = new JRadioButton("Scale individually"); @@ -330,7 +349,7 @@ private void updateStatus() { final String fmtSupport1 = "Supported target: %s"; final String fmtSupport2 = "Supported targets: %s, %s"; - int type = cbType.getSelectedIndex(); + final ScalingType type = (ScalingType) cbType.getSelectedItem(); double factor = getFactor(spinnerFactor); double factorX = getFactor(spinnerFactorX); double factorY = getFactor(spinnerFactorY); @@ -338,7 +357,7 @@ private void updateStatus() { boolean uniformEnabled = rbScaleBoth.isSelected() && isTypeSupported(type); boolean individualEnabled = rbScaleIndividually.isSelected() && isTypeSupported(type); switch (type) { - case TYPE_NEAREST_NEIGHBOR: + case Nearest: taInfo.setText(String.format(fmtSupport2, ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV1], ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV2])); setFactor(spinnerFactor, factor, 0.01, 10.0, 0.05); @@ -352,7 +371,7 @@ private void updateStatus() { spinnerFactorX.setEnabled(individualEnabled); spinnerFactorY.setEnabled(individualEnabled); break; - case TYPE_BILINEAR: + case Bilinear: taInfo.setText(String.format(fmtSupport1, ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV2])); setFactor(spinnerFactor, factor, 0.01, 10.0, 0.05); setFactor(spinnerFactorX, factorX, 0.01, 10.0, 0.05); @@ -365,7 +384,7 @@ private void updateStatus() { spinnerFactorX.setEnabled(individualEnabled); spinnerFactorY.setEnabled(individualEnabled); break; - case TYPE_BICUBIC: + case Bicubic: taInfo.setText(String.format(fmtSupport1, ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV2])); setFactor(spinnerFactor, factor, 0.01, 10.0, 0.05); setFactor(spinnerFactorX, factorX, 0.01, 10.0, 0.05); @@ -378,7 +397,7 @@ private void updateStatus() { spinnerFactorX.setEnabled(individualEnabled); spinnerFactorY.setEnabled(individualEnabled); break; - case TYPE_SCALEX: + case ScaleX: taInfo.setText(String.format(fmtSupport2, ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV1], ConvertToBam.BAM_VERSION_ITEMS[ConvertToBam.VERSION_BAMV2])); setFactor(spinnerFactor, (int) factor, 2, 4, 1); @@ -401,10 +420,10 @@ private void updateStatus() { } } - private boolean isTypeSupported(int type) { + private boolean isTypeSupported(ScalingType type) { switch (type) { - case TYPE_BILINEAR: - case TYPE_BICUBIC: + case Bilinear: + case Bicubic: return !getConverter().isBamV1Selected(); default: return true; @@ -470,18 +489,18 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { BufferedImage dstImage; double factorX = getFactor(rbScaleBoth.isSelected() ? spinnerFactor : spinnerFactorX); double factorY = getFactor(rbScaleBoth.isSelected() ? spinnerFactor : spinnerFactorY); - int type = cbType.getSelectedIndex(); + final ScalingType type = (ScalingType) cbType.getSelectedItem(); switch (type) { - case TYPE_NEAREST_NEIGHBOR: + case Nearest: dstImage = scaleNative(entry.getFrame(), factorX, factorY, AffineTransformOp.TYPE_NEAREST_NEIGHBOR, true); break; - case TYPE_BILINEAR: + case Bilinear: dstImage = scaleNative(entry.getFrame(), factorX, factorY, AffineTransformOp.TYPE_BILINEAR, false); break; - case TYPE_BICUBIC: + case Bicubic: dstImage = scaleNative(entry.getFrame(), factorX, factorY, AffineTransformOp.TYPE_BICUBIC, false); break; - case TYPE_SCALEX: + case ScaleX: dstImage = scaleScaleX(entry.getFrame(), (int) factorX); break; default: diff --git a/src/org/infinity/gui/converter/BamFilterTransformRotate.java b/src/org/infinity/gui/converter/BamFilterTransformRotate.java index 24aa568fb..888ed1cbd 100644 --- a/src/org/infinity/gui/converter/BamFilterTransformRotate.java +++ b/src/org/infinity/gui/converter/BamFilterTransformRotate.java @@ -33,15 +33,32 @@ public class BamFilterTransformRotate extends BamFilterBaseTransform implements private static final String FILTER_NAME = "Rotate BAM frames"; private static final String FILTER_DESC = "This filter allows you to rotate each BAM frame by a specified amount."; - private static final int ANGLE_90 = 0; - private static final int ANGLE_180 = 1; - private static final int ANGLE_270 = 2; - private static final String[] ANGLE_ITEMS = { "90\u00B0", "180\u00B0", "270\u00B0" }; + private enum Angle { + Angle90("90\u00B0"), + Angle180("180\u00B0"), + Angle270("270\u00B0"), + ; + + private final String label; + + private Angle(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public String toString() { + return getLabel(); + } + } private JRadioButton rbCW; private JRadioButton rbCCW; private JCheckBox cbAdjustCenter; - private JComboBox cbAngle; + private JComboBox cbAngle; public static String getFilterName() { return FILTER_NAME; @@ -136,7 +153,7 @@ protected JPanel loadControls() { rbCCW.addActionListener(this); bg.add(rbCW); bg.add(rbCCW); - cbAngle = new JComboBox<>(ANGLE_ITEMS); + cbAngle = new JComboBox<>(Angle.values()); cbAngle.addActionListener(this); cbAdjustCenter = new JCheckBox("Adjust center position", true); cbAdjustCenter.addActionListener(this); @@ -190,9 +207,9 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { int height = entry.getFrame().getHeight(); BufferedImage dstImage = null; int newWidth, newHeight; - switch (cbAngle.getSelectedIndex()) { - case ANGLE_90: - case ANGLE_270: + switch ((Angle) cbAngle.getSelectedItem()) { + case Angle90: + case Angle270: newWidth = height; newHeight = width; break; @@ -216,9 +233,9 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { } // normalizing rotation for easier processing - int angle = cbAngle.getSelectedIndex(); + Angle angle = (Angle) cbAngle.getSelectedItem(); if (rbCCW.isSelected()) { - angle = ANGLE_270 - angle; + angle = Angle.values()[Angle.values().length - angle.ordinal() - 1]; } // rotating each pixel int srcOfs = 0; @@ -226,15 +243,15 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { for (int x = 0; x < width; x++, srcOfs++) { int nx, ny; switch (angle) { - case ANGLE_90: + case Angle90: nx = newWidth - y - 1; ny = x; break; - case ANGLE_180: + case Angle180: nx = newWidth - x - 1; ny = newHeight - y - 1; break; - case ANGLE_270: + case Angle270: nx = y; ny = newHeight - x - 1; break; @@ -257,15 +274,15 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { if (cbAdjustCenter.isSelected()) { int cx = entry.getCenterX(), cy = entry.getCenterY(); switch (angle) { - case ANGLE_90: + case Angle90: cx = newWidth - entry.getCenterY() - 1; cy = entry.getCenterX(); break; - case ANGLE_180: + case Angle180: cx = newWidth - entry.getCenterX() - 1; cy = newHeight - entry.getCenterY() - 1; break; - case ANGLE_270: + case Angle270: cx = entry.getCenterY(); cy = newHeight - entry.getCenterX() - 1; break; diff --git a/src/org/infinity/gui/converter/BamFilterTransformTrim.java b/src/org/infinity/gui/converter/BamFilterTransformTrim.java index 14616e1bc..1f1d234ea 100644 --- a/src/org/infinity/gui/converter/BamFilterTransformTrim.java +++ b/src/org/infinity/gui/converter/BamFilterTransformTrim.java @@ -15,6 +15,7 @@ import java.awt.image.DataBufferInt; import java.awt.image.IndexColorModel; import java.util.Arrays; +import java.util.EnumMap; import javax.swing.JCheckBox; import javax.swing.JLabel; @@ -35,14 +36,30 @@ public class BamFilterTransformTrim extends BamFilterBaseTransform implements Ac private static final String FILTER_DESC = "This filter attempts to remove unused space around each " + "BAM frame. Center positions will be adjusted accordingly."; - private static final int EDGE_TOP = 0; - private static final int EDGE_BOTTOM = 1; - private static final int EDGE_LEFT = 2; - private static final int EDGE_RIGHT = 3; - private static final String[] EDGE_LABELS = { "Top", "Bottom", "Left", "Right" }; + private enum Edge { + Top("Top"), + Bottom("Bottom"), + Left("Left"), + Right("Right"), + ; - private JCheckBox[] cbEdges; + private final String label; + private Edge(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } + + @Override + public String toString() { + return getLabel(); + } + } + + private EnumMap cbEdges; private JSpinner spinnerMargin; private JCheckBox cbAdjustCenter; @@ -71,10 +88,10 @@ public PseudoBamFrameEntry updatePreview(PseudoBamFrameEntry entry) { @Override public String getConfiguration() { StringBuilder sb = new StringBuilder(); - sb.append(cbEdges[EDGE_TOP].isSelected()).append(';'); - sb.append(cbEdges[EDGE_LEFT].isSelected()).append(';'); - sb.append(cbEdges[EDGE_BOTTOM].isSelected()).append(';'); - sb.append(cbEdges[EDGE_RIGHT].isSelected()).append(';'); + sb.append(cbEdges.get(Edge.Top).isSelected()).append(';'); + sb.append(cbEdges.get(Edge.Left).isSelected()).append(';'); + sb.append(cbEdges.get(Edge.Bottom).isSelected()).append(';'); + sb.append(cbEdges.get(Edge.Right).isSelected()).append(';'); sb.append(((SpinnerNumberModel) spinnerMargin.getModel()).getNumber().intValue()).append(';'); sb.append(cbAdjustCenter.isSelected()); return sb.toString(); @@ -144,10 +161,10 @@ public boolean setConfiguration(String config) { } } - cbEdges[EDGE_TOP].setSelected(t); - cbEdges[EDGE_LEFT].setSelected(l); - cbEdges[EDGE_BOTTOM].setSelected(b); - cbEdges[EDGE_RIGHT].setSelected(r); + cbEdges.get(Edge.Top).setSelected(t); + cbEdges.get(Edge.Left).setSelected(l); + cbEdges.get(Edge.Bottom).setSelected(b); + cbEdges.get(Edge.Right).setSelected(r); if (margin != Integer.MIN_VALUE) { spinnerMargin.setValue(margin); } @@ -166,10 +183,11 @@ protected JPanel loadControls() { JLabel l2 = new JLabel("Margin:"); JLabel l3 = new JLabel("pixels"); - cbEdges = new JCheckBox[4]; - for (int i = 0; i < cbEdges.length; i++) { - cbEdges[i] = new JCheckBox(EDGE_LABELS[i], true); - cbEdges[i].addActionListener(this); + cbEdges = new EnumMap<>(Edge.class); + for (final Edge edge : Edge.values()) { + final JCheckBox cb = new JCheckBox(edge.getLabel(), true); + cb.addActionListener(this); + cbEdges.put(edge, cb); } spinnerMargin = new JSpinner(new SpinnerNumberModel(0, 0, 255, 1)); @@ -181,16 +199,16 @@ protected JPanel loadControls() { JPanel p1 = new JPanel(new GridBagLayout()); ViewerUtil.setGBC(c, 0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); - p1.add(cbEdges[EDGE_TOP], c); + p1.add(cbEdges.get(Edge.Top), c); ViewerUtil.setGBC(c, 1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 8, 0, 0), 0, 0); - p1.add(cbEdges[EDGE_LEFT], c); + p1.add(cbEdges.get(Edge.Left), c); ViewerUtil.setGBC(c, 2, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 8, 0, 0), 0, 0); - p1.add(cbEdges[EDGE_BOTTOM], c); + p1.add(cbEdges.get(Edge.Bottom), c); ViewerUtil.setGBC(c, 3, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 8, 0, 0), 0, 0); - p1.add(cbEdges[EDGE_RIGHT], c); + p1.add(cbEdges.get(Edge.Right), c); JPanel p2 = new JPanel(new GridBagLayout()); ViewerUtil.setGBC(c, 1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, @@ -235,8 +253,8 @@ public void actionPerformed(ActionEvent event) { if (event.getSource() == cbAdjustCenter) { fireChangeListener(); } else { - for (JCheckBox cbEdge : cbEdges) { - if (cbEdge == event.getSource()) { + for (final JCheckBox cb : cbEdges.values()) { + if (cb == event.getSource()) { fireChangeListener(); return; } @@ -292,12 +310,12 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { // calculating the properties of the resulting image int left = 0, right = width - 1, top = 0, bottom = height - 1; - boolean edgeLeft = !cbEdges[EDGE_LEFT].isSelected(), edgeRight = !cbEdges[EDGE_RIGHT].isSelected(), - edgeTop = !cbEdges[EDGE_TOP].isSelected(), edgeBottom = !cbEdges[EDGE_BOTTOM].isSelected(); + boolean edgeLeft = !cbEdges.get(Edge.Left).isSelected(), edgeRight = !cbEdges.get(Edge.Right).isSelected(), + edgeTop = !cbEdges.get(Edge.Top).isSelected(), edgeBottom = !cbEdges.get(Edge.Bottom).isSelected(); while ((left < right || top < bottom) && (!edgeLeft || !edgeRight || !edgeTop || !edgeBottom)) { int ofs, step; // checking top edge - if (cbEdges[EDGE_TOP].isSelected() && !edgeTop) { + if (cbEdges.get(Edge.Top).isSelected() && !edgeTop) { ofs = top * width; step = 1; for (int x = 0; x < width; x++, ofs += step) { @@ -316,7 +334,7 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { } // checking bottom edge - if (cbEdges[EDGE_BOTTOM].isSelected() && !edgeBottom) { + if (cbEdges.get(Edge.Bottom).isSelected() && !edgeBottom) { ofs = bottom * width; step = 1; for (int x = 0; x < width; x++, ofs += step) { @@ -335,7 +353,7 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { } // checking left edge - if (cbEdges[EDGE_LEFT].isSelected() && !edgeLeft) { + if (cbEdges.get(Edge.Left).isSelected() && !edgeLeft) { ofs = left; step = width; for (int y = 0; y < height; y++, ofs += step) { @@ -354,7 +372,7 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { } // checking right edge - if (cbEdges[EDGE_RIGHT].isSelected() && !edgeRight) { + if (cbEdges.get(Edge.Right).isSelected() && !edgeRight) { ofs = right; step = width; for (int y = 0; y < height; y++, ofs += step) { @@ -392,18 +410,18 @@ private PseudoBamFrameEntry applyEffect(PseudoBamFrameEntry entry) { int dstY = 0; newWidth = right - left + 1; newHeight = bottom - top + 1; - if (cbEdges[EDGE_LEFT].isSelected()) { + if (cbEdges.get(Edge.Left).isSelected()) { newWidth += margin; dstX += margin; } - if (cbEdges[EDGE_RIGHT].isSelected()) { + if (cbEdges.get(Edge.Right).isSelected()) { newWidth += margin; } - if (cbEdges[EDGE_TOP].isSelected()) { + if (cbEdges.get(Edge.Top).isSelected()) { newHeight += margin; dstY += margin; } - if (cbEdges[EDGE_BOTTOM].isSelected()) { + if (cbEdges.get(Edge.Bottom).isSelected()) { newHeight += margin; } if (srcB != null) { diff --git a/src/org/infinity/gui/converter/ConvertToBam.java b/src/org/infinity/gui/converter/ConvertToBam.java index aefe0a0ff..192d6298f 100644 --- a/src/org/infinity/gui/converter/ConvertToBam.java +++ b/src/org/infinity/gui/converter/ConvertToBam.java @@ -3994,51 +3994,50 @@ private void updateFilteredBamDecoder(int bamVersion, boolean force) throws Exce // Processing each filter sequentially List filters = createFilterList(false); - if (filters != null) { - for (int idx = 0; idx < filters.size(); idx++) { - if (filters.get(idx) instanceof BamFilterBaseColor) { - // processing color filter - try { - BamFilterBaseColor filter = (BamFilterBaseColor) filters.get(idx); - for (PseudoBamFrameEntry element : listFrameEntries.get(BAM_FINAL)) { - BufferedImage image = filter.process(element.getFrame()); - if (image != null) { - element.setFrame(image); - image = null; - } else { - throw new Exception(); - } + for (final BamFilterBase filter : filters) { + if (filter instanceof BamFilterBaseColor) { + // processing color filter + try { + final BamFilterBaseColor colorFilter = (BamFilterBaseColor) filter; + for (PseudoBamFrameEntry element : listFrameEntries.get(BAM_FINAL)) { + BufferedImage image = colorFilter.process(element.getFrame()); + if (image != null) { + element.setFrame(image); + image = null; + } else { + throw new Exception(); } - } catch (Exception e) { - e.printStackTrace(); - throw e; } - } else if (filters.get(idx) instanceof BamFilterBaseTransform) { - // processing transform filter - try { - BamFilterBaseTransform filter = (BamFilterBaseTransform) filters.get(idx); - for (int frameIdx = 0; frameIdx < listFrameEntries.get(BAM_FINAL).size(); frameIdx++) { - PseudoBamFrameEntry entry = filter.process(listFrameEntries.get(BAM_FINAL).get(frameIdx)); - if (entry != null) { - if (entry != listFrameEntries.get(BAM_FINAL).get(frameIdx)) { - listFrameEntries.get(BAM_FINAL).set(frameIdx, entry); - } - } else { - throw new Exception(); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } else if (filter instanceof BamFilterBaseTransform) { + // processing transform filter + try { + final BamFilterBaseTransform transformFilter = (BamFilterBaseTransform) filter; + for (int frameIdx = 0, frameSize = listFrameEntries.get(BAM_FINAL).size(); frameIdx < frameSize; frameIdx++) { + final PseudoBamFrameEntry srcEntry = listFrameEntries.get(BAM_FINAL).get(frameIdx); + final PseudoBamFrameEntry dstEntry = transformFilter.process(srcEntry); + if (dstEntry != null) { + if (dstEntry != srcEntry) { + listFrameEntries.get(BAM_FINAL).set(frameIdx, dstEntry); } + } else { + throw new Exception(String.format("%s: Result is null", transformFilter)); } - } catch (Exception e) { - e.printStackTrace(); - throw e; } - } else if (filters.get(idx) instanceof BamFilterBaseOutput) { - // skipping output filter + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } else if (filter instanceof BamFilterBaseOutput) { + // skipping output filter + } else { + if (filter != null) { + System.err.println(String.format("Skipping unrecognized filter: %s", filter)); } else { - if (filters.get(idx) != null) { - System.err.println(String.format("Unrecognized filter at index %d: %s", idx, filters.get(idx))); - } else { - System.err.println(String.format("null filter at index %d", idx)); - } + System.err.println("Skipping null filter"); } } } From 75d3dc8bbcd8a586a1835dfc5041ee1e6bbaed22 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Sat, 8 Jul 2023 09:58:54 +0200 Subject: [PATCH 15/28] Fix type inference issue See NearInfinityBrowser/NearInfinity#160 --- src/org/infinity/gui/PreferencesDialog.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java index b2c801d78..e5bbc6b48 100644 --- a/src/org/infinity/gui/PreferencesDialog.java +++ b/src/org/infinity/gui/PreferencesDialog.java @@ -25,9 +25,8 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.nio.charset.Charset; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; +import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Locale; @@ -694,11 +693,12 @@ private void setTreeExpandedState(boolean expanded) { /** Used by {@link #setTreeExpandedState(boolean)} to expand nodes of the categories tree. */ private void setTreeNodeExpandedState(DefaultMutableTreeNode node, boolean expanded) { - @SuppressWarnings("unchecked") - final ArrayList list = Collections.list(node.children()); - - for (final DefaultMutableTreeNode curNode: list) { - setTreeNodeExpandedState(curNode, expanded); + final Enumeration children = node.children(); + while (children.hasMoreElements()) { + final Object e = children.nextElement(); + if (e instanceof DefaultMutableTreeNode) { + setTreeNodeExpandedState((DefaultMutableTreeNode) e, expanded); + } } if (!expanded && node.isRoot()) { From 24f43cd58f9ed390d07fa2ff8f172244a912ddc8 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Sat, 8 Jul 2023 22:39:58 +0200 Subject: [PATCH 16/28] General code cleanup - Removed unnecessary typecasts - Removed redundant generic types - Fixed indirect access to static members --- src/org/infinity/AppOption.java | 12 ++++---- src/org/infinity/NearInfinity.java | 18 +++++------ .../infinity/check/StringSoundsChecker.java | 2 +- src/org/infinity/gui/BcsDropFrame.java | 5 ++-- src/org/infinity/gui/OpenFileFrame.java | 3 +- src/org/infinity/gui/PreferencesDialog.java | 5 ++-- src/org/infinity/gui/StringEditor.java | 3 +- src/org/infinity/gui/menu/BrowserMenuBar.java | 1 + src/org/infinity/resource/are/Viewer.java | 5 ++-- .../are/viewer/LayerObjectAreActor.java | 2 +- .../are/viewer/LayerObjectGlobalActor.java | 2 +- .../are/viewer/LayerObjectIniActor.java | 2 +- src/org/infinity/resource/bcs/Decompiler.java | 2 +- .../resource/cre/browser/RenderPanel.java | 2 +- .../resource/cre/browser/SettingsPanel.java | 6 ++-- .../resource/cre/decoder/AmbientDecoder.java | 2 +- .../cre/decoder/AmbientStaticDecoder.java | 2 +- .../cre/decoder/CharacterDecoder.java | 6 ++-- .../cre/decoder/CharacterOldDecoder.java | 4 +-- .../cre/decoder/MonsterAnkhegDecoder.java | 2 +- .../resource/cre/decoder/MonsterDecoder.java | 8 ++--- .../cre/decoder/MonsterIcewindDecoder.java | 4 +-- .../cre/decoder/MonsterLarge16Decoder.java | 2 +- .../cre/decoder/MonsterLargeDecoder.java | 2 +- .../cre/decoder/MonsterLayeredDecoder.java | 2 +- .../decoder/MonsterLayeredSpellDecoder.java | 2 +- .../cre/decoder/MonsterMultiDecoder.java | 4 +-- .../cre/decoder/MonsterMultiNewDecoder.java | 4 +-- .../cre/decoder/MonsterOldDecoder.java | 2 +- .../cre/decoder/MonsterPlanescapeDecoder.java | 4 +-- .../cre/decoder/MonsterQuadrantDecoder.java | 2 +- .../cre/decoder/tables/SpriteTables.java | 2 +- .../resource/cre/decoder/util/FrameInfo.java | 2 +- .../resource/cre/decoder/util/SegmentDef.java | 2 +- .../resource/cre/decoder/util/Sequence.java | 2 +- .../cre/decoder/util/SpriteUtils.java | 2 +- .../infinity/resource/effects/BaseOpcode.java | 2 +- .../resource/graphics/DxtEncoder.java | 22 +++++++------- .../resource/graphics/PltResource.java | 2 +- src/org/infinity/resource/itm/Viewer.java | 3 +- .../resource/other/UnknownResource.java | 5 ++-- .../infinity/resource/sound/AcmBuffer.java | 3 ++ src/org/infinity/resource/spl/Viewer.java | 3 +- .../resource/text/modes/BCSFoldParser.java | 7 +++-- .../resource/text/modes/BCSTokenMaker.java | 30 +++++++++---------- .../resource/text/modes/INITokenMaker.java | 21 ++++++------- .../resource/text/modes/TLKTokenMaker.java | 13 ++++---- .../text/modes/WeiDULogTokenMaker.java | 15 +++++----- .../search/advanced/SearchOptions.java | 2 +- src/org/infinity/util/Misc.java | 5 ++++ 50 files changed, 143 insertions(+), 122 deletions(-) diff --git a/src/org/infinity/AppOption.java b/src/org/infinity/AppOption.java index 98541de6a..f5db46ac9 100644 --- a/src/org/infinity/AppOption.java +++ b/src/org/infinity/AppOption.java @@ -757,31 +757,31 @@ public Object loadValue() throws ClassCastException { final Preferences prefs = getPrefs(); if (Boolean.class.isAssignableFrom(valueType)) { if (prefs != null) { - initialValue = (Boolean) prefs.getBoolean(getName(), (Boolean) getDefault()); + initialValue = prefs.getBoolean(getName(), (Boolean) getDefault()); } else { initialValue = getDefault(); } } else if (Integer.class.isAssignableFrom(valueType)) { if (prefs != null) { - initialValue = (Integer) prefs.getInt(getName(), (Integer) getDefault()); + initialValue = prefs.getInt(getName(), (Integer) getDefault()); } else { initialValue = getDefault(); } } else if (Long.class.isAssignableFrom(valueType)) { if (prefs != null) { - initialValue = (Long) prefs.getLong(getName(), (Long) getDefault()); + initialValue = prefs.getLong(getName(), (Long) getDefault()); } else { initialValue = getDefault(); } } else if (Float.class.isAssignableFrom(valueType)) { if (prefs != null) { - initialValue = (Float) prefs.getFloat(getName(), (Float) getDefault()); + initialValue = prefs.getFloat(getName(), (Float) getDefault()); } else { initialValue = getDefault(); } } else if (Double.class.isAssignableFrom(valueType)) { if (prefs != null) { - initialValue = (Double) prefs.getDouble(getName(), (Double) getDefault()); + initialValue = prefs.getDouble(getName(), (Double) getDefault()); } else { initialValue = getDefault(); } @@ -863,7 +863,7 @@ public boolean equals(Object obj) { private Object validate(Object value) throws ClassCastException { value = validator.apply(value); if ((value == null && validateType(valueType) == valueType) || - valueType.isAssignableFrom(validateType(value.getClass()))) { + (value != null && valueType.isAssignableFrom(validateType(value.getClass())))) { // pass return value; } diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java index ee4d974a0..6394e28e9 100644 --- a/src/org/infinity/NearInfinity.java +++ b/src/org/infinity/NearInfinity.java @@ -1109,7 +1109,7 @@ public boolean isDarkMode() { final Color bg = Misc.getDefaultColor("TextField.background", Color.WHITE); final double bgIntensity; if (bg != null) { - bgIntensity = (double) bg.getRed() * 0.299 + (double) bg.getGreen() * 0.587 + (double) bg.getBlue() * 0.114; + bgIntensity = bg.getRed() * 0.299 + bg.getGreen() * 0.587 + bg.getBlue() * 0.114; } else { bgIntensity = 0.0; } @@ -1117,7 +1117,7 @@ public boolean isDarkMode() { final Color fg = Misc.getDefaultColor("TextField.foreground", Color.BLACK); final double fgIntensity; if (fg != null) { - fgIntensity = (double) fg.getRed() * 0.299 + (double) fg.getGreen() * 0.587 + (double) fg.getBlue() * 0.114; + fgIntensity = fg.getRed() * 0.299 + fg.getGreen() * 0.587 + fg.getBlue() * 0.114; } else { fgIntensity = 255.0; } @@ -1387,13 +1387,13 @@ private JPanel createJavaInfoPanel() { } final List> entries = new ArrayList<>(); - entries.add(new Couple("Near Infinity", getVersion())); - entries.add(new Couple("Java Runtime", System.getProperty("java.runtime.name"))); + entries.add(new Couple<>("Near Infinity", getVersion())); + entries.add(new Couple<>("Java Runtime", System.getProperty("java.runtime.name"))); String s1 = System.getProperty("java.version", "n/a"); String s2 = System.getProperty("java.version.date", ""); String value = s2.isEmpty() ? s1 : String.format("%s (%s)", s1, s2); - entries.add(new Couple("Java Version", value)); + entries.add(new Couple<>("Java Version", value)); value = System.getProperty("java.vm.name", "n/a") + " (" + System.getProperty("java.vm.version", "n/a"); s1 = System.getProperty("java.vm.info", ""); @@ -1401,16 +1401,16 @@ private JPanel createJavaInfoPanel() { value += ", " + s1; } value += ")"; - entries.add(new Couple("Java VM", value)); + entries.add(new Couple<>("Java VM", value)); - entries.add(new Couple("Java VM Architecture", System.getProperty("os.arch", "n/a"))); + entries.add(new Couple<>("Java VM Architecture", System.getProperty("os.arch", "n/a"))); long memoryMax = Runtime.getRuntime().maxMemory(); if (memoryMax != Long.MAX_VALUE) { memoryMax /= 1024L * 1024L; - entries.add(new Couple("Available Memory", String.format("%d MB", memoryMax))); + entries.add(new Couple<>("Available Memory", String.format("%d MB", memoryMax))); } else { - entries.add(new Couple("Available Memory", "n/a")); + entries.add(new Couple<>("Available Memory", "n/a")); } JPanel infoPanel = new JPanel(new GridBagLayout()); diff --git a/src/org/infinity/check/StringSoundsChecker.java b/src/org/infinity/check/StringSoundsChecker.java index 56ab691ae..df67786c1 100644 --- a/src/org/infinity/check/StringSoundsChecker.java +++ b/src/org/infinity/check/StringSoundsChecker.java @@ -222,7 +222,7 @@ private ChildFrame getResultFrame() { buttonPanel.add(openStringTableButton); buttonPanel.add(saveButton); - tabbedPane = new JTabbedPane(JTabbedPane.TOP); + tabbedPane = new JTabbedPane(SwingConstants.TOP); // Male string table JScrollPane scrollTable = new JScrollPane(table); diff --git a/src/org/infinity/gui/BcsDropFrame.java b/src/org/infinity/gui/BcsDropFrame.java index 8fe41cc26..93f1d2bd4 100644 --- a/src/org/infinity/gui/BcsDropFrame.java +++ b/src/org/infinity/gui/BcsDropFrame.java @@ -45,6 +45,7 @@ import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextField; +import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -68,8 +69,8 @@ public class BcsDropFrame extends ChildFrame implements ActionListener, ListSele private final JButton bSelectDir = new JButton(Icons.ICON_OPEN_16.getIcon()); private final JCheckBox cbIgnoreWarnings = new JCheckBox("Ignore compiler warnings", true); private final JFileChooser fc = new JFileChooser(Profile.getGameRoot().toFile()); - private final JLabel compZone = new JLabel("Compiler drop zone (BAF)", JLabel.CENTER); - private final JLabel decompZone = new JLabel("Decompiler drop zone (BCS/BS)", JLabel.CENTER); + private final JLabel compZone = new JLabel("Compiler drop zone (BAF)", SwingConstants.CENTER); + private final JLabel decompZone = new JLabel("Decompiler drop zone (BCS/BS)", SwingConstants.CENTER); private final JLabel statusMsg = new JLabel(" Drag and drop files or folders into the zones"); private final JRadioButton rbSaveBS = new JRadioButton("BS", false); private final JRadioButton rbSaveBCS = new JRadioButton("BCS", true); diff --git a/src/org/infinity/gui/OpenFileFrame.java b/src/org/infinity/gui/OpenFileFrame.java index 4288f65c2..031dcaaa8 100644 --- a/src/org/infinity/gui/OpenFileFrame.java +++ b/src/org/infinity/gui/OpenFileFrame.java @@ -36,6 +36,7 @@ import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; +import javax.swing.SwingConstants; import javax.swing.UIManager; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -55,7 +56,7 @@ public final class OpenFileFrame extends ChildFrame implements ActionListener { private final JButton bOpen = new JButton("Open", Icons.ICON_OPEN_16.getIcon()); private final JButton bOpenNew = new JButton("Open in new window", Icons.ICON_OPEN_16.getIcon()); private final JCheckBox cbStayOpen = new JCheckBox("Keep this dialog open"); - private final JLabel lExternalDrop = new JLabel("or drop file(s) here", JLabel.CENTER); + private final JLabel lExternalDrop = new JLabel("or drop file(s) here", SwingConstants.CENTER); private final JRadioButton rbExternal = new JRadioButton("Open external file"); private final JRadioButton rbInternal = new JRadioButton("Open internal file"); private final JTextField tfExternalName = new JTextField(20); diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java index e5bbc6b48..9dc3b9c0b 100644 --- a/src/org/infinity/gui/PreferencesDialog.java +++ b/src/org/infinity/gui/PreferencesDialog.java @@ -56,6 +56,7 @@ import javax.swing.ScrollPaneConstants; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; +import javax.swing.WindowConstants; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; @@ -753,7 +754,7 @@ private Dimension calculateTextDimension(int rows, int cols, Font font) { } private void init() { - setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), this); getRootPane().getActionMap().put(this, new AbstractAction() { @@ -1315,7 +1316,7 @@ private boolean globalFontSizeOnSelect(OptionGroupBox gb) { try { @SuppressWarnings("unchecked") DataItem item = (DataItem) gb.getItem(gb.getSelectedIndex()); - int size = (Integer) item.getData(); + int size = item.getData(); if (size < 0) { size = gb.getOption().getIntValue(); } diff --git a/src/org/infinity/gui/StringEditor.java b/src/org/infinity/gui/StringEditor.java index 04a2e630b..469209310 100644 --- a/src/org/infinity/gui/StringEditor.java +++ b/src/org/infinity/gui/StringEditor.java @@ -34,6 +34,7 @@ import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.ProgressMonitor; +import javax.swing.SwingConstants; import javax.swing.SwingWorker; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; @@ -72,7 +73,7 @@ public class StringEditor extends ChildFrame implements SearchClient { private final ArrayDeque undoStack = new ArrayDeque<>(); private final Listeners listeners = new Listeners(); - private final JTabbedPane tabPane = new JTabbedPane(JTabbedPane.TOP); + private final JTabbedPane tabPane = new JTabbedPane(SwingConstants.TOP); private final ButtonPopupMenu bpmFind = new ButtonPopupMenu("Find...", ButtonPopupMenu.Align.TOP); private final ButtonPopupMenu bpmExport = new ButtonPopupMenu("Export...", ButtonPopupMenu.Align.TOP); private final ButtonPopupMenu bpmRevert = new ButtonPopupMenu("Revert...", ButtonPopupMenu.Align.TOP); diff --git a/src/org/infinity/gui/menu/BrowserMenuBar.java b/src/org/infinity/gui/menu/BrowserMenuBar.java index 824d9e28b..10208a955 100644 --- a/src/org/infinity/gui/menu/BrowserMenuBar.java +++ b/src/org/infinity/gui/menu/BrowserMenuBar.java @@ -165,6 +165,7 @@ public ToolsMenu getToolsMenu() { } /** Provides access to the "Help" menu. */ + @Override public HelpMenu getHelpMenu() { return helpMenu; } diff --git a/src/org/infinity/resource/are/Viewer.java b/src/org/infinity/resource/are/Viewer.java index 985758b60..0ab255bcd 100644 --- a/src/org/infinity/resource/are/Viewer.java +++ b/src/org/infinity/resource/are/Viewer.java @@ -18,6 +18,7 @@ import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; import org.infinity.datatype.Flag; import org.infinity.gui.ViewerUtil; @@ -55,7 +56,7 @@ private JComponent makeFieldPanel() { fieldBasePanel.add(bView, BorderLayout.SOUTH); JScrollPane scrollPane = new JScrollPane(fieldBasePanel); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); return scrollPane; @@ -72,7 +73,7 @@ private JComponent makeFlagsPanel() { panel.add(locationPanel); JScrollPane scrollPane = new JScrollPane(panel); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); diff --git a/src/org/infinity/resource/are/viewer/LayerObjectAreActor.java b/src/org/infinity/resource/are/viewer/LayerObjectAreActor.java index b2445d19b..a01cd2325 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectAreActor.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectAreActor.java @@ -28,7 +28,7 @@ * Handles specific layer type: ARE/Actor */ public class LayerObjectAreActor extends LayerObjectActor { - private static final EnumMap ICONS = new EnumMap(Allegiance.class); + private static final EnumMap ICONS = new EnumMap<>(Allegiance.class); private static final Point CENTER = new Point(12, 40); diff --git a/src/org/infinity/resource/are/viewer/LayerObjectGlobalActor.java b/src/org/infinity/resource/are/viewer/LayerObjectGlobalActor.java index e24f10d46..5175c1d19 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectGlobalActor.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectGlobalActor.java @@ -28,7 +28,7 @@ * Handles specific layer type: global GAM/Actor */ public class LayerObjectGlobalActor extends LayerObjectActor { - private static final EnumMap ICONS = new EnumMap(Allegiance.class); + private static final EnumMap ICONS = new EnumMap<>(Allegiance.class); private static final Point CENTER = new Point(12, 40); diff --git a/src/org/infinity/resource/are/viewer/LayerObjectIniActor.java b/src/org/infinity/resource/are/viewer/LayerObjectIniActor.java index b65495a04..2b0a6d639 100644 --- a/src/org/infinity/resource/are/viewer/LayerObjectIniActor.java +++ b/src/org/infinity/resource/are/viewer/LayerObjectIniActor.java @@ -26,7 +26,7 @@ * Handles specific layer type: INI/Actor */ public class LayerObjectIniActor extends LayerObjectActor { - private static final EnumMap ICONS = new EnumMap(Allegiance.class); + private static final EnumMap ICONS = new EnumMap<>(Allegiance.class); private static final Point CENTER = new Point(12, 40); diff --git a/src/org/infinity/resource/bcs/Decompiler.java b/src/org/infinity/resource/bcs/Decompiler.java index a8f3ab710..614cffb7e 100644 --- a/src/org/infinity/resource/bcs/Decompiler.java +++ b/src/org/infinity/resource/bcs/Decompiler.java @@ -31,7 +31,7 @@ public final class Decompiler { // List of IDS resources containing bitwise entries - private static final HashSet BITWISE_IDS = new HashSet(Stream.of( + private static final HashSet BITWISE_IDS = new HashSet<>(Stream.of( "areatype", "areaflag", "bits", "classmsk", "crearefl", "damages", "doorflag", "dmgtype", "extstate", "invitem", "itemflag", "jourtype", "magespec", "splcast", "state", "wmpflag") .collect(Collectors.toSet())); diff --git a/src/org/infinity/resource/cre/browser/RenderPanel.java b/src/org/infinity/resource/cre/browser/RenderPanel.java index 7871ea845..fc68cdcda 100644 --- a/src/org/infinity/resource/cre/browser/RenderPanel.java +++ b/src/org/infinity/resource/cre/browser/RenderPanel.java @@ -234,7 +234,7 @@ public Couple setFrame(SpriteBamControl ctrl, Image frame, Rec frame = null; } - Couple retVal = new Couple(frame, frameBounds); + Couple retVal = new Couple<>(frame, frameBounds); return retVal; } diff --git a/src/org/infinity/resource/cre/browser/SettingsPanel.java b/src/org/infinity/resource/cre/browser/SettingsPanel.java index 3177bac64..0110ea97a 100644 --- a/src/org/infinity/resource/cre/browser/SettingsPanel.java +++ b/src/org/infinity/resource/cre/browser/SettingsPanel.java @@ -41,13 +41,13 @@ */ public class SettingsPanel extends JPanel { // Available render canvas backgrounds - public static final List BACKGROUND_LIST = new ArrayList(); + public static final List BACKGROUND_LIST = new ArrayList<>(); // Available items for zoom selection list - private static final Vector> ZOOM_LIST = new Vector>(); + private static final Vector> ZOOM_LIST = new Vector<>(); // Available items for frame rate selection list - private static final Vector> FRAME_RATE_LIST = new Vector>(); + private static final Vector> FRAME_RATE_LIST = new Vector<>(); private static int indexZoom; private static int indexFrameRate; diff --git a/src/org/infinity/resource/cre/decoder/AmbientDecoder.java b/src/org/infinity/resource/cre/decoder/AmbientDecoder.java index 70966bccd..075cbe047 100644 --- a/src/org/infinity/resource/cre/decoder/AmbientDecoder.java +++ b/src/org/infinity/resource/cre/decoder/AmbientDecoder.java @@ -46,7 +46,7 @@ public class AmbientDecoder extends SpriteDecoder { */ public static final int LISTTYPE_FLYING = 2; - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/AmbientStaticDecoder.java b/src/org/infinity/resource/cre/decoder/AmbientStaticDecoder.java index 17663d200..5ba68d2d1 100644 --- a/src/org/infinity/resource/cre/decoder/AmbientStaticDecoder.java +++ b/src/org/infinity/resource/cre/decoder/AmbientStaticDecoder.java @@ -33,7 +33,7 @@ public class AmbientStaticDecoder extends SpriteDecoder { public static final DecoderAttribute KEY_INVULNERABLE = DecoderAttribute.with("invulnerable", DecoderAttribute.DataType.BOOLEAN); - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.STANCE, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/CharacterDecoder.java b/src/org/infinity/resource/cre/decoder/CharacterDecoder.java index fcebaf7b3..7d3b67cca 100644 --- a/src/org/infinity/resource/cre/decoder/CharacterDecoder.java +++ b/src/org/infinity/resource/cre/decoder/CharacterDecoder.java @@ -48,13 +48,13 @@ public class CharacterDecoder extends CharacterBaseDecoder { DecoderAttribute.DataType.STRING); /** Assigns BAM suffix and cycle index to a specific animation sequence (unsplit version). */ - private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap<>(); /** Assigns BAM suffix and cycle index to a specific animation sequence (split version). */ - private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap<>(); /** Set of invalid attack type / animation sequence combinations. */ - private static final EnumMap> FORBIDDEN_SEQUENCES_MAP = new EnumMap>( + private static final EnumMap> FORBIDDEN_SEQUENCES_MAP = new EnumMap<>( AttackType.class); static { diff --git a/src/org/infinity/resource/cre/decoder/CharacterOldDecoder.java b/src/org/infinity/resource/cre/decoder/CharacterOldDecoder.java index 1d62e58a6..c5a10064a 100644 --- a/src/org/infinity/resource/cre/decoder/CharacterOldDecoder.java +++ b/src/org/infinity/resource/cre/decoder/CharacterOldDecoder.java @@ -43,13 +43,13 @@ public class CharacterOldDecoder extends CharacterBaseDecoder { public static final DecoderAttribute KEY_SHADOW = DecoderAttribute.with("shadow", DecoderAttribute.DataType.STRING); /** Assigns BAM suffix and cycle index to a specific animation sequence. */ - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); /** BAM suffix and cycle index for extended walk directions. */ private static final Couple WALK_EXTRA = Couple.with("W2", 0); /** Set of invalid attack type / animation sequence combinations. */ - private static final EnumMap> FORBIDDEN_SEQUENCES_MAP = new EnumMap>( + private static final EnumMap> FORBIDDEN_SEQUENCES_MAP = new EnumMap<>( AttackType.class); // the default shadow of the animation diff --git a/src/org/infinity/resource/cre/decoder/MonsterAnkhegDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterAnkhegDecoder.java index 6982d1306..14ed55aa6 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterAnkhegDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterAnkhegDecoder.java @@ -35,7 +35,7 @@ public class MonsterAnkhegDecoder extends SpriteDecoder { public static final DecoderAttribute KEY_EXTEND_DIRECTION = DecoderAttribute.with("extend_direction", DecoderAttribute.DataType.BOOLEAN); - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { // Note: int value indicates direction segment multiplier diff --git a/src/org/infinity/resource/cre/decoder/MonsterDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterDecoder.java index 3ded7ffab..66c9db069 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterDecoder.java @@ -63,16 +63,16 @@ public class MonsterDecoder extends SpriteDecoder { DecoderAttribute.DataType.STRING); /** Assigns BAM suffix and cycle index to a specific animation sequence (unsplit version). */ - private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap<>(); /** Assigns BAM suffix and cycle index to a specific animation sequence (split version). */ - private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap<>(); /** Replacement sequences if original sequence definition is missing (unsplit version). */ - private static final HashMap> REPLACEMENT_MAP_UNSPLIT = new HashMap>(); + private static final HashMap> REPLACEMENT_MAP_UNSPLIT = new HashMap<>(); /** Replacement sequences if original sequence definition is missing (split version). - not needed - */ - private static final HashMap> REPLACEMENT_MAP_SPLIT = new HashMap>(); + private static final HashMap> REPLACEMENT_MAP_SPLIT = new HashMap<>(); static { SUFFIX_MAP_UNSPLIT.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterIcewindDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterIcewindDecoder.java index 62c38b8aa..653358051 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterIcewindDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterIcewindDecoder.java @@ -33,9 +33,9 @@ public class MonsterIcewindDecoder extends SpriteDecoder { public static final DecoderAttribute KEY_WEAPON_LEFT_HAND = DecoderAttribute.with("weapon_left_hand", DecoderAttribute.DataType.BOOLEAN); - private static final HashMap SEQ_MAP = new HashMap(); + private static final HashMap SEQ_MAP = new HashMap<>(); - private static final HashMap REPLACEMENT_MAP = new HashMap(); + private static final HashMap REPLACEMENT_MAP = new HashMap<>(); static { SEQ_MAP.put(Sequence.ATTACK, "A1"); diff --git a/src/org/infinity/resource/cre/decoder/MonsterLarge16Decoder.java b/src/org/infinity/resource/cre/decoder/MonsterLarge16Decoder.java index 9d87dff4e..69f4cb2b3 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterLarge16Decoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterLarge16Decoder.java @@ -30,7 +30,7 @@ public class MonsterLarge16Decoder extends SpriteDecoder { /** The animation type associated with this class definition. */ public static final AnimationInfo.Type ANIMATION_TYPE = AnimationInfo.Type.MONSTER_LARGE_16; - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterLargeDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterLargeDecoder.java index b51be8516..8368133d7 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterLargeDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterLargeDecoder.java @@ -29,7 +29,7 @@ public class MonsterLargeDecoder extends SpriteDecoder { /** The animation type associated with this class definition. */ public static final AnimationInfo.Type ANIMATION_TYPE = AnimationInfo.Type.MONSTER_LARGE; - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.STAND, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterLayeredDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterLayeredDecoder.java index 28605fceb..8e1428dec 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterLayeredDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterLayeredDecoder.java @@ -36,7 +36,7 @@ public class MonsterLayeredDecoder extends SpriteDecoder { public static final DecoderAttribute KEY_RESREF_WEAPON2 = DecoderAttribute.with("resref_weapon2", DecoderAttribute.DataType.STRING); - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterLayeredSpellDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterLayeredSpellDecoder.java index 37c0c19d4..6c9df79c0 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterLayeredSpellDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterLayeredSpellDecoder.java @@ -41,7 +41,7 @@ public class MonsterLayeredSpellDecoder extends SpriteDecoder { public static final DecoderAttribute KEY_RESREF_WEAPON2 = DecoderAttribute.with("resref_weapon2", DecoderAttribute.DataType.STRING); - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterMultiDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterMultiDecoder.java index e579d8604..51ea0cc86 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterMultiDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterMultiDecoder.java @@ -49,9 +49,9 @@ public class MonsterMultiDecoder extends QuadrantsBaseDecoder { public static final DecoderAttribute KEY_PALETTE_5 = DecoderAttribute.with("palette5", DecoderAttribute.DataType.STRING); - private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap<>(); - private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap<>(); static { // Note: Replace 'underscore' in suffix by one-based quadrant index diff --git a/src/org/infinity/resource/cre/decoder/MonsterMultiNewDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterMultiNewDecoder.java index 93cdaf282..95ac5abb8 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterMultiNewDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterMultiNewDecoder.java @@ -39,8 +39,8 @@ public class MonsterMultiNewDecoder extends QuadrantsBaseDecoder { public static final DecoderAttribute KEY_SPLIT_BAMS = DecoderAttribute.with("split_bams", DecoderAttribute.DataType.BOOLEAN); - private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap>(); - private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap>(); + private static final HashMap> SUFFIX_MAP_SPLIT = new HashMap<>(); + private static final HashMap> SUFFIX_MAP_UNSPLIT = new HashMap<>(); static { // Note: Replace underscore in suffix by one-based quadrant index diff --git a/src/org/infinity/resource/cre/decoder/MonsterOldDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterOldDecoder.java index 76f0980db..f04bf57d6 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterOldDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterOldDecoder.java @@ -45,7 +45,7 @@ public class MonsterOldDecoder extends SpriteDecoder { /** The animation type associated with this class definition. */ public static final AnimationInfo.Type ANIMATION_TYPE = AnimationInfo.Type.MONSTER_OLD; - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/MonsterPlanescapeDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterPlanescapeDecoder.java index c288dced8..077a597e0 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterPlanescapeDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterPlanescapeDecoder.java @@ -82,10 +82,10 @@ public class MonsterPlanescapeDecoder extends SpriteDecoder { }; // available animation slot names - private static final HashMap SLOT_MAP = new HashMap(); + private static final HashMap SLOT_MAP = new HashMap<>(); // action prefixes used to determine BAM resref for animation sequences - private static final HashMap ACTION_PREFIX_MAP = new HashMap(); + private static final HashMap ACTION_PREFIX_MAP = new HashMap<>(); static { SLOT_MAP.put(Sequence.PST_ATTACK1, "attack1"); diff --git a/src/org/infinity/resource/cre/decoder/MonsterQuadrantDecoder.java b/src/org/infinity/resource/cre/decoder/MonsterQuadrantDecoder.java index 3caa66b5d..e5dbe0d93 100644 --- a/src/org/infinity/resource/cre/decoder/MonsterQuadrantDecoder.java +++ b/src/org/infinity/resource/cre/decoder/MonsterQuadrantDecoder.java @@ -39,7 +39,7 @@ public class MonsterQuadrantDecoder extends QuadrantsBaseDecoder { public static final DecoderAttribute KEY_EXTEND_DIRECTION_TEST = DecoderAttribute.with("extend_direction_test", DecoderAttribute.DataType.INT); - private static final HashMap> SUFFIX_MAP = new HashMap>(); + private static final HashMap> SUFFIX_MAP = new HashMap<>(); static { SUFFIX_MAP.put(Sequence.WALK, Couple.with("G1", 0)); diff --git a/src/org/infinity/resource/cre/decoder/tables/SpriteTables.java b/src/org/infinity/resource/cre/decoder/tables/SpriteTables.java index b9c701bd8..f0a7b896b 100644 --- a/src/org/infinity/resource/cre/decoder/tables/SpriteTables.java +++ b/src/org/infinity/resource/cre/decoder/tables/SpriteTables.java @@ -60,7 +60,7 @@ public class SpriteTables { public static final int COLUMN_PST_ARMOR = 7; // int public static final int COLUMN_PST_BESTIARY = 8; // int - private static final EnumMap> TABLE_MAPS = new EnumMap>(Profile.Game.class); + private static final EnumMap> TABLE_MAPS = new EnumMap<>(Profile.Game.class); static { TABLE_MAPS.put(Profile.Game.BG1, Arrays.asList("avatars-bg1.2da")); diff --git a/src/org/infinity/resource/cre/decoder/util/FrameInfo.java b/src/org/infinity/resource/cre/decoder/util/FrameInfo.java index d8c28cb73..3419e0e79 100644 --- a/src/org/infinity/resource/cre/decoder/util/FrameInfo.java +++ b/src/org/infinity/resource/cre/decoder/util/FrameInfo.java @@ -21,7 +21,7 @@ public class FrameInfo { public static final Stroke STROKE_BOUNDING_BOX = new BasicStroke(1.0f); /** Predefined colors for the bounding box around creature sprite elements. */ - public static final EnumMap SPRITE_COLOR = new EnumMap( + public static final EnumMap SPRITE_COLOR = new EnumMap<>( SegmentDef.SpriteType.class); static { diff --git a/src/org/infinity/resource/cre/decoder/util/SegmentDef.java b/src/org/infinity/resource/cre/decoder/util/SegmentDef.java index c81a69f39..e9b3c4d62 100644 --- a/src/org/infinity/resource/cre/decoder/util/SegmentDef.java +++ b/src/org/infinity/resource/cre/decoder/util/SegmentDef.java @@ -58,7 +58,7 @@ public enum Behavior { /** The same as {@link #CUT} but runs from end to start. */ REVERSE_CUT; - private static final EnumMap OPPOSITES_MAP = new EnumMap(Behavior.class); + private static final EnumMap OPPOSITES_MAP = new EnumMap<>(Behavior.class); static { OPPOSITES_MAP.put(REPEAT, REVERSE_REPEAT); diff --git a/src/org/infinity/resource/cre/decoder/util/Sequence.java b/src/org/infinity/resource/cre/decoder/util/Sequence.java index 7e795d1fe..6938ab26d 100644 --- a/src/org/infinity/resource/cre/decoder/util/Sequence.java +++ b/src/org/infinity/resource/cre/decoder/util/Sequence.java @@ -122,7 +122,7 @@ public enum Sequence { PST_MISC19("Custom sequence 19"), PST_MISC20("Custom sequence 20"); - private static final List DEFAULT_SEQUENCES = new ArrayList(); + private static final List DEFAULT_SEQUENCES = new ArrayList<>(); static { DEFAULT_SEQUENCES.add(Sequence.STAND); diff --git a/src/org/infinity/resource/cre/decoder/util/SpriteUtils.java b/src/org/infinity/resource/cre/decoder/util/SpriteUtils.java index fd07c52ab..6d41a2181 100644 --- a/src/org/infinity/resource/cre/decoder/util/SpriteUtils.java +++ b/src/org/infinity/resource/cre/decoder/util/SpriteUtils.java @@ -83,7 +83,7 @@ public class SpriteUtils { /** Mappings between animation types and compatible sprite classes. */ private static final EnumMap> TYPE_ASSOCIATION_MAP = - new EnumMap>(AnimationInfo.Type.class); + new EnumMap<>(AnimationInfo.Type.class); /** A stable pool of random numbers. */ private static int[] randomPool; diff --git a/src/org/infinity/resource/effects/BaseOpcode.java b/src/org/infinity/resource/effects/BaseOpcode.java index 2df494d1a..c3c6fc971 100644 --- a/src/org/infinity/resource/effects/BaseOpcode.java +++ b/src/org/infinity/resource/effects/BaseOpcode.java @@ -141,7 +141,7 @@ public static enum EffectEntry { public static final TreeMap COLOR_LOCATIONS_MAP = new TreeMap<>(); public static final TreeMap PROJECTILES_IWD_MAP = new TreeMap<>(); public static final TreeMap INC_TYPES_MAP = new TreeMap<>(); - public static final TreeMap ATTACKS_EE_MAP = new TreeMap(); + public static final TreeMap ATTACKS_EE_MAP = new TreeMap<>(); public static final String[] INC_TYPES = { "Increment", "Set", "Set % of" }; diff --git a/src/org/infinity/resource/graphics/DxtEncoder.java b/src/org/infinity/resource/graphics/DxtEncoder.java index 8c213361a..e26618ddc 100644 --- a/src/org/infinity/resource/graphics/DxtEncoder.java +++ b/src/org/infinity/resource/graphics/DxtEncoder.java @@ -250,12 +250,12 @@ public ColorSet(final int[] pixels, final DxtType dxtType) { // allocate new points if (j == i) { // normalize coordinates to [0, 1] - final float x = (float) argb(pixels[i], 2) / 255.0f; - final float y = (float) argb(pixels[i], 1) / 255.0f; - final float z = (float) argb(pixels[i], 0) / 255.0f; + final float x = argb(pixels[i], 2) / 255.0f; + final float y = argb(pixels[i], 1) / 255.0f; + final float z = argb(pixels[i], 0) / 255.0f; // ensure there is always non-zero weight even for zero alpha - final float w = (float) (argb(pixels[i], 3) + 1) / 256.0f; + final float w = (argb(pixels[i], 3) + 1) / 256.0f; // add the points points[count] = new Vec3(x, y, z); @@ -273,7 +273,7 @@ public ColorSet(final int[] pixels, final DxtType dxtType) { // get the index of the match final int index = remap[j]; // ensure there is always non-zero weight even for zero alpha - final float w = (float) (argb(pixels[i], 3) + 1) / 256.0f; + final float w = (argb(pixels[i], 3) + 1) / 256.0f; // map to this point and increase the weight weights[index] += w; remap[i] = index; @@ -430,10 +430,10 @@ protected void computeEndPoints(final SingleColorLookup[][] lookups) { // keep it if the error is lower if (error < this.error) { - start = new Vec3((float) sources[0].start / 31.0f, (float) sources[1].start / 63.0f, - (float) sources[2].start / 31.0f); - end = new Vec3((float) sources[0].end / 31.0f, (float) sources[1].end / 63.0f, - (float) sources[2].end / 31.0f); + start = new Vec3(sources[0].start / 31.0f, sources[1].start / 63.0f, + sources[2].start / 31.0f); + end = new Vec3(sources[0].end / 31.0f, sources[1].end / 63.0f, + sources[2].end / 31.0f); this.index = 2 * index; this.error = error; } @@ -1036,8 +1036,8 @@ public static void compressAlphaDxt3(final int[] pixels, final byte[] block) { // quantize and pack the alpha values pairwise for (int i = 0; i < 8; i++) { // quantize down to 4 bits - final float alpha1 = (float) ColorSet.argb(pixels[2 * i], 3) * (15.0f / 255.0f); - final float alpha2 = (float) ColorSet.argb(pixels[2 * i + 1], 3) * (15.0f / 255.0f); + final float alpha1 = ColorSet.argb(pixels[2 * i], 3) * (15.0f / 255.0f); + final float alpha2 = ColorSet.argb(pixels[2 * i + 1], 3) * (15.0f / 255.0f); final int quant1 = Misc.floatToInt(alpha1, 15); final int quant2 = Misc.floatToInt(alpha2, 15); diff --git a/src/org/infinity/resource/graphics/PltResource.java b/src/org/infinity/resource/graphics/PltResource.java index d053d989c..e9b743497 100644 --- a/src/org/infinity/resource/graphics/PltResource.java +++ b/src/org/infinity/resource/graphics/PltResource.java @@ -217,7 +217,7 @@ public JComponent makeViewer(ViewableContainer container) { buttonPanel.getControlByType(ButtonPanel.Control.SAVE).setEnabled(false); buttonPanel.setBorder(BorderFactory.createEmptyBorder(4, 0, 4, 0)); - tabbedPane = new JTabbedPane(JTabbedPane.TOP); + tabbedPane = new JTabbedPane(SwingConstants.TOP); tabbedPane.setBorder(BorderFactory.createEmptyBorder()); tabbedPane.addTab("View", pView); tabbedPane.addTab("Raw", panelRaw); diff --git a/src/org/infinity/resource/itm/Viewer.java b/src/org/infinity/resource/itm/Viewer.java index 99ce23572..ad7614481 100644 --- a/src/org/infinity/resource/itm/Viewer.java +++ b/src/org/infinity/resource/itm/Viewer.java @@ -19,6 +19,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; +import javax.swing.ScrollPaneConstants; import javax.swing.SwingConstants; import org.infinity.datatype.EffectType; @@ -112,7 +113,7 @@ final class Viewer extends JPanel { leftPanel.add(flagsUsabilityPanel, BorderLayout.CENTER); JScrollPane scrollPane = new JScrollPane(leftPanel); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); scrollPane.getVerticalScrollBar().setUnitIncrement(16); diff --git a/src/org/infinity/resource/other/UnknownResource.java b/src/org/infinity/resource/other/UnknownResource.java index a9670078c..cf274148b 100644 --- a/src/org/infinity/resource/other/UnknownResource.java +++ b/src/org/infinity/resource/other/UnknownResource.java @@ -22,6 +22,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; +import javax.swing.SwingConstants; import javax.swing.SwingWorker; import javax.swing.event.CaretEvent; import javax.swing.event.CaretListener; @@ -185,7 +186,7 @@ public JComponent makeViewer(ViewableContainer container) { // creating View tab JPanel panelView = new JPanel(new GridBagLayout()); panelView.setBorder(BorderFactory.createLoweredBevelBorder()); - JLabel label = new JLabel("Unsupported file format", JLabel.CENTER); + JLabel label = new JLabel("Unsupported file format", SwingConstants.CENTER); bShowEditor = new JButton("Edit as text"); bShowEditor.addActionListener(this); gbc = ViewerUtil.setGBC(gbc, 0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, @@ -209,7 +210,7 @@ public JComponent makeViewer(ViewableContainer container) { // creating Raw tab (stub) panelRaw = new JPanel(new BorderLayout()); if (getEntrySize() >= MIN_SIZE_BLOCK_RAW) { - label = new JLabel("File is too big for the hex editor (" + getEntrySize() + " bytes).", JLabel.CENTER); + label = new JLabel("File is too big for the hex editor (" + getEntrySize() + " bytes).", SwingConstants.CENTER); panelRaw.add(label, BorderLayout.CENTER); } diff --git a/src/org/infinity/resource/sound/AcmBuffer.java b/src/org/infinity/resource/sound/AcmBuffer.java index bb71cf083..bbd461a57 100644 --- a/src/org/infinity/resource/sound/AcmBuffer.java +++ b/src/org/infinity/resource/sound/AcmBuffer.java @@ -30,16 +30,19 @@ public AcmBuffer(byte[] buffer, int offset, AudioOverride override) throws Excep } /** Returns the number of audio channels. */ + @Override public int getChannels() { return (acm != null) ? acm.getChannels() : 0; } /** Returns the sample rate in Hz. */ + @Override public int getSampleRate() { return (acm != null) ? acm.getSampleRate() : 0; } /** Returns the bits per sample. */ + @Override public int getBitsPerSample() { return (acm != null) ? acm.getBitsPerSample() : 0; } diff --git a/src/org/infinity/resource/spl/Viewer.java b/src/org/infinity/resource/spl/Viewer.java index 8f6188d44..b87304262 100644 --- a/src/org/infinity/resource/spl/Viewer.java +++ b/src/org/infinity/resource/spl/Viewer.java @@ -16,6 +16,7 @@ import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; +import javax.swing.ScrollPaneConstants; import org.infinity.datatype.EffectType; import org.infinity.datatype.Flag; @@ -149,7 +150,7 @@ private static JPanel makeFieldPanel(SplResource spl) { infoPanel.add(exclusionFlagsPanel, BorderLayout.SOUTH); JScrollPane scrollPane = new JScrollPane(infoPanel); - scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); scrollPane.setBorder(BorderFactory.createEmptyBorder()); scrollPane.setPreferredSize(scrollPane.getMinimumSize()); scrollPane.getVerticalScrollBar().setUnitIncrement(16); diff --git a/src/org/infinity/resource/text/modes/BCSFoldParser.java b/src/org/infinity/resource/text/modes/BCSFoldParser.java index d638ebadf..cfc2a5ee5 100644 --- a/src/org/infinity/resource/text/modes/BCSFoldParser.java +++ b/src/org/infinity/resource/text/modes/BCSFoldParser.java @@ -11,6 +11,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; import org.fife.ui.rsyntaxtextarea.Token; +import org.fife.ui.rsyntaxtextarea.TokenTypes; import org.fife.ui.rsyntaxtextarea.folding.Fold; import org.fife.ui.rsyntaxtextarea.folding.FoldParser; import org.fife.ui.rsyntaxtextarea.folding.FoldType; @@ -61,17 +62,17 @@ public List getFolds(RSyntaxTextArea textArea) { // otherwise this MLC is continuing on to yet another line } else { // if we're in an MLC that ends on a later line... - if (t.getType() == Token.COMMENT_MULTILINE && !t.endsWith(MLC_END)) { + if (t.getType() == TokenTypes.COMMENT_MULTILINE && !t.endsWith(MLC_END)) { inMLC = true; mlcStart = t.getOffset(); } } - } else if (t.is(Token.RESERVED_WORD, BLOCK_START)) { + } else if (t.is(TokenTypes.RESERVED_WORD, BLOCK_START)) { // a script block starts if (curFold == null) { curFold = new Fold(FoldType.CODE, textArea, t.getOffset()); } - } else if (t.is(Token.RESERVED_WORD, BLOCK_END)) { + } else if (t.is(TokenTypes.RESERVED_WORD, BLOCK_END)) { // a script block ends - we don't need to consider nested blocks if (curFold != null) { curFold.setEndOffset(t.getEndOffset() - 1); diff --git a/src/org/infinity/resource/text/modes/BCSTokenMaker.java b/src/org/infinity/resource/text/modes/BCSTokenMaker.java index a752c8699..2a0cdea56 100644 --- a/src/org/infinity/resource/text/modes/BCSTokenMaker.java +++ b/src/org/infinity/resource/text/modes/BCSTokenMaker.java @@ -30,21 +30,21 @@ public class BCSTokenMaker extends AbstractTokenMaker { public static final String SYNTAX_STYLE_BCS = "text/BCS"; // available token types - public static final int TOKEN_IDENTIFIER = Token.IDENTIFIER; // used for unrecognized literals - public static final int TOKEN_KEYWORD = Token.RESERVED_WORD; - public static final int TOKEN_ACTION = Token.FUNCTION; - public static final int TOKEN_TRIGGER = Token.DATA_TYPE; - public static final int TOKEN_OBJECT = Token.VARIABLE; - public static final int TOKEN_NUMBER = Token.LITERAL_NUMBER_DECIMAL_INT; - public static final int TOKEN_HEXNUMBER = Token.LITERAL_NUMBER_HEXADECIMAL; - public static final int TOKEN_BINNUMBER = Token.LITERAL_NUMBER_FLOAT; - public static final int TOKEN_STRING = Token.LITERAL_STRING_DOUBLE_QUOTE; - public static final int TOKEN_COMMENT_LINE = Token.COMMENT_EOL; - public static final int TOKEN_COMMENT_BLOCK = Token.COMMENT_MULTILINE; - public static final int TOKEN_SYMBOL = Token.MARKUP_TAG_NAME; - public static final int TOKEN_SYMBOL_SPELL = Token.MARKUP_TAG_ATTRIBUTE; - public static final int TOKEN_OPERATOR = Token.OPERATOR; - public static final int TOKEN_WHITESPACE = Token.WHITESPACE; + public static final int TOKEN_IDENTIFIER = TokenTypes.IDENTIFIER; // used for unrecognized literals + public static final int TOKEN_KEYWORD = TokenTypes.RESERVED_WORD; + public static final int TOKEN_ACTION = TokenTypes.FUNCTION; + public static final int TOKEN_TRIGGER = TokenTypes.DATA_TYPE; + public static final int TOKEN_OBJECT = TokenTypes.VARIABLE; + public static final int TOKEN_NUMBER = TokenTypes.LITERAL_NUMBER_DECIMAL_INT; + public static final int TOKEN_HEXNUMBER = TokenTypes.LITERAL_NUMBER_HEXADECIMAL; + public static final int TOKEN_BINNUMBER = TokenTypes.LITERAL_NUMBER_FLOAT; + public static final int TOKEN_STRING = TokenTypes.LITERAL_STRING_DOUBLE_QUOTE; + public static final int TOKEN_COMMENT_LINE = TokenTypes.COMMENT_EOL; + public static final int TOKEN_COMMENT_BLOCK = TokenTypes.COMMENT_MULTILINE; + public static final int TOKEN_SYMBOL = TokenTypes.MARKUP_TAG_NAME; + public static final int TOKEN_SYMBOL_SPELL = TokenTypes.MARKUP_TAG_ATTRIBUTE; + public static final int TOKEN_OPERATOR = TokenTypes.OPERATOR; + public static final int TOKEN_WHITESPACE = TokenTypes.WHITESPACE; private static final String CHAR_WHITE_SPACE = " \t"; private static final String CHAR_OPERATOR = "!|,.()[]"; diff --git a/src/org/infinity/resource/text/modes/INITokenMaker.java b/src/org/infinity/resource/text/modes/INITokenMaker.java index 410ad2315..a36ba9fe2 100644 --- a/src/org/infinity/resource/text/modes/INITokenMaker.java +++ b/src/org/infinity/resource/text/modes/INITokenMaker.java @@ -9,6 +9,7 @@ import org.fife.ui.rsyntaxtextarea.AbstractTokenMaker; import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rsyntaxtextarea.TokenMap; +import org.fife.ui.rsyntaxtextarea.TokenTypes; /** * A token maker that turns text into a linked list of {@code Token}s for syntax highlighting Infinity Engine INI @@ -19,12 +20,12 @@ public class INITokenMaker extends AbstractTokenMaker { public static final String SYNTAX_STYLE_INI = "text/INI"; // available token types - public static final int TOKEN_SECTION = Token.PREPROCESSOR; - public static final int TOKEN_KEY = Token.RESERVED_WORD; - public static final int TOKEN_EQUALS = Token.OPERATOR; - public static final int TOKEN_VALUE = Token.LITERAL_STRING_DOUBLE_QUOTE; - public static final int TOKEN_COMMENT = Token.COMMENT_EOL; - public static final int TOKEN_WHITESPACE = Token.WHITESPACE; + public static final int TOKEN_SECTION = TokenTypes.PREPROCESSOR; + public static final int TOKEN_KEY = TokenTypes.RESERVED_WORD; + public static final int TOKEN_EQUALS = TokenTypes.OPERATOR; + public static final int TOKEN_VALUE = TokenTypes.LITERAL_STRING_DOUBLE_QUOTE; + public static final int TOKEN_COMMENT = TokenTypes.COMMENT_EOL; + public static final int TOKEN_WHITESPACE = TokenTypes.WHITESPACE; private static final String WHITESPACE = " \t"; private static final String NOT_IDENTIFIER = " \t\r\n#;/[]="; @@ -72,7 +73,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { for (int i = ofs; i < end; i++) { char c = array[i]; switch (currentTokenType) { - case Token.NULL: { + case TokenTypes.NULL: { currentTokenStart = i; // starting new token here if (isComment(c, i, end, array)) { @@ -97,7 +98,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { currentTokenType = TOKEN_VALUE; } else if (c == ']') { addToken(text, currentTokenStart, i, currentTokenType, newStartOfs + currentTokenStart); - currentTokenType = Token.NULL; + currentTokenType = TokenTypes.NULL; } break; } @@ -163,7 +164,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { } else if (!isWhiteSpace(c)) { addToken(text, currentTokenStart, i - 1, currentTokenType, newStartOfs + currentTokenStart); i--; - currentTokenType = Token.NULL; + currentTokenType = TokenTypes.NULL; } break; } @@ -182,7 +183,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { // adding the current token to the list switch (currentTokenType) { - case Token.NULL: + case TokenTypes.NULL: addNullToken(); break; default: diff --git a/src/org/infinity/resource/text/modes/TLKTokenMaker.java b/src/org/infinity/resource/text/modes/TLKTokenMaker.java index 5453fd350..dda9d9510 100644 --- a/src/org/infinity/resource/text/modes/TLKTokenMaker.java +++ b/src/org/infinity/resource/text/modes/TLKTokenMaker.java @@ -11,6 +11,7 @@ import org.fife.ui.rsyntaxtextarea.AbstractTokenMaker; import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rsyntaxtextarea.TokenMap; +import org.fife.ui.rsyntaxtextarea.TokenTypes; import org.infinity.resource.Profile; /** @@ -22,9 +23,9 @@ public class TLKTokenMaker extends AbstractTokenMaker { public static final String SYNTAX_STYLE_TLK = "text/TLK"; // available token types - public static final int TOKEN_TEXT = Token.IDENTIFIER; // for regular text - public static final int TOKEN_TAG = Token.MARKUP_TAG_NAME; // for tokens - public static final int TOKEN_COLORED = Token.MARKUP_TAG_ATTRIBUTE; // for colored text (EE-specific) + public static final int TOKEN_TEXT = TokenTypes.IDENTIFIER; // for regular text + public static final int TOKEN_TAG = TokenTypes.MARKUP_TAG_NAME; // for tokens + public static final int TOKEN_COLORED = TokenTypes.MARKUP_TAG_ATTRIBUTE; // for colored text (EE-specific) private static final Pattern REG_TOKEN = Pattern.compile("<[^<>]+>"); private static final String CHAR_SEPARATOR = " \t-‒–—―"; @@ -58,7 +59,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { char c = array[i]; switch (currentTokenType) { - case Token.NULL: { + case TokenTypes.NULL: { currentTokenStart = i; // starting new token here if (c == '<' && REG_TOKEN.matcher(new String(array, i, end - i)).lookingAt()) { @@ -116,7 +117,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { } else if (c == '^' && i + 1 < end && array[i + 1] == '-') { i++; addToken(array, currentTokenStart, i, currentTokenType, newStartOfs + currentTokenStart); - currentTokenType = Token.NULL; + currentTokenType = TokenTypes.NULL; } else { if (CHAR_SEPARATOR.indexOf(c) >= 0) { // ensure correct text wrapping at word boundaries @@ -138,7 +139,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { // adding the current token to the list switch (currentTokenType) { - case Token.NULL: + case TokenTypes.NULL: addNullToken(); break; diff --git a/src/org/infinity/resource/text/modes/WeiDULogTokenMaker.java b/src/org/infinity/resource/text/modes/WeiDULogTokenMaker.java index 73238c19d..df19e4613 100644 --- a/src/org/infinity/resource/text/modes/WeiDULogTokenMaker.java +++ b/src/org/infinity/resource/text/modes/WeiDULogTokenMaker.java @@ -9,6 +9,7 @@ import org.fife.ui.rsyntaxtextarea.AbstractTokenMaker; import org.fife.ui.rsyntaxtextarea.Token; import org.fife.ui.rsyntaxtextarea.TokenMap; +import org.fife.ui.rsyntaxtextarea.TokenTypes; /** * A token maker that turns text into a linked list of {@link Token}s for syntax highlighting WeiDU.log content. @@ -18,10 +19,10 @@ public class WeiDULogTokenMaker extends AbstractTokenMaker { public static final String SYNTAX_STYLE_WEIDU = "text/WeiDU"; // available token types - public static final int TOKEN_STRING = Token.LITERAL_STRING_DOUBLE_QUOTE; - public static final int TOKEN_NUMBER = Token.LITERAL_NUMBER_DECIMAL_INT; - public static final int TOKEN_COMMENT = Token.COMMENT_EOL; - public static final int TOKEN_WHITESPACE = Token.WHITESPACE; + public static final int TOKEN_STRING = TokenTypes.LITERAL_STRING_DOUBLE_QUOTE; + public static final int TOKEN_NUMBER = TokenTypes.LITERAL_NUMBER_DECIMAL_INT; + public static final int TOKEN_COMMENT = TokenTypes.COMMENT_EOL; + public static final int TOKEN_WHITESPACE = TokenTypes.WHITESPACE; private static final String CHAR_DIGIT = "-0123456789"; @@ -48,7 +49,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { for (int i = ofs; i < end; i++) { char c = array[i]; switch (currentTokenType) { - case Token.NULL: { + case TokenTypes.NULL: { currentTokenStart = i; // starting new token here if (c == '~') { @@ -65,7 +66,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { case TOKEN_STRING: { if (c == '~') { addToken(text, currentTokenStart, i, currentTokenType, newStartOfs + currentTokenStart); - currentTokenType = Token.NULL; + currentTokenType = TokenTypes.NULL; } break; } @@ -114,7 +115,7 @@ public Token getTokenList(Segment text, int initialTokenType, int startOffset) { // adding the current token to the list switch (currentTokenType) { - case Token.NULL: + case TokenTypes.NULL: addNullToken(); break; default: diff --git a/src/org/infinity/search/advanced/SearchOptions.java b/src/org/infinity/search/advanced/SearchOptions.java index 78287b8cb..c44f1d3ea 100644 --- a/src/org/infinity/search/advanced/SearchOptions.java +++ b/src/org/infinity/search/advanced/SearchOptions.java @@ -398,7 +398,7 @@ public String toString() { break; default: } - sb.append(")=0x").append(Long.toHexString((long) getValueBitfield() & 0xffffffffL)); + sb.append(")=0x").append(Long.toHexString(getValueBitfield() & 0xffffffffL)); break; default: } diff --git a/src/org/infinity/util/Misc.java b/src/org/infinity/util/Misc.java index b03871d9f..b70721ed3 100644 --- a/src/org/infinity/util/Misc.java +++ b/src/org/infinity/util/Misc.java @@ -59,6 +59,11 @@ public int compare(T o1, T o2) { return (o1.toString().compareToIgnoreCase(o2.toString())); } + @Override + public int hashCode() { + return toString().toLowerCase().hashCode(); + } + @Override public boolean equals(Object obj) { return toString().equalsIgnoreCase(obj.toString()); From 8de26a63bb016f6ef46adcd0dde8c767ba28f191 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Sat, 8 Jul 2023 23:37:58 +0200 Subject: [PATCH 17/28] Fix inaccurate highlighting when opening search results in text resources ...and optimize search algorithm. --- src/org/infinity/resource/bcs/BafResource.java | 2 +- src/org/infinity/resource/bcs/BcsResource.java | 2 +- src/org/infinity/resource/mus/MusResource.java | 2 +- src/org/infinity/resource/text/PlainTextResource.java | 2 +- src/org/infinity/search/AttributeSearcher.java | 8 +++++--- src/org/infinity/search/DialogSearcher.java | 6 ++---- src/org/infinity/search/SearchMaster.java | 8 +++----- src/org/infinity/search/TextResourceSearcher.java | 6 ++---- 8 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/org/infinity/resource/bcs/BafResource.java b/src/org/infinity/resource/bcs/BafResource.java index f0e27b37e..d3b0fc962 100644 --- a/src/org/infinity/resource/bcs/BafResource.java +++ b/src/org/infinity/resource/bcs/BafResource.java @@ -228,7 +228,7 @@ public void highlightText(int linenr, String highlightText) { Matcher m = p.matcher(text); if (m.find()) { startOfs += m.start(); - endOfs = startOfs + m.end(); + endOfs = startOfs + m.end() - m.start() + 1; } } highlightText(startOfs, endOfs); diff --git a/src/org/infinity/resource/bcs/BcsResource.java b/src/org/infinity/resource/bcs/BcsResource.java index b5b2e1b82..b51c2bba8 100644 --- a/src/org/infinity/resource/bcs/BcsResource.java +++ b/src/org/infinity/resource/bcs/BcsResource.java @@ -540,7 +540,7 @@ public void highlightText(int linenr, String highlightText) { Matcher m = p.matcher(text); if (m.find()) { startOfs += m.start(); - endOfs = startOfs + m.end() + 1; + endOfs = startOfs + m.end() - m.start() + 1; } } highlightText(startOfs, endOfs); diff --git a/src/org/infinity/resource/mus/MusResource.java b/src/org/infinity/resource/mus/MusResource.java index f3c733cdd..4dff7191d 100644 --- a/src/org/infinity/resource/mus/MusResource.java +++ b/src/org/infinity/resource/mus/MusResource.java @@ -268,7 +268,7 @@ public void highlightText(int linenr, String highlightText) { Matcher m = p.matcher(text); if (m.find()) { startOfs += m.start(); - endOfs = startOfs + m.end() + 1; + endOfs = startOfs + m.end() - m.start() + 1; } } highlightText(startOfs, endOfs); diff --git a/src/org/infinity/resource/text/PlainTextResource.java b/src/org/infinity/resource/text/PlainTextResource.java index 63b89b2d4..1d417d995 100644 --- a/src/org/infinity/resource/text/PlainTextResource.java +++ b/src/org/infinity/resource/text/PlainTextResource.java @@ -450,7 +450,7 @@ public void highlightText(int linenr, String highlightText) { Matcher m = p.matcher(text); if (m.find()) { startOfs += m.start(); - endOfs = startOfs + highlightText.length() + 1; + endOfs = startOfs + m.end() - m.start() + 1; } } highlightText(startOfs, endOfs); diff --git a/src/org/infinity/search/AttributeSearcher.java b/src/org/infinity/search/AttributeSearcher.java index 3ee55557a..e1e47cb57 100644 --- a/src/org/infinity/search/AttributeSearcher.java +++ b/src/org/infinity/search/AttributeSearcher.java @@ -199,8 +199,10 @@ public void run() { return; } } - term = term.replaceAll("(\\W)", "\\\\$1"); - term = cbwhole.isSelected() ? (".*\\b" + term + "\\b.*") : (".*" + term + ".*"); + term = Pattern.quote(term); + if (cbwhole.isSelected()) { + term = "\\b" + term + "\\b"; + } if (cbcase.isSelected()) { regPattern = Pattern.compile(term, Pattern.DOTALL); } else { @@ -241,7 +243,7 @@ protected Runnable newWorker(ResourceEntry entry) { || searchEntry.getName().equalsIgnoreCase(structEntry.getName())) { boolean hit = false; if (rbexact.isSelected()) { - hit = regPattern.matcher(searchEntry.toString()).matches(); + hit = regPattern.matcher(searchEntry.toString()).find(); } else if (rbless.isSelected()) { hit = searchNumber > ((IsNumeric) searchEntry).getValue(); } else if (rbgreater.isSelected()) { diff --git a/src/org/infinity/search/DialogSearcher.java b/src/org/infinity/search/DialogSearcher.java index 57937f7e9..ba6596cea 100644 --- a/src/org/infinity/search/DialogSearcher.java +++ b/src/org/infinity/search/DialogSearcher.java @@ -136,9 +136,7 @@ public void run() { term = Pattern.quote(term); } if (cbwhole.isSelected()) { - term = ".*\\b" + term + "\\b.*"; - } else { - term = ".*" + term + ".*"; + term = "\\b" + term + "\\b"; } try { @@ -208,7 +206,7 @@ protected Runnable newWorker(ResourceEntry entry) { } } final Matcher matcher = regPattern.matcher(s); - if (matcher.matches()) { + if (matcher.find()) { addResult(entry, e.getValue().getName(), searchEntry); } } diff --git a/src/org/infinity/search/SearchMaster.java b/src/org/infinity/search/SearchMaster.java index 872fcf8fa..b03b027a9 100644 --- a/src/org/infinity/search/SearchMaster.java +++ b/src/org/infinity/search/SearchMaster.java @@ -174,12 +174,10 @@ public void run() { index = 0; String term = tfinput.getText(); if (!cbregex.isSelected()) { - term = term.replaceAll("(\\W)", "\\\\$1"); + term = Pattern.quote(term); } if (cbwhole.isSelected()) { - term = ".*\\b" + term + "\\b.*"; - } else { - term = ".*" + term + ".*"; + term = "\\b" + term + "\\b"; } Pattern regPattern; try { @@ -202,7 +200,7 @@ public void run() { if (s == null) { break; } - if (regPattern.matcher(s).matches()) { + if (regPattern.matcher(s).find()) { slave.hitFound(index); blocker.setBlocked(false); container.requestFocus(); diff --git a/src/org/infinity/search/TextResourceSearcher.java b/src/org/infinity/search/TextResourceSearcher.java index 1ee9ef09b..8dc6bf83a 100644 --- a/src/org/infinity/search/TextResourceSearcher.java +++ b/src/org/infinity/search/TextResourceSearcher.java @@ -129,9 +129,7 @@ public void run() { term = Pattern.quote(term); } if (cbwhole.isSelected()) { - term = ".*\\b" + term + "\\b.*"; - } else { - term = ".*" + term + ".*"; + term = "\\b" + term + "\\b"; } try { @@ -174,7 +172,7 @@ protected Runnable newWorker(ResourceEntry entry) { int linenr = 0; while ((line = br.readLine()) != null) { linenr++; - if (regPattern.matcher(line).matches()) { + if (regPattern.matcher(line).find()) { addHit(entry, line, linenr); } } From bd08567a3562c88eded129470bbf5f214c3af3d6 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Mon, 10 Jul 2023 14:28:12 +0200 Subject: [PATCH 18/28] Fix removing ARE actor entries with embedded CRE resources --- src/org/infinity/datatype/Flag.java | 4 ++-- src/org/infinity/resource/AbstractStruct.java | 3 ++- src/org/infinity/resource/are/AreResource.java | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/org/infinity/datatype/Flag.java b/src/org/infinity/datatype/Flag.java index e116982e3..8005e50fe 100644 --- a/src/org/infinity/datatype/Flag.java +++ b/src/org/infinity/datatype/Flag.java @@ -241,8 +241,8 @@ public String getString(int i) { return i < 0 || i > table.length ? null : table[i]; } - public boolean isFlagSet(int i) { - long bitnr = 1L << i; + public boolean isFlagSet(int bit) { + long bitnr = 1L << bit; return (value & bitnr) == bitnr; } diff --git a/src/org/infinity/resource/AbstractStruct.java b/src/org/infinity/resource/AbstractStruct.java index 31e5a4670..b45b6b77a 100644 --- a/src/org/infinity/resource/AbstractStruct.java +++ b/src/org/infinity/resource/AbstractStruct.java @@ -877,7 +877,8 @@ public List removeAllRemoveables() { } public void removeDatatype(AddRemovable removedEntry, boolean removeRecurse) { - if (removeRecurse && removedEntry instanceof HasChildStructs) { // Recusivly removeTableLine substructures first + if (removeRecurse && removedEntry instanceof HasChildStructs) { + // Recursively remove child structures first AbstractStruct removedStruct = (AbstractStruct) removedEntry; for (int i = 0; i < removedStruct.fields.size(); i++) { final StructEntry o = removedStruct.fields.get(i); diff --git a/src/org/infinity/resource/are/AreResource.java b/src/org/infinity/resource/are/AreResource.java index 89df63e35..0811c3416 100644 --- a/src/org/infinity/resource/are/AreResource.java +++ b/src/org/infinity/resource/are/AreResource.java @@ -42,6 +42,7 @@ import org.infinity.resource.ResourceFactory; import org.infinity.resource.StructEntry; import org.infinity.resource.are.viewer.AreaViewer; +import org.infinity.resource.cre.CreResource; import org.infinity.resource.key.ResourceEntry; import org.infinity.resource.vertex.Vertex; import org.infinity.resource.wmp.AreaEntry; @@ -566,6 +567,23 @@ protected void datatypeRemovedInChild(AbstractStruct child, AddRemovable datatyp } } + @Override + public void removeDatatype(AddRemovable removedEntry, boolean removeRecurse) { + if (removedEntry instanceof Actor) { + final Actor actor = (Actor) removedEntry; + if (!((Flag) actor.getAttribute(Actor.ARE_ACTOR_FLAGS)).isFlagSet(0)) { + // remove embedded CRE resource manually + final int creOfs = ((IsNumeric) actor.getAttribute(Actor.ARE_ACTOR_OFFSET_CRE_STRUCTURE)).getValue(); + final int creSize = ((IsNumeric) actor.getAttribute(Actor.ARE_ACTOR_SIZE_CRE_STRUCTURE)).getValue(); + final StructEntry se = actor.getAttribute(Actor.ARE_ACTOR_CRE_FILE); + if (se instanceof CreResource && creOfs > 0 && creSize > 0) { + actor.removeDatatype((CreResource) se, false); + } + } + } + super.removeDatatype(removedEntry, removeRecurse); + } + @Override public int read(ByteBuffer buffer, int offset) throws Exception { addField(new TextString(buffer, offset, 4, COMMON_SIGNATURE)); From e578e1fa8399b12a59c40c2567643bb4854e9483 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:12:37 +0200 Subject: [PATCH 19/28] Add options to show preview icons for ITM and SPL resources in resource tree and resource selection lists --- src/org/infinity/AppOption.java | 6 + src/org/infinity/NearInfinity.java | 93 +++++++++- src/org/infinity/datatype/ResourceRef.java | 15 +- src/org/infinity/gui/PreferencesDialog.java | 10 + src/org/infinity/gui/ResourceTree.java | 17 +- src/org/infinity/gui/TextListPanel.java | 39 +++- .../infinity/gui/menu/OptionsMenuItem.java | 15 +- .../infinity/resource/ResourceFactory.java | 48 +++++ src/org/infinity/util/IconCache.java | 174 ++++++++++++++++++ 9 files changed, 408 insertions(+), 9 deletions(-) create mode 100644 src/org/infinity/util/IconCache.java diff --git a/src/org/infinity/AppOption.java b/src/org/infinity/AppOption.java index f5db46ac9..c693eaaf9 100644 --- a/src/org/infinity/AppOption.java +++ b/src/org/infinity/AppOption.java @@ -104,6 +104,12 @@ public class AppOption { /** Menu Options: ShowTreeSearchNames (Boolean, Default: true) */ public static final AppOption SHOW_TREE_SEARCH_NAMES = new AppOption(OptionsMenuItem.OPTION_SHOWTREESEARCHNAMES, "Show Search Names in Resource Tree", true); + /** Menu Options: Show Icons in Resource List (Boolean, Default: false) */ + public static final AppOption SHOW_RESOURCE_LIST_ICONS = new AppOption(OptionsMenuItem.OPTION_SHOW_RESOURCE_LIST_ICONS, + "Show Icons in Resource List", false); + /** Menu Options: Show Icons in Resource Tree (Boolean, Default: false) */ + public static final AppOption SHOW_RESOURCE_TREE_ICONS = new AppOption(OptionsMenuItem.OPTION_SHOW_RESOURCE_TREE_ICONS, + "Show Icons in Resource Tree", false); /** Menu Options: HighlightOverridden (Boolean, Default: true) */ public static final AppOption HIGHLIGHT_OVERRIDDEN = new AppOption(OptionsMenuItem.OPTION_HIGHLIGHT_OVERRIDDEN, "Show Overridden Files in Bold in Resource Tree", true); diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java index 6394e28e9..4f74a6897 100644 --- a/src/org/infinity/NearInfinity.java +++ b/src/org/infinity/NearInfinity.java @@ -45,6 +45,7 @@ import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutionException; +import java.util.function.Supplier; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -119,6 +120,7 @@ import org.infinity.util.CharsetDetector; import org.infinity.util.CreMapCache; import org.infinity.util.FileDeletionHook; +import org.infinity.util.IconCache; import org.infinity.util.IdsMapCache; import org.infinity.util.IniMapCache; import org.infinity.util.LauncherUtils; @@ -235,6 +237,7 @@ public final class NearInfinity extends JFrame implements ActionListener, Viewab private int tablePanelHeight; private ProgressMonitor pmProgress; private int progressIndex; + private SwingWorker iconCacheWorker; private static Path findKeyfile() { JFileChooser chooser; @@ -428,7 +431,7 @@ private NearInfinity(Options options) { System.exit(10); } - showProgress("Starting Near Infinity" + Misc.MSG_EXPAND_LARGE, 6); + showProgress("Starting Near Infinity" + Misc.MSG_EXPAND_LARGE, 7); SwingWorker worker = new SwingWorker() { @Override protected Void doInBackground() throws Exception { @@ -456,6 +459,9 @@ protected Void doInBackground() throws Exception { // FileWatcher.getInstance().start(); // } + advanceProgress("Caching resources..."); + cacheResourceIcons(false); + return null; } }; @@ -827,7 +833,6 @@ public void openGame(Path keyFile) { Path oldKeyFile = Profile.getChitinKey(); ChildFrame.closeWindows(); clearCache(false); - BaseOpcode.reset(); Profile.openGame(keyFile, BrowserMenuBar.getInstance().getGameMenu().getBookmarkName(keyFile)); // making sure vital game resources are accessible @@ -916,6 +921,7 @@ public void refreshGame() { containerpanel.revalidate(); containerpanel.repaint(); } + cacheResourceIcons(true); } finally { blocker.setBlocked(false); } @@ -1160,6 +1166,7 @@ private static boolean reloadFactory(boolean refreshOnly) { // Central method for clearing cached data private static void clearCache(boolean refreshOnly) { + NearInfinity.getInstance().cancelCacheResourceIcons(); if (ResourceFactory.getKeyfile() != null) { ResourceFactory.getKeyfile().closeBIFFFiles(); } @@ -1168,6 +1175,7 @@ private static void clearCache(boolean refreshOnly) { } DlcManager.close(); FileManager.reset(); + IconCache.clearCache(); IdsMapCache.clearCache(); IniMapCache.clearCache(); Table2daCache.clearCache(); @@ -1459,6 +1467,87 @@ private JPanel createJavaInfoPanel() { return infoPanel; } + /** + * Cancels an ongoing resource icon cache operation. + * + * The method returns only after the operation has been successfully cancelled. + */ + private void cancelCacheResourceIcons() { + if (iconCacheWorker != null) { + iconCacheWorker.cancel(false); + for (int i = 0; i < 100 && iconCacheWorker.getProgress() < 100; i++) { + try { + Thread.sleep(10); + } catch (InterruptedException e) { + } + } + iconCacheWorker = null; + } + } + + /** + * Preloads icons for all ITM and SPL resources into the cache. + * + * @param threaded Whether to perform the operation in a separate thread. + */ + private void cacheResourceIcons(boolean threaded) { + // Operation for caching resource icons + final Supplier operation = () -> { + try { + IconCache.clearCache(); + final List sizeList = new ArrayList<>(); + if (BrowserMenuBar.getInstance().getOptions().showResourceTreeIcons()) { + sizeList.add(IconCache.getDefaultTreeIconSize()); + } + if (BrowserMenuBar.getInstance().getOptions().showResourceListIcons()) { + sizeList.add(IconCache.getDefaultListIconSize()); + } + if (!sizeList.isEmpty()) { + final String[] types = { "ITM", "SPL" }; + int[] sizes = sizeList.stream().mapToInt(Integer::intValue).toArray(); + for (final String type : types) { + final List resources = ResourceFactory.getResources(type); + if (resources != null) { + for (final ResourceEntry e : resources) { + for (final int size : sizes) { + if (iconCacheWorker != null && iconCacheWorker.isCancelled()) { + return null; + } + IconCache.get(e, size); + } + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + }; + + // ensure that ongoing operations have ended before starting a new operation + cancelCacheResourceIcons(); + + if (threaded) { + iconCacheWorker = new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + setProgress(0); + try { + operation.get(); + } catch (Exception e) { + e.printStackTrace(); + } + setProgress(100); + return null; + } + }; + iconCacheWorker.execute(); + } else { + operation.get(); + } + } + // -------------------------- INNER CLASSES -------------------------- private static final class Options { diff --git a/src/org/infinity/datatype/ResourceRef.java b/src/org/infinity/datatype/ResourceRef.java index e5bf54a78..c99d79969 100644 --- a/src/org/infinity/datatype/ResourceRef.java +++ b/src/org/infinity/datatype/ResourceRef.java @@ -16,6 +16,7 @@ import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -128,7 +129,9 @@ public JComponent edit(final ActionListener container) { } addExtraEntries(values); Collections.sort(values, IGNORE_CASE_EXT_COMPARATOR); - list = new TextListPanel<>(values, false); + boolean showIcons = BrowserMenuBar.getInstance().getOptions().showResourceListIcons() && + Arrays.stream(types).anyMatch(s -> s.equalsIgnoreCase("ITM") || s.equalsIgnoreCase("SPL")); + list = new TextListPanel<>(values, false, showIcons); list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { @@ -385,7 +388,7 @@ private void setValue(String newValue) { // -------------------------- INNER CLASSES -------------------------- /** Class that represents resource reference in the list of choice. */ - static final class ResourceRefEntry { + public static final class ResourceRefEntry { final ResourceEntry entry; /** @@ -404,6 +407,14 @@ private ResourceRefEntry(ResourceEntry entry) { this.name = name; } + public ResourceEntry getEntry() { + return entry; + } + + public String getName() { + return name; + } + @Override public String toString() { return entry == null ? name : BrowserMenuBar.getInstance().getOptions().getResRefMode().format(entry); diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java index 9dc3b9c0b..87f2e451e 100644 --- a/src/org/infinity/gui/PreferencesDialog.java +++ b/src/org/infinity/gui/PreferencesDialog.java @@ -173,6 +173,16 @@ public String toString() { "With this option enabled Near Infinity shows the search name of resources in the resource tree " + "in parentheses if available, such as creature, item or spell names.", AppOption.SHOW_TREE_SEARCH_NAMES), + OptionCheckBox.create(AppOption.SHOW_RESOURCE_TREE_ICONS.getName(), AppOption.SHOW_RESOURCE_TREE_ICONS.getLabel(), + "With this option enabled Near Infinity shows icons alongside names in the resource tree for ITM and " + + "SPL resources." + + "

Caution: Enabling this option may result in noticeable lags on slower systems.

", + AppOption.SHOW_RESOURCE_TREE_ICONS), + OptionCheckBox.create(AppOption.SHOW_RESOURCE_LIST_ICONS.getName(), AppOption.SHOW_RESOURCE_LIST_ICONS.getLabel(), + "With this option enabled Near Infinity shows icons alongside names in resource selection lists for " + + "ITM and SPL resources." + + "

Caution: Enabling this option may result in noticeable lags on slower systems.

", + AppOption.SHOW_RESOURCE_LIST_ICONS), OptionCheckBox.create(AppOption.HIGHLIGHT_OVERRIDDEN.getName(), AppOption.HIGHLIGHT_OVERRIDDEN.getLabel(), "If checked, files that are listed in the chitin.key and are also available in the " + "Override folder, will be shown in bold in the resource tree." diff --git a/src/org/infinity/gui/ResourceTree.java b/src/org/infinity/gui/ResourceTree.java index 2bba1da0d..1333a2d03 100644 --- a/src/org/infinity/gui/ResourceTree.java +++ b/src/org/infinity/gui/ResourceTree.java @@ -7,6 +7,7 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; +import java.awt.FontMetrics; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; @@ -23,8 +24,10 @@ import java.util.Locale; import java.util.Stack; +import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFileChooser; +import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; @@ -55,6 +58,7 @@ import org.infinity.resource.key.ResourceEntry; import org.infinity.resource.key.ResourceTreeFolder; import org.infinity.resource.key.ResourceTreeModel; +import org.infinity.util.IconCache; import org.infinity.util.io.FileEx; import org.infinity.util.io.FileManager; import org.infinity.util.io.StreamUtils; @@ -703,7 +707,15 @@ public void popupMenuCanceled(PopupMenuEvent event) { } private static final class ResourceTreeRenderer extends DefaultTreeCellRenderer { + private final int iconSize; + private ResourceTreeRenderer() { + super(); + final JLabel l = new JLabel(); + final FontMetrics fm = l.getFontMetrics(l.getFont()); + int fontHeight = fm.getHeight(); + // scale icon size up to the next multiple of 4 + this.iconSize = Math.max(IconCache.getDefaultTreeIconSize(), (fontHeight + 3) & ~3); } @Override @@ -713,6 +725,9 @@ public Component getTreeCellRendererComponent(JTree tree, Object o, boolean sel, Font font = tree.getFont(); if (leaf && o instanceof ResourceEntry) { final ResourceEntry e = (ResourceEntry) o; + boolean showIcon = BrowserMenuBar.getInstance().getOptions().showResourceTreeIcons() && + (e.getExtension().equalsIgnoreCase("ITM") || e.getExtension().equalsIgnoreCase("SPL")); + final Icon icon = showIcon ? IconCache.get(e, iconSize) : e.getIcon(); final BrowserMenuBar options = BrowserMenuBar.getInstance(); if (options.getOptions().showTreeSearchNames()) { @@ -724,7 +739,7 @@ public Component getTreeCellRendererComponent(JTree tree, Object o, boolean sel, final boolean hasTitle = title != null && !title.isEmpty() && !"No such index".equals(title); setText(hasTitle ? name + " - " + title : name); } - setIcon(e.getIcon()); + setIcon(icon); // Do not use bold in Override mode othrewise almost all entries will be in bold, which looks not so good final boolean inOverrideMode = options.getOptions().getOverrideMode() == OverrideMode.InOverride; if (e.hasOverride() && !inOverrideMode && options.getOptions().highlightOverridden()) { diff --git a/src/org/infinity/gui/TextListPanel.java b/src/org/infinity/gui/TextListPanel.java index a24b32c30..c1669ed28 100644 --- a/src/org/infinity/gui/TextListPanel.java +++ b/src/org/infinity/gui/TextListPanel.java @@ -6,6 +6,7 @@ import java.awt.Adjustable; import java.awt.BorderLayout; +import java.awt.Component; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; @@ -18,6 +19,7 @@ import java.util.Locale; import javax.swing.BorderFactory; +import javax.swing.DefaultListCellRenderer; import javax.swing.JComponent; import javax.swing.JList; import javax.swing.JPanel; @@ -36,29 +38,39 @@ import javax.swing.event.ListSelectionListener; import org.infinity.NearInfinity; +import org.infinity.datatype.ResourceRef; import org.infinity.icon.Icons; import org.infinity.util.FilteredListModel; +import org.infinity.util.IconCache; import org.infinity.util.Misc; -public final class TextListPanel extends JPanel +public class TextListPanel extends JPanel implements DocumentListener, ListSelectionListener, ActionListener, ChangeListener { private static boolean filterEnabled = false; private final FilteredListModel listmodel = new FilteredListModel<>(filterEnabled); private final JList list = new JList<>(); + private final JScrollPane scrollPane; private final JTextField tfield = new JTextField(); private final JToggleButton tbFilter = new JToggleButton(Icons.ICON_FILTER_16.getIcon(), filterEnabled); private boolean sortValues = true; public TextListPanel(List values) { - this(values, true); + this(values, true, false); } public TextListPanel(List values, boolean sortValues) { + this(values, sortValues, false); + } + + public TextListPanel(List values, boolean sortValues, boolean showIcons) { super(new BorderLayout()); this.sortValues = sortValues; setValues(values); + if (showIcons) { + list.setCellRenderer(new IconCellRenderer()); + } list.setModel(listmodel); list.setSelectedIndex(0); list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -67,6 +79,8 @@ public TextListPanel(List values, boolean sortValues) { listmodel.addFilterChangeListener(this); tfield.getDocument().addDocumentListener(this); + scrollPane = new JScrollPane(list); + tbFilter.setToolTipText("Toggle filtering on or off"); tbFilter.addActionListener(this); // Horizontal margins are too wasteful on default l&f @@ -82,7 +96,7 @@ public TextListPanel(List values, boolean sortValues) { pInput.add(tbFilter, BorderLayout.EAST); add(pInput, BorderLayout.NORTH); - add(new JScrollPane(list), BorderLayout.CENTER); + add(scrollPane, BorderLayout.CENTER); ensurePreferredComponentWidth(list, true); ensurePreferredComponentWidth(tfield, false); } @@ -306,4 +320,23 @@ private void calculatePreferredComponentHeight(JComponent c) { c.setPreferredSize(d); c.invalidate(); } + + // -------------------------- INNER CLASSES -------------------------- + + private static class IconCellRenderer extends DefaultListCellRenderer { + public IconCellRenderer() { + super(); + } + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, + boolean cellHasFocus) { + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if (value instanceof ResourceRef.ResourceRefEntry) { + final ResourceRef.ResourceRefEntry entry = (ResourceRef.ResourceRefEntry) value; + setIcon(IconCache.get(entry.getEntry(), IconCache.getDefaultListIconSize())); + } + return this; + } + } } diff --git a/src/org/infinity/gui/menu/OptionsMenuItem.java b/src/org/infinity/gui/menu/OptionsMenuItem.java index 85c86a43a..86604f6f8 100644 --- a/src/org/infinity/gui/menu/OptionsMenuItem.java +++ b/src/org/infinity/gui/menu/OptionsMenuItem.java @@ -123,6 +123,8 @@ public class OptionsMenuItem extends JMenuItem implements ActionListener { public static final String OPTION_LAUNCHGAMEALLOWED = "LaunchGameAllowed"; public static final String OPTION_SHOWUNKNOWNRESOURCES = "ShowUnknownResources"; public static final String OPTION_SHOWTREESEARCHNAMES = "ShowTreeSearchNames"; + public static final String OPTION_SHOW_RESOURCE_LIST_ICONS = "ShowResourceListIcons"; + public static final String OPTION_SHOW_RESOURCE_TREE_ICONS = "ShowResourceTreeIcons"; public static final String OPTION_HIGHLIGHT_OVERRIDDEN = "HighlightOverridden"; public static final String OPTION_CACHEOVERRIDE = "CacheOverride"; public static final String OPTION_KEEPVIEWONCOPY = "UpdateTreeOnCopy"; @@ -421,6 +423,16 @@ public boolean showTreeSearchNames() { return AppOption.SHOW_TREE_SEARCH_NAMES.getBoolValue(); } + /** Returns whether icons are shown alongside resource names for ITM and SPL resources in resource selection lists. */ + public boolean showResourceListIcons() { + return AppOption.SHOW_RESOURCE_LIST_ICONS.getBoolValue(); + } + + /** Returns whether icons are shown alongside resource names for ITM and SPL resources in the resource tree. */ + public boolean showResourceTreeIcons() { + return AppOption.SHOW_RESOURCE_TREE_ICONS.getBoolValue(); + } + /** Returns whether overridden files are displayed in bold in the resource tree. */ public boolean highlightOverridden() { return AppOption.HIGHLIGHT_OVERRIDDEN.getBoolValue(); @@ -860,7 +872,8 @@ private void applyChanges(Collection options) { for (final AppOption option : options) { if (option.isModified()) { if (option.equals(AppOption.SHOW_UNKNOWN_RESOURCES) || - option.equals(AppOption.SHOW_OVERRIDES_IN)) { + option.equals(AppOption.SHOW_OVERRIDES_IN) || + option.equals(AppOption.SHOW_RESOURCE_TREE_ICONS)) { refresh = true; messages.add(String.format("%s: %s", option.getLabel(), option.getValue())); } else if (option.equals(AppOption.UI_SCALE_ENABLED) || diff --git a/src/org/infinity/resource/ResourceFactory.java b/src/org/infinity/resource/ResourceFactory.java index 395d47d69..fe33a92cd 100644 --- a/src/org/infinity/resource/ResourceFactory.java +++ b/src/org/infinity/resource/ResourceFactory.java @@ -268,6 +268,54 @@ public static Resource getResource(ResourceEntry entry, String forcedExtension) return res; } + /** + * Returns the BAM {@link ResourceEntry} of the icon associated with the specified resource. + *

+ * Note: Only {@code ITM} and {@code SPL} resources will return icons if available. + *

+ * + * @param entry The {@code ResourceEntry} of the resource. + * @return BAM {@link ResourceEntry} of the icon associated with the resource. Returns {@code null} if icon is not + * available. + */ + public static ResourceEntry getResourceIcon(ResourceEntry entry) { + return getResourceIcon(entry, null); + } + + /** + * Returns the BAM {@link ResourceEntry} of the icon associated with the specified resource. + *

+ * Note: Only {@code ITM} and {@code SPL} resources will return icons if available. + *

+ * + * @param entry The {@code ResourceEntry} of the resource. + * @param forcedExtension Optional file extension string that is used to override the original file type. + * @return BAM {@link ResourceEntry} of the icon associated with the resource. Returns {@code null} if icon is not + * available. + */ + public static ResourceEntry getResourceIcon(ResourceEntry entry, String forcedExtension) { + ResourceEntry retVal = null; + + Class clsResource = getResourceType(entry, forcedExtension); + if (clsResource != null && + (ItmResource.class.isAssignableFrom(clsResource) || SplResource.class.isAssignableFrom(clsResource))) { + try { + final ByteBuffer buf = entry.getResourceBuffer(); + String iconResref = StreamUtils.readString(buf, 0x3a, 8); + if (!iconResref.isEmpty()) { + final ResourceEntry iconEntry = ResourceFactory.getResourceEntry(iconResref + ".BAM"); + if (iconEntry != null) { + retVal = iconEntry; + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + return retVal; + } + /** * Attempts to detect the resource type from the data itself and returns the respective resource class type, or * {@code null} on failure. diff --git a/src/org/infinity/util/IconCache.java b/src/org/infinity/util/IconCache.java new file mode 100644 index 000000000..794702b6e --- /dev/null +++ b/src/org/infinity/util/IconCache.java @@ -0,0 +1,174 @@ +// Near Infinity - An Infinity Engine Browser and Editor +// Copyright (C) 2001 Jon Olav Hauglid +// See LICENSE.txt for license information + +package org.infinity.util; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.util.HashMap; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import org.infinity.resource.Profile; +import org.infinity.resource.ResourceFactory; +import org.infinity.resource.graphics.BamDecoder; +import org.infinity.resource.graphics.BamDecoder.BamControl; +import org.infinity.resource.graphics.ColorConvert; +import org.infinity.resource.key.ResourceEntry; + +/** + * Cache for icons associated with ITM or SPL resources. + * + * Icons are preprocessed and optimized for display in lists or tables. + */ +public class IconCache { + // Icon width and height cannot be smaller than this + private static final int MIN_SIZE = 2; + private static final int SIZE_LIST = 32; + private static final int SIZE_TREE = 16; + + // Mappings for transparent default icons of various sizes + private static final HashMap DEFAULT_ICONS = new HashMap<>(8); + + // Maps icons of various sizes to a BAM ResourceEntry + private static final HashMap> CACHE = new HashMap<>(); + + /** Returns the default icon width and height used in resource selection lists. */ + public static int getDefaultListIconSize() { + return SIZE_LIST; + } + + /** Returns the default icon width and height used in the resource tree. */ + public static int getDefaultTreeIconSize() { + return SIZE_TREE; + } + + /** + * Returns a transparent default icon of given dimension. + * @param size Width and height of the icon, in pixels. + * @return a transparent {@link Icon} of the given size. {@code null} if specified size is too small. + */ + public static Icon getDefaultIcon(int size) { + if (size < MIN_SIZE) { + return null; + } + + return DEFAULT_ICONS.computeIfAbsent(size, + k -> new ImageIcon(ColorConvert.createCompatibleImage(size, size, Transparency.BITMASK))); + } + + /** Removes all icons associated with the specified BAM {@link ResourceEntry}. */ + public static void remove(ResourceEntry entry) { + if (entry != null) { + CACHE.remove(entry); + } + } + + /** Removes all entries from the cache. */ + public static void clearCache() { + CACHE.clear(); + DEFAULT_ICONS.clear(); + } + + /** Returns the icon associated with the specified BAM {@link ResourceEntry} scaled to the specified size. */ + public static synchronized Icon get(ResourceEntry entry, int size) { + if (size < MIN_SIZE) { + return null; + } + + final ResourceEntry bamEntry = ResourceFactory.getResourceIcon(entry); + Icon retVal = getCachedIcon(bamEntry, size); + + if (bamEntry != null && retVal == null) { + Image image = null; + + final BamDecoder decoder = BamDecoder.loadBam(bamEntry); + if (decoder != null) { + final BamControl control = decoder.createControl(); + + // selecting suitable icon + // PSTEE: cycle 0 contains the non-highlighted icon (which looks better) + // other: cycle 1 contains the inventory icon in most cases + int cycleIdx = (Profile.getGame() == Profile.Game.PSTEE) ? 0 : 1; + cycleIdx = Math.min(cycleIdx, control.cycleCount() - 1); + if (cycleIdx >= 0) { + // getting first available frame from cycle + for (int ci = cycleIdx; ci >= 0; ci--) { + control.cycleSet(ci); + if (control.cycleFrameCount() > 0) { + image = control.cycleGetFrame(control.cycleFrameCount() - 1); + ci = -1; + } + } + } else if (decoder.frameCount() > 0) { + // otherwise, try using frames directly + for (int i = 0, count = decoder.frameCount(); i < count; i++) { + final Image tmp = decoder.frameGet(control, 0); + if (tmp.getWidth(null) >= MIN_SIZE && tmp.getHeight(null) >= MIN_SIZE) { + image = tmp; + i = count; + } + } + } + } + + if (image != null) { + if (image.getHeight(null) != size) { + final int dstWidth; + final int dstHeight; + if (image.getHeight(null) > size) { + // preserve image aspect ratio + dstWidth = (image.getWidth(null) >= image.getHeight(null)) ? size : image.getWidth(null) * size / image.getHeight(null); + dstHeight = (image.getHeight(null) >= image.getWidth(null)) ? size : image.getHeight(null) * size / image.getWidth(null); + } else { + dstWidth = image.getWidth(null); + dstHeight = image.getHeight(null); + } + int x = (size - dstWidth) / 2; + int y = (size - dstHeight) / 2; + final BufferedImage scaledImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2 = scaledImage.createGraphics(); + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + g2.drawImage(image, x, y, dstWidth, dstHeight, null); + g2.dispose(); + image = scaledImage; + } + + retVal = new ImageIcon(image); + setCachedIcon(bamEntry, size, retVal); + } + } + + if (retVal == null) { + retVal = getDefaultIcon(size); + } + + return retVal; + } + + /** Returns the cached icon for the specified BAM {@link ResourceEntry} and {@code size}. */ + private static Icon getCachedIcon(ResourceEntry entry, int size) { + Icon retVal = null; + + if (entry != null) { + final HashMap map = CACHE.get(entry); + if (map != null) { + retVal = map.get(size); + } + } + + return retVal; + } + + /** Adds the given BAM {@link ResourceEntry} to the cache and associates it with the specified {@link Icon}. */ + private static void setCachedIcon(ResourceEntry entry, int size, Icon icon) { + if (entry != null && size > 0 && icon != null) { + CACHE.computeIfAbsent(entry, k -> new HashMap<>(8)).put(size, icon); + } + } +} From bbd36ae2743d4f81e039513cce610b22ce7a3c8e Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Tue, 11 Jul 2023 22:12:27 +0200 Subject: [PATCH 20/28] Expand option to show preview icons Display preview icons in spell selection lists in IWD2 CRE resources (defined as lookup tables instead of straight resrefs). Display icons in View tabs: - CRE: Inventory table, Memorized Spells table, Known Spells list - GAM: Portrait icons for (non-)party characters - ITM: Abilities list - SPL: Abilities list - STO: Items for Sale list, Cures for Sale list --- src/org/infinity/datatype/AbstractBitmap.java | 15 +- src/org/infinity/gui/ResourceTree.java | 8 +- src/org/infinity/gui/TextListPanel.java | 19 ++ .../gui/ToolTipTableCellRenderer.java | 37 +++- src/org/infinity/gui/ViewerUtil.java | 79 ++++++- .../infinity/resource/cre/ViewerItems.java | 4 +- .../infinity/resource/cre/ViewerSpells.java | 4 +- src/org/infinity/util/IconCache.java | 193 +++++++++++++----- 8 files changed, 289 insertions(+), 70 deletions(-) diff --git a/src/org/infinity/datatype/AbstractBitmap.java b/src/org/infinity/datatype/AbstractBitmap.java index c0b92d7da..d0aed501b 100644 --- a/src/org/infinity/datatype/AbstractBitmap.java +++ b/src/org/infinity/datatype/AbstractBitmap.java @@ -26,6 +26,7 @@ import org.infinity.gui.StructViewer; import org.infinity.gui.TextListPanel; import org.infinity.gui.ViewerUtil; +import org.infinity.gui.menu.BrowserMenuBar; import org.infinity.icon.Icons; import org.infinity.resource.AbstractStruct; import org.infinity.util.Misc; @@ -205,14 +206,14 @@ public JComponent edit(ActionListener container) { FormattedData selected = null; final List> items = new ArrayList<>(itemMap.size()); for (final Long key : itemMap.keySet()) { - FormattedData item = new FormattedData<>(key, itemMap.get(key), formatter); + FormattedData item = new FormattedData<>(this, key, itemMap.get(key), formatter); items.add(item); if (key.intValue() == value) { selected = item; } } - list = new TextListPanel<>(items, sortByName); + list = new TextListPanel<>(items, sortByName, BrowserMenuBar.getInstance().getOptions().showResourceListIcons()); list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent event) { @@ -494,17 +495,23 @@ protected String getHexValue(long value) { /** * A helper class used to encapsulate the formatter function object. */ - protected static class FormattedData { + public static class FormattedData { + private final AbstractBitmap parent; private final Long value; private final T data; private final BiFunction formatter; - public FormattedData(long value, T data, BiFunction formatter) { + public FormattedData(AbstractBitmap parent, long value, T data, BiFunction formatter) { + this.parent = parent; this.value = value; this.data = data; this.formatter = formatter; } + public AbstractBitmap getParent() { + return parent; + } + public Long getValue() { return value; } diff --git a/src/org/infinity/gui/ResourceTree.java b/src/org/infinity/gui/ResourceTree.java index 1333a2d03..236eb6581 100644 --- a/src/org/infinity/gui/ResourceTree.java +++ b/src/org/infinity/gui/ResourceTree.java @@ -36,6 +36,7 @@ import javax.swing.JTree; import javax.swing.SwingConstants; import javax.swing.Timer; +import javax.swing.UIManager; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; import javax.swing.event.TreeSelectionEvent; @@ -711,8 +712,11 @@ private static final class ResourceTreeRenderer extends DefaultTreeCellRenderer private ResourceTreeRenderer() { super(); - final JLabel l = new JLabel(); - final FontMetrics fm = l.getFontMetrics(l.getFont()); + Font f = UIManager.getDefaults().getFont("Label.font"); + if (f == null) { + f = new JLabel().getFont(); + } + final FontMetrics fm = getFontMetrics(f); int fontHeight = fm.getHeight(); // scale icon size up to the next multiple of 4 this.iconSize = Math.max(IconCache.getDefaultTreeIconSize(), (fontHeight + 3) & ~3); diff --git a/src/org/infinity/gui/TextListPanel.java b/src/org/infinity/gui/TextListPanel.java index c1669ed28..96a8ce8ad 100644 --- a/src/org/infinity/gui/TextListPanel.java +++ b/src/org/infinity/gui/TextListPanel.java @@ -38,8 +38,12 @@ import javax.swing.event.ListSelectionListener; import org.infinity.NearInfinity; +import org.infinity.datatype.AbstractBitmap; +import org.infinity.datatype.ResourceBitmap; import org.infinity.datatype.ResourceRef; import org.infinity.icon.Icons; +import org.infinity.resource.ResourceFactory; +import org.infinity.resource.key.ResourceEntry; import org.infinity.util.FilteredListModel; import org.infinity.util.IconCache; import org.infinity.util.Misc; @@ -333,8 +337,23 @@ public Component getListCellRendererComponent(JList list, Object value, int i boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof ResourceRef.ResourceRefEntry) { + // resolving Resource Reference final ResourceRef.ResourceRefEntry entry = (ResourceRef.ResourceRefEntry) value; setIcon(IconCache.get(entry.getEntry(), IconCache.getDefaultListIconSize())); + } else if (value instanceof AbstractBitmap.FormattedData) { + // resolving Resource Bitmap + final AbstractBitmap.FormattedData fmt = (AbstractBitmap.FormattedData) value; + if (fmt.getParent() != null) { + final AbstractBitmap bmp = fmt.getParent(); + Object o = bmp.getDataOf(fmt.getValue()); + if (o instanceof ResourceBitmap.RefEntry) { + final ResourceBitmap.RefEntry entry = (ResourceBitmap.RefEntry) o; + final ResourceEntry iconEntry = ResourceFactory.getResourceIcon(entry.getResourceEntry()); + if (iconEntry != null) { + setIcon(IconCache.getIcon(entry.getResourceEntry(), IconCache.getDefaultListIconSize())); + } + } + } } return this; } diff --git a/src/org/infinity/gui/ToolTipTableCellRenderer.java b/src/org/infinity/gui/ToolTipTableCellRenderer.java index b72d652b9..4ff1bfc29 100644 --- a/src/org/infinity/gui/ToolTipTableCellRenderer.java +++ b/src/org/infinity/gui/ToolTipTableCellRenderer.java @@ -5,11 +5,36 @@ package org.infinity.gui; import java.awt.Component; +import java.awt.FontMetrics; +import javax.swing.Icon; import javax.swing.JTable; import javax.swing.table.DefaultTableCellRenderer; -public final class ToolTipTableCellRenderer extends DefaultTableCellRenderer { +import org.infinity.datatype.ResourceRef; +import org.infinity.resource.ResourceFactory; +import org.infinity.util.IconCache; + +public class ToolTipTableCellRenderer extends DefaultTableCellRenderer { + private final boolean showIcons; + private final int iconSize; + + public ToolTipTableCellRenderer() { + this(false); + } + + public ToolTipTableCellRenderer(boolean showIcons) { + super(); + this.showIcons = showIcons; + + int fontHeight = 0; + if (this.showIcons) { + final FontMetrics fm = getFontMetrics(getFont()); + fontHeight = fm.getHeight(); + } + // scale icon size up to the next multiple of 4 + this.iconSize = Math.max(IconCache.getDefaultTreeIconSize(), (fontHeight + 3) & ~3); + } // --------------------- Begin Interface TableCellRenderer --------------------- @@ -38,6 +63,16 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole } else { setToolTipText(null); } + + if (showIcons) { + Icon icon = null; + if (value instanceof ResourceRef) { + final ResourceRef ref = (ResourceRef) value; + icon = IconCache.get(ResourceFactory.getResourceEntry(ref.getResourceName()), iconSize); + } + setIcon(icon); + } + return this; } diff --git a/src/org/infinity/gui/ViewerUtil.java b/src/org/infinity/gui/ViewerUtil.java index 43d4b1965..38be16fb5 100644 --- a/src/org/infinity/gui/ViewerUtil.java +++ b/src/org/infinity/gui/ViewerUtil.java @@ -21,6 +21,7 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -28,6 +29,7 @@ import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; +import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; @@ -51,17 +53,21 @@ import org.infinity.datatype.StringRef; import org.infinity.gui.menu.BrowserMenuBar; import org.infinity.icon.Icons; +import org.infinity.resource.AbstractAbility; import org.infinity.resource.AbstractStruct; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; import org.infinity.resource.StructEntry; import org.infinity.resource.Viewable; +import org.infinity.resource.cre.CreResource; +import org.infinity.resource.gam.PartyNPC; import org.infinity.resource.graphics.BamDecoder; import org.infinity.resource.graphics.BamDecoder.BamControl; import org.infinity.resource.graphics.BamResource; import org.infinity.resource.graphics.GraphicsResource; import org.infinity.resource.graphics.MosResource; import org.infinity.resource.key.ResourceEntry; +import org.infinity.util.IconCache; import org.infinity.util.Misc; import org.infinity.util.SimpleListModel; import org.infinity.util.StringTable; @@ -554,19 +560,37 @@ public static interface ListValueRenderer { String getListValue(Object value); } - private static final class StructListRenderer extends DefaultListCellRenderer implements ListValueRenderer { + public static class StructListRenderer extends DefaultListCellRenderer implements ListValueRenderer { + /** List of classes containing references to associated graphics resources. */ + private static final List> SUPPORTED_STRUCTURES = Arrays.asList( + org.infinity.resource.cre.KnownSpells.class, + org.infinity.resource.sto.Cure.class, + org.infinity.resource.sto.ItemSale.class, + org.infinity.resource.sto.ItemSale11.class + ); + private final String attrName; + private final boolean showIcons; - private StructListRenderer(String attrName) { + public StructListRenderer(String attrName) { this.attrName = attrName; + this.showIcons = BrowserMenuBar.getInstance().getOptions().showResourceListIcons(); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - label.setText(getListValue(value)); - return label; + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setText(getListValue(value)); + + if (showIcons && value instanceof AbstractStruct) { + final Icon icon = loadIcon((AbstractStruct) value); + if (icon != null) { + setIcon(icon); + } + } + + return this; } @Override @@ -587,6 +611,51 @@ public String getListValue(Object value) { } return ""; } + + /** + * Attempts to find and return a graphics associated with the specified {@link AbstractStruct} instance, + * as {@link Icon}. + */ + private Icon loadIcon(AbstractStruct struct) { + Icon retVal = null; + + if (struct != null) { + ResourceEntry entry = null; + StructEntry se = null; + int iconSize = IconCache.getDefaultListIconSize(); + boolean searchExtraDirs = false; + + if (struct instanceof AbstractAbility) { + // ITM/SPL ability icon + se = struct.getAttribute(AbstractAbility.ABILITY_ICON); + } else if (struct instanceof PartyNPC) { + // (Non-)player character portrait + StructEntry cre = struct.getAttribute(PartyNPC.GAM_NPC_CRE_RESOURCE); + if (cre instanceof CreResource) { + se = ((CreResource) cre).getAttribute(CreResource.CRE_PORTRAIT_SMALL); + iconSize = IconCache.getDefaultListIconSize() * 2; // increase to thumbnail size + searchExtraDirs = true; // bitmaps can be in "Portraits" folder + } + } else { + // Resource-specific icon + for (final Class as : SUPPORTED_STRUCTURES) { + if (as.isAssignableFrom(struct.getClass())) { + se = struct.getAttribute(attrName); + break; + } + } + } + + if (se != null) { + if (se instanceof ResourceRef) { + entry = ResourceFactory.getResourceEntry(((ResourceRef) se).getResourceName(), searchExtraDirs); + } + retVal = IconCache.get(entry, iconSize); + } + } + + return retVal; + } } private static final class StructListComparator implements Comparator { diff --git a/src/org/infinity/resource/cre/ViewerItems.java b/src/org/infinity/resource/cre/ViewerItems.java index 8c87f6ff7..940f9f204 100644 --- a/src/org/infinity/resource/cre/ViewerItems.java +++ b/src/org/infinity/resource/cre/ViewerItems.java @@ -31,6 +31,7 @@ import org.infinity.datatype.ResourceRef; import org.infinity.gui.ToolTipTableCellRenderer; import org.infinity.gui.ViewFrame; +import org.infinity.gui.menu.BrowserMenuBar; import org.infinity.icon.Icons; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; @@ -69,7 +70,8 @@ final class ViewerItems extends JPanel implements ActionListener, ListSelectionL } }); table = new JTable(tableModel); - table.setDefaultRenderer(Object.class, new ToolTipTableCellRenderer()); + table.setDefaultRenderer(Object.class, + new ToolTipTableCellRenderer(BrowserMenuBar.getInstance().getOptions().showResourceListIcons())); ((DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer()) .setHorizontalAlignment(SwingConstants.LEFT); table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); diff --git a/src/org/infinity/resource/cre/ViewerSpells.java b/src/org/infinity/resource/cre/ViewerSpells.java index f5f18e27c..593c64865 100644 --- a/src/org/infinity/resource/cre/ViewerSpells.java +++ b/src/org/infinity/resource/cre/ViewerSpells.java @@ -28,6 +28,7 @@ import org.infinity.datatype.ResourceRef; import org.infinity.gui.ToolTipTableCellRenderer; import org.infinity.gui.ViewFrame; +import org.infinity.gui.menu.BrowserMenuBar; import org.infinity.icon.Icons; import org.infinity.resource.Resource; import org.infinity.resource.ResourceFactory; @@ -43,7 +44,8 @@ final class ViewerSpells extends JPanel implements ActionListener { super(new BorderLayout(0, 3)); tableModel = new MemSpellTableModel(cre); table = new JTable(tableModel); - table.setDefaultRenderer(Object.class, new ToolTipTableCellRenderer()); + table.setDefaultRenderer(Object.class, + new ToolTipTableCellRenderer(BrowserMenuBar.getInstance().getOptions().showResourceListIcons())); ((DefaultTableCellRenderer) table.getTableHeader().getDefaultRenderer()) .setHorizontalAlignment(SwingConstants.LEFT); table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); diff --git a/src/org/infinity/util/IconCache.java b/src/org/infinity/util/IconCache.java index 794702b6e..44f781e3c 100644 --- a/src/org/infinity/util/IconCache.java +++ b/src/org/infinity/util/IconCache.java @@ -19,6 +19,7 @@ import org.infinity.resource.graphics.BamDecoder; import org.infinity.resource.graphics.BamDecoder.BamControl; import org.infinity.resource.graphics.ColorConvert; +import org.infinity.resource.graphics.GraphicsResource; import org.infinity.resource.key.ResourceEntry; /** @@ -53,7 +54,7 @@ public static int getDefaultTreeIconSize() { * @param size Width and height of the icon, in pixels. * @return a transparent {@link Icon} of the given size. {@code null} if specified size is too small. */ - public static Icon getDefaultIcon(int size) { + public static synchronized Icon getDefaultIcon(int size) { if (size < MIN_SIZE) { return null; } @@ -63,35 +64,150 @@ public static Icon getDefaultIcon(int size) { } /** Removes all icons associated with the specified BAM {@link ResourceEntry}. */ - public static void remove(ResourceEntry entry) { + public static synchronized void remove(ResourceEntry entry) { if (entry != null) { CACHE.remove(entry); } } /** Removes all entries from the cache. */ - public static void clearCache() { + public static synchronized void clearCache() { CACHE.clear(); DEFAULT_ICONS.clear(); } - /** Returns the icon associated with the specified BAM {@link ResourceEntry} scaled to the specified size. */ - public static synchronized Icon get(ResourceEntry entry, int size) { + /** + * Returns the icon associated with the specified graphics {@link ResourceEntry} scaled to the specified size. + * + * @param entry {@link ResourceEntry} of a supported graphics resource. Currently supported: BAM, BMP. + * @param size Width and height of the resulting icon, in pixels. + * @return {@link Icon} from the specified graphics resource. Returns {@code null} if icon is not available. + */ + public static synchronized Icon getIcon(ResourceEntry entry, int size) { if (size < MIN_SIZE) { return null; } - final ResourceEntry bamEntry = ResourceFactory.getResourceIcon(entry); - Icon retVal = getCachedIcon(bamEntry, size); - - if (bamEntry != null && retVal == null) { + Icon retVal = getCachedIcon(entry, size); + if (entry != null && retVal == null) { Image image = null; + if ("BAM".equalsIgnoreCase(entry.getExtension())) { + // load suitable BAM frame + image = getBamFrameImage(entry); + } else if ("BMP".equalsIgnoreCase(entry.getExtension())) { + // load BMP image + image = getBmpImage(entry); + } + + image = getScaledImage(image, size, true); + if (image != null) { + retVal = new ImageIcon(image); + setCachedIcon(entry, size, retVal); + } + } + + if (retVal == null) { + retVal = getDefaultIcon(size); + } + + return retVal; + } + + /** + * Returns the icon associated with the specified {@link ResourceEntry} scaled to the specified size. + * + * @param entry {@link ResourceEntry} of a supported game resource. Currently supported: ITM, SPL, BAM, BMP. + * @param size Width and height of the resulting icon, in pixels. + * @return {@link Icon} associated with the specified game resource. Returns {@code null} if icon is not available. + */ + public static synchronized Icon get(ResourceEntry entry, int size) { + ResourceEntry graphicsEntry = null; + + if (entry != null) { + final String ext = entry.getExtension().toUpperCase(); + if (ext.equals("ITM") || ext.equals("SPL")) { + graphicsEntry = ResourceFactory.getResourceIcon(entry); + } else if (ext.equals("BAM") || ext.equals("BMP")) { + graphicsEntry = entry; + } + } + + return getIcon(graphicsEntry, size); + } + + /** Returns the cached icon for the specified BAM {@link ResourceEntry} and {@code size}. */ + private static Icon getCachedIcon(ResourceEntry entry, int size) { + Icon retVal = null; + + if (entry != null) { + final HashMap map = CACHE.get(entry); + if (map != null) { + retVal = map.get(size); + } + } + + return retVal; + } + + /** Adds the given BAM {@link ResourceEntry} to the cache and associates it with the specified {@link Icon}. */ + private static synchronized void setCachedIcon(ResourceEntry entry, int size, Icon icon) { + if (entry != null && size > 0 && icon != null) { + CACHE.computeIfAbsent(entry, k -> new HashMap<>(8)).put(size, icon); + } + } + + /** + * Returns a scaled version of the specified {@link Image} that fits into the given size. + * + * @param image {@link Image} to scale. + * @param size Width and height of the returned image should not exceed this value. + * @param quality A rendering hint for the scaled image. Specify {@code true} to apply bicubic interpolation for + * sharper details, or {@code false} for a quicker bilinear interpolation. + * @return The scaled image. + */ + private static synchronized Image getScaledImage(Image image, int size, boolean quality) { + Image retVal = image; + + if (image != null) { + if (image.getHeight(null) != size) { + final int dstWidth; + final int dstHeight; + if (image.getHeight(null) > size) { + // preserve image aspect ratio + dstWidth = (image.getWidth(null) >= image.getHeight(null)) ? size : image.getWidth(null) * size / image.getHeight(null); + dstHeight = (image.getHeight(null) >= image.getWidth(null)) ? size : image.getHeight(null) * size / image.getWidth(null); + } else { + dstWidth = image.getWidth(null); + dstHeight = image.getHeight(null); + } + int x = (size - dstWidth) / 2; + int y = (size - dstHeight) / 2; + final BufferedImage scaledImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); + final Graphics2D g2 = scaledImage.createGraphics(); + final Object interpolation = quality ? RenderingHints.VALUE_INTERPOLATION_BICUBIC : RenderingHints.VALUE_INTERPOLATION_BILINEAR; + g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, interpolation); + g2.drawImage(image, x, y, dstWidth, dstHeight, null); + g2.dispose(); + image = scaledImage; + } + + retVal = image; + } + + return retVal; + } + + /** Returns a suitable (and unscaled) image for display. */ + private static synchronized Image getBamFrameImage(ResourceEntry bamEntry) { + Image retVal = null; + + if (bamEntry != null) { final BamDecoder decoder = BamDecoder.loadBam(bamEntry); if (decoder != null) { final BamControl control = decoder.createControl(); - // selecting suitable icon + // selecting suitable frame // PSTEE: cycle 0 contains the non-highlighted icon (which looks better) // other: cycle 1 contains the inventory icon in most cases int cycleIdx = (Profile.getGame() == Profile.Game.PSTEE) ? 0 : 1; @@ -101,7 +217,7 @@ public static synchronized Icon get(ResourceEntry entry, int size) { for (int ci = cycleIdx; ci >= 0; ci--) { control.cycleSet(ci); if (control.cycleFrameCount() > 0) { - image = control.cycleGetFrame(control.cycleFrameCount() - 1); + retVal = control.cycleGetFrame(control.cycleFrameCount() - 1); ci = -1; } } @@ -110,65 +226,30 @@ public static synchronized Icon get(ResourceEntry entry, int size) { for (int i = 0, count = decoder.frameCount(); i < count; i++) { final Image tmp = decoder.frameGet(control, 0); if (tmp.getWidth(null) >= MIN_SIZE && tmp.getHeight(null) >= MIN_SIZE) { - image = tmp; + retVal = tmp; i = count; } } } } - - if (image != null) { - if (image.getHeight(null) != size) { - final int dstWidth; - final int dstHeight; - if (image.getHeight(null) > size) { - // preserve image aspect ratio - dstWidth = (image.getWidth(null) >= image.getHeight(null)) ? size : image.getWidth(null) * size / image.getHeight(null); - dstHeight = (image.getHeight(null) >= image.getWidth(null)) ? size : image.getHeight(null) * size / image.getWidth(null); - } else { - dstWidth = image.getWidth(null); - dstHeight = image.getHeight(null); - } - int x = (size - dstWidth) / 2; - int y = (size - dstHeight) / 2; - final BufferedImage scaledImage = new BufferedImage(size, size, BufferedImage.TYPE_INT_ARGB); - final Graphics2D g2 = scaledImage.createGraphics(); - g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); - g2.drawImage(image, x, y, dstWidth, dstHeight, null); - g2.dispose(); - image = scaledImage; - } - - retVal = new ImageIcon(image); - setCachedIcon(bamEntry, size, retVal); - } - } - - if (retVal == null) { - retVal = getDefaultIcon(size); } return retVal; } - /** Returns the cached icon for the specified BAM {@link ResourceEntry} and {@code size}. */ - private static Icon getCachedIcon(ResourceEntry entry, int size) { - Icon retVal = null; + /** Returns the specified BMP resource as {@link Image} object. */ + private static synchronized Image getBmpImage(ResourceEntry bmpEntry) { + Image retVal = null; - if (entry != null) { - final HashMap map = CACHE.get(entry); - if (map != null) { - retVal = map.get(size); + if (bmpEntry != null) { + try { + final GraphicsResource res = new GraphicsResource(bmpEntry); + retVal = res.getImage(); + } catch (Exception e) { + e.printStackTrace(); } } return retVal; } - - /** Adds the given BAM {@link ResourceEntry} to the cache and associates it with the specified {@link Icon}. */ - private static void setCachedIcon(ResourceEntry entry, int size, Icon icon) { - if (entry != null && size > 0 && icon != null) { - CACHE.computeIfAbsent(entry, k -> new HashMap<>(8)).put(size, icon); - } - } } From eb3dcc562d49d0b663e37b3de67cb5498572d4e3 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 10:53:52 +0200 Subject: [PATCH 21/28] Fix trailing newlines --- src/org/infinity/gui/ScrollPopupMenu.java | 2 +- src/org/infinity/gui/converter/BamOptionsDialog.java | 2 +- src/org/infinity/gui/menu/RecentGame.java | 2 +- src/org/infinity/gui/options/OptionBase.java | 2 +- src/org/infinity/gui/options/OptionCategory.java | 2 +- src/org/infinity/gui/options/OptionCheckBox.java | 2 +- src/org/infinity/gui/options/OptionContainerBase.java | 2 +- src/org/infinity/gui/options/OptionElementBase.java | 2 +- src/org/infinity/gui/options/OptionGroup.java | 2 +- src/org/infinity/gui/options/OptionGroupBox.java | 2 +- src/org/infinity/resource/dlg/ItemBase.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/org/infinity/gui/ScrollPopupMenu.java b/src/org/infinity/gui/ScrollPopupMenu.java index 6bad1d442..36b2c5a8e 100644 --- a/src/org/infinity/gui/ScrollPopupMenu.java +++ b/src/org/infinity/gui/ScrollPopupMenu.java @@ -295,4 +295,4 @@ public void layoutContainer(Container parent) { } } } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/converter/BamOptionsDialog.java b/src/org/infinity/gui/converter/BamOptionsDialog.java index 72142a67e..fc6182169 100644 --- a/src/org/infinity/gui/converter/BamOptionsDialog.java +++ b/src/org/infinity/gui/converter/BamOptionsDialog.java @@ -582,4 +582,4 @@ private void updateSettings() { // transparency options may have changed: force palette generation converter.getPaletteDialog().setPaletteModified(); } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/menu/RecentGame.java b/src/org/infinity/gui/menu/RecentGame.java index df25f462a..382977bd8 100644 --- a/src/org/infinity/gui/menu/RecentGame.java +++ b/src/org/infinity/gui/menu/RecentGame.java @@ -149,4 +149,4 @@ public static String getPathKey(int index) { return null; } } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionBase.java b/src/org/infinity/gui/options/OptionBase.java index c56531631..791d35ade 100644 --- a/src/org/infinity/gui/options/OptionBase.java +++ b/src/org/infinity/gui/options/OptionBase.java @@ -144,4 +144,4 @@ public boolean equals(Object obj) { OptionBase other = (OptionBase) obj; return Objects.equals(id, other.id) && Objects.equals(label, other.label); } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionCategory.java b/src/org/infinity/gui/options/OptionCategory.java index 7702039b4..e00f1879f 100644 --- a/src/org/infinity/gui/options/OptionCategory.java +++ b/src/org/infinity/gui/options/OptionCategory.java @@ -65,4 +65,4 @@ protected OptionBase setParent(OptionBase parent) { throw new IllegalArgumentException("Argument of type OptionCategory expected"); } } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionCheckBox.java b/src/org/infinity/gui/options/OptionCheckBox.java index e3ac2524f..36f263258 100644 --- a/src/org/infinity/gui/options/OptionCheckBox.java +++ b/src/org/infinity/gui/options/OptionCheckBox.java @@ -201,4 +201,4 @@ public void fireOnAction() { } } } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionContainerBase.java b/src/org/infinity/gui/options/OptionContainerBase.java index 57614f211..eab01d53e 100644 --- a/src/org/infinity/gui/options/OptionContainerBase.java +++ b/src/org/infinity/gui/options/OptionContainerBase.java @@ -74,4 +74,4 @@ public OptionContainerBase clearChildren() { } return this; } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionElementBase.java b/src/org/infinity/gui/options/OptionElementBase.java index 946d77969..63c7cd3cc 100644 --- a/src/org/infinity/gui/options/OptionElementBase.java +++ b/src/org/infinity/gui/options/OptionElementBase.java @@ -157,4 +157,4 @@ protected OptionElementBase removeUiComponent(Component comp) { *

*/ public abstract void fireOnAccept(); -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionGroup.java b/src/org/infinity/gui/options/OptionGroup.java index 78702b49d..5afa2d630 100644 --- a/src/org/infinity/gui/options/OptionGroup.java +++ b/src/org/infinity/gui/options/OptionGroup.java @@ -55,4 +55,4 @@ protected OptionBase setParent(OptionBase parent) { throw new IllegalArgumentException("Argument of types derived from OptionContainerBase expected"); } } -} \ No newline at end of file +} diff --git a/src/org/infinity/gui/options/OptionGroupBox.java b/src/org/infinity/gui/options/OptionGroupBox.java index c769f26b2..08e7de15d 100644 --- a/src/org/infinity/gui/options/OptionGroupBox.java +++ b/src/org/infinity/gui/options/OptionGroupBox.java @@ -317,4 +317,4 @@ public void fireOnSelect() { } } } -} \ No newline at end of file +} diff --git a/src/org/infinity/resource/dlg/ItemBase.java b/src/org/infinity/resource/dlg/ItemBase.java index 0330c9e60..640a0d703 100644 --- a/src/org/infinity/resource/dlg/ItemBase.java +++ b/src/org/infinity/resource/dlg/ItemBase.java @@ -131,4 +131,4 @@ abstract class TransitionOwnerItem extends ItemBase implements Iterable children(); -} \ No newline at end of file +} From db8824ba53b3915a58e70353f935c47c2b112a49 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 10:54:55 +0200 Subject: [PATCH 22/28] Speed up loading Near Infinity when icon preview is enabled --- src/org/infinity/NearInfinity.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java index 4f74a6897..4329efb14 100644 --- a/src/org/infinity/NearInfinity.java +++ b/src/org/infinity/NearInfinity.java @@ -431,7 +431,7 @@ private NearInfinity(Options options) { System.exit(10); } - showProgress("Starting Near Infinity" + Misc.MSG_EXPAND_LARGE, 7); + showProgress("Starting Near Infinity" + Misc.MSG_EXPAND_LARGE, 6); SwingWorker worker = new SwingWorker() { @Override protected Void doInBackground() throws Exception { @@ -459,9 +459,6 @@ protected Void doInBackground() throws Exception { // FileWatcher.getInstance().start(); // } - advanceProgress("Caching resources..."); - cacheResourceIcons(false); - return null; } }; @@ -481,6 +478,7 @@ public void windowClosing(WindowEvent event) { quit(); } }); + try { LookAndFeelInfo info = BrowserMenuBar.getInstance().getOptions().getLookAndFeel(); UIManager.setLookAndFeel(info.getClassName()); @@ -489,6 +487,8 @@ public void windowClosing(WindowEvent event) { e.printStackTrace(); } + cacheResourceIcons(true); + statusBar = new StatusBar(); ResourceTreeModel treemodel = ResourceFactory.getResourceTreeModel(); updateWindowTitle(); From 3b04dbb3e997490a4b3fa6e0b336102309ccc93e Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 13:34:47 +0200 Subject: [PATCH 23/28] Implement new functional interface: Operation A "fire-and-forget" interface for operations that require no explicit input and output. --- src/org/infinity/NearInfinity.java | 11 +++++------ src/org/infinity/util/Operation.java | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 src/org/infinity/util/Operation.java diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java index 4329efb14..a68fed4d6 100644 --- a/src/org/infinity/NearInfinity.java +++ b/src/org/infinity/NearInfinity.java @@ -45,7 +45,6 @@ import java.util.List; import java.util.Locale; import java.util.concurrent.ExecutionException; -import java.util.function.Supplier; import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; @@ -125,6 +124,7 @@ import org.infinity.util.IniMapCache; import org.infinity.util.LauncherUtils; import org.infinity.util.Misc; +import org.infinity.util.Operation; import org.infinity.util.Platform; import org.infinity.util.StringTable; import org.infinity.util.Table2daCache; @@ -1492,7 +1492,7 @@ private void cancelCacheResourceIcons() { */ private void cacheResourceIcons(boolean threaded) { // Operation for caching resource icons - final Supplier operation = () -> { + final Operation operation = () -> { try { IconCache.clearCache(); final List sizeList = new ArrayList<>(); @@ -1511,7 +1511,7 @@ private void cacheResourceIcons(boolean threaded) { for (final ResourceEntry e : resources) { for (final int size : sizes) { if (iconCacheWorker != null && iconCacheWorker.isCancelled()) { - return null; + return; } IconCache.get(e, size); } @@ -1522,7 +1522,6 @@ private void cacheResourceIcons(boolean threaded) { } catch (Exception e) { e.printStackTrace(); } - return null; }; // ensure that ongoing operations have ended before starting a new operation @@ -1534,7 +1533,7 @@ private void cacheResourceIcons(boolean threaded) { protected Void doInBackground() throws Exception { setProgress(0); try { - operation.get(); + operation.perform(); } catch (Exception e) { e.printStackTrace(); } @@ -1544,7 +1543,7 @@ protected Void doInBackground() throws Exception { }; iconCacheWorker.execute(); } else { - operation.get(); + operation.perform(); } } diff --git a/src/org/infinity/util/Operation.java b/src/org/infinity/util/Operation.java new file mode 100644 index 000000000..29f4754f4 --- /dev/null +++ b/src/org/infinity/util/Operation.java @@ -0,0 +1,18 @@ +// Near Infinity - An Infinity Engine Browser and Editor +// Copyright (C) 2001 Jon Olav Hauglid +// See LICENSE.txt for license information + +package org.infinity.util; + +/** + * Represents an operation without explicit input and output. + * + *

+ * This is a functional interface whose functional method is {@link #perform()}. + *

+ */ +@FunctionalInterface +public interface Operation { + /** Performs the operation. */ + void perform(); +} From 1757b798989832a5cf4e203b3c24a9b3e662418f Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 15:19:20 +0200 Subject: [PATCH 24/28] Update Preferences help for "Show Icons in Resource List" option --- src/org/infinity/gui/PreferencesDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/infinity/gui/PreferencesDialog.java b/src/org/infinity/gui/PreferencesDialog.java index 87f2e451e..585afb13b 100644 --- a/src/org/infinity/gui/PreferencesDialog.java +++ b/src/org/infinity/gui/PreferencesDialog.java @@ -179,8 +179,8 @@ public String toString() { + "

Caution: Enabling this option may result in noticeable lags on slower systems.

", AppOption.SHOW_RESOURCE_TREE_ICONS), OptionCheckBox.create(AppOption.SHOW_RESOURCE_LIST_ICONS.getName(), AppOption.SHOW_RESOURCE_LIST_ICONS.getLabel(), - "With this option enabled Near Infinity shows icons alongside names in resource selection lists for " - + "ITM and SPL resources." + "With this option enabled Near Infinity shows icons alongside names in resource selection lists and " + + "tables for ITM and SPL resources as well as portrait thumbnails for characters in GAM resources." + "

Caution: Enabling this option may result in noticeable lags on slower systems.

", AppOption.SHOW_RESOURCE_LIST_ICONS), OptionCheckBox.create(AppOption.HIGHLIGHT_OVERRIDDEN.getName(), AppOption.HIGHLIGHT_OVERRIDDEN.getLabel(), From 5e1e08e7e24b62320973c47735a61d494c7bf8b6 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 18:58:24 +0200 Subject: [PATCH 25/28] Fix display issue with IWD2 CRE spell resource icons --- src/org/infinity/gui/TextListPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/infinity/gui/TextListPanel.java b/src/org/infinity/gui/TextListPanel.java index 96a8ce8ad..192a668a7 100644 --- a/src/org/infinity/gui/TextListPanel.java +++ b/src/org/infinity/gui/TextListPanel.java @@ -350,7 +350,7 @@ public Component getListCellRendererComponent(JList list, Object value, int i final ResourceBitmap.RefEntry entry = (ResourceBitmap.RefEntry) o; final ResourceEntry iconEntry = ResourceFactory.getResourceIcon(entry.getResourceEntry()); if (iconEntry != null) { - setIcon(IconCache.getIcon(entry.getResourceEntry(), IconCache.getDefaultListIconSize())); + setIcon(IconCache.getIcon(iconEntry, IconCache.getDefaultListIconSize())); } } } From 2933128aaed29a7754bc88f40d92f30732a54449 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Wed, 12 Jul 2023 20:16:12 +0200 Subject: [PATCH 26/28] Improve display of (non-)player characters in View tab of GAM resources Shows actual character names instead of garbled internal names (BG2, EE) or internal structure data (BG1, PST). --- src/org/infinity/gui/ViewerUtil.java | 154 +++++++++++++++++++--- src/org/infinity/resource/cre/Viewer.java | 2 +- src/org/infinity/resource/gam/Viewer.java | 53 +++++--- src/org/infinity/resource/sto/Viewer.java | 2 +- 4 files changed, 172 insertions(+), 39 deletions(-) diff --git a/src/org/infinity/gui/ViewerUtil.java b/src/org/infinity/gui/ViewerUtil.java index 38be16fb5..3aca585b1 100644 --- a/src/org/infinity/gui/ViewerUtil.java +++ b/src/org/infinity/gui/ViewerUtil.java @@ -26,6 +26,7 @@ import java.util.Comparator; import java.util.List; import java.util.Locale; +import java.util.function.Function; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; @@ -286,6 +287,19 @@ public static JLabel makeImagePanel(ResourceRef imageRef, boolean searchExtraDir return new JLabel("No " + imageRef.getName().toLowerCase(Locale.ENGLISH), SwingConstants.CENTER); } + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * + * @return Editor for show list of the specified attributes + */ + public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass) { + return new StructListPanel(title, struct, listClass, null, null, null); + } + /** * Creates panel with the name, list control and button for edit selected list element. * @@ -294,21 +308,92 @@ public static JLabel makeImagePanel(ResourceRef imageRef, boolean searchExtraDir * @param listClass List will contain all attributes of {@code struct} with this class * @param attrName Name of attribute in the {@code listClass}, used to show in the list * - * @return Editor for show list of the specified attrubutes + * @return Editor for show list of the specified attributes */ public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, String attrName) { - return new StructListPanel(title, struct, listClass, attrName, null, null); + return new StructListPanel(title, struct, listClass, getAttributeEntry(attrName), null, null); } + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * @param attrName Name of attribute in the {@code listClass}, used to show in the list + * @param renderer A custom renderer for displaying list entries. + * + * @return Editor for show list of the specified attributes + */ public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, String attrName, ListCellRenderer renderer) { - return new StructListPanel(title, struct, listClass, attrName, renderer, null); + return new StructListPanel(title, struct, listClass, getAttributeEntry(attrName), renderer, null); } + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * @param attrName Name of attribute in the {@code listClass}, used to show in the list + * @param renderer A custom renderer for displaying list entries. + * @param listener A custom {@link ListSelectionListener} that reacts to list selection events. + * + * @return Editor for show list of the specified attributes + */ public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, String attrName, ListCellRenderer renderer, ListSelectionListener listener) { - return new StructListPanel(title, struct, listClass, attrName, renderer, listener); + return new StructListPanel(title, struct, listClass, getAttributeEntry(attrName), renderer, listener); + } + + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * @param attrEntry A function that retrieves and returns a {@code StructEntry} to be displayed in the list. + * + * @return Editor for show list of the specified attributes + */ + public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, + AttributeEntry attrEntry) { + return new StructListPanel(title, struct, listClass, attrEntry, null, null); + } + + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * @param attrEntry A function that retrieves and returns a {@code StructEntry} to be displayed in the list. + * @param renderer A custom renderer for displaying list entries. + * + * @return Editor for show list of the specified attributes + */ + public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, + AttributeEntry attrEntry, ListCellRenderer renderer) { + return new StructListPanel(title, struct, listClass, attrEntry, renderer, null); + } + + /** + * Creates panel with the name, list control and button for edit selected list element. + * + * @param title Name of the panel + * @param struct Structure, which attributes must be shown in the returned editor + * @param listClass List will contain all attributes of {@code struct} with this class + * @param attrEntry A function that retrieves and returns a {@code StructEntry} to be displayed in the list. + * @param renderer A custom renderer for displaying list entries. + * @param listener A custom {@link ListSelectionListener} that reacts to list selection events. + * + * @return Editor for show list of the specified attributes + */ + public static JPanel makeListPanel(String title, AbstractStruct struct, Class listClass, + AttributeEntry attrEntry, ListCellRenderer renderer, ListSelectionListener listener) { + return new StructListPanel(title, struct, listClass, attrEntry, renderer, listener); } /** @@ -428,11 +513,41 @@ public static JLabel createUrlLabel(String text, String url, int horizontalAlign return l; } + /** + * Creates a functional object that derives a {@link StructEntry} instance with the specified {@code attrName} + * from a given {@link StructEntry} input object. + * + * @param attrName Name of the attribute to find and return. + * @return A {@link AttributeEntry} object if {@code attrName} parameter is not {@code null}, {@code null} otherwise. + */ + private static AttributeEntry getAttributeEntry(String attrName) { + if (attrName != null) { + return (item) -> (item instanceof AbstractStruct) ? ((AbstractStruct) item).getAttribute(attrName) : item; + } else { + return null; + } + } + private ViewerUtil() { } // -------------------------- INNER CLASSES -------------------------- + /** + * A functional interface that is used to find a {@link StructEntry} attribute from a given resource or substructure + * for display in the list. + * + *

+ * Types: + *

    + *
  • Parameter: {@code StructEntry} that contains the attribute for display.
  • + *
  • Return value: {@code StructEntry} that is used for display in the list.
  • + *
+ *

+ */ + public static interface AttributeEntry extends Function { + } + public static final class StructListPanel extends JPanel implements TableModelListener, ActionListener { private final AbstractStruct struct; private final Class listClass; @@ -441,7 +556,7 @@ public static final class StructListPanel extends JPanel implements TableModelLi private final JButton bOpen = new JButton("View/Edit", Icons.ICON_ZOOM_16.getIcon()); private StructListPanel(String title, AbstractStruct struct, Class listClass, - String attrName, ListCellRenderer renderer, ListSelectionListener listener) { + AttributeEntry attrEntry, ListCellRenderer renderer, ListSelectionListener listener) { super(new BorderLayout(0, 3)); this.struct = struct; this.listClass = listClass; @@ -454,7 +569,7 @@ private StructListPanel(String title, AbstractStruct struct, Class templist = new ArrayList<>(); for (final StructEntry o : struct.getFields()) { @@ -470,7 +585,7 @@ private StructListPanel(String title, AbstractStruct struct, Class list, Object value, int i @Override public String getListValue(Object value) { - if (value instanceof AbstractStruct) { - AbstractStruct effect = (AbstractStruct) value; - StructEntry entry = effect.getAttribute(attrName); + if (value instanceof StructEntry) { + final StructEntry entry = attrEntry.apply((StructEntry) value); if (entry instanceof ResourceRef) { ResourceRef resRef = (ResourceRef) entry; return resRef.getSearchName() + " (" + resRef.getResourceName() + ')'; } else if (entry == null || entry.toString().trim().isEmpty()) { - return effect.toString(); + return value.toString(); } else if (entry != null) { return entry.toString(); } @@ -640,7 +754,7 @@ private Icon loadIcon(AbstractStruct struct) { // Resource-specific icon for (final Class as : SUPPORTED_STRUCTURES) { if (as.isAssignableFrom(struct.getClass())) { - se = struct.getAttribute(attrName); + se = attrEntry.apply(struct); break; } } @@ -659,15 +773,15 @@ private Icon loadIcon(AbstractStruct struct) { } private static final class StructListComparator implements Comparator { - private final String attrName; + private final AttributeEntry attrEntry; - private StructListComparator(String attrName) { - this.attrName = attrName; + private StructListComparator(AttributeEntry attrEntry) { + this.attrEntry = attrEntry; } @Override public int compare(AbstractStruct as1, AbstractStruct as2) { - return as1.getAttribute(attrName).toString().compareTo(as2.getAttribute(attrName).toString()); + return attrEntry.apply(as1).toString().compareTo(attrEntry.apply(as2).toString()); } } diff --git a/src/org/infinity/resource/cre/Viewer.java b/src/org/infinity/resource/cre/Viewer.java index 201251c75..2a580d88b 100644 --- a/src/org/infinity/resource/cre/Viewer.java +++ b/src/org/infinity/resource/cre/Viewer.java @@ -158,7 +158,7 @@ private JPanel makeItemSpellsPanel(CreResource cre) { private JPanel makeItemSpellsPanelIWD2(CreResource cre) { JPanel panel = new JPanel(new GridLayout(1, 2, 6, 0)); panel.add(new ViewerItems(cre)); - panel.add(ViewerUtil.makeListPanel("Spells/abilities (# known)", cre, Iwd2Struct.class, null, + panel.add(ViewerUtil.makeListPanel("Spells/abilities (# known)", cre, Iwd2Struct.class, (String) null, new SpellListRendererIWD2())); panel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3)); return panel; diff --git a/src/org/infinity/resource/gam/Viewer.java b/src/org/infinity/resource/gam/Viewer.java index 5a9db32cc..44d4e99c6 100644 --- a/src/org/infinity/resource/gam/Viewer.java +++ b/src/org/infinity/resource/gam/Viewer.java @@ -12,19 +12,47 @@ import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; -import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import org.infinity.datatype.Flag; +import org.infinity.datatype.ResourceRef; import org.infinity.gui.ViewerUtil; import org.infinity.gui.ViewerUtil.ListValueRenderer; import org.infinity.resource.AbstractStruct; import org.infinity.resource.AbstractVariable; -import org.infinity.resource.Profile; import org.infinity.resource.StructEntry; +import org.infinity.resource.cre.CreResource; final class Viewer extends JPanel { + /** A function that determines the name of (non-)player characters in GAM resources. */ + private static final ViewerUtil.AttributeEntry NPC_ENTRY = (struct) -> { + if (struct instanceof PartyNPC) { + final PartyNPC npc = (PartyNPC) struct; + + StructEntry se = npc.getAttribute(PartyNPC.GAM_NPC_NAME); + if (se != null && !se.toString().isEmpty()) { + // Display character name from PartyNPC structure + return se; + } + + se = npc.getAttribute(PartyNPC.GAM_NPC_CRE_RESOURCE); + if (se instanceof CreResource) { + se = ((CreResource) se).getAttribute(CreResource.CRE_NAME); + if (se != null) { + // Display character name from embedded CRE resource + return se; + } + } else if (se instanceof ResourceRef) { + // Display character info from CRE resref + return se; + } + } + + // Fall-back option: Display original structure + return struct; + }; + private static JPanel makeMiscPanel(GamResource gam) { GridBagLayout gbl = new GridBagLayout(); GridBagConstraints gbc = new GridBagConstraints(); @@ -67,18 +95,8 @@ private static JPanel makeMiscPanel(GamResource gam) { } Viewer(GamResource gam) { - JPanel stats1Panel, stats2Panel; - if (Profile.getEngine() == Profile.Engine.PST || Profile.getEngine() == Profile.Engine.BG1) { - stats1Panel = ViewerUtil.makeListPanel("Non-player characters", gam, NonPartyNPC.class, null); - stats2Panel = ViewerUtil.makeListPanel("Player characters", gam, PartyNPC.class, null); - } else if (Profile.getEngine() == Profile.Engine.IWD || Profile.getEngine() == Profile.Engine.IWD2) { - stats1Panel = ViewerUtil.makeListPanel("Non-player characters", gam, NonPartyNPC.class, PartyNPC.GAM_NPC_NAME); - stats2Panel = ViewerUtil.makeListPanel("Player characters", gam, PartyNPC.class, PartyNPC.GAM_NPC_NAME); - } else { - stats1Panel = ViewerUtil.makeListPanel("Non-player characters", gam, NonPartyNPC.class, - PartyNPC.GAM_NPC_CHARACTER); - stats2Panel = ViewerUtil.makeListPanel("Player characters", gam, PartyNPC.class, PartyNPC.GAM_NPC_CHARACTER); - } + final JPanel stats1Panel = ViewerUtil.makeListPanel("Non-player characters", gam, NonPartyNPC.class, NPC_ENTRY); + final JPanel stats2Panel = ViewerUtil.makeListPanel("Player characters", gam, PartyNPC.class, NPC_ENTRY); JPanel var1Panel = ViewerUtil.makeListPanel("Variables", gam, Variable.class, AbstractVariable.VAR_NAME, new VariableListRenderer()); @@ -95,14 +113,15 @@ private static JPanel makeMiscPanel(GamResource gam) { private static final class VariableListRenderer extends DefaultListCellRenderer implements ListValueRenderer { private VariableListRenderer() { + super(); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { - JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); - label.setText(getListValue(value)); - return label; + super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + setText(getListValue(value)); + return this; } @Override diff --git a/src/org/infinity/resource/sto/Viewer.java b/src/org/infinity/resource/sto/Viewer.java index 5ad5301e9..7d640b255 100644 --- a/src/org/infinity/resource/sto/Viewer.java +++ b/src/org/infinity/resource/sto/Viewer.java @@ -50,7 +50,7 @@ private static JPanel makeFieldPanel(StoResource sto) { } JPanel curePanel = ViewerUtil.makeListPanel("Cures for sale", sto, Cure.class, Cure.STO_CURE_SPELL); JPanel drinkPanel = ViewerUtil.makeListPanel("Drinks for sale", sto, Drink.class, Drink.STO_DRINK_NAME); - JPanel buyPanel = ViewerUtil.makeListPanel("Items purchased", sto, Purchases.class, null); + JPanel buyPanel = ViewerUtil.makeListPanel("Items purchased", sto, Purchases.class); JPanel flagsPanel = ViewerUtil.makeCheckPanel((Flag) sto.getAttribute(StoResource.STO_FLAGS), 1); JPanel fieldPanel = makeFieldPanel(sto); From 408ac6a0273a0638d71a8b649cd9eafbc7fd62ba Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Thu, 13 Jul 2023 12:06:34 +0200 Subject: [PATCH 27/28] Fix scaling issues with very wide preview icons --- src/org/infinity/util/IconCache.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/org/infinity/util/IconCache.java b/src/org/infinity/util/IconCache.java index 44f781e3c..d8bd02ea0 100644 --- a/src/org/infinity/util/IconCache.java +++ b/src/org/infinity/util/IconCache.java @@ -170,10 +170,10 @@ private static synchronized Image getScaledImage(Image image, int size, boolean Image retVal = image; if (image != null) { - if (image.getHeight(null) != size) { + if (image.getWidth(null) != size || image.getHeight(null) != size) { final int dstWidth; final int dstHeight; - if (image.getHeight(null) > size) { + if (image.getWidth(null) > size || image.getHeight(null) > size) { // preserve image aspect ratio dstWidth = (image.getWidth(null) >= image.getHeight(null)) ? size : image.getWidth(null) * size / image.getHeight(null); dstHeight = (image.getHeight(null) >= image.getWidth(null)) ? size : image.getHeight(null) * size / image.getWidth(null); From 128d743109ed6024cdf16d74cf67317884322d23 Mon Sep 17 00:00:00 2001 From: Argent77 <4519923+Argent77@users.noreply.github.com> Date: Fri, 14 Jul 2023 14:57:42 +0200 Subject: [PATCH 28/28] Version 2.4-20230714 --- src/org/infinity/NearInfinity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/infinity/NearInfinity.java b/src/org/infinity/NearInfinity.java index a68fed4d6..dbea922e0 100644 --- a/src/org/infinity/NearInfinity.java +++ b/src/org/infinity/NearInfinity.java @@ -135,7 +135,7 @@ public final class NearInfinity extends JFrame implements ActionListener, ViewableContainer { // the current Near Infinity version - private static final String VERSION = "v2.4-20230625"; + private static final String VERSION = "v2.4-20230714"; // the minimum supported Java version private static final int JAVA_VERSION_MIN = 8;