Add scroll bar to ListView, remove ScrollView

This commit is contained in:
KoffeinFlummi
2019-03-20 22:32:45 +01:00
parent cf482519af
commit b7e0e87e44
5 changed files with 87 additions and 37 deletions

View File

@@ -2,9 +2,10 @@ use std::cmp::{max, min};
use std::sync::{Arc, RwLock};
use cursive::align::HAlign;
use cursive::event::{Event, EventResult, Key};
use cursive::event::{Event, EventResult, MouseEvent, MouseButton};
use cursive::theme::ColorStyle;
use cursive::traits::View;
use cursive::view::ScrollBase;
use cursive::{Printer, Rect, Vec2};
use unicode_width::UnicodeWidthStr;
@@ -13,7 +14,10 @@ use traits::ListItem;
pub struct ListView<I: 'static + ListItem> {
content: Arc<RwLock<Vec<I>>>,
last_content_length: usize,
selected: usize,
last_size: Vec2,
scrollbar: ScrollBase,
queue: Arc<Queue>,
}
@@ -21,7 +25,10 @@ impl<I: ListItem> ListView<I> {
pub fn new(content: Arc<RwLock<Vec<I>>>, queue: Arc<Queue>) -> Self {
Self {
content: content,
last_content_length: 0,
selected: 0,
last_size: Vec2::new(0, 0),
scrollbar: ScrollBase::new(),
queue: queue,
}
}
@@ -37,16 +44,25 @@ impl<I: ListItem> ListView<I> {
self.selected
}
pub fn move_focus_to(&mut self, target: usize) {
let len = self.content.read().unwrap().len();
self.selected = min(target, len - 1);
self.scrollbar.scroll_to(self.selected);
}
pub fn move_focus(&mut self, delta: i32) {
let len = self.content.read().unwrap().len() as i32;
let new = self.selected as i32 + delta;
self.selected = min(max(new, 0), len - 1) as usize;
self.move_focus_to(max(new, 0) as usize);
}
}
impl<I: ListItem> View for ListView<I> {
fn draw(&self, printer: &Printer<'_, '_>) {
for (i, item) in self.content.read().unwrap().iter().enumerate() {
let content = self.content.read().unwrap();
self.scrollbar.draw(printer, |printer, i| {
let item = &content[i];
let style = if self.selected == i {
ColorStyle::highlight()
} else if item.is_playing(self.queue.clone()) {
@@ -60,7 +76,7 @@ impl<I: ListItem> View for ListView<I> {
// draw left string
printer.with_color(style, |printer| {
printer.print((0, i), &left);
printer.print((0, 0), &left);
});
// draw ".." to indicate a cut off string
@@ -68,7 +84,7 @@ impl<I: ListItem> View for ListView<I> {
if max_length < left.width() {
let offset = max_length.checked_sub(1).unwrap_or(0);
printer.with_color(style, |printer| {
printer.print((offset, i), "..");
printer.print((offset, 0), "..");
});
}
@@ -76,31 +92,64 @@ impl<I: ListItem> View for ListView<I> {
let offset = HAlign::Right.get_offset(right.width(), printer.size.x);
printer.with_color(style, |printer| {
printer.print((offset, i), &right);
printer.print((offset, 0), &right);
});
}
});
}
fn layout(&mut self, size: Vec2) {
self.last_content_length = self.content.read().unwrap().len();
self.last_size = size;
self.scrollbar.set_heights(size.y, self.last_content_length);
}
fn needs_relayout(&self) -> bool {
self.content.read().unwrap().len() != self.last_content_length
}
fn on_event(&mut self, e: Event) -> EventResult {
match e {
Event::Key(Key::Up) => {
self.move_focus(-1);
EventResult::Consumed(None)
Event::Mouse {
event: MouseEvent::WheelUp,
..
} => {
self.move_focus(-3)
},
Event::Mouse {
event: MouseEvent::WheelDown,
..
} => {
self.move_focus(3)
},
Event::Mouse {
event: MouseEvent::Press(MouseButton::Left),
position,
offset
} => if self.scrollbar.scrollable() &&
position.y > 0 && position.y <= self.last_size.y &&
position.checked_sub(offset)
.map(|p| self.scrollbar.start_drag(p, self.last_size.x))
.unwrap_or(false)
{},
Event::Mouse {
event: MouseEvent::Hold(MouseButton::Left),
position,
offset
} => if self.scrollbar.scrollable() {
self.scrollbar.drag(position.saturating_sub(offset));
},
Event::Mouse {
event: MouseEvent::Release(MouseButton::Left),
..
} => {
self.scrollbar.release_grab();
}
Event::Key(Key::Down) => {
self.move_focus(1);
EventResult::Consumed(None)
_ => {
return EventResult::Ignored;
}
Event::Key(Key::PageUp) => {
self.move_focus(-10);
EventResult::Consumed(None)
}
Event::Key(Key::PageDown) => {
self.move_focus(10);
EventResult::Consumed(None)
}
_ => EventResult::Ignored,
}
EventResult::Consumed(None)
}
fn required_size(&mut self, constraint: Vec2) -> Vec2 {