File indexing completed on 2025-02-16 13:11:50
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 1997 Martin Jones <mjones@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "kselector.h" 0009 0010 #include <QPaintEvent> 0011 #include <QPainter> 0012 #include <QPixmap> 0013 #include <QStyle> 0014 #include <QStyleOption> 0015 0016 //----------------------------------------------------------------------------- 0017 /* 0018 * 1D value selector with contents drawn by derived class. 0019 * See KColorDialog for example. 0020 */ 0021 0022 #define ARROWSIZE 5 0023 0024 class KSelectorPrivate 0025 { 0026 public: 0027 bool m_indent = true; 0028 QStyle::PrimitiveElement arrowPE = QStyle::PE_IndicatorArrowLeft; 0029 }; 0030 0031 class KGradientSelectorPrivate 0032 { 0033 public: 0034 KGradientSelectorPrivate(KGradientSelector *qq) 0035 : q(qq) 0036 { 0037 } 0038 0039 KGradientSelector *q; 0040 QLinearGradient gradient; 0041 QString text1; 0042 QString text2; 0043 }; 0044 0045 KSelector::KSelector(QWidget *parent) 0046 : QAbstractSlider(parent) 0047 , d(new KSelectorPrivate) 0048 { 0049 setOrientation(Qt::Horizontal); 0050 } 0051 0052 KSelector::KSelector(Qt::Orientation o, QWidget *parent) 0053 : QAbstractSlider(parent) 0054 , d(new KSelectorPrivate) 0055 { 0056 setOrientation(o); 0057 if (o == Qt::Horizontal) { 0058 setArrowDirection(Qt::UpArrow); 0059 } 0060 } 0061 0062 KSelector::~KSelector() = default; 0063 0064 void KSelector::setIndent(bool i) 0065 { 0066 d->m_indent = i; 0067 } 0068 0069 bool KSelector::indent() const 0070 { 0071 return d->m_indent; 0072 } 0073 0074 QRect KSelector::contentsRect() const 0075 { 0076 int w = indent() ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; 0077 // TODO: is the height:width ratio of an indicator arrow always 2:1? hm. 0078 int iw = (w < ARROWSIZE) ? ARROWSIZE : w; 0079 0080 if (orientation() == Qt::Vertical) { 0081 if (arrowDirection() == Qt::RightArrow) { 0082 return QRect(w + ARROWSIZE, // 0083 iw, 0084 width() - w * 2 - ARROWSIZE, 0085 height() - iw * 2); 0086 } else { 0087 return QRect(w, // 0088 iw, 0089 width() - w * 2 - ARROWSIZE, 0090 height() - iw * 2); 0091 } 0092 } else { // Qt::Horizontal 0093 if (arrowDirection() == Qt::UpArrow) { 0094 return QRect(iw, // 0095 w, 0096 width() - 2 * iw, 0097 height() - w * 2 - ARROWSIZE); 0098 } else { 0099 return QRect(iw, // 0100 w + ARROWSIZE, 0101 width() - 2 * iw, 0102 height() - w * 2 - ARROWSIZE); 0103 } 0104 } 0105 } 0106 0107 void KSelector::paintEvent(QPaintEvent *) 0108 { 0109 QPainter painter; 0110 int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); 0111 int iw = (w < ARROWSIZE) ? ARROWSIZE : w; 0112 0113 painter.begin(this); 0114 0115 if (indent()) { 0116 QStyleOptionFrame opt; 0117 opt.initFrom(this); 0118 opt.state = QStyle::State_Sunken; 0119 if (orientation() == Qt::Vertical) { 0120 opt.rect.adjust(0, iw - w, -5, w - iw); 0121 } else { 0122 opt.rect.adjust(iw - w, 0, w - iw, -5); 0123 } 0124 QBrush oldBrush = painter.brush(); 0125 painter.setBrush(Qt::NoBrush); 0126 style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this); 0127 painter.setBrush(oldBrush); 0128 } 0129 0130 drawContents(&painter); 0131 0132 QPoint pos = calcArrowPos(value()); 0133 drawArrow(&painter, pos); 0134 0135 painter.end(); 0136 } 0137 0138 void KSelector::mousePressEvent(QMouseEvent *e) 0139 { 0140 setSliderDown(true); 0141 moveArrow(e->pos()); 0142 } 0143 0144 void KSelector::mouseMoveEvent(QMouseEvent *e) 0145 { 0146 moveArrow(e->pos()); 0147 } 0148 0149 void KSelector::mouseReleaseEvent(QMouseEvent *e) 0150 { 0151 moveArrow(e->pos()); 0152 setSliderDown(false); 0153 } 0154 0155 void KSelector::wheelEvent(QWheelEvent *e) 0156 { 0157 int val = value() + e->angleDelta().y() / 120; 0158 setSliderDown(true); 0159 setValue(val); 0160 setSliderDown(false); 0161 } 0162 0163 void KSelector::moveArrow(const QPoint &pos) 0164 { 0165 int val; 0166 int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); 0167 int iw = (w < ARROWSIZE) ? ARROWSIZE : w; 0168 0169 if (orientation() == Qt::Vertical) { 0170 val = (maximum() - minimum()) * (height() - pos.y() - iw) / (height() - iw * 2) + minimum(); 0171 } else { 0172 val = (maximum() - minimum()) * (pos.x() - iw) / (width() - iw * 2) + minimum(); 0173 } 0174 0175 setValue(val); 0176 update(); 0177 } 0178 0179 QPoint KSelector::calcArrowPos(int val) 0180 { 0181 QPoint p; 0182 int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); 0183 int iw = (w < ARROWSIZE) ? ARROWSIZE : w; 0184 0185 if (orientation() == Qt::Vertical) { 0186 p.setY(height() - iw - 1 - (height() - 2 * iw - 1) * val / (maximum() - minimum())); 0187 0188 if (d->arrowPE == QStyle::PE_IndicatorArrowRight) { 0189 p.setX(0); 0190 } else { 0191 p.setX(width() - 5); 0192 } 0193 } else { 0194 p.setX(iw + (width() - 2 * iw - 1) * val / (maximum() - minimum())); 0195 0196 if (d->arrowPE == QStyle::PE_IndicatorArrowDown) { 0197 p.setY(0); 0198 } else { 0199 p.setY(height() - 5); 0200 } 0201 } 0202 0203 return p; 0204 } 0205 0206 void KSelector::setArrowDirection(Qt::ArrowType direction) 0207 { 0208 switch (direction) { 0209 case Qt::UpArrow: 0210 if (orientation() == Qt::Horizontal) { 0211 d->arrowPE = QStyle::PE_IndicatorArrowUp; 0212 } else { 0213 d->arrowPE = QStyle::PE_IndicatorArrowLeft; 0214 } 0215 break; 0216 case Qt::DownArrow: 0217 if (orientation() == Qt::Horizontal) { 0218 d->arrowPE = QStyle::PE_IndicatorArrowDown; 0219 } else { 0220 d->arrowPE = QStyle::PE_IndicatorArrowRight; 0221 } 0222 break; 0223 case Qt::LeftArrow: 0224 if (orientation() == Qt::Vertical) { 0225 d->arrowPE = QStyle::PE_IndicatorArrowLeft; 0226 } else { 0227 d->arrowPE = QStyle::PE_IndicatorArrowDown; 0228 } 0229 break; 0230 case Qt::RightArrow: 0231 if (orientation() == Qt::Vertical) { 0232 d->arrowPE = QStyle::PE_IndicatorArrowRight; 0233 } else { 0234 d->arrowPE = QStyle::PE_IndicatorArrowUp; 0235 } 0236 break; 0237 0238 case Qt::NoArrow: 0239 break; 0240 } 0241 } 0242 0243 Qt::ArrowType KSelector::arrowDirection() const 0244 { 0245 switch (d->arrowPE) { 0246 case QStyle::PE_IndicatorArrowUp: 0247 return Qt::UpArrow; 0248 case QStyle::PE_IndicatorArrowDown: 0249 return Qt::DownArrow; 0250 case QStyle::PE_IndicatorArrowRight: 0251 return Qt::RightArrow; 0252 case QStyle::PE_IndicatorArrowLeft: 0253 default: 0254 return Qt::LeftArrow; 0255 } 0256 } 0257 0258 void KSelector::drawContents(QPainter *) 0259 { 0260 } 0261 0262 void KSelector::drawArrow(QPainter *painter, const QPoint &pos) 0263 { 0264 painter->setPen(QPen()); 0265 painter->setBrush(QBrush(palette().color(QPalette::ButtonText))); 0266 0267 QStyleOption o; 0268 0269 if (orientation() == Qt::Vertical) { 0270 o.rect = QRect(pos.x(), pos.y() - ARROWSIZE / 2, ARROWSIZE, ARROWSIZE); 0271 } else { 0272 o.rect = QRect(pos.x() - ARROWSIZE / 2, pos.y(), ARROWSIZE, ARROWSIZE); 0273 } 0274 style()->drawPrimitive(d->arrowPE, &o, painter, this); 0275 } 0276 0277 //---------------------------------------------------------------------------- 0278 0279 KGradientSelector::KGradientSelector(QWidget *parent) 0280 : KSelector(parent) 0281 , d(new KGradientSelectorPrivate(this)) 0282 { 0283 } 0284 0285 KGradientSelector::KGradientSelector(Qt::Orientation o, QWidget *parent) 0286 : KSelector(o, parent) 0287 , d(new KGradientSelectorPrivate(this)) 0288 { 0289 } 0290 0291 KGradientSelector::~KGradientSelector() = default; 0292 0293 void KGradientSelector::drawContents(QPainter *painter) 0294 { 0295 d->gradient.setStart(contentsRect().topLeft()); 0296 if (orientation() == Qt::Vertical) { 0297 d->gradient.setFinalStop(contentsRect().bottomLeft()); 0298 } else { 0299 d->gradient.setFinalStop(contentsRect().topRight()); 0300 } 0301 QBrush gradientBrush(d->gradient); 0302 0303 if (!gradientBrush.isOpaque()) { 0304 QPixmap chessboardPattern(16, 16); 0305 QPainter patternPainter(&chessboardPattern); 0306 patternPainter.fillRect(0, 0, 8, 8, Qt::black); 0307 patternPainter.fillRect(8, 8, 8, 8, Qt::black); 0308 patternPainter.fillRect(0, 8, 8, 8, Qt::white); 0309 patternPainter.fillRect(8, 0, 8, 8, Qt::white); 0310 patternPainter.end(); 0311 painter->fillRect(contentsRect(), QBrush(chessboardPattern)); 0312 } 0313 painter->fillRect(contentsRect(), gradientBrush); 0314 0315 if (orientation() == Qt::Vertical) { 0316 int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; 0317 int xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().horizontalAdvance(d->text2)) / 2; 0318 QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); 0319 painter->setPen(pen); 0320 painter->drawText(xPos, yPos, d->text2); 0321 0322 yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; 0323 xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().horizontalAdvance(d->text1)) / 2; 0324 pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); 0325 painter->setPen(pen); 0326 painter->drawText(xPos, yPos, d->text1); 0327 } else { 0328 int yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; 0329 0330 QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); 0331 painter->setPen(pen); 0332 painter->drawText(contentsRect().left() + 2, yPos, d->text1); 0333 0334 pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); 0335 painter->setPen(pen); 0336 painter->drawText(contentsRect().right() - painter->fontMetrics().horizontalAdvance(d->text2) - 2, yPos, d->text2); 0337 } 0338 } 0339 0340 QSize KGradientSelector::minimumSize() const 0341 { 0342 return sizeHint(); 0343 } 0344 0345 void KGradientSelector::setStops(const QGradientStops &stops) 0346 { 0347 d->gradient.setStops(stops); 0348 update(); 0349 } 0350 0351 QGradientStops KGradientSelector::stops() const 0352 { 0353 return d->gradient.stops(); 0354 } 0355 0356 void KGradientSelector::setColors(const QColor &col1, const QColor &col2) 0357 { 0358 d->gradient.setColorAt(0.0, col1); 0359 d->gradient.setColorAt(1.0, col2); 0360 update(); 0361 } 0362 0363 void KGradientSelector::setText(const QString &t1, const QString &t2) 0364 { 0365 d->text1 = t1; 0366 d->text2 = t2; 0367 update(); 0368 } 0369 0370 void KGradientSelector::setFirstColor(const QColor &col) 0371 { 0372 d->gradient.setColorAt(0.0, col); 0373 update(); 0374 } 0375 0376 void KGradientSelector::setSecondColor(const QColor &col) 0377 { 0378 d->gradient.setColorAt(1.0, col); 0379 update(); 0380 } 0381 0382 void KGradientSelector::setFirstText(const QString &t) 0383 { 0384 d->text1 = t; 0385 update(); 0386 } 0387 0388 void KGradientSelector::setSecondText(const QString &t) 0389 { 0390 d->text2 = t; 0391 update(); 0392 } 0393 0394 QColor KGradientSelector::firstColor() const 0395 { 0396 return d->gradient.stops().first().second; 0397 } 0398 0399 QColor KGradientSelector::secondColor() const 0400 { 0401 return d->gradient.stops().last().second; 0402 } 0403 0404 QString KGradientSelector::firstText() const 0405 { 0406 return d->text1; 0407 } 0408 0409 QString KGradientSelector::secondText() const 0410 { 0411 return d->text2; 0412 } 0413 0414 #include "moc_kselector.cpp"