From 7a2e1857a404e386a85cd6cee3b07162266ee597 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pereda?= Date: Fri, 2 Feb 2024 07:11:18 +0100 Subject: [PATCH] move border creation outside of layout pass (#1539) --- .../java/org/controlsfx/tools/Borders.java | 102 ++++++++++-------- 1 file changed, 55 insertions(+), 47 deletions(-) diff --git a/controlsfx/src/main/java/org/controlsfx/tools/Borders.java b/controlsfx/src/main/java/org/controlsfx/tools/Borders.java index 542c2f4de..07f664bb9 100644 --- a/controlsfx/src/main/java/org/controlsfx/tools/Borders.java +++ b/controlsfx/src/main/java/org/controlsfx/tools/Borders.java @@ -1,5 +1,5 @@ /** - * Copyright (c) 2013, 2015, ControlsFX + * Copyright (c) 2013, 2024, ControlsFX * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -723,7 +723,7 @@ public StrokeBorder(String title, BorderStroke... borderStrokes) { } @Override public Node wrap(final Node n) { - StackPane pane = new StackPane() { + return new StackPane() { Label titleLabel; { @@ -733,75 +733,83 @@ public StrokeBorder(String title, BorderStroke... borderStrokes) { // if the title string is set, then also add in the title label if (title != null) { - titleLabel = new Label(title); - + titleLabel = new Label(title) { + + @Override + protected double computePrefWidth(double v) { + return super.computePrefWidth(v) + 2 * TITLE_PADDING; + } + + @Override + protected void layoutChildren() { + super.layoutChildren(); + final double labelHeight = titleLabel.prefHeight(-1); + titleLabel.relocate(TITLE_PADDING * 2, -labelHeight / 2.0 - 1); + } + + }; + // give the text a bit of space on the left... titleLabel.setPadding(new Insets(0, 0, 0, TITLE_PADDING)); getChildren().add(titleLabel); + needsLayoutProperty().addListener((obs, ov, nv) -> titleLabel.requestLayout()); + widthProperty().addListener(o -> setBorder(createTitledBorder(titleLabel, getWidth()))); + setBorder(createTitledBorder(titleLabel, getWidth())); + } else { + setBorder(new javafx.scene.layout.Border(borderStrokes)); } } - @Override protected void layoutChildren() { - super.layoutChildren(); - - if (titleLabel != null) { - // layout the title label - final double labelHeight = titleLabel.prefHeight(-1); - final double labelWidth = titleLabel.prefWidth(labelHeight) + TITLE_PADDING; - titleLabel.resize(labelWidth, labelHeight); - titleLabel.relocate(TITLE_PADDING * 2, -labelHeight / 2.0 - 1); + private javafx.scene.layout.Border createTitledBorder(Label titleLabel, double width) { + final double labelHeight = titleLabel.prefHeight(-1); + final double labelWidth = titleLabel.prefWidth(labelHeight); - List newBorderStrokes = new ArrayList<>(2); + List newBorderStrokes = new ArrayList<>(2); - // create a line gap for the title label - for (BorderStroke bs : borderStrokes) { - List dashList = new ArrayList<>(); + // create a line gap for the title label + for (BorderStroke bs : borderStrokes) { + List dashList = new ArrayList<>(); - // Create a dash list for the line gap or add it at the beginning of an existing dash list. This gap should be wide enough for the title label. - if (bs.getTopStyle().getDashArray().isEmpty()) - dashList.addAll(Arrays.asList(GAP_PADDING, labelWidth, Double.MAX_VALUE)); - else { // dash pattern exists - // insert gap in existing dash pattern and multiply original pattern so that gap does not show more then once - double origDashWidth = bs.getTopStyle().getDashArray().stream().mapToDouble(d -> d).sum(); + // Create a dash list for the line gap or add it at the beginning of an existing dash list. This gap should be wide enough for the title label. + if (bs.getTopStyle().getDashArray().isEmpty()) + dashList.addAll(Arrays.asList(GAP_PADDING, labelWidth, Double.MAX_VALUE)); + else { // dash pattern exists + // insert gap in existing dash pattern and multiply original pattern so that gap does not show more then once + double origDashWidth = bs.getTopStyle().getDashArray().stream().mapToDouble(d -> d).sum(); - if (origDashWidth > GAP_PADDING) { - dashList.add(GAP_PADDING); - dashList.add(labelWidth); - } else { // need to insert dash pattern before the gap - int no = (int) (GAP_PADDING / origDashWidth); + if (origDashWidth > GAP_PADDING) { + dashList.add(GAP_PADDING); + dashList.add(labelWidth); + } else { // need to insert dash pattern before the gap + int no = (int) (GAP_PADDING / origDashWidth); - for (int i = 0; i < no; i++) - dashList.addAll(bs.getTopStyle().getDashArray()); - - if ((dashList.size() & 1) == 0) // if size is even number, add one more element because gap must be at odd index to be transparent - dashList.add(0d); + for (int i = 0; i < no; i++) + dashList.addAll(bs.getTopStyle().getDashArray()); - dashList.add(labelWidth + GAP_PADDING - no * origDashWidth); - } + if ((dashList.size() & 1) == 0) // if size is even number, add one more element because gap must be at odd index to be transparent + dashList.add(0d); - for (int i = 0; i < (getWidth() - labelWidth - origDashWidth) / origDashWidth; i++) - dashList.addAll(bs.getTopStyle().getDashArray()); + dashList.add(labelWidth + GAP_PADDING - no * origDashWidth); } - // create new border stroke style for the top border line with new dash list - BorderStrokeStyle topStrokeStyle = new BorderStrokeStyle( + for (int i = 0; i < (width - labelWidth - origDashWidth) / origDashWidth; i++) + dashList.addAll(bs.getTopStyle().getDashArray()); + } + + // create new border stroke style for the top border line with new dash list + BorderStrokeStyle topStrokeStyle = new BorderStrokeStyle( bs.getTopStyle().getType(), bs.getTopStyle().getLineJoin(), bs.getTopStyle().getLineCap(), bs.getTopStyle().getMiterLimit(), bs.getTopStyle().getDashOffset(), dashList); - // change existing border stroke to utilize new top border line stroke style - newBorderStrokes.add(new BorderStroke( + // change existing border stroke to utilize new top border line stroke style + newBorderStrokes.add(new BorderStroke( bs.getTopStroke(), bs.getRightStroke(), bs.getBottomStroke(), bs.getLeftStroke(), topStrokeStyle, bs.getRightStyle(), bs.getBottomStyle(), bs.getLeftStyle(), bs.getRadii(), bs.getWidths(), null)); - } - - setBorder(new javafx.scene.layout.Border(newBorderStrokes.toArray(new BorderStroke[newBorderStrokes.size()]))); } + return new javafx.scene.layout.Border(newBorderStrokes.toArray(new BorderStroke[newBorderStrokes.size()])); } }; - - pane.setBorder(new javafx.scene.layout.Border(borderStrokes)); - return pane; } } }