Skip to content

创建 SVGContainer 控件#5464

Open
Glavo wants to merge 16 commits intoHMCL-dev:mainfrom
Glavo:svg-icon
Open

创建 SVGContainer 控件#5464
Glavo wants to merge 16 commits intoHMCL-dev:mainfrom
Glavo:svg-icon

Conversation

@Glavo
Copy link
Member

@Glavo Glavo commented Feb 6, 2026

No description provided.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 SVGView control to display SVG icons with configurable size and optional fade animation on icon changes.
  • Refactored icon rendering in SchematicsPage and AdvancedListBox to use SVGView.
  • Extended SVG enum 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());
}
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
}
}
SVGView.this.requestLayout();

Copilot uses AI. Check for mistakes.
Comment on lines 108 to 114
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);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Local variable name leftGraphics is plural but holds a single SVGView. Renaming to leftGraphic/leftIcon (or similar) would better match setLeftGraphic(...) and reduce confusion.

Suggested change
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);

Copilot uses AI. Check for mistakes.
Comment on lines 562 to 564
this.left = new StackPane();
left.setMouseTransparent(true);
left.setPadding(new Insets(0, 8, 0, 0));
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
@Glavo Glavo changed the title 创建 SVGView 控件 创建 SVGContainer 控件 Feb 6, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines 46 to 67
/// 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.
///
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Comment on lines +159 to +160
public SVGContainer createIcon(double size) {
return new SVGContainer(this, size);
Copy link

Copilot AI Feb 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +170 to +173
@Override
protected void layoutChildren() {
// Do nothing
}
Copy link

Copilot AI Feb 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant