Developer Documentation

QtWheel.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openflipper.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenFlipper. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41
42
43
44
45
46 //=============================================================================
47 //
48 // CLASS QtWheel - IMPLEMENTATION
49 //
50 //=============================================================================
51
52 //== INCLUDES =================================================================
53
54 #include "QtWheel.hh"
55
56 #include <cmath>
57 #include <iostream>
58
59 //#include <QDrawutil>
60
61 #include <QPainter>
62 #include <QMenu>
63 #include <QTimer>
64 #include <qdrawutil.h>
65
66
67 //== NAMESPACES ===============================================================
68
69
70 namespace ACG {
71 namespace QtWidgets {
72
73
74 //== IMPLEMENTATION ==========================================================
75
76
77 QtWheel::QtWheel(QWidget* _parent,
78 const char* /* _name */ ,
79 Orientation _orientation)
80 : QFrame(_parent),
81 angle_(0.0),
82 lastAngle_(0.0),
83 gear_(1.0),
84 gearShift_(0),
85 orientation_(_orientation),
86 ticks_(36),
87 marker_(false),
88 dragging_(false),
89 tracking_(false)
90 {
91
92 palette_ = palette();
93 palette_.setColor( QPalette::Dark, QColor(0,0,0));
94
95 setFrameStyle( QtWheel::Panel | QtWheel::Raised );
96 setLineWidth(2);
97
98 setContextMenuPolicy ( Qt::CustomContextMenu );
99
100 connect (this, SIGNAL (customContextMenuRequested ( const QPoint & ) ),
101 this, SLOT( slotCustomContextMenuRequested ( const QPoint & ) ));
102
103 }
104
105
106 QtWheel::~QtWheel() {
107 }
108
109 //----------------------------------------------------------------------------
110
111 void QtWheel::mousePressEvent(QMouseEvent* _e)
112 {
113 if (_e->button()==Qt::LeftButton) {
114 pos_=_e->pos();
115 dragging_=true;
116 lastAngle_=angle_;
117 }
118 }
119
120 void QtWheel::mouseReleaseEvent(QMouseEvent* _e)
121 {
122 if (_e->button()==Qt::LeftButton)
123 {
124 dragging_=false;
125
126 // turn(_e->pos());
127 // emit angleChangedTo(angle_);
128 // emit angleChangedBy(angle_-lastAngle_);
129 }
130 }
131
132
133 void QtWheel::mouseMoveEvent(QMouseEvent* _e)
134 {
135 if (_e->buttons()&Qt::LeftButton)
136 {
137 float dAngle=turn(_e->pos());
138
139 if (tracking_ && dAngle!=0.0) { // 0.0 is explicitly returned
140 lastAngle_=angle_-dAngle;
141
142 emit angleChangedTo(angle_);
143 emit angleChangedBy(dAngle);
144 }
145 }
146 }
147
148
149 double QtWheel::turn(const QPoint& _pos)
150 {
151 QPoint dPos=(_pos-pos_);
152 pos_=_pos;
153
154 int d = orientation_== Horizontal ? dPos.x() : dPos.y();
155
156 double dAngle=0.0;
157
158 if (d!=0) {
159 // full width/height = 180 deg for gear()==1
160 dAngle=double(d)/double(size_)*M_PI*gear_;
161 angle_+=dAngle;
162
163 redrawPixmap();
164 repaint();
165 }
166 return dAngle;
167 }
168
169 //----------------------------------------------------------------------------
170
171 void QtWheel::mouseDoubleClickEvent(QMouseEvent* _e) {
172 if (_e->button()==Qt::LeftButton) {
173 int sz,x;
174 if (orientation_== Horizontal) {
175 sz=width(); x=_e->x();
176 }
177 else {
178 sz=height(); x=_e->y();
179 }
180
181 if (x<sz/2) {
182 if (gearShift_<8) {
183 ++gearShift_;
184 gear_*=2.0;
185
186 redrawPixmap();
187 repaint();
188
189 emit gearUp();
190 }
191 }
192 else {
193 if (gearShift_>-8) {
194 --gearShift_;
195 gear_/=2.0;
196
197 redrawPixmap();
198 repaint();
199
200 emit gearDown();
201 }
202 }
203 }
204 }
205
206 //----------------------------------------------------------------------------
207
208 void QtWheel::keyPressEvent(QKeyEvent* _e) {
209
210 //
211 // This does not work! Do we really need/want keyboard input???
212 //
213
214 if (dragging_)
215 return;
216
217 double dAngle=0.0;
218
219 if (!_e->isAutoRepeat())
220 lastAngle_=angle_;
221
222 switch (_e->key()) {
223 case Qt::Key_Left:
224 case Qt::Key_Up: {
225 dAngle= -M_PI/double(ticks_)*gear_;
226 }
227 break;
228
229 case Qt::Key_Right:
230 case Qt::Key_Down: {
231 dAngle= +M_PI/double(ticks_)*gear_;
232 }
233 break;
234
235 default: return;
236 }
237
238 if (tracking_)
239 lastAngle_=angle_;
240
241 angle_+=dAngle;
242
243 redrawPixmap();
244 repaint();
245
246 if (tracking_) {
247 emit angleChangedTo(angle_);
248 emit angleChangedBy(angle_-lastAngle_);
249 }
250 }
251
252 void QtWheel::keyReleaseEvent(QKeyEvent* _e) {
253 switch (_e->key()) {
254 case Qt::Key_Left:
255 case Qt::Key_Up:
256 case Qt::Key_Right:
257 case Qt::Key_Down: {
258 if (!tracking_) {
259 emit angleChangedTo(angle_);
260 emit angleChangedBy(angle_-lastAngle_);
261 }
262 };
263 break;
264
265 default: return;
266 }
267 }
268
269 //----------------------------------------------------------------------------
270
271 void QtWheel::resizeEvent(QResizeEvent* _e) {
272 QFrame::resizeEvent(_e);
273 redrawPixmap();
274 }
275
276 void QtWheel::paintEvent(QPaintEvent* _e) {
277 if (isVisible()) {
278 QFrame::paintEvent(_e);
279
280
281 QPainter painter(this);
282 QRect r=contentsRect();
283
285 painter.drawPixmap( r.left(), r.top(), pixmap_ );
286
287 }
288 }
289
290 //----------------------------------------------------------------------------
291
292 void QtWheel::redrawPixmap() {
293 QRect r=contentsRect();
294
295 if (r.width()<=0 || r.height()<=0) {
296 pixmap_ = QPixmap( 0, 0 );
297 return;
298 }
299
300 if (pixmap_.size()!=r.size())
301 pixmap_ = QPixmap(r.size());
302
303 QPainter paint;
304
305 paint.begin( &pixmap_);
306 pixmap_.fill( palette().background().color() );
307
308 // coords of wheel frame
309 QRect contents = contentsRect();
310 contents.moveTopLeft(QPoint(0,0)); // transform to pixmap coord sys
311
312 QPen pen(Qt::black, 1);
313 paint.setPen(pen);
314
315 if (orientation_ == Horizontal) {
316
317 shrinkRect(contents, 3, 2);
318
319 // draw a black frame
320 paint.drawRect(contents);
321 shrinkRect(contents, 1, 0);
322 paint.drawRect(contents);
323 shrinkRect(contents, 3, 2);
324
325 int x0 = contents.left();
326 int y0 = contents.top();
327 int w0 = contents.width();
328 int h0 = contents.height();
329
330 size_=w0;
331
332 if (gearShift_>0) {
333 QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
334 int w=std::min(4*gearShift_,w0-8);
335 paint.fillRect(x0+8,y0-1,w,h0+2,b);
336 }
337 else if (gearShift_<0) {
338 QBrush b; b.setColor(QColor(Qt::blue));
339 int w=std::min(-4*gearShift_,w0-8); b.setStyle(Qt::SolidPattern);
340 paint.fillRect(x0+w0-w-8,y0-1,w,h0+2,b);
341 }
342
343 // draw the wheel
344 double step = 2 * M_PI / (double) ticks_;
345 for (int i = 0; i < ticks_; i++) {
346 double x = sin(angle_ + i * step);
347 double y = cos(angle_ + i * step);
348 if (y>0) {
349 qDrawShadeLine( &paint,
350 (int) (x0+(w0+x*w0)/2.0f), y0,
351 (int) (x0+(w0+x*w0)/2.0f), y0+h0,
352 palette_, false, 1, 1);
353 }
354 }
355 }
356
357 else if (orientation_ == Vertical) {
358
359 shrinkRect(contents, 2, 3);
360
361 // draw a black frame
362 paint.drawRect(contents);
363 shrinkRect(contents, 0, 1);
364 paint.drawRect(contents);
365 shrinkRect(contents, 2, 3);
366
367
368 int x0 = contents.left();
369 int y0 = contents.top();
370 int w0 = contents.width();
371 int h0 = contents.height();
372
373 size_=h0;
374
375 if (gearShift_>0) {
376 QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
377 int h=-std::min(-4*gearShift_,h0-8);
378 paint.fillRect(x0-1,y0+8,w0+2,h,b);
379 }
380 else if (gearShift_<0) {
381 QBrush b; b.setColor(QColor(Qt::blue)); b.setStyle(Qt::SolidPattern);
382 int h=-std::min(4*gearShift_,h0-8);
383 paint.fillRect(x0-1,y0+h0-h-8,w0+2,h,b);
384 }
385
386 // draw the wheel
387 double step = 2 * M_PI / (double) ticks_;
388 for (int i = 0; i < ticks_; i++) {
389 double x = sin(angle_ + i * step);
390 double y = cos(angle_ + i * step);
391 if (y>0) {
392 qDrawShadeLine( &paint,
393 x0, (int) (y0+(h0+x*h0)/2.0f),
394 x0+w0, (int) (y0+(h0+x*h0)/2.0f),
395 palette_, false, 1, 1);
396 } // if y
397 } // for ticks_
398 } // if Vertical
399 paint.end();
400 }
401
402 //-----------------------------------------------------------------------------
403
404 void QtWheel::shrinkRect(QRect& _rect, int _dx, int _dy) {
405 _rect.setLeft(_rect.left()+_dx);
406 _rect.setRight(_rect.right()-_dx);
407 _rect.setTop(_rect.top()+_dy); // dy -> -dy
408 _rect.setBottom(_rect.bottom()-_dy);
409 }
410
411 //-----------------------------------------------------------------------------
412
413 QSizePolicy QtWheel::sizePolicy() const
414 {
415 if (orientation_== Horizontal)
416 return QSizePolicy(QSizePolicy::Preferred,
417 QSizePolicy::Minimum);
418 else
419 return QSizePolicy(QSizePolicy::Minimum,
420 QSizePolicy::Preferred);
421 }
422
423 //-----------------------------------------------------------------------------
424
425 QSize QtWheel::sizeHint() const
426 {
427 if (orientation_==Horizontal)
428 return QSize(120,20);
429 else
430 return QSize(20,120);
431 }
432
433 //-----------------------------------------------------------------------------
434
435
436 double QtWheel::clip(double _angle) {
437 return fmod(_angle,2*M_PI);
438 }
439
440 double QtWheel::deg(double _angle) {
441 return _angle*180.0/M_PI;
442 }
443
444 //-----------------------------------------------------------------------------
445
446 void QtWheel::slotCustomContextMenuRequested ( const QPoint & pos ) {
447
448 QMenu* menu = new QMenu(this);
449 QAction *hide = menu->addAction("Hide wheel");
450 connect( hide, SIGNAL(triggered()) , this, SIGNAL(hideWheel()) );
451 menu->popup( mapToGlobal(pos) );
452
453 }
454
455
456 //=============================================================================
457 } // namespace QtWidgets
458 } // namespace ACG
459 //=============================================================================
ACG::QtWidgets::QtWheel::keyReleaseEvent
virtual void keyReleaseEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:252
ACG::QtWidgets::QtWheel::mousePressEvent
virtual void mousePressEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:111
ACG
Namespace providing different geometric functions concerning angles.
Definition: BaseObjectData.hh:68
ACG::QtWidgets::QtWheel::hideWheel
void hideWheel()
Emitted when the wheel will be hidden by the context menu.
ACG::QtWidgets::QtWheel::gearShift_
int gearShift_
click-shifted gear by 2^gearShift_
Definition: QtWheel.hh:275
ACG::QtWidgets::QtWheel::redrawPixmap
virtual void redrawPixmap()
draw wheel to pixmap (double buffering)
Definition: QtWheel.cc:292
ACG::QtWidgets::QtWheel::clip
static double clip(double _angle)
Definition: QtWheel.cc:436
ACG::QtWidgets::QtWheel::keyPressEvent
virtual void keyPressEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:208
ACG::QtWidgets::QtWheel::resizeEvent
virtual void resizeEvent(QResizeEvent *)
reimplemented
Definition: QtWheel.cc:271
ACG::QtWidgets::QtWheel::sizeHint
virtual QSize sizeHint() const
reimplemented
Definition: QtWheel.cc:425
ACG::QtWidgets::QtWheel::mouseMoveEvent
virtual void mouseMoveEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:133
ACG::QtWidgets::QtWheel::angleChangedTo
void angleChangedTo(double _angle)
ACG::QtWidgets::QtWheel::ticks_
int ticks_
number of ticks on the wheel
Definition: QtWheel.hh:279
ACG::QtWidgets::QtWheel::deg
static double deg(double _angle)
maps _angle from radiants to degrees (works also for clip()ped angles)
Definition: QtWheel.cc:440
ACG::QtWidgets::QtWheel::pos_
QPoint pos_
recent mouse position
Definition: QtWheel.hh:282
ACG::QtWidgets::QtWheel::angle_
double angle_
current angle of the wheel
Definition: QtWheel.hh:270
ACG::QtWidgets::QtWheel::mouseDoubleClickEvent
virtual void mouseDoubleClickEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:171
ACG::QtWidgets::QtWheel::angleChangedBy
void angleChangedBy(double _angle)
ACG::QtWidgets::QtWheel::~QtWheel
virtual ~QtWheel()
Destructor.
Definition: QtWheel.cc:106
ACG::QtWidgets::QtWheel::orientation_
Orientation orientation_
orientation of the widget
Definition: QtWheel.hh:277
ACG::QtWidgets::QtWheel::tracking_
bool tracking_
tracking on?
Definition: QtWheel.hh:284
ACG::QtWidgets::QtWheel::dragging_
bool dragging_
currently dragging the slider?
Definition: QtWheel.hh:283
ACG::QtWidgets::QtWheel::sizePolicy
virtual QSizePolicy sizePolicy() const
reimplemented
Definition: QtWheel.cc:413
ACG::QtWidgets::QtWheel::pixmap_
QPixmap pixmap_
pixmap of the wheel
Definition: QtWheel.hh:287
ACG::QtWidgets::QtWheel::gearDown
void gearDown()
Like gearUp() but the value of gear() halves.
ACG::QtWidgets::QtWheel::shrinkRect
void shrinkRect(QRect &, int, int)
expands a rectangle in x/y direction
Definition: QtWheel.cc:404
ACG::QtWidgets::QtWheel::paintEvent
virtual void paintEvent(QPaintEvent *)
reimplemented
Definition: QtWheel.cc:276
ACG::QtWidgets::QtWheel::gear_
double gear_
speed of revolution
Definition: QtWheel.hh:274
ACG::QtWidgets::QtWheel::mouseReleaseEvent
virtual void mouseReleaseEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:120
ACG::QtWidgets::QtWheel::lastAngle_
double lastAngle_
last angle, depends on tracking_
Definition: QtWheel.hh:271
ACG::QtWidgets::QtWheel::QtWheel
QtWheel(QWidget *_parent=0, const char *_name=0, Orientation _orientation=Horizontal)
Constructor.
Definition: QtWheel.cc:77
ACG::QtWidgets::QtWheel::Orientation
Orientation
Orientation of the widget.
Definition: QtWheel.hh:107
ACG::QtWidgets::QtWheel::gearUp
void gearUp()
ACG::QtWidgets::QtWheel::palette_
QPalette palette_
color group
Definition: QtWheel.hh:286
ACG::QtWidgets::QtWheel::size_
int size_
size of wheel in pixels
Definition: QtWheel.hh:272