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  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 
52 //=============================================================================
53 //
54 // CLASS QtWheel - IMPLEMENTATION
55 //
56 //=============================================================================
57 
58 //== INCLUDES =================================================================
59 
60 #include "QtWheel.hh"
61 
62 #include <cmath>
63 #include <iostream>
64 
65 //#include <QDrawutil>
66 
67 #include <QPainter>
68 #include <QMenu>
69 #include <QTimer>
70 #include <qdrawutil.h>
71 
72 
73 //== NAMESPACES ===============================================================
74 
75 
76 namespace ACG {
77 namespace QtWidgets {
78 
79 
80 //== IMPLEMENTATION ==========================================================
81 
82 
83 QtWheel::QtWheel(QWidget* _parent,
84  const char* /* _name */ ,
85  Orientation _orientation)
86  : QFrame(_parent)
87 {
88  angle_ = 0.0;
89  lastAngle_ = 0.0;
90  gear_ = 1.0;
91  gearShift_ = 0;
92  // size_ will be set by redrawPixmap()
93 
94  ticks_ = 36;
95  marker_ = false;
96  orientation_ = _orientation;
97  dragging_ = false;
98  tracking_ = true;
99 
100  palette_ = palette();
101  palette_.setColor( QPalette::Dark, QColor(0,0,0));
102 
103  setFrameStyle( QtWheel::Panel | QtWheel::Raised );
104  setLineWidth(2);
105 
106  setContextMenuPolicy ( Qt::CustomContextMenu );
107 
108  connect (this, SIGNAL (customContextMenuRequested ( const QPoint & ) ),
109  this, SLOT( slotCustomContextMenuRequested ( const QPoint & ) ));
110 
111 }
112 
114 }
115 
116 //----------------------------------------------------------------------------
117 
118 void QtWheel::mousePressEvent(QMouseEvent* _e)
119 {
120  if (_e->button()==Qt::LeftButton) {
121  pos_=_e->pos();
122  dragging_=true;
124  }
125 }
126 
127 void QtWheel::mouseReleaseEvent(QMouseEvent* _e)
128 {
129  if (_e->button()==Qt::LeftButton)
130  {
131  dragging_=false;
132 
133 // turn(_e->pos());
134 // emit angleChangedTo(angle_);
135 // emit angleChangedBy(angle_-lastAngle_);
136  }
137 }
138 
139 
140 void QtWheel::mouseMoveEvent(QMouseEvent* _e)
141 {
142  if (_e->buttons()&Qt::LeftButton)
143  {
144  float dAngle=turn(_e->pos());
145 
146  if (tracking_ && dAngle!=0.0) { // 0.0 is explicitly returned
147  lastAngle_=angle_-dAngle;
148 
149  emit angleChangedTo(angle_);
150  emit angleChangedBy(dAngle);
151  }
152  }
153 }
154 
155 
156 double QtWheel::turn(const QPoint& _pos)
157 {
158  QPoint dPos=(_pos-pos_);
159  pos_=_pos;
160 
161  int d = orientation_== Horizontal ? dPos.x() : dPos.y();
162 
163  double dAngle=0.0;
164 
165  if (d!=0) {
166  // full width/height = 180 deg for gear()==1
167  dAngle=double(d)/double(size_)*M_PI*gear_;
168  angle_+=dAngle;
169 
170  redrawPixmap();
171  repaint();
172  }
173  return dAngle;
174 }
175 
176 //----------------------------------------------------------------------------
177 
178 void QtWheel::mouseDoubleClickEvent(QMouseEvent* _e) {
179  if (_e->button()==Qt::LeftButton) {
180  int sz,x;
181  if (orientation_== Horizontal) {
182  sz=width(); x=_e->x();
183  }
184  else {
185  sz=height(); x=_e->y();
186  }
187 
188  if (x<sz/2) {
189  if (gearShift_<8) {
190  ++gearShift_;
191  gear_*=2.0;
192 
193  redrawPixmap();
194  repaint();
195 
196  emit gearUp();
197  }
198  }
199  else {
200  if (gearShift_>-8) {
201  --gearShift_;
202  gear_/=2.0;
203 
204  redrawPixmap();
205  repaint();
206 
207  emit gearDown();
208  }
209  }
210  }
211 }
212 
213 //----------------------------------------------------------------------------
214 
215 void QtWheel::keyPressEvent(QKeyEvent* _e) {
216 
217  //
218  // This does not work! Do we really need/want keyboard input???
219  //
220 
221  if (dragging_)
222  return;
223 
224  double dAngle=0.0;
225 
226  if (!_e->isAutoRepeat())
228 
229  switch (_e->key()) {
230  case Qt::Key_Left:
231  case Qt::Key_Up: {
232  dAngle= -M_PI/double(ticks_)*gear_;
233  }
234  break;
235 
236  case Qt::Key_Right:
237  case Qt::Key_Down: {
238  dAngle= +M_PI/double(ticks_)*gear_;
239  }
240  break;
241 
242  default: return;
243  }
244 
245  if (tracking_)
247 
248  angle_+=dAngle;
249 
250  redrawPixmap();
251  repaint();
252 
253  if (tracking_) {
254  emit angleChangedTo(angle_);
256  }
257 }
258 
259 void QtWheel::keyReleaseEvent(QKeyEvent* _e) {
260  switch (_e->key()) {
261  case Qt::Key_Left:
262  case Qt::Key_Up:
263  case Qt::Key_Right:
264  case Qt::Key_Down: {
265  if (!tracking_) {
266  emit angleChangedTo(angle_);
268  }
269  };
270  break;
271 
272  default: return;
273  }
274 }
275 
276 //----------------------------------------------------------------------------
277 
278 void QtWheel::resizeEvent(QResizeEvent* _e) {
279  QFrame::resizeEvent(_e);
280  redrawPixmap();
281 }
282 
283 void QtWheel::paintEvent(QPaintEvent* _e) {
284  if (isVisible()) {
285  QFrame::paintEvent(_e);
286 
287 
288  QPainter painter(this);
289  QRect r=contentsRect();
290 
292  painter.drawPixmap( r.left(), r.top(), pixmap_ );
293 
294  }
295 }
296 
297 //----------------------------------------------------------------------------
298 
300  QRect r=contentsRect();
301 
302  if (r.width()<=0 || r.height()<=0) {
303  pixmap_ = QPixmap( 0, 0 );
304  return;
305  }
306 
307  if (pixmap_.size()!=r.size())
308  pixmap_ = QPixmap(r.size());
309 
310  QPainter paint;
311 
312  paint.begin( &pixmap_);
313  pixmap_.fill( palette().background().color() );
314 
315  // coords of wheel frame
316  QRect contents = contentsRect();
317  contents.moveTopLeft(QPoint(0,0)); // transform to pixmap coord sys
318 
319  QPen pen(Qt::black, 1);
320  paint.setPen(pen);
321 
322  if (orientation_ == Horizontal) {
323 
324  shrinkRect(contents, 3, 2);
325 
326  // draw a black frame
327  paint.drawRect(contents);
328  shrinkRect(contents, 1, 0);
329  paint.drawRect(contents);
330  shrinkRect(contents, 3, 2);
331 
332  int x0 = contents.left();
333  int y0 = contents.top();
334  int w0 = contents.width();
335  int h0 = contents.height();
336 
337  size_=w0;
338 
339  if (gearShift_>0) {
340  QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
341  int w=std::min(4*gearShift_,w0-8);
342  paint.fillRect(x0+8,y0-1,w,h0+2,b);
343  }
344  else if (gearShift_<0) {
345  QBrush b; b.setColor(QColor(Qt::blue));
346  int w=std::min(-4*gearShift_,w0-8); b.setStyle(Qt::SolidPattern);
347  paint.fillRect(x0+w0-w-8,y0-1,w,h0+2,b);
348  }
349 
350  // draw the wheel
351  double step = 2 * M_PI / (double) ticks_;
352  for (int i = 0; i < ticks_; i++) {
353  double x = sin(angle_ + i * step);
354  double y = cos(angle_ + i * step);
355  if (y>0) {
356  qDrawShadeLine( &paint,
357  (int) (x0+(w0+x*w0)/2.0f), y0,
358  (int) (x0+(w0+x*w0)/2.0f), y0+h0,
359  palette_, false, 1, 1);
360  }
361  }
362  }
363 
364  else if (orientation_ == Vertical) {
365 
366  shrinkRect(contents, 2, 3);
367 
368  // draw a black frame
369  paint.drawRect(contents);
370  shrinkRect(contents, 0, 1);
371  paint.drawRect(contents);
372  shrinkRect(contents, 2, 3);
373 
374 
375  int x0 = contents.left();
376  int y0 = contents.top();
377  int w0 = contents.width();
378  int h0 = contents.height();
379 
380  size_=h0;
381 
382  if (gearShift_>0) {
383  QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
384  int h=-std::min(-4*gearShift_,h0-8);
385  paint.fillRect(x0-1,y0+8,w0+2,h,b);
386  }
387  else if (gearShift_<0) {
388  QBrush b; b.setColor(QColor(Qt::blue)); b.setStyle(Qt::SolidPattern);
389  int h=-std::min(4*gearShift_,h0-8);
390  paint.fillRect(x0-1,y0+h0-h-8,w0+2,h,b);
391  }
392 
393  // draw the wheel
394  double step = 2 * M_PI / (double) ticks_;
395  for (int i = 0; i < ticks_; i++) {
396  double x = sin(angle_ + i * step);
397  double y = cos(angle_ + i * step);
398  if (y>0) {
399  qDrawShadeLine( &paint,
400  x0, (int) (y0+(h0+x*h0)/2.0f),
401  x0+w0, (int) (y0+(h0+x*h0)/2.0f),
402  palette_, false, 1, 1);
403  } // if y
404  } // for ticks_
405  } // if Vertical
406  paint.end();
407 }
408 
409 //-----------------------------------------------------------------------------
410 
411 void QtWheel::shrinkRect(QRect& _rect, int _dx, int _dy) {
412  _rect.setLeft(_rect.left()+_dx);
413  _rect.setRight(_rect.right()-_dx);
414  _rect.setTop(_rect.top()+_dy); // dy -> -dy
415  _rect.setBottom(_rect.bottom()-_dy);
416 }
417 
418 //-----------------------------------------------------------------------------
419 
420 QSizePolicy QtWheel::sizePolicy() const
421 {
422  if (orientation_== Horizontal)
423  return QSizePolicy(QSizePolicy::Preferred,
424  QSizePolicy::Minimum);
425  else
426  return QSizePolicy(QSizePolicy::Minimum,
427  QSizePolicy::Preferred);
428 }
429 
430 //-----------------------------------------------------------------------------
431 
432 QSize QtWheel::sizeHint() const
433 {
434  if (orientation_==Horizontal)
435  return QSize(120,20);
436  else
437  return QSize(20,120);
438 }
439 
440 //-----------------------------------------------------------------------------
441 
442 
443 double QtWheel::clip(double _angle) {
444  return fmod(_angle,2*M_PI);
445 }
446 
447 double QtWheel::deg(double _angle) {
448  return _angle*180.0/M_PI;
449 }
450 
451 //-----------------------------------------------------------------------------
452 
453 void QtWheel::slotCustomContextMenuRequested ( const QPoint & pos ) {
454 
455  QMenu* menu = new QMenu(this);
456  QAction *hide = menu->addAction("Hide wheel");
457  connect( hide, SIGNAL(triggered()) , this, SIGNAL(hideWheel()) );
458  menu->popup( mapToGlobal(pos) );
459 
460 }
461 
462 
463 //=============================================================================
464 } // namespace QtWidgets
465 } // namespace ACG
466 //=============================================================================
virtual void keyReleaseEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:259
virtual void keyPressEvent(QKeyEvent *)
reimplemented
Definition: QtWheel.cc:215
bool tracking_
tracking on?
Definition: QtWheel.hh:290
double angle_
current angle of the wheel
Definition: QtWheel.hh:276
QPixmap pixmap_
pixmap of the wheel
Definition: QtWheel.hh:293
QPoint pos_
recent mouse position
Definition: QtWheel.hh:288
void shrinkRect(QRect &, int, int)
expands a rectangle in x/y direction
Definition: QtWheel.cc:411
virtual void redrawPixmap()
draw wheel to pixmap (double buffering)
Definition: QtWheel.cc:299
QtWheel(QWidget *_parent=0, const char *_name=0, Orientation _orientation=Horizontal)
Constructor.
Definition: QtWheel.cc:83
virtual QSizePolicy sizePolicy() const
reimplemented
Definition: QtWheel.cc:420
double gear_
speed of revolution
Definition: QtWheel.hh:280
bool dragging_
currently dragging the slider?
Definition: QtWheel.hh:289
void gearDown()
Like gearUp() but the value of gear() halves.
bool marker_
should ticks be marked by colors?
Definition: QtWheel.hh:286
virtual void resizeEvent(QResizeEvent *)
reimplemented
Definition: QtWheel.cc:278
static double deg(double _angle)
maps _angle from radiants to degrees (works also for clip()ped angles)
Definition: QtWheel.cc:447
double lastAngle_
last angle, depends on tracking_
Definition: QtWheel.hh:277
virtual void mouseMoveEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:140
virtual void mouseReleaseEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:127
void angleChangedBy(double _angle)
int size_
size of wheel in pixels
Definition: QtWheel.hh:278
virtual void paintEvent(QPaintEvent *)
reimplemented
Definition: QtWheel.cc:283
static double clip(double _angle)
Definition: QtWheel.cc:443
void angleChangedTo(double _angle)
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
int ticks_
number of ticks on the wheel
Definition: QtWheel.hh:285
virtual ~QtWheel()
Destructor.
Definition: QtWheel.cc:113
QPalette palette_
color group
Definition: QtWheel.hh:292
Orientation orientation_
orientation of the widget
Definition: QtWheel.hh:283
virtual void mousePressEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:118
virtual void mouseDoubleClickEvent(QMouseEvent *)
reimplemented
Definition: QtWheel.cc:178
virtual QSize sizeHint() const
reimplemented
Definition: QtWheel.cc:432
Orientation
Orientation of the widget.
Definition: QtWheel.hh:113
int gearShift_
click-shifted gear by 2^gearShift_
Definition: QtWheel.hh:281
void hideWheel()
Emitted when the wheel will be hidden by the context menu.