-
Notifications
You must be signed in to change notification settings - Fork 30
vaev-layout: Initial implementation of float. #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
module; | ||
|
||
#include <karm-math/au.h> | ||
|
||
export module Vaev.Engine:layout.floats; | ||
|
||
import :values; | ||
|
||
namespace Vaev::Layout { | ||
|
||
export struct FloatsContainer { | ||
struct Placed { | ||
RectAu rect; | ||
Float side; | ||
}; | ||
|
||
Vec<Placed> _placed; | ||
Vec2Au _origin; | ||
Au _inlineSize; | ||
|
||
FloatsContainer(Vec2Au origin, Au inlineSize) | ||
: _origin(origin), _inlineSize(inlineSize) {} | ||
Comment on lines
+21
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constructors should be O(1) and lightweight. The current constructors are already simple, but consider making the parameterized constructor explicit to prevent unintended implicit conversions. Copilot generated this review using guidance from repository custom instructions. Positive FeedbackNegative Feedback |
||
|
||
FloatsContainer() : _origin({0_au, 0_au}), _inlineSize(0_au) {} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Constructors should be O(1) and lightweight. The current constructors are already simple, but consider making the parameterized constructor explicit to prevent unintended implicit conversions. Copilot generated this review using guidance from repository custom instructions. Positive FeedbackNegative Feedback |
||
|
||
static bool _verticallyOverlaps(RectAu const& r, Au bandY, Au bandH) { | ||
Au r0 = r.y; | ||
Au r1 = r.y + r.height; | ||
Au b0 = bandY; | ||
Au b1 = bandY + bandH; | ||
return not(b1 <= r0 or r1 <= b0); | ||
} | ||
|
||
// Compute available inline range [start, end) in container coords at band y..y+h | ||
Pair<Au> inlineAvailable(Au y, Au h) const { | ||
// Fast path: no floats | ||
if (_placed.len() == 0) | ||
return {0_au, _inlineSize}; | ||
|
||
Au left = 0_au; // consumed from Start | ||
Au right = _inlineSize; // open end (exclusive) | ||
for (auto const& pf : _placed) { | ||
if (not _verticallyOverlaps(pf.rect, _origin.y + y, h)) | ||
continue; | ||
if (pf.side == Float::INLINE_START or pf.side == Float::LEFT) { | ||
Au used = (pf.rect.x + pf.rect.width) - _origin.x; | ||
if (used > left) | ||
left = used; | ||
} else if (pf.side == Float::INLINE_END or pf.side == Float::RIGHT) { | ||
Au used = pf.rect.x - _origin.x; | ||
if (used < right) | ||
right = used; | ||
} | ||
} | ||
if (left > right) | ||
left = right; // no space => collapsed interval | ||
return {left, right}; | ||
} | ||
|
||
Au clear(Clear clr, Au fromY) const { | ||
bool start = clr == Clear::BOTH or clr == Clear::INLINE_START or clr == Clear::LEFT; | ||
bool end = clr == Clear::BOTH or clr == Clear::INLINE_END or clr == Clear::RIGHT; | ||
|
||
Au y = fromY; | ||
bool changed = true; | ||
while (changed) { | ||
changed = false; | ||
for (auto const& pf : _placed) { | ||
if (not _verticallyOverlaps(pf.rect, _origin.y + y, 1_au)) | ||
continue; | ||
bool isStart = (pf.side == Float::INLINE_START or pf.side == Float::LEFT); | ||
bool isEnd = (pf.side == Float::INLINE_END or pf.side == Float::RIGHT); | ||
if ((start and isStart) or (end and isEnd)) { | ||
Au ny = (pf.rect.y + pf.rect.height) - _origin.y; | ||
if (ny > y) { | ||
y = ny; | ||
changed = true; | ||
} | ||
} | ||
} | ||
} | ||
return y; | ||
} | ||
|
||
// Place a float box with size (inline=w, block=h) at or after y | ||
RectAu place(Vec2Au size, Float side, Au y) { | ||
Au w = size.x; | ||
Au h = size.y; | ||
if (w <= 0_au or h <= 0_au) | ||
return {_origin.x, _origin.y + y, 0_au, 0_au}; | ||
|
||
Au curY = y; | ||
while (true) { | ||
auto [availStart, availEnd] = inlineAvailable(curY, h); | ||
Au availW = availEnd - availStart; | ||
if (availW >= w) { | ||
Au x = (side == Float::INLINE_START or side == Float::LEFT) | ||
? (_origin.x + availStart) | ||
: (_origin.x + (availEnd - w)); | ||
RectAu rect{x, _origin.y + curY, w, h}; | ||
_placed.pushBack({rect, side}); | ||
return rect; | ||
} | ||
|
||
// Not enough room on this slice; push below the lowest overlapping edge | ||
Au nextY = curY; | ||
for (auto const& pf : _placed) { | ||
if (_verticallyOverlaps(pf.rect, _origin.y + curY, h)) { | ||
Au ny = (pf.rect.y + pf.rect.height) - _origin.y; | ||
if (ny > nextY) | ||
nextY = ny; | ||
} | ||
} | ||
if (nextY == curY) { | ||
// Wider than container: clamp to container width and place at side | ||
Au clampedW = (w > _inlineSize) ? _inlineSize : w; | ||
Au x = (side == Float::INLINE_START or side == Float::LEFT) | ||
? _origin.x | ||
: _origin.x + (_inlineSize - clampedW); | ||
RectAu rect{x, _origin.y + curY, clampedW, h}; | ||
_placed.pushBack({rect, side}); | ||
return rect; | ||
} | ||
curY = nextY; | ||
} | ||
} | ||
}; | ||
|
||
} // namespace Vaev::Layout |
Uh oh!
There was an error while loading. Please reload this page.