DVUI

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;
}