mod: use allocators for Layout and Widget types

This commit is contained in:
2024-11-19 22:56:37 +01:00
parent cd12fb12e6
commit 1c703a196a
18 changed files with 264 additions and 153 deletions

View File

@@ -100,7 +100,8 @@ pub fn build(b: *std.Build) void {
.target = target,
.optimize = optimize,
});
lib_unit_tests.root_module.addImport("zg", zg.module("code_point"));
lib_unit_tests.root_module.addImport("interface", interface.module("interface"));
lib_unit_tests.root_module.addImport("code_point", zg.module("code_point"));
const run_lib_unit_tests = b.addRunArtifact(lib_unit_tests);

View File

@@ -30,19 +30,19 @@ pub fn main() !void {
// TODO: when not running fullscreen, the application needs to screen down accordingly to display the contents
// -> size hint how much should it use?
var layout = Layout.createFrom(Layout.HContainer.init(allocator, .{
var layout = Layout.createFrom(allocator, Layout.HContainer.init(allocator, .{
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
15,
},
.{
Layout.createFrom(Layout.VContainer.init(allocator, .{
Layout.createFrom(allocator, Layout.VContainer.init(allocator, .{
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
25,
},
.{
Widget.createFrom(blk: {
Widget.createFrom(allocator, blk: {
const file = try std.fs.cwd().openFile("./src/app.zig", .{});
defer file.close();
const widget = Widget.RawText.init(allocator, file);
@@ -51,14 +51,14 @@ pub fn main() !void {
50,
},
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
25,
},
})),
70,
},
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
15,
},
}));

View File

@@ -31,14 +31,14 @@ pub fn main() !void {
// TODO: when not running fullscreen, the application needs to screen down accordingly to display the contents
// -> size hint how much should it use?
var layout = Layout.createFrom(Layout.VContainer.init(allocator, .{
var layout = Layout.createFrom(allocator, Layout.VContainer.init(allocator, .{
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
45,
},
.{
Layout.createFrom(Layout.Framing.init(allocator, .{}, .{
.widget = Widget.createFrom(Widget.Text.init(allocator, .center, &[_]Cell{
Layout.createFrom(allocator, Layout.Framing.init(allocator, .{}, .{
.widget = Widget.createFrom(allocator, Widget.Text.init(allocator, .center, &[_]Cell{
.{ .content = "Press " },
.{ .content = "Ctrl+n", .style = .{ .fg = .{ .index = 6 } } },
.{ .content = " to launch $EDITOR" },
@@ -47,7 +47,7 @@ pub fn main() !void {
10,
},
.{
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
45,
},
}));

View File

@@ -30,10 +30,10 @@ pub fn main() !void {
// TODO: when not running fullscreen, the application needs to screen down accordingly to display the contents
// -> size hint how much should it use?
var layout = Layout.createFrom(Layout.Padding.init(allocator, .{
var layout = Layout.createFrom(allocator, Layout.Padding.init(allocator, .{
.padding = 15,
}, .{
.layout = Layout.createFrom(Layout.Framing.init(allocator, .{
.layout = Layout.createFrom(allocator, Layout.Framing.init(allocator, .{
.style = .{
.fg = .{
.index = 6,
@@ -49,13 +49,13 @@ pub fn main() !void {
},
},
}, .{
.layout = Layout.createFrom(Layout.Margin.init(
.layout = Layout.createFrom(allocator, Layout.Margin.init(
allocator,
.{
.margin = 10,
},
.{
.widget = Widget.createFrom(blk: {
.widget = Widget.createFrom(allocator, blk: {
const file = try std.fs.cwd().openFile("./examples/padding.zig", .{});
defer file.close();
const widget = Widget.RawText.init(allocator, file);

View File

@@ -30,7 +30,7 @@ pub fn main() !void {
// TODO: when not running fullscreen, the application needs to screen down accordingly to display the contents
// -> size hint how much should it use?
var layout = Layout.createFrom(Layout.Framing.init(allocator, .{
var layout = Layout.createFrom(allocator, Layout.Framing.init(allocator, .{
.style = .{
.fg = .{
.index = 6,
@@ -46,9 +46,9 @@ pub fn main() !void {
},
},
}, .{
.layout = Layout.createFrom(Layout.HStack.init(allocator, .{
Widget.createFrom(Widget.Spacer.init(allocator)),
Layout.createFrom(Layout.Framing.init(
.layout = Layout.createFrom(allocator, Layout.HStack.init(allocator, .{
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
Layout.createFrom(allocator, Layout.Framing.init(
allocator,
.{
.style = .{
@@ -67,18 +67,18 @@ pub fn main() !void {
},
},
.{
.layout = Layout.createFrom(Layout.Margin.init(allocator, .{
.layout = Layout.createFrom(allocator, Layout.Margin.init(allocator, .{
.margin = 10,
}, .{
.layout = Layout.createFrom(Layout.VStack.init(allocator, .{
Widget.createFrom(blk: {
.layout = Layout.createFrom(allocator, Layout.VStack.init(allocator, .{
Widget.createFrom(allocator, blk: {
const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
defer file.close();
const widget = Widget.RawText.init(allocator, file);
break :blk widget;
}),
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(blk: {
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, blk: {
const file = try std.fs.cwd().openFile("./examples/stack.zig", .{});
defer file.close();
const widget = Widget.RawText.init(allocator, file);
@@ -88,7 +88,7 @@ pub fn main() !void {
})),
},
)),
Widget.createFrom(Widget.Spacer.init(allocator)),
Widget.createFrom(allocator, Widget.Spacer.init(allocator)),
})),
}));
defer layout.deinit();

102
examples/tui.zig Normal file
View File

@@ -0,0 +1,102 @@
const std = @import("std");
const zterm = @import("zterm");
const App = zterm.App(
union(enum) {},
zterm.Renderer.Direct,
true,
);
const Cell = zterm.Cell;
const Key = zterm.Key;
const Layout = App.Layout;
const Widget = App.Widget;
const log = std.log.scoped(.tui);
pub fn main() !void {
errdefer |err| log.err("Application Error: {any}", .{err});
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
var app: App = .{};
var renderer: App.Renderer = .{};
// FIXME: the layout creates an 'incorrect alignment'?
var layout = Layout.createFrom(allocator, Layout.VContainer.init(allocator, .{
.{
Layout.createFrom(allocator, Layout.Framing.init(allocator, .{
.title = .{
.str = "Welcome to my terminal website",
.style = .{
.ul = .{ .index = 6 },
.ul_style = .single,
},
},
}, .{
.layout = Layout.createFrom(allocator, Layout.HContainer.init(allocator, .{
.{
Widget.createFrom(allocator, Widget.Text.init(allocator, .left, &[1]Cell{
.{ .content = "Yves Biener", .style = .{ .bold = true } },
})),
25,
},
.{
Widget.createFrom(allocator, Widget.Text.init(allocator, .center, &[1]Cell{
.{ .content = "File name", .style = .{ .bold = true } },
})),
50,
},
.{
Widget.createFrom(allocator, Widget.Text.init(allocator, .right, &[1]Cell{
.{ .content = "Contact", .style = .{ .bold = true, .ul_style = .single } },
})),
25,
},
})),
})),
10,
},
.{
Layout.createFrom(allocator, Layout.Margin.init(allocator, .{ .left = 15, .right = 15 }, .{
.widget = Widget.createFrom(allocator, Widget.Text.init(allocator, .default, &[1]Cell{
.{ .content = "Does this change anything?", .style = .{ .bold = true, .ul_style = .single } },
})),
})),
90,
},
}));
defer layout.deinit();
try app.start();
defer app.stop() catch unreachable;
// App.Event loop
while (true) {
const event = app.nextEvent();
switch (event) {
.quit => break,
.resize => |size| {
renderer.resize(size);
},
.key => |key| {
// ctrl+c to quit
if (Key.matches(key, .{ .cp = 'c', .mod = .{ .ctrl = true } })) {
app.quit();
}
},
.err => |err| {
log.err("Received {any} with message: {s}", .{ err.err, err.msg });
},
}
const events = try layout.handle(event);
for (events.items) |e| {
app.postEvent(e);
}
try layout.render(&renderer);
}
}

View File

@@ -22,8 +22,8 @@ pub fn Layout(comptime Event: type, comptime Renderer: type) type {
const Type = struct {
const LayoutType = @This();
const Element = union(enum) {
layout: LayoutType,
widget: @import("widget.zig").Widget(Event, Renderer),
layout: *LayoutType,
widget: *@import("widget.zig").Widget(Event, Renderer),
};
pub const Interface = @import("interface").Interface(.{
.handle = fn (anytype, Event) anyerror!*Events,
@@ -37,6 +37,7 @@ pub fn Layout(comptime Event: type, comptime Renderer: type) type {
deinit: *const fn (this: *LayoutType) void,
};
allocator: std.mem.Allocator = undefined,
object: *anyopaque = undefined,
vtable: *const VTable = undefined,
@@ -52,34 +53,36 @@ pub fn Layout(comptime Event: type, comptime Renderer: type) type {
pub fn deinit(this: *LayoutType) void {
this.vtable.deinit(this);
this.allocator.destroy(this);
}
pub fn createFrom(object: anytype) LayoutType {
return LayoutType{
.object = @ptrCast(@alignCast(object)),
.vtable = &.{
pub fn createFrom(allocator: std.mem.Allocator, object: anytype) *LayoutType {
const layout = allocator.create(LayoutType) catch @panic("layout.zig: out of memory");
layout.allocator = allocator;
layout.object = @ptrCast(object);
layout.vtable = &.{
.handle = struct {
// Handle the provided `Event` for this `Layout`.
fn handle(this: *LayoutType, event: Event) !*Events {
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
return try layout.handle(event);
const layout_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
return try layout_ptr.handle(event);
}
}.handle,
.render = struct {
// Render the contents of this `Layout`.
fn render(this: *LayoutType, renderer: *Renderer) !void {
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
try layout.render(renderer);
const layout_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
try layout_ptr.render(renderer);
}
}.render,
.deinit = struct {
fn deinit(this: *LayoutType) void {
const layout: @TypeOf(object) = @ptrCast(@alignCast(this.object));
layout.deinit();
const layout_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
layout_ptr.deinit();
}
}.deinit,
},
};
return layout;
}
// import and export of `Layout` implementations

View File

@@ -51,7 +51,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
pub fn init(allocator: std.mem.Allocator, config: Config, element: Element) *@This() {
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("Framing.zig: out of memory");
layout.allocator = allocator;
layout.config = config;
layout.element = element;
@@ -62,10 +62,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn deinit(this: *@This()) void {
this.events.deinit();
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -97,11 +97,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
},
};
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -110,11 +110,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
},
else => {
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -185,10 +185,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -49,7 +49,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
comptime var total_size = 0;
const fields_info = args_type_info.@"struct".fields;
var containers = Containers.initCapacity(allocator, fields_info.len) catch @panic("OOM");
var containers = Containers.initCapacity(allocator, fields_info.len) catch @panic("HContainer.zig: out of memory");
inline for (comptime fields_info) |field| {
const child = @field(children, field.name);
const ChildType = @TypeOf(child);
@@ -88,7 +88,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
@compileError("nested child: " ++ field.name ++ " is not of type " ++ @typeName(WidgetType) ++ " or " ++ @typeName(LayoutType) ++ " but " ++ @typeName(ChildType));
}
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("HContainer.zig: out of memory");
layout.allocator = allocator;
layout.containers = containers;
layout.events = Events.init(allocator);
@@ -99,10 +99,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
this.events.deinit();
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -140,11 +140,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
offset += cols;
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -155,11 +155,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
else => {
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -174,10 +174,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn render(this: *@This(), renderer: *Renderer) !void {
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -42,7 +42,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
}
const fields_info = args_type_info.@"struct".fields;
var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("OOM");
var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("HStack.zig: out of memory");
inline for (comptime fields_info) |field| {
const child = @field(children, field.name);
const ChildType = @TypeOf(child);
@@ -56,7 +56,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
@compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(WidgetType) ++ " or " ++ @typeName(LayoutType) ++ " but " ++ @typeName(ChildType));
}
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("HStack.zig: out of memory");
layout.allocator = allocator;
layout.elements = elements;
layout.events = Events.init(allocator);
@@ -67,10 +67,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
this.events.deinit();
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -115,11 +115,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
offset += cols;
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -130,11 +130,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
else => {
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -149,10 +149,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn render(this: *@This(), renderer: *Renderer) !void {
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -34,7 +34,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
config: Config = undefined,
const Config = struct {
margin: ?u8 = undefined,
margin: ?u8 = null,
left: u8 = 0,
right: u8 = 0,
top: u8 = 0,
@@ -48,7 +48,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
std.debug.assert(config.left + config.right < 100);
std.debug.assert(config.top + config.bottom < 100);
}
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("Margin.zig: out of memory");
layout.allocator = allocator;
layout.config = config;
layout.element = element;
@@ -59,10 +59,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn deinit(this: *@This()) void {
this.events.deinit();
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -116,11 +116,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
// adjust size according to the containing elements
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -129,11 +129,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
},
else => {
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -151,10 +151,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -34,7 +34,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
config: Config = undefined,
const Config = struct {
padding: ?u16 = undefined,
padding: ?u16 = null,
left: u16 = 0,
right: u16 = 0,
top: u16 = 0,
@@ -42,7 +42,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
pub fn init(allocator: std.mem.Allocator, config: Config, element: Element) *@This() {
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("Padding.zig: out of memory");
layout.allocator = allocator;
layout.config = config;
layout.element = element;
@@ -53,10 +53,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn deinit(this: *@This()) void {
this.events.deinit();
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -104,11 +104,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
// adjust size according to the containing elements
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -117,11 +117,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
},
else => {
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -139,10 +139,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
switch ((&this.element).*) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -49,7 +49,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
comptime var total_size = 0;
const fields_info = args_type_info.@"struct".fields;
var containers = Containers.initCapacity(allocator, fields_info.len) catch @panic("OOM");
var containers = Containers.initCapacity(allocator, fields_info.len) catch @panic("VContainer.zig: out of memory");
inline for (comptime fields_info) |field| {
const child = @field(children, field.name);
const ChildType = @TypeOf(child);
@@ -88,7 +88,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
@compileError("nested child: " ++ field.name ++ " is not of type " ++ @typeName(WidgetType) ++ " or " ++ @typeName(LayoutType) ++ " but " ++ @typeName(ChildType));
}
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("VContainer.zig: out of memory");
layout.allocator = allocator;
layout.containers = containers;
layout.events = Events.init(allocator);
@@ -99,10 +99,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
this.events.deinit();
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -140,11 +140,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
offset += rows;
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -155,11 +155,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
else => {
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -174,10 +174,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn render(this: *@This(), renderer: *Renderer) !void {
for (this.containers.items) |*container| {
switch (container.element) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -42,7 +42,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
@compileError("expected tuple or struct argument, found " ++ @typeName(ArgsType));
}
const fields_info = args_type_info.@"struct".fields;
var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("OOM");
var elements = Elements.initCapacity(allocator, fields_info.len) catch @panic("VStack.zig: out of memory");
inline for (comptime fields_info) |field| {
const child = @field(children, field.name);
const ChildType = @TypeOf(child);
@@ -56,7 +56,7 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
}
@compileError("child: " ++ field.name ++ " is not of type " ++ @typeName(WidgetType) ++ " or " ++ @typeName(LayoutType) ++ " but " ++ @typeName(ChildType));
}
const layout = allocator.create(@This()) catch @panic("OOM");
const layout = allocator.create(@This()) catch @panic("VStack.zig: out of memory");
layout.allocator = allocator;
layout.elements = elements;
layout.events = Events.init(allocator);
@@ -67,10 +67,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
this.events.deinit();
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
layout.deinit();
},
.widget => |*widget| {
.widget => |widget| {
widget.deinit();
},
}
@@ -114,11 +114,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
};
offset += rows;
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(sub_event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(sub_event)) |e| {
try this.events.append(e);
}
@@ -129,11 +129,11 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
else => {
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
const events = try layout.handle(event);
try this.events.appendSlice(events.items);
},
.widget => |*widget| {
.widget => |widget| {
if (widget.handle(event)) |e| {
try this.events.append(e);
}
@@ -148,10 +148,10 @@ pub fn Layout(comptime Event: type, comptime Element: type, comptime Renderer: t
pub fn render(this: *@This(), renderer: *Renderer) !void {
for (this.elements.items) |*element| {
switch (element.*) {
.layout => |*layout| {
.layout => |layout| {
try layout.render(renderer);
},
.widget => |*widget| {
.widget => |widget| {
try widget.render(renderer);
},
}

View File

@@ -10,6 +10,7 @@
//!
//! When `Widget.render` is called the provided `Renderer` type is expected
//! which handles how contents are rendered for a given widget.
const std = @import("std");
const isTaggedUnion = @import("event.zig").isTaggedUnion;
const log = @import("std").log.scoped(.widget);
@@ -32,6 +33,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
deinit: *const fn (this: *WidgetType) void,
};
allocator: std.mem.Allocator = undefined,
object: *anyopaque = undefined,
vtable: *const VTable = undefined,
@@ -58,34 +60,36 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
pub fn deinit(this: *WidgetType) void {
this.vtable.deinit(this);
this.allocator.destroy(this);
}
pub fn createFrom(object: anytype) WidgetType {
return WidgetType{
.object = @ptrCast(@alignCast(object)),
.vtable = &.{
pub fn createFrom(allocator: std.mem.Allocator, object: anytype) *WidgetType {
const widget = allocator.create(WidgetType) catch @panic("widget.zig: out of memory");
widget.allocator = allocator;
widget.object = @ptrCast(object);
widget.vtable = &.{
.handle = struct {
// Handle the provided `Event` for this `Widget`.
fn handle(this: *WidgetType, event: Event) ?Event {
const widget: @TypeOf(object) = @ptrCast(@alignCast(this.object));
return widget.handle(event);
const widget_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
return widget_ptr.handle(event);
}
}.handle,
.render = struct {
// Return the entire content of this `Widget`.
fn render(this: *WidgetType, renderer: *Renderer) !void {
const widget: @TypeOf(object) = @ptrCast(@alignCast(this.object));
try widget.render(renderer);
const widget_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
try widget_ptr.render(renderer);
}
}.render,
.deinit = struct {
fn deinit(this: *WidgetType) void {
const widget: @TypeOf(object) = @ptrCast(@alignCast(this.object));
widget.deinit();
const widget_ptr: @TypeOf(object) = @ptrCast(@alignCast(this.object));
widget_ptr.deinit();
}
}.deinit,
},
};
return widget;
}
// import and export of `Widget` implementations

View File

@@ -26,15 +26,16 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
var line_index = std.ArrayList(usize).init(allocator);
file.reader().readAllArrayList(&contents, std.math.maxInt(usize)) catch {};
line_index.append(0) catch {};
for (contents.items, 0..) |item, i| {
for (contents.items, 1..) |item, i| {
if (item == '\n') {
line_index.append(i + 1) catch {};
line_index.append(i) catch {};
}
}
const widget = allocator.create(@This()) catch @panic("OOM");
const widget = allocator.create(@This()) catch @panic("RawText.zig: out of memory");
widget.allocator = allocator;
widget.contents = contents;
widget.line_index = line_index;
widget.line = 0;
return widget;
}

View File

@@ -16,7 +16,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
size_changed: bool = false,
pub fn init(allocator: std.mem.Allocator) *@This() {
const widget = allocator.create(@This()) catch @panic("OOM");
const widget = allocator.create(@This()) catch @panic("Spacer.zig: out of memory");
widget.allocator = allocator;
return widget;
}

View File

@@ -28,7 +28,7 @@ pub fn Widget(comptime Event: type, comptime Renderer: type) type {
};
pub fn init(allocator: std.mem.Allocator, alignment: Alignment, contents: []const Cell) *@This() {
const widget = allocator.create(@This()) catch @panic("OOM");
const widget = allocator.create(@This()) catch @panic("Text.zig: out of memory");
widget.allocator = allocator;
widget.alignment = alignment;
widget.contents = contents;