使用 LineSelectButton 代替 JFXComboxBox (#5337)

This commit is contained in:
Glavo
2026-01-29 20:28:45 +08:00
committed by GitHub
parent 90a795b2c8
commit e3231859ea
25 changed files with 797 additions and 394 deletions

View File

@@ -137,7 +137,7 @@ public class JFXPopup extends PopupControl {
boolean isRTL = node.getEffectiveNodeOrientation() == NodeOrientation.RIGHT_TO_LEFT;
this.show(parent,
this.show(node,
parent.getX() + scene.getX() + origin.getX() + (hAlign == PopupHPosition.RIGHT ? ((Region) node).getWidth() : 0),
parent.getY() + origin.getY() + scene.getY() + (vAlign == PopupVPosition.BOTTOM ? ((Region) node).getHeight() : 0)
);

View File

@@ -123,6 +123,7 @@ public enum SVG {
TEXTURE("M4.4-3Q3.925-3.1 3.5125-3.5125T3-4.4L19.6-21Q20.125-20.875 20.5-20.4875T21.025-19.6L4.4-3ZM3-9.3V-12.1L11.9-21H14.7L3-9.3ZM3-17V-19Q3-19.825 3.5875-20.4125T5-21H7L3-17ZM17-3 21-7V-5Q21-4.175 20.4125-3.5875T19-3H17ZM9.3-3 21-14.7V-11.9L12.1-3H9.3Z"),
TRIP("M4 21Q3.175 21 2.5875 20.4125T2 19V8Q2 7.175 2.5875 6.5875T4 6H8V4Q8 3.175 8.5875 2.5875T10 2H14Q14.825 2 15.4125 2.5875T16 4V6H20Q20.825 6 21.4125 6.5875T22 8V19Q22 19.825 21.4125 20.4125T20 21H4ZM10 6H14V4H10V6ZM6 8H4V19H6V8ZM16 19V8H8V19H16ZM18 8V19H20V8H18ZM12 13.5Z"),
TUNE("M11 21V15H13V17H21V19H13V21H11ZM3 19V17H9V19H3ZM7 15V13H3V11H7V9H9V15H7ZM11 13V11H21V13H11ZM15 9V3H17V5H21V7H17V9H15ZM3 7V5H13V7H3Z"),
UNFOLD_MORE("M12 21 7.5 16.5l1.45-1.45L12 18.1l3.05-3.05 1.45 1.45L12 21ZM8.95 9.05 7.5 7.6 12 3.1l4.5 4.5-1.45 1.45L12 6 8.95 9.05Z"),
UPDATE("M12 21Q10.125 21 8.4875 20.2875T5.6375 18.3625Q4.425 17.15 3.7125 15.5125T3 12Q3 10.125 3.7125 8.4875T5.6375 5.6375Q6.85 4.425 8.4875 3.7125T12 3Q14.05 3 15.8875 3.875T19 6.35V4H21V10H15V8H17.75Q16.725 6.6 15.225 5.8T12 5Q9.075 5 7.0375 7.0375T5 12Q5 14.925 7.0375 16.9625T12 19Q14.625 19 16.5875 17.3T18.9 13H20.95Q20.575 16.425 18.0125 18.7125T12 21ZM14.8 16.2 11 12.4V7H13V11.6L16.2 14.8 14.8 16.2Z"),
UNDO("M8 19q-.425 0-.712-.288T7 18t.288-.712T8 17h6.1q1.575 0 2.738-1T18 13.5T16.838 11T14.1 10H7.8l1.9 1.9q.275.275.275.7t-.275.7t-.7.275t-.7-.275L4.7 9.7q-.15-.15-.213-.325T4.426 9t.063-.375T4.7 8.3l3.6-3.6q.275-.275.7-.275t.7.275t.275.7t-.275.7L7.8 8h6.3q2.425 0 4.163 1.575T20 13.5t-1.737 3.925T14.1 19z"),
VISIBILITY("M12 16q1.875 0 3.1875-1.3125T16.5 11.5 15.1875 8.3125 12 7 8.8125 8.3125 7.5 11.5t1.3125 3.1875T12 16Zm0-1.8q-1.125 0-1.9125-.7875T9.3 11.5t.7875-1.9125T12 8.8q1.125 0 1.9125.7875T14.7 11.5q0 1.125-.7875 1.9125T12 14.2ZM12 19q-3.65 0-6.65-2.0375T1 11.5Q2.35 8.075 5.35 6.0375T12 4q3.65 0 6.65 2.0375T23 11.5q-1.35 3.425-4.35 5.4625T12 19Zm0-7.5ZM12 17q2.825 0 5.1875-1.4875T20.8 11.5q-1.25-2.525-3.6125-4.0125T12 6 6.8125 7.4875 3.2 11.5q1.25 2.525 3.6125 4.0125T12 17Z"),

View File

@@ -142,7 +142,7 @@ public class ComponentList extends Control {
if (node.getProperties().containsKey("ComponentList.vgrow")) {
VBox.setVgrow(cell, (Priority) node.getProperties().get("ComponentList.vgrow"));
}
if (node.getProperties().containsKey("ComponentList.noPadding")) {
if (node instanceof LineButtonBase || node.getProperties().containsKey("ComponentList.noPadding")) {
cell.getStyleClass().add("no-padding");
}
return cell;

View File

@@ -0,0 +1,123 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.StringPropertyBase;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
/// @author Glavo
public abstract class LineButtonBase extends StackPane {
private static final Insets PADDING = new Insets(8, 8, 8, 16);
protected final BorderPane root;
protected final RipplerContainer container;
private final Label titleLabel;
public LineButtonBase() {
this.root = new BorderPane();
root.setPadding(PADDING);
root.setMinHeight(48);
this.container = new RipplerContainer(root);
this.getChildren().setAll(container);
this.titleLabel = new Label();
root.setCenter(titleLabel);
BorderPane.setAlignment(titleLabel, Pos.CENTER_LEFT);
titleLabel.textProperty().bind(titleProperty());
titleLabel.getStyleClass().add("title");
}
private final StringProperty title = new SimpleStringProperty(this, "title");
public StringProperty titleProperty() {
return title;
}
public String getTitle() {
return titleProperty().get();
}
public void setTitle(String title) {
this.titleProperty().set(title);
}
private StringProperty subtitle;
public StringProperty subtitleProperty() {
if (subtitle == null) {
subtitle = new StringPropertyBase() {
private VBox left;
private Label subtitleLabel;
@Override
public String getName() {
return "subtitle";
}
@Override
public Object getBean() {
return LineButtonBase.this;
}
@Override
protected void invalidated() {
String subtitle = get();
if (subtitle != null && !subtitle.isEmpty()) {
if (left == null) {
left = new VBox();
left.setMouseTransparent(true);
left.setAlignment(Pos.CENTER_LEFT);
subtitleLabel = new Label();
subtitleLabel.setWrapText(true);
subtitleLabel.setMinHeight(Region.USE_PREF_SIZE);
subtitleLabel.getStyleClass().add("subtitle");
}
subtitleLabel.setText(subtitle);
left.getChildren().setAll(titleLabel, subtitleLabel);
root.setCenter(left);
} else if (left != null) {
subtitleLabel.setText(null);
root.setCenter(titleLabel);
}
}
};
}
return subtitle;
}
public String getSubtitle() {
return subtitleProperty().get();
}
public void setSubtitle(String subtitle) {
subtitleProperty().set(subtitle);
}
}

View File

@@ -0,0 +1,112 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ObjectPropertyBase;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.HBox;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
/// @author Glavo
public final class LineNavigationButton extends LineButtonBase {
private static final String DEFAULT_STYLE_CLASS = "line-navigation-button";
public LineNavigationButton() {
getStyleClass().add(DEFAULT_STYLE_CLASS);
root.setMouseTransparent(true);
HBox right = new HBox();
root.setRight(right);
{
right.setAlignment(Pos.CENTER_RIGHT);
Label valueLabel = new Label();
valueLabel.getStyleClass().add("subtitle");
valueLabel.textProperty().bind(messageProperty());
Node arrowIcon = SVG.ARROW_FORWARD.createIcon(24);
HBox.setMargin(arrowIcon, new Insets(0, 8, 0, 8));
disabledProperty().addListener((observable, oldValue, newValue) ->
arrowIcon.setOpacity(newValue ? 0.4 : 1.0));
right.getChildren().setAll(valueLabel, arrowIcon);
}
FXUtils.onClicked(container, this::fire);
}
public void fire() {
fireEvent(new ActionEvent());
}
private final ObjectProperty<EventHandler<ActionEvent>> onAction = new ObjectPropertyBase<>() {
@Override
protected void invalidated() {
setEventHandler(ActionEvent.ACTION, get());
}
@Override
public Object getBean() {
return LineNavigationButton.this;
}
@Override
public String getName() {
return "onAction";
}
};
public ObjectProperty<EventHandler<ActionEvent>> onActionProperty() {
return onAction;
}
public EventHandler<ActionEvent> getOnAction() {
return onActionProperty().get();
}
public void setOnAction(EventHandler<ActionEvent> value) {
onActionProperty().set(value);
}
private final StringProperty message = new SimpleStringProperty(this, "message", "");
public StringProperty messageProperty() {
return message;
}
public String getMessage() {
return messageProperty().get();
}
public void setMessage(String message) {
messageProperty().set(message);
}
}

View File

@@ -0,0 +1,231 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2026 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXPopup;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.*;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
import java.util.Collection;
import java.util.Objects;
import java.util.function.Function;
import static org.jackhuang.hmcl.ui.FXUtils.determineOptimalPopupPosition;
/// @author Glavo
public final class LineSelectButton<T> extends LineButtonBase {
private static final String DEFAULT_STYLE_CLASS = "line-select-button";
private static final PseudoClass SELECTED_PSEUDO_CLASS = PseudoClass.getPseudoClass("selected");
private JFXPopup popup;
public LineSelectButton() {
this.getStyleClass().add(DEFAULT_STYLE_CLASS);
root.setMouseTransparent(true);
HBox right = new HBox();
root.setRight(right);
{
right.setAlignment(Pos.CENTER_RIGHT);
Label valueLabel = new Label();
valueLabel.getStyleClass().add("subtitle");
InvalidationListener updateValue = observable -> {
T value = getValue();
if (value == null)
valueLabel.setText("");
else {
Function<T, String> converter = getConverter();
valueLabel.setText(converter != null ? converter.apply(value) : value.toString());
}
};
converterProperty().addListener(updateValue);
valueProperty().addListener(updateValue);
Node arrowIcon = SVG.UNFOLD_MORE.createIcon(24);
HBox.setMargin(arrowIcon, new Insets(0, 8, 0, 8));
right.getChildren().setAll(valueLabel, arrowIcon);
}
container.addEventHandler(MouseEvent.MOUSE_CLICKED, event -> {
if (event.getButton() == MouseButton.PRIMARY) {
if (popup == null) {
PopupMenu popupMenu = new PopupMenu();
this.popup = new JFXPopup(popupMenu);
container.addEventFilter(ScrollEvent.ANY, ignored -> popup.hide());
Bindings.bindContent(popupMenu.getContent(), MappedObservableList.create(itemsProperty(), item -> {
VBox vbox = new VBox();
var itemTitleLabel = new Label();
itemTitleLabel.getStyleClass().add("title");
itemTitleLabel.textProperty().bind(Bindings.createStringBinding(() -> {
if (item == null)
return "";
Function<T, String> converter = getConverter();
return converter != null ? converter.apply(item) : Objects.toString(item, "");
}, converterProperty()));
var itemSubtitleLabel = new Label();
itemSubtitleLabel.getStyleClass().add("subtitle");
itemSubtitleLabel.textProperty().bind(Bindings.createStringBinding(() -> {
Function<T, String> descriptionConverter = getDescriptionConverter();
return descriptionConverter != null ? descriptionConverter.apply(item) : "";
}, descriptionConverterProperty()));
FXUtils.onChangeAndOperate(itemSubtitleLabel.textProperty(), text -> {
if (text == null || text.isEmpty()) {
vbox.getChildren().setAll(itemTitleLabel);
} else {
vbox.getChildren().setAll(itemTitleLabel, itemSubtitleLabel);
}
});
var wrapper = new StackPane(vbox);
wrapper.setAlignment(Pos.CENTER_LEFT);
wrapper.getStyleClass().add("menu-container");
wrapper.setMouseTransparent(true);
RipplerContainer ripplerContainer = new RipplerContainer(wrapper);
FXUtils.onClicked(ripplerContainer, () -> {
setValue(item);
popup.hide();
});
FXUtils.onChangeAndOperate(valueProperty(),
value -> wrapper.pseudoClassStateChanged(SELECTED_PSEUDO_CLASS, Objects.equals(value, item)));
return ripplerContainer;
}));
popup.showingProperty().addListener((observable, oldValue, newValue) ->
container.getRippler().setRipplerDisabled(newValue));
}
if (popup.isShowing()) {
popup.hide();
} else {
JFXPopup.PopupVPosition vPosition = determineOptimalPopupPosition(this, popup);
popup.show(this, vPosition, JFXPopup.PopupHPosition.RIGHT,
0,
vPosition == JFXPopup.PopupVPosition.TOP ? this.getHeight() : -this.getHeight());
}
event.consume();
} else if (event.getButton() == MouseButton.SECONDARY) {
if (popup != null)
popup.hide();
event.consume();
}
});
}
private final ObjectProperty<T> value = new SimpleObjectProperty<>(this, "value");
public ObjectProperty<T> valueProperty() {
return value;
}
public T getValue() {
return valueProperty().get();
}
public void setValue(T value) {
valueProperty().set(value);
}
private final ObjectProperty<Function<T, String>> converter = new SimpleObjectProperty<>(this, "converter");
public ObjectProperty<Function<T, String>> converterProperty() {
return converter;
}
public Function<T, String> getConverter() {
return converterProperty().get();
}
public void setConverter(Function<T, String> value) {
converterProperty().set(value);
}
private ObjectProperty<Function<T, String>> descriptionConverter;
public ObjectProperty<Function<T, String>> descriptionConverterProperty() {
if (descriptionConverter == null) {
descriptionConverter = new SimpleObjectProperty<>(this, "descriptionConverter");
}
return descriptionConverter;
}
public Function<T, String> getDescriptionConverter() {
return descriptionConverterProperty().get();
}
public void setDescriptionConverter(Function<T, String> value) {
descriptionConverterProperty().set(value);
}
private final ListProperty<T> items = new SimpleListProperty<>(this, "items", FXCollections.emptyObservableList());
public ListProperty<T> itemsProperty() {
return items;
}
public void setItems(ObservableList<T> value) {
itemsProperty().set(value);
}
public void setItems(Collection<T> value) {
if (value instanceof ObservableList<T> observableList) {
this.setItems(observableList);
} else {
this.setItems(FXCollections.observableArrayList(value));
}
}
@SafeVarargs
public final void setItems(T... values) {
this.setItems(FXCollections.observableArrayList(values));
}
public ObservableList<T> getItems() {
return items.get();
}
}

View File

@@ -0,0 +1,57 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXToggleButton;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.geometry.Pos;
import javafx.scene.layout.BorderPane;
import org.jackhuang.hmcl.ui.FXUtils;
public final class LineToggleButton extends LineButtonBase {
private static final String DEFAULT_STYLE_CLASS = "line-toggle-button";
public LineToggleButton() {
this.getStyleClass().add(DEFAULT_STYLE_CLASS);
JFXToggleButton toggleButton = new JFXToggleButton();
toggleButton.selectedProperty().bindBidirectional(selectedProperty());
toggleButton.setSize(8);
FXUtils.setLimitHeight(toggleButton, 30);
BorderPane.setAlignment(toggleButton, Pos.CENTER);
root.setRight(toggleButton);
FXUtils.onClicked(container, toggleButton::fire);
}
private final BooleanProperty selected = new SimpleBooleanProperty(this, "selected");
public BooleanProperty selectedProperty() {
return selected;
}
public boolean isSelected() {
return selectedProperty().get();
}
public void setSelected(boolean selected) {
selectedProperty().set(selected);
}
}

View File

@@ -1,113 +0,0 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2021 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.ui.construct;
import com.jfoenix.controls.JFXToggleButton;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.util.StringUtils;
public class OptionToggleButton extends StackPane {
private final StringProperty title = new SimpleStringProperty();
private final StringProperty subtitle = new SimpleStringProperty();
private final BooleanProperty selected = new SimpleBooleanProperty();
public OptionToggleButton() {
getProperties().put("ComponentList.noPadding", true);
BorderPane pane = new BorderPane();
pane.setPadding(new Insets(8, 8, 8, 16));
RipplerContainer container = new RipplerContainer(pane);
getChildren().setAll(container);
VBox left = new VBox();
left.setMouseTransparent(true);
Label titleLabel = new Label();
titleLabel.textProperty().bind(title);
Label subtitleLabel = new Label();
subtitleLabel.setWrapText(true);
subtitleLabel.setMouseTransparent(true);
subtitleLabel.getStyleClass().add("subtitle");
subtitleLabel.textProperty().bind(subtitle);
pane.setCenter(left);
left.setAlignment(Pos.CENTER_LEFT);
JFXToggleButton toggleButton = new JFXToggleButton();
StackPane right = new StackPane(toggleButton);
right.setAlignment(Pos.CENTER);
pane.setRight(right);
toggleButton.selectedProperty().bindBidirectional(selected);
toggleButton.setSize(8);
FXUtils.setLimitHeight(toggleButton, 30);
FXUtils.onClicked(container, () -> toggleButton.setSelected(!toggleButton.isSelected()));
FXUtils.onChangeAndOperate(subtitleProperty(), subtitle -> {
if (StringUtils.isNotBlank(subtitle)) {
left.getChildren().setAll(titleLabel, subtitleLabel);
} else {
left.getChildren().setAll(titleLabel);
}
});
}
public String getTitle() {
return title.get();
}
public StringProperty titleProperty() {
return title;
}
public void setTitle(String title) {
this.title.set(title);
}
public String getSubtitle() {
return subtitle.get();
}
public StringProperty subtitleProperty() {
return subtitle;
}
public void setSubtitle(String subtitle) {
this.subtitle.set(subtitle);
}
public boolean isSelected() {
return selected.get();
}
public BooleanProperty selectedProperty() {
return selected;
}
public void setSelected(boolean selected) {
this.selected.set(selected);
}
}

View File

@@ -158,6 +158,10 @@ public class RipplerContainer extends StackPane {
updateChildren();
}
public JFXRippler getRippler() {
return buttonRippler;
}
public Node getContainer() {
return container.get();
}

View File

@@ -31,15 +31,15 @@ import org.jackhuang.hmcl.task.FetchTask;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.WeakListenerHolder;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
import java.net.Proxy;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
public class DownloadSettingsPage extends StackPane {
@@ -55,51 +55,37 @@ public class DownloadSettingsPage extends StackPane {
getChildren().setAll(scrollPane);
{
VBox downloadSource = new VBox(8);
var downloadSource = new ComponentList();
downloadSource.getStyleClass().add("card-non-transparent");
{
VBox chooseWrapper = new VBox();
chooseWrapper.setPadding(new Insets(8, 0, 8, 0));
JFXCheckBox chkAutoChooseDownloadSource = new JFXCheckBox(i18n("settings.launcher.download_source.auto"));
chkAutoChooseDownloadSource.selectedProperty().bindBidirectional(config().autoChooseDownloadTypeProperty());
chooseWrapper.getChildren().setAll(chkAutoChooseDownloadSource);
var autoChooseDownloadSource = new LineToggleButton();
autoChooseDownloadSource.setTitle(i18n("settings.launcher.download_source.auto"));
autoChooseDownloadSource.selectedProperty().bindBidirectional(config().autoChooseDownloadTypeProperty());
BorderPane versionListSourcePane = new BorderPane();
versionListSourcePane.setPadding(new Insets(0, 0, 8, 30));
versionListSourcePane.disableProperty().bind(chkAutoChooseDownloadSource.selectedProperty().not());
{
Label label = new Label(i18n("settings.launcher.version_list_source"));
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
versionListSourcePane.setLeft(label);
Function<String, String> converter = key -> i18n("download.provider." + key);
Function<String, String> descriptionConverter = key -> {
String bundleKey = "download.provider." + key + ".desc";
return I18n.hasKey(bundleKey) ? i18n(bundleKey) : null;
};
JFXComboBox<String> cboVersionListSource = new JFXComboBox<>();
cboVersionListSource.setConverter(stringConverter(key -> i18n("download.provider." + key)));
versionListSourcePane.setRight(cboVersionListSource);
FXUtils.setLimitWidth(cboVersionListSource, 400);
var versionListSourcePane = new LineSelectButton<String>();
versionListSourcePane.disableProperty().bind(autoChooseDownloadSource.selectedProperty().not());
versionListSourcePane.setTitle(i18n("settings.launcher.version_list_source"));
versionListSourcePane.setConverter(converter);
versionListSourcePane.setDescriptionConverter(descriptionConverter);
versionListSourcePane.setItems(DownloadProviders.AUTO_PROVIDERS.keySet());
versionListSourcePane.valueProperty().bindBidirectional(config().versionListSourceProperty());
cboVersionListSource.getItems().setAll(DownloadProviders.AUTO_PROVIDERS.keySet());
selectedItemPropertyFor(cboVersionListSource).bindBidirectional(config().versionListSourceProperty());
}
var downloadSourcePane = new LineSelectButton<String>();
downloadSourcePane.disableProperty().bind(autoChooseDownloadSource.selectedProperty());
downloadSourcePane.setTitle(i18n("settings.launcher.download_source"));
downloadSourcePane.setConverter(converter);
downloadSourcePane.setDescriptionConverter(descriptionConverter);
downloadSourcePane.setItems(DownloadProviders.DIRECT_PROVIDERS.keySet());
downloadSourcePane.valueProperty().bindBidirectional(config().downloadTypeProperty());
BorderPane downloadSourcePane = new BorderPane();
downloadSourcePane.setPadding(new Insets(0, 0, 8, 30));
downloadSourcePane.disableProperty().bind(chkAutoChooseDownloadSource.selectedProperty());
{
Label label = new Label(i18n("settings.launcher.download_source"));
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
downloadSourcePane.setLeft(label);
JFXComboBox<String> cboDownloadSource = new JFXComboBox<>();
cboDownloadSource.setConverter(stringConverter(key -> i18n("download.provider." + key)));
downloadSourcePane.setRight(cboDownloadSource);
FXUtils.setLimitWidth(cboDownloadSource, 420);
cboDownloadSource.getItems().setAll(DownloadProviders.DIRECT_PROVIDERS.keySet());
selectedItemPropertyFor(cboDownloadSource).bindBidirectional(config().downloadTypeProperty());
}
downloadSource.getChildren().setAll(chooseWrapper, versionListSourcePane, downloadSourcePane);
downloadSource.getContent().setAll(autoChooseDownloadSource, versionListSourcePane, downloadSourcePane);
}
content.getChildren().addAll(ComponentList.createComponentListTitle(i18n("settings.launcher.download_source")), downloadSource);

View File

@@ -25,7 +25,6 @@ import javafx.beans.binding.StringBinding;
import javafx.beans.binding.When;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.ColorPicker;
@@ -78,19 +77,13 @@ public class PersonalizationPage extends StackPane {
ComponentList themeList = new ComponentList();
{
BorderPane brightnessPane = new BorderPane();
var brightnessPane = new LineSelectButton<String>();
brightnessPane.setTitle(i18n("settings.launcher.brightness"));
brightnessPane.setConverter(name -> i18n("settings.launcher.brightness." + name));
brightnessPane.setItems("auto", "light", "dark");
brightnessPane.valueProperty().bindBidirectional(config().themeBrightnessProperty());
themeList.getContent().add(brightnessPane);
Label left = new Label(i18n("settings.launcher.brightness"));
BorderPane.setAlignment(left, Pos.CENTER_LEFT);
brightnessPane.setLeft(left);
JFXComboBox<String> cboBrightness = new JFXComboBox<>();
cboBrightness.getItems().setAll("auto", "light", "dark");
cboBrightness.setConverter(FXUtils.stringConverter(name -> i18n("settings.launcher.brightness." + name)));
cboBrightness.valueProperty().bindBidirectional(config().themeBrightnessProperty());
brightnessPane.setRight(cboBrightness);
}
{
@@ -112,13 +105,13 @@ public class PersonalizationPage extends StackPane {
Platform.runLater(() -> JFXDepthManager.setDepth(picker, 0));
}
{
OptionToggleButton titleTransparentButton = new OptionToggleButton();
LineToggleButton titleTransparentButton = new LineToggleButton();
themeList.getContent().add(titleTransparentButton);
titleTransparentButton.selectedProperty().bindBidirectional(config().titleTransparentProperty());
titleTransparentButton.setTitle(i18n("settings.launcher.title_transparent"));
}
{
OptionToggleButton animationButton = new OptionToggleButton();
LineToggleButton animationButton = new LineToggleButton();
themeList.getContent().add(animationButton);
animationButton.selectedProperty().bindBidirectional(config().animationDisabledProperty());
animationButton.setTitle(i18n("settings.launcher.turn_off_animations"));
@@ -304,46 +297,33 @@ public class PersonalizationPage extends StackPane {
}
{
BorderPane fontAntiAliasingPane = new BorderPane();
{
VBox left = new VBox();
Label title = new Label(i18n("settings.launcher.font.anti_aliasing"));
title.getStyleClass().add("title");
Label subtitle = new Label(i18n("settings.take_effect_after_restart"));
subtitle.getStyleClass().add("subtitle");
left.getChildren().setAll(title, subtitle);
fontAntiAliasingPane.setLeft(left);
}
{
@SuppressWarnings("unchecked")
JFXComboBox<Optional<FontSmoothingType>> cboAntiAliasing = new JFXComboBox<>(FXCollections.observableArrayList(
var fontAntiAliasingPane = new LineSelectButton<Optional<FontSmoothingType>>();
fontAntiAliasingPane.setTitle(i18n("settings.launcher.font.anti_aliasing"));
fontAntiAliasingPane.setSubtitle(i18n("settings.take_effect_after_restart"));
fontAntiAliasingPane.setConverter(value ->
value.isPresent()
? i18n("settings.launcher.font.anti_aliasing." + value.get().name().toLowerCase(Locale.ROOT))
: i18n("settings.launcher.font.anti_aliasing.auto")
);
fontAntiAliasingPane.setItems(
Optional.empty(),
Optional.of(FontSmoothingType.LCD),
Optional.of(FontSmoothingType.GRAY)
));
);
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.LCD));
fontAntiAliasingPane.setValue(Optional.of(FontSmoothingType.LCD));
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)) {
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.GRAY));
fontAntiAliasingPane.setValue(Optional.of(FontSmoothingType.GRAY));
} else {
cboAntiAliasing.setValue(Optional.empty());
fontAntiAliasingPane.setValue(Optional.empty());
}
cboAntiAliasing.setConverter(FXUtils.stringConverter(value -> {
if (value.isPresent()) {
return i18n("settings.launcher.font.anti_aliasing." + value.get().name().toLowerCase(Locale.ROOT));
} else {
return i18n("settings.launcher.font.anti_aliasing.auto");
}
}));
FXUtils.onChange(cboAntiAliasing.valueProperty(), value ->
FXUtils.onChange(fontAntiAliasingPane.valueProperty(), value ->
globalConfig().setFontAntiAliasing(value.map(it -> it.name().toLowerCase(Locale.ROOT))
.orElse(null)));
fontAntiAliasingPane.setRight(cboAntiAliasing);
}
fontPane.getContent().add(fontAntiAliasingPane);
}

View File

@@ -18,7 +18,6 @@
package org.jackhuang.hmcl.ui.main;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXRadioButton;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
@@ -40,11 +39,8 @@ import org.jackhuang.hmcl.setting.Settings;
import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.ComponentSublist;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.construct.MessageDialogPane.MessageType;
import org.jackhuang.hmcl.ui.construct.MultiFileItem;
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
import org.jackhuang.hmcl.upgrade.RemoteVersion;
import org.jackhuang.hmcl.upgrade.UpdateChannel;
import org.jackhuang.hmcl.upgrade.UpdateChecker;
@@ -69,7 +65,6 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.Lang.thread;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
@@ -206,7 +201,7 @@ public final class SettingsPage extends ScrollPane {
}
{
OptionToggleButton previewPane = new OptionToggleButton();
LineToggleButton previewPane = new LineToggleButton();
previewPane.setTitle(i18n("update.preview"));
previewPane.setSubtitle(i18n("update.preview.subtitle"));
previewPane.selectedProperty().bindBidirectional(config().acceptPreviewUpdateProperty());
@@ -250,37 +245,27 @@ public final class SettingsPage extends ScrollPane {
}
{
BorderPane languagePane = new BorderPane();
VBox left = new VBox();
Label title = new Label(i18n("settings.launcher.language"));
title.getStyleClass().add("title");
Label subtitle = new Label(i18n("settings.take_effect_after_restart"));
subtitle.getStyleClass().add("subtitle");
left.getChildren().setAll(title, subtitle);
languagePane.setLeft(left);
var chooseLanguagePane = new LineSelectButton<SupportedLocale>();
chooseLanguagePane.setTitle(i18n("settings.launcher.language"));
chooseLanguagePane.setSubtitle(i18n("settings.take_effect_after_restart"));
SupportedLocale currentLocale = I18n.getLocale();
JFXComboBox<SupportedLocale> cboLanguage = new JFXComboBox<>();
cboLanguage.setConverter(stringConverter(locale -> {
chooseLanguagePane.setConverter(locale -> {
if (locale.isDefault())
return locale.getDisplayName(currentLocale);
else if (locale.isSameLanguage(currentLocale))
return locale.getDisplayName(locale);
else
return locale.getDisplayName(currentLocale) + " - " + locale.getDisplayName(locale);
}));
cboLanguage.getItems().setAll(SupportedLocale.getSupportedLocales());
selectedItemPropertyFor(cboLanguage).bindBidirectional(config().localizationProperty());
});
chooseLanguagePane.setItems(SupportedLocale.getSupportedLocales());
chooseLanguagePane.valueProperty().bindBidirectional(config().localizationProperty());
FXUtils.setLimitWidth(cboLanguage, 300);
languagePane.setRight(cboLanguage);
settingsPane.getContent().add(languagePane);
settingsPane.getContent().add(chooseLanguagePane);
}
{
OptionToggleButton disableAutoGameOptionsPane = new OptionToggleButton();
LineToggleButton disableAutoGameOptionsPane = new LineToggleButton();
disableAutoGameOptionsPane.setTitle(i18n("settings.launcher.disable_auto_game_options"));
disableAutoGameOptionsPane.selectedProperty().bindBidirectional(config().disableAutoGameOptionsProperty());

View File

@@ -37,7 +37,7 @@ import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.ComponentList;
import org.jackhuang.hmcl.ui.construct.FileItem;
import org.jackhuang.hmcl.ui.construct.OptionToggleButton;
import org.jackhuang.hmcl.ui.construct.LineToggleButton;
import org.jackhuang.hmcl.ui.construct.PageCloseEvent;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.StringUtils;
@@ -55,7 +55,7 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
private final Profile profile;
private final JFXTextField txtProfileName;
private final FileItem gameDir;
private final OptionToggleButton toggleUseRelativePath;
private final LineToggleButton toggleUseRelativePath;
/**
* @param profile null if creating a new profile.
@@ -113,7 +113,7 @@ public final class ProfilePage extends BorderPane implements DecoratorPage {
gameDir.setTitle(i18n("profile.instance_directory.choose"));
gameDir.pathProperty().bindBidirectional(location);
toggleUseRelativePath = new OptionToggleButton();
toggleUseRelativePath = new LineToggleButton();
toggleUseRelativePath.setTitle(i18n("profile.use_relative_path"));
gameDir.convertToRelativePathProperty().bind(toggleUseRelativePath.selectedProperty());

View File

@@ -1,12 +1,10 @@
package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.*;
@@ -26,7 +24,6 @@ import java.nio.file.FileSystems;
import java.util.Arrays;
import java.util.Locale;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class AdvancedVersionSettingPage extends StackPane implements DecoratorPage {
@@ -44,17 +41,17 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
private final JFXTextField txtWrapper;
private final JFXTextField txtPreLaunchCommand;
private final JFXTextField txtPostExitCommand;
private final OptionToggleButton noJVMArgsPane;
private final OptionToggleButton noOptimizingJVMArgsPane;
private final OptionToggleButton noGameCheckPane;
private final OptionToggleButton noJVMCheckPane;
private final OptionToggleButton noNativesPatchPane;
private final OptionToggleButton useNativeGLFWPane;
private final OptionToggleButton useNativeOpenALPane;
private final LineToggleButton noJVMArgsPane;
private final LineToggleButton noOptimizingJVMArgsPane;
private final LineToggleButton noGameCheckPane;
private final LineToggleButton noJVMCheckPane;
private final LineToggleButton noNativesPatchPane;
private final LineToggleButton useNativeGLFWPane;
private final LineToggleButton useNativeOpenALPane;
private final ComponentSublist nativesDirSublist;
private final MultiFileItem<NativesDirectoryType> nativesDirItem;
private final MultiFileItem.FileOption<NativesDirectoryType> nativesDirCustomOption;
private final JFXComboBox<Renderer> cboRenderer;
private final LineSelectButton<Renderer> rendererPane;
public AdvancedVersionSettingPage(Profile profile, @Nullable String versionId, VersionSetting versionSetting) {
this.profile = profile;
@@ -170,40 +167,31 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
nativesDirHint.setText(i18n("settings.advanced.natives_directory.hint"));
nativesDirItem.getChildren().add(nativesDirHint);
BorderPane rendererPane = new BorderPane();
{
Label label = new Label(i18n("settings.advanced.renderer"));
rendererPane.setLeft(label);
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
rendererPane = new LineSelectButton<>();
rendererPane.setTitle(i18n("settings.advanced.renderer"));
rendererPane.setConverter(e -> i18n("settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT)));
rendererPane.setItems(Renderer.values());
cboRenderer = new JFXComboBox<>();
cboRenderer.getItems().setAll(Renderer.values());
cboRenderer.setConverter(stringConverter(e -> i18n("settings.advanced.renderer." + e.name().toLowerCase(Locale.ROOT))));
rendererPane.setRight(cboRenderer);
BorderPane.setAlignment(cboRenderer, Pos.CENTER_RIGHT);
FXUtils.setLimitWidth(cboRenderer, 300);
}
noJVMArgsPane = new OptionToggleButton();
noJVMArgsPane = new LineToggleButton();
noJVMArgsPane.setTitle(i18n("settings.advanced.no_jvm_args"));
noOptimizingJVMArgsPane = new OptionToggleButton();
noOptimizingJVMArgsPane = new LineToggleButton();
noOptimizingJVMArgsPane.setTitle(i18n("settings.advanced.no_optimizing_jvm_args"));
noOptimizingJVMArgsPane.disableProperty().bind(noJVMArgsPane.selectedProperty());
noGameCheckPane = new OptionToggleButton();
noGameCheckPane = new LineToggleButton();
noGameCheckPane.setTitle(i18n("settings.advanced.dont_check_game_completeness"));
noJVMCheckPane = new OptionToggleButton();
noJVMCheckPane = new LineToggleButton();
noJVMCheckPane.setTitle(i18n("settings.advanced.dont_check_jvm_validity"));
noNativesPatchPane = new OptionToggleButton();
noNativesPatchPane = new LineToggleButton();
noNativesPatchPane.setTitle(i18n("settings.advanced.dont_patch_natives"));
useNativeGLFWPane = new OptionToggleButton();
useNativeGLFWPane = new LineToggleButton();
useNativeGLFWPane.setTitle(i18n("settings.advanced.use_native_glfw"));
useNativeOpenALPane = new OptionToggleButton();
useNativeOpenALPane = new LineToggleButton();
useNativeOpenALPane.setTitle(i18n("settings.advanced.use_native_openal"));
workaroundPane.getContent().setAll(
@@ -239,7 +227,7 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
FXUtils.bindString(txtPostExitCommand, versionSetting.postExitCommandProperty());
FXUtils.bindEnum(cboRenderer, versionSetting.rendererProperty());
rendererPane.valueProperty().bindBidirectional(versionSetting.rendererProperty());
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
noJVMArgsPane.selectedProperty().bindBidirectional(versionSetting.noJVMArgsProperty());
@@ -281,7 +269,7 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
FXUtils.unbind(txtWrapper, versionSetting.wrapperProperty());
FXUtils.unbind(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
FXUtils.unbind(txtPostExitCommand, versionSetting.postExitCommandProperty());
FXUtils.unbindEnum(cboRenderer, versionSetting.rendererProperty());
rendererPane.valueProperty().unbindBidirectional(versionSetting.rendererProperty());
noGameCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckGameProperty());
noJVMCheckPane.selectedProperty().unbindBidirectional(versionSetting.notCheckJVMProperty());
noJVMArgsPane.selectedProperty().unbindBidirectional(versionSetting.noJVMArgsProperty());

View File

@@ -43,6 +43,7 @@ import org.jackhuang.hmcl.ui.WeakListenerHolder;
import org.jackhuang.hmcl.ui.construct.*;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.*;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import org.jackhuang.hmcl.util.javafx.PropertyUtils;
import org.jackhuang.hmcl.util.javafx.SafeStringConverter;
@@ -57,7 +58,6 @@ import java.lang.ref.WeakReference;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.DataSizeUnit.GIGABYTES;
import static org.jackhuang.hmcl.util.DataSizeUnit.MEGABYTES;
import static org.jackhuang.hmcl.util.Pair.pair;
@@ -78,7 +78,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
private final JFXComboBox<String> cboWindowsSize;
private final JFXTextField txtServerIP;
private final ComponentList componentList;
private final JFXComboBox<LauncherVisibility> cboLauncherVisibility;
private final LineSelectButton<LauncherVisibility> launcherVisibilityPane;
private final JFXCheckBox chkAutoAllocate;
private final JFXCheckBox chkFullscreen;
private final ComponentSublist javaSublist;
@@ -90,9 +90,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
private final ComponentSublist gameDirSublist;
private final MultiFileItem<GameDirectoryType> gameDirItem;
private final MultiFileItem.FileOption<GameDirectoryType> gameDirCustomOption;
private final JFXComboBox<ProcessPriority> cboProcessPriority;
private final OptionToggleButton showLogsPane;
private final OptionToggleButton enableDebugLogOutputPane;
private final LineSelectButton<ProcessPriority> processPriorityPane;
private final LineToggleButton showLogsPane;
private final LineToggleButton enableDebugLogOutputPane;
private final ImagePickerItem iconPickerItem;
private final ChangeListener<Collection<JavaRuntime>> javaListChangeListener;
@@ -351,17 +351,10 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
maxMemoryPane.getChildren().setAll(title, chkAutoAllocate, lowerBoundPane, progressBarPane, digitalPane);
}
BorderPane launcherVisibilityPane = new BorderPane();
{
Label label = new Label(i18n("settings.advanced.launcher_visible"));
launcherVisibilityPane.setLeft(label);
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
cboLauncherVisibility = new JFXComboBox<>();
launcherVisibilityPane.setRight(cboLauncherVisibility);
BorderPane.setAlignment(cboLauncherVisibility, Pos.CENTER_RIGHT);
FXUtils.setLimitWidth(cboLauncherVisibility, 300);
}
launcherVisibilityPane = new LineSelectButton<>();
launcherVisibilityPane.setTitle(i18n("settings.advanced.launcher_visible"));
launcherVisibilityPane.setItems(LauncherVisibility.values());
launcherVisibilityPane.setConverter(e -> i18n("settings.advanced.launcher_visibility." + e.name().toLowerCase(Locale.ROOT)));
BorderPane dimensionPane = new BorderPane();
{
@@ -391,23 +384,19 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
}
}
showLogsPane = new OptionToggleButton();
showLogsPane = new LineToggleButton();
showLogsPane.setTitle(i18n("settings.show_log"));
enableDebugLogOutputPane = new OptionToggleButton();
enableDebugLogOutputPane = new LineToggleButton();
enableDebugLogOutputPane.setTitle(i18n("settings.enable_debug_log_output"));
BorderPane processPriorityPane = new BorderPane();
{
Label label = new Label(i18n("settings.advanced.process_priority"));
processPriorityPane.setLeft(label);
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
cboProcessPriority = new JFXComboBox<>();
processPriorityPane.setRight(cboProcessPriority);
BorderPane.setAlignment(cboProcessPriority, Pos.CENTER_RIGHT);
FXUtils.setLimitWidth(cboProcessPriority, 300);
}
processPriorityPane = new LineSelectButton<>();
processPriorityPane.setTitle(i18n("settings.advanced.process_priority"));
processPriorityPane.setConverter(e -> i18n("settings.advanced.process_priority." + e.name().toLowerCase(Locale.ROOT)));
processPriorityPane.setDescriptionConverter(e -> {
String bundleKey = "settings.advanced.process_priority." + e.name().toLowerCase(Locale.ROOT) + ".desc";
return I18n.hasKey(bundleKey) ? i18n(bundleKey) : null;
});
processPriorityPane.setItems(ProcessPriority.values());
GridPane serverPane = new GridPane();
{
@@ -436,14 +425,9 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
serverPane.addRow(0, new Label(i18n("settings.advanced.server_ip")), txtServerIP);
}
BorderPane showAdvancedSettingPane = new BorderPane();
{
Label label = new Label(i18n("settings.advanced"));
showAdvancedSettingPane.setLeft(label);
BorderPane.setAlignment(label, Pos.CENTER_LEFT);
JFXButton button = FXUtils.newBorderButton(i18n("settings.advanced.modify"));
button.setOnAction(e -> {
LineNavigationButton showAdvancedSettingPane = new LineNavigationButton();
showAdvancedSettingPane.setTitle(i18n("settings.advanced"));
showAdvancedSettingPane.setOnAction(event -> {
if (lastVersionSetting != null) {
if (advancedVersionSettingPage == null)
advancedVersionSettingPage = new AdvancedVersionSettingPage(profile, versionId, lastVersionSetting);
@@ -451,8 +435,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
Controllers.navigateForward(advancedVersionSettingPage);
}
});
showAdvancedSettingPane.setRight(button);
}
componentList.getContent().addAll(
javaSublist,
@@ -487,12 +469,6 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
addEventHandler(Navigator.NavigationEvent.NAVIGATED, this::onDecoratorPageNavigating);
cboLauncherVisibility.getItems().setAll(LauncherVisibility.values());
cboLauncherVisibility.setConverter(stringConverter(e -> i18n("settings.advanced.launcher_visibility." + e.name().toLowerCase(Locale.ROOT))));
cboProcessPriority.getItems().setAll(ProcessPriority.values());
cboProcessPriority.setConverter(stringConverter(e -> i18n("settings.advanced.process_priority." + e.name().toLowerCase(Locale.ROOT))));
componentList.disableProperty().bind(enableSpecificSettings.not());
}
@@ -537,8 +513,8 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
chkFullscreen.selectedProperty().unbindBidirectional(lastVersionSetting.fullscreenProperty());
showLogsPane.selectedProperty().unbindBidirectional(lastVersionSetting.showLogsProperty());
enableDebugLogOutputPane.selectedProperty().unbindBidirectional(lastVersionSetting.enableDebugLogOutputProperty());
FXUtils.unbindEnum(cboLauncherVisibility, lastVersionSetting.launcherVisibilityProperty());
FXUtils.unbindEnum(cboProcessPriority, lastVersionSetting.processPriorityProperty());
launcherVisibilityPane.valueProperty().unbindBidirectional(lastVersionSetting.launcherVisibilityProperty());
processPriorityPane.valueProperty().unbindBidirectional(lastVersionSetting.processPriorityProperty());
lastVersionSetting.usesGlobalProperty().removeListener(usesGlobalListener);
lastVersionSetting.javaVersionTypeProperty().removeListener(javaListener);
@@ -572,8 +548,8 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
chkFullscreen.selectedProperty().bindBidirectional(versionSetting.fullscreenProperty());
showLogsPane.selectedProperty().bindBidirectional(versionSetting.showLogsProperty());
enableDebugLogOutputPane.selectedProperty().bindBidirectional(versionSetting.enableDebugLogOutputProperty());
FXUtils.bindEnum(cboLauncherVisibility, versionSetting.launcherVisibilityProperty());
FXUtils.bindEnum(cboProcessPriority, versionSetting.processPriorityProperty());
launcherVisibilityPane.valueProperty().bindBidirectional(versionSetting.launcherVisibilityProperty());
processPriorityPane.valueProperty().bindBidirectional(versionSetting.processPriorityProperty());
if (versionId != null)
enableSpecificSettings.set(!versionSetting.isUsesGlobal());

View File

@@ -19,7 +19,6 @@ package org.jackhuang.hmcl.ui.versions;
import com.github.steveice10.opennbt.tag.builtin.*;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXComboBox;
import com.jfoenix.controls.JFXTextField;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
@@ -243,7 +242,7 @@ public final class WorldInfoPage extends SpinnerPane {
});
}
OptionToggleButton allowCheatsButton = new OptionToggleButton();
LineToggleButton allowCheatsButton = new LineToggleButton();
{
allowCheatsButton.setTitle(i18n("world.info.allow_cheats"));
allowCheatsButton.setDisable(worldManagePage.isReadOnly());
@@ -252,7 +251,7 @@ public final class WorldInfoPage extends SpinnerPane {
checkTagAndSetListener(tag, allowCheatsButton);
}
OptionToggleButton generateFeaturesButton = new OptionToggleButton();
LineToggleButton generateFeaturesButton = new LineToggleButton();
{
generateFeaturesButton.setTitle(i18n("world.info.generate_features"));
generateFeaturesButton.setDisable(worldManagePage.isReadOnly());
@@ -261,35 +260,32 @@ public final class WorldInfoPage extends SpinnerPane {
checkTagAndSetListener(tag, generateFeaturesButton);
}
BorderPane difficultyPane = new BorderPane();
LineSelectButton<Difficulty> difficultyButton = new LineSelectButton<>();
{
setLeftLabel(difficultyPane, "world.info.difficulty");
JFXComboBox<Difficulty> difficultyBox = new JFXComboBox<>(Difficulty.items);
difficultyBox.setDisable(worldManagePage.isReadOnly());
BorderPane.setAlignment(difficultyBox, Pos.CENTER_RIGHT);
difficultyPane.setRight(difficultyBox);
difficultyButton.setTitle(i18n("world.info.difficulty"));
difficultyButton.setDisable(worldManagePage.isReadOnly());
difficultyButton.setItems(Difficulty.items);
Tag tag = dataTag.get("Difficulty");
if (tag instanceof ByteTag byteTag) {
Difficulty difficulty = Difficulty.of(byteTag.getValue());
if (difficulty != null) {
difficultyBox.setValue(difficulty);
difficultyBox.valueProperty().addListener((o, oldValue, newValue) -> {
difficultyButton.setValue(difficulty);
difficultyButton.valueProperty().addListener((o, oldValue, newValue) -> {
if (newValue != null) {
byteTag.setValue((byte) newValue.ordinal());
saveLevelDat();
}
});
} else {
difficultyBox.setDisable(true);
difficultyButton.setDisable(true);
}
} else {
difficultyBox.setDisable(true);
difficultyButton.setDisable(true);
}
}
OptionToggleButton difficultyLockPane = new OptionToggleButton();
LineToggleButton difficultyLockPane = new LineToggleButton();
{
difficultyLockPane.setTitle(i18n("world.info.difficulty_lock"));
difficultyLockPane.setDisable(worldManagePage.isReadOnly());
@@ -300,7 +296,7 @@ public final class WorldInfoPage extends SpinnerPane {
basicInfo.getContent().setAll(
worldNamePane, gameVersionPane, iconPane, seedPane, lastPlayedPane, timePane,
allowCheatsButton, generateFeaturesButton, difficultyPane, difficultyLockPane);
allowCheatsButton, generateFeaturesButton, difficultyButton, difficultyLockPane);
rootPane.getChildren().addAll(ComponentList.createComponentListTitle(i18n("world.info.basic")), basicInfo);
}
@@ -373,14 +369,11 @@ public final class WorldInfoPage extends SpinnerPane {
});
}
BorderPane playerGameTypePane = new BorderPane();
LineSelectButton<GameType> playerGameTypeButton = new LineSelectButton<>();
{
setLeftLabel(playerGameTypePane, "world.info.player.game_type");
JFXComboBox<GameType> gameTypeBox = new JFXComboBox<>(GameType.items);
gameTypeBox.setDisable(worldManagePage.isReadOnly());
BorderPane.setAlignment(gameTypeBox, Pos.CENTER_RIGHT);
playerGameTypePane.setRight(gameTypeBox);
playerGameTypeButton.setTitle(i18n("world.info.player.game_type"));
playerGameTypeButton.setDisable(worldManagePage.isReadOnly());
playerGameTypeButton.setItems(GameType.items);
Tag tag = player.get("playerGameType");
Tag hardcoreTag = dataTag.get("hardcore");
@@ -389,8 +382,8 @@ public final class WorldInfoPage extends SpinnerPane {
if (tag instanceof IntTag intTag) {
GameType gameType = GameType.of(intTag.getValue(), isHardcore);
if (gameType != null) {
gameTypeBox.setValue(gameType);
gameTypeBox.valueProperty().addListener((o, oldValue, newValue) -> {
playerGameTypeButton.setValue(gameType);
playerGameTypeButton.valueProperty().addListener((o, oldValue, newValue) -> {
if (newValue != null) {
if (newValue == GameType.HARDCORE) {
intTag.setValue(0); // survival (hardcore worlds are survival+hardcore flag)
@@ -407,10 +400,10 @@ public final class WorldInfoPage extends SpinnerPane {
}
});
} else {
gameTypeBox.setDisable(true);
playerGameTypeButton.setDisable(true);
}
} else {
gameTypeBox.setDisable(true);
playerGameTypeButton.setDisable(true);
}
}
@@ -458,7 +451,7 @@ public final class WorldInfoPage extends SpinnerPane {
playerInfo.getContent().setAll(
locationPane, lastDeathLocationPane, spawnPane,
playerGameTypePane, healthPane, foodLevelPane, xpLevelPane
playerGameTypeButton, healthPane, foodLevelPane, xpLevelPane
);
rootPane.getChildren().addAll(ComponentList.createComponentListTitle(i18n("world.info.player")), playerInfo);
@@ -489,7 +482,7 @@ public final class WorldInfoPage extends SpinnerPane {
borderPane.setRight(label);
}
private void checkTagAndSetListener(Tag tag, OptionToggleButton toggleButton) {
private void checkTagAndSetListener(Tag tag, LineToggleButton toggleButton) {
if (tag instanceof ByteTag byteTag) {
byte value = byteTag.getValue();
if (value == 0 || value == 1) {

View File

@@ -1857,3 +1857,35 @@
.tooltip .text {
-fx-fill: -monet-inverse-on-surface;
}
/*******************************************************************************
* *
* Line Button *
* *
******************************************************************************/
.line-select-button .svg {
-fx-opacity: 1;
}
.line-select-button .svg:disabled {
-fx-opacity: 0.4;
}
.line-select-button .menu-container .title {
-fx-font-size: 13px;
-fx-text-fill: -monet-on-surface;
}
.line-select-button .menu-container:selected .title {
-fx-text-fill: -monet-primary;
}
.line-select-button .menu-container .subtitle {
-fx-text-fill: -monet-on-surface-variant;
}
.line-select-button .menu-container:selected .subtitle {
-fx-text-fill: -monet-primary;
}

View File

@@ -357,11 +357,16 @@ download.failed.empty=No versions are available. Please click here to go back.
download.failed.no_code=Failed to download
download.failed.refresh=Failed to fetch version list. Please click here to retry.
download.game=New Game
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Official (OptiFine is provided by BMCLAPI)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com/
download.provider.mojang=Official
download.provider.mojang.desc=OptiFine is provided by BMCLAPI
download.provider.official=From Official Sources
download.provider.official.desc=Latest, but may load slowly
download.provider.balanced=From Fastest Available
download.provider.balanced.desc=Balanced, but may not be the latest
download.provider.mirror=From Mirror
download.provider.mirror.desc=Fast, but may not be the latest
download.java=Downloading Java
download.java.override=This Java version already exists. Do you want to uninstall and reinstall it?
download.java.process=Java Download Process
@@ -1343,10 +1348,15 @@ settings.advanced.precall_command=Pre-launch Command
settings.advanced.precall_command.prompt=Commands to execute before the game launches
settings.advanced.process_priority=Process Priority
settings.advanced.process_priority.low=Low
settings.advanced.process_priority.low.desc=
settings.advanced.process_priority.below_normal=Below Normal
settings.advanced.process_priority.below_normal.desc=
settings.advanced.process_priority.normal=Normal
settings.advanced.process_priority.normal.desc=
settings.advanced.process_priority.above_normal=Above Normal
settings.advanced.process_priority.above_normal.desc=
settings.advanced.process_priority.high=High
settings.advanced.process_priority.high.desc=
settings.advanced.post_exit_command=Post-exit Command
settings.advanced.post_exit_command.prompt=Commands to execute after the game exits
settings.advanced.renderer=Renderer

View File

@@ -338,8 +338,10 @@ download.failed.empty=No hay versiones disponibles, por favor haga clic aquí pa
download.failed.no_code=No se ha podido descargar
download.failed.refresh=No se ha podido obtener la lista de versiones. Por favor, haga clic aquí para volver a intentarlo.
download.game=Nuevo juego
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Oficial (OptiFine es proporcionado por BMCLAPI)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com/
download.provider.mojang=Oficial
download.provider.mojang.desc=OptiFine es proporcionado por BMCLAPI
download.provider.official=De fuentes oficiales
download.provider.balanced=De la fuente más rápida disponible
download.provider.mirror=Desde espejo

View File

@@ -295,8 +295,10 @@ download.failed=%1$s のダウンロードに失敗しました、応答コー
download.failed.empty=候補者なし。戻るにはここをクリックしてください。
download.failed.refresh=バージョンリストをダウンロードできません。ここをクリックして再試行してください。
download.game=ゲームのダウンロード
download.provider.bmclapi=BMCLAPI(ミラーソース)
download.provider.mojang=MojangOptiFineはBMCLAPIにより提供されます 推奨
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=ミラーソース
download.provider.mojang=Mojang
download.provider.mojang.desc=OptiFineはBMCLAPIにより提供されます
download.provider.official=公式ソースからロード
download.provider.balanced=mcbbsのソースからロード
download.provider.mirror=ミラーソースからロード

View File

@@ -334,11 +334,16 @@ download.failed.empty=[無可裝之版,點此返]\n(君可求助於右上之
download.failed.no_code=引之未成
download.failed.refresh=[載版列未成,點此重試]\n(君可求助於右上之鈕)
download.game=新戲
download.provider.bmclapi=BMCLAPI (bangbang93https://bmclapi2.bangbang93.com)
download.provider.mojang=官版 (Optifine 猶取諸 BMCLAPI 也)
download.provider.official=官版 (至新,容有艱)
download.provider.balanced=先其快者 (均,容有舊)
download.provider.mirror=先別源 (至快,容有舊)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93https://bmclapi2.bangbang93.com
download.provider.mojang=官版
download.provider.mojang.desc=Optifine 猶取諸 BMCLAPI 也
download.provider.official=先官版
download.provider.official.desc=至新,容有艱
download.provider.balanced=先其快者
download.provider.balanced.desc=均,容有舊
download.provider.mirror=先別源
download.provider.mirror.desc=至快,容有舊
download.java=引爪哇
download.java.override=爪哇是版既現,除而復裝諸?
download.java.process=引爪哇
@@ -1066,11 +1071,16 @@ settings.advanced.no_jvm_args=無添爪哇虛機之本通弦
settings.advanced.precall_command=令於戲前
settings.advanced.precall_command.prompt=將前戲啟而行
settings.advanced.process_priority=進程之次
settings.advanced.process_priority.low= (節戲所佔,容有滯焉)
settings.advanced.process_priority.below_normal=略低 (節戲所佔,容有滯焉)
settings.advanced.process_priority.normal=中 (權衡)
settings.advanced.process_priority.above_normal=略高 (以先礦藝之作動而後餘者也)
settings.advanced.process_priority.high=高 (以先礦藝之作動而後餘者也)
settings.advanced.process_priority.low=
settings.advanced.process_priority.low.desc=節戲所佔,容有滯焉
settings.advanced.process_priority.below_normal=略低
settings.advanced.process_priority.below_normal.desc=節戲所佔,容有滯焉
settings.advanced.process_priority.normal=
settings.advanced.process_priority.normal.desc=權衡
settings.advanced.process_priority.above_normal=略高
settings.advanced.process_priority.above_normal.desc=以先礦藝之作動而後餘者也
settings.advanced.process_priority.high=
settings.advanced.process_priority.high.desc=以先礦藝之作動而後餘者也
settings.advanced.post_exit_command=令於戲訖
settings.advanced.post_exit_command.prompt=將後戲訖而行
settings.advanced.renderer=繪器

View File

@@ -335,8 +335,10 @@ download.failed.empty=Версий нет. Нажмите здесь, чтобы
download.failed.no_code=Не удалось скачать
download.failed.refresh=Не удалось получить список версий. Нажмите здесь, чтобы повторить попытку.
download.game=Новая игра
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Официальный (OptiFine предоставляется BMCLAPI)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com/
download.provider.mojang=Официальный
download.provider.mojang.desc=OptiFine предоставляется BMCLAPI
download.provider.official=Из официальных источников
download.provider.balanced=Из самых быстрых доступных
download.provider.mirror=Из зеркала

View File

@@ -334,8 +334,10 @@ download.failed.empty=Немає доступних версій. Натисні
download.failed.no_code=Не вдалося завантажити
download.failed.refresh=Не вдалося отримати список версій. Натисніть тут, щоб повторити спробу.
download.game=Нова гра
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=Офіційне (OptiFine надається BMCLAPI)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com/
download.provider.mojang=Офіційне
download.provider.mojang.desc=OptiFine надається BMCLAPI
download.provider.official=З офіційних джерел
download.provider.balanced=З найшвидшого доступного
download.provider.mirror=З дзеркала

View File

@@ -351,11 +351,16 @@ download.failed.empty=沒有可供安裝的版本,按一下此處返回。
download.failed.no_code=下載失敗
download.failed.refresh=載入版本清單失敗,按一下此處重試。
download.game=新遊戲
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com/)
download.provider.mojang=官方伺服器 (OptiFine 由 BMCLAPI 提供)
download.provider.official=盡量使用官方源 (最新,但可能載入慢)
download.provider.balanced=選取載入速度快的下載源 (平衡,但可能不是最新)
download.provider.mirror=盡量使用鏡像源 (載入快,但可能不是最新)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com/
download.provider.mojang=官方伺服器
download.provider.mojang.desc=OptiFine 由 BMCLAPI 提供
download.provider.official=盡量使用官方源
download.provider.official.desc=最新,但可能載入慢
download.provider.balanced=選取載入速度快的下載源
download.provider.balanced.desc=平衡,但可能不是最新
download.provider.mirror=盡量使用鏡像源
download.provider.mirror.desc=載入快,但可能不是最新
download.java=下載 Java
download.java.override=此 Java 版本已經存在,是否移除並重新安裝?
download.java.process=下載 Java
@@ -1123,11 +1128,16 @@ settings.advanced.no_optimizing_jvm_args=不自動新增 Java 虛擬機最佳化
settings.advanced.precall_command=遊戲啟動前執行指令
settings.advanced.precall_command.prompt=將在遊戲啟動前呼叫使用
settings.advanced.process_priority=處理程式優先度
settings.advanced.process_priority.low= (節省遊戲占用資源,可能會造成遊戲卡頓)
settings.advanced.process_priority.below_normal=較低 (節省遊戲占用資源,可能會造成遊戲卡頓)
settings.advanced.process_priority.normal=中 (平衡)
settings.advanced.process_priority.above_normal=較高 (優先保證遊戲執行,但可能會導致其他程式卡頓)
settings.advanced.process_priority.high=高 (優先保證遊戲執行,但可能會導致其他程式卡頓)
settings.advanced.process_priority.low=
settings.advanced.process_priority.low.desc=節省遊戲占用資源,可能會造成遊戲卡頓
settings.advanced.process_priority.below_normal=較低
settings.advanced.process_priority.below_normal.desc=節省遊戲占用資源,可能會造成遊戲卡頓
settings.advanced.process_priority.normal=
settings.advanced.process_priority.normal.desc=平衡
settings.advanced.process_priority.above_normal=較高
settings.advanced.process_priority.above_normal.desc=優先保證遊戲執行,但可能會導致其他程式卡頓
settings.advanced.process_priority.high=
settings.advanced.process_priority.high.desc=優先保證遊戲執行,但可能會導致其他程式卡頓
settings.advanced.post_exit_command=遊戲結束後執行指令
settings.advanced.post_exit_command.prompt=將在遊戲結束後呼叫使用
settings.advanced.renderer=繪製器

View File

@@ -353,11 +353,16 @@ download.failed.empty=[没有可供安装的版本,点击此处返回]\n(你
download.failed.no_code=下载失败
download.failed.refresh=[加载版本列表失败,点击此处重试]\n(你可以点击右上角帮助按钮进行求助)
download.game=新游戏
download.provider.bmclapi=BMCLAPI (bangbang93, https://bmclapi2.bangbang93.com)
download.provider.mojang=官方 (OptiFine 自动安装使用 BMCLAPI 下载源)
download.provider.official=尽量使用官方源 (最新,但可能加载慢)
download.provider.balanced=选择加载速度快的下载源 (平衡,但可能不是最新)
download.provider.mirror=尽量使用镜像源 (加载快,但可能不是最新)
download.provider.bmclapi=BMCLAPI
download.provider.bmclapi.desc=bangbang93, https://bmclapi2.bangbang93.com
download.provider.mojang=官方
download.provider.mojang.desc=OptiFine 自动安装使用 BMCLAPI 下载源
download.provider.official=尽量使用官方源
download.provider.official.desc=最新,但可能加载慢
download.provider.balanced=选择加载速度快的下载源
download.provider.balanced.desc=平衡,但可能不是最新
download.provider.mirror=尽量使用镜像源
download.provider.mirror.desc=加载快,但可能不是最新
download.java=下载 Java
download.java.override=此 Java 版本已经存在,是否卸载并重新安装?
download.java.process=下载 Java
@@ -1127,11 +1132,16 @@ settings.advanced.no_optimizing_jvm_args=不自动添加 Java 虚拟机优化参
settings.advanced.precall_command=游戏启动前执行命令
settings.advanced.precall_command.prompt=将在游戏启动前调用
settings.advanced.process_priority=进程优先级
settings.advanced.process_priority.low= (节省游戏占用资源,可能会造成游戏卡顿)
settings.advanced.process_priority.below_normal=较低 (节省游戏占用资源,可能会造成游戏卡顿)
settings.advanced.process_priority.normal=中 (平衡)
settings.advanced.process_priority.above_normal=较高 (优先保证游戏运行,但可能会导致其他程序卡顿)
settings.advanced.process_priority.high=高 (优先保证游戏运行,但可能会导致其他程序卡顿)
settings.advanced.process_priority.low=
settings.advanced.process_priority.low.desc=节省游戏占用资源,可能会造成游戏卡顿
settings.advanced.process_priority.below_normal=较低
settings.advanced.process_priority.below_normal.desc=节省游戏占用资源,可能会造成游戏卡顿
settings.advanced.process_priority.normal=
settings.advanced.process_priority.normal.desc=平衡
settings.advanced.process_priority.above_normal=较高
settings.advanced.process_priority.above_normal.desc=优先保证游戏运行,但可能会导致其他程序卡顿
settings.advanced.process_priority.high=
settings.advanced.process_priority.high.desc=优先保证游戏运行,但可能会导致其他程序卡顿
settings.advanced.post_exit_command=游戏结束后执行命令
settings.advanced.post_exit_command.prompt=将在游戏结束后调用
settings.advanced.renderer=渲染器