Compare commits

...

5 Commits

Author SHA1 Message Date
philippeitis
7a4897d2b3 Add backwards fill 2021-10-15 11:33:53 -07:00
philippeitis
0dc25e7c2a Remove target entirely 2021-10-15 11:12:59 -07:00
philippeitis
57389c5b55 Allow user to specify offset directly 2021-10-15 11:12:14 -07:00
philippeitis
a7202307ae Remove duplicate impl block 2021-10-15 10:52:18 -07:00
philippeitis
0c0c396c61 Create List with multiple selections 2021-10-15 10:48:12 -07:00

View File

@@ -1,3 +1,5 @@
use std::collections::BTreeSet;
use crate::{
buffer::Buffer,
layout::{Corner, Rect},
@@ -10,28 +12,38 @@ use unicode_width::UnicodeWidthStr;
#[derive(Debug, Clone)]
pub struct ListState {
offset: usize,
selected: Option<usize>,
selected: BTreeSet<usize>,
}
impl Default for ListState {
fn default() -> ListState {
ListState {
offset: 0,
selected: None,
selected: BTreeSet::new(),
}
}
}
impl ListState {
pub fn selected(&self) -> Option<usize> {
self.selected
pub fn offset(mut self, offset: usize) -> Self {
self.offset = offset;
self
}
pub fn selected(&self) -> &BTreeSet<usize> {
&self.selected
}
pub fn select(&mut self, index: Option<usize>) {
self.selected = index;
if index.is_none() {
self.offset = 0;
}
pub fn select(&mut self, index: usize) {
self.selected.insert(index);
}
pub fn deselect(&mut self, index: usize) {
self.selected.remove(&index);
}
pub fn deselect_all(&mut self) {
self.selected.clear();
}
}
@@ -131,7 +143,6 @@ impl<'a> List<'a> {
fn get_items_bounds(
&self,
selected: Option<usize>,
offset: usize,
max_height: usize,
) -> (usize, usize) {
@@ -139,6 +150,9 @@ impl<'a> List<'a> {
let mut start = offset;
let mut end = offset;
let mut height = 0;
// Fills forwards until max_height is reached
// or no more items are left.
for item in self.items.iter().skip(offset) {
if height + item.height() > max_height {
break;
@@ -146,24 +160,17 @@ impl<'a> List<'a> {
height += item.height();
end += 1;
}
let selected = selected.unwrap_or(0).min(self.items.len() - 1);
while selected >= end {
height = height.saturating_add(self.items[end].height());
end += 1;
while height > max_height {
height = height.saturating_sub(self.items[start].height());
start += 1;
// Fills backwards, if offset is too large
// and we have insufficient items.
for item in self.items[..start].iter().rev() {
if height + item.height() > max_height {
break;
}
}
while selected < start {
height += item.height();
start -= 1;
height = height.saturating_add(self.items[start].height());
while height > max_height {
end -= 1;
height = height.saturating_sub(self.items[end].height());
}
}
(start, end)
}
}
@@ -191,19 +198,18 @@ impl<'a> StatefulWidget for List<'a> {
}
let list_height = list_area.height as usize;
let (start, end) = self.get_items_bounds(state.selected, state.offset, list_height);
state.offset = start;
let (start, end) = self.get_items_bounds(state.offset, list_height);
let highlight_symbol = self.highlight_symbol.unwrap_or("");
let blank_symbol = " ".repeat(highlight_symbol.width());
let mut current_height = 0;
let has_selection = state.selected.is_some();
let has_selection = !state.selected.is_empty();
for (i, item) in self
.items
.iter_mut()
.enumerate()
.skip(state.offset)
.skip(start)
.take(end - start)
{
let (x, y) = match self.start_corner {
@@ -226,7 +232,7 @@ impl<'a> StatefulWidget for List<'a> {
let item_style = self.style.patch(item.style);
buf.set_style(area, item_style);
let is_selected = state.selected.map(|s| s == i).unwrap_or(false);
let is_selected = state.selected.contains(&i);
let elem_x = if has_selection {
let symbol = if is_selected {
highlight_symbol