mirror of
https://github.com/hubaldv/bioz-host-rs.git
synced 2026-07-24 00:57:44 +00:00
Tabcontrol via controller.rs.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
535
src/app.rs
535
src/app.rs
@@ -16,17 +16,13 @@ use tokio::sync::{mpsc, watch};
|
||||
|
||||
use eframe::egui::{self, Button, CollapsingHeader, Color32, ComboBox, DragValue, Id, Key, Label, Layout, Modal, Modifiers, RichText, TextEdit, Widget};
|
||||
use egui_plot::{Corner, GridInput, GridMark, Legend, Line, Plot, PlotPoint, Points};
|
||||
use egui_dock::{DockArea, DockState, Style};
|
||||
use egui_dock::{DockArea, DockState, Style, TabViewer};
|
||||
use egui_extras::{TableBuilder, Column};
|
||||
|
||||
use crate::state::{AppState, ControlCommand, HardwareConnected, HardwareState, MeasurementDataState, Mode};
|
||||
|
||||
use crate::logging::LoggingStates;
|
||||
use crate::plot::{TimeSeriesPlot, BodePlot};
|
||||
|
||||
use crate::signals::{LoggingSignal, StartStopSignal};
|
||||
|
||||
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeConfiguration, ElectrodeOptionsWithMultiplexer};
|
||||
use crate::signals::LoggingSignal;
|
||||
use crate::icd::{BioImpedanceLeadMode, IcdDftNum, SweepPoints, ElectrodeOptionsWithMultiplexer};
|
||||
|
||||
const LEAD_MODES: [BioImpedanceLeadMode; 2] = [
|
||||
BioImpedanceLeadMode::TwoLead,
|
||||
@@ -46,7 +42,7 @@ const SWEEP_POINTS_VARIANTS: [SweepPoints; 2] = [
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy,Debug, PartialEq, Eq)]
|
||||
enum TabActive {
|
||||
pub enum TabActive {
|
||||
Single,
|
||||
Sweep,
|
||||
Shortcuts,
|
||||
@@ -54,11 +50,11 @@ enum TabActive {
|
||||
|
||||
pub struct App {
|
||||
tree: DockState<String>,
|
||||
tab_viewer: TabViewer,
|
||||
tab_active: TabActive,
|
||||
tab_viewer: CustomTabs,
|
||||
// tab_active: TabActive,
|
||||
log_tx: mpsc::Sender<LoggingSignal>,
|
||||
pub gui_logging_state: Arc<Mutex<LoggingStates>>,
|
||||
log_filename: String,
|
||||
log_filename: Arc<Mutex<String>>,
|
||||
log_marker_modal: bool,
|
||||
log_marker: String,
|
||||
measurement_data: Arc<MeasurementDataState>,
|
||||
@@ -67,9 +63,10 @@ pub struct App {
|
||||
hardware_state_rx: sync::watch::Receiver<HardwareState>
|
||||
}
|
||||
|
||||
struct TabViewer {
|
||||
struct CustomTabs {
|
||||
show_settings: bool,
|
||||
show_settings_toggle: Option<bool>,
|
||||
log_filename: Arc<Mutex<String>>,
|
||||
measurement_data: Arc<MeasurementDataState>,
|
||||
control_tx: mpsc::Sender<ControlCommand>,
|
||||
app_state_rx: sync::watch::Receiver<AppState>,
|
||||
@@ -139,113 +136,112 @@ fn render_four_lead<T: ElectrodeOption>(
|
||||
changed
|
||||
}
|
||||
|
||||
impl TabViewer {
|
||||
impl CustomTabs {
|
||||
fn single_tab(&mut self, ui: &mut egui::Ui) {
|
||||
egui::Frame::default().inner_margin(5).show(ui, |ui| {
|
||||
let settings = CollapsingHeader::new("Settings")
|
||||
.open(self.show_settings_toggle)
|
||||
.show(ui, |ui| {
|
||||
if let running = self.hardware_state_rx.borrow().running {
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Lead Mode:");
|
||||
let running = self.hardware_state_rx.borrow().running;
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Lead Mode:");
|
||||
|
||||
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
// Map current lead mode to index
|
||||
let mut index = LEAD_MODES
|
||||
.iter()
|
||||
.position(|&m| m == lead_mode)
|
||||
.unwrap_or(0);
|
||||
// Map current lead mode to index
|
||||
let mut index = LEAD_MODES
|
||||
.iter()
|
||||
.position(|&m| m == lead_mode)
|
||||
.unwrap_or(0);
|
||||
|
||||
ComboBox::from_id_salt("LeadMode")
|
||||
.width(60.0)
|
||||
.show_index(ui, &mut index, LEAD_MODES.len(), |i| {
|
||||
match LEAD_MODES[i] {
|
||||
BioImpedanceLeadMode::TwoLead => "2-Lead",
|
||||
BioImpedanceLeadMode::FourLead => "4-Lead",
|
||||
}
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// Update lead mode if changed
|
||||
if lead_mode != LEAD_MODES[index] {
|
||||
lead_mode = LEAD_MODES[index];
|
||||
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
// Show lead configuration
|
||||
ui.label("Lead Configuration:");
|
||||
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
|
||||
let lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
let mut settings = self.app_state_rx.borrow().electrode_settings;
|
||||
|
||||
match (hardware_connected, lead_mode) {
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
|
||||
ComboBox::from_id_salt("LeadMode")
|
||||
.width(60.0)
|
||||
.show_index(ui, &mut index, LEAD_MODES.len(), |i| {
|
||||
match LEAD_MODES[i] {
|
||||
BioImpedanceLeadMode::TwoLead => "2-Lead",
|
||||
BioImpedanceLeadMode::FourLead => "4-Lead",
|
||||
}
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
ui.label(format!("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)"));
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::None, _) => {}
|
||||
}
|
||||
});
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// Update lead mode if changed
|
||||
if lead_mode != LEAD_MODES[index] {
|
||||
lead_mode = LEAD_MODES[index];
|
||||
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
|
||||
}
|
||||
});
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Single Frequency:");
|
||||
let mut freq = self.app_state_rx.borrow().single_frequency;
|
||||
let response = ui.add(DragValue::new(&mut freq).speed(0.1));
|
||||
if response.changed() {
|
||||
self.control_tx.try_send(ControlCommand::SetFrequency(freq)).unwrap();
|
||||
ui.horizontal(|ui| {
|
||||
// Show lead configuration
|
||||
ui.label("Lead Configuration:");
|
||||
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
|
||||
let lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
let mut settings = self.app_state_rx.borrow().electrode_settings;
|
||||
|
||||
match (hardware_connected, lead_mode) {
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
|
||||
}
|
||||
ui.label("Hz");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("ADC samples per DFT:");
|
||||
let mut dft_num = self.app_state_rx.borrow().dft_num;
|
||||
let mut index = DFTNUM_VARIANTS.iter().position(|&x| x == dft_num).unwrap_or(0);
|
||||
ComboBox::from_id_salt("Dftnum")
|
||||
.width(75.0)
|
||||
.show_index(ui, &mut index, DFTNUM_VARIANTS.len(), |i| {
|
||||
format!("{}", 1 << (2 + i)) // 2^2 = 4, 2^3 = 8, ..., 2^14 = 16384
|
||||
});
|
||||
let new_value = DFTNUM_VARIANTS[index];
|
||||
if dft_num != new_value {
|
||||
dft_num = new_value;
|
||||
self.control_tx.try_send(ControlCommand::ChangeDftNum(dft_num)).unwrap();
|
||||
};
|
||||
});
|
||||
});
|
||||
ui.add_enabled_ui(running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Periods per DFT:");
|
||||
match (running, self.hardware_state_rx.borrow().periods_per_dft) {
|
||||
(true, Some(periods)) => {
|
||||
ui.add(Label::new(format!("{:.2}", periods)));
|
||||
},
|
||||
(true, None) => {
|
||||
ui.add(Label::new("N/A"));
|
||||
},
|
||||
(false, _) => {
|
||||
ui.add(Label::new("Start to determine!"));
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
ui.label(format!("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)"));
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::None, _) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Single Frequency:");
|
||||
let mut freq = self.app_state_rx.borrow().single_frequency;
|
||||
let response = ui.add(DragValue::new(&mut freq).speed(0.1));
|
||||
if response.changed() {
|
||||
self.control_tx.try_send(ControlCommand::SetFrequency(freq)).unwrap();
|
||||
}
|
||||
ui.label("Hz");
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("ADC samples per DFT:");
|
||||
let mut dft_num = self.app_state_rx.borrow().dft_num;
|
||||
let mut index = DFTNUM_VARIANTS.iter().position(|&x| x == dft_num).unwrap_or(0);
|
||||
ComboBox::from_id_salt("Dftnum")
|
||||
.width(75.0)
|
||||
.show_index(ui, &mut index, DFTNUM_VARIANTS.len(), |i| {
|
||||
format!("{}", 1 << (2 + i)) // 2^2 = 4, 2^3 = 8, ..., 2^14 = 16384
|
||||
});
|
||||
let new_value = DFTNUM_VARIANTS[index];
|
||||
if dft_num != new_value {
|
||||
dft_num = new_value;
|
||||
self.control_tx.try_send(ControlCommand::ChangeDftNum(dft_num)).unwrap();
|
||||
};
|
||||
});
|
||||
});
|
||||
ui.add_enabled_ui(running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Periods per DFT:");
|
||||
match (running, self.hardware_state_rx.borrow().periods_per_dft) {
|
||||
(true, Some(periods)) => {
|
||||
ui.add(Label::new(format!("{:.2}", periods)));
|
||||
},
|
||||
(true, None) => {
|
||||
ui.add(Label::new("N/A"));
|
||||
},
|
||||
(false, _) => {
|
||||
ui.add(Label::new("Start to determine!"));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
self.show_settings_toggle = None;
|
||||
@@ -303,137 +299,136 @@ impl TabViewer {
|
||||
let settings = CollapsingHeader::new("Settings")
|
||||
.open(self.show_settings_toggle)
|
||||
.show(ui, |ui| {
|
||||
if let running = self.hardware_state_rx.borrow().running {
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Lead Mode:");
|
||||
let running = self.hardware_state_rx.borrow().running;
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Lead Mode:");
|
||||
|
||||
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
let mut lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
// Map current lead mode to index
|
||||
let mut index = LEAD_MODES
|
||||
.iter()
|
||||
.position(|&m| m == lead_mode)
|
||||
.unwrap_or(0);
|
||||
// Map current lead mode to index
|
||||
let mut index = LEAD_MODES
|
||||
.iter()
|
||||
.position(|&m| m == lead_mode)
|
||||
.unwrap_or(0);
|
||||
|
||||
ComboBox::from_id_salt("LeadMode")
|
||||
.width(60.0)
|
||||
.show_index(ui, &mut index, LEAD_MODES.len(), |i| {
|
||||
match LEAD_MODES[i] {
|
||||
BioImpedanceLeadMode::TwoLead => "2-Lead",
|
||||
BioImpedanceLeadMode::FourLead => "4-Lead",
|
||||
}
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// Update lead mode if changed
|
||||
if lead_mode != LEAD_MODES[index] {
|
||||
lead_mode = LEAD_MODES[index];
|
||||
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
|
||||
}
|
||||
});
|
||||
ui.horizontal(|ui| {
|
||||
// Show lead configuration
|
||||
ui.label("Lead Configuration:");
|
||||
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
|
||||
let lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
let mut settings = self.app_state_rx.borrow().electrode_settings;
|
||||
match (hardware_connected, lead_mode) {
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
|
||||
ComboBox::from_id_salt("LeadMode")
|
||||
.width(60.0)
|
||||
.show_index(ui, &mut index, LEAD_MODES.len(), |i| {
|
||||
match LEAD_MODES[i] {
|
||||
BioImpedanceLeadMode::TwoLead => "2-Lead",
|
||||
BioImpedanceLeadMode::FourLead => "4-Lead",
|
||||
}
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
ui.label("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)");
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::None, _) => {}
|
||||
}
|
||||
});
|
||||
.to_string()
|
||||
});
|
||||
|
||||
// Update lead mode if changed
|
||||
if lead_mode != LEAD_MODES[index] {
|
||||
lead_mode = LEAD_MODES[index];
|
||||
self.control_tx.try_send(ControlCommand::ChangeLeadMode(lead_mode)).unwrap();
|
||||
}
|
||||
});
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Measurement Points:");
|
||||
let mut measurement_points = self.app_state_rx.borrow().sweep_points;
|
||||
let mut index = SWEEP_POINTS_VARIANTS.iter().position(|&x| x == measurement_points).unwrap_or(0);
|
||||
ComboBox::from_id_salt("MeasurementPoints")
|
||||
.width(75.0)
|
||||
.show_index(ui, &mut index, SWEEP_POINTS_VARIANTS.len(), |i| {
|
||||
format!("{:?}", SWEEP_POINTS_VARIANTS[i].len())
|
||||
});
|
||||
let new_value = SWEEP_POINTS_VARIANTS[index];
|
||||
if measurement_points != new_value {
|
||||
measurement_points = new_value;
|
||||
self.control_tx.try_send(ControlCommand::ChangeSweepPoints(measurement_points)).unwrap();
|
||||
info!("Sweep Points setting changed!");
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.add_enabled_ui(running, |ui| {
|
||||
let (freq, periods_per_dft_vec) = self.hardware_state_rx.borrow().periods_per_dft_sweep.clone();
|
||||
ui.horizontal(|ui| {
|
||||
// Show lead configuration
|
||||
ui.label("Lead Configuration:");
|
||||
let hardware_connected = self.hardware_state_rx.borrow().hardware_connected;
|
||||
let lead_mode = self.app_state_rx.borrow().lead_mode;
|
||||
|
||||
fn format_frequency(freq: u32) -> String {
|
||||
if freq >= 1_000 {
|
||||
// kHz
|
||||
if freq % 1_000 == 0 {
|
||||
format!("{}k", (freq / 1_000) as u64)
|
||||
} else {
|
||||
format!("{:.1}k", freq as f32 / 1_000.0)
|
||||
let mut settings = self.app_state_rx.borrow().electrode_settings;
|
||||
match (hardware_connected, lead_mode) {
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
ui.label(format!("Drive/sense: Electrode+ (CE0), Electrode- (AIN1)"));
|
||||
}
|
||||
(HardwareConnected::WithoutMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
ui.label("Drive: I+ (CE0), I- (AIN1) | Sense: V+ (AIN2), V- (AIN3)");
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::TwoLead) => {
|
||||
if render_two_lead(ui, &mut settings.with_multiplexer_2_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::WithMultiplexer, BioImpedanceLeadMode::FourLead) => {
|
||||
if render_four_lead(ui, &mut settings.with_multiplexer_4_lead) {
|
||||
self.control_tx.try_send(ControlCommand::ChangeElectrodeSettings(settings)).unwrap();
|
||||
}
|
||||
}
|
||||
(HardwareConnected::None, _) => {}
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.add_enabled_ui(!running, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Measurement Points:");
|
||||
let mut measurement_points = self.app_state_rx.borrow().sweep_points;
|
||||
let mut index = SWEEP_POINTS_VARIANTS.iter().position(|&x| x == measurement_points).unwrap_or(0);
|
||||
ComboBox::from_id_salt("MeasurementPoints")
|
||||
.width(75.0)
|
||||
.show_index(ui, &mut index, SWEEP_POINTS_VARIANTS.len(), |i| {
|
||||
format!("{:?}", SWEEP_POINTS_VARIANTS[i].len())
|
||||
});
|
||||
let new_value = SWEEP_POINTS_VARIANTS[index];
|
||||
if measurement_points != new_value {
|
||||
measurement_points = new_value;
|
||||
self.control_tx.try_send(ControlCommand::ChangeSweepPoints(measurement_points)).unwrap();
|
||||
info!("Sweep Points setting changed!");
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.add_enabled_ui(running, |ui| {
|
||||
let (freq, periods_per_dft_vec) = self.hardware_state_rx.borrow().periods_per_dft_sweep.clone();
|
||||
|
||||
fn format_frequency(freq: u32) -> String {
|
||||
if freq >= 1_000 {
|
||||
// kHz
|
||||
if freq % 1_000 == 0 {
|
||||
format!("{}k", (freq / 1_000) as u64)
|
||||
} else {
|
||||
// Hz
|
||||
if freq % 1 == 0 {
|
||||
format!("{}", freq as u64)
|
||||
} else {
|
||||
format!("{:.1}", freq)
|
||||
}
|
||||
format!("{:.1}k", freq as f32 / 1_000.0)
|
||||
}
|
||||
} else {
|
||||
// Hz
|
||||
if freq % 1 == 0 {
|
||||
format!("{}", freq as u64)
|
||||
} else {
|
||||
format!("{:.1}", freq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableBuilder::new(ui)
|
||||
.column(Column::auto())
|
||||
.columns(Column::remainder().at_most(30.0), freq.len())
|
||||
.header(10.0, |mut header| {
|
||||
header.col(|ui| {
|
||||
ui.label("Frequency [Hz]:");
|
||||
});
|
||||
for freq in &freq {
|
||||
header.col(|ui| {
|
||||
ui.label(format_frequency(*freq));
|
||||
});
|
||||
}
|
||||
})
|
||||
.body(|mut body| {
|
||||
body.row(5.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label("Periods per DFT:");
|
||||
});
|
||||
if let Some(periods) = periods_per_dft_vec {
|
||||
for period in &periods {
|
||||
row.col(|ui| {
|
||||
ui.label(format!("{:.1}", period));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for _ in &freq {
|
||||
row.col(|ui| {
|
||||
ui.label("N/A");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
TableBuilder::new(ui)
|
||||
.column(Column::auto())
|
||||
.columns(Column::remainder().at_most(30.0), freq.len())
|
||||
.header(10.0, |mut header| {
|
||||
header.col(|ui| {
|
||||
ui.label("Frequency [Hz]:");
|
||||
});
|
||||
});
|
||||
}
|
||||
for freq in &freq {
|
||||
header.col(|ui| {
|
||||
ui.label(format_frequency(*freq));
|
||||
});
|
||||
}
|
||||
})
|
||||
.body(|mut body| {
|
||||
body.row(5.0, |mut row| {
|
||||
row.col(|ui| {
|
||||
ui.label("Periods per DFT:");
|
||||
});
|
||||
if let Some(periods) = periods_per_dft_vec {
|
||||
for period in &periods {
|
||||
row.col(|ui| {
|
||||
ui.label(format!("{:.1}", period));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for _ in &freq {
|
||||
row.col(|ui| {
|
||||
ui.label("N/A");
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
self.show_settings_toggle = None;
|
||||
@@ -575,7 +570,7 @@ fn log10x_formatter(name: &str, value: &PlotPoint) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
impl egui_dock::TabViewer for TabViewer {
|
||||
impl TabViewer for CustomTabs {
|
||||
type Tab = String;
|
||||
|
||||
fn title(&mut self, tab: &mut Self::Tab) -> eframe::egui::WidgetText {
|
||||
@@ -592,6 +587,32 @@ impl egui_dock::TabViewer for TabViewer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_tab_button(&mut self, tab: &mut Self::Tab, _response: &egui::Response) {
|
||||
if _response.clicked() {
|
||||
let tab_active = match tab.as_str() {
|
||||
"Single" => {
|
||||
*self.log_filename.lock().unwrap() = format!("log_{}_single.csv", Local::now().format("%Y%m%d"));
|
||||
TabActive::Single
|
||||
},
|
||||
"Sweep" => {
|
||||
*self.log_filename.lock().unwrap() = format!("log_{}_sweep.csv", Local::now().format("%Y%m%d"));
|
||||
TabActive::Sweep
|
||||
},
|
||||
"Shortcuts" => TabActive::Shortcuts,
|
||||
_ => return,
|
||||
};
|
||||
self.control_tx.try_send(ControlCommand::Stop).unwrap();
|
||||
self.control_tx.try_send(ControlCommand::ChangeActiveTab(tab_active)).unwrap();
|
||||
|
||||
// if *self.gui_logging_state.lock().unwrap() == LoggingStates::Logging {
|
||||
// self.log_tx.try_send(LoggingSignal::StopFileLogging).unwrap_or_else(|e| {
|
||||
// error!("Failed to send logging logging signal: {:?}", e);
|
||||
// });
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -601,28 +622,34 @@ impl App {
|
||||
app_state_rx: watch::Receiver<AppState>,
|
||||
hardware_state_rx: watch::Receiver<HardwareState>) -> Self {
|
||||
// Step 1: Initialize shared fields first
|
||||
let tab_active = TabActive::Single;
|
||||
// let tab_active = app_state_rx.borrow().tab_active;
|
||||
|
||||
// Step 2: Now we can initialize tab_viewer
|
||||
let control_tx_clone = control_tx.clone();
|
||||
let app_state_clone = app_state_rx.clone();
|
||||
let hardware_state_clone = hardware_state_rx.clone();
|
||||
let tab_viewer = TabViewer { measurement_data: measurement_data.clone(),
|
||||
let log_filename = Arc::new(Mutex::new(format!("log_{}_single.csv", Local::now().format("%Y%m%d"))));
|
||||
let log_filename_clone = log_filename.clone();
|
||||
|
||||
let tab_viewer = CustomTabs {
|
||||
measurement_data: measurement_data.clone(),
|
||||
show_settings: false,
|
||||
show_settings_toggle: None,
|
||||
log_filename: log_filename_clone,
|
||||
control_tx: control_tx_clone,
|
||||
app_state_rx: app_state_clone,
|
||||
hardware_state_rx: hardware_state_clone
|
||||
};
|
||||
// tab_viewer.on_tab_button(&mut "Single".to_string(), &egui::Response::clicked());
|
||||
|
||||
// Step 3: Construct App
|
||||
let app = App {
|
||||
tree: DockState::new(vec!["Single".to_string(), "Sweep".to_string(), "Shortcuts".to_string()]),
|
||||
tab_viewer,
|
||||
tab_active,
|
||||
// tab_active,
|
||||
log_tx,
|
||||
gui_logging_state: Arc::new(Mutex::new(LoggingStates::Idle)),
|
||||
log_filename: format!("log_{}_single.csv", Local::now().format("%Y%m%d")),
|
||||
log_filename,
|
||||
log_marker_modal: false,
|
||||
log_marker: String::new(),
|
||||
measurement_data,
|
||||
@@ -654,7 +681,7 @@ impl App {
|
||||
}
|
||||
|
||||
pub fn toggle_start_stop(&self) {
|
||||
match (self.tab_active, self.hardware_state_rx.borrow().running) {
|
||||
match (self.app_state_rx.borrow().tab_active, self.hardware_state_rx.borrow().running) {
|
||||
(TabActive::Single, false) => {
|
||||
self.control_tx.try_send(ControlCommand::Start(Mode::Single)).unwrap();
|
||||
},
|
||||
@@ -724,7 +751,7 @@ impl eframe::App for App {
|
||||
|
||||
if ui.add_enabled(is_connected, custom_toggle_widget(&mut logging_enabled)).changed() {
|
||||
let signal = match gui_logging_state {
|
||||
LoggingStates::Idle => LoggingSignal::StartFileLogging(self.log_filename.clone()),
|
||||
LoggingStates::Idle => LoggingSignal::StartFileLogging(self.log_filename.lock().unwrap().clone()),
|
||||
LoggingStates::Starting | LoggingStates::Logging => LoggingSignal::StopFileLogging,
|
||||
};
|
||||
|
||||
@@ -792,7 +819,7 @@ impl eframe::App for App {
|
||||
|
||||
ui.add_enabled_ui(gui_logging_state == LoggingStates::Idle, |ui| {
|
||||
ui.label("Log filename:");
|
||||
TextEdit::singleline(&mut self.log_filename).desired_width(150.0).id(Id::new("file_name_field")).ui(ui);
|
||||
TextEdit::singleline(&mut *self.log_filename.lock().unwrap()).desired_width(150.0).id(Id::new("file_name_field")).ui(ui);
|
||||
});
|
||||
|
||||
// Spacer to push the LED to the right
|
||||
@@ -837,48 +864,6 @@ impl eframe::App for App {
|
||||
.show_inside(ui, &mut self.tab_viewer);
|
||||
});
|
||||
|
||||
// Do something when a tab is changed
|
||||
if let Some((_, tab)) = self.tree.find_active_focused() {
|
||||
match tab.as_str() {
|
||||
"Single" => {
|
||||
if self.tab_active != TabActive::Single {
|
||||
self.tab_active = TabActive::Single;
|
||||
self.control_tx.try_send(ControlCommand::Stop).unwrap();
|
||||
if *self.gui_logging_state.lock().unwrap() == LoggingStates::Logging {
|
||||
self.log_tx.try_send(LoggingSignal::StopFileLogging).unwrap_or_else(|e| {
|
||||
error!("Failed to send logging logging signal: {:?}", e);
|
||||
});
|
||||
}
|
||||
self.log_filename = format!("log_{}_single.csv", Local::now().format("%Y%m%d"));
|
||||
info!("Switched to Single tab");
|
||||
}
|
||||
}
|
||||
"Sweep" => {
|
||||
if self.tab_active != TabActive::Sweep {
|
||||
self.tab_active = TabActive::Sweep;
|
||||
self.control_tx.try_send(ControlCommand::Stop).unwrap();
|
||||
if *self.gui_logging_state.lock().unwrap() == LoggingStates::Logging {
|
||||
self.log_tx.try_send(LoggingSignal::StopFileLogging).unwrap_or_else(|e| {
|
||||
error!("Failed to send logging logging signal: {:?}", e);
|
||||
});
|
||||
}
|
||||
self.log_filename = format!("log_{}_sweep.csv", Local::now().format("%Y%m%d"));
|
||||
info!("Switched to Sweep tab");
|
||||
}
|
||||
}
|
||||
"Shortcuts" => {
|
||||
// if self.tab_active != TabActive::Shortcuts {
|
||||
// self.tab_active = TabActive::Shortcuts;
|
||||
// *self.on.lock().unwrap() = false;
|
||||
// self.update_start_stop();
|
||||
// info!("Switched to Shortcuts tab");
|
||||
// }
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CMD- or control-W to close window
|
||||
if ctx.input(|i| i.modifiers.cmd_ctrl_matches(Modifiers::COMMAND))
|
||||
&& ctx.input(|i| i.key_pressed(Key::W))
|
||||
@@ -927,7 +912,7 @@ impl eframe::App for App {
|
||||
}
|
||||
},
|
||||
LoggingStates::Idle => {
|
||||
if let Err(e) = self.log_tx.try_send(LoggingSignal::StartFileLogging(self.log_filename.clone())) {
|
||||
if let Err(e) = self.log_tx.try_send(LoggingSignal::StartFileLogging(self.log_filename.lock().unwrap().clone())) {
|
||||
error!("Failed to send logging signal: {:?}", e);
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user