summaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/gui.zig86
1 files changed, 24 insertions, 62 deletions
diff --git a/src/gui/gui.zig b/src/gui/gui.zig
index 0737bb63..a1e21dc0 100644
--- a/src/gui/gui.zig
+++ b/src/gui/gui.zig
@@ -200,55 +200,18 @@ const touch_click_flash_max_frames: u8 = 14;
const touch_click_flash_vertices: usize = 1400;
const touch_scroll_tick: f32 = 0.02;
-const AnimationClock = struct {
- next_ns: u64 = 0,
-
- fn due(clock: *AnimationClock, active: bool, now_ns: u64) bool {
- if (!active) {
- clock.next_ns = 0;
- return false;
- }
- if (clock.next_ns == 0) {
- clock.next_ns = now_ns +| pardes.animation.Animation.frame_ns;
- return false;
- }
- if (now_ns < clock.next_ns) return false;
- clock.next_ns = now_ns +| pardes.animation.Animation.frame_ns;
- return true;
- }
-};
-
-fn finishPresentedAnimationFrame(
- clock: *AnimationClock,
- core: *pardes.Pardes,
- tracks: []const pardes.animation.Track,
- now_ns: u64,
-) void {
- core.acknowledgePanelPresentation(tracks);
- if (clock.due(core.animationActive(), now_ns)) core.update(.tick);
-}
-
-test "GUI animation clock is active-only and cadence gated" {
- var clock: AnimationClock = .{};
- try std.testing.expect(!clock.due(false, 100));
- try std.testing.expect(!clock.due(true, 100));
- try std.testing.expect(!clock.due(true, 100 + pardes.animation.Animation.frame_ns - 1));
- try std.testing.expect(clock.due(true, 100 + pardes.animation.Animation.frame_ns));
- try std.testing.expect(!clock.due(false, 100 + 2 * pardes.animation.Animation.frame_ns));
- try std.testing.expectEqual(@as(u64, 0), clock.next_ns);
-}
-
test "a persistent scene presents a new panel's frame zero before advancing it" {
const core = try pardes.Pardes.init(std.testing.allocator, .{ .tty_only = true });
defer core.deinit();
var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
defer arena.deinit();
- var clock: AnimationClock = .{};
+ const frame = pardes.animation.frame_ns;
core.settings.scene_effects.crt = true;
+ core.advance(100);
const scene_frame = try core.render(arena.allocator());
- finishPresentedAnimationFrame(&clock, core, scene_frame.panelTracks(), 100);
- try std.testing.expectEqual(@as(u64, 100 + pardes.animation.Animation.frame_ns), clock.next_ns);
+ core.acknowledgePanelPresentation(scene_frame.panelTracks());
+ try std.testing.expectEqual(@as(?u64, 100 + frame), core.nextWake());
core.settings.panel_transition = .slide;
core.update(.{ .command = "Newcol" });
@@ -258,12 +221,12 @@ test "a persistent scene presents a new panel's frame zero before advancing it"
try std.testing.expect(track_count > 0);
for (first.panelTracks()) |track| try std.testing.expectEqual(@as(u16, 0), track.frame);
- finishPresentedAnimationFrame(
- &clock,
- core,
- first.panelTracks(),
- 100 + pardes.animation.Animation.frame_ns,
- );
+ core.acknowledgePanelPresentation(first.panelTracks());
+ // Just short of a frame is no frame at all.
+ core.advance(100 + frame - 1);
+ _ = arena.reset(.retain_capacity);
+ for ((try core.render(arena.allocator())).panelTracks()) |track| try std.testing.expectEqual(@as(u16, 0), track.frame);
+ core.advance(100 + frame);
_ = arena.reset(.retain_capacity);
const second = try core.render(arena.allocator());
try std.testing.expectEqual(track_count, second.panelTracks().len);
@@ -3742,7 +3705,6 @@ const Shell = struct {
presented: bool = false,
skipped_presents: u8 = 0,
surface: ?*pardes.Surface = null,
- animation_clock: AnimationClock = .{},
saw_event: bool = false,
dump_err: ?anyerror = null,
retired_shells: [pardes.MAX_PANES]RetiredShell = @splat(.{}),
@@ -3832,6 +3794,7 @@ const Shell = struct {
const vtable: pardes.Host.VTable = .{
.wait_input = waitInput,
+ .now = guiNow,
.present = present,
.post_present = postPresent,
.poll_frame = pollFrame,
@@ -3857,6 +3820,7 @@ const Shell = struct {
const grid_vtable: pardes.Host.VTable = vt: {
var v = vtable;
v.wait_input = null;
+ v.now = null;
v.poll_frame = gridPollFrame;
v.present = gridPresent;
v.post_present = gridPostPresent;
@@ -4106,20 +4070,16 @@ fn present(ctx: ?*anyopaque, surface: *const pardes.Surface) void {
fn postPresent(ctx: ?*anyopaque) void {
const s = shellOf(ctx);
const g = s.gui orelse return;
- if (!s.presented) {
- // No image (a minimized window): time still passes, so a lingering
- // message or a hover wait runs out instead of redrawing forever.
- if (s.animation_clock.due(s.core.animationActive(), c.SDL_GetTicksNS())) s.core.update(.tick);
- return;
- }
+ // No image (a minimized window) shows no tracks; time still passes and
+ // the pump advances it all the same.
+ if (!s.presented) return;
const frame = s.surface orelse return;
refreshPresentedPointer(g, s.core);
- finishPresentedAnimationFrame(
- &s.animation_clock,
- s.core,
- frame.panelTracks(),
- c.SDL_GetTicksNS(),
- );
+ s.core.acknowledgePanelPresentation(frame.panelTracks());
+}
+
+fn guiNow(_: ?*anyopaque) u64 {
+ return c.SDL_GetTicksNS();
}
fn gridPollFrame(ctx: ?*anyopaque) void {
@@ -4129,8 +4089,10 @@ fn gridPollFrame(ctx: ?*anyopaque) void {
if (f.tick().count != 0) s.saw_event = true;
}
pollCwds(s.core, s.ptys);
- if (s.core.animationActive()) {
- s.core.update(.tick);
+ // Grid time is virtual: each poll moves it straight to the core's
+ // next wake, a frame at a time while anything moves.
+ if (s.core.nextWake()) |due| {
+ s.core.advance(due);
s.saw_event = true;
}
}