made popoveres persistent

This commit is contained in:
Martin Wagner 2021-03-24 17:35:05 +01:00
parent 3d82a8fc5a
commit 2b9475efe7

View File

@ -1417,21 +1417,12 @@ class FocusFrame(Gtk.Overlay):
self._widget.connect("focus-out-event", lambda *args: self._frame.hide())
class SongPopover(Gtk.Popover):
def __init__(self, uri, client, relative, x, y, offset=26):
def __init__(self, client):
super().__init__()
rect=Gdk.Rectangle()
rect.x=x
# Gtk places popovers in treeviews 26px above the given position for no obvious reasons, so I move them 26px
# This seems to be related to the width/height of the headers in treeviews
rect.y=y+offset
rect.width=1
rect.height=1
self.set_pointing_to(rect)
self.set_relative_to(relative)
# client calls
song=client.get_metadata(uri)
abs_path=client.get_absolute_path(uri)
# adding vars
self._client=client
self._rect=Gdk.Rectangle()
# popover css
style_context=self.get_style_context()
@ -1440,61 +1431,79 @@ class SongPopover(Gtk.Popover):
provider.load_from_data(css)
style_context.add_provider(provider, 600)
# open with button
# open-with button
open_button=Gtk.Button(image=Gtk.Image.new_from_icon_name("document-open-symbolic",Gtk.IconSize.BUTTON),tooltip_text=_("Open with…"))
style_context=open_button.get_style_context()
style_context.add_class("circular")
open_button_revealer=Gtk.Revealer() # needed for open_button tooltip
open_button_revealer.set_halign(Gtk.Align.END)
open_button_revealer.set_valign(Gtk.Align.END)
open_button_revealer.add(open_button)
# button revealer
self._open_button_revealer=Gtk.Revealer()
self._open_button_revealer.set_halign(Gtk.Align.END)
self._open_button_revealer.set_valign(Gtk.Align.END)
self._open_button_revealer.add(open_button)
# treeview
# (tag, display-value, tooltip)
store=Gtk.ListStore(str, str, str)
treeview=Gtk.TreeView(model=store, headers_visible=False, search_column=-1, tooltip_column=2)
treeview.set_can_focus(False)
treeview.get_selection().set_mode(Gtk.SelectionMode.NONE)
self._store=Gtk.ListStore(str, str, str)
self._treeview=Gtk.TreeView(model=self._store, headers_visible=False, search_column=-1, tooltip_column=2)
self._treeview.set_can_focus(False)
self._treeview.get_selection().set_mode(Gtk.SelectionMode.NONE)
# columns
renderer_text=Gtk.CellRendererText(width_chars=50, ellipsize=Pango.EllipsizeMode.MIDDLE, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0, weight=Pango.Weight.BOLD)
column_tag=Gtk.TreeViewColumn(_("MPD-Tag"), renderer_text_ralign, text=0)
column_tag.set_property("resizable", False)
treeview.append_column(column_tag)
self._treeview.append_column(column_tag)
column_value=Gtk.TreeViewColumn(_("Value"), renderer_text, text=1)
column_value.set_property("resizable", False)
treeview.append_column(column_value)
self._treeview.append_column(column_value)
# populate
song=ClientHelper.song_to_str_dict(song)
for tag, value in song.items():
tooltip=value.replace("&", "&")
if tag == "time":
store.append([tag+":", ClientHelper.seconds_to_display_time(int(value)), tooltip])
elif tag == "last-modified":
time=datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
store.append([tag+":", time.strftime("%a %d %B %Y, %H%M UTC"), tooltip])
else:
store.append([tag+":", value, tooltip])
# scroll
self._scroll=Gtk.ScrolledWindow(border_width=3)
self._scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self._scroll.set_propagate_natural_height(True)
self._scroll.add(self._treeview)
# connect
open_button.connect("clicked", self._on_open_button_clicked)
# packing
overlay=Gtk.Overlay()
scroll=Gtk.ScrolledWindow(border_width=3)
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
window=self.get_toplevel()
scroll.set_max_content_height(window.get_size()[1]//2)
scroll.set_propagate_natural_height(True)
scroll.add(treeview)
overlay.add(scroll)
overlay.add_overlay(open_button_revealer)
if abs_path is not None: # show open with button when song is on the same computer
self._gfile=Gio.File.new_for_path(abs_path)
open_button.connect("clicked", self._on_open_button_clicked)
open_button_revealer.set_reveal_child(True)
overlay.add(self._scroll)
overlay.add_overlay(self._open_button_revealer)
self.add(overlay)
overlay.show_all()
def open(self, uri, widget, x, y, offset=26):
self._rect.x=x
# Gtk places popovers in treeviews 26px above the given position for no obvious reasons, so I move them 26px
# This seems to be related to the width/height of the headers in treeviews
self._rect.y=y+offset
self.set_pointing_to(self._rect)
self.set_relative_to(widget)
window=self.get_toplevel()
self._scroll.set_max_content_height(window.get_size()[1]//2)
self._store.clear()
song=ClientHelper.song_to_str_dict(self._client.get_metadata(uri))
for tag, value in song.items():
tooltip=value.replace("&", "&")
if tag == "time":
self._store.append([tag+":", ClientHelper.seconds_to_display_time(int(value)), tooltip])
elif tag == "last-modified":
time=datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
self._store.append([tag+":", time.strftime("%a %d %B %Y, %H%M UTC"), tooltip])
else:
self._store.append([tag+":", value, tooltip])
abs_path=self._client.get_absolute_path(uri)
if abs_path is None: # show open with button when song is on the same computer
self._open_button_revealer.set_reveal_child(False)
else:
self._gfile=Gio.File.new_for_path(abs_path)
self._open_button_revealer.set_reveal_child(True)
self.popup()
self._treeview.columns_autosize()
def _on_open_button_clicked(self, *args):
self.popdown()
dialog=Gtk.AppChooserDialog(gfile=self._gfile, transient_for=self.get_toplevel())
@ -1510,7 +1519,7 @@ class SongsView(Gtk.TreeView):
super().__init__(model=store, search_column=-1)
self.columns_autosize()
# add vars
# adding vars
self._client=client
self._store=store
self._file_column_id=file_column_id
@ -1519,6 +1528,9 @@ class SongsView(Gtk.TreeView):
# selection
self._selection=self.get_selection()
# song popover
self._song_popover=SongPopover(self._client)
# connect
self.connect("row-activated", self._on_row_activated)
self.connect("button-press-event", self._on_button_press_event)
@ -1558,10 +1570,9 @@ class SongsView(Gtk.TreeView):
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_RELEASE:
uri=self._store[path][self._file_column_id]
if self.get_property("headers-visible"):
pop=SongPopover(uri, self._client, widget, int(event.x), int(event.y))
self._song_popover.open(uri, widget, int(event.x), int(event.y))
else:
pop=SongPopover(uri, self._client, widget, int(event.x), int(event.y), offset=0)
pop.popup()
self._song_popover.open(uri, widget, int(event.x), int(event.y), offset=0)
self._button_event=(None, None)
def _on_key_release_event(self, widget, event):
@ -1574,8 +1585,7 @@ class SongsView(Gtk.TreeView):
elif event.keyval == Gdk.keyval_from_name("Menu"):
path=self._store.get_path(treeiter)
cell=self.get_cell_area(path, None)
pop=SongPopover(self._store[path][self._file_column_id], self._client, widget, cell.x, cell.y)
pop.popup()
self._song_popover.open(self._store[path][self._file_column_id], widget, cell.x, cell.y)
class SongsWindow(Gtk.Box):
def __init__(self, client, store, file_column_id, focus_indicator=True):
@ -1647,23 +1657,56 @@ class SongsWindow(Gtk.Box):
self._client.files_to_playlist(self._songs_view.get_files(), "enqueue")
class AlbumPopover(Gtk.Popover):
def __init__(self, client, settings, album, album_artist, year, widget, x, y):
def __init__(self, client, settings):
super().__init__()
rect=Gdk.Rectangle()
rect.x=x
rect.y=y
rect.width=1
rect.height=1
self.set_pointing_to(rect)
self.set_relative_to(widget)
# adding vars
self._client=client
songs=self._client.find("album", album, "date", year, settings.get_artist_type(), album_artist)
self._settings=settings
self._rect=Gdk.Rectangle()
# store
# songs window
# (track, title (artist), duration, file)
store=Gtk.ListStore(str, str, str, str)
self._store=Gtk.ListStore(str, str, str, str)
songs_window=SongsWindow(self._client, self._store, 3, focus_indicator=False)
# scroll
self._scroll=songs_window.get_scroll()
self._scroll.set_propagate_natural_height(True)
self._scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
self._scroll.set_property("margin-start", 3)
self._scroll.set_property("margin-end", 3)
self._scroll.set_property("margin-top", 3)
# songs view
self._songs_view=songs_window.get_treeview()
self._songs_view.set_property("headers_visible", False)
# columns
renderer_text=Gtk.CellRendererText(width_chars=80, ellipsize=Pango.EllipsizeMode.END, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0)
column_track=Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0)
column_track.set_property("resizable", False)
self._songs_view.append_column(column_track)
column_title=Gtk.TreeViewColumn(_("Title"), renderer_text, markup=1)
column_title.set_property("resizable", False)
self._songs_view.append_column(column_title)
column_time=Gtk.TreeViewColumn(_("Length"), renderer_text_ralign, text=2)
column_time.set_property("resizable", False)
self._songs_view.append_column(column_time)
# packing
self.add(songs_window)
songs_window.show_all()
def open(self, album, album_artist, date, widget, x, y):
self._rect.x=x
self._rect.y=y
self.set_pointing_to(self._rect)
self.set_relative_to(widget)
self._scroll.set_max_content_height(4*widget.get_allocated_height()//7)
self._store.clear()
songs=self._client.find("album", album, "date", date, self._settings.get_artist_type(), album_artist)
for s in songs:
song=ClientHelper.song_to_list_dict(ClientHelper.pepare_song_for_display(s))
track=song["track"][0]
@ -1679,41 +1722,9 @@ class AlbumPopover(Gtk.Popover):
else:
title_artist="<b>{}</b> - {}".format(title, artist)
title_artist=title_artist.replace("&", "&amp;")
store.append([track, title_artist, song["human_duration"][0], song["file"][0]])
# songs window
songs_window=SongsWindow(self._client, store, 3, focus_indicator=False)
# scroll
scroll=songs_window.get_scroll()
scroll.set_max_content_height(4*widget.get_allocated_height()//7)
scroll.set_propagate_natural_height(True)
scroll.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
scroll.set_property("margin-start", 3)
scroll.set_property("margin-end", 3)
scroll.set_property("margin-top", 3)
# songs view
songs_view=songs_window.get_treeview()
songs_view.set_property("headers_visible", False)
# columns
renderer_text=Gtk.CellRendererText(width_chars=80, ellipsize=Pango.EllipsizeMode.END, ellipsize_set=True)
renderer_text_ralign=Gtk.CellRendererText(xalign=1.0)
column_track=Gtk.TreeViewColumn(_("No"), renderer_text_ralign, text=0)
column_track.set_property("resizable", False)
songs_view.append_column(column_track)
column_title=Gtk.TreeViewColumn(_("Title"), renderer_text, markup=1)
column_title.set_property("resizable", False)
column_title.set_property("expand", True)
songs_view.append_column(column_title)
column_time=Gtk.TreeViewColumn(_("Length"), renderer_text_ralign, text=2)
column_time.set_property("resizable", False)
songs_view.append_column(column_time)
# packing
self.add(songs_window)
songs_window.show_all()
self._store.append([track, title_artist, song["human_duration"][0], song["file"][0]])
self.popup()
self._songs_view.columns_autosize()
class Cover(object):
def __init__(self, settings, raw_song):
@ -2145,6 +2156,9 @@ class AlbumWindow(FocusFrame):
# progress bar
self._progress_bar=Gtk.ProgressBar(no_show_all=True)
# album popover
self._album_popover=AlbumPopover(self._client, self._settings)
# connect
self._iconview.connect("item-activated", self._on_item_activated)
self._iconview.connect("button-press-event", self._on_button_press_event)
@ -2330,8 +2344,7 @@ class AlbumWindow(FocusFrame):
artist=self._store[path][6]
v=self._scroll_vadj.get_value()
h=self._scroll_hadj.get_value()
self._popover=AlbumPopover(self._client, self._settings, album, artist, year, widget, event.x-h, event.y-v)
self._popover.popup()
self._album_popover.open(album, artist, year, widget, event.x-h, event.y-v)
self._button_event=(None, None)
def _on_key_release_event(self, widget, event):
@ -2348,8 +2361,7 @@ class AlbumWindow(FocusFrame):
rect=widget.get_cell_rect(paths[0], None)[1]
x=rect.x+rect.width//2
y=rect.y+rect.height//2
self._popover=AlbumPopover(self._client, self._settings, album, artist, year, widget, x, y)
self._popover.popup()
self._album_popover.open(album, artist, year, widget, x, y)
def _on_item_activated(self, widget, path):
treeiter=self._store.get_iter(path)
@ -2360,9 +2372,7 @@ class AlbumWindow(FocusFrame):
def _on_disconnected(self, *args):
self._iconview.set_sensitive(False)
if self._popover is not None:
self._popover.destroy()
self._popover=None
self._album_popover.popdown()
def _on_reconnected(self, *args):
self._iconview.set_sensitive(True)
@ -2659,7 +2669,9 @@ class CoverEventBox(Gtk.EventBox):
# adding vars
self._client=client
self._settings=settings
self._popover=None
# album popover
self._album_popover=AlbumPopover(self._client, self._settings)
# connect
self._button_press_event=self.connect("button-press-event", self._on_button_press_event)
@ -2685,15 +2697,10 @@ class CoverEventBox(Gtk.EventBox):
elif event.button == 2 and event.type == Gdk.EventType.BUTTON_PRESS:
self._client.album_to_playlist(album, artist, album_year, "append")
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS:
self._popover=AlbumPopover(
self._client, self._settings, album, artist, album_year, widget, event.x, event.y
)
self._popover.popup()
self._album_popover.open(album, artist, album_year, widget, event.x, event.y)
def _on_disconnected(self, *args):
if self._popover is not None:
self._popover.destroy()
self._popover=None
self._album_popover.popdown()
class MainCover(Gtk.Frame):
def __init__(self, client, settings):
@ -2753,7 +2760,6 @@ class PlaylistWindow(Gtk.Box):
self._icon_size=self._settings.get_int("icon-size-sec")
self._inserted_path=None # needed for drag and drop
self._button_event=(None, None)
self._popover=None
# buttons
provider=Gtk.CssProvider()
@ -2832,6 +2838,9 @@ class PlaylistWindow(Gtk.Box):
action_bar.pack_end(self._clear_button)
action_bar.pack_end(audio)
# song popover
self._song_popover=SongPopover(self._client)
# connect
self._treeview.connect("row-activated", self._on_row_activated)
self._treeview.connect("button-press-event", self._on_button_press_event)
@ -2922,8 +2931,7 @@ class PlaylistWindow(Gtk.Box):
if event.button == 2 and event.type == Gdk.EventType.BUTTON_RELEASE:
self._store.remove(self._store.get_iter(path))
elif event.button == 3 and event.type == Gdk.EventType.BUTTON_RELEASE:
self._popover=SongPopover(self._store[path][8], self._client, widget, int(event.x), int(event.y))
self._popover.popup()
self._song_popover.open(self._store[path][8], widget, int(event.x), int(event.y))
self._button_event=(None, None)
def _on_key_release_event(self, widget, event):
@ -2939,8 +2947,7 @@ class PlaylistWindow(Gtk.Box):
if treeiter is not None:
path=self._store.get_path(treeiter)
cell=self._treeview.get_cell_area(path, None)
self._popover=SongPopover(self._store[path][8], self._client, widget, int(cell.x), int(cell.y))
self._popover.popup()
self._song_popover.open(self._store[path][8], widget, int(cell.x), int(cell.y))
def _on_row_deleted(self, model, path): # sync treeview to mpd
try:
@ -3031,9 +3038,7 @@ class PlaylistWindow(Gtk.Box):
self._treeview.set_sensitive(False)
self._back_to_current_song_button.set_sensitive(False)
self._clear_button.set_sensitive(False)
if self._popover is not None:
self._popover.destroy()
self._popover=None
self._song_popover.popdown()
self._clear()
def _on_reconnected(self, *args):