1919
2020import com .jfoenix .controls .JFXButton ;
2121import com .jfoenix .controls .JFXDialogLayout ;
22+ import com .jfoenix .controls .JFXListView ;
2223import javafx .geometry .Insets ;
2324import javafx .geometry .Pos ;
25+ import javafx .scene .Group ;
2426import javafx .scene .Node ;
2527import javafx .scene .control .*;
2628import javafx .scene .image .Image ;
3032import javafx .scene .layout .BorderPane ;
3133import javafx .scene .layout .HBox ;
3234import javafx .scene .layout .StackPane ;
35+ import javafx .scene .shape .SVGPath ;
3336import javafx .stage .FileChooser ;
3437import org .jackhuang .hmcl .schematic .LitematicFile ;
3538import org .jackhuang .hmcl .setting .Profile ;
@@ -221,7 +224,7 @@ private void navigateTo(DirItem item) {
221224 getItems ().addAll (item .children );
222225 }
223226
224- abstract class Item extends Control implements Comparable <Item > {
227+ abstract sealed class Item implements Comparable <Item > {
225228
226229 boolean isDirectory () {
227230 return this instanceof DirItem ;
@@ -258,11 +261,6 @@ public int compareTo(@NotNull SchematicsPage.Item o) {
258261
259262 return this .getName ().compareTo (o .getName ());
260263 }
261-
262- @ Override
263- protected Skin <?> createDefaultSkin () {
264- return new ItemSkin (this );
265- }
266264 }
267265
268266 private final class BackItem extends Item {
@@ -438,6 +436,10 @@ SVG getIcon() {
438436 return SVG .SCHEMA ;
439437 }
440438
439+ public @ Nullable Image getImage () {
440+ return image ;
441+ }
442+
441443 Node getIcon (int size ) {
442444 if (image == null ) {
443445 return super .getIcon (size );
@@ -540,62 +542,122 @@ private void updateContent(LitematicFile file) {
540542 }
541543 }
542544
543- private static final class ItemSkin extends SkinBase <Item > {
544- public ItemSkin (Item item ) {
545- super (item );
545+ private static final class Cell extends ListCell <Item > {
546546
547- BorderPane root = new BorderPane ();
547+ private final RipplerContainer graphics ;
548+ private final BorderPane root ;
549+ private final StackPane left ;
550+ private final TwoLineListItem center ;
551+ private final HBox right ;
552+
553+ private final ImageView iconImageView ;
554+ private final SVGPath iconSVG ;
555+ private final StackPane iconSVGWrapper ;
556+
557+ private final Tooltip tooltip = new Tooltip ();
558+
559+ public Cell () {
560+ this .root = new BorderPane ();
548561 root .getStyleClass ().add ("md-list-cell" );
549562 root .setPadding (new Insets (8 ));
550563
551564 {
552- StackPane left = new StackPane ();
553- left .setMaxSize (32 , 32 );
554- left .setPrefSize (32 , 32 );
555- left .getChildren ().add (item .getIcon (24 ));
565+ this .left = new StackPane ();
556566 left .setPadding (new Insets (0 , 8 , 0 , 0 ));
557567
558- Path path = item .getPath ();
559- if (path != null ) {
560- FXUtils .installSlowTooltip (left , path .toAbsolutePath ().normalize ().toString ());
561- }
568+ this .iconImageView = new ImageView ();
569+ FXUtils .limitSize (iconImageView , 32 , 32 );
570+
571+ this .iconSVG = new SVGPath ();
572+ iconSVG .getStyleClass ().add ("svg" );
573+ iconSVG .setScaleX (32.0 / SVG .DEFAULT_SIZE );
574+ iconSVG .setScaleY (32.0 / SVG .DEFAULT_SIZE );
575+
576+ this .iconSVGWrapper = new StackPane (new Group (iconSVG ));
577+ iconSVGWrapper .setAlignment (Pos .CENTER );
578+ FXUtils .setLimitWidth (iconSVGWrapper , 32 );
579+ FXUtils .setLimitHeight (iconSVGWrapper , 32 );
562580
563581 BorderPane .setAlignment (left , Pos .CENTER );
564582 root .setLeft (left );
565583 }
566584
567585 {
568- TwoLineListItem center = new TwoLineListItem ();
569- center .setTitle (item .getName ());
570- center .setSubtitle (item .getDescription ());
571-
586+ this .center = new TwoLineListItem ();
572587 root .setCenter (center );
573588 }
574589
575- if (!( item instanceof BackItem )) {
576- HBox right = new HBox (8 );
590+ {
591+ this . right = new HBox (8 );
577592 right .setAlignment (Pos .CENTER_RIGHT );
578593
579594 JFXButton btnReveal = new JFXButton ();
580595 FXUtils .installFastTooltip (btnReveal , i18n ("reveal.in_file_manager" ));
581596 btnReveal .getStyleClass ().add ("toggle-icon4" );
582597 btnReveal .setGraphic (SVG .FOLDER_OPEN .createIcon ());
583- btnReveal .setOnAction (event -> item .onReveal ());
598+ btnReveal .setOnAction (event -> {
599+ Item item = getItem ();
600+ if (item != null && !(item instanceof BackItem ))
601+ item .onReveal ();
602+ });
584603
585604 JFXButton btnDelete = new JFXButton ();
586605 btnDelete .getStyleClass ().add ("toggle-icon4" );
587606 btnDelete .setGraphic (SVG .DELETE_FOREVER .createIcon ());
588- btnDelete .setOnAction (event ->
607+ btnDelete .setOnAction (event -> {
608+ Item item = getItem ();
609+ if (item != null && !(item instanceof BackItem )) {
589610 Controllers .confirm (i18n ("button.remove.confirm" ), i18n ("button.remove" ),
590- item ::onDelete , null ));
611+ item ::onDelete , null );
612+ }
613+ });
591614
592615 right .getChildren ().setAll (btnReveal , btnDelete );
593- root .setRight (right );
594616 }
595617
596- RipplerContainer container = new RipplerContainer (root );
597- FXUtils .onClicked (container , item ::onClick );
598- this .getChildren ().add (container );
618+ this .graphics = new RipplerContainer (root );
619+ FXUtils .onClicked (graphics , () -> {
620+ Item item = getItem ();
621+ if (item != null )
622+ item .onClick ();
623+ });
624+ }
625+
626+ @ Override
627+ protected void updateItem (Item item , boolean empty ) {
628+ super .updateItem (item , empty );
629+
630+ iconImageView .setImage (null );
631+
632+ if (empty || item == null ) {
633+ setGraphic (null );
634+ center .setTitle ("" );
635+ center .setSubtitle ("" );
636+ } else {
637+ if (item instanceof LitematicFileItem fileItem && fileItem .getImage () != null ) {
638+ iconImageView .setImage (fileItem .getImage ());
639+ left .getChildren ().setAll (iconImageView );
640+ } else {
641+ iconSVG .setContent (item .getIcon ().getPath ());
642+ left .getChildren ().setAll (iconSVGWrapper );
643+ }
644+
645+ center .setTitle (item .getName ());
646+ center .setSubtitle (item .getDescription ());
647+
648+ Path path = item .getPath ();
649+ if (path != null ) {
650+ tooltip .setText (FileUtils .getAbsolutePath (path ));
651+ FXUtils .installSlowTooltip (left , tooltip );
652+ } else {
653+ tooltip .setText ("" );
654+ Tooltip .uninstall (left , tooltip );
655+ }
656+
657+ root .setRight (item instanceof BackItem ? null : right );
658+
659+ setGraphic (graphics );
660+ }
599661 }
600662 }
601663
@@ -612,5 +674,10 @@ protected List<Node> initializeToolbar(SchematicsPage skinnable) {
612674 createToolbarButton2 (i18n ("schematics.create_directory" ), SVG .CREATE_NEW_FOLDER , skinnable ::onCreateDirectory )
613675 );
614676 }
677+
678+ @ Override
679+ protected ListCell <Item > createListCell (JFXListView <Item > listView ) {
680+ return new Cell ();
681+ }
615682 }
616683}
0 commit comments