Skip to content
Snippets Groups Projects
Commit 42fc7fc9 authored by Gino Valente's avatar Gino Valente
Browse files

Fixed missed layouts for on_layout

parent 388bd4bd
No related branches found
No related tags found
No related merge requests found
......@@ -65,6 +65,11 @@ pub struct LayoutEvent {
/// Layout of target component
pub layout: Layout,
/// Flags denoting the layout change.
///
/// Note: The flags can potentially all be unset in cases where the [target's] layout did
/// not change, but one of its immediate children did.
///
/// [target's]: LayoutEvent::target
pub flags: GeometryChanged,
/// The node ID of the element receiving the layout event.
pub target: Index,
......
use std::collections::hash_map::Iter;
use std::collections::HashMap;
use morphorm::{Cache, GeometryChanged};
......@@ -60,6 +61,10 @@ pub struct LayoutCache {
stack_first_child: HashMap<Index, bool>,
stack_last_child: HashMap<Index, bool>,
/// A map of node IDs to their `GeometryChanged` flags
///
/// This should only contain entries for nodes that have _at least one_ flag set.
/// If a node does not have any flags set, then they should be removed from the map.
geometry_changed: HashMap<Index, GeometryChanged>,
visible: HashMap<Index, bool>,
......@@ -95,10 +100,13 @@ impl LayoutCache {
self.size.insert(node_index, Default::default());
self.geometry_changed.insert(node_index, Default::default());
self.visible.insert(node_index, true);
}
/// Returns an iterator over nodes whose layout have been changed since the last update
pub fn iter_changed(&self) -> Iter<'_, Index, GeometryChanged> {
self.geometry_changed.iter()
}
}
impl Cache for LayoutCache {
......@@ -121,8 +129,19 @@ impl Cache for LayoutCache {
}
fn set_geo_changed(&mut self, node: Self::Item, flag: GeometryChanged, value: bool) {
if let Some(geometry_changed) = self.geometry_changed.get_mut(&node) {
if value {
// Setting a flag -> Add entry if it does not already exist
let geometry_changed = self.geometry_changed.entry(node).or_default();
geometry_changed.set(flag, value);
} else {
// Unsetting a flag -> Don't add entry if it does not exist
if let Some(geometry_changed) = self.geometry_changed.get_mut(&node) {
geometry_changed.set(flag, value);
if geometry_changed.is_empty() {
self.geometry_changed.remove(&node);
}
}
}
}
......
use indexmap::IndexSet;
use morphorm::Cache;
use indexmap::IndexMap;
use morphorm::GeometryChanged;
use crate::{Index, KayakContext, KayakContextRef, LayoutEvent};
......@@ -7,53 +7,42 @@ pub(crate) struct LayoutEventDispatcher;
impl LayoutEventDispatcher {
pub fn dispatch(context: &mut KayakContext) {
let dirty_nodes: Vec<Index> = context
let changed = context
.widget_manager
.dirty_render_nodes
.drain(..)
.collect();
.layout_cache
.iter_changed()
.map(|(index, flags)| (*index, *flags))
.collect::<IndexMap<Index, GeometryChanged>>();
// Use IndexSet to prevent duplicates and maintain speed
let mut parents: IndexSet<Index> = IndexSet::default();
for node_index in dirty_nodes {
// If layout is not changed -> skip
if context
.widget_manager
.layout_cache
.geometry_changed(node_index)
.is_empty()
{
continue;
}
let mut parents: IndexMap<Index, GeometryChanged> = IndexMap::default();
for (node_index, flags) in &changed {
// Add parent to set
if let Some(parent_index) = context.widget_manager.tree.get_parent(node_index) {
parents.insert(parent_index);
if let Some(parent_index) = context.widget_manager.tree.get_parent(*node_index) {
if !changed.contains_key(&parent_index) {
parents.insert(parent_index, GeometryChanged::default());
}
}
// Process and dispatch
Self::process(node_index, context);
Self::process(*node_index, *flags, context);
}
// Finally, process all parents
for parent_index in parents {
for (parent_index, flags) in parents {
// Process and dispatch
Self::process(parent_index, context);
Self::process(parent_index, flags, context);
}
}
fn process(index: Index, context: &mut KayakContext) {
fn process(index: Index, flags: GeometryChanged, context: &mut KayakContext) {
// We should be able to just get layout from WidgetManager here
// since the layouts will be calculated by this point
let widget = context.widget_manager.take(index);
if let Some(on_layout) = widget.get_props().get_on_layout() {
if let Some(rect) = context.widget_manager.layout_cache.rect.get(&index) {
let layout_event = LayoutEvent::new(
*rect,
context.widget_manager.layout_cache.geometry_changed(index),
index,
);
let layout_event = LayoutEvent::new(*rect, flags, index);
let mut context_ref = KayakContextRef::new(context, Some(index));
on_layout.try_call(&mut context_ref, &layout_event);
......
......@@ -172,8 +172,8 @@ impl WidgetManager {
pub fn render(&mut self) {
let initial_styles = Style::initial();
let default_styles = Style::new_default();
for dirty_node_index in &self.dirty_render_nodes {
let dirty_widget = self.current_widgets[*dirty_node_index].as_ref().unwrap();
for dirty_node_index in self.dirty_render_nodes.drain(..) {
let dirty_widget = self.current_widgets[dirty_node_index].as_ref().unwrap();
// Get the parent styles. Will be one of the following:
// 1. Already-resolved node styles (best)
// 2. Unresolved widget prop styles
......@@ -232,13 +232,13 @@ impl WidgetManager {
.unwrap_or(vec![]);
let mut node = NodeBuilder::empty()
.with_id(*dirty_node_index)
.with_id(dirty_node_index)
.with_styles(styles, raw_styles)
.with_children(children)
.build();
node.z = current_z;
self.nodes[*dirty_node_index] = Some(node);
self.nodes[dirty_node_index] = Some(node);
}
self.node_tree = self.build_nodes_tree();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment