mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 07:04:17 +00:00
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:
parent
40bad7a718
commit
bcd1e30376
3 changed files with 45 additions and 22 deletions
|
@ -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]);
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue