From 030de803fed3205fbadef057f943945d657cb74c Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Sat, 21 Aug 2021 13:40:45 -0600 Subject: [PATCH] WIP: Start on List::layout Perform layout on any elements that we haven't yet laid out. --- gpui/src/elements/list.rs | 101 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 4 deletions(-) diff --git a/gpui/src/elements/list.rs b/gpui/src/elements/list.rs index d96637ea86..82b3819149 100644 --- a/gpui/src/elements/list.rs +++ b/gpui/src/elements/list.rs @@ -1,6 +1,6 @@ use crate::{ geometry::{rect::RectF, vector::Vector2F}, - sum_tree::{self, SumTree}, + sum_tree::{self, Bias, SumTree}, Element, }; use parking_lot::Mutex; @@ -15,6 +15,7 @@ pub struct List { pub struct ListState(Arc>); struct StateInner { + last_layout_width: f32, elements: Vec, heights: SumTree, } @@ -27,10 +28,20 @@ enum ElementHeight { #[derive(Clone, Debug, Default)] struct ElementHeightSummary { + count: usize, pending_count: usize, height: f32, } +#[derive(Clone, Debug, Default)] +struct Count(usize); + +#[derive(Clone, Debug, Default)] +struct PendingCount(usize); + +#[derive(Clone, Debug, Default)] +struct Height(f32); + impl Element for List { type LayoutState = (); @@ -41,6 +52,37 @@ impl Element for List { constraint: crate::SizeConstraint, cx: &mut crate::LayoutContext, ) -> (Vector2F, Self::LayoutState) { + // TODO: Fully invalidate if width has changed since the last layout. + + let state = &mut *self.state.0.lock(); + let mut old_heights = state.heights.cursor::(); + let mut new_heights = old_heights.slice(&PendingCount(1), sum_tree::Bias::Left, &()); + + let mut item_constraint = constraint; + item_constraint.min.set_y(0.); + item_constraint.max.set_y(f32::INFINITY); + + while let Some(height) = old_heights.item() { + if height.is_pending() { + let size = + state.elements[old_heights.sum_start().count].layout(item_constraint, cx); + new_heights.push(ElementHeight::Ready(size.y()), &()); + old_heights.next(&()); + } else { + new_heights.push_tree( + old_heights.slice( + &PendingCount(old_heights.sum_start().pending_count + 1), + Bias::Left, + &(), + ), + &(), + ); + } + } + + drop(old_heights); + state.heights = new_heights; + todo!() } @@ -79,7 +121,17 @@ impl ListState { pub fn new(elements: Vec) -> Self { let mut heights = SumTree::new(); heights.extend(elements.iter().map(|_| ElementHeight::Pending), &()); - Self(Arc::new(Mutex::new(StateInner { elements, heights }))) + Self(Arc::new(Mutex::new(StateInner { + last_layout_width: 0., + elements, + heights, + }))) + } +} + +impl ElementHeight { + fn is_pending(&self) -> bool { + matches!(self, ElementHeight::Pending) } } @@ -87,15 +139,56 @@ impl sum_tree::Item for ElementHeight { type Summary = ElementHeightSummary; fn summary(&self) -> Self::Summary { - todo!() + match self { + ElementHeight::Pending => ElementHeightSummary { + count: 1, + pending_count: 1, + height: 0., + }, + ElementHeight::Ready(height) => ElementHeightSummary { + count: 1, + pending_count: 0, + height: *height, + }, + } } } impl sum_tree::Summary for ElementHeightSummary { type Context = (); - fn add_summary(&mut self, summary: &Self, cx: &Self::Context) { + fn add_summary(&mut self, summary: &Self, _: &()) { self.pending_count += summary.pending_count; self.height += summary.height; } } + +impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for ElementHeightSummary { + fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) { + sum_tree::Summary::add_summary(self, summary, &()); + } +} + +impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Count { + fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) { + self.0 += summary.count; + } +} + +impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for PendingCount { + fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) { + self.0 += summary.pending_count; + } +} + +impl<'a> sum_tree::SeekDimension<'a, ElementHeightSummary> for PendingCount { + fn cmp(&self, other: &Self, _: &()) -> std::cmp::Ordering { + self.0.cmp(&other.0) + } +} + +impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Height { + fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) { + self.0 += summary.height; + } +}