diff --git a/gpui/src/elements/list.rs b/gpui/src/elements/list.rs index 3864bf3c80daf4f9e2a6c119351838c2aabb2bb3..9fecfd6e61ed06d9859c6b62b3645866b4ce39b6 100644 --- a/gpui/src/elements/list.rs +++ b/gpui/src/elements/list.rs @@ -12,6 +12,7 @@ use std::{cell::RefCell, collections::VecDeque, ops::Range, rc::Rc}; pub struct List { state: ListState, + invalidated_elements: Vec, } #[derive(Clone)] @@ -79,7 +80,10 @@ struct Height(f32); impl List { pub fn new(state: ListState) -> Self { - Self { state } + Self { + state, + invalidated_elements: Default::default(), + } } } @@ -258,10 +262,35 @@ impl Element for List { let mut handled = false; let mut state = self.state.0.borrow_mut(); - for (mut element, _) in state.visible_elements(bounds, scroll_top) { - handled = element.dispatch_event(event, cx) || handled; + let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item); + let mut cursor = state.items.cursor::(); + let mut new_items = cursor.slice(&Count(scroll_top.item_ix), Bias::Right, &()); + while let Some(item) = cursor.item() { + if item_origin.y() > bounds.max_y() { + break; + } + + if let ListItem::Rendered(element) = item { + let prev_notify_count = cx.notify_count(); + let mut element = element.clone(); + handled = element.dispatch_event(event, cx) || handled; + item_origin.set_y(item_origin.y() + element.size().y()); + if cx.notify_count() > prev_notify_count { + new_items.push(ListItem::Unrendered, &()); + self.invalidated_elements.push(element); + } else { + new_items.push(item.clone(), &()); + } + cursor.next(&()); + } else { + unreachable!(); + } } + new_items.push_tree(cursor.suffix(&()), &()); + drop(cursor); + state.items = new_items; + match event { Event::ScrollWheel { position, diff --git a/gpui/src/presenter.rs b/gpui/src/presenter.rs index d6765bec29876889df2f5056d5624a7353de31a0..354f0a0f821af81040581a7afedb2eb4652acbc2 100644 --- a/gpui/src/presenter.rs +++ b/gpui/src/presenter.rs @@ -195,6 +195,7 @@ impl Presenter { text_layout_cache: &self.text_layout_cache, view_stack: Default::default(), invalidated_views: Default::default(), + notify_count: 0, app: cx, } } @@ -300,6 +301,7 @@ pub struct EventContext<'a> { pub font_cache: &'a FontCache, pub text_layout_cache: &'a TextLayoutCache, pub app: &'a mut MutableAppContext, + pub notify_count: usize, view_stack: Vec, invalidated_views: HashSet, } @@ -325,10 +327,15 @@ impl<'a> EventContext<'a> { } pub fn notify(&mut self) { + self.notify_count += 1; if let Some(view_id) = self.view_stack.last() { self.invalidated_views.insert(*view_id); } } + + pub fn notify_count(&self) -> usize { + self.notify_count + } } impl<'a> Deref for EventContext<'a> {