From e95095959f3ec83b3ec4286c283fc0dfea3d80c2 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 01:05:35 +0800 Subject: [PATCH 1/7] Fix: Limit offline account skin dialog height --- .../org/jackhuang/hmcl/ui/account/AccountListItem.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java index fca58b099e3..d2263b2df16 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java @@ -141,7 +141,12 @@ public ObservableBooleanValue canUploadSkin() { @Nullable public Task uploadSkin() { if (account instanceof OfflineAccount) { - Controllers.dialog(new OfflineAccountSkinPane((OfflineAccount) account)); + OfflineAccountSkinPane pane = new OfflineAccountSkinPane((OfflineAccount) account); + + pane.setScaleX(0.85); + pane.setScaleY(0.85); + + Controllers.dialog(pane); return null; } if (!account.canUploadSkin()) { From ccd6baf538087ace5f5611e5395533e84388fc7c Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 14:58:39 +0800 Subject: [PATCH 2/7] Refactor: OfflineAccountSkinPane --- .../hmcl/ui/account/AccountListItem.java | 7 +- .../ui/account/OfflineAccountSkinPane.java | 86 +++++++++++++------ 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java index d2263b2df16..fca58b099e3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListItem.java @@ -141,12 +141,7 @@ public ObservableBooleanValue canUploadSkin() { @Nullable public Task uploadSkin() { if (account instanceof OfflineAccount) { - OfflineAccountSkinPane pane = new OfflineAccountSkinPane((OfflineAccount) account); - - pane.setScaleX(0.85); - pane.setScaleY(0.85); - - Controllers.dialog(pane); + Controllers.dialog(new OfflineAccountSkinPane((OfflineAccount) account)); return null; } if (!account.canUploadSkin()) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index cac425257a2..444cbfd94cc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -75,7 +75,7 @@ public OfflineAccountSkinPane(OfflineAccount account) { BorderPane pane = new BorderPane(); - SkinCanvas canvas = new SkinCanvas(TexturesLoader.getDefaultSkinImage(), 300, 300, true); + SkinCanvas canvas = new SkinCanvas(TexturesLoader.getDefaultSkinImage(), 260, 260, true); StackPane canvasPane = new StackPane(canvas); canvasPane.setPrefWidth(300); canvasPane.setPrefHeight(300); @@ -101,12 +101,17 @@ public OfflineAccountSkinPane(OfflineAccount account) { }); StackPane skinOptionPane = new StackPane(); - skinOptionPane.setMaxWidth(300); - VBox optionPane = new VBox(skinItem, skinOptionPane); - pane.setRight(optionPane); + pane.setRight(skinOptionPane); - skinSelector.maxWidthProperty().bind(skinOptionPane.maxWidthProperty().multiply(0.7)); - capeSelector.maxWidthProperty().bind(skinOptionPane.maxWidthProperty().multiply(0.7)); + skinSelector.setMaxWidth(Double.MAX_VALUE); + capeSelector.setMaxWidth(Double.MAX_VALUE); + modelCombobox.setMaxWidth(Double.MAX_VALUE); + cslApiField.setMaxWidth(Double.MAX_VALUE); + + GridPane.setHgrow(modelCombobox, Priority.ALWAYS); + GridPane.setHgrow(skinSelector, Priority.ALWAYS); + GridPane.setHgrow(capeSelector, Priority.ALWAYS); + GridPane.setHgrow(cslApiField, Priority.ALWAYS); layout.setBody(pane); @@ -182,48 +187,77 @@ public OfflineAccountSkinPane(OfflineAccount account) { FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> { GridPane gridPane = new GridPane(); - // Increase bottom padding to prevent the prompt from overlapping with the dialog action area - gridPane.setPadding(new Insets(0, 0, 45, 10)); + gridPane.setPadding(new Insets(0, 0, 0, 10)); gridPane.setHgap(16); - gridPane.setVgap(8); - gridPane.getColumnConstraints().setAll(new ColumnConstraints(), FXUtils.getColumnHgrowing()); + gridPane.setVgap(12); + + ColumnConstraints column = new ColumnConstraints(); + column.setHgrow(Priority.ALWAYS); + gridPane.getColumnConstraints().setAll(column); switch (selectedData) { case DEFAULT: case STEVE: case ALEX: break; + case LITTLE_SKIN: HintPane hint = new HintPane(MessageDialogPane.MessageType.INFO); hint.setText(i18n("account.skin.type.little_skin.hint")); - // Spanning two columns and expanding horizontally - GridPane.setColumnSpan(hint, 2); - GridPane.setHgrow(hint, Priority.ALWAYS); hint.setMaxWidth(Double.MAX_VALUE); - - // Force top alignment within cells (to avoid vertical offset caused by the baseline) - GridPane.setValignment(hint, VPos.TOP); - - // Set a fixed height as the preferred height to prevent the GridPane from stretching or leaving empty space. - hint.setMaxHeight(Region.USE_PREF_SIZE); - hint.setMinHeight(Region.USE_PREF_SIZE); + GridPane.setHgrow(hint, Priority.ALWAYS); gridPane.addRow(0, hint); break; + case LOCAL_FILE: - gridPane.setPadding(new Insets(0, 0, 0, 10)); - gridPane.addRow(0, new Label(i18n("account.skin.model")), modelCombobox); - gridPane.addRow(1, new Label(i18n("account.skin")), skinSelector); - gridPane.addRow(2, new Label(i18n("account.cape")), capeSelector); + modelCombobox.setMaxWidth(Double.MAX_VALUE); + skinSelector.setMaxWidth(Double.MAX_VALUE); + capeSelector.setMaxWidth(Double.MAX_VALUE); + + GridPane.setHgrow(modelCombobox, Priority.ALWAYS); + GridPane.setHgrow(skinSelector, Priority.ALWAYS); + GridPane.setHgrow(capeSelector, Priority.ALWAYS); + + gridPane.addRow(0, new Label(i18n("account.skin.model"))); + gridPane.addRow(1, modelCombobox); + + gridPane.addRow(2, new Label(i18n("account.skin"))); + gridPane.addRow(3, skinSelector); + + gridPane.addRow(4, new Label(i18n("account.cape"))); + gridPane.addRow(5, capeSelector); break; + case CUSTOM_SKIN_LOADER_API: - gridPane.addRow(0, new Label(i18n("account.skin.type.csl_api.location")), cslApiField); + cslApiField.setMaxWidth(Double.MAX_VALUE); + GridPane.setHgrow(cslApiField, Priority.ALWAYS); + + gridPane.addRow(0, new Label(i18n("account.skin.type.csl_api.location"))); + gridPane.addRow(1, cslApiField); break; } - skinOptionPane.getChildren().setAll(gridPane); + HBox body = new HBox(20); + + skinItem.setPrefWidth(170); + skinItem.setMinWidth(170); + + body.getChildren().add(skinItem); + + if (!gridPane.getChildren().isEmpty()) { + VBox right = new VBox(); + right.getChildren().add(gridPane); + + right.setPrefWidth(230); + HBox.setHgrow(right, Priority.ALWAYS); + + body.getChildren().add(right); + } + + skinOptionPane.getChildren().setAll(body); }); JFXButton acceptButton = new JFXButton(i18n("button.ok")); From e3d9fba9bc28d55452092e3100240dc4127456b7 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:08:00 +0800 Subject: [PATCH 3/7] Refactor: Removed the unused import --- .../org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java | 1 - 1 file changed, 1 deletion(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index 444cbfd94cc..eeda4275c1f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -25,7 +25,6 @@ import javafx.application.Platform; import javafx.beans.InvalidationListener; import javafx.geometry.Insets; -import javafx.geometry.VPos; import javafx.scene.control.Label; import javafx.scene.input.DragEvent; import javafx.scene.input.TransferMode; From 2087889ac47b07612a312fd9b00ed7e807d91f2e Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:21:28 +0800 Subject: [PATCH 4/7] Refactor: Remove duplicate code --- .../hmcl/ui/account/OfflineAccountSkinPane.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index eeda4275c1f..a7c11cc0d32 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -78,7 +78,7 @@ public OfflineAccountSkinPane(OfflineAccount account) { StackPane canvasPane = new StackPane(canvas); canvasPane.setPrefWidth(300); canvasPane.setPrefHeight(300); - pane.setCenter(canvas); + pane.setCenter(canvasPane); canvas.getAnimationPlayer().addSkinAnimation(new SkinAniWavingArms(100, 2000, 7.5, canvas), new SkinAniRunning(100, 100, 30, canvas)); canvas.enableRotation(.5); @@ -212,14 +212,6 @@ public OfflineAccountSkinPane(OfflineAccount account) { break; case LOCAL_FILE: - modelCombobox.setMaxWidth(Double.MAX_VALUE); - skinSelector.setMaxWidth(Double.MAX_VALUE); - capeSelector.setMaxWidth(Double.MAX_VALUE); - - GridPane.setHgrow(modelCombobox, Priority.ALWAYS); - GridPane.setHgrow(skinSelector, Priority.ALWAYS); - GridPane.setHgrow(capeSelector, Priority.ALWAYS); - gridPane.addRow(0, new Label(i18n("account.skin.model"))); gridPane.addRow(1, modelCombobox); @@ -231,9 +223,6 @@ public OfflineAccountSkinPane(OfflineAccount account) { break; case CUSTOM_SKIN_LOADER_API: - cslApiField.setMaxWidth(Double.MAX_VALUE); - GridPane.setHgrow(cslApiField, Priority.ALWAYS); - gridPane.addRow(0, new Label(i18n("account.skin.type.csl_api.location"))); gridPane.addRow(1, cslApiField); break; From c867b0ce425c7bfd7d057e28ee277868a1ca86e5 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:38:18 +0800 Subject: [PATCH 5/7] Refactor: Used canvasPane and remove the redundant configuration code --- .../ui/account/OfflineAccountSkinPane.java | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index a7c11cc0d32..1b7372866a0 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -76,8 +76,8 @@ public OfflineAccountSkinPane(OfflineAccount account) { SkinCanvas canvas = new SkinCanvas(TexturesLoader.getDefaultSkinImage(), 260, 260, true); StackPane canvasPane = new StackPane(canvas); - canvasPane.setPrefWidth(300); - canvasPane.setPrefHeight(300); + canvasPane.setPrefWidth(260); + canvasPane.setPrefHeight(260); pane.setCenter(canvasPane); canvas.getAnimationPlayer().addSkinAnimation(new SkinAniWavingArms(100, 2000, 7.5, canvas), new SkinAniRunning(100, 100, 30, canvas)); canvas.enableRotation(.5); @@ -184,16 +184,28 @@ public OfflineAccountSkinPane(OfflineAccount account) { } }, skinItem.selectedDataProperty(), cslApiField.textProperty(), modelCombobox.valueProperty(), skinSelector.valueProperty(), capeSelector.valueProperty()); - FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> { - GridPane gridPane = new GridPane(); + GridPane gridPane = new GridPane(); + gridPane.setPadding(new Insets(0, 0, 0, 10)); + gridPane.setHgap(16); + gridPane.setVgap(12); + + ColumnConstraints column = new ColumnConstraints(); + column.setHgrow(Priority.ALWAYS); + gridPane.getColumnConstraints().setAll(column); + + VBox right = new VBox(gridPane); + right.setPrefWidth(230); + HBox.setHgrow(right, Priority.ALWAYS); - gridPane.setPadding(new Insets(0, 0, 0, 10)); - gridPane.setHgap(16); - gridPane.setVgap(12); + HBox body = new HBox(20); + skinItem.setPrefWidth(170); + skinItem.setMinWidth(170); + body.getChildren().add(skinItem); - ColumnConstraints column = new ColumnConstraints(); - column.setHgrow(Priority.ALWAYS); - gridPane.getColumnConstraints().setAll(column); + skinOptionPane.getChildren().setAll(body); + + FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> { + gridPane.getChildren().clear(); switch (selectedData) { case DEFAULT: @@ -228,24 +240,11 @@ public OfflineAccountSkinPane(OfflineAccount account) { break; } - HBox body = new HBox(20); - - skinItem.setPrefWidth(170); - skinItem.setMinWidth(170); - - body.getChildren().add(skinItem); - - if (!gridPane.getChildren().isEmpty()) { - VBox right = new VBox(); - right.getChildren().add(gridPane); - - right.setPrefWidth(230); - HBox.setHgrow(right, Priority.ALWAYS); - + if (gridPane.getChildren().isEmpty()) { + body.getChildren().remove(right); + } else if (!body.getChildren().contains(right)) { body.getChildren().add(right); } - - skinOptionPane.getChildren().setAll(body); }); JFXButton acceptButton = new JFXButton(i18n("button.ok")); From 5c6cf0275596690d1825c59588646f57ab1bd113 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 15:52:29 +0800 Subject: [PATCH 6/7] Refactor: Streamlined the code --- .../ui/account/OfflineAccountSkinPane.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index 1b7372866a0..b93a40c58ee 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -193,7 +193,9 @@ public OfflineAccountSkinPane(OfflineAccount account) { column.setHgrow(Priority.ALWAYS); gridPane.getColumnConstraints().setAll(column); - VBox right = new VBox(gridPane); + VBox right = new VBox(); + right.setPadding(new Insets(0, 0, 0, 10)); + right.setSpacing(12); right.setPrefWidth(230); HBox.setHgrow(right, Priority.ALWAYS); @@ -205,7 +207,7 @@ public OfflineAccountSkinPane(OfflineAccount account) { skinOptionPane.getChildren().setAll(body); FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> { - gridPane.getChildren().clear(); + right.getChildren().clear(); switch (selectedData) { case DEFAULT: @@ -218,29 +220,30 @@ public OfflineAccountSkinPane(OfflineAccount account) { hint.setText(i18n("account.skin.type.little_skin.hint")); hint.setMaxWidth(Double.MAX_VALUE); - GridPane.setHgrow(hint, Priority.ALWAYS); - gridPane.addRow(0, hint); + right.getChildren().add(hint); break; case LOCAL_FILE: - gridPane.addRow(0, new Label(i18n("account.skin.model"))); - gridPane.addRow(1, modelCombobox); - - gridPane.addRow(2, new Label(i18n("account.skin"))); - gridPane.addRow(3, skinSelector); - - gridPane.addRow(4, new Label(i18n("account.cape"))); - gridPane.addRow(5, capeSelector); + right.getChildren().addAll( + new Label(i18n("account.skin.model")), + modelCombobox, + new Label(i18n("account.skin")), + skinSelector, + new Label(i18n("account.cape")), + capeSelector + ); break; case CUSTOM_SKIN_LOADER_API: - gridPane.addRow(0, new Label(i18n("account.skin.type.csl_api.location"))); - gridPane.addRow(1, cslApiField); + right.getChildren().addAll( + new Label(i18n("account.skin.type.csl_api.location")), + cslApiField + ); break; } - if (gridPane.getChildren().isEmpty()) { + if (right.getChildren().isEmpty()) { body.getChildren().remove(right); } else if (!body.getChildren().contains(right)) { body.getChildren().add(right); From c26dd0a0c76dcde1a6a2e2ef0820718f7f4ae921 Mon Sep 17 00:00:00 2001 From: KSSJW <165921128+KSSJW@users.noreply.github.com> Date: Sat, 27 Jun 2026 16:01:38 +0800 Subject: [PATCH 7/7] Refactor: Streamlined the code --- .../ui/account/OfflineAccountSkinPane.java | 80 ++++++++----------- 1 file changed, 34 insertions(+), 46 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java index b93a40c58ee..8f3ddc1bebc 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/OfflineAccountSkinPane.java @@ -107,11 +107,6 @@ public OfflineAccountSkinPane(OfflineAccount account) { modelCombobox.setMaxWidth(Double.MAX_VALUE); cslApiField.setMaxWidth(Double.MAX_VALUE); - GridPane.setHgrow(modelCombobox, Priority.ALWAYS); - GridPane.setHgrow(skinSelector, Priority.ALWAYS); - GridPane.setHgrow(capeSelector, Priority.ALWAYS); - GridPane.setHgrow(cslApiField, Priority.ALWAYS); - layout.setBody(pane); cslApiField.setPromptText(i18n("account.skin.type.csl_api.location.hint")); @@ -184,15 +179,6 @@ public OfflineAccountSkinPane(OfflineAccount account) { } }, skinItem.selectedDataProperty(), cslApiField.textProperty(), modelCombobox.valueProperty(), skinSelector.valueProperty(), capeSelector.valueProperty()); - GridPane gridPane = new GridPane(); - gridPane.setPadding(new Insets(0, 0, 0, 10)); - gridPane.setHgap(16); - gridPane.setVgap(12); - - ColumnConstraints column = new ColumnConstraints(); - column.setHgrow(Priority.ALWAYS); - gridPane.getColumnConstraints().setAll(column); - VBox right = new VBox(); right.setPadding(new Insets(0, 0, 0, 10)); right.setSpacing(12); @@ -209,38 +195,40 @@ public OfflineAccountSkinPane(OfflineAccount account) { FXUtils.onChangeAndOperate(skinItem.selectedDataProperty(), selectedData -> { right.getChildren().clear(); - switch (selectedData) { - case DEFAULT: - case STEVE: - case ALEX: - break; - - case LITTLE_SKIN: - HintPane hint = new HintPane(MessageDialogPane.MessageType.INFO); - hint.setText(i18n("account.skin.type.little_skin.hint")); - - hint.setMaxWidth(Double.MAX_VALUE); - - right.getChildren().add(hint); - break; - - case LOCAL_FILE: - right.getChildren().addAll( - new Label(i18n("account.skin.model")), - modelCombobox, - new Label(i18n("account.skin")), - skinSelector, - new Label(i18n("account.cape")), - capeSelector - ); - break; - - case CUSTOM_SKIN_LOADER_API: - right.getChildren().addAll( - new Label(i18n("account.skin.type.csl_api.location")), - cslApiField - ); - break; + if (selectedData != null) { + switch (selectedData) { + case DEFAULT: + case STEVE: + case ALEX: + break; + + case LITTLE_SKIN: + HintPane hint = new HintPane(MessageDialogPane.MessageType.INFO); + hint.setText(i18n("account.skin.type.little_skin.hint")); + + hint.setMaxWidth(Double.MAX_VALUE); + + right.getChildren().add(hint); + break; + + case LOCAL_FILE: + right.getChildren().addAll( + new Label(i18n("account.skin.model")), + modelCombobox, + new Label(i18n("account.skin")), + skinSelector, + new Label(i18n("account.cape")), + capeSelector + ); + break; + + case CUSTOM_SKIN_LOADER_API: + right.getChildren().addAll( + new Label(i18n("account.skin.type.csl_api.location")), + cslApiField + ); + break; + } } if (right.getChildren().isEmpty()) {