a modern tui library written in zig
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}