~ubuntu-branches/ubuntu/oneiric/muse/oneiric

« back to all changes in this revision

Viewing changes to widgets/knob.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Kobras
  • Date: 2002-04-23 17:28:23 UTC
  • Revision ID: james.westby@ubuntu.com-20020423172823-w8yplzr81a759xa3
Tags: upstream-0.5.2
ImportĀ upstreamĀ versionĀ 0.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//======================================================================
 
2
//  MusE
 
3
//  Linux Music Editor
 
4
//    $Id: knob.cpp,v 1.1 2002/01/30 14:54:03 muse Exp $
 
5
//  (C) Copyright 1999 Werner Schweer (ws@seh.de)
 
6
//
 
7
//  Adapted from Qwt Lib:
 
8
//      Copyright (C) 1997  Josef Wilgen
 
9
//      This program is free software; you can redistribute it and/or modify
 
10
//      it under the terms of the GNU General Public License, version 2,
 
11
//      as published by the Free Software Foundation.
 
12
//      This program is distributed in the hope that it will be useful,
 
13
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
//      GNU General Public License for more details.
 
16
//      You should have received a copy of the GNU General Public License
 
17
//      along with this program; if not, write to the Free Software
 
18
//      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
//=========================================================
 
20
 
 
21
#include <stdio.h>
 
22
#include "knob.h"
 
23
#include "math.h"
 
24
#include "mmath.h"
 
25
 
 
26
#include <qpainter.h>
 
27
#include <qpalette.h>
 
28
 
 
29
//---------------------------------------------------------
 
30
//      The QwtKnob widget imitates look and behaviour of a volume knob on a radio.
 
31
//      It contains
 
32
//      a scale around the knob which is set up automatically or can
 
33
//      be configured manually (see @^QwtScaleIf@).
 
34
//      Automatic scrolling is enabled when the user presses a mouse
 
35
//      button on the scale. For a description of signals, slots and other
 
36
//      members, see QwtSliderBase@.
 
37
//---------------------------------------------------------
 
38
 
 
39
 
 
40
//---------------------------------------------------------
 
41
//   Knob
 
42
//---------------------------------------------------------
 
43
 
 
44
Knob::Knob(QWidget* parent, const char* name)
 
45
   : SliderBase(parent, name)
 
46
      {
 
47
      hasScale = false;
 
48
 
 
49
      d_borderWidth   = 2;
 
50
      d_borderDist    = 4;
 
51
      d_totalAngle    = 270.0;
 
52
      d_scaleDist     = 1;
 
53
      d_symbol        = Line;
 
54
      d_maxScaleTicks = 11;
 
55
      d_knobWidth     = 30;
 
56
      d_faceColor     = backgroundColor();
 
57
      d_markerColor   = foregroundColor();
 
58
      d_dotWidth      = 8;
 
59
 
 
60
      setMinimumSize(30,30);
 
61
      setUpdateTime(50);
 
62
      }
 
63
 
 
64
//------------------------------------------------------------
 
65
//      QwtKnob::setTotalAngle
 
66
//  Set the total angle by which the knob can be turned
 
67
//
 
68
//      Syntax
 
69
//      void QwtKnob::setTotalAngle(double angle)
 
70
//
 
71
//      Parameters
 
72
//      double angle    --      angle in degrees.
 
73
//
 
74
//      Description
 
75
//  The default angle is 270 degrees. It is possible to specify
 
76
//  an angle of more than 360 degrees so that the knob can be
 
77
//  turned several times around its axis.
 
78
//------------------------------------------------------------
 
79
 
 
80
void Knob::setTotalAngle (double angle)
 
81
      {
 
82
      if (angle < 10.0)
 
83
            d_totalAngle = 10.0;
 
84
      else
 
85
            d_totalAngle = angle;
 
86
      d_scale.setAngleRange( -0.5 * d_totalAngle, 0.5 * d_totalAngle);
 
87
      }
 
88
 
 
89
//------------------------------------------------------------
 
90
//   QwtKnob::drawKnob
 
91
//    const QRect &r --   borders of the knob
 
92
//------------------------------------------------------------
 
93
 
 
94
void Knob::drawKnob(QPainter* p, const QRect& r)
 
