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