From e4940d693bbafc9c0be131ec4d58e81be890909b Mon Sep 17 00:00:00 2001 From: Elias Projahn Date: Tue, 7 Nov 2023 15:57:56 +0100 Subject: [PATCH] playerbar: Improve seeking --- src/player.rs | 55 ++++++++++++-------------------------------- src/player_bar.rs | 58 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 51 deletions(-) diff --git a/src/player.rs b/src/player.rs index 09285c2..234acfa 100644 --- a/src/player.rs +++ b/src/player.rs @@ -33,9 +33,7 @@ mod imp { #[property(get, set)] pub duration_ms: Cell, #[property(get, set)] - pub current_time_ms: Cell, - #[property(get, set = Self::set_position)] - pub position: Cell, + pub position_ms: Cell, #[property(get, construct_only)] pub player: OnceCell, @@ -74,15 +72,6 @@ mod imp { item.set_is_playing(true); } } - - pub fn set_position(&self, position: f64) { - self.player - .get() - .unwrap() - .seek(gst::ClockTime::from_mseconds( - (position * self.duration_ms.get() as f64) as u64, - )); - } } #[glib::object_subclass] @@ -140,23 +129,11 @@ mod imp { }); let obj = Fragile::new(self.obj().to_owned()); - player.connect_position_updated(move |_, current_time| { - if let Some(current_time) = current_time { + player.connect_position_updated(move |_, position| { + if let Some(position) = position { let obj = obj.get(); - let imp = obj.imp(); - - let current_time_ms = current_time.mseconds(); - let duration_ms = imp.duration_ms.get(); - let mut position = current_time_ms as f64 / duration_ms as f64; - if position > 1.0 { - position = 1.0 - } - - imp.current_time_ms.set(current_time_ms); - obj.notify_current_time_ms(); - - imp.position.set(position); - obj.notify_position(); + obj.imp().position_ms.set(position.mseconds()); + obj.notify_position_ms(); } }); @@ -165,17 +142,12 @@ mod imp { if let Some(duration) = duration { let obj = obj.get(); let imp = obj.imp(); - - let duration_ms = duration.mseconds(); - - imp.duration_ms.set(duration_ms); + + imp.position_ms.set(0); + obj.notify_position_ms(); + + imp.duration_ms.set(duration.mseconds()); obj.notify_duration_ms(); - - imp.current_time_ms.set(0); - obj.notify_current_time_ms(); - - imp.position.set(0.0); - obj.notify_position(); } }); } @@ -200,9 +172,8 @@ impl MusicusPlayer { .property("playing", false) .property("playlist", gio::ListStore::new::()) .property("current-index", 0u32) - .property("current-time-ms", 0u64) + .property("position-ms", 0u64) .property("duration-ms", 60_000u64) - .property("position", 0.0) .property("player", player) .build() } @@ -257,6 +228,10 @@ impl MusicusPlayer { .set_playback_status(PlaybackStatus::Paused); } + pub fn seek_to(&self, time_ms: u64) { + self.player().seek(gst::ClockTime::from_mseconds(time_ms)); + } + pub fn current_item(&self) -> Option { let imp = self.imp(); imp.playlist diff --git a/src/player_bar.rs b/src/player_bar.rs index c73a582..f69fb3f 100644 --- a/src/player_bar.rs +++ b/src/player_bar.rs @@ -1,11 +1,12 @@ use crate::player::MusicusPlayer; use gtk::{ + gdk, glib::{self, clone, subclass::Signal, Properties}, prelude::*, subclass::prelude::*, }; use once_cell::sync::Lazy; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; mod imp { use super::*; @@ -17,6 +18,8 @@ mod imp { #[property(get, construct_only)] pub player: RefCell, + pub seeking: Cell, + #[template_child] pub title_label: TemplateChild, #[template_child] @@ -54,13 +57,22 @@ mod imp { fn update_time(&self) { let player = self.player.borrow(); + let current_time_ms = if self.seeking.get() { + (self.slider.value() * player.duration_ms() as f64) as u64 + } else { + let current_time_ms = player.position_ms(); + self.slider + .set_value(current_time_ms as f64 / player.duration_ms() as f64); + current_time_ms + }; + self.current_time_label - .set_label(&format_time(player.current_time_ms())); + .set_label(&format_time(current_time_ms)); self.remaining_time_label.set_label(&format_time( player .duration_ms() - .checked_sub(player.current_time_ms()) + .checked_sub(current_time_ms) .unwrap_or(0), )); } @@ -120,17 +132,41 @@ mod imp { clone!(@weak obj => move |_, _, _, _| obj.imp().update_item()), ); - player.connect_current_time_ms_notify( - clone!(@weak obj => move |_| obj.imp().update_time()), - ); + player + .connect_position_ms_notify(clone!(@weak obj => move |_| obj.imp().update_time())); player .connect_duration_ms_notify(clone!(@weak obj => move |_| obj.imp().update_time())); - player - .bind_property("position", &self.slider.adjustment(), "value") - .sync_create() - .bidirectional() - .build(); + let seeking_controller = gtk::EventControllerLegacy::new(); + + seeking_controller.connect_event( + clone!(@weak obj => @default-return glib::Propagation::Proceed, move |_, event| { + if let Some(event) = event.downcast_ref::() { + let imp = obj.imp(); + if event.button() == gdk::BUTTON_PRIMARY { + match event.event_type() { + gdk::EventType::ButtonPress => { + imp.seeking.set(true); + } + gdk::EventType::ButtonRelease => { + let player = obj.player(); + player.seek_to((imp.slider.value() * player.duration_ms() as f64) as u64); + imp.seeking.set(false); + } + _ => (), + } + } + + } + + glib::Propagation::Proceed + }), + ); + + self.slider.add_controller(seeking_controller); + + self.slider + .connect_value_changed(clone!(@weak obj => move |_| obj.imp().update_time())); } }