add: animation at title bar

This commit is contained in:
huanghongxun 2020-03-02 00:31:41 +08:00
parent 334e93196b
commit fa13b1fc0d
20 changed files with 180 additions and 183 deletions

View File

@ -101,8 +101,10 @@ public final class FXUtils {
value.addListener((a, b, c) -> consumer.accept(c));
}
public static <T> void onWeakChange(ObservableValue<T> value, Consumer<T> consumer) {
value.addListener(new WeakChangeListener<>((a, b, c) -> consumer.accept(c)));
public static <T> WeakChangeListener<T> onWeakChange(ObservableValue<T> value, Consumer<T> consumer) {
WeakChangeListener<T> listener = new WeakChangeListener<>((a, b, c) -> consumer.accept(c));
value.addListener(listener);
return listener;
}
public static <T> void onChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) {
@ -110,9 +112,9 @@ public final class FXUtils {
onChange(value, consumer);
}
public static <T> void onWeakChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) {
public static <T> WeakChangeListener<T> onWeakChangeAndOperate(ObservableValue<T> value, Consumer<T> consumer) {
consumer.accept(value.getValue());
onWeakChange(value, consumer);
return onWeakChange(value, consumer);
}
public static void runLaterIf(BooleanSupplier condition, Runnable runnable) {

View File

@ -24,11 +24,12 @@ import org.jackhuang.hmcl.ui.Controllers;
import org.jackhuang.hmcl.ui.ListPage;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.javafx.MappedObservableList;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
public class AccountList extends ListPage<AccountListItem> implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.manage"));
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage")));
private final ListProperty<Account> accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList());
private final ObjectProperty<Account> selectedAccount;
@ -51,7 +52,7 @@ public class AccountList extends ListPage<AccountListItem> implements DecoratorP
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
}

View File

