重构 SchematicsPage 以使用 ListCell 展示元素 (#5276)
This commit is contained in:
@@ -19,8 +19,10 @@ package org.jackhuang.hmcl.ui.versions;
|
|||||||
|
|
||||||
import com.jfoenix.controls.JFXButton;
|
import com.jfoenix.controls.JFXButton;
|
||||||
import com.jfoenix.controls.JFXDialogLayout;
|
import com.jfoenix.controls.JFXDialogLayout;
|
||||||
|
import com.jfoenix.controls.JFXListView;
|
||||||
import javafx.geometry.Insets;
|
import javafx.geometry.Insets;
|
||||||
import javafx.geometry.Pos;
|
import javafx.geometry.Pos;
|
||||||
|
import javafx.scene.Group;
|
||||||
import javafx.scene.Node;
|
import javafx.scene.Node;
|
||||||
import javafx.scene.control.*;
|
import javafx.scene.control.*;
|
||||||
import javafx.scene.image.Image;
|
import javafx.scene.image.Image;
|
||||||
@@ -30,6 +32,7 @@ import javafx.scene.image.WritableImage;
|
|||||||
import javafx.scene.layout.BorderPane;
|
import javafx.scene.layout.BorderPane;
|
||||||
import javafx.scene.layout.HBox;
|
import javafx.scene.layout.HBox;
|
||||||
import javafx.scene.layout.StackPane;
|
import javafx.scene.layout.StackPane;
|
||||||
|
import javafx.scene.shape.SVGPath;
|
||||||
import javafx.stage.FileChooser;
|
import javafx.stage.FileChooser;
|
||||||
import org.jackhuang.hmcl.schematic.LitematicFile;
|
import org.jackhuang.hmcl.schematic.LitematicFile;
|
||||||
import org.jackhuang.hmcl.setting.Profile;
|
import org.jackhuang.hmcl.setting.Profile;
|
||||||
@@ -221,7 +224,7 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
getItems().addAll(item.children);
|
getItems().addAll(item.children);
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class Item extends Control implements Comparable<Item> {
|
abstract sealed class Item implements Comparable<Item> {
|
||||||
|
|
||||||
boolean isDirectory() {
|
boolean isDirectory() {
|
||||||
return this instanceof DirItem;
|
return this instanceof DirItem;
|
||||||
@@ -258,11 +261,6 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
|
|
||||||
return this.getName().compareTo(o.getName());
|
return this.getName().compareTo(o.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Skin<?> createDefaultSkin() {
|
|
||||||
return new ItemSkin(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class BackItem extends Item {
|
private final class BackItem extends Item {
|
||||||
@@ -438,6 +436,10 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
return SVG.SCHEMA;
|
return SVG.SCHEMA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Image getImage() {
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
Node getIcon(int size) {
|
Node getIcon(int size) {
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
return super.getIcon(size);
|
return super.getIcon(size);
|
||||||
@@ -540,62 +542,122 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class ItemSkin extends SkinBase<Item> {
|
private static final class Cell extends ListCell<Item> {
|
||||||
public ItemSkin(Item item) {
|
|
||||||
super(item);
|
|
||||||
|
|
||||||
BorderPane root = new BorderPane();
|
private final RipplerContainer graphics;
|
||||||
|
private final BorderPane root;
|
||||||
|
private final StackPane left;
|
||||||
|
private final TwoLineListItem center;
|
||||||
|
private final HBox right;
|
||||||
|
|
||||||
|
private final ImageView iconImageView;
|
||||||
|
private final SVGPath iconSVG;
|
||||||
|
private final StackPane iconSVGWrapper;
|
||||||
|
|
||||||
|
private final Tooltip tooltip = new Tooltip();
|
||||||
|
|
||||||
|
public Cell() {
|
||||||
|
this.root = new BorderPane();
|
||||||
root.getStyleClass().add("md-list-cell");
|
root.getStyleClass().add("md-list-cell");
|
||||||
root.setPadding(new Insets(8));
|
root.setPadding(new Insets(8));
|
||||||
|
|
||||||
{
|
{
|
||||||
StackPane left = new StackPane();
|
this.left = new StackPane();
|
||||||
left.setMaxSize(32, 32);
|
|
||||||
left.setPrefSize(32, 32);
|
|
||||||
left.getChildren().add(item.getIcon(24));
|
|
||||||
left.setPadding(new Insets(0, 8, 0, 0));
|
left.setPadding(new Insets(0, 8, 0, 0));
|
||||||
|
|
||||||
Path path = item.getPath();
|
this.iconImageView = new ImageView();
|
||||||
if (path != null) {
|
FXUtils.limitSize(iconImageView, 32, 32);
|
||||||
FXUtils.installSlowTooltip(left, path.toAbsolutePath().normalize().toString());
|
|
||||||
}
|
this.iconSVG = new SVGPath();
|
||||||
|
iconSVG.getStyleClass().add("svg");
|
||||||
|
iconSVG.setScaleX(32.0 / SVG.DEFAULT_SIZE);
|
||||||
|
iconSVG.setScaleY(32.0 / SVG.DEFAULT_SIZE);
|
||||||
|
|
||||||
|
this.iconSVGWrapper = new StackPane(new Group(iconSVG));
|
||||||
|
iconSVGWrapper.setAlignment(Pos.CENTER);
|
||||||
|
FXUtils.setLimitWidth(iconSVGWrapper, 32);
|
||||||
|
FXUtils.setLimitHeight(iconSVGWrapper, 32);
|
||||||
|
|
||||||
BorderPane.setAlignment(left, Pos.CENTER);
|
BorderPane.setAlignment(left, Pos.CENTER);
|
||||||
root.setLeft(left);
|
root.setLeft(left);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
TwoLineListItem center = new TwoLineListItem();
|
this.center = new TwoLineListItem();
|
||||||
center.setTitle(item.getName());
|
|
||||||
center.setSubtitle(item.getDescription());
|
|
||||||
|
|
||||||
root.setCenter(center);
|
root.setCenter(center);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(item instanceof BackItem)) {
|
{
|
||||||
HBox right = new HBox(8);
|
this.right = new HBox(8);
|
||||||
right.setAlignment(Pos.CENTER_RIGHT);
|
right.setAlignment(Pos.CENTER_RIGHT);
|
||||||
|
|
||||||
JFXButton btnReveal = new JFXButton();
|
JFXButton btnReveal = new JFXButton();
|
||||||
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
FXUtils.installFastTooltip(btnReveal, i18n("reveal.in_file_manager"));
|
||||||
btnReveal.getStyleClass().add("toggle-icon4");
|
btnReveal.getStyleClass().add("toggle-icon4");
|
||||||
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon());
|
btnReveal.setGraphic(SVG.FOLDER_OPEN.createIcon());
|
||||||
btnReveal.setOnAction(event -> item.onReveal());
|
btnReveal.setOnAction(event -> {
|
||||||
|
Item item = getItem();
|
||||||
|
if (item != null && !(item instanceof BackItem))
|
||||||
|
item.onReveal();
|
||||||
|
});
|
||||||
|
|
||||||
JFXButton btnDelete = new JFXButton();
|
JFXButton btnDelete = new JFXButton();
|
||||||
btnDelete.getStyleClass().add("toggle-icon4");
|
btnDelete.getStyleClass().add("toggle-icon4");
|
||||||
btnDelete.setGraphic(SVG.DELETE_FOREVER.createIcon());
|
btnDelete.setGraphic(SVG.DELETE_FOREVER.createIcon());
|
||||||
btnDelete.setOnAction(event ->
|
btnDelete.setOnAction(event -> {
|
||||||
|
Item item = getItem();
|
||||||
|
if (item != null && !(item instanceof BackItem)) {
|
||||||
Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"),
|
Controllers.confirm(i18n("button.remove.confirm"), i18n("button.remove"),
|
||||||
item::onDelete, null));
|
item::onDelete, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
right.getChildren().setAll(btnReveal, btnDelete);
|
right.getChildren().setAll(btnReveal, btnDelete);
|
||||||
root.setRight(right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RipplerContainer container = new RipplerContainer(root);
|
this.graphics = new RipplerContainer(root);
|
||||||
FXUtils.onClicked(container, item::onClick);
|
FXUtils.onClicked(graphics, () -> {
|
||||||
this.getChildren().add(container);
|
Item item = getItem();
|
||||||
|
if (item != null)
|
||||||
|
item.onClick();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateItem(Item item, boolean empty) {
|
||||||
|
super.updateItem(item, empty);
|
||||||
|
|
||||||
|
iconImageView.setImage(null);
|
||||||
|
|
||||||
|
if (empty || item == null) {
|
||||||
|
setGraphic(null);
|
||||||
|
center.setTitle("");
|
||||||
|
center.setSubtitle("");
|
||||||
|
} else {
|
||||||
|
if (item instanceof LitematicFileItem fileItem && fileItem.getImage() != null) {
|
||||||
|
iconImageView.setImage(fileItem.getImage());
|
||||||
|
left.getChildren().setAll(iconImageView);
|
||||||
|
} else {
|
||||||
|
iconSVG.setContent(item.getIcon().getPath());
|
||||||
|
left.getChildren().setAll(iconSVGWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
center.setTitle(item.getName());
|
||||||
|
center.setSubtitle(item.getDescription());
|
||||||
|
|
||||||
|
Path path = item.getPath();
|
||||||
|
if (path != null) {
|
||||||
|
tooltip.setText(FileUtils.getAbsolutePath(path));
|
||||||
|
FXUtils.installSlowTooltip(left, tooltip);
|
||||||
|
} else {
|
||||||
|
tooltip.setText("");
|
||||||
|
Tooltip.uninstall(left, tooltip);
|
||||||
|
}
|
||||||
|
|
||||||
|
root.setRight(item instanceof BackItem ? null : right);
|
||||||
|
|
||||||
|
setGraphic(graphics);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,5 +674,10 @@ public final class SchematicsPage extends ListPageBase<SchematicsPage.Item> impl
|
|||||||
createToolbarButton2(i18n("schematics.create_directory"), SVG.CREATE_NEW_FOLDER, skinnable::onCreateDirectory)
|
createToolbarButton2(i18n("schematics.create_directory"), SVG.CREATE_NEW_FOLDER, skinnable::onCreateDirectory)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ListCell<Item> createListCell(JFXListView<Item> listView) {
|
||||||
|
return new Cell();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user