add standalone mode to library panel

This commit is contained in:
coderkun 2016-06-11 12:25:27 +02:00
parent 267973e72c
commit 48b2bcd05d
3 changed files with 318 additions and 95 deletions

View file

@ -2,6 +2,62 @@
<!-- Generated with glade 3.20.0 --> <!-- Generated with glade 3.20.0 -->
<interface> <interface>
<requires lib="gtk+" version="3.20"/> <requires lib="gtk+" version="3.20"/>
<object class="GtkHeaderBar" id="headerbar-library-standalone">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="headerbar-library-standalone-close">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_headerbar-library-standalone-close_clicked" swapped="no"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="icon_name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
<child type="title">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="headerbar-library-standalone-title">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Title</property>
<property name="selectable">True</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="headerbar-library-standalone-artist">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Artist</property>
<property name="selectable">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkAdjustment" id="library-scale-adjustment"> <object class="GtkAdjustment" id="library-scale-adjustment">
<property name="lower">100</property> <property name="lower">100</property>
<property name="upper">1000</property> <property name="upper">1000</property>
@ -364,6 +420,7 @@
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="kinetic_scrolling">False</property> <property name="kinetic_scrolling">False</property>
<property name="overlay_scrolling">False</property> <property name="overlay_scrolling">False</property>
<signal name="size-allocate" handler="on_cover-scroll_size_allocate" swapped="no"/>
<child> <child>
<object class="GtkViewport"> <object class="GtkViewport">
<property name="visible">True</property> <property name="visible">True</property>
@ -506,7 +563,12 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkBox" id="library-panel"> <object class="GtkStack" id="library-panel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-left-right</property>
<child>
<object class="GtkBox" id="library-panel-normal">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">False</property> <property name="can_focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
@ -554,19 +616,21 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow" id="library-scroll">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<child> <child>
<object class="GtkIconView" id="library-iconview"> <object class="GtkIconView" id="library-iconview">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="margin">0</property> <property name="margin">6</property>
<property name="selection_mode">none</property>
<property name="item_orientation">horizontal</property> <property name="item_orientation">horizontal</property>
<property name="row_spacing">0</property> <property name="row_spacing">0</property>
<property name="column_spacing">0</property> <property name="column_spacing">0</property>
<property name="tooltip_column">1</property> <property name="tooltip_column">1</property>
<property name="item_padding">5</property> <property name="item_padding">5</property>
<property name="activate_on_single_click">True</property>
<signal name="item-activated" handler="on_library-iconview_item_activated" swapped="no"/> <signal name="item-activated" handler="on_library-iconview_item_activated" swapped="no"/>
<style> <style>
<class name="no-bg"/> <class name="no-bg"/>
@ -580,11 +644,86 @@
<packing> <packing>
<property name="expand">True</property> <property name="expand">True</property>
<property name="fill">True</property> <property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
</object> </object>
<packing>
<property name="name">page0</property>
<property name="title" translatable="yes">page0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="library-panel-standalone">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkStack" id="library-standalone-stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSpinner" id="library-standalone-spinner">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="name">standalone-spinne</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="library-standalone-scroll">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="kinetic_scrolling">False</property>
<property name="overlay_scrolling">False</property>
<signal name="size-allocate" handler="on_library-standalone-scroll_size_allocate" swapped="no"/>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="library-standalone-image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="stock">gtk-missing-image</property>
<property name="icon_size">6</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">standalone-scroll</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkActionBar" id="library-standalone-actionbar">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">page1</property>
<property name="title" translatable="yes">page1</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing> <packing>
<property name="name">library</property> <property name="name">library</property>
<property name="title" translatable="yes">Library</property> <property name="title" translatable="yes">Library</property>

View file

@ -21,3 +21,7 @@ GtkIconView.cell:selected:focus {
iconview.view:hover { iconview.view:hover {
-gtk-icon-effect:highlight; -gtk-icon-effect:highlight;
} }
actionbar {
background-color:@theme_unfocused_bg_color;
}

View file

@ -77,6 +77,27 @@ class Application(Gtk.Application):
) )
def load_cover(url):
if not url:
return None
if url.startswith('/'):
try:
return GdkPixbuf.Pixbuf.new_from_file(url)
except Exception as e:
print(e)
return None
else:
try:
response = urllib.request.urlopen(url)
loader = GdkPixbuf.PixbufLoader()
loader.write(response.read())
loader.close()
return loader.get_pixbuf()
except Exception as e:
print(e)
return None
def load_thumbnail(cache, album, size): def load_thumbnail(cache, album, size):
cache_url = cache.create_filename(album) cache_url = cache.create_filename(album)
pixbuf = None pixbuf = None
@ -88,21 +109,7 @@ class Application(Gtk.Application):
print(e) print(e)
else: else:
url = album.get_cover() url = album.get_cover()
if url is not None: pixbuf = Application.load_cover(url)
if url.startswith('/'):
try:
pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_size(url, size, size)
except Exception as e:
print(e)
else:
try:
response = urllib.request.urlopen(url)
loader = GdkPixbuf.PixbufLoader()
loader.write(response.read())
loader.close()
pixbuf = loader.get_pixbuf().scale_simple(size, size, GdkPixbuf.InterpType.HYPER)
except Exception as e:
print(e)
if pixbuf is not None: if pixbuf is not None:
filetype = os.path.splitext(url)[1][1:] filetype = os.path.splitext(url)[1][1:]
if filetype == 'jpg': if filetype == 'jpg':
@ -872,7 +879,7 @@ class CoverPanel(mcg.Base):
url = album.get_cover() url = album.get_cover()
if url is not None and url is not "": if url is not None and url is not "":
# Load image and draw it # Load image and draw it
self._cover_pixbuf = self._load_cover(url) self._cover_pixbuf = Application.load_cover(url)
self._resize_image() self._resize_image()
else: else:
# Reset image # Reset image
@ -906,25 +913,6 @@ class CoverPanel(mcg.Base):
return True return True
def _load_cover(self, url):
if url.startswith('/'):
try:
return GdkPixbuf.Pixbuf.new_from_file(url)
except Exception as e:
print(e)
return None
else:
try:
response = urllib.request.urlopen(url)
loader = GdkPixbuf.PixbufLoader()
loader.write(response.read())
loader.close()
return loader.get_pixbuf()
except Exception as e:
print(e)
return None
def _resize_image(self): def _resize_image(self):
"""Diese Methode skaliert das geladene Bild aus dem Pixelpuffer """Diese Methode skaliert das geladene Bild aus dem Pixelpuffer
auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse auf die Größe des Fensters unter Beibehalt der Seitenverhältnisse
@ -1090,10 +1078,18 @@ class LibraryPanel(mcg.Base):
self._library_lock = threading.Lock() self._library_lock = threading.Lock()
self._library_stop = threading.Event() self._library_stop = threading.Event()
self._icon_theme = Gtk.IconTheme.get_default() self._icon_theme = Gtk.IconTheme.get_default()
self._standalone_pixbuf = None
self._selected_albums = []
# Widgets # Widgets
self._appwindow = builder.get_object('appwindow')
self._panel = builder.get_object('library-panel') self._panel = builder.get_object('library-panel')
self._toolbar = builder.get_object('library-toolbar') self._toolbar = builder.get_object('library-toolbar')
self._headerbar = builder.get_object('headerbar')
self._headerbar_standalone = builder.get_object('headerbar-library-standalone')
self._panel_normal = builder.get_object('library-panel-normal')
self._panel_standalone = builder.get_object('library-panel-standalone')
# Filter/search bar # Filter/search bar
self._filter_bar = builder.get_object('library-filter-bar') self._filter_bar = builder.get_object('library-filter-bar')
self._filter_entry = builder.get_object('library-filter') self._filter_entry = builder.get_object('library-filter')
@ -1122,6 +1118,19 @@ class LibraryPanel(mcg.Base):
self._library_grid.set_pixbuf_column(0) self._library_grid.set_pixbuf_column(0)
self._library_grid.set_text_column(-1) self._library_grid.set_text_column(-1)
self._library_grid.set_tooltip_column(1) self._library_grid.set_tooltip_column(1)
# Standalon labels
self._standalone_title = builder.get_object('headerbar-library-standalone-title')
self._standalone_artist = builder.get_object('headerbar-library-standalone-artist')
# Standalone Image
self._standalone_stack = builder.get_object('library-standalone-stack')
self._standalone_spinner = builder.get_object('library-standalone-spinner')
self._standalone_scroll = builder.get_object('library-standalone-scroll')
self._standalone_image = builder.get_object('library-standalone-image')
# Action bar
action_bar = builder.get_object('library-standalone-actionbar')
play_button = Gtk.Button('play')
play_button.connect('clicked', self.on_standalone_play_clicked)
action_bar.pack_end(play_button)
def get(self): def get(self):
@ -1142,7 +1151,9 @@ class LibraryPanel(mcg.Base):
'on_library-toolbar-sort-order_toggled': self.on_sort_order_toggled, 'on_library-toolbar-sort-order_toggled': self.on_sort_order_toggled,
'on_library-filter-bar_notify': self.on_filter_bar_notify, 'on_library-filter-bar_notify': self.on_filter_bar_notify,
'on_library-filter_search_changed': self.on_filter_entry_changed, 'on_library-filter_search_changed': self.on_filter_entry_changed,
'on_library-iconview_item_activated': self.on_library_grid_clicked 'on_library-iconview_item_activated': self.on_library_grid_clicked,
'on_library-standalone-scroll_size_allocate': self.on_standalone_scroll_size_allocate,
'on_headerbar-library-standalone-close_clicked': self.on_standalone_close_clicked
} }
@ -1199,9 +1210,23 @@ class LibraryPanel(mcg.Base):
def on_library_grid_clicked(self, widget, path): def on_library_grid_clicked(self, widget, path):
# Get selected album
path = self._library_grid_filter.convert_path_to_child_path(path) path = self._library_grid_filter.convert_path_to_child_path(path)
iter = self._library_grid_model.get_iter(path) iter = self._library_grid_model.get_iter(path)
self._callback(LibraryPanel.SIGNAL_PLAY, self._library_grid_model.get_value(iter, 2)) hash = self._library_grid_model.get_value(iter, 2)
album = self._albums[hash]
self._selected_albums = [album]
# Set labels
self._standalone_title.set_text(album.get_title())
self._standalone_artist.set_text(", ".join(album.get_artists()))
# Show panel
self._panel.set_visible_child(self._panel_standalone)
self._appwindow.set_titlebar(self._headerbar_standalone)
# Load cover
threading.Thread(target=self._show_standalone_image, args=(album,)).start()
def on_filter_visible(self, model, iter, data): def on_filter_visible(self, model, iter, data):
@ -1212,6 +1237,19 @@ class LibraryPanel(mcg.Base):
return album.filter(self._filter_string) return album.filter(self._filter_string)
def on_standalone_scroll_size_allocate(self, widget, allocation):
self._resize_standalone_image()
def on_standalone_play_clicked(self, widget):
self._callback(LibraryPanel.SIGNAL_PLAY, self._selected_albums[0].get_hash())
def on_standalone_close_clicked(self, widget):
self._panel.set_visible_child(self._panel.get_children()[0])
self._appwindow.set_titlebar(self._headerbar)
def set_item_size(self, item_size): def set_item_size(self, item_size):
if self._item_size != item_size: if self._item_size != item_size:
self._item_size = item_size self._item_size = item_size
@ -1282,7 +1320,7 @@ class LibraryPanel(mcg.Base):
self._library_lock.acquire() self._library_lock.acquire()
self._library_stop.clear() self._library_stop.clear()
self._albums = albums self._albums = albums
self._progress_revealer.set_reveal_child(True) GObject.idle_add(self._progress_revealer.set_reveal_child, True)
GObject.idle_add(self._progress_bar.set_fraction, 0.0) GObject.idle_add(self._progress_bar.set_fraction, 0.0)
self._library_grid.set_model(None) self._library_grid.set_model(None)
self._library_grid.freeze_child_notify() self._library_grid.freeze_child_notify()
@ -1386,6 +1424,48 @@ class LibraryPanel(mcg.Base):
self.set_albums(self._host, self._albums) self.set_albums(self._host, self._albums)
def _show_standalone_image(self, album):
self._standalone_stack.set_visible_child(self._standalone_spinner)
self._standalone_spinner.start()
url = album.get_cover()
if url is not None and url is not "":
# Load image and draw it
self._standalone_pixbuf = Application.load_cover(url)
self._resize_standalone_image()
else:
# Reset image
self._standalone_image.clear()
self._standalone_stack.set_visible_child(self._standalone_scroll)
self._standalone_spinner.stop()
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()
class StackSwitcher(mcg.Base): class StackSwitcher(mcg.Base):