a modern tui library written in zig
at main 3.4 kB view raw
1const std = @import("std"); 2const vaxis = @import("../main.zig"); 3 4const Allocator = std.mem.Allocator; 5 6const vxfw = @import("vxfw.zig"); 7 8const SizedBox = @This(); 9 10child: vxfw.Widget, 11size: vxfw.Size, 12 13pub fn widget(self: *const SizedBox) vxfw.Widget { 14 return .{ 15 .userdata = @constCast(self), 16 .drawFn = typeErasedDrawFn, 17 }; 18} 19 20fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) Allocator.Error!vxfw.Surface { 21 const self: *const SizedBox = @ptrCast(@alignCast(ptr)); 22 const max: vxfw.MaxSize = .{ 23 .width = if (ctx.max.width) |max_w| max_w else self.size.width, 24 .height = if (ctx.max.height) |max_h| max_h else self.size.height, 25 }; 26 const min: vxfw.Size = .{ 27 .width = @min(@max(ctx.min.width, self.size.width), max.width.?), 28 .height = @min(@max(ctx.min.height, self.size.height), max.height.?), 29 }; 30 return self.child.draw(ctx.withConstraints(min, max)); 31} 32 33test SizedBox { 34 // Create a test widget that saves the constraints it was given 35 const TestWidget = struct { 36 min: vxfw.Size, 37 max: vxfw.MaxSize, 38 39 pub fn widget(self: *@This()) vxfw.Widget { 40 return .{ 41 .userdata = self, 42 .drawFn = @This().typeErasedDrawFn, 43 }; 44 } 45 46 fn typeErasedDrawFn(ptr: *anyopaque, ctx: vxfw.DrawContext) std.mem.Allocator.Error!vxfw.Surface { 47 const self: *@This() = @ptrCast(@alignCast(ptr)); 48 self.min = ctx.min; 49 self.max = ctx.max; 50 return .{ 51 .size = ctx.min, 52 .widget = self.widget(), 53 .buffer = &.{}, 54 .children = &.{}, 55 }; 56 } 57 }; 58 59 // Boiler plate draw context 60 var arena = std.heap.ArenaAllocator.init(std.testing.allocator); 61 defer arena.deinit(); 62 vxfw.DrawContext.init(.unicode); 63 64 var draw_ctx: vxfw.DrawContext = .{ 65 .arena = arena.allocator(), 66 .min = .{}, 67 .max = .{ .width = 16, .height = 16 }, 68 .cell_size = .{ .width = 10, .height = 20 }, 69 }; 70 71 var test_widget: TestWidget = .{ .min = .{}, .max = .{} }; 72 73 // SizedBox tries to draw the child widget at the specified size. It will shrink to fit within 74 // constraints 75 const sized_box: SizedBox = .{ 76 .child = test_widget.widget(), 77 .size = .{ .width = 10, .height = 10 }, 78 }; 79 80 const box_widget = sized_box.widget(); 81 { 82 const result = try box_widget.draw(draw_ctx); 83 // The sized box is smaller than the constraints, so we should be the desired size 84 try std.testing.expectEqual(sized_box.size, result.size); 85 } 86 87 { 88 draw_ctx.max.height = 8; 89 const result = try box_widget.draw(draw_ctx); 90 // The sized box is smaller than the constraints, so we should be that size 91 try std.testing.expectEqual(@as(vxfw.Size, .{ .width = 10, .height = 8 }), result.size); 92 } 93 94 draw_ctx.max.width = 8; 95 _ = try box_widget.draw(draw_ctx); 96 // The sized box is smaller than the constraints, so we should be that size 97 try std.testing.expectEqual(@as(vxfw.Size, .{ .width = 8, .height = 8 }), test_widget.min); 98 try std.testing.expectEqual(@as(vxfw.Size, .{ .width = 8, .height = 8 }), test_widget.max.size()); 99} 100 101test "refAllDecls" { 102 std.testing.refAllDecls(@This()); 103}