From 84455e92544a60dc7d1e9b6ba3c9db535c6e5c5e Mon Sep 17 00:00:00 2001 From: Markus Zehnder Date: Sun, 24 Aug 2025 21:18:56 +0200 Subject: [PATCH] refactor: sensor configuration fields Automatically round decimal values for sensor.x and .y to an integer. Make fields optional which are not used in every sensor. --- doc/sensor_mode1_text.md | 2 -- doc/sensor_mode2_fan.md | 5 ---- doc/sensor_mode3_progress.md | 14 ----------- doc/sensor_mode4_pointer.md | 6 ----- src/cfg.rs | 47 +++++++++++++++++++++++------------- src/render.rs | 38 +++++++++++++++-------------- 6 files changed, 50 insertions(+), 62 deletions(-) diff --git a/doc/sensor_mode1_text.md b/doc/sensor_mode1_text.md index d429afb..43d2bd7 100644 --- a/doc/sensor_mode1_text.md +++ b/doc/sensor_mode1_text.md @@ -53,7 +53,6 @@ The background image and sensor definitions are taken from the default system pa "sensor": [ { "mode": 1, - "type": 1, "name": "CPU temp", "label": "cpu_temperature", "x": 195, @@ -67,7 +66,6 @@ The background image and sensor definitions are taken from the default system pa }, { "mode": 1, - "type": 1, "name": "CPU usage", "label": "cpu_percent", "unit": "%", diff --git a/doc/sensor_mode2_fan.md b/doc/sensor_mode2_fan.md index 5119875..a61780e 100644 --- a/doc/sensor_mode2_fan.md +++ b/doc/sensor_mode2_fan.md @@ -31,7 +31,6 @@ Example `panel.json` with a single "fan" indicator sensor and the following (par "id": "29d9ef2d-30b4-459d-b2b0-43cb6d4d6b41", "itemName": "CPU usage", "mode": 2, - "type": 1, "direction": 1, "label": "cpu_percent", "value": "47.7", @@ -39,10 +38,6 @@ Example `panel.json` with a single "fan" indicator sensor and the following (par "y": 184, "width": 237, "height": 237, - "fontColor": "#ffffff", - "fontSize": 14, - "fontFamily": "default_font", - "textAlign": "left", "minAngle": -160, "maxAngle": 30, "minValue": 0, diff --git a/doc/sensor_mode3_progress.md b/doc/sensor_mode3_progress.md index 0fafaad..b6b84cf 100644 --- a/doc/sensor_mode3_progress.md +++ b/doc/sensor_mode3_progress.md @@ -25,41 +25,30 @@ The background image and sensor definitions are taken from the default system pa "sensor": [ { "mode": 3, - "type": 2, "name": "SSD 4 usage", "label": "storage_ssd4_usage", "x": 400, "y": 45, "direction": 1, "value": "35", - "fontFamily": "HarmonyOS_Sans_SC_Bold", - "fontSize": 24, - "fontColor": -1, - "textAlign": "center", "minValue": 0, "maxValue": 100, "pic": "progress.png" }, { "mode": 3, - "type": 2, "name": "SSD 5 usage", "label": "storage_ssd5_usage", "x": 400, "y": 106, "direction": 1, "value": "80", - "fontFamily": "HarmonyOS_Sans_SC_Bold", - "fontSize": 24, - "fontColor": -1, - "textAlign": "center", "minValue": 0, "maxValue": 100, "pic": "progress.png" }, { "mode": 1, - "type": 2, "name": "SSD 4 temp", "label": "storage_ssd4_temperature", "x": 580, @@ -68,7 +57,6 @@ The background image and sensor definitions are taken from the default system pa "value": "34", "fontFamily": "HarmonyOS_Sans_SC_Bold", "fontSize": 24, - "fontColor": -1, "textAlign": "center", "integerDigits": -1, "decimalDigits": 0, @@ -76,7 +64,6 @@ The background image and sensor definitions are taken from the default system pa }, { "mode": 1, - "type": 2, "name": "SSD 5 temp", "label": "storage_ssd5_temperature", "x": 580, @@ -85,7 +72,6 @@ The background image and sensor definitions are taken from the default system pa "value": "35", "fontFamily": "HarmonyOS_Sans_SC_Bold", "fontSize": 24, - "fontColor": -1, "textAlign": "center", "integerDigits": -1, "decimalDigits": 0, diff --git a/doc/sensor_mode4_pointer.md b/doc/sensor_mode4_pointer.md index ac07e47..5110ff6 100644 --- a/doc/sensor_mode4_pointer.md +++ b/doc/sensor_mode4_pointer.md @@ -31,7 +31,6 @@ Example `panel.json` with a single "pointer" indicator sensor and the following "id": "a9d4acac-2af9-4fe0-9f69-86cd09f25696", "itemName": "CPU dial", "mode": 4, - "type": 1, "direction": 1, "label": "cpu_percent", "value": "47.7", @@ -39,11 +38,6 @@ Example `panel.json` with a single "pointer" indicator sensor and the following "y": 208, "width": 302, "height": 302, - "fontColor": "#ffffff", - "fontSize": 14, - "fontFamily": "", - "fontWeight": "normal", - "textAlign": "left", "minAngle": -110, "maxAngle": 110, "minValue": 0, diff --git a/src/cfg.rs b/src/cfg.rs index 8540db7..63f7b5e 100644 --- a/src/cfg.rs +++ b/src/cfg.rs @@ -91,8 +91,11 @@ pub fn load_custom_panel>(path: P) -> anyhow::Result { { sensor.pic = Some(img_path.join(pic).display().to_string()); } - if !sensor.font_family.is_empty() && !Path::new(&sensor.font_family).is_absolute() { - sensor.font_family = font_path.join(&sensor.font_family).display().to_string(); + if let Some(font_family) = &sensor.font_family + && !font_family.is_empty() + && !Path::new(&font_family).is_absolute() + { + sensor.font_family = Some(font_path.join(font_family).display().to_string()); } } @@ -283,7 +286,7 @@ impl Panel { pub struct Sensor { /// Sensor mode: text, fan, progress, pointer pub mode: SensorMode, - /// Sensor type. TODO verify sensor type values + /// Sensor type, _not used_. /// - 1 Time / Date Labels /// - 2 Windows-specific system info /// - 3 Hardware value @@ -293,7 +296,7 @@ pub struct Sensor { /// - 7 system info ? /// - 8 lm-sensor ? #[serde(rename = "type")] - pub sensor_type: i32, + pub sensor_type: Option, /// Label name for internal panels. pub name: Option, /// Label name for custom panels. @@ -312,12 +315,12 @@ pub struct Sensor { /// Optional unit text to print after the value #[serde(deserialize_with = "empty_string_as_none")] pub unit: Option, - /// x-position. Custom panel coordinates are stored as float! - // TODO use i32 and round from f32 in deserialization - pub x: f32, - /// y-position. - // TODO use i32 and round from f32 in deserialization - pub y: f32, + /// Rounded x-position. Custom panel coordinates are stored as float! + #[serde(deserialize_with = "f32_as_rounded_i32")] + pub x: i32, + /// Rounded y-position. Custom panel coordinates are stored as float! + #[serde(deserialize_with = "f32_as_rounded_i32")] + pub y: i32, /// Used for pointer type pub width: Option, /// Used for pointer type @@ -326,14 +329,14 @@ pub struct Sensor { pub direction: Option, /// Font name matching font filename without file extension. - pub font_family: String, + pub font_family: Option, /// TODO font size unit: points or pixels? - pub font_size: i32, + pub font_size: Option, /// Font color in `#RRGGBB` notation, or -1 if not set. #ffffff = white, #ff0000 = red - pub font_color: FontColor, + pub font_color: Option, /// _Not (yet) used_ - pub font_weight: FontWeight, - pub text_align: TextAlign, + pub font_weight: Option, + pub text_align: Option, /// Number of integer places for the sensor value. // -1 ≈ unset ⇒ Option @@ -429,16 +432,18 @@ pub enum TimeDateLabel { HM3, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum FontWeight { + #[default] Normal, Bold, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Copy, Clone, Default, Serialize, Deserialize)] #[serde(rename_all = "lowercase")] pub enum TextAlign { + #[default] Left, Center, Right, @@ -569,3 +574,11 @@ where let option = Option::::deserialize(deserializer)?; Ok(option.and_then(|s| if s.trim().is_empty() { None } else { Some(s) })) } + +fn f32_as_rounded_i32<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let rounded = f32::deserialize(deserializer).map(f32::round)?; + Ok(rounded as i32) +} diff --git a/src/render.rs b/src/render.rs index 94493a7..54d9c3c 100644 --- a/src/render.rs +++ b/src/render.rs @@ -205,15 +205,16 @@ impl PanelRenderer { value: &str, unit: &str, ) -> Result<(), ImageProcessingError> { - let font = self - .font_handler - .get_ttf_font_or_default(&sensor.font_family); + let font = if let Some(font_family) = &sensor.font_family { + self.font_handler.get_ttf_font_or_default(font_family) + } else { + FontHandler::default_font() + }; + let font_size = sensor.font_size.unwrap_or(14) as f32; // TODO verify pixel scaling! Is font_size point size or pixel size? // This is still a bit off compared to the original AOOSTAR-X. Only tested with HarmonyOS_Sans_SC_Bold! let adjustment_hack = 0.7; - let scale = font - .pt_to_px_scale(sensor.font_size as f32 * adjustment_hack) - .unwrap(); + let scale = font.pt_to_px_scale(font_size * adjustment_hack).unwrap(); let text = format_value( value, @@ -223,12 +224,12 @@ impl PanelRenderer { ); let size = text_size(scale, &font, &text); // TODO verify x & y-coordinate handling - let x = match sensor.text_align { - TextAlign::Left => sensor.x as i32, - TextAlign::Center => sensor.x as i32 - (size.0 / 2) as i32, - TextAlign::Right => sensor.x as i32 - size.0 as i32, + let x = match sensor.text_align.unwrap_or_default() { + TextAlign::Left => sensor.x, + TextAlign::Center => sensor.x - (size.0 / 2) as i32, + TextAlign::Right => sensor.x - size.0 as i32, }; - let y = (sensor.y - scale.y / 2f32) as i32; + let y = (sensor.y as f32 - scale.y / 2f32) as i32; // let y = sensor.y as i32 - (size.1 / 2) as i32; debug!( @@ -236,7 +237,7 @@ impl PanelRenderer { sensor.x, sensor.y ); - let font_color = sensor.font_color.into(); + let font_color = sensor.font_color.unwrap_or_default().into(); draw_text_mut(background, font_color, x, y, scale, &font, &text); Ok(()) @@ -257,8 +258,8 @@ impl PanelRenderer { return Err(ImageProcessingError::InvalidDirection(direction)); } - let pos_x = sensor.x as i32; - let pos_y = sensor.y as i32; + let pos_x = sensor.x; + let pos_y = sensor.y; let pic_path = sensor.pic.as_ref().ok_or_else(|| { ImageProcessingError::ImageLoadError("No picture specified".to_string()) @@ -385,8 +386,8 @@ impl PanelRenderer { } } - let pos_x = sensor.x as i32; - let pos_y = sensor.y as i32; + let pos_x = sensor.x; + let pos_y = sensor.y; if let Some(progress_layer) = self.get_layer(SensorMode::Progress) { PanelRenderer::paste_image(progress_layer, &processed_img, pos_x, pos_y); @@ -420,8 +421,8 @@ impl PanelRenderer { return Err(ImageProcessingError::InvalidDirection(direction)); } - let x_center = sensor.x as i32; - let y_center = sensor.y as i32; + let x_center = sensor.x; + let y_center = sensor.y; let xz_x = sensor.xz_x.unwrap_or(0); let xz_y = sensor.xz_y.unwrap_or(0); @@ -429,6 +430,7 @@ impl PanelRenderer { ImageProcessingError::ImageLoadError("No picture specified".to_string()) })?; + // TODO combine get image with resize let mut pic = self .image_cache .get(pic_path, None)