list.rs

  1use crate::{
  2    geometry::{rect::RectF, vector::Vector2F},
  3    sum_tree::{self, Bias, SumTree},
  4    Element,
  5};
  6use parking_lot::Mutex;
  7use std::sync::Arc;
  8
  9use crate::ElementBox;
 10
 11pub struct List {
 12    state: ListState,
 13}
 14
 15pub struct ListState(Arc<Mutex<StateInner>>);
 16
 17struct StateInner {
 18    last_layout_width: f32,
 19    elements: Vec<ElementBox>,
 20    heights: SumTree<ElementHeight>,
 21}
 22
 23#[derive(Clone, Debug)]
 24enum ElementHeight {
 25    Pending,
 26    Ready(f32),
 27}
 28
 29#[derive(Clone, Debug, Default)]
 30struct ElementHeightSummary {
 31    count: usize,
 32    pending_count: usize,
 33    height: f32,
 34}
 35
 36#[derive(Clone, Debug, Default)]
 37struct Count(usize);
 38
 39#[derive(Clone, Debug, Default)]
 40struct PendingCount(usize);
 41
 42#[derive(Clone, Debug, Default)]
 43struct Height(f32);
 44
 45impl Element for List {
 46    type LayoutState = ();
 47
 48    type PaintState = ();
 49
 50    fn layout(
 51        &mut self,
 52        constraint: crate::SizeConstraint,
 53        cx: &mut crate::LayoutContext,
 54    ) -> (Vector2F, Self::LayoutState) {
 55        // TODO: Fully invalidate if width has changed since the last layout.
 56
 57        let state = &mut *self.state.0.lock();
 58        let mut old_heights = state.heights.cursor::<PendingCount, ElementHeightSummary>();
 59        let mut new_heights = old_heights.slice(&PendingCount(1), sum_tree::Bias::Left, &());
 60
 61        let mut item_constraint = constraint;
 62        item_constraint.min.set_y(0.);
 63        item_constraint.max.set_y(f32::INFINITY);
 64
 65        while let Some(height) = old_heights.item() {
 66            if height.is_pending() {
 67                let size =
 68                    state.elements[old_heights.sum_start().count].layout(item_constraint, cx);
 69                new_heights.push(ElementHeight::Ready(size.y()), &());
 70                old_heights.next(&());
 71            } else {
 72                new_heights.push_tree(
 73                    old_heights.slice(
 74                        &PendingCount(old_heights.sum_start().pending_count + 1),
 75                        Bias::Left,
 76                        &(),
 77                    ),
 78                    &(),
 79                );
 80            }
 81        }
 82
 83        drop(old_heights);
 84        state.heights = new_heights;
 85
 86        todo!()
 87    }
 88
 89    fn paint(
 90        &mut self,
 91        bounds: RectF,
 92        layout: &mut Self::LayoutState,
 93        cx: &mut crate::PaintContext,
 94    ) -> Self::PaintState {
 95        todo!()
 96    }
 97
 98    fn dispatch_event(
 99        &mut self,
100        event: &crate::Event,
101        bounds: RectF,
102        layout: &mut Self::LayoutState,
103        paint: &mut Self::PaintState,
104        cx: &mut crate::EventContext,
105    ) -> bool {
106        todo!()
107    }
108
109    fn debug(
110        &self,
111        bounds: RectF,
112        layout: &Self::LayoutState,
113        paint: &Self::PaintState,
114        cx: &crate::DebugContext,
115    ) -> serde_json::Value {
116        todo!()
117    }
118}
119
120impl ListState {
121    pub fn new(elements: Vec<ElementBox>) -> Self {
122        let mut heights = SumTree::new();
123        heights.extend(elements.iter().map(|_| ElementHeight::Pending), &());
124        Self(Arc::new(Mutex::new(StateInner {
125            last_layout_width: 0.,
126            elements,
127            heights,
128        })))
129    }
130}
131
132impl ElementHeight {
133    fn is_pending(&self) -> bool {
134        matches!(self, ElementHeight::Pending)
135    }
136}
137
138impl sum_tree::Item for ElementHeight {
139    type Summary = ElementHeightSummary;
140
141    fn summary(&self) -> Self::Summary {
142        match self {
143            ElementHeight::Pending => ElementHeightSummary {
144                count: 1,
145                pending_count: 1,
146                height: 0.,
147            },
148            ElementHeight::Ready(height) => ElementHeightSummary {
149                count: 1,
150                pending_count: 0,
151                height: *height,
152            },
153        }
154    }
155}
156
157impl sum_tree::Summary for ElementHeightSummary {
158    type Context = ();
159
160    fn add_summary(&mut self, summary: &Self, _: &()) {
161        self.pending_count += summary.pending_count;
162        self.height += summary.height;
163    }
164}
165
166impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for ElementHeightSummary {
167    fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) {
168        sum_tree::Summary::add_summary(self, summary, &());
169    }
170}
171
172impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Count {
173    fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) {
174        self.0 += summary.count;
175    }
176}
177
178impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for PendingCount {
179    fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) {
180        self.0 += summary.pending_count;
181    }
182}
183
184impl<'a> sum_tree::SeekDimension<'a, ElementHeightSummary> for PendingCount {
185    fn cmp(&self, other: &Self, _: &()) -> std::cmp::Ordering {
186        self.0.cmp(&other.0)
187    }
188}
189
190impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Height {
191    fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) {
192        self.0 += summary.height;
193    }
194}