1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006-2007 Sebastian Trueg <trueg@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kratingwidget.h"
9#include "kratingpainter.h"
10
11#include <QIcon>
12#include <QMouseEvent>
13#include <QPainter>
14#include <QPixmap>
15
16class KRatingWidgetPrivate
17{
18public:
19 int rating = 0;
20 int hoverRating = -1;
21 int pixSize = 16;
22
23 KRatingPainter ratingPainter;
24};
25
26KRatingWidget::KRatingWidget(QWidget *parent)
27 : QFrame(parent)
28 , d(new KRatingWidgetPrivate())
29{
30 setMouseTracking(true);
31}
32
33KRatingWidget::~KRatingWidget() = default;
34
35void KRatingWidget::setCustomPixmap(const QPixmap &pix)
36{
37 d->ratingPainter.setCustomPixmap(pix);
38 update();
39}
40
41void KRatingWidget::setIcon(const QIcon &icon)
42{
43 d->ratingPainter.setIcon(icon);
44 update();
45}
46
47void KRatingWidget::setPixmapSize(int size)
48{
49 d->pixSize = size;
50 updateGeometry();
51}
52
53int KRatingWidget::spacing() const
54{
55 return d->ratingPainter.spacing();
56}
57
58QIcon KRatingWidget::icon() const
59{
60 return d->ratingPainter.icon();
61}
62
63void KRatingWidget::setSpacing(int s)
64{
65 d->ratingPainter.setSpacing(s);
66 update();
67}
68
69Qt::Alignment KRatingWidget::alignment() const
70{
71 return d->ratingPainter.alignment();
72}
73
74void KRatingWidget::setAlignment(Qt::Alignment align)
75{
76 d->ratingPainter.setAlignment(align);
77 update();
78}
79
80Qt::LayoutDirection KRatingWidget::layoutDirection() const
81{
82 return d->ratingPainter.layoutDirection();
83}
84
85void KRatingWidget::setLayoutDirection(Qt::LayoutDirection direction)
86{
87 d->ratingPainter.setLayoutDirection(direction);
88 update();
89}
90
91int KRatingWidget::rating() const
92{
93 return d->rating;
94}
95
96int KRatingWidget::maxRating() const
97{
98 return d->ratingPainter.maxRating();
99}
100
101bool KRatingWidget::halfStepsEnabled() const
102{
103 return d->ratingPainter.halfStepsEnabled();
104}
105
106void KRatingWidget::setRating(int rating)
107{
108 if (rating != d->rating) {
109 d->rating = rating;
110 d->hoverRating = rating;
111 Q_EMIT ratingChanged(rating);
112 update();
113 }
114}
115
116void KRatingWidget::setMaxRating(int max)
117{
118 d->ratingPainter.setMaxRating(max);
119 update();
120}
121
122void KRatingWidget::setHalfStepsEnabled(bool enabled)
123{
124 d->ratingPainter.setHalfStepsEnabled(enabled);
125 update();
126}
127
128static inline int adjustedHoverRating(bool halfStep, int hoverRating, int rating)
129{
130 // intentionally skip zero, or half step is disabled.
131 if (!halfStep || hoverRating == 0) {
132 return hoverRating;
133 }
134
135 // See bug 171343, if we click on a star we want it to be full star, click again
136 // make it half, click third time make it clear.
137
138 // round up hoverRating to next full star rating
139 const int hoveredFullStarRating = hoverRating + (hoverRating % 2);
140 // Check if the star under mouse is the last half or whole star of the rating.
141 if (hoveredFullStarRating == rating || hoveredFullStarRating == rating + 1) {
142 // If current pointed star is not empty, next rating will be rating - 1
143 // if we point at 4th star and rating is 8 (4 star), next click will make it 7
144 // if we point at 4th star and rating is 7 (3.5 star), next click will make it 6
145 hoverRating = rating - 1;
146 } else {
147 // otherwise make it a full star rating
148 hoverRating = hoveredFullStarRating;
149 }
150 return hoverRating;
151}
152
153void KRatingWidget::mousePressEvent(QMouseEvent *e)
154{
155 if (e->button() == Qt::LeftButton) {
156 d->hoverRating = adjustedHoverRating(halfStep: halfStepsEnabled(), hoverRating: d->ratingPainter.ratingFromPosition(rect: contentsRect(), pos: e->pos()), rating: d->rating);
157 // avoid set a rating to something less than zero, it may happen if widget is scaled and
158 // mouse is clicked outside the star region.
159 if (d->hoverRating >= 0) {
160 setRating(d->hoverRating);
161 }
162 }
163}
164
165void KRatingWidget::mouseMoveEvent(QMouseEvent *e)
166{
167 // when moving the mouse we show the user what the result of clicking will be
168 const int prevHoverRating = d->hoverRating;
169 d->hoverRating = adjustedHoverRating(halfStep: halfStepsEnabled(), hoverRating: d->ratingPainter.ratingFromPosition(rect: contentsRect(), pos: e->pos()), rating: d->rating);
170 if (d->hoverRating != prevHoverRating) {
171 update();
172 }
173}
174
175void KRatingWidget::leaveEvent(QEvent *)
176{
177 d->hoverRating = -1;
178 update();
179}
180
181void KRatingWidget::paintEvent(QPaintEvent *e)
182{
183 QFrame::paintEvent(e);
184 QPainter p(this);
185 d->ratingPainter.setEnabled(isEnabled());
186 d->ratingPainter.paint(painter: &p, rect: contentsRect(), rating: d->rating, hoverRating: d->hoverRating);
187}
188
189QSize KRatingWidget::sizeHint() const
190{
191 int numPix = d->ratingPainter.maxRating();
192 if (d->ratingPainter.halfStepsEnabled()) {
193 numPix /= 2;
194 }
195
196 QSize pixSize(d->pixSize, d->pixSize);
197 if (!d->ratingPainter.customPixmap().isNull()) {
198 pixSize = d->ratingPainter.customPixmap().size() / d->ratingPainter.customPixmap().devicePixelRatio();
199 }
200
201 return QSize(pixSize.width() * numPix + spacing() * (numPix - 1) + frameWidth() * 2, pixSize.height() + frameWidth() * 2);
202}
203
204void KRatingWidget::resizeEvent(QResizeEvent *e)
205{
206 QFrame::resizeEvent(event: e);
207}
208
209#include "moc_kratingwidget.cpp"
210

source code of kwidgetsaddons/src/kratingwidget.cpp