237 lines
7.9 KiB
Zig
237 lines
7.9 KiB
Zig
const std = @import("std");
|
|
const App = @import("../app.zig");
|
|
const UI = @import("../ui.zig");
|
|
const srcery = @import("../srcery.zig");
|
|
const NIDaq = @import("../ni-daq/root.zig");
|
|
|
|
const assert = std.debug.assert;
|
|
const log = std.log.scoped(.channel_from_device_screen);
|
|
|
|
const Screen = @This();
|
|
|
|
app: *App,
|
|
|
|
hot_channel: ?[:0]const u8 = null,
|
|
|
|
// TODO: 32 limit
|
|
selected_channels: std.BoundedArray([:0]u8, 32) = .{},
|
|
// TODO: Don't use arena
|
|
channel_names: std.heap.ArenaAllocator,
|
|
|
|
pub fn init(app: *App) Screen {
|
|
return Screen{
|
|
.app = app,
|
|
.channel_names = std.heap.ArenaAllocator.init(app.allocator)
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *Screen) void {
|
|
_ = self.channel_names.reset(.free_all);
|
|
}
|
|
|
|
fn isChannelSelected(self: *Screen, channel: []const u8) bool {
|
|
for (self.selected_channels.slice()) |selected_channel| {
|
|
if (std.mem.eql(u8, selected_channel, channel)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
fn selectChannel(self: *Screen, channel: []const u8) void {
|
|
if (self.selected_channels.unusedCapacitySlice().len == 0) {
|
|
log.warn("Maximum number of selected channels reached", .{});
|
|
return;
|
|
}
|
|
|
|
if (self.isChannelSelected(channel)) {
|
|
return;
|
|
}
|
|
|
|
const allocator = self.channel_names.allocator();
|
|
const channel_dupe = allocator.dupeZ(u8, channel) catch |e| {
|
|
log.err("Failed to duplicate channel name: {}", .{e});
|
|
return;
|
|
};
|
|
|
|
self.selected_channels.appendAssumeCapacity(channel_dupe);
|
|
}
|
|
|
|
fn deselectChannel(self: *Screen, channel: []const u8) void {
|
|
for (0.., self.selected_channels.slice()) |i, selected_channel| {
|
|
if (std.mem.eql(u8, selected_channel, channel)) {
|
|
_ = self.selected_channels.swapRemove(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
fn toggleChannel(self: *Screen, channel: []const u8) void {
|
|
if (self.isChannelSelected(channel)) {
|
|
self.deselectChannel(channel);
|
|
} else {
|
|
self.selectChannel(channel);
|
|
}
|
|
}
|
|
|
|
pub fn tick(self: *Screen) !void {
|
|
var ni_daq = self.app.ni_daq orelse return;
|
|
var ui = &self.app.ui;
|
|
|
|
if (ui.isKeyboardPressed(.key_escape)) {
|
|
self.app.screen = .main;
|
|
}
|
|
|
|
const root = ui.parentBox().?;
|
|
root.layout_direction = .left_to_right;
|
|
|
|
{
|
|
const panel = ui.beginScrollbar(ui.keyFromString("Channels"));
|
|
defer ui.endScrollbar();
|
|
panel.layout_direction = .top_to_bottom;
|
|
|
|
const devices = try ni_daq.listDeviceNames();
|
|
for (devices) |device| {
|
|
var ai_voltage_physical_channels: []const [:0]const u8 = &.{};
|
|
if (try ni_daq.checkDeviceAIMeasurementType(device, .Voltage)) {
|
|
ai_voltage_physical_channels = try ni_daq.listDeviceAIPhysicalChannels(device);
|
|
}
|
|
|
|
// var ao_physical_channels: []const [:0]const u8 = &.{};
|
|
// if (try ni_daq.checkDeviceAOOutputType(device, .Voltage)) {
|
|
// ao_physical_channels = try ni_daq.listDeviceAOPhysicalChannels(device);
|
|
// }
|
|
|
|
inline for (.{ ai_voltage_physical_channels }) |channels| {
|
|
for (channels) |channel| {
|
|
const channel_button = ui.textButton(channel);
|
|
channel_button.background = srcery.black;
|
|
if (self.isChannelSelected(channel)) {
|
|
channel_button.background = srcery.bright_white;
|
|
channel_button.text_color = srcery.black;
|
|
}
|
|
|
|
if (self.app.getChannelByName(channel) != null) {
|
|
channel_button.text_color = srcery.white;
|
|
channel_button.background = srcery.hard_black;
|
|
} else {
|
|
const signal = ui.signal(channel_button);
|
|
if (signal.clicked()) {
|
|
self.toggleChannel(channel);
|
|
}
|
|
|
|
if (signal.hot) {
|
|
self.hot_channel = channel;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
const panel = ui.createBox(.{
|
|
.size_x = UI.Sizing.initGrowFull(),
|
|
.size_y = UI.Sizing.initGrowFull(),
|
|
.borders = .{
|
|
.left = .{ .color = srcery.hard_black, .size = 4 }
|
|
},
|
|
.layout_direction = .top_to_bottom,
|
|
.padding = UI.Padding.all(ui.rem(2))
|
|
});
|
|
panel.beginChildren();
|
|
defer panel.endChildren();
|
|
|
|
const info_container = ui.createBox(.{
|
|
.size_x = UI.Sizing.initGrowFull(),
|
|
.size_y = UI.Sizing.initGrowFull(),
|
|
.layout_direction = .top_to_bottom,
|
|
});
|
|
|
|
if (self.hot_channel) |hot_channel| {
|
|
info_container.beginChildren();
|
|
defer info_container.endChildren();
|
|
|
|
var maybe_hot_device: ?[:0]const u8 = null;
|
|
var device_buff: NIDaq.BoundedDeviceName = .{};
|
|
if (NIDaq.getDeviceNameFromChannel(hot_channel)) |device| {
|
|
device_buff.appendSliceAssumeCapacity(device);
|
|
device_buff.buffer[device_buff.len] = 0;
|
|
maybe_hot_device = device_buff.buffer[0..device_buff.len :0];
|
|
}
|
|
|
|
var channel_type_name: []const u8 = "unknown";
|
|
if (NIDaq.getChannelType(hot_channel)) |channel_type| {
|
|
channel_type_name = channel_type.name();
|
|
}
|
|
|
|
{
|
|
const channel_info = ui.createBox(.{
|
|
.size_x = UI.Sizing.initGrowFull(),
|
|
.size_y = UI.Sizing.initFitChildren(),
|
|
.padding = .{
|
|
.bottom = ui.rem(2)
|
|
},
|
|
.layout_direction = .top_to_bottom
|
|
});
|
|
channel_info.beginChildren();
|
|
defer channel_info.endChildren();
|
|
|
|
_ = ui.label("Channel properties", .{});
|
|
_ = ui.label("Name: {s}", .{hot_channel});
|
|
_ = ui.label("Type: {s}", .{channel_type_name});
|
|
}
|
|
|
|
if (maybe_hot_device) |hot_device| {
|
|
_ = ui.label("Device properties", .{});
|
|
|
|
if (ni_daq.listDeviceAIMeasurementTypes(hot_device)) |measurement_types| {
|
|
_ = ui.label("Measurement types: {} types", .{measurement_types.len});
|
|
} else |e| {
|
|
log.err("ni_daq.listDeviceAIMeasurementTypes(): {}", .{ e });
|
|
}
|
|
}
|
|
} else {
|
|
info_container.alignment.x = .center;
|
|
info_container.alignment.y = .center;
|
|
info_container.setText("Hover on a channel");
|
|
info_container.flags.insert(.wrap_text);
|
|
info_container.text_color = srcery.hard_black;
|
|
info_container.font = .{
|
|
.variant = .bold_italic,
|
|
.size = ui.rem(3)
|
|
};
|
|
}
|
|
|
|
const add_button = ui.button(ui.keyFromString("Add channels"));
|
|
add_button.setFmtText("Add {} selected channels", .{self.selected_channels.len});
|
|
add_button.size.x = UI.Sizing.initGrowFull();
|
|
add_button.alignment.x = .center;
|
|
if (self.selected_channels.len > 0) {
|
|
add_button.borders = UI.Borders.all(.{
|
|
.color = srcery.green,
|
|
.size = 2
|
|
});
|
|
|
|
const signal = ui.signal(add_button);
|
|
if (signal.clicked()) {
|
|
self.app.screen = .main;
|
|
for (self.selected_channels.slice()) |channel| {
|
|
_ = try self.app.addView(.{
|
|
.channel = try self.app.addChannel(channel)
|
|
});
|
|
}
|
|
|
|
_ = self.channel_names.reset(.free_all);
|
|
self.selected_channels.len = 0;
|
|
}
|
|
|
|
} else {
|
|
add_button.borders = UI.Borders.all(.{
|
|
.color = srcery.hard_black,
|
|
.size = 2
|
|
});
|
|
}
|
|
}
|
|
} |