Monado app switcher, lang update

This commit is contained in:
Aleksander
2026-01-08 19:46:34 +01:00
parent 650bc99a95
commit e421c39539
22 changed files with 566 additions and 153 deletions

View File

@@ -10,9 +10,16 @@ mod widget_rectangle;
mod widget_sprite;
use crate::{
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::{
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::{
component_button::parse_component_button,
component_checkbox::{parse_component_checkbox, CheckboxKind},
component_checkbox::{CheckboxKind, parse_component_checkbox},
component_radio_group::parse_component_radio_group,
component_slider::parse_component_slider,
widget_div::parse_widget_div,
@@ -20,7 +27,9 @@ 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;
@@ -215,7 +224,10 @@ impl ParserState {
template_parameters: HashMap<Rc<str>, Rc<str>>,
) -> anyhow::Result<ParserData> {
let Some(template) = self.data.templates.get(template_name) else {
anyhow::bail!("{:?}: no template named \"{template_name}\" found", self.path.get_path_buf());
anyhow::bail!(
"{:?}: no template named \"{template_name}\" found",
self.path.get_path_buf().display()
);
};
let mut ctx = ParserContext {
@@ -280,7 +292,7 @@ impl ParserState {
for attrib in child.attributes() {
let (key, value) = (attrib.name(), attrib.value());
match key {
"text" => title = Some(Translation::from_raw_text(value)),
"translation" => title = Some(Translation::from_translation_key(value)),
@@ -291,7 +303,7 @@ impl ParserState {
if !other.starts_with('_') {
anyhow::bail!("unexpected \"{other}\" attribute");
}
attribs.push(AttribPair::new(key, replace_vars(value, &template_params)));
attribs.push(AttribPair::new(key, replace_vars(value, template_params)));
}
}
}
@@ -305,14 +317,12 @@ impl ParserState {
});
}
other => {
anyhow::bail!("{:?}: unexpected <{other}> tag", self.path.get_path_buf());
anyhow::bail!("{:?}: unexpected <{other}> tag", self.path.get_path_buf().display());
}
}
}
Ok(
cells,
)
Ok(cells)
}
}
@@ -470,65 +480,71 @@ 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<f32> {
let Ok(val) = value.parse::<f32>() 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<f32> {
let Some(val_str) = value.split('%').next() else {
self.print_invalid_attrib(tag_name, key, value);
return None;
};
let Ok(val) = val_str.parse::<f32>() else {
self.print_invalid_attrib(tag_name, key, value);
return None;
};
Some(val / 100.0)
}
fn parse_size_unit<T>(&self, tag_name: &str, key: &str, value: &str) -> Option<T>
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 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 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 print_missing_attrib(&self, tag_name: &str, attr: &str) {
log::warn!(
"{}: <{tag_name}> is missing \"{attr}\".",
self.doc_params.path.get_str()
);
}
}
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_val(&self, tag_name: &str, key: &str, value: &str) -> Option<f32> {
let Ok(val) = value.parse::<f32>() 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<f32> {
let Some(val_str) = value.split('%').next() else {
self.print_invalid_attrib(tag_name, key, value);
return None;
};
let Ok(val) = val_str.parse::<f32>() else {
self.print_invalid_attrib(tag_name, key, value);
return None;
};
Some(val / 100.0)
}
fn parse_size_unit<T>(&self, tag_name: &str, key: &str, value: &str) -> Option<T>
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<i32> {
@@ -583,7 +599,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 parse_widget_other_internal(
template: &Rc<Template>,
template_parameters: HashMap<Rc<str>, Rc<str>>,
@@ -617,7 +632,10 @@ fn parse_widget_other(
attribs: &[AttribPair],
) -> anyhow::Result<()> {
let Some(template) = ctx.get_template(xml_tag_name) else {
log::error!("{}: Undefined tag named \"{xml_tag_name}\"", ctx.doc_params.path.get_str());
log::error!(
"{}: Undefined tag named \"{xml_tag_name}\"",
ctx.doc_params.path.get_str()
);
return Ok(()); // not critical
};
@@ -746,6 +764,7 @@ pub fn replace_vars(input: &str, vars: &HashMap<Rc<str>, Rc<str>>) -> Rc<str> {
}
#[allow(clippy::manual_strip)]
#[allow(clippy::single_match_else)]
fn process_attrib(
template_parameters: &HashMap<Rc<str>, Rc<str>>,
ctx: &ParserContext,
@@ -760,7 +779,7 @@ fn process_attrib(
None => {
log::warn!("{}: undefined variable \"{value}\"", ctx.doc_params.path.get_str());
AttribPair::new(key, "undefined")
},
}
}
} else {
AttribPair::new(key, replace_vars(value, template_parameters))
@@ -797,7 +816,10 @@ fn process_attribs<'a>(
res.push(process_attrib(&file.template_parameters, ctx, macro_key, macro_value));
}
} else {
log::warn!("{}: requested macro named \"{value}\" not found!", ctx.doc_params.path.get_str());
log::warn!(
"{}: requested macro named \"{value}\" not found!",
ctx.doc_params.path.get_str()
);
}
} else {
res.push(process_attrib(&file.template_parameters, ctx, key, value));
@@ -816,7 +838,10 @@ fn parse_tag_theme<'a>(ctx: &mut ParserContext, node: roxmltree::Node<'a, 'a>) {
}
"" => { /* ignore */ }
_ => {
log::warn!("{}: <{child_name}> is not a valid child to <theme>.", ctx.doc_params.path.get_str());
log::warn!(
"{}: <{child_name}> is not a valid child to <theme>.",
ctx.doc_params.path.get_str()
);
}
}
}
@@ -837,7 +862,7 @@ fn parse_tag_template(file: &ParserFile, ctx: &mut ParserContext, node: roxmltre
}
}
}
let Some(name) = template_name else {
ctx.print_missing_attrib("template", "name");
return;
@@ -865,7 +890,11 @@ fn parse_tag_macro(file: &ParserFile, ctx: &mut ParserContext, node: roxmltree::
}
_ => {
if macro_attribs.insert(pair.attrib.clone(), pair.value).is_some() {
log::warn!("{}: macro attrib \"{}\" already defined!", ctx.doc_params.path.get_str(), pair.attrib);
log::warn!(
"{}: macro attrib \"{}\" already defined!",
ctx.doc_params.path.get_str(),
pair.attrib
);
}
}
}
@@ -963,19 +992,29 @@ fn parse_child<'a>(
new_widget_id = Some(parse_widget_div(file, ctx, child_node, parent_id, &attribs, tag_name)?);
}
"rectangle" => {
new_widget_id = Some(parse_widget_rectangle(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_widget_rectangle(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"label" => {
new_widget_id = Some(parse_widget_label(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_widget_label(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"sprite" => {
new_widget_id = Some(parse_widget_sprite(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_widget_sprite(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"image" => {
new_widget_id = Some(parse_widget_image(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_widget_image(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"Button" => {
new_widget_id = Some(parse_component_button(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_component_button(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"Slider" => {
new_widget_id = Some(parse_component_slider(ctx, parent_id, &attribs, tag_name)?);
@@ -999,7 +1038,9 @@ fn parse_child<'a>(
)?);
}
"RadioGroup" => {
new_widget_id = Some(parse_component_radio_group(file, ctx, child_node, parent_id, &attribs, tag_name)?);
new_widget_id = Some(parse_component_radio_group(
file, ctx, child_node, parent_id, &attribs, tag_name,
)?);
}
"" => { /* ignore */ }
other_tag_name => {