mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-18 00:10:33 -04:00
alt: some UI details
This commit is contained in:
parent
5b1c72ad5c
commit
1726cc7ec7
@ -41,7 +41,6 @@ public abstract class ToolbarListPageSkin<T extends ListPageBase<? extends Node>
|
||||
|
||||
SpinnerPane spinnerPane = new SpinnerPane();
|
||||
spinnerPane.getStyleClass().add("large-spinner-pane");
|
||||
spinnerPane.getStyleClass().add("content-background");
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
|
||||
|
@ -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<T> extends ListCell<T> {
|
||||
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<T> extends ListCell<T> {
|
||||
@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);
|
||||
}
|
||||
|
@ -1,135 +0,0 @@
|
||||
/*
|
||||
* Hello Minecraft! Launcher
|
||||
* Copyright (C) 2020 huangyuhui <huanghongxun2008@126.com> 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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<S,T> extends TreeTableCell<S,T> {
|
||||
private final StackPane pane;
|
||||
private final CheckBox checkBox;
|
||||
private boolean showLabel;
|
||||
private ObservableValue<Boolean> booleanProperty;
|
||||
|
||||
public JFXCheckBoxTreeTableCell() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
public JFXCheckBoxTreeTableCell(
|
||||
final Callback<Integer, ObservableValue<Boolean>> getSelectedProperty) {
|
||||
this(getSelectedProperty, null);
|
||||
}
|
||||
|
||||
public JFXCheckBoxTreeTableCell(
|
||||
final Callback<Integer, ObservableValue<Boolean>> getSelectedProperty,
|
||||
final StringConverter<T> 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<StringConverter<T>> converter =
|
||||
new SimpleObjectProperty<StringConverter<T>>(this, "converter") {
|
||||
protected void invalidated() {
|
||||
updateShowLabel();
|
||||
}
|
||||
};
|
||||
|
||||
public final ObjectProperty<StringConverter<T>> converterProperty() {
|
||||
return converter;
|
||||
}
|
||||
public final void setConverter(StringConverter<T> value) {
|
||||
converterProperty().set(value);
|
||||
}
|
||||
public final StringConverter<T> getConverter() {
|
||||
return converterProperty().get();
|
||||
}
|
||||
|
||||
private ObjectProperty<Callback<Integer, ObservableValue<Boolean>>>
|
||||
selectedStateCallback = new SimpleObjectProperty<>(this, "selectedStateCallback");
|
||||
|
||||
public final ObjectProperty<Callback<Integer, ObservableValue<Boolean>>> selectedStateCallbackProperty() {
|
||||
return selectedStateCallback;
|
||||
}
|
||||
|
||||
public final void setSelectedStateCallback(Callback<Integer, ObservableValue<Boolean>> value) {
|
||||
selectedStateCallbackProperty().set(value);
|
||||
}
|
||||
|
||||
public final Callback<Integer, ObservableValue<Boolean>> 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<T> 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<Boolean>) 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());
|
||||
}
|
||||
}
|
@ -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());
|
||||
|
||||
|
@ -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<DatapackListPageSkin.Datapack
|
||||
datapack.loadFromDir();
|
||||
}
|
||||
|
||||
void removeSelected(ObservableList<TreeItem<DatapackListPageSkin.DatapackInfoObject>> selectedItems) {
|
||||
void removeSelected(ObservableList<DatapackListPageSkin.DatapackInfoObject> selectedItems) {
|
||||
selectedItems.stream()
|
||||
.map(TreeItem::getValue)
|
||||
.map(DatapackListPageSkin.DatapackInfoObject::getPackInfo)
|
||||
.forEach(pack -> {
|
||||
try {
|
||||
@ -117,16 +115,14 @@ public class DatapackListPage extends ListPageBase<DatapackListPageSkin.Datapack
|
||||
});
|
||||
}
|
||||
|
||||
void enableSelected(ObservableList<TreeItem<DatapackListPageSkin.DatapackInfoObject>> selectedItems) {
|
||||
void enableSelected(ObservableList<DatapackListPageSkin.DatapackInfoObject> selectedItems) {
|
||||
selectedItems.stream()
|
||||
.map(TreeItem::getValue)
|
||||
.map(DatapackListPageSkin.DatapackInfoObject::getPackInfo)
|
||||
.forEach(info -> info.setActive(true));
|
||||
}
|
||||
|
||||
void disableSelected(ObservableList<TreeItem<DatapackListPageSkin.DatapackInfoObject>> selectedItems) {
|
||||
void disableSelected(ObservableList<DatapackListPageSkin.DatapackInfoObject> selectedItems) {
|
||||
selectedItems.stream()
|
||||
.map(TreeItem::getValue)
|
||||
.map(DatapackListPageSkin.DatapackInfoObject::getPackInfo)
|
||||
.forEach(info -> info.setActive(false));
|
||||
}
|
||||
|
@ -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<DatapackListPage> {
|
||||
super(skinnable);
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
JFXTreeTableView<DatapackInfoObject> tableView = new JFXTreeTableView<>();
|
||||
JFXListView<DatapackInfoObject> listView = new JFXListView<>();
|
||||
|
||||
{
|
||||
HBox toolbar = new HBox();
|
||||
@ -62,13 +59,13 @@ class DatapackListPageSkin extends SkinBase<DatapackListPage> {
|
||||
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<DatapackListPage> {
|
||||
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<DatapackInfoObject>() {
|
||||
JFXCheckBox checkBox = new JFXCheckBox();
|
||||
TwoLineListItem content = new TwoLineListItem();
|
||||
BooleanProperty booleanProperty;
|
||||
|
||||
JFXTreeTableColumn<DatapackInfoObject, Boolean> 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<DatapackInfoObject, Node> 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<DatapackListPage> {
|
||||
static class DatapackInfoObject extends RecursiveTreeObject<DatapackInfoObject> {
|
||||
private final BooleanProperty active;
|
||||
private final Datapack.Pack packInfo;
|
||||
private final ObjectProperty<Node> 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<Node> nodeProperty() {
|
||||
return node;
|
||||
String getSubtitle() {
|
||||
return StringUtils.parseColorEscapes(packInfo.getDescription());
|
||||
}
|
||||
|
||||
Datapack.Pack getPackInfo() {
|
||||
|
@ -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<GameListItem> implements DecoratorPag
|
||||
});
|
||||
|
||||
Profiles.registerVersionsListener(this::loadVersions);
|
||||
addEventHandler(Navigator.NavigationEvent.NAVIGATING, this::onDecoratorPageNavigating);
|
||||
}
|
||||
|
||||
private void loadVersions(Profile profile) {
|
||||
|
@ -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<ModListPageSkin.ModInfoObjec
|
||||
this.parentTab = parentTab;
|
||||
}
|
||||
|
||||
public void removeSelected(ObservableList<TreeItem<ModListPageSkin.ModInfoObject>> selectedItems) {
|
||||
public void removeSelected(ObservableList<ModListPageSkin.ModInfoObject> 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<ModListPageSkin.ModInfoObjec
|
||||
}
|
||||
}
|
||||
|
||||
public void enableSelected(ObservableList<TreeItem<ModListPageSkin.ModInfoObject>> selectedItems) {
|
||||
public void enableSelected(ObservableList<ModListPageSkin.ModInfoObject> selectedItems) {
|
||||
selectedItems.stream()
|
||||
.map(TreeItem::getValue)
|
||||
.filter(Objects::nonNull)
|
||||
.map(ModListPageSkin.ModInfoObject::getModInfo)
|
||||
.forEach(info -> info.setActive(true));
|
||||
}
|
||||
|
||||
public void disableSelected(ObservableList<TreeItem<ModListPageSkin.ModInfoObject>> selectedItems) {
|
||||
public void disableSelected(ObservableList<ModListPageSkin.ModInfoObject> selectedItems) {
|
||||
selectedItems.stream()
|
||||
.map(TreeItem::getValue)
|
||||
.filter(Objects::nonNull)
|
||||
.map(ModListPageSkin.ModInfoObject::getModInfo)
|
||||
.forEach(info -> info.setActive(false));
|
||||
}
|
||||
|
@ -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<ModListPage> {
|
||||
pane.getStyleClass().addAll("notice-pane");
|
||||
|
||||
BorderPane root = new BorderPane();
|
||||
JFXTreeTableView<ModInfoObject> tableView = new JFXTreeTableView<>();
|
||||
JFXListView<ModInfoObject> listView = new JFXListView<>();
|
||||
|
||||
{
|
||||
HBox toolbar = new HBox();
|
||||
@ -68,13 +65,13 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
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<ModListPage> {
|
||||
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<ModInfoObject>() {
|
||||
JFXCheckBox checkBox = new JFXCheckBox();
|
||||
TwoLineListItem content = new TwoLineListItem();
|
||||
BooleanProperty booleanProperty;
|
||||
|
||||
JFXTreeTableColumn<ModInfoObject, Boolean> 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<ModInfoObject, Node> 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<ModListPage> {
|
||||
static class ModInfoObject extends RecursiveTreeObject<ModInfoObject> {
|
||||
private final BooleanProperty active;
|
||||
private final ModInfo modInfo;
|
||||
private final ObjectProperty<Node> node;
|
||||
private final String message;
|
||||
|
||||
ModInfoObject(ModInfo modInfo) {
|
||||
this.modInfo = modInfo;
|
||||
@ -132,15 +146,15 @@ class ModListPageSkin extends SkinBase<ModListPage> {
|
||||
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<Node> nodeProperty() {
|
||||
return node;
|
||||
String getSubtitle() {
|
||||
return message;
|
||||
}
|
||||
|
||||
ModInfo getModInfo() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user