From 5efc8d6fa9e53d729be7669252fab76d8eac6659 Mon Sep 17 00:00:00 2001 From: huangyuhui Date: Fri, 31 Aug 2018 12:13:47 +0800 Subject: [PATCH] Refactor View and ViewModel to Control and Skin --- .../jackhuang/hmcl/ui/AdvancedListItem2.java | 103 +++++++----------- .../hmcl/ui/AdvancedListItemSkin.java | 102 +++++++++++++++++ .../hmcl/ui/AdvancedListItemViewModel.java | 38 ------- .../org/jackhuang/hmcl/ui/Controllers.java | 30 +++-- .../jackhuang/hmcl/ui/LeftPaneController.java | 16 ++- ...odel.java => AccountAdvancedListItem.java} | 11 +- ...untListViewModel.java => AccountList.java} | 32 ++++-- ...temViewModel.java => AccountListItem.java} | 11 +- ...ItemView.java => AccountListItemSkin.java} | 39 ++++--- ...ountListView.java => AccountListSkin.java} | 26 ++--- .../hmcl/ui/construct/AdvancedListBox.java | 3 +- ...ewModel.java => GameAdvancedListItem.java} | 12 +- .../{GameListViewModel.java => GameList.java} | 36 ++++-- ...stItemViewModel.java => GameListItem.java} | 11 +- ...istItemView.java => GameListItemSkin.java} | 53 +++++---- .../{GameListView.java => GameListSkin.java} | 39 +++---- 16 files changed, 320 insertions(+), 242 deletions(-) create mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemSkin.java delete mode 100644 HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemViewModel.java rename HMCL/src/main/java/org/jackhuang/hmcl/ui/account/{AccountAdvancedListItemViewModel.java => AccountAdvancedListItem.java} (91%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/account/{AccountListViewModel.java => AccountList.java} (68%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/account/{AccountListItemViewModel.java => AccountListItem.java} (93%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/account/{AccountListItemView.java => AccountListItemSkin.java} (72%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/account/{AccountListView.java => AccountListSkin.java} (72%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{GameAdvancedListItemViewModel.java => GameAdvancedListItem.java} (90%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{GameListViewModel.java => GameList.java} (78%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{GameListItemViewModel.java => GameListItem.java} (94%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{GameListItemView.java => GameListItemSkin.java} (73%) rename HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/{GameListView.java => GameListSkin.java} (78%) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItem2.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItem2.java index bd091f404..1933ba7b3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItem2.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItem2.java @@ -17,80 +17,59 @@ */ package org.jackhuang.hmcl.ui; -import com.jfoenix.controls.JFXButton; -import javafx.geometry.Insets; -import javafx.geometry.Pos; -import javafx.scene.control.Label; -import javafx.scene.image.ImageView; -import javafx.scene.layout.BorderPane; -import javafx.scene.layout.HBox; -import javafx.scene.layout.StackPane; -import javafx.scene.layout.VBox; -import javafx.scene.text.TextAlignment; -import org.jackhuang.hmcl.setting.Theme; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.ObjectPropertyBase; +import javafx.beans.property.StringProperty; +import javafx.event.ActionEvent; +import javafx.event.EventHandler; +import javafx.geometry.Rectangle2D; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; +import javafx.scene.image.Image; -import java.util.Optional; +public abstract class AdvancedListItem2 extends Control { -public class AdvancedListItem2 extends StackPane { + public abstract ObjectProperty imageProperty(); - public AdvancedListItem2(AdvancedListItemViewModel viewModel) { - BorderPane root = new BorderPane(); - root.setPickOnBounds(false); + public ObjectProperty viewportProperty() { + return null; + } - HBox left = new HBox(); - left.setAlignment(Pos.CENTER); - left.setMouseTransparent(true); + public abstract StringProperty titleProperty(); - StackPane imageViewContainer = new StackPane(); - FXUtils.setLimitWidth(imageViewContainer, 32); - FXUtils.setLimitHeight(imageViewContainer, 32); + public abstract StringProperty subtitleProperty(); - ImageView imageView = new ImageView(); - FXUtils.limitSize(imageView, 32, 32); - imageView.setPreserveRatio(true); - imageView.imageProperty().bind(viewModel.imageProperty()); - Optional.ofNullable(viewModel.viewportProperty()) - .ifPresent(imageView.viewportProperty()::bind); - imageViewContainer.getChildren().setAll(imageView); + public final ObjectProperty> onActionProperty() { + return onAction; + } - VBox vbox = new VBox(); - vbox.setAlignment(Pos.CENTER_LEFT); - vbox.setPadding(new Insets(0, 0, 0, 10)); + public final void setOnAction(EventHandler value) { + onActionProperty().set(value); + } - Label title = new Label(); - title.textProperty().bind(viewModel.titleProperty()); - title.setMaxWidth(90); - title.setStyle("-fx-font-size: 15;"); - title.setTextAlignment(TextAlignment.JUSTIFY); - vbox.getChildren().add(title); + public final EventHandler getOnAction() { + return onActionProperty().get(); + } - if (viewModel.subtitleProperty() != null) { - Label subtitle = new Label(); - subtitle.textProperty().bind(viewModel.subtitleProperty()); - subtitle.setMaxWidth(90); - subtitle.setStyle("-fx-font-size: 10;"); - subtitle.setTextAlignment(TextAlignment.JUSTIFY); - vbox.getChildren().add(subtitle); + private ObjectProperty> onAction = new ObjectPropertyBase>() { + @Override + protected void invalidated() { + setEventHandler(ActionEvent.ACTION, get()); } - left.getChildren().setAll(imageViewContainer, vbox); - root.setLeft(left); + @Override + public Object getBean() { + return AdvancedListItem2.this; + } - HBox right = new HBox(); - right.setAlignment(Pos.CENTER); - right.setPickOnBounds(false); + @Override + public String getName() { + return "onAction"; + } + }; - JFXButton settings = new JFXButton(); - FXUtils.setLimitWidth(settings, 40); - settings.setOnMouseClicked(e -> viewModel.action()); - settings.getStyleClass().setAll("toggle-icon4"); - settings.setGraphic(SVG.gear(Theme.blackFillBinding(), -1, -1)); - right.getChildren().setAll(settings); - root.setRight(right); - - setStyle("-fx-padding: 10 16 10 16;"); - getStyleClass().setAll("transparent"); - setPickOnBounds(false); - getChildren().setAll(root); + @Override + protected Skin createDefaultSkin() { + return new AdvancedListItemSkin(this); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemSkin.java new file mode 100644 index 000000000..3aa303374 --- /dev/null +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemSkin.java @@ -0,0 +1,102 @@ +/* + * Hello Minecraft! Launcher. + * Copyright (C) 2017 huangyuhui + * + * 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 {http://www.gnu.org/licenses/}. + */ +package org.jackhuang.hmcl.ui; + +import com.jfoenix.controls.JFXButton; +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.SkinBase; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.StackPane; +import javafx.scene.layout.VBox; +import javafx.scene.text.TextAlignment; +import org.jackhuang.hmcl.setting.Theme; + +import java.util.Optional; + +public class AdvancedListItemSkin extends SkinBase { + + public AdvancedListItemSkin(AdvancedListItem2 skinnable) { + super(skinnable); + + StackPane stackPane = new StackPane(); + + BorderPane root = new BorderPane(); + root.setPickOnBounds(false); + + HBox left = new HBox(); + left.setAlignment(Pos.CENTER); + left.setMouseTransparent(true); + + StackPane imageViewContainer = new StackPane(); + FXUtils.setLimitWidth(imageViewContainer, 32); + FXUtils.setLimitHeight(imageViewContainer, 32); + + ImageView imageView = new ImageView(); + FXUtils.limitSize(imageView, 32, 32); + imageView.setPreserveRatio(true); + imageView.imageProperty().bind(skinnable.imageProperty()); + Optional.ofNullable(skinnable.viewportProperty()) + .ifPresent(imageView.viewportProperty()::bind); + imageViewContainer.getChildren().setAll(imageView); + + VBox vbox = new VBox(); + vbox.setAlignment(Pos.CENTER_LEFT); + vbox.setPadding(new Insets(0, 0, 0, 10)); + + Label title = new Label(); + title.textProperty().bind(skinnable.titleProperty()); + title.setMaxWidth(90); + title.setStyle("-fx-font-size: 15;"); + title.setTextAlignment(TextAlignment.JUSTIFY); + vbox.getChildren().add(title); + + if (skinnable.subtitleProperty() != null) { + Label subtitle = new Label(); + subtitle.textProperty().bind(skinnable.subtitleProperty()); + subtitle.setMaxWidth(90); + subtitle.setStyle("-fx-font-size: 10;"); + subtitle.setTextAlignment(TextAlignment.JUSTIFY); + vbox.getChildren().add(subtitle); + } + + left.getChildren().setAll(imageViewContainer, vbox); + root.setLeft(left); + + HBox right = new HBox(); + right.setAlignment(Pos.CENTER); + right.setPickOnBounds(false); + + JFXButton settings = new JFXButton(); + FXUtils.setLimitWidth(settings, 40); + settings.getStyleClass().setAll("toggle-icon4"); + settings.setGraphic(SVG.gear(Theme.blackFillBinding(), -1, -1)); + right.getChildren().setAll(settings); + root.setRight(right); + + stackPane.setStyle("-fx-padding: 10 16 10 16;"); + stackPane.getStyleClass().setAll("transparent"); + stackPane.setPickOnBounds(false); + stackPane.getChildren().setAll(root); + + getChildren().setAll(stackPane); + } +} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemViewModel.java deleted file mode 100644 index ffb1fa339..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/AdvancedListItemViewModel.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Hello Minecraft! Launcher. - * Copyright (C) 2017 huangyuhui - * - * 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 {http://www.gnu.org/licenses/}. - */ -package org.jackhuang.hmcl.ui; - -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.StringProperty; -import javafx.geometry.Rectangle2D; -import javafx.scene.image.Image; - -public abstract class AdvancedListItemViewModel { - - public abstract void action(); - - public abstract ObjectProperty imageProperty(); - - public ObjectProperty viewportProperty() { - return null; - } - - public abstract StringProperty titleProperty(); - - public abstract StringProperty subtitleProperty(); -} diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java index a70dc1b0f..9834cb62f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/Controllers.java @@ -27,15 +27,13 @@ import org.jackhuang.hmcl.Metadata; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; -import org.jackhuang.hmcl.ui.account.AccountListView; -import org.jackhuang.hmcl.ui.account.AccountListViewModel; +import org.jackhuang.hmcl.ui.account.AccountList; import org.jackhuang.hmcl.ui.account.AuthlibInjectorServersPage; import org.jackhuang.hmcl.ui.construct.InputDialogPane; import org.jackhuang.hmcl.ui.construct.MessageBox; import org.jackhuang.hmcl.ui.construct.MessageDialogPane; import org.jackhuang.hmcl.ui.construct.TaskExecutorDialogPane; -import org.jackhuang.hmcl.ui.versions.GameListView; -import org.jackhuang.hmcl.ui.versions.GameListViewModel; +import org.jackhuang.hmcl.ui.versions.GameList; import org.jackhuang.hmcl.util.FutureCallback; import org.jackhuang.hmcl.util.JavaVersion; @@ -50,8 +48,8 @@ public final class Controllers { private static MainPage mainPage = null; private static SettingsPage settingsPage = null; private static VersionPage versionPage = null; - private static GameListView gameListView = null; - private static AccountListView accountListView = null; + private static GameList gameListPage = null; + private static AccountList accountListPage = null; private static AuthlibInjectorServersPage serversPage = null; private static LeftPaneController leftPaneController; private static Decorator decorator; @@ -72,17 +70,17 @@ public final class Controllers { } // FXThread - public static GameListView getGameListView() { - if (gameListView == null) - gameListView = new GameListView(new GameListViewModel()); - return gameListView; + public static GameList getGameListPage() { + if (gameListPage == null) + gameListPage = new GameList(); + return gameListPage; } // FXThread - public static AccountListView getAccountListView() { - if (accountListView == null) - accountListView = new AccountListView(new AccountListViewModel()); - return accountListView; + public static AccountList getAccountListPage() { + if (accountListPage == null) + accountListPage = new AccountList(); + return accountListPage; } // FXThread @@ -202,7 +200,7 @@ public final class Controllers { decorator = null; stage = null; scene = null; - gameListView = null; - accountListView = null; + gameListPage = null; + accountListPage = null; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java index 849f5ed63..9b2d143b2 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/LeftPaneController.java @@ -25,8 +25,10 @@ import javafx.scene.Node; import javafx.scene.layout.Region; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; - -import org.jackhuang.hmcl.event.*; +import org.jackhuang.hmcl.event.EventBus; +import org.jackhuang.hmcl.event.ProfileChangedEvent; +import org.jackhuang.hmcl.event.ProfileLoadingEvent; +import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.game.HMCLGameRepository; import org.jackhuang.hmcl.game.ModpackHelper; import org.jackhuang.hmcl.mod.Modpack; @@ -35,10 +37,10 @@ import org.jackhuang.hmcl.setting.*; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.task.TaskExecutor; -import org.jackhuang.hmcl.ui.account.AccountAdvancedListItemViewModel; +import org.jackhuang.hmcl.ui.account.AccountAdvancedListItem; import org.jackhuang.hmcl.ui.account.AddAccountPane; import org.jackhuang.hmcl.ui.construct.*; -import org.jackhuang.hmcl.ui.versions.GameAdvancedListItemViewModel; +import org.jackhuang.hmcl.ui.versions.GameAdvancedListItem; import org.jackhuang.hmcl.upgrade.UpdateChecker; import org.jackhuang.hmcl.util.Lang; @@ -56,8 +58,10 @@ public final class LeftPaneController { public LeftPaneController(AdvancedListBox leftPane) { this.leftPane = leftPane; - AdvancedListItem2 accountListItem = new AdvancedListItem2(new AccountAdvancedListItemViewModel()); - AdvancedListItem2 gameListItem = new AdvancedListItem2(new GameAdvancedListItemViewModel()); + AdvancedListItem2 accountListItem = new AccountAdvancedListItem(); + accountListItem.setOnAction(e -> Controllers.navigate(Controllers.getAccountListPage())); + AdvancedListItem2 gameListItem = new GameAdvancedListItem(); + gameListItem.setOnAction(e -> Controllers.navigate(Controllers.getGameListPage())); IconedItem launcherSettingsItem = new IconedItem(SVG.gear(Theme.blackFillBinding(), 20, 20)); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItemViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItem.java similarity index 91% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItemViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItem.java index 8110af52b..17dd802a3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItemViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountAdvancedListItem.java @@ -29,19 +29,18 @@ import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount; import org.jackhuang.hmcl.game.AccountHelper; import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.task.Schedulers; -import org.jackhuang.hmcl.ui.AdvancedListItemViewModel; -import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.AdvancedListItem2; import org.jackhuang.hmcl.ui.FXUtils; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class AccountAdvancedListItemViewModel extends AdvancedListItemViewModel { +public class AccountAdvancedListItem extends AdvancedListItem2 { private final ObjectProperty image = new SimpleObjectProperty<>(); private final ObjectProperty viewport = new SimpleObjectProperty<>(AccountHelper.getViewport(4)); private final StringProperty title = new SimpleStringProperty(); private final StringProperty subtitle = new SimpleStringProperty(); - public AccountAdvancedListItemViewModel() { + public AccountAdvancedListItem() { FXUtils.onChangeAndOperate(Accounts.selectedAccountProperty(), account -> { if (account == null) { @@ -65,8 +64,8 @@ public class AccountAdvancedListItemViewModel extends AdvancedListItemViewModel } @Override - public void action() { - Controllers.navigate(Controllers.getAccountListView()); + protected void layoutChildren() { + super.layoutChildren(); } @Override diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java similarity index 68% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java index 034cde399..e2293af2c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountList.java @@ -17,21 +17,23 @@ */ package org.jackhuang.hmcl.ui.account; -import javafx.beans.property.ListProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleListProperty; -import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.*; import javafx.collections.FXCollections; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; import javafx.scene.control.ToggleGroup; import org.jackhuang.hmcl.auth.Account; import org.jackhuang.hmcl.setting.Accounts; import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.wizard.DecoratorPage; import org.jackhuang.hmcl.util.MappedObservableList; import static org.jackhuang.hmcl.ui.FXUtils.onInvalidating; +import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class AccountListViewModel { - private final ListProperty items = new SimpleListProperty<>(FXCollections.observableArrayList()); +public class AccountList extends Control implements DecoratorPage { + private final StringProperty title = new SimpleStringProperty(i18n("account.manage")); + private final ListProperty items = new SimpleListProperty<>(FXCollections.observableArrayList()); private ObjectProperty selectedAccount = new SimpleObjectProperty() { { items.addListener(onInvalidating(this::invalidated)); @@ -46,25 +48,35 @@ public class AccountListViewModel { private ToggleGroup toggleGroup; - public AccountListViewModel() { + public AccountList() { toggleGroup = new ToggleGroup(); items.bindContent(MappedObservableList.create( Accounts.accountsProperty(), - account -> new AccountListItemViewModel(toggleGroup, account))); + account -> new AccountListItem(toggleGroup, account))); selectedAccount.bindBidirectional(Accounts.selectedAccountProperty()); toggleGroup.selectedToggleProperty().addListener((o, a, toggle) -> { if (toggle == null || toggle.getUserData() == null) return; - selectedAccount.set(((AccountListItemViewModel) toggle.getUserData()).getAccount()); + selectedAccount.set(((AccountListItem) toggle.getUserData()).getAccount()); }); } + @Override + protected Skin createDefaultSkin() { + return new AccountListSkin(this); + } + public void addNewAccount() { Controllers.dialog(new AddAccountPane()); } - public ListProperty itemsProperty() { + public ListProperty itemsProperty() { return items; } + + @Override + public StringProperty titleProperty() { + return title; + } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java similarity index 93% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java index c28e107df..fe46ed324 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java @@ -19,6 +19,8 @@ package org.jackhuang.hmcl.ui.account; import javafx.beans.property.*; import javafx.geometry.Rectangle2D; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; import javafx.scene.control.ToggleGroup; import javafx.scene.image.Image; import org.jackhuang.hmcl.auth.Account; @@ -32,7 +34,7 @@ import org.jackhuang.hmcl.task.Schedulers; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class AccountListItemViewModel { +public class AccountListItem extends Control { private final Account account; private final ToggleGroup toggleGroup; private final StringProperty title = new SimpleStringProperty(); @@ -41,7 +43,7 @@ public class AccountListItemViewModel { private final ObjectProperty image = new SimpleObjectProperty<>(); private final ObjectProperty viewport = new SimpleObjectProperty<>(); - public AccountListItemViewModel(ToggleGroup toggleGroup, Account account) { + public AccountListItem(ToggleGroup toggleGroup, Account account) { this.account = account; this.toggleGroup = toggleGroup; @@ -67,6 +69,11 @@ public class AccountListItemViewModel { } } + @Override + protected Skin createDefaultSkin() { + return new AccountListItemSkin(this); + } + public ToggleGroup getToggleGroup() { return toggleGroup; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java similarity index 72% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemView.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java index 8728c20df..148e16d7a 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItemSkin.java @@ -22,6 +22,7 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXRadioButton; import com.jfoenix.effects.JFXDepthManager; import javafx.geometry.Pos; +import javafx.scene.control.SkinBase; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; @@ -33,15 +34,19 @@ import org.jackhuang.hmcl.ui.TwoLineListItem; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class AccountListItemView extends BorderPane { +public class AccountListItemSkin extends SkinBase { + + public AccountListItemSkin(AccountListItem skinnable) { + super(skinnable); + + BorderPane root = new BorderPane(); - public AccountListItemView(AccountListItemViewModel viewModel) { JFXRadioButton chkSelected = new JFXRadioButton(); BorderPane.setAlignment(chkSelected, Pos.CENTER); - chkSelected.setUserData(viewModel); - chkSelected.selectedProperty().bindBidirectional(viewModel.selectedProperty()); - chkSelected.setToggleGroup(viewModel.getToggleGroup()); - setLeft(chkSelected); + chkSelected.setUserData(skinnable); + chkSelected.selectedProperty().bindBidirectional(skinnable.selectedProperty()); + chkSelected.setToggleGroup(skinnable.getToggleGroup()); + root.setLeft(chkSelected); HBox center = new HBox(); center.setSpacing(8); @@ -53,36 +58,38 @@ public class AccountListItemView extends BorderPane { ImageView imageView = new ImageView(); FXUtils.limitSize(imageView, 32, 32); - imageView.imageProperty().bind(viewModel.imageProperty()); - imageView.viewportProperty().bind(viewModel.viewportProperty()); + imageView.imageProperty().bind(skinnable.imageProperty()); + imageView.viewportProperty().bind(skinnable.viewportProperty()); imageViewContainer.getChildren().setAll(imageView); TwoLineListItem item = new TwoLineListItem(); BorderPane.setAlignment(item, Pos.CENTER); center.getChildren().setAll(imageView, item); - setCenter(center); + root.setCenter(center); HBox right = new HBox(); right.setAlignment(Pos.CENTER_RIGHT); JFXButton btnRefresh = new JFXButton(); - btnRefresh.setOnMouseClicked(e -> viewModel.refresh()); + btnRefresh.setOnMouseClicked(e -> skinnable.refresh()); btnRefresh.getStyleClass().add("toggle-icon4"); btnRefresh.setGraphic(SVG.refresh(Theme.blackFillBinding(), -1, -1)); JFXUtilities.runInFX(() -> FXUtils.installTooltip(btnRefresh, i18n("button.refresh"))); right.getChildren().add(btnRefresh); JFXButton btnRemove = new JFXButton(); - btnRemove.setOnMouseClicked(e -> viewModel.remove()); + btnRemove.setOnMouseClicked(e -> skinnable.remove()); btnRemove.getStyleClass().add("toggle-icon4"); BorderPane.setAlignment(btnRemove, Pos.CENTER); btnRemove.setGraphic(SVG.delete(Theme.blackFillBinding(), -1, -1)); JFXUtilities.runInFX(() -> FXUtils.installTooltip(btnRefresh, i18n("button.delete"))); right.getChildren().add(btnRemove); - setRight(right); + root.setRight(right); - setStyle("-fx-background-color: white; -fx-padding: 8 8 8 0;"); - JFXDepthManager.setDepth(this, 1); - item.titleProperty().bind(viewModel.titleProperty()); - item.subtitleProperty().bind(viewModel.subtitleProperty()); + root.setStyle("-fx-background-color: white; -fx-padding: 8 8 8 0;"); + JFXDepthManager.setDepth(root, 1); + item.titleProperty().bind(skinnable.titleProperty()); + item.subtitleProperty().bind(skinnable.subtitleProperty()); + + getChildren().setAll(root); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListSkin.java similarity index 72% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListView.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListSkin.java index 8e0cc566d..8173b067e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListSkin.java @@ -19,25 +19,23 @@ package org.jackhuang.hmcl.ui.account; import com.jfoenix.controls.JFXButton; import javafx.beans.binding.Bindings; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.control.ScrollPane; +import javafx.scene.control.SkinBase; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; -import org.jackhuang.hmcl.ui.wizard.DecoratorPage; -import org.jackhuang.hmcl.util.MappedObservableList; -import static org.jackhuang.hmcl.util.i18n.I18n.i18n; +public class AccountListSkin extends SkinBase { -public class AccountListView extends StackPane implements DecoratorPage { - private final StringProperty title = new SimpleStringProperty(i18n("account.manage")); + public AccountListSkin(AccountList skinnable) { + super(skinnable); + + StackPane root = new StackPane(); - public AccountListView(AccountListViewModel viewModel) { ScrollPane scrollPane = new ScrollPane(); { scrollPane.setFitToWidth(true); @@ -47,8 +45,7 @@ public class AccountListView extends StackPane implements DecoratorPage { accountList.setSpacing(10); accountList.setStyle("-fx-padding: 10 10 10 10;"); - Bindings.bindContent(accountList.getChildren(), - MappedObservableList.create(viewModel.itemsProperty(), AccountListItemView::new)); + Bindings.bindContent(accountList.getChildren(), skinnable.itemsProperty()); scrollPane.setContent(accountList); } @@ -66,16 +63,13 @@ public class AccountListView extends StackPane implements DecoratorPage { btnAdd.getStyleClass().setAll("jfx-button-raised-round"); btnAdd.setButtonType(JFXButton.ButtonType.RAISED); btnAdd.setGraphic(SVG.plus(Theme.whiteFillBinding(), -1, -1)); - btnAdd.setOnMouseClicked(e -> viewModel.addNewAccount()); + btnAdd.setOnMouseClicked(e -> skinnable.addNewAccount()); vBox.getChildren().setAll(btnAdd); } - getChildren().setAll(scrollPane, vBox); - } + root.getChildren().setAll(scrollPane, vBox); - @Override - public StringProperty titleProperty() { - return title; + getChildren().setAll(root); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java index 2cad4d23c..3b1ea32a6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java @@ -23,6 +23,7 @@ import javafx.scene.control.ScrollPane; import javafx.scene.layout.Pane; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import org.jackhuang.hmcl.ui.AdvancedListItem2; import org.jackhuang.hmcl.ui.FXUtils; public class AdvancedListBox extends ScrollPane { @@ -42,7 +43,7 @@ public class AdvancedListBox extends ScrollPane { } public AdvancedListBox add(Node child) { - if (child instanceof Pane) + if (child instanceof Pane || child instanceof AdvancedListItem2) container.getChildren().add(child); else { StackPane pane = new StackPane(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItemViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java similarity index 90% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItemViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java index f4581c0f0..ddeb7bf1f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItemViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameAdvancedListItem.java @@ -29,13 +29,12 @@ import org.jackhuang.hmcl.event.ProfileChangedEvent; import org.jackhuang.hmcl.event.RefreshedVersionsEvent; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Settings; -import org.jackhuang.hmcl.ui.AdvancedListItemViewModel; -import org.jackhuang.hmcl.ui.Controllers; +import org.jackhuang.hmcl.ui.AdvancedListItem2; import org.jackhuang.hmcl.ui.WeakListenerHelper; import java.io.File; -public class GameAdvancedListItemViewModel extends AdvancedListItemViewModel { +public class GameAdvancedListItem extends AdvancedListItem2 { private final ObjectProperty image = new SimpleObjectProperty<>(); private final StringProperty title = new SimpleStringProperty(); private final WeakListenerHelper helper = new WeakListenerHelper(); @@ -43,7 +42,7 @@ public class GameAdvancedListItemViewModel extends AdvancedListItemViewModel { private Profile profile; private InvalidationListener listener = o -> loadVersion(); - public GameAdvancedListItemViewModel() { + public GameAdvancedListItem() { helper.add(EventBus.EVENT_BUS.channel(ProfileChangedEvent.class).registerWeak(event -> { JFXUtilities.runInFX(() -> loadProfile(event.getProfile())); })); @@ -77,11 +76,6 @@ public class GameAdvancedListItemViewModel extends AdvancedListItemViewModel { title.set(version); } - @Override - public void action() { - Controllers.navigate(Controllers.getGameListView()); - } - @Override public ObjectProperty imageProperty() { return image; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java similarity index 78% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java index c54d64bc7..346f42c80 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameList.java @@ -18,11 +18,10 @@ package org.jackhuang.hmcl.ui.versions; import com.jfoenix.concurrency.JFXUtilities; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ListProperty; -import javafx.beans.property.SimpleBooleanProperty; -import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.*; import javafx.collections.FXCollections; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; import javafx.scene.control.ToggleGroup; import org.jackhuang.hmcl.event.EventBus; import org.jackhuang.hmcl.event.ProfileChangedEvent; @@ -33,21 +32,24 @@ import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Settings; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.download.DownloadWizardProvider; +import org.jackhuang.hmcl.ui.wizard.DecoratorPage; import org.jackhuang.hmcl.util.VersionNumber; +import org.jackhuang.hmcl.util.i18n.I18n; import java.util.List; import java.util.stream.Collectors; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class GameListViewModel { +public class GameList extends Control implements DecoratorPage { + private final StringProperty title = new SimpleStringProperty(I18n.i18n("version.manage")); private final BooleanProperty loading = new SimpleBooleanProperty(true); - private final ListProperty items = new SimpleListProperty<>(FXCollections.observableArrayList()); + private final ListProperty items = new SimpleListProperty<>(FXCollections.observableArrayList()); private Profile profile; private ToggleGroup toggleGroup; - public GameListViewModel() { + public GameList() { EventBus.EVENT_BUS.channel(RefreshedVersionsEvent.class).register(event -> { if (event.getSource() == profile.getRepository()) loadVersions((HMCLGameRepository) event.getSource()); @@ -69,24 +71,29 @@ public class GameListViewModel { private void loadVersions(HMCLGameRepository repository) { toggleGroup = new ToggleGroup(); - List children = repository.getVersions().parallelStream() + List children = repository.getVersions().parallelStream() .filter(version -> !version.isHidden()) .sorted((a, b) -> VersionNumber.COMPARATOR.compare(VersionNumber.asVersion(a.getId()), VersionNumber.asVersion(b.getId()))) - .map(version -> new GameListItemViewModel(toggleGroup, profile, version.getId())) + .map(version -> new GameListItem(toggleGroup, profile, version.getId())) .collect(Collectors.toList()); JFXUtilities.runInFX(() -> { if (profile == repository.getProfile()) { loading.set(false); items.setAll(children); - children.forEach(GameListItemViewModel::checkSelection); + children.forEach(GameListItem::checkSelection); } toggleGroup.selectedToggleProperty().addListener((o, a, toggle) -> { - GameListItemViewModel model = (GameListItemViewModel) toggle.getUserData(); + GameListItem model = (GameListItem) toggle.getUserData(); model.getProfile().setSelectedVersion(model.getVersion()); }); }); } + @Override + protected Skin createDefaultSkin() { + return new GameListSkin(this); + } + public void addNewGame() { Controllers.getDecorator().startWizard(new DownloadWizardProvider(0), i18n("install.new_game")); } @@ -103,11 +110,16 @@ public class GameListViewModel { // Controllers.navigate(); } + @Override + public StringProperty titleProperty() { + return title; + } + public BooleanProperty loadingProperty() { return loading; } - public ListProperty itemsProperty() { + public ListProperty itemsProperty() { return items; } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemViewModel.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java similarity index 94% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemViewModel.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java index 7cee5029a..e8f5f1c5b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemViewModel.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItem.java @@ -18,6 +18,8 @@ package org.jackhuang.hmcl.ui.versions; import javafx.beans.property.*; +import javafx.scene.control.Control; +import javafx.scene.control.Skin; import javafx.scene.control.ToggleGroup; import javafx.scene.image.Image; import org.jackhuang.hmcl.download.LibraryAnalyzer; @@ -31,7 +33,7 @@ import static org.jackhuang.hmcl.util.StringUtils.removePrefix; import static org.jackhuang.hmcl.util.StringUtils.removeSuffix; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class GameListItemViewModel { +public class GameListItem extends Control { private final Profile profile; private final String version; private final boolean isModpack; @@ -41,7 +43,7 @@ public class GameListItemViewModel { private final BooleanProperty selected = new SimpleBooleanProperty(); private final ObjectProperty image = new SimpleObjectProperty<>(); - public GameListItemViewModel(ToggleGroup toggleGroup, Profile profile, String id) { + public GameListItem(ToggleGroup toggleGroup, Profile profile, String id) { this.profile = profile; this.version = id; this.toggleGroup = toggleGroup; @@ -66,6 +68,11 @@ public class GameListItemViewModel { image.set(new Image("/assets/img/grass.png")); } + @Override + protected Skin createDefaultSkin() { + return new GameListItemSkin(this); + } + public ToggleGroup getToggleGroup() { return toggleGroup; } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java similarity index 73% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemView.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java index 42d6e26c2..99b43a860 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListItemSkin.java @@ -21,6 +21,7 @@ import com.jfoenix.concurrency.JFXUtilities; import com.jfoenix.controls.*; import com.jfoenix.effects.JFXDepthManager; import javafx.geometry.Pos; +import javafx.scene.control.SkinBase; import javafx.scene.image.ImageView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; @@ -32,15 +33,19 @@ import org.jackhuang.hmcl.ui.TwoLineListItem; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; -public class GameListItemView extends BorderPane { +public class GameListItemSkin extends SkinBase { + + public GameListItemSkin(GameListItem skinnable) { + super(skinnable); + + BorderPane root = new BorderPane(); - public GameListItemView(GameListItemViewModel viewModel) { JFXRadioButton chkSelected = new JFXRadioButton(); BorderPane.setAlignment(chkSelected, Pos.CENTER); - chkSelected.setUserData(viewModel); - chkSelected.selectedProperty().bindBidirectional(viewModel.selectedProperty()); - chkSelected.setToggleGroup(viewModel.getToggleGroup()); - setLeft(chkSelected); + chkSelected.setUserData(skinnable); + chkSelected.selectedProperty().bindBidirectional(skinnable.selectedProperty()); + chkSelected.setToggleGroup(skinnable.getToggleGroup()); + root.setLeft(chkSelected); HBox center = new HBox(); center.setSpacing(8); @@ -52,13 +57,13 @@ public class GameListItemView extends BorderPane { ImageView imageView = new ImageView(); FXUtils.limitSize(imageView, 32, 32); - imageView.imageProperty().bind(viewModel.imageProperty()); + imageView.imageProperty().bind(skinnable.imageProperty()); imageViewContainer.getChildren().setAll(imageView); TwoLineListItem item = new TwoLineListItem(); BorderPane.setAlignment(item, Pos.CENTER); center.getChildren().setAll(imageView, item); - setCenter(center); + root.setCenter(center); JFXListView menu = new JFXListView<>(); menu.getItems().setAll( @@ -74,34 +79,34 @@ public class GameListItemView extends BorderPane { popup.hide(); switch (menu.getSelectionModel().getSelectedIndex()) { case 0: - viewModel.modifyGameSettings(); + skinnable.modifyGameSettings(); break; case 1: - viewModel.rename(); + skinnable.rename(); break; case 2: - viewModel.remove(); + skinnable.remove(); break; case 3: - viewModel.export(); + skinnable.export(); break; case 4: - viewModel.browse(); + skinnable.browse(); break; case 5: - viewModel.launch(); + skinnable.launch(); break; case 6: - viewModel.generateLaunchScript(); + skinnable.generateLaunchScript(); break; } }); HBox right = new HBox(); right.setAlignment(Pos.CENTER_RIGHT); - if (viewModel.canUpdate()) { + if (skinnable.canUpdate()) { JFXButton btnUpgrade = new JFXButton(); - btnUpgrade.setOnMouseClicked(e -> viewModel.update()); + btnUpgrade.setOnMouseClicked(e -> skinnable.update()); btnUpgrade.getStyleClass().add("toggle-icon4"); btnUpgrade.setGraphic(SVG.update(Theme.blackFillBinding(), -1, -1)); JFXUtilities.runInFX(() -> FXUtils.installTooltip(btnUpgrade, i18n("version.update"))); @@ -111,17 +116,19 @@ public class GameListItemView extends BorderPane { JFXButton btnManage = new JFXButton(); btnManage.setOnMouseClicked(e -> { menu.getSelectionModel().select(-1); - popup.show(this, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.RIGHT, 0, this.getHeight()); + popup.show(root, JFXPopup.PopupVPosition.TOP, JFXPopup.PopupHPosition.RIGHT, 0, root.getHeight()); }); btnManage.getStyleClass().add("toggle-icon4"); BorderPane.setAlignment(btnManage, Pos.CENTER); btnManage.setGraphic(SVG.dotsVertical(Theme.blackFillBinding(), -1, -1)); right.getChildren().add(btnManage); - setRight(right); + root.setRight(right); - setStyle("-fx-background-color: white; -fx-padding: 8 8 8 0;"); - JFXDepthManager.setDepth(this, 1); - item.titleProperty().bind(viewModel.titleProperty()); - item.subtitleProperty().bind(viewModel.subtitleProperty()); + root.setStyle("-fx-background-color: white; -fx-padding: 8 8 8 0;"); + JFXDepthManager.setDepth(root, 1); + item.titleProperty().bind(skinnable.titleProperty()); + item.subtitleProperty().bind(skinnable.subtitleProperty()); + + getChildren().setAll(root); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListView.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListSkin.java similarity index 78% rename from HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListView.java rename to HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListSkin.java index 1bca1d9a8..f5b76e594 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListView.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/GameListSkin.java @@ -21,11 +21,10 @@ import com.jfoenix.controls.JFXButton; import com.jfoenix.controls.JFXSpinner; import com.jfoenix.effects.JFXDepthManager; import javafx.beans.binding.Bindings; -import javafx.beans.property.SimpleStringProperty; -import javafx.beans.property.StringProperty; import javafx.geometry.Insets; import javafx.scene.Node; import javafx.scene.control.ScrollPane; +import javafx.scene.control.SkinBase; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; import javafx.scene.layout.StackPane; @@ -33,12 +32,9 @@ import javafx.scene.layout.VBox; import org.jackhuang.hmcl.setting.Theme; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; -import org.jackhuang.hmcl.ui.wizard.DecoratorPage; -import org.jackhuang.hmcl.util.MappedObservableList; import org.jackhuang.hmcl.util.i18n.I18n; -public class GameListView extends BorderPane implements DecoratorPage { - private final StringProperty title = new SimpleStringProperty(I18n.i18n("version.manage")); +public class GameListSkin extends SkinBase { private static Node wrap(Node node) { StackPane stackPane = new StackPane(); @@ -47,7 +43,11 @@ public class GameListView extends BorderPane implements DecoratorPage { return stackPane; } - public GameListView(GameListViewModel viewModel) { + public GameListSkin(GameList skinnable) { + super(skinnable); + + BorderPane root = new BorderPane(); + { HBox toolbar = new HBox(); toolbar.getStyleClass().setAll("jfx-tool-bar-second"); @@ -59,7 +59,7 @@ public class GameListView extends BorderPane implements DecoratorPage { btnAddNewGame.textFillProperty().bind(Theme.foregroundFillBinding()); btnAddNewGame.setGraphic(wrap(SVG.plus(Theme.foregroundFillBinding(), -1, -1))); btnAddNewGame.setText(I18n.i18n("install.new_game")); - btnAddNewGame.setOnMouseClicked(e -> viewModel.addNewGame()); + btnAddNewGame.setOnMouseClicked(e -> skinnable.addNewGame()); toolbar.getChildren().add(btnAddNewGame); JFXButton btnImportModpack = new JFXButton(); @@ -67,7 +67,7 @@ public class GameListView extends BorderPane implements DecoratorPage { btnImportModpack.textFillProperty().bind(Theme.foregroundFillBinding()); btnImportModpack.setGraphic(wrap(SVG.importIcon(Theme.foregroundFillBinding(), -1, -1))); btnImportModpack.setText(I18n.i18n("install.modpack")); - btnImportModpack.setOnMouseClicked(e -> viewModel.importModpack()); + btnImportModpack.setOnMouseClicked(e -> skinnable.importModpack()); toolbar.getChildren().add(btnImportModpack); JFXButton btnRefresh = new JFXButton(); @@ -75,7 +75,7 @@ public class GameListView extends BorderPane implements DecoratorPage { btnRefresh.textFillProperty().bind(Theme.foregroundFillBinding()); btnRefresh.setGraphic(wrap(SVG.refresh(Theme.foregroundFillBinding(), -1, -1))); btnRefresh.setText(I18n.i18n("button.refresh")); - btnRefresh.setOnMouseClicked(e -> viewModel.refresh()); + btnRefresh.setOnMouseClicked(e -> skinnable.refresh()); toolbar.getChildren().add(btnRefresh); JFXButton btnModify = new JFXButton(); @@ -83,10 +83,10 @@ public class GameListView extends BorderPane implements DecoratorPage { btnModify.textFillProperty().bind(Theme.foregroundFillBinding()); btnModify.setGraphic(wrap(SVG.gear(Theme.foregroundFillBinding(), -1, -1))); btnModify.setText(I18n.i18n("settings.type.global.manage")); - btnModify.setOnMouseClicked(e -> viewModel.modifyGlobalGameSettings()); + btnModify.setOnMouseClicked(e -> skinnable.modifyGlobalGameSettings()); toolbar.getChildren().add(btnModify); - setTop(toolbar); + root.setTop(toolbar); } { @@ -103,23 +103,16 @@ public class GameListView extends BorderPane implements DecoratorPage { gameList.setSpacing(10); gameList.setStyle("-fx-padding: 10 10 10 10;"); - Bindings.bindContent(gameList.getChildren(), - MappedObservableList.create(viewModel.itemsProperty(), model -> { - GameListItemView view = new GameListItemView(model); - return view; - })); + Bindings.bindContent(gameList.getChildren(), skinnable.itemsProperty()); scrollPane.setContent(gameList); - FXUtils.onChangeAndOperate(viewModel.loadingProperty(), + FXUtils.onChangeAndOperate(skinnable.loadingProperty(), loading -> center.getChildren().setAll(loading ? spinner : scrollPane)); - setCenter(center); + root.setCenter(center); } - } - @Override - public StringProperty titleProperty() { - return title; + getChildren().setAll(root); } }