From fa13b1fc0d8df940a87dcb5a5808d5323882da53 Mon Sep 17 00:00:00 2001 From: huanghongxun Date: Mon, 2 Mar 2020 00:31:41 +0800 Subject: [PATCH] add: animation at title bar --- .../java/org/jackhuang/hmcl/ui/FXUtils.java | 10 +-- .../hmcl/ui/account/AccountList.java | 7 +- .../account/AuthlibInjectorServersPage.java | 17 ++--- .../hmcl/ui/construct/Navigator.java | 2 - .../hmcl/ui/decorator/Decorator.java | 14 ++-- .../ui/decorator/DecoratorController.java | 13 +--- .../ui/decorator/DecoratorNavigatorPage.java | 13 ++-- .../hmcl/ui/decorator/DecoratorPage.java | 57 ++++++++++++++-- .../hmcl/ui/decorator/DecoratorSkin.java | 68 +++++++++++-------- .../ui/decorator/DecoratorTransitionPage.java | 41 +++-------- .../decorator/DecoratorWizardDisplayer.java | 6 +- .../org/jackhuang/hmcl/ui/main/MainPage.java | 14 +--- .../jackhuang/hmcl/ui/main/SettingsPage.java | 18 ++--- .../hmcl/ui/profile/ProfileList.java | 6 +- .../hmcl/ui/profile/ProfilePage.java | 21 ++---- .../hmcl/ui/versions/DatapackListPage.java | 12 ++-- .../jackhuang/hmcl/ui/versions/GameList.java | 11 ++- .../hmcl/ui/versions/VersionRootPage.java | 17 +++-- .../hmcl/ui/versions/VersionSettingsPage.java | 12 ++-- HMCL/src/main/resources/assets/css/root.css | 4 -- 20 files changed, 180 insertions(+), 183 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index 4aaba552f..2e2005e24 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -101,8 +101,10 @@ public final class FXUtils { value.addListener((a, b, c) -> consumer.accept(c)); } - public static void onWeakChange(ObservableValue value, Consumer consumer) { - value.addListener(new WeakChangeListener<>((a, b, c) -> consumer.accept(c))); + public static WeakChangeListener onWeakChange(ObservableValue value, Consumer consumer) { + WeakChangeListener listener = new WeakChangeListener<>((a, b, c) -> consumer.accept(c)); + value.addListener(listener); + return listener; } public static void onChangeAndOperate(ObservableValue value, Consumer consumer) { @@ -110,9 +112,9 @@ public final class FXUtils { onChange(value, consumer); } - public static void onWeakChangeAndOperate(ObservableValue value, Consumer consumer) { + public static WeakChangeListener onWeakChangeAndOperate(ObservableValue value, Consumer consumer) { consumer.accept(value.getValue()); - onWeakChange(value, consumer); + return onWeakChange(value, consumer); } public static void runLaterIf(BooleanSupplier condition, Runnable runnable) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java index 1f61514ba..e3848c3c5 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java @@ -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 implements DecoratorPage { - private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.manage")); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.manage"))); private final ListProperty accounts = new SimpleListProperty<>(this, "accounts", FXCollections.observableArrayList()); private final ObjectProperty selectedAccount; @@ -51,7 +52,7 @@ public class AccountList extends ListPage implements DecoratorP } @Override - public ReadOnlyStringProperty titleProperty() { - return title.getReadOnlyProperty(); + public ReadOnlyObjectProperty stateProperty() { + return state.getReadOnlyProperty(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AuthlibInjectorServersPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AuthlibInjectorServersPage.java index a20044b41..d10aa329e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AuthlibInjectorServersPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AuthlibInjectorServersPage.java @@ -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 implements DecoratorPage { - private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(this, "title", i18n("account.injector.manage.title")); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("account.injector.manage.title"))); private final ObservableList serverItems; @@ -50,16 +49,8 @@ public class AuthlibInjectorServersPage extends ListPage stateProperty() { + return state; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java index 910a65a0a..44415de47 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/Navigator.java @@ -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 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)) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java index c9f35cc7d..99bfa44bc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/Decorator.java @@ -35,7 +35,7 @@ public class Decorator extends Control { private final ListProperty content = new SimpleListProperty<>(FXCollections.observableArrayList()); private final ListProperty container = new SimpleListProperty<>(FXCollections.observableArrayList()); private final ObjectProperty contentBackground = new SimpleObjectProperty<>(); - private final StringProperty title = new SimpleStringProperty(); + private final ObjectProperty state = new SimpleObjectProperty<>(); private final StringProperty drawerTitle = new SimpleStringProperty(); private final ObjectProperty onCloseButtonAction = new SimpleObjectProperty<>(); private final ObjectProperty> 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 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() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index ced703cb1..b7e83f65f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -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()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorNavigatorPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorNavigatorPage.java index 6c67b02e2..f74f18c5e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorNavigatorPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorNavigatorPage.java @@ -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. diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java index eba652ee1..255c3e700 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorPage.java @@ -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 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; + } + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java index 1b65fd9c0..e4ea4c533 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java @@ -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 { @@ -45,6 +50,7 @@ public class DecoratorSkin extends SkinBase { 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 { 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 { 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 { 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 { 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 { 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()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTransitionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTransitionPage.java index 73522d7f4..1b00cc0a1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTransitionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorTransitionPage.java @@ -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 = 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 stateProperty() { + return state.getReadOnlyProperty(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java index fdfef24e3..dc385eb20 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorWizardDisplayer.java @@ -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 diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java index c5379abf4..15e94b611 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/MainPage.java @@ -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 = 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 stateProperty() { + return state; } public String getCurrentGame() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java index c2b09dfa9..211679600 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/SettingsPage.java @@ -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 = 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 stateProperty() { + return state.getReadOnlyProperty(); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfileList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfileList.java index a29a8c850..4e936054d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfileList.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfileList.java @@ -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 implements DecoratorPage { - private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(i18n("profile.manage")); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("profile.manage"))); private final ListProperty profiles = new SimpleListProperty<>(FXCollections.observableArrayList()); private ObjectProperty selectedProfile; @@ -52,7 +52,7 @@ public class ProfileList extends ListPage implements DecoratorP } @Override - public ReadOnlyStringProperty titleProperty() { - return title.getReadOnlyProperty(); + public ReadOnlyObjectProperty stateProperty() { + return state.getReadOnlyProperty(); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfilePage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfilePage.java index 405cdb1fc..e5ad0caa7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfilePage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/profile/ProfilePage.java @@ -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 = 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 stateProperty() { + return state.getReadOnlyProperty(); } public String getLocation() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java index 278c60c59..e66b512d6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPage.java @@ -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 implements DecoratorPage { - private final StringProperty title = new SimpleStringProperty(); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(); private final Path worldDir; private final Datapack datapack; @@ -52,7 +52,7 @@ public class DatapackListPage extends ListPageBase stateProperty() { + return state.getReadOnlyProperty(); } public void add() { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java index 6466402c2..8cced310d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java @@ -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 implements DecoratorPage { - private final ReadOnlyStringWrapper title = new ReadOnlyStringWrapper(I18n.i18n("version.manage")); + private final ReadOnlyObjectWrapper state = new ReadOnlyObjectWrapper<>(State.fromTitle(i18n("version.manage"))); private ToggleGroup toggleGroup; @@ -123,8 +122,8 @@ public class GameList extends ListPageBase implements DecoratorPag } @Override - public ReadOnlyStringProperty titleProperty() { - return title.getReadOnlyProperty(); + public ReadOnlyObjectProperty stateProperty() { + return state.getReadOnlyProperty(); } private class GameListSkin extends ToolbarListPageSkin { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionRootPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionRootPage.java index a0ecd1aeb..b5c1b946f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionRootPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionRootPage.java @@ -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 = new ReadOnlyObjectWrapper<>(); private final BooleanProperty loading = new SimpleBooleanProperty(); private final JFXListView 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 stateProperty() { + return state.getReadOnlyProperty(); } public static class Skin extends SkinBase { @@ -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); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index 3450b8745..f0258bc67 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -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 = 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 stateProperty() { + return state.getReadOnlyProperty(); } } diff --git a/HMCL/src/main/resources/assets/css/root.css b/HMCL/src/main/resources/assets/css/root.css index e8c5a4da2..e426f550a 100644 --- a/HMCL/src/main/resources/assets/css/root.css +++ b/HMCL/src/main/resources/assets/css/root.css @@ -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; }