diff --git a/crates/ewwii/src/widgets/build_widget.rs b/crates/ewwii/src/widgets/build_widget.rs index 9abf5bc..8f61b43 100644 --- a/crates/ewwii/src/widgets/build_widget.rs +++ b/crates/ewwii/src/widgets/build_widget.rs @@ -50,6 +50,9 @@ fn build_gtk_widget_from_node( WidgetNode::ToolTip { props, children } => { build_tooltip(props, children, widget_reg)?.upcast() } + WidgetNode::LocalBind { props, children } => { + build_localbind(props, children, widget_reg)?.upcast() + } WidgetNode::CircularProgress { props } => { build_circular_progress_bar(props, widget_reg)?.upcast() } diff --git a/crates/ewwii/src/widgets/widget_definitions.rs b/crates/ewwii/src/widgets/widget_definitions.rs index 1e39eed..b865b70 100644 --- a/crates/ewwii/src/widgets/widget_definitions.rs +++ b/crates/ewwii/src/widgets/widget_definitions.rs @@ -13,6 +13,7 @@ use gtk4::{ }; use rhai::Map; use rhai_impl::ast::{get_id_to_widget_info, hash_props_and_type, WidgetNode}; +use rhai_impl::updates::LocalSignal; use super::widget_definitions_helper::*; use shared_utils::extract_props::*; @@ -418,6 +419,78 @@ pub(super) fn build_tooltip( Ok(gtk_widget) } +pub(super) fn build_localbind( + props: &Map, + children: &Vec, + widget_registry: &mut WidgetRegistry, +) -> Result { + let gtk_widget = gtk4::Box::new(gtk4::Orientation::Horizontal, 0); + + let count = children.len(); + + if count < 1 { + bail!("localbind must contain exactly 1 child"); + } else if count > 1 { + bail!("localbind must contain exactly 1 child, but got more"); + } + + let child_node = children.get(0).cloned().ok_or_else(|| anyhow!("missing child"))?; + let child_widget = build_gtk_widget(&WidgetInput::Node(child_node), widget_registry)?; + gtk_widget.append(&child_widget); + + let bindings_variant = props.get("bindings"); + + if bindings_variant.is_none() { + bail!("No 'bindings' map found in props."); + } + + let bindings = match bindings_variant.and_then(|v| v.clone().try_cast::()) { + Some(map) => map, + None => { + bail!("'bindings' is not a valid map."); + } + }; + + for (prop_name, localsignal_val) in bindings { + let prop_name = prop_name.clone(); + + let localsignal = match localsignal_val.clone().try_cast::() { + Some(sig) => sig, + None => { + bail!("Invalid localsignal for property '{}'", prop_name); + } + }; + + let data_obj: glib::Object = localsignal.data.as_ref().clone().upcast(); + + data_obj + .bind_property("value", &child_widget, &prop_name) + .flags(glib::BindingFlags::SYNC_CREATE) + .build(); + } + + let gtk_widget_clone = gtk_widget.clone(); + let update_fn: UpdateFn = Box::new(move |props: &Map| { + // now re-apply generic widget attrs + if let Err(err) = + resolve_rhai_widget_attrs(>k_widget_clone.clone().upcast::(), &props) + { + eprintln!("Failed to update widget attrs: {:?}", err); + } + }); + + let id = hash_props_and_type(&props, "LocalBind"); + + widget_registry + .widgets + .insert(id, WidgetEntry { widget: gtk_widget.clone().upcast(), update_fn }); + + resolve_rhai_widget_attrs(>k_widget.clone().upcast::(), &props)?; + + Ok(gtk_widget) +} + + struct EventBoxCtrlData { // hover controller data onhover_cmd: String, diff --git a/crates/rhai_impl/src/ast.rs b/crates/rhai_impl/src/ast.rs index 2aced53..8c4ebde 100644 --- a/crates/rhai_impl/src/ast.rs +++ b/crates/rhai_impl/src/ast.rs @@ -32,6 +32,7 @@ pub enum WidgetNode { Transform { props: Map }, EventBox { props: Map, children: Vec }, ToolTip { props: Map, children: Vec }, + LocalBind { props: Map, children: Vec }, // Top-level macros DefWindow { name: String, props: Map, node: Box }, @@ -151,6 +152,13 @@ pub fn get_id_to_widget_info<'a>( get_id_to_widget_info(child, id_to_props, Some(id))?; } } + WidgetNode::LocalBind { props, children } => { + let id = hash_props_and_type(props, "LocalBind"); + insert_wdgt_info(node, props, "LocalBind", children.as_slice(), parent_id, id_to_props)?; + for child in children { + get_id_to_widget_info(child, id_to_props, Some(id))?; + } + } WidgetNode::ColorChooser { props } => { // let id = hash_props_and_type(props, "ColorChooser"); insert_wdgt_info(node, props, "ColorChooser", &[], parent_id, id_to_props)?; diff --git a/crates/rhai_impl/src/builtins.rs b/crates/rhai_impl/src/builtins.rs index c6248cf..f1f75ab 100644 --- a/crates/rhai_impl/src/builtins.rs +++ b/crates/rhai_impl/src/builtins.rs @@ -78,6 +78,7 @@ pub fn register_all_widgets(engine: &mut Engine, all_nodes: &Rc Result> { diff --git a/crates/rhai_impl/src/dyn_id.rs b/crates/rhai_impl/src/dyn_id.rs index 8d7b7ed..a18618a 100644 --- a/crates/rhai_impl/src/dyn_id.rs +++ b/crates/rhai_impl/src/dyn_id.rs @@ -71,6 +71,10 @@ impl WidgetNode { props: with_dyn_id(props.clone(), parent_path), children: process_children(children, parent_path, "tooltip"), }, + WidgetNode::LocalBind { props, children } => WidgetNode::LocalBind { + props: with_dyn_id(props.clone(), parent_path), + children: process_children(children, parent_path, "localbind"), + }, // == Top-level container for multiple widgets == WidgetNode::Enter(children) => {