Streamline memory allocation options and improve preset management (#6330)
Fix #6307
This commit is contained in:
1 parent
accef4a93f
commit
74ddbf5623
2 files changed
+287
-66
No files matched your search
@@ -71,7 +71,6 @@ import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.SettingsManager.settings;
|
||||
import static org.jackhuang.hmcl.util.Pair.pair;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
@@ -107,6 +106,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
private boolean updatingJavaSetting = false;
|
||||
private boolean updatingSelectedJava = false;
|
||||
private boolean updatingParentSetting = false;
|
||||
private final ObjectProperty<GameSettings.@Nullable Preset> activeParentSetting =
|
||||
new SimpleObjectProperty<>(this, "activeParentSetting");
|
||||
|
||||
// GUI
|
||||
private final ScrollPane scrollPane;
|
||||
@@ -133,6 +134,9 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
assert settingType == GameSettings.Preset.class || settingType == GameSettings.Instance.class;
|
||||
|
||||
this.isPresetSetting = settingType == GameSettings.Preset.class;
|
||||
if (!isPresetSetting) {
|
||||
bindActiveParentSetting();
|
||||
}
|
||||
|
||||
this.scrollPane = new ScrollPane();
|
||||
scrollPane.setFitToHeight(true);
|
||||
@@ -274,9 +278,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
refreshJavaSettings();
|
||||
});
|
||||
SettingsManager.getGameSettings().addListener(weakJavaListener);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakJavaListener);
|
||||
|
||||
activeParentSetting.addListener(weakJavaListener);
|
||||
javaItem.selectedChoiceProperty().addListener((observable, oldChoice, newChoice) -> {
|
||||
S setting = currentSetting.get();
|
||||
if (setting == null || updatingSelectedJava) {
|
||||
@@ -362,6 +364,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
// Memory Setting
|
||||
@Nullable JFXButton autoMemoryButton = !isPresetSetting ? createInheritanceButton() : null;
|
||||
ObjectProperty<Boolean> memorySelectedValue = new SimpleObjectProperty<>(true);
|
||||
var memorySublist = new ComponentSublist(() -> {
|
||||
var memoryItem = new RadioChoiceList<Boolean>();
|
||||
memoryItem.setFallbackValue(true);
|
||||
@@ -381,16 +384,18 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
maxMemoryButton = createInheritanceButton();
|
||||
}
|
||||
|
||||
var options = new ArrayList<RadioChoiceList.Choice<Boolean>>();
|
||||
options.add(new RadioChoiceList.Choice<>(i18n("settings.memory.auto_allocate"), true));
|
||||
var manualMemoryEditor = new HBox(8);
|
||||
manualMemoryEditor.setAlignment(Pos.CENTER_RIGHT);
|
||||
manualMemoryEditor.getChildren().setAll(
|
||||
maxMemorySlider,
|
||||
maxMemoryTextField,
|
||||
new Label(i18n("settings.memory.unit.mib")));
|
||||
options.add(new EditorChoice<>(i18n("settings.memory.manual_allocate"), false, manualMemoryEditor, maxMemoryButton));
|
||||
memoryItem.setChoices(options);
|
||||
memoryItem.setChoices(List.of(
|
||||
new RadioChoiceList.Choice<>(i18n("settings.memory.auto_allocate"), true),
|
||||
new EditorChoice<>(i18n("settings.memory.manual_allocate"), false, manualMemoryEditor, maxMemoryButton)
|
||||
));
|
||||
memoryItem.selectedValueProperty().addListener((observable, oldValue, newValue) ->
|
||||
memorySelectedValue.set(newValue));
|
||||
|
||||
var memoryStatusBar = new MemoryStatusBar();
|
||||
|
||||
@@ -418,7 +423,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
maxMemoryButton,
|
||||
GameSettingsPage::updateInheritanceButton,
|
||||
holder,
|
||||
this::getEffectiveParentGameSettings);
|
||||
this::getEffectiveParentGameSettings,
|
||||
activeParentSetting);
|
||||
|
||||
return List.of(memoryItem, memoryStatusPane);
|
||||
});
|
||||
@@ -428,7 +434,10 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
gameSettings.getContent().add(memorySublist);
|
||||
memorySublist.setTitle(i18n("settings.memory"));
|
||||
memorySublist.setHasSubtitle(true);
|
||||
memorySublist.setDescription(i18n("settings.memory.auto_allocate"));
|
||||
memorySelectedValue.addListener((observable, oldValue, newValue) ->
|
||||
memorySublist.setDescription(getMemoryAllocationDisplayName(newValue)));
|
||||
memorySublist.setDescription(getMemoryAllocationDisplayName(memorySelectedValue.get()));
|
||||
bindMemorySelectedValue(memorySelectedValue);
|
||||
|
||||
// Launcher Visibility Setting
|
||||
var launcherVisibilityPane = createInheritableButton(
|
||||
@@ -837,18 +846,19 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
private void bindInstanceParentSetting(LineSelectButton<GameSettings.@Nullable Preset> button) {
|
||||
ObservableList<GameSettings.Preset> items = FXCollections.observableArrayList();
|
||||
ObservableList<GameSettings.Preset> presets = getAvailableParentPresets();
|
||||
InvalidationListener updateItems = observable -> {
|
||||
@Nullable GameSettings.Preset selected = button.getValue();
|
||||
items.setAll((GameSettings.Preset) null);
|
||||
items.addAll(SettingsManager.getGameSettings());
|
||||
items.addAll(presets);
|
||||
refreshInstanceParentSettingConverter(button);
|
||||
if (selected != null && SettingsManager.getGameSettings(selected.idProperty().getValue()) == null) {
|
||||
if (selected != null && getAvailableParentPreset(selected.idProperty().getValue()) == null) {
|
||||
button.setValue(null);
|
||||
}
|
||||
};
|
||||
InvalidationListener weakUpdateItems = holder.weak(updateItems);
|
||||
updateItems.invalidated(SettingsManager.getGameSettings());
|
||||
SettingsManager.getGameSettings().addListener(weakUpdateItems);
|
||||
updateItems.invalidated(presets);
|
||||
presets.addListener(weakUpdateItems);
|
||||
button.setItems(items);
|
||||
refreshInstanceParentSettingConverter(button);
|
||||
|
||||
@@ -865,7 +875,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
try {
|
||||
refreshInstanceParentSettingConverter(button);
|
||||
GameSettingsPresetID parent = setting.parentProperty().getValue();
|
||||
button.setValue(parent != null ? SettingsManager.getGameSettings(parent) : null);
|
||||
button.setValue(parent != null ? getAvailableParentPreset(parent) : null);
|
||||
} finally {
|
||||
updatingParentSetting = false;
|
||||
}
|
||||
@@ -880,6 +890,49 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
: i18n("settings.type.global.preset.default"));
|
||||
}
|
||||
|
||||
/// Returns the presets that can be selected as an instance parent.
|
||||
private ObservableList<GameSettings.Preset> getAvailableParentPresets() {
|
||||
return SettingsManager.gameSettingsPresets().getPresets();
|
||||
}
|
||||
|
||||
/// Returns the preset selected by an instance parent ID.
|
||||
private GameSettings.@Nullable Preset getAvailableParentPreset(@Nullable GameSettingsPresetID id) {
|
||||
return SettingsManager.gameSettingsPresets().getPreset(id);
|
||||
}
|
||||
|
||||
/// Keeps [#activeParentSetting] synchronized with the current instance's resolved parent preset.
|
||||
private void bindActiveParentSetting() {
|
||||
InvalidationListener refresh = observable -> refreshActiveParentSetting();
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
|
||||
getAvailableParentPresets().addListener(weakRefresh);
|
||||
SettingsManager.settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
currentSetting.addListener((observable, oldValue, newValue) -> {
|
||||
if (oldValue != null) {
|
||||
oldValue.removeListener(weakRefresh);
|
||||
}
|
||||
|
||||
if (newValue != null) {
|
||||
newValue.addListener(weakRefresh);
|
||||
}
|
||||
|
||||
refreshActiveParentSetting();
|
||||
});
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
setting.addListener(weakRefresh);
|
||||
}
|
||||
refreshActiveParentSetting();
|
||||
}
|
||||
|
||||
/// Refreshes the current instance's resolved parent preset.
|
||||
private void refreshActiveParentSetting() {
|
||||
activeParentSetting.set(currentSetting.get() instanceof GameSettings.Instance instance
|
||||
? getEffectiveParentGameSettings(instance)
|
||||
: null);
|
||||
}
|
||||
|
||||
/// Adds the title-line inheritance button for the Java selection sublist.
|
||||
private void bindJavaInheritanceButton(ComponentSublist sublist) {
|
||||
if (isPresetSetting) {
|
||||
@@ -1033,7 +1086,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
this::createInheritanceButton,
|
||||
GameSettingsPage::updateInheritanceButton,
|
||||
holder,
|
||||
this::getEffectiveParentGameSettings);
|
||||
this::getEffectiveParentGameSettings,
|
||||
activeParentSetting);
|
||||
}
|
||||
|
||||
/// Binds an integer text field to a setting property with independent override state.
|
||||
@@ -1050,7 +1104,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
this::createInheritanceButton,
|
||||
GameSettingsPage::updateInheritanceButton,
|
||||
holder,
|
||||
this::getEffectiveParentGameSettings);
|
||||
this::getEffectiveParentGameSettings,
|
||||
activeParentSetting);
|
||||
}
|
||||
|
||||
/// Binds the windowed resolution selector to the width and height settings.
|
||||
@@ -1093,6 +1148,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
};
|
||||
InvalidationListener weakPropertyListener = holder.weak(propertyListener);
|
||||
refreshHolder.value = weakPropertyListener;
|
||||
activeParentSetting.addListener(weakPropertyListener);
|
||||
|
||||
ChangeListener<@Nullable Boolean> focusedListener = (observable, oldValue, newValue) -> {
|
||||
if (!newValue) {
|
||||
@@ -1178,8 +1234,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
widthProperty.addListener(weakPropertyListener);
|
||||
heightProperty.addListener(weakPropertyListener);
|
||||
}
|
||||
SettingsManager.getGameSettings().addListener(weakPropertyListener);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakPropertyListener);
|
||||
propertyListener.invalidated(setting);
|
||||
}
|
||||
|
||||
@@ -1416,7 +1470,11 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(setting, activeParentProperty, propertyGetter, refreshHolder.value);
|
||||
updateParentInheritablePropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
refreshHolder.value);
|
||||
InheritableProperty<String> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -1434,6 +1492,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
textProperty.addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -1499,9 +1558,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
InheritableProperty<String> property = propertyGetter.apply(setting);
|
||||
@@ -1524,7 +1580,11 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(setting, activeParentProperty, propertyGetter, refreshHolder.value);
|
||||
updateParentInheritablePropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
refreshHolder.value);
|
||||
InheritableProperty<String> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -1542,6 +1602,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
textProperty.addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -1607,9 +1668,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
InheritableProperty<String> property = propertyGetter.apply(setting);
|
||||
@@ -1728,6 +1786,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
inheritButton.addEventFilter(MouseEvent.MOUSE_CLICKED, event -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -1779,9 +1838,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting instanceof GameSettings.Instance instance) {
|
||||
instance.addListener(weakRefresh);
|
||||
@@ -1825,13 +1881,96 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
}
|
||||
|
||||
/// Keeps a listener attached to the current instance's parent preset setting property.
|
||||
private <T extends @UnknownNullability Object> void updateParentSettingPropertyListener(
|
||||
@Nullable GameSettings setting,
|
||||
ObjectProperty<@Nullable SettingProperty<T>> activeParentProperty,
|
||||
Function<GameSettings, ? extends SettingProperty<T>> propertyGetter,
|
||||
InvalidationListener listener) {
|
||||
SettingProperty<T> oldParentProperty = activeParentProperty.get();
|
||||
SettingProperty<T> newParentProperty = setting instanceof GameSettings.Instance instance
|
||||
? propertyGetter.apply(getEffectiveParentGameSettings(instance))
|
||||
: null;
|
||||
if (oldParentProperty == newParentProperty) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldParentProperty != null) {
|
||||
oldParentProperty.removeListener(listener);
|
||||
}
|
||||
activeParentProperty.set(newParentProperty);
|
||||
if (newParentProperty != null) {
|
||||
newParentProperty.addListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
/// Binds the memory sublist description source to the effective automatic memory setting.
|
||||
private void bindMemorySelectedValue(ObjectProperty<Boolean> memorySelectedValue) {
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeAutoMemoryProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeParentAutoMemoryProperty = new SimpleObjectProperty<>();
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
S setting = currentSetting.get();
|
||||
updateParentSettingPropertyListener(
|
||||
setting,
|
||||
activeParentAutoMemoryProperty,
|
||||
GameSettings::autoMemoryProperty,
|
||||
refreshHolder.value);
|
||||
if (setting == null) {
|
||||
memorySelectedValue.set(true);
|
||||
return;
|
||||
}
|
||||
|
||||
memorySelectedValue.set(resolveEffectiveSetting(setting)
|
||||
.get(GameSettings::autoMemoryProperty));
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
currentSetting.addListener((observable, oldValue, newValue) -> {
|
||||
if (oldValue != null) {
|
||||
oldValue.removeListener(weakRefresh);
|
||||
}
|
||||
|
||||
SettingProperty<Boolean> oldAutoMemoryProperty = activeAutoMemoryProperty.get();
|
||||
if (oldAutoMemoryProperty != null) {
|
||||
oldAutoMemoryProperty.removeListener(weakRefresh);
|
||||
}
|
||||
|
||||
SettingProperty<Boolean> newAutoMemoryProperty = newValue != null
|
||||
? newValue.autoMemoryProperty()
|
||||
: null;
|
||||
activeAutoMemoryProperty.set(newAutoMemoryProperty);
|
||||
if (newValue != null) {
|
||||
newValue.addListener(weakRefresh);
|
||||
}
|
||||
if (newAutoMemoryProperty != null) {
|
||||
newAutoMemoryProperty.addListener(weakRefresh);
|
||||
}
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
SettingProperty<Boolean> autoMemoryProperty = setting.autoMemoryProperty();
|
||||
activeAutoMemoryProperty.set(autoMemoryProperty);
|
||||
setting.addListener(weakRefresh);
|
||||
autoMemoryProperty.addListener(weakRefresh);
|
||||
}
|
||||
refresh.invalidated(setting);
|
||||
}
|
||||
|
||||
/// Binds a radio choice list to an inheritable setting property.
|
||||
private <T> void bindInheritableRadioChoiceList(
|
||||
ComponentSublist sublist,
|
||||
RadioChoiceList<T> item,
|
||||
Function<GameSettings, InheritableProperty<T>> propertyGetter) {
|
||||
ObjectProperty<@Nullable InheritableProperty<T>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable InheritableProperty<T>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
@Nullable JFXButton inheritButton = null;
|
||||
if (!isPresetSetting) {
|
||||
inheritButton = createInheritanceButton();
|
||||
@@ -1841,6 +1980,11 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
InvalidationListener propertyListener = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
refreshHolder.value);
|
||||
InheritableProperty<T> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -1857,6 +2001,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
};
|
||||
InvalidationListener weakPropertyListener = holder.weak(propertyListener);
|
||||
refreshHolder.value = weakPropertyListener;
|
||||
activeParentSetting.addListener(weakPropertyListener);
|
||||
|
||||
ChangeListener<@Nullable T> itemListener = (observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -1921,9 +2067,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
propertyListener.invalidated(newProperty);
|
||||
});
|
||||
SettingsManager.getGameSettings().addListener(weakPropertyListener);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakPropertyListener);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
InheritableProperty<T> property = propertyGetter.apply(setting);
|
||||
@@ -1937,7 +2080,9 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
/// Binds the window type editor to the window type setting.
|
||||
private void bindWindowSettings(ComponentSublist sublist, RadioChoiceList<GameWindowType> item) {
|
||||
ObjectProperty<@Nullable InheritableProperty<GameWindowType>> activeWindowTypeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable InheritableProperty<GameWindowType>> activeParentWindowTypeProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
@Nullable JFXButton inheritButton = null;
|
||||
if (!isPresetSetting) {
|
||||
inheritButton = createInheritanceButton();
|
||||
@@ -1947,6 +2092,11 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
InvalidationListener propertyListener = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(
|
||||
setting,
|
||||
activeParentWindowTypeProperty,
|
||||
GameSettings::windowTypeProperty,
|
||||
refreshHolder.value);
|
||||
InheritableProperty<GameWindowType> property = activeWindowTypeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -1963,6 +2113,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
};
|
||||
InvalidationListener weakPropertyListener = holder.weak(propertyListener);
|
||||
refreshHolder.value = weakPropertyListener;
|
||||
activeParentSetting.addListener(weakPropertyListener);
|
||||
|
||||
item.selectedValueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -2022,9 +2174,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
propertyListener.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakPropertyListener);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakPropertyListener);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
activeWindowTypeProperty.set(setting.windowTypeProperty());
|
||||
@@ -2057,8 +2206,19 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
private <T> void bindInheritableSublistDescription(ComponentSublist sublist,
|
||||
Function<GameSettings, InheritableProperty<T>> propertyGetter,
|
||||
Function<T, String> converter) {
|
||||
InvalidationListener propertyListener = observable -> initInheritableSublistDescription(sublist, propertyGetter, converter);
|
||||
ObjectProperty<@Nullable InheritableProperty<T>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
InvalidationListener propertyListener = observable -> {
|
||||
updateParentInheritablePropertyListener(
|
||||
currentSetting.get(),
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
refreshHolder.value);
|
||||
initInheritableSublistDescription(sublist, propertyGetter, converter);
|
||||
};
|
||||
InvalidationListener weakPropertyListener = holder.weak(propertyListener);
|
||||
refreshHolder.value = weakPropertyListener;
|
||||
activeParentSetting.addListener(weakPropertyListener);
|
||||
|
||||
currentSetting.addListener((observable, oldValue, newValue) -> {
|
||||
if (oldValue != null) {
|
||||
@@ -2069,16 +2229,13 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
propertyGetter.apply(newValue).addListener(weakPropertyListener);
|
||||
}
|
||||
|
||||
initInheritableSublistDescription(sublist, propertyGetter, converter);
|
||||
propertyListener.invalidated(newValue);
|
||||
});
|
||||
SettingsManager.getGameSettings().addListener(weakPropertyListener);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakPropertyListener);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
propertyGetter.apply(setting).addListener(weakPropertyListener);
|
||||
}
|
||||
initInheritableSublistDescription(sublist, propertyGetter, converter);
|
||||
propertyListener.invalidated(setting);
|
||||
}
|
||||
|
||||
private <T> void initInheritableSublistDescription(ComponentSublist sublist,
|
||||
@@ -2093,6 +2250,13 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
sublist.setDescription(converter.apply(getEffectiveValue(setting, propertyGetter)));
|
||||
}
|
||||
|
||||
/// Returns the localized memory allocation mode display name.
|
||||
private static String getMemoryAllocationDisplayName(Boolean autoMemory) {
|
||||
return i18n(Boolean.TRUE.equals(autoMemory)
|
||||
? "settings.memory.auto_allocate"
|
||||
: "settings.memory.manual_allocate");
|
||||
}
|
||||
|
||||
private static String getWindowTypeDisplayName(GameWindowType type) {
|
||||
return switch (type) {
|
||||
case FULLSCREEN -> i18n("settings.game.window_type.fullscreen");
|
||||
@@ -2139,7 +2303,13 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
button.setOverriddenTooltip(i18n("settings.game.override_global"));
|
||||
button.setInheritAvailable(!isPresetSetting);
|
||||
|
||||
IndependentSettingBinder.bindToggleButton(currentSetting, button, propertyGetter, holder, this::getEffectiveParentGameSettings);
|
||||
IndependentSettingBinder.bindToggleButton(
|
||||
currentSetting,
|
||||
button,
|
||||
propertyGetter,
|
||||
holder,
|
||||
this::getEffectiveParentGameSettings,
|
||||
activeParentSetting);
|
||||
return button;
|
||||
}
|
||||
|
||||
@@ -2160,7 +2330,9 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
LineSelectButton<T> button,
|
||||
Function<GameSettings, InheritableProperty<T>> propertyGetter) {
|
||||
ObjectProperty<@Nullable InheritableProperty<T>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable InheritableProperty<T>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
@Nullable JFXButton inheritButton = null;
|
||||
if (!isPresetSetting) {
|
||||
inheritButton = createInheritanceButton();
|
||||
@@ -2170,6 +2342,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(setting, activeParentProperty, propertyGetter, refreshHolder.value);
|
||||
InheritableProperty<T> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -2186,6 +2359,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
button.valueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -2251,9 +2426,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
activeProperty.set(propertyGetter.apply(setting));
|
||||
@@ -2268,10 +2440,13 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
LineInheritableToggleButton button,
|
||||
Function<GameSettings, InheritableProperty<Boolean>> propertyGetter) {
|
||||
ObjectProperty<@Nullable InheritableProperty<Boolean>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable InheritableProperty<Boolean>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentInheritablePropertyListener(setting, activeParentProperty, propertyGetter, refreshHolder.value);
|
||||
InheritableProperty<Boolean> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -2280,7 +2455,9 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
updating.value = true;
|
||||
try {
|
||||
boolean overridden = isPropertyOverridden(setting, property);
|
||||
button.setRawValue(overridden ? getDirectValue(property) : getEffectiveValue(setting, propertyGetter));
|
||||
button.setRawValue(overridden
|
||||
? getDirectValue(property)
|
||||
: getEffectiveValue(setting, propertyGetter));
|
||||
button.setOverridden(overridden);
|
||||
button.setEffectiveValue(getEffectiveValue(setting, propertyGetter));
|
||||
} finally {
|
||||
@@ -2288,6 +2465,8 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
}
|
||||
};
|
||||
InvalidationListener weakRefresh = holder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
activeParentSetting.addListener(weakRefresh);
|
||||
|
||||
button.rawValueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
InheritableProperty<Boolean> property = activeProperty.get();
|
||||
@@ -2338,9 +2517,6 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
S setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
activeProperty.set(propertyGetter.apply(setting));
|
||||
@@ -2409,7 +2585,7 @@ public final class GameSettingsPage<S extends GameSettings> extends StackPane
|
||||
/// Returns the explicitly configured parent preset for an instance, falling back to the default preset.
|
||||
private GameSettings.Preset getExplicitParentGameSettings(GameSettings.Instance instance) {
|
||||
GameSettingsPresetID parent = instance.parentProperty().getValue();
|
||||
GameSettings.Preset parentSetting = SettingsManager.getGameSettings(parent);
|
||||
GameSettings.Preset parentSetting = getAvailableParentPreset(parent);
|
||||
return parentSetting != null ? parentSetting : SettingsManager.getDefaultGameSettingsPresetOrCreate();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXSlider;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
import javafx.beans.InvalidationListener;
|
||||
import javafx.beans.Observable;
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
@@ -28,7 +29,6 @@ import javafx.scene.control.Label;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import org.jackhuang.hmcl.game.HMCLGameRepository;
|
||||
import org.jackhuang.hmcl.setting.SettingsManager;
|
||||
import org.jackhuang.hmcl.setting.GameSettings;
|
||||
import org.jackhuang.hmcl.setting.property.SettingProperty;
|
||||
import org.jackhuang.hmcl.ui.MemoryStatusBar;
|
||||
@@ -48,7 +48,6 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.SettingsManager.settings;
|
||||
import static org.jackhuang.hmcl.util.DataSizeUnit.GIGABYTES;
|
||||
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
@@ -69,7 +68,8 @@ final class IndependentSettingBinder {
|
||||
Supplier<JFXButton> inheritanceButtonFactory,
|
||||
BiConsumer<JFXButton, Boolean> inheritanceButtonUpdater,
|
||||
WeakListenerHolder listenerHolder,
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter) {
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter,
|
||||
Observable parentSettingsInvalidation) {
|
||||
ObjectProperty<@Nullable SettingProperty<String>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<String>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
@@ -84,7 +84,12 @@ final class IndependentSettingBinder {
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentPropertyListener(setting, activeParentProperty, propertyGetter, parentGetter, refreshHolder.value);
|
||||
updateParentPropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
parentGetter,
|
||||
refreshHolder.value);
|
||||
SettingProperty<String> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -104,6 +109,7 @@ final class IndependentSettingBinder {
|
||||
};
|
||||
InvalidationListener weakRefresh = listenerHolder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
parentSettingsInvalidation.addListener(weakRefresh);
|
||||
|
||||
textField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -161,9 +167,12 @@ final class IndependentSettingBinder {
|
||||
Supplier<JFXButton> inheritanceButtonFactory,
|
||||
BiConsumer<JFXButton, Boolean> inheritanceButtonUpdater,
|
||||
WeakListenerHolder listenerHolder,
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter) {
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter,
|
||||
Observable parentSettingsInvalidation) {
|
||||
ObjectProperty<@Nullable SettingProperty<Integer>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Integer>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
@Nullable JFXButton inheritButton;
|
||||
if (presetSetting) {
|
||||
inheritButton = null;
|
||||
@@ -174,6 +183,12 @@ final class IndependentSettingBinder {
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentPropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
parentGetter,
|
||||
refreshHolder.value);
|
||||
SettingProperty<Integer> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -193,6 +208,8 @@ final class IndependentSettingBinder {
|
||||
}
|
||||
};
|
||||
InvalidationListener weakRefresh = listenerHolder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
parentSettingsInvalidation.addListener(weakRefresh);
|
||||
|
||||
textField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -257,12 +274,16 @@ final class IndependentSettingBinder {
|
||||
@Nullable JFXButton maxMemoryButton,
|
||||
BiConsumer<JFXButton, Boolean> inheritanceButtonUpdater,
|
||||
WeakListenerHolder listenerHolder,
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter) {
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter,
|
||||
Observable parentSettingsInvalidation) {
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeAutoMemoryProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Integer>> activeMaxMemoryProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeParentAutoMemoryProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Integer>> activeParentMaxMemoryProperty = new SimpleObjectProperty<>();
|
||||
Label physicalMemoryLabel = (Label) memoryStatusLabels.getLeft();
|
||||
Label allocatedMemoryLabel = (Label) memoryStatusLabels.getRight();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
|
||||
int totalMemoryMiB = Math.max(1, (int) MEGABYTES.convertFromBytes(SystemInfo.getTotalMemorySize()));
|
||||
maxMemorySlider.setValueFactory(slider -> Bindings.createStringBinding(
|
||||
@@ -271,6 +292,18 @@ final class IndependentSettingBinder {
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentPropertyListener(
|
||||
setting,
|
||||
activeParentAutoMemoryProperty,
|
||||
GameSettings::autoMemoryProperty,
|
||||
parentGetter,
|
||||
refreshHolder.value);
|
||||
updateParentPropertyListener(
|
||||
setting,
|
||||
activeParentMaxMemoryProperty,
|
||||
GameSettings::maxMemoryProperty,
|
||||
parentGetter,
|
||||
refreshHolder.value);
|
||||
SettingProperty<Boolean> autoMemoryProperty = activeAutoMemoryProperty.get();
|
||||
SettingProperty<Integer> maxMemoryProperty = activeMaxMemoryProperty.get();
|
||||
if (setting == null || autoMemoryProperty == null || maxMemoryProperty == null || updating.value) {
|
||||
@@ -299,6 +332,8 @@ final class IndependentSettingBinder {
|
||||
}
|
||||
};
|
||||
InvalidationListener weakRefresh = listenerHolder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
parentSettingsInvalidation.addListener(weakRefresh);
|
||||
|
||||
choiceList.selectedValueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -433,8 +468,6 @@ final class IndependentSettingBinder {
|
||||
}
|
||||
refresh.invalidated(newValue);
|
||||
});
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
memoryStatusBar.memoryStatusProperty().addListener(observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
if (setting == null) {
|
||||
@@ -468,12 +501,21 @@ final class IndependentSettingBinder {
|
||||
LineInheritableToggleButton button,
|
||||
Function<GameSettings, SettingProperty<Boolean>> propertyGetter,
|
||||
WeakListenerHolder listenerHolder,
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter) {
|
||||
Function<GameSettings.Instance, GameSettings.Preset> parentGetter,
|
||||
Observable parentSettingsInvalidation) {
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeProperty = new SimpleObjectProperty<>();
|
||||
ObjectProperty<@Nullable SettingProperty<Boolean>> activeParentProperty = new SimpleObjectProperty<>();
|
||||
final Holder<Boolean> updating = new Holder<>(false);
|
||||
final Holder<InvalidationListener> refreshHolder = new Holder<>();
|
||||
|
||||
InvalidationListener refresh = observable -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
updateParentPropertyListener(
|
||||
setting,
|
||||
activeParentProperty,
|
||||
propertyGetter,
|
||||
parentGetter,
|
||||
refreshHolder.value);
|
||||
SettingProperty<Boolean> property = activeProperty.get();
|
||||
if (setting == null || property == null || updating.value) {
|
||||
return;
|
||||
@@ -483,7 +525,9 @@ final class IndependentSettingBinder {
|
||||
try {
|
||||
boolean overridden = isOverridden(setting, property);
|
||||
Boolean effectiveValue = getEffectiveValue(setting, propertyGetter, parentGetter);
|
||||
button.setRawValue(overridden ? getDirectValue(property) : Boolean.TRUE.equals(effectiveValue));
|
||||
button.setRawValue(overridden
|
||||
? getDirectValue(property)
|
||||
: Boolean.TRUE.equals(effectiveValue));
|
||||
button.setOverridden(overridden);
|
||||
button.setEffectiveValue(Boolean.TRUE.equals(effectiveValue));
|
||||
} finally {
|
||||
@@ -491,6 +535,8 @@ final class IndependentSettingBinder {
|
||||
}
|
||||
};
|
||||
InvalidationListener weakRefresh = listenerHolder.weak(refresh);
|
||||
refreshHolder.value = weakRefresh;
|
||||
parentSettingsInvalidation.addListener(weakRefresh);
|
||||
|
||||
button.rawValueProperty().addListener((observable, oldValue, newValue) -> {
|
||||
GameSettings setting = currentSetting.get();
|
||||
@@ -503,7 +549,8 @@ final class IndependentSettingBinder {
|
||||
try {
|
||||
setOverridden(setting, property, true);
|
||||
property.setValue(newValue);
|
||||
button.setEffectiveValue(Boolean.TRUE.equals(getEffectiveValue(setting, propertyGetter, parentGetter)));
|
||||
button.setEffectiveValue(Boolean.TRUE.equals(
|
||||
getEffectiveValue(setting, propertyGetter, parentGetter)));
|
||||
} finally {
|
||||
updating.value = false;
|
||||
}
|
||||
@@ -522,7 +569,8 @@ final class IndependentSettingBinder {
|
||||
if (newValue) {
|
||||
property.setValue(button.getRawValue());
|
||||
}
|
||||
button.setEffectiveValue(Boolean.TRUE.equals(getEffectiveValue(setting, propertyGetter, parentGetter)));
|
||||
button.setEffectiveValue(Boolean.TRUE.equals(
|
||||
getEffectiveValue(setting, propertyGetter, parentGetter)));
|
||||
} finally {
|
||||
updating.value = false;
|
||||
}
|
||||
@@ -656,9 +704,6 @@ final class IndependentSettingBinder {
|
||||
}
|
||||
refresh.invalidated(newProperty);
|
||||
});
|
||||
SettingsManager.getGameSettings().addListener(weakRefresh);
|
||||
settings().defaultGameSettingsPresetProperty().addListener(weakRefresh);
|
||||
|
||||
GameSettings setting = currentSetting.get();
|
||||
if (setting != null) {
|
||||
SettingProperty<T> property = propertyGetter.apply(setting);
|
||||
|
||||
Reference in new issue
Block a user