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}