from typing import List, Any from .. import util from ..common import IconButton, IconToggleButton, SpinnerImage, SpinnerPicture from .manager import Manager from ...util import resolve_path from ..actions import run_action from gi.repository import Gdk, GdkPixbuf, GLib, GObject, Gtk, Pango, Handy def create_play_button(manager: Manager, large=True, **kwargs): button = IconButton( "media-playback-start-symbolic", "Play", relief=large, icon_size=Gtk.IconSize.LARGE_TOOLBAR, **kwargs, ) if large: button.get_style_context().add_class("play-button-large") button.set_action_name("app.play-pause") manager.bind_property("has-song", button, "sensitive") manager.bind_property("play-button-icon", button, "icon-name") manager.bind_property("play-button-tooltip", button, "tooltip-text") return button def create_repeat_button(manager: Manager, **kwargs): button = IconToggleButton("media-playlist-repeat", "Switch between repeat modes", **kwargs) button.set_action_name("app.repeat") manager.bind_property("repeat-button-icon", button, "icon-name") def on_active_change(*_): if manager.repeat_button_active != button.get_active(): # Don't run the action, just update visual state button.set_action_name(None) button.set_active(manager.repeat_button_active) button.set_action_name("app.repeat") manager.connect("notify::repeat-button-active", on_active_change) return button def create_shuffle_button(manager: Manager, **kwargs): button = IconToggleButton("media-playlist-shuffle-symbolic", "Toggle playlist shuffling", **kwargs) button.set_action_name("app.shuffle") def on_active_change(*_): if manager.shuffle_button_active != button.get_active(): # Don't run the action, just update visual state button.set_action_name(None) button.set_active(manager.shuffle_button_active) button.set_action_name("app.shuffle") manager.connect("notify::shuffle-button-active", on_active_change) return button def create_next_button(manager: Manager, **kwargs): button = IconButton( "media-skip-forward-symbolic", "Go to next song", icon_size=Gtk.IconSize.LARGE_TOOLBAR, **kwargs, ) button.set_action_name("app.next-track") manager.bind_property("has-song", button, "sensitive") return button def create_prev_button(manager: Manager, **kwargs): button = IconButton( "media-skip-backward-symbolic", "Go to previous song", icon_size=Gtk.IconSize.LARGE_TOOLBAR, **kwargs, ) button.set_action_name("app.prev-track") manager.bind_property("has-song", button, "sensitive") return button def create_label(manager: Manager, property: str, **kwargs): label = Gtk.Label(**kwargs) manager.bind_property(property, label, "label") return label def show_play_queue_popover(manager: Manager, relative_to, paths: List[str], pos_x: int, pos_y: int): song_ids = [manager.play_queue_store[p][-1] for p in paths] remove_text = ( "Remove " + util.pluralize("song", len(song_ids)) + " from queue" ) def on_download_state_change(song_id: str): # Refresh the entire window (no force) because the song could # be in a list anywhere in the window. manager.emit("refresh-window", {}, False) def on_remove_songs_click(_: Any): manager.emit("songs-removed", [p.get_indices()[0] for p in paths]) util.show_song_popover( song_ids, pos_x, pos_y, relative_to, manager.offline_mode, on_download_state_change=on_download_state_change, extra_menu_items=[ (Gtk.ModelButton(text=remove_text), on_remove_songs_click), ], ) # Album Art column. This function defines what image to use for the play queue # song icon. def filename_to_pixbuf(manager: Manager): def f2p( column: Any, cell: Gtk.CellRendererPixbuf, model: Gtk.ListStore, tree_iter: Gtk.TreeIter, flags: Any, ): cell.set_property("sensitive", model.get_value(tree_iter, 0)) filename = model.get_value(tree_iter, 1) playing = model.get_value(tree_iter, 3) pixbuf = manager.get_play_queue_cover_art(filename, playing) if not pixbuf: cell.set_property("icon_name", "") else: cell.set_property("pixbuf", pixbuf) return f2p def create_play_queue_list(manager: Manager): view = Gtk.TreeView( model=manager.play_queue_store, reorderable=True, headers_visible=False, ) view.get_style_context().add_class("background") renderer = Gtk.CellRendererPixbuf() renderer.set_fixed_size(55, 60) column = Gtk.TreeViewColumn("", renderer) column.set_cell_data_func(renderer, filename_to_pixbuf(manager)) column.set_resizable(True) view.append_column(column) renderer = Gtk.CellRendererText(markup=True, ellipsize=Pango.EllipsizeMode.END) column = Gtk.TreeViewColumn("", renderer, markup=2, sensitive=0) column.set_expand(True) view.append_column(column) renderer = Gtk.CellRendererPixbuf(icon_name="view-more-symbolic") renderer.set_fixed_size(45, 60) view_more_column = Gtk.TreeViewColumn("", renderer) view_more_column.set_resizable(True) view.append_column(view_more_column) renderer = Gtk.CellRendererPixbuf(icon_name="window-close-symbolic") renderer.set_fixed_size(45, 60) close_column = Gtk.TreeViewColumn("", renderer) close_column.set_resizable(True) view.append_column(close_column) def on_play_queue_button_press(tree: Any, event: Gdk.EventButton) -> bool: if event.button == 1: path, column, cell_x, cell_y = tree.get_path_at_pos(event.x, event.y) song_idx = path.get_indices()[0] tree_width = tree.get_allocation().width if column == close_column: # manager.emit("songs-removed", [song_idx]) pass elif column == view_more_column: area = tree.get_cell_area(path, view_more_column) x = area.x + area.width / 2 y = area.y + area.height / 2 show_play_queue_popover(manager, view, [path], x, y) else: run_action(view, 'app.play-song', song_idx, [], {"no_reshuffle": None}) return True return False view.connect("button-press-event", on_play_queue_button_press) return view