Commit c311afbe authored by Marinus Schraal's avatar Marinus Schraal

disclistboxwidget: Factor out SongWidget

Move the SongWidget logic to a separate class and use Gtk.Template. Cleanup
and improve where applicable.

Rename the TrackWidget.ui to SongWidget.ui for consistency.
parent e031da13
......@@ -2,7 +2,7 @@
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkEventBox" id="eventbox1">
<template class="SongWidget" parent="GtkEventBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
......@@ -21,7 +21,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="image1">
<object class="GtkImage" id="_play_icon">
<property name="can_focus">False</property>
<property name="icon_size">1</property>
</object>
......@@ -34,12 +34,13 @@
</packing>
</child>
<child>
<object class="GtkCheckButton" id="select">
<object class="GtkCheckButton" id="_select_button">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="receives_default">False</property>
<property name="no_show_all">True</property>
<property name="draw_indicator">True</property>
<signal name="toggled" handler="_on_selection_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
......@@ -48,7 +49,7 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="num">
<object class="GtkLabel" id="_number_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
......@@ -78,7 +79,7 @@
<property name="margin_top">1</property>
<property name="margin_bottom">1</property>
<child>
<object class="GtkLabel" id="title">
<object class="GtkLabel" id="_title_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
......@@ -95,7 +96,7 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="duration">
<object class="GtkLabel" id="_duration_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
......@@ -117,15 +118,18 @@
</packing>
</child>
<child>
<object class="GtkEventBox" id="starevent">
<object class="GtkEventBox" id="_star_eventbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="visible_window">True</property>
<signal name="button-release-event" handler="_on_star_toggle" swapped="no"/>
<signal name="enter-notify-event" handler="_on_star_hover" swapped="no"/>
<signal name="leave-notify-event" handler="_on_star_unhover" swapped="no"/>
<child>
<object class="StarImage" id="starimage">
<object class="StarImage" id="_star_image">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">center</property>
......@@ -144,5 +148,5 @@
</child>
</object>
</child>
</object>
</template>
</interface>
......@@ -12,8 +12,8 @@
<file preprocess="xml-stripblanks">ArtistAlbumsWidget.ui</file>
<file preprocess="xml-stripblanks">PlayerToolbar.ui</file>
<file preprocess="xml-stripblanks">SelectionToolbar.ui</file>
<file preprocess="xml-stripblanks">SongWidget.ui</file>
<file preprocess="xml-stripblanks">headerbar.ui</file>
<file preprocess="xml-stripblanks">TrackWidget.ui</file>
<file preprocess="xml-stripblanks">NoMusic.ui</file>
<file preprocess="xml-stripblanks">PlaylistContextMenu.ui</file>
<file preprocess="xml-stripblanks">PlaylistControls.ui</file>
......
......@@ -30,6 +30,7 @@ from gnomemusic.albumartcache import Art, ArtImage
from gnomemusic.grilo import grilo
from gnomemusic.gstplayer import Playback
from gnomemusic.widgets.disclistboxwidget import DiscBox, DiscListBox
from gnomemusic.widgets.songwidget import SongWidget
import gnomemusic.utils as utils
......@@ -241,7 +242,7 @@ class AlbumWidget(Gtk.EventBox):
return
if self._selection_mode:
song_widget.check_button.toggled()
song_widget.selected = not song_widget.selected
return
self._player.stop()
......@@ -306,21 +307,15 @@ class AlbumWidget(Gtk.EventBox):
song = playlist[_iter][player.Field.SONG]
song_widget = song.song_widget
self._duration += song.get_duration()
context = song_widget.title.get_style_context()
if (song == current_song):
song_widget.now_playing_sign.show()
context.remove_class('dim-label')
context.add_class('playing-song-label')
song_widget.state = SongWidget.State.PLAYING
song_passed = True
elif (song_passed):
song_widget.now_playing_sign.hide()
context.remove_class('dim-label')
context.remove_class('playing-song-label')
# Counter intuitive, but this is due to call order.
song_widget.state = SongWidget.State.UNPLAYED
else:
song_widget.now_playing_sign.hide()
context.remove_class('playing-song-label')
context.add_class('dim-label')
song_widget.state = SongWidget.State.PLAYED
_iter = playlist.iter_next(_iter)
......
......@@ -29,6 +29,7 @@ from gi.repository import GObject, Gtk
from gnomemusic import log
from gnomemusic.widgets.artistalbumwidget import ArtistAlbumWidget
from gnomemusic.widgets.songwidget import SongWidget
logger = logging.getLogger(__name__)
......@@ -149,21 +150,15 @@ class ArtistAlbumsWidget(Gtk.Box):
itr = playlist.iter_next(itr)
continue
context = song_widget.title.get_style_context()
if (song == current_song):
song_widget.now_playing_sign.show()
context.remove_class('dim-label')
context.add_class('playing-song-label')
song_widget.state = SongWidget.State.PLAYING
song_passed = True
elif (song_passed):
song_widget.now_playing_sign.hide()
context.remove_class('dim-label')
context.remove_class('playing-song-label')
# Counter intuitive, but this is due to call order.
song_widget.state = SongWidget.State.UNPLAYED
else:
song_widget.now_playing_sign.hide()
context.remove_class('playing-song-label')
context.add_class('dim-label')
song_widget.state = SongWidget.State.PLAYED
itr = playlist.iter_next(itr)
return False
......@@ -175,11 +170,8 @@ class ArtistAlbumsWidget(Gtk.Box):
while itr:
song = self._model[itr][5]
song_widget = song.song_widget
if song_widget.can_be_played:
song_widget.now_playing_sign.hide()
context = song_widget.title.get_style_context()
context.remove_class('playing-song-label')
context.remove_class('dim-label')
song_widget.state = SongWidget.State.UNPLAYED
itr = self._model.iter_next(itr)
return False
......
......@@ -22,13 +22,11 @@
# code, but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version.
from gettext import gettext as _
from gi.repository import Gdk, GObject, Gtk
from gnomemusic import log
from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists, StaticPlaylists
from gnomemusic.widgets.songwidget import SongWidget
import gnomemusic.utils as utils
......@@ -44,48 +42,49 @@ class StarImage(Gtk.Image):
super().__init__()
self._favorite = False
self._hover = False
self.get_style_context().add_class("star")
self.show_all()
@GObject.Property(type=bool, default=False)
@log
def favorite(self):
"""Return the current state of the widget
:return: The state of the widget
:rtype: bool
"""
return self._favorite
@favorite.setter
@log
def set_favorite(self, favorite):
def favorite(self, value):
"""Set favorite
Set the current widget as favorite or not.
:param bool favorite: Value to switch the widget state to
:param bool value: Value to switch the widget state to
"""
self._favorite = favorite
self._favorite = value
if self._favorite:
self.set_state_flags(Gtk.StateFlags.SELECTED, False)
else:
self.unset_state_flags(Gtk.StateFlags.SELECTED)
@GObject.Property(type=bool, default=False)
@log
def get_favorite(self):
"""Return the current state of the widget
:return: The state of the widget
:rtype: bool
"""
return self._favorite
def hover(self):
return self._hover
@hover.setter
@log
def toggle_favorite(self):
"""Toggle the widget state"""
self._favorite = not self._favorite
self.set_favorite(self._favorite)
@log
def hover(self, widget, event, data):
self.set_state_flags(Gtk.StateFlags.PRELIGHT, False)
@log
def unhover(self, widget, event, data):
self.unset_state_flags(Gtk.StateFlags.PRELIGHT)
def hover(self, value):
if value:
self.set_state_flags(Gtk.StateFlags.PRELIGHT, False)
else:
self.unset_state_flags(Gtk.StateFlags.PRELIGHT)
class DiscSongsFlowBox(Gtk.FlowBox):
......@@ -142,11 +141,8 @@ class DiscBox(Gtk.Box):
'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
'selection-toggle': (GObject.SignalFlags.RUN_FIRST, None, ()),
'song-activated': (GObject.SignalFlags.RUN_FIRST, None, (Gtk.Widget,))
}
_playlists = Playlists.get_default()
def __repr__(self):
return '<DiscBox>'
......@@ -208,7 +204,7 @@ class DiscBox(Gtk.Box):
:param bool show_duration: Display the song durations
"""
def child_show_duration(child):
child.get_child().duration.set_visible(show_duration)
child.get_child().show_duration = show_duration
self._disc_songs_flowbox.foreach(child_show_duration)
......@@ -220,7 +216,7 @@ class DiscBox(Gtk.Box):
switches
"""
def child_show_favorites(child):
child.get_child().starevent.set_visible(show_favorites)
child.get_child().show_favorite = show_favorites
self._disc_songs_flowbox.foreach(child_show_favorites)
......@@ -231,7 +227,7 @@ class DiscBox(Gtk.Box):
:param bool show_song_number: Display the song number
"""
def child_show_song_number(child):
child.get_child().number.set_visible(show_song_number)
child.get_child().show_song_number = show_song_number
self._disc_songs_flowbox.foreach(child_show_song_number)
......@@ -272,7 +268,7 @@ class DiscBox(Gtk.Box):
def _get_selected(self, child):
song_widget = child.get_child()
if song_widget.check_button.get_active():
if song_widget.selected:
itr = song_widget.itr
self._selected_items.append(self._model[itr][5])
......@@ -305,9 +301,7 @@ class DiscBox(Gtk.Box):
:returns: A complete song widget
:rtype: Gtk.EventBox
"""
builder = Gtk.Builder()
builder.add_from_resource('/org/gnome/Music/TrackWidget.ui')
song_widget = builder.get_object('eventbox1')
song_widget = SongWidget(song)
self._songs.append(song_widget)
title = utils.get_media_title(song)
......@@ -318,64 +312,14 @@ class DiscBox(Gtk.Box):
song_widget.itr = itr
song_widget.model = self._model
song_number = song.get_track_number()
if song_number == 0:
song_number = ""
song_widget.number = builder.get_object('num')
song_widget.number.set_label(str(song_number))
song_widget.number.set_no_show_all(True)
song_widget.title = builder.get_object('title')
song_widget.title.set_text(title)
song_widget.title.set_max_width_chars(50)
song_widget.duration = builder.get_object('duration')
time = utils.seconds_to_string(song.get_duration())
song_widget.duration.set_text(time)
song_widget.check_button = builder.get_object('select')
song_widget.check_button.set_visible(False)
song_widget.check_button.connect('toggled',
self._check_button_toggled,
song_widget)
song_widget.now_playing_sign = builder.get_object('image1')
song_widget.now_playing_sign.set_from_icon_name(
'media-playback-start-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
song_widget.now_playing_sign.set_no_show_all(True)
song_widget.can_be_played = True
song_widget.connect('button-release-event', self._song_activated)
song_widget.connect('selection-changed', self._on_selection_changed)
song_widget.star_image = builder.get_object('starimage')
song_widget.star_image.set_favorite(song.get_favourite())
song_widget.star_image.set_visible(True)
song_widget.starevent = builder.get_object('starevent')
song_widget.starevent.connect('button-release-event',
self._toggle_favorite,
song_widget)
song_widget.starevent.connect('enter-notify-event',
song_widget.star_image.hover, None)
song_widget.starevent.connect('leave-notify-event',
song_widget.star_image.unhover, None)
return song_widget
@log
def _toggle_favorite(self, widget, event, song_widget):
if event.button == Gdk.BUTTON_PRIMARY:
song_widget.star_image.toggle_favorite()
# FIXME: ugleh. Should probably be triggered by a
# signal.
favorite = song_widget.star_image.get_favorite()
grilo.set_favorite(self._model[song_widget.itr][5], favorite)
self._playlists.update_static_playlist(StaticPlaylists.Favorites)
return True
@log
def _check_button_toggled(self, widget, song_widget):
def _on_selection_changed(self, widget):
self.emit('selection-changed')
return True
......@@ -383,10 +327,7 @@ class DiscBox(Gtk.Box):
@log
def _toggle_widget_selection(self, child):
song_widget = child.get_child()
song_widget.check_button.set_visible(self._selection_mode)
if self._selection_mode is False:
if song_widget.check_button.get_active():
song_widget.check_button.set_active(False)
song_widget.selection_mode = self._selection_mode
@log
def _song_activated(self, widget, event):
......@@ -415,8 +356,8 @@ class DiscBox(Gtk.Box):
song_widget = model[itr][5].song_widget
selected = model[itr][6]
if selected != song_widget.check_button.get_active():
song_widget.check_button.set_active(selected)
if selected != song_widget.selected:
song_widget.selected = selected
return True
......
# Copyright © 2018 The GNOME Music developers
#
# GNOME Music is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# GNOME Music is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with GNOME Music; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# The GNOME Music authors hereby grant permission for non-GPL compatible
# GStreamer plugins to be used and distributed together with GStreamer
# and GNOME Music. This permission is above and beyond the permissions
# granted by the GPL license by which GNOME Music is covered. If you
# modify this code, you may extend this exception to your version of the
# code, but you are not obligated to do so. If you do not wish to do so,
# delete this exception statement from your version.
from enum import IntEnum
from gi.repository import Gdk, GObject, Gtk
from gnomemusic import log
from gnomemusic import utils
from gnomemusic.grilo import grilo
from gnomemusic.playlists import Playlists, StaticPlaylists
@Gtk.Template(resource_path='/org/gnome/Music/SongWidget.ui')
class SongWidget(Gtk.EventBox):
"""The single song widget used in DiscListBox
Contains
* play icon (depending on state)
* selection check box (optional)
* song number on disc (optional)
* song title
* song duration (optional)
* favorite/star picker (optional)
"""
__gtype_name__ = 'SongWidget'
__gsignals__ = {
'selection-changed': (GObject.SignalFlags.RUN_FIRST, None, ()),
}
selected = GObject.Property(type=bool, default=False)
show_duration = GObject.Property(type=bool, default=True)
show_favorite = GObject.Property(type=bool, default=True)
show_song_number = GObject.Property(type=bool, default=True)
_playlists = Playlists.get_default()
_select_button = Gtk.Template.Child()
_number_label = Gtk.Template.Child()
_title_label = Gtk.Template.Child()
_duration_label = Gtk.Template.Child()
_star_eventbox = Gtk.Template.Child()
_star_image = Gtk.Template.Child()
_play_icon = Gtk.Template.Child()
class State(IntEnum):
"""The state of the SongWidget
"""
PLAYED = 0
PLAYING = 1
UNPLAYED = 2
@log
def __init__(self, media):
super().__init__()
self._media = media
self._selection_mode = False
self._state = SongWidget.State.UNPLAYED
song_number = media.get_track_number()
if song_number == 0:
song_number = ""
self._number_label.set_text(str(song_number))
title = utils.get_media_title(media)
self._title_label.set_max_width_chars(50)
self._title_label.set_text(title)
time = utils.seconds_to_string(media.get_duration())
self._duration_label.set_text(time)
self._star_image.favorite = media.get_favourite()
self._select_button.set_visible(False)
self._play_icon.set_from_icon_name(
'media-playback-start-symbolic', Gtk.IconSize.SMALL_TOOLBAR)
self._play_icon.set_no_show_all(True)
self.bind_property(
'selected', self._select_button, 'active',
GObject.BindingFlags.BIDIRECTIONAL |
GObject.BindingFlags.SYNC_CREATE)
self.bind_property(
'show-duration', self._duration_label, 'visible',
GObject.BindingFlags.SYNC_CREATE)
self._duration_label.set_no_show_all(True)
self.bind_property(
'show-favorite', self._star_eventbox, 'visible',
GObject.BindingFlags.SYNC_CREATE)
self._star_eventbox.set_no_show_all(True)
self.bind_property(
'show-song-number', self._number_label, 'visible',
GObject.BindingFlags.SYNC_CREATE)
self._number_label.set_no_show_all(True)
@Gtk.Template.Callback()
@log
def _on_selection_changed(self, klass):
self.emit('selection-changed')
@Gtk.Template.Callback()
@log
def _on_star_toggle(self, widget, event):
if event.button != Gdk.BUTTON_PRIMARY:
return False
favorite = not self._star_image.favorite
self._star_image.favorite = favorite
# TODO: Rework and stop updating widgets from here directly.
grilo.set_favorite(self._media, favorite)
self._playlists.update_static_playlist(StaticPlaylists.Favorites)
return True
@Gtk.Template.Callback()
@log
def _on_star_hover(self, widget, event):
self._star_image.hover = True
@Gtk.Template.Callback()
@log
def _on_star_unhover(self, widget, event):
self._star_image.hover = False
@GObject.Property(type=bool, default=False)
@log
def selection_mode(self):
"""Selection mode
:returns: Selection mode
:rtype: bool
"""
return self._selection_mode
@selection_mode.setter
@log
def selection_mode(self, value):
"""Set the selection mode
:param bool value: Selection mode
"""
self._selection_mode = value
self._select_button.set_visible(value)
if not value:
self.selected = False
@GObject.Property
@log
def state(self):
"""State of the widget
:returns: Widget state
:rtype: SongWidget.State
"""
return self._state
@state.setter
def state(self, value):
"""Set state of the of widget
This influences the look of the widgets label and if there is a
song play indicator being shown.
:param SongWidget.State value: Widget state
"""
self._state = value
style_ctx = self._title_label.get_style_context()
style_ctx.remove_class('dim-label')
style_ctx.remove_class('playing-song-label')
self._play_icon.set_visible(False)
if value == SongWidget.State.PLAYED:
style_ctx.add_class('dim-label')
elif value == SongWidget.State.PLAYING:
self._play_icon.set_visible(True)
style_ctx.add_class('playing-song-label')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment