Files
RedBear-OS/local/recipes/kde/kf6-kwidgetsaddons/source/src/kselector.cpp
T
2026-04-14 10:51:06 +01:00

415 lines
10 KiB
C++

/*
This file is part of the KDE libraries
SPDX-FileCopyrightText: 1997 Martin Jones <mjones@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kselector.h"
#include <QPaintEvent>
#include <QPainter>
#include <QPixmap>
#include <QStyle>
#include <QStyleOption>
//-----------------------------------------------------------------------------
/*
* 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"