@@ -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<Mutex<StateInner>>);
struct StateInner {
+ last_layout_width: f32,
elements: Vec<ElementBox>,
heights: SumTree<ElementHeight>,
}
@@ -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::<PendingCount, ElementHeightSummary>();
+ 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<ElementBox>) -> 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;
+ }
+}