init
It's expected to call this when self is undefined
Parameters
- self:*CacheWidget
- *CacheWidget
- src:std.builtin.SourceLocation
- std.builtin.SourceLocation
- init_opts:InitOptions
- InitOptions
- opts:Options
- Options
Source
Implementation
pub fn init(self: *CacheWidget, src: std.builtin.SourceLocation, init_opts: InitOptions, opts: Options) void {
const defaults = Options{ .name = "Cache" };
self.* = .{
.wd = .init(src, .{}, defaults.override(opts)),
.init_opts = init_opts,
// SAFETY: Set bellow
.hash = undefined,
// SAFETY: Set bellow
.tex_uv = undefined,
.refresh_prev_value = dvui.currentWindow().extra_frames_needed,
};
self.hash = self.data().id.update("_tex").asU64();
self.tex_uv = dvui.dataGet(null, self.data().id, "_tex_uv", Size) orelse .{};
dvui.currentWindow().extra_frames_needed = 0;
if (dvui.dataGet(null, self.data().id, "_unsupported", bool) orelse false) self.state = .unsupported;
dvui.parentSet(self.widget());
self.data().register();
self.data().borderAndBackground(.{});
if (self.init_opts.invalidate) {
if (dvui.textureGetCached(self.hash)) |t| {
// if we had a texture, show it this frame because our contents needs a frame to get sizing
self.drawCachedTexture(t);
dvui.textureInvalidateCache(self.hash);
// now we've shown the texture, so prevent any widgets from drawing on top of it this frame
// - can happen if some widgets precalculate their size (like label)
self.old_clip = dvui.clip(.{});
}
}
if (self.state != .ok) return;
if (dvui.textureGetCached(self.hash)) |t| {
// successful cache, draw texture and enforce min size
self.drawCachedTexture(t);
const tex_size: dvui.Size = .{ .w = @floatFromInt(t.width), .h = @floatFromInt(t.height) };
const rs = self.data().rectScale();
self.data().minSizeMax(self.data().options.padSize(tex_size.scale(1.0 / rs.s, dvui.Size)));
} else {
// we need to cache, but only do it if we didn't have any refreshes from last frame
if (dvui.dataGet(null, self.data().id, "_cache_now", bool) orelse false) {
const rs = self.data().contentRectScale();
const w: u32 = @ceil(rs.r.w);
const h: u32 = @ceil(rs.r.h);
self.tex_uv = .{ .w = rs.r.w / @ceil(rs.r.w), .h = rs.r.h / @ceil(rs.r.h) };
self.caching_tex = dvui.textureCreateTarget(.{ .width = w, .height = h }) catch |err| blk: switch (err) {
error.TextureCreate, error.NotImplemented => {
self.state = .texture_create_error;
if (dvui.dataGet(null, self.data().id, "_texture_create_error", bool) orelse false) {
// indicate that texture failed last frame to prevent backends that always return errors from forever refreshing
dvui.dataSet(null, self.data().id, "_texture_create_error", true);
}
break :blk null;
},
else => {
dvui.logError(@src(), err, "Could not create cache texture", .{});
break :blk null;
},
};
if (self.caching_tex) |tex| {
var offset = rs.r.topLeft();
if (dvui.snapToPixels()) {
offset.x = @round(offset.x);
offset.y = @round(offset.y);
}
self.old_target = dvui.renderTarget(.{ .texture = tex, .offset = offset });
// clip to just us, even if we are off screen
self.old_clip = dvui.clipGet();
dvui.clipSet(rs.r);
} else if (self.state != .texture_create_error) {
// `textureCreateTarget` returned null, indicating render target are unsupported
dvui.dataSet(null, self.data().id, "_unsupported", true);
}
}
}
}