@@ -4,7 +4,7 @@ use crate::{
Element,
};
use parking_lot::Mutex;
-use std::sync::Arc;
+use std::{ops::Range, sync::Arc};
use crate::ElementBox;
@@ -12,6 +12,7 @@ pub struct List {
state: ListState,
}
+#[derive(Clone)]
pub struct ListState(Arc<Mutex<StateInner>>);
struct StateInner {
@@ -26,7 +27,7 @@ enum ElementHeight {
Ready(f32),
}
-#[derive(Clone, Debug, Default)]
+#[derive(Clone, Debug, Default, PartialEq)]
struct ElementHeightSummary {
count: usize,
pending_count: usize,
@@ -42,6 +43,12 @@ struct PendingCount(usize);
#[derive(Clone, Debug, Default)]
struct Height(f32);
+impl List {
+ pub fn new(state: ListState) -> Self {
+ Self { state }
+ }
+}
+
impl Element for List {
type LayoutState = ();
@@ -82,8 +89,7 @@ impl Element for List {
drop(old_heights);
state.heights = new_heights;
-
- todo!()
+ (constraint.max, ())
}
fn paint(
@@ -127,6 +133,33 @@ impl ListState {
heights,
})))
}
+
+ pub fn splice(
+ &self,
+ old_range: Range<usize>,
+ new_elements: impl IntoIterator<Item = ElementBox>,
+ ) {
+ let state = &mut *self.0.lock();
+
+ let mut old_heights = state.heights.cursor::<Count, ()>();
+ let mut new_heights = old_heights.slice(&Count(old_range.start), Bias::Right, &());
+ old_heights.seek_forward(&Count(old_range.end), Bias::Right, &());
+
+ let mut len = 0;
+ let old_elements = state.elements.splice(
+ old_range,
+ new_elements.into_iter().map(|e| {
+ len += 1;
+ e
+ }),
+ );
+ drop(old_elements);
+
+ new_heights.extend((0..len).map(|_| ElementHeight::Pending), &());
+ new_heights.push_tree(old_heights.suffix(&()), &());
+ drop(old_heights);
+ state.heights = new_heights;
+ }
}
impl ElementHeight {
@@ -158,6 +191,7 @@ impl sum_tree::Summary for ElementHeightSummary {
type Context = ();
fn add_summary(&mut self, summary: &Self, _: &()) {
+ self.count += summary.count;
self.pending_count += summary.pending_count;
self.height += summary.height;
}
@@ -175,6 +209,12 @@ impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Count {
}
}
+impl<'a> sum_tree::SeekDimension<'a, ElementHeightSummary> for Count {
+ fn cmp(&self, other: &Self, _: &()) -> std::cmp::Ordering {
+ self.0.cmp(&other.0)
+ }
+}
+
impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for PendingCount {
fn add_summary(&mut self, summary: &'a ElementHeightSummary, _: &()) {
self.0 += summary.pending_count;
@@ -196,10 +236,58 @@ impl<'a> sum_tree::Dimension<'a, ElementHeightSummary> for Height {
#[cfg(test)]
mod tests {
use super::*;
+ use crate::{elements::*, geometry::vector::vec2f};
#[crate::test(self)]
fn test_layout(cx: &mut crate::MutableAppContext) {
let mut presenter = cx.build_presenter(0, 20.0);
- let layout_cx = presenter.layout_cx(cx);
+ let mut layout_cx = presenter.layout_cx(cx);
+ let state = ListState::new(vec![item(20.), item(30.), item(10.)]);
+ let mut list = List::new(state.clone()).boxed();
+
+ let size = list.layout(
+ SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)),
+ &mut layout_cx,
+ );
+ assert_eq!(size, vec2f(100., 40.));
+ assert_eq!(
+ state.0.lock().heights.summary(),
+ ElementHeightSummary {
+ count: 3,
+ pending_count: 0,
+ height: 60.
+ }
+ );
+
+ state.splice(1..2, vec![item(40.), item(50.)]);
+ state.splice(3..3, vec![item(60.)]);
+ assert_eq!(
+ state.0.lock().heights.summary(),
+ ElementHeightSummary {
+ count: 5,
+ pending_count: 3,
+ height: 30.
+ }
+ );
+ let size = list.layout(
+ SizeConstraint::new(vec2f(0., 0.), vec2f(100., 40.)),
+ &mut layout_cx,
+ );
+ assert_eq!(size, vec2f(100., 40.));
+ assert_eq!(
+ state.0.lock().heights.summary(),
+ ElementHeightSummary {
+ count: 5,
+ pending_count: 0,
+ height: 180.
+ }
+ );
+ }
+
+ fn item(height: f32) -> ElementBox {
+ ConstrainedBox::new(Empty::new().boxed())
+ .with_height(height)
+ .with_width(100.)
+ .boxed()
}
}