DVUI

init

It's expected to call this when self is undefined

Parameters

#
self:*ScrollAreaWidget
*ScrollAreaWidget
src:std.builtin.SourceLocation
std.builtin.SourceLocation
init_opts:InitOpts
InitOpts
opts:Options
Options

Source

Implementation

#
pub fn init(self: *ScrollAreaWidget, src: std.builtin.SourceLocation, init_opts: InitOpts, opts: Options) void {
    self.* = .{
        .hbox = undefined, // set below
    };

    self.hbox.init(src, .{ .dir = .horizontal }, defaults.override(opts));

    if (init_opts.scroll_info) |si| {
        self.si = si;
        if (init_opts.vertical != null) {
            dvui.log.debug("ScrollAreaWidget {x} init_opts.vertical .{s} overridden by init_opts.scroll_info.vertical .{s}\n", .{ self.hbox.data().id, @tagName(init_opts.vertical.?), @tagName(si.vertical) });
        }
        if (init_opts.horizontal != null) {
            dvui.log.debug("ScrollAreaWidget {x} init_opts.horizontal .{s} overridden by init_opts.scroll_info.horizontal .{s}\n", .{ self.hbox.data().id, @tagName(init_opts.horizontal.?), @tagName(si.horizontal) });
        }
    } else {
        self.si = dvui.dataGetPtrDefault(null, self.hbox.data().id, "_scroll_info", ScrollInfo, .{});

        // outside code might have changed what direction we scroll in
        self.si.vertical = init_opts.vertical orelse .auto;
        self.si.horizontal = init_opts.horizontal orelse .none;
    }

    self.hbox.drawBackground();

    const focus_target = init_opts.focus_id orelse dvui.dataGet(null, self.hbox.data().id, "_scroll_id", dvui.Id);

    const crect = self.hbox.data().contentRect();

    // First assume ScrollContainer gets all our space.
    self.si.viewport.w = crect.w;
    self.si.viewport.h = crect.h;

    // Now adjust if we got insets from last frame.
    if (dvui.dataGet(null, self.hbox.data().id, "_linsets", dvui.Size)) |inset| {
        self.si.viewport.w -= inset.w;
        self.si.viewport.h -= inset.h;
    } else if (!dvui.firstFrame(self.hbox.data().id)) {
        dvui.log.debug("ScrollAreaWidget {x} missing insets from last frame\n", .{self.hbox.data().id});
    }

    // due to floating point inaccuracies, give ourselves a tiny bit of extra wiggle room

    var do_vbar = false;
    var do_hbar = false;
    if (self.si.vertical != .none) {
        if (init_opts.vertical_bar == .show or (init_opts.vertical_bar.autoAny() and (self.si.virtual_size.h > (self.si.viewport.h + 0.001)))) {
            do_vbar = true;
            if (init_opts.vertical_bar != .auto_overlay) {
                self.si.viewport.w -= ScrollBarWidget.defaults.min_sizeGet().w;
            }
        }
    }

    if (self.si.horizontal != .none) {
        if (init_opts.horizontal_bar == .show or (init_opts.horizontal_bar.autoAny() and (self.si.virtual_size.w > (self.si.viewport.w + 0.001)))) {
            do_hbar = true;
            if (init_opts.horizontal_bar != .auto_overlay) {
                self.si.viewport.h -= ScrollBarWidget.defaults.min_sizeGet().h;
            }
        }
    }

    // test for vbar again because hbar might have removed some of our room
    if (!do_vbar and do_hbar and self.si.vertical != .none) {
        if (init_opts.vertical_bar.autoAny() and (self.si.virtual_size.h > (self.si.viewport.h + 0.001))) {
            do_vbar = true;
            if (init_opts.vertical_bar != .auto_overlay) {
                self.si.viewport.w -= ScrollBarWidget.defaults.min_sizeGet().w;
            }
        }
    }

    if (do_vbar) {
        // do the scrollbars first so that they still appear even if there's not enough space
        const overlay = init_opts.vertical_bar == .auto_overlay;
        self.vbar = @as(ScrollBarWidget, undefined); // Must be a non-null value for `.?` bellow
        self.vbar.?.init(
            @src(),
            .{ .scroll_info = self.si, .focus_id = focus_target },
            self.hbox.data().options.strip().override(.{ .gravity_x = if (overlay) 0.999 else 1.0, .expand = .vertical }),
        );
        if (overlay) {
            self.vbar_grab = self.vbar.?.grab();
        } else {
            self.vbar.?.grab().draw();
        }
        self.vbar.?.deinit();
    }

    self.vbox.init(@src(), .{ .dir = .vertical }, self.hbox.data().options.strip().override(.{ .expand = .both, .name = "ScrollAreaWidget vbox" }));
    self.vbox.drawBackground();

    if (do_hbar) {
        const overlay = init_opts.horizontal_bar == .auto_overlay;
        self.hbar = @as(ScrollBarWidget, undefined); // Must be a non-null value for `.?` bellow
        self.hbar.?.init(
            @src(),
            .{ .direction = .horizontal, .scroll_info = self.si, .focus_id = focus_target },
            self.hbox.data().options.strip().override(.{ .expand = .horizontal, .gravity_y = if (overlay) 0.999 else 1.0 }),
        );
        if (overlay) {
            self.hbar_grab = self.hbar.?.grab();
        } else {
            self.hbar.?.grab().draw();
        }
        self.hbar.?.deinit();
    }

    if (init_opts.container) {
        const container_opts = self.hbox.data().options.strip().override(.{ .expand = .both });
        self.scroll = @as(ScrollContainerWidget, undefined);
        self.scroll.?.init(@src(), self.si, .{ .scroll_area = self, .lock_visible = init_opts.lock_visible, .user_scroll = init_opts.user_scroll, .frame_viewport = init_opts.frame_viewport, .process_events_after = init_opts.process_events_after }, container_opts);

        self.scroll.?.processEvents();
        self.scroll.?.processVelocity();
    }
}