95
      {
 
96
      QRect aRect;
 
97
 
 
98
      QColorGroup g = colorGroup();
 
99
      QPen pn;
 
100
      int bw2 = d_borderWidth / 2;
 
101
 
 
102
      aRect.setRect(r.x() + bw2,
 
103
                        r.y() + bw2,
 
104
                        r.width()  - 2*bw2,
 
105
                        r.height() - 2*bw2);
 
106
 
 
107
    //
 
108
    // draw button face
 
109
    //
 
110
    p->setPen(NoPen);
 
111
    p->setBrush(d_faceColor);
 
112
    p->drawEllipse(aRect);
 
113
 
 
114
    //
 
115
    // draw button shades
 
116
    //
 
117
    pn.setWidth(d_borderWidth);
 
118
 
 
119
 
 
120
    pn.setColor(g.light());
 
121
    p->setPen(pn);
 
122
    p->drawArc(aRect, 45*16,180*16);
 
123
 
 
124
    pn.setColor(g.dark());
 
125
    p->setPen(pn);
 
126
    p->drawArc(aRect, 225*16,180*16);
 
127
 
 
128
      //
 
129
      // draw marker
 
130
      //
 
131
      drawMarker(p, d_angle, d_markerColor);
 
132
      }
 
133
 
 
134
//------------------------------------------------------------
 
135
//.F    QwtSliderBase::valueChange
 
136
//      Notify change of value
 
137
//
 
138
//.u    Parameters
 
139
//      double x  --    new value
 
140
//
 
141
//.u    Description
 
142
//      Sets the slider's value to the nearest multiple
 
143
//          of the step size.
 
144
//------------------------------------------------------------
 
145
 
 
146
void Knob::valueChange()
 
147
      {
 
148
      recalcAngle();
 
149
      d_newVal++;
 
150
      repaint(kRect, FALSE);
 
151
      SliderBase::valueChange();
 
152
      }
 
153
 
 
154
//------------------------------------------------------------
 
155
//.F    QwtKnob::getValue
 
156
//      Determine the value corresponding to a specified position
 
157
//
 
158
//.u    Parameters:
 
159
//      const QPoint &p -- point
 
160
//
 
161
//.u    Description:
 
162
//      Called by QwtSliderBase
 
163
//------------------------------------------------------------
 
164
 
 
165
double Knob::getValue(const QPoint &p)
 
166
      {
 
167
      double newValue;
 
168
      double oneTurn;
 
169
      double eqValue;
 
170
      double arc;
 
171
 
 
172
    const QRect& r = rect();
 
173
 
 
174
    double dx = double((r.x() + r.width() / 2) - p.x() );
 
175
    double dy = double((r.y() + r.height() / 2) - p.y() );
 
176
 
 
177
    arc = atan2(-dx,dy) * 180.0 / M_PI;
 
178
 
 
179
    newValue =  0.5 * (minValue() + maxValue())
 
180
       + (arc + d_nTurns * 360.0) * (maxValue() - minValue())
 
181
          / d_totalAngle;
 
182
 
 
183
    oneTurn = fabs(maxValue() - minValue()) * 360.0 / d_totalAngle;
 
184
    eqValue = value() + d_mouseOffset;
 
185
 
 
186
    if (fabs(newValue - eqValue) > 0.5 * oneTurn)
 
187
    {
 
188
        if (newValue < eqValue)
 
189
           newValue += oneTurn;
 
190
        else
 
191
           newValue -= oneTurn;
 
192
    }
 
193
 
 
194
    return newValue;    
 
195
 
 
196
}
 
197
 
 
198
 
 
199
 
 
200
//------------------------------------------------------------
 
201
//.-
 
202
//.F    QwtKnob::setScrollMode
 
203
//      Determine the scrolling mode and direction
 
204
//      corresponding to a specified position
 
205
//
 
206
//.u    Parameters
 
207
//      const QPoint &p -- point in question
 
208
//
 
209
//.u    Description
 
210
//      Called by QwtSliderBase
 
211
//------------------------------------------------------------
 
212
void Knob::getScrollMode(const QPoint &p, int &scrollMode, int &direction)
 
