diff --git a/src/ui/panes.rs b/src/ui/panes.rs
index d8e52d1e66f1ae3c67700db06202731c1d0e4b06..208b3ca6c23507c31e8442c67baac2aca5ea993a 100644
--- a/src/ui/panes.rs
+++ b/src/ui/panes.rs
@@ -1,6 +1,5 @@
 mod default;
 mod messages_viewer;
-mod pid;
 mod pid_drawing_tool;
 pub mod plot;
 
@@ -50,11 +49,8 @@ pub enum PaneKind {
     #[strum(message = "Plot 2D")]
     Plot2D(plot::Plot2DPane),
 
-    #[strum(message = "PID Old")]
+    #[strum(message = "Pid")]
     PidOld(pid_drawing_tool::PidPane),
-
-    #[strum(message = "PID New")]
-    Pid(pid::Pid),
 }
 
 impl Default for PaneKind {
diff --git a/src/ui/panes/pid_drawing_tool.rs b/src/ui/panes/pid_drawing_tool.rs
index 0b68be7608c1178dec86908d3a729a420c7870c9..26ca3ea3056035eb29826bb54806cb111e51d700 100644
--- a/src/ui/panes/pid_drawing_tool.rs
+++ b/src/ui/panes/pid_drawing_tool.rs
@@ -11,9 +11,8 @@ use elements::Element;
 use glam::Vec2;
 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};
 
@@ -207,22 +206,12 @@ impl PidPane {
             return;
         }
 
