mod imp { use adw::prelude::*; use adw::subclass::prelude::*; use glib::subclass::InitializingObject; use gtk::{gdk, glib}; use std::cell::{Cell, RefCell}; #[derive(glib::Properties, gtk::CompositeTemplate, Default)] #[properties(wrapper_type = super::Playbar)] #[template(resource = "/eu/callcc/audrey/playbar.ui")] pub struct Playbar { #[property(get, set)] song: RefCell>, #[property(get, set)] playing_cover_art: RefCell>, #[property(get, set)] playbin: RefCell>, // TODO: weak #[property(get, set, default = true)] show_cover_art: Cell, #[property(get, set)] volume: Cell, } #[glib::object_subclass] impl ObjectSubclass for Playbar { const NAME: &'static str = "AudreyUiPlaybar"; type Type = super::Playbar; type ParentType = adw::Bin; fn class_init(klass: &mut Self::Class) { klass.bind_template(); klass.bind_template_callbacks(); } fn instance_init(obj: &InitializingObject) { obj.init_template(); } } #[glib::derived_properties] impl ObjectImpl for Playbar {} impl WidgetImpl for Playbar {} impl BinImpl for Playbar {} #[gtk::template_callbacks] impl Playbar { #[template_callback] fn song_title(&self, song: Option<&crate::playbin::Song>) -> String { match song { None => "".to_owned(), Some(song) => song.get_title().to_string(), } } #[template_callback] fn song_artist(&self, song: Option<&crate::playbin::Song>) -> String { match song { None => "".to_owned(), Some(song) => song.get_artist().to_string(), } } #[template_callback] fn song_album(&self, song: Option<&crate::playbin::Song>) -> String { match song { None => "".to_owned(), Some(song) => song.get_album().to_string(), } } #[template_callback] fn format_timestamp(&self, s: f64) -> String { format!("{:02}:{:02}", (s as i64) / 64, (s as i64) % 60) } #[template_callback] fn playbin_active(&self, state: crate::playbin::State) -> bool { state != crate::playbin::State::Stopped } #[template_callback] fn can_press_play(&self, state: crate::playbin::State, n_items: u32) -> bool { !(state == crate::playbin::State::Stopped && n_items == 0) } #[template_callback] fn play_pause_icon_name(&self, state: crate::playbin::State) -> &'static str { match state { crate::playbin::State::Playing => "media-playback-pause", _ => "media-playback-start", } } #[template_callback] fn mute_button_icon_name(&self, mute: bool) -> &'static str { if mute { "audio-volume-muted" } else { "audio-volume-high" } } #[template_callback] fn on_play_position_seek(&self, _range: >k::Range, _scroll_type: gtk::ScrollType, _value: f64) -> bool { /* if (range.adjustment.lower < range.adjustment.upper) { this.playbin.seek ((int64) value); } return false; */ todo!() } #[template_callback] fn on_skip_forward_clicked(&self) { // this.playbin.go_to_next_track (); todo!() } #[template_callback] fn on_skip_backward_clicked(&self) { // this.playbin.go_to_prev_track (); todo!() } #[template_callback] fn seek_backward(&self) { // 10 seconds // double new_position = playbin.position - 10.0; // if (new_position < 0.0) new_position = 0.0; // this.playbin.seek (new_position); todo!() } #[template_callback] fn seek_forward(&self) { // 10 seconds // double new_position = playbin.position + 10.0; // if (new_position > this.playbin.duration) new_position = this.playbin.duration; // this.playbin.seek (new_position); todo!() } #[template_callback] fn on_play_pause_clicked(&self) { // if (this.playbin.state == PlaybinState.PLAYING) { // this.playbin.pause(); // } else { // this.playbin.play(); // } todo!() } #[template_callback] fn on_mute_toggle(&self) { //this.playbin.mute = !this.playbin.mute; todo!() } } } use gtk::glib; glib::wrapper! { pub struct Playbar(ObjectSubclass) @extends adw::Bin, gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget; } mod ffi { use glib::translate::IntoGlib; use gtk::glib; use gtk::prelude::*; #[no_mangle] pub extern "C" fn audrey_ui_playbar_get_type() -> glib::ffi::GType { super::Playbar::static_type().into_glib() } }