QtWheel.cc 12.3 KB
Newer Older
Jan Möbius's avatar
Jan Möbius committed
1 2 3
/*===========================================================================*\
 *                                                                           *
 *                              OpenFlipper                                  *
Jan Möbius's avatar
Jan Möbius committed
4
 *      Copyright (C) 2001-2011 by Computer Graphics Group, RWTH Aachen      *
Jan Möbius's avatar
Jan Möbius committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *                           www.openflipper.org                             *
 *                                                                           *
 *---------------------------------------------------------------------------*
 *  This file is part of OpenFlipper.                                        *
 *                                                                           *
 *  OpenFlipper is free software: you can redistribute it and/or modify      *
 *  it under the terms of the GNU Lesser General Public License as           *
 *  published by the Free Software Foundation, either version 3 of           *
 *  the License, or (at your option) any later version with the              *
 *  following exceptions:                                                    *
 *                                                                           *
 *  If other files instantiate templates or use macros                       *
 *  or inline functions from this file, or you compile this file and         *
 *  link it with other files to produce an executable, this file does        *
 *  not by itself cause the resulting executable to be covered by the        *
 *  GNU Lesser General Public License. This exception does not however       *
 *  invalidate any other reasons why the executable file might be            *
 *  covered by the GNU Lesser General Public License.                        *
 *                                                                           *
 *  OpenFlipper is distributed in the hope that it will be useful,           *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
 *  GNU Lesser General Public License for more details.                      *
 *                                                                           *
 *  You should have received a copy of the GNU LesserGeneral Public          *
 *  License along with OpenFlipper. If not,                                  *
 *  see <http://www.gnu.org/licenses/>.                                      *
 *                                                                           *
\*===========================================================================*/
34

Jan Möbius's avatar
Jan Möbius committed
35 36
/*===========================================================================*\
 *                                                                           *
Jan Möbius's avatar
Jan Möbius committed
37
 *   $Revision$                                                       *
Jan Möbius's avatar
Jan Möbius committed
38 39 40 41
 *   $Author$                                                      *
 *   $Date$                   *
 *                                                                           *
\*===========================================================================*/
42 43 44 45 46 47 48 49 50 51 52 53 54



//=============================================================================
//
//  CLASS QtWheel - IMPLEMENTATION
//
//=============================================================================

//== INCLUDES =================================================================

#include "QtWheel.hh"

55 56
#include <cmath>
#include <cfloat>
57 58 59 60 61 62 63
#include <iostream>
#include <algorithm>

//#include <QDrawutil>

#include <QEvent>
#include <QPainter>
Jan Möbius's avatar
Jan Möbius committed
64
#include <QMenu>
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
#include <QPixmap>
#include <QTimer>
#include <QCursor>
#include <QBrush>
#include <QPaintEvent>
#include <QKeyEvent>
#include <QResizeEvent>
#include <QMouseEvent>


//== NAMESPACES ===============================================================


