Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 345e7697ff | |||
| 7d474598e3 | |||
| 9b29f7b274 | |||
| 0a109bc886 | |||
| 9311f9974a | |||
| 08cd9dbe65 | |||
| 099adbab8c | |||
| 3d91ab1b35 | |||
| dce1c441a0 | |||
| cd4f32e7f2 | |||
| 79b3111fb0 |
9 changed files with 112 additions and 64 deletions
|
|
@ -36,7 +36,7 @@ For testing the application and running it without (system-wide) installation,
|
|||
donwload/clone the code, build it with the `--prefix` option and install it
|
||||
with `ninja`:
|
||||
|
||||
$ meson --prefix $(pwd)/install build
|
||||
$ meson setup --prefix $(pwd)/install build
|
||||
$ ninja -C build
|
||||
$ ninja -C build install
|
||||
|
||||
|
|
|
|||
|
|
@ -141,6 +141,7 @@
|
|||
<child>
|
||||
<object class="GtkScale" id="songs_scale">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">fill</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="restrict-to-fill-level">False</property>
|
||||
|
|
@ -158,4 +159,3 @@
|
|||
</child>
|
||||
</template>
|
||||
</interface>
|
||||
|
||||
|
|
|
|||
|
|
@ -221,10 +221,14 @@
|
|||
<property name="child">
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
<child>
|
||||
<object class="GtkPicture">
|
||||
<property name="content-fit">contain</property>
|
||||
<property name="can-shrink">false</property>
|
||||
<property name="vexpand">true</property>
|
||||
<property name="hexpand">true</property>
|
||||
<binding name="tooltip-markup">
|
||||
<lookup name="tooltip" type="GridItem">
|
||||
<lookup name="item">GtkListItem</lookup>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
project('mcg',
|
||||
version: '4.0',
|
||||
version: '4.0.2',
|
||||
meson_version: '>= 0.59.0',
|
||||
default_options: [
|
||||
'warning_level=2',
|
||||
|
|
|
|||
|
|
@ -180,6 +180,21 @@ class CoverPanel(Gtk.Overlay):
|
|||
length, Gtk.PositionType.RIGHT,
|
||||
"{0[0]:02d}:{0[1]:02d} minutes".format(divmod(length, 60)))
|
||||
|
||||
# Align marks
|
||||
self._align_songs_scale_marks()
|
||||
|
||||
def _align_songs_scale_marks(self):
|
||||
self._align_songs_scale_mark(self.songs_scale)
|
||||
|
||||
def _align_songs_scale_mark(self, widget):
|
||||
child = widget.get_first_child()
|
||||
while child:
|
||||
if type(child) is Gtk.Label:
|
||||
child.set_halign(Gtk.Align.START)
|
||||
else:
|
||||
self._align_songs_scale_mark(child)
|
||||
child = child.get_next_sibling()
|
||||
|
||||
def _enable_tracklist(self):
|
||||
if self._current_album:
|
||||
# enable
|
||||
|
|
@ -221,6 +236,7 @@ class CoverPanel(Gtk.Overlay):
|
|||
pixbuf = self._cover_pixbuf
|
||||
# Check pixelbuffer
|
||||
if pixbuf is None:
|
||||
self.cover_default.set_pixel_size(min(size_width, size_height)/2)
|
||||
return
|
||||
|
||||
# Skalierungswert für Breite und Höhe ermitteln
|
||||
|
|
@ -236,4 +252,5 @@ class CoverPanel(Gtk.Overlay):
|
|||
return
|
||||
self.cover_image.set_from_pixbuf(
|
||||
pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
|
||||
self.cover_image.set_pixel_size(min(width, height))
|
||||
self.cover_image.show()
|
||||
|
|
|
|||
|
|
@ -293,15 +293,13 @@ class LibraryPanel(Adw.Bin):
|
|||
|
||||
def set_albumart(self, album, data):
|
||||
if album in self._selected_albums:
|
||||
self._standalone_pixbuf = None
|
||||
if data:
|
||||
# Load image and draw it
|
||||
try:
|
||||
self._standalone_pixbuf = Utils.load_pixbuf(data)
|
||||
except Exception:
|
||||
self._logger.exception("Failed to set albumart")
|
||||
self._standalone_pixbuf = self._get_default_image()
|
||||
else:
|
||||
self._standalone_pixbuf = self._get_default_image()
|
||||
# Show image
|
||||
GObject.idle_add(self._show_image)
|
||||
|
||||
|
|
@ -335,23 +333,24 @@ class LibraryPanel(Adw.Bin):
|
|||
self._grid_pixbufs.clear()
|
||||
for album_id in albums.keys():
|
||||
album = albums[album_id]
|
||||
grid_item = GridItem(album)
|
||||
|
||||
pixbuf = None
|
||||
try:
|
||||
pixbuf = Utils.load_thumbnail(cache, self._client, album, size)
|
||||
except client.CommandException:
|
||||
# Exception is handled by client
|
||||
pass
|
||||
except Exception as e:
|
||||
self._logger.exception("Failed to load albumart", e)
|
||||
except Exception:
|
||||
self._logger.exception("Failed to load albumart")
|
||||
if pixbuf is None:
|
||||
pixbuf = self._icon_theme.lookup_icon(
|
||||
Utils.STOCK_ICON_DEFAULT, None, self._item_size,
|
||||
self._item_size, Gtk.TextDirection.LTR,
|
||||
Gtk.IconLookupFlags.FORCE_SYMBOLIC)
|
||||
if pixbuf is not None:
|
||||
icon = self._get_default_icon(self._item_size, self._item_size)
|
||||
grid_item.set_icon(icon)
|
||||
else:
|
||||
self._grid_pixbufs[album.get_id()] = pixbuf
|
||||
GObject.idle_add(self._library_grid_model.append,
|
||||
GridItem(album, pixbuf))
|
||||
grid_item.set_cover(pixbuf)
|
||||
|
||||
GObject.idle_add(self._library_grid_model.append, grid_item)
|
||||
|
||||
i += 1
|
||||
GObject.idle_add(self.progress_bar.set_fraction, i / n)
|
||||
|
|
@ -361,6 +360,7 @@ class LibraryPanel(Adw.Bin):
|
|||
self._library_lock.release()
|
||||
GObject.idle_add(self.stack.set_visible_child, self.scroll)
|
||||
self._sort_grid_model()
|
||||
GObject.idle_add(self.library_grid.scroll_to, 0, Gtk.ListScrollFlags.NONE, None)
|
||||
|
||||
def _set_widget_grid_size(self, grid_widget, size, vertical):
|
||||
self._library_stop.set()
|
||||
|
|
@ -439,27 +439,26 @@ class LibraryPanel(Adw.Bin):
|
|||
pixbuf = self._standalone_pixbuf
|
||||
# Check pixelbuffer
|
||||
if pixbuf is None:
|
||||
icon = self._get_default_icon(size_width, size_height)
|
||||
self.standalone_image.set_from_paintable(icon)
|
||||
self.standalone_image.set_pixel_size(min(size_width, size_height)/2)
|
||||
return
|
||||
|
||||
# Skalierungswert für Breite und Höhe ermitteln
|
||||
ratio_w = float(size_width) / float(pixbuf.get_width())
|
||||
ratio_h = float(size_height) / float(pixbuf.get_height())
|
||||
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
|
||||
ratio = min(ratio_w, ratio_h)
|
||||
ratio = min(ratio, 1)
|
||||
# Neue Breite und Höhe berechnen
|
||||
width = int(math.floor(pixbuf.get_width() * ratio))
|
||||
height = int(math.floor(pixbuf.get_height() * ratio))
|
||||
(width, height) = Utils.calculate_size(pixbuf.get_width(),
|
||||
pixbuf.get_height(), size_width,
|
||||
size_height)
|
||||
if width <= 0 or height <= 0:
|
||||
return
|
||||
# Pixelpuffer auf Oberfläche zeichnen
|
||||
self.standalone_image.set_from_pixbuf(
|
||||
pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
|
||||
self.standalone_image.set_pixel_size(min(width, height))
|
||||
self.standalone_image.show()
|
||||
|
||||
def _get_default_image(self):
|
||||
def _get_default_icon(self, width, height):
|
||||
return self._icon_theme.lookup_icon(Utils.STOCK_ICON_DEFAULT, None,
|
||||
512, 512, Gtk.TextDirection.LTR,
|
||||
width, height,
|
||||
Gtk.TextDirection.LTR,
|
||||
Gtk.IconLookupFlags.FORCE_SYMBOLIC)
|
||||
|
||||
def _get_selected_albums(self):
|
||||
|
|
|
|||
|
|
@ -171,15 +171,13 @@ class PlaylistPanel(Adw.Bin):
|
|||
|
||||
def set_albumart(self, album, data):
|
||||
if album in self._selected_albums:
|
||||
self._standalone_pixbuf = None
|
||||
if data:
|
||||
# Load image and draw it
|
||||
try:
|
||||
self._standalone_pixbuf = Utils.load_pixbuf(data)
|
||||
except Exception:
|
||||
self._logger.exception("Failed to set albumart")
|
||||
self._cover_pixbuf = self._get_default_image()
|
||||
else:
|
||||
self._cover_pixbuf = self._get_default_image()
|
||||
# Show image
|
||||
GObject.idle_add(self._show_image)
|
||||
|
||||
|
|
@ -197,6 +195,8 @@ class PlaylistPanel(Adw.Bin):
|
|||
|
||||
cache = client.MCGCache(host, size)
|
||||
for album in playlist:
|
||||
grid_item = GridItem(album)
|
||||
|
||||
pixbuf = None
|
||||
# Load albumart thumbnail
|
||||
try:
|
||||
|
|
@ -207,12 +207,12 @@ class PlaylistPanel(Adw.Bin):
|
|||
except Exception:
|
||||
self._logger.exception("Failed to load albumart")
|
||||
if pixbuf is None:
|
||||
pixbuf = self._icon_theme.lookup_icon(
|
||||
Utils.STOCK_ICON_DEFAULT, None, self._item_size,
|
||||
self._item_size, Gtk.TextDirection.LTR,
|
||||
Gtk.IconLookupFlags.FORCE_SYMBOLIC)
|
||||
if pixbuf is not None:
|
||||
self._playlist_grid_model.append(GridItem(album, pixbuf))
|
||||
icon = self._get_default_icon(self._item_size, self._item_size)
|
||||
grid_item.set_icon(icon)
|
||||
else:
|
||||
grid_item.set_cover(pixbuf)
|
||||
|
||||
GObject.idle_add(self._playlist_grid_model.append, grid_item)
|
||||
|
||||
if self._playlist_stop.is_set():
|
||||
self._playlist_lock.release()
|
||||
|
|
@ -247,27 +247,26 @@ class PlaylistPanel(Adw.Bin):
|
|||
pixbuf = self._standalone_pixbuf
|
||||
# Check pixelbuffer
|
||||
if pixbuf is None:
|
||||
icon = self._get_default_icon(size_width, size_height)
|
||||
self.standalone_image.set_from_paintable(icon)
|
||||
self.standalone_image.set_pixel_size(min(size_width, size_height)/2)
|
||||
return
|
||||
|
||||
# Skalierungswert für Breite und Höhe ermitteln
|
||||
ratio_w = float(size_width) / float(pixbuf.get_width())
|
||||
ratio_h = float(size_height) / float(pixbuf.get_height())
|
||||
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
|
||||
ratio = min(ratio_w, ratio_h)
|
||||
ratio = min(ratio, 1)
|
||||
# Neue Breite und Höhe berechnen
|
||||
width = int(math.floor(pixbuf.get_width() * ratio))
|
||||
height = int(math.floor(pixbuf.get_height() * ratio))
|
||||
(width, height) = Utils.calculate_size(pixbuf.get_width(),
|
||||
pixbuf.get_height(), size_width,
|
||||
size_height)
|
||||
if width <= 0 or height <= 0:
|
||||
return
|
||||
# Pixelpuffer auf Oberfläche zeichnen
|
||||
self.standalone_image.set_from_pixbuf(
|
||||
pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
|
||||
self.standalone_image.set_pixel_size(min(width, height))
|
||||
self.standalone_image.show()
|
||||
|
||||
def _get_default_image(self):
|
||||
def _get_default_icon(self, width, height):
|
||||
return self._icon_theme.lookup_icon(Utils.STOCK_ICON_DEFAULT, None,
|
||||
512, 512, Gtk.TextDirection.LTR,
|
||||
width, height,
|
||||
Gtk.TextDirection.LTR,
|
||||
Gtk.IconLookupFlags.FORCE_SYMBOLIC)
|
||||
|
||||
def _get_selected_albums(self):
|
||||
|
|
|
|||
34
src/utils.py
34
src/utils.py
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
import gi
|
||||
import hashlib
|
||||
import math
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
|
||||
gi.require_version('Gtk', '4.0')
|
||||
|
|
@ -35,9 +37,17 @@ class Utils:
|
|||
if albumart:
|
||||
pixbuf = Utils.load_pixbuf(albumart)
|
||||
if pixbuf is not None:
|
||||
pixbuf = pixbuf.scale_simple(size, size,
|
||||
(width, height) = Utils.calculate_size(pixbuf.get_width(),
|
||||
pixbuf.get_height(),
|
||||
size, size)
|
||||
pixbuf = pixbuf.scale_simple(width, height,
|
||||
GdkPixbuf.InterpType.HYPER)
|
||||
pixbuf.savev(cache_url, 'jpeg', [], [])
|
||||
try:
|
||||
pixbuf.savev(cache_url, 'jpeg', [], [])
|
||||
except Exception as e:
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.warning("Failed to save thumbnail for album\"%s\": "
|
||||
"%s", album.get_title(), e)
|
||||
return pixbuf
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -72,6 +82,19 @@ class Utils:
|
|||
m.update(value.encode('utf-8'))
|
||||
return m.hexdigest()
|
||||
|
||||
@staticmethod
|
||||
def calculate_size(src_width, src_height, dest_width, dest_height):
|
||||
ratio_w = float(dest_width) / float(src_width)
|
||||
ratio_h = float(dest_height) / float(src_height)
|
||||
ratio = min(min(ratio_w, ratio_h), 1)
|
||||
if ratio == 1:
|
||||
return (src_width, src_height)
|
||||
|
||||
width = int(math.floor(src_width * ratio))
|
||||
height = int(math.floor(src_height * ratio))
|
||||
|
||||
return (width, height)
|
||||
|
||||
|
||||
class SortOrder:
|
||||
ARTIST = 0
|
||||
|
|
@ -86,11 +109,9 @@ class GridItem(GObject.GObject):
|
|||
tooltip = GObject.Property(type=str, default=None)
|
||||
cover = GObject.Property(type=Gdk.Paintable, default=None)
|
||||
|
||||
def __init__(self, album, cover):
|
||||
def __init__(self, album):
|
||||
super().__init__()
|
||||
self._album = album
|
||||
if cover:
|
||||
self.cover = Gdk.Texture.new_for_pixbuf(cover)
|
||||
self.tooltip = GObject.markup_escape_text("\n".join([
|
||||
album.get_title(), ', '.join(album.get_dates()),
|
||||
Utils.create_artists_label(album),
|
||||
|
|
@ -103,6 +124,9 @@ class GridItem(GObject.GObject):
|
|||
def set_cover(self, cover):
|
||||
self.cover = Gdk.Texture.new_for_pixbuf(cover)
|
||||
|
||||
def set_icon(self, icon):
|
||||
self.cover = icon
|
||||
|
||||
|
||||
class SearchFilter(Gtk.Filter):
|
||||
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ class Window(Adw.ApplicationWindow):
|
|||
self._setting_volume = False
|
||||
self._headerbar_connection_button_active = True
|
||||
self._headerbar_playpause_button_active = True
|
||||
self._width = 0
|
||||
self._height = 0
|
||||
|
||||
# Help/Shortcuts dialog
|
||||
self.set_help_overlay(ShortcutsDialog())
|
||||
|
|
@ -144,8 +146,6 @@ class Window(Adw.ApplicationWindow):
|
|||
self._settings.get_boolean(Window.SETTING_SORT_TYPE))
|
||||
|
||||
# Signals
|
||||
self.connect("notify::default-width", self.on_resize)
|
||||
self.connect("notify::default-height", self.on_resize)
|
||||
self.connect("notify::maximized", self.on_maximized)
|
||||
self.connect("notify::fullscreened", self.on_fullscreened)
|
||||
self._connection_panel.connect(
|
||||
|
|
@ -258,6 +258,22 @@ class Window(Adw.ApplicationWindow):
|
|||
self.on_menu_search_library)
|
||||
self.add_action(self._search_library_action)
|
||||
|
||||
def do_size_allocate(self, width, height, baseline):
|
||||
Gtk.ApplicationWindow().do_size_allocate(self, width, height, baseline)
|
||||
|
||||
if self._width == width and self._height == height:
|
||||
return
|
||||
self._width = width
|
||||
self._height = height
|
||||
|
||||
if width > 0:
|
||||
self._cover_panel.set_width(width)
|
||||
if not self._state.get_property(WindowState.PROP_MAXIMIZED):
|
||||
self._state.set_property(WindowState.PROP_WIDTH, width)
|
||||
self._state.set_property(WindowState.PROP_HEIGHT, height)
|
||||
GObject.idle_add(self._playlist_panel.set_size, width, height)
|
||||
GObject.idle_add(self._library_panel.set_size, width, height)
|
||||
|
||||
# Menu callbacks
|
||||
|
||||
def on_menu_connect(self, action, value):
|
||||
|
|
@ -287,17 +303,6 @@ class Window(Adw.ApplicationWindow):
|
|||
|
||||
# Window callbacks
|
||||
|
||||
def on_resize(self, widget, event):
|
||||
width = self.get_size(Gtk.Orientation.HORIZONTAL)
|
||||
height = self.get_size(Gtk.Orientation.VERTICAL)
|
||||
if width > 0:
|
||||
self._cover_panel.set_width(width)
|
||||
if not self._state.get_property(WindowState.PROP_MAXIMIZED):
|
||||
self._state.set_property(WindowState.PROP_WIDTH, width)
|
||||
self._state.set_property(WindowState.PROP_HEIGHT, height)
|
||||
GObject.idle_add(self._playlist_panel.set_size, width, height)
|
||||
GObject.idle_add(self._library_panel.set_size, width, height)
|
||||
|
||||
def on_maximized(self, widget, maximized):
|
||||
self._state.set_property(WindowState.PROP_MAXIMIZED, maximized is True)
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue