From c5f2ac785105d4ef906cc69a9e8e5041c16f79e5 Mon Sep 17 00:00:00 2001
From: Alberto Nidasio <alberto.nidasio@skywarder.eu>
Date: Sat, 11 Jan 2025 19:19:28 +0100
Subject: [PATCH] Reorganized PID structs into submodules

---
 src/ui/app.rs                                 |  4 +-
 src/ui/panes.rs                               |  2 +-
 src/ui/panes/pid_drawing_tool.rs              | 89 ++++++++++++-------
 src/ui/panes/pid_drawing_tool/pid_elements.rs | 48 ----------
 4 files changed, 58 insertions(+), 85 deletions(-)
 delete mode 100644 src/ui/panes/pid_drawing_tool/pid_elements.rs

diff --git a/src/ui/app.rs b/src/ui/app.rs
index b3faad0..6947aeb 100644
--- a/src/ui/app.rs
+++ b/src/ui/app.rs
@@ -425,7 +425,7 @@ impl Behavior<Pane> for AppBehavior {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub struct PaneResponse {
     pub action_called: Option<PaneAction>,
     pub drag_response: egui_tiles::UiResponse,
@@ -450,7 +450,7 @@ impl Default for PaneResponse {
     }
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub enum PaneAction {
     SplitH,
     SplitV,
diff --git a/src/ui/panes.rs b/src/ui/panes.rs
index 0bf1385..d51fea6 100644
--- a/src/ui/panes.rs
+++ b/src/ui/panes.rs
@@ -13,7 +13,7 @@ use crate::mavlink::{MavMessage, TimedMessage};
 
 use super::app::PaneResponse;
 
-#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
+#[derive(Clone, PartialEq, Default, Serialize, Deserialize)]
 pub struct Pane {
     pub pane: PaneKind,
 }
diff --git a/src/ui/panes/pid_drawing_tool.rs b/src/ui/panes/pid_drawing_tool.rs
index 26150f1..c704868 100644
--- a/src/ui/panes/pid_drawing_tool.rs
+++ b/src/ui/panes/pid_drawing_tool.rs
@@ -1,22 +1,34 @@
-mod pid_elements;
-
-use egui::{epaint::PathStroke, Color32, PointerButton, Pos2, Sense, Theme, Vec2};
-use pid_elements::{PidElement, PidSymbol};
+mod connections;
+mod elements;
+mod pos;
+mod symbols;
+
+use connections::Connection;
+use egui::{epaint::PathStroke, Color32, CursorIcon, PointerButton, Pos2, Sense, Theme, Vec2};
+use elements::Element;
+use pos::Pos;
 use serde::{Deserialize, Serialize};
 use std::f32::consts::PI;
 use strum::IntoEnumIterator;
+use symbols::Symbol;
 
 use crate::ui::composable_view::PaneResponse;
 
 use super::PaneBehavior;
 
-#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq)]
+/// Piping and instrumentation diagram
+#[derive(Default, Clone, Serialize, Deserialize, PartialEq)]
 pub struct PidPane {
-    elements: Vec<PidElement>,
+    elements: Vec<Element>,
+    connections: Vec<Connection>,
+
+    /// Index of the element the drag operation started on
     dragged: Option<usize>,
-    context_menu_pos: (i32, i32),
+
+    /// Index of the element the connection operation started on
     connect_element: Option<usize>,
-    connections: Vec<(usize, usize)>,
+
+    context_menu_pos: Pos,
 }
 
 impl PaneBehavior for PidPane {
@@ -25,6 +37,9 @@ impl PaneBehavior for PidPane {
         let window_rect = ui.max_rect();
         let painter = ui.painter();
 
+        ui.ctx()
+            .output_mut(|output| output.cursor_icon = CursorIcon::Grab);
+
         let theme = ui.ctx().options(|options| match options.theme_preference {
             egui::ThemePreference::Light => Theme::Light,
             egui::ThemePreference::Dark => Theme::Dark,
@@ -55,13 +70,13 @@ impl PaneBehavior for PidPane {
         }
 
         for connection in &self.connections {
-            let elem1 = &self.elements[connection.0];
-            let elem2 = &self.elements[connection.1];
+            let elem1 = &self.elements[connection.start];
+            let elem2 = &self.elements[connection.end];
 
-            let x1 = (elem1.pos.0 + elem1.size / 2) * step_size;
-            let y1 = (elem1.pos.1 + elem1.size / 2) * step_size;
-            let x2 = (elem2.pos.0 + elem2.size / 2) * step_size;
-            let y2 = (elem2.pos.1 + elem2.size / 2) * step_size;
+            let x1 = (elem1.position.x + elem1.size / 2) * step_size;
+            let y1 = (elem1.position.y + elem1.size / 2) * step_size;
+            let x2 = (elem2.position.x + elem2.size / 2) * step_size;
+            let y2 = (elem2.position.y + elem2.size / 2) * step_size;
 
             painter.line_segment(
                 [
@@ -76,8 +91,8 @@ impl PaneBehavior for PidPane {
         for element in &self.elements {
             let image_rect = egui::Rect::from_min_size(
                 egui::Pos2::new(
-                    (element.pos.0 * step_size) as f32,
-                    (element.pos.1 * step_size) as f32,
+                    (element.position.x * step_size) as f32,
+                    (element.position.y * step_size) as f32,
                 ),
                 egui::Vec2::new(
                     (element.size * step_size) as f32,
@@ -85,7 +100,7 @@ impl PaneBehavior for PidPane {
                 ),
             );
 
-            egui::Image::new(element.get_image(theme))
+            egui::Image::new(element.symbol.get_image(theme))
                 .rotate(element.rotation, Vec2::new(0.5, 0.5))
                 .paint_at(ui, image_rect);
         }
@@ -94,21 +109,24 @@ impl PaneBehavior for PidPane {
 
         let pointer_pos = response
             .hover_pos()
-            .map(|pos| (pos.x as i32 / step_size, pos.y as i32 / step_size))
-            .unwrap_or((0, 0));
+            .map(|pos| Pos {
+                x: pos.x as i32 / step_size,
+                y: pos.y as i32 / step_size,
+            })
+            .unwrap_or(Pos { x: 0, y: 0 });
 
         if response.clicked_by(PointerButton::Secondary) {
-            self.context_menu_pos = pointer_pos;
+            self.context_menu_pos = pointer_pos.clone();
         }
         response.context_menu(|ui| {
             ui.set_max_width(200.0); // To make sure we wrap long text
 
-            if self.is_hovering_element(self.context_menu_pos) {
+            if self.is_hovering_element(&self.context_menu_pos) {
                 if ui.button("Connect").clicked() {
                     self.connect_element = self
                         .elements
                         .iter()
-                        .position(|element| element.contains(self.context_menu_pos));
+                        .position(|element| element.contains(&self.context_menu_pos));
                     ui.close_menu();
                 }
 
@@ -116,7 +134,7 @@ impl PaneBehavior for PidPane {
                     if let Some(elem) = self
                         .elements
                         .iter_mut()
-                        .find(|element| element.contains(self.context_menu_pos))
+                        .find(|element| element.contains(&self.context_menu_pos))
                     {
                         elem.rotation += PI / 2.0;
                     }
@@ -126,7 +144,7 @@ impl PaneBehavior for PidPane {
                     if let Some(elem) = self
                         .elements
                         .iter_mut()
-                        .find(|element| element.contains(self.context_menu_pos))
+                        .find(|element| element.contains(&self.context_menu_pos))
                     {
                         elem.rotation -= PI / 2.0;
                     }
@@ -135,13 +153,13 @@ impl PaneBehavior for PidPane {
             }
 
             ui.menu_button("Symbols", |ui| {
-                for symbol in PidSymbol::iter() {
+                for symbol in Symbol::iter() {
                     if ui.button(symbol.to_string()).clicked() {
-                        self.elements.push(PidElement {
-                            pos: self.context_menu_pos,
+                        self.elements.push(Element {
+                            position: self.context_menu_pos.clone(),
                             size: 10,
-                            symbol,
                             rotation: 0.0,
+                            symbol,
                         });
                         ui.close_menu();
                     }
@@ -153,11 +171,14 @@ impl PaneBehavior for PidPane {
             let second_connect_element = self
                 .elements
                 .iter()
-                .position(|element| element.contains(pointer_pos));
+                .position(|element| element.contains(&pointer_pos));
 
             if let (Some(elem1), Some(elem2)) = (self.connect_element, second_connect_element) {
                 if elem1 != elem2 {
-                    self.connections.push((elem1, elem2));
+                    self.connections.push(Connection {
+                        start: elem1,
+                        end: elem2,
+                    });
                 }
                 self.connect_element.take();
             }
@@ -168,14 +189,14 @@ impl PaneBehavior for PidPane {
             self.dragged = self
                 .elements
                 .iter()
-                .position(|element| element.contains(pointer_pos));
+                .position(|element| element.contains(&pointer_pos));
         }
         if response.dragged() {
             if let Some(dragged) = self.dragged {
                 let element = &mut self.elements[dragged];
 
-                element.pos.0 = pointer_pos.0 - element.size / 2;
-                element.pos.1 = pointer_pos.1 - element.size / 2;
+                element.position.x = pointer_pos.x - element.size / 2;
+                element.position.y = pointer_pos.y - element.size / 2;
             }
         }
         if response.drag_stopped() {
@@ -191,7 +212,7 @@ impl PaneBehavior for PidPane {
 }
 
 impl PidPane {
-    fn is_hovering_element(&self, pointer_pos: (i32, i32)) -> bool {
+    fn is_hovering_element(&self, pointer_pos: &Pos) -> bool {
         self.elements
             .iter()
             .find(|element| element.contains(pointer_pos))
diff --git a/src/ui/panes/pid_drawing_tool/pid_elements.rs b/src/ui/panes/pid_drawing_tool/pid_elements.rs
deleted file mode 100644
index fd571ae..0000000
--- a/src/ui/panes/pid_drawing_tool/pid_elements.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-use egui::{ImageSource, Theme};
-use serde::{Deserialize, Serialize};
-use strum_macros::{Display, EnumIter};
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct PidElement {
-    pub pos: (i32, i32),
-    pub size: i32,
-    pub symbol: PidSymbol,
-    pub rotation: f32,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, EnumIter, Display)]
-pub enum PidSymbol {
-    BallValve,
-    CheckValve,
-    PressurizedVessel,
-}
-
-impl PidElement {
-    pub fn contains(&self, pos: (i32, i32)) -> bool {
-        (pos.0 >= self.pos.0 && pos.0 < (self.pos.0 + self.size))
-            && (pos.1 >= self.pos.1 && pos.1 < (self.pos.1 + self.size))
-    }
-
-    pub fn get_image(&self, theme: Theme) -> ImageSource {
-        match (&self.symbol, theme) {
-            (PidSymbol::BallValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/ball_valve_light.svg")
-            }
-            (PidSymbol::BallValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/ball_valve_dark.svg")
-            }
-            (PidSymbol::CheckValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/check_valve_light.svg")
-            }
-            (PidSymbol::CheckValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/check_valve_dark.svg")
-            }
-            (PidSymbol::PressurizedVessel, Theme::Light) => {
-                egui::include_image!("../../../../icons/pressurized_vessel_light.svg")
-            }
-            (PidSymbol::PressurizedVessel, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pressurized_vessel_dark.svg")
-            }
-        }
-    }
-}
-- 
GitLab