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 
107 }
108 
109 //----------------------------------------------------------------------------
110 
111 void QtWheel::mousePressEvent(QMouseEvent* _e)
112 {
113  if (_e->button()==Qt::LeftButton) {
114  pos_=_e->pos();
115  dragging_=true;
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())
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_) {
247  emit angleChangedTo(angle_);
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_);
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 
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 //=============================================================================
virtual QSize sizeHint() const
reimplemented
Definition: QtWheel.cc:425
virtual ~QtWheel()
Destructor.
Definition: QtWheel.cc:106
void hideWheel()
Emitted when the wheel will be hidden by the context menu.
QPalette palette_
color group
Definition: QtWheel.hh:286
QPixmap pixmap_
pixmap of the wheel
Definition: QtWheel.hh:287
int size_
size of wheel in pixels
Definition: QtWheel.hh:272
virtual void paintEvent(QPaintEvent *)
reimplemented
Definition: QtWheel.cc:276
virtual void resizeEvent(QResizeEvent *)
reimplemented
Definition: QtWheel.cc:271
Orientation
Orientation of the widget.
Definition: QtWheel.hh:107
Namespace providing different geometric functions concerning angles.
QPoint pos_
recent mouse position
Definition: QtWheel.hh:282
virtual void mouseMoveEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:133
bool dragging_
currently dragging the slider?
Definition: QtWheel.hh:283
virtual void mouseDoubleClickEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:171
void shrinkRect(QRect &, int, int)
expands a rectangle in x/y direction
Definition: QtWheel.cc:404
double angle_
current angle of the wheel
Definition: QtWheel.hh:270
double lastAngle_
last angle, depends on tracking_
Definition: QtWheel.hh:271
Orientation orientation_
orientation of the widget
Definition: QtWheel.hh:277
void angleChangedBy(double _angle)
virtual QSizePolicy sizePolicy() const
reimplemented
Definition: QtWheel.cc:413
int ticks_
number of ticks on the wheel
Definition: QtWheel.hh:279
virtual void redrawPixmap()
draw wheel to pixmap (double buffering)
Definition: QtWheel.cc:292
static double deg(double _angle)
maps _angle from radiants to degrees (works also for clip()ped angles)
Definition: QtWheel.cc:440
static double clip(double _angle)
Definition: QtWheel.cc:436
void angleChangedTo(double _angle)
QtWheel(QWidget *_parent=0, const char *_name=0, Orientation _orientation=Horizontal)
Constructor.
Definition: QtWheel.cc:77
virtual void keyReleaseEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:252
virtual void mousePressEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:111
virtual void mouseReleaseEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:120
void gearDown()
Like gearUp() but the value of gear() halves.
bool tracking_
tracking on?
Definition: QtWheel.hh:284
virtual void keyPressEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:208
double gear_
speed of revolution
Definition: QtWheel.hh:274
int gearShift_
click-shifted gear by 2^gearShift_
Definition: QtWheel.hh:275