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@132
|
18 #include <QMouseEvent>
|
Chris@132
|
19 #include <QPaintEvent>
|
Chris@132
|
20 #include <QWheelEvent>
|
Chris@132
|
21 #include <QPainter>
|
Chris@132
|
22
|
Chris@132
|
23 #include <cmath>
|
Chris@132
|
24 #include <iostream>
|
Chris@132
|
25
|
Chris@133
|
26 Thumbwheel::Thumbwheel(Qt::Orientation orientation,
|
Chris@132
|
27 QWidget *parent) :
|
Chris@132
|
28 QWidget(parent),
|
Chris@133
|
29 m_min(0),
|
Chris@133
|
30 m_max(100),
|
Chris@133
|
31 m_default(50),
|
Chris@133
|
32 m_value(50),
|
Chris@165
|
33 m_rotation(0.5),
|
Chris@132
|
34 m_orientation(orientation),
|
Chris@165
|
35 m_speed(1.0),
|
Chris@132
|
36 m_tracking(true),
|
Chris@132
|
37 m_showScale(true),
|
Chris@132
|
38 m_clicked(false),
|
Chris@133
|
39 m_atDefault(true),
|
Chris@165
|
40 m_clickRotation(m_rotation)
|
Chris@132
|
41 {
|
Chris@132
|
42 }
|
Chris@132
|
43
|
Chris@132
|
44 Thumbwheel::~Thumbwheel()
|
Chris@132
|
45 {
|
Chris@132
|
46 }
|
Chris@132
|
47
|
Chris@132
|
48 void
|
Chris@133
|
49 Thumbwheel::setMinimumValue(int min)
|
Chris@133
|
50 {
|
Chris@133
|
51 if (m_min == min) return;
|
Chris@133
|
52
|
Chris@133
|
53 m_min = min;
|
Chris@133
|
54 if (m_max <= m_min) m_max = m_min + 1;
|
Chris@133
|
55 if (m_value < m_min) m_value = m_min;
|
Chris@133
|
56 if (m_value > m_max) m_value = m_max;
|
Chris@165
|
57
|
Chris@165
|
58 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@165
|
59 update();
|
Chris@133
|
60 }
|
Chris@133
|
61
|
Chris@133
|
62 int
|
Chris@133
|
63 Thumbwheel::getMinimumValue() const
|
Chris@133
|
64 {
|
Chris@133
|
65 return m_min;
|
Chris@133
|
66 }
|
Chris@133
|
67
|
Chris@133
|
68 void
|
Chris@133
|
69 Thumbwheel::setMaximumValue(int max)
|
Chris@133
|
70 {
|
Chris@133
|
71 if (m_max == max) return;
|
Chris@133
|
72
|
Chris@133
|
73 m_max = max;
|
Chris@133
|
74 if (m_min >= m_max) m_min = m_max - 1;
|
Chris@133
|
75 if (m_value < m_min) m_value = m_min;
|
Chris@133
|
76 if (m_value > m_max) m_value = m_max;
|
Chris@165
|
77
|
Chris@165
|
78 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@165
|
79 update();
|
Chris@133
|
80 }
|
Chris@133
|
81
|
Chris@133
|
82 int
|
Chris@133
|
83 Thumbwheel::getMaximumValue() const
|
Chris@133
|
84 {
|
Chris@133
|
85 return m_max;
|
Chris@133
|
86 }
|
Chris@133
|
87
|
Chris@133
|
88 void
|
Chris@133
|
89 Thumbwheel::setDefaultValue(int deft)
|
Chris@133
|
90 {
|
Chris@133
|
91 if (m_default == deft) return;
|
Chris@133
|
92
|
Chris@133
|
93 m_default = deft;
|
Chris@133
|
94 if (m_atDefault) {
|
Chris@133
|
95 setValue(m_default);
|
Chris@165
|
96 m_atDefault = true; // setValue unsets this
|
Chris@133
|
97 emit valueChanged(getValue());
|
Chris@133
|
98 }
|
Chris@133
|
99 }
|
Chris@133
|
100
|
Chris@133
|
101 int
|
Chris@133
|
102 Thumbwheel::getDefaultValue() const
|
Chris@133
|
103 {
|
Chris@133
|
104 return m_default;
|
Chris@133
|
105 }
|
Chris@133
|
106
|
Chris@133
|
107 void
|
Chris@132
|
108 Thumbwheel::setValue(int value)
|
Chris@132
|
109 {
|
Chris@165
|
110 // std::cerr << "Thumbwheel::setValue(" << value << ") (from " << m_value
|
Chris@165
|
111 // << ", rotation " << m_rotation << ")" << std::endl;
|
Chris@133
|
112
|
Chris@165
|
113 if (m_value != value) {
|
Chris@165
|
114
|
Chris@165
|
115 m_atDefault = false;
|
Chris@165
|
116
|
Chris@165
|
117 if (value < m_min) value = m_min;
|
Chris@165
|
118 if (value > m_max) value = m_max;
|
Chris@165
|
119 m_value = value;
|
Chris@165
|
120 }
|
Chris@165
|
121
|
Chris@165
|
122 m_rotation = float(m_value - m_min) / float(m_max - m_min);
|
Chris@132
|
123 update();
|
Chris@132
|
124 }
|
Chris@132
|
125
|
Chris@133
|
126 void
|
Chris@133
|
127 Thumbwheel::resetToDefault()
|
Chris@133
|
128 {
|
Chris@133
|
129 if (m_default == m_value) return;
|
Chris@133
|
130 setValue(m_default);
|
Chris@133
|
131 m_atDefault = true;
|
Chris@133
|
132 emit valueChanged(getValue());
|
Chris@133
|
133 }
|
Chris@133
|
134
|
Chris@132
|
135 int
|
Chris@132
|
136 Thumbwheel::getValue() const
|
Chris@132
|
137 {
|
Chris@132
|
138 return m_value;
|
Chris@132
|
139 }
|
Chris@132
|
140
|
Chris@132
|
141 void
|
Chris@132
|
142 Thumbwheel::setSpeed(float speed)
|
Chris@132
|
143 {
|
Chris@132
|
144 m_speed = speed;
|
Chris@132
|
145 }
|
Chris@132
|
146
|
Chris@132
|
147 float
|
Chris@132
|
148 Thumbwheel::getSpeed() const
|
Chris@132
|
149 {
|
Chris@132
|
150 return m_speed;
|
Chris@132
|
151 }
|
Chris@132
|
152
|
Chris@132
|
153 void
|
Chris@132
|
154 Thumbwheel::setTracking(bool tracking)
|
Chris@132
|
155 {
|
Chris@132
|
156 m_tracking = tracking;
|
Chris@132
|
157 }
|
Chris@132
|
158
|
Chris@132
|
159 bool
|
Chris@132
|
160 Thumbwheel::getTracking() const
|
Chris@132
|
161 {
|
Chris@132
|
162 return m_tracking;
|
Chris@132
|
163 }
|
Chris@132
|
164
|
Chris@132
|
165 void
|
Chris@132
|
166 Thumbwheel::setShowScale(bool showScale)
|
Chris@132
|
167 {
|
Chris@132
|
168 m_showScale = showScale;
|
Chris@132
|
169 }
|
Chris@132
|
170
|
Chris@132
|
171 bool
|
Chris@132
|
172 Thumbwheel::getShowScale() const
|
Chris@132
|
173 {
|
Chris@132
|
174 return m_showScale;
|
Chris@132
|
175 }
|
Chris@132
|
176
|
Chris@132
|
177 void
|
Chris@132
|
178 Thumbwheel::mousePressEvent(QMouseEvent *e)
|
Chris@132
|
179 {
|
Chris@133
|
180 if (e->button() == Qt::LeftButton) {
|
Chris@133
|
181 m_clicked = true;
|
Chris@133
|
182 m_clickPos = e->pos();
|
Chris@165
|
183 m_clickRotation = m_rotation;
|
Chris@133
|
184 } else if (e->button() == Qt::MidButton) {
|
Chris@133
|
185 resetToDefault();
|
Chris@133
|
186 }
|
Chris@132
|
187 }
|
Chris@132
|
188
|
Chris@132
|
189 void
|
Chris@132
|
190 Thumbwheel::mouseDoubleClickEvent(QMouseEvent *)
|
Chris@132
|
191 {
|
Chris@133
|
192 resetToDefault();
|
Chris@132
|
193 }
|
Chris@132
|
194
|
Chris@132
|
195 void
|
Chris@132
|
196 Thumbwheel::mouseMoveEvent(QMouseEvent *e)
|
Chris@132
|
197 {
|
Chris@133
|
198 if (!m_clicked) return;
|
Chris@132
|
199 int dist = 0;
|
Chris@132
|
200 if (m_orientation == Qt::Horizontal) {
|
Chris@132
|
201 dist = e->x() - m_clickPos.x();
|
Chris@132
|
202 } else {
|
Chris@132
|
203 dist = e->y() - m_clickPos.y();
|
Chris@132
|
204 }
|
Chris@165
|
205
|
Chris@165
|
206 float rotation = m_clickRotation + (m_speed * dist) / 100;
|
Chris@165
|
207 if (rotation < 0.f) rotation = 0.f;
|
Chris@165
|
208 if (rotation > 1.f) rotation = 1.f;
|
Chris@165
|
209 int value = lrintf(m_min + (m_max - m_min) * m_rotation);
|
Chris@132
|
210 if (value != m_value) {
|
Chris@132
|
211 setValue(value);
|
Chris@132
|
212 if (m_tracking) emit valueChanged(getValue());
|
Chris@165
|
213 m_rotation = rotation;
|
Chris@165
|
214 } else if (fabsf(rotation - m_rotation) > 0.001) {
|
Chris@165
|
215 m_rotation = rotation;
|
Chris@165
|
216 repaint();
|
Chris@165
|
217 }
|
Chris@132
|
218 }
|
Chris@132
|
219
|
Chris@132
|
220 void
|
Chris@132
|
221 Thumbwheel::mouseReleaseEvent(QMouseEvent *e)
|
Chris@132
|
222 {
|
Chris@133
|
223 if (!m_clicked) return;
|
Chris@132
|
224 bool reallyTracking = m_tracking;
|
Chris@132
|
225 m_tracking = true;
|
Chris@132
|
226 mouseMoveEvent(e);
|
Chris@132
|
227 m_tracking = reallyTracking;
|
Chris@133
|
228 m_clicked = false;
|
Chris@132
|
229 }
|
Chris@132
|
230
|
Chris@132
|
231 void
|
Chris@132
|
232 Thumbwheel::wheelEvent(QWheelEvent *e)
|
Chris@132
|
233 {
|
Chris@132
|
234 int step = lrintf(m_speed);
|
Chris@132
|
235 if (step == 0) step = 1;
|
Chris@132
|
236
|
Chris@132
|
237 if (e->delta() > 0) {
|
Chris@132
|
238 setValue(m_value + step);
|
Chris@132
|
239 } else {
|
Chris@132
|
240 setValue(m_value - step);
|
Chris@132
|
241 }
|
Chris@132
|
242
|
Chris@132
|
243 emit valueChanged(getValue());
|
Chris@132
|
244 }
|
Chris@132
|
245
|
Chris@132
|
246 void
|
Chris@132
|
247 Thumbwheel::paintEvent(QPaintEvent *)
|
Chris@132
|
248 {
|
Chris@133
|
249 QPainter paint(this);
|
Chris@133
|
250 paint.fillRect(rect(), palette().background().color());
|
Chris@133
|
251 paint.setRenderHint(QPainter::Antialiasing, false);
|
Chris@133
|
252
|
Chris@133
|
253 int bw = 3;
|
Chris@133
|
254
|
Chris@133
|
255 for (int i = 0; i < bw; ++i) {
|
Chris@133
|
256 int grey = (i + 1) * (256 / (bw + 1));
|
Chris@133
|
257 QColor fc = QColor(grey, grey, grey);
|
Chris@133
|
258 paint.setPen(fc);
|
Chris@133
|
259 paint.drawRect(i, i, width() - i*2 - 1, height() - i*2 - 1);
|
Chris@133
|
260 }
|
Chris@133
|
261
|
Chris@133
|
262 paint.setClipRect(QRect(bw, bw, width() - bw*2, height() - bw*2));
|
Chris@133
|
263
|
Chris@165
|
264 float radians = m_rotation * 1.5f * M_PI;
|
Chris@132
|
265
|
Chris@132
|
266 // std::cerr << "value = " << m_value << ", min = " << m_min << ", max = " << m_max << ", rotation = " << rotation << std::endl;
|
Chris@132
|
267
|
Chris@133
|
268 int w = (m_orientation == Qt::Horizontal ? width() : height()) - bw*2;
|
Chris@132
|
269
|
Chris@132
|
270 // total number of notches on the entire wheel
|
Chris@132
|
271 int notches = 25;
|
Chris@132
|
272
|
Chris@132
|
273 // radius of the wheel including invisible part
|
Chris@132
|
274 int radius = w / 2 + 2;
|
Chris@132
|
275
|
Chris@132
|
276 paint.setRenderHint(QPainter::Antialiasing, true);
|
Chris@132
|
277
|
Chris@132
|
278 for (int i = 0; i < notches; ++i) {
|
Chris@132
|
279
|
Chris@165
|
280 float a0 = (2.f * M_PI * i) / notches + radians;
|
Chris@132
|
281 float a1 = a0 + M_PI / (notches * 2);
|
Chris@165
|
282 float a2 = (2.f * M_PI * (i + 1)) / notches + radians;
|
Chris@132
|
283
|
Chris@132
|
284 float depth = cosf((a0 + a2) / 2);
|
Chris@132
|
285 if (depth < 0) continue;
|
Chris@132
|
286
|
Chris@132
|
287 float x0 = radius * sinf(a0) + w/2;
|
Chris@132
|
288 float x1 = radius * sinf(a1) + w/2;
|
Chris@132
|
289 float x2 = radius * sinf(a2) + w/2;
|
Chris@132
|
290 if (x2 < 0 || x0 > w) continue;
|
Chris@132
|
291
|
Chris@132
|
292 if (x0 < 0) x0 = 0;
|
Chris@132
|
293 if (x2 > w) x2 = w;
|
Chris@132
|
294
|
Chris@133
|
295 x0 += bw;
|
Chris@133
|
296 x1 += bw;
|
Chris@133
|
297 x2 += bw;
|
Chris@133
|
298
|
Chris@132
|
299 int grey = lrintf(255 * depth);
|
Chris@132
|
300 QColor fc = QColor(grey, grey, grey);
|
Chris@132
|
301 QColor oc = palette().dark().color();
|
Chris@132
|
302
|
Chris@132
|
303 paint.setPen(oc);
|
Chris@132
|
304 paint.setBrush(fc);
|
Chris@132
|
305
|
Chris@132
|
306 if (m_orientation == Qt::Horizontal) {
|
Chris@133
|
307 paint.drawRect(QRectF(x1, bw, x2 - x1, height() - bw*2));
|
Chris@132
|
308 } else {
|
Chris@133
|
309 paint.drawRect(QRectF(bw, x1, width() - bw*2, x2 - x1));
|
Chris@132
|
310 }
|
Chris@132
|
311
|
Chris@132
|
312 if (m_showScale) {
|
Chris@132
|
313
|
Chris@132
|
314 paint.setBrush(oc);
|
Chris@132
|
315
|
Chris@132
|
316 float prop;
|
Chris@132
|
317 if (i >= notches / 4) {
|
Chris@132
|
318 prop = float(notches - (((i - float(notches) / 4.f) * 4.f) / 3.f))
|
Chris@132
|
319 / notches;
|
Chris@132
|
320 } else {
|
Chris@132
|
321 prop = 0.f;
|
Chris@132
|
322 }
|
Chris@132
|
323
|
Chris@132
|
324 if (m_orientation == Qt::Horizontal) {
|
Chris@133
|
325 paint.drawRect(QRectF(x1, height() - (height() - bw*2) * prop - bw,
|
Chris@132
|
326 x2 - x1, height() * prop));
|
Chris@132
|
327 } else {
|
Chris@133
|
328 paint.drawRect(QRectF(bw, x1, (width() - bw*2) * prop, x2 - x1));
|
Chris@132
|
329 }
|
Chris@132
|
330 }
|
Chris@132
|
331
|
Chris@132
|
332 paint.setPen(oc);
|
Chris@132
|
333 paint.setBrush(palette().background().color());
|
Chris@132
|
334
|
Chris@132
|
335 if (m_orientation == Qt::Horizontal) {
|
Chris@133
|
336 paint.drawRect(QRectF(x0, bw, x1 - x0, height() - bw*2));
|
Chris@132
|
337 } else {
|
Chris@133
|
338 paint.drawRect(QRectF(bw, x0, width() - bw*2, x1 - x0));
|
Chris@132
|
339 }
|
Chris@132
|
340 }
|
Chris@132
|
341 }
|
Chris@132
|
342
|
Chris@132
|
343 QSize
|
Chris@132
|
344 Thumbwheel::sizeHint() const
|
Chris@132
|
345 {
|
Chris@132
|
346 if (m_orientation == Qt::Horizontal) {
|
Chris@132
|
347 return QSize(80, 12);
|
Chris@132
|
348 } else {
|
Chris@132
|
349 return QSize(12, 80);
|
Chris@132
|
350 }
|
Chris@132
|
351 }
|
Chris@132
|
352
|