File indexing completed on 2025-02-02 14:20:09
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2006-2007 Sebastian Trueg <trueg@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kratingwidget.h" 0009 #include "kratingpainter.h" 0010 0011 #include <QIcon> 0012 #include <QMouseEvent> 0013 #include <QPainter> 0014 #include <QPixmap> 0015 0016 class KRatingWidgetPrivate 0017 { 0018 public: 0019 int rating = 0; 0020 int hoverRating = -1; 0021 int pixSize = 16; 0022 0023 KRatingPainter ratingPainter; 0024 }; 0025 0026 KRatingWidget::KRatingWidget(QWidget *parent) 0027 : QFrame(parent) 0028 , d(new KRatingWidgetPrivate()) 0029 { 0030 setMouseTracking(true); 0031 } 0032 0033 KRatingWidget::~KRatingWidget() = default; 0034 0035 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0036 void KRatingWidget::setPixmap(const QPixmap &pix) 0037 { 0038 setCustomPixmap(pix); 0039 } 0040 #endif 0041 0042 void KRatingWidget::setCustomPixmap(const QPixmap &pix) 0043 { 0044 d->ratingPainter.setCustomPixmap(pix); 0045 update(); 0046 } 0047 0048 void KRatingWidget::setIcon(const QIcon &icon) 0049 { 0050 d->ratingPainter.setIcon(icon); 0051 update(); 0052 } 0053 0054 void KRatingWidget::setPixmapSize(int size) 0055 { 0056 d->pixSize = size; 0057 updateGeometry(); 0058 } 0059 0060 int KRatingWidget::spacing() const 0061 { 0062 return d->ratingPainter.spacing(); 0063 } 0064 0065 QIcon KRatingWidget::icon() const 0066 { 0067 return d->ratingPainter.icon(); 0068 } 0069 0070 void KRatingWidget::setSpacing(int s) 0071 { 0072 d->ratingPainter.setSpacing(s); 0073 update(); 0074 } 0075 0076 Qt::Alignment KRatingWidget::alignment() const 0077 { 0078 return d->ratingPainter.alignment(); 0079 } 0080 0081 void KRatingWidget::setAlignment(Qt::Alignment align) 0082 { 0083 d->ratingPainter.setAlignment(align); 0084 update(); 0085 } 0086 0087 Qt::LayoutDirection KRatingWidget::layoutDirection() const 0088 { 0089 return d->ratingPainter.layoutDirection(); 0090 } 0091 0092 void KRatingWidget::setLayoutDirection(Qt::LayoutDirection direction) 0093 { 0094 d->ratingPainter.setLayoutDirection(direction); 0095 update(); 0096 } 0097 0098 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 85) 0099 unsigned int KRatingWidget::rating() const 0100 #else 0101 int KRatingWidget::rating() const 0102 #endif 0103 { 0104 return d->rating; 0105 } 0106 0107 int KRatingWidget::maxRating() const 0108 { 0109 return d->ratingPainter.maxRating(); 0110 } 0111 0112 bool KRatingWidget::halfStepsEnabled() const 0113 { 0114 return d->ratingPainter.halfStepsEnabled(); 0115 } 0116 0117 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0118 void KRatingWidget::setRating(unsigned int rating) 0119 { 0120 setRating((int)rating); 0121 } 0122 #endif 0123 0124 void KRatingWidget::setRating(int rating) 0125 { 0126 if (rating != d->rating) { 0127 d->rating = rating; 0128 d->hoverRating = rating; 0129 Q_EMIT ratingChanged(rating); 0130 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 85) 0131 Q_EMIT ratingChanged((unsigned int)rating); 0132 #endif 0133 update(); 0134 } 0135 } 0136 0137 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0138 void KRatingWidget::setMaxRating(unsigned int max) 0139 { 0140 setMaxRating((int)max); 0141 } 0142 #endif 0143 0144 void KRatingWidget::setMaxRating(int max) 0145 { 0146 d->ratingPainter.setMaxRating(max); 0147 update(); 0148 } 0149 0150 void KRatingWidget::setHalfStepsEnabled(bool enabled) 0151 { 0152 d->ratingPainter.setHalfStepsEnabled(enabled); 0153 update(); 0154 } 0155 0156 #if KWIDGETSADDONS_BUILD_DEPRECATED_SINCE(5, 0) 0157 void KRatingWidget::setOnlyPaintFullSteps(bool fs) 0158 { 0159 setHalfStepsEnabled(!fs); 0160 } 0161 #endif 0162 0163 static inline int adjustedHoverRating(bool halfStep, int hoverRating, int rating) 0164 { 0165 // intentionally skip zero, or half step is disabled. 0166 if (!halfStep || hoverRating == 0) { 0167 return hoverRating; 0168 } 0169 0170 // See bug 171343, if we click on a star we want it to be full star, click again 0171 // make it half, click third time make it clear. 0172 0173 // round up hoverRating to next full star rating 0174 const int hoveredFullStarRating = hoverRating + (hoverRating % 2); 0175 // Check if the star under mouse is the last half or whole star of the rating. 0176 if (hoveredFullStarRating == rating || hoveredFullStarRating == rating + 1) { 0177 // If current pointed star is not empty, next rating will be rating - 1 0178 // if we point at 4th star and rating is 8 (4 star), next click will make it 7 0179 // if we point at 4th star and rating is 7 (3.5 star), next click will make it 6 0180 hoverRating = rating - 1; 0181 } else { 0182 // otherwise make it a full star rating 0183 hoverRating = hoveredFullStarRating; 0184 } 0185 return hoverRating; 0186 } 0187 0188 void KRatingWidget::mousePressEvent(QMouseEvent *e) 0189 { 0190 if (e->button() == Qt::LeftButton) { 0191 d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); 0192 // avoid set a rating to something less than zero, it may happen if widget is scaled and 0193 // mouse is clicked outside the star region. 0194 if (d->hoverRating >= 0) { 0195 setRating(d->hoverRating); 0196 } 0197 } 0198 } 0199 0200 void KRatingWidget::mouseMoveEvent(QMouseEvent *e) 0201 { 0202 // when moving the mouse we show the user what the result of clicking will be 0203 const int prevHoverRating = d->hoverRating; 0204 d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); 0205 if (d->hoverRating != prevHoverRating) { 0206 update(); 0207 } 0208 } 0209 0210 void KRatingWidget::leaveEvent(QEvent *) 0211 { 0212 d->hoverRating = -1; 0213 update(); 0214 } 0215 0216 void KRatingWidget::paintEvent(QPaintEvent *e) 0217 { 0218 QFrame::paintEvent(e); 0219 QPainter p(this); 0220 d->ratingPainter.setEnabled(isEnabled()); 0221 d->ratingPainter.paint(&p, contentsRect(), d->rating, d->hoverRating); 0222 } 0223 0224 QSize KRatingWidget::sizeHint() const 0225 { 0226 int numPix = d->ratingPainter.maxRating(); 0227 if (d->ratingPainter.halfStepsEnabled()) { 0228 numPix /= 2; 0229 } 0230 0231 QSize pixSize(d->pixSize, d->pixSize); 0232 if (!d->ratingPainter.customPixmap().isNull()) { 0233 pixSize = d->ratingPainter.customPixmap().size() / d->ratingPainter.customPixmap().devicePixelRatio(); 0234 } 0235 0236 return QSize(pixSize.width() * numPix + spacing() * (numPix - 1) + frameWidth() * 2, pixSize.height() + frameWidth() * 2); 0237 } 0238 0239 void KRatingWidget::resizeEvent(QResizeEvent *e) 0240 { 0241 QFrame::resizeEvent(e); 0242 } 0243 0244 #include "moc_kratingwidget.cpp"