diff --git a/src/app.zig b/src/app.zig index 7553031..0ad4af1 100644 --- a/src/app.zig +++ b/src/app.zig @@ -854,7 +854,6 @@ pub const View = struct { // TODO: Implement different styles of following: Look ahead, sliding, sliding window follow: bool = false, graph_opts: Graph.ViewOptions = .{}, - sync_controls: bool = false, marked_ranges: std.BoundedArray(MarkedRange, 32) = .{}, markers: std.BoundedArray(f64, max_markers) = .{}, transforms: BoundedTransformsArray = .{}, @@ -1787,7 +1786,7 @@ fn exportProject(self: *App) !void { { try writer.writeAll("Pipete Solution:\n"); - try writer.writeAll(self.project.pipete_solution.notes.items); + try writer.writeAll(self.project.pipete_solution.items); try writer.writeAll("\n"); } @@ -1796,6 +1795,8 @@ fn exportProject(self: *App) !void { try writer.writeAll(self.project.notes.items); try writer.writeAll("\n"); } + + // TODO: export channels } pub fn tick(self: *App) !void { diff --git a/src/components/systems/view_controls.zig b/src/components/systems/view_controls.zig index e65d877..788a698 100644 --- a/src/components/systems/view_controls.zig +++ b/src/components/systems/view_controls.zig @@ -31,20 +31,14 @@ pub const ViewAxisPosition = struct { } fn get(optional_self: *?ViewAxisPosition, project: *App.Project, view_id: Id, axis: UI.Axis) ?f64 { + _ = project; + const self = optional_self.* orelse return null; if (self.axis != axis) return null; - const view = project.views.get(view_id) orelse return null; - if (view.sync_controls) { - const owner_view = project.views.get(self.view_id).?; - if (!owner_view.sync_controls) { - return null; - } - } else { - if (!self.view_id.eql(view_id)) { - return null; - } + if (!self.view_id.eql(view_id)) { + return null; } return self.position; @@ -242,39 +236,21 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang } } - var sync_controls = false; - if (self.project.views.get(view_id)) |view| { - sync_controls = view.sync_controls; - } + var command: *Command = undefined; + if (frame.findCommandByView(view_id)) |prev_command| { + command = prev_command; - var view_ids: std.BoundedArray(Id, constants.max_views) = .{}; - if (sync_controls) { - var iter = self.project.views.idIterator(); - while (iter.next()) |id| { - if (self.project.views.get(id).?.sync_controls) { - view_ids.appendAssumeCapacity(id); - } - } + command.move_and_zoom.x = x_range; + command.move_and_zoom.y = y_range; } else { - view_ids.appendAssumeCapacity(view_id); - } - - for (view_ids.constSlice()) |id| { - var command: *Command = undefined; - if (frame.findCommandByView(id)) |prev_command| { - command = prev_command; - - 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; + if (self.project.views.get(view_id)) |view| { const view_rect = &view.graph_opts; command = frame.commands.addOneAssumeCapacity(); command.* = Command{ .move_and_zoom = .{ - .view_id = id, + .view_id = view_id, .before_x = view_rect.x_range, .before_y = view_rect.y_range, .x = x_range, @@ -283,7 +259,6 @@ pub fn pushViewMove(self: *System, view_id: Id, x_range: RangeF64, y_range: Rang }; } } - } pub fn pushViewMoveAxis(self: *System, view_id: Id, axis: UI.Axis, view_range: RangeF64) void { diff --git a/src/components/view.zig b/src/components/view.zig index 4aaa48c..58f0025 100644 --- a/src/components/view.zig +++ b/src/components/view.zig @@ -17,8 +17,6 @@ const Id = App.Id; const remap = utils.remap; const assert = std.debug.assert; -const ruler_size = UI.Sizing.initFixed(.{ .pixels = 32 }); - pub const ZoomStart = UIViewRuler.ZoomStart; pub const Context = struct { @@ -236,16 +234,6 @@ fn showToolbar(ctx: Context, view_id: Id) void { view_name = std.fs.path.stem(file.path); } - if (view.sync_controls) { - const btn = ui.button(ui.keyFromString("Disable sync")); - btn.texture = Assets.cross; - btn.size.y = UI.Sizing.initGrowFull(); - btn.tooltip = "Disable sync controls"; - if (ui.signal(btn).clicked()) { - view.sync_controls = false; - } - } - if (view_name) |text| { _ = ui.createBox(.{ .size_x = UI.Sizing.initGrowFull() @@ -314,14 +302,14 @@ pub fn show(ctx: Context, view_id: Id, height: UI.Sizing) !Result { const container = ui.createBox(.{ .layout_direction = .left_to_right, .size_x = UI.Sizing.initGrowFull(), - .size_y = ruler_size, + .size_y = UIViewRuler.ruler_size_y, }); container.beginChildren(); defer container.endChildren(); _ = ui.createBox(.{ - .size_x = ruler_size, - .size_y = ruler_size, + .size_x = UIViewRuler.ruler_size_x, + .size_y = UIViewRuler.ruler_size_y, .background = srcery.hard_black, }); diff --git a/src/components/view_ruler.zig b/src/components/view_ruler.zig index 6ccd10f..b91521c 100644 --- a/src/components/view_ruler.zig +++ b/src/components/view_ruler.zig @@ -6,6 +6,7 @@ const RangeF64 = @import("../range.zig").RangeF64; const srcery = @import("../srcery.zig"); const utils = @import("../utils.zig"); const constants = @import("../constants.zig"); +const Assets = @import("../assets.zig"); const ViewControlsSystem = @import("./systems/view_controls.zig"); @@ -13,7 +14,8 @@ const Id = App.Id; const remap = utils.remap; const assert = std.debug.assert; -const ruler_size = UI.Sizing.initFixed(.{ .pixels = 32 }); +pub const ruler_size_x = UI.Sizing.initFixed(.{ .pixels = 32*3 }); +pub const ruler_size_y = UI.Sizing.initFixed(.{ .pixels = 32 }); const Ruler = struct { project: *App.Project, @@ -57,11 +59,13 @@ const DrawContext = struct { available_range: RangeF64, axis: UI.Axis, rect: rl.Rectangle = .{ .x = 0, .y = 0, .width = 0, .height = 0 }, + project: *App.Project, fn init(axis: UI.Axis, project: *App.Project, view_id: Id) DrawContext { const view = project.views.get(view_id).?; return DrawContext{ + .project = project, .one_unit = switch (axis) { .X => project.getSampleRate(), .Y => 1 @@ -159,33 +163,43 @@ pub fn createBox(ctx: Context, key: UI.Key, axis: UI.Axis) *UI.Box { }); if (axis == .X) { ruler.size.x = UI.Sizing.initGrowFull(); - ruler.size.y = ruler_size; + ruler.size.y = ruler_size_y; } else { - ruler.size.x = ruler_size; + ruler.size.x = ruler_size_x; ruler.size.y = UI.Sizing.initGrowFull(); } return ruler; } -fn drawRulerTicks(_ctx: ?*anyopaque, box: *UI.Box) void { +fn formatAxisLabel(allocator: std.mem.Allocator, project: *App.Project, axis: UI.Axis, position: f64) ![]u8 { + const sample_rate = project.sample_rate; + if (axis == .X and sample_rate != null) { + const seconds = position / sample_rate.?; + return try utils.formatDuration(allocator, seconds); + } else { + return try std.fmt.allocPrint(allocator, "{d:.3}", .{ position }); + } +} + +fn drawRulerTicks(_ctx: ?*anyopaque, ui: *UI, box: *UI.Box) void { const ctx: *DrawContext = @ptrCast(@alignCast(_ctx)); ctx.rect = box.rect(); ctx.drawLine(ctx.available_range.lower, 1, srcery.yellow); ctx.drawLine(ctx.available_range.upper, 1, srcery.yellow); - if (ctx.available_range.hasExclusive(0)) { - ctx.drawLine(0, 0.75, srcery.yellow); - } + // if (ctx.available_range.hasExclusive(0)) { + // ctx.drawLine(0, 0.75, srcery.yellow); + // } - var one_unit = ctx.one_unit orelse return; + var one_unit = ctx.one_unit orelse 5000; - while (ctx.render_range.size() < 5*one_unit) { + while (ctx.render_range.size() < 2*one_unit) { one_unit /= 2; } - while (ctx.render_range.size() > 50*one_unit) { + while (ctx.render_range.size() > 10*one_unit) { one_unit *= 2; } @@ -194,6 +208,18 @@ fn drawRulerTicks(_ctx: ?*anyopaque, box: *UI.Box) void { ctx.drawTicks(ticks_range.lower, ticks_range.upper, one_unit, 0.5, srcery.yellow); ctx.drawTicks(ticks_range.lower + one_unit/2, ticks_range.upper, one_unit, 0.25, srcery.yellow); + + const font = Assets.font(box.font); + + const allocator = ui.frameAllocator(); + + { + var position = ticks_range.lower + one_unit; + while (position < ticks_range.upper - one_unit) : (position += one_unit) { + const text = formatAxisLabel(allocator, ctx.project, ctx.axis, position) catch continue; + font.drawTextCenter(text, ctx.getPoint(position, 0.8), srcery.bright_white); + } + } } fn showMouseTooltip(ctx: Context, axis: UI.Axis, view_id: Id, position: f64) void { diff --git a/src/main.zig b/src/main.zig index 1f86d70..08427ac 100644 --- a/src/main.zig +++ b/src/main.zig @@ -118,9 +118,13 @@ pub fn main() !void { if (app_config_dir.openFile("config.bin", .{})) |save_file| { defer save_file.close(); - app.loadProject(save_file) catch |e| { - log.err("Failed to load project: {}", .{e}); - }; + + _ = try app.addView(.{ + .file = try app.addFile("./samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin") + }); + // app.loadProject(save_file) catch |e| { + // log.err("Failed to load project: {}", .{e}); + // }; } else |e| switch (e) { error.FileNotFound => {}, else => return e diff --git a/src/screens/main_screen.zig b/src/screens/main_screen.zig index 57a379d..3d90d27 100644 --- a/src/screens/main_screen.zig +++ b/src/screens/main_screen.zig @@ -525,12 +525,6 @@ fn showViewSettings(self: *MainScreen, view_id: Id) !void { _ = ui.createBox(.{ .size_y = UI.Sizing.initFixedPixels(ui.rem(1)) }); } - _ = ui.checkbox(.{ - .value = &view.sync_controls, - .label = "Sync controls" - }); - - switch (view.reference) { .channel => |channel_id| { const channel = project.channels.get(channel_id).?; diff --git a/src/ui.zig b/src/ui.zig index c31e4c6..ce1d347 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -519,7 +519,7 @@ pub const Box = struct { pub const Draw = struct { ctx: ?*anyopaque = null, - do: *const fn(ctx: ?*anyopaque, box: *Box) void + do: *const fn(ctx: ?*anyopaque, ui: *UI, box: *Box) void }; const max_wrapped_lines = 64; @@ -1828,7 +1828,7 @@ fn drawBox(self: *UI, box: *Box, on_top_pass: ?bool) void { } if (box.draw) |box_draw| { - box_draw.do(box_draw.ctx, box); + box_draw.do(box_draw.ctx, self, box); } const alignment_x_coeff = box.alignment.x.getCoefficient();