refactor: update List select behavior

* allow a selectable list to have no selected item
* show highlight_symbol only when something is selected
This commit is contained in:
Florian Dehau 2018-09-04 21:45:03 +02:00
parent 40bad7a718
commit bcd1e30376
3 changed files with 45 additions and 22 deletions

View file

@ -355,7 +355,7 @@ fn draw_charts(f: &mut Frame<MouseBackend>, app: &App, area: Rect) {
SelectableList::default()
.block(Block::default().borders(Borders::ALL).title("List"))
.items(&app.items)
.select(app.selected)
.select(Some(app.selected))
.highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
.highlight_symbol(">")
.render(f, chunks[0]);

View file

@ -18,7 +18,7 @@ use tui::Terminal;
struct App<'a> {
size: Rect,
items: Vec<&'a str>,
selected: usize,
selected: Option<usize>,
events: Vec<(&'a str, &'a str)>,
info_style: Style,
warning_style: Style,
@ -35,7 +35,7 @@ impl<'a> App<'a> {
"Item10", "Item11", "Item12", "Item13", "Item14", "Item15", "Item16", "Item17",
"Item18", "Item19", "Item20", "Item21", "Item22", "Item23", "Item24",
],
selected: 0,
selected: None,
events: vec![
("Event1", "INFO"),
("Event2", "INFO"),
@ -132,17 +132,31 @@ fn main() {
event::Key::Char('q') => {
break;
}
event::Key::Left => {
app.selected = None;
}
event::Key::Down => {
app.selected += 1;
if app.selected > app.items.len() - 1 {
app.selected = 0;
app.selected = if let Some(selected) = app.selected {
if selected >= app.items.len() - 1 {
Some(0)
} else {
Some(selected + 1)
}
} else {
Some(0)
}
}
event::Key::Up => {
app.selected = if let Some(selected) = app.selected {
if selected > 0 {
Some(selected - 1)
} else {
Some(app.items.len() - 1)
}
} else {
Some(0)
}
}
event::Key::Up => if app.selected > 0 {
app.selected -= 1;
} else {
app.selected = app.items.len() - 1;
},
_ => {}
},
Event::Tick => {
@ -153,6 +167,7 @@ fn main() {
}
terminal.show_cursor().unwrap();
terminal.clear().unwrap();
}
fn draw(t: &mut Terminal<MouseBackend>, app: &App) -> Result<(), io::Error> {
@ -181,7 +196,7 @@ fn draw(t: &mut Terminal<MouseBackend>, app: &App) -> Result<(), io::Error> {
"WARNING" => &app.warning_style,
_ => &app.info_style,
},
)
)
});
List::new(events)
.block(Block::default().borders(Borders::ALL).title("List"))

View file

@ -137,7 +137,7 @@ where
/// SelectableList::default()
/// .block(Block::default().title("SelectableList").borders(Borders::ALL))
/// .items(&["Item 1", "Item 2", "Item 3"])
/// .select(1)
/// .select(Some(1))
/// .style(Style::default().fg(Color::White))
/// .highlight_style(Style::default().modifier(Modifier::Italic))
/// .highlight_symbol(">>");
@ -199,8 +199,8 @@ impl<'b> SelectableList<'b> {
self
}
pub fn select(mut self, index: usize) -> SelectableList<'b> {
self.selected = Some(index);
pub fn select(mut self, index: Option<usize>) -> SelectableList<'b> {
self.selected = index;
self
}
}
@ -216,16 +216,20 @@ impl<'b> Widget for SelectableList<'b> {
// Use highlight_style only if something is selected
let (selected, highlight_style) = match self.selected {
Some(i) => (i, &self.highlight_style),
None => (0, &self.style),
Some(i) => (Some(i), &self.highlight_style),
None => (None, &self.style),
};
let highlight_symbol = self.highlight_symbol.unwrap_or("");
let blank_symbol = iter::repeat(" ")
.take(highlight_symbol.width())
.collect::<String>();
// Make sure the list show the selected item
let offset = if selected >= list_height {
selected - list_height + 1
let offset = if let Some(selected) = selected {
if selected >= list_height {
selected - list_height + 1
} else {
0
}
} else {
0
};
@ -236,10 +240,14 @@ impl<'b> Widget for SelectableList<'b> {
.iter()
.enumerate()
.map(|(i, item)| {
if i == selected {
Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
if let Some(s) = selected {
if i == s {
Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
} else {
Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
}
} else {
Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
Item::StyledData(format!("{}", item), &self.style)
}
})
.skip(offset as usize);