From 636774d787ea2d01e36475ff8326decb3c01db8e Mon Sep 17 00:00:00 2001 From: Erica Z Date: Wed, 16 Oct 2024 11:43:11 +0200 Subject: [PATCH] selection model bull shit --- src/meson.build | 1 - src/play_queue.vala | 136 ---------------------------------- src/ui/play_queue.blp | 2 +- src/ui/play_queue.vala | 164 +++++++++++++++++++++++++++++++++++++++-- src/ui/window.blp | 2 +- src/ui/window.vala | 16 ++-- 6 files changed, 169 insertions(+), 152 deletions(-) delete mode 100644 src/play_queue.vala diff --git a/src/meson.build b/src/meson.build index d986e5a..b6dd941 100644 --- a/src/meson.build +++ b/src/meson.build @@ -4,7 +4,6 @@ audrey_sources = [ 'globalconf.vala', 'main.vala', 'mpris.vala', - 'play_queue.vala', 'playbin.vala', 'ui/play_queue.vala', 'ui/setup.vala', diff --git a/src/play_queue.vala b/src/play_queue.vala deleted file mode 100644 index 0a8df44..0000000 --- a/src/play_queue.vala +++ /dev/null @@ -1,136 +0,0 @@ -// this is a custom SelectionModel that lets us only signal the -// selection has changed on user interaction -internal class Audrey.PlayQueue : GLib.Object, GLib.ListModel, Gtk.SelectionModel { - public GLib.ListStore inner { get; private set; } - // if current_position == inner.get_n_items (), play queue is stopped - public uint current_position { get; private set; } - - // emitted when a track is purposefully selected - public signal void user_selected (uint position); - - public PlayQueue () { - this.inner = new GLib.ListStore (typeof (Song)); - this.current_position = this.inner.get_n_items (); - - this.inner.items_changed.connect (this.on_inner_items_changed); - } - - // only called by playbin - // does not emit user_selected - internal void playbin_select (uint new_position) { - var previous_position = this.current_position; - this.current_position = new_position; - - if (previous_position < this.inner.get_n_items ()) { - if (new_position < this.inner.get_n_items ()) { - if (previous_position < new_position) { - this.selection_changed (previous_position, new_position-previous_position+1); - } else { - this.selection_changed (new_position, previous_position-new_position+1); - } - } else { - this.selection_changed (previous_position, 1); - } - } else { - if (new_position < this.inner.get_n_items ()) { - this.selection_changed (new_position, 1); - } - } - } - - // called by anything else that wishes to switch tracks - // emits user_selected - public void user_select (uint position) - requires (position < this.get_n_items ()) - { - this.user_selected (position); - } - - private void on_inner_items_changed (GLib.ListModel inner, uint position, uint removed, uint added) { - // FIXME: potentially try to see if the current item was reordered - // see what Gtk.SingleSelection does - - bool emit_signal = false; - - if (this.current_position >= position) { - if (this.current_position < position+removed && added == 0) { - emit_signal = true; - this.current_position = position; - } else { - this.current_position += added; - this.current_position -= removed; - } - } - - this.items_changed (position, removed, added); - if (emit_signal) this.selection_changed (position, 1); - // user_select doesnt need to be signalled, since the playqueue - // handles this on its own - } - - // Gtk.SelectionModel methods - - Gtk.Bitset get_selection_in_range (uint position, uint n_items) - requires (position+n_items <= this.inner.get_n_items ()) - { - var bitset = new Gtk.Bitset.empty (); - bitset.add (this.current_position); - return bitset; - } - - bool is_selected (uint position) - requires (position < this.inner.get_n_items ()) - { - return position == this.current_position; - } - - bool select_all () { - return false; - } - - bool select_item (uint position, bool unselect_rest) - requires (position < this.inner.get_n_items ()) - { - if (!unselect_rest) { - return false; - } - - this.user_select (position); - - return true; - } - - bool select_range (uint position, uint n_items, bool unselect_rest) { - return false; - } - - bool set_selection (Gtk.Bitset selected, Gtk.Bitset mask) { - return false; - } - - bool unselect_all () { - return false; - } - - bool unselect_item (uint position) { - return false; - } - - bool unselect_range (uint position, uint n_items) { - return false; - } - - // GLib.ListView methods - - Object? get_item (uint position) { - return this.inner.get_item (position); - } - - Type get_item_type () { - return this.inner.get_item_type (); - } - - uint get_n_items () { - return this.inner.get_n_items (); - } -} diff --git a/src/ui/play_queue.blp b/src/ui/play_queue.blp index 949aece..246eaec 100644 --- a/src/ui/play_queue.blp +++ b/src/ui/play_queue.blp @@ -18,7 +18,7 @@ template $UiPlayQueue: Adw.NavigationPage { ColumnView view { styles [ "data-table" ] - model: bind template.model; + model: bind template.selection; //ColumnViewColumn { // factory: SignalListItemFactory { diff --git a/src/ui/play_queue.vala b/src/ui/play_queue.vala index 77a54e4..3d0b09c 100644 --- a/src/ui/play_queue.vala +++ b/src/ui/play_queue.vala @@ -1,13 +1,167 @@ [GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")] public class Ui.PlayQueue : Adw.NavigationPage { - [GtkChild] private unowned Gtk.ColumnView view; - public Gtk.SelectionModel model { get; set; } + public PlayQueueSelection selection { get; default = new PlayQueueSelection (); } - public bool can_clear_all { get; private set; default = false; } + private GLib.ListStore _store; + public GLib.ListStore store { + get { return _store; } + set { + // can only be set once + assert (_store == null); + _store = value; + _store.items_changed.connect (this.on_store_items_changed); + this.can_clear_all = _store.get_n_items () > 0; + this.selection.model = _store; + } + } - public signal void clear (); + public bool can_clear_all { get; private set; } [GtkCallback] private void on_clear () { - this.clear (); + this.store.remove_all (); + } + + private void on_store_items_changed (GLib.ListModel store, uint position, uint removed, uint added) { + this.can_clear_all = store.get_n_items () > 0; + } +} + +// this is a custom SelectionModel that lets us only signal the +// selection has changed on user interaction +public class PlayQueueSelection : GLib.Object, GLib.ListModel, Gtk.SelectionModel { + private GLib.ListModel _model; + public GLib.ListModel model { + get { return _model; } + set { + // can only be set once + assert (_model == null); + _model = value; + _model.items_changed.connect (this.on_model_items_changed); + } + } + + // if current_position == model.get_n_items (), play queue is stopped + public uint current_position { get; private set; } + + // emitted when a track is purposefully selected + public signal void user_selected (uint position); + + // only called by playbin + // does not emit user_selected + internal void playbin_select (uint new_position) { + var previous_position = this.current_position; + this.current_position = new_position; + + if (previous_position < this.get_n_items ()) { + if (new_position < this.get_n_items ()) { + if (previous_position < new_position) { + this.selection_changed (previous_position, new_position-previous_position+1); + } else { + this.selection_changed (new_position, previous_position-new_position+1); + } + } else { + this.selection_changed (previous_position, 1); + } + } else { + if (new_position < this.get_n_items ()) { + this.selection_changed (new_position, 1); + } + } + } + + // called by anything else that wishes to switch tracks + // emits user_selected + public void user_select (uint position) + requires (position < this.get_n_items ()) + { + this.user_selected (position); + } + + private void on_model_items_changed (GLib.ListModel model, uint position, uint removed, uint added) { + // FIXME: potentially try to see if the current item was reordered + // see what Gtk.SingleSelection does + + bool emit_signal = false; + + if (this.current_position >= position) { + if (this.current_position < position+removed && added == 0) { + emit_signal = true; + this.current_position = position; + } else { + this.current_position += added; + this.current_position -= removed; + } + } + + this.items_changed (position, removed, added); + if (emit_signal) this.selection_changed (position, 1); + // user_select doesnt need to be signalled, since the playqueue + // handles this on its own + } + + // Gtk.SelectionModel methods + + Gtk.Bitset get_selection_in_range (uint position, uint n_items) + requires (position+n_items <= this.get_n_items ()) + { + var bitset = new Gtk.Bitset.empty (); + bitset.add (this.current_position); + return bitset; + } + + bool is_selected (uint position) + requires (position < this.get_n_items ()) + { + return position == this.current_position; + } + + bool select_all () { + return false; + } + + bool select_item (uint position, bool unselect_rest) + requires (position < this.get_n_items ()) + { + if (!unselect_rest) { + return false; + } + + this.user_select (position); + + return true; + } + + bool select_range (uint position, uint n_items, bool unselect_rest) { + return false; + } + + bool set_selection (Gtk.Bitset selected, Gtk.Bitset mask) { + return false; + } + + bool unselect_all () { + return false; + } + + bool unselect_item (uint position) { + return false; + } + + bool unselect_range (uint position, uint n_items) { + return false; + } + + // GLib.ListModel methods + + Object? get_item (uint position) { + return this.model.get_item (position); + } + + Type get_item_type () { + return this.model.get_item_type (); + } + + uint get_n_items () { + return this.model.get_n_items (); } } diff --git a/src/ui/window.blp b/src/ui/window.blp index 034e3d2..06b3bfb 100644 --- a/src/ui/window.blp +++ b/src/ui/window.blp @@ -82,7 +82,7 @@ template $UiWindow: Adw.ApplicationWindow { title: _("Play queue"); child: $UiPlayQueue play_queue { - model: bind template.play_queue_model; + store: bind template.play_queue_store; }; } } diff --git a/src/ui/window.vala b/src/ui/window.vala index 70f23c4..d44e824 100644 --- a/src/ui/window.vala +++ b/src/ui/window.vala @@ -28,7 +28,7 @@ class Ui.Window : Adw.ApplicationWindow { public Gdk.Paintable playing_cover_art { get; set; } public Playbin playbin { get; private set; default = new Playbin (); } - public Audrey.PlayQueue play_queue_model { get; private set; default = new Audrey.PlayQueue (); } + public ListStore play_queue_store { get; private set; default = new ListStore (typeof (Song)); } public Window (Gtk.Application app) { Object (application: app); @@ -54,7 +54,7 @@ class Ui.Window : Adw.ApplicationWindow { () => {}, () => { error ("could not acquire dbus name"); }); - this.playbin.play_queue = this.play_queue_model; + this.playbin.play_queue = this.play_queue_store; this.setup = new Setup (); @@ -65,10 +65,10 @@ class Ui.Window : Adw.ApplicationWindow { this.song = song; this.duration = duration; api.scrobble.begin (song.id); - this.play_queue_model.playbin_select (position); + this.play_queue.selection.playbin_select (position); }); - this.play_queue_model.user_selected.connect ((position) => { + this.play_queue.selection.user_selected.connect ((position) => { this.playbin.select_track (position); }); @@ -77,9 +77,9 @@ class Ui.Window : Adw.ApplicationWindow { this.shuffle_all_tracks.sensitive = true; this.shuffle_all_tracks.activated.connect (() => { this.shuffle_all_tracks.sensitive = false; - this.play_queue_model.inner.remove_all (); + this.play_queue_store.remove_all (); api.get_random_songs.begin (null, (song) => { - this.play_queue_model.inner.append (song); + this.play_queue_store.append (song); }, (obj, res) => { try { api.get_random_songs.end (res); @@ -88,7 +88,7 @@ class Ui.Window : Adw.ApplicationWindow { } this.shuffle_all_tracks.sensitive = true; - this.play_queue_model.select_item (0, true); + this.playbin.select_track (0); }); }); }); @@ -196,7 +196,7 @@ class Ui.Window : Adw.ApplicationWindow { [GtkCallback] private void on_skip_backward_clicked () { if (this.playbin.current_position > 0) { - this.play_queue_model.user_select (this.playbin.current_position-1); + this.playbin.select_track (this.playbin.current_position-1); } }