diff --git a/crates/ewwii/src/app.rs b/crates/ewwii/src/app.rs index 3752a75..a937c98 100644 --- a/crates/ewwii/src/app.rs +++ b/crates/ewwii/src/app.rs @@ -23,7 +23,7 @@ use ewwii_shared_util::Span; use gdk::Monitor; use glib::ObjectExt; use gtk::{gdk, glib}; -use iirhai::widgetnode::{get_id_to_props_map, WidgetNode}; +use iirhai::widgetnode::WidgetNode; use itertools::Itertools; use once_cell::sync::Lazy; use rhai::{Dynamic, Scope}; @@ -344,10 +344,7 @@ impl App { let vars = store.read().unwrap().clone(); if let Ok(new_widget) = generate_new_widgetnode(&vars, &config_path).await { - let mut id_to_prop = HashMap::new(); - let _ = get_id_to_props_map(&new_widget, &mut id_to_prop); - - widget_reg_store.update_prop_changes(id_to_prop); + widget_reg_store.update_widget_tree(new_widget); } else { log::error!("Failed to generate new widgetnode"); } diff --git a/crates/ewwii/src/widgets/widget_definitions.rs b/crates/ewwii/src/widgets/widget_definitions.rs index 30e2bec..e6a73e3 100644 --- a/crates/ewwii/src/widgets/widget_definitions.rs +++ b/crates/ewwii/src/widgets/widget_definitions.rs @@ -8,7 +8,7 @@ use anyhow::{anyhow, bail, Result}; use gdk::{ModifierType, NotifyType}; use gtk::{self, prelude::*, DestDefaults, TargetEntry, TargetList}; use gtk::{gdk, glib, pango}; -use iirhai::widgetnode::{hash_props_and_type, WidgetNode}; +use iirhai::widgetnode::{hash_props_and_type, WidgetNode, get_id_to_widget_info}; use once_cell::sync::Lazy; use rhai::Map; @@ -53,7 +53,7 @@ macro_rules! connect_signal_handler { pub type UpdateFn = Box; pub struct WidgetEntry { - // pub widget: gtk::Widget, // not needed now + pub widget: gtk::Widget, pub update_fn: UpdateFn, } @@ -63,29 +63,24 @@ pub struct WidgetRegistry { } pub enum PatchGtkWidget { - Create(u64, Map), + Create(WidgetNode), Update(u64, Map), Remove(u64), } impl WidgetRegistry { pub fn new() -> Self { - Self { widgets: HashMap::new() } - } - - fn diff_trees(old: Option, new: WidgetNode) -> Vec { - let mut id_to_prop = HashMap::new(); - let _ = get_id_to_props_map(&new_widget, &mut id_to_prop); + Self { widgets: HashMap::new(), stored_widget_node: None } } pub fn update_widget_tree(&mut self, new_tree: WidgetNode) { let old_tree = self.stored_widget_node.take(); - let patch = diff_trees(old_tree, new_tree.clone()); + let patch = Self::diff_trees(old_tree.as_ref(), &new_tree); for op in patch { match op { - PatchGtkWidget::Create(widget_id, props) => self.create_widget(widget_id, props), + PatchGtkWidget::Create(w_node) => build_gtk_widget(WidgetInput::Node(w_node), &mut self), PatchGtkWidget::Update(widget_id, new_props) => self.update_props(widget_id, new_props), PatchGtkWidget::Remove(widget_id) => self.remove_widget(widget_id), } @@ -94,15 +89,53 @@ impl WidgetRegistry { self.stored_widget_node = Some(new_tree); } + pub fn diff_trees(old: Option<&WidgetNode>, new: &WidgetNode) -> Vec { + let mut patch = Vec::new(); + + let mut old_map = HashMap::new(); + if let Some(old_node) = old { + let _ = get_id_to_widget_info(old_node, &mut old_map); + } + + let mut new_map = HashMap::new(); + let _ = get_id_to_widget_info(new, &mut new_map); + + // Updates and creations + for (id, new_info) in &new_map { + match old_map.get(id) { + Some(old_info) if old_info.props != new_info.props => { + patch.push(PatchGtkWidget::Update(*id, new_info.props.clone())); + } + None => { + if let Some(info) = new_info.get(&id) { + patch.push(PatchGtkWidget::Create(info.node.clone())); + } + } + _ => {} + } + } + + // Removals + for id in old_map.keys() { + if !new_map.contains_key(id) { + patch.push(PatchGtkWidget::Remove(*id)); + } + } + + patch + } + pub fn update_props(&self, id_to_props: HashMap) { for (id, props) in id_to_props { if let Some(entry) = self.widgets.get(&id) { (entry.update_fn)(&props); - } // else { - // println!("Warning: id {} not found in widget_registry", id); - // } + } } } + + pub fn remove_widget(&self, widget_id: u64) { + + } } pub(super) fn build_gtk_box(props: Map, children: Vec, widget_registry: &mut WidgetRegistry) -> Result { @@ -154,7 +187,7 @@ pub(super) fn build_gtk_box(props: Map, children: Vec, widget_regist widget_registry.widgets.insert( id, WidgetEntry { - // widget: gtk_widget.upcast(), + widget: gtk_widget.upcast(), update_fn, }, ); @@ -281,7 +314,7 @@ pub(super) fn build_center_box(props: Map, children: Vec, widget_reg let id = hash_props_and_type(&props, "CenterBox"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast() }); Ok(gtk_widget) } @@ -506,7 +539,7 @@ pub(super) fn build_gtk_event_box( let id = hash_props_and_type(&props, "EventBox"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -555,7 +588,7 @@ pub(super) fn build_gtk_stack(props: Map, children: Vec, widget_regi let id = hash_props_and_type(&props, "Stack"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -616,7 +649,7 @@ pub(super) fn build_transform(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Transform"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: widget.upcast(), }); Ok(widget) } @@ -658,7 +691,7 @@ pub(super) fn build_circular_progress_bar(props: Map, widget_registry: &mut Widg let id = hash_props_and_type(&props, "CircularProgressBar"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: widget.upcast(), }); Ok(widget) } @@ -739,7 +772,7 @@ pub(super) fn build_graph(props: Map, widget_registry: &mut WidgetRegistry) -> R let id = hash_props_and_type(&props, "Graph"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: widget.upcast(), }); Ok(widget) } @@ -782,7 +815,7 @@ pub(super) fn build_gtk_progress(props: Map, widget_registry: &mut WidgetRegistr let id = hash_props_and_type(&props, "Progress"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -860,7 +893,7 @@ pub(super) fn build_gtk_image(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Image"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -934,7 +967,7 @@ pub(super) fn build_gtk_button(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Button"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1037,7 +1070,7 @@ pub(super) fn build_gtk_label(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Label"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1090,7 +1123,7 @@ pub(super) fn build_gtk_input(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Input"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1169,7 +1202,7 @@ pub(super) fn build_gtk_calendar(props: Map, widget_registry: &mut WidgetRegistr let id = hash_props_and_type(&props, "Calendar"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1212,7 +1245,7 @@ pub(super) fn build_gtk_combo_box_text(props: Map, widget_registry: &mut WidgetR let id = hash_props_and_type(&props, "ComboBoxText"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1263,7 +1296,7 @@ pub(super) fn build_gtk_expander( let id = hash_props_and_type(&props, "Expander"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1315,7 +1348,7 @@ pub(super) fn build_gtk_revealer( let id = hash_props_and_type(&props, "Revealer"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1355,7 +1388,7 @@ pub(super) fn build_gtk_checkbox(props: Map, widget_registry: &mut WidgetRegistr let id = hash_props_and_type(&props, "Checkbox"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1399,7 +1432,7 @@ pub(super) fn build_gtk_color_button(props: Map, widget_registry: &mut WidgetReg let id = hash_props_and_type(&props, "ColorButton"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1443,7 +1476,7 @@ pub(super) fn build_gtk_color_chooser(props: Map, widget_registry: &mut WidgetRe let id = hash_props_and_type(&props, "ColorChooser"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1488,7 +1521,7 @@ pub(super) fn build_gtk_scale(props: Map, widget_registry: &mut WidgetRegistry) let id = hash_props_and_type(&props, "Slider"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } @@ -1540,7 +1573,7 @@ pub(super) fn build_gtk_scrolledwindow( let id = hash_props_and_type(&props, "ScrolledWindow"); - widget_registry.widgets.insert(id, WidgetEntry { update_fn }); + widget_registry.widgets.insert(id, WidgetEntry { update_fn, widget: gtk_widget.upcast(), }); Ok(gtk_widget) } diff --git a/crates/iirhai/src/widgetnode.rs b/crates/iirhai/src/widgetnode.rs index 5913ac5..68df98c 100644 --- a/crates/iirhai/src/widgetnode.rs +++ b/crates/iirhai/src/widgetnode.rs @@ -39,121 +39,135 @@ pub enum WidgetNode { Enter(Vec), } -// Get `HashMap` -// not exactly a get function as it mutates id_to_props -// instead of returning any value. -// it sounds misleading but i cant think of a better name. -pub fn get_id_to_props_map( - root_node: &WidgetNode, - id_to_props: &mut HashMap +#[derive(Clone)] +pub struct WidgetInfo { + pub node: WidgetNode, + pub props: Map, + pub widget_type: String, + pub children: Vec, +} + +pub fn get_id_to_widget_info( + node: &WidgetNode, + id_to_props: &mut HashMap, ) -> Result<()> { - match root_node { + match node { WidgetNode::Box { props, children } => { - insert_props(props, "Box", id_to_props)?; + insert_wdgt_info(node, props, "Box", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::CenterBox { props, children } => { - insert_props(props, "CenterBox", id_to_props)?; + insert_wdgt_info(node, props, "CenterBox", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::EventBox { props, children } => { - insert_props(props, "EventBox", id_to_props)?; + insert_wdgt_info(node, props, "EventBox", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::CircularProgress { props } => { - insert_props(props, "CircularProgress", id_to_props)?; + insert_wdgt_info(node, props, "CircularProgress", vec![], id_to_props)?; } WidgetNode::Graph { props } => { - insert_props(props, "Graph", id_to_props)?; + insert_wdgt_info(node, props, "Graph", vec![], id_to_props)?; } WidgetNode::Transform { props } => { - insert_props(props, "Transform", id_to_props)?; + insert_wdgt_info(node, props, "Transform", vec![], id_to_props)?; } WidgetNode::Slider { props } => { - insert_props(props, "Slider", id_to_props)?; + insert_wdgt_info(node, props, "Slider", vec![], id_to_props)?; } WidgetNode::Progress { props } => { - insert_props(props, "Progress", id_to_props)?; + insert_wdgt_info(node, props, "Progress", vec![], id_to_props)?; } WidgetNode::Image { props } => { - insert_props(props, "Image", id_to_props)?; + insert_wdgt_info(node, props, "Image", vec![], id_to_props)?; } WidgetNode::Button { props } => { - insert_props(props, "Button", id_to_props)?; + insert_wdgt_info(node, props, "Button", vec![], id_to_props)?; } WidgetNode::Label { props } => { - insert_props(props, "Label", id_to_props)?; + insert_wdgt_info(node, props, "Label", vec![], id_to_props)?; } WidgetNode::Input { props } => { - insert_props(props, "Input", id_to_props)?; + insert_wdgt_info(node, props, "Input", vec![], id_to_props)?; } WidgetNode::Calendar { props } => { - insert_props(props, "Calendar", id_to_props)?; + insert_wdgt_info(node, props, "Calendar", vec![], id_to_props)?; } WidgetNode::ColorButton { props } => { - insert_props(props, "ColorButton", id_to_props)?; + insert_wdgt_info(node, props, "ColorButton", vec![], id_to_props)?; } WidgetNode::Expander { props, children } => { - insert_props(props, "Expander", id_to_props)?; + insert_wdgt_info(node, props, "Expander", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::ToolTip { children } => { for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::ColorChooser { props } => { - insert_props(props, "ColorChooser", id_to_props)?; + insert_wdgt_info(node, props, "ColorChooser", vec![], id_to_props)?; } WidgetNode::ComboBoxText { props } => { - insert_props(props, "ComboBoxText", id_to_props)?; + insert_wdgt_info(node, props, "ComboBoxText", vec![], id_to_props)?; } WidgetNode::Checkbox { props } => { - insert_props(props, "Checkbox", id_to_props)?; + insert_wdgt_info(node, props, "Checkbox", vec![], id_to_props)?; } WidgetNode::Revealer { props, children } => { - insert_props(props, "Revealer", id_to_props)?; + insert_wdgt_info(node, props, "Revealer", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::Scroll { props, children } => { - insert_props(props, "Scroll", id_to_props)?; - + insert_wdgt_info(node, props, "Scroll", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::OverLay { children } => { for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } WidgetNode::Stack { props, children } => { - insert_props(props, "Stack", id_to_props)?; + insert_wdgt_info(node, props, "Stack", children.clone(), id_to_props)?; for child in children { - get_id_to_props_map(child, id_to_props)?; + get_id_to_widget_info(child, id_to_props)?; } } - _ => { - // do nothing for now ig? - } + _ => { /* do nothinnng */ } } Ok(()) } -fn insert_props(props: &Map, widget_type: &str, id_to_props: &mut HashMap) -> Result<()> { + +fn insert_wdgt_info( + node: &WidgetNode, + props: &Map, + widget_type: &str, + children: Vec, + id_to_info: &mut HashMap +) -> Result<()> { let id = hash_props_and_type(props, widget_type); - id_to_props.insert(id, props.clone()); + let info = WidgetInfo { + node: node.clone(), + props: props.clone(), + widget_type: widget_type.to_string(), + children, + }; + id_to_info.insert(id, info); Ok(()) }