mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-12 13:24:19 +00:00
Implement and test splice
for ListState
Co-Authored-By: Nathan Sobo <nathan@zed.dev>
This commit is contained in:
parent
2c3ba00d3e
commit
03b7c3c8c6
1 changed files with 93 additions and 5 deletions
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue