diff --git a/core/resources/l10n/messages.properties b/core/resources/l10n/messages.properties
index 1cfdddc3f..e8dc1d512 100644
--- a/core/resources/l10n/messages.properties
+++ b/core/resources/l10n/messages.properties
@@ -403,7 +403,8 @@ PreferencesOptionPanel.checkbox.windowInfo = Export window information (position
PreferencesOptionPanel.checkbox.windowInfo.ttip = If unchecked, window information (position, size\u2026) will not be exported.
! UI Themes
-UITheme.Light = Light (Default)
+UITheme.Auto = Auto (detect)
+UITheme.Light = Light (default)
UITheme.Dark = Dark
! Welcome dialog
diff --git a/swing/.classpath b/swing/.classpath
index 5aa1c307e..763ac63b0 100644
--- a/swing/.classpath
+++ b/swing/.classpath
@@ -11,6 +11,13 @@
+
+
+
+
+
+
+
diff --git a/swing/OpenRocket Swing.iml b/swing/OpenRocket Swing.iml
index 55f1c84b1..fd79a03a1 100644
--- a/swing/OpenRocket Swing.iml
+++ b/swing/OpenRocket Swing.iml
@@ -5,6 +5,13 @@
+ $
+
+
+
+
+
+
@@ -109,9 +116,63 @@
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/swing/build.xml b/swing/build.xml
index af521340f..0a95921d1 100644
--- a/swing/build.xml
+++ b/swing/build.xml
@@ -116,6 +116,13 @@
+
+
+
+
+
+
+
diff --git a/swing/lib/annotations-24.0.1.jar b/swing/lib/annotations-24.0.1.jar
new file mode 100644
index 000000000..a4198f711
Binary files /dev/null and b/swing/lib/annotations-24.0.1.jar differ
diff --git a/swing/lib/jSystemThemeDetector-3.8.jar b/swing/lib/jSystemThemeDetector-3.8.jar
new file mode 100644
index 000000000..a8ac11f54
Binary files /dev/null and b/swing/lib/jSystemThemeDetector-3.8.jar differ
diff --git a/swing/lib/jfa-1.2.0.jar b/swing/lib/jfa-1.2.0.jar
new file mode 100644
index 000000000..2efd423eb
Binary files /dev/null and b/swing/lib/jfa-1.2.0.jar differ
diff --git a/swing/lib/jna-5.13.0.jar b/swing/lib/jna-5.13.0.jar
new file mode 100644
index 000000000..3d49c8188
Binary files /dev/null and b/swing/lib/jna-5.13.0.jar differ
diff --git a/swing/lib/jna-platform-5.13.0.jar b/swing/lib/jna-platform-5.13.0.jar
new file mode 100644
index 000000000..816a567cc
Binary files /dev/null and b/swing/lib/jna-platform-5.13.0.jar differ
diff --git a/swing/lib/oshi-core-6.4.4.jar b/swing/lib/oshi-core-6.4.4.jar
new file mode 100644
index 000000000..2e8b714f9
Binary files /dev/null and b/swing/lib/oshi-core-6.4.4.jar differ
diff --git a/swing/lib/versioncompare-1.4.1.jar b/swing/lib/versioncompare-1.4.1.jar
new file mode 100644
index 000000000..14ab48bd6
Binary files /dev/null and b/swing/lib/versioncompare-1.4.1.jar differ
diff --git a/swing/src/net/sf/openrocket/gui/dialogs/AboutDialog.java b/swing/src/net/sf/openrocket/gui/dialogs/AboutDialog.java
index 480c32367..880fdbae5 100644
--- a/swing/src/net/sf/openrocket/gui/dialogs/AboutDialog.java
+++ b/swing/src/net/sf/openrocket/gui/dialogs/AboutDialog.java
@@ -76,6 +76,7 @@ public class AboutDialog extends JDialog {
"Java library for parsing and rendering CommonMark" + href("https://github.com/commonmark/commonmark-java", true, true) + "
" +
"RSyntaxTextArea" + href("http://bobbylight.github.io/RSyntaxTextArea", true, true) + "
" +
"Darklaf (dark theme)" + href("https://github.com/weisJ/darklaf", true, true) + "
" +
+ "jSystemThemeDetector" + href("https://github.com/Dansoftowner/jSystemThemeDetector", true, true) + "
" +
"
" +
"OpenRocket gratefully acknowledges our use of the following databases:
" +
"
" +
diff --git a/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java b/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java
index 004895c02..22dd90c15 100644
--- a/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java
+++ b/swing/src/net/sf/openrocket/gui/util/SwingPreferences.java
@@ -337,8 +337,8 @@ public class SwingPreferences extends net.sf.openrocket.startup.Preferences {
}
private UITheme.Theme getUIThemeAsTheme() {
- String themeName = getString(net.sf.openrocket.startup.Preferences.UI_THEME, UITheme.Themes.LIGHT.name());
- if (themeName == null) return UITheme.Themes.LIGHT; // Default theme
+ String themeName = getString(net.sf.openrocket.startup.Preferences.UI_THEME, UITheme.Themes.AUTO.name());
+ if (themeName == null) return UITheme.Themes.AUTO; // Default theme
return UITheme.Themes.valueOf(themeName);
}
diff --git a/swing/src/net/sf/openrocket/gui/util/UITheme.java b/swing/src/net/sf/openrocket/gui/util/UITheme.java
index 43805d870..ecc1a2d1a 100644
--- a/swing/src/net/sf/openrocket/gui/util/UITheme.java
+++ b/swing/src/net/sf/openrocket/gui/util/UITheme.java
@@ -2,6 +2,7 @@ package net.sf.openrocket.gui.util;
import com.github.weisj.darklaf.LafManager;
import com.github.weisj.darklaf.theme.DarculaTheme;
+import com.jthemedetecor.OsThemeDetector;
import net.sf.openrocket.l10n.Translator;
import net.sf.openrocket.startup.Application;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
@@ -10,14 +11,17 @@ import org.slf4j.LoggerFactory;
import javax.swing.BorderFactory;
import javax.swing.Icon;
+import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.Border;
import java.awt.Color;
import java.awt.Font;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
public class UITheme {
private static final Translator trans = Application.getTranslator();
@@ -527,6 +531,243 @@ public class UITheme {
log.warn("Unable to load RSyntaxTextArea theme", ioe);
}
}
+ },
+ AUTO {
+ private final String displayName = trans.get("UITheme.Auto");
+
+ private Theme getCurrentTheme() {
+ try {
+ final OsThemeDetector detector = OsThemeDetector.getDetector();
+ final boolean isDarkThemeUsed = detector.isDark();
+ if (isDarkThemeUsed) {
+ return Themes.DARK;
+ } else {
+ return Themes.LIGHT;
+ }
+ } catch (Exception ignore) {}
+
+ return Themes.LIGHT;
+ }
+
+ @Override
+ public void applyTheme() {
+ getCurrentTheme().applyTheme();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public Color getBackgroundColor() {
+ return getCurrentTheme().getBackgroundColor();
+ }
+
+ @Override
+ public Color getBorderColor() {
+ return getCurrentTheme().getBorderColor();
+ }
+
+ @Override
+ public Color getTextColor() {
+ return getCurrentTheme().getTextColor();
+ }
+
+ @Override
+ public Color getDimTextColor() {
+ return getCurrentTheme().getDimTextColor();
+ }
+
+ @Override
+ public Color getTextSelectionForegroundColor() {
+ return getCurrentTheme().getTextSelectionForegroundColor();
+ }
+
+ @Override
+ public Color getTextSelectionBackgroundColor() {
+ return getCurrentTheme().getTextSelectionBackgroundColor();
+ }
+
+ @Override
+ public Color getWarningColor() {
+ return getCurrentTheme().getWarningColor();
+ }
+
+ @Override
+ public Color getDarkWarningColor() {
+ return getCurrentTheme().getDarkWarningColor();
+ }
+
+ @Override
+ public Color getRowBackgroundLighterColor() {
+ return getCurrentTheme().getRowBackgroundLighterColor();
+ }
+
+ @Override
+ public Color getRowBackgroundDarkerColor() {
+ return getCurrentTheme().getRowBackgroundDarkerColor();
+ }
+
+ @Override
+ public Color getFlightDataTextActiveColor() {
+ return getCurrentTheme().getFlightDataTextActiveColor();
+ }
+
+ @Override
+ public Color getFlightDataTextInactiveColor() {
+ return getCurrentTheme().getFlightDataTextInactiveColor();
+ }
+
+ @Override
+ public String getDefaultBodyComponentColor() {
+ return getCurrentTheme().getDefaultBodyComponentColor();
+ }
+
+ @Override
+ public String getDefaultTubeFinSetColor() {
+ return getCurrentTheme().getDefaultTubeFinSetColor();
+ }
+
+ @Override
+ public String getDefaultFinSetColor() {
+ return getCurrentTheme().getDefaultFinSetColor();
+ }
+
+ @Override
+ public String getDefaultLaunchLugColor() {
+ return getCurrentTheme().getDefaultLaunchLugColor();
+ }
+
+ @Override
+ public String getDefaultRailButtonColor() {
+ return getCurrentTheme().getDefaultRailButtonColor();
+ }
+
+ @Override
+ public String getDefaultInternalComponentColor() {
+ return getCurrentTheme().getDefaultInternalComponentColor();
+ }
+
+ @Override
+ public String getDefaultMassObjectColor() {
+ return getCurrentTheme().getDefaultMassObjectColor();
+ }
+
+ @Override
+ public String getDefaultRecoveryDeviceColor() {
+ return getCurrentTheme().getDefaultRecoveryDeviceColor();
+ }
+
+ @Override
+ public String getDefaultPodSetColor() {
+ return getCurrentTheme().getDefaultPodSetColor();
+ }
+
+ @Override
+ public String getDefaultParallelStageColor() {
+ return getCurrentTheme().getDefaultParallelStageColor();
+ }
+
+ @Override
+ public Color getMotorBorderColor() {
+ return getCurrentTheme().getMotorBorderColor();
+ }
+
+ @Override
+ public Color getMotorFillColor() {
+ return getCurrentTheme().getMotorFillColor();
+ }
+
+ @Override
+ public Color getCGColor() {
+ return getCurrentTheme().getCGColor();
+ }
+
+ @Override
+ public Color getCPColor() {
+ return getCurrentTheme().getCPColor();
+ }
+
+ @Override
+ public Color getURLColor() {
+ return getCurrentTheme().getURLColor();
+ }
+
+ @Override
+ public Color getComponentTreeBackgroundColor() {
+ return getCurrentTheme().getComponentTreeBackgroundColor();
+ }
+
+ @Override
+ public Color getComponentTreeForegroundColor() {
+ return getCurrentTheme().getComponentTreeForegroundColor();
+ }
+
+ @Override
+ public Color getFinPointGridMajorLineColor() {
+ return getCurrentTheme().getFinPointGridMajorLineColor();
+ }
+
+ @Override
+ public Color getFinPointGridMinorLineColor() {
+ return getCurrentTheme().getFinPointGridMinorLineColor();
+ }
+
+ @Override
+ public Color getFinPointPointColor() {
+ return getCurrentTheme().getFinPointPointColor();
+ }
+
+ @Override
+ public Color getFinPointSelectedPointColor() {
+ return getCurrentTheme().getFinPointSelectedPointColor();
+ }
+
+ @Override
+ public Color getFinPointBodyLineColor() {
+ return getCurrentTheme().getFinPointBodyLineColor();
+ }
+
+ @Override
+ public Icon getMassOverrideIcon() {
+ return getCurrentTheme().getMassOverrideIcon();
+ }
+
+ @Override
+ public Icon getMassOverrideSubcomponentIcon() {
+ return getCurrentTheme().getMassOverrideSubcomponentIcon();
+ }
+
+ @Override
+ public Icon getCGOverrideIcon() {
+ return getCurrentTheme().getCGOverrideIcon();
+ }
+
+ @Override
+ public Icon getCGOverrideSubcomponentIcon() {
+ return getCurrentTheme().getCGOverrideSubcomponentIcon();
+ }
+
+ @Override
+ public Icon getCDOverrideIcon() {
+ return getCurrentTheme().getCDOverrideIcon();
+ }
+
+ @Override
+ public Icon getCDOverrideSubcomponentIcon() {
+ return getCurrentTheme().getCDOverrideSubcomponentIcon();
+ }
+
+ @Override
+ public Border getBorder() {
+ return getCurrentTheme().getBorder();
+ }
+
+ @Override
+ public void formatScriptTextArea(RSyntaxTextArea textArea) {
+ getCurrentTheme().formatScriptTextArea(textArea);
+ }
}
}