File indexing completed on 2024-04-28 15:32:17

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 "kxyselector.h"
0009 
0010 #include "loggingcategory.h"
0011 
0012 #include <QMouseEvent>
0013 #include <QPainter>
0014 #include <QStyle>
0015 #include <QStyleOptionFrame>
0016 
0017 //-----------------------------------------------------------------------------
0018 /*
0019  * 2D value selector.
0020  * The contents of the selector are drawn by derived class.
0021  */
0022 
0023 class KXYSelectorPrivate
0024 {
0025 public:
0026     KXYSelectorPrivate(KXYSelector *qq)
0027         : q(qq)
0028         , xPos(0)
0029         , yPos(0)
0030         , minX(0)
0031         , maxX(100)
0032         , minY(0)
0033         , maxY(100)
0034         , m_markerColor(Qt::white)
0035     {
0036     }
0037 
0038     void setValues(int _xPos, int _yPos);
0039 
0040     KXYSelector *const q;
0041     int px;
0042     int py;
0043     int xPos;
0044     int yPos;
0045     int minX;
0046     int maxX;
0047     int minY;
0048     int maxY;
0049     QColor m_markerColor;
0050 };
0051 
0052 KXYSelector::KXYSelector(QWidget *parent)
0053     : QWidget(parent)
0054     , d(new KXYSelectorPrivate(this))
0055 {
0056 }
0057 
0058 KXYSelector::~KXYSelector() = default;
0059 
0060 int KXYSelector::xValue() const
0061 {
0062     return d->xPos;
0063 }
0064 
0065 int KXYSelector::yValue() const
0066 {
0067     return d->yPos;
0068 }
0069 
0070 void KXYSelector::setRange(int _minX, int _minY, int _maxX, int _maxY)
0071 {
0072     if (_maxX == _minX) {
0073         qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxX << " == " << _minX << " (for X) ";
0074         return;
0075     }
0076     if (_maxY == _minY) {
0077         qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxY << " == " << _minY << " (for Y) ";
0078         return;
0079     }
0080 
0081     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0082     d->px = w;
0083     d->py = w;
0084     d->minX = _minX;
0085     d->minY = _minY;
0086     d->maxX = _maxX;
0087     d->maxY = _maxY;
0088 }
0089 
0090 void KXYSelector::setXValue(int _xPos)
0091 {
0092     setValues(_xPos, d->yPos);
0093 }
0094 
0095 void KXYSelector::setYValue(int _yPos)
0096 {
0097     setValues(d->xPos, _yPos);
0098 }
0099 
0100 void KXYSelector::setValues(int _xPos, int _yPos)
0101 {
0102     d->setValues(_xPos, _yPos);
0103 }
0104 
0105 void KXYSelectorPrivate::setValues(int _xPos, int _yPos)
0106 {
0107     int w = q->style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0108 
0109     xPos = _xPos;
0110     yPos = _yPos;
0111 
0112     if (xPos > maxX) {
0113         xPos = maxX;
0114     } else if (xPos < minX) {
0115         xPos = minX;
0116     }
0117 
0118     if (yPos > maxY) {
0119         yPos = maxY;
0120     } else if (yPos < minY) {
0121         yPos = minY;
0122     }
0123 
0124     Q_ASSERT(maxX != minX);
0125     int xp = w + (q->width() - 2 * w) * xPos / (maxX - minX);
0126 
0127     Q_ASSERT(maxY != minY);
0128     int yp = q->height() - w - (q->height() - 2 * w) * yPos / (maxY - minY);
0129 
0130     q->setPosition(xp, yp);
0131 }
0132 
0133 void KXYSelector::setMarkerColor(const QColor &col)
0134 {
0135     d->m_markerColor = col;
0136 }
0137 
0138 QRect KXYSelector::contentsRect() const
0139 {
0140     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0141     return rect().adjusted(w, w, -w, -w);
0142 }
0143 
0144 QSize KXYSelector::minimumSizeHint() const
0145 {
0146     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0147     return QSize(2 * w, 2 * w);
0148 }
0149 
0150 void KXYSelector::paintEvent(QPaintEvent * /* ev */)
0151 {
0152     QStyleOptionFrame opt;
0153     opt.initFrom(this);
0154 
0155     QPainter painter;
0156     painter.begin(this);
0157 
0158     drawContents(&painter);
0159     drawMarker(&painter, d->px, d->py);
0160 
0161     style()->drawPrimitive(QStyle::PE_Frame, &opt, &painter, this);
0162 
0163     painter.end();
0164 }
0165 
0166 void KXYSelector::mousePressEvent(QMouseEvent *e)
0167 {
0168     mouseMoveEvent(e);
0169 }
0170 
0171 void KXYSelector::mouseMoveEvent(QMouseEvent *e)
0172 {
0173     int xVal;
0174     int yVal;
0175     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0176     valuesFromPosition(e->pos().x() - w, e->pos().y() - w, xVal, yVal);
0177     setValues(xVal, yVal);
0178 
0179     Q_EMIT valueChanged(d->xPos, d->yPos);
0180 }
0181 
0182 void KXYSelector::wheelEvent(QWheelEvent *e)
0183 {
0184     setValues(xValue() + e->angleDelta().x() / 120, yValue() + e->angleDelta().y() / 120);
0185     Q_EMIT valueChanged(d->xPos, d->yPos);
0186 }
0187 
0188 void KXYSelector::valuesFromPosition(int x, int y, int &xVal, int &yVal) const
0189 {
0190     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0191 
0192     xVal = ((d->maxX - d->minX) * (x - w)) / (width() - 2 * w);
0193     yVal = d->maxY - (((d->maxY - d->minY) * (y - w)) / (height() - 2 * w));
0194 
0195     if (xVal > d->maxX) {
0196         xVal = d->maxX;
0197     } else if (xVal < d->minX) {
0198         xVal = d->minX;
0199     }
0200 
0201     if (yVal > d->maxY) {
0202         yVal = d->maxY;
0203     } else if (yVal < d->minY) {
0204         yVal = d->minY;
0205     }
0206 }
0207 
0208 void KXYSelector::setPosition(int xp, int yp)
0209 {
0210     int w = style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
0211 
0212     if (xp < w) {
0213         xp = w;
0214     } else if (xp > width() - w) {
0215         xp = width() - w;
0216     }
0217 
0218     if (yp < w) {
0219         yp = w;
0220     } else if (yp > height() - w) {
0221         yp = height() - w;
0222     }
0223 
0224     d->px = xp;
0225     d->py = yp;
0226 
0227     update();
0228 }
0229 
0230 void KXYSelector::drawContents(QPainter *)
0231 {
0232 }
0233 
0234 void KXYSelector::drawMarker(QPainter *p, int xp, int yp)
0235 {
0236     QPen pen(d->m_markerColor);
0237     p->setPen(pen);
0238 
0239     /*
0240       p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 );
0241       p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 );
0242       p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 );
0243       p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 );
0244     */
0245     p->drawEllipse(xp - 4, yp - 4, 8, 8);
0246 }
0247 
0248 #include "moc_kxyselector.cpp"