diff --git a/src/animations/ColorMix.zig b/src/animations/ColorMix.zig index 95e7df0..95b454c 100644 --- a/src/animations/ColorMix.zig +++ b/src/animations/ColorMix.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const Animation = @import("../tui/Animation.zig"); const TerminalBuffer = @import("../tui/TerminalBuffer.zig"); const utils = @import("../tui/utils.zig"); @@ -43,7 +44,15 @@ pub fn init(terminal_buffer: *TerminalBuffer, col1: u32, col2: u32, col3: u32) C }; } -pub fn draw(self: *ColorMix) void { +pub fn animation(self: *ColorMix) Animation { + return Animation.init(self, deinit, realloc, draw); +} + +fn deinit(_: *ColorMix) void {} + +fn realloc(_: *ColorMix) anyerror!void {} + +fn draw(self: *ColorMix) void { self.frames +%= 1; const time: f32 = @as(f32, @floatFromInt(self.frames)) * time_scale; diff --git a/src/animations/Doom.zig b/src/animations/Doom.zig index 6b0d46a..bbc0a86 100644 --- a/src/animations/Doom.zig +++ b/src/animations/Doom.zig @@ -1,5 +1,6 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +const Animation = @import("../tui/Animation.zig"); const TerminalBuffer = @import("../tui/TerminalBuffer.zig"); const utils = @import("../tui/utils.zig"); @@ -38,17 +39,21 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, top_color: u }; } -pub fn deinit(self: Doom) void { +pub fn animation(self: *Doom) Animation { + return Animation.init(self, deinit, realloc, draw); +} + +fn deinit(self: *Doom) void { self.allocator.free(self.buffer); } -pub fn realloc(self: *Doom) !void { +fn realloc(self: *Doom) anyerror!void { const buffer = try self.allocator.realloc(self.buffer, self.terminal_buffer.width * self.terminal_buffer.height); initBuffer(buffer, self.terminal_buffer.width); self.buffer = buffer; } -pub fn draw(self: Doom) void { +fn draw(self: *Doom) void { for (0..self.terminal_buffer.width) |x| { for (1..self.terminal_buffer.height) |y| { const source = y * self.terminal_buffer.width + x; diff --git a/src/animations/Matrix.zig b/src/animations/Matrix.zig index 18636fc..c60aa17 100644 --- a/src/animations/Matrix.zig +++ b/src/animations/Matrix.zig @@ -1,6 +1,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; const Random = std.Random; +const Animation = @import("../tui/Animation.zig"); const TerminalBuffer = @import("../tui/TerminalBuffer.zig"); const utils = @import("../tui/utils.zig"); @@ -54,12 +55,16 @@ pub fn init(allocator: Allocator, terminal_buffer: *TerminalBuffer, fg_ini: u32, }; } -pub fn deinit(self: Matrix) void { +pub fn animation(self: *Matrix) Animation { + return Animation.init(self, deinit, realloc, draw); +} + +fn deinit(self: *Matrix) void { self.allocator.free(self.dots); self.allocator.free(self.lines); } -pub fn realloc(self: *Matrix) !void { +fn realloc(self: *Matrix) anyerror!void { const dots = try self.allocator.realloc(self.dots, self.terminal_buffer.width * (self.terminal_buffer.height + 1)); const lines = try self.allocator.realloc(self.lines, self.terminal_buffer.width); @@ -69,7 +74,7 @@ pub fn realloc(self: *Matrix) !void { self.lines = lines; } -pub fn draw(self: *Matrix) void { +fn draw(self: *Matrix) void { const buf_height = self.terminal_buffer.height; const buf_width = self.terminal_buffer.width; self.count += 1; diff --git a/src/main.zig b/src/main.zig index e9de028..54e62aa 100644 --- a/src/main.zig +++ b/src/main.zig @@ -11,6 +11,7 @@ const interop = @import("interop.zig"); const Doom = @import("animations/Doom.zig"); const Matrix = @import("animations/Matrix.zig"); const ColorMix = @import("animations/ColorMix.zig"); +const Animation = @import("tui/Animation.zig"); const TerminalBuffer = @import("tui/TerminalBuffer.zig"); const Session = @import("tui/components/Session.zig"); const Text = @import("tui/components/Text.zig"); @@ -336,24 +337,24 @@ pub fn main() !void { } // Initialize the animation, if any - var doom: Doom = undefined; - var matrix: Matrix = undefined; - var color_mix: ColorMix = undefined; + var animation: Animation = undefined; switch (config.animation) { .none => {}, - .doom => doom = try Doom.init(allocator, &buffer, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color), - .matrix => matrix = try Matrix.init(allocator, &buffer, config.cmatrix_fg, config.cmatrix_min_codepoint, config.cmatrix_max_codepoint), - .colormix => color_mix = ColorMix.init(&buffer, config.colormix_col1, config.colormix_col2, config.colormix_col3), - } - defer { - switch (config.animation) { - .none => {}, - .doom => doom.deinit(), - .matrix => matrix.deinit(), - .colormix => {}, - } + .doom => { + var doom = try Doom.init(allocator, &buffer, config.doom_top_color, config.doom_middle_color, config.doom_bottom_color); + animation = doom.animation(); + }, + .matrix => { + var matrix = try Matrix.init(allocator, &buffer, config.cmatrix_fg, config.cmatrix_min_codepoint, config.cmatrix_max_codepoint); + animation = matrix.animation(); + }, + .colormix => { + var color_mix = ColorMix.init(&buffer, config.colormix_col1, config.colormix_col2, config.colormix_col3); + animation = color_mix.animation(); + }, } + defer animation.deinit(); const animate = config.animation != .none; const shutdown_key = try std.fmt.parseInt(u8, config.shutdown_key[1..], 10); @@ -382,7 +383,7 @@ pub fn main() !void { while (run) { // If there's no input or there's an animation, a resolution change needs to be checked - if (!update or config.animation != .none) { + if (!update or animate) { if (!update) std.time.sleep(std.time.ns_per_ms * 100); _ = termbox.tb_present(); // Required to update tb_width() and tb_height() @@ -396,16 +397,9 @@ pub fn main() !void { buffer.width = width; buffer.height = height; - switch (config.animation) { - .none => {}, - .doom => doom.realloc() catch { - try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); - }, - .matrix => matrix.realloc() catch { - try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); - }, - .colormix => {}, - } + animation.realloc() catch { + try info_line.addMessage(lang.err_alloc, config.error_bg, config.error_fg); + }; update = true; resolution_changed = true; @@ -417,14 +411,7 @@ pub fn main() !void { if (auth_fails < config.auth_fails) { _ = termbox.tb_clear(); - if (!animation_timed_out) { - switch (config.animation) { - .none => {}, - .doom => doom.draw(), - .matrix => matrix.draw(), - .colormix => color_mix.draw(), - } - } + if (!animation_timed_out) animation.draw(); buffer.drawLabel(ly_top_str, 0, 0); @@ -585,12 +572,7 @@ pub fn main() !void { if (config.animation_timeout_sec > 0 and tv.tv_sec - tv_zero.tv_sec > config.animation_timeout_sec) { animation_timed_out = true; - switch (config.animation) { - .none => {}, - .doom => doom.deinit(), - .matrix => matrix.deinit(), - .colormix => {}, - } + animation.deinit(); } } else if (config.bigclock != .none and config.clock == null) { var tv: interop.system_time.timeval = undefined; @@ -736,9 +718,6 @@ pub fn main() !void { const password_text = try allocator.dupeZ(u8, password.text.items); defer allocator.free(password_text); - // Give up control on the TTY - // _ = termbox.tb_shutdown(); - session_pid = try std.posix.fork(); if (session_pid == 0) { const current_environment = session.label.list.items[session.label.current]; diff --git a/src/tui/Animation.zig b/src/tui/Animation.zig new file mode 100644 index 0000000..2311bba --- /dev/null +++ b/src/tui/Animation.zig @@ -0,0 +1,61 @@ +const Animation = @This(); + +const VTable = struct { + deinit_fn: *const fn (ptr: *anyopaque) void, + realloc_fn: *const fn (ptr: *anyopaque) anyerror!void, + draw_fn: *const fn (ptr: *anyopaque) void, +}; + +pointer: *anyopaque, +vtable: VTable, + +pub fn init( + pointer: anytype, + comptime deinit_fn: fn (ptr: @TypeOf(pointer)) void, + comptime realloc_fn: fn (ptr: @TypeOf(pointer)) anyerror!void, + comptime draw_fn: fn (ptr: @TypeOf(pointer)) void, +) Animation { + const Pointer = @TypeOf(pointer); + const Impl = struct { + pub fn deinitImpl(ptr: *anyopaque) void { + const impl: Pointer = @ptrCast(@alignCast(ptr)); + return @call(.always_inline, deinit_fn, .{impl}); + } + + pub fn reallocImpl(ptr: *anyopaque) anyerror!void { + const impl: Pointer = @ptrCast(@alignCast(ptr)); + return @call(.always_inline, realloc_fn, .{impl}); + } + + pub fn drawImpl(ptr: *anyopaque) void { + const impl: Pointer = @ptrCast(@alignCast(ptr)); + return @call(.always_inline, draw_fn, .{impl}); + } + + const vtable = VTable{ + .deinit_fn = deinitImpl, + .realloc_fn = reallocImpl, + .draw_fn = drawImpl, + }; + }; + + return .{ + .pointer = pointer, + .vtable = Impl.vtable, + }; +} + +pub fn deinit(self: *Animation) void { + const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer)); + return @call(.auto, self.vtable.deinit_fn, .{impl}); +} + +pub fn realloc(self: *Animation) anyerror!void { + const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer)); + return @call(.auto, self.vtable.realloc_fn, .{impl}); +} + +pub fn draw(self: *Animation) void { + const impl: @TypeOf(self.pointer) = @ptrCast(@alignCast(self.pointer)); + return @call(.auto, self.vtable.draw_fn, .{impl}); +}