def _set_content(self, content, stream): """ Set content @param content as string @param data as Gio.MemoryInputStream """ if content is not None: self._content.set_markup(escape(content.decode('utf-8'))) if stream is not None: scale = self._image.get_scale_factor() pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, Lp().settings.get_value( 'cover-size').get_int32() + 50 * scale, -1, True, None) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf self._image.set_from_surface(surface) del surface self._image.show() self.set_visible_child_name('widget') else: self._on_not_found() self._spinner.stop()
def getIcon(item, widget): wrapper = SurfaceWrapper(None) pixbuf = None if item is None: return wrapper if isinstance(item, CMenu.TreeDirectory): gicon = item.get_icon() elif isinstance(item, CMenu.TreeEntry): app_info = item.get_app_info() gicon = app_info.get_icon() else: return wrapper if gicon is None: return wrapper icon_theme = Gtk.IconTheme.get_default() size = 24 * widget.get_scale_factor() info = icon_theme.lookup_by_gicon(gicon, size, 0) if info is None: return wrapper try: pixbuf = info.load_icon() except GLib.GError: return wrapper if pixbuf is None: return wrapper if pixbuf.get_width() != size or pixbuf.get_height() != size: pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.HYPER) wrapper.surface = Gdk.cairo_surface_create_from_pixbuf (pixbuf, widget.get_scale_factor(), widget.get_window()) return wrapper
def set_image_internal(self, path): pixbuf = None scaled_max_size = self.max_size * self.get_scale_factor() try: pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) except GLib.Error as e: message = "Could not load pixbuf from '%s' for FramedImage: %s" % (path, e.message) error = True if pixbuf != None: if (pixbuf.get_height() > scaled_max_size or pixbuf.get_width() > scaled_max_size) or \ (self.scale_up and (pixbuf.get_height() < scaled_max_size / 2 or pixbuf.get_width() < scaled_max_size / 2)): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, scaled_max_size, scaled_max_size) except GLib.Error as e: message = "Could not scale pixbuf from '%s' for FramedImage: %s" % (path, e.message) error = True if pixbuf: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.get_scale_factor(), self.get_window()) self.set_from_surface(surface) self.emit("surface-changed", surface) else: print(message) self.clear_image()
def _set_content(self, content, stream): """ Set content @param content as string @param data as Gio.MemoryInputStream """ # Happens if widget is destroyed while loading content from the web if self.get_child_by_name('widget') is None: return if content is not None: self._content.set_markup(escape(content.decode('utf-8'))) if stream is not None: scale = self._image.get_scale_factor() pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, Lp().settings.get_value( 'cover-size').get_int32() + 50 * scale, -1, True, None) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf self._image.set_from_surface(surface) del surface self._image_frame.show() self.set_visible_child_name('widget') else: self.set_visible_child_name('notfound')
def __set_content(self, content, stream): """ Set content @param content as string @param data as Gio.MemoryInputStream """ if content is not None: self.__content.set_markup( GLib.markup_escape_text(content.decode('utf-8'))) if stream is not None: scale = self.__image.get_scale_factor() # Will happen if cache is broken or when reading empty files try: pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, Lp().settings.get_value( 'cover-size').get_int32() + 50 * scale, -1, True, None) stream.close() surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) del pixbuf self.__image.set_from_surface(surface) del surface self.__image.show() except: pass self.set_visible_child_name('widget') else: self.__on_not_found() self._spinner.stop()
def get_album_artwork(self, album, size): """ Return a cairo surface for album_id, covers are cached as jpg. @param album as Album @param pixbuf size as int @return cairo surface """ filename = self._get_album_cache_name(album) cache_path_jpg = "%s/%s_%s.jpg" % (self._CACHE_PATH, filename, size) pixbuf = None try: # Look in cache if os.path.exists(cache_path_jpg): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_jpg, size, size) else: # Use favorite folder artwork if pixbuf is None: path = self.get_album_artwork_path(album) # Look in album folder if path is not None: ratio = self._respect_ratio(path) pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, size, ratio) # Use tags artwork if pixbuf is None and album.tracks: try: pixbuf = self.pixbuf_from_tags( album.tracks[0].path, size) except Exception as e: pass # Use folder artwork if pixbuf is None: path = self.get_first_album_artwork(album) # Look in album folder if path is not None: ratio = self._respect_ratio(path) pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, size, size, ratio) # Use default artwork if pixbuf is None: self.download_album_art(album.id) return self._get_default_icon(size, 'folder-music-symbolic') else: pixbuf.savev(cache_path_jpg, "jpeg", ["quality"], ["90"]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf return surface except Exception as e: print(e) return self._get_default_icon(size, 'folder-music-symbolic')
def _on_artwork_draw(self, image, ctx): """ Draw rounded image @param image as Gtk.Image @param ctx as cairo.Context """ pixbuf = image.get_pixbuf() if pixbuf is None: return surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, image.get_scale_factor(), None) ctx.translate(2, 2) size = ArtSize.ARTIST_SMALL * 2 - 4 ctx.new_sub_path() radius = size / 2 ctx.arc(size / 2, size / 2, radius, 0, 2 * pi) ctx.set_source_rgb(1, 1, 1) ctx.fill_preserve() ctx.set_line_width(2) ctx.set_source_rgba(0, 0, 0, 0.3) ctx.stroke_preserve() ctx.set_source_surface(surface, 0, 0) ctx.clip() ctx.paint() return True
def _add_pixbuf(self, stream): """ Add stream to the view """ try: pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, ArtSize.MONSTER, ArtSize.MONSTER, True, None) image = Gtk.Image() image.get_style_context().add_class("cover-frame") image.set_property("halign", Gtk.Align.CENTER) image.set_property("valign", Gtk.Align.CENTER) self._orig_pixbufs[image] = pixbuf # Scale preserving aspect ratio width = pixbuf.get_width() height = pixbuf.get_height() if width > height: height = height * ArtSize.BIG * self.get_scale_factor() / width width = ArtSize.BIG * self.get_scale_factor() else: width = width * ArtSize.BIG * self.get_scale_factor() / height height = ArtSize.BIG * self.get_scale_factor() scaled_pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR) del pixbuf surface = Gdk.cairo_surface_create_from_pixbuf(scaled_pixbuf, self.get_scale_factor(), None) del scaled_pixbuf image.set_from_surface(surface) del surface image.show() self._view.add(image) except Exception as e: print(e) pass if self._stack.get_visible_child_name() == "spinner": self._spinner.stop() self._stack.set_visible_child_name("logo")
def set_icon_from_pixbuf_with_scale(icon, pixbuf, scale=1): if scale == 1 or scale is None or pixbuf is None: icon.set_from_pixbuf(pixbuf) return None surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) icon.set_from_surface(surface) return None
def _cache_hit(self, klass, pixbuf): surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self._scale, None) surface = _make_icon_frame(surface, self._size, self._scale) self._surface = surface self._set_grilo_thumbnail_path() self.emit('finished')
def get_default_icon(self, icon_name, size, scale): """ Construct an empty cover album, code forked Gnome Music, see copyright header @param icon_name as str @param size as int @param scale factor as int @return pixbuf as cairo.Surface """ try: # First look in cache cache_path_jpg = self._get_default_icon_path(size, icon_name) f = Lio.File.new_for_path(cache_path_jpg) if f.query_exists(): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( cache_path_jpg, size, size, False) else: # get a small pixbuf with the given path icon_size = size / 4 icon = Gtk.IconTheme.get_default().load_icon(icon_name, icon_size, 0) # create an empty pixbuf with the requested size pixbuf = GdkPixbuf.Pixbuf.new(icon.get_colorspace(), True, icon.get_bits_per_sample(), size, size) pixbuf.fill(0xffffffff) icon.composite(pixbuf, icon_size * 3 / 2, icon_size * 3 / 2, icon_size, icon_size, icon_size * 3 / 2, icon_size * 3 / 2, 1, 1, GdkPixbuf.InterpType.NEAREST, 255) # Gdk < 3.15 was missing save method # > 3.15 is missing savev method try: pixbuf.save(cache_path_jpg, "jpeg", ["quality"], [str(Lp().settings.get_value( 'cover-quality').get_int32())]) except: pixbuf.savev(cache_path_jpg, "jpeg", ["quality"], [str(Lp().settings.get_value( 'cover-quality').get_int32())]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) del pixbuf return surface except: return self.get_default_icon('computer-fail-symbolic', ArtSize.MEDIUM, scale)
def __set_artwork(self): """ Set artist artwork """ artwork_height = 0 if Lp().settings.get_value('artist-artwork'): if len(self._artist_ids) == 1 and\ Lp().settings.get_value('artist-artwork'): artist = Lp().artists.get_name(self._artist_ids[0]) size = ArtSize.ARTIST_SMALL * 2 * self.__scale_factor for suffix in ["lastfm", "spotify", "wikipedia"]: uri = InfoCache.get_artwork(artist, suffix, size) if uri is not None: f = Lio.File.new_for_path(uri) (status, data, tag) = f.load_contents(None) stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, size, size, True, None) stream.close() surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self.__scale_factor, None) del pixbuf self.__artwork.set_from_surface(surface) del surface artwork_height = ArtSize.ARTIST_SMALL * 2 self.__artwork.get_style_context().remove_class( 'artwork-icon') self.__artwork.show() self.__artwork_box.show() break # Add a default icon if len(self._artist_ids) == 1 and artwork_height == 0: self.__artwork.set_from_icon_name( 'avatar-default-symbolic', Gtk.IconSize.DND) artwork_height = 32 self.__artwork.get_style_context().add_class('artwork-icon') self.__artwork.show() self.__artwork_box.show() # Create an self.__empty widget with header height ctx = self.__label.get_pango_context() layout = Pango.Layout.new(ctx) layout.set_text("a", 1) # Font scale 2 font_height = int(layout.get_pixel_size()[1]) * 2 if artwork_height > font_height: self.__empty.set_property('height-request', artwork_height) else: self.__empty.set_property('height-request', font_height)
def get_radio_artwork(self, name, size): """ Return a cairo surface for radio name @param radio name as string @param pixbuf size as int @return cairo surface """ filename = self._get_radio_cache_name(name) cache_path_png = "%s/%s_%s.png" % (self._CACHE_PATH, filename, size) pixbuf = None try: # Look in cache if os.path.exists(cache_path_png): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_png, size, size) else: path = self._get_radio_art_path(name) if path is not None: pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, size, size) pixbuf.fill(0xffffffff) cover = GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size) cover_width = cover.get_width() cover_height = cover.get_height() cover.composite(pixbuf, (size-cover_width)/2, (size-cover_height)/2, cover_width, cover_height, (size-cover_width)/2, (size-cover_height)/2, 1, 1, GdkPixbuf.InterpType.HYPER, 255) if pixbuf is None: return self._get_default_icon( size, 'audio-input-microphone-symbolic') pixbuf.savev(cache_path_png, "png", [None], [None]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf return surface except Exception as e: print(e) return self._get_default_icon(size, 'audio-input-microphone-symbolic')
def set_cover(self, pixbuf): """ Set cover @param pixbuf as GdkPixbuf.Pixbuf """ surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.get_scale_factor(), None) del pixbuf self.__cover.set_from_surface(surface) del surface
def _make_icon_frame(pixbuf, art_size=None, scale=1): border = 3 * scale degrees = pi / 180 radius = 3 * scale ratio = pixbuf.get_height() / pixbuf.get_width() # Scale down the image according to the biggest axis if ratio > 1: w = int(art_size.width / ratio * scale) h = art_size.height * scale else: w = art_size.width * scale h = int(art_size.height * ratio * scale) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, w, h) ctx = cairo.Context(surface) # draw outline ctx.new_sub_path() ctx.arc(w - radius, radius, radius - 0.5, -90 * degrees, 0 * degrees) ctx.arc(w - radius, h - radius, radius - 0.5, 0 * degrees, 90 * degrees) ctx.arc(radius, h - radius, radius - 0.5, 90 * degrees, 180 * degrees) ctx.arc(radius, radius, radius - 0.5, 180 * degrees, 270 * degrees) ctx.close_path() ctx.set_line_width(0.6) ctx.set_source_rgb(0.2, 0.2, 0.2) ctx.stroke_preserve() # fill the center ctx.set_source_rgb(1, 1, 1) ctx.fill() matrix = cairo.Matrix() matrix.scale(pixbuf.get_width() / (w - border * 2), pixbuf.get_height() / (h - border * 2)) matrix.translate(-border, -border) # paste the scaled pixbuf in the center Gdk.cairo_set_source_pixbuf(ctx, pixbuf, 0, 0) pattern = ctx.get_source() pattern.set_matrix(matrix) ctx.rectangle(border, border, w - border * 2, h - border * 2) ctx.fill() border_pixbuf = Gdk.pixbuf_get_from_surface(surface, 0, 0, w, h) surface = Gdk.cairo_surface_create_from_pixbuf(border_pixbuf, scale, None) return surface
def get_pbosf_for_pixbuf(widget, pixbuf): """Returns a cairo surface or the same pixbuf, let's call it PixbufOrSurface.. """ if hasattr(Gdk, "cairo_surface_create_from_pixbuf"): scale_factor = widget.get_scale_factor() # Don't create a surface if we don't have to if scale_factor == 1: return pixbuf return Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale_factor, widget.get_window()) else: return pixbuf
def show_image(self, uri, pbuf): """ Show the loaded image and switch to it on the view """ self.uri = uri self.page_loading.stop() try: surface = Gdk.cairo_surface_create_from_pixbuf( pbuf, self.get_scale_factor(), self.get_window()) self.page_image.set_from_surface(surface) except Exception as e: print(e) self.page_image.set_from_pixbuf(pbuf) self.stack.set_visible_child_name("page-image")
def get_album_artwork2(self, uri, size): """ Return a cairo surface with borders for uri No cache usage @param uri as string @param size as int @return cairo surface """ pixbuf = self.pixbuf_from_tags(GLib.filename_from_uri(uri)[0], size) if pixbuf is not None: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf return surface else: return self._get_default_icon(size, 'folder-music-symbolic')
def _get_default_icon(self, size, icon_name): """ Construct an empty cover album, code forked Gnome Music, see copyright header @param size as int @param icon_name as str @return pixbuf as Gdk.Pixbuf """ # First look in cache cache_path_jpg = self._get_default_icon_path(size, icon_name) if os.path.exists(cache_path_jpg): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(cache_path_jpg, size, size, False) else: # get a small pixbuf with the given path icon_size = size / 4 icon = Gtk.IconTheme.get_default().load_icon(icon_name, icon_size, 0) # create an empty pixbuf with the requested size pixbuf = GdkPixbuf.Pixbuf.new(icon.get_colorspace(), True, icon.get_bits_per_sample(), size, size) pixbuf.fill(0xffffffff) icon.composite(pixbuf, icon_size * 3 / 2, icon_size * 3 / 2, icon_size, icon_size, icon_size * 3 / 2, icon_size * 3 / 2, 1, 1, GdkPixbuf.InterpType.NEAREST, 255) # Gdk < 3.15 was missing save method # > 3.15 is missing savev method try: pixbuf.save(cache_path_jpg, "jpeg", ["quality"], ["90"]) except: pixbuf.savev(cache_path_jpg, "jpeg", ["quality"], ["90"]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf return surface
def _set_image(self, image, stream): """ Set image with stream @param image as Gtk.Image @param stream as Gio.MemoryInputStream """ pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale(stream, ArtSize.MEDIUM, ArtSize.MEDIUM, True, None) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, 0, None) del pixbuf image.set_from_surface(surface) del surface
def _add_pixbuf(self, pixbuf): """ Add pixbuf to the view @param pixbuf as Gdk.Pixbuf """ image = Gtk.Image() self._orig_pixbufs[image] = pixbuf scaled_pixbuf = pixbuf.scale_simple( ArtSize.BIG * self.get_scale_factor(), ArtSize.BIG * self.get_scale_factor(), 2 ) del pixbuf surface = Gdk.cairo_surface_create_from_pixbuf(scaled_pixbuf, 0, None) del scaled_pixbuf image.set_from_surface(surface) del surface image.show() self._view.add(image)
def get_album_artwork2(self, uri, size, scale): """ Return a cairo surface with borders for uri No cache usage @param uri as string @param size as int @param scale as int @return cairo surface """ size *= scale pixbuf = self.pixbuf_from_tags(uri, size) if pixbuf is not None: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) del pixbuf return surface else: return self.get_default_icon('folder-music-symbolic', size, scale)
def _add_pixbuf(self, monster, big): """ Add pixbuf to the view @param monster as Gdk.Pixbuf @param big as Gdk.Pixbuf """ image = Gtk.Image() self._monster_pixbufs[image] = monster surface = Gdk.cairo_surface_create_from_pixbuf(big, 0, None) del monster del big image.set_from_surface(surface) del surface image.show() self._view.add(image)
def create_image(self, image_name=None, scale_ratio=1, window=None): """ The function creates a image from name defined in image_name """ size = 48 * scale_ratio pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(image_name, -1, size, True) image = Gtk.Image() # Creating the cairo surface is necessary for proper scaling on HiDPI try: surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale_ratio, window) image.set_from_surface(surface) # Fallback for GTK+ older than 3.10 except AttributeError: image.set_from_pixbuf(pixbuf) return image
def do_own_render(self, ctx, widget, cell_area, size): surface = None alpha = False if self.rowid in self._surfaces.keys(): surface = self._surfaces[self.rowid] if surface is None: for suffix in ["lastfm", "spotify", "wikipedia"]: uri = InfoCache.get_artwork(self.artist, suffix, size) if uri is not None: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(uri, size, size) surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, widget.get_scale_factor(), None) self._surfaces[self.rowid] = surface del pixbuf break if surface is None: alpha = True surface = Gtk.IconTheme.get_default().load_surface( 'media-optical-cd-audio-symbolic', ArtSize.ARTIST_SMALL, 1, widget.get_window(), 0) ctx.translate(cell_area.x, cell_area.y) ctx.new_sub_path() radius = ArtSize.ARTIST_SMALL / 2 ctx.arc(ArtSize.ARTIST_SMALL/2, ArtSize.ARTIST_SMALL/2, radius, 0, 2 * pi) ctx.set_source_rgb(1, 1, 1) ctx.fill_preserve() ctx.set_line_width(2) ctx.set_source_rgba(0, 0, 0, 0.3) ctx.stroke_preserve() ctx.set_source_surface(surface, 0, 0) ctx.clip() if alpha: ctx.paint_with_alpha(0.5) else: ctx.paint()
def get_radio_artwork(self, name, size, scale): """ Return a cairo surface for radio name @param radio name as string @param pixbuf size as int @param scale factor as int @return cairo surface """ size *= scale filename = self.__get_radio_cache_name(name) cache_path_png = "%s/%s_%s.png" % (self._CACHE_PATH, filename, size) pixbuf = None try: # Look in cache f = Gio.File.new_for_path(cache_path_png) if f.query_exists(): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_png, size, size) else: path = self.__get_radio_art_path(name) if path is not None: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(path, size, size) if pixbuf is None: return self.get_default_icon( 'audio-input-microphone-symbolic', size, scale) pixbuf.savev(cache_path_png, "png", [None], [None]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) del pixbuf return surface except Exception as e: print(e) return self.get_default_icon('audio-input-microphone-symbolic', size, scale)
def _add_pixbuf(self, data): """ Add pixbuf to the view @param data as bytes """ try: stream = Gio.MemoryInputStream.new_from_data(data, None) if stream is not None: monster = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, True, None) stream = Gio.MemoryInputStream.new_from_data(data, None) if stream is not None: big = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.BIG, ArtSize.BIG, True, None) image = Gtk.Image() image.get_style_context().add_class('cover-frame') image.set_property('halign', Gtk.Align.CENTER) image.set_property('valign', Gtk.Align.CENTER) self._datas[image] = data surface = Gdk.cairo_surface_create_from_pixbuf(big, 0, None) del monster del big image.set_from_surface(surface) del surface image.show() self._view.add(image) except Exception as e: print("ArtworkSearch::_add_pixbuf: %s" % e) # Remove spinner if exist if self._stack.get_visible_child_name() == 'spinner': self._spinner.stop() self._label.set_text(_("Select artwork")) self._stack.set_visible_child_name('main')
def _add_pixbuf(self, stream): """ Add stream to the view """ try: pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, ArtSize.MONSTER, ArtSize.MONSTER, True, None) image = Gtk.Image() self._orig_pixbufs[image] = pixbuf # Scale preserving aspect ratio width = pixbuf.get_width() height = pixbuf.get_height() if width > height: height = height*ArtSize.BIG*self.get_scale_factor()/width width = ArtSize.BIG*self.get_scale_factor() else: width = width*ArtSize.BIG*self.get_scale_factor()/height height = ArtSize.BIG*self.get_scale_factor() scaled_pixbuf = pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.BILINEAR) del pixbuf surface = Gdk.cairo_surface_create_from_pixbuf(scaled_pixbuf, 0, None) del scaled_pixbuf image.set_from_surface(surface) del surface image.show() self._view.add(image) except Exception as e: print(e) pass # Remove spinner if exist if self._spinner is not None: self._stack.set_visible_child(self._logo) self._stack.clean_old_views(self._logo) self._spinner = None
def _add_pixbuf(self, monster, big): """ Add pixbuf to the view @param monster as Gdk.Pixbuf @param big as Gdk.Pixbuf """ if monster is None or big is None: return image = Gtk.Image() image.get_style_context().add_class('cover-frame') image.set_property('halign', Gtk.Align.CENTER) image.set_property('valign', Gtk.Align.CENTER) self._monster_pixbufs[image] = monster surface = Gdk.cairo_surface_create_from_pixbuf(big, 0, None) del monster del big image.set_from_surface(surface) del surface image.show() self._view.add(image)
def _on_artwork_draw(self, image, ctx): """ Draw rounded image @param image as Gtk.Image @param ctx as cairo.Context """ # Update image if scale factor changed if self.__scale_factor != image.get_scale_factor(): self.__scale_factor = image.get_scale_factor() self.__set_artwork() if not image.is_drawable(): return if image.props.surface is None: pixbuf = image.get_pixbuf() if pixbuf is None: return surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self.__scale_factor, None) del pixbuf else: surface = image.props.surface ctx.translate(2, 2) size = ArtSize.ARTIST_SMALL * 2 - 4 ctx.new_sub_path() radius = size / 2 ctx.arc(size/2, size/2, radius, 0, 2 * pi) ctx.set_source_rgb(1, 1, 1) ctx.fill_preserve() ctx.set_line_width(2) ctx.set_source_rgba(0, 0, 0, 0.3) ctx.stroke_preserve() ctx.set_source_surface(surface, 0, 0) ctx.clip() ctx.paint() return True
def __init__(self, book, size, scale, bordered=False, square=False): """ :param size: the size for the longer side of the image :param bordered: should there be a border around the album art? :param square: should the widget be always a square? """ super().__init__() self.book = book self.selected = False self.signal_ids = [] self.play_signal_ids = [] # the event box is used for mouse enter and leave signals self.event_box = Gtk.EventBox() self.event_box.set_property("halign", Gtk.Align.CENTER) self.event_box.set_property("valign", Gtk.Align.CENTER) # scale the book cover to a fix size. pixbuf = artwork_cache.get_cover_pixbuf(book, scale, size) # box is the main container for the album art self.set_halign(Gtk.Align.CENTER) self.set_valign(Gtk.Align.CENTER) # img contains the album art img = Gtk.Image() img.set_halign(Gtk.Align.CENTER) img.set_valign(Gtk.Align.CENTER) if bordered: img.get_style_context().add_class("bordered") surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) img.set_from_surface(surface) self.play_box = Gtk.EventBox() # on click we want to play the audio book self.play_signal_ids.append( self.play_box.connect("button-press-event", self._on_play_button_press)) self.play_box.set_property("halign", Gtk.Align.CENTER) self.play_box.set_property("valign", Gtk.Align.CENTER) self.play_box.set_tooltip_text(_("Play this book")) # play_color is an overlay for the play button # with this it should be visible on any album art color play_image = GdkPixbuf.Pixbuf.new_from_resource( "/de/geigi/cozy/play_background.svg") if square: play_image = play_image.scale_simple(size - 10, size - 10, GdkPixbuf.InterpType.BILINEAR) if size < 100: self.icon_size = Gtk.IconSize.LARGE_TOOLBAR else: self.icon_size = Gtk.IconSize.DIALOG self.play_button = Gtk.Image.new_from_icon_name( "media-playback-start-symbolic", self.icon_size) self.play_button.set_property("halign", Gtk.Align.CENTER) self.play_button.set_property("valign", Gtk.Align.CENTER) self.play_button.get_style_context().add_class("white") # this is the main overlay for the album art # we need to create field for the overlays # to change the opacity of them on mouse over/leave events self.overlay = Gtk.Overlay.new() # this is the play symbol overlay self.play_overlay = Gtk.Overlay.new() # this is for the play button animation self.play_revealer = Gtk.Revealer() self.play_revealer.set_transition_type( Gtk.RevealerTransitionType.CROSSFADE) self.play_revealer.set_transition_duration(300) self.play_revealer.add(self.play_overlay) self.play_revealer.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK) self.play_revealer.add_events(Gdk.EventMask.LEAVE_NOTIFY_MASK) # this grid has a background color to act as a visible overlay color = Gtk.Grid() color.set_property("halign", Gtk.Align.CENTER) color.set_property("valign", Gtk.Align.CENTER) if square: self.set_size_request(size, size) smaller_width = size - pixbuf.get_width() if smaller_width > 1: self.event_box.set_margin_left(smaller_width / 2) # assemble play overlay self.play_box.add(self.play_button) self.play_overlay.add(self.play_box) # assemble overlay with album art self.overlay.add(img) self.overlay.add_overlay(self.play_revealer) # assemble overlay color color.add(self.overlay) self.event_box.add(color) self.add(self.event_box) # connect signals self.play_signal_ids.append( self.play_box.connect("enter-notify-event", self._on_play_enter_notify)) self.play_signal_ids.append( self.play_box.connect("leave-notify-event", self._on_play_leave_notify)) # connect mouse events to the event box self.signal_ids.append( self.event_box.connect("enter-notify-event", self._on_enter_notify)) self.signal_ids.append( self.event_box.connect("leave-notify-event", self._on_leave_notify))
def op_blur(self, source_pixbuf, blur_algo, blur_radius): surface = Gdk.cairo_surface_create_from_pixbuf(source_pixbuf, 0, None) bs = utilities_fast_blur(surface, blur_radius, blur_algo) bp = Gdk.pixbuf_get_from_surface(bs, 0, 0, bs.get_width(), bs.get_height()) self.get_image().set_temp_pixbuf(bp)
def surface_for_path(self, path, scale): pixbuf = GdkPixbuf.Pixbuf.new_from_file(path) return Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale)
def set_image_from_item(self, image, item, store=None, size=64): """ Set the GtkImage if possible """ icon_name = item.get_icon_name() if icon_name: image.set_from_icon_name(icon_name, Gtk.IconSize.INVALID) return # Grab app bits id = item.get_id() app = self.get_store_variant(store, id) # No app? Set default icon for hidpi support. if not app: self.set_fallback_icon(image) return size = size * self.scale_factor original_size = size # No icon? icon = self.find_icon(app, size, size) if not icon: size /= self.scale_factor icon = self.find_icon(app, size, size) if not icon: self.set_fallback_icon(image) return # Find out what kind of icon this is kind = icon.get_kind() if kind == As.IconKind.STOCK: image.set_from_icon_name(icon.get_name(), Gtk.IconSize.INVALID) return # We're dealing with an unknown if kind == As.IconKind.UNKNOWN or kind == As.IconKind.REMOTE: self.set_fallback_icon(image) return icon.set_scale(self.scale_factor) # Try to load the cached/available icon try: if not icon.load(As.IconLoadFlags.SEARCH_SIZE): self.set_fallback_icon(image) return except Exception as e: print("Should not happen: {}".format(e)) self.set_fallback_icon(image) return # At this point we're dealing with pixbufs pbuf = icon.get_pixbuf() # Ensure we upscale on HiDPI if pbuf.get_height() != original_size: pbuf = pbuf.scale_simple(original_size, original_size, GdkPixbuf.InterpType.BILINEAR) if self.scale_factor == 1: image.set_from_pixbuf(pbuf) return window = self.window.get_window() if not window: self.set_fallback_icon(image) return try: surface = Gdk.cairo_surface_create_from_pixbuf( pbuf, self.scale_factor, window) image.set_from_surface(surface) except Exception as e: print(e) self.set_fallback_icon(image)
def data_func_surface(self, column, cell, model, iter_, *args): pixbuf = model.get_value(iter_, CHANNEL_LOGO) surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self.window.get_scale_factor()) cell.set_property("surface", surface)
def refresh_channel_logo(self, channel, image): pixbuf = self.get_pixbuf(channel.logo_path) surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self.window.get_scale_factor()) image.set_from_surface(surface)
def paint_menu(self, paint_background, paint_selected, paint_activated, page_number): coordinates = [] if self.sf is None: self.sf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 720, int(self.y)) self.cr = cairo.Context(self.sf) if self.cached_menu_font != self.entry_font: # memorize the font sizes (fontname, fontstyle, fontslant, fontsize) = self.get_font_params(self.entry_font) self.cr.select_font_face(fontname, fontslant, fontstyle) self.cr.set_font_size(fontsize) extents = self.cr.font_extents() self.cached_menu_size = extents[2] self.cached_menu_font = self.entry_font if paint_background: extra_pixbuf = GdkPixbuf.Pixbuf.new_from_file( self.background_picture) extra_x = float(extra_pixbuf.get_width()) extra_y = float(extra_pixbuf.get_height()) self.cr.save() self.cr.scale(720.0 / extra_x, self.y / extra_y) surface = Gdk.cairo_surface_create_from_pixbuf( extra_pixbuf, 1, None) self.cr.set_source_surface(surface, 0, 0) self.cr.paint() self.cr.restore() hmargin = self.title_horizontal * 720.0 / 100.0 self.write_text(self.title_text, "title", 0 + hmargin, 720 + hmargin, self.title_vertical * self.y / 100.0, "center") # else: # self.cr.set_source_rgb(1.0,1.0,1.0) # self.cr.paint() top_margin_p = self.y * self.margin_top / 100.0 bottom_margin_p = self.y * self.margin_bottom / 100.0 left_margin_p = 720.0 * self.margin_left / 100.0 right_margin_p = 720.0 * self.margin_right / 100.0 entry_height = self.cached_menu_size + self.entry_vertical_margin * 2.0 + self.entry_separation entries_per_page = int( (self.y - top_margin_p - bottom_margin_p) / entry_height) if (self.play_all_c): entries_per_page -= 1 n_entries = len(self.title_list) if (n_entries > entries_per_page): paint_arrows = True entries_per_page -= 1 else: paint_arrows = False self.pages = int(n_entries / entries_per_page) if (n_entries == 0) or ((n_entries % entries_per_page) != 0): self.pages += 1 if (page_number >= self.pages) and (page_number > 0): page_number -= 1 if self.wcurrent_page is not None: self.wcurrent_page.set_text( _("Page %(X)d of %(Y)d") % { "X": page_number + 1, "Y": self.pages }) xl = left_margin_p xr = 720.0 - right_margin_p y = top_margin_p + entry_height / 2.0 height = (self.cached_menu_size + self.entry_vertical_margin) / 2.0 if (self.play_all_c): coordinates.append([xl, y - height, xr, y + height, "play_all"]) if paint_background: self.paint_base(xl, xr, y, 0) self.write_text("Play All", "menu_entry", xl, xr, y, self.position_horizontal) if paint_selected: self.write_text("Play All", "menu_entry_selected", xl, xr, y, self.position_horizontal) if paint_activated: self.write_text("Play All", "menu_entry_activated", xl, xr, y, self.position_horizontal) y += entry_height for entry in self.title_list[page_number * entries_per_page:(page_number + 1) * entries_per_page]: coordinates.append([xl, y - height, xr, y + height, "entry"]) text = entry[0].title_name if paint_background: self.paint_base(xl, xr, y, 0) self.write_text(text, "menu_entry", xl, xr, y, self.position_horizontal) if paint_selected: self.write_text(text, "menu_entry_selected", xl, xr, y, self.position_horizontal) if paint_activated: self.write_text(text, "menu_entry_activated", xl, xr, y, self.position_horizontal) y += entry_height if paint_arrows: if page_number == 0: coordinates.append([xl, y - height, xr, y + height, "right"]) if paint_background: self.paint_base(xl, xr, y, 0) self.paint_arrow(xl, xr, y, "menu_entry", False) if paint_selected: self.paint_arrow(xl, xr, y, "menu_entry_selected", False) if paint_activated: self.paint_arrow(xl, xr, y, "menu_entry_activated", False) elif page_number == (self.pages - 1): coordinates.append([xl, y - height, xr, y + height, "left"]) if paint_background: self.paint_base(xl, xr, y, 0) self.paint_arrow(xl, xr, y, "menu_entry", True) if paint_selected: self.paint_arrow(xl, xr, y, "menu_entry_selected", True) if paint_activated: self.paint_arrow(xl, xr, y, "menu_entry_activated", True) else: med = (xl + xr) / 2.0 coordinates.append([xl, y - height, med, y + height, "left"]) coordinates.append([med, y - height, xr, y + height, "right"]) if paint_background: self.paint_base(xl, xr, y, 1) self.paint_base(xl, xr, y, 2) self.paint_arrow(med, xr, y, "menu_entry", False) self.paint_arrow(xl, med, y, "menu_entry", True) if paint_selected: self.paint_arrow(med, xr, y, "menu_entry_selected", False) self.paint_arrow(xl, med, y, "menu_entry_selected", True) if paint_activated: self.paint_arrow(med, xr, y, "menu_entry_activated", False) self.paint_arrow(xl, med, y, "menu_entry_activated", True) return coordinates
def use_stable_pixbuf(self): # print('image/384: use_stable_pixbuf') self.surface = Gdk.cairo_surface_create_from_pixbuf( self.main_pixbuf, 0, None)
def op_blur(self, source_pixbuf, blur_algo, blur_direction, radius): surface = Gdk.cairo_surface_create_from_pixbuf(source_pixbuf, 0, None) surface.set_device_scale(self.scale_factor(), self.scale_factor()) bs = utilities_blur_surface(surface, radius, blur_algo, blur_direction) bp = Gdk.pixbuf_get_from_surface(bs, 0, 0, bs.get_width(), bs.get_height()) self.get_image().set_temp_pixbuf(bp)
def get_album_artwork(self, album, size, scale): """ Return a cairo surface for album_id, covers are cached as jpg. @param album as Album @param pixbuf size as int @param scale factor as int @return cairo surface """ size *= scale filename = self.get_album_cache_name(album) cache_path_jpg = "%s/%s_%s.jpg" % (self._CACHE_PATH, filename, size) pixbuf = None try: # Look in cache f = Lio.File.new_for_path(cache_path_jpg) if f.query_exists(): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(cache_path_jpg, size, size) else: # Use favorite folder artwork if pixbuf is None: uri = self.get_album_artwork_uri(album) data = None if uri is not None: f = Lio.File.new_for_uri(uri) (status, data, tag) = f.load_contents(None) ratio = self._respect_ratio(uri) stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, size, size, ratio, None) stream.close() # Use tags artwork if pixbuf is None and album.tracks: try: pixbuf = self.pixbuf_from_tags( album.tracks[0].uri, size) except Exception as e: print("AlbumArt::get_album_artwork()", e) # Use folder artwork if pixbuf is None and album.uri != "": uri = self.get_first_album_artwork(album) # Look in album folder if uri is not None: f = Lio.File.new_for_uri(uri) (status, data, tag) = f.load_contents(None) ratio = self._respect_ratio(uri) stream = Gio.MemoryInputStream.new_from_data(data, None) pixbuf = GdkPixbuf.Pixbuf.new_from_stream_at_scale( stream, size, size, ratio, None) stream.close() # Use default artwork if pixbuf is None: self.cache_album_art(album.id) return self.get_default_icon("folder-music-symbolic", size, scale) else: pixbuf.savev(cache_path_jpg, "jpeg", ["quality"], [str(Lp().settings.get_value( "cover-quality").get_int32())]) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale, None) del pixbuf return surface except Exception as e: print("AlbumArt::get_album_artwork()", e) return self.get_default_icon("folder-music-symbolic", size, scale)
def set_picture_from_file(self, path): pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size( path, -1, FLAG_SIZE * self.scale) surface = Gdk.cairo_surface_create_from_pixbuf(pixbuf, self.scale) self.button_image.set_from_surface(surface)
def set_book(self, book): """ Display the given book in the book overview. """ if self.book and self.book.id == book.id: self.update_time() return self.book = Book.get(Book.id == book.id) if player.is_playing( ) and self.ui.titlebar.current_book and self.book.id == self.ui.titlebar.current_book.id: self.play_book_button.set_image(self.pause_img) else: self.play_book_button.set_image(self.play_img) self.name_label.set_text(book.name) self.author_label.set_text(book.author) self.update_offline_status() pixbuf = artwork_cache.get_cover_pixbuf( book, self.ui.window.get_scale_factor(), 250) if pixbuf: surface = Gdk.cairo_surface_create_from_pixbuf( pixbuf, self.ui.window.get_scale_factor(), None) self.cover_img.set_from_surface(surface) else: self.cover_img.set_from_icon_name("book-open-variant-symbolic", Gtk.IconSize.DIALOG) self.cover_img.props.pixel_size = 250 self.duration = get_book_duration(book) self.speed = self.book.playback_speed self.total_label.set_text( tools.seconds_to_human_readable(self.duration / self.speed)) self.last_played_label.set_text( tools.past_date_to_human_readable(book.last_played)) self.published_label.set_visible(False) self.published_text.set_visible(False) # track list # This box contains all track content self.track_box = Gtk.Box() self.track_box.set_orientation(Gtk.Orientation.VERTICAL) self.track_box.set_halign(Gtk.Align.START) self.track_box.set_valign(Gtk.Align.START) self.track_box.props.margin = 8 disk_number = -1 first_disk_element = None disk_count = 0 for track in get_tracks(book): # Insert disk headers if track.disk != disk_number: disc_element = DiskElement(track.disk) self.track_box.add(disc_element) if disk_number == -1: first_disk_element = disc_element if track.disk < 2: first_disk_element.set_hidden(True) else: first_disk_element.show_all() disc_element.show_all() disk_number = track.disk disk_count += 1 track_element = TrackElement(track, self) self.track_box.add(track_element) track_element.show_all() tools.remove_all_children(self.track_list_container) self.track_box.show() self.track_box.set_halign(Gtk.Align.FILL) self.track_list_container.add(self.track_box) self._mark_current_track() self.update_time()