a modern tui library written in zig
at v0.5.0 119 lines 3.5 kB view raw
1const std = @import("std"); 2const vaxis = @import("vaxis"); 3const Cell = vaxis.Cell; 4 5const Event = union(enum) { 6 key_press: vaxis.Key, 7 winsize: vaxis.Winsize, 8}; 9 10pub const panic = vaxis.panic_handler; 11 12pub fn main() !void { 13 var gpa = std.heap.GeneralPurposeAllocator(.{}){}; 14 defer { 15 const deinit_status = gpa.deinit(); 16 //fail test; can't try in defer as defer is executed after we return 17 if (deinit_status == .leak) { 18 std.log.err("memory leak", .{}); 19 } 20 } 21 const alloc = gpa.allocator(); 22 23 var tty = try vaxis.Tty.init(); 24 defer tty.deinit(); 25 26 var vx = try vaxis.init(alloc, .{}); 27 defer vx.deinit(alloc, tty.anyWriter()); 28 29 var loop: vaxis.Loop(Event) = .{ .tty = &tty, .vaxis = &vx }; 30 try loop.init(); 31 32 try loop.start(); 33 defer loop.stop(); 34 35 try vx.enterAltScreen(tty.anyWriter()); 36 try vx.queryTerminal(tty.anyWriter(), 1 * std.time.ns_per_s); 37 38 try vx.queryColor(tty.anyWriter(), .fg); 39 try vx.queryColor(tty.anyWriter(), .bg); 40 var pct: u8 = 0; 41 var dir: enum { 42 up, 43 down, 44 } = .up; 45 46 const fg = [_]u8{ 192, 202, 245 }; 47 const bg = [_]u8{ 26, 27, 38 }; 48 49 // block until we get a resize 50 while (true) { 51 const event = loop.nextEvent(); 52 switch (event) { 53 .key_press => |key| if (key.matches('c', .{ .ctrl = true })) return, 54 .winsize => |ws| { 55 try vx.resize(alloc, tty.anyWriter(), ws); 56 break; 57 }, 58 } 59 } 60 61 while (true) { 62 while (loop.tryEvent()) |event| { 63 switch (event) { 64 .key_press => |key| if (key.matches('c', .{ .ctrl = true })) return, 65 .winsize => |ws| try vx.resize(alloc, tty.anyWriter(), ws), 66 } 67 } 68 69 const win = vx.window(); 70 win.clear(); 71 72 const color = try blendColors(bg, fg, pct); 73 74 const style: vaxis.Style = .{ .fg = color }; 75 76 const segment: vaxis.Segment = .{ 77 .text = vaxis.logo, 78 .style = style, 79 }; 80 const center = vaxis.widgets.alignment.center(win, 28, 4); 81 _ = try center.printSegment(segment, .{ .wrap = .grapheme }); 82 try vx.render(tty.anyWriter()); 83 std.time.sleep(16 * std.time.ns_per_ms); 84 switch (dir) { 85 .up => { 86 pct += 1; 87 if (pct == 100) dir = .down; 88 }, 89 .down => { 90 pct -= 1; 91 if (pct == 0) dir = .up; 92 }, 93 } 94 } 95} 96 97/// blend two rgb colors. pct is an integer percentage for te portion of 'b' in 98/// 'a' 99fn blendColors(a: [3]u8, b: [3]u8, pct: u8) !vaxis.Color { 100 // const r_a = (a[0] * (100 -| pct)) / 100; 101 102 const r_a = (@as(u16, a[0]) * @as(u16, (100 -| pct))) / 100; 103 const r_b = (@as(u16, b[0]) * @as(u16, pct)) / 100; 104 105 const g_a = (@as(u16, a[1]) * @as(u16, (100 -| pct))) / 100; 106 const g_b = (@as(u16, b[1]) * @as(u16, pct)) / 100; 107 // const g_a = try std.math.mul(u8, a[1], (100 -| pct) / 100); 108 // const g_b = (b[1] * pct) / 100; 109 110 const b_a = (@as(u16, a[2]) * @as(u16, (100 -| pct))) / 100; 111 const b_b = (@as(u16, b[2]) * @as(u16, pct)) / 100; 112 // const b_a = try std.math.mul(u8, a[2], (100 -| pct) / 100); 113 // const b_b = (b[2] * pct) / 100; 114 return .{ .rgb = [_]u8{ 115 @min(r_a + r_b, 255), 116 @min(g_a + g_b, 255), 117 @min(b_a + b_b, 255), 118 } }; 119}