使用 LineSelectButton 代替 JFXComboxBox (#5337)
This commit is contained in:
@@ -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)
|
||||
);
|
||||
|
||||
@@ -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"),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -158,6 +158,10 @@ public class RipplerContainer extends StackPane {
|
||||
updateChildren();
|
||||
}
|
||||
|
||||
public JFXRippler getRippler() {
|
||||
return buttonRippler;
|
||||
}
|
||||
|
||||
public Node getContainer() {
|
||||
return container.get();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,45 +297,32 @@ 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);
|
||||
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)) {
|
||||
fontAntiAliasingPane.setValue(Optional.of(FontSmoothingType.LCD));
|
||||
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
fontAntiAliasingPane.setValue(Optional.of(FontSmoothingType.GRAY));
|
||||
} else {
|
||||
fontAntiAliasingPane.setValue(Optional.empty());
|
||||
}
|
||||
|
||||
{
|
||||
@SuppressWarnings("unchecked")
|
||||
JFXComboBox<Optional<FontSmoothingType>> cboAntiAliasing = new JFXComboBox<>(FXCollections.observableArrayList(
|
||||
Optional.empty(),
|
||||
Optional.of(FontSmoothingType.LCD),
|
||||
Optional.of(FontSmoothingType.GRAY)
|
||||
));
|
||||
String fontAntiAliasing = globalConfig().getFontAntiAliasing();
|
||||
if ("lcd".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.LCD));
|
||||
} else if ("gray".equalsIgnoreCase(fontAntiAliasing)) {
|
||||
cboAntiAliasing.setValue(Optional.of(FontSmoothingType.GRAY));
|
||||
} else {
|
||||
cboAntiAliasing.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 ->
|
||||
globalConfig().setFontAntiAliasing(value.map(it -> it.name().toLowerCase(Locale.ROOT))
|
||||
.orElse(null)));
|
||||
|
||||
fontAntiAliasingPane.setRight(cboAntiAliasing);
|
||||
}
|
||||
FXUtils.onChange(fontAntiAliasingPane.valueProperty(), value ->
|
||||
globalConfig().setFontAntiAliasing(value.map(it -> it.name().toLowerCase(Locale.ROOT))
|
||||
.orElse(null)));
|
||||
|
||||
fontPane.getContent().add(fontAntiAliasingPane);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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,23 +425,16 @@ 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);
|
||||
LineNavigationButton showAdvancedSettingPane = new LineNavigationButton();
|
||||
showAdvancedSettingPane.setTitle(i18n("settings.advanced"));
|
||||
showAdvancedSettingPane.setOnAction(event -> {
|
||||
if (lastVersionSetting != null) {
|
||||
if (advancedVersionSettingPage == null)
|
||||
advancedVersionSettingPage = new AdvancedVersionSettingPage(profile, versionId, lastVersionSetting);
|
||||
|
||||
JFXButton button = FXUtils.newBorderButton(i18n("settings.advanced.modify"));
|
||||
button.setOnAction(e -> {
|
||||
if (lastVersionSetting != null) {
|
||||
if (advancedVersionSettingPage == null)
|
||||
advancedVersionSettingPage = new AdvancedVersionSettingPage(profile, versionId, lastVersionSetting);
|
||||
|
||||
Controllers.navigateForward(advancedVersionSettingPage);
|
||||
}
|
||||
});
|
||||
showAdvancedSettingPane.setRight(button);
|
||||
}
|
||||
Controllers.navigateForward(advancedVersionSettingPage);
|
||||
}
|
||||
});
|
||||
|
||||
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());
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -295,8 +295,10 @@ download.failed=%1$s のダウンロードに失敗しました、応答コー
|
||||
download.failed.empty=候補者なし。戻るにはここをクリックしてください。
|
||||
download.failed.refresh=バージョンリストをダウンロードできません。ここをクリックして再試行してください。
|
||||
download.game=ゲームのダウンロード
|
||||
download.provider.bmclapi=BMCLAPI(ミラーソース)
|
||||
download.provider.mojang=Mojang(OptiFineは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=ミラーソースからロード
|
||||
|
||||
@@ -334,11 +334,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=引爪哇
|
||||
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=繪器
|
||||
|
||||
@@ -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=Из зеркала
|
||||
|
||||
@@ -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=З дзеркала
|
||||
|
||||
@@ -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=繪製器
|
||||
|
||||
@@ -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=渲染器
|
||||
|
||||
Reference in New Issue
Block a user