add file input for changing opened file view

This commit is contained in:
Rokas Puzonas 2025-04-10 00:23:53 +03:00
parent da7a580e55
commit faa0a534d5
5 changed files with 72 additions and 17 deletions

View File

@ -626,7 +626,8 @@ pub const Command = union(enum) {
load_project, load_project,
stop_output: Id, // Channel id stop_output: Id, // Channel id
start_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 { pub const CollectionTask = struct {
@ -742,7 +743,7 @@ fn deinitUI(self: *App) void {
} }
fn loadProject(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", .{}); log.warn("Attempt to load while collection is still in progress. Loading canceled", .{});
return; return;
} }
@ -786,7 +787,7 @@ fn loadProject(self: *App) !void {
} }
fn saveProject(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", .{}); log.warn("Attempt to save while collection is still in progress. Saving canceled", .{});
return; return;
} }
@ -933,6 +934,11 @@ pub fn tick(self: *App) !void {
}, },
.stop_output => |channel_id| { .stop_output => |channel_id| {
self.stopOutput(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; 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 { pub fn collectionThreadCallback(self: *App) void {
while (!self.should_close) { while (!self.should_close) {
@ -1214,6 +1234,7 @@ pub fn loadFile(self: *App, id: Id) !void {
file.clear(self.allocator); file.clear(self.allocator);
const cwd = std.fs.cwd(); const cwd = std.fs.cwd();
const samples_file = try cwd.openFile(file.path, .{ .mode = .read_only }); const samples_file = try cwd.openFile(file.path, .{ .mode = .read_only });
defer samples_file.close(); 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).?; const channel = self.project.channels.get(id).?;
channel.* = Channel{ 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| { self.loadChannel(id) catch |e| {
log.err("Failed to load channel: {}", .{ e }); log.err("Failed to load channel: {}", .{ e });
}; };

View File

@ -103,6 +103,15 @@ pub fn main() !void {
defer app.deinit(); defer app.deinit();
if (builtin.mode == .Debug) { 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(.{ _ = try app.addView(.{
.channel = try app.addChannel("Dev1/ai0") .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") // .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("Dev1/ai0");
// try app.appendChannelFromDevice("Dev3/ao0"); // try app.appendChannelFromDevice("Dev3/ao0");
// try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin"); // try app.appendChannelFromFile("samples/HeLa Cx37_ 40nM GFX + 35uM Propofol_18-Sep-2024_0003_I.bin");

View File

@ -37,6 +37,7 @@ parsed_sample_rate: ?f64 = null,
// View settings // View settings
channel_save_file_picker: ?Platform.FilePickerId = null, channel_save_file_picker: ?Platform.FilePickerId = null,
file_save_file_picker: ?Platform.FilePickerId = null,
pub fn init(app: *App) !MainScreen { pub fn init(app: *App) !MainScreen {
const allocator = app.allocator; const allocator = app.allocator;
@ -336,7 +337,8 @@ fn showViewSettings(self: *MainScreen, view_id: Id) !void {
.key = ui.keyFromString("Save location"), .key = ui.keyFromString("Save location"),
.allocator = self.app.allocator, .allocator = self.app.allocator,
.file_picker = &self.channel_save_file_picker, .file_picker = &self.channel_save_file_picker,
.path = channel.saved_collected_samples .path = channel.saved_collected_samples,
.open_dialog = false
})) |path| { })) |path| {
if (channel.saved_collected_samples) |current_path| { if (channel.saved_collected_samples) |current_path| {
self.app.allocator.free(current_path); self.app.allocator.free(current_path);
@ -353,6 +355,17 @@ fn showViewSettings(self: *MainScreen, view_id: Id) !void {
if (file.samples) |samples| { if (file.samples) |samples| {
sample_count = samples.len; 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 });
}
} }
} }

View File

@ -2277,6 +2277,7 @@ pub const FileInputOptions = struct {
key: Key, key: Key,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
file_picker: *?Platform.FilePickerId, file_picker: *?Platform.FilePickerId,
open_dialog: bool = true,
path: ?[]const u8 = null path: ?[]const u8 = null
}; };
@ -2819,8 +2820,13 @@ pub fn fileInput(self: *UI, opts: FileInputOptions) ?[]u8 {
const container_signal = self.signal(container); const container_signal = self.signal(container);
if (container_signal.clicked()) { if (container_signal.clicked()) {
var file_open_options: Platform.OpenFileOptions = .{}; var file_open_options: Platform.OpenFileOptions = .{};
file_open_options.style = .save; if (opts.open_dialog) {
file_open_options.prompt_overwrite = true; 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("All", "*") catch unreachable;
file_open_options.appendFilter("Binary", "*.bin") catch unreachable; file_open_options.appendFilter("Binary", "*.bin") catch unreachable;

View File

@ -74,7 +74,7 @@ pub fn initBoundedStringZ(comptime BoundedString: type, text: []const u8) !Bound
return bounded_string; 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]; return bounded_array.buffer[0..(bounded_array.len-1) :0];
} }