diff --git a/masonry/src/contexts.rs b/masonry/src/contexts.rs index 1ecf03aa5..d4ea73933 100644 --- a/masonry/src/contexts.rs +++ b/masonry/src/contexts.rs @@ -477,6 +477,29 @@ impl<'w> QueryCtx<'w> { widget: child.item, } } + + // TODO temporary until arena is more efficient (I think this might not always return the correct order of the children)? + /// To avoid quadratic behavior with manually iterating over children with [`Widget::children_ids`] by accessing these with [`Self::get`], this method allows to linearly iterate over all children. + pub fn children_iter( + self, + ) -> impl DoubleEndedIterator> + ExactSizeIterator { + self.widget_children + .iter() + .zip(self.widget_state_children.iter()) + .map(|(child, child_state)| { + let ctx = QueryCtx { + global_state: self.global_state, + widget_state_children: child_state.children, + widget_children: child.children, + widget_state: child_state.item, + }; + + WidgetRef { + ctx, + widget: child.item.as_dyn(), + } + }) + } } // --- MARK: UPDATE FLAGS --- diff --git a/masonry/src/tree_arena.rs b/masonry/src/tree_arena.rs index 00026c885..6eb73e0bd 100644 --- a/masonry/src/tree_arena.rs +++ b/masonry/src/tree_arena.rs @@ -268,6 +268,12 @@ impl<'a, Item> ArenaRefChildren<'a, Item> { .map(|child| child.arena_ref(self.id, self.parents_map.parents_map)) } + pub fn iter(self) -> impl DoubleEndedIterator> + ExactSizeIterator { + self.children + .iter() + .map(move |child| child.arena_ref(self.id, self.parents_map.parents_map)) + } + /// Get the child of the item this handle is associated with, which has the given id. /// /// This is the same as [`get_child`](Self::get_child), except it consumes the diff --git a/masonry/src/widget/widget.rs b/masonry/src/widget/widget.rs index 34735490f..05445ba87 100644 --- a/masonry/src/widget/widget.rs +++ b/masonry/src/widget/widget.rs @@ -342,8 +342,9 @@ pub(crate) fn find_widget_at_pos<'c>( // Assumes `Self::children_ids` is in increasing "z-order", picking the last child in case // of overlapping children. - for child_id in widget.children_ids().iter().rev() { - let child_ref = widget.ctx.get(*child_id); + // for child_id in widget.children_ids().iter().rev() { + // let child_ref = widget.ctx.get(*child_id); + for child_ref in widget.ctx.children_iter().rev() { if let Some(child) = child_ref.widget.find_widget_at_pos(child_ref.ctx, pos) { return Some(child); }