diff --git a/resources/play_queue.blp b/resources/play_queue.blp index 62f21e1..02e103c 100644 --- a/resources/play_queue.blp +++ b/resources/play_queue.blp @@ -28,16 +28,16 @@ template $AudreyUiPlayQueue: Adw.Bin { show-separators: true; single-click-activate: true; - activate => $on_row_activated (); + activate => $on_row_activated () swapped; model: NoSelection { model: bind template.playbin as <$AudreyPlaybin>.play_queue; }; factory: SignalListItemFactory { - setup => $on_song_list_setup (); - bind => $on_song_list_bind (); - unbind => $on_song_list_unbind (); + setup => $on_song_list_setup () swapped; + bind => $on_song_list_bind () swapped; + unbind => $on_song_list_unbind () swapped; }; } }; diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..92ab8ff --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,6 @@ +#![allow(dead_code)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(non_upper_case_globals)] + +include!(concat!(env!("OUT_DIR"), "/audrey_ffi.rs")); diff --git a/src/main.rs b/src/main.rs index 8e2ab9d..75e2201 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,6 +29,7 @@ fn main() -> glib::ExitCode { gio::resources_register_include!("audrey.gresource").expect("could not register resources"); ui::Playbar::ensure_type(); + ui::PlayQueue::ensure_type(); gtk::disable_setlocale(); bindtextdomain("audrey", meson_config::LOCALEDIR).expect("failed to bind text domain"); diff --git a/src/meson.build b/src/meson.build index ec7a7eb..8a23701 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,7 +5,6 @@ audrey_sources = [ 'playbin.vala', 'rust.vapi', 'subsonic.vala', - 'ui/play_queue.vala', 'ui/setup.vala', 'ui/window.vala', ] diff --git a/src/playbin.rs b/src/playbin.rs index f2814dd..e822edd 100644 --- a/src/playbin.rs +++ b/src/playbin.rs @@ -40,6 +40,7 @@ pub mod ffi { to: std::ffi::c_uint, ); pub fn audrey_playbin_remove_track(self_: *mut AudreyPlaybin, position: std::ffi::c_uint); + pub fn audrey_playbin_select_track(self_: *mut AudreyPlaybin, position: std::ffi::c_uint); } } @@ -116,4 +117,8 @@ impl Playbin { pub fn remove_track(&self, position: u32) { unsafe { ffi::audrey_playbin_remove_track(self.to_glib_none().0, position) } } + + pub fn select_track(&self, position: u32) { + unsafe { ffi::audrey_playbin_select_track(self.to_glib_none().0, position) } + } } diff --git a/src/rust.h b/src/rust.h index e7cc8db..8effb57 100644 --- a/src/rust.h +++ b/src/rust.h @@ -15,3 +15,6 @@ void audrey_ui_play_queue_song_set_show_artist(AudreyUiPlayQueueSong *self, gboo void audrey_ui_play_queue_song_set_show_cover(AudreyUiPlayQueueSong *self, gboolean show_cover); void audrey_ui_play_queue_song_bind(AudreyUiPlayQueueSong *self, guint position, void *song); void audrey_ui_play_queue_song_unbind(AudreyUiPlayQueueSong *self); + +// ui::PlayQueue +typedef void AudreyUiPlayQueue; diff --git a/src/rust.vapi b/src/rust.vapi index 13969c5..1c226ab 100644 --- a/src/rust.vapi +++ b/src/rust.vapi @@ -23,4 +23,9 @@ namespace Audrey { public void unbind (); } + public class Ui.PlayQueue : Adw.Bin { + public Playbin playbin { get; set; } + public bool can_clear_all { get; } + } + } diff --git a/src/ui/play_queue.rs b/src/ui/play_queue.rs index 7817c03..426ecfa 100644 --- a/src/ui/play_queue.rs +++ b/src/ui/play_queue.rs @@ -1,32 +1,92 @@ pub mod song; pub use song::Song; -mod ffi { - use gtk::glib; +mod imp { + use adw::{glib, prelude::*, subclass::prelude::*}; + use glib::{subclass::InitializingObject, WeakRef}; - #[repr(C)] - pub struct AudreyUiPlayQueue { - _data: [u8; 0], + #[derive(gtk::CompositeTemplate, glib::Properties, Default)] + #[template(resource = "/eu/callcc/audrey/play_queue.ui")] + #[properties(wrapper_type = super::PlayQueue)] + pub struct PlayQueue { + #[property(get, set)] + playbin: WeakRef, } - #[repr(C)] - pub struct AudreyUiPlayQueueClass { - _data: [u8; 0], + #[glib::object_subclass] + impl ObjectSubclass for PlayQueue { + const NAME: &'static str = "AudreyUiPlayQueue"; + type Type = super::PlayQueue; + 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(); + } } - extern "C" { - pub fn audrey_ui_play_queue_get_type() -> glib::ffi::GType; + #[glib::derived_properties] + impl ObjectImpl for PlayQueue {} + + impl WidgetImpl for PlayQueue {} + + impl BinImpl for PlayQueue {} + + #[gtk::template_callbacks] + impl PlayQueue { + #[template_callback] + fn visible_child_name(&self, n_items: u32) -> &'static str { + if n_items > 0 { + "not-empty" + } else { + "empty" + } + } + + #[template_callback] + fn on_song_list_setup(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) { + let child = super::Song::new(&self.playbin.upgrade().unwrap()); + + child.set_draggable(true); + child.set_show_position(true); + child.set_show_artist(true); + child.set_show_cover(true); + + item.set_child(Some(&child)); + } + + #[template_callback] + fn on_song_list_bind(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) { + let child = item.child().and_downcast::().unwrap(); + + child.bind( + item.position(), + item.item().unwrap().downcast_ref::().unwrap(), + ); + } + + #[template_callback] + fn on_song_list_unbind(&self, item: >k::ListItem, _factory: >k::SignalListItemFactory) { + let child = item.child().and_downcast::().unwrap(); + + child.unbind(); + } + + #[template_callback] + fn on_row_activated(&self, position: u32) { + self.obj().playbin().unwrap().select_track(position); + } } } use gtk::glib; glib::wrapper! { - pub struct PlayQueue(Object) + pub struct PlayQueue(ObjectSubclass) @extends adw::Bin, gtk::Widget, @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget; - - match fn { - type_ => || ffi::audrey_ui_play_queue_get_type(), - } } diff --git a/src/ui/play_queue.vala b/src/ui/play_queue.vala deleted file mode 100644 index 5f1ec92..0000000 --- a/src/ui/play_queue.vala +++ /dev/null @@ -1,63 +0,0 @@ -/* -[GtkTemplate (ui = "/eu/callcc/audrey/play_queue.ui")] -public class Audrey.Ui.PlayQueue : Adw.Bin { - private weak Playbin _playbin; - public Playbin playbin { - get { return _playbin; } - set { - assert (_playbin == null); // only set once - _playbin = value; - - _playbin.play_queue.items_changed.connect (this.on_store_items_changed); - this.can_clear_all = _playbin.play_queue.get_n_items () > 0; - } - } - - public bool can_clear_all { get; private set; } - - /*[GtkCallback] private void on_clear () { - this.playbin.clear (); - }*/ - - private void on_store_items_changed (GLib.ListModel store, uint position, uint removed, uint added) { - this.can_clear_all = store.get_n_items () > 0; - } - - [GtkCallback] private void on_song_list_setup (Gtk.SignalListItemFactory factory, Object object) { - var item = object as Gtk.ListItem; - var child = new PlayQueueSong (this.playbin); - - child.draggable = true; - child.show_position = true; - child.show_artist = true; - child.show_cover = true; - - item.child = child; - } - - [GtkCallback] private void on_song_list_bind (Gtk.SignalListItemFactory factory, Object object) { - var item = object as Gtk.ListItem; - var child = item.child as PlayQueueSong; - - child.bind (item.position, item.item as PlaybinSong); - } - - [GtkCallback] private void on_song_list_unbind (Gtk.SignalListItemFactory factory, Object object) { - var item = object as Gtk.ListItem; - var child = item.child as PlayQueueSong; - - child.unbind (); - } - - [GtkCallback] private void on_row_activated (uint position) { - playbin.select_track (position); - } - - [GtkCallback] private string visible_child_name (uint n_items) { - return n_items > 0 ? "not-empty" : "empty"; - } - - ~PlayQueue () { - debug ("destroying play queue widget"); - } -} diff --git a/src/ui/play_queue/song.rs b/src/ui/play_queue/song.rs index c5d1a0b..d5e259e 100644 --- a/src/ui/play_queue/song.rs +++ b/src/ui/play_queue/song.rs @@ -1,7 +1,7 @@ mod imp { use glib::{subclass::InitializingObject, WeakRef}; use gtk::{gdk, gio, glib, prelude::*, subclass::prelude::*}; - use std::cell::{RefCell, Cell}; + use std::cell::{Cell, RefCell}; #[derive(gtk::CompositeTemplate, glib::Properties, Default)] #[template(resource = "/eu/callcc/audrey/play_queue_song.ui")]