WIP: Start on List::layout

Perform layout on any elements that we haven't yet laid out.
This commit is contained in:
Nathan Sobo 2021-08-21 13:40:45 -06:00
parent d68e0b0b97
commit 030de803fe

View file

@ -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;
}
}