def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.Grid.__init__(self) self.__object = object self.__button = button # Check portal for tag editor dbus_helper = DBusHelper() dbus_helper.call("CanLaunchTagEditor", None, self.__on_can_launch_tag_editor, None) self.__edit = HoverWidget("document-properties-symbolic", self.__edit_tags) self.__edit.set_tooltip_text(_("Modify information")) self.__edit.set_margin_end(10) self.add(self.__edit) playlist = HoverWidget("view-list-symbolic", self.__show_playlist_manager) playlist.set_tooltip_text(_("Add to playlist")) playlist.show() self.add(playlist) if isinstance(self.__object, Album): if Lp().player.album_in_queue(self.__object): queue = HoverWidget("list-remove-symbolic", self.__add_to_queue) queue.set_tooltip_text(_("Remove from queue")) else: queue = HoverWidget("list-add-symbolic", self.__add_to_queue) queue.set_tooltip_text(_("Add to queue")) queue.set_margin_start(10) queue.show() self.add(queue) else: rating = RatingWidget(object) rating.set_margin_top(5) rating.set_margin_end(10) rating.set_margin_bottom(5) rating.set_property("halign", Gtk.Align.END) rating.set_property("hexpand", True) rating.show() loved = LovedWidget(object) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.show() self.add(rating) self.add(loved)
def __init__(self, track, menu): """ Init widget @param track as Track @param menu as Gio.Menu """ Popover.__init__(self) if menu is not None: self.bind_model(menu, None) if track.year is not None: year_label = Gtk.Label() year_label.set_text(str(track.year)) dt = GLib.DateTime.new_from_unix_local(track.timestamp) year_label.set_tooltip_text(dt.format(_("%Y-%m-%d"))) year_label.set_margin_end(5) year_label.get_style_context().add_class("dim-label") year_label.set_property("halign", Gtk.Align.END) year_label.set_property("hexpand", True) year_label.show() # Hack to add two widgets in popover grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, "main") stack.show_all() menu_widget = self.get_child() if menu_widget is not None: self.remove(menu_widget) grid.add(menu_widget) hgrid = Gtk.Grid() hgrid.get_style_context().add_class("popover-rating-loved-grid") rating = RatingWidget(track) rating.set_property("halign", Gtk.Align.START) rating.set_margin_end(10) rating.show() loved = LovedWidget(track) loved.set_property("halign", Gtk.Align.START) loved.set_property("hexpand", True) loved.show() hgrid.add(rating) hgrid.add(loved) if track.year is not None: hgrid.add(year_label) hgrid.show() grid.add(hgrid) self.add(stack)
def __init__(self, track, menu): """ Init widget @param track as Track @param menu as Gio.Menu """ Gtk.Popover.__init__(self) if menu is not None: self.bind_model(menu, None) if track.year != track.album.year: track_year = str(track.year) else: track_year = "" rating = RatingWidget(track) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(track.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) if track_year == "": loved.set_property('halign', Gtk.Align.END) else: loved.set_property('halign', Gtk.Align.CENTER) loved.set_property('hexpand', True) loved.show() if track_year != "": year = Gtk.Label() year.set_text(track_year) year.set_margin_end(5) year.set_margin_top(5) year.set_margin_bottom(5) year.get_style_context().add_class('dim-label') year.set_property('halign', Gtk.Align.END) year.set_property('hexpand', True) year.show() if track.album.is_web: uri = Lp().tracks.get_uri(track.id) web = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name('web-browser-symbolic', Gtk.IconSize.MENU) web.set_image(icon) web.get_style_context().add_class('no-padding') web.set_margin_end(5) web.set_tooltip_text(uri) web.show_all() uri = "https://www.youtube.com/results?search_query=%s" %\ (track.artists[0] + " " + track.name,) search = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name('edit-find-symbolic', Gtk.IconSize.MENU) search.set_image(icon) search.get_style_context().add_class('no-padding') search.set_margin_end(5) search.set_tooltip_text(uri) search.show_all() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable) grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, 'main') stack.show_all() menu_widget = self.get_child() if menu_widget is not None: menu_widget.reparent(grid) if not track.album.is_web: separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) if track.album.is_web: hgrid.add(web) hgrid.add(search) if track_year != "": hgrid.add(year) hgrid.show() if track.album.is_web: grid.set_row_spacing(2) uri = Lp().tracks.get_uri(track.id) edit = Gtk.Entry() edit.set_margin_start(5) edit.set_margin_end(5) edit.set_margin_bottom(5) edit.set_tooltip_text(_("Video address")) edit.set_property('hexpand', True) edit.set_text(uri) edit.connect('changed', self.__on_edit_changed, track.id) edit.show() grid.add(edit) grid.add(hgrid) self.add(stack)
class AlbumBannerWidget(Gtk.Bin): """ Banner for album """ def __init__(self, album, view_type=ViewType.DEFAULT): """ Init cover widget @param album @param view_type as ViewType """ Gtk.Bin.__init__(self) self.__view_type = view_type self.__height = None self.__width = 0 self.__cloud_image = None self.__allocation_timeout_id = None self.__album = album self.set_property("valign", Gtk.Align.START) builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui") builder.connect_signals(self) self.__title_label = builder.get_object("name_label") self.__title_label.connect("query-tooltip", on_query_tooltip) self.__year_label = builder.get_object("year_label") self.__duration_label = builder.get_object("duration_label") self.__menu_button = builder.get_object("menu_button") self.__cover_widget = CoverWidget(album, view_type) self.__cover_widget.set_vexpand(True) self.__cover_widget.show() album_name = GLib.markup_escape_text(album.name) markup = "<b>%s</b>" % album_name if view_type & ViewType.ALBUM: artist_name = GLib.markup_escape_text(", ".join(album.artists)) if view_type & ViewType.SMALL: markup += "\n<span alpha='40000'>%s</span>" % artist_name else: markup += "\n<span size='x-small' alpha='40000'>%s</span>" %\ artist_name self.__title_label.set_markup(markup) if album.year is not None: self.__year_label.set_text(str(album.year)) else: self.__year_label.hide() year_eventbox = builder.get_object("year_eventbox") year_eventbox.connect("realize", on_realize) year_eventbox.connect("button-release-event", self.__on_year_button_release_event) duration = App().albums.get_duration(self.__album.id, self.__album.genre_ids) self.__duration_label.set_text(get_human_duration(duration)) self.__artwork = builder.get_object("artwork") self.__grid = builder.get_object("grid") self.__widget = builder.get_object("widget") if view_type & ViewType.ALBUM: self.__menu_button.get_style_context().add_class( "black-transparent") self.get_style_context().add_class("black") self.__artwork.get_style_context().add_class("black") self.connect("size-allocate", self.__on_size_allocate) self.connect("destroy", self.__on_destroy) self.__art_signal_id = App().art.connect( "album-artwork-changed", self.__on_album_artwork_changed) else: self.__grid.get_style_context().add_class("banner-frame") self.__grid.attach(self.__cover_widget, 0, 0, 1, 3) self.__rating_grid = builder.get_object("rating_grid") if album.mtime <= 0: self.__cloud_image = Gtk.Image.new() self.__cloud_image.show() self.__cloud_image.set_margin_start(MARGIN) self.__rating_grid.attach(self.__cloud_image, 1, 0, 1, 1) self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID) self.__rating_widget.set_property("halign", Gtk.Align.START) self.__rating_widget.set_property("valign", Gtk.Align.CENTER) self.__rating_widget.show() self.__rating_grid.attach(self.__rating_widget, 2, 0, 1, 1) self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID) self.__loved_widget.set_margin_start(10) self.__loved_widget.set_property("halign", Gtk.Align.START) self.__loved_widget.set_property("valign", Gtk.Align.CENTER) self.__loved_widget.show() self.__rating_grid.attach(self.__loved_widget, 3, 0, 1, 1) self.add(self.__widget) self.__cover_widget.set_margin_start(MARGIN) self.__year_label.set_margin_end(MARGIN) self.__duration_label.set_margin_start(MARGIN) self.__rating_grid.set_margin_end(MARGIN) self.set_view_type(view_type) def set_view_type(self, view_type): """ Update widget internals for view_type @param view_type as ViewType """ self.__view_type = view_type art_size = 0 if view_type & ViewType.SMALL: art_size = ArtSize.LARGE style = "menu-button" icon_size = Gtk.IconSize.BUTTON self.__title_label.get_style_context().add_class( "text-large") self.__year_label.get_style_context().add_class( "text-large") elif view_type & ViewType.MEDIUM: art_size = ArtSize.BANNER style = "menu-button-48" icon_size = Gtk.IconSize.LARGE_TOOLBAR self.__title_label.get_style_context().add_class( "text-x-large") self.__year_label.get_style_context().add_class( "text-large") else: art_size = ArtSize.BANNER style = "menu-button-48" icon_size = Gtk.IconSize.LARGE_TOOLBAR self.__title_label.get_style_context().add_class( "text-xx-large") self.__year_label.get_style_context().add_class( "text-x-large") self.__rating_widget.set_icon_size(icon_size) self.__loved_widget.set_icon_size(icon_size) if self.__cloud_image is not None: self.__cloud_image.set_from_icon_name("goa-panel-symbolic", icon_size) self.__cover_widget.set_artwork(art_size) menu_button_style_context = self.__menu_button.get_style_context() menu_button_style_context.remove_class("menu-button-48") menu_button_style_context.remove_class("menu-button") menu_button_style_context.add_class(style) self.__menu_button.get_image().set_from_icon_name( "view-more-symbolic", icon_size) self.set_height(self.height) def set_height(self, height): """ Set height @param height as int """ if height < self.default_height: self.__height = height # Make grid cover artwork # No idea why... self.__grid.set_size_request(-1, height + 1) self.__cover_widget.hide() self.__duration_label.hide() self.__rating_grid.hide() self.__year_label.set_vexpand(True) self.__set_text_height(True) else: self.__height = None # Make grid cover artwork # No idea why... self.__grid.set_size_request(-1, height + 1) self.__cover_widget.show() self.__duration_label.show() self.__rating_grid.show() self.__year_label.set_vexpand(False) self.__set_text_height(False) def do_get_preferred_width(self): """ Force preferred width """ return (0, 0) def do_get_preferred_height(self): """ Force preferred height """ return (self.height, self.height) def set_selected(self, selected): """ Mark widget as selected @param selected as bool """ if selected: self.__grid.set_state_flags(Gtk.StateFlags.SELECTED, True) else: self.__grid.set_state_flags(Gtk.StateFlags.NORMAL, True) @property def height(self): """ Get height @return int """ return self.__height if self.__height is not None\ else self.default_height @property def default_height(self): """ Get default height """ if self.__view_type & ViewType.SMALL: return ArtSize.LARGE + 40 elif self.__view_type & ViewType.MEDIUM: return ArtSize.BANNER + 40 else: return ArtSize.BANNER + 40 ####################### # PROTECTED # ####################### def _on_menu_button_clicked(self, button): """ Show album menu @param button as Gtk.Button """ from lollypop.menu_objects import AlbumMenu menu = AlbumMenu(self.__album, self.__view_type) popover = Gtk.Popover.new_from_model(button, menu) popover.popup() ####################### # PRIVATE # ####################### def __set_text_height(self, collapsed): """ Set text height @param collapsed as bool """ title_context = self.__title_label.get_style_context() year_context = self.__year_label.get_style_context() for c in title_context.list_classes(): title_context.remove_class(c) for c in year_context.list_classes(): title_context.remove_class(c) if self.__view_type & ViewType.SMALL: if not collapsed: self.__title_label.get_style_context().add_class("text-large") # Collapsed not implemented for MEDIUM elif self.__view_type & ViewType.MEDIUM: self.__title_label.get_style_context().add_class( "text-x-large") self.__year_label.get_style_context().add_class( "text-large") elif collapsed: self.__title_label.get_style_context().add_class( "text-x-large") self.__year_label.get_style_context().add_class( "text-large") else: self.__title_label.get_style_context().add_class( "text-xx-large") self.__year_label.get_style_context().add_class( "text-x-large") def __handle_size_allocate(self, allocation): """ Change box max/min children @param allocation as Gtk.Allocation """ self.__allocation_timeout_id = None if allocation.width == 1 or self.__width == allocation.width: return self.__width = allocation.width App().art_helper.set_album_artwork( self.__album, # +100 to prevent resize lag allocation.width + 100, self.default_height, self.__artwork.get_scale_factor(), ArtBehaviour.BLUR_HARD | ArtBehaviour.DARKER, self.__on_album_artwork) def __on_destroy(self, widget): """ Disconnect signal @param widget as Gtk.Widget """ if self.__art_signal_id is not None: App().art.disconnect(self.__art_signal_id) def __on_album_artwork_changed(self, art, album_id): """ Update cover for album_id @param art as Art @param album_id as int """ if album_id == self.__album.id: App().art_helper.set_album_artwork( self.__album, # +100 to prevent resize lag self.get_allocated_width() + 100, self.default_height, self.__artwork.get_scale_factor(), ArtBehaviour.BLUR_HARD | ArtBehaviour.DARKER, self.__on_album_artwork) def __on_album_artwork(self, surface): """ Set album artwork @param surface as str """ if surface is not None: self.__artwork.set_from_surface(surface) def __on_year_button_release_event(self, widget, event): """ Show year view @param widget as Gtk.Widget @param event as Gdk.event """ App().window.emit("can-go-back-changed", True) App().window.emit("show-can-go-back", True) App().window.container.show_view([Type.YEARS], [self.__album.year]) def __on_size_allocate(self, widget, allocation): """ Delayed handling @param widget as Gtk.Widget @param allocation as Gtk.Allocation """ if self.__allocation_timeout_id is not None: GLib.source_remove(self.__allocation_timeout_id) self.__allocation_timeout_id = GLib.idle_add( self.__handle_size_allocate, allocation)
def __init__(self, object_id, menu): """ Init widget @param object id as int @param menu as Gio.Menu """ Gtk.Popover.__init__(self) self.bind_model(menu, None) rating = RatingWidget(Track(object_id)) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(object_id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.set_property('halign', Gtk.Align.END) loved.set_property('hexpand', True) loved.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable) grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, 'main') stack.show_all() menu_widget = self.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) hgrid.show() grid.add(hgrid) self.add(stack)
def _on_infobox_clicked(self, eventbox, event): """ Pop albums from current artistleft click Show playlist menu on right @param eventbox as Gtk.EventBox @param event as Gdk.Event """ if Lp.player.current_track.id == Type.EXTERNALS: expopover = ExternalsPopover() expopover.set_relative_to(eventbox) expopover.populate() expopover.show() elif Lp.player.current_track.id is not None: if event.button == 1: if Lp.player.current_track.id == Type.RADIOS: if self._pop_tunein is None: self._pop_tunein = TuneinPopover() self._pop_tunein.populate() self._pop_tunein.set_relative_to(self._infobox) self._pop_tunein.show() else: if self._pop_infos is None: self._pop_infos = InfosPopover() self._pop_infos.set_relative_to(self._infobox) self._pop_infos.show() elif Lp.player.current_track.id >= 0: menu = PopToolbarMenu(Lp.player.current_track.id, None) popover = Gtk.Popover.new_from_model(eventbox, menu) rating = RatingWidget(Lp.player.current_track) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(Lp.player.current_track.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.set_property('halign', Gtk.Align.END) loved.set_property('hexpand', True) loved.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later # (GTK>3.16 available on Debian stable) stack = Gtk.Stack() grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack.add_named(grid, 'main') stack.show_all() menu_widget = popover.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) hgrid.show() grid.add(hgrid) popover.add(stack) popover.show() return True
class AlbumBannerWidget(BannerWidget, SignalsHelper): """ Banner for album """ @signals_map def __init__(self, album, storage_type, view_type): """ Init cover widget @param album @param storage_type as int @param view_type as ViewType """ BannerWidget.__init__(self, view_type) self.__album = album self.__storage_type = storage_type self.__widget = None return [ (App().window.container.widget, "notify::folded", "_on_container_folded"), (App().art, "album-artwork-changed", "_on_album_artwork_changed"), (App().player, "playback-added", "_on_playback_changed"), (App().player, "playback-updated", "_on_playback_changed"), (App().player, "playback-setted", "_on_playback_changed"), (App().player, "playback-removed", "_on_playback_changed") ] def populate(self): """ Populate the view """ if self.__widget is not None: return self.__widget = Gtk.Grid.new() self.__widget.set_margin_start(MARGIN) self.__widget.set_margin_end(MARGIN_MEDIUM) self.__widget.set_margin_top(MARGIN_SMALL) self.__widget.set_margin_bottom(MARGIN_SMALL) self.__widget.set_row_spacing(MARGIN_SMALL) self.__widget.set_column_spacing(MARGIN_MEDIUM) self.__top_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__middle_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__bottom_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__labels_box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) self.__top_box.set_vexpand(True) self.__middle_box.set_halign(Gtk.Align.END) self.__middle_box.set_valign(Gtk.Align.CENTER) self.__middle_box.set_hexpand(True) self.__bottom_box.set_vexpand(True) self.__year_eventbox = Gtk.EventBox.new() self.__year_eventbox.set_hexpand(True) self.__year_eventbox.set_halign(Gtk.Align.END) self.__year_label = Gtk.Label.new() self.__year_label.get_style_context().add_class("dim-label") self.__year_eventbox.add(self.__year_label) self.__year_eventbox.connect("realize", set_cursor_type) self.__gesture_year = GesturesHelper( self.__year_eventbox, primary_press_callback=self._on_year_press) self.__play_button = Gtk.Button.new_from_icon_name( "media-playback-start-symbolic", Gtk.IconSize.BUTTON) self.__add_button = Gtk.Button.new_from_icon_name( "list-add-symbolic", Gtk.IconSize.BUTTON) self.__menu_button = Gtk.Button.new_from_icon_name( "view-more-symbolic", Gtk.IconSize.BUTTON) self.__play_button.connect("clicked", self.__on_play_button_clicked) self.__add_button.connect("clicked", self.__on_add_button_clicked) self.__menu_button.connect("clicked", self.__on_menu_button_clicked) self.__title_label = Gtk.Label.new() self.__title_label.set_valign(Gtk.Align.END) self.__title_label.set_vexpand(True) self.__title_label.connect("query-tooltip", on_query_tooltip) self.__title_label.set_ellipsize(Pango.EllipsizeMode.END) self.__title_label.set_halign(Gtk.Align.START) self.__title_label.set_xalign(0) self.__artist_label = Gtk.Label.new() self.__artist_eventbox = Gtk.EventBox.new() self.__artist_eventbox.set_valign(Gtk.Align.START) self.__artist_eventbox.add(self.__artist_label) self.__artist_eventbox.connect("realize", set_cursor_type) self.__artist_label.connect("query-tooltip", on_query_tooltip) self.__artist_label.set_ellipsize(Pango.EllipsizeMode.END) self.__artist_label.set_halign(Gtk.Align.START) self.__artist_label.set_xalign(0) self.__gesture_artist = GesturesHelper( self.__artist_eventbox, primary_press_callback=self._on_artist_press) self.__duration_label = Gtk.Label.new() self.__duration_label.get_style_context().add_class("dim-label") self.__top_box.pack_end(self.__year_eventbox, False, True, 0) self.__middle_box.add(self.__play_button) self.__middle_box.add(self.__add_button) self.__middle_box.add(self.__menu_button) self.__middle_box.get_style_context().add_class("linked") self.__bottom_box.pack_end(self.__duration_label, False, True, 0) self.__labels_box.add(self.__title_label) self.__labels_box.add(self.__artist_eventbox) self.__widget.attach(self.__top_box, 2, 0, 1, 1) self.__widget.attach(self.__middle_box, 2, 1, 1, 1) self.__widget.attach(self.__bottom_box, 1, 2, 2, 1) self.__widget.attach(self.__labels_box, 1, 0, 1, 2) self.__widget.show_all() if self.view_type & ViewType.OVERLAY: style = "banner-button" else: style = "menu-button" self.__play_button.get_style_context().add_class(style) self.__add_button.get_style_context().add_class(style) self.__menu_button.get_style_context().add_class(style) self.__title_label.set_label(self.__album.name) if self.view_type & ViewType.ALBUM: self.__cover_widget = EditCoverWidget(self.__album, self.view_type) self.__artist_label.get_style_context().add_class("dim-label") self.__artist_label.set_label(", ".join(self.__album.artists)) else: self.__artist_label.hide() self.__cover_widget = CoverWidget(self.__album, self.view_type) self.__cover_widget.set_margin_top(MARGIN_MEDIUM) self.__cover_widget.set_margin_bottom(MARGIN_MEDIUM) self.__cover_widget.connect("populated", self.__on_cover_populated) self.__cover_widget.show() if self.__album.year is not None: self.__year_label.set_label(str(self.__album.year)) self.__year_label.show() human_duration = get_human_duration(self.__album.duration) self.__duration_label.set_text(human_duration) self.__widget.attach(self.__cover_widget, 0, 0, 1, 3) self.__loved_widget = LovedWidget(self.__album, Gtk.IconSize.INVALID) self.__loved_widget.show() self.__bottom_box.pack_start(self.__loved_widget, 0, False, False) self.__rating_widget = RatingWidget(self.__album, Gtk.IconSize.INVALID) self.__rating_widget.show() self.__bottom_box.pack_start(self.__rating_widget, 0, True, True) if self.view_type & ViewType.OVERLAY: self._overlay.add_overlay(self.__widget) self._overlay.set_overlay_pass_through(self.__widget, True) else: self.add(self.__widget) self.__update_add_button() self.__set_internal_size() def update_for_width(self, width): """ Update banner internals for width, call this before showing banner @param width as int """ BannerWidget.update_for_width(self, width) self.__set_artwork() def set_selected(self, selected): """ Mark widget as selected @param selected as bool """ if selected: self.__widget.set_state_flags(Gtk.StateFlags.SELECTED, True) else: self.__widget.set_state_flags(Gtk.StateFlags.NORMAL, True) ####################### # PROTECTED # ####################### def _handle_width_allocate(self, allocation): """ Update artwork @param allocation as Gtk.Allocation """ if BannerWidget._handle_width_allocate(self, allocation): self.__set_artwork() def _on_container_folded(self, leaflet, folded): """ Handle libhandy folded status @param leaflet as Handy.Leaflet @param folded as Gparam """ self.__set_internal_size() def _on_album_artwork_changed(self, art, album_id): """ Update cover for album_id @param art as Art @param album_id as int """ if album_id == self.__album.id: self.__set_artwork() def _on_playback_changed(self, *ignore): """ Update add button """ self.__update_add_button() def _on_year_press(self, x, y, event): """ Show year view @param x as int @param y as int @param event as Gdk.EventButton """ App().window.container.show_view([Type.YEARS], [self.__album.year]) def _on_artist_press(self, x, y, event): """ Show artist view @param x as int @param y as int @param event as Gdk.EventButton """ App().window.container.show_view([Type.ARTISTS], self.__album.artist_ids) ####################### # PRIVATE # ####################### def __close_artwork_menu(self, action, variant): if App().window.folded: App().window.container.go_back() else: self.__artwork_popup.destroy() def __set_artwork(self): """ Set artwork on banner """ if self._artwork is not None and\ self.view_type & ViewType.ALBUM and\ App().animations: App().art_helper.set_album_artwork( self.__album, # +100 to prevent resize lag self.width + 100, self.height, self._artwork.get_scale_factor(), ArtBehaviour.BLUR_HARD | ArtBehaviour.DARKER, self._on_artwork) if self.width < ArtSize.BANNER * 3: if self.__widget.get_child_at(2, 0) == self.__top_box: self.__widget.remove(self.__labels_box) self.__widget.remove(self.__top_box) self.__widget.attach(self.__top_box, 1, 1, 1, 1) self.__widget.attach(self.__labels_box, 1, 0, 2, 1) elif self.__widget.get_child_at(1, 0) == self.__labels_box: self.__widget.remove(self.__labels_box) self.__widget.remove(self.__top_box) self.__widget.attach(self.__top_box, 2, 0, 1, 1) self.__widget.attach(self.__labels_box, 1, 0, 1, 2) def __update_add_button(self): """ Set image as +/- """ if self.__album.id in App().player.album_ids: self.__add_button.get_image().set_from_icon_name( "list-remove-symbolic", Gtk.IconSize.BUTTON) else: self.__add_button.get_image().set_from_icon_name( "list-add-symbolic", Gtk.IconSize.BUTTON) def __set_internal_size(self): """ Set content size based on available width """ classes = ["text-medium", "text-large", "text-x-large"] # Text size for label in [self.__title_label, self.__artist_label, self.__year_label, self.__duration_label]: context = label.get_style_context() for c in classes: context.remove_class(c) if App().window.folded: art_size = ArtSize.MEDIUM icon_size = Gtk.IconSize.BUTTON cls_title = "text-medium" cls_others = "text-medium" elif not self.view_type & ViewType.OVERLAY: art_size = ArtSize.BANNER icon_size = Gtk.IconSize.LARGE_TOOLBAR cls_title = "text-large" cls_others = "text-large" else: art_size = ArtSize.BANNER icon_size = Gtk.IconSize.LARGE_TOOLBAR cls_title = "text-x-large" cls_others = "text-large" self.__title_label.get_style_context().add_class(cls_title) self.__artist_label.get_style_context().add_class(cls_title) self.__year_label.get_style_context().add_class(cls_others) self.__duration_label.get_style_context().add_class(cls_others) self.__rating_widget.set_icon_size(icon_size) self.__loved_widget.set_icon_size(icon_size) self.__cover_widget.set_art_size(art_size) def __on_cover_populated(self, widget): """ Pass signal @param widget as Gtk.Widget """ emit_signal(self, "populated") def __on_menu_button_clicked(self, button): """ Show album menu @param button as Gtk.Button """ from lollypop.widgets_menu import MenuBuilder from lollypop.menu_objects import AlbumMenu from lollypop.menu_artwork import AlbumArtworkMenu menu = AlbumMenu(self.__album, self.__storage_type, self.view_type) menu_widget = MenuBuilder(menu) menu_widget.show() if App().window.folded: menu_ext = AlbumArtworkMenu(self.__album, self.view_type, True) menu_ext.connect("hidden", self.__close_artwork_menu) menu_ext.show() menu_widget.add_widget(menu_ext, -2) popup_widget(menu_widget, button, None, None, button) def __on_play_button_clicked(self, button): """ Play album @param button as Gtk.Button """ App().player.play_album(self.__album.clone(False)) def __on_add_button_clicked(self, button): """ Add/Remove album @param button as Gtk.Button """ if self.__album.id in App().player.album_ids: App().player.remove_album_by_id(self.__album.id) else: App().player.add_album(self.__album.clone(False))
def populate(self): """ Populate the view """ if self.__widget is not None: return self.__widget = Gtk.Grid.new() self.__widget.set_margin_start(MARGIN) self.__widget.set_margin_end(MARGIN_MEDIUM) self.__widget.set_margin_top(MARGIN_SMALL) self.__widget.set_margin_bottom(MARGIN_SMALL) self.__widget.set_row_spacing(MARGIN_SMALL) self.__widget.set_column_spacing(MARGIN_MEDIUM) self.__top_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__middle_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__bottom_box = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 0) self.__labels_box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) self.__top_box.set_vexpand(True) self.__middle_box.set_halign(Gtk.Align.END) self.__middle_box.set_valign(Gtk.Align.CENTER) self.__middle_box.set_hexpand(True) self.__bottom_box.set_vexpand(True) self.__year_eventbox = Gtk.EventBox.new() self.__year_eventbox.set_hexpand(True) self.__year_eventbox.set_halign(Gtk.Align.END) self.__year_label = Gtk.Label.new() self.__year_label.get_style_context().add_class("dim-label") self.__year_eventbox.add(self.__year_label) self.__year_eventbox.connect("realize", set_cursor_type) self.__gesture_year = GesturesHelper( self.__year_eventbox, primary_press_callback=self._on_year_press) self.__play_button = Gtk.Button.new_from_icon_name( "media-playback-start-symbolic", Gtk.IconSize.BUTTON) self.__add_button = Gtk.Button.new_from_icon_name( "list-add-symbolic", Gtk.IconSize.BUTTON) self.__menu_button = Gtk.Button.new_from_icon_name( "view-more-symbolic", Gtk.IconSize.BUTTON) self.__play_button.connect("clicked", self.__on_play_button_clicked) self.__add_button.connect("clicked", self.__on_add_button_clicked) self.__menu_button.connect("clicked", self.__on_menu_button_clicked) self.__title_label = Gtk.Label.new() self.__title_label.set_valign(Gtk.Align.END) self.__title_label.set_vexpand(True) self.__title_label.connect("query-tooltip", on_query_tooltip) self.__title_label.set_ellipsize(Pango.EllipsizeMode.END) self.__title_label.set_halign(Gtk.Align.START) self.__title_label.set_xalign(0) self.__artist_label = Gtk.Label.new() self.__artist_eventbox = Gtk.EventBox.new() self.__artist_eventbox.set_valign(Gtk.Align.START) self.__artist_eventbox.add(self.__artist_label) self.__artist_eventbox.connect("realize", set_cursor_type) self.__artist_label.connect("query-tooltip", on_query_tooltip) self.__artist_label.set_ellipsize(Pango.EllipsizeMode.END) self.__artist_label.set_halign(Gtk.Align.START) self.__artist_label.set_xalign(0) self.__gesture_artist = GesturesHelper( self.__artist_eventbox, primary_press_callback=self._on_artist_press) self.__duration_label = Gtk.Label.new() self.__duration_label.get_style_context().add_class("dim-label") self.__top_box.pack_end(self.__year_eventbox, False, True, 0) self.__middle_box.add(self.__play_button) self.__middle_box.add(self.__add_button) self.__middle_box.add(self.__menu_button) self.__middle_box.get_style_context().add_class("linked") self.__bottom_box.pack_end(self.__duration_label, False, True, 0) self.__labels_box.add(self.__title_label) self.__labels_box.add(self.__artist_eventbox) self.__widget.attach(self.__top_box, 2, 0, 1, 1) self.__widget.attach(self.__middle_box, 2, 1, 1, 1) self.__widget.attach(self.__bottom_box, 1, 2, 2, 1) self.__widget.attach(self.__labels_box, 1, 0, 1, 2) self.__widget.show_all() if self.view_type & ViewType.OVERLAY: style = "banner-button" else: style = "menu-button" self.__play_button.get_style_context().add_class(style) self.__add_button.get_style_context().add_class(style) self.__menu_button.get_style_context().add_class(style) self.__title_label.set_label(self.__album.name) if self.view_type & ViewType.ALBUM: self.__cover_widget = EditCoverWidget(self.__album, self.view_type) self.__artist_label.get_style_context().add_class("dim-label") self.__artist_label.set_label(", ".join(self.__album.artists)) else: self.__artist_label.hide() self.__cover_widget = CoverWidget(self.__album, self.view_type) self.__cover_widget.set_margin_top(MARGIN_MEDIUM) self.__cover_widget.set_margin_bottom(MARGIN_MEDIUM) self.__cover_widget.connect("populated", self.__on_cover_populated) self.__cover_widget.show() if self.__album.year is not None: self.__year_label.set_label(str(self.__album.year)) self.__year_label.show() human_duration = get_human_duration(self.__album.duration) self.__duration_label.set_text(human_duration) self.__widget.attach(self.__cover_widget, 0, 0, 1, 3) self.__loved_widget = LovedWidget(self.__album, Gtk.IconSize.INVALID) self.__loved_widget.show() self.__bottom_box.pack_start(self.__loved_widget, 0, False, False) self.__rating_widget = RatingWidget(self.__album, Gtk.IconSize.INVALID) self.__rating_widget.show() self.__bottom_box.pack_start(self.__rating_widget, 0, True, True) if self.view_type & ViewType.OVERLAY: self._overlay.add_overlay(self.__widget) self._overlay.set_overlay_pass_through(self.__widget, True) else: self.add(self.__widget) self.__update_add_button() self.__set_internal_size()
def __init__(self, track, menu): """ Init widget @param track as Track @param menu as Gio.Menu """ Gtk.Popover.__init__(self) if menu is not None: self.bind_model(menu, None) # FIXME Does it works? => year in popover if track.year != track.album.year: track_year = str(track.year) else: track_year = "" if track_year != "": year = Gtk.Label() year.set_text(track_year) year.set_margin_end(5) year.get_style_context().add_class("dim-label") year.set_property("halign", Gtk.Align.END) year.set_property("hexpand", True) year.show() # Hack to add two widgets in popover grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, "main") stack.show_all() menu_widget = self.get_child() if menu_widget is not None: self.remove(menu_widget) grid.add(menu_widget) hgrid = Gtk.Grid() hgrid.get_style_context().add_class("popover-rating-loved-grid") rating = RatingWidget(track) rating.set_property("halign", Gtk.Align.START) rating.set_property("hexpand", True) rating.show() loved = LovedWidget(track) loved.set_margin_end(5) if track_year == "": loved.set_property("halign", Gtk.Align.END) else: loved.set_property("halign", Gtk.Align.CENTER) loved.set_property("hexpand", True) loved.show() hgrid.add(rating) hgrid.add(loved) if track_year != "": hgrid.add(year) hgrid.show() grid.add(hgrid) self.add(stack)
def _popup_menu(self, widget, xcoordinate=None, ycoordinate=None): """ Popup menu for track @param widget as Gtk.Button @param xcoordinate as int (or None) @param ycoordinate as int (or None) """ menu = TrackMenu(self._object_id, None) popover = Gtk.Popover.new_from_model(widget, menu) if xcoordinate is not None and ycoordinate is not None: rect = widget.get_allocation() rect.x = xcoordinate rect.y = ycoordinate rect.width = rect.height = 1 popover.set_pointing_to(rect) rating = RatingWidget(self._object) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(self._object_id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.set_property('halign', Gtk.Align.END) loved.set_property('hexpand', True) loved.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable) grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, 'main') stack.show_all() menu_widget = popover.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) hgrid.show() grid.add(hgrid) popover.add(stack) popover.connect('closed', self._on_closed) self.get_style_context().add_class('track-menu-selected') popover.show()
def __init__(self, album, view_type=ViewType.DEFAULT): """ Init cover widget @param album @param view_type as ViewType """ Gtk.Bin.__init__(self) self.__view_type = view_type self.__height = None self.__width = 0 self.__cloud_image = None self.__allocation_timeout_id = None self.__album = album self.set_property("valign", Gtk.Align.START) builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui") builder.connect_signals(self) self.__title_label = builder.get_object("name_label") self.__title_label.connect("query-tooltip", on_query_tooltip) self.__year_label = builder.get_object("year_label") self.__duration_label = builder.get_object("duration_label") self.__menu_button = builder.get_object("menu_button") self.__cover_widget = CoverWidget(album, view_type) self.__cover_widget.set_vexpand(True) self.__cover_widget.show() album_name = GLib.markup_escape_text(album.name) markup = "<b>%s</b>" % album_name if view_type & ViewType.ALBUM: artist_name = GLib.markup_escape_text(", ".join(album.artists)) if view_type & ViewType.SMALL: markup += "\n<span alpha='40000'>%s</span>" % artist_name else: markup += "\n<span size='x-small' alpha='40000'>%s</span>" %\ artist_name self.__title_label.set_markup(markup) if album.year is not None: self.__year_label.set_text(str(album.year)) else: self.__year_label.hide() year_eventbox = builder.get_object("year_eventbox") year_eventbox.connect("realize", on_realize) year_eventbox.connect("button-release-event", self.__on_year_button_release_event) duration = App().albums.get_duration(self.__album.id, self.__album.genre_ids) self.__duration_label.set_text(get_human_duration(duration)) self.__artwork = builder.get_object("artwork") self.__grid = builder.get_object("grid") self.__widget = builder.get_object("widget") if view_type & ViewType.ALBUM: self.__menu_button.get_style_context().add_class( "black-transparent") self.get_style_context().add_class("black") self.__artwork.get_style_context().add_class("black") self.connect("size-allocate", self.__on_size_allocate) self.connect("destroy", self.__on_destroy) self.__art_signal_id = App().art.connect( "album-artwork-changed", self.__on_album_artwork_changed) else: self.__grid.get_style_context().add_class("banner-frame") self.__grid.attach(self.__cover_widget, 0, 0, 1, 3) self.__rating_grid = builder.get_object("rating_grid") if album.mtime <= 0: self.__cloud_image = Gtk.Image.new() self.__cloud_image.show() self.__cloud_image.set_margin_start(MARGIN) self.__rating_grid.attach(self.__cloud_image, 1, 0, 1, 1) self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID) self.__rating_widget.set_property("halign", Gtk.Align.START) self.__rating_widget.set_property("valign", Gtk.Align.CENTER) self.__rating_widget.show() self.__rating_grid.attach(self.__rating_widget, 2, 0, 1, 1) self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID) self.__loved_widget.set_margin_start(10) self.__loved_widget.set_property("halign", Gtk.Align.START) self.__loved_widget.set_property("valign", Gtk.Align.CENTER) self.__loved_widget.show() self.__rating_grid.attach(self.__loved_widget, 3, 0, 1, 1) self.add(self.__widget) self.__cover_widget.set_margin_start(MARGIN) self.__year_label.set_margin_end(MARGIN) self.__duration_label.set_margin_start(MARGIN) self.__rating_grid.set_margin_end(MARGIN) self.set_view_type(view_type)
def __init__(self, album_id, genre_ids, artist_ids, art_size): """ Init detailed album widget @param album id as int @param genre ids as [int] @param artist ids as [int] @param lazy as LazyLoadingView @param art size as ArtSize """ Gtk.Bin.__init__(self) AlbumWidget.__init__(self, album_id, genre_ids, artist_ids, art_size) self._album.set_artists(artist_ids) self.__width = None self.__context = None # Cover + rating + spacing self.__height = ArtSize.BIG + 26 self.__orientation = None self.__child_height = TrackRow.get_best_height(self) # Header + separator + spacing + margin self.__requested_height = self.__child_height + 6 # Discs to load, will be emptied self.__discs = self._album.discs self.__locked_widget_right = True self.set_property('height-request', self.__height) self.connect('size-allocate', self.__on_size_allocate) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/AlbumDetailedWidget.ui') builder.connect_signals(self) self._widget = builder.get_object('widget') album_info = builder.get_object('albuminfo') title_label = builder.get_object('title') title_label.set_property('has-tooltip', True) artist_label = builder.get_object('artist') artist_label.set_property('has-tooltip', True) year_label = builder.get_object('year') self.__header = builder.get_object('header') self.__overlay = builder.get_object('overlay') self.__duration_label = builder.get_object('duration') self.__context_button = builder.get_object('context') if art_size == ArtSize.NONE: self._cover = None rating = RatingWidget(self._album) rating.set_hexpand(True) rating.set_property('halign', Gtk.Align.END) rating.set_property('valign', Gtk.Align.CENTER) rating.show() self.__header.attach(rating, 4, 0, 1, 1) loved = LovedWidget(self._album) loved.set_property('halign', Gtk.Align.END) loved.set_property('valign', Gtk.Align.CENTER) loved.show() self.__header.attach(loved, 5, 0, 1, 1) artist_label.set_text(", ".join(self._album.artists)) artist_label.show() if self._album.year: year_label.set_label(self._album.year) year_label.show() else: self.__duration_label.set_hexpand(True) builder = Gtk.Builder() builder.add_from_resource('/org/gnome/Lollypop/CoverBox.ui') builder.connect_signals(self) self._play_button = builder.get_object('play-button') self._action_button = builder.get_object('action-button') self._action_event = builder.get_object('action-event') self._cover = builder.get_object('cover') self.__coverbox = builder.get_object('coverbox') # 6 for 2*3px (application.css) self.__coverbox.set_property('width-request', art_size + 6) if art_size == ArtSize.BIG: self._cover.get_style_context().add_class('cover-frame') self._artwork_button = builder.get_object('artwork-button') if self._album.year: year_label.set_label(self._album.year) year_label.show() grid = Gtk.Grid() grid.set_column_spacing(10) grid.set_property('halign', Gtk.Align.CENTER) grid.show() rating = RatingWidget(self._album) loved = LovedWidget(self._album) rating.show() loved.show() grid.add(rating) grid.add(loved) self.__coverbox.add(grid) self._widget.attach(self.__coverbox, 0, 0, 1, 1) if Lp().window.get_view_width() < WindowSize.MEDIUM: self.__coverbox.hide() if len(artist_ids) > 1: artist_label.set_text(", ".join(self._album.artists)) artist_label.show() elif art_size == ArtSize.HEADER: # Here we are working around default CoverBox ui # Do we really need to have another ui file? # So just hack values on the fly self._cover.set_halign(Gtk.Align.CENTER) self._cover.get_style_context().add_class('small-cover-frame') self.__coverbox.set_margin_bottom(5) # We want a smaller button, so reload image self._rounded_class = "rounded-icon-small" self._play_button.set_from_icon_name( "media-playback-start-symbolic", Gtk.IconSize.MENU) overlay_grid = builder.get_object('overlay-grid') overlay_grid.set_margin_bottom(2) overlay_grid.set_margin_end(2) overlay_grid.set_column_spacing(0) self._play_button.set_margin_start(2) self._play_button.set_margin_bottom(2) play_event = builder.get_object('play-event') play_event.set_property('halign', Gtk.Align.START) play_event.set_property('valign', Gtk.Align.END) album_info.attach(self.__coverbox, 0, 0, 1, 1) artist_label.set_text(", ".join(self._album.artists)) artist_label.show() self.__set_duration() self.__box = Gtk.Grid() self.__box.set_column_homogeneous(True) self.__box.set_property('valign', Gtk.Align.START) self.__box.show() album_info.add(self.__box) self._tracks_left = {} self._tracks_right = {} self.set_cover() self.update_state() title_label.set_label(self._album.name) for disc in self.__discs: self.__add_disc_container(disc.number) self.__set_disc_height(disc) self.add(self._widget) # We start transparent, we switch opaque at size allocation # This prevent artifacts self.set_opacity(0) if self._album.is_web and self._cover is not None: self._cover.get_style_context().add_class( 'cover-frame-web')
def __init__(self, track): """ Init widget @param track as Track """ Gtk.Grid.__init__(self) self.set_margin_top(MARGIN_SMALL) self.set_row_spacing(MARGIN_SMALL) self.set_orientation(Gtk.Orientation.VERTICAL) if track.year is not None: year_label = Gtk.Label.new() year_label.set_text(str(track.year)) dt = GLib.DateTime.new_from_unix_local(track.timestamp) year_label.set_tooltip_text(dt.format(_("%Y-%m-%d"))) year_label.set_margin_end(5) year_label.get_style_context().add_class("dim-label") year_label.set_property("halign", Gtk.Align.START) year_label.set_property("hexpand", True) year_label.show() hgrid = Gtk.Grid() rating = RatingWidget(track) rating.set_property("halign", Gtk.Align.START) if App().window.folded: rating.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR) rating.show() loved = LovedWidget(track) loved.set_property("halign", Gtk.Align.START) if App().window.folded: loved.set_icon_size(Gtk.IconSize.LARGE_TOOLBAR) loved.show() if track.year is not None: hgrid.add(year_label) hgrid.add(loved) hgrid.add(rating) hgrid.show() if not track.storage_type & StorageType.COLLECTION: try: escaped = GLib.uri_escape_string(track.uri, None, True) uri = load(open("%s/web_%s" % (CACHE_PATH, escaped), "rb")) except: uri = "" edit = Gtk.Entry() edit.set_placeholder_text(_("YouTube page address")) edit.set_margin_top(MARGIN_SMALL) edit.set_margin_start(MARGIN_SMALL) edit.set_margin_end(MARGIN_SMALL) edit.set_margin_bottom(MARGIN_SMALL) edit.set_property("hexpand", True) edit.set_text(uri) edit.connect("changed", self.__on_edit_changed, track) edit.show() self.add(edit) separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL) separator.show() self.add(separator) self.add(hgrid)
def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.EventBox.__init__(self) self.__object = object self.__button = button self.connect("button-release-event", self.__on_button_release_event) grid = Gtk.Grid() grid.show() if isinstance(object, Disc): play_button = Gtk.Button.new_from_icon_name( "media-playback-start-symbolic", Gtk.IconSize.BUTTON) play_button.connect("clicked", self.__on_play_button_clicked) play_button.get_style_context().add_class("dim-button") play_button.set_tooltip_text(_("Play")) play_button.set_margin_end(2) play_button.show() grid.add(play_button) else: edit_button = Gtk.Button.new_from_icon_name( "document-properties-symbolic", Gtk.IconSize.BUTTON) edit_button.connect("clicked", self.__on_edit_button_clicked) edit_button.get_style_context().add_class("dim-button") edit_button.set_tooltip_text(_("Modify information")) edit_button.set_margin_end(2) grid.add(edit_button) # Check portal for tag editor if App().art.tag_editor: edit_button.show() if isinstance(object, Track): add_to_queue = True string = _("Add to queue") icon = "zoom-in-symbolic" if App().player.track_in_queue(self.__object): add_to_queue = False string = _("Remove from queue") icon = "zoom-out-symbolic" queue_button = Gtk.Button.new_from_icon_name( icon, Gtk.IconSize.BUTTON) queue_button.connect("clicked", self.__on_queue_button_clicked, add_to_queue) queue_button.get_style_context().add_class("dim-button") queue_button.set_tooltip_text(string) queue_button.set_margin_end(2) queue_button.show() grid.add(queue_button) else: add = True string = _("Add to current playlist") icon = "list-add-symbolic" # Search album in player if isinstance(object, Disc): album = object.album else: album = object player_album_track_ids = [] for _album in App().player.albums: if album.id == _album.id: player_album_track_ids += _album.track_ids if len(set(player_album_track_ids) & set(object.track_ids)) == len( object.track_ids): add = False string = _("Remove from current playlist") icon = "list-remove-symbolic" current_playlist_button = Gtk.Button.new_from_icon_name( icon, Gtk.IconSize.BUTTON) current_playlist_button.connect( "clicked", self.__on_current_playlist_button_clicked, add) current_playlist_button.get_style_context().add_class("dim-button") current_playlist_button.set_tooltip_text(string) current_playlist_button.set_margin_end(2) current_playlist_button.show() grid.add(current_playlist_button) playlist_button = Gtk.Button.new_from_icon_name( "view-list-symbolic", Gtk.IconSize.BUTTON) playlist_button.connect("clicked", self.__on_playlist_button_clicked) playlist_button.get_style_context().add_class("dim-button") playlist_button.set_tooltip_text(_("Add to playlist")) playlist_button.show() grid.add(playlist_button) if isinstance(self.__object, Track): rating = RatingWidget(object) rating.set_margin_end(2) rating.set_property("halign", Gtk.Align.END) rating.set_property("hexpand", True) rating.show() loved = LovedWidget(object) loved.set_margin_end(2) loved.show() grid.add(rating) grid.add(loved) self.add(grid)
class AlbumBannerWidget(BannerWidget, SignalsHelper): """ Banner for album """ @signals_map def __init__(self, album, storage_type, view_type): """ Init cover widget @param album @param storage_type as int @param view_type as ViewType """ BannerWidget.__init__(self, view_type) self.__album = album self.__storage_type = storage_type builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui") builder.connect_signals(self) self.__labels = builder.get_object("labels") self.__title_label = builder.get_object("title_label") self.__title_label.connect("query-tooltip", on_query_tooltip) self.__artist_label = builder.get_object("artist_label") self.__artist_label.connect("query-tooltip", on_query_tooltip) self.__year_label = builder.get_object("year_label") self.__duration_label = builder.get_object("duration_label") self.__play_button = builder.get_object("play_button") self.__add_button = builder.get_object("add_button") self.__menu_button = builder.get_object("menu_button") self.__widget = builder.get_object("widget") if view_type & ViewType.OVERLAY: style = "banner-button" else: style = "menu-button" self.__play_button.get_style_context().add_class(style) self.__add_button.get_style_context().add_class(style) self.__menu_button.get_style_context().add_class(style) self.__cover_widget = CoverWidget(album, view_type) self.__cover_widget.show() self.__title_label.set_label(album.name) if view_type & ViewType.ALBUM: self.__artist_label.show() self.__artist_label.set_label(", ".join(album.artists)) else: self.__title_label.set_opacity(0.8) self.__year_label.set_opacity(0.7) self.__duration_label.set_opacity(0.6) self.__widget.get_style_context().add_class("album-banner") if album.year is not None: self.__year_label.set_label(str(album.year)) self.__year_label.show() human_duration = get_human_duration(album.duration) self.__duration_label.set_text(human_duration) artist_eventbox = builder.get_object("artist_eventbox") artist_eventbox.connect("realize", set_cursor_type) self.__gesture1 = GesturesHelper( artist_eventbox, primary_press_callback=self._on_artist_press) year_eventbox = builder.get_object("year_eventbox") year_eventbox.connect("realize", set_cursor_type) self.__gesture2 = GesturesHelper( year_eventbox, primary_press_callback=self._on_year_press) self.__widget.attach(self.__cover_widget, 0, 0, 1, 3) self.__bottom_box = builder.get_object("bottom_box") self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID) self.__loved_widget.show() self.__bottom_box.pack_start(self.__loved_widget, 0, False, False) self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID) self.__rating_widget.show() self.__bottom_box.pack_start(self.__rating_widget, 0, True, True) if view_type & ViewType.OVERLAY: self._overlay.add_overlay(self.__widget) self._overlay.set_overlay_pass_through(self.__widget, True) else: self.add(self.__widget) self.__update_add_button() self.__set_internal_size() return [(App().window.container.widget, "notify::folded", "_on_container_folded"), (App().art, "album-artwork-changed", "_on_album_artwork_changed"), (App().player, "playback-added", "_on_playback_changed"), (App().player, "playback-updated", "_on_playback_changed"), (App().player, "playback-removed", "_on_playback_changed")] def update_for_width(self, width): """ Update banner internals for width, call this before showing banner @param width as int """ BannerWidget.update_for_width(self, width) self.__set_artwork() def set_selected(self, selected): """ Mark widget as selected @param selected as bool """ if selected: self.__widget.set_state_flags(Gtk.StateFlags.SELECTED, True) else: self.__widget.set_state_flags(Gtk.StateFlags.NORMAL, True) ####################### # PROTECTED # ####################### def _handle_width_allocate(self, allocation): """ Update artwork @param allocation as Gtk.Allocation """ if BannerWidget._handle_width_allocate(self, allocation): self.__set_artwork() def _on_container_folded(self, leaflet, folded): """ Handle libhandy folded status @param leaflet as Handy.Leaflet @param folded as Gparam """ self.__set_internal_size() def _on_menu_button_clicked(self, button): """ Show album menu @param button as Gtk.Button """ from lollypop.widgets_menu import MenuBuilder from lollypop.menu_objects import AlbumMenu from lollypop.menu_artwork import AlbumArtworkMenu menu = AlbumMenu(self.__album, self.__storage_type, self.view_type) menu_widget = MenuBuilder(menu) menu_widget.show() if App().window.folded: menu_ext = AlbumArtworkMenu(self.__album, self.view_type, True) menu_ext.connect("hidden", self.__close_artwork_menu) menu_ext.show() menu_widget.add_widget(menu_ext, -2) popup_widget(menu_widget, button, None, None, button) def _on_play_button_clicked(self, button): """ Play album @param button as Gtk.Button """ App().player.play_album(self.__album.clone(False)) def _on_add_button_clicked(self, button): """ Add/Remove album @param button as Gtk.Button """ if self.__album.id in App().player.album_ids: App().player.remove_album_by_id(self.__album.id) else: App().player.add_album(self.__album.clone(False)) def _on_album_artwork_changed(self, art, album_id): """ Update cover for album_id @param art as Art @param album_id as int """ if album_id == self.__album.id: self.__set_artwork() def _on_playback_changed(self, *ignore): """ Update add button """ self.__update_add_button() def _on_year_press(self, x, y, event): """ Show year view @param x as int @param y as int @param event as Gdk.EventButton """ App().window.container.show_view([Type.YEARS], [self.__album.year]) def _on_artist_press(self, x, y, event): """ Show artist view @param x as int @param y as int @param event as Gdk.EventButton """ App().window.container.show_view([Type.ARTISTS], self.__album.artist_ids) ####################### # PRIVATE # ####################### def __close_artwork_menu(self, action, variant): if App().window.folded: App().window.container.go_back() else: self.__artwork_popup.destroy() def __set_artwork(self): """ Set artwork on banner """ if self._artwork is not None and\ self.view_type & ViewType.ALBUM and\ App().animations: App().art_helper.set_album_artwork( self.__album, # +100 to prevent resize lag self.width + 100, self.height, self._artwork.get_scale_factor(), ArtBehaviour.BLUR_HARD | ArtBehaviour.DARKER, self._on_artwork) if self.width < ArtSize.BANNER * 3: if self.__cover_widget.get_opacity() == 1: self.__cover_widget.set_opacity(0.1) self.__widget.remove(self.__labels) self.__widget.attach(self.__labels, 0, 0, 2, 2) elif self.__cover_widget.get_opacity() != 1: self.__cover_widget.set_opacity(1) self.__widget.remove(self.__labels) self.__widget.attach(self.__labels, 1, 0, 1, 2) def __update_add_button(self): """ Set image as +/- """ if self.__album.id in App().player.album_ids: self.__add_button.get_image().set_from_icon_name( "list-remove-symbolic", Gtk.IconSize.BUTTON) else: self.__add_button.get_image().set_from_icon_name( "list-add-symbolic", Gtk.IconSize.BUTTON) def __set_internal_size(self): """ Set content size based on available width """ # Text size for label in [ self.__title_label, self.__artist_label, self.__year_label, self.__duration_label ]: context = label.get_style_context() for c in context.list_classes(): context.remove_class(c) if App().window.folded: art_size = ArtSize.MEDIUM icon_size = Gtk.IconSize.BUTTON cls_title = "text-medium" cls_others = "text-medium" else: art_size = ArtSize.BANNER icon_size = Gtk.IconSize.LARGE_TOOLBAR cls_title = "text-x-large" cls_others = "text-large" self.__title_label.get_style_context().add_class(cls_title) self.__artist_label.get_style_context().add_class(cls_title) self.__year_label.get_style_context().add_class(cls_others) self.__duration_label.get_style_context().add_class(cls_others) self.__rating_widget.set_icon_size(icon_size) self.__loved_widget.set_icon_size(icon_size) self.__cover_widget.set_art_size(art_size)
def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.Grid.__init__(self) self.__object = object self.__button = button self.__tag_editor = None if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): save = HoverWidget('document-save-symbolic', self.__save_object) save.set_tooltip_text(_("Save into collection")) save.set_margin_end(10) save.show() else: trash = HoverWidget('user-trash-symbolic', self.__remove_object) if isinstance(self.__object, Album): trash.set_tooltip_text(_("Remove album")) else: trash.set_tooltip_text(_("Remove track")) trash.set_margin_end(10) trash.show() else: # Search for tag editor favorite = Lp().settings.get_value('tag-editor').get_string() for editor in [favorite] + TAG_EDITORS: if GLib.find_program_in_path(editor) is not None: self.__tag_editor = editor if self.__tag_editor is not None: edit = HoverWidget('document-properties-symbolic', self.__edit_tags) edit.set_tooltip_text(_("Modify information")) edit.set_margin_end(10) edit.show() playlist = HoverWidget('view-list-symbolic', self.__show_playlist_manager) playlist.set_tooltip_text(_("Playlists")) playlist.show() if isinstance(self.__object, Album): if Lp().player.album_in_queue(self.__object): queue = HoverWidget('list-remove-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Remove from queue")) else: queue = HoverWidget('list-add-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Add to queue")) queue.set_margin_start(10) queue.show() else: rating = RatingWidget(object) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.END) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(object.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.show() if self.__object.is_web: web = Gtk.LinkButton(self.__object.uri) icon = Gtk.Image.new_from_icon_name('web-browser-symbolic', Gtk.IconSize.MENU) web.set_image(icon) web.get_style_context().add_class('no-padding') web.set_margin_start(5) web.set_tooltip_text(self.__object.uri) web.show_all() uri = "https://www.youtube.com/results?search_query=%s" %\ (self.__object.artists[0] + " " + self.__object.name,) search = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name('edit-find-symbolic', Gtk.IconSize.MENU) search.set_image(icon) search.get_style_context().add_class('no-padding') search.set_tooltip_text(uri) search.show_all() if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): self.add(save) else: self.add(trash) elif self.__tag_editor is not None: self.add(edit) self.add(playlist) if isinstance(self.__object, Album): self.add(queue) else: if self.__object.album.is_web: self.add(web) self.add(search) self.add(rating) self.add(loved)
def __init__(self, album, storage_type, view_type): """ Init cover widget @param album @param storage_type as int @param view_type as ViewType """ BannerWidget.__init__(self, view_type) self.__album = album self.__storage_type = storage_type builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/AlbumBannerWidget.ui") builder.connect_signals(self) self.__labels = builder.get_object("labels") self.__title_label = builder.get_object("title_label") self.__title_label.connect("query-tooltip", on_query_tooltip) self.__artist_label = builder.get_object("artist_label") self.__artist_label.connect("query-tooltip", on_query_tooltip) self.__year_label = builder.get_object("year_label") self.__duration_label = builder.get_object("duration_label") self.__play_button = builder.get_object("play_button") self.__add_button = builder.get_object("add_button") self.__menu_button = builder.get_object("menu_button") self.__widget = builder.get_object("widget") if view_type & ViewType.OVERLAY: style = "banner-button" else: style = "menu-button" self.__play_button.get_style_context().add_class(style) self.__add_button.get_style_context().add_class(style) self.__menu_button.get_style_context().add_class(style) self.__cover_widget = CoverWidget(album, view_type) self.__cover_widget.show() self.__title_label.set_label(album.name) if view_type & ViewType.ALBUM: self.__artist_label.show() self.__artist_label.set_label(", ".join(album.artists)) else: self.__title_label.set_opacity(0.8) self.__year_label.set_opacity(0.7) self.__duration_label.set_opacity(0.6) self.__widget.get_style_context().add_class("album-banner") if album.year is not None: self.__year_label.set_label(str(album.year)) self.__year_label.show() human_duration = get_human_duration(album.duration) self.__duration_label.set_text(human_duration) artist_eventbox = builder.get_object("artist_eventbox") artist_eventbox.connect("realize", set_cursor_type) self.__gesture1 = GesturesHelper( artist_eventbox, primary_press_callback=self._on_artist_press) year_eventbox = builder.get_object("year_eventbox") year_eventbox.connect("realize", set_cursor_type) self.__gesture2 = GesturesHelper( year_eventbox, primary_press_callback=self._on_year_press) self.__widget.attach(self.__cover_widget, 0, 0, 1, 3) self.__bottom_box = builder.get_object("bottom_box") self.__loved_widget = LovedWidget(album, Gtk.IconSize.INVALID) self.__loved_widget.show() self.__bottom_box.pack_start(self.__loved_widget, 0, False, False) self.__rating_widget = RatingWidget(album, Gtk.IconSize.INVALID) self.__rating_widget.show() self.__bottom_box.pack_start(self.__rating_widget, 0, True, True) if view_type & ViewType.OVERLAY: self._overlay.add_overlay(self.__widget) self._overlay.set_overlay_pass_through(self.__widget, True) else: self.add(self.__widget) self.__update_add_button() self.__set_internal_size() return [(App().window.container.widget, "notify::folded", "_on_container_folded"), (App().art, "album-artwork-changed", "_on_album_artwork_changed"), (App().player, "playback-added", "_on_playback_changed"), (App().player, "playback-updated", "_on_playback_changed"), (App().player, "playback-removed", "_on_playback_changed")]
def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.Grid.__init__(self) self.__object = object self.__button = button if self.__object.is_web: if Type.CHARTS in self.__object.genre_ids: if isinstance(self.__object, Album): save = HoverWidget("document-save-symbolic", self.__save_object) save.set_tooltip_text(_("Save into collection")) save.set_margin_end(10) save.show() self.add(save) else: trash = HoverWidget("user-trash-symbolic", self.__remove_object) if isinstance(self.__object, Album): trash.set_tooltip_text(_("Remove album")) else: trash.set_tooltip_text(_("Remove track")) trash.set_margin_end(10) trash.show() self.add(trash) else: # Check portal for tag editor try: Gio.bus_get(Gio.BusType.SESSION, None, self.__on_get_bus, "CanLaunchTagEditor", None, self.__on_can_launch_tag_editor) except Exception as e: print("ContextWidget::__init__():", e) self.__edit = HoverWidget("document-properties-symbolic", self.__edit_tags) self.__edit.set_tooltip_text(_("Modify information")) self.__edit.set_margin_end(10) self.add(self.__edit) if Type.CHARTS not in self.__object.genre_ids: playlist = HoverWidget("view-list-symbolic", self.__show_playlist_manager) playlist.set_tooltip_text(_("Add to playlist")) playlist.show() self.add(playlist) if isinstance(self.__object, Album): if Lp().player.album_in_queue(self.__object): queue = HoverWidget("list-remove-symbolic", self.__add_to_queue) queue.set_tooltip_text(_("Remove from queue")) else: queue = HoverWidget("list-add-symbolic", self.__add_to_queue) queue.set_tooltip_text(_("Add to queue")) queue.set_margin_start(10) queue.show() self.add(queue) else: if self.__object.is_web: web = Gtk.LinkButton(self.__object.uri) icon = Gtk.Image.new_from_icon_name("web-browser-symbolic", Gtk.IconSize.MENU) web.set_image(icon) web.get_style_context().add_class("no-padding") web.set_margin_start(5) web.set_tooltip_text(self.__object.uri) web.show_all() uri = "https://www.youtube.com/results?search_query=%s" %\ (self.__object.artists[0] + " " + self.__object.name,) search = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name("edit-find-symbolic", Gtk.IconSize.MENU) search.set_image(icon) search.get_style_context().add_class("no-padding") search.set_tooltip_text(uri) search.show_all() self.add(web) self.add(search) if Type.CHARTS not in self.__object.genre_ids: rating = RatingWidget(object) rating.set_margin_top(5) rating.set_margin_end(10) rating.set_margin_bottom(5) rating.set_property("halign", Gtk.Align.END) rating.set_property("hexpand", True) rating.show() loved = LovedWidget(object) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.show() self.add(rating) self.add(loved)
def populate(self): """ Populate widget content """ if self._widget is None: OverlayAlbumHelper.__init__(self) self.__context = None grid = Gtk.Grid() grid.set_margin_start(5) grid.set_margin_end(5) grid.set_row_spacing(1) grid.set_vexpand(True) grid.show() self.__title_label = Gtk.Label() self.__title_label.set_margin_end(10) self.__title_label.set_ellipsize(Pango.EllipsizeMode.END) self.__title_label.get_style_context().add_class("dim-label") self.__title_label.set_property("has-tooltip", True) self.__title_label.connect("query-tooltip", self.__on_query_tooltip) self.__title_label.show() self.__artist_label = Gtk.Label() self.__artist_label.set_margin_end(10) self.__artist_label.set_ellipsize(Pango.EllipsizeMode.END) self.__artist_label.set_property("has-tooltip", True) self.__artist_label.connect("query-tooltip", self.__on_query_tooltip) self.__artist_label.show() self.__year_label = Gtk.Label() self.__year_label.set_margin_end(10) self.__year_label.get_style_context().add_class("dim-label") self.__year_label.show() self.__duration_label = Gtk.Label() self.__duration_label.get_style_context().add_class("dim-label") self.__duration_label.show() self.__context_button = Gtk.Button.new_from_icon_name( "go-next-symbolic", Gtk.IconSize.BUTTON) self.__context_button.set_relief(Gtk.ReliefStyle.NONE) self.__context_button.connect("clicked", self.__on_context_clicked) self.__context_button.get_style_context().add_class("menu-button") self.__context_button.get_style_context().add_class( "album-menu-button") self.__context_button.show() self._widget = Gtk.Grid() self._widget.set_orientation(Gtk.Orientation.VERTICAL) self._widget.set_row_spacing(2) self._widget.show() self.__header = Gtk.Grid() self.__header.add(self.__artist_label) self.__header.add(self.__title_label) self.__header.add(self.__year_label) self.__header.add(self.__context_button) self.__header.show() self._widget.add(self.__header) separator = Gtk.Separator.new(Gtk.Orientation.HORIZONTAL) separator.show() self._widget.add(separator) loved = LovedWidget(self._album) loved.set_property("valign", Gtk.Align.CENTER) loved.set_margin_end(10) loved.show() rating = RatingWidget(self._album) rating.set_property("valign", Gtk.Align.CENTER) rating.set_property("halign", Gtk.Align.END) rating.set_margin_end(10) rating.show() if self.__show_cover: self.__header.add(self.__duration_label) self.__duration_label.set_hexpand(True) self.__duration_label.set_property("halign", Gtk.Align.END) eventbox = Gtk.EventBox() eventbox.connect("enter-notify-event", self._on_enter_notify) eventbox.connect("leave-notify-event", self._on_leave_notify) eventbox.connect("button-press-event", self._on_button_press) eventbox.show() self.set_property("valign", Gtk.Align.CENTER) self._artwork = App().art_helper.get_image(ArtSize.BIG, ArtSize.BIG, "cover-frame") self._artwork.show() eventbox.add(self._artwork) self.__duration_label.set_hexpand(True) self._overlay = Gtk.Overlay.new() self._overlay.add(eventbox) self._overlay.show() self.__coverbox = Gtk.Grid() self.__coverbox.set_row_spacing(2) self.__coverbox.set_margin_end(10) self.__coverbox.set_orientation(Gtk.Orientation.VERTICAL) self.__coverbox.show() self.__coverbox.attach(self._overlay, 0, 0, 2, 1) loved.set_property("halign", Gtk.Align.START) self.__coverbox.attach(rating, 0, 1, 1, 1) self.__coverbox.attach_next_to(loved, rating, Gtk.PositionType.RIGHT, 1, 1) if App().window.container.stack.get_allocation().width <\ Sizing.MEDIUM: self.__coverbox.hide() if len(self._artist_ids) > 1: self.__artist_label.set_text( ", ".join(self._album.artists)) self.__artist_label.show() else: self._artwork = None loved.set_property("halign", Gtk.Align.END) self.__header.add(rating) self.__header.add(loved) rating.set_hexpand(True) self.__header.add(self.__duration_label) self.__artist_label.set_text(", ".join(self._album.artists)) self.__artist_label.show() self.__set_duration() album_name = GLib.markup_escape_text(self._album.name) artist_name = GLib.markup_escape_text( ", ".join(self._album.artists)) self.__title_label.set_markup("<b>%s</b>" % album_name) self.__artist_label.set_markup("<b>%s</b>" % artist_name) if self._album.year is not None: self.__year_label.set_label(str(self._album.year)) self.__year_label.show() self.set_selection() if self._artwork is None: TracksView.populate(self) self._widget.add(self._responsive_widget) self._responsive_widget.show() else: grid.add(self.__coverbox) self.set_artwork() grid.add(self._widget) self.add(grid) else: TracksView.populate(self)
def __init__(self, album_id, genre_ids, artist_ids, art_size): """ Init detailed album widget @param album id as int @param genre ids as [int] @param artist ids as [int] @param lazy as LazyLoadingView @param art size as ArtSize """ Gtk.Bin.__init__(self) AlbumWidget.__init__(self, album_id, genre_ids, artist_ids, art_size) self._rounded_class = "rounded-icon-small" self.__width = None self.__context = None # Cover + rating + spacing self.__height = ArtSize.BIG + 26 self.__orientation = None self.__child_height = TrackRow.get_best_height(self) # Header + separator + spacing + margin self.__requested_height = self.__child_height + 6 # Discs to load, will be emptied self.__discs = self._album.discs self.__locked_widget_right = True self.set_property("height-request", self.__height) self.connect("size-allocate", self.__on_size_allocate) builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/AlbumDetailedWidget.ui") builder.connect_signals(self) self._widget = builder.get_object("widget") album_info = builder.get_object("albuminfo") title_label = builder.get_object("title") title_label.set_property("has-tooltip", True) artist_label = builder.get_object("artist") artist_label.set_property("has-tooltip", True) year_label = builder.get_object("year") self.__header = builder.get_object("header") self.__overlay = builder.get_object("overlay") self.__duration_label = builder.get_object("duration") self.__context_button = builder.get_object("context") if art_size == ArtSize.NONE: self._cover = None rating = RatingWidget(self._album) rating.set_hexpand(True) rating.set_property("halign", Gtk.Align.END) rating.set_property("valign", Gtk.Align.CENTER) rating.show() self.__header.attach(rating, 4, 0, 1, 1) loved = LovedWidget(self._album) loved.set_property("halign", Gtk.Align.END) loved.set_property("valign", Gtk.Align.CENTER) loved.show() self.__header.attach(loved, 5, 0, 1, 1) artist_label.set_text(", ".join(self._album.artists)) artist_label.show() if self._album.year is not None: year_label.set_label(str(self._album.year)) year_label.show() else: self.__duration_label.set_hexpand(True) builder = Gtk.Builder() builder.add_from_resource("/org/gnome/Lollypop/CoverBox.ui") builder.connect_signals(self) self._play_button = builder.get_object("play-button") self._action_button = builder.get_object("action-button") self._action_event = builder.get_object("action-event") self._cover = builder.get_object("cover") self.__coverbox = builder.get_object("coverbox") # 6 for 2*3px (application.css) self.__coverbox.set_property("width-request", art_size + 6) if art_size == ArtSize.BIG: self._cover.get_style_context().add_class("cover-frame") self._artwork_button = builder.get_object("artwork-button") if self._album.year is not None: year_label.set_label(str(self._album.year)) year_label.show() grid = Gtk.Grid() grid.set_column_spacing(10) grid.set_property("halign", Gtk.Align.CENTER) grid.show() rating = RatingWidget(self._album) loved = LovedWidget(self._album) rating.show() loved.show() grid.add(rating) grid.add(loved) self.__coverbox.add(grid) self._widget.attach(self.__coverbox, 0, 0, 1, 1) if Lp().window.get_view_width() < WindowSize.MEDIUM: self.__coverbox.hide() if len(artist_ids) > 1: artist_label.set_text(", ".join(self._album.artists)) artist_label.show() elif art_size == ArtSize.HEADER: # Here we are working around default CoverBox ui # Do we really need to have another ui file? # So just hack values on the fly self._cover.get_style_context().add_class("small-cover-frame") overlay_grid = builder.get_object("overlay-grid") overlay_grid.set_margin_bottom(2) overlay_grid.set_margin_end(2) overlay_grid.set_column_spacing(0) play_event = builder.get_object("play-event") play_event.set_margin_start(2) play_event.set_margin_bottom(2) album_info.attach(self.__coverbox, 0, 0, 1, 1) artist_label.set_text(", ".join(self._album.artists)) artist_label.show() self.__set_duration() self.__box = Gtk.Grid() self.__box.set_column_homogeneous(True) self.__box.set_property("valign", Gtk.Align.START) self.__box.show() album_info.add(self.__box) self._tracks_left = {} self._tracks_right = {} self.set_cover() self.update_state() title_label.set_label(self._album.name) for disc in self.__discs: self.__add_disc_container(disc.number) self.__set_disc_height(disc) self.add(self._widget) # We start transparent, we switch opaque at size allocation # This prevent artifacts self.set_opacity(0) self._lock_overlay = False
def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.Grid.__init__(self) self.__object = object self.__button = button can_launch = False if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): save = HoverWidget('document-save-symbolic', self.__save_object) save.set_tooltip_text(_("Save into collection")) save.set_margin_end(10) save.show() else: trash = HoverWidget('user-trash-symbolic', self.__remove_object) if isinstance(self.__object, Album): trash.set_tooltip_text(_("Remove album")) else: trash.set_tooltip_text(_("Remove track")) trash.set_margin_end(10) trash.show() else: # Check portal for tag editor try: bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) proxy = Gio.DBusProxy.new_sync( bus, Gio.DBusProxyFlags.NONE, None, 'org.gnome.Lollypop.Portal', '/org/gnome/LollypopPortal', 'org.gnome.Lollypop.Portal', None) can_launch = proxy.call_sync('CanLaunchTagEditor', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None)[0] except Exception as e: print("ContextWidget::__init__():", e) if can_launch: edit = HoverWidget('document-properties-symbolic', self.__edit_tags) edit.set_tooltip_text(_("Modify information")) edit.set_margin_end(10) edit.show() playlist = HoverWidget('view-list-symbolic', self.__show_playlist_manager) playlist.set_tooltip_text(_("Playlists")) playlist.show() if isinstance(self.__object, Album): if Lp().player.album_in_queue(self.__object): queue = HoverWidget('list-remove-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Remove from queue")) else: queue = HoverWidget('list-add-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Add to queue")) queue.set_margin_start(10) queue.show() else: rating = RatingWidget(object) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.END) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(object.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.show() if self.__object.is_web: web = Gtk.LinkButton(self.__object.uri) icon = Gtk.Image.new_from_icon_name('web-browser-symbolic', Gtk.IconSize.MENU) web.set_image(icon) web.get_style_context().add_class('no-padding') web.set_margin_start(5) web.set_tooltip_text(self.__object.uri) web.show_all() uri = "https://www.youtube.com/results?search_query=%s" %\ (self.__object.artists[0] + " " + self.__object.name,) search = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name('edit-find-symbolic', Gtk.IconSize.MENU) search.set_image(icon) search.get_style_context().add_class('no-padding') search.set_tooltip_text(uri) search.show_all() if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): self.add(save) else: self.add(trash) elif can_launch: self.add(edit) self.add(playlist) if isinstance(self.__object, Album): self.add(queue) else: if self.__object.album.is_web: self.add(web) self.add(search) self.add(rating) self.add(loved)
def _popup_menu(self, widget, xcoordinate=None, ycoordinate=None): """ Popup menu for track @param widget as Gtk.Button @param xcoordinate as int (or None) @param ycoordinate as int (or None) """ menu = TrackMenu(self._object_id, None) popover = Gtk.Popover.new_from_model(widget, menu) if xcoordinate is not None and ycoordinate is not None: rect = widget.get_allocation() rect.x = xcoordinate rect.y = ycoordinate rect.width = 1 rect.height = 1 popover.set_pointing_to(rect) rating = RatingWidget(self._object) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(self._object_id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.set_property('halign', Gtk.Align.END) loved.set_property('hexpand', True) loved.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable) grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, 'main') stack.show_all() menu_widget = popover.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) hgrid.show() grid.add(hgrid) popover.add(stack) popover.connect('closed', self._on_closed) self.get_style_context().add_class('track-menu-selected') popover.show()
def __init__(self, object, button): """ Init widget @param object as Track/Album @param button as Gtk.Button """ Gtk.Grid.__init__(self) self.__object = object self.__button = button can_launch = False if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): save = HoverWidget('document-save-symbolic', self.__save_object) save.set_tooltip_text(_("Save into collection")) save.set_margin_end(10) save.show() else: trash = HoverWidget('user-trash-symbolic', self.__remove_object) if isinstance(self.__object, Album): trash.set_tooltip_text(_("Remove album")) else: trash.set_tooltip_text(_("Remove track")) trash.set_margin_end(10) trash.show() else: # Check portal for tag editor try: bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) proxy = Gio.DBusProxy.new_sync(bus, Gio.DBusProxyFlags.NONE, None, 'org.gnome.Lollypop.Portal', '/org/gnome/LollypopPortal', 'org.gnome.Lollypop.Portal', None) can_launch = proxy.call_sync('CanLaunchTagEditor', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None)[0] except: print("You are missing lollypop-portal: " "https://github.com/gnumdk/lollypop-portal") if can_launch: edit = HoverWidget('document-properties-symbolic', self.__edit_tags) edit.set_tooltip_text(_("Modify information")) edit.set_margin_end(10) edit.show() playlist = HoverWidget('view-list-symbolic', self.__show_playlist_manager) playlist.set_tooltip_text(_("Playlists")) playlist.show() if isinstance(self.__object, Album): if Lp().player.album_in_queue(self.__object): queue = HoverWidget('list-remove-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Remove from queue")) else: queue = HoverWidget('list-add-symbolic', self.__add_to_queue) queue.set_tooltip_text(_("Add to queue")) queue.set_margin_start(10) queue.show() else: rating = RatingWidget(object) rating.set_margin_top(5) rating.set_margin_end(10) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.END) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(object) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.show() if self.__object.is_web: web = Gtk.LinkButton(self.__object.uri) icon = Gtk.Image.new_from_icon_name('web-browser-symbolic', Gtk.IconSize.MENU) web.set_image(icon) web.get_style_context().add_class('no-padding') web.set_margin_start(5) web.set_tooltip_text(self.__object.uri) web.show_all() uri = "https://www.youtube.com/results?search_query=%s" %\ (self.__object.artists[0] + " " + self.__object.name,) search = Gtk.LinkButton(uri) icon = Gtk.Image.new_from_icon_name('edit-find-symbolic', Gtk.IconSize.MENU) search.set_image(icon) search.get_style_context().add_class('no-padding') search.set_tooltip_text(uri) search.show_all() if self.__object.is_web: if self.__object.genre_ids == [Type.CHARTS]: if isinstance(self.__object, Album): self.add(save) else: self.add(trash) elif can_launch: self.add(edit) self.add(playlist) if isinstance(self.__object, Album): self.add(queue) else: if self.__object.album.is_web: self.add(web) self.add(search) self.add(rating) self.add(loved)
def __init__(self, track, menu): """ Init widget @param track as Track @param menu as Gio.Menu """ Gtk.Popover.__init__(self) self.bind_model(menu, None) if track.year != track.album.year: track_year = str(track.year) else: track_year = "" rating = RatingWidget(track) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(track.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) if track_year == "": loved.set_property('halign', Gtk.Align.END) else: loved.set_property('halign', Gtk.Align.CENTER) loved.set_property('hexpand', True) loved.show() if track_year != "": year = Gtk.Label() year.set_text(track_year) year.set_margin_end(5) year.set_margin_top(5) year.set_margin_bottom(5) year.get_style_context().add_class('dim-label') year.set_property('halign', Gtk.Align.END) year.set_property('hexpand', True) year.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later (GTK>3.16 available on Debian stable) grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack = Gtk.Stack() stack.add_named(grid, 'main') stack.show_all() menu_widget = self.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) if track_year != "": hgrid.add(year) hgrid.show() grid.add(hgrid) self.add(stack)
def _on_infobox_clicked(self, eventbox, event): """ Pop albums from current artistleft click Show playlist menu on right @param eventbox as Gtk.EventBox @param event as Gdk.Event """ if Lp().player.current_track.id == Type.EXTERNALS: expopover = ExternalsPopover() expopover.set_relative_to(eventbox) expopover.populate() expopover.show() elif Lp().player.current_track.id is not None: if event.button == 1: if Lp().player.current_track.id == Type.RADIOS: if self._pop_tunein is None: self._pop_tunein = TuneinPopover() self._pop_tunein.populate() self._pop_tunein.set_relative_to(self._infobox) self._pop_tunein.show() else: if self._pop_infos is None: self._pop_infos = InfosPopover() self._pop_infos.set_relative_to(self._infobox) self._pop_infos.show() elif Lp().player.current_track.id >= 0: menu = PopToolbarMenu(Lp().player.current_track.id, None) popover = Gtk.Popover.new_from_model(eventbox, menu) rating = RatingWidget(Lp().player.current_track) rating.set_margin_top(5) rating.set_margin_bottom(5) rating.set_property('halign', Gtk.Align.START) rating.set_property('hexpand', True) rating.show() loved = LovedWidget(Lp().player.current_track.id) loved.set_margin_end(5) loved.set_margin_top(5) loved.set_margin_bottom(5) loved.set_property('halign', Gtk.Align.END) loved.set_property('hexpand', True) loved.show() # Hack to add two widgets in popover # Use a Gtk.PopoverMenu later # (GTK>3.16 available on Debian stable) stack = Gtk.Stack() grid = Gtk.Grid() grid.set_orientation(Gtk.Orientation.VERTICAL) stack.add_named(grid, 'main') stack.show_all() menu_widget = popover.get_child() menu_widget.reparent(grid) separator = Gtk.Separator() separator.show() grid.add(separator) hgrid = Gtk.Grid() hgrid.add(rating) hgrid.add(loved) hgrid.show() grid.add(hgrid) popover.add(stack) popover.show() return True