DVUI

init

It's expected to call this when self is undefined

Parameters

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

Source

Implementation

#
pub fn init(self: *PlotWidget, src: std.builtin.SourceLocation, init_opts: InitOptions, opts: Options) void {
    self.* = .{
        .src = src,
        .opts = opts,
        .init_options = init_opts,
    };

    self.box.init(self.src, .{ .dir = .vertical }, defaults.override(self.opts));
    if (self.init_options.x_axis) |xa| {
        self.x_axis = xa;
    } else {
        if (dvui.dataGet(null, self.box.data().id, "_x_axis", Axis)) |xaxis| {
            self.x_axis_store = xaxis;
        }
        self.x_axis = &self.x_axis_store;
    }

    if (self.init_options.y_axis) |ya| {
        self.y_axis = ya;
    } else {
        if (dvui.dataGet(null, self.box.data().id, "_y_axis", Axis)) |yaxis| {
            self.y_axis_store = yaxis;
        }
        self.y_axis = &self.y_axis_store;
    }

    self.box.drawBackground();

    if (self.init_options.title) |title| {
        dvui.label(@src(), "{s}", .{title}, .{ .gravity_x = 0.5, .font = opts.themeGet().font_title });
    }

    const tick_font = opts.themeGet().font_body.larger(-3);

    var yticks = self.y_axis.getTicks(dvui.currentWindow().lifo()) catch Axis.Ticks.empty;
    defer yticks.deinit(dvui.currentWindow().lifo());

    var xticks = self.x_axis.getTicks(dvui.currentWindow().lifo()) catch Axis.Ticks.empty;
    defer xticks.deinit(dvui.currentWindow().lifo());

    const y_axis_tick_width: f32 = blk: {
        if (self.y_axis.name == null) break :blk 0;
        var max_width: f32 = 0;

        for (yticks.values) |ytick| {
            const tick_str = self.y_axis.formatTick(dvui.currentWindow().lifo(), ytick) catch "";
            defer dvui.currentWindow().lifo().free(tick_str);
            max_width = @max(max_width, tick_font.textSize(tick_str).w);
        }

        break :blk max_width;
    };

    const x_axis_last_tick_width: f32 = blk: {
        if (xticks.values.len == 0) break :blk 0;
        const str = self.x_axis.formatTick(
            dvui.currentWindow().lifo(),
            xticks.values[xticks.values.len - 1],
        ) catch "";
        defer dvui.currentWindow().lifo().free(str);

        break :blk tick_font.sizeM(@as(f32, @floatFromInt(str.len)), 1).w;
    };

    var hbox1 = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .both });

    // y axis label
    var yaxis = dvui.box(@src(), .{ .dir = .horizontal }, .{
        .expand = .vertical,
        .min_size_content = .{ .w = y_axis_tick_width },
        .padding = dvui.Rect{ .w = y_axis_tick_width },
    });
    var yaxis_rect = yaxis.data().rect;
    if (self.y_axis.name) |yname| {
        if (yname.len > 0) {
            dvui.label(@src(), "{s}", .{yname}, .{ .gravity_y = 0.5, .rotation = std.math.pi * 1.5 });
        }
    }
    yaxis.deinit();

    // x axis padding
    if (self.x_axis.name) |_| {
        var xaxis_padding = dvui.box(@src(), .{ .dir = .horizontal }, .{
            .gravity_x = 1.0,
            .expand = .vertical,
            .min_size_content = .{ .w = x_axis_last_tick_width / 2 },
        });
        xaxis_padding.deinit();
    }

    // data area
    var data_box = dvui.box(@src(), .{ .dir = .horizontal }, .{
        .expand = .both,
        .role = .image,
        .label = .{ .text = self.init_options.title orelse "" },
    });

    // mouse hover
    if (self.init_options.mouse_hover) {
        const evts = dvui.events();
        for (evts) |*e| {
            if (!dvui.eventMatchSimple(e, data_box.data()))
                continue;

            switch (e.evt) {
                .mouse => |me| {
                    if (me.action == .position) {
                        dvui.cursorSet(.arrow);
                        self.mouse_point = me.p;
                    }
                },
                else => {},
            }
        }
    }

    yaxis_rect.h = data_box.data().rect.h;
    self.data_rs = data_box.data().contentRectScale();
    data_box.deinit();

    const bt: f32 = self.init_options.border_thick orelse 0.0;
    const bc: dvui.Color = self.init_options.spine_color orelse self.box.data().options.color(.text);

    const pad = 2 * self.data_rs.s;

    hbox1.deinit();

    var hbox2 = dvui.box(@src(), .{ .dir = .horizontal }, .{ .expand = .horizontal });

    // bottom left corner under y axis
    _ = dvui.spacer(@src(), .{ .min_size_content = .width(yaxis_rect.w), .expand = .vertical });

    var x_tick_height: f32 = 0;
    if (self.x_axis.name) |_| {
        if (self.x_axis.min != null or self.x_axis.max != null) {
            x_tick_height = tick_font.sizeM(1, 1).h;
        }
    }

    // x axis label
    var xaxis = dvui.box(@src(), .{}, .{
        .gravity_y = 1.0,
        .expand = .horizontal,
        .min_size_content = .{ .h = x_tick_height * 3 },
    });
    if (self.x_axis.name) |xname| {
        if (xname.len > 0) {
            dvui.label(@src(), "{s}", .{xname}, .{ .gravity_x = 0.5, .gravity_y = 1.0 });
        }
    }
    xaxis.deinit();

    _ = dvui.spacer(@src(), .{
        .min_size_content = .width(x_axis_last_tick_width / 2),
        .expand = .vertical,
    });

    hbox2.deinit();

    const tick_line_len = 5;
    const subtick_line_len = 3;

    // y axis ticks
    if (self.y_axis.name) |_| {
        for (yticks.values) |ytick| {
            const tick: Data = .{ .x = self.x_axis.min orelse 0, .y = ytick };
            const tick_str = self.y_axis.formatTick(dvui.currentWindow().lifo(), ytick) catch "";
            defer dvui.currentWindow().lifo().free(tick_str);
            const tick_str_size = tick_font.textSize(tick_str).scale(self.data_rs.s, Size.Physical);

            const tick_p = self.dataToScreen(tick);
            self.drawTickline(
                .vertical,
                tick_p,
                tick_line_len,
                self.y_axis.ticks.side,
                bc,
                self.y_axis.gridline_color,
            );

            var tick_label_p = tick_p;
            tick_label_p.x -= tick_str_size.w + pad;
            tick_label_p.y -= tick_str_size.h / 2;
            const tick_rs: RectScale = .{ .r = Rect.Physical.fromPoint(tick_label_p).toSize(tick_str_size), .s = self.data_rs.s };

            dvui.renderText(.{
                .font = tick_font,
                .text = tick_str,
                .rs = tick_rs,
                .color = self.box.data().options.color(.text),
            }) catch |err| {
                dvui.logError(@src(), err, "y axis tick text for {d}", .{ytick});
            };
        }

        for (yticks.subticks) |ytick| {
            const tick: Data = .{ .x = self.x_axis.min orelse 0, .y = ytick };
            const tick_p = self.dataToScreen(tick);
            self.drawTickline(
                .vertical,
                tick_p,
                subtick_line_len,
                self.y_axis.ticks.side,
                bc,
                self.y_axis.subtick_gridline_color,
            );
        }
    }

    // x axis ticks
    if (self.x_axis.name) |_| {
        for (xticks.values) |xtick| {
            const tick: Data = .{ .x = xtick, .y = self.y_axis.min orelse 0 };
            const tick_str = self.x_axis.formatTick(dvui.currentWindow().lifo(), xtick) catch "";
            defer dvui.currentWindow().lifo().free(tick_str);
            const tick_str_size = tick_font.textSize(tick_str).scale(self.data_rs.s, Size.Physical);

            const tick_p = self.dataToScreen(tick);
            self.drawTickline(
                .horizontal,
                tick_p,
                tick_line_len,
                self.x_axis.ticks.side,
                bc,
                self.x_axis.gridline_color,
            );

            var tick_label_p = tick_p;
            tick_label_p.x -= tick_str_size.w / 2;
            tick_label_p.y += pad;
            const tick_rs: RectScale = .{ .r = Rect.Physical.fromPoint(tick_label_p).toSize(tick_str_size), .s = self.data_rs.s };

            dvui.renderText(.{
                .font = tick_font,
                .text = tick_str,
                .rs = tick_rs,
                .color = self.box.data().options.color(.text),
            }) catch |err| {
                dvui.logError(@src(), err, "x axis tick text for {d}", .{xtick});
            };
        }

        for (xticks.subticks) |xtick| {
            const tick: Data = .{ .x = xtick, .y = self.y_axis.min orelse 0 };
            const tick_p = self.dataToScreen(tick);
            self.drawTickline(
                .horizontal,
                tick_p,
                subtick_line_len,
                self.x_axis.ticks.side,
                bc,
                self.x_axis.subtick_gridline_color,
            );
        }
    }

    if (bt > 0) {
        self.data_rs.r.stroke(.{}, .{ .thickness = bt * self.data_rs.s, .color = bc });
    }

    self.old_clip = dvui.clip(self.data_rs.r);
}