From 1e5bbc63baf619a2f6e5c66b9d081d9cf08e2edc Mon Sep 17 00:00:00 2001 From: danielperano <51095634+danielperano@users.noreply.github.com> Date: Thu, 22 Feb 2024 10:33:08 -0800 Subject: [PATCH] Corrected Local Bounds for Absolute Positioning Yoga adds the offsets of a node into the bounds when that node is positioned absolutely. This removes the offsets from the reported bounds in these cases, since this is confusing behavior that usually needs to be accounted for downstream. --- .../myworld/obsidian/layout/LayoutEngine.java | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/Obsidian/src/main/java/myworld/obsidian/layout/LayoutEngine.java b/Obsidian/src/main/java/myworld/obsidian/layout/LayoutEngine.java index e92b2ce..2d3fb50 100644 --- a/Obsidian/src/main/java/myworld/obsidian/layout/LayoutEngine.java +++ b/Obsidian/src/main/java/myworld/obsidian/layout/LayoutEngine.java @@ -95,20 +95,50 @@ public float getHeight(Component component){ return LAYOUT_UNDEFINED; } + protected boolean isAbsolute(Component component){ + var isAbsolute = component.layout().positionType().is(PositionType.ABSOLUTE); + if(!isAbsolute && component.hasParent()){ + return isAbsolute(component.getParent()); + } + return isAbsolute; + } + public Bounds2D getLocalBounds(Component component){ var node = getYogaNode(component); if(node != null){ + var isAbsolute = isAbsolute(component); + var offsets = component.layout().offsets().get(Offsets.ZERO); + + var rawWidth = YGNodeLayoutGetWidth(node); + var rawHeight = YGNodeLayoutGetHeight(node); + + var width = rawWidth; + var height = rawHeight; + + if(isAbsolute){ + // Yoga considers the offsets to be part of the width/height when absolute positioning is used, + // but this is very awkward for downstream consumers since it requires different layout logic. + // Instead, compute the visual bounds as usual without regard for offsets when absolute positioning + // is used. + width -= Math.abs(maybeAutoToPixels(offsets.left(), width) + maybeAutoToPixels(offsets.right(), width)); + height -= Math.abs(maybeAutoToPixels(offsets.top(), height) + maybeAutoToPixels(offsets.bottom(), height)); + } + return new Bounds2D( new Point2D( YGNodeLayoutGetLeft(node), YGNodeLayoutGetTop(node)), - YGNodeLayoutGetWidth(node), - YGNodeLayoutGetHeight(node) + width, + height ); } return Bounds2D.UNDEFINED; } + protected float maybeAutoToPixels(Distance d, float pxSize){ + return d.equals(Layout.AUTO) ? 0f : d.toPixels(pxSize); + } + public Bounds2D getSceneBounds(Component component){ var bounds = getLocalBounds(component); float x = bounds.origin().x();