mirror of
https://github.com/Rafostar/clapper.git
synced 2025-08-29 23:32:04 +02:00
Some titles might be more than few words and will not fit in current playlist popover. Instead of stretching it, show full playlist item filename (or path) on hover in a tooltip.
230 lines
5.6 KiB
JavaScript
230 lines
5.6 KiB
JavaScript
const { Gdk, GLib, GObject, Gst, Gtk, Pango } = imports.gi;
|
|
|
|
var PlaylistWidget = GObject.registerClass(
|
|
class ClapperPlaylistWidget extends Gtk.ListBox
|
|
{
|
|
_init()
|
|
{
|
|
super._init({
|
|
selection_mode: Gtk.SelectionMode.NONE,
|
|
});
|
|
this.activeRowId = -1;
|
|
this.connect('row-activated', this._onRowActivated.bind(this));
|
|
}
|
|
|
|
addItem(uri)
|
|
{
|
|
const item = new PlaylistItem(uri);
|
|
this.append(item);
|
|
}
|
|
|
|
removeItem(item)
|
|
{
|
|
const itemIndex = item.get_index();
|
|
|
|
if(itemIndex === this.activeRowId) {
|
|
const root = this.get_root();
|
|
root.emit('close-request');
|
|
|
|
return;
|
|
}
|
|
|
|
if(itemIndex < this.activeRowId)
|
|
this.activeRowId--;
|
|
|
|
this.remove(item);
|
|
}
|
|
|
|
removeAll()
|
|
{
|
|
let oldItem;
|
|
while((oldItem = this.get_row_at_index(0)))
|
|
this.remove(oldItem);
|
|
|
|
this.activeRowId = -1;
|
|
}
|
|
|
|
nextTrack()
|
|
{
|
|
const nextRow = this.get_row_at_index(this.activeRowId + 1);
|
|
if(!nextRow)
|
|
return false;
|
|
|
|
nextRow.activate();
|
|
|
|
return true;
|
|
}
|
|
|
|
getActiveRow()
|
|
{
|
|
return this.get_row_at_index(this.activeRowId);
|
|
}
|
|
|
|
getActiveFilename()
|
|
{
|
|
const row = this.getActiveRow();
|
|
if(!row) return null;
|
|
|
|
return row.filename;
|
|
}
|
|
|
|
deactivateActiveItem()
|
|
{
|
|
if(this.activeRowId < 0)
|
|
return;
|
|
|
|
const row = this.getActiveRow();
|
|
if(!row) return null;
|
|
|
|
const icon = row.child.get_first_child();
|
|
const button = row.child.get_last_child();
|
|
|
|
icon.icon_name = 'open-menu-symbolic';
|
|
button.icon_name = 'list-remove-symbolic';
|
|
}
|
|
|
|
_onRowActivated(listBox, row)
|
|
{
|
|
const { player } = this.get_ancestor(Gtk.Grid);
|
|
const icon = row.child.get_first_child();
|
|
const button = row.child.get_last_child();
|
|
|
|
this.deactivateActiveItem();
|
|
icon.icon_name = 'media-playback-start-symbolic';
|
|
button.icon_name = 'window-close-symbolic';
|
|
|
|
this.activeRowId = row.get_index();
|
|
player.set_uri(row.uri);
|
|
}
|
|
});
|
|
|
|
let PlaylistItem = GObject.registerClass(
|
|
class ClapperPlaylistItem extends Gtk.ListBoxRow
|
|
{
|
|
_init(uri)
|
|
{
|
|
super._init({
|
|
/* TODO: Fix playlist navigation in fullscreen */
|
|
can_focus: false,
|
|
});
|
|
|
|
this.uri = uri;
|
|
this.isLocalFile = false;
|
|
|
|
let filename;
|
|
if(Gst.Uri.get_protocol(uri) === 'file') {
|
|
filename = GLib.path_get_basename(
|
|
GLib.filename_from_uri(uri)[0]
|
|
);
|
|
this.isLocalFile = true;
|
|
}
|
|
this.filename = filename || uri;
|
|
this.set_tooltip_text(this.filename);
|
|
|
|
const box = new Gtk.Box({
|
|
orientation: Gtk.Orientation.HORIZONTAL,
|
|
spacing: 6,
|
|
margin_start: 6,
|
|
margin_end: 6,
|
|
height_request: 22,
|
|
});
|
|
const icon = new Gtk.Image({
|
|
icon_name: 'open-menu-symbolic',
|
|
});
|
|
const label = new Gtk.Label({
|
|
label: this.filename,
|
|
single_line_mode: true,
|
|
ellipsize: Pango.EllipsizeMode.END,
|
|
width_chars: 5,
|
|
hexpand: true,
|
|
halign: Gtk.Align.START,
|
|
});
|
|
const button = new Gtk.Button({
|
|
icon_name: 'list-remove-symbolic',
|
|
});
|
|
button.add_css_class('flat');
|
|
button.add_css_class('circular');
|
|
button.add_css_class('popoverbutton');
|
|
button.connect('clicked', this._onRemoveClicked.bind(this));
|
|
|
|
box.append(icon);
|
|
box.append(label);
|
|
box.append(button);
|
|
this.set_child(box);
|
|
|
|
/* FIXME: D&D inside popover is broken in GTK4
|
|
const dragSource = new Gtk.DragSource({
|
|
actions: Gdk.DragAction.MOVE
|
|
});
|
|
dragSource.connect('prepare', this._onDragPrepare.bind(this));
|
|
dragSource.connect('drag-begin', this._onDragBegin.bind(this));
|
|
dragSource.connect('drag-end', this._onDragEnd.bind(this));
|
|
this.add_controller(dragSource);
|
|
|
|
const dropTarget = new Gtk.DropTarget({
|
|
actions: Gdk.DragAction.MOVE,
|
|
preload: true,
|
|
});
|
|
dropTarget.set_gtypes([PlaylistItem]);
|
|
dropTarget.connect('enter', this._onEnter.bind(this));
|
|
dropTarget.connect('drop', this._onDrop.bind(this));
|
|
this.add_controller(dropTarget);
|
|
*/
|
|
}
|
|
|
|
_onRemoveClicked(button)
|
|
{
|
|
const listBox = this.get_ancestor(Gtk.ListBox);
|
|
|
|
listBox.removeItem(this);
|
|
}
|
|
|
|
_onDragPrepare(source, x, y)
|
|
{
|
|
const widget = source.get_widget();
|
|
const paintable = new Gtk.WidgetPaintable({ widget });
|
|
const staticImg = paintable.get_current_image();
|
|
|
|
source.set_icon(staticImg, x, y);
|
|
|
|
return Gdk.ContentProvider.new_for_value(widget);
|
|
}
|
|
|
|
_onDragBegin(source, drag)
|
|
{
|
|
this.child.set_opacity(0.3);
|
|
}
|
|
|
|
_onDragEnd(source, drag, deleteData)
|
|
{
|
|
this.child.set_opacity(1.0);
|
|
}
|
|
|
|
_onEnter(target, x, y)
|
|
{
|
|
return (target.value)
|
|
? Gdk.DragAction.MOVE
|
|
: 0;
|
|
}
|
|
|
|
_onDrop(target, value, x, y)
|
|
{
|
|
const destIndex = this.get_index();
|
|
const targetIndex = value.get_index();
|
|
|
|
if(destIndex === targetIndex)
|
|
return true;
|
|
|
|
const listBox = this.get_ancestor(Gtk.ListBox);
|
|
|
|
if(listBox && destIndex >= 0) {
|
|
listBox.remove(value);
|
|
listBox.insert(value, destIndex);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
});
|