@ -18,8 +18,7 @@
package org.jackhuang.hmcl.ui.account;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.ObservableList;
import org.jackhuang.hmcl.auth.authlibinjector.AuthlibInjectorServer;
import org.jackhuang.hmcl.ui.Controllers;
@ -31,7 +30,7 @@ import static org.jackhuang.hmcl.setting.ConfigHolder.config;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class AuthlibInjectorServersPage extends ListPage<AuthlibInjectorServerItem> implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.injector.manage.title"));
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.injector.manage.title")));
private final ObservableList<AuthlibInjectorServerItem> serverItems;
@ -50,16 +49,8 @@ public class AuthlibInjectorServersPage extends ListPage<AuthlibInjectorServerIt
Controllers.dialog(new AddAuthlibInjectorServerPane());
}
public String getTitle() {
return title.get();
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public void setTitle(String title) {
this.title.set(title);
public ReadOnlyObjectWrapper<State> stateProperty() {
return state;
}
}

View File

@ -71,7 +71,6 @@ public class Navigator extends TransitionPane {
setContent(node, animationProducer);
NavigationEvent navigated = new NavigationEvent(this, node, NavigationEvent.NAVIGATED);
fireEvent(navigated);
node.fireEvent(navigated);
EventHandler<PageCloseEvent> handler = event -> close(node);
@ -118,7 +117,6 @@ public class Navigator extends TransitionPane {
}
NavigationEvent navigated = new NavigationEvent(this, node, NavigationEvent.NAVIGATED);
fireEvent(navigated);
node.fireEvent(navigated);
Optional.ofNullable(from.getProperties().get(PROPERTY_DIALOG_CLOSE_HANDLER))

View File

@ -35,7 +35,7 @@ public class Decorator extends Control {
private final ListProperty<Node> content = new SimpleListProperty<>(FXCollections.observableArrayList());
private final ListProperty<Node> container = new SimpleListProperty<>(FXCollections.observableArrayList());
private final ObjectProperty<Background> contentBackground = new SimpleObjectProperty<>();
private final StringProperty title = new SimpleStringProperty();
private final ObjectProperty<DecoratorPage.State> state = new SimpleObjectProperty<>();
private final StringProperty drawerTitle = new SimpleStringProperty();
private final ObjectProperty<Runnable> onCloseButtonAction = new SimpleObjectProperty<>();
private final ObjectProperty<EventHandler<ActionEvent>> onCloseNavButtonAction = new SimpleObjectProperty<>();
@ -90,16 +90,16 @@ public class Decorator extends Control {
this.content.set(content);
}
public String getTitle() {
return title.get();
public DecoratorPage.State getState() {
return state.get();
}
public StringProperty titleProperty() {
return title;
public ObjectProperty<DecoratorPage.State> stateProperty() {
return state;
}
public void setTitle(String title) {
this.title.set(title);
public void setState(DecoratorPage.State state) {
this.state.set(state);
}
public String getDrawerTitle() {

View File

@ -71,14 +71,11 @@ public class DecoratorController {
private final Decorator decorator;
private final ImageView welcomeView;
private final Navigator navigator;
private final Node mainPage;
private JFXDialog dialog;
private StackContainerPane dialogPane;
public DecoratorController(Stage stage, Node mainPage) {
this.mainPage = mainPage;
decorator = new Decorator(stage);
decorator.setOnCloseButtonAction(Launcher::stopApplication);
@ -269,16 +266,12 @@ public class DecoratorController {
}
if (to instanceof DecoratorPage) {
decorator.drawerTitleProperty().bind(((DecoratorPage) to).titleProperty());
decorator.showCloseAsHomeProperty().set(!((DecoratorPage) to).isPageCloseable());
decorator.canBackProperty().bind(Bindings.createBooleanBinding(() -> navigator.canGoBack() || ((DecoratorPage) to).backableProperty().get(),
((DecoratorPage) to).backableProperty()));
decorator.stateProperty().bind(((DecoratorPage) to).stateProperty());
} else {
decorator.drawerTitleProperty().unbind();
decorator.drawerTitleProperty().set("");
decorator.showCloseAsHomeProperty().set(true);
decorator.canBackProperty().unbind();
decorator.canBackProperty().setValue(navigator.canGoBack());
decorator.stateProperty().unbind();
decorator.stateProperty().set(new DecoratorPage.State("", null, navigator.canGoBack(), false, true));
}
decorator.canCloseProperty().set(navigator.canGoBack());

View File

@ -17,6 +17,7 @@
*/
package org.jackhuang.hmcl.ui.decorator;
import javafx.beans.binding.Bindings;
import javafx.scene.Node;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
@ -35,7 +36,6 @@ public abstract class DecoratorNavigatorPage extends DecoratorTransitionPage {
@Override
protected void navigate(Node page, AnimationProducer animationProducer) {
navigator.navigate(page, animationProducer);
setRefreshable(page instanceof Refreshable);
}
@Override
@ -68,14 +68,15 @@ public abstract class DecoratorNavigatorPage extends DecoratorTransitionPage {
}
if (to instanceof DecoratorPage) {
titleProperty().bind(((DecoratorPage) to).titleProperty());
state.bind(Bindings.createObjectBinding(() -> {
State state = ((DecoratorPage) to).stateProperty().get();
return new State(state.getTitle(), state.getTitleNode(), navigator.canGoBack(), state.isRefreshable(), true);
}, ((DecoratorPage) to).stateProperty()));
} else {
titleProperty().unbind();
titleProperty().set("");
state.unbind();
state.set(new State("", null, navigator.canGoBack(), false, true));
}
setBackable(navigator.canGoBack());
if (to instanceof Region) {
Region region = (Region) to;
// Let root pane fix window size.

View File

@ -17,14 +17,13 @@
*/
package org.jackhuang.hmcl.ui.decorator;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.scene.Node;
import org.jackhuang.hmcl.ui.construct.Navigator;
import org.jackhuang.hmcl.ui.wizard.Refreshable;
public interface DecoratorPage {
ReadOnlyStringProperty titleProperty();
public interface DecoratorPage extends Refreshable {
ReadOnlyObjectProperty<State> stateProperty();
default boolean isPageCloseable() {
return false;
@ -34,8 +33,8 @@ public interface DecoratorPage {
return true;
}
default BooleanProperty backableProperty() {
return new SimpleBooleanProperty(true);
@Override
default void refresh() {
}
default void closePage() {
@ -44,4 +43,48 @@ public interface DecoratorPage {
default void onDecoratorPageNavigating(Navigator.NavigationEvent event) {
((Node) this).getStyleClass().add("content-background");
}
class State {
private final String title;
private final Node titleNode;
private final boolean backable;
private final boolean refreshable;
private final boolean animate;
public State(String title, Node titleNode, boolean backable, boolean refreshable, boolean animate) {
this.title = title;
this.titleNode = titleNode;
this.backable = backable;
this.refreshable = refreshable;
this.animate = animate;
}
public static State fromTitle(String title) {
return new State(title, null, true, false, true);
}
public static State fromTitleNode(Node titleNode) {
return new State(null, titleNode, true, false, true);
}
public String getTitle() {
return title;
}
public Node getTitleNode() {
return titleNode;
}
public boolean isBackable() {
return backable;
}
public boolean isRefreshable() {
return refreshable;
}
public boolean isAnimate() {
return animate;
}
}
}

View File

@ -29,13 +29,18 @@ import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.SkinBase;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.*;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import org.jackhuang.hmcl.setting.Theme;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.SVG;
import org.jackhuang.hmcl.ui.animation.ContainerAnimations;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.util.Lang;
public class DecoratorSkin extends SkinBase<Decorator> {
@ -45,6 +50,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
private final BorderPane titleContainer;
private final StackPane contentPlaceHolder;
private final Stage primaryStage;
private final TransitionPane navBarPane;
private double xOffset, yOffset, newX, newY, initX, initY;
private boolean allowMove, isDragging;
@ -125,7 +131,17 @@ public class DecoratorSkin extends SkinBase<Decorator> {
rectangle.heightProperty().bind(titleContainer.heightProperty().add(100));
titleContainer.setClip(rectangle);
{
titleContainer.setCenter(createNavBar(skinnable));
navBarPane = new TransitionPane();
FXUtils.onChangeAndOperate(skinnable.stateProperty(), s -> {
if (s == null) return;
Node node = createNavBar(skinnable, s.isBackable(), skinnable.canCloseProperty().get(), skinnable.showCloseAsHomeProperty().get(), s.isRefreshable(), s.getTitle(), s.getTitleNode());
if (s.isAnimate()) {
navBarPane.setContent(node, ContainerAnimations.FADE.getAnimationProducer());
} else {
navBarPane.getChildren().setAll(node);
}
});
titleContainer.setCenter(navBarPane);
HBox buttonsContainer = new HBox();
buttonsContainer.setStyle("-fx-background-color: transparent;");
@ -153,7 +169,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
getChildren().setAll(root);
}
private Node createNavBar(Decorator skinnable) {
private Node createNavBar(Decorator skinnable, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) {
BorderPane navBar = new BorderPane();
{
HBox navLeft = new HBox();
@ -165,7 +181,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
backNavButton.getStyleClass().add("jfx-decorator-button");
backNavButton.ripplerFillProperty().bind(Theme.whiteFillBinding());
backNavButton.onActionProperty().bind(skinnable.onBackNavButtonActionProperty());
backNavButton.visibleProperty().bind(skinnable.canBackProperty());
backNavButton.visibleProperty().set(canBack);
JFXButton closeNavButton = new JFXButton();
closeNavButton.setGraphic(SVG.close(Theme.foregroundFillBinding(), -1, -1));
@ -173,31 +189,29 @@ public class DecoratorSkin extends SkinBase<Decorator> {
closeNavButton.ripplerFillProperty().bind(Theme.whiteFillBinding());
closeNavButton.onActionProperty().bind(skinnable.onCloseNavButtonActionProperty());
FXUtils.onChangeAndOperate(skinnable.canBackProperty(), (newValue) -> {
navLeft.getChildren().remove(backNavButton);
if (newValue) navLeft.getChildren().add(0, backNavButton);
});
FXUtils.onChangeAndOperate(skinnable.canCloseProperty(), (newValue) -> {
navLeft.getChildren().remove(closeNavButton);
if (newValue) navLeft.getChildren().add(closeNavButton);
});
FXUtils.onChangeAndOperate(skinnable.showCloseAsHomeProperty(), (newValue) -> {
if (newValue)
closeNavButton.setGraphic(SVG.home(Theme.foregroundFillBinding(), -1, -1));
else
closeNavButton.setGraphic(SVG.close(Theme.foregroundFillBinding(), -1, -1));
});
if (canBack) navLeft.getChildren().add(backNavButton);
if (canClose) navLeft.getChildren().add(closeNavButton);
if (showCloseAsHome)
closeNavButton.setGraphic(SVG.home(Theme.foregroundFillBinding(), -1, -1));
else
closeNavButton.setGraphic(SVG.close(Theme.foregroundFillBinding(), -1, -1));
}
navBar.setLeft(navLeft);
VBox navCenter = new VBox();
navCenter.setAlignment(Pos.CENTER_LEFT);
Label titleLabel = new Label();
titleLabel.getStyleClass().add("jfx-decorator-title");
titleLabel.textProperty().bind(skinnable.drawerTitleProperty());
navCenter.getChildren().setAll(titleLabel);
navBar.setCenter(navCenter);
BorderPane center = new BorderPane();
if (title != null) {
Label titleLabel = new Label();
titleLabel.getStyleClass().add("jfx-decorator-title");
titleLabel.setText(title);
center.setLeft(titleLabel);
BorderPane.setAlignment(titleLabel, Pos.CENTER_LEFT);
}
if (titleNode != null) {
center.setCenter(titleNode);
BorderPane.setAlignment(titleNode, Pos.CENTER_LEFT);
BorderPane.setMargin(titleNode, new Insets(0, 0, 0, 8));
}
navBar.setCenter(center);
HBox navRight = new HBox();
navRight.setAlignment(Pos.CENTER_RIGHT);
@ -206,7 +220,7 @@ public class DecoratorSkin extends SkinBase<Decorator> {
refreshNavButton.getStyleClass().add("jfx-decorator-button");
refreshNavButton.ripplerFillProperty().bind(Theme.whiteFillBinding());
refreshNavButton.onActionProperty().bind(skinnable.onRefreshNavButtonActionProperty());
refreshNavButton.visibleProperty().bind(skinnable.canRefreshProperty());
refreshNavButton.visibleProperty().set(canRefresh);
Rectangle separator = new Rectangle();
separator.visibleProperty().bind(refreshNavButton.visibleProperty());

View File

@ -18,9 +18,9 @@
package org.jackhuang.hmcl.ui.decorator;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Node;
import javafx.scene.control.Control;
import javafx.scene.control.Skin;
@ -28,10 +28,11 @@ import org.jackhuang.hmcl.ui.animation.AnimationProducer;
import org.jackhuang.hmcl.ui.animation.TransitionPane;
import org.jackhuang.hmcl.ui.wizard.Refreshable;
public abstract class DecoratorTransitionPage extends Control implements DecoratorPage, Refreshable {
private final StringProperty title = new SimpleStringProperty();
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public abstract class DecoratorTransitionPage extends Control implements DecoratorPage {
protected final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("")));
private final BooleanProperty refreshable = new SimpleBooleanProperty(false);
private final BooleanProperty backable = new SimpleBooleanProperty();
private Node currentPage;
protected final TransitionPane transitionPane = new TransitionPane();
@ -47,28 +48,10 @@ public abstract class DecoratorTransitionPage extends Control implements Decorat
return currentPage;
}
public String getTitle() {
return title.get();
}
@Override
public StringProperty titleProperty() {
return title;
}
public void setTitle(String title) {
this.title.set(title);
}
public boolean isRefreshable() {
return refreshable.get();
}
@Override
public void refresh() {
// empty implementation for default
}
@Override
public BooleanProperty refreshableProperty() {
return refreshable;
@ -78,16 +61,8 @@ public abstract class DecoratorTransitionPage extends Control implements Decorat
this.refreshable.set(refreshable);
}
public boolean isBackable() {
return backable.get();
}
@Override
public BooleanProperty backableProperty() {
return backable;
}
public void setBackable(boolean backable) {
this.backable.set(backable);
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
}

View File

@ -71,8 +71,12 @@ public class DecoratorWizardDisplayer extends DecoratorTransitionPage implements
String prefix = category == null ? "" : category + " - ";
String title;
if (page instanceof WizardPage)
setTitle(prefix + ((WizardPage) page).getTitle());
title = prefix + ((WizardPage) page).getTitle();
else
title = "";
state.set(new State(title, null, true, refreshableProperty().get(), true));
}
@Override

View File

@ -59,7 +59,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.SINE;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class MainPage extends StackPane implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", "Hello Minecraft! Launcher " + Metadata.VERSION);
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle("Hello Minecraft! Launcher " + Metadata.VERSION));
private final PopupMenu menu = new PopupMenu();
private final JFXPopup popup = new JFXPopup(menu);
@ -236,17 +236,9 @@ public final class MainPage extends StackPane implements DecoratorPage {
showUpdate.set(false);
}
public String getTitle() {
return title.get();
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public void setTitle(String title) {
this.title.set(title);
public ReadOnlyObjectWrapper<State> stateProperty() {
return state;
}
public String getCurrentGame() {

View File

@ -24,8 +24,8 @@ import javafx.beans.InvalidationListener;
import javafx.beans.WeakInvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.When;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.control.ToggleGroup;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
@ -67,7 +67,7 @@ import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.reservedSelected
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.selectedItemPropertyFor;
public final class SettingsPage extends SettingsView implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("settings.launcher"));
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("settings.launcher")));
private InvalidationListener updateListener;
@ -200,17 +200,9 @@ public final class SettingsPage extends SettingsView implements DecoratorPage {
// ====
}
public String getTitle() {
return title.get();
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public void setTitle(String title) {
this.title.set(title);
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
@Override

View File

@ -29,7 +29,7 @@ import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
import static org.jackhuang.hmcl.util.javafx.ExtendedProperties.createSelectedItemPropertyFor;
public class ProfileList extends ListPage<ProfileListItem> implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(i18n("profile.manage"));
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("profile.manage")));
private final ListProperty<Profile> profiles = new SimpleListProperty<>(FXCollections.observableArrayList());
private ObjectProperty<Profile> selectedProfile;
@ -52,7 +52,7 @@ public class ProfileList extends ListPage<ProfileListItem> implements DecoratorP
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
}

View File

@ -21,8 +21,8 @@ import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXCheckBox;
import com.jfoenix.controls.JFXTextField;
import com.jfoenix.validation.base.ValidatorBase;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
@ -41,7 +41,7 @@ import java.util.Optional;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class ProfilePage extends StackPane implements DecoratorPage {
private final ReadOnlyStringWrapper title;
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final StringProperty location;
private final Profile profile;
@ -57,8 +57,7 @@ public final class ProfilePage extends StackPane implements DecoratorPage {
this.profile = profile;
String profileDisplayName = Optional.ofNullable(profile).map(Profiles::getProfileDisplayName).orElse("");
title = new ReadOnlyStringWrapper(this, "title",
profile == null ? i18n("profile.new") : i18n("profile") + " - " + profileDisplayName);
state.set(State.fromTitle(profile == null ? i18n("profile.new") : i18n("profile") + " - " + profileDisplayName));
location = new SimpleStringProperty(this, "location",
Optional.ofNullable(profile).map(Profile::getGameDir).map(File::getAbsolutePath).orElse(".minecraft"));
@ -111,17 +110,9 @@ public final class ProfilePage extends StackPane implements DecoratorPage {
fireEvent(new PageCloseEvent());
}
public String getTitle() {
return title.get();
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
}
public void setTitle(String title) {
this.title.set(title);
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
public String getLocation() {

View File

@ -17,8 +17,8 @@
*/
package org.jackhuang.hmcl.ui.versions;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.ObservableList;
import javafx.scene.control.Skin;
import javafx.stage.FileChooser;
@ -43,7 +43,7 @@ import java.util.logging.Level;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class DatapackListPage extends ListPageBase<DatapackListPageSkin.DatapackInfoObject> implements DecoratorPage {
private final StringProperty title = new SimpleStringProperty();
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final Path worldDir;
private final Datapack datapack;
@ -52,7 +52,7 @@ public class DatapackListPage extends ListPageBase<DatapackListPageSkin.Datapack
public DatapackListPage(String worldName, Path worldDir) {
this.worldDir = worldDir;
title.set(i18n("datapack.title", worldName));
state.set(State.fromTitle(i18n("datapack.title", worldName)));
datapack = new Datapack(worldDir.resolve("datapacks"));
datapack.loadFromDir();
@ -86,8 +86,8 @@ public class DatapackListPage extends ListPageBase<DatapackListPageSkin.Datapack
}
@Override
public StringProperty titleProperty() {
return title;
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
public void add() {

View File

@ -18,8 +18,8 @@
package org.jackhuang.hmcl.ui.versions;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.scene.Node;
import javafx.scene.control.ToggleGroup;
import org.jackhuang.hmcl.event.EventBus;
@ -33,7 +33,6 @@ import org.jackhuang.hmcl.ui.construct.Navigator;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider;
import org.jackhuang.hmcl.ui.download.VanillaInstallWizardProvider;
import org.jackhuang.hmcl.util.i18n.I18n;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.util.Arrays;
@ -46,7 +45,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class GameList extends ListPageBase<GameListItem> implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(I18n.i18n("version.manage"));
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("version.manage")));
private ToggleGroup toggleGroup;
@ -123,8 +122,8 @@ public class GameList extends ListPageBase<GameListItem> implements DecoratorPag
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
private class GameListSkin extends ToolbarListPageSkin<GameList> {

View File

@ -18,13 +18,15 @@
package org.jackhuang.hmcl.ui.versions;
import com.jfoenix.controls.JFXListView;
import com.jfoenix.controls.JFXTabPane;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.scene.control.Control;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.SkinBase;
import javafx.scene.control.Tab;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
@ -35,6 +37,7 @@ import org.jackhuang.hmcl.setting.Profile;
import org.jackhuang.hmcl.setting.Profiles;
import org.jackhuang.hmcl.ui.FXUtils;
import org.jackhuang.hmcl.ui.construct.SpinnerPane;
import org.jackhuang.hmcl.ui.construct.TabHeader;
import org.jackhuang.hmcl.ui.decorator.DecoratorPage;
import org.jackhuang.hmcl.util.versioning.VersionNumber;
@ -44,9 +47,10 @@ import java.util.List;
import java.util.stream.Collectors;
import static org.jackhuang.hmcl.ui.FXUtils.runInFX;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public class VersionRootPage extends Control implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper();
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>();
private final BooleanProperty loading = new SimpleBooleanProperty();
private final JFXListView<String> listView = new JFXListView<>();
private final VersionPage versionPage = new VersionPage();
@ -88,8 +92,8 @@ public class VersionRootPage extends Control implements DecoratorPage {
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title.getReadOnlyProperty();
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
public static class Skin extends SkinBase<VersionRootPage> {
@ -129,8 +133,9 @@ public class VersionRootPage extends Control implements DecoratorPage {
root.setLeft(leftRootPane);
}
control.state.set(new State(i18n("version.manage.manage"), null, true, false, true));
root.setCenter(control.versionPage);
control.title.bind(control.versionPage.titleProperty());
spinnerPane.loadingProperty().bind(control.versionPage.loadingProperty());
spinnerPane.setContent(root);

View File

@ -24,8 +24,8 @@ import com.jfoenix.controls.JFXToggleButton;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
@ -63,7 +63,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.stringConverter;
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
public final class VersionSettingsPage extends StackPane implements DecoratorPage {
private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper();
private final ReadOnlyObjectWrapper<State> state = new ReadOnlyObjectWrapper<>(new State("", null, false, false, false));
private VersionSetting lastVersionSetting = null;
private Profile profile;
@ -163,7 +163,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
rootPane.getChildren().remove(iconPickerItemWrapper);
rootPane.getChildren().remove(settingsTypePane);
chkEnableSpecificSettings.setSelected(true);
title.set(Profiles.getProfileDisplayName(profile) + " - " + i18n("settings.type.global.manage"));
state.set(State.fromTitle(Profiles.getProfileDisplayName(profile) + " - " + i18n("settings.type.global.manage")));
}
VersionSetting versionSetting = profile.getVersionSetting(versionId);
@ -328,7 +328,7 @@ public final class VersionSettingsPage extends StackPane implements DecoratorPag
}
@Override
public ReadOnlyStringProperty titleProperty() {
return title;
public ReadOnlyObjectProperty<State> stateProperty() {
return state.getReadOnlyProperty();
}
}

View File

@ -23,10 +23,6 @@
}
.scroll-bar .track {
-fx-stroke-width: 1;
-fx-stroke: -c-dark-glass;
-fx-arc-width: 5px;
-fx-arc-height: 5px;
-fx-fill: transparent;
}