diff --git a/src/app.zig b/src/app.zig index c69ccd0..9012569 100644 --- a/src/app.zig +++ b/src/app.zig @@ -626,7 +626,8 @@ pub const Command = union(enum) { load_project, stop_output: Id, // Channel id start_output: Id, // Channel id - add_file_from_picker + add_file_from_picker, + reload_file: Id, // File id }; pub const CollectionTask = struct { @@ -742,7 +743,7 @@ fn deinitUI(self: *App) void { } fn loadProject(self: *App) !void { - if (self.isCollectionInProgress()) { + if (self.isNiDaqInUse()) { log.warn("Attempt to load while collection is still in progress. Loading canceled", .{}); return; } @@ -786,7 +787,7 @@ fn loadProject(self: *App) !void { } fn saveProject(self: *App) !void { - if (self.isCollectionInProgress()) { + if (self.isNiDaqInUse()) { log.warn("Attempt to save while collection is still in progress. Saving canceled", .{}); return; } @@ -933,6 +934,11 @@ pub fn tick(self: *App) !void { }, .stop_output => |channel_id| { self.stopOutput(channel_id); + }, + .reload_file => |file_id| { + self.loadFile(file_id) catch |e| { + log.err("Failed to load file: {}", .{ e }); + }; } } } @@ -1105,6 +1111,20 @@ pub fn isCollectionInProgress(self: *App) bool { return self.collection_task != null; } +pub fn isOutputingInProgress(self: *App) bool { + var channel_iter = self.project.channels.idIterator(); + while (channel_iter.next()) |channel_id| { + if (self.isChannelOutputing(channel_id)) { + return true; + } + } + return false; +} + +fn isNiDaqInUse(self: *App) bool { + return self.isCollectionInProgress() or self.isOutputingInProgress(); +} + pub fn collectionThreadCallback(self: *App) void { while (!self.should_close) { @@ -1214,6 +1234,7 @@ pub fn loadFile(self: *App, id: Id) !void { file.clear(self.allocator); const cwd = std.fs.cwd(); + const samples_file = try cwd.openFile(file.path, .{ .mode = .read_only }); defer samples_file.close(); @@ -1244,9 +1265,24 @@ pub fn addChannel(self: *App, channel_name: []const u8) !Id { const channel = self.project.channels.get(id).?; channel.* = Channel{ - .name = try utils.initBoundedStringZ(Channel.Name, channel_name) + .name = try utils.initBoundedStringZ(Channel.Name, channel_name), }; + if (self.project.save_location) |project_file_path| { + if (std.fs.path.dirname(project_file_path)) |project_dir| { + var clean_channel_name_buff = channel.name; + const clean_channel_name = utils.getBoundedStringZ(&clean_channel_name_buff); + + // Sanitize the channel name, because it will be used as a filename + std.mem.replaceScalar(u8, clean_channel_name, '/', '_'); + + const filename = try std.mem.concat(self.allocator, u8, &.{ clean_channel_name, ".bin" }); + defer self.allocator.free(filename); + + channel.saved_collected_samples = try std.fs.path.join(self.allocator, &.{ project_dir, filename }); + } + } + self.loadChannel(id) catch |e| { log.err("Failed to load channel: {}", .{ e }); }; diff --git a/src/main.zig b/src/main.zig index 09a8b9f..59e65ce 100644 --- a/src/main.zig +++ b/src/main.zig @@ -103,6 +103,15 @@ pub fn main() !void { defer app.deinit(); if (builtin.mode == .Debug) { + var cwd_realpath_buff: [std.fs.MAX_PATH_BYTES]u8 = undefined; + const cwd_realpath = try std.fs.cwd().realpath(".", &cwd_realpath_buff); + + const save_location = try std.fs.path.join(allocator, &.{ cwd_realpath, "project.proj" }); + errdefer allocator.free(save_location); + + app.project.save_location = save_location; + app.project.sample_rate = 5000; + _ = try app.addView(.{ .channel = try app.addChannel("Dev1/ai0") }); @@ -137,15 +146,6 @@ pub fn main() !void { // .file = try app.addFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin") // }); - var cwd_realpath_buff: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const cwd_realpath = try std.fs.cwd().realpath(".", &cwd_realpath_buff); - - const save_location = try std.fs.path.join(allocator, &.{ cwd_realpath, "project.proj" }); - errdefer allocator.free(allocator); - - app.project.save_location = save_location; - app.project.sample_rate = 5000; - // try app.appendChannelFromDevice("Dev1/ai0"); // try app.appendChannelFromDevice("Dev3/ao0"); // try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin"); diff --git a/src/screens/main_screen.zig b/src/screens/main_screen.zig index fe53da7..d4c925d 100644 --- a/src/screens/main_screen.zig +++ b/src/screens/main_screen.zig @@ -37,6 +37,7 @@ parsed_sample_rate: ?f64 = null, // View settings channel_save_file_picker: ?Platform.FilePickerId = null, +file_save_file_picker: ?Platform.FilePickerId = null, pub fn init(app: *App) !MainScreen { const allocator = app.allocator; @@ -336,7 +337,8 @@ fn showViewSettings(self: *MainScreen, view_id: Id) !void { .key = ui.keyFromString("Save location"), .allocator = self.app.allocator, .file_picker = &self.channel_save_file_picker, - .path = channel.saved_collected_samples + .path = channel.saved_collected_samples, + .open_dialog = false })) |path| { if (channel.saved_collected_samples) |current_path| { self.app.allocator.free(current_path); @@ -353,6 +355,17 @@ fn showViewSettings(self: *MainScreen, view_id: Id) !void { if (file.samples) |samples| { sample_count = samples.len; } + + if (ui.fileInput(.{ + .key = ui.keyFromString("Filename"), + .allocator = self.app.allocator, + .file_picker = &self.file_save_file_picker, + .path = file.path + })) |path| { + self.app.allocator.free(file.path); + file.path = path; + self.app.pushCommand(.{ .reload_file = file_id }); + } } } diff --git a/src/ui.zig b/src/ui.zig index 77d4d50..5d825d3 100644 --- a/src/ui.zig +++ b/src/ui.zig @@ -2277,6 +2277,7 @@ pub const FileInputOptions = struct { key: Key, allocator: std.mem.Allocator, file_picker: *?Platform.FilePickerId, + open_dialog: bool = true, path: ?[]const u8 = null }; @@ -2819,8 +2820,13 @@ pub fn fileInput(self: *UI, opts: FileInputOptions) ?[]u8 { const container_signal = self.signal(container); if (container_signal.clicked()) { var file_open_options: Platform.OpenFileOptions = .{}; - file_open_options.style = .save; - file_open_options.prompt_overwrite = true; + if (opts.open_dialog) { + file_open_options.style = .open; + file_open_options.file_must_exist = true; + } else { + file_open_options.style = .save; + file_open_options.prompt_overwrite = true; + } file_open_options.appendFilter("All", "*") catch unreachable; file_open_options.appendFilter("Binary", "*.bin") catch unreachable; diff --git a/src/utils.zig b/src/utils.zig index 0981e68..2006156 100644 --- a/src/utils.zig +++ b/src/utils.zig @@ -74,7 +74,7 @@ pub fn initBoundedStringZ(comptime BoundedString: type, text: []const u8) !Bound return bounded_string; } -pub fn getBoundedStringZ(bounded_array: anytype) [:0]const u8 { +pub fn getBoundedStringZ(bounded_array: anytype) [:0]u8 { return bounded_array.buffer[0..(bounded_array.len-1) :0]; }