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
70namespace ACG {
71namespace QtWidgets {
72
73
74//== IMPLEMENTATION ==========================================================
75
76
77QtWheel::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 palette_(palette())
91{
92
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(QPoint) ),
101 this, SLOT( slotCustomContextMenuRequested(QPoint) ));
102
103}
104
105
107}
108
109//----------------------------------------------------------------------------
110
111void QtWheel::mousePressEvent(QMouseEvent* _e)
112{
113 if (_e->button()==Qt::LeftButton) {
114 pos_=_e->pos();
115 dragging_=true;
117 }
118}
119
120void QtWheel::mouseReleaseEvent(QMouseEvent* _e)
121{
122 if (_e->button()==Qt::LeftButton)
123 {
124 dragging_=false;
125
126 turn(_e->pos());
129 }
130}
131
132
133void 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
143 emit angleChangedBy(dAngle);
144 }
145 }
146}
147
148
149double 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
171void QtWheel::mouseDoubleClickEvent(QMouseEvent* _e) {
172 if (_e->button()==Qt::LeftButton) {
173 int sz,x;
174 if (orientation_== Horizontal) {
175 sz=width(); x=_e->pos().x();
176 }
177 else {
178 sz=height(); x=_e->pos().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
208void 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())
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_)
240
241 angle_+=dAngle;
242
243 redrawPixmap();
244 repaint();
245
246 if (tracking_) {
249 }
250}
251
252void 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_) {
261 }
262 };
263 break;
264
265 default: return;
266 }
267}
268
269//----------------------------------------------------------------------------
270
271void QtWheel::resizeEvent(QResizeEvent* _e) {
272 QFrame::resizeEvent(_e);
273 redrawPixmap();
274}
275
276void 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
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().window().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
404void 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
413QSizePolicy 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
425QSize 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
436double QtWheel::clip(double _angle) {
437 return fmod(_angle,2*M_PI);
438}
439
440double QtWheel::deg(double _angle) {
441 return _angle*180.0/M_PI;
442}
443
444//-----------------------------------------------------------------------------
445
446void 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//=============================================================================
void shrinkRect(QRect &, int, int)
expands a rectangle in x/y direction
Definition: QtWheel.cc:404
void gearDown()
Like gearUp() but the value of gear() halves.
int ticks_
number of ticks on the wheel
Definition: QtWheel.hh:279
virtual void mouseDoubleClickEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:171
double angle_
current angle of the wheel
Definition: QtWheel.hh:270
virtual void paintEvent(QPaintEvent *)
reimplemented
Definition: QtWheel.cc:276
static double clip(double _angle)
Definition: QtWheel.cc:436
bool dragging_
currently dragging the slider?
Definition: QtWheel.hh:283
virtual QSize sizeHint() const
reimplemented
Definition: QtWheel.cc:425
int gearShift_
click-shifted gear by 2^gearShift_
Definition: QtWheel.hh:275
void angleChangedTo(double _angle)
int size_
size of wheel in pixels
Definition: QtWheel.hh:272
virtual void resizeEvent(QResizeEvent *)
reimplemented
Definition: QtWheel.cc:271
virtual QSizePolicy sizePolicy() const
reimplemented
Definition: QtWheel.cc:413
QtWheel(QWidget *_parent=0, const char *_name=0, Orientation _orientation=Horizontal)
Constructor.
Definition: QtWheel.cc:77
QPalette palette_
color group
Definition: QtWheel.hh:286
virtual void mouseReleaseEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:120
virtual void redrawPixmap()
draw wheel to pixmap (double buffering)
Definition: QtWheel.cc:292
void angleChangedBy(double _angle)
QPixmap pixmap_
pixmap of the wheel
Definition: QtWheel.hh:287
static double deg(double _angle)
maps _angle from radiants to degrees (works also for clip()ped angles)
Definition: QtWheel.cc:440
virtual ~QtWheel()
Destructor.
Definition: QtWheel.cc:106
void hideWheel()
Emitted when the wheel will be hidden by the context menu.
Orientation
Orientation of the widget.
Definition: QtWheel.hh:107
double lastAngle_
last angle, depends on tracking_
Definition: QtWheel.hh:271
double gear_
speed of revolution
Definition: QtWheel.hh:274
virtual void mouseMoveEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:133
Orientation orientation_
orientation of the widget
Definition: QtWheel.hh:277
bool tracking_
tracking on?
Definition: QtWheel.hh:284
virtual void keyPressEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:208
virtual void mousePressEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:111
QPoint pos_
recent mouse position
Definition: QtWheel.hh:282
virtual void keyReleaseEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:252
Namespace providing different geometric functions concerning angles.