libvaxis/examples/xev.zig

132 lines
3.6 KiB
Zig
Raw Normal View History

const std = @import("std");
const vaxis = @import("vaxis");
const xev = @import("xev");
const Cell = vaxis.Cell;
pub const panic = vaxis.panic_handler;
const App = struct {
const lower_limit: u8 = 30;
const next_ms: u64 = 8;
allocator: std.mem.Allocator,
vx: *vaxis.Vaxis,
buffered_writer: std.io.BufferedWriter(4096, std.io.AnyWriter),
color_idx: u8,
dir: enum {
up,
down,
},
fn draw(self: *App) !void {
const style: vaxis.Style = .{ .fg = .{ .rgb = [_]u8{ self.color_idx, self.color_idx, self.color_idx } } };
const segment: vaxis.Segment = .{
.text = vaxis.logo,
.style = style,
};
const win = self.vx.window();
win.clear();
const center = vaxis.widgets.alignment.center(win, 28, 4);
_ = try center.printSegment(segment, .{ .wrap = .grapheme });
switch (self.dir) {
.up => {
self.color_idx += 1;
if (self.color_idx == 255) self.dir = .down;
},
.down => {
self.color_idx -= 1;
if (self.color_idx == lower_limit) self.dir = .up;
},
}
try self.vx.render(self.buffered_writer.writer().any());
try self.buffered_writer.flush();
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer {
const deinit_status = gpa.deinit();
//fail test; can't try in defer as defer is executed after we return
if (deinit_status == .leak) {
std.log.err("memory leak", .{});
}
}
const alloc = gpa.allocator();
var tty = try vaxis.Tty.init();
var vx = try vaxis.init(alloc, .{});
defer vx.deinit(alloc, tty.anyWriter());
var loop = try xev.Loop.init(.{});
defer loop.deinit();
var app: App = .{
.allocator = alloc,
.buffered_writer = tty.bufferedWriter(),
.color_idx = App.lower_limit,
.dir = .up,
.vx = &vx,
};
var vx_loop: vaxis.xev.TtyWatcher(App) = undefined;
try vx_loop.init(&tty, &vx, &loop, &app, eventCallback);
try vx.enterAltScreen(tty.anyWriter());
// send queries asynchronously
try vx.queryTerminalSend(tty.anyWriter());
const timer = try xev.Timer.init();
var timer_cmp: xev.Completion = .{};
timer.run(&loop, &timer_cmp, App.next_ms, App, &app, timerCallback);
try loop.run(.until_done);
}
fn eventCallback(
ud: ?*App,
loop: *xev.Loop,
watcher: *vaxis.xev.TtyWatcher(App),
event: vaxis.xev.Event,
) xev.CallbackAction {
const app = ud orelse unreachable;
const writer = app.buffered_writer.writer().any();
switch (event) {
.key_press => |key| {
if (key.matches('c', .{ .ctrl = true })) {
loop.stop();
return .disarm;
}
},
.winsize => |ws| watcher.vx.resize(app.allocator, writer, ws) catch @panic("TODO"),
else => {},
}
const win = watcher.vx.window();
win.clear();
watcher.vx.render(writer) catch {
std.log.err("couldn't render", .{});
return .disarm;
};
app.buffered_writer.flush() catch @panic("couldn't flush");
return .rearm;
}
fn timerCallback(
ud: ?*App,
l: *xev.Loop,
c: *xev.Completion,
r: xev.Timer.RunError!void,
) xev.CallbackAction {
_ = r catch @panic("timer error");
var app = ud orelse return .disarm;
app.draw() catch @panic("couldn't draw");
const timer = try xev.Timer.init();
timer.run(l, c, App.next_ms, App, ud, timerCallback);
return .disarm;
}