213
{
 
214
    int dx, dy, r;
 
215
    double arc;
 
216
 
 
217
    r = kRect.width() / 2;
 
218
 
 
219
    dx = kRect.x() + r - p.x();
 
220
    dy = kRect.y() + r - p.y();
 
221
 
 
222
    if ( (dx * dx) + (dy * dy) <= (r * r)) // point is inside the knob
 
223
    {
 
224
        scrollMode = ScrMouse;
 
225
        direction = 0;
 
226
    }
 
227
    else                                                                // point lies outside
 
228
    {
 
229
        scrollMode = ScrTimer;
 
230
        arc = atan2(double(-dx),double(dy)) * 180.0 / M_PI;
 
231
        if ( arc < d_angle)
 
232
           direction = -1;
 
233
        else if (arc > d_angle)
 
234
           direction = 1;
 
235
        else
 
236
           direction = 0;
 
237
    }
 
238
    return;
 
239
}
 
240
 
 
241
 
 
242
 
 
243
//------------------------------------------------------------
 
244
//.F  QwtKnob::rangeChange
 
245
//      Notify a change of the range
 
246
//
 
247
//.u  Description
 
248
//      Called by QwtSliderBase
 
249
//------------------------------------------------------------
 
250
 
 
251
void Knob::rangeChange()
 
252
{
 
253
    if (!hasUserScale())
 
254
    {
 
255
        d_scale.setScale(minValue(), maxValue(),
 
256
                         d_maxMajor, d_maxMinor);
 
257
    }
 
258
    recalcAngle();
 
259
    resize(size());
 
260
    repaint(FALSE);
 
261
}
 
262
 
 
263
//---------------------------------------------------------
 
264
//   resizeEvent
 
265
//---------------------------------------------------------
 
266
 
 
267
void Knob::resizeEvent(QResizeEvent *)
 
268
      {
 
269
      int width, width_2;
 
270
 
 
271
      const QRect& r = rect();
 
272
 
 
273
// printf("resize %d %d %d\n", r.height(), r.width(), d_knobWidth);
 
274
 
 
275
//      width = qwtMin(qwtMin(r.height(), r.width()), d_knobWidth);
 
276
      width = qwtMin(r.height(), r.width());
 
277
      width_2 = width / 2;
 
278
 
 
279
      int x = r.x() + r.width()  / 2 - width_2;
 
280
      int y = r.y() + r.height() / 2 - width_2;
 
281
 
 
282
      kRect.setRect(x, y, width, width);
 
283
 
 
284
      x = kRect.x() - d_scaleDist;
 
285
      y = kRect.y() - d_scaleDist;
 
286
      int w = width + 2 * d_scaleDist;
 
287
 
 
288
      d_scale.setGeometry(x, y, w, ScaleDraw::Round);
 
289
      }
 
290
 
 
291
//------------------------------------------------------------
 
292
//    paintEvent
 
293
//------------------------------------------------------------
 
294
 
 
295
void Knob::paintEvent(QPaintEvent* e)
 
296
      {
 
297
      QPainter p(this);
 
298
      const QRect &r = e->rect();
 
299
 
 
300
      if ((r == kRect) && d_newVal ) {        // event from valueChange()
 
301
              if (d_newVal > 1)                     // lost paintEvents()?
 
302
                      drawKnob(&p, kRect);
 
303
            else {
 
304
                  drawMarker(&p, d_oldAngle, d_faceColor);
 
305
                  drawMarker(&p, d_angle, d_markerColor);
 
306
                  }
 
307
            }
 
308
      else {
 
309
            p.eraseRect(rect());
 
310
            if (hasScale)
 
311
                  d_scale.draw(&p);
 
312
            drawKnob(&p, kRect);
 
313
            }
 
314
      d_newVal = 0;
 
315
      }
 
316
 
 
317
//------------------------------------------------------------
 
318
//.-
 
319
//.F    QwtKnob::drawMarker
 
320
//      Draw the marker at the knob's front
 
321
//
 
322
//.u    Parameters
 
323
//.p    QPainter *p     --      painter
 
324
//      double arc      --      angle of the marker
 
325
//      const QColor &c  --     marker color
 
326
//
 
327
//.u    Syntax
 
328
//                              void QwtKnob::drawMarker(QPainter *p)
 
329
//
 
330
//------------------------------------------------------------
 
331
void Knob::drawMarker(QPainter *p, double arc, const QColor &c)
 
