DVUI

init

It's expected to call this when self is undefined

Parameters

#
self:*FloatingMenuWidget
*FloatingMenuWidget
src:std.builtin.SourceLocation
std.builtin.SourceLocation
init_opts:InitOptions
InitOptions
opts:Options
Options

Source

Implementation

#
pub fn init(self: *FloatingMenuWidget, src: std.builtin.SourceLocation, init_opts: InitOptions, opts: Options) void {
    self.* = .{
        // the widget itself doesn't have any styling, it comes from the
        // embedded MenuWidget
        // passing options.rect will stop WidgetData.init from calling
        // rectFor/minSizeForChild which is important because we are outside
        // normal layout
        .wd = .init(src, .{ .subwindow = true }, .{ .id_extra = opts.id_extra, .rect = .{} }),
        // get scale from parent
        .scale_val = dvui.parentGet().screenRectScale(Rect{}).s / dvui.windowNaturalScale(),

        .render_ftb = undefined,
        .prev_last_focus = undefined,
        .prevClip = undefined,
        .menu = undefined,
        .scaler = undefined,
        .scroll = undefined,
    };

    const options = defaults.override(opts);
    // NOTE: options is really for our embedded ScrollAreaWidget

    const avoid: dvui.PlaceOnScreenAvoid = switch (init_opts.avoid) {
        .none => .none,
        .horizontal => .horizontal,
        .vertical => .vertical,
        .auto => if (dvui.MenuWidget.current()) |pm| switch (pm.init_opts.dir) {
            .horizontal => .vertical,
            .vertical => .horizontal,
        } else .none,
    };

    self.data().rect = Rect.fromPoint(.cast(init_opts.from.topLeft()));
    if (dvui.minSizeGet(self.data().id)) |_| {
        const ms = dvui.minSize(self.data().id, options.min_sizeGet());
        self.data().rect = self.data().rect.toSize(ms);
        self.data().rect = .cast(dvui.placeOnScreen(dvui.windowRect(), init_opts.from, avoid, .cast(self.data().rect)));
        if (dvui.dataGet(null, self.data().id, "_check_focus", void) != null) {
            dvui.dataRemove(null, self.data().id, "_check_focus");
            if (dvui.MenuWidget.current() == null or !dvui.MenuWidget.current().?.mouse_mode or self.data().rectScale().r.contains(dvui.currentWindow().mouse_pt)) {
                dvui.focusSubwindow(self.data().id, null);
            }
        }
    } else {
        self.data().rect = .cast(dvui.placeOnScreen(dvui.windowRect(), init_opts.from, avoid, .cast(self.data().rect)));
        dvui.dataSet(null, self.data().id, "_check_focus", {});

        // need a second frame to fit contents (FocusWindow calls refresh but
        // here for clarity)
        dvui.refresh(null, @src(), self.data().id);
    }

    self.data().register();
    dvui.parentSet(self.widget());

    // standard subwindow stuff
    {
        const rs = self.data().rectScale();
        self.render_ftb.initReset();
        self.prev_windowInfo = dvui.subwindowCurrentSet(self.data().id, null);
        dvui.subwindowAdd(self.data().id, self.data().rect, rs.r, false, null, true);
        dvui.captureMouseMaintain(.{ .id = self.data().id, .rect = rs.r, .subwindow_id = self.data().id });
        self.prevClip = dvui.clipGet();
        dvui.clipSet(dvui.windowRectPixels()); // break out of whatever clipping we were in
        self.prev_scroll = dvui.ScrollContainerWidget.scrollSet(null);
    }

    // prevents parents from processing key events if focus is inside the floating window
    self.prev_last_focus = dvui.lastFocusedIdInFrame();

    self.parent_fmw = currentSet(self);

    const rs = self.data().rectScale();
    const evts = dvui.events();
    for (evts) |*e| {
        if (!dvui.eventMatch(e, .{ .id = self.data().id, .r = rs.r }))
            continue;

        if (e.evt == .mouse and e.evt.mouse.action == .focus) {
            // focus but let the focus event propagate to widgets
            dvui.focusSubwindow(self.data().id, e.num);
        }
    }

    self.scaler.init(@src(), .{ .scale = &self.scale_val }, .{ .expand = .both });

    // we are using scroll to do border/background but floating windows
    // don't have margin, so turn that off
    self.scroll.init(@src(), .{ .horizontal = .none }, options.override(.{ .margin = .{}, .expand = .both }));

    if (dvui.MenuWidget.current()) |pm| {
        pm.child_popup_rect = rs.r;
    }

    self.menu.init(@src(), .{ .dir = .vertical, .parentSubwindowId = self.prev_windowInfo.id }, options.strip().override(.{ .role = .none, .expand = .horizontal }));
}