From adf8da2fc56652299ee0d51a867fcbe66509936e Mon Sep 17 00:00:00 2001 From: Henrik Friedrichsen Date: Thu, 13 Jan 2022 21:09:26 +0100 Subject: [PATCH] Move from `ScrollBase` to `scroll` module `ScrollBase` is deprecated --- src/ui/listview.rs | 77 +++++++++++++++++++++++++--------------- src/ui/pagination.rs | 15 ++++++-- src/ui/search_results.rs | 5 +-- 3 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/ui/listview.rs b/src/ui/listview.rs index b68aca3..e783529 100644 --- a/src/ui/listview.rs +++ b/src/ui/listview.rs @@ -1,3 +1,4 @@ +use cursive::view::scroll::Scroller; use log::info; use std::cmp::{max, min, Ordering}; use std::sync::{Arc, RwLock}; @@ -6,7 +7,7 @@ use cursive::align::HAlign; use cursive::event::{Event, EventResult, MouseButton, MouseEvent}; use cursive::theme::{ColorStyle, ColorType, PaletteColor}; use cursive::traits::View; -use cursive::view::ScrollBase; +use cursive::view::scroll; use cursive::{Cursive, Printer, Rect, Vec2}; use unicode_width::UnicodeWidthStr; @@ -38,13 +39,23 @@ pub struct ListView { search_indexes: Vec, search_selected_index: usize, last_size: Vec2, - scrollbar: ScrollBase, + scroller: scroll::Core, queue: Arc, library: Arc, pagination: Pagination, title: String, } +impl Scroller for ListView { + fn get_scroller_mut(&mut self) -> &mut scroll::Core { + &mut self.scroller + } + + fn get_scroller(&self) -> &scroll::Core { + &self.scroller + } +} + impl ListView { pub fn new(content: Arc>>, queue: Arc, library: Arc) -> Self { Self { @@ -55,7 +66,7 @@ impl ListView { search_indexes: Vec::new(), search_selected_index: 0, last_size: Vec2::new(0, 0), - scrollbar: ScrollBase::new(), + scroller: scroll::Core::new(), queue, library, pagination: Pagination::default(), @@ -72,13 +83,22 @@ impl ListView { &self.pagination } - fn can_paginate(&self) -> bool { - if let Some(max) = self.get_pagination().max_content() { - if max > self.last_content_len { - return true; - } + pub fn content_height_with_paginator(&self) -> usize { + let content_len = self.content.read().unwrap().len(); + log::info!("content len: {content_len}"); + + // add 1 more row for paginator if we can paginate + if self.can_paginate() { + content_len + 1 + } else { + content_len } - false + } + + fn can_paginate(&self) -> bool { + let loaded = self.get_pagination().loaded_content(); + log::info!("can paginate: {loaded}"); + self.get_pagination().max_content().unwrap_or(0) > self.get_pagination().loaded_content() } pub fn get_selected_index(&self) -> usize { @@ -102,7 +122,7 @@ impl ListView { pub fn move_focus_to(&mut self, target: usize) { let len = self.content.read().unwrap().len().saturating_sub(1); self.selected = min(target, len); - self.scrollbar.scroll_to(self.selected); + self.scroller.scroll_to_y(self.selected); } pub fn move_focus(&mut self, delta: i32) { @@ -138,7 +158,7 @@ impl View for ListView { fn draw(&self, printer: &Printer<'_, '_>) { let content = self.content.read().unwrap(); - self.scrollbar.draw(printer, |printer, i| { + scroll::draw_lines(self, printer, |_, printer, i| { // draw paginator after content if i == content.len() && self.can_paginate() { let style = ColorStyle::secondary(); @@ -245,25 +265,26 @@ impl View for ListView { } fn layout(&mut self, size: Vec2) { - let content_len = self.content.read().unwrap().len(); - - // add 1 more row for paginator if we can paginate - self.last_content_len = if self.can_paginate() { - content_len + 1 - } else { - content_len - }; - self.last_size = size; - self.scrollbar.set_heights(size.y, self.last_content_len); + self.last_content_len = self.content_height_with_paginator(); + + let relayout_scroller = self.content.read().unwrap().len() != self.last_content_len; + + scroll::layout( + self, + size, + relayout_scroller, + |_, _| {}, + |s, c| Vec2::new(c.x, s.content_height_with_paginator()), + ); } fn needs_relayout(&self) -> bool { - self.content.read().unwrap().len() != self.last_content_len + self.scroller.needs_relayout() } fn required_size(&mut self, constraint: Vec2) -> Vec2 { - Vec2::new(constraint.x, self.content.read().unwrap().len()) + constraint } fn on_event(&mut self, e: Event) -> EventResult { @@ -281,12 +302,12 @@ impl View for ListView { position, offset, } => { - if self.scrollbar.scrollable() + if self.scroller.get_show_scrollbars() && position.y > 0 && position.y <= self.last_size.y && position .checked_sub(offset) - .map(|p| self.scrollbar.start_drag(p, self.last_size.x)) + .map(|p| self.scroller.start_drag(p)) .unwrap_or(false) {} } @@ -295,15 +316,15 @@ impl View for ListView { position, offset, } => { - if self.scrollbar.scrollable() { - self.scrollbar.drag(position.saturating_sub(offset)); + if self.scroller.get_show_scrollbars() { + self.scroller.drag(position.saturating_sub(offset)); } } Event::Mouse { event: MouseEvent::Release(MouseButton::Left), .. } => { - self.scrollbar.release_grab(); + self.scroller.release_grab(); } _ => { return EventResult::Ignored; diff --git a/src/ui/pagination.rs b/src/ui/pagination.rs index 1aeec2d..36f2ca6 100644 --- a/src/ui/pagination.rs +++ b/src/ui/pagination.rs @@ -50,7 +50,9 @@ impl ApiResult { pub fn apply_pagination(self, pagination: &Pagination) { let total = self.total as usize; + let fetched_items = self.items.read().unwrap().len(); pagination.set( + fetched_items, total, Box::new(move |_| { self.next(); @@ -79,6 +81,7 @@ impl ApiResult { pub type Paginator = Box>>) + Send + Sync>; pub struct Pagination { + loaded_content: Arc>, max_content: Arc>>, callback: Arc>>>, busy: Arc>, @@ -87,6 +90,7 @@ pub struct Pagination { impl Default for Pagination { fn default() -> Self { Pagination { + loaded_content: Arc::new(RwLock::new(0)), max_content: Arc::new(RwLock::new(None)), callback: Arc::new(RwLock::new(None)), busy: Arc::new(RwLock::new(false)), @@ -98,6 +102,7 @@ impl Default for Pagination { impl Clone for Pagination { fn clone(&self) -> Self { Pagination { + loaded_content: self.loaded_content.clone(), max_content: self.max_content.clone(), callback: self.callback.clone(), busy: self.busy.clone(), @@ -110,11 +115,16 @@ impl Pagination { *self.max_content.write().unwrap() = None; *self.callback.write().unwrap() = None; } - pub fn set(&self, max_content: usize, callback: Paginator) { + pub fn set(&self, loaded_content: usize, max_content: usize, callback: Paginator) { + *self.loaded_content.write().unwrap() = loaded_content; *self.max_content.write().unwrap() = Some(max_content); *self.callback.write().unwrap() = Some(callback); } + pub fn loaded_content(&self) -> usize { + *self.loaded_content.read().unwrap() + } + pub fn max_content(&self) -> Option { *self.max_content.read().unwrap() } @@ -132,7 +142,8 @@ impl Pagination { let cb = pagination.callback.read().unwrap(); if let Some(ref cb) = *cb { debug!("calling paginator!"); - cb(content); + cb(content.clone()); + *pagination.loaded_content.write().unwrap() = content.read().unwrap().len(); *pagination.busy.write().unwrap() = false; library.trigger_redraw(); } diff --git a/src/ui/search_results.rs b/src/ui/search_results.rs index e7ffa62..ca692fa 100644 --- a/src/ui/search_results.rs +++ b/src/ui/search_results.rs @@ -366,7 +366,8 @@ impl SearchResultsView { // register paginator if the API has more than one page of results if let Some(mut paginator) = paginator { - if total_items > results.read().unwrap().len() { + let loaded_items = results.read().unwrap().len(); + if total_items > loaded_items { let ev = ev.clone(); // paginator callback @@ -375,7 +376,7 @@ impl SearchResultsView { handler(&spotify, &results, &query, offset, true); ev.trigger(); }; - paginator.set(total_items, Box::new(cb)); + paginator.set(loaded_items, total_items, Box::new(cb)); } else { paginator.clear() }