diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java index 57a031d24..2cda33e6a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/animation/TransitionPane.java @@ -26,7 +26,6 @@ import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.util.Duration; import org.jackhuang.hmcl.ui.FXUtils; -import org.jackhuang.hmcl.ui.construct.TabHeader; import org.jetbrains.annotations.Nullable; public class TransitionPane extends StackPane { @@ -41,17 +40,6 @@ public class TransitionPane extends StackPane { return currentNode; } - public void bindTabHeader(TabHeader tabHeader) { - this.setContent(tabHeader.getSelectionModel().getSelectedItem().getNode(), ContainerAnimations.NONE); - FXUtils.onChange(tabHeader.getSelectionModel().selectedItemProperty(), newValue -> { - this.setContent(newValue.getNode(), - ContainerAnimations.SLIDE_UP_FADE_IN, - Motion.MEDIUM4, - Motion.EASE_IN_OUT_CUBIC_EMPHASIZED - ); - }); - } - public final void setContent(Node newView, AnimationProducer transition) { setContent(newView, transition, Motion.SHORT4); } @@ -66,6 +54,7 @@ public class TransitionPane extends StackPane { currentNode = newView; if (!AnimationUtils.isAnimationEnabled() || previousNode == null || transition == ContainerAnimations.NONE) { + AnimationUtils.reset(newView, true); getChildren().setAll(newView); return; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TabHeader.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TabHeader.java index c83708848..d41dce3d7 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TabHeader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/TabHeader.java @@ -36,12 +36,24 @@ import javafx.scene.transform.Rotate; import javafx.scene.transform.Scale; import javafx.util.Duration; import org.jackhuang.hmcl.ui.FXUtils; +import org.jackhuang.hmcl.ui.animation.ContainerAnimations; +import org.jackhuang.hmcl.ui.animation.Motion; +import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.util.javafx.MappedObservableList; +import org.jetbrains.annotations.Nullable; @SuppressWarnings("deprecation") public class TabHeader extends Control implements TabControl, PageAware { + private final TransitionPane contentPane; + public TabHeader(Tab... tabs) { + this(null, tabs); + } + + public TabHeader(@Nullable TransitionPane contentPane, Tab... tabs) { + this.contentPane = contentPane; + getStyleClass().setAll("tab-header"); if (tabs != null) { getTabs().addAll(tabs); @@ -49,41 +61,48 @@ public class TabHeader extends Control implements TabControl, PageAware { } private final ObservableList> tabs = FXCollections.observableArrayList(); - private final ObjectProperty side = new SimpleObjectProperty<>(Side.TOP); @Override public ObservableList> getTabs() { return tabs; } - private final ObjectProperty>> selectionModel = new SimpleObjectProperty<>(this, "selectionModel", new TabControlSelectionModel(this)); + private final SingleSelectionModel> selectionModel = new TabControlSelectionModel(this); public SingleSelectionModel> getSelectionModel() { - return selectionModel.get(); - } - - public ObjectProperty>> selectionModelProperty() { return selectionModel; } - public void setSelectionModel(SingleSelectionModel> selectionModel) { - this.selectionModel.set(selectionModel); + public void select(Tab tab) { + select(tab, true); } - public void select(Tab tab) { + public void select(Tab tab, boolean playAnimation) { Tab oldTab = getSelectionModel().getSelectedItem(); if (oldTab != null) { - if (oldTab.getNode() instanceof PageAware) { - ((PageAware) oldTab.getNode()).onPageHidden(); + if (oldTab.getNode() instanceof PageAware pageAware) { + pageAware.onPageHidden(); } } tab.initializeIfNeeded(); - if (tab.getNode() instanceof PageAware) { - ((PageAware) tab.getNode()).onPageShown(); + if (tab.getNode() instanceof PageAware pageAware) { + pageAware.onPageShown(); } getSelectionModel().select(tab); + + if (contentPane != null) { + if (playAnimation && contentPane.getCurrentNode() != null) { + contentPane.setContent(tab.getNode(), + ContainerAnimations.SLIDE_UP_FADE_IN, + Motion.MEDIUM4, + Motion.EASE_IN_OUT_CUBIC_EMPHASIZED + ); + } else { + contentPane.setContent(tab.getNode(), ContainerAnimations.NONE); + } + } } @Override @@ -106,12 +125,7 @@ public class TabHeader extends Control implements TabControl, PageAware { } } - /** - * The position to place the tabs. - */ - public Side getSide() { - return side.get(); - } + private final ObjectProperty side = new SimpleObjectProperty<>(Side.TOP); /** * The position of the tabs. @@ -120,6 +134,13 @@ public class TabHeader extends Control implements TabControl, PageAware { return side; } + /** + * The position to place the tabs. + */ + public Side getSide() { + return side.get(); + } + /** * The position the place the tabs in this TabHeader. */ diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index 7680b27b3..fc66f761d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -39,7 +39,6 @@ import org.jackhuang.hmcl.ui.WeakListenerHolder; import org.jackhuang.hmcl.ui.animation.TransitionPane; import org.jackhuang.hmcl.ui.construct.AdvancedListBox; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; -import org.jackhuang.hmcl.ui.construct.TabControl; import org.jackhuang.hmcl.ui.construct.TabHeader; import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; @@ -99,12 +98,11 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage resourcePackTab.setNodeSupplier(loadVersionFor(() -> HMCLLocalizedDownloadListPage.ofResourcePack((profile, version, file) -> download(profile, version, file, "resourcepacks"), true))); shaderTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(ModrinthRemoteModRepository.SHADER_PACKS, (profile, version, file) -> download(profile, version, file, "shaderpacks"), true))); worldTab.setNodeSupplier(loadVersionFor(() -> new DownloadListPage(CurseForgeRemoteModRepository.WORLDS))); - tab = new TabHeader(newGameTab, modpackTab, modTab, resourcePackTab, shaderTab, worldTab); + tab = new TabHeader(transitionPane, newGameTab, modpackTab, modTab, resourcePackTab, shaderTab, worldTab); Profiles.registerVersionsListener(this::loadVersions); tab.select(newGameTab); - transitionPane.bindTabHeader(tab); AdvancedListBox sideBar = new AdvancedListBox() .startCategory(i18n("download.game").toUpperCase(Locale.ROOT)) @@ -121,13 +119,6 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage setCenter(transitionPane); } - private void selectTabIfCurseForgeAvailable(TabControl.Tab newTab) { - if (CurseForgeRemoteModRepository.isAvailable()) - tab.select(newTab); - else - Controllers.dialog(i18n("download.curseforge.unavailable")); - } - private static Supplier loadVersionFor(Supplier nodeSupplier) { return () -> { T node = nodeSupplier.get(); @@ -202,20 +193,20 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage } public void showGameDownloads() { - tab.select(newGameTab); + tab.select(newGameTab, false); } public void showModpackDownloads() { - tab.select(modpackTab); + tab.select(modpackTab, false); } public DownloadListPage showModDownloads() { - tab.select(modTab); + tab.select(modTab, false); return modTab.getNode(); } public void showWorldDownloads() { - tab.select(worldTab); + tab.select(worldTab, false); } private static final class DownloadNavigator implements Navigation { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java index eb6444223..07753b934 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/main/LauncherSettingsPage.java @@ -55,11 +55,10 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor helpTab.setNodeSupplier(HelpPage::new); feedbackTab.setNodeSupplier(FeedbackPage::new); aboutTab.setNodeSupplier(AboutPage::new); - tab = new TabHeader(gameTab, javaManagementTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, aboutTab); + tab = new TabHeader(transitionPane, gameTab, javaManagementTab, settingsTab, personalizationTab, downloadTab, helpTab, feedbackTab, aboutTab); tab.select(gameTab); addEventHandler(Navigator.NavigationEvent.NAVIGATED, event -> gameTab.getNode().loadVersion(Profiles.getSelectedProfile(), null)); - transitionPane.bindTabHeader(tab); AdvancedListBox sideBar = new AdvancedListBox() .addNavigationDrawerTab(tab, gameTab, i18n("settings.type.global.manage"), SVG.STADIA_CONTROLLER, SVG.STADIA_CONTROLLER_FILL) @@ -90,11 +89,11 @@ public class LauncherSettingsPage extends DecoratorAnimatedPage implements Decor public void showGameSettings(Profile profile) { gameTab.getNode().loadVersion(profile, null); - tab.select(gameTab); + tab.select(gameTab, false); } public void showFeedback() { - tab.select(feedbackTab); + tab.select(feedbackTab, false); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java index 48f130954..ff8f2af4b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/terracotta/TerracottaPage.java @@ -56,9 +56,8 @@ public class TerracottaPage extends DecoratorAnimatedPage implements DecoratorPa public TerracottaPage() { statusPage.setNodeSupplier(TerracottaControllerPage::new); - tab = new TabHeader(statusPage); + tab = new TabHeader(transitionPane, statusPage); tab.select(statusPage); - transitionPane.bindTabHeader(tab); BorderPane left = new BorderPane(); FXUtils.setLimitWidth(left, 200); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java index c509393d3..7162cf6ab 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionPage.java @@ -71,13 +71,11 @@ public class VersionPage extends DecoratorAnimatedPage implements DecoratorPage worldListTab.setNodeSupplier(loadVersionFor(WorldListPage::new)); schematicsTab.setNodeSupplier(loadVersionFor(SchematicsPage::new)); - tab = new TabHeader(versionSettingsTab, installerListTab, modListTab, worldListTab, schematicsTab); + tab = new TabHeader(transitionPane, versionSettingsTab, installerListTab, modListTab, worldListTab, schematicsTab); + tab.select(versionSettingsTab); addEventHandler(Navigator.NavigationEvent.NAVIGATED, this::onNavigated); - tab.select(versionSettingsTab); - transitionPane.bindTabHeader(tab); - listenerHolder.add(EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).registerWeak(event -> checkSelectedVersion(), EventPriority.HIGHEST)); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java index c86befc77..64679346b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/WorldManagePage.java @@ -64,15 +64,13 @@ public final class WorldManagePage extends DecoratorAnimatedPage implements Deco this.world = world; this.backupsDir = backupsDir; + this.worldInfoTab.setNodeSupplier(() -> new WorldInfoPage(this)); + this.worldBackupsTab.setNodeSupplier(() -> new WorldBackupsPage(this)); + this.datapackTab.setNodeSupplier(() -> new DatapackListPage(this)); + this.state = new SimpleObjectProperty<>(State.fromTitle(i18n("world.manage.title", world.getWorldName()))); - this.header = new TabHeader(worldInfoTab, worldBackupsTab); - - worldInfoTab.setNodeSupplier(() -> new WorldInfoPage(this)); - worldBackupsTab.setNodeSupplier(() -> new WorldBackupsPage(this)); - datapackTab.setNodeSupplier(() -> new DatapackListPage(this)); - + this.header = new TabHeader(transitionPane, worldInfoTab, worldBackupsTab); header.select(worldInfoTab); - transitionPane.bindTabHeader(header); setCenter(transitionPane);