1# -*- coding: utf-8 -*-
2#
3# Picard, the next-generation MusicBrainz tagger
4#
5# Copyright (C) 2008, 2018-2019 Philipp Wolfer
6# Copyright (C) 2011, 2013 Michael Wiencek
7# Copyright (C) 2013, 2018 Laurent Monin
8# Copyright (C) 2016-2017 Sambhav Kothari
9# Copyright (C) 2018 Vishal Choudhary
10#
11# This program is free software; you can redistribute it and/or
12# modify it under the terms of the GNU General Public License
13# as published by the Free Software Foundation; either version 2
14# of the License, or (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
25
26from PyQt5 import (
27    QtCore,
28    QtGui,
29    QtWidgets,
30)
31
32from picard.config import get_config
33
34
35class RatingWidget(QtWidgets.QWidget):
36
37    def __init__(self, parent, track):
38        super().__init__(parent)
39        self._track = track
40        config = get_config()
41        self._maximum = config.setting["rating_steps"] - 1
42        try:
43            self._rating = int(track.metadata["~rating"] or 0)
44        except ValueError:
45            self._rating = 0
46        self._highlight = 0
47        self._star_pixmap = QtGui.QPixmap(":/images/star.png")
48        self._star_gray_pixmap = QtGui.QPixmap(":/images/star-gray.png")
49        self._star_size = 16
50        self._star_spacing = 2
51        self._offset = 16
52        self._width = self._maximum * (self._star_size + self._star_spacing) + self._offset
53        self._height = self._star_size + 6
54        self.setMaximumSize(self._width, self._height)
55        self.setMinimumSize(self._width, self._height)
56        self.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
57        self.setMouseTracking(True)
58
59    def sizeHint(self):
60        return QtCore.QSize(self._width, self._height)
61
62    def _setHighlight(self, highlight):
63        assert 0 <= highlight <= self._maximum
64        if highlight != self._highlight:
65            self._highlight = highlight
66            self.update()
67
68    def mousePressEvent(self, event):
69        if event.button() == QtCore.Qt.LeftButton:
70            x = event.x()
71            if x < self._offset:
72                return
73            rating = self._getRatingFromPosition(x)
74            if self._rating == rating:
75                rating = 0
76            self._rating = rating
77            self._update_track()
78            self.update()
79            event.accept()
80
81    def mouseMoveEvent(self, event):
82        self._setHighlight(self._getRatingFromPosition(event.x()))
83        event.accept()
84
85    def leaveEvent(self, event):
86        self._setHighlight(0)
87        event.accept()
88
89    def _getRatingFromPosition(self, position):
90        rating = int((position - self._offset) / (self._star_size + self._star_spacing)) + 1
91        if rating > self._maximum:
92            rating = self._maximum
93        return rating
94
95    def _update_track(self):
96        track = self._track
97        rating = str(self._rating)
98        track.metadata["~rating"] = rating
99        for file in track.files:
100            file.metadata["~rating"] = rating
101        config = get_config()
102        if config.setting["submit_ratings"]:
103            ratings = {("recording", track.id): self._rating}
104            self.tagger.mb_api.submit_ratings(ratings, None)
105
106    def paintEvent(self, event=None):
107        painter = QtGui.QPainter(self)
108        offset = self._offset
109        for i in range(1, self._maximum + 1):
110            if i <= self._rating or i <= self._highlight:
111                pixmap = self._star_pixmap
112            else:
113                pixmap = self._star_gray_pixmap
114            painter.drawPixmap(offset, 3, pixmap)
115            offset += self._star_size + self._star_spacing
116