diff --git a/src/components/systems/view_controls.zig b/src/components/systems/view_controls.zig index b4a69a7..559ee80 100644 --- a/src/components/systems/view_controls.zig +++ b/src/components/systems/view_controls.zig @@ -51,23 +51,23 @@ pub const ViewAxisPosition = struct { } }; -pub const Command = struct { - view_id: Id, - action: union(enum) { - move_and_zoom: struct { - before_x: RangeF64, - before_y: RangeF64, - x: RangeF64, - y: RangeF64 - } +pub const Command = union(enum) { + breakpoint, + move_and_zoom: struct { + view_id: Id, + before_x: RangeF64, + before_y: RangeF64, + x: RangeF64, + y: RangeF64 }, fn apply(self: *const Command, system: *System) void { const project = system.project; - const view = project.views.get(self.view_id) orelse return; - switch (self.action) { + switch (self.*) { + .breakpoint => {}, .move_and_zoom => |move_and_zoom| { + const view = project.views.get(move_and_zoom.view_id) orelse return; const view_rect = &view.graph_opts; view_rect.x_range = move_and_zoom.x; view_rect.y_range = move_and_zoom.y; @@ -78,10 +78,11 @@ pub const Command = struct { fn undo(self: *const Command, system: *System) void { const project = system.project; - const view = project.views.get(self.view_id) orelse return; - switch (self.action) { + switch (self.*) { + .breakpoint => {}, .move_and_zoom => |move_and_zoom| { + const view = project.views.get(move_and_zoom.view_id) orelse return; const view_rect = &view.graph_opts; view_rect.x_range = move_and_zoom.before_x; view_rect.y_range = move_and_zoom.before_y; @@ -95,8 +96,9 @@ pub const CommandFrame = struct { commands: std.BoundedArray(Command, constants.max_views) = .{}, fn findCommandByView(self: *CommandFrame, view_id: Id) ?*Command { - for (self.commands.slice()) |*command| { - if (command.view_id.eql(view_id)) { + const commands: []Command = self.commands.slice(); + for (commands) |*command| { + if (command.* == .move_and_zoom and command.move_and_zoom.view_id.eql(view_id)) { return command; } } @@ -117,6 +119,16 @@ pub const CommandFrame = struct { command.undo(system); } } + + fn hasBreakpoint(self: *const CommandFrame) bool { + const commands: []const Command = self.commands.constSlice(); + for (commands) |*command| { + if (command.* == .breakpoint) { + return true; + } + } + return false; + } }; pub const CommandFrameArray = std.BoundedArray(CommandFrame, 64); @@ -146,6 +158,7 @@ fn pushCommandFrame(self: *System) *CommandFrame { var frame = self.undo_stack.addOneAssumeCapacity(); frame.updated_at_ns = std.time.nanoTimestamp(); + frame.commands.len = 0; return frame; } @@ -157,9 +170,19 @@ fn lastCommandFrame(self: *System) ?*CommandFrame { return null; } +pub fn pushBreakpoint(self: *System) void { + if (self.lastCommandFrame()) |last_frame| { + // No need to have 2 break points in a row + if (last_frame.hasBreakpoint()) { + return; + } + } + + const frame = self.pushCommandFrame(); + frame.commands.appendAssumeCapacity(.{ .breakpoint = {} }); +} + pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: RangeF64) void { - - var frame: *CommandFrame = undefined; { var push_new_command = true; @@ -204,8 +227,8 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang if (frame.findCommandByView(id)) |prev_command| { command = prev_command; - command.action.move_and_zoom.x = x_range; - command.action.move_and_zoom.y = y_range; + command.move_and_zoom.x = x_range; + command.move_and_zoom.y = y_range; } else { const view = self.project.views.get(view_id) orelse continue; const view_rect = &view.graph_opts; @@ -213,14 +236,12 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang command = frame.commands.addOneAssumeCapacity(); command.* = Command{ - .view_id = id, - .action = .{ - .move_and_zoom = .{ - .before_x = view_rect.x_range, - .before_y = view_rect.y_range, - .x = x_range, - .y = y_range - } + .move_and_zoom = .{ + .view_id = id, + .before_x = view_rect.x_range, + .before_y = view_rect.y_range, + .x = x_range, + .y = y_range } }; } @@ -240,11 +261,15 @@ pub fn pushViewMoveAxis(self: *System, view_id: Id, axis: UI.Axis, view_range: R } pub fn undoLastMove(self: *System) void { - const frame = self.undo_stack.popOrNull() orelse return; + while (self.undo_stack.popOrNull()) |frame| { + frame.undo(self); - frame.undo(self); + self.last_applied_command = @min(self.last_applied_command, self.undo_stack.len); - self.last_applied_command = @min(self.last_applied_command, self.undo_stack.len); + if (!frame.hasBreakpoint()) { + break; + } + } } pub fn applyCommands(self: *System) void { diff --git a/src/components/view.zig b/src/components/view.zig index 6d19ea9..945e7aa 100644 --- a/src/components/view.zig +++ b/src/components/view.zig @@ -100,6 +100,10 @@ fn showGraph(ctx: Context, view_id: Id) *UI.Box { ctx.view_controls.pushViewMove(view_id, view.available_x_range, view.available_y_range); } + if (signal.flags.contains(.left_released)) { + ctx.view_controls.pushBreakpoint(); + } + view.graph_cache.min_max_cache = app.getViewMinMaxCache(view_id); Graph.drawCached(&view.graph_cache, graph_box.persistent.size, view_opts.*, samples);