mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-30 14:32:01 +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
@ -355,7 +355,7 @@ fn draw_charts(f: &mut Frame<MouseBackend>, app: &App, area: Rect) {
|
|||||||
SelectableList::default()
|
SelectableList::default()
|
||||||
.block(Block::default().borders(Borders::ALL).title("List"))
|
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||||
.items(&app.items)
|
.items(&app.items)
|
||||||
.select(app.selected)
|
.select(Some(app.selected))
|
||||||
.highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
|
.highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
|
||||||
.highlight_symbol(">")
|
.highlight_symbol(">")
|
||||||
.render(f, chunks[0]);
|
.render(f, chunks[0]);
|
||||||
|
@ -18,7 +18,7 @@ use tui::Terminal;
|
|||||||
struct App<'a> {
|
struct App<'a> {
|
||||||
size: Rect,
|
size: Rect,
|
||||||
items: Vec<&'a str>,
|
items: Vec<&'a str>,
|
||||||
selected: usize,
|
selected: Option<usize>,
|
||||||
events: Vec<(&'a str, &'a str)>,
|
events: Vec<(&'a str, &'a str)>,
|
||||||
info_style: Style,
|
info_style: Style,
|
||||||
warning_style: Style,
|
warning_style: Style,
|
||||||
@ -35,7 +35,7 @@ impl<'a> App<'a> {
|
|||||||
"Item10", "Item11", "Item12", "Item13", "Item14", "Item15", "Item16", "Item17",
|
"Item10", "Item11", "Item12", "Item13", "Item14", "Item15", "Item16", "Item17",
|
||||||
"Item18", "Item19", "Item20", "Item21", "Item22", "Item23", "Item24",
|
"Item18", "Item19", "Item20", "Item21", "Item22", "Item23", "Item24",
|
||||||
],
|
],
|
||||||
selected: 0,
|
selected: None,
|
||||||
events: vec![
|
events: vec![
|
||||||
("Event1", "INFO"),
|
("Event1", "INFO"),
|
||||||
("Event2", "INFO"),
|
("Event2", "INFO"),
|
||||||
@ -132,17 +132,31 @@ fn main() {
|
|||||||
event::Key::Char('q') => {
|
event::Key::Char('q') => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
event::Key::Left => {
|
||||||
|
app.selected = None;
|
||||||
|
}
|
||||||
event::Key::Down => {
|
event::Key::Down => {
|
||||||
app.selected += 1;
|
app.selected = if let Some(selected) = app.selected {
|
||||||
if app.selected > app.items.len() - 1 {
|
if selected >= app.items.len() - 1 {
|
||||||
app.selected = 0;
|
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 => {
|
Event::Tick => {
|
||||||
@ -153,6 +167,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
terminal.show_cursor().unwrap();
|
terminal.show_cursor().unwrap();
|
||||||
|
terminal.clear().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw(t: &mut Terminal<MouseBackend>, app: &App) -> Result<(), io::Error> {
|
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,
|
"WARNING" => &app.warning_style,
|
||||||
_ => &app.info_style,
|
_ => &app.info_style,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
List::new(events)
|
List::new(events)
|
||||||
.block(Block::default().borders(Borders::ALL).title("List"))
|
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||||
|
@ -137,7 +137,7 @@ where
|
|||||||
/// SelectableList::default()
|
/// SelectableList::default()
|
||||||
/// .block(Block::default().title("SelectableList").borders(Borders::ALL))
|
/// .block(Block::default().title("SelectableList").borders(Borders::ALL))
|
||||||
/// .items(&["Item 1", "Item 2", "Item 3"])
|
/// .items(&["Item 1", "Item 2", "Item 3"])
|
||||||
/// .select(1)
|
/// .select(Some(1))
|
||||||
/// .style(Style::default().fg(Color::White))
|
/// .style(Style::default().fg(Color::White))
|
||||||
/// .highlight_style(Style::default().modifier(Modifier::Italic))
|
/// .highlight_style(Style::default().modifier(Modifier::Italic))
|
||||||
/// .highlight_symbol(">>");
|
/// .highlight_symbol(">>");
|
||||||
@ -199,8 +199,8 @@ impl<'b> SelectableList<'b> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn select(mut self, index: usize) -> SelectableList<'b> {
|
pub fn select(mut self, index: Option<usize>) -> SelectableList<'b> {
|
||||||
self.selected = Some(index);
|
self.selected = index;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -216,16 +216,20 @@ impl<'b> Widget for SelectableList<'b> {
|
|||||||
|
|
||||||
// Use highlight_style only if something is selected
|
// Use highlight_style only if something is selected
|
||||||
let (selected, highlight_style) = match self.selected {
|
let (selected, highlight_style) = match self.selected {
|
||||||
Some(i) => (i, &self.highlight_style),
|
Some(i) => (Some(i), &self.highlight_style),
|
||||||
None => (0, &self.style),
|
None => (None, &self.style),
|
||||||
};
|
};
|
||||||
let highlight_symbol = self.highlight_symbol.unwrap_or("");
|
let highlight_symbol = self.highlight_symbol.unwrap_or("");
|
||||||
let blank_symbol = iter::repeat(" ")
|
let blank_symbol = iter::repeat(" ")
|
||||||
.take(highlight_symbol.width())
|
.take(highlight_symbol.width())
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
// Make sure the list show the selected item
|
// Make sure the list show the selected item
|
||||||
let offset = if selected >= list_height {
|
let offset = if let Some(selected) = selected {
|
||||||
selected - list_height + 1
|
if selected >= list_height {
|
||||||
|
selected - list_height + 1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@ -236,10 +240,14 @@ impl<'b> Widget for SelectableList<'b> {
|
|||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(i, item)| {
|
.map(|(i, item)| {
|
||||||
if i == selected {
|
if let Some(s) = selected {
|
||||||
Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
|
if i == s {
|
||||||
|
Item::StyledData(format!("{} {}", highlight_symbol, item), highlight_style)
|
||||||
|
} else {
|
||||||
|
Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Item::StyledData(format!("{} {}", blank_symbol, item), &self.style)
|
Item::StyledData(format!("{}", item), &self.style)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.skip(offset as usize);
|
.skip(offset as usize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user