mirror of
https://github.com/fairyglade/ly.git
synced 2026-03-21 22:43:38 +00:00
Make animation timeout independent of event loop
Signed-off-by: AnErrupTion <anerruption@disroot.org>
This commit is contained in:
@@ -1,6 +1,10 @@
|
||||
const std = @import("std");
|
||||
const math = std.math;
|
||||
|
||||
const ly_core = @import("ly-core");
|
||||
const interop = ly_core.interop;
|
||||
const TimeOfDay = interop.TimeOfDay;
|
||||
|
||||
const Cell = @import("../tui/Cell.zig");
|
||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||
const Widget = @import("../tui/Widget.zig");
|
||||
@@ -16,8 +20,10 @@ fn length(vec: Vec2) f32 {
|
||||
return math.sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
|
||||
}
|
||||
|
||||
start_time: TimeOfDay,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
frames: u64,
|
||||
pattern_cos_mod: f32,
|
||||
pattern_sin_mod: f32,
|
||||
@@ -28,11 +34,14 @@ pub fn init(
|
||||
col1: u32,
|
||||
col2: u32,
|
||||
col3: u32,
|
||||
timeout: *bool,
|
||||
) ColorMix {
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
) !ColorMix {
|
||||
return .{
|
||||
.start_time = try interop.getTimeOfDay(),
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.timeout = timeout,
|
||||
.animate = animate,
|
||||
.timeout_sec = timeout_sec,
|
||||
.frames = 0,
|
||||
.pattern_cos_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
|
||||
.pattern_sin_mod = terminal_buffer.random.float(f32) * math.pi * 2.0,
|
||||
@@ -60,13 +69,13 @@ pub fn widget(self: *ColorMix) Widget {
|
||||
null,
|
||||
null,
|
||||
draw,
|
||||
null,
|
||||
update,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
fn draw(self: *ColorMix) void {
|
||||
if (self.timeout.*) return;
|
||||
if (!self.animate.*) return;
|
||||
|
||||
self.frames +%= 1;
|
||||
const time: f32 = @as(f32, @floatFromInt(self.frames)) * time_scale;
|
||||
@@ -99,3 +108,11 @@ fn draw(self: *ColorMix) void {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self: *ColorMix, _: *anyopaque) !void {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const ly_core = @import("ly-core");
|
||||
const interop = ly_core.interop;
|
||||
const TimeOfDay = interop.TimeOfDay;
|
||||
|
||||
const Cell = @import("../tui/Cell.zig");
|
||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||
const Widget = @import("../tui/Widget.zig");
|
||||
@@ -11,9 +15,11 @@ pub const STEPS = 12;
|
||||
pub const HEIGHT_MAX = 9;
|
||||
pub const SPREAD_MAX = 4;
|
||||
|
||||
start_time: TimeOfDay,
|
||||
allocator: Allocator,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
buffer: []u8,
|
||||
height: u8,
|
||||
spread: u8,
|
||||
@@ -27,7 +33,8 @@ pub fn init(
|
||||
bottom_color: u32,
|
||||
fire_height: u8,
|
||||
fire_spread: u8,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
) !Doom {
|
||||
const buffer = try allocator.alloc(u8, terminal_buffer.width * terminal_buffer.height);
|
||||
initBuffer(buffer, terminal_buffer.width);
|
||||
@@ -50,9 +57,11 @@ pub fn init(
|
||||
};
|
||||
|
||||
return .{
|
||||
.start_time = try interop.getTimeOfDay(),
|
||||
.allocator = allocator,
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.timeout = timeout,
|
||||
.animate = animate,
|
||||
.timeout_sec = timeout_sec,
|
||||
.buffer = buffer,
|
||||
.height = @min(HEIGHT_MAX, fire_height),
|
||||
.spread = @min(SPREAD_MAX, fire_spread),
|
||||
@@ -67,7 +76,7 @@ pub fn widget(self: *Doom) Widget {
|
||||
deinit,
|
||||
realloc,
|
||||
draw,
|
||||
null,
|
||||
update,
|
||||
null,
|
||||
);
|
||||
}
|
||||
@@ -83,7 +92,7 @@ fn realloc(self: *Doom) !void {
|
||||
}
|
||||
|
||||
fn draw(self: *Doom) void {
|
||||
if (self.timeout.*) return;
|
||||
if (!self.animate.*) return;
|
||||
|
||||
for (0..self.terminal_buffer.width) |x| {
|
||||
// We start from 1 so that we always have the topmost line when spreading fire
|
||||
@@ -130,3 +139,11 @@ fn initBuffer(buffer: []u8, width: usize) void {
|
||||
@memset(slice_start, 0);
|
||||
@memset(slice_end, STEPS);
|
||||
}
|
||||
|
||||
fn update(self: *Doom, _: *anyopaque) !void {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ const eql = std.mem.eql;
|
||||
const flate = std.compress.flate;
|
||||
|
||||
const ly_core = @import("ly-core");
|
||||
const interop = ly_core.interop;
|
||||
const TimeOfDay = interop.TimeOfDay;
|
||||
const LogFile = ly_core.LogFile;
|
||||
|
||||
const enums = @import("../enums.zig");
|
||||
@@ -300,6 +302,7 @@ const VEC_Y = 1;
|
||||
|
||||
const DurFile = @This();
|
||||
|
||||
start_time: TimeOfDay,
|
||||
allocator: Allocator,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
dur_movie: DurFormat,
|
||||
@@ -307,7 +310,8 @@ frames: u64,
|
||||
frame_size: UVec2,
|
||||
start_pos: IVec2,
|
||||
full_color: bool,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
frame_time: u32,
|
||||
time_previous: i64,
|
||||
is_color_format_16: bool,
|
||||
@@ -367,7 +371,8 @@ pub fn init(
|
||||
x_offset: i32,
|
||||
y_offset: i32,
|
||||
full_color: bool,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
) !DurFile {
|
||||
var dur_movie: DurFormat = .init(allocator);
|
||||
|
||||
@@ -399,6 +404,7 @@ pub fn init(
|
||||
const frame_time: u32 = @intFromFloat(1000 / dur_movie.framerate.?);
|
||||
|
||||
return .{
|
||||
.start_time = try interop.getTimeOfDay(),
|
||||
.allocator = allocator,
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.frames = 0,
|
||||
@@ -406,7 +412,8 @@ pub fn init(
|
||||
.frame_size = frame_size,
|
||||
.start_pos = start_pos,
|
||||
.full_color = full_color,
|
||||
.timeout = timeout,
|
||||
.animate = animate,
|
||||
.timeout_sec = timeout_sec,
|
||||
.dur_movie = dur_movie,
|
||||
.frame_time = frame_time,
|
||||
.is_color_format_16 = eql(u8, dur_movie.colorFormat.?, "16"),
|
||||
@@ -422,7 +429,7 @@ pub fn widget(self: *DurFile) Widget {
|
||||
deinit,
|
||||
realloc,
|
||||
draw,
|
||||
null,
|
||||
update,
|
||||
null,
|
||||
);
|
||||
}
|
||||
@@ -438,7 +445,7 @@ fn realloc(self: *DurFile) !void {
|
||||
}
|
||||
|
||||
fn draw(self: *DurFile) void {
|
||||
if (self.timeout.*) return;
|
||||
if (!self.animate.*) return;
|
||||
|
||||
const current_frame = self.dur_movie.frames.items[self.frames];
|
||||
|
||||
@@ -493,3 +500,11 @@ fn draw(self: *DurFile) void {
|
||||
self.frames = (self.frames + 1) % frame_count;
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self: *DurFile, _: *anyopaque) !void {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
const ly_core = @import("ly-core");
|
||||
const interop = ly_core.interop;
|
||||
const TimeOfDay = interop.TimeOfDay;
|
||||
|
||||
const Cell = @import("../tui/Cell.zig");
|
||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||
const Widget = @import("../tui/Widget.zig");
|
||||
@@ -16,6 +20,7 @@ const NEIGHBOR_DIRS = [_][2]i8{
|
||||
.{ 1, 0 }, .{ 1, 1 },
|
||||
};
|
||||
|
||||
start_time: TimeOfDay,
|
||||
allocator: Allocator,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
current_grid: []bool,
|
||||
@@ -26,7 +31,8 @@ fg_color: u32,
|
||||
entropy_interval: usize,
|
||||
frame_delay: usize,
|
||||
initial_density: f32,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
dead_cell: Cell,
|
||||
width: usize,
|
||||
height: usize,
|
||||
@@ -38,7 +44,8 @@ pub fn init(
|
||||
entropy_interval: usize,
|
||||
frame_delay: usize,
|
||||
initial_density: f32,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
) !GameOfLife {
|
||||
const width = terminal_buffer.width;
|
||||
const height = terminal_buffer.height;
|
||||
@@ -48,6 +55,7 @@ pub fn init(
|
||||
const next_grid = try allocator.alloc(bool, grid_size);
|
||||
|
||||
var game = GameOfLife{
|
||||
.start_time = try interop.getTimeOfDay(),
|
||||
.allocator = allocator,
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.current_grid = current_grid,
|
||||
@@ -58,7 +66,8 @@ pub fn init(
|
||||
.entropy_interval = entropy_interval,
|
||||
.frame_delay = frame_delay,
|
||||
.initial_density = initial_density,
|
||||
.timeout = timeout,
|
||||
.animate = animate,
|
||||
.timeout_sec = timeout_sec,
|
||||
.dead_cell = .{ .ch = DEAD_CHAR, .fg = @intCast(TerminalBuffer.Color.DEFAULT), .bg = terminal_buffer.bg },
|
||||
.width = width,
|
||||
.height = height,
|
||||
@@ -77,7 +86,7 @@ pub fn widget(self: *GameOfLife) Widget {
|
||||
deinit,
|
||||
realloc,
|
||||
draw,
|
||||
null,
|
||||
update,
|
||||
null,
|
||||
);
|
||||
}
|
||||
@@ -105,7 +114,7 @@ fn realloc(self: *GameOfLife) !void {
|
||||
}
|
||||
|
||||
fn draw(self: *GameOfLife) void {
|
||||
if (self.timeout.*) return;
|
||||
if (!self.animate.*) return;
|
||||
|
||||
// Update game state at controlled frame rate
|
||||
self.frame_counter += 1;
|
||||
@@ -132,6 +141,14 @@ fn draw(self: *GameOfLife) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self: *GameOfLife, _: *anyopaque) !void {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn updateGeneration(self: *GameOfLife) void {
|
||||
// Conway's Game of Life rules with optimized neighbor counting
|
||||
for (0..self.height) |y| {
|
||||
|
||||
@@ -2,6 +2,10 @@ const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Random = std.Random;
|
||||
|
||||
const ly_core = @import("ly-core");
|
||||
const interop = ly_core.interop;
|
||||
const TimeOfDay = interop.TimeOfDay;
|
||||
|
||||
const Cell = @import("../tui/Cell.zig");
|
||||
const TerminalBuffer = @import("../tui/TerminalBuffer.zig");
|
||||
const Widget = @import("../tui/Widget.zig");
|
||||
@@ -24,6 +28,7 @@ pub const Line = struct {
|
||||
update: usize,
|
||||
};
|
||||
|
||||
start_time: TimeOfDay,
|
||||
allocator: Allocator,
|
||||
terminal_buffer: *TerminalBuffer,
|
||||
dots: []Dot,
|
||||
@@ -34,7 +39,8 @@ fg: u32,
|
||||
head_col: u32,
|
||||
min_codepoint: u16,
|
||||
max_codepoint: u16,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
default_cell: Cell,
|
||||
|
||||
pub fn init(
|
||||
@@ -44,7 +50,8 @@ pub fn init(
|
||||
head_col: u32,
|
||||
min_codepoint: u16,
|
||||
max_codepoint: u16,
|
||||
timeout: *bool,
|
||||
animate: *bool,
|
||||
timeout_sec: u12,
|
||||
) !Matrix {
|
||||
const dots = try allocator.alloc(Dot, terminal_buffer.width * (terminal_buffer.height + 1));
|
||||
const lines = try allocator.alloc(Line, terminal_buffer.width);
|
||||
@@ -52,6 +59,7 @@ pub fn init(
|
||||
initBuffers(dots, lines, terminal_buffer.width, terminal_buffer.height, terminal_buffer.random);
|
||||
|
||||
return .{
|
||||
.start_time = try interop.getTimeOfDay(),
|
||||
.allocator = allocator,
|
||||
.terminal_buffer = terminal_buffer,
|
||||
.dots = dots,
|
||||
@@ -62,7 +70,8 @@ pub fn init(
|
||||
.head_col = head_col,
|
||||
.min_codepoint = min_codepoint,
|
||||
.max_codepoint = max_codepoint - min_codepoint,
|
||||
.timeout = timeout,
|
||||
.animate = animate,
|
||||
.timeout_sec = timeout_sec,
|
||||
.default_cell = .{ .ch = ' ', .fg = fg, .bg = terminal_buffer.bg },
|
||||
};
|
||||
}
|
||||
@@ -74,7 +83,7 @@ pub fn widget(self: *Matrix) Widget {
|
||||
deinit,
|
||||
realloc,
|
||||
draw,
|
||||
null,
|
||||
update,
|
||||
null,
|
||||
);
|
||||
}
|
||||
@@ -95,7 +104,7 @@ fn realloc(self: *Matrix) !void {
|
||||
}
|
||||
|
||||
fn draw(self: *Matrix) void {
|
||||
if (self.timeout.*) return;
|
||||
if (!self.animate.*) return;
|
||||
|
||||
const buf_height = self.terminal_buffer.height;
|
||||
const buf_width = self.terminal_buffer.width;
|
||||
@@ -188,6 +197,14 @@ fn draw(self: *Matrix) void {
|
||||
}
|
||||
}
|
||||
|
||||
fn update(self: *Matrix, _: *anyopaque) !void {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (self.timeout_sec > 0 and time.seconds - self.start_time.seconds > self.timeout_sec) {
|
||||
self.animate.* = false;
|
||||
}
|
||||
}
|
||||
|
||||
fn initBuffers(dots: []Dot, lines: []Line, width: usize, height: usize, random: Random) void {
|
||||
var y: usize = 0;
|
||||
while (y <= height) : (y += 1) {
|
||||
|
||||
31
src/main.zig
31
src/main.zig
@@ -76,7 +76,6 @@ const UiState = struct {
|
||||
active_tty: u8,
|
||||
buffer: TerminalBuffer,
|
||||
labels_max_length: usize,
|
||||
animation_timed_out: bool,
|
||||
shutdown_label: Label,
|
||||
restart_label: Label,
|
||||
sleep_label: Label,
|
||||
@@ -152,9 +151,6 @@ pub fn main() !void {
|
||||
|
||||
state.allocator = gpa.allocator();
|
||||
|
||||
// Allows stopping an animation after some time
|
||||
const animation_time_start = try interop.getTimeOfDay();
|
||||
|
||||
// Load arguments
|
||||
const params = comptime clap.parseParamsComptime(
|
||||
\\-h, --help Shows all commands.
|
||||
@@ -884,7 +880,8 @@ pub fn main() !void {
|
||||
state.config.doom_bottom_color,
|
||||
state.config.doom_fire_height,
|
||||
state.config.doom_fire_spread,
|
||||
&state.animation_timed_out,
|
||||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
);
|
||||
animation = doom.widget();
|
||||
},
|
||||
@@ -896,17 +893,19 @@ pub fn main() !void {
|
||||
state.config.cmatrix_head_col,
|
||||
state.config.cmatrix_min_codepoint,
|
||||
state.config.cmatrix_max_codepoint,
|
||||
&state.animation_timed_out,
|
||||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
);
|
||||
animation = matrix.widget();
|
||||
},
|
||||
.colormix => {
|
||||
var color_mix = ColorMix.init(
|
||||
var color_mix = try ColorMix.init(
|
||||
&state.buffer,
|
||||
state.config.colormix_col1,
|
||||
state.config.colormix_col2,
|
||||
state.config.colormix_col3,
|
||||
&state.animation_timed_out,
|
||||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
);
|
||||
animation = color_mix.widget();
|
||||
},
|
||||
@@ -918,7 +917,8 @@ pub fn main() !void {
|
||||
state.config.gameoflife_entropy_interval,
|
||||
state.config.gameoflife_frame_delay,
|
||||
state.config.gameoflife_initial_density,
|
||||
&state.animation_timed_out,
|
||||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
);
|
||||
animation = game_of_life.widget();
|
||||
},
|
||||
@@ -932,7 +932,8 @@ pub fn main() !void {
|
||||
state.config.dur_x_offset,
|
||||
state.config.dur_y_offset,
|
||||
state.config.full_color,
|
||||
&state.animation_timed_out,
|
||||
&state.animate,
|
||||
state.config.animation_timeout_sec,
|
||||
);
|
||||
animation = dur.widget();
|
||||
},
|
||||
@@ -949,7 +950,6 @@ pub fn main() !void {
|
||||
state.auth_fails = 0;
|
||||
state.run = true;
|
||||
state.update = true;
|
||||
state.animation_timed_out = false;
|
||||
state.animate = state.config.animation != .none;
|
||||
state.insert_mode = !state.config.vi_mode or state.config.vi_default_mode == .insert;
|
||||
state.edge_margin = Position.init(
|
||||
@@ -1148,15 +1148,8 @@ pub fn main() !void {
|
||||
var timeout: i32 = -1;
|
||||
|
||||
// Calculate the maximum timeout based on current animations, or the (big) clock. If there's none, we wait for the event indefinitely instead
|
||||
if (state.animate and !state.animation_timed_out) {
|
||||
if (state.animate) {
|
||||
timeout = state.config.animation_frame_delay;
|
||||
|
||||
// Check how long we've been running so we can turn off the animation
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
if (state.config.animation_timeout_sec > 0 and time.seconds - animation_time_start.seconds > state.config.animation_timeout_sec) {
|
||||
state.animation_timed_out = true;
|
||||
}
|
||||
} else if (state.config.bigclock != .none and state.config.clock == null) {
|
||||
const time = try interop.getTimeOfDay();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user