rectFor
Parameters
- self:*ScrollContainerWidget
- *ScrollContainerWidget
- id:dvui.Id
- dvui.Id
- min_size:Size
- Size
- e:Options.Expand
- Options.Expand
- g:Options.Gravity
- Options.Gravity
Source
Implementation
pub fn rectFor(self: *ScrollContainerWidget, id: dvui.Id, min_size: Size, e: Options.Expand, g: Options.Gravity) Rect {
// todo: do horizontal properly
if (self.seen_expanded_child) {
// Having one expanded child makes sense - could be taking the rest of
// the given space or filling the visible space (if bigger than the min
// virtual size). But that should be the last (usually only) child
// that asks for space.
//
// We saw an expanded child and gave it the rest of the space, and now
// another child has asked for space, which shouldn't happen. Visually
// the new child might not appear at all or appear on top of the
// expanded child.
//
// If you are reading this, make sure that children of scrollArea() are
// not expanded in the scrollArea's layout direction, or that only the
// last child is.
dvui.log.err("{s}:{d} got child {x} after expanded child", .{ @src().file, @src().line, id });
var iter = dvui.parentGet().data().iterator();
while (iter.next()) |wd| {
dvui.log.debug(" {s}:{d} {s} {x}", .{
wd.src.file,
wd.src.line,
wd.options.name orelse "???",
wd.id,
});
dvui.Debug.errorOutline(wd.rectScale().r);
}
} else if (e.isVertical()) {
self.seen_expanded_child = true;
}
const y = self.nextVirtualSize.h;
const h = switch (self.si.vertical) {
// no scrolling, you only get the visible space
.none => self.si.viewport.h - y,
// you get the space you need or more if there is extra visible space
// and you are expanded
.auto => @max(self.si.viewport.h - y, min_size.h),
// you get the given space
.given => self.si.virtual_size.h - y,
};
// todo: do horizontal properly
const maxw = @max(self.si.virtual_size.w, self.si.viewport.w);
const rect = Rect{ .x = 0, .y = y, .w = maxw, .h = h };
const ret = dvui.placeIn(rect, min_size, e, g);
if (self.lock_visible and self.first_visible_id == id) {
self.first_visible_id = .zero;
self.lock_visible = false;
const scroll_since_last_frame = self.frame_viewport.diff(self.first_visible_viewport);
self.frame_viewport.x = 0; // todo
self.frame_viewport.y = y + self.first_visible_offset.y + scroll_since_last_frame.y;
self.si.viewport.x = self.frame_viewport.x;
self.si.viewport.y = self.frame_viewport.y;
}
if (!self.lock_visible and self.first_visible_id == .zero and self.frame_viewport.y < (ret.y + ret.h)) {
self.first_visible_id = id;
self.first_visible_offset = Point.diff(self.frame_viewport, ret.topLeft());
// record where the viewport was, so that if we do lock_visible next
// frame we can tell how much scrolling happened
self.first_visible_viewport = self.frame_viewport;
}
return ret;
}