1 //=========================================================
2 //  MusE
3 //  Linux Music Editor
4 //  $Id: ./muse/widgets/slider.cpp $
5 //
6 //  Copyright (C) 1999-2011 by Werner Schweer and others
7 //  (C) Copyright 2011 Orcan Ogetbil (ogetbilo at sf.net)
8 //  (C) Copyright 2015-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 #include "muse_math.h"
26 #include "mmath.h"
27 
28 #include <QPainterPath>
29 #include <QMouseEvent>
30 
31 #include "utils.h"
32 #include "slider.h"
33 
34 // For debugging output: Uncomment the fprintf section.
35 #define DEBUG_SLIDER(dev, format, args...) // fprintf(dev, format, ##args);
36 
37 
38 namespace MusEGui {
39 
40 //-------------------------------------------------------------
41 //  Slider - The Slider Widget
42 //
43 //  Slider is a slider widget which operates on an interval
44 //  of type double. Slider supports different layouts as
45 //  well as a scale.
46 //------------------------------------------------------------
47 
48 //------------------------------------------------------------
49 //.F  Slider::Slider
50 //
51 //    Constructor
52 //
53 //.u  Syntax:
54 //.f  Slider::Slider(QWidget *parent, const char *name, Orientation orient = Horizontal, ScalePos scalePos = None, int bgStyle = BgTrough)
55 //
56 //.u  Parameters
57 //.p
58 //  QWidget *parent --  parent widget
59 //  const char *name -- The Widget's name. Default = 0.
60 //  Orientation Orient -- Orientation of the slider. Can be Slider::Horizontal
61 //        or Slider::Vertical.
62 //                    Defaults to Horizontal.
63 //  ScalePos scalePos --  Position of the scale.  Can be Slider::None,
64 //        Slider::Left, Slider::Right, Slider::Top,
65 //        or Slider::Bottom. Defaults to Slider::None.  !!! CURRENTLY only Slider::None supported - oget 20110913
66 //  QColor fillcolor -- the color used to fill in the full side
67 //        of the Slider. If fillColor is invalid (default) it will draw with the palette highlight colour.
68 //------------------------------------------------------------
69 
Slider(QWidget * parent,const char * name,Qt::Orientation orient,ScalePos scalePos,int grooveWidth,QColor fillColor,ScaleDraw::TextHighlightMode textHighlightMode,QColor handleColor)70 Slider::Slider(QWidget *parent, const char *name,
71                Qt::Orientation orient,
72                ScalePos scalePos,
73                int grooveWidth,
74                QColor fillColor,
75                ScaleDraw::TextHighlightMode textHighlightMode,
76                QColor handleColor)
77       : SliderBase(parent,name), d_scalePos(scalePos), d_grooveWidth(grooveWidth),
78         d_fillColor(fillColor), d_handleColor(handleColor)
79       {
80       setPagingButtons(Qt::RightButton);
81 
82       d_thumbLength = 16;
83       d_thumbHalf = 8;
84       d_thumbWidth = 16;
85       d_fillThumb = true;
86       d_fillEmptySide = true;
87       d_frame = false;
88 
89       d_radius = 4;
90       d_radiusHandle = 2;
91       d_useGradient = true;
92 
93       d_scaleDist   = 4;
94       d_scaleStep   = 0.0;
95       d_xMargin     = 0;
96       d_yMargin     = 0;
97       d_mMargin    = 1;
98 
99       horizontal_hint = 40;
100       vertical_hint = 40;
101 
102       // set to sane values to avoid erratic size hint
103       //  calculation -> drawing problems (kybos)
104       if (orient == Qt::Vertical)
105       {
106           d_sliderRect.setRect(0, 0, 20, 100);
107       }
108       else
109       {
110           d_sliderRect.setRect(0, 0, 100, 20);
111       }
112 
113       setOrientation(orient);
114       d_scale.setTextHighlightMode(textHighlightMode);
115       }
116 
117 //------------------------------------------------------------
118 //.F  Slider::setSizeHint
119 //------------------------------------------------------------
120 
setSizeHint(uint w,uint h)121 void Slider::setSizeHint(uint w, uint h)
122       {
123       horizontal_hint = w;
124       vertical_hint = h;
125       }
126 
127 //------------------------------------------------------------
128 //.F  Slider::~Slider
129 //    Destructor
130 //.u  Syntax
131 //.f  Slider::~Slider()
132 //------------------------------------------------------------
133 
~Slider()134 Slider::~Slider()
135       {
136       }
137 
138 //----------------------------------------------------
139 //
140 //.F  Slider::setThumbLength
141 //
142 //    Set the slider's thumb length
143 //
144 //.u  Syntax
145 //  void Slider::setThumbLength(int l)
146 //
147 //.u  Parameters
148 //.p  int l   --    new length
149 //
150 //-----------------------------------------------------
setThumbLength(int l)151 void Slider::setThumbLength(int l)
152 {
153 //     d_thumbLength = MusECore::qwtMax(l,8);
154     d_thumbLength = l;
155     d_thumbHalf = d_thumbLength / 2;
156     resize(size());
157 }
158 
159 //------------------------------------------------------------
160 //
161 //.F  Slider::setThumbWidth
162 //  Change the width of the thumb
163 //
164 //.u  Syntax
165 //.p  void Slider::setThumbWidth(int w)
166 //
167 //.u  Parameters
168 //.p  int w -- new width
169 //
170 //------------------------------------------------------------
setThumbWidth(int w)171 void Slider::setThumbWidth(int w)
172 {
173     d_thumbWidth = MusECore::qwtMax(w,4);
174     resize(size());
175 }
176 
177 
178 //------------------------------------------------------------
179 //.-
180 //.F  Slider::scaleChange
181 //  Notify changed scale
182 //
183 //.u  Syntax
184 //.f  void Slider::scaleChange()
185 //
186 //.u  Description
187 //  Called by QwtScaledWidget
188 //
189 //------------------------------------------------------------
scaleChange()190 void Slider::scaleChange()
191 {
192     if (!hasUserScale())
193        d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor);
194     update();
195 }
196 
197 
198 //------------------------------------------------------------
199 //.-
200 //.F  Slider::fontChange
201 //  Notify change in font
202 //
203 //.u  Syntax
204 //.f   Slider::fontChange(const QFont &oldFont)
205 //
206 //------------------------------------------------------------
fontChange(const QFont &)207 void Slider::fontChange(const QFont & /*oldFont*/)
208 {
209 //     repaint();
210     update();
211 }
212 
drawThumb(QPainter * p,const QRect & r)213 void Slider::drawThumb(QPainter *p, const QRect &r)
214 {
215   p->setRenderHint(QPainter::Antialiasing);
216 
217   QColor thumb_edge;
218   QColor thumb_center;
219   const QPalette& pal = palette();
220   if (d_handleColor.isValid()) {
221       thumb_edge = d_handleColor;
222       thumb_center = d_handleColor.lighter();
223   } else {
224       thumb_edge = pal.dark().color();
225       thumb_center = pal.mid().color();
226   }
227   QLinearGradient thumbGrad;
228   thumbGrad.setColorAt(0, thumb_edge);
229   thumbGrad.setColorAt(0.5, thumb_center);
230   thumbGrad.setColorAt(1, thumb_edge);
231 
232   const double rpos = (value(ConvertNone) - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone));
233 
234   if(d_orient == Qt::Horizontal)
235   {
236     int crh, thh;
237 //     if(d_scalePos == InsideHorizontal)
238 //     {
239 //       crh = height() - r.y() - d_yMargin - 2 * d_mMargin;
240 //       thh = height() - r.y() - d_yMargin - d_mMargin;
241 //     }
242 //     else
243     {
244       crh = r.height() - 2 * d_mMargin;
245       thh = r.height();
246     }
247 
248     const QRect cr(r.x(),
249                    r.y() + d_mMargin,
250                    r.width(),
251                    //r.height() - 2*d_mMargin);
252                    crh);
253 
254     const int dist1 = int(double(cr.width() - d_thumbLength) * rpos);
255     const int ipos =  cr.x() + dist1;
256     markerPos = ipos + d_thumbHalf;
257 
258     //
259     //  Draw thumb
260     //
261 
262     QPainterPath thumb_rect = MusECore::roundedPath(ipos, r.y(),
263                                           //d_thumbLength, r.height(),
264                                           d_thumbLength, thh,
265                                           d_radiusHandle, d_radiusHandle,
266                                           (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight | MusECore::CornerLowerLeft | MusECore::CornerLowerRight) );
267 
268 //     thumbGrad.setStart(QPointF(0, cr.y()));
269 //     thumbGrad.setFinalStop(QPointF(0, cr.y() + cr.height()));
270     thumbGrad.setStart(QPointF(ipos, 0));
271     thumbGrad.setFinalStop(QPointF(ipos + d_thumbLength, 0));
272 
273     if(d_fillThumb)
274       p->fillPath(thumb_rect, QBrush(thumbGrad));
275     else
276     {
277       p->setPen(pal.shadow().color());
278       p->drawPath(thumb_rect);
279     }
280 
281     // center line
282     p->fillRect(ipos + d_thumbHalf, cr.y(), 1, cr.height(), pal.dark().color());
283   }
284   else
285   {
286     int crw, thw;
287 //     if(d_scalePos == InsideVertical)
288 //     {
289 //       crw = width() - r.x() - d_xMargin - 2 * d_mMargin;
290 //       thw = width() - r.x() - d_xMargin - d_mMargin;
291 //     }
292 //     else
293     {
294       crw = r.width() - 2 * d_mMargin;
295       thw = r.width();
296     }
297 
298     const QRect cr(r.x() + d_mMargin,
299                    r.y(),
300                    //r.width() - 2*d_mMargin,
301                    crw,
302                    r.height());
303 
304     const int dist1 = int(double(cr.height() - d_thumbLength) * (1.0 - rpos));
305     const int ipos = cr.y() + dist1;
306     markerPos = ipos + d_thumbHalf;
307 
308     //
309     //  Draw thumb
310     //
311 
312     QPainterPath thumb_rect = MusECore::roundedPath(r.x(), ipos,
313                                           //r.width(), d_thumbLength,
314                                           thw, d_thumbLength,
315                                           d_radiusHandle, d_radiusHandle,
316                                           (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight | MusECore::CornerLowerLeft | MusECore::CornerLowerRight) );
317 
318 //     thumbGrad.setStart(QPointF(cr.x(), 0));
319 //     thumbGrad.setFinalStop(QPointF(cr.x() + cr.width(), 0));
320     thumbGrad.setStart(QPointF(0, ipos));
321     thumbGrad.setFinalStop(QPointF(0, ipos + d_thumbLength));
322 
323     if(d_fillThumb)
324       p->fillPath(thumb_rect, QBrush(thumbGrad));
325     else
326     {
327       p->setPen(pal.shadow().color());
328       p->drawPath(thumb_rect);
329     }
330 
331     // center line
332     p->fillRect(cr.x(), ipos + d_thumbHalf, cr.width(), 1, pal.dark().color());
333   }
334 
335 }
336 
337 //------------------------------------------------------------
338 //    drawSlider
339 //     Draw the slider into the specified rectangle.
340 //------------------------------------------------------------
341 
drawSlider(QPainter * p,const QRect & r)342 void Slider::drawSlider(QPainter *p, const QRect &r)
343 {
344     p->setRenderHint(QPainter::Antialiasing);
345 
346     const QPalette& pal = palette();
347 
348     // for the full side
349     const double rpos = (value(ConvertNone)  - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone));
350 
351     QColor f_mask_min(d_fillColor.isValid() ? d_fillColor : pal.highlight().color());
352     QColor f_mask_max(f_mask_min);
353     if (d_useGradient) {
354         f_mask_min.setAlpha(40);
355         //f_mask_max.setAlpha(200);
356         f_mask_max.setAlpha(255);
357     }
358     QLinearGradient f_mask;
359 
360     if (d_orient == Qt::Horizontal)
361         {
362 
363         const QRect cr(r.x(),
364                        r.y() + r.height() / 2 - d_grooveWidth / 2,
365                        r.width(),
366                        d_grooveWidth);
367 
368         QPainterPath clip_path;
369         clip_path.addRoundedRect(cr.x() + d_thumbHalf, cr.y(),
370                                  cr.width() - d_thumbLength, r.height(),
371                                  d_radius, d_radius);
372         p->setClipPath(clip_path);
373 
374         //
375         // Draw background
376         //
377 
378         const int dist1 = int(double(cr.width() - (d_fillThumb ? d_thumbLength : d_thumbHalf)) * rpos);
379         const int ipos =  cr.x() + dist1;
380         markerPos = ipos + d_thumbHalf;
381 
382         //
383         // Draw groove empty right side
384         //
385 
386         if(d_fillEmptySide)
387         {
388           QPainterPath e_rect = MusECore::roundedPath(ipos + (d_fillThumb ? d_thumbLength : d_thumbHalf), cr.y(),
389                                             cr.width() - (d_fillThumb ? d_thumbLength : d_thumbHalf) - dist1, cr.height(),
390                                             d_radius, d_radius, (MusECore::Corner) (MusECore::CornerUpperRight | MusECore::CornerLowerRight) );
391 
392           p->fillPath(e_rect, f_mask_min);
393         }
394 
395 
396         //
397         // Draw groove full left side
398         //
399 
400         f_mask.setColorAt(0, f_mask_min);
401         f_mask.setColorAt(1, f_mask_max);
402         f_mask.setStart(QPointF(cr.x(), cr.y()));
403         f_mask.setFinalStop(QPointF(cr.x() + ipos + (d_fillThumb ? 0 : d_thumbHalf), cr.y()));
404 
405         QPainterPath f_rect = MusECore::roundedPath(cr.x(), cr.y(),
406                                           ipos + (d_fillThumb ? 0 : d_thumbHalf), cr.height(),
407                                           d_radius, d_radius,
408                                           (MusECore::Corner) (MusECore::CornerLowerLeft | MusECore::CornerUpperLeft) );
409 
410         p->fillPath(f_rect, QBrush(f_mask));
411         p->setClipping(false);
412         }
413     else // (d_orient == Qt::Vertical)
414         {
415         const QRect cr(r.x() + r.width() / 2 - d_grooveWidth / 2,
416                        r.y(),
417                        d_grooveWidth,
418                        r.height());
419 
420         QPainterPath clip_path;
421         clip_path.addRoundedRect(cr.x(), cr.y() + d_thumbHalf,
422                                  cr.width(), r.height() - d_thumbLength,
423                                  d_radius, d_radius);
424         p->setClipPath(clip_path);
425 
426         //
427         // Draw background
428         //
429 
430         const int dist1 = int(double(cr.height() - (d_fillThumb ? d_thumbLength : d_thumbHalf)) * (1.0 - rpos));
431         const int ipos = cr.y() + dist1;
432         markerPos = ipos + d_thumbHalf;
433 
434         //
435         // Draw groove empty upper filling
436         //
437 
438         if(d_fillEmptySide)
439         {
440           QPainterPath e_rect = MusECore::roundedPath(cr.x(), cr.y(),
441                                             cr.width(), ipos + (d_fillThumb ? 0 : d_thumbHalf),
442                                             d_radius, d_radius,
443                                             (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight) );
444 
445           p->fillPath(e_rect, QBrush(f_mask_min));
446         }
447 
448         //
449         // Draw groove lower filling mask
450         //
451 
452         f_mask.setColorAt(0, f_mask_max);
453         f_mask.setColorAt(1, f_mask_min);
454         f_mask.setStart(QPointF(cr.x(), markerPos));
455         f_mask.setFinalStop(QPointF(cr.x(), cr.y() + cr.height()));
456 
457         QPainterPath f_rect = MusECore::roundedPath(cr.x(), ipos + (d_fillThumb ? d_thumbLength : d_thumbHalf),
458                                           cr.width(), cr.height() - (d_fillThumb ? d_thumbLength : d_thumbHalf) - dist1,
459                                           d_radius, d_radius, (MusECore::Corner) (MusECore::CornerLowerLeft | MusECore::CornerLowerRight) );
460 
461         p->fillPath(f_rect, QBrush(f_mask));
462         p->setClipping(false);
463 
464     if (d_frame) {
465         p->setPen(d_frameColor);
466         p->drawPath(clip_path);
467     }
468     }
469 }
470 
471 //------------------------------------------------------------
472 //.-
473 //.F  Slider::getValue
474 //  Determine the value corresponding to a specified
475 //  mouse location.
476 //
477 //.u  Syntax
478 //.f     double Slider::getValue(const QPoint &p)
479 //
480 //.u  Parameters
481 //.p  const QPoint &p --
482 //
483 //.u  Description
484 //  Called by SliderBase
485 //------------------------------------------------------------
getValue(const QPoint & p)486 double Slider::getValue( const QPoint &p)
487 {
488   double rv;
489   const QRect r = d_sliderRect;
490   const double val = value(ConvertNone);
491 
492   if(borderlessMouse() && d_scrollMode != ScrDirect)
493   {
494     DEBUG_SLIDER(stderr, "Slider::getValue value:%.20f p x:%d y:%d step:%.20f x change:%.20f\n",
495                          val, p.x(), p.y(), step(), p.x() * step());
496     if(d_orient == Qt::Horizontal)
497       return val + p.x() * step();
498     else
499       return val - p.y() * step();
500   }
501 
502   const double min = minValue(ConvertNone);
503   const double max = maxValue(ConvertNone);
504   const double drange = max - min;
505 
506   if(d_orient == Qt::Horizontal)
507   {
508     if(r.width() <= d_thumbLength)
509       rv = 0.5 * (min + max);
510     else
511     {
512       const double dpos = double(p.x() - r.x() - d_thumbHalf);
513       const double dwidth = double(r.width() - d_thumbLength);
514       rv  =  min + rint(drange * dpos / dwidth / step()) * step();
515     }
516   }
517   else
518   {
519     if(r.height() <= d_thumbLength)
520       rv = 0.5 * (min + max);
521     else
522     {
523       const double dpos = double(p.y() - r.y() - d_thumbHalf);
524       double dheight = double(r.height() - d_thumbLength);
525       rv =  min + rint(drange * (1.0 - dpos / dheight) / step()) * step();
526     }
527   }
528   return(rv);
529 }
530 
531 //------------------------------------------------------------
532 //
533 //.F  Slider::moveValue
534 //  Determine the value corresponding to a specified mouse movement.
535 //
536 //.u  Syntax
537 //.f  void Slider::moveValue(const QPoint &deltaP, bool fineMode)
538 //
539 //.u  Parameters
540 //.p  const QPoint &deltaP -- Change in position
541 //.p  bool fineMode -- Fine mode if true, coarse mode if false.
542 //
543 //.u  Description
544 //    Called by SliderBase
545 //    Coarse mode (the normal mode) maps pixels to values depending on range and width,
546 //     such that the slider follows the mouse cursor. Fine mode maps one step() value per pixel.
547 //------------------------------------------------------------
moveValue(const QPoint & deltaP,bool fineMode)548 double Slider::moveValue(const QPoint &deltaP, bool fineMode)
549 {
550   double rv;
551   const QRect r = d_sliderRect;
552 
553   const double val = value(ConvertNone);
554 
555   if((fineMode || borderlessMouse()) && d_scrollMode != ScrDirect)
556   {
557     DEBUG_SLIDER(stderr, "Slider::moveValue value:%.20f p x:%d y:%d step:%.20f x change:%.20f\n",
558                          val, deltaP.x(), deltaP.y(), step(), deltaP.x() * step());
559 
560     double newval;
561     if(d_orient == Qt::Horizontal)
562       newval = val + deltaP.x() * step();
563     else
564       newval = val - deltaP.y() * step();
565     d_valAccum = newval; // Reset.
566     return newval;
567   }
568 
569   const double min = minValue(ConvertNone);
570   const double max = maxValue(ConvertNone);
571   const double drange = max - min;
572 
573   if(d_orient == Qt::Horizontal)
574   {
575     if(r.width() <= d_thumbLength)
576       rv = 0.5 * (min + max);
577     else
578     {
579       const double dpos = double(deltaP.x());
580       const double dwidth = double(r.width() - d_thumbLength);
581       const double dval_diff = (drange * dpos) / dwidth;
582       d_valAccum += dval_diff;
583       rv = rint(d_valAccum / step()) * step();
584 
585       DEBUG_SLIDER(stderr, "Slider::moveValue Horizontal value:%.20f p dx:%d dy:%d drange:%.20f step:%.20f dval_diff:%.20f d_valAccum:%.20f rv:%.20f\n",
586                        val, deltaP.x(), deltaP.y(), drange, step(), dval_diff, d_valAccum, rv);
587     }
588   }
589   else
590   {
591     if(r.height() <= d_thumbLength)
592       rv = 0.5 * (min + max);
593     else
594     {
595       const double dpos = double(-deltaP.y());
596       const double dheight = double(r.height() - d_thumbLength);
597       const double dval_diff = (drange * dpos) / dheight;
598       d_valAccum += dval_diff;
599       rv = rint(d_valAccum / step()) * step();
600 
601       DEBUG_SLIDER(stderr, "Slider::moveValue Vertical value:%.20f p dx:%d dy:%d drange:%.20f step:%.20f dval_diff:%.20f d_valAccum:%.20f rv:%.20f\n",
602                        val, deltaP.x(), deltaP.y(), drange, step(), dval_diff, d_valAccum, rv);
603     }
604   }
605   return(rv);
606 }
607 
608 //------------------------------------------------------------
609 //.-
610 //.F  Slider::getScrollMode
611 //  Determine scrolling mode and direction
612 //
613 //.u  Syntax
614 //.f   void Slider::getScrollMode( const QPoint &p, int &scrollMode, int &direction )
615 //
616 //.u  Parameters
617 //.p  const QPoint &p -- point
618 //
619 //.u  Description
620 //  Called by SliderBase
621 //
622 //------------------------------------------------------------
getScrollMode(QPoint & p,const Qt::MouseButton & button,const Qt::KeyboardModifiers & modifiers,int & scrollMode,int & direction)623 void Slider::getScrollMode( QPoint &p, const Qt::MouseButton &button, const Qt::KeyboardModifiers& modifiers, int &scrollMode, int &direction )
624 {
625   // If modifier or button is held, jump directly to the position at first.
626   // After handling it, the caller can change to SrcMouse scroll mode.
627   if(modifiers & Qt::ControlModifier || button == Qt::MidButton)
628   {
629     scrollMode = ScrDirect;
630     direction = 0;
631     return;
632   }
633 
634   if(borderlessMouse())
635   {
636     if(button != Qt::NoButton && d_sliderRect.contains(p))
637     {
638       scrollMode = ScrMouse;
639       direction = 0;
640       return;
641     }
642   }
643   else
644   {
645     if(cursorHoming() && button == Qt::LeftButton)
646     {
647       if(d_sliderRect.contains(p))
648       {
649         DEBUG_SLIDER(stderr, "Slider::getScrollMode cursor homing + left button: ScrMouse\n");
650         scrollMode = ScrMouse;
651         direction = 0;
652 
653         int mp = 0;
654         QRect cr;
655         QPoint cp;
656         int ipos,dist1;
657         double rpos;
658 
659         cr = d_sliderRect;
660 
661         rpos = (value(ConvertNone)  - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone));
662 
663         if(d_orient == Qt::Horizontal)
664         {
665           dist1 = int(double(cr.width() - d_thumbLength) * rpos);
666           ipos =  cr.x() + dist1;
667           mp = ipos + d_thumbHalf;
668 
669           p.setX(mp);
670           cp = mapToGlobal( QPoint(mp, p.y()) );
671         }
672         else
673         {
674           dist1 = int(double(cr.height() - d_thumbLength) * (1.0 - rpos));
675           ipos = cr.y() + dist1;
676           mp = ipos + d_thumbHalf;
677           p.setY(mp);
678           cp = mapToGlobal( QPoint(p.x(), mp) );
679         }
680         cursor().setPos(cp.x(), cp.y());
681         return;
682       }
683     }
684     else
685     {
686       int currentPos;
687       if(d_orient == Qt::Horizontal)
688        currentPos = p.x();
689       else
690        currentPos = p.y();
691 
692       if(d_sliderRect.contains(p))
693       {
694         if((currentPos > markerPos - d_thumbHalf)
695             && (currentPos < markerPos + d_thumbHalf))
696         {
697           DEBUG_SLIDER(stderr, "Slider::getScrollMode ScrMouse\n");
698           scrollMode = ScrMouse;
699           direction = 0;
700           return;
701         }
702         else if(pagingButtons().testFlag(button))
703         {
704           DEBUG_SLIDER(stderr, "Slider::getScrollMode ScrPage\n");
705           scrollMode = ScrPage;
706           if (((currentPos > markerPos) && (d_orient == Qt::Horizontal))
707               || ((currentPos <= markerPos) && (d_orient != Qt::Horizontal)))
708             direction = 1;
709           else
710             direction = -1;
711           return;
712         }
713       }
714     }
715   }
716 
717   scrollMode = ScrNone;
718   direction = 0;
719 }
720 
721 //------------------------------------------------------------
722 //.F  Slider::paintEvent
723 //  Qt paint event
724 //
725 //.u  Syntax
726 //.f  void Slider::paintEvent(QPaintEvent *e)
727 //------------------------------------------------------------
728 
paintEvent(QPaintEvent *)729 void Slider::paintEvent(QPaintEvent* /*ev*/)
730 {
731   QPainter p(this);
732   if(d_grooveWidth != 0)
733     drawSlider(&p, d_sliderRect);
734 
735   if(d_thumbLength != 0)
736     drawThumb(&p, d_sliderRect);
737   if(d_scalePos != None)
738   {
739 //     p.fillRect(rect(), palette().window());
740     p.setRenderHint(QPainter::Antialiasing, false);
741     d_scale.draw(&p, palette(), value());
742   }
743 }
744 
adjustSize(const QSize & s)745 void Slider::adjustSize(const QSize& s)
746 {
747     const QFontMetrics fm = fontMetrics();
748     const int sliderWidth = d_thumbWidth;
749     // reposition slider
750     if(d_orient == Qt::Horizontal)
751     {
752       switch(d_scalePos)
753       {
754         case Top:
755             d_sliderRect.setRect(this->rect().x() + d_xMargin,
756               this->rect().y() + s.height() - 1
757               - d_yMargin - sliderWidth,
758               s.width() - 2 * d_xMargin,
759               sliderWidth);
760             d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf,
761               d_sliderRect.y() - d_scaleDist,
762               d_sliderRect.width() - d_thumbLength,
763               ScaleDraw::Top);
764             break;
765 
766         case Bottom:
767             d_sliderRect.setRect(this->rect().x() + d_xMargin,
768               this->rect().y() + d_yMargin,
769               s.width() - 2*d_xMargin,
770               sliderWidth);
771             d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf,
772               d_sliderRect.y() + d_sliderRect.height() +  d_scaleDist,
773               d_sliderRect.width() - d_thumbLength,
774               ScaleDraw::Bottom);
775             break;
776 
777         case InsideHorizontal:
778             d_sliderRect.setRect(this->rect().x() + d_xMargin,
779               this->rect().y() + s.height() - 1
780               - d_yMargin - sliderWidth,
781               s.width() - 2 * d_xMargin,
782               sliderWidth);
783             d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf,
784               //d_sliderRect.y() - d_scaleDist,
785               this->rect().y() + d_yMargin + d_scale.maxHeight(fm) + d_scaleDist,
786               d_sliderRect.width() - d_thumbLength,
787               ScaleDraw::InsideHorizontal);
788             break;
789 
790         default:
791             d_sliderRect.setRect(this->rect().x(), this->rect().x(),
792               s.width(), s.height());
793             break;
794       }
795     }
796     else // d_orient == Qt::Vertical
797     {
798       switch(d_scalePos)
799       {
800         case Left:
801             d_sliderRect.setRect(this->rect().x() + s.width()
802               - sliderWidth - 1 - d_xMargin,
803               this->rect().y() + d_yMargin,
804               sliderWidth,
805               s.height() - 2 * d_yMargin);
806             d_scale.setGeometry(d_sliderRect.x() - d_scaleDist,
807               d_sliderRect.y() + d_thumbHalf,
808               s.height() - d_thumbLength,
809               ScaleDraw::Left);
810             break;
811 
812         case Right:
813         {
814             d_sliderRect.setRect(this->rect().x() + d_xMargin,
815               this->rect().y() + d_yMargin,
816               sliderWidth,
817               s.height() - 2* d_yMargin);
818             d_scale.setGeometry(this->rect().x() + d_sliderRect.width()
819               + d_scaleDist,
820               d_sliderRect.y() + d_thumbHalf,
821               s.height() - d_thumbLength,
822               ScaleDraw::Right);
823             break;
824         }
825 
826         case InsideVertical:
827         {
828 //             d_sliderRect.setRect(this->rect().x() + s.width()
829 //               - sliderWidth - 1 - d_xMargin,
830 //             d_sliderRect.setRect(this->rect().x() + d_xMargin,
831 //             d_sliderRect.setRect(this->rect().x() + d_xMargin + d_scale.maxLabelWidth(fm, false) - sliderWidth,
832             const int mxlw = d_scale.maxLabelWidth(fm, false);
833             const int sclw = d_scale.scaleWidth();
834             const int sldw = mxlw > sliderWidth ? sliderWidth : mxlw;
835             const int sldoffs = mxlw > sliderWidth ? ((mxlw - sldw) / 2) : 0;
836             const int fh = fm.ascent() + 2;
837             const int fh2 = fh / 2;
838             const int margin = d_thumbLength > fh ? d_thumbLength : fh;
839             const int margin2 = d_thumbHalf > fh2 ? d_thumbHalf : fh2;
840             const int sldymargin = fh > d_thumbLength ? fh - d_thumbLength : 0;
841             const int sldymargin2 = fh2 > d_thumbHalf ? fh2 - d_thumbHalf : 0;
842 
843 //             d_sliderRect.setRect(this->rect().x() + (s.width() - 1) - sliderWidth - sclw + sldoffs, // - d_xMargin,
844             d_sliderRect.setRect(this->rect().x() + s.width() - sliderWidth - sclw + sldoffs, // - d_xMargin,
845 //               this->rect().y() + d_yMargin,
846               this->rect().y() + d_yMargin + sldymargin2,
847               sliderWidth,
848 //               s.height() - 2 * d_yMargin);
849 //               s.height() - margin - 2 * d_yMargin);
850               s.height() - sldymargin - 2 * d_yMargin);
851 
852             //d_scale.setGeometry(d_sliderRect.x() - d_scaleDist,
853 //             d_scale.setGeometry(this->rect().x() + d_xMargin + d_scale.maxWidth(fm, false) + d_scaleDist,
854             d_scale.setGeometry(this->rect().x() + d_xMargin + mxlw + sclw + d_scaleDist,
855 //               d_sliderRect.y() + d_thumbHalf,
856 //               d_sliderRect.y(),
857               this->rect().y() + d_yMargin + margin2,
858 //               s.height() - d_thumbLength,
859 //               s.height() - margin,
860 //               d_sliderRect.height(),
861               s.height() - margin - 2 * d_yMargin,
862               ScaleDraw::InsideVertical);
863         }
864         break;
865 
866         default:
867             d_sliderRect.setRect(this->rect().x(), this->rect().x(),
868               s.width(), s.height());
869             break;
870       }
871     }
872 
873   adjustScale();
874 }
875 
adjustScale()876 void Slider::adjustScale()
877 {
878   const double range = maxValue() - minValue();
879   if(range == 0.0)
880     return;
881 
882   int maxMaj = 5;
883   int maxMin = 3;
884   double mstep = scaleStep();
885 
886   QFontMetrics fm = fontMetrics();
887   if(d_orient == Qt::Horizontal)
888   {
889 // Width() is obsolete. Qt >= 5.11 use horizontalAdvance().
890 #if QT_VERSION >= 0x050b00
891     int unit_w = fm.horizontalAdvance("888.8888");
892 #else
893     int unit_w = fm.width("888.8888");
894 #endif
895     if(unit_w == 0)
896       unit_w = 20;
897 
898     if(hasUserScale())
899     {
900       if(d_sliderRect.width() != 0)
901       {
902         const int fact = (int)(3.0 * range / (double)(d_sliderRect.width())) + 1;
903         mstep *= fact;
904       }
905     }
906     else
907     {
908       maxMaj = (int)((double)(d_sliderRect.width()) / (1.5 * ((double)unit_w)));
909       if(maxMaj < 1)
910         maxMaj = 1;
911       if(maxMaj > 5)
912         maxMaj = 5;
913     }
914     maxMin = (int)((double)(d_sliderRect.width()) / (1.5 * ((double)unit_w)));
915     if(maxMin < 1)
916       maxMin = 1;
917     if(maxMin > 5)
918       maxMin = 5;
919   }
920   else
921   {
922     int unit_h = fm.height();
923     if(unit_h == 0)
924       unit_h = 20;
925 
926     if(hasUserScale())
927     {
928       if(d_sliderRect.height() != 0)
929       {
930         const int fact = (int)(3.0 * range / (double)(d_sliderRect.height())) + 1;
931         mstep *= fact;
932       }
933     }
934     else
935     {
936       maxMaj = (int)((double)(d_sliderRect.height()) / (1.5 * ((double)unit_h)));
937       if(maxMaj < 1)
938         maxMaj = 1;
939       if(maxMaj > 5)
940         maxMaj = 5;
941     }
942     maxMin = (int)((double)(d_sliderRect.height()) / (1.5 * ((double)unit_h)));
943     if(maxMin < 1)
944       maxMin = 1;
945     if(maxMin > 5)
946       maxMin = 5;
947   }
948 
949   DEBUG_SLIDER(stderr, "Slider::adjustScale: maxMaj:%d maxMin:%d scaleStep:%f\n", maxMaj, maxMin, mstep);
950   d_maxMajor = maxMaj;
951   d_maxMinor = maxMin;
952   if(hasUserScale())
953     d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor, mstep, log());
954   else
955     d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor, log());
956 //   update();
957   updateGeometry();
958 }
959 
960 //------------------------------------------------------------
961 //.F  Slider::resizeEvent
962 //  Qt resize event
963 //
964 //.u  Parameters
965 //.p  QResizeEvent *e
966 //
967 //.u  Syntax
968 //.f  void Slider::resizeEvent(QResizeEvent *e)
969 //------------------------------------------------------------
970 
resizeEvent(QResizeEvent * e)971 void Slider::resizeEvent(QResizeEvent *e)
972 {
973     SliderBase::resizeEvent(e);
974     adjustSize(e->size());
975 }
976 
setScale(double vmin,double vmax,int logarithmic)977 void Slider::setScale(double vmin, double vmax, int logarithmic)
978 {
979   ScaleIf::setScale(vmin, vmax, logarithmic);
980   // Must adjust the scale.
981    adjustScale();
982 }
983 
setScale(double vmin,double vmax,double step,int logarithmic)984 void Slider::setScale(double vmin, double vmax, double step, int logarithmic)
985 {
986   ScaleIf::setScale(vmin, vmax, step, logarithmic);
987   // Must adjust the scale.
988   adjustScale();
989 }
990 
setScale(const ScaleDiv & s)991 void Slider::setScale(const ScaleDiv &s)
992 {
993   ScaleIf::setScale(s);
994   // Must adjust the scale.
995    adjustScale();
996 }
997 
setScaleMaxMajor(int ticks)998 void Slider::setScaleMaxMajor(int ticks)
999 {
1000   ScaleIf::setScaleMaxMajor(ticks);
1001   // Must adjust the scale.
1002    adjustScale();
1003 }
1004 
setScaleMaxMinor(int ticks)1005 void Slider::setScaleMaxMinor(int ticks)
1006 {
1007   ScaleIf::setScaleMaxMinor(ticks);
1008   // Must adjust the scale.
1009    adjustScale();
1010 }
1011 
setScaleBackBone(bool v)1012 void Slider::setScaleBackBone(bool v)
1013 {
1014   ScaleIf::setScaleBackBone(v);
1015   // Must adjust the scale.
1016   adjustScale();
1017 }
1018 
1019 //------------------------------------------------------------
1020 //.-
1021 //.F  Slider::valueChange
1022 //  Notify change of value
1023 //
1024 //.u  Syntax
1025 //.f  void Slider::valueChange()
1026 //
1027 //------------------------------------------------------------
1028 
valueChange()1029 void Slider::valueChange()
1030       {
1031       update();
1032 
1033       // HACK
1034       // In direct mode let the inherited classes (this) call these in their valueChange() methods,
1035       //  so that they may be called BEFORE valueChanged signal is emitted by the setPosition() call above.
1036       // ScrDirect mode only happens once upon press with a modifier. After that, another mode is set.
1037       // Hack: Since valueChange() is NOT called if nothing changed, in that case these are called for us by the SliderBase.
1038       if(d_scrollMode == ScrDirect)
1039       {
1040         processSliderPressed(id());
1041         emit sliderPressed(value(), id());
1042       }
1043 
1044       // Emits valueChanged if tracking enabled.
1045       SliderBase::valueChange();
1046       }
1047 
1048 //------------------------------------------------------------
1049 //.-
1050 //.F  Slider::rangeChange
1051 //  Notify change of range
1052 //
1053 //.u  Description
1054 //
1055 //.u  Syntax
1056 //.f  void Slider::rangeChange()
1057 //
1058 //------------------------------------------------------------
rangeChange()1059 void Slider::rangeChange()
1060 {
1061     if (!hasUserScale())
1062        d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor);
1063     SliderBase::rangeChange();
1064 //     repaint();
1065     update();
1066 }
1067 
1068 //------------------------------------------------------------
1069 //
1070 //.F  Slider::setMargins
1071 //  Set distances between the widget's border and
1072 //  internals.
1073 //
1074 //.u  Syntax
1075 //.f  void Slider::setMargins(int hor, int vert)
1076 //
1077 //.u  Parameters
1078 //.p  int hor, int vert -- Margins
1079 //
1080 //------------------------------------------------------------
setMargins(int hor,int vert)1081 void Slider::setMargins(int hor, int vert)
1082 {
1083     d_xMargin = MusECore::qwtMax(0, hor);
1084     d_yMargin = MusECore::qwtMax(0, vert);
1085     resize(this->size());
1086 }
1087 
1088 //------------------------------------------------------------
1089 //
1090 //.F  Slider::sizeHint
1091 //  Return a recommended size
1092 //
1093 //.u  Syntax
1094 //.f  QSize Slider::sizeHint() const
1095 //
1096 //.u  Note
1097 //  The return value of sizeHint() depends on the font and the
1098 //  scale.
1099 //------------------------------------------------------------
1100 
sizeHint() const1101 QSize Slider::sizeHint() const
1102       {
1103       int w = 40;
1104       int h = 40;
1105       const QFontMetrics fm = fontMetrics();
1106       int msWidth = 0, msHeight = 0;
1107 
1108       if (d_scalePos != None)
1109       {
1110         msWidth = d_scale.maxWidth(fm, false);
1111         msHeight = d_scale.maxHeight(fm);
1112 
1113         switch(d_orient)
1114         {
1115           case Qt::Vertical:
1116           {
1117             h = vertical_hint;
1118             const int smw = msWidth + d_scaleDist;
1119             switch(d_scalePos)
1120             {
1121               case Left:
1122               case Right:
1123                 w = 2*d_xMargin + d_thumbWidth + smw + 2;
1124               break;
1125 
1126               case InsideVertical:
1127               {
1128                 const int aw = smw > d_thumbWidth ? smw : d_thumbWidth;
1129                 w = 2*d_xMargin + aw + 2;
1130               }
1131               break;
1132 
1133               case Top:
1134               case Bottom:
1135               case InsideHorizontal:
1136               case None:
1137               break;
1138             }
1139           }
1140           break;
1141 
1142           case Qt::Horizontal:
1143           {
1144             w = horizontal_hint;
1145             const int smh = msHeight + d_scaleDist;
1146             switch(d_scalePos)
1147             {
1148               case Top:
1149               case Bottom:
1150                 h = 2*d_yMargin + d_thumbWidth + smh;
1151               break;
1152 
1153               case InsideHorizontal:
1154               {
1155                 const int ah = smh > d_thumbWidth ? smh : d_thumbWidth;
1156                 h = 2*d_yMargin + ah;
1157               }
1158               break;
1159 
1160               case Left:
1161               case Right:
1162               case InsideVertical:
1163               case None:
1164               break;
1165             }
1166           }
1167           break;
1168         }
1169       }
1170       else
1171       {      // no scale
1172         switch(d_orient)
1173         {
1174           case Qt::Vertical:
1175                 w = 16;
1176                 h = vertical_hint;
1177                 break;
1178           case Qt::Horizontal:
1179                 h = 16;
1180                 w = horizontal_hint;
1181                 break;
1182         }
1183       }
1184 
1185       return QSize(w, h);
1186       }
1187 
1188 //---------------------------------------------------------
1189 //   setOrientation
1190 //---------------------------------------------------------
1191 
setOrientation(Qt::Orientation o)1192 void Slider::setOrientation(Qt::Orientation o)
1193       {
1194       d_orient = o;
1195       ScaleDraw::OrientationX so = ScaleDraw::Bottom;
1196       switch(d_orient) {
1197             case Qt::Vertical:
1198                   switch(d_scalePos)
1199                   {
1200                     case Right:
1201                       so = ScaleDraw::Right;
1202                     break;
1203                     case Left:
1204                       so = ScaleDraw::Left;
1205                     break;
1206                     case InsideVertical:
1207                       so = ScaleDraw::InsideVertical;
1208                     break;
1209                     case Bottom:
1210                     case Top:
1211                     case InsideHorizontal:
1212                     case None:
1213                     break;
1214                   }
1215             break;
1216             case Qt::Horizontal:
1217                   switch(d_scalePos)
1218                   {
1219                     case Bottom:
1220                       so = ScaleDraw::Bottom;
1221                     break;
1222                     case Top:
1223                       so = ScaleDraw::Top;
1224                     break;
1225                     case InsideHorizontal:
1226                       so = ScaleDraw::InsideHorizontal;
1227                     break;
1228                     case Right:
1229                     case Left:
1230                     case InsideVertical:
1231                     case None:
1232                     break;
1233                   }
1234             break;
1235             }
1236 
1237       d_scale.setGeometry(0, 0, 40, so);
1238       if (d_orient == Qt::Vertical)
1239       {
1240             setMinimumSize(10,20);
1241       }
1242       else
1243       {
1244             setMinimumSize(20,10);
1245       }
1246       QRect r = geometry();
1247       setGeometry(r.x(), r.y(), r.height(), r.width());
1248       update();
1249       }
1250 
orientation() const1251 Qt::Orientation Slider::orientation() const
1252       {
1253       return d_orient;
1254       }
1255 
scaleEndpointsMargin() const1256 int Slider::scaleEndpointsMargin() const
1257 {
1258   const QFontMetrics fm = fontMetrics();
1259   const int fh = fm.ascent() + 2;
1260   const int fh2 = fh / 2;
1261   const int margin2 = d_thumbHalf > fh2 ? d_thumbHalf : fh2;
1262   return d_yMargin + margin2;
1263 }
1264 
lineStep() const1265 double Slider::lineStep() const
1266       {
1267       return 1.0;
1268       }
1269 
pageStep() const1270 double Slider::pageStep() const
1271       {
1272       return 1.0;
1273       }
1274 
setLineStep(double)1275 void Slider::setLineStep(double)
1276       {
1277       }
1278 
setPageStep(double)1279 void Slider::setPageStep(double)
1280       {
1281       }
1282 
1283 } // namespace MusEGui
1284