File indexing completed on 2024-04-28 03:59:12
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 void KRatingWidget::setCustomPixmap(const QPixmap &pix) 0036 { 0037 d->ratingPainter.setCustomPixmap(pix); 0038 update(); 0039 } 0040 0041 void KRatingWidget::setIcon(const QIcon &icon) 0042 { 0043 d->ratingPainter.setIcon(icon); 0044 update(); 0045 } 0046 0047 void KRatingWidget::setPixmapSize(int size) 0048 { 0049 d->pixSize = size; 0050 updateGeometry(); 0051 } 0052 0053 int KRatingWidget::spacing() const 0054 { 0055 return d->ratingPainter.spacing(); 0056 } 0057 0058 QIcon KRatingWidget::icon() const 0059 { 0060 return d->ratingPainter.icon(); 0061 } 0062 0063 void KRatingWidget::setSpacing(int s) 0064 { 0065 d->ratingPainter.setSpacing(s); 0066 update(); 0067 } 0068 0069 Qt::Alignment KRatingWidget::alignment() const 0070 { 0071 return d->ratingPainter.alignment(); 0072 } 0073 0074 void KRatingWidget::setAlignment(Qt::Alignment align) 0075 { 0076 d->ratingPainter.setAlignment(align); 0077 update(); 0078 } 0079 0080 Qt::LayoutDirection KRatingWidget::layoutDirection() const 0081 { 0082 return d->ratingPainter.layoutDirection(); 0083 } 0084 0085 void KRatingWidget::setLayoutDirection(Qt::LayoutDirection direction) 0086 { 0087 d->ratingPainter.setLayoutDirection(direction); 0088 update(); 0089 } 0090 0091 int KRatingWidget::rating() const 0092 { 0093 return d->rating; 0094 } 0095 0096 int KRatingWidget::maxRating() const 0097 { 0098 return d->ratingPainter.maxRating(); 0099 } 0100 0101 bool KRatingWidget::halfStepsEnabled() const 0102 { 0103 return d->ratingPainter.halfStepsEnabled(); 0104 } 0105 0106 void KRatingWidget::setRating(int rating) 0107 { 0108 if (rating != d->rating) { 0109 d->rating = rating; 0110 d->hoverRating = rating; 0111 Q_EMIT ratingChanged(rating); 0112 update(); 0113 } 0114 } 0115 0116 void KRatingWidget::setMaxRating(int max) 0117 { 0118 d->ratingPainter.setMaxRating(max); 0119 update(); 0120 } 0121 0122 void KRatingWidget::setHalfStepsEnabled(bool enabled) 0123 { 0124 d->ratingPainter.setHalfStepsEnabled(enabled); 0125 update(); 0126 } 0127 0128 static inline int adjustedHoverRating(bool halfStep, int hoverRating, int rating) 0129 { 0130 // intentionally skip zero, or half step is disabled. 0131 if (!halfStep || hoverRating == 0) { 0132 return hoverRating; 0133 } 0134 0135 // See bug 171343, if we click on a star we want it to be full star, click again 0136 // make it half, click third time make it clear. 0137 0138 // round up hoverRating to next full star rating 0139 const int hoveredFullStarRating = hoverRating + (hoverRating % 2); 0140 // Check if the star under mouse is the last half or whole star of the rating. 0141 if (hoveredFullStarRating == rating || hoveredFullStarRating == rating + 1) { 0142 // If current pointed star is not empty, next rating will be rating - 1 0143 // if we point at 4th star and rating is 8 (4 star), next click will make it 7 0144 // if we point at 4th star and rating is 7 (3.5 star), next click will make it 6 0145 hoverRating = rating - 1; 0146 } else { 0147 // otherwise make it a full star rating 0148 hoverRating = hoveredFullStarRating; 0149 } 0150 return hoverRating; 0151 } 0152 0153 void KRatingWidget::mousePressEvent(QMouseEvent *e) 0154 { 0155 if (e->button() == Qt::LeftButton) { 0156 d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); 0157 // avoid set a rating to something less than zero, it may happen if widget is scaled and 0158 // mouse is clicked outside the star region. 0159 if (d->hoverRating >= 0) { 0160 setRating(d->hoverRating); 0161 } 0162 } 0163 } 0164 0165 void KRatingWidget::mouseMoveEvent(QMouseEvent *e) 0166 { 0167 // when moving the mouse we show the user what the result of clicking will be 0168 const int prevHoverRating = d->hoverRating; 0169 d->hoverRating = adjustedHoverRating(halfStepsEnabled(), d->ratingPainter.ratingFromPosition(contentsRect(), e->pos()), d->rating); 0170 if (d->hoverRating != prevHoverRating) { 0171 update(); 0172 } 0173 } 0174 0175 void KRatingWidget::leaveEvent(QEvent *) 0176 { 0177 d->hoverRating = -1; 0178 update(); 0179 } 0180 0181 void KRatingWidget::paintEvent(QPaintEvent *e) 0182 { 0183 QFrame::paintEvent(e); 0184 QPainter p(this); 0185 d->ratingPainter.setEnabled(isEnabled()); 0186 d->ratingPainter.paint(&p, contentsRect(), d->rating, d->hoverRating); 0187 } 0188 0189 QSize KRatingWidget::sizeHint() const 0190 { 0191 int numPix = d->ratingPainter.maxRating(); 0192 if (d->ratingPainter.halfStepsEnabled()) { 0193 numPix /= 2; 0194 } 0195 0196 QSize pixSize(d->pixSize, d->pixSize); 0197 if (!d->ratingPainter.customPixmap().isNull()) { 0198 pixSize = d->ratingPainter.customPixmap().size() / d->ratingPainter.customPixmap().devicePixelRatio(); 0199 } 0200 0201 return QSize(pixSize.width() * numPix + spacing() * (numPix - 1) + frameWidth() * 2, pixSize.height() + frameWidth() * 2); 0202 } 0203 0204 void KRatingWidget::resizeEvent(QResizeEvent *e) 0205 { 0206 QFrame::resizeEvent(e); 0207 } 0208 0209 #include "moc_kratingwidget.cpp"