diff --git a/hammond-gtk/src/utils.rs b/hammond-gtk/src/utils.rs index d6c85fe..a2a57a3 100644 --- a/hammond-gtk/src/utils.rs +++ b/hammond-gtk/src/utils.rs @@ -1,5 +1,6 @@ #![cfg_attr(feature = "cargo-clippy", allow(type_complexity))] +use gdk::FrameClockExt; use gdk_pixbuf::Pixbuf; use glib; use gtk; @@ -101,6 +102,40 @@ where }); } +// Kudos to Julian Sparber +// https://blogs.gnome.org/jsparber/2018/04/29/animate-a-scrolledwindow/ +pub fn smooth_scroll_to(view: gtk::ScrolledWindow, target: gtk::Adjustment) { + if let Some(adj) = view.get_vadjustment() { + if let Some(clock) = view.get_frame_clock() { + let duration = 200; + let start = adj.get_value(); + let end = target.get_value(); + let start_time = clock.get_frame_time(); + let end_time = start_time + 1000 * duration; + + view.add_tick_callback(move |_, clock| { + let now = clock.get_frame_time(); + if now < end_time && adj.get_value() != end { + let mut t = (now - start_time) as f64 / (end_time - start_time) as f64; + t = ease_out_cubic(t); + adj.set_value(start + t * (end - start)); + return glib::Continue(true); + } else { + adj.set_value(end); + return glib::Continue(false); + } + }); + } + } +} + +// From clutter-easing.c, based on Robert Penner's +// infamous easing equations, MIT license. +fn ease_out_cubic(t: f64) -> f64 { + let p = t - 1f64; + return p * p * p + 1f64; +} + lazy_static! { static ref IGNORESHOWS: Arc>> = Arc::new(Mutex::new(HashSet::new())); } diff --git a/hammond-gtk/src/widgets/home_view.rs b/hammond-gtk/src/widgets/home_view.rs index d60bcde..6334b06 100644 --- a/hammond-gtk/src/widgets/home_view.rs +++ b/hammond-gtk/src/widgets/home_view.rs @@ -1,5 +1,6 @@ use chrono::prelude::*; use failure::Error; + use gtk; use gtk::prelude::*; @@ -8,8 +9,7 @@ use hammond_data::EpisodeWidgetQuery; use send_cell::SendCell; use app::Action; -use utils::lazy_load_full; -use utils::{get_ignored_shows, set_image_from_path}; +use utils::{self, lazy_load_full}; use widgets::EpisodeWidget; use std::rc::Rc; @@ -90,7 +90,7 @@ impl HomeView { use self::ListSplit::*; let view = Rc::new(HomeView::default()); - let ignore = get_ignored_shows()?; + let ignore = utils::get_ignored_shows()?; let episodes = dbqueries::get_episodes_widgets_filter_limit(&ignore, 100)?; let now_utc = Utc::now(); @@ -132,7 +132,7 @@ impl HomeView { // Copy the vertical scrollbar adjustment from the old view into the new one. sendcell .try_get() - .map(|x| self.scrolled_window.set_vadjustment(&x)); + .map(|x| utils::smooth_scroll_to(self.scrolled_window.clone(), x.clone())); } Ok(()) @@ -231,6 +231,6 @@ impl EpisodesViewWidget { #[inline] fn set_cover(&self, podcast_id: i32) -> Result<(), Error> { - set_image_from_path(&self.image, podcast_id, 64) + utils::set_image_from_path(&self.image, podcast_id, 64) } } diff --git a/hammond-gtk/src/widgets/show.rs b/hammond-gtk/src/widgets/show.rs index e4b7bd3..3095518 100644 --- a/hammond-gtk/src/widgets/show.rs +++ b/hammond-gtk/src/widgets/show.rs @@ -165,7 +165,7 @@ impl ShowWidget { // Copy the vertical scrollbar adjustment from the old view into the new one. sendcell .try_get() - .map(|x| self.scrolled_window.set_vadjustment(&x)); + .map(|x| utils::smooth_scroll_to(self.scrolled_window.clone(), x.clone())); } Ok(())