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
diff --git a/README.md b/README.md
index 7c3d15237..455a2ddbe 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,16 @@
-[![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)
# 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)
diff --git a/src/org/infinity/AppOption.java b/src/org/infinity/AppOption.java
index 98541de6a..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);
@@ -757,31 +763,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 +869,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..dbea922e0 100644
--- a/src/org/infinity/NearInfinity.java
+++ b/src/org/infinity/NearInfinity.java
@@ -119,10 +119,12 @@
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;
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;
@@ -133,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;
@@ -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;
@@ -475,6 +478,7 @@ public void windowClosing(WindowEvent event) {
quit();
}
});
+
try {
LookAndFeelInfo info = BrowserMenuBar.getInstance().getOptions().getLookAndFeel();
UIManager.setLookAndFeel(info.getClassName());
@@ -483,6 +487,8 @@ public void windowClosing(WindowEvent event) {
e.printStackTrace();
}
+ cacheResourceIcons(true);
+
statusBar = new StatusBar();
ResourceTreeModel treemodel = ResourceFactory.getResourceTreeModel();
updateWindowTitle();
@@ -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);
}
@@ -1109,7 +1115,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 +1123,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;
}
@@ -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();
@@ -1387,13 +1395,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 +1409,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());
@@ -1459,6 +1467,86 @@ 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 Operation 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;
+ }
+ IconCache.get(e, size);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ };
+
+ // 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.perform();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ setProgress(100);
+ return null;
+ }
+ };
+ iconCacheWorker.execute();
+ } else {
+ operation.perform();
+ }
+ }
+
// -------------------------- INNER CLASSES --------------------------
private static final class Options {
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/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/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/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/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 eaba73182..585afb13b 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;
@@ -57,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;
@@ -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 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(),
"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."
@@ -255,7 +265,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 +288,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 +307,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 +323,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 +339,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 +355,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 +371,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(
@@ -687,11 +704,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()) {
@@ -746,7 +764,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() {
@@ -1158,6 +1176,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" };
@@ -1223,7 +1326,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/ResourceTree.java b/src/org/infinity/gui/ResourceTree.java
index 2bba1da0d..236eb6581 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;
@@ -33,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;
@@ -55,6 +59,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 +708,18 @@ public void popupMenuCanceled(PopupMenuEvent event) {
}
private static final class ResourceTreeRenderer extends DefaultTreeCellRenderer {
+ private final int iconSize;
+
private ResourceTreeRenderer() {
+ super();
+ 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);
}
@Override
@@ -713,6 +729,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 +743,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/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/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/TextListPanel.java b/src/org/infinity/gui/TextListPanel.java
index a24b32c30..192a668a7 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,43 @@
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;
-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 extends E> values) {
- this(values, true);
+ this(values, true, false);
}
public TextListPanel(List extends E> values, boolean sortValues) {
+ this(values, sortValues, false);
+ }
+
+ public TextListPanel(List extends E> 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 +83,8 @@ public TextListPanel(List extends E> 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 +100,7 @@ public TextListPanel(List extends E> 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 +324,38 @@ 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) {
+ // 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(iconEntry, 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 b36c1573f..3aca585b1 100644
--- a/src/org/infinity/gui/ViewerUtil.java
+++ b/src/org/infinity/gui/ViewerUtil.java
@@ -21,13 +21,16 @@
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;
import java.util.Locale;
+import java.util.function.Function;
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 +54,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;
@@ -236,11 +243,11 @@ 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) {
+ 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());
@@ -280,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 extends StructEntry> listClass) {
+ return new StructListPanel(title, struct, listClass, null, null, null);
+ }
+
/**
* Creates panel with the name, list control and button for edit selected list element.
*
@@ -288,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 extends StructEntry> 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 extends StructEntry> listClass,
String attrName, ListCellRenderer
+ */
+ public static interface AttributeEntry extends Function {
+ }
+
public static final class StructListPanel extends JPanel implements TableModelListener, ActionListener {
private final AbstractStruct struct;
private final Class extends StructEntry> listClass;
@@ -435,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 extends StructEntry> listClass,
- String attrName, ListCellRenderer renderer, ListSelectionListener listener) {
+ AttributeEntry attrEntry, ListCellRenderer renderer, ListSelectionListener listener) {
super(new BorderLayout(0, 3));
this.struct = struct;
this.listClass = listClass;
@@ -448,7 +569,7 @@ private StructListPanel(String title, AbstractStruct struct, Class extends Str
if (renderer != null) {
list.setCellRenderer(renderer);
}
- if (attrName == null) {
+ if (attrEntry == null) {
for (final StructEntry o : struct.getFields()) {
if (o.getClass() == listClass) {
listModel.addElement(o);
@@ -456,7 +577,7 @@ private StructListPanel(String title, AbstractStruct struct, Class extends Str
}
} else {
if (renderer == null) {
- list.setCellRenderer(new StructListRenderer(attrName));
+ list.setCellRenderer(new StructListRenderer(attrEntry));
}
final List templist = new ArrayList<>();
for (final StructEntry o : struct.getFields()) {
@@ -464,7 +585,7 @@ private StructListPanel(String title, AbstractStruct struct, Class extends Str
templist.add((AbstractStruct) o);
}
}
- Collections.sort(templist, new StructListComparator(attrName));
+ Collections.sort(templist, new StructListComparator(attrEntry));
for (AbstractStruct s : templist) {
listModel.addElement(s);
}
@@ -554,31 +675,48 @@ public static interface ListValueRenderer {
String getListValue(Object value);
}
- private static final class StructListRenderer extends DefaultListCellRenderer implements ListValueRenderer {
- private final String attrName;
-
- private StructListRenderer(String attrName) {
- this.attrName = attrName;
+ 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 AttributeEntry attrEntry;
+ private final boolean showIcons;
+
+ public StructListRenderer(AttributeEntry attrEntry) {
+ this.attrEntry = attrEntry;
+ 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
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();
}
@@ -587,18 +725,63 @@ 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 extends AbstractStruct> as : SUPPORTED_STRUCTURES) {
+ if (as.isAssignableFrom(struct.getClass())) {
+ se = attrEntry.apply(struct);
+ 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 {
- 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/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/BamOptionsDialog.java b/src/org/infinity/gui/converter/BamOptionsDialog.java
index 0a619bdfd..fc6182169 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();
}
@@ -371,9 +374,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);
}
}
@@ -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..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");
}
}
}
@@ -4146,15 +4145,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);
}
}
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/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/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 dee582eeb..36f263258 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;
}
@@ -205,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 10c8dc994..63c7cd3cc 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.
@@ -115,4 +157,4 @@ protected OptionBase setParent(OptionBase parent) {
*
*/
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 3e0ced9a0..08e7de15d 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;
}
@@ -322,4 +317,4 @@ public void fireOnSelect() {
}
}
}
-}
\ No newline at end of file
+}
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/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 extends Resource> 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/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));
diff --git a/src/org/infinity/resource/are/Viewer.java b/src/org/infinity/resource/are/Viewer.java
index 1d80a82b6..0ab255bcd 100644
--- a/src/org/infinity/resource/are/Viewer.java
+++ b/src/org/infinity/resource/are/Viewer.java
@@ -13,10 +13,12 @@
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;
import javax.swing.JScrollPane;
+import javax.swing.ScrollPaneConstants;
import org.infinity.datatype.Flag;
import org.infinity.gui.ViewerUtil;
@@ -54,12 +56,30 @@ 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;
}
+ 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(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+ scrollPane.setBorder(BorderFactory.createEmptyBorder());
+ scrollPane.setPreferredSize(scrollPane.getMinimumSize());
+
+ return scrollPane;
+ }
+
Viewer(AreResource are) {
this.are = are;
@@ -70,7 +90,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
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 extends LayerObject> list = layerManager.getLayerObjects(Settings.stackingToLayer(type));
+ for (final LayerStackingType layer : Settings.LIST_LAYER_ORDER) {
+ final List extends LayerObject> 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/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/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/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/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 000000000..e6c3c7b71
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_Container1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_Container2.png b/src/org/infinity/resource/are/viewer/icon/itm_Container2.png
new file mode 100644
index 000000000..1da69f4eb
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_Container2.png differ
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 000000000..a4a378d4f
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch2.png b/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch2.png
new file mode 100644
index 000000000..717a31d23
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_ContainerLaunch2.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed1.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed1.png
new file mode 100644
index 000000000..caa2e4656
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed1.png differ
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 000000000..0b791e50f
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorClosed2.png differ
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 000000000..f9bc13e56
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch2.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch2.png
new file mode 100644
index 000000000..e3b2cb4b2
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorLaunch2.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen1.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen1.png
new file mode 100644
index 000000000..3b397c79f
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen2.png b/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen2.png
new file mode 100644
index 000000000..bcae0d834
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_DoorOpen2.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_Region1.png b/src/org/infinity/resource/are/viewer/icon/itm_Region1.png
new file mode 100644
index 000000000..fb74edc6f
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_Region1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_Region2.png b/src/org/infinity/resource/are/viewer/icon/itm_Region2.png
new file mode 100644
index 000000000..a24197536
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_Region2.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation1.png b/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation1.png
new file mode 100644
index 000000000..13b0b5203
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation2.png b/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation2.png
new file mode 100644
index 000000000..9809fb6d6
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_RegionActivation2.png differ
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 000000000..21a8ba68a
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker1.png differ
diff --git a/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker2.png b/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker2.png
new file mode 100644
index 000000000..b7f6c7d74
Binary files /dev/null and b/src/org/infinity/resource/are/viewer/icon/itm_RegionSpeaker2.png differ
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/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/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/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/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/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
+}
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/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) {
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/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 38c0b97ab..ad7614481 100644
--- a/src/org/infinity/resource/itm/Viewer.java
+++ b/src/org/infinity/resource/itm/Viewer.java
@@ -13,11 +13,13 @@
import java.nio.ByteBuffer;
import javax.swing.BorderFactory;
+import javax.swing.BoxLayout;
import javax.swing.JComponent;
import javax.swing.JLabel;
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;
@@ -36,28 +38,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.setHorizontalScrollBarPolicy(ScrollPaneConstants.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);
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/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 cf45f7ef4..b87304262 100644
--- a/src/org/infinity/resource/spl/Viewer.java
+++ b/src/org/infinity/resource/spl/Viewer.java
@@ -16,8 +16,10 @@
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;
import org.infinity.datatype.ResourceRef;
import org.infinity.gui.ViewerUtil;
import org.infinity.resource.AbstractAbility;
@@ -140,13 +142,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.setHorizontalScrollBarPolicy(ScrollPaneConstants.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);
diff --git a/src/org/infinity/resource/sto/Viewer.java b/src/org/infinity/resource/sto/Viewer.java
index fee7abbf2..7d640b255 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;
}
@@ -44,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);
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/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/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);
}
}
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/IconCache.java b/src/org/infinity/util/IconCache.java
new file mode 100644
index 000000000..d8bd02ea0
--- /dev/null
+++ b/src/org/infinity/util/IconCache.java
@@ -0,0 +1,255 @@
+// 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.graphics.GraphicsResource;
+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 synchronized 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 synchronized void remove(ResourceEntry entry) {
+ if (entry != null) {
+ CACHE.remove(entry);
+ }
+ }
+
+ /** Removes all entries from the cache. */
+ public static synchronized void clearCache() {
+ CACHE.clear();
+ DEFAULT_ICONS.clear();
+ }
+
+ /**
+ * 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;
+ }
+
+ 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.getWidth(null) != size || image.getHeight(null) != size) {
+ final int dstWidth;
+ final int dstHeight;
+ 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);
+ } 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 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;
+ 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) {
+ retVal = 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) {
+ retVal = tmp;
+ i = count;
+ }
+ }
+ }
+ }
+ }
+
+ return retVal;
+ }
+
+ /** Returns the specified BMP resource as {@link Image} object. */
+ private static synchronized Image getBmpImage(ResourceEntry bmpEntry) {
+ Image retVal = null;
+
+ if (bmpEntry != null) {
+ try {
+ final GraphicsResource res = new GraphicsResource(bmpEntry);
+ retVal = res.getImage();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ return retVal;
+ }
+}
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());
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()}.
+ *