-        let elem_idx = self.hovers_element(pointer_pos);
-        if let Some(elem_idx) = elem_idx {
+        if let Some(elem_idx) = self.hovers_element(pointer_pos) {
             if ui.button("Connect").clicked() {
                 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 +240,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 +324,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..f64649842abc007f0dd81773b9737bc9757e2ca6 100644
--- a/src/ui/panes/pid_drawing_tool/elements.rs
+++ b/src/ui/panes/pid_drawing_tool/elements.rs
@@ -1,14 +1,16 @@
-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 crate::{error::ErrInstrument, msg_broker, MSG_MANAGER};
+
+use super::{
+    grid::GridInfo,
+    symbols::{icons::Icon, 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 +20,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 +35,6 @@ impl Element {
         Self {
             position: center - symbol.size() / 2.0,
             rotation: 0.0,
-            anchor_points: symbol.anchor_points(),
             symbol,
         }
     }
@@ -54,6 +48,7 @@ impl Element {
         // The bounding box is just the size
         let min_e = Vec2::ZERO;
         let max_e = self.symbol.size();
+        println!("size: {max_e:?}");
 
         // Check if the point is in the bounding box
         min_e.x <= p_e.x && p_e.x <= max_e.x && min_e.y <= p_e.y && p_e.y <= max_e.y
@@ -72,9 +67,28 @@ impl Element {
 
     pub fn change_symbol(&mut self, symbol: Symbol) {
         self.symbol = symbol;
+    }
 
-        // Anchor points can be different between symbols, realod the cache
-        self.reload_anchor_points();
+    pub fn get_symbol(&self) -> Symbol {
+        self.symbol.clone()
+    }
+
+    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 +101,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 +131,14 @@ 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);
+        let pos = grid.grid_to_screen(self.position);
+        let size = grid.size();
+        self.symbol.paint(ui, theme, pos, size, self.rotation);
 
-        if let Symbol::MotorValve(motor_valve) = &mut self.symbol {
+        if let Symbol::Icon(Icon::MotorValve(motor_valve)) = &mut self.symbol {
             msg_broker!().refresh_view(motor_valve).log_expect("bruh");
+        } else if let Symbol::Label(label) = &mut self.symbol {
+            msg_broker!().refresh_view(label).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
-    }
-}
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..5653b2635be6f62d10537c3be77b26c232051296 100644
--- a/src/ui/panes/pid_drawing_tool/symbols/icons.rs
+++ b/src/ui/panes/pid_drawing_tool/symbols/icons.rs
@@ -6,7 +6,11 @@ use motor_valve::MotorValve;
 use serde::{Deserialize, Serialize};
 use strum_macros::{Display, EnumIter};
 
-use crate::ui::utils::glam_to_egui;
+use crate::{
+    mavlink::{MessageBroker, ViewId},
+    msg_broker,
+    ui::utils::glam_to_egui,
+};
 
 use super::SymbolBehavior;
 
@@ -214,7 +218,7 @@ struct MavlinkValue {
     field: String,
 
     #[serde(skip)]
-    view_id: egui::Id,
+    view_id: ViewId,
 }
 
 #[derive(Deserialize)]
@@ -228,7 +232,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 {
diff --git a/src/ui/panes/pid_drawing_tool/symbols/labels.rs b/src/ui/panes/pid_drawing_tool/symbols/labels.rs
index 03c974fa193317cf2695ea64783c076477a012ee..7534969d4018fe799721a4b7e8486803eb4f26b9 100644
--- a/src/ui/panes/pid_drawing_tool/symbols/labels.rs
+++ b/src/ui/panes/pid_drawing_tool/symbols/labels.rs
@@ -1,17 +1,44 @@
 use serde::{Deserialize, Serialize};
+use skyward_mavlink::{mavlink::MessageData, orion};
 
-use crate::ui::utils::glam_to_egui;
+use crate::{
+    mavlink::{extract_from_message, MavlinkResult, MessageView, ViewId},
+    ui::utils::{egui_to_glam, glam_to_egui},
+};
 
-use super::SymbolBehavior;
+use super::{MavlinkValue, SymbolBehavior};
 use egui::{Align2, Color32, FontId, Rounding, Stroke, Theme, Ui};
 use glam::Vec2;
 
-#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
+const FONT_SIZE: f32 = 2.0;
+
+#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
 pub struct Label {
-    last_value: Option<f32>,
-    format_string: String,
+    text: String,
+    units: String,
     #[serde(skip)]
     show_window: bool,
+
+    last_value: Option<f32>,
+    source: MavlinkValue,
+    size: Vec2,
+}
+
+impl Default for Label {
+    fn default() -> Self {
+        Self {
+            text: "0.00".to_string(),
+            units: "".to_string(),
+            show_window: false,
+            source: MavlinkValue {
+                msg_id: orion::GSE_TM_DATA::ID,
+                field: "n2o_vessel_pressure".to_string(),
+                view_id: ViewId::new(),
+            },
+            last_value: Some(0.0),
+            size: Vec2::new(FONT_SIZE * 0.6 * 4.0, FONT_SIZE),
+        }
+    }
 }
 
 impl SymbolBehavior for Label {
@@ -22,13 +49,14 @@ impl SymbolBehavior for Label {
             Theme::Dark => Color32::WHITE,
         };
 
-        painter.text(
+        let text_rect = painter.text(
             glam_to_egui(pos).to_pos2(),
             Align2::LEFT_TOP,
-            &self.format_string,
-            FontId::monospace(self.size().y * size),
+            &self.text,
+            FontId::monospace(FONT_SIZE * size),
             color,
         );
+        self.size = egui_to_glam(text_rect.size()) / size;
         painter.rect(
             egui::Rect::from_min_size(
                 glam_to_egui(pos).to_pos2(),
@@ -48,7 +76,7 @@ impl SymbolBehavior for Label {
             .movable(true)
             .open(&mut show_window)
             .show(ui.ctx(), |ui| {
-                ui.text_edit_singleline(&mut self.format_string);
+                ui.text_edit_singleline(&mut self.units);
             });
         self.show_window = show_window;
     }
@@ -58,14 +86,54 @@ impl SymbolBehavior for Label {
     }
 
     fn size(&self) -> Vec2 {
-        let font_size = 2.0;
-        Vec2::new(font_size * 0.6 * self.format_string.len() as f32, font_size)
+        self.size
     }
 
     fn context_menu(&mut self, ui: &mut Ui) {
+        println!("Label context menu");
         if ui.button("Edit").clicked() {
             self.show_window = true;
             ui.close_menu();
         }
     }
 }
+
+impl MessageView for Label {
+    fn view_id(&self) -> ViewId {
+        self.source.view_id
+    }
+
+    fn id_of_interest(&self) -> u32 {
+        self.source.msg_id
+    }
+
+    fn is_valid(&self) -> bool {
+        self.last_value.is_some()
+    }
+
+    fn populate_view(
+        &mut self,
+        msg_slice: &[crate::mavlink::TimedMessage],
+    ) -> crate::mavlink::MavlinkResult<()> {
+        self.update_view(msg_slice)
+    }
+
+    fn update_view(
+        &mut self,
+        msg_slice: &[crate::mavlink::TimedMessage],
+    ) -> crate::mavlink::MavlinkResult<()> {
+        if let Some(msg) = msg_slice.last() {
+            let values: MavlinkResult<Vec<Option<f32>>> =
+                extract_from_message(&msg.message, [&self.source.field]);
+            if let Ok(values) = values {
+                if !values.is_empty() {
+                    if let Some(value) = values[0] {
+                        self.last_value = Some(value);
+                        self.text = format!("{:.2}{}", value, self.units);
+                    }
+                }
+            }
+        }
+        Ok(())
+    }
+}