1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1997 Martin Jones <mjones@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "kxyselector.h"
9
10#include "loggingcategory.h"
11
12#include <QMouseEvent>
13#include <QPainter>
14#include <QStyle>
15#include <QStyleOptionFrame>
16
17//-----------------------------------------------------------------------------
18/*
19 * 2D value selector.
20 * The contents of the selector are drawn by derived class.
21 */
22
23class KXYSelectorPrivate
24{
25public:
26 KXYSelectorPrivate(KXYSelector *qq)
27 : q(qq)
28 , xPos(0)
29 , yPos(0)
30 , minX(0)
31 , maxX(100)
32 , minY(0)
33 , maxY(100)
34 , m_markerColor(Qt::white)
35 {
36 }
37
38 void setValues(int _xPos, int _yPos);
39
40 KXYSelector *const q;
41 int px;
42 int py;
43 int xPos;
44 int yPos;
45 int minX;
46 int maxX;
47 int minY;
48 int maxY;
49 QColor m_markerColor;
50};
51
52KXYSelector::KXYSelector(QWidget *parent)
53 : QWidget(parent)
54 , d(new KXYSelectorPrivate(this))
55{
56}
57
58KXYSelector::~KXYSelector() = default;
59
60int KXYSelector::xValue() const
61{
62 return d->xPos;
63}
64
65int KXYSelector::yValue() const
66{
67 return d->yPos;
68}
69
70void KXYSelector::setRange(int _minX, int _minY, int _maxX, int _maxY)
71{
72 if (_maxX == _minX) {
73 qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxX << " == " << _minX << " (for X) ";
74 return;
75 }
76 if (_maxY == _minY) {
77 qCWarning(KWidgetsAddonsLog) << "KXYSelector::setRange invalid range: " << _maxY << " == " << _minY << " (for Y) ";
78 return;
79 }
80
81 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
82 d->px = w;
83 d->py = w;
84 d->minX = _minX;
85 d->minY = _minY;
86 d->maxX = _maxX;
87 d->maxY = _maxY;
88}
89
90void KXYSelector::setXValue(int _xPos)
91{
92 setValues(xPos: _xPos, yPos: d->yPos);
93}
94
95void KXYSelector::setYValue(int _yPos)
96{
97 setValues(xPos: d->xPos, yPos: _yPos);
98}
99
100void KXYSelector::setValues(int _xPos, int _yPos)
101{
102 d->setValues(_xPos, _yPos);
103}
104
105void KXYSelectorPrivate::setValues(int _xPos, int _yPos)
106{
107 int w = q->style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
108
109 xPos = _xPos;
110 yPos = _yPos;
111
112 if (xPos > maxX) {
113 xPos = maxX;
114 } else if (xPos < minX) {
115 xPos = minX;
116 }
117
118 if (yPos > maxY) {
119 yPos = maxY;
120 } else if (yPos < minY) {
121 yPos = minY;
122 }
123
124 Q_ASSERT(maxX != minX);
125 int xp = w + (q->width() - 2 * w) * xPos / (maxX - minX);
126
127 Q_ASSERT(maxY != minY);
128 int yp = q->height() - w - (q->height() - 2 * w) * yPos / (maxY - minY);
129
130 q->setPosition(xp, yp);
131}
132
133void KXYSelector::setMarkerColor(const QColor &col)
134{
135 d->m_markerColor = col;
136}
137
138QRect KXYSelector::contentsRect() const
139{
140 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
141 return rect().adjusted(xp1: w, yp1: w, xp2: -w, yp2: -w);
142}
143
144QSize KXYSelector::minimumSizeHint() const
145{
146 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
147 return QSize(2 * w, 2 * w);
148}
149
150void KXYSelector::paintEvent(QPaintEvent * /* ev */)
151{
152 QStyleOptionFrame opt;
153 opt.initFrom(w: this);
154
155 QPainter painter;
156 painter.begin(this);
157
158 drawContents(&painter);
159 drawMarker(p: &painter, xp: d->px, yp: d->py);
160
161 style()->drawPrimitive(pe: QStyle::PE_Frame, opt: &opt, p: &painter, w: this);
162
163 painter.end();
164}
165
166void KXYSelector::mousePressEvent(QMouseEvent *e)
167{
168 mouseMoveEvent(e);
169}
170
171void KXYSelector::mouseMoveEvent(QMouseEvent *e)
172{
173 int xVal;
174 int yVal;
175 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
176 valuesFromPosition(x: e->pos().x() - w, y: e->pos().y() - w, xVal, yVal);
177 setValues(xPos: xVal, yPos: yVal);
178
179 Q_EMIT valueChanged(x: d->xPos, y: d->yPos);
180}
181
182void KXYSelector::wheelEvent(QWheelEvent *e)
183{
184 setValues(xPos: xValue() + e->angleDelta().x() / 120, yPos: yValue() + e->angleDelta().y() / 120);
185 Q_EMIT valueChanged(x: d->xPos, y: d->yPos);
186}
187
188void KXYSelector::valuesFromPosition(int x, int y, int &xVal, int &yVal) const
189{
190 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
191
192 xVal = ((d->maxX - d->minX) * (x - w)) / (width() - 2 * w);
193 yVal = d->maxY - (((d->maxY - d->minY) * (y - w)) / (height() - 2 * w));
194
195 if (xVal > d->maxX) {
196 xVal = d->maxX;
197 } else if (xVal < d->minX) {
198 xVal = d->minX;
199 }
200
201 if (yVal > d->maxY) {
202 yVal = d->maxY;
203 } else if (yVal < d->minY) {
204 yVal = d->minY;
205 }
206}
207
208void KXYSelector::setPosition(int xp, int yp)
209{
210 int w = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth);
211
212 if (xp < w) {
213 xp = w;
214 } else if (xp > width() - w) {
215 xp = width() - w;
216 }
217
218 if (yp < w) {
219 yp = w;
220 } else if (yp > height() - w) {
221 yp = height() - w;
222 }
223
224 d->px = xp;
225 d->py = yp;
226
227 update();
228}
229
230void KXYSelector::drawContents(QPainter *)
231{
232}
233
234void KXYSelector::drawMarker(QPainter *p, int xp, int yp)
235{
236 QPen pen(d->m_markerColor);
237 p->setPen(pen);
238
239 /*
240 p->drawLine( xp - 6, yp - 6, xp - 2, yp - 2 );
241 p->drawLine( xp - 6, yp + 6, xp - 2, yp + 2 );
242 p->drawLine( xp + 6, yp - 6, xp + 2, yp - 2 );
243 p->drawLine( xp + 6, yp + 6, xp + 2, yp + 2 );
244 */
245 p->drawEllipse(x: xp - 4, y: yp - 4, w: 8, h: 8);
246}
247
248#include "moc_kxyselector.cpp"
249

source code of kwidgetsaddons/src/kxyselector.cpp