From cdf4ed3882d09ca2e7eb8f9c5444608de64b82d4 Mon Sep 17 00:00:00 2001 From: galister <22305755+galister@users.noreply.github.com> Date: Thu, 8 Jan 2026 19:16:11 +0900 Subject: [PATCH] more useful parser warnings + cleanups --- dash-frontend/assets/gui/dashboard.xml | 4 +- wgui/src/parser/component_button.rs | 30 ++- wgui/src/parser/component_checkbox.rs | 11 +- wgui/src/parser/component_radio_group.rs | 7 +- wgui/src/parser/component_slider.rs | 17 +- wgui/src/parser/mod.rs | 241 ++++++++++----------- wgui/src/parser/style.rs | 114 +++++----- wgui/src/parser/widget_div.rs | 7 +- wgui/src/parser/widget_image.rs | 17 +- wgui/src/parser/widget_label.rs | 12 +- wgui/src/parser/widget_rectangle.rs | 21 +- wgui/src/parser/widget_sprite.rs | 13 +- wgui/src/windowing/window.rs | 7 +- wlx-overlay-s/src/assets/gui/keyboard.xml | 23 +- wlx-overlay-s/src/assets/gui/watch.xml | 28 +-- wlx-overlay-s/src/gui/panel/button.rs | 105 ++++----- wlx-overlay-s/src/gui/panel/device_list.rs | 2 - wlx-overlay-s/src/gui/panel/label.rs | 61 ++++-- wlx-overlay-s/src/gui/panel/mod.rs | 38 +++- wlx-overlay-s/src/main.rs | 1 + 20 files changed, 399 insertions(+), 360 deletions(-) diff --git a/dash-frontend/assets/gui/dashboard.xml b/dash-frontend/assets/gui/dashboard.xml index 5d214f2..9a0c017 100644 --- a/dash-frontend/assets/gui/dashboard.xml +++ b/dash-frontend/assets/gui/dashboard.xml @@ -29,7 +29,7 @@
- \ No newline at end of file + diff --git a/wgui/src/parser/component_button.rs b/wgui/src/parser/component_button.rs index 9857d80..aa58840 100644 --- a/wgui/src/parser/component_button.rs +++ b/wgui/src/parser/component_button.rs @@ -5,7 +5,7 @@ use crate::{ i18n::Translation, layout::WidgetID, parser::{ - parse_check_f32, parse_check_i32, parse_children, parse_f32, print_invalid_attrib, process_component, + parse_children, parse_f32, process_component, style::{parse_color_opt, parse_round, parse_style, parse_text_style}, AttribPair, ParserContext, ParserFile, }, @@ -19,6 +19,7 @@ pub fn parse_component_button<'a>( node: roxmltree::Node<'a, 'a>, parent_id: WidgetID, attribs: &[AttribPair], + tag_name: &str, ) -> anyhow::Result { let mut color: Option = None; let mut border = 2.0; @@ -34,8 +35,8 @@ pub fn parse_component_button<'a>( let mut translation: Option = None; - let text_style = parse_text_style(attribs); - let style = parse_style(attribs); + let text_style = parse_text_style(ctx, attribs, tag_name); + let style = parse_style(ctx, attribs, tag_name); for pair in attribs { let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref()); @@ -51,22 +52,29 @@ pub fn parse_component_button<'a>( } } "round" => { - parse_round(value, &mut round, ctx.doc_params.globals.get().defaults.rounding_mult); + parse_round( + ctx, + tag_name, + key, + value, + &mut round, + ctx.doc_params.globals.get().defaults.rounding_mult, + ); } "color" => { - parse_color_opt(value, &mut color); + parse_color_opt(ctx, tag_name, key, value, &mut color); } "border" => { - parse_check_f32(value, &mut border); + ctx.parse_check_f32(tag_name, key, value, &mut border); } "border_color" => { - parse_color_opt(value, &mut border_color); + parse_color_opt(ctx, tag_name, key, value, &mut border_color); } "hover_color" => { - parse_color_opt(value, &mut hover_color); + parse_color_opt(ctx, tag_name, key, value, &mut hover_color); } "hover_border_color" => { - parse_color_opt(value, &mut hover_border_color); + parse_color_opt(ctx, tag_name, key, value, &mut hover_border_color); } "sprite_src" | "sprite_src_ext" | "sprite_src_builtin" | "sprite_src_internal" => { let asset_path = match key { @@ -90,14 +98,14 @@ pub fn parse_component_button<'a>( "top" => Some(tooltip::TooltipSide::Top), "bottom" => Some(tooltip::TooltipSide::Bottom), _ => { - print_invalid_attrib(key, value); + ctx.print_invalid_attrib(tag_name, key, value); None } } } "sticky" => { let mut sticky_i32 = 0; - sticky = parse_check_i32(value, &mut sticky_i32) && sticky_i32 == 1; + sticky = ctx.parse_check_i32(tag_name, key, value, &mut sticky_i32) && sticky_i32 == 1; } "long_press_time" => { long_press_time = parse_f32(value).unwrap_or(long_press_time); diff --git a/wgui/src/parser/component_checkbox.rs b/wgui/src/parser/component_checkbox.rs index 5cf7c26..5d3cdd5 100644 --- a/wgui/src/parser/component_checkbox.rs +++ b/wgui/src/parser/component_checkbox.rs @@ -2,9 +2,7 @@ use crate::{ components::{checkbox, radio_group::ComponentRadioGroup, Component}, i18n::Translation, layout::WidgetID, - parser::{ - parse_check_f32, parse_check_i32, process_component, style::parse_style, AttribPair, Fetchable, ParserContext, - }, + parser::{process_component, style::parse_style, AttribPair, Fetchable, ParserContext}, }; pub enum CheckboxKind { @@ -16,6 +14,7 @@ pub fn parse_component_checkbox( ctx: &mut ParserContext, parent_id: WidgetID, attribs: &[AttribPair], + tag_name: &str, kind: CheckboxKind, ) -> anyhow::Result { let mut box_size = 24.0; @@ -23,7 +22,7 @@ pub fn parse_component_checkbox( let mut checked = 0; let mut component_value = None; - let style = parse_style(attribs); + let style = parse_style(ctx, attribs, tag_name); for pair in attribs { let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref()); @@ -42,10 +41,10 @@ pub fn parse_component_checkbox( component_value = Some(value.into()); } "box_size" => { - parse_check_f32(value, &mut box_size); + ctx.parse_check_f32(tag_name, key, value, &mut box_size); } "checked" => { - parse_check_i32(value, &mut checked); + ctx.parse_check_i32(tag_name, key, value, &mut checked); } _ => {} } diff --git a/wgui/src/parser/component_radio_group.rs b/wgui/src/parser/component_radio_group.rs index 7cab53a..6587b08 100644 --- a/wgui/src/parser/component_radio_group.rs +++ b/wgui/src/parser/component_radio_group.rs @@ -1,7 +1,7 @@ use crate::{ - components::{Component, radio_group}, + components::{radio_group, Component}, layout::WidgetID, - parser::{AttribPair, ParserContext, ParserFile, parse_children, process_component, style::parse_style}, + parser::{parse_children, process_component, style::parse_style, AttribPair, ParserContext, ParserFile}, }; pub fn parse_component_radio_group<'a>( @@ -10,8 +10,9 @@ pub fn parse_component_radio_group<'a>( node: roxmltree::Node<'a, 'a>, parent_id: WidgetID, attribs: &[AttribPair], + tag_name: &str, ) -> anyhow::Result { - let style = parse_style(attribs); + let style = parse_style(ctx, attribs, tag_name); let (widget, component) = radio_group::construct(&mut ctx.get_construct_essentials(parent_id), style)?; diff --git a/wgui/src/parser/component_slider.rs b/wgui/src/parser/component_slider.rs index 54f3fdf..4a6e1a3 100644 --- a/wgui/src/parser/component_slider.rs +++ b/wgui/src/parser/component_slider.rs @@ -1,7 +1,7 @@ use crate::{ - components::{Component, slider}, + components::{slider, Component}, layout::WidgetID, - parser::{AttribPair, ParserContext, parse_check_f32, parse_check_i32, process_component, style::parse_style}, + parser::{process_component, style::parse_style, AttribPair, ParserContext}, widget::ConstructEssentials, }; @@ -9,6 +9,7 @@ pub fn parse_component_slider( ctx: &mut ParserContext, parent_id: WidgetID, attribs: &[AttribPair], + tag_name: &str, ) -> anyhow::Result { let mut min_value = 0.0; let mut max_value = 1.0; @@ -16,25 +17,25 @@ pub fn parse_component_slider( let mut step = 1.0; let mut show_value = 1; - let style = parse_style(attribs); + let style = parse_style(ctx, attribs, tag_name); for pair in attribs { let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref()); match key { "min_value" => { - parse_check_f32(value, &mut min_value); + ctx.parse_check_f32(tag_name, key, value, &mut min_value); } "max_value" => { - parse_check_f32(value, &mut max_value); + ctx.parse_check_f32(tag_name, key, value, &mut max_value); } "value" => { - parse_check_f32(value, &mut initial_value); + ctx.parse_check_f32(tag_name, key, value, &mut initial_value); } "step" => { - parse_check_f32(value, &mut step); + ctx.parse_check_f32(tag_name, key, value, &mut step); } "show_value" => { - parse_check_i32(value, &mut show_value); + ctx.parse_check_i32(tag_name, key, value, &mut show_value); } _ => {} } diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs index 7f1c144..e5c7f76 100644 --- a/wgui/src/parser/mod.rs +++ b/wgui/src/parser/mod.rs @@ -10,16 +10,9 @@ mod widget_rectangle; mod widget_sprite; use crate::{ - assets::{AssetPath, AssetPathOwned, normalize_path}, - components::{Component, ComponentWeak}, - drawing::{self}, - globals::WguiGlobals, - i18n::Translation, - layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap, WidgetPair}, - log::LogErr, - parser::{ + assets::{normalize_path, AssetPath, AssetPathOwned}, components::{Component, ComponentWeak}, drawing::{self}, globals::WguiGlobals, i18n::Translation, layout::{Layout, LayoutParams, LayoutState, Widget, WidgetID, WidgetMap, WidgetPair}, log::LogErr, parser::{ component_button::parse_component_button, - component_checkbox::{CheckboxKind, parse_component_checkbox}, + component_checkbox::{parse_component_checkbox, CheckboxKind}, component_radio_group::parse_component_radio_group, component_slider::parse_component_slider, widget_div::parse_widget_div, @@ -27,9 +20,7 @@ use crate::{ widget_label::parse_widget_label, widget_rectangle::parse_widget_rectangle, widget_sprite::parse_widget_sprite, - }, - widget::ConstructEssentials, - windowing::context_menu, + }, widget::ConstructEssentials, windowing::context_menu }; use anyhow::Context; use ouroboros::self_referencing; @@ -224,7 +215,7 @@ impl ParserState { template_parameters: HashMap, Rc>, ) -> anyhow::Result { let Some(template) = self.data.templates.get(template_name) else { - anyhow::bail!("no template named \"{template_name}\" found"); + anyhow::bail!("{:?}: no template named \"{template_name}\" found", self.path.get_path_buf()); }; let mut ctx = ParserContext { @@ -314,7 +305,7 @@ impl ParserState { }); } other => { - anyhow::bail!("unexpected <{other}> tag"); + anyhow::bail!("{:?}: unexpected <{other}> tag", self.path.get_path_buf()); } } } @@ -443,7 +434,7 @@ impl ParserContext<'_> { .insert(id.clone(), component.weak()) .is_some() { - log::warn!("duplicate component ID \"{id}\" in the same layout file!"); + log::warn!("{}: duplicate component ID \"{id}\"", self.doc_params.path.get_str()); } self.data_local.components.push(component); @@ -451,7 +442,7 @@ impl ParserContext<'_> { fn insert_id(&mut self, id: &Rc, widget_id: WidgetID) { if self.data_local.ids.insert(id.clone(), widget_id).is_some() { - log::warn!("duplicate widget ID \"{id}\" in the same layout file!"); + log::warn!("{}: duplicate widget ID \"{id}\"", self.doc_params.path.get_str()); } } @@ -479,6 +470,77 @@ impl ParserContext<'_> { insert_color_vars!(self, "faded", def.faded_color, def.translucent_alpha); insert_color_vars!(self, "bg", def.bg_color, def.translucent_alpha); } +fn print_invalid_attrib(&self, tag_name: &str, key: &str, value: &str) { + log::warn!("{}: <{tag_name}> value for \"{key}\" is invalid: \"{value}\"", self.doc_params.path.get_str()); +} + +fn print_missing_attrib(&self, tag_name: &str, attr: &str) { + log::warn!("{}: <{tag_name}> is missing \"{attr}\".", self.doc_params.path.get_str()); +} + +fn parse_val(&self, tag_name: &str, key: &str, value: &str) -> Option { + let Ok(val) = value.parse::() else { + self.print_invalid_attrib(tag_name, key, value); + return None; + }; + Some(val) +} + +fn parse_percent(&self, tag_name: &str, key: &str, value: &str) -> Option { + let Some(val_str) = value.split('%').next() else { + self.print_invalid_attrib(tag_name, key, value); + return None; + }; + + let Ok(val) = val_str.parse::() else { + self.print_invalid_attrib(tag_name, key, value); + return None; + }; + Some(val / 100.0) +} + +fn parse_size_unit(&self, tag_name: &str, key: &str, value: &str) -> Option +where + T: taffy::prelude::FromPercent + taffy::prelude::FromLength, +{ + if is_percent(value) { + Some(taffy::prelude::percent(self.parse_percent(tag_name, key, value)?)) + } else { + Some(taffy::prelude::length(parse_f32(value)?)) + } +} + +fn parse_check_i32(&self, tag_name: &str, key: &str, value: &str, num: &mut i32) -> bool { + if let Some(value) = parse_i32(value) { + *num = value; + true + } else { + self.print_invalid_attrib(tag_name, key, value); + false + } +} + +fn parse_check_f32(&self, tag_name: &str, key: &str, value: &str, num: &mut f32) -> bool { + if let Some(value) = parse_f32(value) { + *num = value; + true + } else { + self.print_invalid_attrib(tag_name, key, value); + false + } +} +} + +fn parse_i32(value: &str) -> Option { + value.parse::().ok() +} + +fn parse_f32(value: &str) -> Option { + value.parse::().ok() +} + +fn is_percent(value: &str) -> bool { + value.ends_with('%') } // Parses a color from a HTML hex string @@ -510,7 +572,6 @@ pub fn parse_color_hex(html_hex: &str) -> Option { f32::from(a) / 255., )); } - log::warn!("failed to parse color \"{html_hex}\""); None } @@ -522,81 +583,6 @@ fn require_tag_by_name<'a>(node: &roxmltree::Node<'a, 'a>, name: &str) -> anyhow get_tag_by_name(node, name).ok_or_else(|| anyhow::anyhow!("Tag \"{name}\" not found")) } -fn print_invalid_attrib(key: &str, value: &str) { - log::warn!("Invalid value \"{value}\" in attribute \"{key}\""); -} - -fn print_missing_attrib(tag_name: &str, attr: &str) { - log::warn!("Missing attribute {attr} in tag <{tag_name}>"); -} - -fn print_invalid_value(value: &str) { - log::warn!("Invalid value \"{value}\""); -} - -fn parse_val(value: &str) -> Option { - let Ok(val) = value.parse::() else { - print_invalid_value(value); - return None; - }; - Some(val) -} - -fn is_percent(value: &str) -> bool { - value.ends_with('%') -} - -fn parse_percent(value: &str) -> Option { - let Some(val_str) = value.split('%').next() else { - print_invalid_value(value); - return None; - }; - - let Ok(val) = val_str.parse::() else { - print_invalid_value(value); - return None; - }; - Some(val / 100.0) -} - -fn parse_i32(value: &str) -> Option { - value.parse::().ok() -} - -fn parse_f32(value: &str) -> Option { - value.parse::().ok() -} - -fn parse_check_i32(value: &str, num: &mut i32) -> bool { - if let Some(value) = parse_i32(value) { - *num = value; - true - } else { - print_invalid_value(value); - false - } -} - -fn parse_check_f32(value: &str, num: &mut f32) -> bool { - if let Some(value) = parse_f32(value) { - *num = value; - true - } else { - print_invalid_value(value); - false - } -} - -fn parse_size_unit(value: &str) -> Option -where - T: taffy::prelude::FromPercent + taffy::prelude::FromLength, -{ - if is_percent(value) { - Some(taffy::prelude::percent(parse_percent(value)?)) - } else { - Some(taffy::prelude::length(parse_f32(value)?)) - } -} fn parse_widget_other_internal( template: &Rc