From 9c6ecabd0bce0965d6e1e2ea7276ba9fde1f53ac Mon Sep 17 00:00:00 2001 From: ToobLac Date: Sat, 5 Sep 2026 12:36:22 +0800 Subject: [PATCH] main window mask --- .../jackhuang/hmcl/setting/StyleSheets.java | 49 ++++++++++++++++++- .../hmcl/ui/decorator/Decorator.java | 9 ++-- .../hmcl/ui/decorator/MainWindowPane.java | 15 +++++- 3 files changed, 66 insertions(+), 7 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java index 60f64c91777..813d710f4a1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/StyleSheets.java @@ -17,17 +17,25 @@ */ package org.jackhuang.hmcl.setting; +import com.jfoenix.transitions.CachedTransition; +import javafx.animation.KeyFrame; +import javafx.animation.KeyValue; +import javafx.animation.Timeline; +import javafx.animation.Transition; import javafx.beans.binding.Bindings; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.scene.Scene; import javafx.scene.paint.Color; +import javafx.util.Duration; import org.glavo.monetfx.Brightness; import org.glavo.monetfx.ColorRole; import org.glavo.monetfx.ColorScheme; import org.jackhuang.hmcl.theme.ResolvedTheme; import org.jackhuang.hmcl.theme.ThemeColor; import org.jackhuang.hmcl.theme.Themes; +import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.animation.Motion; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -54,9 +62,46 @@ public final class StyleSheets { stylesheets = FXCollections.observableList(Arrays.asList(array)); FontManager.fontProperty().addListener(o -> stylesheets.set(FONT_STYLE_SHEET_INDEX, getFontStyleSheet())); + + Transition animation; + if (!SettingsManager.settings().isAnimationDisabled()) { + var mask = Controllers.getDecorator().getMask(); + animation = new CachedTransition(mask, new Timeline( + new KeyFrame(Duration.ZERO, + new KeyValue(mask.visibleProperty(), false, Motion.LINEAR) + ), + new KeyFrame(Duration.millis(10), + new KeyValue(mask.visibleProperty(), true, Motion.LINEAR), + new KeyValue(mask.opacityProperty(), 0D, Motion.EMPHASIZED_DECELERATE) + ), + new KeyFrame(Motion.LONG2, + new KeyValue(mask.visibleProperty(), true, Motion.LINEAR), + new KeyValue(mask.opacityProperty(), 1D, Motion.EMPHASIZED_DECELERATE) + )) + ) { + { + setCycleDuration(Motion.MEDIUM2); + setDelay(Duration.ZERO); + } + }; + } else { + animation = null; + } Themes.colorSchemeProperty().addListener(o -> { - stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet()); - stylesheets.set(BRIGHTNESS_SHEET_INDEX, getBrightnessStyleSheet()); + if (animation != null) { + animation.setRate(1D); + animation.setOnFinished(e -> { + stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet()); + stylesheets.set(BRIGHTNESS_SHEET_INDEX, getBrightnessStyleSheet()); + animation.setOnFinished(null); + animation.setRate(-1D); + animation.play(); + }); + animation.play(); + } else { + stylesheets.set(THEME_STYLE_SHEET_INDEX, getThemeStyleSheet()); + stylesheets.set(BRIGHTNESS_SHEET_INDEX, getBrightnessStyleSheet()); + } }); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java index 1cb1bb8505a..607540144a5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java @@ -47,10 +47,7 @@ import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; -import javafx.scene.layout.Background; -import javafx.scene.layout.BackgroundFill; -import javafx.scene.layout.Region; -import javafx.scene.layout.StackPane; +import javafx.scene.layout.*; import javafx.scene.paint.Color; import javafx.stage.Screen; import javafx.stage.Stage; @@ -330,6 +327,10 @@ public StackPane getDialogContainer() { return mainWindowPane; } + public Pane getMask() { + return mainWindowPane.getMask(); + } + /// Returns the navigation stack rendered by the main window. /// /// @return this decorator's navigator diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java index 106d7ec2c5f..cbc094f0d7b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/MainWindowPane.java @@ -75,6 +75,9 @@ final class MainWindowPane extends StackPane { /// The transition container used when the title-bar state changes. private final TransitionPane navBarPane; + /// The mask layer that covers the stage when changing color scheme. + private final Pane mask; + /// Retains listener delegates that are registered through weak listener wrappers. @SuppressWarnings("FieldCanBeLocal") private final WeakListenerHolder holder = new WeakListenerHolder(); @@ -133,7 +136,17 @@ final class MainWindowPane extends StackPane { decorator.capableDraggingWindow(titleBar); - getChildren().setAll(backgroundNode, frame); + mask = new StackPane(); + mask.setBackground(new Background(new BackgroundFill(Color.gray(0.5D), null, null))); + mask.setVisible(false); + mask.setOpacity(0D); + mask.setPickOnBounds(false); + + getChildren().setAll(backgroundNode, frame, mask); + } + + public Pane getMask() { + return mask; } /// Updates the content-corner shape for an edge-to-edge window state.