diff --git a/src/ui/panes/pid_drawing_tool.rs b/src/ui/panes/pid_drawing_tool.rs
index 0b68be7608c1178dec86908d3a729a420c7870c9..35a766e5d90c57ee8de6f4e1de77a9c1a02990ff 100644
--- a/src/ui/panes/pid_drawing_tool.rs
+++ b/src/ui/panes/pid_drawing_tool.rs
@@ -13,7 +13,7 @@ use grid::GridInfo;
 use serde::{Deserialize, Serialize};
 use std::f32::consts::PI;
 use strum::IntoEnumIterator;
-use symbols::Symbol;
+use symbols::{icons::Icon, Symbol};
 
 use crate::ui::{composable_view::PaneResponse, utils::egui_to_glam};
 
@@ -213,16 +213,7 @@ impl PidPane {
                 self.action = Some(Action::Connect(elem_idx));
                 ui.close_menu();
             }
-            if ui.button("Rotate 90° ⟲").clicked() {
-                self.elements[elem_idx].rotate(-PI / 2.0);
-                self.action.take();
-                ui.close_menu();
-            }
-            if ui.button("Rotate 90° ⟳").clicked() {
-                self.elements[elem_idx].rotate(PI / 2.0);
-                self.action.take();
-                ui.close_menu();
-            }
+            self.elements[elem_idx].context_menu(ui);
             if ui.button("Delete").clicked() {
                 self.delete_element(elem_idx);
                 self.action.take();
@@ -251,7 +242,20 @@ impl PidPane {
         } else {
             ui.menu_button("Symbols", |ui| {
                 for symbol in Symbol::iter() {
-                    if ui.button(symbol.to_string()).clicked() {
+                    if let Symbol::Icon(_) = symbol {
+                        ui.menu_button("Icons", |ui| {
+                            for icon in Icon::iter() {
+                                if ui.button(icon.to_string()).clicked() {
+                                    self.elements.push(Element::new(
+                                        self.grid.screen_to_grid(pointer_pos).round(),
+                                        Symbol::Icon(icon),
+                                    ));
+                                    self.action.take();
+                                    ui.close_menu();
+                                }
+                            }
+                        });
+                    } else if ui.button(symbol.to_string()).clicked() {
                         self.elements.push(Element::new(
                             self.grid.screen_to_grid(pointer_pos).round(),
                             symbol,
@@ -322,8 +326,8 @@ impl PidPane {
             self.grid.apply_scroll_delta(scroll_delta, pointer_pos);
 
             // Invalidate the cache to redraw the images
-            for symbol in Symbol::iter() {
-                let img: egui::ImageSource = symbol.get_image(theme);
+            for icon in Icon::iter() {
+                let img: egui::ImageSource = icon.get_image(theme);
                 ui.ctx().forget_image(img.uri().unwrap());
             }
         }
diff --git a/src/ui/panes/pid_drawing_tool/elements.rs b/src/ui/panes/pid_drawing_tool/elements.rs
index db0c3154333913f315f573f46f4bc5d08b03161c..638f5ca4eee6781f0c58a56f13245b8e39249158 100644
--- a/src/ui/panes/pid_drawing_tool/elements.rs
+++ b/src/ui/panes/pid_drawing_tool/elements.rs
@@ -1,14 +1,14 @@
-use crate::{msg_broker, ui::utils::glam_to_egui};
+use std::f32::consts::PI;
 
-use super::grid::GridInfo;
-use super::symbols::Symbol;
-use crate::error::ErrInstrument;
-use egui::{Rect, Theme, Ui};
+use super::{
+    grid::GridInfo,
+    symbols::{Symbol, SymbolBehavior},
+};
+use egui::{Theme, Ui};
 use glam::{Mat2, Vec2};
 use serde::{Deserialize, Serialize};
 
 #[derive(Clone, Serialize, Deserialize, Debug)]
-#[serde(from = "SerialElement")]
 pub struct Element {
     /// Anchor postion in grid coordinates, top-left corner
     position: glam::Vec2,
@@ -18,13 +18,6 @@ pub struct Element {
 
     /// Rotation in radiants
     rotation: f32,
-
-    /// Anchor point in grid coordinates relative to the element's center
-    ///
-    /// These vectors include the current rotation of the element.
-    /// They are cached to avoid recomputing the rotation.
-    #[serde(skip)]
-    anchor_points: Vec<Vec2>,
 }
 
 impl PartialEq for Element {
@@ -40,7 +33,6 @@ impl Element {
         Self {
             position: center - symbol.size() / 2.0,
             rotation: 0.0,
-            anchor_points: symbol.anchor_points(),
             symbol,
         }
     }
@@ -72,9 +64,28 @@ impl Element {
 
     pub fn change_symbol(&mut self, symbol: Symbol) {
         self.symbol = symbol;
+    }
+
+    pub fn get_symbol(&self) -> Symbol {
+        self.symbol.clone()
+    }
 
-        // Anchor points can be different between symbols, realod the cache
-        self.reload_anchor_points();
+    pub fn context_menu(&mut self, ui: &mut Ui) {
+        match &mut self.symbol {
+            Symbol::Icon(_) => {
+                if ui.button("Rotate 90° ⟲").clicked() {
+                    self.rotate(-PI / 2.0);
+                    ui.close_menu();
+                }
+                if ui.button("Rotate 90° ⟳").clicked() {
+                    self.rotate(PI / 2.0);
+                    ui.close_menu();
+                }
+            }
+            Symbol::Label(label) => {
+                label.context_menu(ui);
+            }
+        }
     }
 
     /// Rotate the element by its center
@@ -87,31 +98,23 @@ impl Element {
 
         // Update absolute rotation
         self.rotation += rotation;
-
-        // Recompute anchor points cache
-        self.reload_anchor_points();
-    }
-
-    fn reload_anchor_points(&mut self) {
-        // Rotation matrix from element's frame to grid's frame
-        let rotm_e_to_g = Mat2::from_angle(self.rotation);
-
-        // Then rotate the anchor points
-        self.anchor_points = self
-            .symbol
-            .anchor_points()
-            .iter()
-            .map(|&p| rotm_e_to_g * p)
-            .collect();
     }
 
     /// Returns the position of one anchor point in grid coordinates
     pub fn anchor_point(&self, idx: usize) -> Vec2 {
-        self.anchor_points[idx] + self.position
+        if let Some(anchor_points) = self.symbol.anchor_points() {
+            // Rotation matrix from element's frame to grid's frame
+            let rotm_e_to_g = Mat2::from_angle(self.rotation);
+
+            // Then rotate and translate the anchor points
+            rotm_e_to_g * anchor_points[idx] + self.position
+        } else {
+            Vec2::ZERO
+        }
     }
 
     pub fn anchor_points_len(&self) -> usize {
-        self.anchor_points.len()
+        self.symbol.anchor_points().map_or(0, |v| v.len())
     }
 
     /// Size in grid units
@@ -125,35 +128,8 @@ impl Element {
     }
 
     pub fn draw(&mut self, grid: &GridInfo, ui: &Ui, theme: Theme) {
-        let center = glam_to_egui(grid.grid_to_screen(self.position)).to_pos2();
-        let image_rect = Rect::from_min_size(center, glam_to_egui(self.size() * grid.size()));
-
-        egui::Image::new(self.symbol.get_image(theme))
-            .rotate(self.rotation, egui::Vec2::splat(0.0))
-            .paint_at(ui, image_rect);
-
-        if let Symbol::MotorValve(motor_valve) = &mut self.symbol {
-            msg_broker!().refresh_view(motor_valve).log_expect("bruh");
-        }
-    }
-}
-
-#[derive(Deserialize)]
-pub struct SerialElement {
-    position: glam::Vec2,
-    symbol: Symbol,
-    rotation: f32,
-}
-
-impl From<SerialElement> for Element {
-    fn from(value: SerialElement) -> Self {
-        let mut value = Self {
-            position: value.position,
-            symbol: value.symbol,
-            rotation: value.rotation,
-            anchor_points: Vec::new(),
-        };
-        value.reload_anchor_points();
-        value
+        let pos = grid.grid_to_screen(self.position);
+        let size = grid.size();
+        self.symbol.paint(ui, theme, pos, size, self.rotation);
     }
 }
diff --git a/src/ui/panes/pid_drawing_tool/symbols.rs b/src/ui/panes/pid_drawing_tool/symbols.rs
index d4b92f3ed0f2f811c2b7f6d6b31cf2f1d6d32454..4f8f4a8b26befc953a20d79578743b82893eb20e 100644
--- a/src/ui/panes/pid_drawing_tool/symbols.rs
+++ b/src/ui/panes/pid_drawing_tool/symbols.rs
@@ -1,169 +1,64 @@
-mod motor_valve;
+pub mod icons;
+mod labels;
 
-use egui::{ImageSource, Theme};
+use crate::mavlink::ViewId;
+use egui::{Theme, Ui};
+use enum_dispatch::enum_dispatch;
 use glam::Vec2;
-use motor_valve::MotorValve;
+use icons::Icon;
+use labels::Label;
 use serde::{Deserialize, Serialize};
 use strum_macros::{Display, EnumIter};
 
-use crate::mavlink::ViewId;
-
 #[derive(Clone, Serialize, Deserialize, PartialEq, EnumIter, Display, Debug)]
+#[enum_dispatch]
 pub enum Symbol {
-    Arrow,
-    BurstDisk,
-    CheckValve,
-    FlexibleConnection,
-    ManualValve,
-    MotorValve(MotorValve),
-    PressureGauge,
-    PressureRegulator,
-    PressureTransducer,
-    QuickConnector,
-    ReliefValve,
-    ThreeWayValve,
-    Vessel,
+    Icon(Icon),
+    Label(Label),
 }
 
-impl Symbol {
-    pub fn get_image(&self, theme: Theme) -> ImageSource {
-        match (&self, theme) {
-            (Symbol::Arrow, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/arrow.svg")
-            }
-            (Symbol::Arrow, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/arrow.svg")
-            }
-            (Symbol::BurstDisk, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/burst_disk.svg")
-            }
-            (Symbol::BurstDisk, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/burst_disk.svg")
-            }
-            (Symbol::ManualValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/manual_valve.svg")
-            }
-            (Symbol::ManualValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/manual_valve.svg")
-            }
-            (Symbol::CheckValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/check_valve.svg")
-            }
-            (Symbol::CheckValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/check_valve.svg")
-            }
-            (Symbol::ReliefValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/relief_valve.svg")
-            }
-            (Symbol::ReliefValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/relief_valve.svg")
-            }
-            (Symbol::MotorValve(state), Theme::Light) => match state.last_value {
-                None => egui::include_image!("../../../../icons/pid_symbols/light/motor_valve.svg"),
-                Some(true) => {
-                    egui::include_image!(
-                        "../../../../icons/pid_symbols/light/motor_valve_green.svg"
-                    )
-                }
-                Some(false) => {
-                    egui::include_image!("../../../../icons/pid_symbols/light/motor_valve_red.svg")
-                }
-            },
-            (Symbol::MotorValve(state), Theme::Dark) => match state.last_value {
-                None => egui::include_image!("../../../../icons/pid_symbols/dark/motor_valve.svg"),
-                Some(true) => {
-                    egui::include_image!("../../../../icons/pid_symbols/dark/motor_valve_green.svg")
-                }
-                Some(false) => {
-                    egui::include_image!("../../../../icons/pid_symbols/dark/motor_valve_red.svg")
-                }
-            },
-            (Symbol::ThreeWayValve, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/three_way_valve.svg")
-            }
-            (Symbol::ThreeWayValve, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/three_way_valve.svg")
-            }
-            (Symbol::PressureRegulator, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/pressure_regulator.svg")
-            }
-            (Symbol::PressureRegulator, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/pressure_regulator.svg")
-            }
-            (Symbol::QuickConnector, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/quick_connector.svg")
-            }
-            (Symbol::QuickConnector, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/quick_connector.svg")
-            }
-            (Symbol::PressureTransducer, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/pressure_transducer.svg")
-            }
-            (Symbol::PressureTransducer, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/pressure_transducer.svg")
-            }
-            (Symbol::PressureGauge, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/pressure_gauge.svg")
-            }
-            (Symbol::PressureGauge, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/pressure_gauge.svg")
-            }
-            (Symbol::FlexibleConnection, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/flexible_connection.svg")
-            }
-            (Symbol::FlexibleConnection, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/flexible_connection.svg")
-            }
-            (Symbol::Vessel, Theme::Light) => {
-                egui::include_image!("../../../../icons/pid_symbols/light/vessel.svg")
-            }
-            (Symbol::Vessel, Theme::Dark) => {
-                egui::include_image!("../../../../icons/pid_symbols/dark/vessel.svg")
-            }
-        }
+impl Default for Symbol {
+    fn default() -> Self {
+        Symbol::Icon(Icon::default())
     }
+}
+
+#[enum_dispatch(Symbol)]
+pub trait SymbolBehavior {
+    fn paint(&mut self, ui: &Ui, theme: Theme, pos: Vec2, size: f32, rotation: f32);
+
+    /// Anchor point in grid coordinates relative to the element's center
+    ///
+    /// These vectors include the current rotation of the element.
+    /// They are cached to avoid recomputing the rotation.
+    fn anchor_points(&self) -> Option<Vec<Vec2>>;
 
     /// Symbol size in grid coordinates
-    pub fn size(&self) -> Vec2 {
-        match self {
-            Symbol::Arrow => (4.0, 4.0),
-            Symbol::BurstDisk => (4.0, 6.0),
-            Symbol::CheckValve => (10.0, 5.0),
-            Symbol::FlexibleConnection => (10.0, 6.0),
-            Symbol::ManualValve => (10.0, 5.0),
-            Symbol::MotorValve(_) => (10.0, 8.0),
-            Symbol::PressureGauge => (7.0, 7.0),
-            Symbol::PressureRegulator => (10.0, 10.0),
-            Symbol::PressureTransducer => (7.0, 7.0),
-            Symbol::QuickConnector => (6.0, 5.0),
-            Symbol::ReliefValve => (6.0, 10.0),
-            Symbol::ThreeWayValve => (10.0, 8.0),
-            Symbol::Vessel => (8.2, 15.2),
-        }
-        .into()
-    }
+    fn size(&self) -> Vec2;
 
-    /// Anchor point position relative to top right corner in grid units
-    pub fn anchor_points(&self) -> Vec<Vec2> {
-        match self {
-            Symbol::Arrow => vec![(0.0, 2.0), (4.0, 2.0)],
-            Symbol::BurstDisk => vec![(0.0, 3.0), (4.0, 3.0)],
-            Symbol::CheckValve => vec![(0.0, 2.5), (10.0, 2.5)],
-            Symbol::FlexibleConnection => vec![(0.0, 3.0), (10.0, 3.0)],
-            Symbol::ManualValve => vec![(0.0, 2.5), (10.0, 2.5)],
-            Symbol::MotorValve(_) => vec![(0.0, 5.0), (10.0, 5.0)],
-            Symbol::PressureGauge => vec![(3.5, 7.0)],
-            Symbol::PressureRegulator => vec![(0.0, 7.0), (10.0, 7.0)],
-            Symbol::PressureTransducer => vec![(3.5, 7.0)],
-            Symbol::QuickConnector => vec![(0.0, 2.5), (6.0, 2.5)],
-            Symbol::ReliefValve => vec![(3.0, 10.0)],
-            Symbol::ThreeWayValve => vec![(0.0, 3.0), (10.0, 3.0), (5.0, 8.0)],
-            Symbol::Vessel => vec![(0.0, 7.6), (8.2, 7.6), (4.1, 0.0), (4.1, 15.1)],
-        }
-        .iter()
-        .map(|&p| p.into())
-        .collect()
-    }
+    // /// Anchor point position relative to top right corner in grid units
+    // pub fn anchor_points(&self) -> Vec<Vec2> {
+    //     match self {
+    //         Symbol::Arrow => vec![(0.0, 2.0), (4.0, 2.0)],
+    //         Symbol::BurstDisk => vec![(0.0, 3.0), (4.0, 3.0)],
+    //         Symbol::CheckValve => vec![(0.0, 2.5), (10.0, 2.5)],
+    //         Symbol::FlexibleConnection => vec![(0.0, 3.0), (10.0, 3.0)],
+    //         Symbol::ManualValve => vec![(0.0, 2.5), (10.0, 2.5)],
+    //         Symbol::MotorValve(_) => vec![(0.0, 5.0), (10.0, 5.0)],
+    //         Symbol::PressureGauge => vec![(3.5, 7.0)],
+    //         Symbol::PressureRegulator => vec![(0.0, 7.0), (10.0, 7.0)],
+    //         Symbol::PressureTransducer => vec![(3.5, 7.0)],
+    //         Symbol::QuickConnector => vec![(0.0, 2.5), (6.0, 2.5)],
+    //         Symbol::ReliefValve => vec![(3.0, 10.0)],
+    //         Symbol::ThreeWayValve => vec![(0.0, 3.0), (10.0, 3.0), (5.0, 8.0)],
+    //         Symbol::Vessel => vec![(0.0, 7.6), (8.2, 7.6), (4.1, 0.0), (4.1, 15.1)],
+    //     }
+    //     .iter()
+    //     .map(|&p| p.into())
+    //     .collect()
+    // }
+
+    fn context_menu(&mut self, ui: &mut Ui) {}
 }
 
 /// Single MavLink value source info
diff --git a/src/ui/panes/pid_drawing_tool/symbols/icons.rs b/src/ui/panes/pid_drawing_tool/symbols/icons.rs
index 66192cc3f40199b4f83ecec56c3592415186713c..3ba10fe7b80793e1d20f5a42e3a09d49b342da4f 100644
--- a/src/ui/panes/pid_drawing_tool/symbols/icons.rs
+++ b/src/ui/panes/pid_drawing_tool/symbols/icons.rs
@@ -6,7 +6,7 @@ use motor_valve::MotorValve;
 use serde::{Deserialize, Serialize};
 use strum_macros::{Display, EnumIter};
 
-use crate::ui::utils::glam_to_egui;
+use crate::{mavlink::ViewId, ui::utils::glam_to_egui};
 
 use super::SymbolBehavior;
 
@@ -214,7 +214,7 @@ struct MavlinkValue {
     field: String,
 
     #[serde(skip)]
-    view_id: egui::Id,
+    view_id: ViewId,
 }
 
 #[derive(Deserialize)]
@@ -228,7 +228,7 @@ impl From<SerialMavlinkValue> for MavlinkValue {
         Self {
             msg_id: value.msg_id,
             field: value.field,
-            view_id: egui::Id::new(""),
+            view_id: ViewId::new(),
         }
     }
 }
diff --git a/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs b/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs
index af4f38f55f56eef934762ba41ab9218be32d8111..09819c6f1e26a087185386955b340e0e51338457 100644
--- a/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs
+++ b/src/ui/panes/pid_drawing_tool/symbols/icons/motor_valve.rs
@@ -1,4 +1,4 @@
-use crate::mavlink::{extract_from_message, MavlinkResult, MessageView, TimedMessage};
+use crate::mavlink::{extract_from_message, MavlinkResult, MessageView, TimedMessage, ViewId};
 
 use super::MavlinkValue;
 
@@ -19,7 +19,7 @@ impl Default for MotorValve {
             source: MavlinkValue {
                 msg_id: orion::GSE_TM_DATA::ID,
                 field: "n2o_filling_valve_state".to_string(),
-                view_id: egui::Id::new(""),
+                view_id: ViewId::new(),
             },
             last_value: None,
         }
@@ -27,8 +27,8 @@ impl Default for MotorValve {
 }
 
 impl MessageView for MotorValve {
-    fn widget_id(&self) -> &egui::Id {
-        &self.source.view_id
+    fn view_id(&self) -> crate::mavlink::ViewId {
+        self.source.view_id
     }
 
     fn id_of_interest(&self) -> u32 {