use gpui::{
AnyElement, IntoElement, ListAlignment, ListSizingBehavior, Pixels, RenderOnce, Styled, list,
};
#[allow(clippy::type_complexity)]
type RenderRowFn = Box<dyn FnMut(usize, &mut gpui::Window, &mut gpui::App) -> AnyElement + 'static>;
#[derive(Clone, Debug)]
pub struct VirtualListController {
state: gpui::ListState,
}
impl VirtualListController {
pub fn new(state: gpui::ListState) -> Self {
Self { state }
}
pub fn state(&self) -> gpui::ListState {
self.state.clone()
}
pub fn reset(&self, element_count: usize) {
self.state.reset(element_count);
}
pub fn splice(&self, old_range: std::ops::Range<usize>, count: usize) {
self.state.splice(old_range, count);
}
pub fn scroll_to_reveal_item(&self, ix: usize) {
self.state.scroll_to_reveal_item(ix);
}
}
#[derive(IntoElement)]
pub struct VirtualList {
state: gpui::ListState,
sizing_behavior: ListSizingBehavior,
render_row: RenderRowFn,
style: gpui::StyleRefinement,
}
impl VirtualList {
pub fn new(
state: gpui::ListState,
render_row: impl FnMut(usize, &mut gpui::Window, &mut gpui::App) -> AnyElement + 'static,
) -> Self {
Self {
state,
sizing_behavior: ListSizingBehavior::default(),
render_row: Box::new(render_row),
style: gpui::StyleRefinement::default(),
}
}
pub fn with_sizing_behavior(mut self, behavior: ListSizingBehavior) -> Self {
self.sizing_behavior = behavior;
self
}
}
impl Styled for VirtualList {
fn style(&mut self) -> &mut gpui::StyleRefinement {
&mut self.style
}
}
impl RenderOnce for VirtualList {
fn render(self, _window: &mut gpui::Window, _cx: &mut gpui::App) -> impl IntoElement {
let mut inner =
list(self.state.clone(), self.render_row).with_sizing_behavior(self.sizing_behavior);
*inner.style() = self.style;
inner
}
}
#[derive(Clone, Debug)]
pub struct VirtualListHandle {
state: gpui::ListState,
controller: VirtualListController,
}
impl VirtualListHandle {
pub fn new(item_count: usize, alignment: ListAlignment, overdraw: Pixels) -> Self {
let state = virtual_list_state(item_count, alignment, overdraw);
let controller = VirtualListController::new(state.clone());
Self { state, controller }
}
pub fn state(&self) -> gpui::ListState {
self.state.clone()
}
pub fn controller(&self) -> VirtualListController {
self.controller.clone()
}
}
#[track_caller]
pub fn virtual_list(
state: gpui::ListState,
render_row: impl FnMut(usize, &mut gpui::Window, &mut gpui::App) -> AnyElement + 'static,
) -> VirtualList {
VirtualList::new(state, render_row)
}
pub fn virtual_list_state(
item_count: usize,
alignment: ListAlignment,
overdraw: Pixels,
) -> gpui::ListState {
gpui::ListState::new(item_count, alignment, overdraw)
}