diff --git a/cursive-core/src/views/list_view.rs b/cursive-core/src/views/list_view.rs index 7fc5e658..91a9c034 100644 --- a/cursive-core/src/views/list_view.rs +++ b/cursive-core/src/views/list_view.rs @@ -39,11 +39,16 @@ type ListCallback = dyn Fn(&mut Cursive, &String) + Send + Sync; /// Displays a list of elements. pub struct ListView { children: Vec, + // Height for each child. // This should have the same size as the `children` list. children_heights: Vec, + // Which child is focused? Should index into the `children` list. + // + // This is `0` when `children` is empty. focus: usize, + // This callback is called when the selection is changed. on_select: Option>, } @@ -80,6 +85,10 @@ impl ListView { } /// Returns a reference to the child at the given position. + /// + /// # Panics + /// + /// If `id >= self.len()`. pub fn get_row(&self, id: usize) -> &ListChild { &self.children[id] } @@ -93,6 +102,20 @@ impl ListView { &mut self.children[id] } + /// Gives mutable access to the child at the given position. + /// + /// Returns `None` if `id >= self.len()`. + pub fn try_row_mut(&mut self, id: usize) -> Option<&mut ListChild> { + self.children.get_mut(id) + } + + /// Gives access to the child at the given position. + /// + /// Returns `None` if `id >= self.len()`. + pub fn try_row(&self, id: usize) -> Option<&ListChild> { + self.children.get(id) + } + /// Sets the children for this view. pub fn set_children(&mut self, children: Vec) { self.children_heights.resize(children.len(), 0); @@ -109,10 +132,30 @@ impl ListView { self.children_heights.push(0); } + /// Attempts to set the focus to the given position. + /// + /// Returns `None` if `if >= self.len()` or if the child at this location is not focusable. + pub fn set_focus(&mut self, id: usize) -> Option { + if id >= self.len() { + return None; + } + + let ListChild::Row(_, ref mut view) = self.children[id] else { + return None; + }; + + let Ok(res) = view.take_focus(direction::Direction::none()) else { + return None; + }; + + Some(self.set_focus_unchecked(id).and(res)) + } + /// Removes all children from this view. pub fn clear(&mut self) { self.children.clear(); self.children_heights.clear(); + self.focus = 0; } /// Adds a view to the end of the list. @@ -143,10 +186,23 @@ impl ListView { /// /// If `index >= self.len()`. pub fn remove_child(&mut self, index: usize) -> ListChild { + // TODO: fix the focus if it's > index. + // Drop the EventResult that would come from that? self.children_heights.remove(index); self.children.remove(index) } + /// Removes a child from the view. + /// + /// Returns `None` if `index >= self.len()`. + pub fn try_remove(&mut self, index: usize) -> Option { + if index >= self.len() { + None + } else { + Some(self.remove_child(index)) + } + } + /// Sets a callback to be used when an item is selected. #[crate::callback_helpers] pub fn set_on_select(&mut self, cb: F) @@ -169,7 +225,7 @@ impl ListView { /// Returns the index of the currently focused item. /// - /// Panics if the list is empty. + /// Returns `0` if the list is empty. pub fn focus(&self) -> usize { self.focus }