DVUI

init

Parameters

#
src:std.builtin.SourceLocation
std.builtin.SourceLocation
gpa:std.mem.Allocator
std.mem.Allocator
backend_ctx:dvui.Backend
dvui.Backend
init_opts:InitOptions
InitOptions

Source

Implementation

#
pub fn init(
    src: std.builtin.SourceLocation,
    gpa: std.mem.Allocator,
    backend_ctx: dvui.Backend,
    init_opts: InitOptions,
) !Self {
    const hashval = if (dvui.current_window) |cw|
        cw.data().id.extendId(src, init_opts.id_extra)
    else
        dvui.Id.extendId(null, src, init_opts.id_extra);

    var self = Self{
        .gpa = gpa,
        ._arena = if (init_opts.arena) |a| a else .init(gpa),
        ._lifo_arena = .init(gpa),
        ._widget_stack = .init(gpa),
        .wd = WidgetData{
            .src = src,
            .id = hashval,
            .init_options = .{ .subwindow = true },
            .options = .{ .name = "Window", .role = .window },
            // Unused
            .min_size = .{},
            // Set in `begin`
            .rect = undefined,
            // Set in `begin`
            .parent = undefined,
        },
        // Set in `begin`
        .current_parent = undefined,
        .theme = undefined, // set below
        .open_flag = init_opts.open_flag,
        .backend = backend_ctx,
        .accesskit = .{},
    };

    if (init_opts.theme) |t| {
        self.themeSet(t);
    } else switch (init_opts.color_scheme orelse backend_ctx.preferredColorScheme() orelse .light) {
        .light => self.themeSet(Theme.builtin.adwaita_light),
        .dark => self.themeSet(Theme.builtin.adwaita_dark),
    }

    try self.initEvents();

    self.button_order = init_opts.button_order orelse switch (builtin.os.tag) {
        .windows => .ok_cancel,
        else => .cancel_ok,
    };

    const kb = init_opts.keybinds orelse blk: {
        if (builtin.os.tag.isDarwin()) {
            break :blk .mac;
        } else {
            break :blk .windows;
        }
    };

    if (kb == .windows or kb == .mac) {
        try self.keybinds.putNoClobber(self.gpa, "activate", .{ .key = .enter, .also = "activate_1" });
        try self.keybinds.putNoClobber(self.gpa, "activate_1", .{ .key = .space });

        try self.keybinds.putNoClobber(self.gpa, "next_widget", .{ .key = .tab, .shift = false });
        try self.keybinds.putNoClobber(self.gpa, "prev_widget", .{ .key = .tab, .shift = true });
    }

    switch (kb) {
        .none => {},
        .windows => {
            // zig fmt: off
                try self.keybinds.putNoClobber(self.gpa, "cut",        .{ .key = .x, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "copy",       .{ .key = .c, .control = true, .also = "copy_1" });
                try self.keybinds.putNoClobber(self.gpa, "copy_1",       .{ .key = .insert, .control = true, .shift = false, .alt = false, .command = false });
                try self.keybinds.putNoClobber(self.gpa, "paste",      .{ .key = .v, .control = true, .also = "paste_1" });
                try self.keybinds.putNoClobber(self.gpa, "paste_1",       .{ .key = .insert, .control = false, .shift = true, .alt = false, .command = false });
                try self.keybinds.putNoClobber(self.gpa, "select_all", .{ .key = .a, .control = true });

                // use with mod.matchBind
                try self.keybinds.putNoClobber(self.gpa, "ctrl/cmd",   .{ .control = true });

                try self.keybinds.putNoClobber(self.gpa, "text_start",        .{ .key = .home, .shift = false, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "text_end",          .{ .key = .end,  .shift = false, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "text_start_select", .{ .key = .home, .shift = true,  .control = true });
                try self.keybinds.putNoClobber(self.gpa, "text_end_select",   .{ .key = .end,  .shift = true,  .control = true });

                try self.keybinds.putNoClobber(self.gpa, "line_start",        .{ .key = .home, .shift = false, .control = false });
                try self.keybinds.putNoClobber(self.gpa, "line_end",          .{ .key = .end,  .shift = false, .control = false });
                try self.keybinds.putNoClobber(self.gpa, "line_start_select", .{ .key = .home, .shift = true,  .control = false });
                try self.keybinds.putNoClobber(self.gpa, "line_end_select",   .{ .key = .end,  .shift = true,  .control = false });

                try self.keybinds.putNoClobber(self.gpa, "word_left",         .{ .key = .left,  .shift = false, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "word_right",        .{ .key = .right, .shift = false, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "word_left_select",  .{ .key = .left,  .shift = true,  .control = true });
                try self.keybinds.putNoClobber(self.gpa, "word_right_select", .{ .key = .right, .shift = true,  .control = true });

                try self.keybinds.putNoClobber(self.gpa, "char_left",         .{ .key = .left,  .shift = false, .control = false });
                try self.keybinds.putNoClobber(self.gpa, "char_right",        .{ .key = .right, .shift = false, .control = false });
                try self.keybinds.putNoClobber(self.gpa, "char_left_select",  .{ .key = .left,  .shift = true,  .control = false });
                try self.keybinds.putNoClobber(self.gpa, "char_right_select", .{ .key = .right, .shift = true,  .control = false });

                try self.keybinds.putNoClobber(self.gpa, "char_up",          .{ .key = .up,   .shift = false });
                try self.keybinds.putNoClobber(self.gpa, "char_down",        .{ .key = .down, .shift = false });
                try self.keybinds.putNoClobber(self.gpa, "char_up_select",   .{ .key = .up,   .shift = true });
                try self.keybinds.putNoClobber(self.gpa, "char_down_select", .{ .key = .down, .shift = true });

                try self.keybinds.putNoClobber(self.gpa, "delete_prev_word", .{ .key = .backspace, .control = true });
                try self.keybinds.putNoClobber(self.gpa, "delete_next_word", .{ .key = .delete,    .control = true });
                // zig fmt: on
        },
        .mac => {
            // zig fmt: off
                try self.keybinds.putNoClobber(self.gpa, "cut",        .{ .key = .x, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "copy",       .{ .key = .c, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "paste",      .{ .key = .v, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "select_all", .{ .key = .a, .command = true });

                // use with mod.matchBind
                try self.keybinds.putNoClobber(self.gpa, "ctrl/cmd",   .{ .command = true });

                try self.keybinds.putNoClobber(self.gpa, "text_start",        .{ .key = .up,   .shift = false, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "text_end",          .{ .key = .down, .shift = false, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "text_start_select", .{ .key = .up,   .shift = true,  .command = true });
                try self.keybinds.putNoClobber(self.gpa, "text_end_select",   .{ .key = .down, .shift = true,  .command = true });

                try self.keybinds.putNoClobber(self.gpa, "line_start",        .{ .key = .left,  .shift = false, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "line_end",          .{ .key = .right, .shift = false, .command = true });
                try self.keybinds.putNoClobber(self.gpa, "line_start_select", .{ .key = .left,  .shift = true,  .command = true });
                try self.keybinds.putNoClobber(self.gpa, "line_end_select",   .{ .key = .right, .shift = true,  .command = true });

                try self.keybinds.putNoClobber(self.gpa, "word_left",         .{ .key = .left,  .shift = false, .alt = true });
                try self.keybinds.putNoClobber(self.gpa, "word_right",        .{ .key = .right, .shift = false, .alt = true });
                try self.keybinds.putNoClobber(self.gpa, "word_left_select",  .{ .key = .left,  .shift = true,  .alt = true });
                try self.keybinds.putNoClobber(self.gpa, "word_right_select", .{ .key = .right, .shift = true,  .alt = true });

                try self.keybinds.putNoClobber(self.gpa, "char_left",         .{ .key = .left,  .shift = false, .alt = false });
                try self.keybinds.putNoClobber(self.gpa, "char_right",        .{ .key = .right, .shift = false, .alt = false });
                try self.keybinds.putNoClobber(self.gpa, "char_left_select",  .{ .key = .left,  .shift = true,  .alt = false });
                try self.keybinds.putNoClobber(self.gpa, "char_right_select", .{ .key = .right, .shift = true,  .alt = false });

                try self.keybinds.putNoClobber(self.gpa, "char_up",          .{ .key = .up,   .shift = false, .command = false });
                try self.keybinds.putNoClobber(self.gpa, "char_down",        .{ .key = .down, .shift = false, .command = false });
                try self.keybinds.putNoClobber(self.gpa, "char_up_select",   .{ .key = .up,   .shift = true,  .command = false });
                try self.keybinds.putNoClobber(self.gpa, "char_down_select", .{ .key = .down, .shift = true,  .command = false });

                try self.keybinds.putNoClobber(self.gpa, "delete_prev_word", .{ .key = .backspace, .alt = true });
                try self.keybinds.putNoClobber(self.gpa, "delete_next_word", .{ .key = .delete,    .alt = true });
                // zig fmt: on
        },
    }

    const winSize = self.backend.windowSize();
    const pxSize = self.backend.pixelSize();
    const sysContentScale = self.backend.contentScale();

    // Even on hidpi screens I see slight flattening of the sides of glyphs
    // when snap_to_pixels is false, so we are going to default on for now.
    //const total_scale = self.content_scale * pxSize.w / winSize.w;
    //if (total_scale >= 2.0) {
    //    self.snap_to_pixels = false;
    //}

    log.info("window logical {f} pixels {f} pixel scale {d} initial content scale {d} snap_to_pixels {any} accesskit {any}\n", .{ winSize, pxSize, pxSize.w / winSize.w, sysContentScale, self.snap_to_pixels, dvui.accesskit_enabled });

    errdefer self.deinit();

    self.subwindows.focused_id = self.data().id;
    self.frame_time_ns = 1;

    if (dvui.useFreeType) {
        dvui.Font.FreeType.intToError(c.FT_Init_FreeType(&dvui.ft2lib)) catch |err| {
            dvui.log.err("freetype error {any} trying to init freetype library\n", .{err});
            return error.freetypeError;
        };
    }

    return self;
}