/* Crafter®.Graphics Copyright (C) 2026 Catcrafts® catcrafts.net This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3.0 as published by the Free Software Foundation; This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ export module Crafter.Graphics:UILayout; import std; import :UILength; import :UIWidget; export namespace Crafter::UI { // Convert a Length to device pixels. `parentExtent` is the parent's // available extent on the same axis (already in device px). `autoFn` // produces the size to use for `Auto` and `Frac` modes — for Auto this // is the desired-content size, for Frac it's the same fallback (Frac // is meaningful only inside a stack container, which resolves it // separately; everywhere else it's just "fill what's available", same // as Auto). template constexpr float ResolveLength(Length len, float parentExtent, float scale, AutoFn&& autoFn) { switch (len.mode) { case Length::Mode::Px: return len.value * scale; case Length::Mode::Pct: return len.value * 0.01f * parentExtent; case Length::Mode::Auto: return static_cast(autoFn()); case Length::Mode::Frac: return static_cast(autoFn()); } return 0.0f; } // Edges resolved into device pixels (no Length involvement; Edges are // already plain floats in logical px). struct EdgesPx { float top = 0, right = 0, bottom = 0, left = 0; constexpr float Horiz() const { return left + right; } constexpr float Vert() const { return top + bottom; } }; constexpr EdgesPx ResolveEdges(Edges e, float scale) { return { e.top * scale, e.right * scale, e.bottom * scale, e.left * scale }; } // Rect minus padding — yields the content rect. constexpr Rect ShrinkBy(Rect r, EdgesPx p) { return { r.x + p.left, r.y + p.top, std::max(0.0f, r.w - p.Horiz()), std::max(0.0f, r.h - p.Vert()), }; } // Run the two-pass measure/arrange on a root widget bound to a surface // of `surfacePx` device pixels at `scale`. The root receives the full // surface as its arrange rect. inline void RunLayout(Widget& root, Size surfacePx, float scale) { LayoutContext ctx{ .scale = scale, .surfaceSize = surfacePx }; root.Measure(surfacePx, ctx); root.Arrange({0, 0, surfacePx.w, surfacePx.h}, ctx); } }