mirror of https://github.com/fdehau/tui-rs
Add list widget and improve rendering
parent
459201bc65
commit
13f6a5a98b
@ -1,2 +1,3 @@
|
||||
target
|
||||
Cargo.lock
|
||||
*.log
|
||||
|
@ -0,0 +1,7 @@
|
||||
use std::hash::{Hash, SipHasher, Hasher};
|
||||
|
||||
pub fn hash<T: Hash>(t: &T) -> u64 {
|
||||
let mut s = SipHasher::new();
|
||||
t.hash(&mut s);
|
||||
s.finish()
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
use std::cmp::{min, max};
|
||||
use std::fmt::Display;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
use buffer::Buffer;
|
||||
use widgets::{Widget, WidgetType, Block};
|
||||
use style::Color;
|
||||
use layout::Rect;
|
||||
|
||||
pub struct List<'a, T> {
|
||||
block: Block<'a>,
|
||||
selected: usize,
|
||||
formatter: Box<Fn(&T, bool) -> String>,
|
||||
items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> Hash for List<'a, T>
|
||||
where T: Hash
|
||||
{
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.block.hash(state);
|
||||
self.selected.hash(state);
|
||||
self.items.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Default for List<'a, T> {
|
||||
fn default() -> List<'a, T> {
|
||||
List {
|
||||
block: Block::default(),
|
||||
selected: 0,
|
||||
formatter: Box::new(|e: &T, selected: bool| String::from("")),
|
||||
items: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> List<'a, T>
|
||||
where T: Clone
|
||||
{
|
||||
pub fn block<F>(&'a mut self, f: F) -> &mut List<'a, T>
|
||||
where F: Fn(&mut Block)
|
||||
{
|
||||
f(&mut self.block);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn formatter<F>(&'a mut self, f: F) -> &mut List<'a, T>
|
||||
where F: 'static + Fn(&T, bool) -> String
|
||||
{
|
||||
self.formatter = Box::new(f);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn items(&'a mut self, items: &'a [T]) -> &mut List<'a, T> {
|
||||
self.items = items.to_vec();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn select(&'a mut self, index: usize) -> &mut List<'a, T> {
|
||||
self.selected = index;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Widget for List<'a, T>
|
||||
where T: Display + Hash
|
||||
{
|
||||
fn buffer(&self, area: &Rect) -> Buffer {
|
||||
let mut buf = self.block.buffer(area);
|
||||
if area.area() == 0 {
|
||||
return buf;
|
||||
}
|
||||
|
||||
let list_length = self.items.len();
|
||||
let list_area = area.inner(1);
|
||||
let list_height = list_area.height as usize;
|
||||
let bound = min(list_height, list_length);
|
||||
let offset = if self.selected > list_height {
|
||||
min(self.selected - list_height, list_length - list_height)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
for i in 0..bound {
|
||||
let index = i + offset;
|
||||
let ref item = self.items[index];
|
||||
let ref formatter = self.formatter;
|
||||
let mut string = formatter(item, self.selected == index);
|
||||
string.truncate(list_area.width as usize);
|
||||
buf.set_string(1, 1 + i as u16, &string);
|
||||
}
|
||||
buf
|
||||
}
|
||||
|
||||
fn widget_type(&self) -> WidgetType {
|
||||
WidgetType::List
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue