~ubuntu-branches/ubuntu/hoary/kdemultimedia/hoary

« back to all changes in this revision

Viewing changes to arts/gui/kde/kpoti.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Martin Schulze
  • Date: 2003-01-22 15:00:51 UTC
  • Revision ID: james.westby@ubuntu.com-20030122150051-uihwkdoxf15mi1tn
Tags: upstream-2.2.2
ImportĀ upstreamĀ versionĀ 2.2.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                          kpoti.cpp  -  potentiometer widget
 
3
                             -------------------
 
4
    begin                : Wed Apr 28 23:05:05 MEST 1999
 
5
 
 
6
    copyright            : (C) 1999 by Martin Lorenz
 
7
    email                : lorenz@ch.tum.de
 
8
 ***************************************************************************/
 
9
 
 
10
/***************************************************************************
 
11
 *                                                                         *
 
12
 *   This program is free software; you can redistribute it and/or modify  *
 
13
 *   it under the terms of the GNU General Public License as published by  *
 
14
 *   the Free Software Foundation; either version 2 of the License, or     *
 
15
 *   (at your option) any later version.                                   *
 
16
 *                                                                         *
 
17
 ***************************************************************************/
 
18
 
 
19
#include "kpoti.h"
 
20
#include "kpoti.moc"
 
21
#include <kdebug.h>
 
22
#include <qpainter.h>
 
23
#include <qcolor.h>
 
24
#include <qdrawutl.h>
 
25
#include <qtimer.h>
 
26
#include <qkeycode.h>
 
27
#include <math.h>
 
28
#include <iostream.h>
 
29
#include <qpen.h>
 
30
 
 
31
#define PI 3.1415926
 
32
static const int motifBorder = 2;
 
33
static const int motifLength = 30;
 
34
static const int winLength = 9; // Must be odd
 
35
static const int thresholdTime = 500;
 
36
static const int repeatTime    = 100;
 
37
static const float maxAngle = PI*135/180; // 140 degrees to both sides
 
38
static const float tickLength = 0.25;
 
39
static const int fontSize=8;
 
40
 
 
41
/**
 
42
  Constructs a poti.
 
43
 
 
44
  The \e parent and \e name arguments are sent to the QWidget constructor.
 
45
*/
 
46
KPoti::KPoti( QWidget *parent, const char *name )
 
47
    : QWidget( parent, name )
 
48
{
 
49
    init();
 
50
}
 
51
 
 
52
 
 
53
 
 
54
/**
 
55
  Constructs a poti.
 
56
 
 
57
  \arg \e minValue is the minimum slider value.
 
58
  \arg \e maxValue is the maximum slider value.
 
59
  \arg \e step is the page step value.
 
60
  \arg \e value is the initial value.
 
61
 
 
62
  The \e parent and \e name arguments are sent to the QWidget constructor.
 
63
*/
 
64
 
 
65
KPoti::KPoti( int minValue, int maxValue, int step,
 
66
                  int value, QWidget *parent, const char *name )
 
67
    : QWidget( parent, name ),
 
68
      QRangeControl( minValue, maxValue, 1, step, value )
 
69
{
 
70
    init(value);
 
71
}
 
72
 
 
73
 
 
74
void KPoti::init(int value)
 
75
{
 
76
  color.setNamedColor("red");
 
77
  timer = 0;
 
78
  potiVal = value;
 
79
  potiPos = positionFromValue(value);
 
80
  clickOffset = 0;
 
81
  state = Idle;
 
82
  track = TRUE;
 
83
  ticks = TRUE;
 
84
  label=TRUE;
 
85
  tickInt = 0;
 
86
  fontHeight=fontMetrics().height();
 
87
  
 
88
  space = QMIN( height(), width() );
 
89
  center.setX(space/2); center.setY(space/2); 
 
90
  setBackgroundMode( PaletteMid );
 
91
  
 
92
  setFocusPolicy( TabFocus );
 
93
  initTicks();
 
94
}
 
95
 
 
96
 
 
97
/**
 
98
  Does what's needed when someone changes the tickmark status
 
99
*/
 
100
 
 
101
void KPoti::initTicks()
 
102
 
103
 
 
104
  space = QMIN( height(), width() );
 
105
  center.setX(width()/2); 
 
106
  if (label==TRUE) {
 
107
    space -= fontSize -2;
 
108
  }
 
109
  if ( ticks == TRUE ) 
 
110
  {
 
111
    double spaced = space;
 
112
        spaced /= 1.0+tickLength/2;
 
113
 
 
114
    space=(int)spaced;
 
115
  }
 
116
  
 
117
  buttonRadius = (space-1)/2 ; center.setY(height()-buttonRadius-1);
 
118
 
 
119
}
 
120
 
 
121
 
 
122
/**
 
123
  Enables slider tracking if \e enable is TRUE, or disables tracking
 
124
  if \e enable is FALSE.
 
125
 
 
126
  If tracking is enabled (default), the slider emits the
 
127
  valueChanged() signal whenever the slider is being dragged.  If
 
128
  tracking is disabled, the slider emits the valueChanged() signal
 
129
  when the user releases the mouse button (unless the value happens to
 
130
  be the same as before).
 
131
 
 
132
  \sa tracking()
 
133
*/
 
134
 
 
135
void KPoti::setTracking( bool enable )
 
136
{
 
137
    track = enable;
 
138
}
 
139
 
 
140
 
 
141
/**
 
142
  \fn bool KPoti::tracking() const
 
143
  Returns TRUE if tracking is enabled, or FALSE if tracking is disabled.
 
144
 
 
145
  Tracking is initially enabled.
 
146
 
 
147
  \sa setTracking()
 
148
*/
 
149
 
 
150
 
 
151
/**
 
152
  \fn void KPoti::valueChanged( int value )
 
153
  This signal is emitted when the slider value is changed, with the
 
154
  new slider value as an argument.
 
155
*/
 
156
 
 
157
/**
 
158
  \fn void KPoti::sliderPressed()
 
159
  This signal is emitted when the user presses the slider with the mouse.
 
160
*/
 
161
 
 
162
/**
 
163
  \fn void KPoti::sliderMoved( int value )
 
164
  This signal is emitted when the slider is dragged, with the
 
165
  new slider value as an argument.
 
166
*/
 
167
 
 
168
/**
 
169
  \fn void KPoti::sliderReleased()
 
170
  This signal is emitted when the user releases the slider with the mouse.
 
171
*/
 
172
 
 
173
/**
 
174
  Calculates slider position corresponding to value \a v. Does not perform
 
175
  rounding.
 
176
*/
 
177
 
 
178
float KPoti::positionFromValue( int v ) const
 
179
{
 
180
 
 
181
    int range = maxValue() - minValue();
 
182
    return ( (v - minValue() ) *2* maxAngle) / range - maxAngle;
 
183
}
 
184
 
 
185
 
 
186
/**
 
187
  Calculates value corresponding to poti position \a p. Performs rounding.
 
188
*/
 
189
 
 
190
int KPoti::valueFromPosition( float p ) const
 
191
{
 
192
    int range = maxValue() - minValue();
 
193
    return (int) (minValue() + ((p+maxAngle)*range)/(2*maxAngle));
 
194
}
 
195
 
 
196
/*!
 
197
  Implements the virtual QRangeControl function.
 
198
*/
 
199
 
 
200
void KPoti::rangeChange()
 
201
{
 
202
    float newPos = positionFromValue( value() );
 
203
    if ( newPos != potiPos ) {
 
204
        reallyMovePoti( newPos ); 
 
205
    }
 
206
}
 
207
 
 
208
/*!
 
209
  Changes the value (slot)
 
210
*/
 
211
 
 
212
void KPoti::valueChange()
 
213
{
 
214
    if ( potiVal != value() ) {
 
215
        float newPos = positionFromValue( value() );
 
216
        potiVal = value();
 
217
        reallyMovePoti( newPos );
 
218
    }
 
219
    emit valueChanged(value());
 
220
}
 
