From c39e046f2a6f896ed16f025ae4c6e3d341a7a175 Mon Sep 17 00:00:00 2001 From: RavenYin <178878631@qq.com> Date: Tue, 9 Jun 2026 02:11:20 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E8=83=8C=E6=99=AF=E5=9B=BE=E7=89=87?= =?UTF-8?q?=E4=BB=8E=E9=BB=98=E8=AE=A4=E7=9A=84=E5=B7=A6=E4=B8=8A=E8=A7=92?= =?UTF-8?q?=E9=80=82=E5=BA=94=E4=BF=AE=E6=94=B9=E4=B8=BA=E5=B1=85=E4=B8=AD?= =?UTF-8?q?=E9=80=82=E5=BA=94=20=E5=8E=9F=E5=85=88=E4=BB=A5=E5=B7=A6?= =?UTF-8?q?=E4=B8=8A=E8=A7=92=E4=B8=BA=E8=B5=B7=E7=82=B9=EF=BC=8C=E6=A0=B9?= =?UTF-8?q?=E6=8D=AE=E7=AA=97=E5=8F=A3=E5=A4=A7=E5=B0=8F=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E8=A3=81=E5=88=87=E5=8F=B3=E9=83=A8=E4=B8=8E=E5=BA=95=E9=83=A8?= =?UTF-8?q?=EF=BC=8C=E8=BF=99=E7=A7=8D=E6=96=B9=E5=BC=8F=E4=B8=8D=E9=80=82?= =?UTF-8?q?=E5=90=88=E8=83=8C=E6=99=AF=20=E4=BF=AE=E6=94=B9=E5=90=8E?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E5=9B=BE=E7=89=87=E9=BB=98=E8=AE=A4=E5=B1=85?= =?UTF-8?q?=E4=B8=AD=EF=BC=8C=E6=A0=B9=E6=8D=AE=E7=AA=97=E5=8F=A3=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E8=87=AA=E5=8A=A8=E8=A3=81=E5=88=87=E5=B7=A6=E5=8F=B3?= =?UTF-8?q?=E6=88=96=E4=B8=8A=E4=B8=8B=EF=BC=8C=E7=AC=A6=E5=90=88=E8=83=8C?= =?UTF-8?q?=E6=99=AF=E7=9A=84=E9=9C=80=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/decorator/DecoratorController.java | 20 ++++- .../hmcl/ui/decorator/DecoratorSkin.java | 85 ++++++++++++++++++- 2 files changed, 99 insertions(+), 6 deletions(-) diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index 4f3b060c412..2c79580da05 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -246,8 +246,14 @@ private Background createBackgroundWithOpacity(Image image, int opacity) { image, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, - BackgroundPosition.DEFAULT, - new BackgroundSize(800, 480, false, false, true, true) + BackgroundPosition.CENTER, + new BackgroundSize( + BackgroundSize.AUTO, + BackgroundSize.AUTO, + false, + false, + false, + false) )); } else { WritableImage tempImage = new WritableImage((int) image.getWidth(), (int) image.getHeight()); @@ -265,8 +271,14 @@ private Background createBackgroundWithOpacity(Image image, int opacity) { tempImage, BackgroundRepeat.NO_REPEAT, BackgroundRepeat.NO_REPEAT, - BackgroundPosition.DEFAULT, - new BackgroundSize(800, 480, false, false, true, true) + BackgroundPosition.CENTER, + new BackgroundSize( + BackgroundSize.AUTO, + BackgroundSize.AUTO, + false, + false, + false, + false) )); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java index ad3f86aca56..6dcf57eaa5f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorSkin.java @@ -36,6 +36,7 @@ import javafx.scene.control.SkinBase; import javafx.scene.effect.BlurType; import javafx.scene.effect.DropShadow; +import javafx.scene.image.Image; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; @@ -183,13 +184,13 @@ public DecoratorSkin(Decorator control) { // and decide whether the whole top bar should be rendered in white or black. TODO FXUtils.onChangeAndOperate(skinnable.titleTransparentProperty(), titleTransparent -> { if (titleTransparent) { - wrapper.backgroundProperty().bind(skinnable.contentBackgroundProperty()); + bindContentBackground(wrapper, skinnable); container.backgroundProperty().unbind(); container.setBackground(null); titleContainer.getStyleClass().remove("background"); titleContainer.getStyleClass().add("gray-background"); } else { - container.backgroundProperty().bind(skinnable.contentBackgroundProperty()); + bindContentBackground(container, skinnable); wrapper.backgroundProperty().unbind(); wrapper.setBackground(null); titleContainer.getStyleClass().add("background"); @@ -263,6 +264,86 @@ public DecoratorSkin(Decorator control) { getChildren().add(root); } + /// Binds the target region to a background rebuilt for the region's current size. + private void bindContentBackground(Region target, Decorator skinnable) { + target.backgroundProperty().unbind(); + target.backgroundProperty().bind(Bindings.createObjectBinding( + () -> createCenteredCoverBackground( + skinnable.getContentBackground(), + target.getWidth(), + target.getHeight() + ), + skinnable.contentBackgroundProperty(), + target.widthProperty(), + target.heightProperty() + )); + } + + /// Creates a background whose image layers use centered cover sizing without JavaFX cover mode. + private Background createCenteredCoverBackground(Background background, double regionWidth, double regionHeight) { + if (background == null || background.getImages().isEmpty()) { + return background; + } + + return new Background( + background.getFills(), + background.getImages().stream() + .map(backgroundImage -> new BackgroundImage( + backgroundImage.getImage(), + backgroundImage.getRepeatX(), + backgroundImage.getRepeatY(), + BackgroundPosition.CENTER, + createCenteredCoverSize( + backgroundImage.getImage(), + regionWidth, + regionHeight + ) + )) + .toList() + ); + } + + /// Calculates percentage sizing that fills the region while letting BackgroundPosition center crop the overflow. + private BackgroundSize createCenteredCoverSize(Image image, double regionWidth, double regionHeight) { + if (image == null + || image.getWidth() <= 0 + || image.getHeight() <= 0 + || regionWidth <= 0 + || regionHeight <= 0) { + return new BackgroundSize( + BackgroundSize.AUTO, + BackgroundSize.AUTO, + false, + false, + false, + false + ); + } + + double imageRatio = image.getWidth() / image.getHeight(); + double regionRatio = regionWidth / regionHeight; + + if (regionRatio > imageRatio) { + return new BackgroundSize( + 1.0, + BackgroundSize.AUTO, + true, + false, + false, + false + ); + } else { + return new BackgroundSize( + BackgroundSize.AUTO, + 1.0, + false, + true, + false, + false + ); + } + } + private Node createNavBar(Decorator skinnable, double leftPaneWidth, boolean canBack, boolean canClose, boolean showCloseAsHome, boolean canRefresh, String title, Node titleNode) { BorderPane navBar = new BorderPane(); navBar.getStyleClass().add("navigation-bar");