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