Source code for sublime_music.ui.common.rating_button
"""
sublime-music
Copyright (C) 2021 LoveIsGrief
This program 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 3 of the License, or
(at your option) any later version.
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
"""
from gi.repository import GObject, Gtk
from sublime_music.adapters import AdapterManager
from sublime_music.ui.common import IconButton
[docs]class RatingButton(IconButton):
[docs] def __init__(self, *args, **kwargs):
kwargs["name"] = "ratingbutton"
kwargs["relief"] = False
super().__init__(*args, **kwargs)
[docs]class RatingButtonBox(Gtk.Box):
"""
A simple GtkBox containing buttons that allow rating something.
It doesn't know what it's rating just what the rating is when it changed
"""
__gsignals__ = {
# The rating has been set and is reflected in the UI
"rating-changed": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()),
# It has just been clicked, but no rating has been set
"rating-clicked": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, (int,)),
"rating-remove": (GObject.SignalFlags.RUN_FIRST, GObject.TYPE_NONE, ()),
}
MAX_VALUE = 5
[docs] def __init__(
self,
icon_rated: str = "star-full",
icon_unrated: str = "star-empty",
**kwargs,
):
kwargs["orientation"] = kwargs.get("orientation", Gtk.Orientation.HORIZONTAL)
super().__init__(**kwargs)
self.set_css_name("ratingbuttonbox")
self.set_property("valign", Gtk.Align.CENTER)
self.set_property("halign", Gtk.Align.CENTER)
self._rating: int | None = None
# Icons to use for the rating indicators/buttons
self.icon_rated = icon_rated
self.icon_unrated = icon_unrated
self._buttons = []
for i in range(1, self.MAX_VALUE + 1):
rating_button = RatingButton(self.icon_unrated)
rating_button.connect("clicked", self._on_rating_clicked, i)
self._buttons.append(rating_button)
self.pack_start(rating_button, False, False, 1)
@property
def rating(self) -> int | None:
return self._rating
@rating.setter
def rating(self, rating: int | None):
"""
Update the UI to reflect a new rating
"""
self.validate_rating(rating)
for i, _button in enumerate(self._buttons, start=1):
_button.set_icon(
self.icon_rated if rating is not None and i <= rating else self.icon_unrated
)
self._rating = rating
self.emit("rating-changed")
[docs] def validate_rating(self, rating: int | None):
if rating is not None and 1 >= rating > self.MAX_VALUE:
raise ValueError("Must pass a value between 1 and " + str(self.MAX_VALUE))
def _on_rating_clicked(self, button: IconButton, rating: int):
if AdapterManager.can_set_song_rating():
if self.rating == rating:
self.rating = None
self.emit("rating-remove")
else:
self.rating = rating
self.emit("rating-clicked", rating)