221
 
 
222
 
 
223
/*!
 
224
  Handles resize events for the poti.
 
225
*/
 
226
 
 
227
void KPoti::resizeEvent( QResizeEvent * )
 
228
{
 
229
    rangeChange();
 
230
    initTicks();
 
231
}
 
232
 
 
233
 
 
234
/*!
 
235
  Reimplements the virtual function QWidget::setPalette().
 
236
 
 
237
*/
 
238
 
 
239
void KPoti::setPalette( const QPalette &p )
 
240
{
 
241
  
 
242
    setBackgroundMode( PaletteMid );
 
243
    QWidget::setPalette( p );
 
244
}
 
245
 
 
246
 
 
247
void KPoti::setLabel(bool s)
 
248
{
 
249
  label=s;
 
250
  initTicks();
 
251
}
 
252
 
 
253
/**
 
254
  Sets the color of the button
 
255
  */
 
256
void KPoti::setColor( const QColor &c )
 
257
{
 
258
  color=c;
 
259
  repaint();
 
260
}
 
261
 
 
262
 
 
263
void KPoti::paintPoti( QPainter *p)
 
264
{
 
265
  QColorGroup g = colorGroup();
 
266
  p->setBrush( color );
 
267
  QCOORD x=center.x(), y=center.y();
 
268
  
 
269
 
 
270
  //qDrawShadePanel( p, r, g, FALSE, 2, &fill );
 
271
  p->drawEllipse(x-buttonRadius+5,y-buttonRadius+5,
 
272
                 (buttonRadius-5)*2, (buttonRadius-5)*2);
 
273
  //p->drawLine((int)( x+s*buttonRadius),(int)( y-c*buttonRadius),
 
274
  //    (int)(x+s*buttonRadius*0.3),(int)( y-c*buttonRadius*0.3));
 
275
  p->translate(x-1,y);
 
276
  p->rotate(potiPos*180/PI);
 
277
  int end=((buttonRadius -5)*4)/10;
 
278
  if (end<=2) end=0;
 
279
  qDrawShadeLine (p, 0, -buttonRadius+6,0 ,-end ,
 
280
                  g, TRUE, 1,2);
 
281
}
 
282
 
 
283
/*!
 
284
  Performs the actual moving of the slider.
 
285
*/
 
286
 
 
287
void KPoti::reallyMovePoti( float newPos )
 
288
{
 
289
  QPainter p;
 
290
  p.begin( this );  
 
291
  p.setPen(NoPen);
 
292
  potiPos = newPos;
 
293
  paintPoti(&p);
 
294
  p.end();
 
295
}
 
296
 
 
297
 
 
298
 
 
299
 
 
300
/**
 
301
  Handles paint events for the slider.
 
302
*/
 
303
 
 
304
void KPoti::paintEvent( QPaintEvent *e )
 
305
{
 
306
    
 
307
    QPainter p;
 
308
    QPen pen;
 
309
    p.begin( this );
 
310
    QRect paintRect = e->rect();
 
311
    p.setClipRect( paintRect );
 
312
    
 
313
    QColorGroup g = colorGroup();
 
314
        if(backgroundMode() == FixedPixmap)
 
315
        {
 
316
                p.drawTiledPixmap( 0, 0, width(), height(), *backgroundPixmap() );
 
317
        }
 
318
        else
 
319
        {
 
320
        p.fillRect( 0, 0, width(), height(), g.background() );
 
321
        }
 
322
    
 
323
    const QColor c0 = black;
 
324
    const QColor c4 = g.light();
 
325
 
 
326
    QFont font;
 
327
    font=p.font(); font.setPointSize(8); p.setFont(font);
 
328
    p.drawText(0,fontSize,name());
 
329
 
 
330
    int interval = tickInt;
 
331
    if ( interval <= 0 ) {
 
332
        interval = 12;
 
333
    }
 
334
    if (ticks)
 
335
        drawTicks( &p, buttonRadius+2, (int)(buttonRadius*(1+tickLength)), interval );
 
336
        
 
337
 
 
338
    p.setBrush(darkGray);
 
339
    p.drawEllipse(center.x()-buttonRadius,center.y()-buttonRadius,
 
340
               2*(buttonRadius),2*(buttonRadius));
 
341
    p.setPen(c0);
 
342
    p.drawArc(center.x()-buttonRadius,center.y()-buttonRadius,
 
343
               2*buttonRadius,2*buttonRadius, 45*16,180*16);
 
344
    pen=p.pen();
 
345
    pen.setWidth(2);
 
346
    p.setPen(pen);
 
347
    p.drawArc(center.x()-buttonRadius+3,center.y()-buttonRadius+3,
 
348
              2*(buttonRadius-3),2*(buttonRadius-3), 45*16,-180*16);
 
349
  
 
350
    p.setPen(c4);
 
351
    p.drawArc(center.x()-buttonRadius,center.y()-buttonRadius,
 
352
              2*buttonRadius,2*buttonRadius, 45*16,-180*16);
 
353
    pen=p.pen();
 
354
    pen.setWidth(2);
 
355
    p.setPen(pen);
 
356
    p.drawArc(center.x()-buttonRadius+3,center.y()-buttonRadius+3,
 
357
              2*(buttonRadius-3),2*(buttonRadius-3), 45*16,180*16);
 
358
  
 
359
    if ( hasFocus() ) {
 
360
      p.setPen( black ); p.setBrush(NoBrush);
 
361
      p.drawRect(  0,0, width(), height() );
 
362
    }
 
363
 
 
364
 
 
365
    p.setPen(NoPen);
 
366
    paintPoti( &p);
 
367
 
 
368
    p.end();
 
369
}
 
370
 
 
371
 
 
372
/*!
 
373
  Handles mouse press events for the slider.
 
374
*/
 
375
 
 
376
void KPoti::mousePressEvent( QMouseEvent *e )
 
377
{
 
378
  resetState();
 
379
 
 
380
  if ( e->button() == MidButton ) {
 
381
    float pos = atan2( e->pos().x()-center.x(),- e->pos().y() + center.y() );
 
382
    movePoti( pos );
 
383
    return;
 
384
  }
 
385
  if ( e->button() != LeftButton )
 
386
    return;
 
387
 
 
388
  
 
389
  int dx=e->pos().x()-center.x(), dy=e->pos().y()-center.y();
 
390
  
 
391
  if ( dx*dx+dy*dy < buttonRadius*buttonRadius ) {
 
392
    state = Dragging;
 
393
    clickOffset =  potiVal + (e->pos().y() ) ;
 
394
    emit potiPressed();
 
395
  }  else if ( e->pos().x() < width()/2 ) {
 
396
    state = TimingDown;
 
397
    subtractPage();
 
398
    if ( !timer )
 
399
      timer = new QTimer( this );
 
400
    connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
 
401
    timer->start( thresholdTime, TRUE ); 
 
402
  } else  {
 
403
    state = TimingUp;
 
404
    addPage();
 
405
    if ( !timer )
 
406
      timer = new QTimer( this );
 
407
    connect( timer, SIGNAL(timeout()), SLOT(repeatTimeout()) );
 
408
    timer->start( thresholdTime, TRUE ); 
 
409
  }
 
410
}
 
411
 
 
412
/*!
 
413
  Handles mouse move events for the slider.
 
414
*/
 
415
void KPoti::mouseMoveEvent( QMouseEvent *e )
 
416
{
 
417
 
 
418
    if ( (e->state() & MidButton) ) {           // middle button wins
 
419
      float pos = atan2( e->pos().x()-center.x(),- e->pos().y()+center.y() );
 
420
      movePoti( pos );
 
421
      return;   
 
422
    }
 
423
    if ( !(e->state() & LeftButton) )
 
424
        return;                                 // left mouse button is up
 
425
    if ( state != Dragging )
 
426
        return;
 
427
    
 
428
    
 
429
    movePoti( positionFromValue(- e->pos().y() + clickOffset ));
 
430
}
 
431
 
 
432
 
 
433
/*!
 
434
  Handles mouse release events for the slider.
 
435
*/
 
436
 
 
437
void KPoti::mouseReleaseEvent( QMouseEvent *e )
 
438
{
 
439
    if ( !(e->button() & LeftButton) )
 
440
        return;
 
441
    resetState();
 
442
}
 
443
 
 
444
/*!
 
445
  Handles focus in events for the slider.
 
446
*/
 
447
 
 
448
void KPoti::focusInEvent( QFocusEvent * )
 
449
{
 
450
    repaint( FALSE );
 
451
}
 
452
 
 
453
 
 
454
/*!
 
455
  Handles mouse entering events.
 
456
*/
 
457
 
 
458
void KPoti::enterEvent( QEvent * )
 
459
{
 
460
    emit mouseEntered( potiVal );
 
461
}
 
462
 
 
463
 
 
464
/*!
 
465
  Moves the left (or top) edge of the slider to position 
 
466
  \a pos. Performs snapping.
 
467
*/
 
468
 
 
469
void KPoti::movePoti( float pos )
 
470
{
 
471
    float newPos = QMIN( maxAngle, QMAX( -maxAngle, pos ) );
 
472
    int newVal = valueFromPosition( newPos );
 
473
    if ( potiVal != newVal ) {
 
474
        potiVal = newVal;
 
475
        emit potiMoved( potiVal );
 
476
    }
 
477
    if ( tracking() && potiVal != value() ) {
 
478
        directSetValue( potiVal );
 
479
        emit valueChanged( potiVal );
 
480
    }
 
481
 
 
482
 
 
483
    if ( potiPos != newPos )
 
484
        reallyMovePoti( newPos );
 
485
}
 
486
 
 
487
 
 
488
/*!
 
489
  Resets all state information and stops my timer.
 
490
*/
 
491
 
 
492
void KPoti::resetState()
 
493
{
 
494
    if ( timer ) {
 
495
        timer->stop();
 
496
        timer->disconnect();
 
497
    }
 
498
    switch ( state ) {
 
499
    case TimingUp:
 
500
    case TimingDown:
 
501
        break;
 
502
    case Dragging: {
 
503
        setValue( valueFromPosition( potiPos ) );
 
504
        emit potiReleased();
 
505
        break;
 
506
    }
 
507
    case Idle:
 
508
        break;
 
509
    default:
 
510
        kdWarning() << "KPoti: in wrong state" << endl;
 
511
    }
 
512
    state = Idle;
 
513
}
 
514
 
 
515
 
 
516
/*!
 
517
  Handles key press events for the slider.
 
518
*/
 
519
 
 
520
void KPoti::keyPressEvent( QKeyEvent *e )
 
521
{
 
522
 
 
523
    switch ( e->key() ) {
 
524
    case Key_Left:
 
525
      subtractLine();
 
526
      break;
 
527
    case Key_Right:
 
528
      addLine();
 
529
      break;
 
530
    case Key_Up:
 
531
      addLine();
 
532
      break;
 
533
    case Key_Down:
 
534
      subtractLine();
 
535
      break;
 
536
    case Key_Prior:
 
537
      subtractPage();
 
538
      break;
 
539
    case Key_Next:
 
540
      addPage();
 
541
      break;
 
542
    case Key_Home:
 
543
      setValue( minValue() );
 
544
      break;
 
545
    case Key_End:
 
546
      setValue( maxValue() );
 
547
      break;
 
548
    default:
 
549
        e->ignore();
 
550
        return;
 
551
    }
 
552
    e->accept();
 
553
}
 
554
 
 
555
 
 
556
 
 
557
 
 
558
 
 
559
/*!
 
560
  Makes QRangeControl::setValue() available as a slot.
 
561
*/
 
562
 
 
563
void KPoti::setValue( int value )
 
564
{
 
565
    QRangeControl::setValue( value );
 
566
}
 
