attribs rework
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
use crate::{
|
||||
components::{Component, button},
|
||||
components::{button, Component},
|
||||
drawing::Color,
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_children, process_component,
|
||||
parse_children, process_component,
|
||||
style::{parse_color_opt, parse_round, parse_style, parse_text_style},
|
||||
AttribPair, ParserContext, ParserFile,
|
||||
},
|
||||
widget::util::WLength,
|
||||
};
|
||||
@@ -15,6 +16,7 @@ pub fn parse_component_button<'a, U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut 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 translation: Option<Translation> = None;
|
||||
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
let text_style = parse_text_style(&attribs);
|
||||
let style = parse_style(&attribs);
|
||||
let text_style = parse_text_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() {
|
||||
"text" => {
|
||||
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)?;
|
||||
|
||||
Ok(new_id)
|
||||
|
||||
@@ -1,38 +1,35 @@
|
||||
use crate::{
|
||||
components::{Component, checkbox},
|
||||
components::{checkbox, Component},
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_check_f32, parse_check_i32, process_component, style::parse_style,
|
||||
},
|
||||
parser::{parse_check_f32, parse_check_i32, process_component, style::parse_style, AttribPair, ParserContext},
|
||||
};
|
||||
|
||||
pub fn parse_component_checkbox<'a, U1, U2>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut box_size = 24.0;
|
||||
let mut translation = Translation::default();
|
||||
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 {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"text" => {
|
||||
translation = Translation::from_raw_text(&value);
|
||||
translation = Translation::from_raw_text(value);
|
||||
}
|
||||
"translation" => {
|
||||
translation = Translation::from_translation_key(&value);
|
||||
translation = Translation::from_translation_key(value);
|
||||
}
|
||||
"box_size" => {
|
||||
parse_check_f32(value.as_ref(), &mut box_size);
|
||||
parse_check_f32(value, &mut box_size);
|
||||
}
|
||||
"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)
|
||||
}
|
||||
|
||||
@@ -1,32 +1,31 @@
|
||||
use crate::{
|
||||
components::{Component, slider},
|
||||
components::{slider, Component},
|
||||
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>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut min_value = 0.0;
|
||||
let mut max_value = 1.0;
|
||||
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 {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"min_value" => {
|
||||
parse_check_f32(value.as_ref(), &mut min_value);
|
||||
parse_check_f32(value, &mut min_value);
|
||||
}
|
||||
"max_value" => {
|
||||
parse_check_f32(value.as_ref(), &mut max_value);
|
||||
parse_check_f32(value, &mut max_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)
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ fn print_invalid_value(value: &str) {
|
||||
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 {
|
||||
print_invalid_value(value);
|
||||
return None;
|
||||
@@ -534,15 +534,16 @@ fn parse_widget_other<'a, U1, U2>(
|
||||
xml_tag_name: &str,
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<()> {
|
||||
let Some(template) = ctx.get_template(xml_tag_name) else {
|
||||
log::error!("Undefined tag named \"{xml_tag_name}\"");
|
||||
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)
|
||||
}
|
||||
@@ -550,17 +551,15 @@ fn parse_widget_other<'a, U1, U2>(
|
||||
fn parse_tag_include<'a, U1, U2>(
|
||||
file: &ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<()> {
|
||||
for attrib in node.attributes() {
|
||||
let (key, value) = (attrib.name(), attrib.value());
|
||||
|
||||
for pair in attribs {
|
||||
#[allow(clippy::single_match)]
|
||||
match key {
|
||||
match pair.attrib.as_ref() {
|
||||
"src" => {
|
||||
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_file, node_layout) = get_doc_from_path(ctx, &new_path)?;
|
||||
@@ -569,7 +568,7 @@ fn parse_tag_include<'a, U1, U2>(
|
||||
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>,
|
||||
key: &str,
|
||||
value: &str,
|
||||
) -> (Rc<str>, Rc<str>) {
|
||||
) -> AttribPair {
|
||||
if value.starts_with('~') {
|
||||
let name = &value[1..];
|
||||
|
||||
(
|
||||
Rc::from(key),
|
||||
match ctx.get_var(name) {
|
||||
Some(name) => name,
|
||||
None => Rc::from("undefined"),
|
||||
},
|
||||
)
|
||||
match ctx.get_var(name) {
|
||||
Some(name) => AttribPair::new(key, name.clone()),
|
||||
None => AttribPair::new(key, "undefined"),
|
||||
}
|
||||
} 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,
|
||||
ctx: &'a ParserContext<U1, U2>,
|
||||
node: &'a roxmltree::Node<'a, 'a>,
|
||||
is_tag_macro: bool,
|
||||
) -> impl Iterator<Item = (/*key*/ Rc<str>, /*value*/ Rc<str>)> + 'a {
|
||||
let mut res = Vec::<(Rc<str>, Rc<str>)>::new();
|
||||
|
||||
) -> Vec<AttribPair> {
|
||||
if is_tag_macro {
|
||||
// return as-is, no attrib post-processing
|
||||
for attrib in node.attributes() {
|
||||
let (key, value) = (attrib.name(), attrib.value());
|
||||
res.push((Rc::from(key), Rc::from(value)));
|
||||
}
|
||||
return res.into_iter();
|
||||
return raw_attribs(node);
|
||||
}
|
||||
let mut res = vec![];
|
||||
|
||||
for attrib in node.attributes() {
|
||||
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>) {
|
||||
@@ -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<'_, '_>) {
|
||||
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 {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
match pair.attrib.as_ref() {
|
||||
"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<'_, '_>) {
|
||||
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();
|
||||
|
||||
for (key, value) in attribs {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
match pair.attrib.as_ref() {
|
||||
"name" => {
|
||||
macro_name = Some(value);
|
||||
macro_name = Some(pair.value);
|
||||
}
|
||||
_ => {
|
||||
if macro_attribs.insert(key.clone(), value).is_some() {
|
||||
log::warn!("macro attrib \"{key}\" already defined!");
|
||||
if macro_attribs.insert(pair.attrib.clone(), pair.value).is_some() {
|
||||
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>(
|
||||
file: &'a ParserFile,
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
component: Component,
|
||||
widget_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) {
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
|
||||
let mut component_id: Option<Rc<str>> = None;
|
||||
|
||||
for (key, value) in attribs {
|
||||
for pair in attribs {
|
||||
#[allow(clippy::single_match)]
|
||||
match key.as_ref() {
|
||||
match pair.attrib.as_ref() {
|
||||
"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);
|
||||
}
|
||||
|
||||
fn parse_widget_universal<'a, U1, U2>(
|
||||
file: &'a ParserFile,
|
||||
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 {
|
||||
fn parse_widget_universal<'a, U1, U2>(ctx: &mut ParserContext<U1, U2>, widget_id: WidgetID, attribs: &[AttribPair]) {
|
||||
for pair in attribs {
|
||||
#[allow(clippy::single_match)]
|
||||
match key.as_ref() {
|
||||
match pair.attrib.as_ref() {
|
||||
"id" => {
|
||||
// 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;
|
||||
|
||||
match child_node.tag_name().name() {
|
||||
"include" => {
|
||||
parse_tag_include(file, ctx, child_node, parent_id)?;
|
||||
parse_tag_include(file, ctx, parent_id, &attribs)?;
|
||||
}
|
||||
"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" => {
|
||||
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" => {
|
||||
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" => {
|
||||
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" => {
|
||||
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" => {
|
||||
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" => {
|
||||
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 */ }
|
||||
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
|
||||
&& 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() {
|
||||
let attr_name = attrib.name();
|
||||
if !attr_name.starts_with('_') || attr_name.is_empty() {
|
||||
for pair in attribs {
|
||||
if !pair.attrib.starts_with('_') || pair.attrib.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let attr_without_prefix = &attr_name[1..]; // safe
|
||||
|
||||
pairs.push(CustomAttribPair {
|
||||
attrib: attr_without_prefix,
|
||||
value: attrib.value(),
|
||||
});
|
||||
pairs.push(pair.clone());
|
||||
}
|
||||
|
||||
if !pairs.is_empty() {
|
||||
@@ -921,16 +906,30 @@ fn create_default_context<'a, U1, U2>(
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CustomAttribPair<'a> {
|
||||
pub attrib: &'a str, // without _ at the beginning
|
||||
pub value: &'a str,
|
||||
#[derive(Clone)]
|
||||
pub struct AttribPair {
|
||||
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 parent_id: WidgetID,
|
||||
pub widget_id: WidgetID,
|
||||
pub widgets: &'a WidgetMap,
|
||||
pub pairs: &'a [CustomAttribPair<'a>],
|
||||
pub pairs: &'a [AttribPair],
|
||||
}
|
||||
|
||||
// helper functions
|
||||
@@ -943,11 +942,11 @@ impl CustomAttribsInfo<'_> {
|
||||
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
|
||||
for pair in self.pairs {
|
||||
if pair.attrib == attrib_name {
|
||||
return Some(pair.value);
|
||||
if *pair.attrib == *attrib_name {
|
||||
return Some(pair.value.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -958,35 +957,23 @@ impl CustomAttribsInfo<'_> {
|
||||
CustomAttribsInfoOwned {
|
||||
parent_id: self.parent_id,
|
||||
widget_id: self.widget_id,
|
||||
pairs: self
|
||||
.pairs
|
||||
.iter()
|
||||
.map(|p| CustomAttribPairOwned {
|
||||
attrib: p.attrib.to_string(),
|
||||
value: p.value.to_string(),
|
||||
})
|
||||
.collect(),
|
||||
pairs: self.pairs.iter().cloned().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CustomAttribPairOwned {
|
||||
pub attrib: String, // without _ at the beginning
|
||||
pub value: String,
|
||||
}
|
||||
|
||||
pub struct CustomAttribsInfoOwned {
|
||||
pub parent_id: WidgetID,
|
||||
pub widget_id: WidgetID,
|
||||
pub pairs: Vec<CustomAttribPairOwned>,
|
||||
pub pairs: Vec<AttribPair>,
|
||||
}
|
||||
|
||||
impl CustomAttribsInfoOwned {
|
||||
pub fn get_value(&self, attrib_name: &str) -> Option<&str> {
|
||||
// O(n) search, these pairs won't be problematically big anyways
|
||||
for pair in &self.pairs {
|
||||
if pair.attrib == attrib_name {
|
||||
return Some(pair.value.as_str());
|
||||
if pair.attrib.as_ref() == attrib_name {
|
||||
return Some(pair.value.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1091,7 +1078,7 @@ fn parse_document_root<U1, U2>(
|
||||
#[allow(clippy::single_match)]
|
||||
match child_node.tag_name().name() {
|
||||
/* 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),
|
||||
"template" => parse_tag_template(file, ctx, child_node),
|
||||
"macro" => parse_tag_macro(file, ctx, child_node),
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
use std::rc::Rc;
|
||||
|
||||
use taffy::{
|
||||
AlignContent, AlignItems, AlignSelf, BoxSizing, Display, FlexDirection, FlexWrap, JustifyContent,
|
||||
JustifySelf, Overflow,
|
||||
AlignContent, AlignItems, AlignSelf, BoxSizing, Display, FlexDirection, FlexWrap, JustifyContent, JustifySelf,
|
||||
Overflow,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
drawing,
|
||||
parser::{
|
||||
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val,
|
||||
print_invalid_attrib, print_invalid_value,
|
||||
is_percent, parse_color_hex, parse_f32, parse_percent, parse_size_unit, parse_val, print_invalid_attrib,
|
||||
print_invalid_value, AttribPair,
|
||||
},
|
||||
renderer_vk::text::{FontWeight, HorizontalAlign, TextStyle},
|
||||
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();
|
||||
|
||||
for (key, value) in attribs {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"color" => {
|
||||
if let Some(color) = parse_color_hex(value) {
|
||||
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::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();
|
||||
|
||||
for (key, value) in attribs {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key.as_ref() {
|
||||
"display" => match value.as_ref() {
|
||||
"flex" => style.display = Display::Flex,
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use crate::{
|
||||
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},
|
||||
widget::div::WidgetDiv,
|
||||
};
|
||||
|
||||
@@ -12,15 +9,13 @@ pub fn parse_widget_div<'a, U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> 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
|
||||
.layout
|
||||
.add_child(parent_id, WidgetDiv::create(), style)?;
|
||||
let (new_id, _) = ctx.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)?;
|
||||
|
||||
Ok(new_id)
|
||||
|
||||
@@ -2,8 +2,9 @@ use crate::{
|
||||
i18n::Translation,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
||||
parse_children, parse_widget_universal,
|
||||
style::{parse_style, parse_text_style},
|
||||
AttribPair, ParserContext, ParserFile,
|
||||
},
|
||||
widget::label::{WidgetLabel, WidgetLabelParams},
|
||||
};
|
||||
@@ -13,23 +14,24 @@ pub fn parse_widget_label<'a, U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut params = WidgetLabelParams::default();
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
|
||||
let style = parse_style(&attribs);
|
||||
params.style = parse_text_style(&attribs);
|
||||
let style = parse_style(attribs);
|
||||
params.style = parse_text_style(attribs);
|
||||
|
||||
for (key, value) in attribs {
|
||||
match &*key {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"text" => {
|
||||
if !value.is_empty() {
|
||||
params.content = Translation::from_raw_text(&value);
|
||||
params.content = Translation::from_raw_text(value);
|
||||
}
|
||||
}
|
||||
"translation" => {
|
||||
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
|
||||
.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)?;
|
||||
|
||||
Ok(new_id)
|
||||
|
||||
@@ -2,9 +2,9 @@ use crate::{
|
||||
drawing::GradientMode,
|
||||
layout::WidgetID,
|
||||
parser::{
|
||||
ParserContext, ParserFile, iter_attribs, parse_children, parse_widget_universal,
|
||||
print_invalid_attrib,
|
||||
parse_children, parse_widget_universal, print_invalid_attrib,
|
||||
style::{parse_color, parse_round, parse_style},
|
||||
AttribPair, ParserContext, ParserFile,
|
||||
},
|
||||
widget::rectangle::{WidgetRectangle, WidgetRectangleParams},
|
||||
};
|
||||
@@ -14,42 +14,43 @@ pub fn parse_widget_rectangle<'a, U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut params = WidgetRectangleParams::default();
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
let style = parse_style(&attribs);
|
||||
|
||||
for (key, value) in attribs {
|
||||
match &*key {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"color" => {
|
||||
parse_color(&value, &mut params.color);
|
||||
parse_color(value, &mut params.color);
|
||||
}
|
||||
"color2" => {
|
||||
parse_color(&value, &mut params.color2);
|
||||
parse_color(value, &mut params.color2);
|
||||
}
|
||||
"gradient" => {
|
||||
params.gradient = match &*value {
|
||||
params.gradient = match value {
|
||||
"horizontal" => GradientMode::Horizontal,
|
||||
"vertical" => GradientMode::Vertical,
|
||||
"radial" => GradientMode::Radial,
|
||||
"none" => GradientMode::None,
|
||||
_ => {
|
||||
print_invalid_attrib(&key, &value);
|
||||
print_invalid_attrib(key, value);
|
||||
GradientMode::None
|
||||
}
|
||||
}
|
||||
}
|
||||
"round" => {
|
||||
parse_round(&value, &mut params.round);
|
||||
parse_round(value, &mut params.round);
|
||||
}
|
||||
"border" => {
|
||||
params.border = value.parse().unwrap_or_else(|_| {
|
||||
print_invalid_attrib(&key, &value);
|
||||
print_invalid_attrib(key, value);
|
||||
0.0
|
||||
});
|
||||
}
|
||||
"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
|
||||
.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)?;
|
||||
|
||||
Ok(new_id)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
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},
|
||||
widget::sprite::{WidgetSprite, WidgetSpriteParams},
|
||||
};
|
||||
@@ -12,17 +12,18 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
||||
ctx: &mut ParserContext<U1, U2>,
|
||||
node: roxmltree::Node<'a, 'a>,
|
||||
parent_id: WidgetID,
|
||||
attribs: &[AttribPair],
|
||||
) -> anyhow::Result<WidgetID> {
|
||||
let mut params = WidgetSpriteParams::default();
|
||||
let attribs: Vec<_> = iter_attribs(file, ctx, &node, false).collect();
|
||||
let style = parse_style(&attribs);
|
||||
|
||||
let mut glyph = None;
|
||||
for (key, value) in attribs {
|
||||
match key.as_ref() {
|
||||
for pair in attribs {
|
||||
let (key, value) = (pair.attrib.as_ref(), pair.value.as_ref());
|
||||
match key {
|
||||
"src" => {
|
||||
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),
|
||||
Err(e) => {
|
||||
log::warn!("failed to load {value}: {e}");
|
||||
@@ -32,15 +33,15 @@ pub fn parse_widget_sprite<'a, U1, U2>(
|
||||
}
|
||||
}
|
||||
"src_ext" => {
|
||||
if !value.is_empty() && std::fs::exists(value.as_ref()).unwrap_or(false) {
|
||||
glyph = CustomGlyphContent::from_file(&value).ok();
|
||||
if !value.is_empty() && std::fs::exists(value).unwrap_or(false) {
|
||||
glyph = CustomGlyphContent::from_file(value).ok();
|
||||
}
|
||||
}
|
||||
"color" => {
|
||||
if let Some(color) = parse_color_hex(&value) {
|
||||
if let Some(color) = parse_color_hex(value) {
|
||||
params.color = Some(color);
|
||||
} 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)?;
|
||||
|
||||
parse_widget_universal(file, ctx, node, new_id);
|
||||
parse_widget_universal(ctx, new_id, attribs);
|
||||
parse_children(file, ctx, node, new_id)?;
|
||||
|
||||
Ok(new_id)
|
||||
|
||||
Reference in New Issue
Block a user