From b7e0e87e44a8b72b80782d764b32dc1299a3ea5c Mon Sep 17 00:00:00 2001 From: KoffeinFlummi Date: Wed, 20 Mar 2019 22:32:45 +0100 Subject: [PATCH] Add scroll bar to ListView, remove ScrollView --- src/commands.rs | 4 ++ src/ui/listview.rs | 95 ++++++++++++++++++++++++++++++++++----------- src/ui/playlists.rs | 9 ++--- src/ui/queue.rs | 9 ++--- src/ui/search.rs | 7 ++-- 5 files changed, 87 insertions(+), 37 deletions(-) diff --git a/src/commands.rs b/src/commands.rs index c8e7408..2c68bb8 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -367,8 +367,12 @@ impl CommandManager { kb.insert("F3".into(), "playlists".into()); kb.insert("F9".into(), "log".into()); + kb.insert("Up".into(), "move up".into()); + kb.insert("Down".into(), "move down".into()); kb.insert("Left".into(), "move left".into()); kb.insert("Right".into(), "move right".into()); + kb.insert("PageUp".into(), "move up 5".into()); + kb.insert("PageDown".into(), "move down 5".into()); kb.insert("k".into(), "move up".into()); kb.insert("j".into(), "move down".into()); kb.insert("h".into(), "move left".into()); diff --git a/src/ui/listview.rs b/src/ui/listview.rs index de3d52b..961c8f3 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -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 { content: Arc>>, + last_content_length: usize, selected: usize, + last_size: Vec2, + scrollbar: ScrollBase, queue: Arc, } @@ -21,7 +25,10 @@ impl ListView { pub fn new(content: Arc>>, queue: Arc) -> 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 ListView { 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 View for ListView { 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 View for ListView { // 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 View for ListView { 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 View for ListView { 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 { diff --git a/src/ui/playlists.rs b/src/ui/playlists.rs index 0bce36d..8252b08 100644 --- a/src/ui/playlists.rs +++ b/src/ui/playlists.rs @@ -2,25 +2,24 @@ use std::sync::Arc; use cursive::traits::Identifiable; use cursive::view::ViewWrapper; -use cursive::views::{IdView, ScrollView}; +use cursive::views::IdView; use playlists::{Playlist, Playlists}; use queue::Queue; use ui::listview::ListView; pub struct PlaylistView { - list: ScrollView>>, + list: IdView>, } impl PlaylistView { pub fn new(playlists: &Playlists, queue: Arc) -> PlaylistView { let list = ListView::new(playlists.store.clone(), queue).with_id("list"); - let scrollable = ScrollView::new(list); - PlaylistView { list: scrollable } + PlaylistView { list: list } } } impl ViewWrapper for PlaylistView { - wrap_impl!(self.list: ScrollView>>); + wrap_impl!(self.list: IdView>); } diff --git a/src/ui/queue.rs b/src/ui/queue.rs index a9432a3..9e31b3a 100644 --- a/src/ui/queue.rs +++ b/src/ui/queue.rs @@ -1,6 +1,6 @@ use cursive::traits::Identifiable; use cursive::view::ViewWrapper; -use cursive::views::{IdView, ScrollView}; +use cursive::views::IdView; use std::sync::Arc; @@ -9,18 +9,17 @@ use track::Track; use ui::listview::ListView; pub struct QueueView { - list: ScrollView>>, + list: IdView>, } impl QueueView { pub fn new(queue: Arc) -> QueueView { let list = ListView::new(queue.queue.clone(), queue.clone()).with_id("queue_list"); - let scrollable = ScrollView::new(list); - QueueView { list: scrollable } + QueueView { list: list } } } impl ViewWrapper for QueueView { - wrap_impl!(self.list: ScrollView>>); + wrap_impl!(self.list: IdView>); } diff --git a/src/ui/search.rs b/src/ui/search.rs index 147481d..b73d976 100644 --- a/src/ui/search.rs +++ b/src/ui/search.rs @@ -4,7 +4,7 @@ use cursive::direction::Orientation; use cursive::event::{AnyCb, Event, EventResult, Key}; use cursive::traits::{Boxable, Finder, Identifiable, View}; use cursive::view::{Selector, ViewWrapper}; -use cursive::views::{EditView, IdView, ScrollView, ViewRef}; +use cursive::views::{EditView, IdView, ViewRef}; use cursive::{Cursive, Printer, Vec2}; use std::cell::RefCell; use std::sync::{Arc, Mutex, RwLock}; @@ -17,7 +17,7 @@ use ui::listview::ListView; pub struct SearchView { results: Arc>>, edit: IdView, - list: ScrollView>>, + list: IdView>, edit_focused: bool, } @@ -36,12 +36,11 @@ impl SearchView { }) .with_id("search_edit"); let list = ListView::new(results.clone(), queue).with_id("list"); - let scrollable = ScrollView::new(list); SearchView { results: results, edit: searchfield, - list: scrollable, + list: list, edit_focused: true, } }