this repo has no description
at main 162 lines 4.6 kB view raw
1const std = @import("std"); 2const builtin = @import("builtin"); 3 4const vaxis = @import("vaxis"); 5const vxfw = vaxis.vxfw; 6 7const Allocator = std.mem.Allocator; 8 9var debug_allocator: std.heap.DebugAllocator(.{}) = .init; 10 11const Column = struct { 12 children: []vxfw.Widget, 13 14 pub fn widget(self: *Model) vxfw.Widget { 15 return .{ 16 .userdata = self, 17 .eventHandler = @This().typeErasedEventHandler, 18 .drawFn = @This().typeErasedDrawFn, 19 }; 20 } 21 22 fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void { 23 _ = ptr; 24 _ = ctx; 25 _ = event; 26 } 27 28 fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 29 const self: *@This() = @ptrCast(@alignCast(ptr)); 30 31 const max_size = ctx.max.size(); 32 33 const children = try ctx.arena.alloc(vxfw.SubSurface, self.children.len); 34 35 for (self.children, 0..) |child, n| { 36 children[n] = child.draw(ctx); 37 } 38 39 return .{ 40 .size = max_size, 41 .widget = self.widget(), 42 .buffer = &.{}, 43 .children = children, 44 }; 45 } 46}; 47 48const Revset = struct { 49 revset_str: []const u8, 50}; 51 52const Model = struct { 53 count: u32 = 0, 54 header: Revset, 55 button: vxfw.Button, 56 57 pub fn widget(self: *Model) vxfw.Widget { 58 return .{ 59 .userdata = self, 60 .eventHandler = Model.typeErasedEventHandler, 61 .drawFn = Model.typeErasedDrawFn, 62 }; 63 } 64 65 fn typeErasedEventHandler(ptr: *anyopaque, ctx: *vxfw.EventContext, event: vxfw.Event) anyerror!void { 66 const self: *Model = @ptrCast(@alignCast(ptr)); 67 switch (event) { 68 .init => return ctx.requestFocus(self.button.widget()), 69 .key_press => |key| { 70 if (key.matches('q', .{})) { 71 ctx.quit = true; 72 return; 73 } 74 if (key.matches('c', .{ .ctrl = true })) { 75 ctx.quit = true; 76 return; 77 } 78 }, 79 .focus_in => return ctx.requestFocus(self.button.widget()), 80 else => {}, 81 } 82 } 83 84 fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 85 const self: *Model = @ptrCast(@alignCast(ptr)); 86 87 const max_size = ctx.max.size(); 88 89 const count_text = try std.fmt.allocPrint(ctx.arena, "{d}", .{self.count}); 90 const text: vxfw.Text = .{ .text = count_text }; 91 92 const header: vxfw.Text = .{ .text = self.header.revset_str }; 93 94 const header_child: vxfw.SubSurface = .{ 95 .origin = .{ .row = 0, .col = 0 }, 96 .surface = try header.draw(ctx), 97 }; 98 99 const text_child: vxfw.SubSurface = .{ 100 .origin = .{ .row = 2, .col = 0 }, 101 .surface = try text.draw(ctx), 102 }; 103 104 const button_child: vxfw.SubSurface = .{ 105 .origin = .{ .row = 4, .col = 2 }, 106 .surface = try self.button.draw(ctx.withConstraints(ctx.min, .{ .width = 16, .height = 3 })), 107 }; 108 109 const children = try ctx.arena.alloc(vxfw.SubSurface, 3); 110 111 children[0] = header_child; 112 children[1] = text_child; 113 children[2] = button_child; 114 115 return .{ 116 .size = max_size, 117 .widget = self.widget(), 118 119 .buffer = &.{}, 120 .children = children, 121 }; 122 } 123 124 fn onClick(maybe_ptr: ?*anyopaque, ctx: *vxfw.EventContext) anyerror!void { 125 const ptr = maybe_ptr orelse return; 126 const self: *Model = @ptrCast(@alignCast(ptr)); 127 self.count += 1; 128 return ctx.consumeAndRedraw(); 129 } 130}; 131 132pub fn main() !void { 133 var gpa, const is_debug = gpa: { 134 break :gpa switch (builtin.mode) { 135 .Debug, .ReleaseSafe => .{ debug_allocator, true }, 136 .ReleaseFast, .ReleaseSmall => .{ std.heap.smp_allocator, false }, 137 }; 138 }; 139 defer if (is_debug) { 140 _ = debug_allocator.deinit(); 141 }; 142 143 const allocator: Allocator = gpa.allocator(); 144 145 var app = try vxfw.App.init(allocator); 146 defer app.deinit(); 147 148 const model = try allocator.create(Model); 149 defer allocator.destroy(model); 150 151 model.* = .{ 152 .count = 0, 153 .header = .{ .revset_str = "hello" }, 154 .button = .{ 155 .label = "Click me!", 156 .onClick = Model.onClick, 157 .userdata = model, 158 }, 159 }; 160 161 try app.run(model.widget(), .{}); 162}