332
{
 
333
 
 
334
    QPen pn;
 
335
    int radius;
 
336
    double rb,re;
 
337
    double rarc;
 
338
 
 
339
    rarc = arc * M_PI / 180.0;
 
340
    double ca = cos(rarc);
 
341
    double sa = - sin(rarc);
 
342
    radius = kRect.width() / 2 - d_borderWidth;
 
343
    if (radius < 3) radius = 3; 
 
344
    int ym = kRect.y() + radius + d_borderWidth;
 
345
    int xm = kRect.x() + radius + d_borderWidth;
 
346
 
 
347
    switch (d_symbol)
 
348
    {
 
349
    case Dot:
 
350
        
 
351
        p->setBrush(c);
 
352
        p->setPen(NoPen);
 
353
        rb = double(qwtMax(radius - 4 - d_dotWidth / 2, 0));
 
354
        p->drawEllipse(xm - int(rint(sa * rb)) - d_dotWidth / 2,
 
355
                       ym - int(rint(ca * rb)) - d_dotWidth / 2,
 
356
                       d_dotWidth, d_dotWidth);
 
357
        
 
358
        break;
 
359
        
 
360
    case Line:
 
361
        
 
362
        pn.setColor(c);
 
363
        pn.setWidth(2);
 
364
        p->setPen(pn);
 
365
        
 
366
        rb = qwtMax(double((radius - 4) / 3.0), 0.0);
 
367
        re = qwtMax(double(radius - 4), 0.0);
 
368
        
 
369
        p->drawLine( xm - int(rint(sa * rb)),
 
370
                    ym - int(rint(ca * rb)),
 
371
                    xm - int(rint(sa * re)),
 
372
                    ym - int(rint(ca * re)));
 
373
        
 
374
        break;
 
375
    }
 
376
 
 
377
 
 
378
}
 
379
 
 
380
//------------------------------------------------------------
 
381
//
 
382
//.F    QwtKnob::setKnobWidth
 
383
//              Change the knob's width.
 
384
//
 
385
//.u    Syntax
 
386
//.f    void QwtKnob::setKnobWidth(int w)
 
387
//
 
388
//.u    Parameters
 
389
//.p    int w     --    new width
 
390
//
 
391
//.u    Description
 
392
//              The specified width must be >= 5, or it will be clipped.
 
393
//
 
394
//------------------------------------------------------------
 
395
void Knob::setKnobWidth(int w)
 
396
{
 
397
    d_knobWidth = qwtMax(w,5);
 
398
    resize(size());
 
399
    repaint(FALSE);
 
400
}
 
401
 
 
402
//------------------------------------------------------------
 
403
//
 
404
//.F    QwtKnob::setBorderWidth
 
405
//              Set the knob's border width
 
406
//
 
407
//.u    Syntax
 
408
//.f    void QwtKnob::setBorderWidth(int bw)
 
409
//
 
410
//.u    Parameters
 
411
//.p    int bw -- new border width
 
412
//
 
413
//------------------------------------------------------------
 
414
void Knob::setBorderWidth(int bw)
 
415
{
 
416
    d_borderWidth = qwtMax(bw, 0);
 
417
    resize(size());
 
418
    repaint(FALSE);
 
419
}
 
420
 
 
421
//------------------------------------------------------------
 
422
//.-
 
423
//.F    QwtKnob::recalcAngle
 
424
//              Recalculate the marker angle corresponding to the
 
425
//              current value
 
426
//
 
427
//.u    Syntax
 
428
//.f    void QwtKnob::recalcAngle()
 
429
//
 
430
//------------------------------------------------------------
 
431
void Knob::recalcAngle()
 
432
{
 
433
    d_oldAngle = d_angle;
 
434
 
 
435
    //
 
436
    // calculate the angle corresponding to the value
 
437
    //
 
438
    if (maxValue() == minValue())
 
439
    {
 
440
        d_angle = 0;
 
441
        d_nTurns = 0;
 
442
    }
 
443
    else
 
444
    {
 
445
        d_angle = (value() - 0.5 * (minValue() + maxValue()))
 
446
           / (maxValue() - minValue()) * d_totalAngle;
 
447
        d_nTurns = floor((d_angle + 180.0) / 360.0);
 
448
        d_angle = d_angle - d_nTurns * 360.0;
 
449
        
 
450
    }
 
451
 
 
452
}