/* This file is part of the KDE libraries SPDX-FileCopyrightText: 1997 Martin Jones SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kselector.h" #include #include #include #include #include //----------------------------------------------------------------------------- /* * 1D value selector with contents drawn by derived class. * See KColorDialog for example. */ #define ARROWSIZE 5 class KSelectorPrivate { public: bool m_indent = true; QStyle::PrimitiveElement arrowPE = QStyle::PE_IndicatorArrowLeft; }; class KGradientSelectorPrivate { public: KGradientSelectorPrivate(KGradientSelector *qq) : q(qq) { } KGradientSelector *q; QLinearGradient gradient; QString text1; QString text2; }; KSelector::KSelector(QWidget *parent) : QAbstractSlider(parent) , d(new KSelectorPrivate) { setOrientation(Qt::Horizontal); } KSelector::KSelector(Qt::Orientation o, QWidget *parent) : QAbstractSlider(parent) , d(new KSelectorPrivate) { setOrientation(o); if (o == Qt::Horizontal) { setArrowDirection(Qt::UpArrow); } } KSelector::~KSelector() = default; void KSelector::setIndent(bool i) { d->m_indent = i; } bool KSelector::indent() const { return d->m_indent; } QRect KSelector::contentsRect() const { int w = indent() ? style()->pixelMetric(QStyle::PM_DefaultFrameWidth) : 0; // TODO: is the height:width ratio of an indicator arrow always 2:1? hm. int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) { if (arrowDirection() == Qt::RightArrow) { return QRect(w + ARROWSIZE, // iw, width() - w * 2 - ARROWSIZE, height() - iw * 2); } else { return QRect(w, // iw, width() - w * 2 - ARROWSIZE, height() - iw * 2); } } else { // Qt::Horizontal if (arrowDirection() == Qt::UpArrow) { return QRect(iw, // w, width() - 2 * iw, height() - w * 2 - ARROWSIZE); } else { return QRect(iw, // w + ARROWSIZE, width() - 2 * iw, height() - w * 2 - ARROWSIZE); } } } void KSelector::paintEvent(QPaintEvent *) { QPainter painter; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; painter.begin(this); if (indent()) { QStyleOptionFrame opt; opt.initFrom(this); opt.state = QStyle::State_Sunken; if (orientation() == Qt::Vertical) { opt.rect.adjust(0, iw - w, -5, w - iw); } else { opt.rect.adjust(iw - w, 0, w - iw, -5); } QBrush oldBrush = painter.brush(); painter.setBrush(Qt::NoBrush); style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this); painter.setBrush(oldBrush); } drawContents(&painter); QPoint pos = calcArrowPos(value()); drawArrow(&painter, pos); painter.end(); } void KSelector::mousePressEvent(QMouseEvent *e) { setSliderDown(true); moveArrow(e->pos()); } void KSelector::mouseMoveEvent(QMouseEvent *e) { moveArrow(e->pos()); } void KSelector::mouseReleaseEvent(QMouseEvent *e) { moveArrow(e->pos()); setSliderDown(false); } void KSelector::wheelEvent(QWheelEvent *e) { int val = value() + e->angleDelta().y() / 120; setSliderDown(true); setValue(val); setSliderDown(false); } void KSelector::moveArrow(const QPoint &pos) { int val; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) { val = (maximum() - minimum()) * (height() - pos.y() - iw) / (height() - iw * 2) + minimum(); } else { val = (maximum() - minimum()) * (pos.x() - iw) / (width() - iw * 2) + minimum(); } setValue(val); update(); } QPoint KSelector::calcArrowPos(int val) { QPoint p; int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth); int iw = (w < ARROWSIZE) ? ARROWSIZE : w; if (orientation() == Qt::Vertical) { p.setY(height() - iw - 1 - (height() - 2 * iw - 1) * val / (maximum() - minimum())); if (d->arrowPE == QStyle::PE_IndicatorArrowRight) { p.setX(0); } else { p.setX(width() - 5); } } else { p.setX(iw + (width() - 2 * iw - 1) * val / (maximum() - minimum())); if (d->arrowPE == QStyle::PE_IndicatorArrowDown) { p.setY(0); } else { p.setY(height() - 5); } } return p; } void KSelector::setArrowDirection(Qt::ArrowType direction) { switch (direction) { case Qt::UpArrow: if (orientation() == Qt::Horizontal) { d->arrowPE = QStyle::PE_IndicatorArrowUp; } else { d->arrowPE = QStyle::PE_IndicatorArrowLeft; } break; case Qt::DownArrow: if (orientation() == Qt::Horizontal) { d->arrowPE = QStyle::PE_IndicatorArrowDown; } else { d->arrowPE = QStyle::PE_IndicatorArrowRight; } break; case Qt::LeftArrow: if (orientation() == Qt::Vertical) { d->arrowPE = QStyle::PE_IndicatorArrowLeft; } else { d->arrowPE = QStyle::PE_IndicatorArrowDown; } break; case Qt::RightArrow: if (orientation() == Qt::Vertical) { d->arrowPE = QStyle::PE_IndicatorArrowRight; } else { d->arrowPE = QStyle::PE_IndicatorArrowUp; } break; case Qt::NoArrow: break; } } Qt::ArrowType KSelector::arrowDirection() const { switch (d->arrowPE) { case QStyle::PE_IndicatorArrowUp: return Qt::UpArrow; case QStyle::PE_IndicatorArrowDown: return Qt::DownArrow; case QStyle::PE_IndicatorArrowRight: return Qt::RightArrow; case QStyle::PE_IndicatorArrowLeft: default: return Qt::LeftArrow; } } void KSelector::drawContents(QPainter *) { } void KSelector::drawArrow(QPainter *painter, const QPoint &pos) { painter->setPen(QPen()); painter->setBrush(QBrush(palette().color(QPalette::ButtonText))); QStyleOption o; if (orientation() == Qt::Vertical) { o.rect = QRect(pos.x(), pos.y() - ARROWSIZE / 2, ARROWSIZE, ARROWSIZE); } else { o.rect = QRect(pos.x() - ARROWSIZE / 2, pos.y(), ARROWSIZE, ARROWSIZE); } style()->drawPrimitive(d->arrowPE, &o, painter, this); } //---------------------------------------------------------------------------- KGradientSelector::KGradientSelector(QWidget *parent) : KSelector(parent) , d(new KGradientSelectorPrivate(this)) { } KGradientSelector::KGradientSelector(Qt::Orientation o, QWidget *parent) : KSelector(o, parent) , d(new KGradientSelectorPrivate(this)) { } KGradientSelector::~KGradientSelector() = default; void KGradientSelector::drawContents(QPainter *painter) { d->gradient.setStart(contentsRect().topLeft()); if (orientation() == Qt::Vertical) { d->gradient.setFinalStop(contentsRect().bottomLeft()); } else { d->gradient.setFinalStop(contentsRect().topRight()); } QBrush gradientBrush(d->gradient); if (!gradientBrush.isOpaque()) { QPixmap chessboardPattern(16, 16); QPainter patternPainter(&chessboardPattern); patternPainter.fillRect(0, 0, 8, 8, Qt::black); patternPainter.fillRect(8, 8, 8, 8, Qt::black); patternPainter.fillRect(0, 8, 8, 8, Qt::white); patternPainter.fillRect(8, 0, 8, 8, Qt::white); patternPainter.end(); painter->fillRect(contentsRect(), QBrush(chessboardPattern)); } painter->fillRect(contentsRect(), gradientBrush); if (orientation() == Qt::Vertical) { int yPos = contentsRect().top() + painter->fontMetrics().ascent() + 2; int xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().horizontalAdvance(d->text2)) / 2; QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(xPos, yPos, d->text2); yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; xPos = contentsRect().left() + (contentsRect().width() - painter->fontMetrics().horizontalAdvance(d->text1)) / 2; pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(xPos, yPos, d->text1); } else { int yPos = contentsRect().bottom() - painter->fontMetrics().descent() - 2; QPen pen(qGray(firstColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(contentsRect().left() + 2, yPos, d->text1); pen.setColor(qGray(secondColor().rgb()) > 180 ? Qt::black : Qt::white); painter->setPen(pen); painter->drawText(contentsRect().right() - painter->fontMetrics().horizontalAdvance(d->text2) - 2, yPos, d->text2); } } QSize KGradientSelector::minimumSize() const { return sizeHint(); } void KGradientSelector::setStops(const QGradientStops &stops) { d->gradient.setStops(stops); update(); } QGradientStops KGradientSelector::stops() const { return d->gradient.stops(); } void KGradientSelector::setColors(const QColor &col1, const QColor &col2) { d->gradient.setColorAt(0.0, col1); d->gradient.setColorAt(1.0, col2); update(); } void KGradientSelector::setText(const QString &t1, const QString &t2) { d->text1 = t1; d->text2 = t2; update(); } void KGradientSelector::setFirstColor(const QColor &col) { d->gradient.setColorAt(0.0, col); update(); } void KGradientSelector::setSecondColor(const QColor &col) { d->gradient.setColorAt(1.0, col); update(); } void KGradientSelector::setFirstText(const QString &t) { d->text1 = t; update(); } void KGradientSelector::setSecondText(const QString &t) { d->text2 = t; update(); } QColor KGradientSelector::firstColor() const { return d->gradient.stops().first().second; } QColor KGradientSelector::secondColor() const { return d->gradient.stops().last().second; } QString KGradientSelector::firstText() const { return d->text1; } QString KGradientSelector::secondText() const { return d->text2; } #include "moc_kselector.cpp"