1 //=========================================================
2 // MusE
3 // Linux Music Editor
4 // $Id: scldraw.cpp,v 1.1.1.1 2003/10/27 18:54:36 wschweer Exp $
5 //
6 // Copyright (C) 1997 Josef Wilgen
7 // (C) Copyright 2000 Werner Schweer (ws@seh.de)
8 // (C) Copyright 2016 Tim E. Real (terminator356 on sourceforge)
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; version 2 of
13 // the License, or (at your option) any later version.
14 //
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 //
24 //=========================================================
25
26 #include <QPainter>
27 #include <QFontMetrics>
28 #include <QPalette>
29 #include <QApplication>
30
31 #include "muse_math.h"
32 #include "mmath.h"
33 #include "scldraw.h"
34
35 namespace MusEGui {
36
37 int const ScaleDraw::minLen = 10;
38
39 const double step_eps = 1.0e-6;
40 static const double WorstCase = -8.8888888888888888888888e-88;
41
42 //------------------------------------------------------------
43 //.H ScaleDraw | 3 | 30/08/97 | Qwt Widget Library | Qwt Programmer's Manual
44 //.I scldraw Different Scales
45 //.U NAME
46 // ScaleDraw - A class for drawing scales
47 //
48 //.U SYNOPSIS
49 // #include <qwt_scldraw.h>
50 //
51 //.U DESCRIPTION
52 // ScaleDraw can be used to draw linear or logarithmic scales.
53 // A scale has an origin,
54 // an orientation and a length, which all can be specified with
55 // @ScaleDraw::setGeometry@.
56 // After a scale division has been specified as a @^QwtScaleDiv@ object
57 // using @ScaleDraw::setScale (1)@
58 // or determined internally using @ScaleDraw::setScale (2)@,
59 // the scale can be drawn with the @QwtScaleDiv::draw@ member.
60 //
61 //.U INHERITED CLASSES
62 // @QwtDiMap@
63 //
64 //.U PUBLIC MEMBERS
65 //.R
66 // ScaleDraw::ScaleDraw -- constructor
67 // ScaleDraw::setScale (1) -- set scale using QwtScaleDiv
68 // ScaleDraw::setScale (2) -- set scale directly
69 // ScaleDraw::setGeometry -- specify geometry
70 // ScaleDraw::setAngleRange -- specify angle range for round scales
71 // ScaleDraw::setLabelFormat -- set number format
72 // ScaleDraw::scalediv -- return scale division
73 // ScaleDraw::orientation -- return orientation
74 // ScaleDraw::maxBoundingRect -- return maximum bounding rectangle
75 // ScaleDraw::maxWidth -- return maximum width
76 // ScaleDraw::maxHeight -- return maximum height
77 // ScaleDraw::maxLabelWidth -- return maximum width of the number labels
78 // ScaleDraw::draw -- draw the scale
79 //
80 //.U STATIC DATA MEMBERS
81 //.t
82 // enum ScaleDraw::Orientation { Left, Right, Top, Bottom, Round } --
83 // Scale orientation
84 //------------------------------------------------------------
85
86 //------------------------------------------------------------
87 //.U MEMBER FUNCTION DESCRIPTION
88 //------------------------------------------------------------
89
90 //------------------------------------------------------------
91 //
92 //.F ScaleDraw::ScaleDraw
93 //
94 // Constructor
95 //.u Description
96 // The range of the scale is initialized to [0, 100],
97 // the angle range is set to [-135, 135], the geometry
98 // is initialized such that the origin is at (0,0), the
99 // length is 100, and the orientation is ScaleDraw::Bottom.
100 //
101 //------------------------------------------------------------
ScaleDraw()102 ScaleDraw::ScaleDraw()
103 {
104 d_hpad = 3;
105 d_vpad = 1;
106 d_majLen = 4;
107 d_medLen = 3;
108 d_minLen = 2;
109
110 d_minAngle = -135 * 16;
111 d_maxAngle = 135 * 16;
112 d_fmt = 'M'; // Metric suffix G M K.
113 d_prec = 4;
114
115 d_drawBackBone = true;
116 d_textHighlightMode = TextHighlightNone;
117
118 // initialize scale and geometry
119 setGeometry(0,0,100,Bottom);
120 setScale(0,100,0,0,10);
121 }
122
123
124 //------------------------------------------------------------
125 //
126 //.F ScaleDraw::setScale (1)
127 // Adjust the range of the scale
128 //
129 //.u Syntax
130 //.f void ScaleDraw::setScale(double x1, double x2, double step, int logscale)
131 //
132 //.u Parameters
133 //.p double x1 -- value at the left/low endpoint of the scale
134 // double x2 -- value at the right/high endpoint of the scale
135 // double step -- step size (default : 0.0)
136 // int logscale -- logarithmic scale (default : 0)
137 //
138 //.u Description
139 // If step == 0.0, the step width is calculated automatically
140 // dependent on the maximal number of scale ticks.
141 //
142 //------------------------------------------------------------
setScale(double x1,double x2,int maxMajIntv,int maxMinIntv,double step,int logscale)143 void ScaleDraw::setScale(double x1, double x2, int maxMajIntv,
144 int maxMinIntv, double step, int logscale)
145 {
146 d_scldiv.rebuild( x1, x2, maxMajIntv, maxMinIntv, logscale, step, false );
147 setDblRange( d_scldiv.lBound(), d_scldiv.hBound(), d_scldiv.logScale());
148 }
149
150
151 //------------------------------------------------------------
152 //
153 //.F ScaleDraw::setScale (2)
154 // Change the scale division
155 //
156 //.u Syntax
157 //.f void ScaleDraw::setScale(QwtAutoScale &as)
158 //
159 //.u Parameters
160 //.p const QwtScaleDiv& sd -- new scale division
161 //
162 //------------------------------------------------------------
163
setScale(const ScaleDiv & s)164 void ScaleDraw::setScale(const ScaleDiv &s)
165 {
166 d_scldiv = s;
167 setDblRange(d_scldiv.lBound(),d_scldiv.hBound(),d_scldiv.logScale());
168 }
169
composeLabelText(double val,char fmt,int prec) const170 QString ScaleDraw::composeLabelText(double val, char fmt, int prec) const
171 {
172 if(fmt == 'M')
173 {
174 if(val > 1000000000.0)
175 return QString("%L1").arg(val / 1000000000.0, 0, 'g', prec) + "G";
176 else if(val > 1000000.0)
177 return QString("%L1").arg(val / 1000000.0, 0, 'g', prec) + "M";
178 else if(val > 1000.0)
179 return QString("%L1").arg(val / 1000.0, 0, 'g', prec) + "K";
180 else
181 return QString("%L1").arg(val, 0, 'g', prec);
182 }
183 return QString("%L1").arg(val, 0, fmt, prec);
184 }
185
186 //------------------------------------------------------------
187 //.F ScaleDraw::draw
188 // Draw the scale
189 //.u Parameters
190 //.p QPainter *p -- the painter
191 //------------------------------------------------------------
192
draw(QPainter * p,const QPalette & palette,double curValue)193 void ScaleDraw::draw(QPainter *p, const QPalette& palette, double curValue)// const
194 {
195 double val,hval,majTick;
196
197 int i,k,kmax;
198
199 p->setPen(palette.text().color());
200 const int majCnt = d_scldiv.majCnt();
201 const int minCnt = d_scldiv.minCnt();
202
203 for (i=0; i< majCnt; i++)
204 {
205 val = d_scldiv.majMark(i);
206 drawTick(p, palette, curValue, val, d_majLen);
207 }
208
209 for (i=0; i< majCnt; i++)
210 {
211 val = d_scldiv.majMark(i);
212 drawLabel(p, palette, curValue, val, i == 0);
213 }
214
215 if (d_scldiv.logScale())
216 {
217 for (i=0; i< minCnt; i++)
218 {
219 drawTick(p,palette,curValue,d_scldiv.minMark(i),d_minLen);
220 }
221 }
222 else
223 {
224 k = 0;
225 kmax = majCnt - 1;
226 if (kmax > 0)
227 {
228 majTick = d_scldiv.majMark(0);
229 hval = majTick - 0.5 * d_scldiv.majStep();
230
231 for (i=0; i< minCnt; i++)
232 {
233 val = d_scldiv.minMark(i);
234 if (val > majTick)
235 {
236 if (k < kmax)
237 {
238 k++;
239 majTick = d_scldiv.majMark(k);
240 }
241 else
242 {
243 majTick += d_scldiv.majMark(kmax) + d_scldiv.majStep();
244 }
245 hval = majTick - 0.5 * d_scldiv.majStep();
246
247 }
248 if (MusECore::qwtAbs(val-hval) < step_eps * d_scldiv.majStep())
249 drawTick(p, palette, curValue, val, d_medLen);
250 else
251 drawTick(p, palette, curValue, val, d_minLen);
252 }
253 }
254 }
255
256 //
257 // draw backbone
258 //
259 if (d_drawBackBone)
260 drawBackbone(p, palette, curValue);
261
262 }
263
264
265 //------------------------------------------------------------
266 //.F ScaleDraw::drawTick
267 // Draws a singls scale tick
268 //
269 //.u Parameters
270 //.p QPainter *p, double val, int len
271 //------------------------------------------------------------
272
drawTick(QPainter * p,const QPalette &,double,double val,int len) const273 void ScaleDraw::drawTick(QPainter *p, const QPalette& /*palette*/, double /*curValue*/, double val, int len) const
274 {
275 int tval = transform(val);
276 double arc;
277 int x1, x2, y1, y2;
278
279 switch(d_orient)
280 {
281 case Right:
282
283 p->drawLine(d_xorg, tval, d_xorg + len, tval);
284 break;
285
286 case Bottom:
287 p->drawLine(tval, d_yorg, tval, d_yorg + len);
288 break;
289
290 case InsideHorizontal:
291 p->drawLine(tval, d_vpad + d_majLen - len, tval, d_vpad + d_majLen);
292 break;
293
294 case Left:
295 case InsideVertical:
296
297 p->drawLine(d_xorg, tval, d_xorg - len, tval);
298 break;
299
300 case Round:
301
302 if ((tval <= d_minAngle + 359 * 16) || (tval >= d_minAngle - 359 * 16))
303 {
304 arc = double(tval) / 16.0 * M_PI / 180.0;
305 x1 = MusECore::qwtInt(d_xCenter + sin(arc) * d_radius);
306 x2 = MusECore::qwtInt(d_xCenter + sin(arc) * (d_radius + double(len)));
307 y1 = MusECore::qwtInt(d_yCenter - cos(arc) * d_radius);
308 y2 = MusECore::qwtInt(d_yCenter - cos(arc) * (d_radius + double(len)));
309 p->drawLine(x1, y1, x2, y2);
310 }
311 break;
312
313 case Top:
314 default:
315
316 p->drawLine(tval, d_yorg, tval, d_yorg - len);
317 break;
318
319
320 }
321
322 }
323
324 //------------------------------------------------------------
325 //.-
326 //.F ScaleDraw::drawLabel
327 // Draws the number label for a major scale tick
328 //
329 //.u Parameters
330 //.p QPainter *p, double val
331 //
332 //------------------------------------------------------------
drawLabel(QPainter * p,const QPalette & palette,double curValue,double val,bool isSpecialText) const333 void ScaleDraw::drawLabel(QPainter *p, const QPalette& palette, double curValue, double val, bool isSpecialText) const
334 {
335
336 static QString label;
337 static double pi_4 = M_PI * 0.25;
338 static double pi_75 = M_PI * 0.75;
339
340 double arc;
341 int xpos, ypos, x0, y0;
342 int tval;
343
344 QFontMetrics fm = p->fontMetrics();
345
346 tval = transform(val);
347
348 // correct rounding errors if val = 0
349 if ((!d_scldiv.logScale()) && (MusECore::qwtAbs(val) < MusECore::qwtAbs(step_eps * d_scldiv.majStep())))
350 val = 0.0;
351
352 if(isSpecialText && !_specialText.isEmpty())
353 label = _specialText;
354 else
355 label = composeLabelText(val, d_fmt, d_prec);
356
357 switch(d_orient)
358 {
359 case Right:
360 x0 = d_xorg + d_majLen + d_hpad;
361 y0 = tval + (fm.ascent()-1) / 2;
362 break;
363 case Left:
364 case InsideVertical:
365 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
366 #if QT_VERSION >= 0x050b00
367 x0 = d_xorg - d_majLen - d_hpad - fm.horizontalAdvance(label);
368 #else
369 x0 = d_xorg - d_majLen - d_hpad - fm.width(label);
370 #endif
371 y0 = tval + (fm.ascent() -1) / 2;
372 break;
373 case Bottom:
374 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
375 #if QT_VERSION >= 0x050b00
376 x0 = tval - (fm.horizontalAdvance(label)-1) / 2;
377 #else
378 x0 = tval - (fm.width(label)-1) / 2;
379 #endif
380 y0 = d_yorg + d_majLen + d_vpad + fm.ascent();
381 break;
382
383 case InsideHorizontal:
384 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
385 #if QT_VERSION >= 0x050b00
386 x0 = tval - (fm.horizontalAdvance(label)-1) / 2;
387 #else
388 x0 = tval - (fm.width(label)-1) / 2;
389 #endif
390 //y0 = d_yorg + d_majLen + d_vpad + fm.ascent();
391 y0 = d_majLen + d_vpad + fm.ascent();
392 break;
393
394 case Round:
395
396 if ((tval > d_minAngle + 359 * 16) || (tval < d_minAngle - 359 * 16))
397 // break;
398 return;
399
400 arc = double(tval) / 16.0 * M_PI / 180.0;
401
402 // Map arc into the interval -pi <= arc <= pi
403 if ((arc < -M_PI) || (arc > M_PI))
404 arc -= floor((arc + M_PI) / M_PI * 0.5) * 2.0 * M_PI;
405
406 xpos = 1 + MusECore::qwtInt(d_xCenter + (d_radius + double(d_majLen + d_vpad)) * sin(arc));
407 ypos = MusECore::qwtInt(d_yCenter - (d_radius + double(d_majLen + d_vpad)) * cos(arc));
408
409 if (arc < -pi_75)
410 {
411 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
412 #if QT_VERSION >= 0x050b00
413 x0 = xpos - MusECore::qwtInt(double(fm.horizontalAdvance(label))
414 #else
415 x0 = xpos - MusECore::qwtInt(double(fm.width(label))
416 #endif
417 * (1.0 + (arc + pi_75) * M_2_PI));
418 y0 = ypos + fm.ascent() - 1;
419 }
420 else if (arc < -M_PI_4)
421 {
422 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
423 #if QT_VERSION >= 0x050b00
424 x0 = xpos - fm.horizontalAdvance(label);
425 #else
426 x0 = xpos - fm.width(label);
427 #endif
428 y0 = ypos - MusECore::qwtInt(double(fm.ascent() - 1)
429 * (arc + M_PI_4) * M_2_PI);
430 }
431 else if (arc < pi_4)
432 {
433 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
434 #if QT_VERSION >= 0x050b00
435 x0 = xpos + MusECore::qwtInt(double(fm.horizontalAdvance(label))
436 #else
437 x0 = xpos + MusECore::qwtInt(double(fm.width(label))
438 #endif
439 * ( arc - M_PI_4 ) * M_2_PI );
440 y0 = ypos;
441 }
442 else if (arc < pi_75)
443 {
444 x0 = xpos;
445 y0 = ypos + MusECore::qwtInt(double(fm.ascent() - 1)
446 * (arc - M_PI_4) * M_2_PI);
447 }
448 else
449 {
450 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
451 #if QT_VERSION >= 0x050b00
452 x0 = xpos - MusECore::qwtInt(double(fm.horizontalAdvance(label))
453 #else
454 x0 = xpos - MusECore::qwtInt(double(fm.width(label))
455 #endif
456 * ( arc - pi_75) * M_2_PI );
457 y0 = ypos + fm.ascent() - 1;
458 }
459 break;
460 case Top:
461 default:
462 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
463 #if QT_VERSION >= 0x050b00
464 x0 = tval - (fm.horizontalAdvance(label)-1) / 2;
465 #else
466 x0 = tval - (fm.width(label)-1) / 2;
467 #endif
468 y0 = d_yorg - d_majLen - d_vpad;
469 break;
470 }
471
472 p->save();
473
474 switch(d_textHighlightMode)
475 {
476 case TextHighlightNone:
477 p->setPen(palette.text().color());
478 p->drawText(x0, y0, label);
479 break;
480
481 case TextHighlightAlways:
482 p->setPen(palette.brightText().color());
483 p->drawText(x0, y0, label);
484 break;
485
486 case TextHighlightSplit:
487 if(val > curValue)
488 {
489 p->setPen(palette.text().color());
490 p->drawText(x0, y0, label);
491 }
492 else
493 {
494 p->setPen(palette.brightText().color());
495 p->drawText(x0, y0, label);
496 }
497 break;
498
499 case TextHighlightShadow:
500 // Text shadow:
501 p->setPen(Qt::black);
502 p->drawText(x0 + 1, y0 + 1, label);
503 // Text:
504 p->setPen(QColor(Qt::white).darker(120)); // Meh, not quite so bright,
505 p->drawText(x0, y0, label);
506 break;
507
508 case TextHighlightSplitAndShadow:
509 //fprintf(stderr, "ScaleDraw::drawLabel val:%.20f curValue:%.20f\n", val, curValue);
510 if(val > curValue)
511 {
512 //fprintf(stderr, " drawing normal\n");
513 p->setPen(palette.text().color());
514 p->drawText(x0, y0, label);
515 }
516 else
517 {
518 // Text shadow:
519 p->setPen(Qt::black);
520 p->drawText(x0 + 1, y0 + 1, label);
521 // Text:
522 //p->setPen(palette.brightText().color().darker(120)); // Meh, not quite so bright,
523 p->setPen(QColor(Qt::white).darker(120)); // Meh, not quite so bright,
524 p->drawText(x0, y0, label);
525 }
526 break;
527 }
528
529 p->restore();
530 }
531
532 //------------------------------------------------------------
533 //.-
534 //.F ScaleDraw::drawBackbone
535 // Draws the baseline of the scale
536 //
537 //
538 //.u Parameters
539 //.p QPainter *p
540 //
541 //------------------------------------------------------------
drawBackbone(QPainter * p,const QPalette &,double) const542 void ScaleDraw::drawBackbone(QPainter *p, const QPalette& /*palette*/, double /*curValue*/) const
543 {
544 int bw2;
545 int a1, a2;
546 bw2 = p->pen().width() / 2;
547
548
549 switch(d_orient)
550 {
551 case Left:
552 case InsideVertical:
553 p->drawLine(d_xorg - bw2, d_yorg, d_xorg - bw2, d_yorg + d_len - 1);
554 break;
555 case Right:
556 p->drawLine(d_xorg + bw2, d_yorg, d_xorg + bw2, d_yorg + d_len - 1);
557 break;
558 case Round:
559
560 a1 = MusECore::qwtMin(i1(), i2()) - 90 * 16;
561 a2 = MusECore::qwtMax(i1(), i2()) - 90 * 16;
562
563 p->drawArc(d_xorg, d_yorg, d_len,
564 d_len,
565 -a2, a2 - a1 + 1); // counterclockwise
566
567 break;
568
569 case Top:
570 p->drawLine(d_xorg, d_yorg - bw2, d_xorg + d_len - 1, d_yorg-bw2);
571 break;
572 case Bottom:
573 p->drawLine(d_xorg, d_yorg+bw2, d_xorg + d_len - 1, d_yorg+bw2);
574 break;
575 case InsideHorizontal:
576 p->drawLine(d_xorg, d_majLen + d_vpad, d_xorg + d_len - 1, d_majLen + d_vpad);
577 break;
578 default:
579 p->drawLine(d_xorg, d_yorg, d_xorg + d_len - 1, d_yorg);
580 break;
581 }
582
583 }
584
585
586 //------------------------------------------------------------
587 //
588 //.F ScaleDraw::setGeometry
589 // Specify the geometry of the scale
590 //
591 //
592 //.u Parameters
593 //.p int xorigin -- x coordinate of the origin
594 // int yorigin -- y coordinate of the origin
595 // int length -- length or diameter of the scale
596 // Orientation o -- The orientation
597 //
598 //.u Description
599 //
600 // The parameters xorigin, yorigin and length have different meanings,
601 // dependent on the
602 // orientation:
603 //.t
604 // ScaleDraw::Left -- The origin is the topmost point of the
605 // baseline. The baseline is a vertical line with the
606 // specified length. Scale marks and labels are drawn
607 // at the left of the baseline.
608 //
609 // ScaleDraw::Right -- The origin is the topmost point of the
610 // baseline. The baseline is a vertical line with the
611 // specified length. Scale marks and labels are drawn
612 // at the right of the baseline.
613 //
614 // ScaleDraw::Top -- The origin is the leftmost point of the
615 // baseline. The baseline is a horizontal line with the
616 // specified length. Scale marks and labels are drawn
617 // above the baseline.
618 //
619 // ScaleDraw::Bottom -- The origin is the leftmost point of the
620 // baseline. The baseline is a horizontal line with the
621 // specified length. Scale marks and labels are drawn
622 // below the baseline.
623 //
624 // ScaleDraw::Round -- The origin is the top left corner of the
625 // bounding rectangle of the baseline circle. The baseline
626 // is the segment of a circle with a diameter of the specified length.
627 // Scale marks and labels are drawn outside the baseline
628 // circle.
629 //
630 //------------------------------------------------------------
setGeometry(int xorigin,int yorigin,int length,OrientationX o)631 void ScaleDraw::setGeometry(int xorigin, int yorigin, int length, OrientationX o)
632 {
633
634 d_xorg = xorigin;
635 d_yorg = yorigin;
636 d_radius = double(length) * 0.5;
637 d_xCenter = double(xorigin) + double(length) * 0.5;
638 d_yCenter = double(yorigin) + double(length) * 0.5;
639
640 if (length > minLen)
641 d_len = length;
642 else
643 d_len = minLen;
644
645 d_orient = o;
646
647 switch(d_orient)
648 {
649 case Left:
650 case Right:
651 case InsideVertical:
652 setIntRange(d_yorg + d_len - 1, d_yorg);
653 break;
654 case Round:
655 setIntRange(d_minAngle, d_maxAngle);
656 break;
657 case Top:
658 case Bottom:
659 case InsideHorizontal:
660 setIntRange(d_xorg, d_xorg + d_len - 1);
661 break;
662 }
663 }
664
665 //------------------------------------------------------------
666 //
667 //.F ScaleDraw::maxWidth
668 // Return the maximum width of the scale for a specified QPainter
669 //
670 //.u Syntax
671 //.f int ScaleDraw::maxWidth(QPainter *p, int penWidth)
672 //
673 //.u Parameters
674 //.p const QFontMetrics& fm -- font metrics used for calculations
675 // bool worst -- if TRUE, assume the worst possible case. If FALSE,
676 // calculate the real maximum width, which is more
677 // CPU intensive.
678 // int penWidth -- the width of the pen that will be used to draw the scale
679 //
680 //------------------------------------------------------------
maxWidth(const QFontMetrics & fm,bool worst,int penWidth) const681 int ScaleDraw::maxWidth(const QFontMetrics& fm, bool worst, int penWidth) const
682 {
683 return maxLabelWidth(fm,worst) + scaleWidth(penWidth);
684 }
685
686 //------------------------------------------------------------
687 //
688 //.F ScaleDraw::maxHeight
689 // Return the maximum height of the scale for the
690 // specified painter
691 //
692 //.u Syntax
693 //.f int ScaleDraw::maxHeight(QPainter *p)
694 //
695 //.u Parameters
696 //.p const QFontMetrics& fm -- font metrics used for calculations
697 // int penWidth -- the width of the pen that will be used to draw the scale
698 //
699 //------------------------------------------------------------
maxHeight(const QFontMetrics & fm,int) const700 int ScaleDraw::maxHeight(const QFontMetrics& fm, int /*penWidth*/) const
701 {
702 int rv = 0;
703 switch (d_orient)
704 {
705 case Top:
706 case Bottom:
707 case Round:
708 case InsideHorizontal:
709 //rv = penWidth + d_vpad + d_majLen + fm.height();
710 rv = 2 * d_vpad + d_majLen + fm.ascent();
711 break;
712 case Left:
713 case Right:
714 case InsideVertical:
715 //rv = d_len + ((fm.height() + 1) / 2);
716 rv = d_len + ((fm.ascent() + 1) / 2);
717 break;
718 }
719
720 return rv;
721
722 }
723
724 //------------------------------------------------------------
725 //
726 //.F ScaleDraw:maxBoundingRect
727 // Return the maximum bounding rectangle of the scale
728 // for a specified painter
729 //
730 //.u Parameters
731 //.p const QFontMetrics& fm -- font metrics used for calculations
732 //
733 //.u Description
734 // The bounding rectangle is not very exact for round scales
735 // with strange angle ranges.
736 //
737 //------------------------------------------------------------
maxBoundingRect(const QFontMetrics & fm) const738 QRect ScaleDraw::maxBoundingRect(const QFontMetrics& fm) const
739 {
740 int i, wl; //,wmax;
741 int a, ar, amin, amax;
742 double arc;
743
744 QRect r;
745
746 wl = maxLabelWidth(fm, true);
747
748 switch(d_orient)
749 {
750 case Left:
751
752 r = QRect( d_xorg - d_hpad - d_majLen - wl,
753 d_yorg - fm.ascent(),
754 d_majLen + d_hpad + wl,
755 d_len + fm.height());
756 break;
757
758 case Right:
759
760 r = QRect( d_xorg,
761 d_yorg - fm.ascent(),
762 d_majLen + d_hpad + wl,
763 d_len + fm.height());
764 break;
765
766 case Top:
767
768 r = QRect ( d_xorg - wl / 2,
769 d_yorg - d_majLen - fm.ascent(),
770 d_len + wl,
771 d_majLen + d_vpad + fm.ascent());
772 break;
773
774 case Bottom:
775
776 r = QRect ( d_xorg - wl / 2,
777 d_yorg,
778 d_len + wl,
779 d_majLen + d_vpad + fm.height());
780 break;
781
782 case Round:
783
784 amin = 2880;
785 amax = 0;
786 ar = 0;
787
788 for (i=0; i< d_scldiv.majCnt(); i++)
789 {
790 a = transform(d_scldiv.majMark(i));
791
792 while (a > 2880) a -= 5760;
793 while (a < - 2880) a += 5760;
794
795 ar = MusECore::qwtAbs(a);
796
797 if (ar < amin) amin = ar;
798 if (ar > amax) amax = ar;
799
800 }
801
802 for (i=0; i< d_scldiv.minCnt(); i++)
803 {
804 a = transform(d_scldiv.majMark(i));
805
806 while (a > 2880) a -= 5760;
807 while (a < - 2880) a += 5760;
808
809 ar = MusECore::qwtAbs(a);
810
811 if (ar < amin) amin = ar;
812 if (ar > amax) amax = ar;
813 }
814
815 arc = double(amin) / 16.0 * M_PI / 180.0;
816 r.setTop(MusECore::qwtInt(d_yCenter - (d_radius + double(d_majLen + d_vpad)) * cos(arc))
817 + fm.ascent() );
818
819 arc = double(amax) / 16.0 * M_PI / 180.0;
820 r.setBottom(MusECore::qwtInt(d_yCenter - (d_radius + double(d_majLen + d_vpad)) * cos(arc))
821 + fm.height() );
822
823 //wmax = d_len + d_majLen + d_hpad + wl; DELETETHIS
824
825 r.setLeft(d_xorg - d_majLen - d_hpad - wl);
826 r.setWidth(d_len + 2*(d_majLen + d_hpad + wl));
827 break;
828
829 case InsideHorizontal:
830 case InsideVertical:
831 return r;
832 break;
833 }
834
835 return r;
836
837 }
838
839 //------------------------------------------------------------
840 //
841 //.F ScaleDraw::setAngleRange
842 // Adjust the baseline circle segment for round scales.
843 //
844 //.u Syntax
845 //.f void ScaleDraw::setAngleRange(double angle1, double angle2)
846 //
847 //.u Parameters
848 //.p double angle1, double angle2
849 // boundaries of the angle interval in degrees.
850 //
851 //.u Description
852 // The baseline will be drawn from min(angle1,angle2) to max(angle1, angle2).
853 // The settings have no effect if the scale orientation is not set to
854 // ScaleDraw::Round. The default setting is [ -135, 135 ].
855 // An angle of 0 degrees corresponds to the 12 o'clock position,
856 // and positive angles count in a clockwise direction.
857 //
858 //.u Note
859 //.i
860 // -- The angle range is limited to [-360, 360] degrees. Angles exceeding
861 // this range will be clipped.
862 // -- For angles more than 359 degrees above or below min(angle1, angle2),
863 // scale marks will not be drawn.
864 // -- If you need a counterclockwise scale, use @QwtScaleDiv::setRange (1)@
865 // or @QwtScaleDiv::setRange (2)@.
866 //------------------------------------------------------------
setAngleRange(double angle1,double angle2)867 void ScaleDraw::setAngleRange(double angle1, double angle2)
868 {
869 int amin, amax;
870
871 angle1 = MusECore::qwtLim(angle1, -360.0, 360.0);
872 angle2 = MusECore::qwtLim(angle2, -360.0, 360.0);
873 amin = int(rint(MusECore::qwtMin(angle1, angle2) * 16.0));
874 amax = int(rint(MusECore::qwtMax(angle1, angle2) * 16.0));
875
876 if (amin == amax)
877 {
878 amin -= 1;
879 amax += 1;
880 }
881
882 d_minAngle = amin;
883 d_maxAngle = amax;
884 setIntRange(d_minAngle, d_maxAngle);
885 }
886
887
888 //------------------------------------------------------------
889 //
890 //.F ScaleDraw::setLabelFormat
891 // Set the number format for the major scale labels
892 //
893 //.u Syntax
894 //.f void ScaleDraw::setLabelFormat(char f, int prec)
895 //
896 //.u Parameters
897 //.p char f -- format character
898 // int prec -- precision
899 //
900 //.u Description
901 // Format character and precision have the same meaning as for the
902 // QString class, with one exception: Special format 'M' (Metric suffix G M K)
903 //
904 //
905 //.u See also
906 // QString::setNum in the Qt manual
907 //
908 //------------------------------------------------------------
setLabelFormat(char f,int prec)909 void ScaleDraw::setLabelFormat(char f, int prec)
910 {
911 d_fmt = f;
912 d_prec = prec;
913 }
914
915 //------------------------------------------------------------
916 //
917 //.F ScaleDraw::maxLabelWidth
918 // Return the maximum width of a label
919 //
920 //.u Syntax
921 //.f int ScaleDraw::maxLabelWidth(QPainter *p, int worst)
922 //
923 //.u Parameters
924 //.p const QFontMetrics& fm -- font metrics used for calculations
925 // int worst -- If TRUE, take the worst case. If FALSE, take
926 // the actual width of the largest label.
927 //
928 //------------------------------------------------------------
maxLabelWidth(const QFontMetrics & fm,bool worst) const929 int ScaleDraw::maxLabelWidth(const QFontMetrics& fm, bool worst) const
930 {
931 int i,rv = 0;
932 double val;
933 QString s;
934
935 if (worst) // worst case
936 {
937 s = composeLabelText(WorstCase, d_fmt, d_prec);
938 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
939 #if QT_VERSION >= 0x050b00
940 rv = fm.horizontalAdvance(s);
941 #else
942 rv = fm.width(s);
943 #endif
944 }
945 else // actual width
946 {
947 for (i=0;i<d_scldiv.majCnt(); i++)
948 {
949 val = d_scldiv.majMark(i);
950 // correct rounding errors if val = 0
951 if ((!d_scldiv.logScale()) && (MusECore::qwtAbs(val) < step_eps * MusECore::qwtAbs(d_scldiv.majStep())))
952 val = 0.0;
953 s = composeLabelText(val, d_fmt, d_prec);
954 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
955 #if QT_VERSION >= 0x050b00
956 rv = MusECore::qwtMax(rv,fm.horizontalAdvance(s));
957 #else
958 rv = MusECore::qwtMax(rv,fm.width(s));
959 #endif
960 }
961 }
962 return rv;
963 }
964
965 //------------------------------------------------------------
966 //
967 //.F ScaleDraw::scaleWidth
968 // Return the maximum width of the scale (minus the labels)
969 //
970 //.u Syntax
971 //.f int ScaleDraw::scaleWidth(int penWidth)
972 //
973 //.u Parameters
974 // int penWidth -- the width of the pen that will be used to draw the scale
975 //------------------------------------------------------------
scaleWidth(int penWidth) const976 int ScaleDraw::scaleWidth(int penWidth) const
977 {
978 switch (d_orient)
979 {
980 case Left:
981 case Right:
982 case InsideVertical:
983 return penWidth + d_hpad + d_majLen;
984 break;
985 case Round:
986 return penWidth + d_vpad + d_majLen;
987 break;
988 case Top:
989 case Bottom:
990 case InsideHorizontal:
991 return d_len;
992 break;
993 }
994 return d_len;
995 }
996
997 //------------------------------------------------------------
998 //
999 //.F ScaleDraw::scaleDiv
1000 // Return the scale division
1001 //
1002 //.u Syntax
1003 //.f const QwtScaleDiv & ScaleDraw::scaleDiv() const
1004 //
1005 //.u See also
1006 // @^QwtScaleDiv@
1007 //------------------------------------------------------------
1008
1009 //------------------------------------------------------------
1010 //
1011 //.F ScaleDraw::orientation
1012 // Return the orientation
1013 //
1014 //.u Syntax
1015 //.f int ScaleDraw::orientation() const
1016 //
1017 //.u See also
1018 // @ScaleDraw::setGeometry@
1019 //
1020 //------------------------------------------------------------
1021
1022 } // namespace MusEGui
1023
1024
1025