567
 
 
568
 
 
569
/*!
 
570
  Moves the slider one pageStep() upwards.
 
571
*/
 
572
 
 
573
void KPoti::addStep()
 
574
{
 
575
    addPage();
 
576
}
 
577
 
 
578
 
 
579
/*!
 
580
  Moves the slider one pageStep() downwards.
 
581
*/
 
582
 
 
583
void KPoti::subtractStep()
 
584
{
 
585
    subtractPage();
 
586
}
 
587
 
 
588
 
 
589
/*!
 
590
  Waits for autorepeat.
 
591
*/
 
592
 
 
593
void KPoti::repeatTimeout()
 
594
{
 
595
    ASSERT( timer );
 
596
    timer->disconnect();
 
597
    if ( state == TimingDown )
 
598
        connect( timer, SIGNAL(timeout()), SLOT(subtractStep()) );
 
599
    else if ( state == TimingUp )
 
600
        connect( timer, SIGNAL(timeout()), SLOT(addStep()) );
 
601
    timer->start( repeatTime, FALSE );   
 
602
}
 
603
 
 
604
 
 
605
 
 
606
 
 
607
/*!  
 
608
  Using \a p, draws tickmarks at a distance of \a d from the edge
 
609
  of the widget, using \a w pixels and \a i intervals.  
 
610
  */
 
611
 
 
612
void KPoti::drawTicks( QPainter *p, int d, int w, int i ) const
 
613
{
 
614
  p->setPen( colorGroup().foreground() );
 
615
  float angle,s,c;
 
616
  for (int v=0; v<=i; v++) {
 
617
    angle=-maxAngle+2*maxAngle*v/i;
 
618
    s=sin(angle); c=cos(angle);
 
619
 
 
620
    p->drawLine( (int)(center.x()-s*d), (int)(center.y()-c*d),
 
621
                 (int)(center.x()-s*w), (int)(center.y()-c*w) );
 
622
    }
 
623
}
 
624
 
 
625
void KPoti::wheelEvent(QWheelEvent *e)
 
626
{
 
627
        setValue(value()+e->delta()/120*8);
 
628
}
 
629
 
 
630
 
 
631
/*!
 
632
  Sets the way tickmarks are displayed by the slider. \a s can take 
 
633
  the following values:
 
634
  <ul>
 
635
  <li> \c NoMarks
 
636
  <li> \c Above
 
637
  <li> \c Left
 
638
  <li> \c Below
 
639
  <li> \c Right
 
640
  <li> \c Both
 
641
  </ul>
 
642
  The initial value is \c NoMarks.
 
643
  \sa tickmarks(), setTickInterval()
 
644
*/
 
645
 
 
646
void KPoti::setTickmarks( bool s )
 
647
{
 
648
    ticks = s;
 
649
    initTicks();
 
650
    update();
 
651
}
 
652
 
 
653
 
 
654
 
 
655
/*!
 
656
  Sets the interval between tickmarks to \a i. This is a value interval, 
 
657
  not a pixel interval. If \a i is 0, the slider
 
658
  will choose between lineStep() and pageStep(). The initial value of 
 
659
  tickInterval() is 0.
 
660
  \sa tickInterval(), QRangeControl::lineStep(), QRangeControl::pageStep()
 
661
*/
 
662
 
 
663
void KPoti::setTickInterval( int i )
 
664
{
 
665
    tickInt = QMAX( 0, i );
 
666
    update();
 
667
}
 
668
 
 
669
 
 
670
/*!
 
671
  \fn int KPoti::tickInterval() const
 
672
  Returns the interval between tickmarks. Returns 0 if the slider
 
673
  chooses between pageStep() and lineStep().
 
674
  \sa setTickInterval()
 
675
*/
 
676
 
 
677
 
 
678
 
 
679
 
 
680
 
 
681
 
 
682
 
 
683
 
 
684
 
 
685
 
 
686
 
 
687
 
 
688
 
 
689
 
 
690
 
 
691