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