Chris@132
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@132
|
2
|
Chris@132
|
3 /*
|
Chris@132
|
4 Sonic Visualiser
|
Chris@132
|
5 An audio file viewer and annotation editor.
|
Chris@132
|
6 Centre for Digital Music, Queen Mary, University of London.
|
Chris@182
|
7 This file copyright 2006 QMUL.
|
Chris@132
|
8
|
Chris@132
|
9 This program is free software; you can redistribute it and/or
|
Chris@132
|
10 modify it under the terms of the GNU General Public License as
|
Chris@132
|
11 published by the Free Software Foundation; either version 2 of the
|
Chris@132
|
12 License, or (at your option) any later version. See the file
|
Chris@132
|
13 COPYING included with this distribution for more information.
|
Chris@132
|
14 */
|
Chris@132
|
15
|
Chris@132
|
16 #include "Thumbwheel.h"
|
Chris@132
|
17
|
Chris@187
|
18 #include "base/RangeMapper.h"
|
Chris@190
|
19 #include "base/Profiler.h"
|
Chris@187
|
20
|
Chris@132
|
21 #include <QMouseEvent>
|
Chris@132
|
22 #include <QPaintEvent>
|
Chris@132
|
23 #include <QWheelEvent>
|
Chris@187
|
24 #include <QInputDialog>
|
Chris@132
|
25 #include <QPainter>
|
Chris@190
|
26 #include <QPainterPath>
|
Chris@1586
|
27 #include <QMenu>
|
Chris@1586
|
28
|
Chris@1586
|
29 #include "MenuTitle.h"
|
Chris@132
|
30
|
Chris@132
|
31 #include <cmath>
|
Chris@132
|
32 #include <iostream>
|
Chris@132
|
33
|
Chris@133
|
34 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
|
Chris@1266
|
35 QWidget *parent) :
|
Chris@132
|
36 QWidget(parent),
|
Chris@133
|
37 m_min(0),
|
Chris@133
|
38 m_max(100),
|
Chris@133
|
39 m_default(50),
|
Chris@133
|
40 m_value(50),
|
Chris@187
|
41 m_mappedValue(50),
|
Chris@187
|
42 m_noMappedUpdate(false),
|
Chris@165
|
43 m_rotation(0.5),
|
Chris@132
|
44 m_orientation(orientation),
|
Chris@165
|
45 m_speed(1.0),
|
Chris@132
|
46 m_tracking(true),
|
Chris@132
|
47 m_showScale(true),
|
Chris@132
|
48 m_clicked(false),
|
Chris@133
|
49 m_atDefault(true),
|
Chris@187
|
50 m_clickRotation(m_rotation),
|
Chris@187
|
51 m_showTooltip(true),
|
Chris@1586
|
52 m_provideContextMenu(true),
|
Chris@1586
|
53 m_lastContextMenu(nullptr),
|
Chris@1408
|
54 m_rangeMapper(nullptr)
|
Chris@132
|
55 {
|
Chris@1586
|
56 setContextMenuPolicy(Qt::CustomContextMenu);
|
Chris@1586
|
57 connect(this, SIGNAL(customContextMenuRequested(const QPoint &)),
|
Chris@1586
|
58 this, SLOT(contextMenuRequested(const QPoint &)));
|
Chris@132
|
59 }
|
Chris@132
|
60
|
Chris@132
|
61 Thumbwheel::~Thumbwheel()
|
Chris@132
|
62 {
|
Chris@187
|
63 delete m_rangeMapper;
|
Chris@1586
|
64 delete m_lastContextMenu;
|
Chris@1586
|
65 }
|
Chris@1586
|
66
|
Chris@1586
|
67 void
|
Chris@1586
|
68 Thumbwheel::contextMenuRequested(const QPoint &pos)
|
Chris@1586
|
69 {
|
Chris@1586
|
70 if (!m_provideContextMenu) {
|
Chris@1586
|
71 return;
|
Chris@1586
|
72 }
|
Chris@1586
|
73
|
Chris@1586
|
74 if (m_lastContextMenu) {
|
Chris@1586
|
75 delete m_lastContextMenu;
|
Chris@1586
|
76 }
|
Chris@1586
|
77
|
Chris@1586
|
78 QMenu *m = new QMenu;
|
Chris@1586
|
79
|
Chris@1586
|
80 if (m_title == "") {
|
Chris@1586
|
81 MenuTitle::addTitle(m, tr("Thumbwheel"));
|
Chris@1586
|
82 } else {
|
Chris@1586
|
83 MenuTitle::addTitle(m, m_title);
|
Chris@1586
|
84 }
|
Chris@1586
|
85
|
Chris@1586
|
86 m->addAction(tr("&Edit..."),
|
Chris@1586
|
87 [=]() {
|
Chris@1586
|
88 edit();
|
Chris@1586
|
89 });
|
Chris@1586
|
90 m->addAction(tr("&Reset to Default"),
|
Chris@1586
|
91 [=]() {
|
Chris@1586
|
92 resetToDefault();
|
Chris@1586
|
93 });
|
Chris@1586
|
94
|
Chris@1586
|
95 m->popup(mapToGlobal(pos));
|
Chris@1586
|
96 m_lastContextMenu = m;
|
Chris@187
|
97 }
|
Chris@187
|
98
|
Chris@187
|
99 void
|
Chris@187
|
100 Thumbwheel::setRangeMapper(RangeMapper *mapper)
|
Chris@187
|
101 {
|
Chris@187
|
102 if (m_rangeMapper == mapper) return;
|
Chris@187
|
103
|
Chris@187
|
104 if (!m_rangeMapper && mapper) {
|
Chris@187
|
105 connect(this, SIGNAL(valueChanged(int)),
|
Chris@187
|
106 this, SLOT(updateMappedValue(int)));
|
Chris@187
|
107 }
|
Chris@187
|
108
|
Chris@187
|
109 delete m_rangeMapper;
|
Chris@187
|
110 m_rangeMapper = mapper;
|
Chris@187
|
111
|
Chris@187
|
112 updateMappedValue(getValue());
|
Chris@187
|
113 }
|
Chris@187
|
114
|
Chris@187
|
115 void
|
Chris@187
|
116 Thumbwheel::setShowToolTip(bool show)
|
Chris@187
|
117 {
|
Chris@187
|
118 m_showTooltip = show;
|
Chris@187
|
119 m_noMappedUpdate = true;
|
Chris@187
|
120 updateMappedValue(getValue());
|
Chris@187
|
121 m_noMappedUpdate = false;
|
Chris@132
|
122 }
|
Chris@132
|
123
|
Chris@132
|
124 void
|
Chris@133
|
125 Thumbwheel::setMinimumValue(int min)
|
Chris@133
|
126 {
|
Chris@133
|
127 if (m_min == min) return;
|
Chris@133
|
128
|
Chris@133
|
129 m_min = min;
|
Chris@133
|
130 if (m_max <= m_min) m_max = m_min + 1;
|
Chris@133
|
131 if (m_value < m_min) m_value = m_min;
|
Chris@133
|
132 if (m_value > m_max) m_value = m_max;
|
Chris@165
|
133
|
Chris@165
|
134 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@165
|
135 update();
|
Chris@133
|
136 }
|
Chris@133
|
137
|
Chris@133
|
138 int
|
Chris@133
|
139 Thumbwheel::getMinimumValue() const
|
Chris@133
|
140 {
|
Chris@133
|
141 return m_min;
|
Chris@133
|
142 }
|
Chris@133
|
143
|
Chris@133
|
144 void
|
Chris@133
|
145 Thumbwheel::setMaximumValue(int max)
|
Chris@133
|
146 {
|
Chris@133
|
147 if (m_max == max) return;
|
Chris@133
|
148
|
Chris@133
|
149 m_max = max;
|
Chris@133
|
150 if (m_min >= m_max) m_min = m_max - 1;
|
Chris@133
|
151 if (m_value < m_min) m_value = m_min;
|
Chris@133
|
152 if (m_value > m_max) m_value = m_max;
|
Chris@165
|
153
|
Chris@165
|
154 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@165
|
155 update();
|
Chris@133
|
156 }
|
Chris@133
|
157
|
Chris@133
|
158 int
|
Chris@133
|
159 Thumbwheel::getMaximumValue() const
|
Chris@133
|
160 {
|
Chris@133
|
161 return m_max;
|
Chris@133
|
162 }
|
Chris@133
|
163
|
Chris@133
|
164 void
|
Chris@133
|
165 Thumbwheel::setDefaultValue(int deft)
|
Chris@133
|
166 {
|
Chris@133
|
167 if (m_default == deft) return;
|
Chris@133
|
168
|
Chris@133
|
169 m_default = deft;
|
Chris@133
|
170 if (m_atDefault) {
|
Chris@133
|
171 setValue(m_default);
|
Chris@165
|
172 m_atDefault = true; // setValue unsets this
|
Chris@382
|
173 m_cache = QImage();
|
Chris@133
|
174 emit valueChanged(getValue());
|
Chris@133
|
175 }
|
Chris@133
|
176 }
|
Chris@133
|
177
|
Chris@187
|
178 void
|
Chris@908
|
179 Thumbwheel::setMappedValue(double mappedValue)
|
Chris@187
|
180 {
|
Chris@187
|
181 if (m_rangeMapper) {
|
Chris@187
|
182 int newValue = m_rangeMapper->getPositionForValue(mappedValue);
|
Chris@190
|
183 bool changed = (m_mappedValue != mappedValue);
|
Chris@187
|
184 m_mappedValue = mappedValue;
|
Chris@187
|
185 m_noMappedUpdate = true;
|
Chris@587
|
186 // SVDEBUG << "Thumbwheel::setMappedValue(" << mappedValue << "): new value is " << newValue << " (visible " << isVisible() << ")" << endl;
|
Chris@187
|
187 if (newValue != getValue()) {
|
Chris@187
|
188 setValue(newValue);
|
Chris@190
|
189 changed = true;
|
Chris@382
|
190 m_cache = QImage();
|
Chris@187
|
191 }
|
Chris@190
|
192 if (changed) emit valueChanged(newValue);
|
Chris@187
|
193 m_noMappedUpdate = false;
|
Chris@187
|
194 } else {
|
Chris@190
|
195 int v = int(mappedValue);
|
Chris@190
|
196 if (v != getValue()) {
|
Chris@190
|
197 setValue(v);
|
Chris@382
|
198 m_cache = QImage();
|
Chris@190
|
199 emit valueChanged(v);
|
Chris@190
|
200 }
|
Chris@187
|
201 }
|
Chris@187
|
202 }
|
Chris@187
|
203
|
Chris@133
|
204 int
|
Chris@133
|
205 Thumbwheel::getDefaultValue() const
|
Chris@133
|
206 {
|
Chris@133
|
207 return m_default;
|
Chris@133
|
208 }
|
Chris@133
|
209
|
Chris@133
|
210 void
|
Chris@132
|
211 Thumbwheel::setValue(int value)
|
Chris@132
|
212 {
|
Chris@587
|
213 // SVDEBUG << "Thumbwheel::setValue(" << value << ") (from " << m_value
|
Chris@585
|
214 // << ", rotation " << m_rotation << ")" << " (visible " << isVisible() << ")" << endl;
|
Chris@133
|
215
|
Chris@165
|
216 if (m_value != value) {
|
Chris@165
|
217
|
Chris@165
|
218 m_atDefault = false;
|
Chris@165
|
219
|
Chris@165
|
220 if (value < m_min) value = m_min;
|
Chris@165
|
221 if (value > m_max) value = m_max;
|
Chris@165
|
222 m_value = value;
|
Chris@165
|
223 }
|
Chris@165
|
224
|
Chris@165
|
225 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@382
|
226 m_cache = QImage();
|
Chris@1586
|
227
|
Chris@1586
|
228 if (isVisible()) {
|
Chris@1586
|
229 update();
|
Chris@1586
|
230 updateTitle();
|
Chris@1586
|
231 }
|
Chris@132
|
232 }
|
Chris@132
|
233
|
Chris@133
|
234 void
|
Chris@133
|
235 Thumbwheel::resetToDefault()
|
Chris@133
|
236 {
|
Chris@133
|
237 if (m_default == m_value) return;
|
Chris@133
|
238 setValue(m_default);
|
Chris@133
|
239 m_atDefault = true;
|
Chris@382
|
240 m_cache = QImage();
|
Chris@133
|
241 emit valueChanged(getValue());
|
Chris@133
|
242 }
|
Chris@133
|
243
|
Chris@132
|
244 int
|
Chris@132
|
245 Thumbwheel::getValue() const
|
Chris@132
|
246 {
|
Chris@132
|
247 return m_value;
|
Chris@132
|
248 }
|
Chris@132
|
249
|
Chris@908
|
250 double
|
Chris@187
|
251 Thumbwheel::getMappedValue() const
|
Chris@187
|
252 {
|
Chris@187
|
253 if (m_rangeMapper) {
|
Chris@587
|
254 // SVDEBUG << "Thumbwheel::getMappedValue(): value = " << getValue() << ", mappedValue = " << m_mappedValue << endl;
|
Chris@187
|
255 return m_mappedValue;
|
Chris@187
|
256 }
|
Chris@187
|
257 return getValue();
|
Chris@187
|
258 }
|
Chris@187
|
259
|
Chris@187
|
260 void
|
Chris@187
|
261 Thumbwheel::updateMappedValue(int value)
|
Chris@187
|
262 {
|
Chris@187
|
263 if (!m_noMappedUpdate) {
|
Chris@187
|
264 if (m_rangeMapper) {
|
Chris@187
|
265 m_mappedValue = m_rangeMapper->getValueForPosition(value);
|
Chris@187
|
266 } else {
|
Chris@187
|
267 m_mappedValue = value;
|
Chris@187
|
268 }
|
Chris@187
|
269 }
|
Chris@187
|
270
|
Chris@1586
|
271 updateTitle();
|
Chris@1586
|
272 }
|
Chris@1586
|
273
|
Chris@1586
|
274 void
|
Chris@1586
|
275 Thumbwheel::updateTitle()
|
Chris@1586
|
276 {
|
Chris@1586
|
277 QString name = objectName();
|
Chris@1586
|
278 QString unit = "";
|
Chris@1586
|
279 QString text;
|
Chris@1586
|
280 double mappedValue = getMappedValue();
|
Chris@1586
|
281
|
Chris@1586
|
282 if (m_rangeMapper) unit = m_rangeMapper->getUnit();
|
Chris@1586
|
283 if (name != "") {
|
Chris@1586
|
284 text = tr("%1: %2%3").arg(name).arg(mappedValue).arg(unit);
|
Chris@1586
|
285 } else {
|
Chris@1586
|
286 text = tr("%2%3").arg(mappedValue).arg(unit);
|
Chris@1586
|
287 }
|
Chris@1586
|
288
|
Chris@1586
|
289 m_title = text;
|
Chris@1586
|
290
|
Chris@187
|
291 if (m_showTooltip) {
|
Chris@187
|
292 setToolTip(text);
|
Chris@1586
|
293 } else {
|
Chris@1586
|
294 setToolTip("");
|
Chris@187
|
295 }
|
Chris@187
|
296 }
|
Chris@187
|
297
|
Chris@132
|
298 void
|
Chris@256
|
299 Thumbwheel::scroll(bool up)
|
Chris@256
|
300 {
|
Chris@908
|
301 int step = int(lrintf(m_speed));
|
Chris@256
|
302 if (step == 0) step = 1;
|
Chris@256
|
303
|
Chris@256
|
304 if (up) {
|
Chris@1266
|
305 setValue(m_value + step);
|
Chris@256
|
306 } else {
|
Chris@1266
|
307 setValue(m_value - step);
|
Chris@256
|
308 }
|
Chris@256
|
309
|
Chris@256
|
310 emit valueChanged(getValue());
|
Chris@256
|
311 }
|
Chris@256
|
312
|
Chris@256
|
313 void
|
Chris@132
|
314 Thumbwheel::setSpeed(float speed)
|
Chris@132
|
315 {
|
Chris@132
|
316 m_speed = speed;
|
Chris@132
|
317 }
|
Chris@132
|
318
|
Chris@132
|
319 float
|
Chris@132
|
320 Thumbwheel::getSpeed() const
|
Chris@132
|
321 {
|
Chris@132
|
322 return m_speed;
|
Chris@132
|
323 }
|
Chris@132
|
324
|
Chris@132
|
325 void
|
Chris@132
|
326 Thumbwheel::setTracking(bool tracking)
|
Chris@132
|
327 {
|
Chris@132
|
328 m_tracking = tracking;
|
Chris@132
|
329 }
|
Chris@132
|
330
|
Chris@132
|
331 bool
|
Chris@132
|
332 Thumbwheel::getTracking() const
|
Chris@132
|
333 {
|
Chris@132
|
334 return m_tracking;
|
Chris@132
|
335 }
|
Chris@132
|
336
|
Chris@132
|
337 void
|
Chris@132
|
338 Thumbwheel::setShowScale(bool showScale)
|
Chris@132
|
339 {
|
Chris@132
|
340 m_showScale = showScale;
|
Chris@132
|
341 }
|
Chris@132
|
342
|
Chris@132
|
343 bool
|
Chris@132
|
344 Thumbwheel::getShowScale() const
|
Chris@132
|
345 {
|
Chris@132
|
346 return m_showScale;
|
Chris@132
|
347 }
|
Chris@132
|
348
|
Chris@132
|
349 void
|
Chris@189
|
350 Thumbwheel::enterEvent(QEvent *)
|
Chris@189
|
351 {
|
Chris@189
|
352 emit mouseEntered();
|
Chris@189
|
353 }
|
Chris@189
|
354
|
Chris@189
|
355 void
|
Chris@189
|
356 Thumbwheel::leaveEvent(QEvent *)
|
Chris@189
|
357 {
|
Chris@189
|
358 emit mouseLeft();
|
Chris@189
|
359 }
|
Chris@189
|
360
|
Chris@189
|
361 void
|
Chris@132
|
362 Thumbwheel::mousePressEvent(QMouseEvent *e)
|
Chris@132
|
363 {
|
Chris@187
|
364 if (e->button() == Qt::MidButton ||
|
Chris@187
|
365 ((e->button() == Qt::LeftButton) &&
|
Chris@187
|
366 (e->modifiers() & Qt::ControlModifier))) {
|
Chris@187
|
367 resetToDefault();
|
Chris@187
|
368 } else if (e->button() == Qt::LeftButton) {
|
Chris@133
|
369 m_clicked = true;
|
Chris@133
|
370 m_clickPos = e->pos();
|
Chris@165
|
371 m_clickRotation = m_rotation;
|
Chris@133
|
372 }
|
Chris@132
|
373 }
|
Chris@132
|
374
|
Chris@132
|
375 void
|
Chris@187
|
376 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *mouseEvent)
|
Chris@132
|
377 {
|
Chris@188
|
378 //!!! needs a common base class with AudioDial (and Panner?)
|
Chris@187
|
379
|
Chris@187
|
380 if (mouseEvent->button() != Qt::LeftButton) {
|
Chris@187
|
381 return;
|
Chris@187
|
382 }
|
Chris@187
|
383
|
Chris@1586
|
384 edit();
|
Chris@1586
|
385 }
|
Chris@1586
|
386
|
Chris@1586
|
387 void
|
Chris@1586
|
388 Thumbwheel::edit()
|
Chris@1586
|
389 {
|
Chris@187
|
390 bool ok = false;
|
Chris@187
|
391
|
Chris@187
|
392 if (m_rangeMapper) {
|
Chris@187
|
393
|
Chris@908
|
394 double min = m_rangeMapper->getValueForPosition(m_min);
|
Chris@908
|
395 double max = m_rangeMapper->getValueForPosition(m_max);
|
Chris@187
|
396
|
Chris@187
|
397 if (min > max) {
|
Chris@908
|
398 double tmp = min;
|
Chris@187
|
399 min = max;
|
Chris@187
|
400 max = tmp;
|
Chris@187
|
401 }
|
Chris@187
|
402
|
Chris@187
|
403 QString unit = m_rangeMapper->getUnit();
|
Chris@187
|
404
|
Chris@187
|
405 QString text;
|
Chris@187
|
406 if (objectName() != "") {
|
Chris@187
|
407 if (unit != "") {
|
Chris@187
|
408 text = tr("New value for %1, from %2 to %3 %4:")
|
Chris@187
|
409 .arg(objectName()).arg(min).arg(max).arg(unit);
|
Chris@187
|
410 } else {
|
Chris@187
|
411 text = tr("New value for %1, from %2 to %3:")
|
Chris@187
|
412 .arg(objectName()).arg(min).arg(max);
|
Chris@187
|
413 }
|
Chris@187
|
414 } else {
|
Chris@187
|
415 if (unit != "") {
|
Chris@187
|
416 text = tr("Enter a new value from %1 to %2 %3:")
|
Chris@187
|
417 .arg(min).arg(max).arg(unit);
|
Chris@187
|
418 } else {
|
Chris@187
|
419 text = tr("Enter a new value from %1 to %2:")
|
Chris@187
|
420 .arg(min).arg(max);
|
Chris@187
|
421 }
|
Chris@187
|
422 }
|
Chris@187
|
423
|
Chris@908
|
424 double newValue = QInputDialog::getDouble
|
Chris@187
|
425 (this,
|
Chris@187
|
426 tr("Enter new value"),
|
Chris@187
|
427 text,
|
Chris@187
|
428 m_mappedValue,
|
Chris@187
|
429 min,
|
Chris@187
|
430 max,
|
Chris@187
|
431 4,
|
Chris@187
|
432 &ok);
|
Chris@187
|
433
|
Chris@187
|
434 if (ok) {
|
Chris@187
|
435 setMappedValue(newValue);
|
Chris@187
|
436 }
|
Chris@187
|
437
|
Chris@187
|
438 } else {
|
Chris@187
|
439
|
Chris@616
|
440 int newValue = QInputDialog::getInt
|
Chris@187
|
441 (this,
|
Chris@187
|
442 tr("Enter new value"),
|
Chris@187
|
443 tr("Enter a new value from %1 to %2:")
|
Chris@187
|
444 .arg(m_min).arg(m_max),
|
Chris@187
|
445 getValue(), m_min, m_max, 1, &ok);
|
Chris@187
|
446
|
Chris@187
|
447 if (ok) {
|
Chris@187
|
448 setValue(newValue);
|
Chris@187
|
449 }
|
Chris@187
|
450 }
|
Chris@132
|
451 }
|
Chris@132
|
452
|
Chris@187
|
453
|
Chris@132
|
454 void
|
Chris@132
|
455 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
|
Chris@132
|
456 {
|
Chris@133
|
457 if (!m_clicked) return;
|
Chris@132
|
458 int dist = 0;
|
Chris@132
|
459 if (m_orientation == Qt::Horizontal) {
|
Chris@132
|
460 dist = e->x() - m_clickPos.x();
|
Chris@132
|
461 } else {
|
Chris@132
|
462 dist = e->y() - m_clickPos.y();
|
Chris@132
|
463 }
|
Chris@165
|
464
|
Chris@908
|
465 float rotation = m_clickRotation + (m_speed * float(dist)) / 100;
|
Chris@165
|
466 if (rotation < 0.f) rotation = 0.f;
|
Chris@165
|
467 if (rotation > 1.f) rotation = 1.f;
|
Chris@908
|
468 int value = int(lrintf(float(m_min) + float(m_max - m_min) * m_rotation));
|
Chris@132
|
469 if (value != m_value) {
|
Chris@132
|
470 setValue(value);
|
Chris@132
|
471 if (m_tracking) emit valueChanged(getValue());
|
Chris@165
|
472 m_rotation = rotation;
|
Chris@165
|
473 } else if (fabsf(rotation - m_rotation) > 0.001) {
|
Chris@165
|
474 m_rotation = rotation;
|
Chris@165
|
475 repaint();
|
Chris@165
|
476 }
|
Chris@132
|
477 }
|
Chris@132
|
478
|
Chris@132
|
479 void
|
Chris@132
|
480 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
|
Chris@132
|
481 {
|
Chris@133
|
482 if (!m_clicked) return;
|
Chris@132
|
483 bool reallyTracking = m_tracking;
|
Chris@132
|
484 m_tracking = true;
|
Chris@132
|
485 mouseMoveEvent(e);
|
Chris@132
|
486 m_tracking = reallyTracking;
|
Chris@133
|
487 m_clicked = false;
|
Chris@132
|
488 }
|
Chris@132
|
489
|
Chris@132
|
490 void
|
Chris@132
|
491 Thumbwheel::wheelEvent(QWheelEvent *e)
|
Chris@132
|
492 {
|
Chris@1303
|
493 int delta = m_wheelCounter.count(e);
|
Chris@132
|
494
|
Chris@1303
|
495 if (delta == 0) {
|
Chris@1303
|
496 return;
|
Chris@132
|
497 }
|
Chris@1303
|
498
|
Chris@1303
|
499 setValue(m_value + delta);
|
Chris@132
|
500 emit valueChanged(getValue());
|
Chris@132
|
501 }
|
Chris@132
|
502
|
Chris@132
|
503 void
|
Chris@132
|
504 Thumbwheel::paintEvent(QPaintEvent *)
|
Chris@132
|
505 {
|
Chris@382
|
506 Profiler profiler("Thumbwheel::paintEvent");
|
Chris@382
|
507
|
Chris@382
|
508 if (!m_cache.isNull()) {
|
Chris@382
|
509 QPainter paint(this);
|
Chris@1192
|
510 paint.drawImage(rect(), m_cache, m_cache.rect());
|
Chris@382
|
511 return;
|
Chris@382
|
512 }
|
Chris@382
|
513
|
Chris@382
|
514 Profiler profiler2("Thumbwheel::paintEvent (no cache)");
|
Chris@382
|
515
|
Chris@1192
|
516 QSize imageSize = size() * devicePixelRatio();
|
Chris@1192
|
517 m_cache = QImage(imageSize, QImage::Format_ARGB32);
|
Chris@382
|
518 m_cache.fill(Qt::transparent);
|
Chris@190
|
519
|
Chris@1193
|
520 int w = m_cache.width();
|
Chris@1193
|
521 int h = m_cache.height();
|
Chris@1192
|
522 int bw = 3; // border width
|
Chris@191
|
523
|
Chris@191
|
524 QRect subclip;
|
Chris@191
|
525 if (m_orientation == Qt::Horizontal) {
|
Chris@1192
|
526 subclip = QRect(bw, bw+1, w - bw*2, h - bw*2 - 2);
|
Chris@191
|
527 } else {
|
Chris@1192
|
528 subclip = QRect(bw+1, bw, w - bw*2 - 2, h - bw*2);
|
Chris@191
|
529 }
|
Chris@191
|
530
|
Chris@382
|
531 QPainter paint(&m_cache);
|
Chris@1192
|
532 paint.setClipRect(m_cache.rect());
|
Chris@1478
|
533 paint.fillRect(subclip, palette().window().color());
|
Chris@190
|
534
|
Chris@190
|
535 paint.setRenderHint(QPainter::Antialiasing, true);
|
Chris@133
|
536
|
Chris@908
|
537 double w0 = 0.5;
|
Chris@908
|
538 double w1 = w - 0.5;
|
Chris@190
|
539
|
Chris@908
|
540 double h0 = 0.5;
|
Chris@908
|
541 double h1 = h - 0.5;
|
Chris@190
|
542
|
Chris@190
|
543 for (int i = bw-1; i >= 0; --i) {
|
Chris@190
|
544
|
Chris@133
|
545 int grey = (i + 1) * (256 / (bw + 1));
|
Chris@133
|
546 QColor fc = QColor(grey, grey, grey);
|
Chris@133
|
547 paint.setPen(fc);
|
Chris@190
|
548
|
Chris@190
|
549 QPainterPath path;
|
Chris@190
|
550
|
Chris@190
|
551 if (m_orientation == Qt::Horizontal) {
|
Chris@190
|
552 path.moveTo(w0 + i, h0 + i + 2);
|
Chris@190
|
553 path.quadTo(w/2, i * 1.25, w1 - i, h0 + i + 2);
|
Chris@190
|
554 path.lineTo(w1 - i, h1 - i - 2);
|
Chris@190
|
555 path.quadTo(w/2, h - i * 1.25, w0 + i, h1 - i - 2);
|
Chris@190
|
556 path.closeSubpath();
|
Chris@190
|
557 } else {
|
Chris@190
|
558 path.moveTo(w0 + i + 2, h0 + i);
|
Chris@190
|
559 path.quadTo(i * 1.25, h/2, w0 + i + 2, h1 - i);
|
Chris@190
|
560 path.lineTo(w1 - i - 2, h1 - i);
|
Chris@190
|
561 path.quadTo(w - i * 1.25, h/2, w1 - i - 2, h0 + i);
|
Chris@190
|
562 path.closeSubpath();
|
Chris@190
|
563 }
|
Chris@190
|
564
|
Chris@190
|
565 paint.drawPath(path);
|
Chris@133
|
566 }
|
Chris@133
|
567
|
Chris@191
|
568 paint.setClipRect(subclip);
|
Chris@133
|
569
|
Chris@908
|
570 double radians = m_rotation * 1.5f * M_PI;
|
Chris@132
|
571
|
Chris@682
|
572 // cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << endl;
|
Chris@132
|
573
|
Chris@1192
|
574 int ww = (m_orientation == Qt::Horizontal ? w : h) - bw*2; // wheel width
|
Chris@132
|
575
|
Chris@132
|
576 // total number of notches on the entire wheel
|
Chris@132
|
577 int notches = 25;
|
Chris@132
|
578
|
Chris@132
|
579 // radius of the wheel including invisible part
|
Chris@1192
|
580 int radius = int(ww / 2 + 2);
|
Chris@132
|
581
|
Chris@132
|
582 for (int i = 0; i < notches; ++i) {
|
Chris@132
|
583
|
Chris@908
|
584 double a0 = (2.0 * M_PI * i) / notches + radians;
|
Chris@908
|
585 double a1 = a0 + M_PI / (notches * 2);
|
Chris@908
|
586 double a2 = (2.0 * M_PI * (i + 1)) / notches + radians;
|
Chris@132
|
587
|
Chris@908
|
588 double depth = cos((a0 + a2) / 2);
|
Chris@132
|
589 if (depth < 0) continue;
|
Chris@132
|
590
|
Chris@1192
|
591 double x0 = radius * sin(a0) + ww/2;
|
Chris@1192
|
592 double x1 = radius * sin(a1) + ww/2;
|
Chris@1192
|
593 double x2 = radius * sin(a2) + ww/2;
|
Chris@1192
|
594 if (x2 < 0 || x0 > ww) continue;
|
Chris@132
|
595
|
Chris@132
|
596 if (x0 < 0) x0 = 0;
|
Chris@1192
|
597 if (x2 > ww) x2 = ww;
|
Chris@132
|
598
|
Chris@133
|
599 x0 += bw;
|
Chris@133
|
600 x1 += bw;
|
Chris@133
|
601 x2 += bw;
|
Chris@133
|
602
|
Chris@908
|
603 int grey = int(lrint(120 * depth));
|
Chris@541
|
604
|
Chris@132
|
605 QColor fc = QColor(grey, grey, grey);
|
Chris@541
|
606 QColor oc = palette().highlight().color();
|
Chris@132
|
607
|
Chris@541
|
608 paint.setPen(fc);
|
Chris@132
|
609
|
Chris@132
|
610 if (m_showScale) {
|
Chris@132
|
611
|
Chris@132
|
612 paint.setBrush(oc);
|
Chris@132
|
613
|
Chris@908
|
614 double prop;
|
Chris@132
|
615 if (i >= notches / 4) {
|
Chris@908
|
616 prop = double(notches - (((i - double(notches) / 4.f) * 4.f) / 3.f))
|
Chris@132
|
617 / notches;
|
Chris@132
|
618 } else {
|
Chris@132
|
619 prop = 0.f;
|
Chris@132
|
620 }
|
Chris@132
|
621
|
Chris@132
|
622 if (m_orientation == Qt::Horizontal) {
|
Chris@1192
|
623 paint.drawRect(QRectF(x1, h - (h - bw*2) * prop - bw,
|
Chris@1192
|
624 x2 - x1, h * prop));
|
Chris@132
|
625 } else {
|
Chris@1192
|
626 paint.drawRect(QRectF(bw, x1, (w - bw*2) * prop, x2 - x1));
|
Chris@132
|
627 }
|
Chris@132
|
628 }
|
Chris@132
|
629
|
Chris@541
|
630 paint.setPen(fc);
|
Chris@1478
|
631 paint.setBrush(palette().window().color());
|
Chris@132
|
632
|
Chris@132
|
633 if (m_orientation == Qt::Horizontal) {
|
Chris@1192
|
634 paint.drawRect(QRectF(x0, bw, x1 - x0, h - bw*2));
|
Chris@132
|
635 } else {
|
Chris@1192
|
636 paint.drawRect(QRectF(bw, x0, w - bw*2, x1 - x0));
|
Chris@132
|
637 }
|
Chris@132
|
638 }
|
Chris@382
|
639
|
Chris@382
|
640 QPainter paint2(this);
|
Chris@1192
|
641 paint2.drawImage(rect(), m_cache, m_cache.rect());
|
Chris@132
|
642 }
|
Chris@132
|
643
|
Chris@132
|
644 QSize
|
Chris@132
|
645 Thumbwheel::sizeHint() const
|
Chris@132
|
646 {
|
Chris@132
|
647 if (m_orientation == Qt::Horizontal) {
|
Chris@132
|
648 return QSize(80, 12);
|
Chris@132
|
649 } else {
|
Chris@132
|
650 return QSize(12, 80);
|
Chris@132
|
651 }
|
Chris@132
|
652 }
|
Chris@132
|
653
|