diff --git a/gui/src/main/java/devtoolsfx/gui/Preferences.java b/gui/src/main/java/devtoolsfx/gui/Preferences.java index f3ea1fa..5093291 100644 --- a/gui/src/main/java/devtoolsfx/gui/Preferences.java +++ b/gui/src/main/java/devtoolsfx/gui/Preferences.java @@ -36,6 +36,7 @@ public class Preferences { protected final BooleanProperty ignoreMouseTransparent = new SimpleBooleanProperty(false); protected final BooleanProperty enableEventLog = new SimpleBooleanProperty(false); // non-UI protected final IntegerProperty maxEventLogSize = new SimpleIntegerProperty(DEFAULT_EVENT_LOG_SIZE); + protected final BooleanProperty darkMode = new SimpleBooleanProperty(false); protected final HostServices hostServices; @@ -206,6 +207,21 @@ public class Preferences { maxEventLogSize.set(size); } + /** + * Activates or deactivates dark mode for the dev tools UI. + */ + public BooleanProperty darkModeProperty() { + return darkMode; + } + + public boolean getDarkMode() { + return darkMode.get(); + } + + public void setDarkMode(boolean darkMode) { + this.darkMode.set(darkMode); + } + @Override public String toString() { return "Preferences{" + @@ -219,6 +235,7 @@ public class Preferences { ", ignoreMouseTransparent=" + ignoreMouseTransparent + ", enableEventLog=" + enableEventLog + ", maxEventLogSize=" + maxEventLogSize + + ", darkMode=" + darkMode + ", hostServices=" + hostServices + '}'; } diff --git a/gui/src/main/java/devtoolsfx/gui/ToolPane.java b/gui/src/main/java/devtoolsfx/gui/ToolPane.java index cc6ab92..7a302db 100644 --- a/gui/src/main/java/devtoolsfx/gui/ToolPane.java +++ b/gui/src/main/java/devtoolsfx/gui/ToolPane.java @@ -5,6 +5,7 @@ import devtoolsfx.connector.ConnectorOptions; import devtoolsfx.connector.Env; import devtoolsfx.connector.HighlightOptions; import devtoolsfx.event.*; +import devtoolsfx.gui.controls.Dialog; import devtoolsfx.gui.controls.TabLine; import devtoolsfx.gui.env.EnvironmentTab; import devtoolsfx.gui.eventlog.EventLogTab; @@ -24,6 +25,7 @@ import javafx.scene.control.Button; import javafx.scene.control.ContentDisplay; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; +import javafx.stage.Window; import javafx.util.Duration; import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; @@ -42,6 +44,7 @@ public final class ToolPane extends BorderPane { private static final Logger LOGGER = System.getLogger(ToolPane.class.getName()); private static final PseudoClass ACTIVE = PseudoClass.getPseudoClass("active"); + private static final PseudoClass DARK_MODE = PseudoClass.getPseudoClass("dark"); // we can't use close() because we are not in FXThread private final Connector connector; @@ -91,7 +94,8 @@ public final class ToolPane extends BorderPane { createLayout(); initListeners(); - getStylesheets().add(GUI.USER_AGENT_STYLESHEET); + toggleDarkMode(preferences.getDarkMode()); + tabLine.selectTab(InspectorTab.TAB_NAME); startListenToEvents(false); } @@ -247,7 +251,12 @@ public final class ToolPane extends BorderPane { LOGGER.log(Level.WARNING, Formatters.exceptionToString(e)); } - /////////////////////////////////////////////////////////////////////////// + @Override + public String getUserAgentStylesheet() { + return GUI.USER_AGENT_STYLESHEET; + } + +/////////////////////////////////////////////////////////////////////////// // UI construction // /////////////////////////////////////////////////////////////////////////// @@ -283,6 +292,8 @@ public final class ToolPane extends BorderPane { preferences.showBoundsInParentProperty().subscribe(refreshSelectionHandler); preferences.showBaselineProperty().subscribe(refreshSelectionHandler); + preferences.darkModeProperty().addListener((obs, old, val) -> toggleDarkMode(val)); + tabLine.setOnTabSelect(tab -> { switch (tab) { case InspectorTab.TAB_NAME -> inspectorTab.toFront(); @@ -377,4 +388,11 @@ public final class ToolPane extends BorderPane { } } } + + private void toggleDarkMode(boolean darkMode) { + pseudoClassStateChanged(DARK_MODE, darkMode); + Window.getWindows().stream() + .filter(w -> w instanceof Dialog>) + .forEach(dialog -> ((Dialog>) dialog).toggleDarkMode(darkMode)); + } } diff --git a/gui/src/main/java/devtoolsfx/gui/controls/Dialog.java b/gui/src/main/java/devtoolsfx/gui/controls/Dialog.java index 22e845d..e8cf872 100644 --- a/gui/src/main/java/devtoolsfx/gui/controls/Dialog.java +++ b/gui/src/main/java/devtoolsfx/gui/controls/Dialog.java @@ -1,6 +1,7 @@ package devtoolsfx.gui.controls; import devtoolsfx.gui.GUI; +import javafx.css.PseudoClass; import javafx.scene.Parent; import javafx.scene.Scene; import javafx.stage.Modality; @@ -15,32 +16,42 @@ import java.util.Objects; @NullMarked public final class Dialog
extends Stage {
+ private static final PseudoClass DARK_MODE = PseudoClass.getPseudoClass("dark");
private static final double DEFAULT_WIDTH = 640;
private static final double DEFAULT_HEIGHT = 480;
private final P root;
- public Dialog(P root) {
- this(root, "", DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ public Dialog(P root, boolean darkMode) {
+ this(root, "", DEFAULT_WIDTH, DEFAULT_HEIGHT, darkMode);
}
- public Dialog(P root, String title, double width, double height) {
+ public Dialog(P root,
+ String title,
+ double width,
+ double height,
+ boolean darkMode) {
super();
this.root = Objects.requireNonNull(root, "parent node cannot be null");
- createLayout(root, title, width, height);
+ createLayout(root, title, width, height, darkMode);
}
public P getRoot() {
return root;
}
- private void createLayout(P parent, String title, double width, double height) {
+ public void toggleDarkMode(boolean darkMode) {
+ getRoot().pseudoClassStateChanged(DARK_MODE, darkMode);
+ }
+
+ private void createLayout(P parent, String title, double width, double height, boolean darkMode) {
setTitle(title);
initModality(Modality.NONE);
var scene = new Scene(parent);
- scene.getStylesheets().add(GUI.USER_AGENT_STYLESHEET);
+ scene.setUserAgentStylesheet(GUI.USER_AGENT_STYLESHEET);
+ toggleDarkMode(darkMode);
setWidth(width);
setHeight(height);
diff --git a/gui/src/main/java/devtoolsfx/gui/env/EnvironmentTab.java b/gui/src/main/java/devtoolsfx/gui/env/EnvironmentTab.java
index 75f4c88..e3fe38c 100644
--- a/gui/src/main/java/devtoolsfx/gui/env/EnvironmentTab.java
+++ b/gui/src/main/java/devtoolsfx/gui/env/EnvironmentTab.java
@@ -52,11 +52,13 @@ public class EnvironmentTab extends VBox {
);
private @Nullable Dialog