DVUI

rectFor

Parameters

#
self:*BoxWidget
*BoxWidget
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: *BoxWidget, id: dvui.Id, min_size: Size, e: Options.Expand, g: Options.Gravity) Rect {
    if (self.first_child) {
        self.first_child = false;

        // Lazily running this stuff that used to be in init so that using
        // .data().rectSet() after init works.

        // our rect for children has to start at 0,0
        self.child_rect = self.data().contentRect().justSize();

        if (self.data_prev) |dp| {
            if (self.init_opts.equal_space) {
                if (dp.packed_children > 0) {
                    switch (self.init_opts.dir) {
                        .horizontal => self.pixels_per_w = self.child_rect.w / dp.packed_children,
                        .vertical => self.pixels_per_w = self.child_rect.h / dp.packed_children,
                    }
                }
            } else {
                var packed_weight = dp.total_weight;
                if (self.init_opts.num_packed_expanded) |num| {
                    packed_weight = @floatFromInt(num);
                }

                if (packed_weight > 0) {
                    switch (self.init_opts.dir) {
                        .horizontal => self.pixels_per_w = @max(0, self.child_rect.w - dp.min_space_taken) / packed_weight,
                        .vertical => self.pixels_per_w = @max(0, self.child_rect.h - dp.min_space_taken) / packed_weight,
                    }
                }
            }
        }
    }

    if (builtin.mode == .Debug) {
        if (self.child_id != .zero) {
            dvui.logError(@src(), error.BadOrder, "rectFor called before previous widget called minSizeForChild", .{});
        }

        self.child_id = id;
    }

    self.child_positioned = switch (self.init_opts.dir) {
        .horizontal => g.x > 0 and g.x < 1.0,
        .vertical => g.y > 0 and g.y < 1.0,
    };

    if (self.child_positioned) {
        // don't pack this, we treat this like overlay - put it where they asked
        return dvui.placeIn(self.data().contentRect().justSize(), min_size, e, g);
    }

    self.packed_children += 1;
    var current_weight: f32 = 0.0;
    if ((self.init_opts.dir == .horizontal and e.isHorizontal()) or (self.init_opts.dir == .vertical and e.isVertical())) {
        current_weight = 1.0;
    }
    self.total_weight += current_weight;

    const available = self.child_rect;

    // adjust min size for expand ratio, which is forced
    var ms = min_size;
    self.ratio_extra = 0;
    if (e == .ratio and ms.w != 0 and ms.h != 0) {
        switch (self.init_opts.dir) {
            .horizontal => {
                const ratio = ms.w / ms.h;
                ms.h = available.h;
                ms.w = available.h * ratio;
                self.ratio_extra = ms.w - min_size.w;
            },
            .vertical => {
                const ratio = ms.h / ms.w;
                ms.h = available.w * ratio;
                ms.w = available.w;
                self.ratio_extra = ms.h - min_size.h;
            },
        }
    }

    // min size after ratio
    const child_min_size = ms;

    const ret: Rect = if (self.init_opts.equal_space) blk: {
        // position child inside the space we allocate for it
        switch (self.init_opts.dir) {
            .horizontal => {
                ms.w = self.pixels_per_w;
                ms.h = available.h;
                const avail = dvui.placeIn(available, ms, .none, g);
                self.removeSpace(avail, g);
                break :blk dvui.placeIn(avail, child_min_size, e, g);
            },
            .vertical => {
                ms.h = self.pixels_per_w;
                ms.w = available.w;
                const avail = dvui.placeIn(available, ms, .none, g);
                self.removeSpace(avail, g);
                break :blk dvui.placeIn(avail, child_min_size, e, g);
            },
        }
    } else blk: {
        //  adjust min size for normal expand (since you only get prorated extra space)
        // - keep the expand in the non box direction
        var ee: Options.Expand = .none;
        switch (self.init_opts.dir) {
            .horizontal => {
                ms.w += self.pixels_per_w * current_weight;
                if (e.isVertical()) ee = .vertical;
            },
            .vertical => {
                ms.h += self.pixels_per_w * current_weight;
                if (e.isHorizontal()) ee = .horizontal;
            },
        }

        const ret = dvui.placeIn(available, ms, ee, g);
        self.removeSpace(ret, g);
        break :blk ret;
    };

    switch (self.init_opts.dir) {
        .horizontal => if (ret.w + 0.001 < child_min_size.w) {
            self.ran_off = true;
        },
        .vertical => if (ret.h + 0.001 < child_min_size.h) {
            self.ran_off = true;
        },
    }

    return ret;
}