636 lines
22 KiB
Python
636 lines
22 KiB
Python
#!/usr/bin/env python3
|
|
|
|
|
|
import gi
|
|
gi.require_version('Gtk', '3.0')
|
|
import gettext
|
|
import logging
|
|
import math
|
|
import threading
|
|
|
|
from gi.repository import Gtk, GObject, GdkPixbuf
|
|
|
|
from mcg import client
|
|
from mcg.albumheaderbar import AlbumHeaderbar
|
|
from mcg.utils import SortOrder
|
|
from mcg.utils import Utils
|
|
|
|
|
|
|
|
|
|
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-toolbar.ui')
|
|
class LibraryToolbar(Gtk.ButtonBox):
|
|
__gtype_name__ = 'McgLibraryToolbar'
|
|
__gsignals__ = {
|
|
'select': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
|
|
'toggle-search': (GObject.SIGNAL_RUN_FIRST, None, (bool,)),
|
|
'update': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
|
'start-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
|
'end-scale': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
|
'sort': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
|
'sort-type': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,))
|
|
}
|
|
|
|
# Widgets
|
|
select_button = Gtk.Template.Child()
|
|
toolbar_search_bar = Gtk.Template.Child()
|
|
toolbar_popover = Gtk.Template.Child()
|
|
toolbar_sort_order_button = Gtk.Template.Child()
|
|
sort_artist = Gtk.Template.Child()
|
|
sort_title = Gtk.Template.Child()
|
|
sort_year = Gtk.Template.Child()
|
|
grid_scale = Gtk.Template.Child()
|
|
|
|
|
|
def __init__(self, item_size):
|
|
super().__init__()
|
|
|
|
# Toolbar menu
|
|
self.grid_scale.set_value(item_size)
|
|
self._toolbar_sort_buttons = {
|
|
SortOrder.ARTIST: self.sort_artist,
|
|
SortOrder.TITLE: self.sort_title,
|
|
SortOrder.YEAR: self.sort_year
|
|
}
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_select_toggled(self, widget):
|
|
self.emit('select', widget.get_active())
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_search_toggled(self, widget):
|
|
self.emit('toggle-search', widget.get_active())
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_update_clicked(self, widget):
|
|
self.emit('update')
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_grid_scale_change(self, widget, scroll, value):
|
|
self.emit('start-scale', value)
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_grid_scale_changed(self, widget, event):
|
|
self.emit('end-scale', self.grid_scale.get_value())
|
|
self.toolbar_popover.popdown()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_sort_toggled(self, widget):
|
|
if widget.get_active():
|
|
sort = [key for key, value in self._toolbar_sort_buttons.items() if value is widget][0]
|
|
self.emit('sort', sort)
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_sort_order_toggled(self, button):
|
|
if button.get_active():
|
|
sort_type = Gtk.SortType.DESCENDING
|
|
else:
|
|
sort_type = Gtk.SortType.ASCENDING
|
|
self.emit('sort-type', sort_type)
|
|
|
|
|
|
def get_grid_scale(self):
|
|
return self.grid_scale
|
|
|
|
|
|
def is_search_active(self):
|
|
return self.toolbar_search_bar.get_active()
|
|
|
|
|
|
def set_search_active(self, active):
|
|
self.toolbar_search_bar.set_active(active)
|
|
|
|
|
|
def exit_selection(self):
|
|
self.select_button.set_active(False)
|
|
|
|
|
|
|
|
|
|
@Gtk.Template(resource_path='/xyz/suruatoel/mcg/ui/library-panel.ui')
|
|
class LibraryPanel(Gtk.Stack):
|
|
__gtype_name__ = 'McgLibraryPanel'
|
|
__gsignals__ = {
|
|
'open-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
|
'close-standalone': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
|
'update': (GObject.SIGNAL_RUN_FIRST, None, ()),
|
|
'play': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
|
|
'queue': (GObject.SIGNAL_RUN_FIRST, None, (str,)),
|
|
'queue-multiple': (GObject.SIGNAL_RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)),
|
|
'item-size-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
|
'sort-order-changed': (GObject.SIGNAL_RUN_FIRST, None, (int,)),
|
|
'sort-type-changed': (GObject.SIGNAL_RUN_FIRST, None, (Gtk.SortType,)),
|
|
'albumart': (GObject.SIGNAL_RUN_FIRST, None, (str,))
|
|
}
|
|
|
|
|
|
# Widgets
|
|
panel_standalone = Gtk.Template.Child()
|
|
actionbar_revealer = Gtk.Template.Child()
|
|
# Filter/search bar
|
|
filter_bar = Gtk.Template.Child()
|
|
filter_entry = Gtk.Template.Child()
|
|
# Progress Bar
|
|
stack = Gtk.Template.Child()
|
|
progress_box = Gtk.Template.Child()
|
|
progress_image = Gtk.Template.Child()
|
|
progress_bar = Gtk.Template.Child()
|
|
scroll = Gtk.Template.Child()
|
|
# Library Grid
|
|
library_grid = Gtk.Template.Child()
|
|
# Standalone Image
|
|
standalone_stack = Gtk.Template.Child()
|
|
standalone_spinner = Gtk.Template.Child()
|
|
standalone_scroll = Gtk.Template.Child()
|
|
standalone_image = Gtk.Template.Child()
|
|
|
|
|
|
def __init__(self, client):
|
|
super().__init__()
|
|
self._logger = logging.getLogger(__name__)
|
|
self._client = client
|
|
self._buttons = {}
|
|
self._albums = None
|
|
self._host = "localhost"
|
|
self._filter_string = ""
|
|
self._item_size = 150
|
|
self._sort_order = SortOrder.YEAR
|
|
self._sort_type = Gtk.SortType.DESCENDING
|
|
self._grid_pixbufs = {}
|
|
self._old_ranges = {}
|
|
self._library_lock = threading.Lock()
|
|
self._library_stop = threading.Event()
|
|
self._icon_theme = Gtk.IconTheme.get_default()
|
|
self._standalone_pixbuf = None
|
|
self._selected_albums = []
|
|
self._allocation = (0, 0)
|
|
self._is_selected = False
|
|
|
|
# Widgets
|
|
self._toolbar = LibraryToolbar(self._item_size)
|
|
self._toolbar.connect('select', self.on_toolbar_select)
|
|
self._toolbar.connect('toggle-search', self.on_toolbar_toggle_search)
|
|
self._toolbar.connect('update', self.on_toolbar_update)
|
|
self._toolbar.connect('start-scale', self.on_toolbar_scale)
|
|
self._toolbar.connect('end-scale', self.on_toolbar_scaled)
|
|
self._toolbar.connect('sort', self.on_toolbar_sort)
|
|
self._toolbar.connect('sort-type', self.on_toolbar_sort_type)
|
|
# Header bar
|
|
self._headerbar_standalone = AlbumHeaderbar()
|
|
self._headerbar_standalone.connect('close', self.on_standalone_close_clicked)
|
|
# Progress Bar
|
|
self.progress_image.set_from_pixbuf(self._get_default_image())
|
|
# Library Grid: Model
|
|
self._library_grid_model = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str)
|
|
self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order)
|
|
self._library_grid_model.set_sort_column_id(2, self._sort_type)
|
|
self._library_grid_filter = self._library_grid_model.filter_new()
|
|
self._library_grid_filter.set_visible_func(self.on_filter_visible)
|
|
# Library Grid
|
|
self.library_grid.set_model(self._library_grid_filter)
|
|
self.library_grid.set_pixbuf_column(0)
|
|
self.library_grid.set_text_column(-1)
|
|
self.library_grid.set_tooltip_column(1)
|
|
|
|
|
|
def get_headerbar_standalone(self):
|
|
return self._headerbar_standalone
|
|
|
|
|
|
def get_toolbar(self):
|
|
return self._toolbar
|
|
|
|
|
|
def set_selected(self, selected):
|
|
self._is_selected = selected
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_resize(self, widget, event):
|
|
new_allocation = (widget.get_allocation().width, widget.get_allocation().height)
|
|
if new_allocation == self._allocation:
|
|
return
|
|
self._allocation = new_allocation
|
|
self._toolbar.get_grid_scale().clear_marks()
|
|
width = widget.get_allocation().width
|
|
|
|
lower = int(self._toolbar.get_grid_scale().get_adjustment().get_lower())
|
|
upper = int(self._toolbar.get_grid_scale().get_adjustment().get_upper())
|
|
countMin = max(int(width / upper), 1)
|
|
countMax = max(int(width / lower), 1)
|
|
for index in range(countMin, countMax):
|
|
pixel = int(width / index)
|
|
pixel = pixel - (2 * int(pixel / 100))
|
|
self._toolbar.get_grid_scale().add_mark(
|
|
pixel,
|
|
Gtk.PositionType.BOTTOM,
|
|
None
|
|
)
|
|
|
|
|
|
def on_toolbar_toggle_search(self, widget, active):
|
|
self.filter_bar.set_search_mode(active)
|
|
|
|
|
|
def on_toolbar_select(self, widget, active):
|
|
if active:
|
|
self.actionbar_revealer.set_reveal_child(True)
|
|
self.library_grid.set_selection_mode(Gtk.SelectionMode.MULTIPLE)
|
|
self.library_grid.get_style_context().add_class(Utils.CSS_SELECTION)
|
|
else:
|
|
self.actionbar_revealer.set_reveal_child(False)
|
|
self.library_grid.set_selection_mode(Gtk.SelectionMode.SINGLE)
|
|
self.library_grid.get_style_context().remove_class(Utils.CSS_SELECTION)
|
|
|
|
|
|
def on_toolbar_update(self, widget):
|
|
self.emit('update')
|
|
|
|
|
|
def on_toolbar_scale(self, widget, value):
|
|
size = math.floor(value)
|
|
range = self._toolbar.get_grid_scale().get_adjustment()
|
|
if size < range.get_lower() or size > range.get_upper():
|
|
return
|
|
self._item_size = size
|
|
GObject.idle_add(self.library_grid.set_item_padding, size / 100)
|
|
GObject.idle_add(self._set_widget_grid_size, self.library_grid, size, True)
|
|
|
|
|
|
def on_toolbar_scaled(self, widget, value):
|
|
size = round(value)
|
|
range = self._toolbar.get_grid_scale().get_adjustment()
|
|
if size < range.get_lower() or size > range.get_upper():
|
|
return False
|
|
self.emit('item-size-changed', size)
|
|
self._redraw()
|
|
return False
|
|
|
|
|
|
def on_toolbar_sort(self, widget, sort):
|
|
self._change_sort(sort)
|
|
|
|
|
|
def on_toolbar_sort_type(self, widget, sort_type):
|
|
self._sort_type = sort_type
|
|
self._library_grid_model.set_sort_column_id(2, sort_type)
|
|
self.emit('sort-type-changed', sort_type)
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_filter_bar_notify(self, widget, value):
|
|
if self._toolbar.is_search_active() is not self.filter_bar.get_search_mode():
|
|
self._toolbar.set_search_active(self.filter_bar.get_search_mode())
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_filter_entry_changed(self, widget):
|
|
self._filter_string = self.filter_entry.get_text()
|
|
GObject.idle_add(self._library_grid_filter.refilter)
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_library_grid_clicked(self, widget, path):
|
|
# Get selected album
|
|
path = self._library_grid_filter.convert_path_to_child_path(path)
|
|
iter = self._library_grid_model.get_iter(path)
|
|
id = self._library_grid_model.get_value(iter, 2)
|
|
album = self._albums[id]
|
|
self._selected_albums = [album]
|
|
self.emit('albumart', id)
|
|
|
|
# Show standalone album
|
|
if widget.get_selection_mode() == Gtk.SelectionMode.SINGLE:
|
|
# Set labels
|
|
self._headerbar_standalone.set_album(album)
|
|
|
|
# Show panel
|
|
self._open_standalone()
|
|
|
|
# Set cover loading indicator
|
|
self.standalone_stack.set_visible_child(self.standalone_spinner)
|
|
self.standalone_spinner.start()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_library_grid_selection_changed(self, widget):
|
|
self._selected_albums = []
|
|
for path in widget.get_selected_items():
|
|
path = self._library_grid_filter.convert_path_to_child_path(path)
|
|
iter = self._library_grid_model.get_iter(path)
|
|
id = self._library_grid_model.get_value(iter, 2)
|
|
self._selected_albums.insert(0, self._albums[id])
|
|
|
|
|
|
def on_filter_visible(self, model, iter, data):
|
|
id = model.get_value(iter, 2)
|
|
if not id in self._albums.keys():
|
|
return
|
|
album = self._albums[id]
|
|
return album.filter(self._filter_string)
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_selection_cancel_clicked(self, widget):
|
|
self._toolbar.exit_selection()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_selection_add_clicked(self, widget):
|
|
ids = [album.get_id() for album in self._selected_albums]
|
|
self.emit('queue-multiple', ids)
|
|
self._toolbar.exit_selection()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_standalone_scroll_size_allocate(self, widget, allocation):
|
|
self._resize_standalone_image()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_standalone_play_clicked(self, widget):
|
|
self.emit('play', self._selected_albums[0].get_id())
|
|
self._close_standalone()
|
|
|
|
|
|
@Gtk.Template.Callback()
|
|
def on_standalone_queue_clicked(self, widget):
|
|
self.emit('queue', self._selected_albums[0].get_id())
|
|
self._close_standalone()
|
|
|
|
|
|
def on_standalone_close_clicked(self, widget):
|
|
self._close_standalone()
|
|
|
|
|
|
def set_item_size(self, item_size):
|
|
if self._item_size != item_size:
|
|
self._item_size = item_size
|
|
self._toolbar.get_grid_scale().set_value(item_size)
|
|
self._redraw()
|
|
|
|
|
|
def get_item_size(self):
|
|
return self._item_size
|
|
|
|
|
|
def set_sort_order(self, sort):
|
|
if self._sort_order != sort:
|
|
button = self._toolbar_sort_buttons[sort]
|
|
if button and not button.get_active():
|
|
button.set_active(True)
|
|
self._sort_order = sort
|
|
self._library_grid_model.set_sort_func(2, self.compare_albums, self._sort_order)
|
|
|
|
|
|
def get_sort_order(self):
|
|
return self._sort_order
|
|
|
|
|
|
def set_sort_type(self, sort_type):
|
|
if self._sort_type != sort_type:
|
|
if sort_type:
|
|
sort_type_gtk = Gtk.SortType.DESCENDING
|
|
self.toolbar_sort_order_button.set_active(True)
|
|
else:
|
|
sort_type_gtk = Gtk.SortType.ASCENDING
|
|
self.toolbar_sort_order_button.set_active(False)
|
|
if self._sort_type != sort_type_gtk:
|
|
self._sort_type = sort_type_gtk
|
|
self._library_grid_model.set_sort_column_id(2, sort_type)
|
|
|
|
|
|
def get_sort_type(self):
|
|
return (self._sort_type != Gtk.SortType.ASCENDING)
|
|
|
|
|
|
def init_albums(self):
|
|
self.progress_bar.set_text(gettext.gettext("Loading albums"))
|
|
|
|
|
|
def load_albums(self):
|
|
self.progress_bar.pulse()
|
|
|
|
|
|
def set_albums(self, host, albums):
|
|
self._host = host
|
|
self._library_stop.set()
|
|
threading.Thread(target=self._set_albums, args=(host, albums, self._item_size,)).start()
|
|
|
|
|
|
def set_albumart(self, album, data):
|
|
if album in self._selected_albums:
|
|
if data:
|
|
# Load image and draw it
|
|
try:
|
|
self._standalone_pixbuf = Utils.load_pixbuf(data)
|
|
except Exception as e:
|
|
self._logger.exception("Failed to set albumart")
|
|
self._standalone_pixbuf = self._get_default_image()
|
|
else:
|
|
self._standalone_pixbuf = self._get_default_image()
|
|
# Show image
|
|
self._resize_standalone_image()
|
|
self.standalone_stack.set_visible_child(self.standalone_scroll)
|
|
self.standalone_spinner.stop()
|
|
|
|
|
|
def compare_albums(self, model, row1, row2, criterion):
|
|
id1 = model.get_value(row1, 2)
|
|
id2 = model.get_value(row2, 2)
|
|
|
|
if not id1 or not id2:
|
|
return
|
|
return client.MCGAlbum.compare(self._albums[id1], self._albums[id2], criterion)
|
|
|
|
|
|
def stop_threads(self):
|
|
self._library_stop.set()
|
|
|
|
|
|
def _change_sort(self, sort):
|
|
self._sort_order = sort
|
|
self._library_grid_model.set_sort_func(2, self.compare_albums, sort)
|
|
self.emit('sort-order-changed', sort)
|
|
|
|
|
|
def _set_albums(self, host, albums, size):
|
|
if not self._is_selected and albums != self._albums:
|
|
GObject.idle_add(
|
|
self.get_parent().child_set_property,
|
|
self,
|
|
'needs-attention',
|
|
True
|
|
)
|
|
self._library_lock.acquire()
|
|
self._library_stop.clear()
|
|
self._albums = albums
|
|
GObject.idle_add(self.stack.set_visible_child, self.progress_box)
|
|
GObject.idle_add(self.progress_bar.set_fraction, 0.0)
|
|
GObject.idle_add(self.library_grid.set_item_padding, size / 100)
|
|
self.library_grid.set_model(None)
|
|
self.library_grid.freeze_child_notify()
|
|
self._library_grid_model.clear()
|
|
|
|
i = 0
|
|
n = len(albums)
|
|
cache = client.MCGCache(host, size)
|
|
self._grid_pixbufs.clear()
|
|
for album_id in albums.keys():
|
|
album = albums[album_id]
|
|
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")
|
|
if pixbuf is None:
|
|
pixbuf = self._icon_theme.load_icon(
|
|
Utils.STOCK_ICON_DEFAULT,
|
|
self._item_size,
|
|
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE
|
|
)
|
|
if pixbuf is not None:
|
|
self._grid_pixbufs[album.get_id()] = pixbuf
|
|
self._library_grid_model.append([
|
|
pixbuf,
|
|
GObject.markup_escape_text("\n".join([
|
|
album.get_title(),
|
|
', '.join(album.get_dates()),
|
|
Utils.create_artists_label(album),
|
|
Utils.create_length_label(album)
|
|
])),
|
|
album_id
|
|
])
|
|
|
|
i += 1
|
|
GObject.idle_add(self.progress_bar.set_fraction, i/n)
|
|
GObject.idle_add(self.progress_bar.set_text, gettext.gettext("Loading images"))
|
|
if self._library_stop.is_set():
|
|
self._library_lock.release()
|
|
return
|
|
|
|
self.library_grid.set_model(self._library_grid_filter)
|
|
self.library_grid.thaw_child_notify()
|
|
self.library_grid.set_item_width(-1)
|
|
self._library_lock.release()
|
|
self.stack.set_visible_child(self.scroll)
|
|
|
|
|
|
def _set_widget_grid_size(self, grid_widget, size, vertical):
|
|
self._library_stop.set()
|
|
threading.Thread(target=self._set_widget_grid_size_thread, args=(grid_widget, size, vertical,)).start()
|
|
|
|
|
|
def _set_widget_grid_size_thread(self, grid_widget, size, vertical):
|
|
self._library_lock.acquire()
|
|
self._library_stop.clear()
|
|
grid_filter = grid_widget.get_model()
|
|
grid_model = grid_filter.get_model()
|
|
|
|
# get old_range
|
|
grid_widget_id = id(grid_widget)
|
|
if grid_widget_id not in self._old_ranges or self._old_ranges[grid_widget_id] is None:
|
|
self._old_ranges[grid_widget_id] = range(0, len(grid_filter))
|
|
old_range = self._old_ranges[grid_widget_id]
|
|
old_start = len(old_range) > 0 and old_range[0] or 0
|
|
old_end = len(old_range) > 0 and old_range[len(old_range)-1] + 1 or 0
|
|
|
|
# calculate visible range
|
|
w = (grid_widget.get_allocation().width // size) + (vertical and 0 or 1)
|
|
h = (grid_widget.get_allocation().height // size) + (vertical and 1 or 0)
|
|
c = w * h
|
|
vis_range = grid_widget.get_visible_range()
|
|
if vis_range is None:
|
|
self._library_lock.release()
|
|
return
|
|
(vis_start,), (vis_end,) = vis_range
|
|
vis_end = min(vis_start + c, len(grid_filter))
|
|
vis_range = range(vis_start, vis_end)
|
|
|
|
# set pixbuf
|
|
cur_start = min(old_start, vis_start)
|
|
cur_end = max(old_end, vis_end)
|
|
cur_range = range(cur_start, cur_end)
|
|
for index in cur_range:
|
|
iter = grid_filter.convert_iter_to_child_iter(grid_filter[index].iter)
|
|
if index in vis_range:
|
|
album_id = grid_model.get_value(iter, 2)
|
|
pixbuf = self._grid_pixbufs[album_id]
|
|
pixbuf = pixbuf.scale_simple(size, size, GdkPixbuf.InterpType.NEAREST)
|
|
else:
|
|
pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 1, 1)
|
|
grid_model.set_value(iter, 0, pixbuf)
|
|
|
|
if self._library_stop.is_set():
|
|
self._library_lock.release()
|
|
return
|
|
|
|
self._old_ranges[grid_widget_id] = vis_range
|
|
grid_widget.set_item_width(size)
|
|
|
|
self._library_lock.release()
|
|
|
|
|
|
def _redraw(self):
|
|
if self._albums is not None:
|
|
self.set_albums(self._host, self._albums)
|
|
|
|
|
|
def _open_standalone(self):
|
|
self.set_visible_child(self.panel_standalone)
|
|
self.emit('open-standalone')
|
|
|
|
|
|
def _close_standalone(self):
|
|
self.set_visible_child(self.get_children()[0])
|
|
self.emit('close-standalone')
|
|
|
|
|
|
def _resize_standalone_image(self):
|
|
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
|
|
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
|
|
"""
|
|
pixbuf = self._standalone_pixbuf
|
|
size = self.standalone_scroll.get_allocation()
|
|
# Check pixelbuffer
|
|
if pixbuf is None:
|
|
return
|
|
|
|
# Skalierungswert für Breite und Höhe ermitteln
|
|
ratioW = float(size.width) / float(pixbuf.get_width())
|
|
ratioH = float(size.height) / float(pixbuf.get_height())
|
|
# Kleineren beider Skalierungswerte nehmen, nicht Hochskalieren
|
|
ratio = min(ratioW, ratioH)
|
|
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))
|
|
if width <= 0 or height <= 0:
|
|
return
|
|
# Pixelpuffer auf Oberfläche zeichnen
|
|
self.standalone_image.set_allocation(self.standalone_scroll.get_allocation())
|
|
self.standalone_image.set_from_pixbuf(pixbuf.scale_simple(width, height, GdkPixbuf.InterpType.HYPER))
|
|
self.standalone_image.show()
|
|
|
|
|
|
def _get_default_image(self):
|
|
return self._icon_theme.load_icon(
|
|
Utils.STOCK_ICON_DEFAULT,
|
|
512,
|
|
Gtk.IconLookupFlags.FORCE_SVG & Gtk.IconLookupFlags.FORCE_SIZE
|
|
)
|
|
|
|
|
|
|
|
|