Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a reusable SVGView JavaFX control to render SVG enum icons (with optional fade transitions) and refactors existing UI code to use it instead of manually wiring SVGPath/Group wrappers.
Changes:
- Added
SVGViewcontrol to displaySVGicons with configurable size and optional fade animation on icon changes. - Refactored icon rendering in
SchematicsPageandAdvancedListBoxto useSVGView. - Extended
SVGenum with an explicit empty icon (NONE) and centralized SVGPath creation/sizing helpers.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/SchematicsPage.java |
Replaces per-cell SVGPath/wrapper usage with SVGView for list item icons. |
HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/AdvancedListBox.java |
Switches navigation drawer tab icon swapping to SVGView with animation duration. |
HMCL/src/main/java/org/jackhuang/hmcl/ui/SVGView.java |
Adds new SVGView JavaFX Control with CSS-styleable icon and size plus fade transition support. |
HMCL/src/main/java/org/jackhuang/hmcl/ui/SVG.java |
Adds NONE and refactors SVGPath creation/sizing into reusable helpers used by SVGView. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| protected void invalidated() { | ||
| if (getSkin() instanceof Skin skin) { | ||
| skin.updateSize(get()); | ||
| } |
There was a problem hiding this comment.
iconSizeProperty changes affect this control’s min/pref size, but the property invalidation only updates the SVGPath scale. Without calling requestLayout() (or at least SVGView.this.requestLayout()), parent containers may not relayout when the icon size changes (especially when size is set via CSS at runtime). Trigger a layout pass when iconSize is invalidated.
| } | |
| } | |
| SVGView.this.requestLayout(); |
| var leftGraphics = new SVGView(AdvancedListItem.LEFT_ICON_SIZE); | ||
| leftGraphics.setMouseTransparent(true); | ||
| AdvancedListItem.setAlignment(leftGraphics, Pos.CENTER); | ||
| AdvancedListItem.setMargin(leftGraphics, AdvancedListItem.LEFT_ICON_MARGIN); | ||
| FXUtils.onChangeAndOperate(item.activeProperty(), active -> leftGraphics.setIcon(active ? selectedGraphic : unselectedGraphic)); | ||
| leftGraphics.setAnimationDuration(Motion.SHORT4); | ||
| item.setLeftGraphic(leftGraphics); |
There was a problem hiding this comment.
Local variable name leftGraphics is plural but holds a single SVGView. Renaming to leftGraphic/leftIcon (or similar) would better match setLeftGraphic(...) and reduce confusion.
| var leftGraphics = new SVGView(AdvancedListItem.LEFT_ICON_SIZE); | |
| leftGraphics.setMouseTransparent(true); | |
| AdvancedListItem.setAlignment(leftGraphics, Pos.CENTER); | |
| AdvancedListItem.setMargin(leftGraphics, AdvancedListItem.LEFT_ICON_MARGIN); | |
| FXUtils.onChangeAndOperate(item.activeProperty(), active -> leftGraphics.setIcon(active ? selectedGraphic : unselectedGraphic)); | |
| leftGraphics.setAnimationDuration(Motion.SHORT4); | |
| item.setLeftGraphic(leftGraphics); | |
| var leftGraphic = new SVGView(AdvancedListItem.LEFT_ICON_SIZE); | |
| leftGraphic.setMouseTransparent(true); | |
| AdvancedListItem.setAlignment(leftGraphic, Pos.CENTER); | |
| AdvancedListItem.setMargin(leftGraphic, AdvancedListItem.LEFT_ICON_MARGIN); | |
| FXUtils.onChangeAndOperate(item.activeProperty(), active -> leftGraphic.setIcon(active ? selectedGraphic : unselectedGraphic)); | |
| leftGraphic.setAnimationDuration(Motion.SHORT4); | |
| item.setLeftGraphic(leftGraphic); |
| this.left = new StackPane(); | ||
| left.setMouseTransparent(true); | ||
| left.setPadding(new Insets(0, 8, 0, 0)); |
There was a problem hiding this comment.
left is set to mouseTransparent, but later a tooltip is installed on left. A mouse-transparent node won't receive hover events, so the tooltip likely never shows. Consider removing left.setMouseTransparent(true) or moving the tooltip installation to a node that still receives mouse events (e.g., the cell root/graphics), while keeping only the icon node mouse-transparent if needed for click-through.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /// Creates an SVGView with the default icon and the default icon size. | ||
| public SVGContainer() { | ||
| this(SVG.NONE, SVG.DEFAULT_SIZE); | ||
| } | ||
|
|
||
| /// Creates an SVGView showing the given icon using the default icon size. | ||
| /// | ||
| /// @param icon the [SVG] icon to display | ||
| public SVGContainer(SVG icon) { | ||
| this(icon, SVG.DEFAULT_SIZE); | ||
| } | ||
|
|
||
| /// Creates an SVGView with a custom icon size. The initial icon is | ||
| /// [SVG#NONE]. | ||
| /// | ||
| /// @param iconSize the icon size | ||
| public SVGContainer(double iconSize) { | ||
| this(SVG.NONE, iconSize); | ||
| } | ||
|
|
||
| /// Creates an SVGView with the specified icon and size. | ||
| /// |
There was a problem hiding this comment.
The Javadoc-style comments repeatedly refer to this component as “SVGView” (e.g., “Creates an SVGView …”), but the class name is SVGContainer. This is confusing for readers and makes searching harder; please update the wording to match the actual type name.
| public SVGContainer createIcon(double size) { | ||
| return new SVGContainer(this, size); |
There was a problem hiding this comment.
Changing public ... createIcon(double size) to return SVGContainer instead of Node changes the method descriptor and is binary-incompatible with any already-compiled code calling this API. If this method is part of a stable API surface, consider keeping the original Node-returning signature (e.g., return type Node while still constructing an SVGContainer internally, or introduce a new method for SVGContainer and keep the old one for compatibility).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @Override | ||
| protected void layoutChildren() { | ||
| // Do nothing | ||
| } |
There was a problem hiding this comment.
layoutChildren() is a no-op, so the internal SVGPath nodes are never positioned/sized by the container. This can lead to inconsistent alignment (especially during cross-fade when there are two paths) and can also make the container’s size depend on the raw path bounds rather than the requested iconSize. Consider making this a Region/StackPane (or overriding isResizable() and laying out children) and explicitly centering the path(s) within an iconSize × iconSize box.
No description provided.