Skip to content

Commit

Permalink
ARE View tab: Link to a default area script if field is empty in ARE …
Browse files Browse the repository at this point in the history
…resource

Some games seem to fall back to a default area script if the area script
field is empty in the ARE resource. Affected games are:
- IWD
- IWD2
  • Loading branch information
Argent77 committed Nov 12, 2024
1 parent 0c96cd6 commit dea2da3
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 10 deletions.
99 changes: 91 additions & 8 deletions src/org/infinity/gui/LinkButton.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package org.infinity.gui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
Expand All @@ -16,6 +17,7 @@
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.SwingConstants;
import javax.swing.UIManager;

import org.infinity.NearInfinity;
import org.infinity.datatype.ResourceRef;
Expand All @@ -27,11 +29,18 @@
/**
* A JLabel-based control which supports either internal game resources or external URLs.
*/
final public class LinkButton extends JLabel implements MouseListener, ActionListener {
public class LinkButton extends JLabel implements MouseListener, ActionListener {
private static final String CMD_OPEN = "OPEN"; // open resource in same window
private static final String CMD_OPEN_NEW = "OPEN_NEW"; // open resource in new window
private static final String CMD_BROWSE = "BROWSE"; // open URL in system-default browser

/** Tooltip text if an alternate resource reference is used for the link button. */
private static final String TOOLTIP_ALTERNATE_RESREF = "No resource assigned: Showing default resource.";

/** Color of the linked text if an alternate resource reference is used (for light and dark L&F themes). */
private static final Color LINK_COLOR_ALTERNATE_RESREF_LIGHT = new Color(0x800000);
private static final Color LINK_COLOR_ALTERNATE_RESREF_DARK = new Color(0xC04000);

private final List<ActionListener> listeners = new ArrayList<>();

private ResourceEntry entry;
Expand Down Expand Up @@ -60,6 +69,20 @@ public LinkButton(ResourceRef resourceRef, int maxLength) {
setResource(resourceRef, maxLength);
}

/**
* Creates a link button which points to an internal game resource as specified by the argument.
*
* @param resourceRef The game resource as ResourceRef object.
* @param maxLength Max. number of characters displayed in the label text. Full string is displayed as tooltip
* instead.
* @param isAlternate Specify {@code true} to change link color and tooltip to indicate that a fallback resource is
* used.
*/
public LinkButton(ResourceRef resourceRef, int maxLength, boolean isAlternate) {
setHorizontalAlignment(SwingConstants.LEFT);
setResource(resourceRef, maxLength, isAlternate);
}

/**
* Creates a link button which points to an internal game resource as specified by the argument.
*
Expand All @@ -77,9 +100,22 @@ public LinkButton(String resourceName) {
* instead.
*/
public LinkButton(String resourceName, int maxLength) {
this(resourceName, maxLength, false);
}

/**
* Creates a link button which points to an internal game resource as specified by the argument.
*
* @param resourceName The game resource as string.
* @param maxLength Max. number of characters displayed in the label text. Full string is displayed as tooltip
* instead.
* @param isAlternate Specify {@code true} to change link color and tooltip to indicate that a fallback resource is
* used.
*/
public LinkButton(String resourceName, int maxLength, boolean isAlternate) {
super();
setHorizontalAlignment(SwingConstants.LEFT);
setResource(resourceName, maxLength);
setResource(resourceName, maxLength, isAlternate);
}

/**
Expand Down Expand Up @@ -113,8 +149,14 @@ public void setResource(ResourceRef resourceRef) {

/** Creates a link from the specified resource reference. */
public void setResource(ResourceRef resourceRef, int maxLength) {
setResource(resourceRef, maxLength, false);
}

/** Creates a link from the specified resource reference. */
public void setResource(ResourceRef resourceRef, int maxLength, boolean isAlternate) {
if (resourceRef != null) {
setResource(ResourceFactory.getResourceEntry(resourceRef.getResourceName()), resourceRef.toString(), maxLength);
setResource(ResourceFactory.getResourceEntry(resourceRef.getResourceName()), resourceRef.toString(), maxLength,
isAlternate);
} else {
setResource(null, null, maxLength);
}
Expand All @@ -127,16 +169,28 @@ public void setResource(String resourceName) {

/** Attempts to create a link from the specified resource name. */
public void setResource(String resourceName, int maxLength) {
setResource(ResourceFactory.getResourceEntry(resourceName), resourceName, maxLength);
setResource(resourceName, maxLength, false);
}

/**
* Attempts to create a link from the specified resource name. Link color and tooltip are changed if
* {@code isAlternate} is {@code true}.
*/
public void setResource(String resourceName, int maxLength, boolean isAlternate) {
setResource(ResourceFactory.getResourceEntry(resourceName), resourceName, maxLength, isAlternate);
}

private void setResource(ResourceEntry entry, String resourceName, int maxLength) {
setResource(entry, resourceName, maxLength, false);
}

private void setResource(ResourceEntry entry, String resourceName, int maxLength, boolean isAlternate) {
isResource = true;
removeActionListener(this);
this.entry = entry;
if (entry != null) {
addActionListener(this);
setLink(resourceName, entry.getResourceName(), true, maxLength);
setLink(resourceName, entry.getResourceName(), true, maxLength, isAlternate);
setEnabled(true);
// setToolTipText(null);
} else {
Expand All @@ -148,22 +202,40 @@ private void setResource(ResourceEntry entry, String resourceName, int maxLength

/** Sets link or label text, depending on arguments. */
private void setLink(String text, String resource, boolean asLink, int maxLength) {
setLink(text, resource, asLink, maxLength, false);
}

/** Sets link or label text, depending on arguments. */
private void setLink(String text, String resource, boolean asLink, int maxLength, boolean isAlternate) {
removeMouseListener(this);
setCursor(null);

if (text == null) {
text = resource;
}
String toolTip = null;

String toolTip = isAlternate ? TOOLTIP_ALTERNATE_RESREF : null;
Color color = isAlternate ? getAlternateLinkColor() : null;

if (maxLength > 0 && text != null && text.length() > maxLength) {
toolTip = text;
if (toolTip == null || toolTip.isEmpty()) {
toolTip = text;
} else {
toolTip = text + " - " + toolTip;
}
text = text.substring(0, maxLength) + "...";
}

if (!asLink) {
setText(text);
} else if (resource != null && !resource.isEmpty()) {
setText("<html><a href=\"" + resource + "\">" + text + "</a></html");
final String colorAttr;
if (color != null) {
colorAttr = String.format(" color=\"#%02X%02X%02X\"", color.getRed(), color.getGreen(), color.getBlue());
} else {
colorAttr = "";
}
setText("<html><a" + colorAttr + " href=\"" + resource + "\">" + text + "</a></html");
addMouseListener(this);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
} else {
Expand All @@ -175,6 +247,17 @@ private void setLink(String text, String resource, boolean asLink, int maxLength
}
}

/** Returns a color value that is suitable for the current L&F UI scheme. */
private static Color getAlternateLinkColor() {
final Color color = UIManager.getColor("Panel.background");
final int brightness = Math.max(Math.max(color.getRed(), color.getGreen()), color.getBlue());
if (brightness >= 0xa0) {
return LINK_COLOR_ALTERNATE_RESREF_LIGHT;
} else {
return LINK_COLOR_ALTERNATE_RESREF_DARK;
}
}

/** Creates a link to an external URL. */
public void setUrl(String text, String url) {
setUrl(text, url, 0);
Expand Down
2 changes: 1 addition & 1 deletion src/org/infinity/resource/Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public enum Engine {
PST,
/** Includes IWD, IWDHoW and IWDTotLM. */
IWD,
/** Includes IWD2. */
/** Includes IWD2 and IWD2EE. */
IWD2,
/** Includes BG1EE, BG1SoD, BG2EE, IWDEE, PSTEE and EET. */
EE,
Expand Down
22 changes: 21 additions & 1 deletion src/org/infinity/resource/are/Viewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;

import org.infinity.datatype.Flag;
import org.infinity.datatype.ResourceRef;
import org.infinity.gui.LinkButton;
import org.infinity.gui.ViewerUtil;
import org.infinity.icon.Icons;
import org.infinity.resource.Profile;
import org.infinity.resource.ResourceFactory;
import org.infinity.resource.are.viewer.AreaViewer;

final class Viewer extends JPanel implements ActionListener {
Expand All @@ -47,7 +52,22 @@ private JComponent makeFieldPanel() {
ViewerUtil.addLabelFieldPair(fieldPanel, are.getAttribute(AreResource.ARE_PROBABILITY_SNOW), gbl, gbc, true);
ViewerUtil.addLabelFieldPair(fieldPanel, are.getAttribute(AreResource.ARE_PROBABILITY_FOG), gbl, gbc, true);
ViewerUtil.addLabelFieldPair(fieldPanel, are.getAttribute(AreResource.ARE_PROBABILITY_LIGHTNING), gbl, gbc, true);
ViewerUtil.addLabelFieldPair(fieldPanel, are.getAttribute(AreResource.ARE_AREA_SCRIPT), gbl, gbc, true);

// Special: IWD and IWD2 may fall back to a default area script if the script field is empty in the ARE resource
final boolean allowAlternate = (Profile.getEngine() == Profile.Engine.IWD) ||
(Profile.getEngine() == Profile.Engine.IWD2);
final ResourceRef scriptRef = (ResourceRef) are.getAttribute(AreResource.ARE_AREA_SCRIPT);
String scriptResref = scriptRef.getResourceName();
boolean isAlternate = false;
if (allowAlternate && scriptRef.isEmpty()) {
final String areString = are.getResourceEntry().getResourceRef() + ".BCS";
if (ResourceFactory.resourceExists(areString)) {
scriptResref = areString;
isAlternate = true;
}
}
ViewerUtil.addLabelFieldPair(fieldPanel, new JLabel(AreResource.ARE_AREA_SCRIPT),
new LinkButton(scriptResref, 0, isAlternate), gbl, gbc, true);

JButton bView = new JButton("View Area", Icons.ICON_VOLUME_16.getIcon());
bView.setActionCommand(CMD_VIEWAREA);
Expand Down

0 comments on commit dea2da3

Please sign in to comment.