diff --git a/uidev/assets/gui/various_widgets.xml b/uidev/assets/gui/various_widgets.xml
index d4c4c4f..ec7eb24 100644
--- a/uidev/assets/gui/various_widgets.xml
+++ b/uidev/assets/gui/various_widgets.xml
@@ -24,11 +24,19 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/uidev/src/testbed/testbed_generic.rs b/uidev/src/testbed/testbed_generic.rs
index 2343a3f..17f8a65 100644
--- a/uidev/src/testbed/testbed_generic.rs
+++ b/uidev/src/testbed/testbed_generic.rs
@@ -62,16 +62,28 @@ impl TestbedGeneric {
let globals = WguiGlobals::new(Box::new(assets::Asset {}), Default::default())?;
let extra = ParseDocumentExtra {
- on_custom_attrib: Some(Box::new(move |par| {
- if par.attrib == "my_custom" {
- let mut rect = par.get_widget_as::().unwrap();
- rect.params.color = match par.value {
- "red" => Color::new(1.0, 0.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),
- _ => Color::new(1.0, 1.0, 1.0, 1.0),
- }
- }
+ on_custom_attribs: Some(Box::new(move |par| {
+ let Some(my_custom_value) = par.get_value("my_custom") else {
+ return;
+ };
+
+ let Some(mult_value) = par.get_value("mult") else {
+ return;
+ };
+
+ let mult_f32 = mult_value.parse::().unwrap();
+
+ let mut color = match my_custom_value {
+ "red" => Color::new(1.0, 0.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),
+ _ => Color::new(1.0, 1.0, 1.0, 1.0),
+ };
+
+ color = color.mult_rgb(mult_f32);
+
+ let mut rect = par.get_widget_as::().unwrap();
+ rect.params.color = color;
})),
dev_mode: false,
};
diff --git a/wgui/src/drawing.rs b/wgui/src/drawing.rs
index a3828a3..5ac29a8 100644
--- a/wgui/src/drawing.rs
+++ b/wgui/src/drawing.rs
@@ -61,6 +61,16 @@ impl Color {
}
}
+ #[must_use]
+ pub fn mult_rgb(&self, n: f32) -> Self {
+ Self {
+ r: self.r * n,
+ g: self.g * n,
+ b: self.b * n,
+ a: self.a,
+ }
+ }
+
#[must_use]
pub fn lerp(&self, other: &Self, n: f32) -> Self {
Self {
@@ -159,12 +169,7 @@ fn draw_widget(
}
}
-fn draw_children(
- layout: &Layout,
- state: &mut DrawState,
- parent_node_id: taffy::NodeId,
- model: &glam::Mat4,
-) {
+fn draw_children(layout: &Layout, state: &mut DrawState, parent_node_id: taffy::NodeId, model: &glam::Mat4) {
for node_id in layout.state.tree.child_ids(parent_node_id) {
let Some(widget_id) = layout.state.tree.get_node_context(node_id).copied() else {
debug_assert!(false);
@@ -207,14 +212,7 @@ pub fn draw(layout: &Layout) -> anyhow::Result> {
depth: 0.0,
};
- draw_widget(
- layout,
- &mut params,
- layout.root_node,
- style,
- root_widget,
- &model,
- );
+ draw_widget(layout, &mut params, layout.root_node, style, root_widget, &model);
Ok(primitives)
}
diff --git a/wgui/src/parser/mod.rs b/wgui/src/parser/mod.rs
index 3676747..e785673 100644
--- a/wgui/src/parser/mod.rs
+++ b/wgui/src/parser/mod.rs
@@ -21,6 +21,7 @@ use crate::{
},
};
use ouroboros::self_referencing;
+use smallvec::SmallVec;
use std::{
cell::RefMut,
collections::HashMap,
@@ -640,7 +641,9 @@ fn parse_child<'a, U1, U2>(
// check for custom attributes (if the callback is set)
if let Some(widget_id) = new_widget_id {
- if let Some(on_custom_attrib) = &ctx.doc_params.extra.on_custom_attrib {
+ if let Some(on_custom_attribs) = &ctx.doc_params.extra.on_custom_attribs {
+ let mut pairs = SmallVec::<[CustomAttribPair; 4]>::new();
+
for attrib in child_node.attributes() {
let attr_name = attrib.name();
if !attr_name.starts_with('_') || attr_name.is_empty() {
@@ -649,12 +652,18 @@ fn parse_child<'a, U1, U2>(
let attr_without_prefix = &attr_name[1..]; // safe
- on_custom_attrib(CustomAttribInfo {
+ pairs.push(CustomAttribPair {
+ attrib: attr_without_prefix,
+ value: attrib.value(),
+ });
+ }
+
+ if !pairs.is_empty() {
+ on_custom_attribs(CustomAttribsInfo {
widgets: &ctx.layout.state.widgets,
parent_id,
widget_id,
- attrib: attr_without_prefix,
- value: attrib.value(),
+ pairs: &pairs,
});
}
}
@@ -694,16 +703,20 @@ fn create_default_context<'a, U1, U2>(
}
}
-pub struct CustomAttribInfo<'a> {
- pub parent_id: WidgetID,
- pub widget_id: WidgetID,
- pub widgets: &'a WidgetMap,
+pub struct CustomAttribPair<'a> {
pub attrib: &'a str, // without _ at the beginning
pub value: &'a str,
}
+pub struct CustomAttribsInfo<'a> {
+ pub parent_id: WidgetID,
+ pub widget_id: WidgetID,
+ pub widgets: &'a WidgetMap,
+ pub pairs: &'a [CustomAttribPair<'a>],
+}
+
// helper functions
-impl CustomAttribInfo<'_> {
+impl CustomAttribsInfo<'_> {
pub fn get_widget(&self) -> Option<&Widget> {
self.widgets.get(self.widget_id)
}
@@ -711,13 +724,24 @@ impl CustomAttribInfo<'_> {
pub fn get_widget_as(&self) -> Option> {
self.widgets.get(self.widget_id)?.get_as_mut::()
}
+
+ 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);
+ }
+ }
+
+ None
+ }
}
-pub type OnCustomAttribFunc = Box;
+pub type OnCustomAttribsFunc = Box;
#[derive(Default)]
pub struct ParseDocumentExtra {
- pub on_custom_attrib: Option, // all attributes with '_' character prepended
+ pub on_custom_attribs: Option, // all attributes with '_' character prepended
pub dev_mode: bool,
}