namespace ACG {
namespace QtWidgets {


Jan Möbius's avatar
Jan Möbius committed
82 83
//== IMPLEMENTATION ==========================================================

84 85 86 87

QtWheel::QtWheel(QWidget* _parent,
	       const char* /* _name */ ,
	       Orientation _orientation)
Jan Möbius's avatar
Jan Möbius committed
88
  : QFrame(_parent)
89 90 91 92 93 94
{
  angle_       = 0.0;
  lastAngle_   = 0.0;
  gear_        = 1.0;
  gearShift_   = 0;
  // size_ will be set by redrawPixmap()
Jan Möbius's avatar
Jan Möbius committed
95

96 97 98 99 100
  ticks_       = 36;
  marker_      = false;
  orientation_ = _orientation;
  dragging_    = false;
  tracking_    = true;
Jan Möbius's avatar
Jan Möbius committed
101

102 103 104 105 106
  palette_     = palette();
  palette_.setColor( QPalette::Dark,  QColor(0,0,0));

  setFrameStyle( QtWheel::Panel | QtWheel::Raised );
  setLineWidth(2);
Jan Möbius's avatar
Jan Möbius committed
107 108 109 110 111 112

  setContextMenuPolicy ( Qt::CustomContextMenu );

  connect (this, SIGNAL (customContextMenuRequested ( const QPoint & ) ),
           this, SLOT( slotCustomContextMenuRequested ( const QPoint & ) ));

113 114 115 116 117 118 119
}

QtWheel::~QtWheel() {
}

//----------------------------------------------------------------------------

Jan Möbius's avatar
Jan Möbius committed
120 121
void QtWheel::mousePressEvent(QMouseEvent* _e)
{
122 123 124 125 126 127 128
  if (_e->button()==Qt::LeftButton) {
    pos_=_e->pos();
    dragging_=true;
    lastAngle_=angle_;
  }
}

Jan Möbius's avatar
Jan Möbius committed
129 130 131 132
void QtWheel::mouseReleaseEvent(QMouseEvent* _e)
{
  if (_e->button()==Qt::LeftButton)
  {
133 134
    dragging_=false;

Jan Möbius's avatar
Jan Möbius committed
135
//     turn(_e->pos());
136
//     emit angleChangedTo(angle_);
Jan Möbius's avatar
Jan Möbius committed
137
//     emit angleChangedBy(angle_-lastAngle_);
138 139 140 141
  }
}


Jan Möbius's avatar
Jan Möbius committed
142
void QtWheel::mouseMoveEvent(QMouseEvent* _e)
143
{
Jan Möbius's avatar
Jan Möbius committed
144
  if (_e->buttons()&Qt::LeftButton)
145 146 147 148 149 150
  {
    float dAngle=turn(_e->pos());

    if (tracking_ && dAngle!=0.0) { // 0.0 is explicitly returned
      lastAngle_=angle_-dAngle;

Jan Möbius's avatar
Jan Möbius committed
151
      emit angleChangedTo(angle_);
152 153 154 155 156 157
      emit angleChangedBy(dAngle);
    }
  }
}


Jan Möbius's avatar
Jan Möbius committed
158
double QtWheel::turn(const QPoint& _pos)
159 160 161 162 163 164 165
{
  QPoint dPos=(_pos-pos_);
  pos_=_pos;

  int d = orientation_== Horizontal ? dPos.x() : dPos.y();

  double dAngle=0.0;
Jan Möbius's avatar
Jan Möbius committed
166 167

  if (d!=0) {
168
    // full width/height = 180 deg for gear()==1
Jan Möbius's avatar
Jan Möbius committed
169 170
    dAngle=double(d)/double(size_)*M_PI*gear_;
    angle_+=dAngle;
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

    redrawPixmap();
    repaint();
  }
  return dAngle;
}

//----------------------------------------------------------------------------

void QtWheel::mouseDoubleClickEvent(QMouseEvent* _e) {
  if (_e->button()==Qt::LeftButton) {
    int sz,x;
    if (orientation_== Horizontal) {
      sz=width();  x=_e->x();
    }
    else {
      sz=height(); x=_e->y();
    }

    if (x<sz/2) {
      if (gearShift_<8) {
Jan Möbius's avatar
Jan Möbius committed
192 193 194 195 196 197 198
        ++gearShift_;
        gear_*=2.0;

        redrawPixmap();
        repaint();

        emit gearUp();
199 200 201 202
      }
    }
    else {
      if (gearShift_>-8) {
Jan Möbius's avatar
Jan Möbius committed
203 204
        --gearShift_;
        gear_/=2.0;
205

Jan Möbius's avatar
Jan Möbius committed
206 207 208 209
        redrawPixmap();
        repaint();

        emit gearDown();
210 211 212 213 214 215 216
      }
    }
  }
}

//----------------------------------------------------------------------------

Jan Möbius's avatar
Jan Möbius committed
217
void QtWheel::keyPressEvent(QKeyEvent* _e) {
218 219 220 221

  //
  // This does not work! Do we really need/want keyboard input???
  //
Jan Möbius's avatar
Jan Möbius committed
222

223
  if (dragging_)
Jan Möbius's avatar
Jan Möbius committed
224
    return;
225

Jan Möbius's avatar
Jan Möbius committed
226
  double dAngle=0.0;
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255

  if (!_e->isAutoRepeat())
    lastAngle_=angle_;

  switch (_e->key()) {
    case Qt::Key_Left:
    case Qt::Key_Up: {
      dAngle= -M_PI/double(ticks_)*gear_;
    }
    break;

    case Qt::Key_Right:
    case Qt::Key_Down: {
      dAngle= +M_PI/double(ticks_)*gear_;
    }
    break;

    default: return;
  }

  if (tracking_)
    lastAngle_=angle_;

  angle_+=dAngle;

  redrawPixmap();
  repaint();

  if (tracking_) {
Jan Möbius's avatar
Jan Möbius committed
256
    emit angleChangedTo(angle_);
257 258 259 260
    emit angleChangedBy(angle_-lastAngle_);
  }
}

Jan Möbius's avatar
Jan Möbius committed
261
void QtWheel::keyReleaseEvent(QKeyEvent* _e) {
262 263
  switch (_e->key()) {
    case Qt::Key_Left:
Jan Möbius's avatar
Jan Möbius committed
264
    case Qt::Key_Up:
265 266 267
    case Qt::Key_Right:
    case Qt::Key_Down: {
      if (!tracking_) {
Jan Möbius's avatar
Jan Möbius committed
268 269
        emit angleChangedTo(angle_);
        emit angleChangedBy(angle_-lastAngle_);
270 271 272 273 274 275 276 277 278 279 280 281
      }
    };
    break;

    default: return;
  }
}

//----------------------------------------------------------------------------

void QtWheel::resizeEvent(QResizeEvent* _e) {
  QFrame::resizeEvent(_e);
Jan Möbius's avatar
Jan Möbius committed
282
  redrawPixmap();
283 284
}

Jan Möbius's avatar
Jan Möbius committed
285
void QtWheel::paintEvent(QPaintEvent* _e) {
286 287 288 289 290 291 292
  if (isVisible()) {
    QFrame::paintEvent(_e);


    QPainter painter(this);
    QRect r=contentsRect();

Jan Möbius's avatar
Jan Möbius committed
293
    /// @todo: bitBlt(this,r.left(),r.top(),pixmap_);
294 295 296 297 298 299 300
    painter.drawPixmap( r.left(), r.top(), pixmap_ );

  }
}

//----------------------------------------------------------------------------

Jan Möbius's avatar
Jan Möbius committed
301
void QtWheel::redrawPixmap() {
302
 QRect r=contentsRect();
Jan Möbius's avatar
Jan Möbius committed
303

304 305 306 307
 if (r.width()<=0 || r.height()<=0) {
   pixmap_ = QPixmap( 0, 0 );
   return;
 }
Jan Möbius's avatar
Jan Möbius committed
308

309 310 311 312
 if (pixmap_.size()!=r.size())
   pixmap_ = QPixmap(r.size());

  QPainter paint;
Jan Möbius's avatar
Jan Möbius committed
313

314 315 316 317 318 319
  paint.begin( &pixmap_);
  pixmap_.fill( palette().background().color() );

  // coords of wheel frame
  QRect contents = contentsRect();
  contents.moveTopLeft(QPoint(0,0)); // transform to pixmap coord sys
Jan Möbius's avatar
Jan Möbius committed
320

321 322
  QPen pen(Qt::black, 1);
  paint.setPen(pen);
Jan Möbius's avatar
Jan Möbius committed
323

324
  if (orientation_ == Horizontal) {
Jan Möbius's avatar
Jan Möbius committed
325

326
    shrinkRect(contents, 3, 2);
Jan Möbius's avatar
Jan Möbius committed
327 328

    // draw a black frame
329 330
    paint.drawRect(contents);
    shrinkRect(contents, 1, 0);
Jan Möbius's avatar
Jan Möbius committed
331
    paint.drawRect(contents);
332
    shrinkRect(contents, 3, 2);
Jan Möbius's avatar
Jan Möbius committed
333 334 335

    int x0 = contents.left();
    int y0 = contents.top();
336 337 338 339
    int w0 = contents.width();
    int h0 = contents.height();

    size_=w0;
Jan Möbius's avatar
Jan Möbius committed
340

341 342 343 344 345 346 347 348 349 350
    if (gearShift_>0) {
      QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
      int w=std::min(4*gearShift_,w0-8);
      paint.fillRect(x0+8,y0-1,w,h0+2,b);
    }
    else if (gearShift_<0) {
      QBrush b; b.setColor(QColor(Qt::blue));
      int w=std::min(-4*gearShift_,w0-8); b.setStyle(Qt::SolidPattern);
      paint.fillRect(x0+w0-w-8,y0-1,w,h0+2,b);
    }
Jan Möbius's avatar
Jan Möbius committed
351 352

    // draw the wheel
353 354 355 356 357
    double step = 2 * M_PI / (double) ticks_;
    for (int i = 0; i < ticks_; i++) {
      double x = sin(angle_ + i * step);
      double y = cos(angle_ + i * step);
      if (y>0) {
Jan Möbius's avatar
Jan Möbius committed
358 359 360 361
        qDrawShadeLine( &paint,
                        (int) (x0+(w0+x*w0)/2.0f), y0,
                        (int) (x0+(w0+x*w0)/2.0f), y0+h0,
                        palette_, false, 1, 1);
362 363 364 365 366
      }
    }
  }

  else if (orientation_ == Vertical) {
Jan Möbius's avatar
Jan Möbius committed
367

368
    shrinkRect(contents, 2, 3);
Jan Möbius's avatar
Jan Möbius committed
369 370

    // draw a black frame
371 372
    paint.drawRect(contents);
    shrinkRect(contents, 0, 1);
Jan Möbius's avatar
Jan Möbius committed
373
    paint.drawRect(contents);
374
    shrinkRect(contents, 2, 3);
Jan Möbius's avatar
Jan Möbius committed
375 376


377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
    int x0 = contents.left();
    int y0 = contents.top();
    int w0 = contents.width();
    int h0 = contents.height();

    size_=h0;

    if (gearShift_>0) {
      QBrush b; b.setColor(QColor(Qt::red)); b.setStyle(Qt::SolidPattern);
      int h=-std::min(-4*gearShift_,h0-8);
      paint.fillRect(x0-1,y0+8,w0+2,h,b);
    }
    else if (gearShift_<0) {
      QBrush b; b.setColor(QColor(Qt::blue)); b.setStyle(Qt::SolidPattern);
      int h=-std::min(4*gearShift_,h0-8);
      paint.fillRect(x0-1,y0+h0-h-8,w0+2,h,b);
    }
Jan Möbius's avatar
Jan Möbius committed
394 395

    // draw the wheel
396 397 398 399 400
    double step = 2 * M_PI / (double) ticks_;
    for (int i = 0; i < ticks_; i++) {
      double x = sin(angle_ + i * step);
      double y = cos(angle_ + i * step);
      if (y>0) {
Jan Möbius's avatar
Jan Möbius committed
401 402 403 404
	     qDrawShadeLine( &paint,
                        x0,    (int) (y0+(h0+x*h0)/2.0f),
                        x0+w0, (int) (y0+(h0+x*h0)/2.0f),
                        palette_, false, 1, 1);
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
      } // if y
    } // for ticks_
  } // if Vertical
  paint.end();
}

//-----------------------------------------------------------------------------

void QtWheel::shrinkRect(QRect& _rect, int _dx, int _dy) {
  _rect.setLeft(_rect.left()+_dx);
  _rect.setRight(_rect.right()-_dx);
  _rect.setTop(_rect.top()+_dy); // dy -> -dy
  _rect.setBottom(_rect.bottom()-_dy);
}

//-----------------------------------------------------------------------------

Jan Möbius's avatar
Jan Möbius committed
422
QSizePolicy QtWheel::sizePolicy() const
423
{
Jan Möbius's avatar
Jan Möbius committed
424
  if (orientation_== Horizontal)
425 426
    return QSizePolicy(QSizePolicy::Preferred,
		       QSizePolicy::Minimum);
Jan Möbius's avatar
Jan Möbius committed
427
  else
428 429 430 431 432 433
    return QSizePolicy(QSizePolicy::Minimum,
		       QSizePolicy::Preferred);
}

//-----------------------------------------------------------------------------

Jan Möbius's avatar
Jan Möbius committed
434
QSize QtWheel::sizeHint() const
435 436 437
{
  if (orientation_==Horizontal)
    return QSize(120,20);
Jan Möbius's avatar
Jan Möbius committed
438
  else
439 440
    return QSize(20,120);
}
Jan Möbius's avatar
Jan Möbius committed
441

442 443 444 445 446 447 448 449 450 451 452
//-----------------------------------------------------------------------------


double QtWheel::clip(double _angle) {
  return fmod(_angle,2*M_PI);
}

double QtWheel::deg(double _angle) {
  return _angle*180.0/M_PI;
}

Jan Möbius's avatar
Jan Möbius committed
453 454 455 456 457 458 459 460 461 462 463
//-----------------------------------------------------------------------------

void QtWheel::slotCustomContextMenuRequested ( const QPoint & pos ) {

  QMenu* menu = new QMenu(this);
  QAction *hide = menu->addAction("Hide wheel");
  connect( hide, SIGNAL(triggered()) , this, SIGNAL(hideWheel()) );
  menu->popup( mapToGlobal(pos) );

}

464 465 466 467 468

//=============================================================================
} // namespace QtWidgets
} // namespace ACG
//=============================================================================