diff --git a/src/app.zig b/src/app.zig index d1a869d..2c3ab9d 100644 --- a/src/app.zig +++ b/src/app.zig @@ -199,7 +199,7 @@ pub const Transform = struct { pub const GainChanges = std.BoundedArray(GainChange, max_gain_changes); pub const GainChange = struct { gain: f64, - sample: f64 + sample: f64, }; gain_changes: GainChanges = .{}, @@ -1026,6 +1026,35 @@ pub const Project = struct { } } + pub fn updateGainChange(self: *Project, index: usize, sample_index: f64) void { + const gain_change: *Transform.GainChange = &self.gain_changes.slice()[index]; + + if (index > 0) { + if (self.gain_changes.buffer[index - 1].sample + SampleList.Block.capacity > sample_index) { + return; + } + } + + if (index < self.gain_changes.len - 1) { + if (sample_index > self.gain_changes.buffer[index + 1].sample - SampleList.Block.capacity) { + return; + } + } + + const previous_sample_index = gain_change.sample; + gain_change.sample = sample_index; + + const invalidated_range = RangeF64.init( + @min(previous_sample_index, sample_index), + @max(previous_sample_index, sample_index) + ); + + var view_iter = self.views.iterator(); + while (view_iter.next()) |view| { + view.invalidated_transform_ranges.append(invalidated_range) catch continue; + } + } + // ------------------- Serialization ------------------ // pub fn initFromFile(self: *Project, allocator: Allocator, f: std.fs.File) !void { @@ -1755,6 +1784,7 @@ pub fn tick(self: *App) !void { for (view.invalidated_transform_ranges.constSlice()) |range| { const from_block: usize = @intFromFloat(@divFloor(range.lower, block_size)); const to_block: usize = @intFromFloat(@divFloor(@min(range.upper, @as(f64, @floatFromInt(reference_len)) - 1), block_size)); + if (from_block > to_block) continue; const block_count = to_block - from_block + 1; try computed_samples.ensureTotalBlocks(from_block + block_count); diff --git a/src/components/view_ruler.zig b/src/components/view_ruler.zig index f7053c7..5cddf8f 100644 --- a/src/components/view_ruler.zig +++ b/src/components/view_ruler.zig @@ -400,7 +400,7 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U // } // } - for (0.., project.gain_changes.slice()) |i, gain_change| { + for (0.., project.gain_changes.slice()) |i, *gain_change| { const color = srcery.bright_orange; const sample = gain_change.sample; @@ -422,7 +422,7 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U .float_rect = ruler.getGraphDrawContext().getRect(sample - clickable_width/2, clickable_width, 0, 1), .float_relative_to = ruler.graph_box, .parent = ruler.graph_box, - .flags = &.{ .draw_hot, .draw_active, .clickable }, + .flags = &.{ .draw_hot, .draw_active, .clickable, .draggable }, .hot_cursor = .mouse_cursor_pointing_hand, }); @@ -434,11 +434,26 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U _ = ui.label("Gain: {d:.3}", .{ gain_change.gain }); } + + const view_range = view.getGraphView(axis); + const mouse_range = switch (axis) { + .X => RangeF64.init(0, ruler.graph_box.persistent.size.x), + .Y => RangeF64.init(0, ruler.graph_box.persistent.size.y) + }; + const mouse_position = switch (axis) { + .X => signal.mouse.x - ruler.graph_box.persistent.position.x, + .Y => signal.mouse.y - ruler.graph_box.persistent.position.y + }; + + if (signal.dragged() and i != 0) { + project.updateGainChange(i, mouse_range.remapTo(view_range.*, mouse_position)); + } } } } const signal = ui.signal(box); + const view_range = view.getGraphView(axis); const mouse_position = switch (axis) { .X => signal.relative_mouse.x, .Y => signal.relative_mouse.y @@ -447,7 +462,6 @@ pub fn show(ctx: Context, box: *UI.Box, graph_box: *UI.Box, view_id: Id, axis: U .X => RangeF64.init(0, box.persistent.size.x), .Y => RangeF64.init(0, box.persistent.size.y) }; - const view_range = view.getGraphView(axis); if (signal.hot and view_range.size() > 0) { const mouse_position_on_graph = mouse_range.remapTo(view_range.*, mouse_position);