diff --git a/CHANGELOG.md b/CHANGELOG.md index 976fa343..d5f1b14c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,14 @@ follow semantic versioning; release dates are ISO 8601. regression baselines, and reusable `Subheadline` / `SectionHeader.flatSpacedCaps` widget support. +### Public API + +- **`PageBackgroundFill` band helpers.** Added `topBand`, `bottomBand`, + `band`, `topBandPoints`, and `bandPoints` factory methods for full-width + horizontal background bands (top, bottom, or arbitrary vertical offset; + ratio- or point-based), complementing the existing column helpers and + building on the v1.6.5 y-coordinate fix below. + ### Bug fixes - **`PageBackgroundFill` y-coordinate.** A partial-height page-background diff --git a/src/main/java/com/demcha/compose/document/api/PageBackgroundFill.java b/src/main/java/com/demcha/compose/document/api/PageBackgroundFill.java index 8b73efc3..5c450cef 100644 --- a/src/main/java/com/demcha/compose/document/api/PageBackgroundFill.java +++ b/src/main/java/com/demcha/compose/document/api/PageBackgroundFill.java @@ -21,6 +21,13 @@ * column aligned to the right edge. *
  • {@link #column(double, double, DocumentColor)} — arbitrary * horizontal slice spanning the full page height.
  • + *
  • {@link #topBand(double, DocumentColor)} / + * {@link #bottomBand(double, DocumentColor)} / + * {@link #band(double, double, DocumentColor)} — full-width + * horizontal bands at the top, bottom, or an arbitrary vertical + * offset (also available in absolute points via + * {@link #topBandPoints(double, double, DocumentColor)} and + * {@link #bandPoints(double, double, double, DocumentColor)}).
  • * * *

    Fills supplied to a session are painted at z=0 (below every other @@ -88,4 +95,41 @@ public static PageBackgroundFill column(double xRatio, DocumentColor color) { return new PageBackgroundFill(xRatio, 0.0, widthRatio, 1.0, color); } + + /** Full-width band flush with the top of the page (height = ratio of page height). */ + public static PageBackgroundFill topBand(double heightRatio, + DocumentColor color) { + return new PageBackgroundFill(0.0, 0.0, 1.0, heightRatio, color); + } + + /** Full-width band flush with the bottom of the page (height = ratio of page height). */ + public static PageBackgroundFill bottomBand(double heightRatio, + DocumentColor color) { + return new PageBackgroundFill(0.0, 1.0 - heightRatio, 1.0, + heightRatio, color); + } + + /** Full-width band whose top edge sits {@code yRatioFromTop} down the page (0.0 = page top). */ + public static PageBackgroundFill band(double yRatioFromTop, + double heightRatio, + DocumentColor color) { + return new PageBackgroundFill(0.0, yRatioFromTop, 1.0, + heightRatio, color); + } + + /** Top-aligned band sized in absolute points, converted against {@code pageHeight}. */ + public static PageBackgroundFill topBandPoints(double heightPoints, + double pageHeight, + DocumentColor color) { + return topBand(heightPoints / pageHeight, color); + } + + /** Band positioned and sized in absolute points from the page top, converted against {@code pageHeight}. */ + public static PageBackgroundFill bandPoints(double yFromTopPoints, + double heightPoints, + double pageHeight, + DocumentColor color) { + return band(yFromTopPoints / pageHeight, heightPoints / pageHeight, + color); + } } diff --git a/src/test/java/com/demcha/compose/document/api/PageBackgroundTest.java b/src/test/java/com/demcha/compose/document/api/PageBackgroundTest.java index b4cae9b2..a7f7fd17 100644 --- a/src/test/java/com/demcha/compose/document/api/PageBackgroundTest.java +++ b/src/test/java/com/demcha/compose/document/api/PageBackgroundTest.java @@ -341,6 +341,51 @@ void midPageBandLandsAtCorrectVerticalPosition() { } } + // -- Band factory helpers (build on the corrected coordinate model) -- + + @Test + void bandFactoryHelpersComputeRatiosCorrectly() { + DocumentColor c = DocumentColor.WHITE; + assertThat(PageBackgroundFill.topBand(0.16, c)) + .isEqualTo(new PageBackgroundFill(0.0, 0.0, 1.0, 0.16, c)); + assertThat(PageBackgroundFill.bottomBand(0.16, c)) + .isEqualTo(new PageBackgroundFill(0.0, 0.84, 1.0, 0.16, c)); + assertThat(PageBackgroundFill.band(0.4, 0.2, c)) + .isEqualTo(new PageBackgroundFill(0.0, 0.4, 1.0, 0.2, c)); + assertThat(PageBackgroundFill.topBandPoints(48, 300, c)) + .isEqualTo(new PageBackgroundFill(0.0, 0.0, 1.0, 48.0 / 300.0, c)); + assertThat(PageBackgroundFill.bandPoints(120, 60, 300, c)) + .isEqualTo(new PageBackgroundFill(0.0, 120.0 / 300.0, 1.0, 60.0 / 300.0, c)); + } + + @Test + void topBandAndBottomBandHelpersRenderAtCorrectEdges() { + DocumentColor fill = DocumentColor.of(Color.DARK_GRAY); + try (DocumentSession session = GraphCompose.document() + .pageSize(400, 300) + .margin(DocumentInsets.zero()) + .pageBackgrounds(List.of( + PageBackgroundFill.topBand(0.16, fill), + PageBackgroundFill.bottomBand(0.16, fill))) + .create()) { + + session.add(new SpacerNode("Block", 200, 80, + DocumentInsets.zero(), DocumentInsets.zero())); + List bg = session.layoutGraph().fragments().stream() + .filter(this::isPageBackgroundFragment) + .toList(); + + assertThat(bg).hasSize(2); + // List order: topBand first, bottomBand second. + assertThat(bg.get(0).y()).isCloseTo(252.0, within(EPS)); // top band + assertThat(bg.get(0).height()).isCloseTo(48.0, within(EPS)); + assertThat(bg.get(1).y()).isCloseTo(0.0, within(EPS)); // bottom band + assertThat(bg.get(1).height()).isCloseTo(48.0, within(EPS)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + private boolean isPageBackgroundFragment(PlacedFragment fragment) { return fragment.payload() instanceof ShapeFragmentPayload payload && payload.fillColor() != null