audrey/src/ui/play_queue.vala

170 lines
5 KiB
Vala
Raw Normal View History

2024-10-13 14:24:25 +00:00
[GtkTemplate (ui = "/eu/callcc/audrey/ui/play_queue.ui")]
public class Ui.PlayQueue : Adw.NavigationPage {
2024-10-16 09:43:11 +00:00
public PlayQueueSelection selection { get; default = new PlayQueueSelection (); }
2024-10-13 14:24:25 +00:00
2024-10-16 09:43:11 +00:00
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;
}
}
2024-10-13 14:24:25 +00:00
2024-10-16 09:43:11 +00:00
public bool can_clear_all { get; private set; }
[GtkCallback] private void on_clear () {
2024-10-16 09:43:11 +00:00
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) {
2024-10-16 10:15:00 +00:00
if (position < this.get_n_items ()) emit_signal = true;
2024-10-16 09:43:11 +00:00
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) {
2024-10-16 10:04:58 +00:00
if (this.model == null) return null;
2024-10-16 09:43:11 +00:00
return this.model.get_item (position);
}
Type get_item_type () {
return this.model.get_item_type ();
}
uint get_n_items () {
2024-10-16 10:04:58 +00:00
if (this.model == null) return 0;
2024-10-16 09:43:11 +00:00
return this.model.get_n_items ();
2024-10-12 12:28:05 +00:00
}
2024-10-10 09:53:52 +00:00
}