mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2026-10-16 21:21:33 +08:00
@@ -24,8 +24,7 @@ import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.binding.BooleanBinding;
|
||||
import javafx.beans.binding.ObjectBinding;
|
||||
import javafx.beans.binding.ObjectExpression;
|
||||
import javafx.beans.property.ReadOnlyObjectProperty;
|
||||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.*;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.beans.value.ObservableValue;
|
||||
import javafx.collections.SetChangeListener;
|
||||
@@ -80,6 +79,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@@ -283,6 +283,9 @@ public final class Themes {
|
||||
colorScheme
|
||||
);
|
||||
|
||||
/// Whether the current color scheme brightness is inherited from system.
|
||||
private static final ReadOnlyBooleanWrapper autoBrightness = new ReadOnlyBooleanWrapper();
|
||||
|
||||
/// The current JavaFX launcher background and its node opacity.
|
||||
private static final ReadOnlyObjectWrapper<LauncherBackground> background = new ReadOnlyObjectWrapper<>(
|
||||
new LauncherBackground(
|
||||
@@ -380,6 +383,35 @@ public final class Themes {
|
||||
}
|
||||
|
||||
static {
|
||||
Supplier<@Nullable Brightness> effectiveBrightnessSupplier = () -> {
|
||||
try {
|
||||
return ThemePackManager.resolveCurrentThemeBrightness(ThemePackManager.currentResolveContext());
|
||||
} catch (IOException | RuntimeException e) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
InvalidationListener autoBrightnessListener = o -> {
|
||||
boolean auto;
|
||||
if (settings().getThemeAppearanceOverrides().contains(LauncherSettings.THEME_APPEARANCE_BRIGHTNESS_MODE)) {
|
||||
String val = settings().themeBrightnessModeProperty().get();
|
||||
auto = val == null || switch (val.trim().toLowerCase(Locale.ROOT)) {
|
||||
case "light", "dark" -> false;
|
||||
default -> true;
|
||||
};
|
||||
} else {
|
||||
auto = effectiveBrightnessSupplier.get() == null;
|
||||
}
|
||||
autoBrightness.set(auto);
|
||||
};
|
||||
settings().selectedThemeProperty().addListener(autoBrightnessListener);
|
||||
settings().getThemeAppearanceOverrides().addListener(autoBrightnessListener);
|
||||
settings().themeBrightnessModeProperty().addListener(autoBrightnessListener);
|
||||
settings().backgroundTypeProperty().addListener(autoBrightnessListener);
|
||||
if (FXUtils.DARK_MODE != null) {
|
||||
FXUtils.DARK_MODE.addListener(autoBrightnessListener);
|
||||
}
|
||||
autoBrightnessListener.invalidated(null);
|
||||
|
||||
ChangeListener<ResolvedTheme> listener = (observable, oldValue, newValue) -> {
|
||||
if (!Objects.equals(oldValue, newValue)) {
|
||||
colorScheme.set(newValue.toColorScheme());
|
||||
@@ -433,7 +465,7 @@ public final class Themes {
|
||||
}
|
||||
|
||||
String themeBrightnessMode = settings().themeBrightnessModeProperty().get();
|
||||
return switch (Objects.toString(themeBrightnessMode, "").toLowerCase(Locale.ROOT).trim()) {
|
||||
return switch (Objects.toString(themeBrightnessMode, "").trim().toLowerCase(Locale.ROOT)) {
|
||||
case "light" -> Brightness.LIGHT;
|
||||
case "dark" -> Brightness.DARK;
|
||||
default -> getAutomaticBrightness();
|
||||
@@ -444,24 +476,16 @@ public final class Themes {
|
||||
///
|
||||
/// @return the effective launcher brightness
|
||||
public static Brightness getCurrentBrightness() {
|
||||
Brightness contextBrightness = getThemeConditionBrightness();
|
||||
if (!settings().getThemeAppearanceOverrides().contains(LauncherSettings.THEME_APPEARANCE_BRIGHTNESS_MODE)) {
|
||||
Brightness contextBrightness = getThemeConditionBrightness();
|
||||
try {
|
||||
return Objects.requireNonNullElse(
|
||||
ThemePackManager.resolveCurrentThemeBrightness(ThemeResolveContext.current(contextBrightness)),
|
||||
contextBrightness);
|
||||
} catch (IOException | RuntimeException e) {
|
||||
return contextBrightness;
|
||||
} catch (IOException | RuntimeException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
String themeBrightnessMode = settings().themeBrightnessModeProperty().get();
|
||||
return switch (Objects.toString(themeBrightnessMode, "").toLowerCase(Locale.ROOT).trim()) {
|
||||
case "auto" -> getAutomaticBrightness();
|
||||
case "dark" -> Brightness.DARK;
|
||||
case "light" -> Brightness.LIGHT;
|
||||
default -> getAutomaticBrightness();
|
||||
};
|
||||
return contextBrightness;
|
||||
}
|
||||
|
||||
/// Returns the brightness requested by the current system or platform settings.
|
||||
@@ -1119,6 +1143,11 @@ public final class Themes {
|
||||
return darkMode;
|
||||
}
|
||||
|
||||
/// Returns whether the current color scheme brightness is inherited from system.
|
||||
public static ReadOnlyBooleanProperty autoBrightnessProperty() {
|
||||
return autoBrightness.getReadOnlyProperty();
|
||||
}
|
||||
|
||||
/// Applies native dark-mode integration to a JavaFX stage where the platform supports it.
|
||||
public static void applyNativeDarkMode(Stage stage) {
|
||||
if (OperatingSystem.SYSTEM_VERSION.isAtLeast(OSVersion.WINDOWS_11) && NativeUtils.USE_JNA && Dwmapi.INSTANCE != null) {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
package org.jackhuang.hmcl.ui;
|
||||
|
||||
import com.sun.jna.Pointer;
|
||||
import javafx.beans.property.ReadOnlyBooleanProperty;
|
||||
import org.jackhuang.hmcl.theme.Themes;
|
||||
import org.jackhuang.hmcl.util.platform.macos.ObjectiveCRuntime;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -56,8 +58,30 @@ public final class MacOSNativeUtils {
|
||||
return pointer == null || Pointer.nativeValue(pointer) == 0;
|
||||
}
|
||||
|
||||
private static final ReadOnlyBooleanProperty autoBrightness = Themes.autoBrightnessProperty();
|
||||
|
||||
static {
|
||||
FXUtils.onChange(autoBrightness, b -> setAppearance(Themes.darkModeProperty().get()));
|
||||
}
|
||||
|
||||
public static void setAppearance(boolean dark) {
|
||||
setAppearance(dark, false);
|
||||
if (autoBrightness.get()) {
|
||||
clearAppearance();
|
||||
} else {
|
||||
setAppearance(dark, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearAppearance() {
|
||||
if (nsApp == null) return;
|
||||
|
||||
try {
|
||||
var objc = ObjectiveCRuntime.INSTANCE;
|
||||
Pointer setSel = objc.sel_registerName("setAppearance:");
|
||||
objc.objc_msgSend(nsApp, setSel, Pointer.NULL);
|
||||
} catch (Throwable t) {
|
||||
LOG.warning("Failed to set macOS appearance", t);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAppearance(boolean dark, boolean highContrast) {
|
||||
|
||||
@@ -435,7 +435,7 @@ public class PersonalizationPage extends StackPane {
|
||||
LineSelectButton<String> brightnessPane = new LineSelectButton<>();
|
||||
brightnessPane.setTitle(i18n("settings.launcher.brightness"));
|
||||
brightnessPane.setConverter(name -> i18n("settings.launcher.brightness."
|
||||
+ Objects.requireNonNullElse(name, "auto")));
|
||||
+ Objects.requireNonNullElse(name, "auto").trim().toLowerCase(Locale.ROOT)));
|
||||
brightnessPane.setItems(Arrays.asList("auto", "light", "dark"));
|
||||
bindThemeAppearanceLineSelectButton(
|
||||
brightnessPane,
|
||||
|
||||
Reference in New Issue
Block a user