diff --git a/src/main/java/net/rptools/maptool/client/AppActions.java b/src/main/java/net/rptools/maptool/client/AppActions.java index 3e6e36cdcf..8f23aa05f1 100644 --- a/src/main/java/net/rptools/maptool/client/AppActions.java +++ b/src/main/java/net/rptools/maptool/client/AppActions.java @@ -1578,6 +1578,44 @@ protected void executeAction() { } }; + /** This is the menu option turns the lumens overlay on and off. */ + public static final Action TOGGLE_LUMENS_OVERLAY = + new ZoneAdminClientAction() { + { + init("action.showLumensOverlay"); + } + + @Override + public boolean isSelected() { + return AppState.isShowLumensOverlay(); + } + + @Override + protected void executeAction() { + AppState.setShowLumensOverlay(!AppState.isShowLumensOverlay()); + MapTool.getFrame().refresh(); + } + }; + + /** This is the menu option turns the lumens overlay on and off. */ + public static final Action TOGGLE_SHOW_LIGHTS = + new ZoneAdminClientAction() { + { + init("action.showLights"); + } + + @Override + public boolean isSelected() { + return AppState.isShowLights(); + } + + @Override + protected void executeAction() { + AppState.setShowLights(!AppState.isShowLights()); + MapTool.getFrame().refresh(); + } + }; + /** Start entering text into the chat field */ public static final String CHAT_COMMAND_ID = "action.sendChat"; diff --git a/src/main/java/net/rptools/maptool/client/AppPreferences.java b/src/main/java/net/rptools/maptool/client/AppPreferences.java index 95291802a8..6fa5ed8662 100644 --- a/src/main/java/net/rptools/maptool/client/AppPreferences.java +++ b/src/main/java/net/rptools/maptool/client/AppPreferences.java @@ -84,11 +84,8 @@ public class AppPreferences { private static final String KEY_AURA_OVERLAY_OPACITY = "auraOverlayOpacity"; private static final int DEFAULT_AURA_OVERLAY_OPACITY = 60; - private static final String KEY_LIGHT_OVERLAY_OPACITY = "lightOverlayOpacity"; - private static final int DEFAULT_LIGHT_OVERLAY_OPACITY = 60; - - private static final String KEY_DARKNESS_OVERLAY_OPACITY = "darknessOverlayOpacity"; - private static final int DEFAULT_DARKNESS_OVERLAY_OPACITY = 200; + private static final String KEY_LUMENS_OVERLAY_OPACITY = "lumensOverlayOpacity"; + private static final int DEFAULT_LUMENS_OVERLAY_OPACITY = 120; private static final String KEY_FOG_OVERLAY_OPACITY = "fogOverlayOpacity"; private static final int DEFAULT_FOG_OVERLAY_OPACITY = 100; @@ -341,21 +338,12 @@ public static int getAuraOverlayOpacity() { return range0to255(value); } - public static void setLightOverlayOpacity(int size) { - prefs.putInt(KEY_LIGHT_OVERLAY_OPACITY, range0to255(size)); - } - - public static int getLightOverlayOpacity() { - int value = prefs.getInt(KEY_LIGHT_OVERLAY_OPACITY, DEFAULT_LIGHT_OVERLAY_OPACITY); - return range0to255(value); - } - - public static void setDarknessOverlayOpacity(int size) { - prefs.putInt(KEY_DARKNESS_OVERLAY_OPACITY, range0to255(size)); + public static void setLumensOverlayOpacity(int size) { + prefs.putInt(KEY_LUMENS_OVERLAY_OPACITY, range0to255(size)); } - public static int getDarknessOverlayOpacity() { - int value = prefs.getInt(KEY_DARKNESS_OVERLAY_OPACITY, DEFAULT_DARKNESS_OVERLAY_OPACITY); + public static int getLumensOverlayOpacity() { + int value = prefs.getInt(KEY_LUMENS_OVERLAY_OPACITY, DEFAULT_LUMENS_OVERLAY_OPACITY); return range0to255(value); } diff --git a/src/main/java/net/rptools/maptool/client/AppState.java b/src/main/java/net/rptools/maptool/client/AppState.java index fe1aa578b0..21ccb85231 100644 --- a/src/main/java/net/rptools/maptool/client/AppState.java +++ b/src/main/java/net/rptools/maptool/client/AppState.java @@ -36,6 +36,8 @@ public class AppState { private static boolean enforceNotification = false; private static File campaignFile; private static int gridSize = 1; + private static boolean showLumensOverlay = true; + private static boolean showLights = false; private static boolean showAsPlayer = false; private static boolean showLightSources = false; private static boolean zoomLocked = false; @@ -172,6 +174,22 @@ public static boolean getShowTextLabels() { return showTextLabels; } + public static boolean isShowLights() { + return showLights; + } + + public static void setShowLights(boolean show) { + showLights = show; + } + + public static boolean isShowLumensOverlay() { + return showLumensOverlay; + } + + public static void setShowLumensOverlay(boolean show) { + showLumensOverlay = show; + } + public static boolean isShowAsPlayer() { return showAsPlayer; } diff --git a/src/main/java/net/rptools/maptool/client/functions/getInfoFunction.java b/src/main/java/net/rptools/maptool/client/functions/getInfoFunction.java index 2c33faefcf..8b515cad5b 100644 --- a/src/main/java/net/rptools/maptool/client/functions/getInfoFunction.java +++ b/src/main/java/net/rptools/maptool/client/functions/getInfoFunction.java @@ -327,8 +327,6 @@ private JsonObject getCampaignInfo() throws ParserException { linfo.addProperty("name", ls.getName()); linfo.addProperty("max range", ls.getMaxRange()); linfo.addProperty("type", ls.getType().toString()); - linfo.addProperty("shape", ls.getShapeType().toString()); - linfo.addProperty("lumens", ls.getLumens()); linfo.addProperty("scale", ls.isScaleWithToken()); // List lights = new ArrayList(); // for (Light light : ls.getLightList()) { diff --git a/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java b/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java index cff7337ecf..605e5b8af1 100644 --- a/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java +++ b/src/main/java/net/rptools/maptool/client/ui/AppMenuBar.java @@ -270,6 +270,16 @@ protected JMenu createViewMenu() { gridSizeMenu.add(gridSize5); menu.add(gridSizeMenu); + menu.addSeparator(); + JCheckBoxMenuItem toggleLumensOverlay = + new RPCheckBoxMenuItem(AppActions.TOGGLE_LUMENS_OVERLAY, menu); + toggleLumensOverlay.setSelected(AppState.isShowLumensOverlay()); + menu.add(toggleLumensOverlay); + JCheckBoxMenuItem toggleShowLights = + new RPCheckBoxMenuItem(AppActions.TOGGLE_SHOW_LIGHTS, menu); + toggleShowLights.setSelected(AppState.isShowLights()); + menu.add(toggleShowLights); + menu.addSeparator(); menu.add(new RPCheckBoxMenuItem(AppActions.TOGGLE_DRAW_MEASUREMENTS, menu)); menu.add(new RPCheckBoxMenuItem(AppActions.TOGGLE_DOUBLE_WIDE, menu)); diff --git a/src/main/java/net/rptools/maptool/client/ui/campaignproperties/CampaignPropertiesDialog.java b/src/main/java/net/rptools/maptool/client/ui/campaignproperties/CampaignPropertiesDialog.java index b10e4bad62..7810d9b18b 100644 --- a/src/main/java/net/rptools/maptool/client/ui/campaignproperties/CampaignPropertiesDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/campaignproperties/CampaignPropertiesDialog.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.regex.Pattern; import javax.swing.*; import net.rptools.lib.FileUtil; import net.rptools.maptool.client.AppConstants; @@ -309,14 +310,14 @@ private String updateSightPanel(Map sightTypeMap) { Color color = (Color) light.getPaint().getPaint(); builder.append(toHex(color)); } - + final var lumens = light.getLumens(); + if (lumens >= 0) { + builder.append('+'); + } + builder.append(Integer.toString(lumens, 10)); builder.append(' '); } } - - if (source.getLumens() != 0) { - builder.append("lumens=").append(source.getLumens()).append(' '); - } } builder.append('\n'); } @@ -387,9 +388,13 @@ private String updateLightPanel(Map> lightSources Color color = (Color) light.getPaint().getPaint(); builder.append(toHex(color)); } - } - if (lightSource.getLumens() != 0) { - builder.append(" lumens=").append(lightSource.getLumens()); + if (lightSource.getType() == LightSource.Type.NORMAL) { + final var lumens = light.getLumens(); + if (lumens >= 0) { + builder.append('+'); + } + builder.append(Integer.toString(lumens, 10)); + } } builder.append('\n'); } @@ -507,33 +512,51 @@ private void commitSightMap(final String text) { errmsg = "msg.error.mtprops.sight.multiplier"; // (ditto) magnifier = StringUtil.parseDecimal(toBeParsed); } else if (arg.startsWith("r")) { // XXX Why not "r=#" instead of "r#"?? - Color personalLightColor = null; toBeParsed = arg.substring(1); - - split = toBeParsed.indexOf('#'); - if (split > 0) { - String colorString = toBeParsed.substring(split); // Keep the '#' - toBeParsed = toBeParsed.substring(0, split); - personalLightColor = Color.decode(colorString); - } - errmsg = "msg.error.mtprops.sight.range"; - pLightRange = StringUtil.parseDecimal(toBeParsed); - if (personalLight == null) { - personalLight = new LightSource(); - } - DrawableColorPaint personalLightPaint = - personalLightColor != null ? new DrawableColorPaint(personalLightColor) : null; - personalLight.add(new Light(shape, 0, pLightRange, arc, personalLightPaint)); - personalLight.setScaleWithToken(scaleWithToken); - } else if (arg.toUpperCase().startsWith("LUMENS=")) { - if (personalLight != null) { - personalLight.setLumens(Integer.parseInt(arg.substring(7))); + final var rangeRegex = Pattern.compile("([^#+-]*)(#[0-9a-fA-F]+)?([+-]\\d*)?"); + final var matcher = rangeRegex.matcher(toBeParsed); + if (matcher.find()) { + pLightRange = StringUtil.parseDecimal(matcher.group(1)); + final var colorString = matcher.group(2); + final var lumensString = matcher.group(3); + // Note that Color.decode() _wants_ the leading "#", otherwise it might not treat + // the value as a hex code. + Color personalLightColor = null; + if (colorString != null) { + personalLightColor = Color.decode(colorString); + } + int perRangeLumens = 100; + if (lumensString != null) { + perRangeLumens = Integer.parseInt(lumensString, 10); + if (perRangeLumens == 0) { + errlog.add( + I18N.getText("msg.error.mtprops.sight.zerolumens", reader.getLineNumber())); + perRangeLumens = 100; + } + } + + if (personalLight == null) { + personalLight = new LightSource(); + personalLight.setType(LightSource.Type.NORMAL); + } + personalLight.add( + new Light( + shape, + 0, + pLightRange, + arc, + personalLightColor == null + ? null + : new DrawableColorPaint(personalLightColor), + perRangeLumens, + false, + false)); + personalLight.setScaleWithToken(scaleWithToken); } else { - errlog.add( - I18N.getText( - "msg.error.mtprops.sight.lumensWithoutLight", reader.getLineNumber())); + throw new ParseException( + String.format("Unrecognized personal light syntax: %s", arg), 0); } } else if (arg.startsWith("arc=") && arg.length() > 4) { toBeParsed = arg.substring(4); @@ -669,16 +692,6 @@ private Map> commitLightMap( lightSource.setScaleWithToken(true); continue; } - // Lumens designation - if (arg.toUpperCase().startsWith("LUMENS=")) { - try { - lightSource.setLumens(Integer.parseInt(arg.substring(7))); - continue; - } catch (NullPointerException noe) { - errlog.add( - I18N.getText("msg.error.mtprops.light.lumens", reader.getLineNumber(), arg)); - } - } // Shape designation ? try { shape = ShapeType.valueOf(arg.toUpperCase()); @@ -725,14 +738,32 @@ private Map> commitLightMap( } continue; } + Color color = null; + int perRangeLumens = 100; distance = arg; - split = arg.indexOf('#'); - if (split > 0) { - String colorString = arg.substring(split); // Keep the '#' - distance = arg.substring(0, split); - color = Color.decode(colorString); + + final var rangeRegex = Pattern.compile("([^#+-]*)(#[0-9a-fA-F]+)?([+-]\\d*)?"); + final var matcher = rangeRegex.matcher(arg); + if (matcher.find()) { + distance = matcher.group(1); + final var colorString = matcher.group(2); + final var lumensString = matcher.group(3); + // Note that Color.decode() _wants_ the leading "#", otherwise it might not treat the + // value as a hex code. + if (colorString != null) { + color = Color.decode(colorString); + } + if (lumensString != null) { + perRangeLumens = Integer.parseInt(lumensString, 10); + if (perRangeLumens == 0) { + errlog.add( + I18N.getText("msg.error.mtprops.light.zerolumens", reader.getLineNumber())); + perRangeLumens = 100; + } + } } + boolean isAura = lightSource.getType() == LightSource.Type.AURA; if (!isAura && (gmOnly || owner)) { errlog.add(I18N.getText("msg.error.mtprops.light.gmOrOwner", reader.getLineNumber())); @@ -747,7 +778,8 @@ private Map> commitLightMap( offset, StringUtil.parseDecimal(distance), arc, - color != null ? new DrawableColorPaint(color) : null, + color == null ? null : new DrawableColorPaint(color), + perRangeLumens, gmOnly, owner); lightSource.add(t); diff --git a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java index 2780990d00..accaa2d518 100644 --- a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java +++ b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialog.java @@ -97,8 +97,7 @@ public class PreferencesDialog extends JDialog { private final JSpinner haloLineWidthSpinner; private final JSpinner haloOverlayOpacitySpinner; private final JSpinner auraOverlayOpacitySpinner; - private final JSpinner lightOverlayOpacitySpinner; - private final JSpinner darknessOverlayOpacitySpinner; + private final JSpinner lumensOverlayOpacitySpinner; private final JSpinner fogOverlayOpacitySpinner; private final JCheckBox useHaloColorAsVisionOverlayCheckBox; private final JCheckBox autoRevealVisionOnGMMoveCheckBox; @@ -334,8 +333,7 @@ public PreferencesDialog() { haloLineWidthSpinner = panel.getSpinner("haloLineWidthSpinner"); haloOverlayOpacitySpinner = panel.getSpinner("haloOverlayOpacitySpinner"); auraOverlayOpacitySpinner = panel.getSpinner("auraOverlayOpacitySpinner"); - lightOverlayOpacitySpinner = panel.getSpinner("lightOverlayOpacitySpinner"); - darknessOverlayOpacitySpinner = panel.getSpinner("darknessOverlayOpacitySpinner"); + lumensOverlayOpacitySpinner = panel.getSpinner("lumensOverlayOpacitySpinner"); fogOverlayOpacitySpinner = panel.getSpinner("fogOverlayOpacitySpinner"); mapVisibilityWarning = panel.getCheckBox("mapVisibilityWarning"); @@ -709,19 +707,11 @@ protected void storeSpinnerValue(int value) { MapTool.getFrame().refresh(); } }); - lightOverlayOpacitySpinner.addChangeListener( + lumensOverlayOpacitySpinner.addChangeListener( new ChangeListenerProxy() { @Override protected void storeSpinnerValue(int value) { - AppPreferences.setLightOverlayOpacity(value); - MapTool.getFrame().refresh(); - } - }); - darknessOverlayOpacitySpinner.addChangeListener( - new ChangeListenerProxy() { - @Override - protected void storeSpinnerValue(int value) { - AppPreferences.setDarknessOverlayOpacity(value); + AppPreferences.setLumensOverlayOpacity(value); MapTool.getFrame().refresh(); } }); @@ -1093,10 +1083,8 @@ private void setInitialState() { new SpinnerNumberModel(AppPreferences.getHaloOverlayOpacity(), 0, 255, 1)); auraOverlayOpacitySpinner.setModel( new SpinnerNumberModel(AppPreferences.getAuraOverlayOpacity(), 0, 255, 1)); - lightOverlayOpacitySpinner.setModel( - new SpinnerNumberModel(AppPreferences.getLightOverlayOpacity(), 0, 255, 1)); - darknessOverlayOpacitySpinner.setModel( - new SpinnerNumberModel(AppPreferences.getDarknessOverlayOpacity(), 0, 255, 1)); + lumensOverlayOpacitySpinner.setModel( + new SpinnerNumberModel(AppPreferences.getLumensOverlayOpacity(), 0, 255, 1)); fogOverlayOpacitySpinner.setModel( new SpinnerNumberModel(AppPreferences.getFogOverlayOpacity(), 0, 255, 1)); diff --git a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.form b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.form index 5a44c04205..0b7bdeab72 100644 --- a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.form +++ b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.form @@ -1445,7 +1445,7 @@ - + @@ -1493,7 +1493,7 @@ - + @@ -1502,7 +1502,7 @@ - + @@ -1524,8 +1524,8 @@ - - + + @@ -1541,12 +1541,12 @@ - + - + @@ -1555,7 +1555,7 @@ - + @@ -1582,7 +1582,7 @@ - + @@ -1591,7 +1591,7 @@ - + @@ -1599,23 +1599,6 @@ - - - - - - - - - - - - - - - - - diff --git a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.java b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.java index aca7b21663..be19525d7b 100644 --- a/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.java +++ b/src/main/java/net/rptools/maptool/client/ui/preferencesdialog/PreferencesDialogView.java @@ -674,7 +674,7 @@ public class PreferencesDialogView { final Spacer spacer8 = new Spacer(); panel19.add(spacer8, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); final JPanel panel21 = new JPanel(); - panel21.setLayout(new GridLayoutManager(9, 4, new Insets(0, 0, 0, 0), -1, -1)); + panel21.setLayout(new GridLayoutManager(8, 4, new Insets(0, 0, 0, 0), -1, -1)); panel19.add(panel21, new GridConstraints(1, 0, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, true)); panel21.setBorder(BorderFactory.createTitledBorder(null, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.map"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$("Dialog", Font.BOLD, 12, panel21.getFont()), new Color(-13538620))); final JLabel label62 = new JLabel(); @@ -694,33 +694,33 @@ public class PreferencesDialogView { final JLabel label64 = new JLabel(); this.$$$loadLabelText$$$(label64, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.autoexpose")); label64.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.autoexpose.tooltip")); - panel21.add(label64, new GridConstraints(7, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(label64, new GridConstraints(6, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox34 = new JCheckBox(); checkBox34.setActionCommand("Auto-expose Fog"); checkBox34.setName("autoRevealVisionOnGMMoveCheckBox"); checkBox34.setText(""); - panel21.add(checkBox34, new GridConstraints(7, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(checkBox34, new GridConstraints(6, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label65 = new JLabel(); this.$$$loadLabelText$$$(label65, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.aura.opacity")); label65.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.aura.opacity.tooltip")); panel21.add(label65, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label66 = new JLabel(); - this.$$$loadLabelText$$$(label66, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.light.opacity")); - label66.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.light.opacity.tooltip")); + this.$$$loadLabelText$$$(label66, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.lumens.opacity")); + label66.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.lumens.opacity.tooltip")); panel21.add(label66, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JSpinner spinner6 = new JSpinner(); spinner6.setName("auraOverlayOpacitySpinner"); panel21.add(spinner6, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JSpinner spinner7 = new JSpinner(); - spinner7.setName("lightOverlayOpacitySpinner"); + spinner7.setName("lumensOverlayOpacitySpinner"); panel21.add(spinner7, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label67 = new JLabel(); this.$$$loadLabelText$$$(label67, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.opacity")); label67.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.opacity.tooltip")); - panel21.add(label67, new GridConstraints(6, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(label67, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JSpinner spinner8 = new JSpinner(); spinner8.setName("fogOverlayOpacitySpinner"); - panel21.add(spinner8, new GridConstraints(6, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(spinner8, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label68 = new JLabel(); this.$$$loadLabelText$$$(label68, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.halo.color")); label68.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.halo.color.tooltip")); @@ -733,19 +733,12 @@ public class PreferencesDialogView { final JLabel label69 = new JLabel(); this.$$$loadLabelText$$$(label69, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.mapvisibilitywarning")); label69.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.fog.mapvisibilitywarning.tooltip")); - panel21.add(label69, new GridConstraints(8, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(label69, new GridConstraints(7, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox36 = new JCheckBox(); checkBox36.setActionCommand("Auto-expose Fog"); checkBox36.setName("mapVisibilityWarning"); checkBox36.setText(""); - panel21.add(checkBox36, new GridConstraints(8, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label70 = new JLabel(); - this.$$$loadLabelText$$$(label70, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.darkness.opacity")); - label70.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.darkness.opacity.tooltip")); - panel21.add(label70, new GridConstraints(5, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JSpinner spinner9 = new JSpinner(); - spinner9.setName("darknessOverlayOpacitySpinner"); - panel21.add(spinner9, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + panel21.add(checkBox36, new GridConstraints(7, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final Spacer spacer9 = new Spacer(); panel21.add(spacer9, new GridConstraints(0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); final JPanel panel22 = new JPanel(); @@ -762,19 +755,19 @@ public class PreferencesDialogView { checkBox37.setName("playSystemSounds"); checkBox37.setText(""); panel23.add(checkBox37, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label71 = new JLabel(); - this.$$$loadLabelText$$$(label71, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.system")); - label71.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.system.tooltip")); - panel23.add(label71, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label70 = new JLabel(); + this.$$$loadLabelText$$$(label70, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.system")); + label70.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.system.tooltip")); + panel23.add(label70, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox38 = new JCheckBox(); checkBox38.setActionCommand("Only when window not focused"); checkBox38.setName("soundsOnlyWhenNotFocused"); checkBox38.setText(""); panel23.add(checkBox38, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label72 = new JLabel(); - this.$$$loadLabelText$$$(label72, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.syrinscape")); - label72.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.syrinscape.tooltip")); - panel23.add(label72, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label71 = new JLabel(); + this.$$$loadLabelText$$$(label71, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.syrinscape")); + label71.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.syrinscape.tooltip")); + panel23.add(label71, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox39 = new JCheckBox(); checkBox39.setName("syrinscapeActive"); checkBox39.setText(""); @@ -784,14 +777,14 @@ public class PreferencesDialogView { checkBox40.setName("playStreams"); checkBox40.setText(""); panel23.add(checkBox40, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label72 = new JLabel(); + this.$$$loadLabelText$$$(label72, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.stream")); + label72.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.stream.tooltip")); + panel23.add(label72, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label73 = new JLabel(); - this.$$$loadLabelText$$$(label73, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.stream")); - label73.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.stream.tooltip")); - panel23.add(label73, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label74 = new JLabel(); - this.$$$loadLabelText$$$(label74, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.focus")); - label74.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.focus.tooltip")); - panel23.add(label74, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + this.$$$loadLabelText$$$(label73, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.focus")); + label73.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.sound.focus.tooltip")); + panel23.add(label73, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox41 = new JCheckBox(); checkBox41.setActionCommand("Only when window not focused"); checkBox41.setName("playStreams"); @@ -810,21 +803,21 @@ public class PreferencesDialogView { final JList list1 = new JList(); list1.setName("themeList"); scrollPane1.setViewportView(list1); + final JLabel label74 = new JLabel(); + label74.setName("themeImage"); + label74.setText(""); + panel24.add(label74, new GridConstraints(0, 3, 6, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label75 = new JLabel(); - label75.setName("themeImage"); - label75.setText(""); - panel24.add(label75, new GridConstraints(0, 3, 6, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label76 = new JLabel(); - this.$$$loadLabelText$$$(label76, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.useThemeForChat")); - panel24.add(label76, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + this.$$$loadLabelText$$$(label75, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.useThemeForChat")); + panel24.add(label75, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox42 = new JCheckBox(); checkBox42.setName("useThemeForChat"); checkBox42.setText(""); panel24.add(checkBox42, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label77 = new JLabel(); - this.$$$loadLabelText$$$(label77, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.theme.macroeditor")); - label77.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.macroeditor.tooltip")); - panel24.add(label77, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label76 = new JLabel(); + this.$$$loadLabelText$$$(label76, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.theme.macroeditor")); + label76.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.macroeditor.tooltip")); + panel24.add(label76, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JComboBox comboBox9 = new JComboBox(); comboBox9.setActionCommand("comboBoxChanged"); final DefaultComboBoxModel defaultComboBoxModel1 = new DefaultComboBoxModel(); @@ -832,10 +825,10 @@ public class PreferencesDialogView { comboBox9.setModel(defaultComboBoxModel1); comboBox9.setName("macroEditorThemeCombo"); panel24.add(comboBox9, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label78 = new JLabel(); - this.$$$loadLabelText$$$(label78, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.icontheme")); - label78.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.icontheme.tooltip")); - panel24.add(label78, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label77 = new JLabel(); + this.$$$loadLabelText$$$(label77, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.icontheme")); + label77.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.icontheme.tooltip")); + panel24.add(label77, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JComboBox comboBox10 = new JComboBox(); comboBox10.setActionCommand("comboBoxChanged"); final DefaultComboBoxModel defaultComboBoxModel2 = new DefaultComboBoxModel(); @@ -847,9 +840,9 @@ public class PreferencesDialogView { panel24.add(spacer12, new GridConstraints(5, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); final Spacer spacer13 = new Spacer(); panel24.add(spacer13, new GridConstraints(6, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false)); - final JLabel label79 = new JLabel(); - this.$$$loadLabelText$$$(label79, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.filterTheme")); - panel24.add(label79, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label78 = new JLabel(); + this.$$$loadLabelText$$$(label78, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.filterTheme")); + panel24.add(label78, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JComboBox comboBox11 = new JComboBox(); comboBox11.setActionCommand("comboBoxChanged"); final DefaultComboBoxModel defaultComboBoxModel3 = new DefaultComboBoxModel(); @@ -857,21 +850,21 @@ public class PreferencesDialogView { comboBox11.setModel(defaultComboBoxModel3); comboBox11.setName("themeFilterCombo"); panel24.add(comboBox11, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label79 = new JLabel(); + this.$$$loadLabelText$$$(label79, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.currentTheme")); + panel24.add(label79, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label80 = new JLabel(); - this.$$$loadLabelText$$$(label80, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.currentTheme")); - panel24.add(label80, new GridConstraints(3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label81 = new JLabel(); - label81.setName("currentThemeName"); - label81.setText(""); - panel24.add(label81, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + label80.setName("currentThemeName"); + label80.setText(""); + panel24.add(label80, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JPanel panel25 = new JPanel(); panel25.setLayout(new GridLayoutManager(3, 4, new Insets(5, 5, 5, 5), -1, -1)); panel25.setVisible(false); tabbedPane1.addTab(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Label.auth"), panel25); - final JLabel label82 = new JLabel(); - this.$$$loadLabelText$$$(label82, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.auth.publicKey")); - label82.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.auth.publicKey.tooltip")); - panel25.add(label82, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label81 = new JLabel(); + this.$$$loadLabelText$$$(label81, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.auth.publicKey")); + label81.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.auth.publicKey.tooltip")); + panel25.add(label81, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JScrollPane scrollPane2 = new JScrollPane(); panel25.add(scrollPane2, new GridConstraints(0, 2, 2, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JTextArea textArea1 = new JTextArea(); @@ -897,14 +890,14 @@ public class PreferencesDialogView { panel27.setLayout(new GridLayoutManager(3, 2, new Insets(0, 0, 0, 0), -1, -1)); panel26.add(panel27, new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, true)); panel27.setBorder(BorderFactory.createTitledBorder(null, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$("Dialog", Font.BOLD, 12, panel27.getFont()), new Color(-13538620))); + final JLabel label82 = new JLabel(); + this.$$$loadLabelText$$$(label82, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.heap")); + label82.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.heap.tooltip")); + panel27.add(label82, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label83 = new JLabel(); - this.$$$loadLabelText$$$(label83, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.heap")); - label83.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.heap.tooltip")); - panel27.add(label83, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label84 = new JLabel(); - this.$$$loadLabelText$$$(label84, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.min")); - label84.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.min.tooltip")); - panel27.add(label84, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + this.$$$loadLabelText$$$(label83, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.min")); + label83.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.min.tooltip")); + panel27.add(label83, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JTextField textField13 = new JTextField(); textField13.setEditable(false); textField13.setHorizontalAlignment(4); @@ -925,10 +918,10 @@ public class PreferencesDialogView { textField14.setText("4G"); textField14.setToolTipText("Oracle recommends setting the minimum heap size (-Xms) equal to the maximum heap size (-Xmx) to minimize garbage collections."); panel27.add(textField14, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label85 = new JLabel(); - this.$$$loadLabelText$$$(label85, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.stack")); - label85.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.stack.tooltip")); - panel27.add(label85, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label84 = new JLabel(); + this.$$$loadLabelText$$$(label84, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.stack")); + label84.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.jvm.stack.tooltip")); + panel27.add(label84, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JTextField textField15 = new JTextField(); textField15.setEditable(false); textField15.setHorizontalAlignment(4); @@ -953,15 +946,15 @@ public class PreferencesDialogView { checkBox44.setName("jvmOpenGLCheckbox"); checkBox44.setText(""); panel28.add(checkBox44, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label85 = new JLabel(); + this.$$$loadLabelText$$$(label85, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.direct3d")); + panel28.add(label85, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label86 = new JLabel(); - this.$$$loadLabelText$$$(label86, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.direct3d")); - panel28.add(label86, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + this.$$$loadLabelText$$$(label86, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.opengl")); + panel28.add(label86, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JLabel label87 = new JLabel(); - this.$$$loadLabelText$$$(label87, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.opengl")); - panel28.add(label87, new GridConstraints(1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); - final JLabel label88 = new JLabel(); - this.$$$loadLabelText$$$(label88, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.javafx")); - panel28.add(label88, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + this.$$$loadLabelText$$$(label87, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.advanced.javafx")); + panel28.add(label87, new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JCheckBox checkBox45 = new JCheckBox(); checkBox45.setEnabled(false); checkBox45.setName("jvmInitAwtCheckbox"); @@ -971,10 +964,10 @@ public class PreferencesDialogView { panel29.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); panel26.add(panel29, new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, true)); panel29.setBorder(BorderFactory.createTitledBorder(null, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.language.override"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$("Dialog", Font.BOLD, 12, panel29.getFont()), new Color(-13538620))); - final JLabel label89 = new JLabel(); - label89.setText("Language"); - label89.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.language.tooltip")); - panel29.add(label89, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label88 = new JLabel(); + label88.setText("Language"); + label88.setToolTipText(this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.language.tooltip")); + panel29.add(label88, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JComboBox comboBox12 = new JComboBox(); comboBox12.setActionCommand("comboBoxChanged"); comboBox12.setEnabled(false); @@ -987,9 +980,9 @@ public class PreferencesDialogView { panel30.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1)); panel26.add(panel30, new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, true)); panel30.setBorder(BorderFactory.createTitledBorder(null, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.options"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$("Dialog", Font.BOLD, 12, panel30.getFont()), new Color(-13538620))); - final JLabel label90 = new JLabel(); - this.$$$loadLabelText$$$(label90, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.options.directory")); - panel30.add(label90, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label89 = new JLabel(); + this.$$$loadLabelText$$$(label89, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.label.options.directory")); + panel30.add(label89, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final JTextField textField16 = new JTextField(); textField16.setEditable(false); textField16.setHorizontalAlignment(2); @@ -1003,10 +996,10 @@ public class PreferencesDialogView { panel31.setLayout(new GridLayoutManager(1, 1, new Insets(0, 0, 0, 0), -1, -1)); panel26.add(panel31, new GridConstraints(0, 2, 5, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); panel31.setBorder(BorderFactory.createTitledBorder(null, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "Preferences.startup.label.info"), TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION, this.$$$getFont$$$("Dialog", Font.BOLD, 12, panel31.getFont()), new Color(-13538620))); - final JLabel label91 = new JLabel(); - label91.setName("startupInfoLabel"); - this.$$$loadLabelText$$$(label91, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "startup.preferences.info")); - panel31.add(label91, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); + final JLabel label90 = new JLabel(); + label90.setName("startupInfoLabel"); + this.$$$loadLabelText$$$(label90, this.$$$getMessageFromBundle$$$("net/rptools/maptool/language/i18n", "startup.preferences.info")); + panel31.add(label90, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); final Spacer spacer15 = new Spacer(); panel26.add(spacer15, new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false)); final Spacer spacer16 = new Spacer(); @@ -1023,11 +1016,13 @@ public class PreferencesDialogView { String resultName; if (fontName == null) { resultName = currentFont.getName(); - } else { + } + else { Font testFont = new Font(fontName, Font.PLAIN, 10); if (testFont.canDisplay('a') && testFont.canDisplay('1')) { resultName = fontName; - } else { + } + else { resultName = currentFont.getName(); } } @@ -1048,7 +1043,8 @@ public class PreferencesDialogView { $$$cachedGetBundleMethod$$$ = dynamicBundleClass.getMethod("getBundle", String.class, Class.class); } bundle = (ResourceBundle) $$$cachedGetBundleMethod$$$.invoke(null, path, thisClass); - } catch (Exception e) { + } + catch (Exception e) { bundle = ResourceBundle.getBundle(path); } return bundle.getString(key); diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/BlendingComposite.java b/src/main/java/net/rptools/maptool/client/ui/zone/BlendingComposite.java deleted file mode 100644 index 0ac8b6568d..0000000000 --- a/src/main/java/net/rptools/maptool/client/ui/zone/BlendingComposite.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * This software Copyright by the RPTools.net development team, and - * licensed under the Affero GPL Version 3 or, at your option, any later - * version. - * - * MapTool Source Code is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU Affero General Public - * License * along with this source Code. If not, please visit - * and specifically the Affero license - * text at . - */ -package net.rptools.maptool.client.ui.zone; - -import java.awt.Composite; -import java.awt.CompositeContext; -import java.awt.RenderingHints; -import java.awt.image.ColorModel; -import java.awt.image.DataBuffer; -import java.awt.image.DirectColorModel; -import java.awt.image.Raster; -import java.awt.image.RasterFormatException; -import java.awt.image.WritableRaster; -import org.checkerframework.common.value.qual.IntRange; - -/** - * A custom Composite class to replace AlphaComposite for the purposes of mixing lights, auras, and - * other colored effects. http://www.java2s.com/Code/Java/2D-Graphics-GUI/BlendCompositeDemo.htm - */ -class BlendingComposite implements Composite { - public enum Operation { - SCREEN, - MULTIPLY - } - - private final Operation operation; - - public BlendingComposite(Operation operation) { - this.operation = operation; - } - - private static boolean checkComponentsOrder(ColorModel cm) { - if (cm instanceof DirectColorModel directCM && cm.getTransferType() == DataBuffer.TYPE_INT) { - - return directCM.getRedMask() == 0x00FF0000 - && directCM.getGreenMask() == 0x0000FF00 - && directCM.getBlueMask() == 0x000000FF - && (directCM.getNumComponents() != 4 || directCM.getAlphaMask() == 0xFF000000); - } - - return false; - } - - @Override - public CompositeContext createContext( - ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) { - if (!checkComponentsOrder(srcColorModel) || !checkComponentsOrder(dstColorModel)) { - throw new RasterFormatException("Incompatible color models"); - } - - return switch (operation) { - case MULTIPLY -> new MultiplyContext(); - case SCREEN -> new ScreenContext(); - }; - } - - private abstract static class AbstractBlendingContext implements CompositeContext { - protected abstract @IntRange(from = 0, to = 255) int blend( - @IntRange(from = 0, to = 255) int src, @IntRange(from = 0, to = 255) int dst); - - @Override - public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { - final int w = Math.min(src.getWidth(), dstIn.getWidth()); - final int h = Math.min(src.getHeight(), dstIn.getHeight()); - - final int[] srcPixels = new int[w]; - final int[] dstPixels = new int[w]; - - for (int y = 0; y < h; y++) { - src.getDataElements(0, y, w, 1, srcPixels); - dstIn.getDataElements(0, y, w, 1, dstPixels); - - for (int x = 0; x < w; x++) { - final int srcPixel = srcPixels[x]; - final int dstPixel = dstPixels[x]; - - /* - * checkComponentsOrder() guarantees that we are handling simple integer ARGB formats. - * If this changes in the future, we could work with the color model here to handle more - * cases, though with more overhead. - */ - - if (dstPixel == 0) { - // Since lights are drawn onto a transparent black image, a fairly common case is that - // dstPixel is black and will not affect srcPixel at all. - dstPixels[x] = srcPixel; - } else { - dstPixels[x] = - (blend((dstPixel >>> 24) & 0xFF, (srcPixel >>> 24) & 0xFF) << 24) - | (blend((dstPixel >>> 16) & 0xFF, (srcPixel >>> 16) & 0xFF) << 16) - | (blend((dstPixel >>> 8) & 0xFF, (srcPixel >>> 8) & 0xFF) << 8) - | (blend(dstPixel & 0xFF, srcPixel & 0xFF)); - } - } - - dstOut.setDataElements(0, y, w, 1, dstPixels); - } - } - - @Override - public void dispose() {} - } - - private static final class MultiplyContext extends AbstractBlendingContext { - - /** - * Applies a "multiply" blend - * mode to two color components. - * - *

This operation is just multiplication, so it is commutative and associative (i.e., it is - * order independent). A maximum input (white) acts as an identity element, causing the result - * to simply be the other input. A zero input (black) acts an absorbing element, causing the - * result to also be black. For all other inputs, the result is darker than both of the inputs. - * - * @param src The first color component to blend. - * @param dst The second color component to blend. - * @return The multiply blending of the inputs. - */ - protected @IntRange(from = 0, to = 255) int blend( - @IntRange(from = 0, to = 255) int src, @IntRange(from = 0, to = 255) int dst) { - return src * dst / 255; - } - } - - private static final class ScreenContext extends AbstractBlendingContext { - /** - * Applies a "screen" blend mode - * to two color components. - * - *

This operation is basically fancy multiplication, so it is commutative and associative - * (i.e., it is order independent). A zero input (black) acts as an identity element, causing - * the result to simply be the other input. A maximum input (white) acts an absorbing element, - * causing the result to also be white. For all other inputs, the result is brighter than both - * of the inputs, though not as bright as would be with addition. - * - * @param src The first color component to blend. - * @param dst The second color component to blend. - * @return The screen blending of the inputs. - */ - protected @IntRange(from = 0, to = 255) int blend( - @IntRange(from = 0, to = 255) int src, @IntRange(from = 0, to = 255) int dst) { - return 255 - (255 - src) * (255 - dst) / 255; - } - } -} diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/DrawableLight.java b/src/main/java/net/rptools/maptool/client/ui/zone/DrawableLight.java index 0240e216a6..3125c14809 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/DrawableLight.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/DrawableLight.java @@ -15,21 +15,18 @@ package net.rptools.maptool.client.ui.zone; import java.awt.geom.Area; -import net.rptools.maptool.model.LightSource; import net.rptools.maptool.model.drawing.DrawablePaint; public class DrawableLight { private DrawablePaint paint; private Area area; - private LightSource.Type type; private int lumens; - public DrawableLight(LightSource.Type type, DrawablePaint paint, Area area, int lumens) { + public DrawableLight(DrawablePaint paint, Area area, int lumens) { super(); this.paint = paint; this.area = area; - this.type = type; this.lumens = lumens; } @@ -41,10 +38,6 @@ public Area getArea() { return area; } - public LightSource.Type getType() { - return type; - } - public int getLumens() { return lumens; } diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/LightingComposite.java b/src/main/java/net/rptools/maptool/client/ui/zone/LightingComposite.java new file mode 100644 index 0000000000..2daf6a8a6e --- /dev/null +++ b/src/main/java/net/rptools/maptool/client/ui/zone/LightingComposite.java @@ -0,0 +1,219 @@ +/* + * This software Copyright by the RPTools.net development team, and + * licensed under the Affero GPL Version 3 or, at your option, any later + * version. + * + * MapTool Source Code is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public + * License * along with this source Code. If not, please visit + * and specifically the Affero license + * text at . + */ +package net.rptools.maptool.client.ui.zone; + +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.RenderingHints; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; +import java.awt.image.WritableRaster; + +/** + * A custom Composite class to replace AlphaComposite for the purposes of mixing lights, auras, and + * other colored effects. ... + */ +public class LightingComposite implements Composite { + /** + * Used to blend lights together to give an additive effect. + * + *

To use to good effect, the initial image should be black and then lights should be added to + * it one-by-one. + */ + public static final Composite BlendedLights = new LightingComposite(new ScreenBlender()); + + /** Used to blend lighting results with an underlying image. */ + public static final Composite OverlaidLights = + new LightingComposite(new ConstrainedBrightenBlender()); + + // Blenders are stateless, so no point making new ones all the time. + private final Blender blender; + + public LightingComposite(Blender blender) { + this.blender = blender; + } + + private static void checkComponentsOrder(ColorModel cm) throws RasterFormatException { + if (cm.getTransferType() != DataBuffer.TYPE_INT) { + throw new RasterFormatException("Color model must be represented as an int array."); + } + if (cm instanceof DirectColorModel directCM) { + if (directCM.getRedMask() != 0x00FF0000 + || directCM.getGreenMask() != 0x0000FF00 + || directCM.getBlueMask() != 0x000000FF + || (directCM.getNumComponents() == 4 && directCM.getAlphaMask() != 0xFF000000)) { + throw new RasterFormatException("Color model must be RGB or ARGB"); + } + } else { + throw new RasterFormatException( + "Color model must be a DirectColorModel so that each pixel is one int"); + } + } + + @Override + public CompositeContext createContext( + ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) { + checkComponentsOrder(srcColorModel); + checkComponentsOrder(dstColorModel); + + return new BlenderContext(blender); + } + + private static final class BlenderContext implements CompositeContext { + private final Blender blender; + + public BlenderContext(Blender blender) { + this.blender = blender; + } + + @Override + public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { + final int w = Math.min(src.getWidth(), dstIn.getWidth()); + final int h = Math.min(src.getHeight(), dstIn.getHeight()); + + final int[] srcPixels = new int[w]; + final int[] dstPixels = new int[w]; + final int[] dstOutPixels = new int[w]; + + for (int y = 0; y < h; y++) { + src.getDataElements(src.getMinX(), y + src.getMinY(), w, 1, srcPixels); + dstIn.getDataElements(dstIn.getMinX(), y + dstIn.getMinY(), w, 1, dstPixels); + + blender.blendRow(dstPixels, srcPixels, dstOutPixels, w); + + dstOut.setDataElements(dstOut.getMinX(), y + dstOut.getMinY(), w, 1, dstOutPixels); + } + } + + @Override + public void dispose() {} + } + + public interface Blender { + /** + * Blend source and destination pixels for a row of pixels. + * + *

The pixels must be encoded as 32-bit ARGB, and the result will be likewise. + * + * @param dstPixels The bottom layer pixels. + * @param srcPixels The top layer pixels. + * @param outPixels A buffer that this method will write results into. + * @param samples The number of pixels in the row. + */ + void blendRow(int[] dstPixels, int[] srcPixels, int[] outPixels, int samples); + } + + /** + * Additive lights based on the screen blend mode. + * + *

The result of screen blending is always greater than the top and bottom inputs. + * + *

Special cases: + * + *

    + *
  • When the bottom component is 0, the result is the top component. + *
  • When the top component is 0, the result is the bottom component. + *
  • When either the top component or the bottom component is maxed, the result is maxed. + *
+ */ + private static final class ScreenBlender implements Blender { + public void blendRow(int[] dstPixels, int[] srcPixels, int[] outPixels, int samples) { + for (int x = 0; x < samples; ++x) { + final int srcPixel = srcPixels[x]; + final int dstPixel = dstPixels[x]; + + // This keeps the bottom alpha around. + int resultPixel = dstPixel & (0xFF << 24); + + for (int shift = 0; shift < 24; shift += 8) { + final var dstC = (dstPixel >>> shift) & 0xFF; + final var srcC = (srcPixel >>> shift) & 0xFF; + + final var resultC = dstC + srcC - (dstC * srcC) / 255; + + resultPixel |= (resultC << shift); + } + + outPixels[x] = resultPixel; + } + } + } + + /** + * Inspired by overlay blending, this is an alternative that never darkens and which boosts dark + * components by no more than some multiple of the component. + * + *

When the bottom component ({@code dstC}) is low, the result is between the bottom component + * and a multiple of the bottom component controlled by {@link #MAX_DARKNESS_BOOST_PER_128}. The + * exact result is determined by using the top component ({@code srcC}) to interpolate between the + * two bounds. + * + *

When the bottom component is high, the result is between the bottom component and 255, again + * using the top component to interpolate between the two. + * + *

The transition point from low to high depends on the value of {@link + * #MAX_DARKNESS_BOOST_PER_128} - the higher that value, the lower the transition point. + * + *

When viewed as a function of the bottom component, this blend mode is built from two linear + * pieces. The first piece has a slope no less than 1, and the second piece has a slope no greater + * than one. So in addition to brightening, this function increases the contrast in dark regions, + * while tapering off in bright regions. + * + *

The behaviour is actually is very similar to overlay, but where the value at the transition + * point is always greater than the bottom component (in overlay it can be greater than or less + * than the bottom component). The relation can be best seen when {@link + * #MAX_DARKNESS_BOOST_PER_128} is set to 1. It also has a much looser relation to the soft light + * blend mode, which inspired the idea of constraining the increase of dark components by some + * multiple. + * + *

Special cases: + * + *

    + *
  • When the bottom component is 0, the result is 0. + *
  • When the bottom component is maxed, the result is maxed. + *
  • When the top component is 0, the result is the bottom component. + *
  • + *
+ */ + private static final class ConstrainedBrightenBlender implements Blender { + private static final int MAX_DARKNESS_BOOST_PER_128 = 192; + + public void blendRow(int[] dstPixels, int[] srcPixels, int[] outPixels, int samples) { + for (int x = 0; x < samples; ++x) { + final int srcPixel = srcPixels[x]; + final int dstPixel = dstPixels[x]; + + // This keeps the bottom alpha around. + int resultPixel = dstPixel & (0xFF << 24); + + for (int shift = 0; shift < 24; shift += 8) { + final var dstC = (dstPixel >>> shift) & 0xFF; + final var srcC = (srcPixel >>> shift) & 0xFF; + + final var resultC = + dstC + srcC * Math.min(MAX_DARKNESS_BOOST_PER_128 * dstC / 128, 255 - dstC) / 255; + + resultPixel |= (resultC << shift); + } + + outPixels[x] = resultPixel; + } + } + } +} diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java index 63a4e11b48..9bfba13d90 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneRenderer.java @@ -1454,36 +1454,45 @@ private void renderLights(Graphics2D g, PlayerView view) { timer.stop("renderLights:populateCache"); } timer.start("renderLights:filterLights"); - final var darknessLights = - drawableLights.stream().filter(light -> light.getLumens() < 0).toList(); - final var nonDarknessLights = - drawableLights.stream().filter(light -> light.getLumens() >= 0).toList(); - timer.stop("renderLights:filterLights"); - timer.stop("renderLights:getLights"); - - timer.start("renderLights:renderLightOverlay"); - renderLightOverlay( - g, - AlphaComposite.SrcOver.derive(AppPreferences.getLightOverlayOpacity() / 255.0f), - view.isGMView() ? null : LightOverlayClipStyle.CLIP_TO_VISIBLE_AREA, - nonDarknessLights, - new Color(255, 255, 255, 255), - 1.0f); - timer.stop("renderLights:renderLightOverlay"); - - // Players should not be able to discern the nature of the darkness, so we always render it as - // black for them. - timer.start("renderLights:renderDarknessOverlay"); - renderLightOverlay( - g, - view.isGMView() - ? AlphaComposite.SrcOver.derive(AppPreferences.getDarknessOverlayOpacity() / 255.0f) - : new SolidColorComposite(0xff000000), - view.isGMView() ? null : LightOverlayClipStyle.CLIP_TO_NOT_VISIBLE_AREA, - darknessLights, - new Color(0, 0, 0, 255), - 1.0f); - timer.stop("renderLights:renderDarknessOverlay"); + + if (AppState.isShowLights()) { + // Lighting enabled. + timer.start("renderLights:renderLightOverlay"); + renderLightOverlay( + g, + LightingComposite.BlendedLights, + LightingComposite.OverlaidLights, + LightOverlayClipStyle.CLIP_TO_VISIBLE_AREA, + drawableLights, + Color.black, + Color.black); + timer.stop("renderLights:renderLightOverlay"); + } + + if (!view.isGMView()) { + // Note that the ZoneView has already restricted the darkness to its affected areas. + final var darknessLights = + drawableLights.stream().filter(light -> light.getLumens() <= 0).toList(); + renderLightOverlay( + g, + new SolidColorComposite(0xff000000), + AlphaComposite.SrcOver, + LightOverlayClipStyle.CLIP_TO_NOT_VISIBLE_AREA, + darknessLights, + Color.black, + new Color(0, 0, 0, 0)); + } + + if (AppState.isShowLumensOverlay()) { + // Lumens overlay enabled. + timer.start("renderLights:renderLumensOverlay"); + renderLumensOverlay( + g, + view, + view.isGMView() ? null : LightOverlayClipStyle.CLIP_TO_VISIBLE_AREA, + AppPreferences.getLumensOverlayOpacity() / 255.0f); + timer.stop("renderLights:renderLumensOverlay"); + } } /** Caches the lights to be drawn as returned ZoneView. */ @@ -1510,36 +1519,136 @@ private void renderAuras(Graphics2D g, PlayerView view) { renderLightOverlay( g, AlphaComposite.SrcOver.derive(AppPreferences.getAuraOverlayOpacity() / 255.0f), + AlphaComposite.SrcOver, view.isGMView() ? null : LightOverlayClipStyle.CLIP_TO_VISIBLE_AREA, drawableAuras, new Color(255, 255, 255, 150), - 1.0f); + new Color(0, 0, 0, 0)); timer.stop("renderAuras:renderAuraOverlay"); } + private void addLitAreaToLumensOverlay( + Graphics2D overlayG, Area area, float shade, float opacity) { + overlayG.setPaint(new Color(shade, shade, shade, opacity)); + + timer.start("renderLumensOverlay:drawLights:fillArea"); + overlayG.fill(area); + timer.stop("renderLumensOverlay:drawLights:fillArea"); + + timer.start("renderLumensOverlay:drawLights:drawArea"); + overlayG.setStroke(new BasicStroke(5.f)); + overlayG.setPaint(Color.black); + overlayG.draw(area); + timer.stop("renderLumensOverlay:drawLights:drawArea"); + } + + private void renderLumensOverlay( + Graphics2D g, + PlayerView view, + @Nullable LightOverlayClipStyle clipStyle, + float overlayOpacity) { + g = (Graphics2D) g.create(); + + final var lumensLevels = zoneView.getLumensLevels(view); + + timer.start("renderLumensOverlay:allocateBuffer"); + try (final var bufferHandle = tempBufferPool.acquire()) { + BufferedImage lumensOverlay = bufferHandle.get(); + timer.stop("renderLumensOverlay:allocateBuffer"); + + Graphics2D newG = lumensOverlay.createGraphics(); + SwingUtil.useAntiAliasing(newG); + + // At night, show any uncovered areas as dark. In daylight, show them as light (clear). + newG.setPaint( + zone.getVisionType() == Zone.VisionType.NIGHT + ? new Color(0, 0, 0, overlayOpacity) + : new Color(1.f, 1.f, 1.f, 0.f)); + newG.fillRect(0, 0, lumensOverlay.getWidth(), lumensOverlay.getHeight()); + + if (clipStyle != null && visibleScreenArea != null) { + timer.start("renderLumensOverlay:setClip"); + Area clip = new Area(g.getClip()); + switch (clipStyle) { + case CLIP_TO_VISIBLE_AREA -> clip.intersect(visibleScreenArea); + case CLIP_TO_NOT_VISIBLE_AREA -> clip.subtract(visibleScreenArea); + } + newG.setClip(clip); + g.setClip(clip); + timer.stop("renderLumensOverlay:setClip"); + } + + timer.start("renderLumensOverlay:setTransform"); + AffineTransform af = new AffineTransform(); + af.translate(getViewOffsetX(), getViewOffsetY()); + af.scale(getScale(), getScale()); + newG.setTransform(af); + timer.stop("renderLumensOverlay:setTransform"); + + timer.start("renderLumensOverlay:drawLumens"); + // Lumens are ordered to be weak to strong. That works for us as well will draw the stronger + // areas overtop the weaker areas using `AlphaComposite.Src` to make sure the stronger one + // "wins". + newG.setComposite(AlphaComposite.Src); + for (final var lumensLevel : lumensLevels) { + final var lumensStrength = lumensLevel.lumensStrength(); + + // Light is weaker than darkness, so do it first. + float lightOpacity; + float lightShade; + if (lumensStrength == 0) { + // This area represents daylight, so draw it as clear despite the low value. + lightShade = 1.f; + lightOpacity = 0; + } else if (lumensStrength >= 100) { + // Bright light, render mostly clear. + lightShade = 1.f; + lightOpacity = 1.f / 10.f; + } else { + lightShade = Math.max(0.f, Math.min(lumensStrength / 100.f, 1.f)); + lightShade *= lightShade; + lightOpacity = 1.f; + } + addLitAreaToLumensOverlay(newG, lumensLevel.lightArea(), lightShade, lightOpacity); + + addLitAreaToLumensOverlay(newG, lumensLevel.darknessArea(), 0, 1.f); + } + timer.stop("renderLumensOverlay:drawLumens"); + newG.dispose(); + + timer.start("renderLumensOverlay:drawBuffer"); + g.setComposite(AlphaComposite.SrcOver.derive(overlayOpacity)); + g.drawImage(lumensOverlay, null, 0, 0); + timer.stop("renderLumensOverlay:drawBuffer"); + } + } + /** * Combines a set of lights into an image that is then rendered into the zone. * * @param g The graphics object used to render the zone. - * @param composite The composite used to blend lights together. + * @param lightBlending The composite used to blend lights together within the overlay + * @param overlayBlending The composite used when blending the overlay with the underlying image. * @param clipStyle How to clip the overlay relative to the visible area. Set to null for no extra * clipping. * @param lights The lights that will be rendered and blended. * @param defaultPaint A default paint for lights without a paint. - * @param overlayOpacity The opacity used when rendering the final overlay on top of the zone. */ private void renderLightOverlay( Graphics2D g, - Composite composite, + Composite lightBlending, + Composite overlayBlending, @Nullable LightOverlayClipStyle clipStyle, - List lights, + Collection lights, Paint defaultPaint, - float overlayOpacity) { + Paint backgroundFill) { if (lights.isEmpty()) { - // No points spending resources accomplishing nothing. + // No point spending resources accomplishing nothing. return; } + g = (Graphics2D) g.create(); + // Set up a buffer image for lights to be drawn onto before the map timer.start("renderLightOverlay:allocateBuffer"); try (final var bufferHandle = tempBufferPool.acquire()) { @@ -1547,7 +1656,9 @@ private void renderLightOverlay( timer.stop("renderLightOverlay:allocateBuffer"); Graphics2D newG = lightOverlay.createGraphics(); - SwingUtil.useAntiAliasing(newG); + newG.setComposite(AlphaComposite.Src); + newG.setPaint(backgroundFill); + newG.fillRect(0, 0, lightOverlay.getWidth(), lightOverlay.getHeight()); if (clipStyle != null && visibleScreenArea != null) { timer.start("renderLightOverlay:setClip"); @@ -1567,24 +1678,24 @@ private void renderLightOverlay( newG.setTransform(af); timer.stop("renderLightOverlay:setTransform"); - newG.setComposite(composite); + newG.setComposite(lightBlending); // Draw lights onto the buffer image so the map doesn't affect how they blend timer.start("renderLightOverlay:drawLights"); for (var light : lights) { var paint = light.getPaint() != null ? light.getPaint().getPaint() : defaultPaint; newG.setPaint(paint); + timer.start("renderLightOverlay:fillLight"); newG.fill(light.getArea()); + timer.stop("renderLightOverlay:fillLight"); } timer.stop("renderLightOverlay:drawLights"); newG.dispose(); // Draw the buffer image with all the lights onto the map timer.start("renderLightOverlay:drawBuffer"); - Composite previousComposite = g.getComposite(); - g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, overlayOpacity)); + g.setComposite(overlayBlending); g.drawImage(lightOverlay, null, 0, 0); - g.setComposite(previousComposite); timer.stop("renderLightOverlay:drawBuffer"); } } diff --git a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java index f2e7c29b1c..fa2d086353 100644 --- a/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java +++ b/src/main/java/net/rptools/maptool/client/ui/zone/ZoneView.java @@ -54,7 +54,7 @@ public class ZoneView { private record ContributedLight(LitArea litArea, LightInfo lightInfo) { public static ContributedLight forDaylight(Area visibleArea) { - return new ContributedLight(new LitArea(1, visibleArea), null); + return new ContributedLight(new LitArea(0, visibleArea), null); } } @@ -162,9 +162,6 @@ public record IlluminationKey(double multiplier) {} private final Map topologyTrees = new EnumMap<>(Zone.TopologyType.class); - /** Lumen for personal vision (darkvision). */ - private static final int LUMEN_VISION = 100; - /** * Construct ZoneView from zone. Build lightSourceMap, and add ZoneView to Zone as listener. * @@ -368,13 +365,11 @@ private List calculateLitAreaForLightSource( } final var litAreas = new ArrayList(); - var lumens = lightSource.getLumens(); - if (lumens == 0) { - lumens = LUMEN_VISION; - } // Tracks the cummulative inner ranges of light sources so that we can cut them out of the // outer ranges and end up with disjoint sets, even when magnifying. + // Note that this "hole punching" has nothing to do with lumen strength, it's just a way of + // making smaller ranges act as lower bounds for larger ranges. final var cummulativeNotTransformedArea = new Area(); for (final var light : lightSource.getLightList()) { final var notScaledLightArea = @@ -383,20 +378,59 @@ private List calculateLitAreaForLightSource( continue; } final var lightArea = new Area(notScaledLightArea); - lightArea.subtract(cummulativeNotTransformedArea); - if (lightSource.getType() == LightSource.Type.NORMAL && multiplier != 1) { + // Lowlight vision does not magnify darkness. + if (multiplier != 1 + && lightSource.getType() == LightSource.Type.NORMAL + && light.getLumens() >= 0) { lightArea.transform(magnifyTransform); } + + lightArea.subtract(cummulativeNotTransformedArea); lightArea.transform(translateTransform); lightArea.intersect(lightSourceVisibleArea); litAreas.add( - new ContributedLight(new LitArea(lumens, lightArea), new LightInfo(lightSource, light))); + new ContributedLight( + new LitArea(light.getLumens(), lightArea), new LightInfo(lightSource, light))); cummulativeNotTransformedArea.add(notScaledLightArea); } + // Magnification can cause different ranges for a single light source to overlap. This is not + // fundamentally a problem, but does open the possibility that different ranges are rendered + // overtop one another. So here we subtract any stronger ranges (higher lumens values) from + // weaker ranges (lower lumens values). + + final var cummulativeStrongerArea = new Area(); + // The light source may have produced both light and darkness, so make sure darkness is treated + // as stronger than light. + litAreas.sort( + (lhs, rhs) -> { + final var lhsLumens = lhs.litArea().lumens(); + final var rhsLumens = rhs.litArea().lumens(); + final var comparison = Integer.compare(lhsLumens, rhsLumens); + if (comparison == 0) { + // Exactly equal. + return 0; + } + + final var absComparison = Integer.compare(Math.abs(lhsLumens), Math.abs(rhsLumens)); + if (absComparison != 0) { + // Different magnitudes. Order large to small. + return -absComparison; + } + + // Same magnitude, different sign. Put light (positive) after darkness as it's weaker. + return comparison; + }); + for (final var litArea : litAreas) { + // Update to not include any stronger areas. + final var originalArea = new Area(litArea.litArea().area()); + litArea.litArea().area().subtract(cummulativeStrongerArea); + cummulativeStrongerArea.add(originalArea); + } + return litAreas; } @@ -479,8 +513,8 @@ private Illumination getIllumination(IlluminationKey illuminationKey) { final var tokenVisibleArea = getTokenVisibleArea(token); if (zone.getVisionType() != Zone.VisionType.NIGHT) { - final var contributedLight = ContributedLight.forDaylight(tokenVisibleArea); // Treat the entire visible area like a light source of minimal lumens. + final var contributedLight = ContributedLight.forDaylight(tokenVisibleArea); personalLights.add(contributedLight); } @@ -712,14 +746,9 @@ public List getDrawableAuras() { // Calculate the area covered by this particular range. Area lightArea = lightSource.getArea(token, zone, light); - if (lightArea == null) { - continue; - } lightArea.transform(AffineTransform.getTranslateInstance(p.x, p.y)); lightArea.intersect(visibleArea); - lightList.add( - new DrawableLight( - LightSource.Type.AURA, light.getPaint(), visibleArea, lightSource.getLumens())); + lightList.add(new DrawableLight(light.getPaint(), visibleArea, light.getLumens())); } } } @@ -789,10 +818,7 @@ public Collection getDrawableLights(PlayerView view) { ? lumensLevel.get().darknessArea() : lumensLevel.get().lightArea()); return new DrawableLight( - laud.lightInfo().lightSource().getType(), - laud.lightInfo().light().getPaint(), - obscuredArea, - laud.litArea.lumens()); + laud.lightInfo().light().getPaint(), obscuredArea, laud.litArea.lumens()); }) .filter(Objects::nonNull) .toList(); diff --git a/src/main/java/net/rptools/maptool/model/Light.java b/src/main/java/net/rptools/maptool/model/Light.java index 8b4505c1d1..67981b9dce 100644 --- a/src/main/java/net/rptools/maptool/model/Light.java +++ b/src/main/java/net/rptools/maptool/model/Light.java @@ -15,108 +15,89 @@ package net.rptools.maptool.model; import java.awt.geom.Area; +import java.io.Serial; +import java.io.Serializable; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.rptools.maptool.model.drawing.DrawablePaint; import net.rptools.maptool.server.proto.LightDto; import net.rptools.maptool.server.proto.ShapeTypeDto; -public class Light { - private DrawablePaint paint; - private double facingOffset; - private double radius; - private double arcAngle; - private ShapeType shape; - private boolean isGM; - private boolean ownerOnly; - - public Light() { - // For serialization - } +public class Light implements Serializable { + private final @Nonnull ShapeType shape; + private final double facingOffset; + private final double radius; + private final double arcAngle; + private final @Nullable DrawablePaint paint; + private final int lumens; + private final boolean isGM; + private final boolean ownerOnly; public Light( - ShapeType shape, double facingOffset, double radius, double arcAngle, DrawablePaint paint) { - this.facingOffset = facingOffset; - this.shape = shape; - this.radius = radius; - this.arcAngle = arcAngle; - this.paint = paint; - this.isGM = false; - this.ownerOnly = false; - - if (arcAngle == 0) { - this.arcAngle = 90; - } - } - - public Light( - ShapeType shape, + @Nonnull ShapeType shape, double facingOffset, double radius, double arcAngle, - DrawablePaint paint, + @Nullable DrawablePaint paint, + int lumens, boolean isGM, boolean owner) { - this.facingOffset = facingOffset; this.shape = shape; + this.facingOffset = facingOffset; this.radius = radius; - this.arcAngle = arcAngle; + this.arcAngle = (arcAngle == 0) ? 90 : arcAngle; this.paint = paint; + this.lumens = lumens; this.isGM = isGM; this.ownerOnly = owner; - if (arcAngle == 0) { - this.arcAngle = 90; - } } - public DrawablePaint getPaint() { + @SuppressWarnings("ConstantConditions") + @Serial + private @Nonnull Object readResolve() { + // Rather than modifying the current object, we'll create a replacement that is definitely + // initialized properly. + return new Light( + shape == null ? ShapeType.CIRCLE : shape, + facingOffset, + radius, + arcAngle, + paint, + lumens == 0 ? 100 : lumens, + isGM, + ownerOnly); + } + + public @Nullable DrawablePaint getPaint() { return paint; } - public void setPaint(DrawablePaint paint) { - this.paint = paint; + public int getLumens() { + return lumens; } public double getFacingOffset() { return facingOffset; } - public void setFacingOffset(double facingOffset) { - this.facingOffset = facingOffset; - } - public double getRadius() { return radius; } - public void setRadius(double radius) { - this.radius = radius; - } - public double getArcAngle() { return arcAngle; } - public void setArcAngle(double arcAngle) { - this.arcAngle = arcAngle; - } - - public ShapeType getShape() { + public @Nonnull ShapeType getShape() { return shape; } - public void setShape(ShapeType shape) { - this.shape = shape; - } - - public Area getArea(Token token, Zone zone, boolean scaleWithToken) { + public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, boolean scaleWithToken) { return zone.getGrid() .getShapedArea( getShape(), token, getRadius(), getArcAngle(), (int) getFacingOffset(), scaleWithToken); } - public void setGM(boolean b) { - isGM = b; - } - public boolean isGM() { return isGM; } @@ -125,33 +106,30 @@ public boolean isOwnerOnly() { return ownerOnly; } - public void setOwnerOnly(boolean owner) { - ownerOnly = owner; - } - - public static Light fromDto(LightDto dto) { - var light = new Light(); - light.paint = dto.hasPaint() ? DrawablePaint.fromDto(dto.getPaint()) : null; - light.facingOffset = dto.getFacingOffset(); - light.radius = dto.getRadius(); - light.arcAngle = dto.getArcAngle(); - light.shape = ShapeType.valueOf(dto.getShape().name()); - light.isGM = dto.getIsGm(); - light.ownerOnly = dto.getOwnerOnly(); - return light; + public static @Nonnull Light fromDto(@Nonnull LightDto dto) { + return new Light( + ShapeType.valueOf(dto.getShape().name()), + dto.getFacingOffset(), + dto.getRadius(), + dto.getArcAngle(), + dto.hasPaint() ? DrawablePaint.fromDto(dto.getPaint()) : null, + dto.getLumens(), + dto.getIsGm(), + dto.getOwnerOnly()); } - public LightDto toDto() { + public @Nonnull LightDto toDto() { var dto = LightDto.newBuilder(); - if (paint != null) dto.setPaint(paint.toDto()); + if (paint != null) { + dto.setPaint(paint.toDto()); + } dto.setFacingOffset(facingOffset); dto.setRadius(radius); dto.setArcAngle(arcAngle); - // default shape is circle - if (shape == null) shape = ShapeType.CIRCLE; dto.setShape(ShapeTypeDto.valueOf(shape.name())); dto.setIsGm(isGM); dto.setOwnerOnly(ownerOnly); + dto.setLumens(lumens); return dto.build(); } } diff --git a/src/main/java/net/rptools/maptool/model/LightSource.java b/src/main/java/net/rptools/maptool/model/LightSource.java index bc31f17d59..6d6bcff161 100644 --- a/src/main/java/net/rptools/maptool/model/LightSource.java +++ b/src/main/java/net/rptools/maptool/model/LightSource.java @@ -17,37 +17,109 @@ import com.google.protobuf.StringValue; import java.awt.geom.Area; import java.io.IOException; +import java.io.Serial; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import net.rptools.lib.FileUtil; import net.rptools.maptool.server.proto.LightSourceDto; -import net.rptools.maptool.server.proto.ShapeTypeDto; import org.apache.commons.lang.math.NumberUtils; -import org.jetbrains.annotations.NotNull; -public class LightSource implements Comparable { +public class LightSource implements Comparable, Serializable { public enum Type { NORMAL, AURA } - private List lightList; - private String name; - private GUID id; - private Type type = Type.NORMAL; - private ShapeType shapeType = ShapeType.CIRCLE; - private int lumens = 0; - private boolean scaleWithToken = false; + private @Nullable String name; + private @Nullable GUID id; + private @Nonnull Type type; + private boolean scaleWithToken; + private final @Nonnull List lightList; + // Lumens are now in the individual Lights. This field is only here for backwards compatibility + // and should not otherwise be used. + @Deprecated private final int lumens = Integer.MIN_VALUE; + + /** + * Constructs a personal light source. + * + *

Since a personal light source is directly attached to a specific sight type, they do not + * need (or have) names and GUIDs. + */ public LightSource() { - // for serialization + this(null, null, Type.NORMAL, false, Collections.emptyList()); + } + + /** + * Constructs a non-personal light source. + * + *

These light sources are referenced both by name and GUID, and thus need both. A new GUID + * will be created automatically. + * + * @param name The name of the light source. + */ + public LightSource(@Nonnull String name) { + this(name, new GUID(), Type.NORMAL, false, Collections.emptyList()); } - public LightSource(String name) { - id = new GUID(); + private LightSource( + @Nullable String name, + @Nullable GUID id, + @Nonnull Type type, + boolean scaleWithToken, + @Nonnull Collection lights) { this.name = name; + this.id = id; + this.type = type; + this.scaleWithToken = scaleWithToken; + + this.lightList = new LinkedList<>(); + this.lightList.addAll(lights); + } + + @SuppressWarnings("ConstantConditions") + @Serial + private @Nonnull Object readResolve() { + final List lights; + if (lumens == Integer.MIN_VALUE) { + // This is an up-to-date Lightsource with lumens already stored in the Lights. + lights = this.lightList; + } else { + // This is an old light source with a lumens value that needs to be pushed into the individual + // Lights. + lights = new ArrayList<>(); + for (final var light : + Objects.requireNonNullElse(lightList, Collections.emptyList())) { + lights.add( + new Light( + light.getShape(), + light.getFacingOffset(), + light.getRadius(), + light.getArcAngle(), + light.getPaint(), + lumens == 0 ? 100 : lumens, + light.isGM(), + light.isOwnerOnly())); + } + } + + // Rather than modifying the current object, we'll create a replacement that is definitely + // initialized properly. + return new LightSource( + this.name, + this.id, + Objects.requireNonNullElse(this.type, Type.NORMAL), + this.scaleWithToken, + lights); } @Override @@ -55,12 +127,12 @@ public boolean equals(Object obj) { if (!(obj instanceof LightSource)) { return false; } - return ((LightSource) obj).id.equals(id); + return Objects.equals(((LightSource) obj).id, id); } public double getMaxRange() { double range = 0; - for (Light light : getLightList()) { + for (Light light : lightList) { range = Math.max(range, light.getRadius()); } return range; @@ -68,65 +140,46 @@ public double getMaxRange() { @Override public int hashCode() { - return id.hashCode(); + return Objects.hashCode(id); } - public void setId(GUID id) { + public void setId(@Nonnull GUID id) { this.id = id; } - public GUID getId() { + public @Nullable GUID getId() { return id; } - public String getName() { + public @Nullable String getName() { return name; } - public void setName(String name) { + public void setName(@Nonnull String name) { this.name = name; } - public void add(Light source) { - getLightList().add(source); + public void add(@Nonnull Light source) { + lightList.add(source); } - public void remove(Light source) { - getLightList().remove(source); + public void remove(@Nonnull Light source) { + lightList.remove(source); } - /** @return the lightList of the LightSource */ - public List getLightList() { - if (lightList == null) { - lightList = new LinkedList(); - } - return lightList; + /** @return the lights belonging to this LightSource. */ + public @Nonnull List getLightList() { + return Collections.unmodifiableList(lightList); } - public Type getType() { - return type != null ? type : Type.NORMAL; + public @Nonnull Type getType() { + return type; } - public void setType(Type type) { + public void setType(@Nonnull Type type) { this.type = type; } - public void setShapeType(ShapeType type) { - this.shapeType = type; - } - - public ShapeType getShapeType() { - return shapeType != null ? shapeType : ShapeType.CIRCLE; - } - - public void setLumens(int lumens) { - this.lumens = lumens; - } - - public int getLumens() { - return lumens; - } - public void setScaleWithToken(boolean scaleWithToken) { this.scaleWithToken = scaleWithToken; } @@ -138,22 +191,21 @@ public boolean isScaleWithToken() { /* * Area for a single light, subtracting any previous lights */ - public Area getArea(Token token, Zone zone, Light light) { + public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone, @Nonnull Light light) { Area area = light.getArea(token, zone, scaleWithToken); // TODO: This seems horribly inefficient // Subtract out the lights that are previously defined - for (int i = getLightList().indexOf(light) - 1; i >= 0; i--) { - Light lessLight = getLightList().get(i); + for (int i = lightList.indexOf(light) - 1; i >= 0; i--) { + Light lessLight = lightList.get(i); area.subtract(lessLight.getArea(token, zone, scaleWithToken)); } return area; } /* Area for all lights combined */ - public Area getArea(Token token, Zone zone) { + public @Nonnull Area getArea(@Nonnull Token token, @Nonnull Zone zone) { Area area = new Area(); - - for (Light light : getLightList()) { + for (Light light : lightList) { area.add(light.getArea(token, zone, isScaleWithToken())); } @@ -161,7 +213,8 @@ public Area getArea(Token token, Zone zone) { } @SuppressWarnings("unchecked") - public static Map> getDefaultLightSources() throws IOException { + public static @Nonnull Map> getDefaultLightSources() + throws IOException { Object defaultLights = FileUtil.objFromResource("net/rptools/maptool/model/defaultLightSourcesMap.xml"); return (Map>) defaultLights; @@ -172,22 +225,17 @@ public String toString() { return name; } - private Object readResolve() { - if (type == null) { - type = Type.NORMAL; - } - if (lightList == null) { - lightList = new LinkedList<>(); - } - return this; - } - /* - * (non-Javadoc) + * Compares this light source with another. + * + * Light sources are compared by name. If both names are numeric strings, they will be compared as + * integers. Otherwise they will be compared lexicographically. + * + * This must only be called on light source that have a name, i.e., not on personal lights. * * @see java.lang.Comparable#compareTo(java.lang.Object) */ - public int compareTo(@NotNull LightSource o) { + public int compareTo(@Nonnull LightSource o) { if (o != this) { int nameLong = NumberUtils.toInt(name, Integer.MIN_VALUE); int onameLong = NumberUtils.toInt(o.name, Integer.MIN_VALUE); @@ -198,20 +246,16 @@ public int compareTo(@NotNull LightSource o) { return 0; } - public static LightSource fromDto(LightSourceDto dto) { - var lightSource = new LightSource(); - lightSource.lightList = - dto.getLightsList().stream().map(l -> Light.fromDto(l)).collect(Collectors.toList()); - lightSource.name = dto.hasName() ? dto.getName().getValue() : null; - lightSource.id = dto.hasId() ? GUID.valueOf(dto.getId().getValue()) : null; - lightSource.type = Type.valueOf(dto.getType().name()); - lightSource.shapeType = ShapeType.valueOf(dto.getShapeType().name()); - lightSource.lumens = dto.getLumens(); - lightSource.scaleWithToken = dto.getScaleWithToken(); - return lightSource; + public static @Nonnull LightSource fromDto(@Nonnull LightSourceDto dto) { + return new LightSource( + dto.hasName() ? dto.getName().getValue() : null, + dto.hasId() ? GUID.valueOf(dto.getId().getValue()) : null, + Type.valueOf(dto.getType().name()), + dto.getScaleWithToken(), + dto.getLightsList().stream().map(Light::fromDto).toList()); } - public LightSourceDto toDto() { + public @Nonnull LightSourceDto toDto() { var dto = LightSourceDto.newBuilder(); dto.addAllLights(lightList.stream().map(l -> l.toDto()).collect(Collectors.toList())); if (name != null) { @@ -221,10 +265,6 @@ public LightSourceDto toDto() { dto.setId(StringValue.of(id.toString())); } dto.setType(LightSourceDto.LightTypeDto.valueOf(type.name())); - // default shape type - if (shapeType == null) shapeType = ShapeType.CIRCLE; - dto.setShapeType(ShapeTypeDto.valueOf(shapeType.name())); - dto.setLumens(lumens); dto.setScaleWithToken(scaleWithToken); return dto.build(); } diff --git a/src/main/java/net/rptools/maptool/tool/LightSourceCreator.java b/src/main/java/net/rptools/maptool/tool/LightSourceCreator.java index 540d914949..a6d2fe74bf 100644 --- a/src/main/java/net/rptools/maptool/tool/LightSourceCreator.java +++ b/src/main/java/net/rptools/maptool/tool/LightSourceCreator.java @@ -59,7 +59,7 @@ public static void main(String[] args) { private static LightSource createLightSource(String name, double radius, double arcAngle) { LightSource source = new LightSource(name); // source.add(new Light(0, 5, arcAngle, new DrawableColorPaint(new Color(255, 255, 0, 50)))); - source.add(new Light(ShapeType.CIRCLE, 0, radius, arcAngle, null)); + source.add(new Light(ShapeType.CIRCLE, 0, radius, arcAngle, null, 100, false, false)); return source; } @@ -67,14 +67,17 @@ private static LightSource createD20LightSource(String name, double radius, doub LightSource source = new LightSource(name); // source.add(new Light(0, 5, arcAngle, new DrawableColorPaint(new Color(255, 255, 0, 50)))); - source.add(new Light(ShapeType.CIRCLE, 0, radius, arcAngle, null)); + source.add(new Light(ShapeType.CIRCLE, 0, radius, arcAngle, null, 100, false, false)); source.add( new Light( ShapeType.CIRCLE, 0, radius * 2, arcAngle, - new DrawableColorPaint(new Color(0, 0, 0, 100)))); + new DrawableColorPaint(new Color(0, 0, 0, 100)), + 100, + false, + false)); return source; } diff --git a/src/main/proto/data_transfer_objects.proto b/src/main/proto/data_transfer_objects.proto index 87af1a80c4..686d104894 100644 --- a/src/main/proto/data_transfer_objects.proto +++ b/src/main/proto/data_transfer_objects.proto @@ -74,9 +74,7 @@ message LightSourceDto { google.protobuf.StringValue name = 2; google.protobuf.StringValue id = 3; LightTypeDto type = 4; - ShapeTypeDto shape_type = 5; - int32 lumens = 6;; - bool scale_with_token = 7; + bool scale_with_token = 5; } enum ShapeTypeDto { @@ -95,6 +93,7 @@ message LightDto { ShapeTypeDto shape = 5; bool is_gm = 6; bool owner_only = 7; + int32 lumens = 8; } message LocationDto { diff --git a/src/main/resources/net/rptools/maptool/language/i18n.properties b/src/main/resources/net/rptools/maptool/language/i18n.properties index 32c595cf45..82aad47e8a 100644 --- a/src/main/resources/net/rptools/maptool/language/i18n.properties +++ b/src/main/resources/net/rptools/maptool/language/i18n.properties @@ -635,6 +635,8 @@ Preferences.label.halo.opacity = Halo opacity Preferences.label.halo.opacity.tooltip = Measures how opaque the halo vision overlay is drawn (0-255). Preferences.label.aura.opacity = Aura opacity Preferences.label.aura.opacity.tooltip = Measures how opaque the aura overlay is drawn (0-255). +Preferences.label.lumens.opacity = Lumens overlay opacity +Preferences.label.lumens.opacity.tooltip = Measures how opaque the lumens overlay is drawn (0-255). Preferences.label.light.opacity = Light opacity Preferences.label.light.opacity.tooltip = Measures how opaque the light overlay is drawn (0-255). Preferences.label.darkness.opacity = Darkness opacity @@ -1254,6 +1256,11 @@ action.showPlayerView.accel = shift P action.showPlayerView.description = Causes your view to (mostly) show what a player would see. action.toggleDoubleWide = &Straight Line Width Doubled action.toggleDoubleWide.description = When selected the line template will draw straight lines at double width. +action.showLumensOverlay = Show Lumens Overlay +action.showLumensOverlay.description = Render the lumens levels on top of the map. +action.showLights = Show Lights +action.showLights.description = Draw lights onto the map as part of the environment. + action.toggleDrawMeasurements = Display Drawing &Distances action.toggleDrawMeasurements.description = When selected the drawing tools will display distances during drawing. action.toggleMovementLock = &Lock Player Movement @@ -2015,6 +2022,7 @@ msg.error.mtprops.light.distance = Light:line {0,number}:unrecogniz msg.error.mtprops.light.gmOrOwner = Light:line {0,number}:GM and OWNER can only be specified for auras. msg.error.mtprops.light.ioexception = Error reading Light definition from string -- shouldn't happen! msg.error.mtprops.light.lumens = Light:line {0,number}:unrecognizable lumens "{1}" +msg.error.mtprops.light.zerolumens = Light:line {0,number}: lumens must not be zero msg.error.mtprops.properties.duplicate = Property name in "{0}" duplicates the one in "{1}". msg.error.mtprops.properties.duplicateComment = The line "{0}" appears to be a comment, but duplicates "{1}" and must be unique to prevent this warning. msg.error.mtprops.properties.ending = You will be placed back into edit mode. @@ -2023,6 +2031,7 @@ msg.error.mtprops.sight.arc = Sight:line {0,number}:unrecogniz msg.error.mtprops.sight.definition = Error(s) in Sight definitions. Correct error(s) or select Cancel on the Campaign Properties dialog. msg.error.mtprops.sight.distance = Sight:line {0,number}:unrecognizable distance "{1}" msg.error.mtprops.sight.ioexception = Error reading Sight definition from string -- shouldn't happen! +msg.error.mtprops.sight.zerolumens = Sight:line {0,number}: lumens must not be zero # For parsing anything in the Campaign Properties dialog. Each tab # should have its own subcategory underneath "msg.error.mtprops"