diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/ToolbarListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/ToolbarListPageSkin.java index 5b61526f3..cc466e14e 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/ToolbarListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/ToolbarListPageSkin.java @@ -41,7 +41,6 @@ public abstract class ToolbarListPageSkin SpinnerPane spinnerPane = new SpinnerPane(); spinnerPane.getStyleClass().add("large-spinner-pane"); - spinnerPane.getStyleClass().add("content-background"); BorderPane root = new BorderPane(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FloatListCell.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FloatListCell.java index 59e6f547a..26e6c3f28 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FloatListCell.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/FloatListCell.java @@ -19,6 +19,7 @@ package org.jackhuang.hmcl.ui.construct; import com.jfoenix.effects.JFXDepthManager; import javafx.geometry.Insets; +import javafx.scene.Cursor; import javafx.scene.control.ListCell; import javafx.scene.layout.StackPane; @@ -29,7 +30,9 @@ public abstract class FloatListCell extends ListCell { setText(null); setGraphic(null); - pane.setStyle("-fx-background-color: white; -fx-padding: 8; -fx-cursor: HAND"); + pane.setStyle("-fx-background-color: white"); + pane.setCursor(Cursor.HAND); + pane.setPadding(new Insets(8)); setPadding(new Insets(5)); JFXDepthManager.setDepth(pane, 1); } @@ -37,13 +40,13 @@ public abstract class FloatListCell extends ListCell { @Override protected void updateItem(T item, boolean empty) { super.updateItem(item, empty); + updateControl(item, empty); if (empty) { setGraphic(null); } else { - updateControl(item); setGraphic(pane); } } - protected abstract void updateControl(T dataItem); + protected abstract void updateControl(T dataItem, boolean empty); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXCheckBoxTreeTableCell.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXCheckBoxTreeTableCell.java deleted file mode 100644 index 7645615cd..000000000 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/JFXCheckBoxTreeTableCell.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Hello Minecraft! Launcher - * Copyright (C) 2020 huangyuhui and contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package org.jackhuang.hmcl.ui.construct; - -import com.jfoenix.controls.JFXCheckBox; -import javafx.beans.binding.Bindings; -import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; -import javafx.beans.value.ObservableValue; -import javafx.geometry.Pos; -import javafx.scene.control.CheckBox; -import javafx.scene.control.TreeTableCell; -import javafx.scene.layout.StackPane; -import javafx.util.Callback; -import javafx.util.StringConverter; - -public class JFXCheckBoxTreeTableCell extends TreeTableCell { - private final StackPane pane; - private final CheckBox checkBox; - private boolean showLabel; - private ObservableValue booleanProperty; - - public JFXCheckBoxTreeTableCell() { - this(null, null); - } - - public JFXCheckBoxTreeTableCell( - final Callback> getSelectedProperty) { - this(getSelectedProperty, null); - } - - public JFXCheckBoxTreeTableCell( - final Callback> getSelectedProperty, - final StringConverter converter) { - this.getStyleClass().add("check-box-tree-table-cell"); - this.checkBox = new JFXCheckBox(); - this.pane = new StackPane(checkBox); - this.pane.setAlignment(Pos.CENTER); - setGraphic(null); - setSelectedStateCallback(getSelectedProperty); - setConverter(converter); - } - - private ObjectProperty> converter = - new SimpleObjectProperty>(this, "converter") { - protected void invalidated() { - updateShowLabel(); - } - }; - - public final ObjectProperty> converterProperty() { - return converter; - } - public final void setConverter(StringConverter value) { - converterProperty().set(value); - } - public final StringConverter getConverter() { - return converterProperty().get(); - } - - private ObjectProperty>> - selectedStateCallback = new SimpleObjectProperty<>(this, "selectedStateCallback"); - - public final ObjectProperty>> selectedStateCallbackProperty() { - return selectedStateCallback; - } - - public final void setSelectedStateCallback(Callback> value) { - selectedStateCallbackProperty().set(value); - } - - public final Callback> getSelectedStateCallback() { - return selectedStateCallbackProperty().get(); - } - - @SuppressWarnings("unchecked") - @Override public void updateItem(T item, boolean empty) { - super.updateItem(item, empty); - - if (empty) { - setText(null); - setGraphic(null); - } else { - StringConverter c = getConverter(); - - if (showLabel) { - setText(c.toString(item)); - } - - setGraphic(pane); - - if (booleanProperty instanceof BooleanProperty) { - checkBox.selectedProperty().unbindBidirectional((BooleanProperty)booleanProperty); - } - ObservableValue obsValue = getSelectedProperty(); - if (obsValue instanceof BooleanProperty) { - booleanProperty = (ObservableValue) obsValue; - checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty); - } - - checkBox.disableProperty().bind(Bindings.not( - getTreeTableView().editableProperty().and( - getTableColumn().editableProperty()).and( - editableProperty()) - )); - } - } - - private void updateShowLabel() { - this.showLabel = converter != null; - this.checkBox.setAlignment(showLabel ? Pos.CENTER_LEFT : Pos.CENTER); - } - - private ObservableValue getSelectedProperty() { - return getSelectedStateCallback() != null ? - getSelectedStateCallback().call(getIndex()) : - getTableColumn().getCellObservableValue(getIndex()); - } -} \ No newline at end of file diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java index c9461eee2..253b37dad 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/VersionsPage.java @@ -123,7 +123,8 @@ public final class VersionsPage extends BorderPane implements WizardPage, Refres } @Override - protected void updateControl(RemoteVersion remoteVersion) { + protected void updateControl(RemoteVersion remoteVersion, boolean empty) { + if (empty) return; content.setTitle(remoteVersion.getSelfVersion()); content.setSubtitle(remoteVersion.getGameVersion()); 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 eb43d629f..278c60c59 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 @@ -21,7 +21,6 @@ import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.collections.ObservableList; import javafx.scene.control.Skin; -import javafx.scene.control.TreeItem; import javafx.stage.FileChooser; import org.jackhuang.hmcl.mod.Datapack; import org.jackhuang.hmcl.task.Schedulers; @@ -103,9 +102,8 @@ public class DatapackListPage extends ListPageBase> selectedItems) { + void removeSelected(ObservableList selectedItems) { selectedItems.stream() - .map(TreeItem::getValue) .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) .forEach(pack -> { try { @@ -117,16 +115,14 @@ public class DatapackListPage extends ListPageBase> selectedItems) { + void enableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(TreeItem::getValue) .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) .forEach(info -> info.setActive(true)); } - void disableSelected(ObservableList> selectedItems) { + void disableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(TreeItem::getValue) .map(DatapackListPageSkin.DatapackInfoObject::getPackInfo) .forEach(info -> info.setActive(false)); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java index ce5f7808a..157c4d793 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DatapackListPageSkin.java @@ -17,30 +17,27 @@ */ package org.jackhuang.hmcl.ui.versions; -import com.jfoenix.controls.JFXTreeTableColumn; -import com.jfoenix.controls.JFXTreeTableView; -import com.jfoenix.controls.RecursiveTreeItem; +import com.jfoenix.controls.JFXCheckBox; +import com.jfoenix.controls.JFXListView; import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject; import com.jfoenix.effects.JFXDepthManager; +import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.geometry.Insets; -import javafx.scene.Node; +import javafx.geometry.Pos; import javafx.scene.control.SelectionMode; import javafx.scene.control.SkinBase; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; import org.jackhuang.hmcl.mod.Datapack; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.SVG; -import org.jackhuang.hmcl.ui.construct.JFXCheckBoxTreeTableCell; +import org.jackhuang.hmcl.ui.construct.FloatListCell; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; import org.jackhuang.hmcl.util.StringUtils; -import static org.jackhuang.hmcl.ui.FXUtils.setupCellValueFactory; -import static org.jackhuang.hmcl.ui.FXUtils.wrapMargin; import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -50,7 +47,7 @@ class DatapackListPageSkin extends SkinBase { super(skinnable); BorderPane root = new BorderPane(); - JFXTreeTableView tableView = new JFXTreeTableView<>(); + JFXListView listView = new JFXListView<>(); { HBox toolbar = new HBox(); @@ -62,13 +59,13 @@ class DatapackListPageSkin extends SkinBase { toolbar.getChildren().add(createToolbarButton(i18n("datapack.add"), SVG::plus, skinnable::add)); toolbar.getChildren().add(createToolbarButton(i18n("button.remove"), SVG::delete, () -> { Controllers.confirmDialog(i18n("button.remove.confirm"), i18n("button.remove"), () -> { - skinnable.removeSelected(tableView.getSelectionModel().getSelectedItems()); + skinnable.removeSelected(listView.getSelectionModel().getSelectedItems()); }, null); })); toolbar.getChildren().add(createToolbarButton(i18n("mods.enable"), SVG::check, () -> - skinnable.enableSelected(tableView.getSelectionModel().getSelectedItems()))); + skinnable.enableSelected(listView.getSelectionModel().getSelectedItems()))); toolbar.getChildren().add(createToolbarButton(i18n("mods.disable"), SVG::close, () -> - skinnable.disableSelected(tableView.getSelectionModel().getSelectedItems()))); + skinnable.disableSelected(listView.getSelectionModel().getSelectedItems()))); root.setTop(toolbar); } @@ -77,26 +74,43 @@ class DatapackListPageSkin extends SkinBase { center.getStyleClass().add("large-spinner-pane"); center.loadingProperty().bind(skinnable.loadingProperty()); - tableView.getStyleClass().addAll("no-header"); - tableView.setShowRoot(false); - tableView.setEditable(true); - tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - tableView.setRoot(new RecursiveTreeItem<>(skinnable.getItems(), RecursiveTreeObject::getChildren)); + listView.setCellFactory(x -> new FloatListCell() { + JFXCheckBox checkBox = new JFXCheckBox(); + TwoLineListItem content = new TwoLineListItem(); + BooleanProperty booleanProperty; - JFXTreeTableColumn activeColumn = new JFXTreeTableColumn<>(); - setupCellValueFactory(activeColumn, DatapackInfoObject::activeProperty); - activeColumn.setCellFactory(c -> new JFXCheckBoxTreeTableCell<>()); - activeColumn.setEditable(true); - activeColumn.setMaxWidth(40); - activeColumn.setMinWidth(40); + { + Region clippedContainer = (Region)listView.lookup(".clipped-container"); + setPrefWidth(0); + HBox container = new HBox(8); + container.setPadding(new Insets(0, 0, 0, 6)); + container.setAlignment(Pos.CENTER_LEFT); + pane.getChildren().add(container); + pane.setPadding(new Insets(8, 8, 8, 0)); + if (clippedContainer != null) { + maxWidthProperty().bind(clippedContainer.widthProperty()); + prefWidthProperty().bind(clippedContainer.widthProperty()); + minWidthProperty().bind(clippedContainer.widthProperty()); + } - JFXTreeTableColumn detailColumn = new JFXTreeTableColumn<>(); - setupCellValueFactory(detailColumn, DatapackInfoObject::nodeProperty); + container.getChildren().setAll(checkBox, content); + } - tableView.getColumns().setAll(activeColumn, detailColumn); + @Override + protected void updateControl(DatapackInfoObject dataItem, boolean empty) { + if (empty) return; + content.setTitle(dataItem.getTitle()); + content.setSubtitle(dataItem.getSubtitle()); + if (booleanProperty != null) { + checkBox.selectedProperty().unbindBidirectional(booleanProperty); + } + checkBox.selectedProperty().bindBidirectional(booleanProperty = dataItem.active); + } + }); + listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + Bindings.bindContent(listView.getItems(), skinnable.getItems()); - tableView.setColumnResizePolicy(JFXTreeTableView.CONSTRAINED_RESIZE_POLICY); - center.setContent(tableView); + center.setContent(listView); root.setCenter(center); } @@ -106,21 +120,18 @@ class DatapackListPageSkin extends SkinBase { static class DatapackInfoObject extends RecursiveTreeObject { private final BooleanProperty active; private final Datapack.Pack packInfo; - private final ObjectProperty node; DatapackInfoObject(Datapack.Pack packInfo) { this.packInfo = packInfo; this.active = packInfo.activeProperty(); - this.node = new SimpleObjectProperty<>(wrapMargin(new TwoLineListItem(packInfo.getId(), StringUtils.parseColorEscapes(packInfo.getDescription())), - new Insets(8, 0, 8, 0))); } - BooleanProperty activeProperty() { - return active; + String getTitle() { + return packInfo.getId(); } - ObjectProperty nodeProperty() { - return node; + String getSubtitle() { + return StringUtils.parseColorEscapes(packInfo.getDescription()); } Datapack.Pack getPackInfo() { 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 0636bb9fc..6466402c2 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 @@ -29,6 +29,7 @@ import org.jackhuang.hmcl.game.Version; import org.jackhuang.hmcl.setting.Profile; import org.jackhuang.hmcl.setting.Profiles; import org.jackhuang.hmcl.ui.*; +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; @@ -56,6 +57,7 @@ public class GameList extends ListPageBase implements DecoratorPag }); Profiles.registerVersionsListener(this::loadVersions); + addEventHandler(Navigator.NavigationEvent.NAVIGATING, this::onDecoratorPageNavigating); } private void loadVersions(Profile profile) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java index 7bb2ad8a7..14fc899df 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPage.java @@ -22,7 +22,6 @@ import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.collections.ObservableList; import javafx.scene.control.Skin; -import javafx.scene.control.TreeItem; import javafx.stage.FileChooser; import org.jackhuang.hmcl.download.LibraryAnalyzer; import org.jackhuang.hmcl.mod.ModInfo; @@ -139,11 +138,9 @@ public final class ModListPage extends ListPageBase> selectedItems) { + public void removeSelected(ObservableList selectedItems) { try { modManager.removeMods(selectedItems.stream() - .filter(Objects::nonNull) - .map(TreeItem::getValue) .filter(Objects::nonNull) .map(ModListPageSkin.ModInfoObject::getModInfo) .toArray(ModInfo[]::new)); @@ -153,16 +150,16 @@ public final class ModListPage extends ListPageBase> selectedItems) { + public void enableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(TreeItem::getValue) + .filter(Objects::nonNull) .map(ModListPageSkin.ModInfoObject::getModInfo) .forEach(info -> info.setActive(true)); } - public void disableSelected(ObservableList> selectedItems) { + public void disableSelected(ObservableList selectedItems) { selectedItems.stream() - .map(TreeItem::getValue) + .filter(Objects::nonNull) .map(ModListPageSkin.ModInfoObject::getModInfo) .forEach(info -> info.setActive(false)); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java index a9ed31889..9bbde83a3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModListPageSkin.java @@ -17,32 +17,29 @@ */ package org.jackhuang.hmcl.ui.versions; -import com.jfoenix.controls.JFXTreeTableColumn; -import com.jfoenix.controls.JFXTreeTableView; -import com.jfoenix.controls.RecursiveTreeItem; +import com.jfoenix.controls.JFXCheckBox; +import com.jfoenix.controls.JFXListView; import com.jfoenix.controls.datamodels.treetable.RecursiveTreeObject; import com.jfoenix.effects.JFXDepthManager; +import javafx.beans.binding.Bindings; import javafx.beans.property.BooleanProperty; -import javafx.beans.property.ObjectProperty; -import javafx.beans.property.SimpleObjectProperty; import javafx.geometry.Insets; -import javafx.scene.Node; +import javafx.geometry.Pos; import javafx.scene.control.Label; import javafx.scene.control.SelectionMode; import javafx.scene.control.SkinBase; import javafx.scene.layout.BorderPane; import javafx.scene.layout.HBox; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; import org.jackhuang.hmcl.mod.ModInfo; import org.jackhuang.hmcl.ui.Controllers; import org.jackhuang.hmcl.ui.FXUtils; import org.jackhuang.hmcl.ui.SVG; -import org.jackhuang.hmcl.ui.construct.JFXCheckBoxTreeTableCell; +import org.jackhuang.hmcl.ui.construct.FloatListCell; import org.jackhuang.hmcl.ui.construct.SpinnerPane; import org.jackhuang.hmcl.ui.construct.TwoLineListItem; -import static org.jackhuang.hmcl.ui.FXUtils.setupCellValueFactory; -import static org.jackhuang.hmcl.ui.FXUtils.wrapMargin; import static org.jackhuang.hmcl.ui.ToolbarListPageSkin.createToolbarButton; import static org.jackhuang.hmcl.util.StringUtils.isNotBlank; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -56,7 +53,7 @@ class ModListPageSkin extends SkinBase { pane.getStyleClass().addAll("notice-pane"); BorderPane root = new BorderPane(); - JFXTreeTableView tableView = new JFXTreeTableView<>(); + JFXListView listView = new JFXListView<>(); { HBox toolbar = new HBox(); @@ -68,13 +65,13 @@ class ModListPageSkin extends SkinBase { toolbar.getChildren().add(createToolbarButton(i18n("mods.add"), SVG::plus, skinnable::add)); toolbar.getChildren().add(createToolbarButton(i18n("button.remove"), SVG::delete, () -> { Controllers.confirmDialog(i18n("button.remove.confirm"), i18n("button.remove"), () -> { - skinnable.removeSelected(tableView.getSelectionModel().getSelectedItems()); + skinnable.removeSelected(listView.getSelectionModel().getSelectedItems()); }, null); })); toolbar.getChildren().add(createToolbarButton(i18n("mods.enable"), SVG::check, () -> - skinnable.enableSelected(tableView.getSelectionModel().getSelectedItems()))); + skinnable.enableSelected(listView.getSelectionModel().getSelectedItems()))); toolbar.getChildren().add(createToolbarButton(i18n("mods.disable"), SVG::close, () -> - skinnable.disableSelected(tableView.getSelectionModel().getSelectedItems()))); + skinnable.disableSelected(listView.getSelectionModel().getSelectedItems()))); root.setTop(toolbar); } @@ -83,26 +80,43 @@ class ModListPageSkin extends SkinBase { center.getStyleClass().add("large-spinner-pane"); center.loadingProperty().bind(skinnable.loadingProperty()); - tableView.getStyleClass().add("no-header"); - tableView.setShowRoot(false); - tableView.setEditable(true); - tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); - tableView.setRoot(new RecursiveTreeItem<>(skinnable.getItems(), RecursiveTreeObject::getChildren)); + listView.setCellFactory(x -> new FloatListCell() { + JFXCheckBox checkBox = new JFXCheckBox(); + TwoLineListItem content = new TwoLineListItem(); + BooleanProperty booleanProperty; - JFXTreeTableColumn activeColumn = new JFXTreeTableColumn<>(); - setupCellValueFactory(activeColumn, ModInfoObject::activeProperty); - activeColumn.setCellFactory(c -> new JFXCheckBoxTreeTableCell<>()); - activeColumn.setEditable(true); - activeColumn.setMaxWidth(40); - activeColumn.setMinWidth(40); + { + Region clippedContainer = (Region)listView.lookup(".clipped-container"); + setPrefWidth(0); + HBox container = new HBox(8); + container.setPadding(new Insets(0, 0, 0, 6)); + container.setAlignment(Pos.CENTER_LEFT); + pane.getChildren().add(container); + pane.setPadding(new Insets(8, 8, 8, 0)); + if (clippedContainer != null) { + maxWidthProperty().bind(clippedContainer.widthProperty()); + prefWidthProperty().bind(clippedContainer.widthProperty()); + minWidthProperty().bind(clippedContainer.widthProperty()); + } - JFXTreeTableColumn detailColumn = new JFXTreeTableColumn<>(); - setupCellValueFactory(detailColumn, ModInfoObject::nodeProperty); + container.getChildren().setAll(checkBox, content); + } - tableView.getColumns().setAll(activeColumn, detailColumn); + @Override + protected void updateControl(ModInfoObject dataItem, boolean empty) { + if (empty) return; + content.setTitle(dataItem.getTitle()); + content.setSubtitle(dataItem.getSubtitle()); + if (booleanProperty != null) { + checkBox.selectedProperty().unbindBidirectional(booleanProperty); + } + checkBox.selectedProperty().bindBidirectional(booleanProperty = dataItem.active); + } + }); + listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + Bindings.bindContent(listView.getItems(), skinnable.getItems()); - tableView.setColumnResizePolicy(JFXTreeTableView.CONSTRAINED_RESIZE_POLICY); - center.setContent(tableView); + center.setContent(listView); root.setCenter(center); } @@ -120,7 +134,7 @@ class ModListPageSkin extends SkinBase { static class ModInfoObject extends RecursiveTreeObject { private final BooleanProperty active; private final ModInfo modInfo; - private final ObjectProperty node; + private final String message; ModInfoObject(ModInfo modInfo) { this.modInfo = modInfo; @@ -132,15 +146,15 @@ class ModListPageSkin extends SkinBase { message.append(", ").append(i18n("archive.game_version")).append(": ").append(modInfo.getGameVersion()); if (isNotBlank(modInfo.getAuthors())) message.append(", ").append(i18n("archive.author")).append(": ").append(modInfo.getAuthors()); - this.node = new SimpleObjectProperty<>(wrapMargin(new TwoLineListItem(modInfo.getFileName(), message.toString()), new Insets(8, 0, 8, 0))); + this.message = message.toString(); } - BooleanProperty activeProperty() { - return active; + String getTitle() { + return modInfo.getFileName(); } - ObjectProperty nodeProperty() { - return node; + String getSubtitle() { + return message; } ModInfo getModInfo() {