attribs rework
This commit is contained in:
@@ -7,9 +7,9 @@ use crate::{
|
|||||||
use glam::Vec2;
|
use glam::Vec2;
|
||||||
use wgui::{
|
use wgui::{
|
||||||
components::{
|
components::{
|
||||||
Component,
|
|
||||||
button::{ButtonClickCallback, ComponentButton},
|
button::{ButtonClickCallback, ComponentButton},
|
||||||
checkbox::ComponentCheckbox,
|
checkbox::ComponentCheckbox,
|
||||||
|
Component,
|
||||||
},
|
},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
event::EventListenerCollection,
|
event::EventListenerCollection,
|
||||||
@@ -66,17 +66,17 @@ impl TestbedGeneric {
|
|||||||
|
|
||||||
let extra = ParseDocumentExtra {
|
let extra = ParseDocumentExtra {
|
||||||
on_custom_attribs: Some(Box::new(move |par| {
|
on_custom_attribs: Some(Box::new(move |par| {
|
||||||
let Some(my_custom_value) = par.get_value("my_custom") else {
|
let Some(my_custom_value) = par.get_value("_my_custom") else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(mult_value) = par.get_value("mult") else {
|
let Some(mult_value) = par.get_value("_mult") else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let mult_f32 = mult_value.parse::<f32>().unwrap();
|
let mult_f32 = mult_value.parse::<f32>().unwrap();
|
||||||
|
|
||||||
let mut color = match my_custom_value {
|
let mut color = match my_custom_value.as_ref() {
|
||||||
"red" => Color::new(1.0, 0.0, 0.0, 1.0),
|
"red" => Color::new(1.0, 0.0, 0.0, 1.0),
|
||||||
"green" => Color::new(0.0, 1.0, 0.0, 1.0),
|
"green" => Color::new(0.0, 1.0, 0.0, 1.0),
|
||||||
"blue" => Color::new(0.0, 0.0, 1.0, 1.0),
|
"blue" => Color::new(0.0, 0.0, 1.0, 1.0),
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::{Component, button},
|
components::{button, Component},
|
||||||
drawing::Color,
|
drawing::Color,
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, process_component,
|
parse_children, process_component,
|
||||||
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
||||||
|
AttribPair, ParserContext, ParserFile,
|
||||||
},
|
},
|
||||||
widget::util::WLength,
|
widget::util::WLength,
|
||||||
};
|
};
|
||||||
@@ -15,6 +16,7 @@ pub fn parse_component_button<'a, U1, U2>(
|
|||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut color: Option<Color> = None;
|
let mut color: Option<Color> = None;
|
||||||
let mut border_color: Option<Color> = None;
|
let mut border_color: Option<Color> = None;
|
||||||
@@ -23,11 +25,11 @@ pub fn parse_component_button<'a, U1, U2>(
|
|||||||
let mut round = WLength::Units(4.0);
|
let mut round = WLength::Units(4.0);
|
||||||
let mut translation: Option<Translation> = None;
|
let mut translation: Option<Translation> = None;
|
||||||
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
let text_style = parse_text_style(attribs);
|
||||||
let text_style = parse_text_style(&attribs);
|
let style = parse_style(attribs);
|
||||||
let style = parse_style(&attribs);
|
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
"text" => {
|
"text" => {
|
||||||
translation = Some(Translation::from_raw_text(&value));
|
translation = Some(Translation::from_raw_text(&value));
|
||||||
@@ -73,7 +75,7 @@ pub fn parse_component_button<'a, U1, U2>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
process_component(file, ctx, node, Component(component), new_id);
|
process_component(ctx, Component(component), new_id, attribs);
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
|
|||||||
@@ -1,38 +1,35 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::{Component, checkbox},
|
components::{checkbox, Component},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{parse_check_f32, parse_check_i32, process_component, style::parse_style, AttribPair, ParserContext},
|
||||||
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, process_component, style::parse_style,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_component_checkbox<'a, U1, U2>(
|
pub fn parse_component_checkbox<'a, U1, U2>(
|
||||||
file: &'a ParserFile,
|
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut box_size = 24.0;
|
let mut box_size = 24.0;
|
||||||
let mut translation = Translation::default();
|
let mut translation = Translation::default();
|
||||||
let mut checked = 0;
|
let mut checked = 0;
|
||||||
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
let style = parse_style(attribs);
|
||||||
let style = parse_style(&attribs);
|
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"text" => {
|
"text" => {
|
||||||
translation = Translation::from_raw_text(&value);
|
translation = Translation::from_raw_text(value);
|
||||||
}
|
}
|
||||||
"translation" => {
|
"translation" => {
|
||||||
translation = Translation::from_translation_key(&value);
|
translation = Translation::from_translation_key(value);
|
||||||
}
|
}
|
||||||
"box_size" => {
|
"box_size" => {
|
||||||
parse_check_f32(value.as_ref(), &mut box_size);
|
parse_check_f32(value, &mut box_size);
|
||||||
}
|
}
|
||||||
"checked" => {
|
"checked" => {
|
||||||
parse_check_i32(value.as_ref(), &mut checked);
|
parse_check_i32(value, &mut checked);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -50,7 +47,7 @@ pub fn parse_component_checkbox<'a, U1, U2>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
process_component(file, ctx, node, Component(component), new_id);
|
process_component(ctx, Component(component), new_id, attribs);
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,31 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
components::{Component, slider},
|
components::{slider, Component},
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{ParserContext, ParserFile, iter_attribs, parse_check_f32, process_component, style::parse_style},
|
parser::{parse_check_f32, process_component, style::parse_style, AttribPair, ParserContext},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse_component_slider<'a, U1, U2>(
|
pub fn parse_component_slider<'a, U1, U2>(
|
||||||
file: &'a ParserFile,
|
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut min_value = 0.0;
|
let mut min_value = 0.0;
|
||||||
let mut max_value = 1.0;
|
let mut max_value = 1.0;
|
||||||
let mut initial_value = 0.5;
|
let mut initial_value = 0.5;
|
||||||
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
let style = parse_style(attribs);
|
||||||
let style = parse_style(&attribs);
|
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"min_value" => {
|
"min_value" => {
|
||||||
parse_check_f32(value.as_ref(), &mut min_value);
|
parse_check_f32(value, &mut min_value);
|
||||||
}
|
}
|
||||||
"max_value" => {
|
"max_value" => {
|
||||||
parse_check_f32(value.as_ref(), &mut max_value);
|
parse_check_f32(value, &mut max_value);
|
||||||
}
|
}
|
||||||
"value" => {
|
"value" => {
|
||||||
parse_check_f32(value.as_ref(), &mut initial_value);
|
parse_check_f32(value, &mut initial_value);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -46,7 +45,7 @@ pub fn parse_component_slider<'a, U1, U2>(
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
process_component(file, ctx, node, Component(component), new_id);
|
process_component(ctx, Component(component), new_id, attribs);
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -441,7 +441,7 @@ fn print_invalid_value(value: &str) {
|
|||||||
log::warn!("Invalid value \"{value}\"");
|
log::warn!("Invalid value \"{value}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_val(value: &Rc<str>) -> Option<f32> {
|
fn parse_val(value: &str) -> Option<f32> {
|
||||||
let Ok(val) = value.parse::<f32>() else {
|
let Ok(val) = value.parse::<f32>() else {
|
||||||
print_invalid_value(value);
|
print_invalid_value(value);
|
||||||
return None;
|
return None;
|
||||||
@@ -534,15 +534,16 @@ fn parse_widget_other<'a, U1, U2>(
|
|||||||
xml_tag_name: &str,
|
xml_tag_name: &str,
|
||||||
file: &'a ParserFile,
|
file: &'a ParserFile,
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let Some(template) = ctx.get_template(xml_tag_name) else {
|
let Some(template) = ctx.get_template(xml_tag_name) else {
|
||||||
log::error!("Undefined tag named \"{xml_tag_name}\"");
|
log::error!("Undefined tag named \"{xml_tag_name}\"");
|
||||||
return Ok(()); // not critical
|
return Ok(()); // not critical
|
||||||
};
|
};
|
||||||
|
|
||||||
let template_parameters: HashMap<Rc<str>, Rc<str>> = iter_attribs(file, ctx, &node, false).collect();
|
let template_parameters: HashMap<Rc<str>, Rc<str>> =
|
||||||
|
attribs.iter().map(|a| (a.attrib.clone(), a.value.clone())).collect();
|
||||||
|
|
||||||
parse_widget_other_internal(&template, template_parameters, file, ctx, parent_id)
|
parse_widget_other_internal(&template, template_parameters, file, ctx, parent_id)
|
||||||
}
|
}
|
||||||
@@ -550,17 +551,15 @@ fn parse_widget_other<'a, U1, U2>(
|
|||||||
fn parse_tag_include<'a, U1, U2>(
|
fn parse_tag_include<'a, U1, U2>(
|
||||||
file: &ParserFile,
|
file: &ParserFile,
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
for attrib in node.attributes() {
|
for pair in attribs {
|
||||||
let (key, value) = (attrib.name(), attrib.value());
|
|
||||||
|
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match key {
|
match pair.attrib.as_ref() {
|
||||||
"src" => {
|
"src" => {
|
||||||
let mut new_path = file.path.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
let mut new_path = file.path.parent().unwrap_or_else(|| Path::new("/")).to_path_buf();
|
||||||
new_path.push(value);
|
new_path.push(pair.value.as_ref());
|
||||||
let new_path = assets::normalize_path(&new_path);
|
let new_path = assets::normalize_path(&new_path);
|
||||||
|
|
||||||
let (new_file, node_layout) = get_doc_from_path(ctx, &new_path)?;
|
let (new_file, node_layout) = get_doc_from_path(ctx, &new_path)?;
|
||||||
@@ -569,7 +568,7 @@ fn parse_tag_include<'a, U1, U2>(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
print_invalid_attrib(key, value);
|
print_invalid_attrib(pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -637,38 +636,39 @@ fn process_attrib<'a, U1, U2>(
|
|||||||
ctx: &'a ParserContext<U1, U2>,
|
ctx: &'a ParserContext<U1, U2>,
|
||||||
key: &str,
|
key: &str,
|
||||||
value: &str,
|
value: &str,
|
||||||
) -> (Rc<str>, Rc<str>) {
|
) -> AttribPair {
|
||||||
if value.starts_with('~') {
|
if value.starts_with('~') {
|
||||||
let name = &value[1..];
|
let name = &value[1..];
|
||||||
|
|
||||||
(
|
match ctx.get_var(name) {
|
||||||
Rc::from(key),
|
Some(name) => AttribPair::new(key, name.clone()),
|
||||||
match ctx.get_var(name) {
|
None => AttribPair::new(key, "undefined"),
|
||||||
Some(name) => name,
|
}
|
||||||
None => Rc::from("undefined"),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(Rc::from(key), replace_vars(value, &file.template_parameters))
|
AttribPair::new(key, replace_vars(value, &file.template_parameters))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn iter_attribs<'a, U1, U2>(
|
fn raw_attribs<'a>(node: &'a roxmltree::Node<'a, 'a>) -> Vec<AttribPair> {
|
||||||
|
let mut res = vec![];
|
||||||
|
for attrib in node.attributes() {
|
||||||
|
let (key, value) = (attrib.name(), attrib.value());
|
||||||
|
res.push(AttribPair::new(key, value));
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_attribs<'a, U1, U2>(
|
||||||
file: &'a ParserFile,
|
file: &'a ParserFile,
|
||||||
ctx: &'a ParserContext<U1, U2>,
|
ctx: &'a ParserContext<U1, U2>,
|
||||||
node: &'a roxmltree::Node<'a, 'a>,
|
node: &'a roxmltree::Node<'a, 'a>,
|
||||||
is_tag_macro: bool,
|
is_tag_macro: bool,
|
||||||
) -> impl Iterator<Item = (/*key*/ Rc<str>, /*value*/ Rc<str>)> + 'a {
|
) -> Vec<AttribPair> {
|
||||||
let mut res = Vec::<(Rc<str>, Rc<str>)>::new();
|
|
||||||
|
|
||||||
if is_tag_macro {
|
if is_tag_macro {
|
||||||
// return as-is, no attrib post-processing
|
// return as-is, no attrib post-processing
|
||||||
for attrib in node.attributes() {
|
return raw_attribs(node);
|
||||||
let (key, value) = (attrib.name(), attrib.value());
|
|
||||||
res.push((Rc::from(key), Rc::from(value)));
|
|
||||||
}
|
|
||||||
return res.into_iter();
|
|
||||||
}
|
}
|
||||||
|
let mut res = vec![];
|
||||||
|
|
||||||
for attrib in node.attributes() {
|
for attrib in node.attributes() {
|
||||||
let (key, value) = (attrib.name(), attrib.value());
|
let (key, value) = (attrib.name(), attrib.value());
|
||||||
@@ -686,7 +686,7 @@ fn iter_attribs<'a, U1, U2>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.into_iter()
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'a, 'a>) {
|
fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'a, 'a>) {
|
||||||
@@ -707,15 +707,15 @@ fn parse_tag_theme<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, node: roxmltree:
|
|||||||
fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||||
let mut template_name: Option<Rc<str>> = None;
|
let mut template_name: Option<Rc<str>> = None;
|
||||||
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
let attribs = process_attribs(file, ctx, &node, false);
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
match pair.attrib.as_ref() {
|
||||||
"name" => {
|
"name" => {
|
||||||
template_name = Some(value);
|
template_name = Some(pair.value);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
print_invalid_attrib(&key, &value);
|
print_invalid_attrib(pair.value.as_ref(), pair.value.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -737,17 +737,17 @@ fn parse_tag_template<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>
|
|||||||
fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, node: roxmltree::Node<'_, '_>) {
|
||||||
let mut macro_name: Option<Rc<str>> = None;
|
let mut macro_name: Option<Rc<str>> = None;
|
||||||
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, true).collect();
|
let attribs = process_attribs(file, ctx, &node, true);
|
||||||
let mut macro_attribs = HashMap::<Rc<str>, Rc<str>>::new();
|
let mut macro_attribs = HashMap::<Rc<str>, Rc<str>>::new();
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
match pair.attrib.as_ref() {
|
||||||
"name" => {
|
"name" => {
|
||||||
macro_name = Some(value);
|
macro_name = Some(pair.value);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if macro_attribs.insert(key.clone(), value).is_some() {
|
if macro_attribs.insert(pair.attrib.clone(), pair.value).is_some() {
|
||||||
log::warn!("macro attrib \"{key}\" already defined!");
|
log::warn!("macro attrib \"{}\" already defined!", pair.attrib);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -762,21 +762,18 @@ fn parse_tag_macro<U1, U2>(file: &ParserFile, ctx: &mut ParserContext<U1, U2>, n
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn process_component<'a, U1, U2>(
|
fn process_component<'a, U1, U2>(
|
||||||
file: &'a ParserFile,
|
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
component: Component,
|
component: Component,
|
||||||
widget_id: WidgetID,
|
widget_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) {
|
) {
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
|
||||||
|
|
||||||
let mut component_id: Option<Rc<str>> = None;
|
let mut component_id: Option<Rc<str>> = None;
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match key.as_ref() {
|
match pair.attrib.as_ref() {
|
||||||
"id" => {
|
"id" => {
|
||||||
component_id = Some(value);
|
component_id = Some(pair.value.clone());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -785,20 +782,13 @@ fn process_component<'a, U1, U2>(
|
|||||||
ctx.insert_component(widget_id, component, component_id);
|
ctx.insert_component(widget_id, component, component_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_widget_universal<'a, U1, U2>(
|
fn parse_widget_universal<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: WidgetID, attribs: &[AttribPair]) {
|
||||||
file: &'a ParserFile,
|
for pair in attribs {
|
||||||
ctx: &mut ParserContext<U1, U2>,
|
|
||||||
node: roxmltree::Node<'a, 'a>,
|
|
||||||
widget_id: WidgetID,
|
|
||||||
) {
|
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
|
||||||
|
|
||||||
for (key, value) in attribs {
|
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match key.as_ref() {
|
match pair.attrib.as_ref() {
|
||||||
"id" => {
|
"id" => {
|
||||||
// Attach a specific widget to name-ID map (just like getElementById)
|
// Attach a specific widget to name-ID map (just like getElementById)
|
||||||
ctx.insert_id(&value, widget_id);
|
ctx.insert_id(&pair.value, widget_id);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -827,36 +817,38 @@ fn parse_child<'a, U1, U2>(
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let attribs = process_attribs(file, ctx, &child_node, false);
|
||||||
|
|
||||||
let mut new_widget_id: Option<WidgetID> = None;
|
let mut new_widget_id: Option<WidgetID> = None;
|
||||||
|
|
||||||
match child_node.tag_name().name() {
|
match child_node.tag_name().name() {
|
||||||
"include" => {
|
"include" => {
|
||||||
parse_tag_include(file, ctx, child_node, parent_id)?;
|
parse_tag_include(file, ctx, parent_id, &attribs)?;
|
||||||
}
|
}
|
||||||
"div" => {
|
"div" => {
|
||||||
new_widget_id = Some(parse_widget_div(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_widget_div(file, ctx, child_node, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"rectangle" => {
|
"rectangle" => {
|
||||||
new_widget_id = Some(parse_widget_rectangle(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_widget_rectangle(file, ctx, child_node, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"label" => {
|
"label" => {
|
||||||
new_widget_id = Some(parse_widget_label(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_widget_label(file, ctx, child_node, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"sprite" => {
|
"sprite" => {
|
||||||
new_widget_id = Some(parse_widget_sprite(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_widget_sprite(file, ctx, child_node, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"Button" => {
|
"Button" => {
|
||||||
new_widget_id = Some(parse_component_button(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_component_button(file, ctx, child_node, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"Slider" => {
|
"Slider" => {
|
||||||
new_widget_id = Some(parse_component_slider(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_component_slider(ctx, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"CheckBox" => {
|
"CheckBox" => {
|
||||||
new_widget_id = Some(parse_component_checkbox(file, ctx, child_node, parent_id)?);
|
new_widget_id = Some(parse_component_checkbox(ctx, parent_id, &attribs)?);
|
||||||
}
|
}
|
||||||
"" => { /* ignore */ }
|
"" => { /* ignore */ }
|
||||||
other_tag_name => {
|
other_tag_name => {
|
||||||
parse_widget_other(other_tag_name, file, ctx, child_node, parent_id)?;
|
parse_widget_other(other_tag_name, file, ctx, parent_id, &attribs)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -864,20 +856,13 @@ fn parse_child<'a, U1, U2>(
|
|||||||
if let Some(widget_id) = new_widget_id
|
if let Some(widget_id) = new_widget_id
|
||||||
&& let Some(on_custom_attribs) = &ctx.doc_params.extra.on_custom_attribs
|
&& let Some(on_custom_attribs) = &ctx.doc_params.extra.on_custom_attribs
|
||||||
{
|
{
|
||||||
let mut pairs = SmallVec::<[CustomAttribPair; 4]>::new();
|
let mut pairs = SmallVec::<[AttribPair; 4]>::new();
|
||||||
|
|
||||||
for attrib in child_node.attributes() {
|
for pair in attribs {
|
||||||
let attr_name = attrib.name();
|
if !pair.attrib.starts_with('_') || pair.attrib.is_empty() {
|
||||||
if !attr_name.starts_with('_') || attr_name.is_empty() {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
pairs.push(pair.clone());
|
||||||
let attr_without_prefix = &attr_name[1..]; // safe
|
|
||||||
|
|
||||||
pairs.push(CustomAttribPair {
|
|
||||||
attrib: attr_without_prefix,
|
|
||||||
value: attrib.value(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !pairs.is_empty() {
|
if !pairs.is_empty() {
|
||||||
@@ -921,16 +906,30 @@ fn create_default_context<'a, U1, U2>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CustomAttribPair<'a> {
|
#[derive(Clone)]
|
||||||
pub attrib: &'a str, // without _ at the beginning
|
pub struct AttribPair {
|
||||||
pub value: &'a str,
|
pub attrib: Rc<str>,
|
||||||
|
pub value: Rc<str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AttribPair {
|
||||||
|
fn new<A, V>(attrib: A, value: V) -> Self
|
||||||
|
where
|
||||||
|
A: Into<Rc<str>>,
|
||||||
|
V: Into<Rc<str>>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
attrib: attrib.into(),
|
||||||
|
value: value.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CustomAttribsInfo<'a> {
|
pub struct CustomAttribsInfo<'a> {
|
||||||
pub parent_id: WidgetID,
|
pub parent_id: WidgetID,
|
||||||
pub widget_id: WidgetID,
|
pub widget_id: WidgetID,
|
||||||
pub widgets: &'a WidgetMap,
|
pub widgets: &'a WidgetMap,
|
||||||
pub pairs: &'a [CustomAttribPair<'a>],
|
pub pairs: &'a [AttribPair],
|
||||||
}
|
}
|
||||||
|
|
||||||
// helper functions
|
// helper functions
|
||||||
@@ -943,11 +942,11 @@ impl CustomAttribsInfo<'_> {
|
|||||||
self.widgets.get(self.widget_id)?.get_as_mut::<T>()
|
self.widgets.get(self.widget_id)?.get_as_mut::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_value(&self, attrib_name: &str) -> Option<&str> {
|
pub fn get_value(&self, attrib_name: &str) -> Option<Rc<str>> {
|
||||||
// O(n) search, these pairs won't be problematically big anyways
|
// O(n) search, these pairs won't be problematically big anyways
|
||||||
for pair in self.pairs {
|
for pair in self.pairs {
|
||||||
if pair.attrib == attrib_name {
|
if *pair.attrib == *attrib_name {
|
||||||
return Some(pair.value);
|
return Some(pair.value.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -958,35 +957,23 @@ impl CustomAttribsInfo<'_> {
|
|||||||
CustomAttribsInfoOwned {
|
CustomAttribsInfoOwned {
|
||||||
parent_id: self.parent_id,
|
parent_id: self.parent_id,
|
||||||
widget_id: self.widget_id,
|
widget_id: self.widget_id,
|
||||||
pairs: self
|
pairs: self.pairs.iter().cloned().collect(),
|
||||||
.pairs
|
|
||||||
.iter()
|
|
||||||
.map(|p| CustomAttribPairOwned {
|
|
||||||
attrib: p.attrib.to_string(),
|
|
||||||
value: p.value.to_string(),
|
|
||||||
})
|
|
||||||
.collect(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CustomAttribPairOwned {
|
|
||||||
pub attrib: String, // without _ at the beginning
|
|
||||||
pub value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CustomAttribsInfoOwned {
|
pub struct CustomAttribsInfoOwned {
|
||||||
pub parent_id: WidgetID,
|
pub parent_id: WidgetID,
|
||||||
pub widget_id: WidgetID,
|
pub widget_id: WidgetID,
|
||||||
pub pairs: Vec<CustomAttribPairOwned>,
|
pub pairs: Vec<AttribPair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CustomAttribsInfoOwned {
|
impl CustomAttribsInfoOwned {
|
||||||
pub fn get_value(&self, attrib_name: &str) -> Option<&str> {
|
pub fn get_value(&self, attrib_name: &str) -> Option<&str> {
|
||||||
// O(n) search, these pairs won't be problematically big anyways
|
// O(n) search, these pairs won't be problematically big anyways
|
||||||
for pair in &self.pairs {
|
for pair in &self.pairs {
|
||||||
if pair.attrib == attrib_name {
|
if pair.attrib.as_ref() == attrib_name {
|
||||||
return Some(pair.value.as_str());
|
return Some(pair.value.as_ref());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1091,7 +1078,7 @@ fn parse_document_root<U1, U2>(
|
|||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match child_node.tag_name().name() {
|
match child_node.tag_name().name() {
|
||||||
/* topmost include directly in <layout> */
|
/* topmost include directly in <layout> */
|
||||||
"include" => parse_tag_include(file, ctx, child_node, parent_id)?,
|
"include" => parse_tag_include(file, ctx, parent_id, &raw_attribs(&child_node))?,
|
||||||
"theme" => parse_tag_theme(ctx, child_node),
|
"theme" => parse_tag_theme(ctx, child_node),
|
||||||
"template" => parse_tag_template(file, ctx, child_node),
|
"template" => parse_tag_template(file, ctx, child_node),
|
||||||
"macro" => parse_tag_macro(file, ctx, child_node),
|
"macro" => parse_tag_macro(file, ctx, child_node),
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
use taffy::{
|
use taffy::{
|
||||||
AlignContent, AlignItems, AlignSelf, BoxSizing, Display, FlexDirection, FlexWrap, JustifyContent,
|
AlignContent, AlignItems, AlignSelf, BoxSizing, Display, FlexDirection, FlexWrap, JustifyContent, JustifySelf,
|
||||||
JustifySelf, Overflow,
|
Overflow,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
drawing,
|
drawing,
|
||||||
parser::{
|
parser::{
|
||||||
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val,
|
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val, print_invalid_attrib,
|
||||||
print_invalid_attrib, print_invalid_value,
|
print_invalid_value, AttribPair,
|
||||||
},
|
},
|
||||||
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
|
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
|
||||||
widget::util::WLength,
|
widget::util::WLength,
|
||||||
@@ -45,11 +43,12 @@ pub fn parse_color_opt(value: &str, color: &mut Option<drawing::Color>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_text_style(attribs: &[(Rc<str>, Rc<str>)]) -> TextStyle {
|
pub fn parse_text_style(attribs: &[AttribPair]) -> TextStyle {
|
||||||
let mut style = TextStyle::default();
|
let mut style = TextStyle::default();
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"color" => {
|
"color" => {
|
||||||
if let Some(color) = parse_color_hex(value) {
|
if let Some(color) = parse_color_hex(value) {
|
||||||
style.color = Some(color);
|
style.color = Some(color);
|
||||||
@@ -88,10 +87,11 @@ pub fn parse_text_style(attribs: &[(Rc<str>, Rc<str>)]) -> TextStyle {
|
|||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
#[allow(clippy::cognitive_complexity)]
|
#[allow(clippy::cognitive_complexity)]
|
||||||
pub fn parse_style(attribs: &[(Rc<str>, Rc<str>)]) -> taffy::Style {
|
pub fn parse_style(attribs: &[AttribPair]) -> taffy::Style {
|
||||||
let mut style = taffy::Style::default();
|
let mut style = taffy::Style::default();
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
match key.as_ref() {
|
match key.as_ref() {
|
||||||
"display" => match value.as_ref() {
|
"display" => match value.as_ref() {
|
||||||
"flex" => style.display = Display::Flex,
|
"flex" => style.display = Display::Flex,
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
|
||||||
style::parse_style,
|
|
||||||
},
|
|
||||||
widget::div::WidgetDiv,
|
widget::div::WidgetDiv,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -12,15 +9,13 @@ pub fn parse_widget_div<'a, U1, U2>(
|
|||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
let style = parse_style(attribs);
|
||||||
let style = parse_style(&attribs);
|
|
||||||
|
|
||||||
let (new_id, _) = ctx
|
let (new_id, _) = ctx.layout.add_child(parent_id, WidgetDiv::create(), style)?;
|
||||||
.layout
|
|
||||||
.add_child(parent_id, WidgetDiv::create(), style)?;
|
|
||||||
|
|
||||||
parse_widget_universal(file, ctx, node, new_id);
|
parse_widget_universal(ctx, new_id, attribs);
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
|
|||||||
@@ -2,8 +2,9 @@ use crate::{
|
|||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
parse_children, parse_widget_universal,
|
||||||
style::{parse_style, parse_text_style},
|
style::{parse_style, parse_text_style},
|
||||||
|
AttribPair, ParserContext, ParserFile,
|
||||||
},
|
},
|
||||||
widget::label::{WidgetLabel, WidgetLabelParams},
|
widget::label::{WidgetLabel, WidgetLabelParams},
|
||||||
};
|
};
|
||||||
@@ -13,23 +14,24 @@ pub fn parse_widget_label<'a, U1, U2>(
|
|||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut params = WidgetLabelParams::default();
|
let mut params = WidgetLabelParams::default();
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
|
||||||
|
|
||||||
let style = parse_style(&attribs);
|
let style = parse_style(attribs);
|
||||||
params.style = parse_text_style(&attribs);
|
params.style = parse_text_style(attribs);
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match &*key {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"text" => {
|
"text" => {
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
params.content = Translation::from_raw_text(&value);
|
params.content = Translation::from_raw_text(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"translation" => {
|
"translation" => {
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
params.content = Translation::from_translation_key(&value);
|
params.content = Translation::from_translation_key(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -42,7 +44,7 @@ pub fn parse_widget_label<'a, U1, U2>(
|
|||||||
.layout
|
.layout
|
||||||
.add_child(parent_id, WidgetLabel::create(&mut globals.get(), params), style)?;
|
.add_child(parent_id, WidgetLabel::create(&mut globals.get(), params), style)?;
|
||||||
|
|
||||||
parse_widget_universal(file, ctx, node, new_id);
|
parse_widget_universal(ctx, new_id, attribs);
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ use crate::{
|
|||||||
drawing::GradientMode,
|
drawing::GradientMode,
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{
|
parser::{
|
||||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
parse_children, parse_widget_universal, print_invalid_attrib,
|
||||||
print_invalid_attrib,
|
|
||||||
style::{parse_color, parse_round, parse_style},
|
style::{parse_color, parse_round, parse_style},
|
||||||
|
AttribPair, ParserContext, ParserFile,
|
||||||
},
|
},
|
||||||
widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
|
widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||||
};
|
};
|
||||||
@@ -14,42 +14,43 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
|
|||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut params = WidgetRectangleParams::default();
|
let mut params = WidgetRectangleParams::default();
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
|
||||||
let style = parse_style(&attribs);
|
let style = parse_style(&attribs);
|
||||||
|
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match &*key {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"color" => {
|
"color" => {
|
||||||
parse_color(&value, &mut params.color);
|
parse_color(value, &mut params.color);
|
||||||
}
|
}
|
||||||
"color2" => {
|
"color2" => {
|
||||||
parse_color(&value, &mut params.color2);
|
parse_color(value, &mut params.color2);
|
||||||
}
|
}
|
||||||
"gradient" => {
|
"gradient" => {
|
||||||
params.gradient = match &*value {
|
params.gradient = match value {
|
||||||
"horizontal" => GradientMode::Horizontal,
|
"horizontal" => GradientMode::Horizontal,
|
||||||
"vertical" => GradientMode::Vertical,
|
"vertical" => GradientMode::Vertical,
|
||||||
"radial" => GradientMode::Radial,
|
"radial" => GradientMode::Radial,
|
||||||
"none" => GradientMode::None,
|
"none" => GradientMode::None,
|
||||||
_ => {
|
_ => {
|
||||||
print_invalid_attrib(&key, &value);
|
print_invalid_attrib(key, value);
|
||||||
GradientMode::None
|
GradientMode::None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"round" => {
|
"round" => {
|
||||||
parse_round(&value, &mut params.round);
|
parse_round(value, &mut params.round);
|
||||||
}
|
}
|
||||||
"border" => {
|
"border" => {
|
||||||
params.border = value.parse().unwrap_or_else(|_| {
|
params.border = value.parse().unwrap_or_else(|_| {
|
||||||
print_invalid_attrib(&key, &value);
|
print_invalid_attrib(key, value);
|
||||||
0.0
|
0.0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
"border_color" => {
|
"border_color" => {
|
||||||
parse_color(&value, &mut params.border_color);
|
parse_color(value, &mut params.border_color);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -59,7 +60,7 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
|
|||||||
.layout
|
.layout
|
||||||
.add_child(parent_id, WidgetRectangle::create(params), style)?;
|
.add_child(parent_id, WidgetRectangle::create(params), style)?;
|
||||||
|
|
||||||
parse_widget_universal(file, ctx, node, new_id);
|
parse_widget_universal(ctx, new_id, attribs);
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
layout::WidgetID,
|
layout::WidgetID,
|
||||||
parser::{ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal, style::parse_style},
|
parser::{parse_children, parse_widget_universal, style::parse_style, AttribPair, ParserContext, ParserFile},
|
||||||
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
renderer_vk::text::custom_glyph::{CustomGlyphContent, CustomGlyphData},
|
||||||
widget::sprite::{WidgetSprite, WidgetSpriteParams},
|
widget::sprite::{WidgetSprite, WidgetSpriteParams},
|
||||||
};
|
};
|
||||||
@@ -12,17 +12,18 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
ctx: &mut ParserContext<U1, U2>,
|
ctx: &mut ParserContext<U1, U2>,
|
||||||
node: roxmltree::Node<'a, 'a>,
|
node: roxmltree::Node<'a, 'a>,
|
||||||
parent_id: WidgetID,
|
parent_id: WidgetID,
|
||||||
|
attribs: &[AttribPair],
|
||||||
) -> anyhow::Result<WidgetID> {
|
) -> anyhow::Result<WidgetID> {
|
||||||
let mut params = WidgetSpriteParams::default();
|
let mut params = WidgetSpriteParams::default();
|
||||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
|
||||||
let style = parse_style(&attribs);
|
let style = parse_style(&attribs);
|
||||||
|
|
||||||
let mut glyph = None;
|
let mut glyph = None;
|
||||||
for (key, value) in attribs {
|
for pair in attribs {
|
||||||
match key.as_ref() {
|
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||||
|
match key {
|
||||||
"src" => {
|
"src" => {
|
||||||
if !value.is_empty() {
|
if !value.is_empty() {
|
||||||
glyph = match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals.assets(), &value) {
|
glyph = match CustomGlyphContent::from_assets(&mut ctx.layout.state.globals.assets(), value) {
|
||||||
Ok(glyph) => Some(glyph),
|
Ok(glyph) => Some(glyph),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
log::warn!("failed to load {value}: {e}");
|
log::warn!("failed to load {value}: {e}");
|
||||||
@@ -32,15 +33,15 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"src_ext" => {
|
"src_ext" => {
|
||||||
if !value.is_empty() && std::fs::exists(value.as_ref()).unwrap_or(false) {
|
if !value.is_empty() && std::fs::exists(value).unwrap_or(false) {
|
||||||
glyph = CustomGlyphContent::from_file(&value).ok();
|
glyph = CustomGlyphContent::from_file(value).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"color" => {
|
"color" => {
|
||||||
if let Some(color) = parse_color_hex(&value) {
|
if let Some(color) = parse_color_hex(value) {
|
||||||
params.color = Some(color);
|
params.color = Some(color);
|
||||||
} else {
|
} else {
|
||||||
print_invalid_attrib(&key, &value);
|
print_invalid_attrib(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@@ -55,7 +56,7 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
|||||||
|
|
||||||
let (new_id, _) = ctx.layout.add_child(parent_id, WidgetSprite::create(params), style)?;
|
let (new_id, _) = ctx.layout.add_child(parent_id, WidgetSprite::create(params), style)?;
|
||||||
|
|
||||||
parse_widget_universal(file, ctx, node, new_id);
|
parse_widget_universal(ctx, new_id, attribs);
|
||||||
parse_children(file, ctx, node, new_id)?;
|
parse_children(file, ctx, node, new_id)?;
|
||||||
|
|
||||||
Ok(new_id)
|
Ok(new_id)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use wgui::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{common::OverlaySelector, overlay::OverlayID, task::TaskType, wayvr::WayVRAction},
|
backend::{common::OverlaySelector, overlay::OverlayID, task::TaskType, wayvr::WayVRAction},
|
||||||
config::{AStrSetExt, save_layout},
|
config::{save_layout, AStrSetExt},
|
||||||
state::AppState,
|
state::AppState,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -24,8 +24,8 @@ pub(super) fn setup_custom_button<S>(
|
|||||||
_app: &AppState,
|
_app: &AppState,
|
||||||
) {
|
) {
|
||||||
const EVENTS: [(&str, EventListenerKind); 2] = [
|
const EVENTS: [(&str, EventListenerKind); 2] = [
|
||||||
("press", EventListenerKind::MousePress),
|
("_press", EventListenerKind::MousePress),
|
||||||
("release", EventListenerKind::MouseRelease),
|
("_release", EventListenerKind::MouseRelease),
|
||||||
];
|
];
|
||||||
|
|
||||||
for (name, kind) in &EVENTS {
|
for (name, kind) in &EVENTS {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use wgui::{
|
|||||||
event::{self, EventCallback, EventListenerCollection, ListenerHandleVec},
|
event::{self, EventCallback, EventListenerCollection, ListenerHandleVec},
|
||||||
i18n::Translation,
|
i18n::Translation,
|
||||||
layout::Layout,
|
layout::Layout,
|
||||||
parser::{CustomAttribsInfoOwned, parse_color_hex},
|
parser::{parse_color_hex, CustomAttribsInfoOwned},
|
||||||
widget::label::WidgetLabel,
|
widget::label::WidgetLabel,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -31,14 +31,14 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
listener_handles: &mut ListenerHandleVec,
|
listener_handles: &mut ListenerHandleVec,
|
||||||
app: &AppState,
|
app: &AppState,
|
||||||
) {
|
) {
|
||||||
let Some(source) = attribs.get_value("source") else {
|
let Some(source) = attribs.get_value("_source") else {
|
||||||
log::warn!("custom label with no source!");
|
log::warn!("custom label with no source!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let callback: EventCallback<AppState, S> = match source {
|
let callback: EventCallback<AppState, S> = match source {
|
||||||
"shell" => {
|
"shell" => {
|
||||||
let Some(exec) = attribs.get_value("exec") else {
|
let Some(exec) = attribs.get_value("_exec") else {
|
||||||
log::warn!("label with shell source but no exec attribute!");
|
log::warn!("label with shell source but no exec attribute!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -57,7 +57,7 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
"fifo" => {
|
"fifo" => {
|
||||||
let Some(path) = attribs.get_value("path") else {
|
let Some(path) = attribs.get_value("_path") else {
|
||||||
log::warn!("label with fifo source but no path attribute!");
|
log::warn!("label with fifo source but no path attribute!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -76,7 +76,7 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
}
|
}
|
||||||
"battery" => {
|
"battery" => {
|
||||||
let Some(device) = attribs
|
let Some(device) = attribs
|
||||||
.get_value("device")
|
.get_value("_device")
|
||||||
.and_then(|s| s.parse::<usize>().ok())
|
.and_then(|s| s.parse::<usize>().ok())
|
||||||
else {
|
else {
|
||||||
log::warn!("label with battery source but no device attribute!");
|
log::warn!("label with battery source but no device attribute!");
|
||||||
@@ -85,19 +85,19 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
|
|
||||||
let state = BatteryLabelState {
|
let state = BatteryLabelState {
|
||||||
low_color: attribs
|
low_color: attribs
|
||||||
.get_value("low_color")
|
.get_value("_low_color")
|
||||||
.and_then(parse_color_hex)
|
.and_then(parse_color_hex)
|
||||||
.unwrap_or(BAT_LOW),
|
.unwrap_or(BAT_LOW),
|
||||||
normal_color: attribs
|
normal_color: attribs
|
||||||
.get_value("normal_color")
|
.get_value("_normal_color")
|
||||||
.and_then(parse_color_hex)
|
.and_then(parse_color_hex)
|
||||||
.unwrap_or(BAT_NORMAL),
|
.unwrap_or(BAT_NORMAL),
|
||||||
charging_color: attribs
|
charging_color: attribs
|
||||||
.get_value("charging_color")
|
.get_value("_charging_color")
|
||||||
.and_then(parse_color_hex)
|
.and_then(parse_color_hex)
|
||||||
.unwrap_or(BAT_CHARGING),
|
.unwrap_or(BAT_CHARGING),
|
||||||
low_threshold: attribs
|
low_threshold: attribs
|
||||||
.get_value("low_threshold")
|
.get_value("_low_threshold")
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(BAT_LOW_THRESHOLD),
|
.unwrap_or(BAT_LOW_THRESHOLD),
|
||||||
device,
|
device,
|
||||||
@@ -108,7 +108,7 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
"clock" => {
|
"clock" => {
|
||||||
let Some(display) = attribs.get_value("display") else {
|
let Some(display) = attribs.get_value("_display") else {
|
||||||
log::warn!("label with clock source but no display attribute!");
|
log::warn!("label with clock source but no display attribute!");
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@@ -116,7 +116,7 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
let format = match display {
|
let format = match display {
|
||||||
"name" => {
|
"name" => {
|
||||||
let maybe_pretty_tz = attribs
|
let maybe_pretty_tz = attribs
|
||||||
.get_value("timezone")
|
.get_value("_timezone")
|
||||||
.and_then(|tz| tz.parse::<usize>().ok())
|
.and_then(|tz| tz.parse::<usize>().ok())
|
||||||
.and_then(|tz_idx| app.session.config.timezones.get(tz_idx))
|
.and_then(|tz_idx| app.session.config.timezones.get(tz_idx))
|
||||||
.and_then(|tz_name| {
|
.and_then(|tz_name| {
|
||||||
@@ -152,7 +152,7 @@ pub(super) fn setup_custom_label<S>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let tz_str = attribs
|
let tz_str = attribs
|
||||||
.get_value("timezone")
|
.get_value("_timezone")
|
||||||
.and_then(|tz| tz.parse::<usize>().ok())
|
.and_then(|tz| tz.parse::<usize>().ok())
|
||||||
.and_then(|tz_idx| app.session.config.timezones.get(tz_idx));
|
.and_then(|tz_idx| app.session.config.timezones.get(tz_idx));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user