diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..23fd35f0e0e708ef622c7d957b9c8bb60c7876eb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} \ No newline at end of file diff --git a/src/mavlink/reflection.rs b/src/mavlink/reflection.rs index 4162f24df0f391d151a7c8664e6a747be13bb9cc..9ff04a4bfb6da4ac564972f1a6281debff575698 100644 --- a/src/mavlink/reflection.rs +++ b/src/mavlink/reflection.rs @@ -164,6 +164,14 @@ impl IndexedField { pub fn name(&self) -> &str { &self.field.name } + + pub fn extract_as_string<T: Message>(&self, message: &T) -> Result<String, String> { + let value = message + .get_field(self.id) + .ok_or("Field not found".to_string())?; + let str_value = format!("{:?}", value); + Ok(str_value) + } } /// ### Extractors diff --git a/src/ui/panes/messages_viewer.rs b/src/ui/panes/messages_viewer.rs index 5a43e635d04734573557c3fb40a71f3af6a4f974..4c5806170c817f1677e6fe9294ce106996c4d4b0 100644 --- a/src/ui/panes/messages_viewer.rs +++ b/src/ui/panes/messages_viewer.rs @@ -1,14 +1,13 @@ -use egui::{ScrollArea, Window, Response}; // Importa i moduli necessari da egui -use serde::{Serialize, Deserialize}; // Importa i moduli per la serializzazione e deserializzazione -use std::collections::{HashSet, HashMap}; // Importa HashSet e HashMap dalla libreria standard -use crate::mavlink::{TimedMessage, extract_from_message}; // Importa moduli specifici dal crate mavlink +use crate::MAVLINK_PROFILE; use crate::mavlink::reflection::ReflectionContext; // Importa ReflectionContext dal crate mavlink +use crate::mavlink::{TimedMessage}; // Importa moduli specifici dal crate mavlink use crate::ui::panes::{PaneBehavior, PaneResponse}; // Importa i comportamenti e le risposte del pannello -use crate::mavlink::Message; -use crate::MAVLINK_PROFILE; - +use crate::ui::shortcuts::ShortcutHandler; +use egui::{Response, ScrollArea, Window}; // Importa i moduli necessari da egui +use serde::{Deserialize, Serialize}; // Importa i moduli per la serializzazione e deserializzazione +use std::collections::{HashMap, HashSet}; // Importa HashSet e HashMap dalla libreria standard -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub struct MessagesViewerPane { #[serde(skip)] contains_pointer: bool, // Indica se il puntatore è contenuto nel pannello @@ -18,31 +17,30 @@ pub struct MessagesViewerPane { #[serde(skip)] settings_visible: bool, // Indica se le impostazioni sono visibili #[serde(skip)] - available_messages: Vec<String>, // Elenco dei messaggi disponibili + available_messages: Vec<u32>, // Elenco dei messaggi disponibili #[serde(skip)] - seen_message_types: HashSet<String>, // Tipi di messaggi visti + seen_message_types: HashSet<u32>, // Tipi di messaggi visti #[serde(skip)] - field_map: HashMap<String, Option<String>>, // Mappa dei campi + field_map: HashMap<usize, Option<String>>, // Mappa dei campi #[serde(skip)] selected_message: Option<u32>, // Messaggio selezionato #[serde(skip)] - selected_fields: HashSet<String>, // Campi selezionati + selected_fields: HashSet<usize>, // Campi selezionati #[serde(skip)] message_log: Vec<String>, // Registro dei messaggi sampling_frequency: f32, // Frequenza di campionamento } -impl Default for MessagesViewerPane { +impl Default for MessagesViewerPane { fn default() -> Self { Self { contains_pointer: false, settings_visible: false, items: vec![], settings: MsgSources::default(), - available_messages: ReflectionContext::new() - .sorted_messages() - .iter() - .map(|&s| s.to_string()) + available_messages: MAVLINK_PROFILE + .get_sorted_msgs().iter() + .map(|&s| s.id) .collect(), seen_message_types: HashSet::new(), sampling_frequency: 10.0, @@ -55,14 +53,19 @@ impl Default for MessagesViewerPane { } impl PaneBehavior for MessagesViewerPane { - fn ui(&mut self, ui: &mut egui::Ui, _tile_id: egui_tiles::TileId) -> PaneResponse { + fn ui(&mut self, ui: &mut egui::Ui, _shortcut_handler: &mut ShortcutHandler) -> PaneResponse { let response = PaneResponse::default(); // Crea una risposta predefinita del pannello ui.heading("Messages Viewer"); if ui.button("Open Message Filter").clicked() { self.settings_visible = true; // Mostra le impostazioni se il pulsante è cliccato } - + if self.settings_visible { + let msg_name = self + .selected_message + .and_then(|id| MAVLINK_PROFILE.get_msg(id)) + .map(|msg| msg.name.clone()) + .unwrap_or_else(|| "Select a message".to_string()); // Finestra di configurazione Window::new("Messages Viewer Settings") .collapsible(false) @@ -70,10 +73,20 @@ impl PaneBehavior for MessagesViewerPane { .open(&mut self.settings_visible) .show(ui.ctx(), |ui| { egui::ComboBox::new("message_kind", "Message Kind") - .selected_text(self.selected_message.clone().unwrap_or("Select a message".to_string())) + .selected_text(msg_name) .show_ui(ui, |ui| { for message_type in &self.available_messages { - if ui.selectable_label(self.selected_message.as_deref() == Some(message_type), message_type).clicked() { + let message_name = MAVLINK_PROFILE + .get_msg(*message_type) + .map(|msg| msg.name.clone()) + .unwrap(); + if ui + .selectable_label( + self.selected_message.is_some_and(|v| v == *message_type), + message_name, + ) + .clicked() + { self.selected_message = Some(message_type.clone()); self.selected_fields.clear(); } @@ -83,48 +96,48 @@ impl PaneBehavior for MessagesViewerPane { if let Some(ref selected_msg) = self.selected_message { ui.label("Select Fields:"); ScrollArea::both() - .auto_shrink([false, true]) - .max_width(300.0) - .max_height(100.0) - .show(ui, |ui| { - let mut select_all = false; - let mut deselect_all = false; - - if let Ok(fields) = MAVLINK_PROFILE.get_fields_by_name(selected_msg) { - if fields.len() > 1 { - ui.horizontal(|ui| { - ui.checkbox(&mut select_all, "Select All"); - ui.checkbox(&mut deselect_all, "Deselect All"); - }); + .auto_shrink([false, true]) + .max_width(300.0) + .max_height(100.0) + .show(ui, |ui| { + let mut select_all = false; + let mut deselect_all = false; + + if let Some(fields) = MAVLINK_PROFILE.get_fields(*selected_msg) { + if fields.len() > 1 { + ui.horizontal(|ui| { + ui.checkbox(&mut select_all, "Select All"); + ui.checkbox(&mut deselect_all, "Deselect All"); + }); + } } - } - if select_all { - if let Ok(fields) = MAVLINK_PROFILE.get_fields_by_name(selected_msg) { - for field in &fields { - self.selected_fields.insert(field.to_string()); + if select_all { + if let Some(fields) = MAVLINK_PROFILE.get_fields(*selected_msg) { + for field in &fields { + self.selected_fields.insert(field.id()); + } } } - } - - if deselect_all { - self.selected_fields.clear(); - } - if let Ok(fields) = ReflectionContext::new().get_fields_by_name(selected_msg) { - for field in fields { - let mut selected = self.selected_fields.contains(field); - let response: Response = ui.checkbox(&mut selected, field); - if response.clicked() { - if selected { - self.selected_fields.insert(field.to_string()); - } else { - self.selected_fields.remove(field); + if deselect_all { + self.selected_fields.clear(); + } + + if let Some(fields) = MAVLINK_PROFILE.get_fields(*selected_msg) { + for field in fields { + let mut selected = self.selected_fields.contains(&field.id()); + let response: Response = ui.checkbox(&mut selected, field.field().name.clone()); + if response.clicked() { + if selected { + self.selected_fields.insert(field.id()); + } else { + self.selected_fields.remove(&field.id()); + } } } } - } - }); + }); } ui.add_space(7.0); @@ -134,16 +147,17 @@ impl PaneBehavior for MessagesViewerPane { } egui::Grid::new("message_viewer").show(ui, |ui| { if let Some(selected_msg) = &self.selected_message { - if let Ok(fields) = MAVLINK_PROFILE.get_fields_by_name(selected_msg) { + if let Some(fields) = MAVLINK_PROFILE.get_fields(*selected_msg) { for field in fields { // Usa field come &str per il controllo - if self.selected_fields.contains(field) { - let value = self.field_map - .get(field) + if self.selected_fields.contains(&field.id()) { + let value = self + .field_map + .get(&field.id()) .and_then(|v| v.as_deref()) .unwrap_or("N/A"); - - ui.label(field); + + ui.label(field.field().name.clone()); ui.label(value); ui.end_row(); } @@ -154,39 +168,29 @@ impl PaneBehavior for MessagesViewerPane { } }); - - response } - - fn contains_pointer(&self) -> bool { - self.contains_pointer - } - -fn update(&mut self, messages: &[TimedMessage]) { - for msg in messages { - if let Some(selected_msg) = &self.selected_message { - - if let Ok(fields) = MAVLINK_PROFILE.get_fields(selected_msg) { + fn update(&mut self, messages: &[&TimedMessage]) { + for msg in messages { + if let Some(selected_msg) = &self.selected_message { + if let Some(fields) = MAVLINK_PROFILE.get_fields(*selected_msg) { for field in fields { - if self.selected_fields.contains(field) { - if let Ok(values) = extract_from_message(&msg.message, &[field]) { - if !values.is_empty() { - let value: f64 = values[0]; - self.field_map.insert(field.to_string(), Some(value.to_string())); - } + if self.selected_fields.contains(&field.id()) { + if let Ok(value) = field.extract_as_f64(&msg.message) { + self.field_map + .insert(field.id(), Some(value.to_string())); + } } } } } } - -} + } - fn get_message_subscription(&self) -> Option<u32> { - None + fn get_message_subscriptions(&self) -> Box<dyn Iterator<Item = u32>> { + Box::new(self.selected_message.clone().into_iter()) } fn should_send_message_history(&self) -> bool { @@ -213,4 +217,4 @@ impl PartialEq for MsgSources { fn eq(&self, other: &Self) -> bool { self.msg_id == other.msg_id && self.fields_with_checkbox == other.fields_with_checkbox } -} \ No newline at end of file +}