//========================================================= // MusE // Linux Music Editor // $Id: ./muse/widgets/slider.cpp $ // // Copyright (C) 1999-2011 by Werner Schweer and others // (C) Copyright 2011 Orcan Ogetbil (ogetbilo at sf.net) // (C) Copyright 2015-2016 Tim E. Real (terminator356 on sourceforge) // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; version 2 of // the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // //========================================================= #include "muse_math.h" #include "mmath.h" #include #include #include "utils.h" #include "slider.h" // For debugging output: Uncomment the fprintf section. #define DEBUG_SLIDER(dev, format, args...) // fprintf(dev, format, ##args); namespace MusEGui { //------------------------------------------------------------- // Slider - The Slider Widget // // Slider is a slider widget which operates on an interval // of type double. Slider supports different layouts as // well as a scale. //------------------------------------------------------------ //------------------------------------------------------------ //.F Slider::Slider // // Constructor // //.u Syntax: //.f Slider::Slider(QWidget *parent, const char *name, Orientation orient = Horizontal, ScalePos scalePos = None, int bgStyle = BgTrough) // //.u Parameters //.p // QWidget *parent -- parent widget // const char *name -- The Widget's name. Default = 0. // Orientation Orient -- Orientation of the slider. Can be Slider::Horizontal // or Slider::Vertical. // Defaults to Horizontal. // ScalePos scalePos -- Position of the scale. Can be Slider::None, // Slider::Left, Slider::Right, Slider::Top, // or Slider::Bottom. Defaults to Slider::None. !!! CURRENTLY only Slider::None supported - oget 20110913 // QColor fillcolor -- the color used to fill in the full side // of the Slider. If fillColor is invalid (default) it will draw with the palette highlight colour. //------------------------------------------------------------ Slider::Slider(QWidget *parent, const char *name, Qt::Orientation orient, ScalePos scalePos, int grooveWidth, QColor fillColor, ScaleDraw::TextHighlightMode textHighlightMode, QColor handleColor) : SliderBase(parent,name), d_scalePos(scalePos), d_grooveWidth(grooveWidth), d_fillColor(fillColor), d_handleColor(handleColor) { setPagingButtons(Qt::RightButton); d_thumbLength = 16; d_thumbHalf = 8; d_thumbWidth = 16; d_fillThumb = true; d_fillEmptySide = true; d_frame = false; d_radius = 4; d_radiusHandle = 2; d_useGradient = true; d_scaleDist = 4; d_scaleStep = 0.0; d_xMargin = 0; d_yMargin = 0; d_mMargin = 1; horizontal_hint = 40; vertical_hint = 40; // set to sane values to avoid erratic size hint // calculation -> drawing problems (kybos) if (orient == Qt::Vertical) { d_sliderRect.setRect(0, 0, 20, 100); } else { d_sliderRect.setRect(0, 0, 100, 20); } setOrientation(orient); d_scale.setTextHighlightMode(textHighlightMode); } //------------------------------------------------------------ //.F Slider::setSizeHint //------------------------------------------------------------ void Slider::setSizeHint(uint w, uint h) { horizontal_hint = w; vertical_hint = h; } //------------------------------------------------------------ //.F Slider::~Slider // Destructor //.u Syntax //.f Slider::~Slider() //------------------------------------------------------------ Slider::~Slider() { } //---------------------------------------------------- // //.F Slider::setThumbLength // // Set the slider's thumb length // //.u Syntax // void Slider::setThumbLength(int l) // //.u Parameters //.p int l -- new length // //----------------------------------------------------- void Slider::setThumbLength(int l) { // d_thumbLength = MusECore::qwtMax(l,8); d_thumbLength = l; d_thumbHalf = d_thumbLength / 2; resize(size()); } //------------------------------------------------------------ // //.F Slider::setThumbWidth // Change the width of the thumb // //.u Syntax //.p void Slider::setThumbWidth(int w) // //.u Parameters //.p int w -- new width // //------------------------------------------------------------ void Slider::setThumbWidth(int w) { d_thumbWidth = MusECore::qwtMax(w,4); resize(size()); } //------------------------------------------------------------ //.- //.F Slider::scaleChange // Notify changed scale // //.u Syntax //.f void Slider::scaleChange() // //.u Description // Called by QwtScaledWidget // //------------------------------------------------------------ void Slider::scaleChange() { if (!hasUserScale()) d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor); update(); } //------------------------------------------------------------ //.- //.F Slider::fontChange // Notify change in font // //.u Syntax //.f Slider::fontChange(const QFont &oldFont) // //------------------------------------------------------------ void Slider::fontChange(const QFont & /*oldFont*/) { // repaint(); update(); } void Slider::drawThumb(QPainter *p, const QRect &r) { p->setRenderHint(QPainter::Antialiasing); QColor thumb_edge; QColor thumb_center; const QPalette& pal = palette(); if (d_handleColor.isValid()) { thumb_edge = d_handleColor; thumb_center = d_handleColor.lighter(); } else { thumb_edge = pal.dark().color(); thumb_center = pal.mid().color(); } QLinearGradient thumbGrad; thumbGrad.setColorAt(0, thumb_edge); thumbGrad.setColorAt(0.5, thumb_center); thumbGrad.setColorAt(1, thumb_edge); const double rpos = (value(ConvertNone) - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone)); if(d_orient == Qt::Horizontal) { int crh, thh; // if(d_scalePos == InsideHorizontal) // { // crh = height() - r.y() - d_yMargin - 2 * d_mMargin; // thh = height() - r.y() - d_yMargin - d_mMargin; // } // else { crh = r.height() - 2 * d_mMargin; thh = r.height(); } const QRect cr(r.x(), r.y() + d_mMargin, r.width(), //r.height() - 2*d_mMargin); crh); const int dist1 = int(double(cr.width() - d_thumbLength) * rpos); const int ipos = cr.x() + dist1; markerPos = ipos + d_thumbHalf; // // Draw thumb // QPainterPath thumb_rect = MusECore::roundedPath(ipos, r.y(), //d_thumbLength, r.height(), d_thumbLength, thh, d_radiusHandle, d_radiusHandle, (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight | MusECore::CornerLowerLeft | MusECore::CornerLowerRight) ); // thumbGrad.setStart(QPointF(0, cr.y())); // thumbGrad.setFinalStop(QPointF(0, cr.y() + cr.height())); thumbGrad.setStart(QPointF(ipos, 0)); thumbGrad.setFinalStop(QPointF(ipos + d_thumbLength, 0)); if(d_fillThumb) p->fillPath(thumb_rect, QBrush(thumbGrad)); else { p->setPen(pal.shadow().color()); p->drawPath(thumb_rect); } // center line p->fillRect(ipos + d_thumbHalf, cr.y(), 1, cr.height(), pal.dark().color()); } else { int crw, thw; // if(d_scalePos == InsideVertical) // { // crw = width() - r.x() - d_xMargin - 2 * d_mMargin; // thw = width() - r.x() - d_xMargin - d_mMargin; // } // else { crw = r.width() - 2 * d_mMargin; thw = r.width(); } const QRect cr(r.x() + d_mMargin, r.y(), //r.width() - 2*d_mMargin, crw, r.height()); const int dist1 = int(double(cr.height() - d_thumbLength) * (1.0 - rpos)); const int ipos = cr.y() + dist1; markerPos = ipos + d_thumbHalf; // // Draw thumb // QPainterPath thumb_rect = MusECore::roundedPath(r.x(), ipos, //r.width(), d_thumbLength, thw, d_thumbLength, d_radiusHandle, d_radiusHandle, (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight | MusECore::CornerLowerLeft | MusECore::CornerLowerRight) ); // thumbGrad.setStart(QPointF(cr.x(), 0)); // thumbGrad.setFinalStop(QPointF(cr.x() + cr.width(), 0)); thumbGrad.setStart(QPointF(0, ipos)); thumbGrad.setFinalStop(QPointF(0, ipos + d_thumbLength)); if(d_fillThumb) p->fillPath(thumb_rect, QBrush(thumbGrad)); else { p->setPen(pal.shadow().color()); p->drawPath(thumb_rect); } // center line p->fillRect(cr.x(), ipos + d_thumbHalf, cr.width(), 1, pal.dark().color()); } } //------------------------------------------------------------ // drawSlider // Draw the slider into the specified rectangle. //------------------------------------------------------------ void Slider::drawSlider(QPainter *p, const QRect &r) { p->setRenderHint(QPainter::Antialiasing); const QPalette& pal = palette(); // for the full side const double rpos = (value(ConvertNone) - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone)); QColor f_mask_min(d_fillColor.isValid() ? d_fillColor : pal.highlight().color()); QColor f_mask_max(f_mask_min); if (d_useGradient) { f_mask_min.setAlpha(40); //f_mask_max.setAlpha(200); f_mask_max.setAlpha(255); } QLinearGradient f_mask; if (d_orient == Qt::Horizontal) { const QRect cr(r.x(), r.y() + r.height() / 2 - d_grooveWidth / 2, r.width(), d_grooveWidth); QPainterPath clip_path; clip_path.addRoundedRect(cr.x() + d_thumbHalf, cr.y(), cr.width() - d_thumbLength, r.height(), d_radius, d_radius); p->setClipPath(clip_path); // // Draw background // const int dist1 = int(double(cr.width() - (d_fillThumb ? d_thumbLength : d_thumbHalf)) * rpos); const int ipos = cr.x() + dist1; markerPos = ipos + d_thumbHalf; // // Draw groove empty right side // if(d_fillEmptySide) { QPainterPath e_rect = MusECore::roundedPath(ipos + (d_fillThumb ? d_thumbLength : d_thumbHalf), cr.y(), cr.width() - (d_fillThumb ? d_thumbLength : d_thumbHalf) - dist1, cr.height(), d_radius, d_radius, (MusECore::Corner) (MusECore::CornerUpperRight | MusECore::CornerLowerRight) ); p->fillPath(e_rect, f_mask_min); } // // Draw groove full left side // f_mask.setColorAt(0, f_mask_min); f_mask.setColorAt(1, f_mask_max); f_mask.setStart(QPointF(cr.x(), cr.y())); f_mask.setFinalStop(QPointF(cr.x() + ipos + (d_fillThumb ? 0 : d_thumbHalf), cr.y())); QPainterPath f_rect = MusECore::roundedPath(cr.x(), cr.y(), ipos + (d_fillThumb ? 0 : d_thumbHalf), cr.height(), d_radius, d_radius, (MusECore::Corner) (MusECore::CornerLowerLeft | MusECore::CornerUpperLeft) ); p->fillPath(f_rect, QBrush(f_mask)); p->setClipping(false); } else // (d_orient == Qt::Vertical) { const QRect cr(r.x() + r.width() / 2 - d_grooveWidth / 2, r.y(), d_grooveWidth, r.height()); QPainterPath clip_path; clip_path.addRoundedRect(cr.x(), cr.y() + d_thumbHalf, cr.width(), r.height() - d_thumbLength, d_radius, d_radius); p->setClipPath(clip_path); // // Draw background // const int dist1 = int(double(cr.height() - (d_fillThumb ? d_thumbLength : d_thumbHalf)) * (1.0 - rpos)); const int ipos = cr.y() + dist1; markerPos = ipos + d_thumbHalf; // // Draw groove empty upper filling // if(d_fillEmptySide) { QPainterPath e_rect = MusECore::roundedPath(cr.x(), cr.y(), cr.width(), ipos + (d_fillThumb ? 0 : d_thumbHalf), d_radius, d_radius, (MusECore::Corner) (MusECore::CornerUpperLeft | MusECore::CornerUpperRight) ); p->fillPath(e_rect, QBrush(f_mask_min)); } // // Draw groove lower filling mask // f_mask.setColorAt(0, f_mask_max); f_mask.setColorAt(1, f_mask_min); f_mask.setStart(QPointF(cr.x(), markerPos)); f_mask.setFinalStop(QPointF(cr.x(), cr.y() + cr.height())); QPainterPath f_rect = MusECore::roundedPath(cr.x(), ipos + (d_fillThumb ? d_thumbLength : d_thumbHalf), cr.width(), cr.height() - (d_fillThumb ? d_thumbLength : d_thumbHalf) - dist1, d_radius, d_radius, (MusECore::Corner) (MusECore::CornerLowerLeft | MusECore::CornerLowerRight) ); p->fillPath(f_rect, QBrush(f_mask)); p->setClipping(false); if (d_frame) { p->setPen(d_frameColor); p->drawPath(clip_path); } } } //------------------------------------------------------------ //.- //.F Slider::getValue // Determine the value corresponding to a specified // mouse location. // //.u Syntax //.f double Slider::getValue(const QPoint &p) // //.u Parameters //.p const QPoint &p -- // //.u Description // Called by SliderBase //------------------------------------------------------------ double Slider::getValue( const QPoint &p) { double rv; const QRect r = d_sliderRect; const double val = value(ConvertNone); if(borderlessMouse() && d_scrollMode != ScrDirect) { DEBUG_SLIDER(stderr, "Slider::getValue value:%.20f p x:%d y:%d step:%.20f x change:%.20f\n", val, p.x(), p.y(), step(), p.x() * step()); if(d_orient == Qt::Horizontal) return val + p.x() * step(); else return val - p.y() * step(); } const double min = minValue(ConvertNone); const double max = maxValue(ConvertNone); const double drange = max - min; if(d_orient == Qt::Horizontal) { if(r.width() <= d_thumbLength) rv = 0.5 * (min + max); else { const double dpos = double(p.x() - r.x() - d_thumbHalf); const double dwidth = double(r.width() - d_thumbLength); rv = min + rint(drange * dpos / dwidth / step()) * step(); } } else { if(r.height() <= d_thumbLength) rv = 0.5 * (min + max); else { const double dpos = double(p.y() - r.y() - d_thumbHalf); double dheight = double(r.height() - d_thumbLength); rv = min + rint(drange * (1.0 - dpos / dheight) / step()) * step(); } } return(rv); } //------------------------------------------------------------ // //.F Slider::moveValue // Determine the value corresponding to a specified mouse movement. // //.u Syntax //.f void Slider::moveValue(const QPoint &deltaP, bool fineMode) // //.u Parameters //.p const QPoint &deltaP -- Change in position //.p bool fineMode -- Fine mode if true, coarse mode if false. // //.u Description // Called by SliderBase // Coarse mode (the normal mode) maps pixels to values depending on range and width, // such that the slider follows the mouse cursor. Fine mode maps one step() value per pixel. //------------------------------------------------------------ double Slider::moveValue(const QPoint &deltaP, bool fineMode) { double rv; const QRect r = d_sliderRect; const double val = value(ConvertNone); if((fineMode || borderlessMouse()) && d_scrollMode != ScrDirect) { DEBUG_SLIDER(stderr, "Slider::moveValue value:%.20f p x:%d y:%d step:%.20f x change:%.20f\n", val, deltaP.x(), deltaP.y(), step(), deltaP.x() * step()); double newval; if(d_orient == Qt::Horizontal) newval = val + deltaP.x() * step(); else newval = val - deltaP.y() * step(); d_valAccum = newval; // Reset. return newval; } const double min = minValue(ConvertNone); const double max = maxValue(ConvertNone); const double drange = max - min; if(d_orient == Qt::Horizontal) { if(r.width() <= d_thumbLength) rv = 0.5 * (min + max); else { const double dpos = double(deltaP.x()); const double dwidth = double(r.width() - d_thumbLength); const double dval_diff = (drange * dpos) / dwidth; d_valAccum += dval_diff; rv = rint(d_valAccum / step()) * step(); 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", val, deltaP.x(), deltaP.y(), drange, step(), dval_diff, d_valAccum, rv); } } else { if(r.height() <= d_thumbLength) rv = 0.5 * (min + max); else { const double dpos = double(-deltaP.y()); const double dheight = double(r.height() - d_thumbLength); const double dval_diff = (drange * dpos) / dheight; d_valAccum += dval_diff; rv = rint(d_valAccum / step()) * step(); 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", val, deltaP.x(), deltaP.y(), drange, step(), dval_diff, d_valAccum, rv); } } return(rv); } //------------------------------------------------------------ //.- //.F Slider::getScrollMode // Determine scrolling mode and direction // //.u Syntax //.f void Slider::getScrollMode( const QPoint &p, int &scrollMode, int &direction ) // //.u Parameters //.p const QPoint &p -- point // //.u Description // Called by SliderBase // //------------------------------------------------------------ void Slider::getScrollMode( QPoint &p, const Qt::MouseButton &button, const Qt::KeyboardModifiers& modifiers, int &scrollMode, int &direction ) { // If modifier or button is held, jump directly to the position at first. // After handling it, the caller can change to SrcMouse scroll mode. if(modifiers & Qt::ControlModifier || button == Qt::MidButton) { scrollMode = ScrDirect; direction = 0; return; } if(borderlessMouse()) { if(button != Qt::NoButton && d_sliderRect.contains(p)) { scrollMode = ScrMouse; direction = 0; return; } } else { if(cursorHoming() && button == Qt::LeftButton) { if(d_sliderRect.contains(p)) { DEBUG_SLIDER(stderr, "Slider::getScrollMode cursor homing + left button: ScrMouse\n"); scrollMode = ScrMouse; direction = 0; int mp = 0; QRect cr; QPoint cp; int ipos,dist1; double rpos; cr = d_sliderRect; rpos = (value(ConvertNone) - minValue(ConvertNone)) / (maxValue(ConvertNone) - minValue(ConvertNone)); if(d_orient == Qt::Horizontal) { dist1 = int(double(cr.width() - d_thumbLength) * rpos); ipos = cr.x() + dist1; mp = ipos + d_thumbHalf; p.setX(mp); cp = mapToGlobal( QPoint(mp, p.y()) ); } else { dist1 = int(double(cr.height() - d_thumbLength) * (1.0 - rpos)); ipos = cr.y() + dist1; mp = ipos + d_thumbHalf; p.setY(mp); cp = mapToGlobal( QPoint(p.x(), mp) ); } cursor().setPos(cp.x(), cp.y()); return; } } else { int currentPos; if(d_orient == Qt::Horizontal) currentPos = p.x(); else currentPos = p.y(); if(d_sliderRect.contains(p)) { if((currentPos > markerPos - d_thumbHalf) && (currentPos < markerPos + d_thumbHalf)) { DEBUG_SLIDER(stderr, "Slider::getScrollMode ScrMouse\n"); scrollMode = ScrMouse; direction = 0; return; } else if(pagingButtons().testFlag(button)) { DEBUG_SLIDER(stderr, "Slider::getScrollMode ScrPage\n"); scrollMode = ScrPage; if (((currentPos > markerPos) && (d_orient == Qt::Horizontal)) || ((currentPos <= markerPos) && (d_orient != Qt::Horizontal))) direction = 1; else direction = -1; return; } } } } scrollMode = ScrNone; direction = 0; } //------------------------------------------------------------ //.F Slider::paintEvent // Qt paint event // //.u Syntax //.f void Slider::paintEvent(QPaintEvent *e) //------------------------------------------------------------ void Slider::paintEvent(QPaintEvent* /*ev*/) { QPainter p(this); if(d_grooveWidth != 0) drawSlider(&p, d_sliderRect); if(d_thumbLength != 0) drawThumb(&p, d_sliderRect); if(d_scalePos != None) { // p.fillRect(rect(), palette().window()); p.setRenderHint(QPainter::Antialiasing, false); d_scale.draw(&p, palette(), value()); } } void Slider::adjustSize(const QSize& s) { const QFontMetrics fm = fontMetrics(); const int sliderWidth = d_thumbWidth; // reposition slider if(d_orient == Qt::Horizontal) { switch(d_scalePos) { case Top: d_sliderRect.setRect(this->rect().x() + d_xMargin, this->rect().y() + s.height() - 1 - d_yMargin - sliderWidth, s.width() - 2 * d_xMargin, sliderWidth); d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf, d_sliderRect.y() - d_scaleDist, d_sliderRect.width() - d_thumbLength, ScaleDraw::Top); break; case Bottom: d_sliderRect.setRect(this->rect().x() + d_xMargin, this->rect().y() + d_yMargin, s.width() - 2*d_xMargin, sliderWidth); d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf, d_sliderRect.y() + d_sliderRect.height() + d_scaleDist, d_sliderRect.width() - d_thumbLength, ScaleDraw::Bottom); break; case InsideHorizontal: d_sliderRect.setRect(this->rect().x() + d_xMargin, this->rect().y() + s.height() - 1 - d_yMargin - sliderWidth, s.width() - 2 * d_xMargin, sliderWidth); d_scale.setGeometry(d_sliderRect.x() + d_thumbHalf, //d_sliderRect.y() - d_scaleDist, this->rect().y() + d_yMargin + d_scale.maxHeight(fm) + d_scaleDist, d_sliderRect.width() - d_thumbLength, ScaleDraw::InsideHorizontal); break; default: d_sliderRect.setRect(this->rect().x(), this->rect().x(), s.width(), s.height()); break; } } else // d_orient == Qt::Vertical { switch(d_scalePos) { case Left: d_sliderRect.setRect(this->rect().x() + s.width() - sliderWidth - 1 - d_xMargin, this->rect().y() + d_yMargin, sliderWidth, s.height() - 2 * d_yMargin); d_scale.setGeometry(d_sliderRect.x() - d_scaleDist, d_sliderRect.y() + d_thumbHalf, s.height() - d_thumbLength, ScaleDraw::Left); break; case Right: { d_sliderRect.setRect(this->rect().x() + d_xMargin, this->rect().y() + d_yMargin, sliderWidth, s.height() - 2* d_yMargin); d_scale.setGeometry(this->rect().x() + d_sliderRect.width() + d_scaleDist, d_sliderRect.y() + d_thumbHalf, s.height() - d_thumbLength, ScaleDraw::Right); break; } case InsideVertical: { // d_sliderRect.setRect(this->rect().x() + s.width() // - sliderWidth - 1 - d_xMargin, // d_sliderRect.setRect(this->rect().x() + d_xMargin, // d_sliderRect.setRect(this->rect().x() + d_xMargin + d_scale.maxLabelWidth(fm, false) - sliderWidth, const int mxlw = d_scale.maxLabelWidth(fm, false); const int sclw = d_scale.scaleWidth(); const int sldw = mxlw > sliderWidth ? sliderWidth : mxlw; const int sldoffs = mxlw > sliderWidth ? ((mxlw - sldw) / 2) : 0; const int fh = fm.ascent() + 2; const int fh2 = fh / 2; const int margin = d_thumbLength > fh ? d_thumbLength : fh; const int margin2 = d_thumbHalf > fh2 ? d_thumbHalf : fh2; const int sldymargin = fh > d_thumbLength ? fh - d_thumbLength : 0; const int sldymargin2 = fh2 > d_thumbHalf ? fh2 - d_thumbHalf : 0; // d_sliderRect.setRect(this->rect().x() + (s.width() - 1) - sliderWidth - sclw + sldoffs, // - d_xMargin, d_sliderRect.setRect(this->rect().x() + s.width() - sliderWidth - sclw + sldoffs, // - d_xMargin, // this->rect().y() + d_yMargin, this->rect().y() + d_yMargin + sldymargin2, sliderWidth, // s.height() - 2 * d_yMargin); // s.height() - margin - 2 * d_yMargin); s.height() - sldymargin - 2 * d_yMargin); //d_scale.setGeometry(d_sliderRect.x() - d_scaleDist, // d_scale.setGeometry(this->rect().x() + d_xMargin + d_scale.maxWidth(fm, false) + d_scaleDist, d_scale.setGeometry(this->rect().x() + d_xMargin + mxlw + sclw + d_scaleDist, // d_sliderRect.y() + d_thumbHalf, // d_sliderRect.y(), this->rect().y() + d_yMargin + margin2, // s.height() - d_thumbLength, // s.height() - margin, // d_sliderRect.height(), s.height() - margin - 2 * d_yMargin, ScaleDraw::InsideVertical); } break; default: d_sliderRect.setRect(this->rect().x(), this->rect().x(), s.width(), s.height()); break; } } adjustScale(); } void Slider::adjustScale() { const double range = maxValue() - minValue(); if(range == 0.0) return; int maxMaj = 5; int maxMin = 3; double mstep = scaleStep(); QFontMetrics fm = fontMetrics(); if(d_orient == Qt::Horizontal) { // Width() is obsolete. Qt >= 5.11 use horizontalAdvance(). #if QT_VERSION >= 0x050b00 int unit_w = fm.horizontalAdvance("888.8888"); #else int unit_w = fm.width("888.8888"); #endif if(unit_w == 0) unit_w = 20; if(hasUserScale()) { if(d_sliderRect.width() != 0) { const int fact = (int)(3.0 * range / (double)(d_sliderRect.width())) + 1; mstep *= fact; } } else { maxMaj = (int)((double)(d_sliderRect.width()) / (1.5 * ((double)unit_w))); if(maxMaj < 1) maxMaj = 1; if(maxMaj > 5) maxMaj = 5; } maxMin = (int)((double)(d_sliderRect.width()) / (1.5 * ((double)unit_w))); if(maxMin < 1) maxMin = 1; if(maxMin > 5) maxMin = 5; } else { int unit_h = fm.height(); if(unit_h == 0) unit_h = 20; if(hasUserScale()) { if(d_sliderRect.height() != 0) { const int fact = (int)(3.0 * range / (double)(d_sliderRect.height())) + 1; mstep *= fact; } } else { maxMaj = (int)((double)(d_sliderRect.height()) / (1.5 * ((double)unit_h))); if(maxMaj < 1) maxMaj = 1; if(maxMaj > 5) maxMaj = 5; } maxMin = (int)((double)(d_sliderRect.height()) / (1.5 * ((double)unit_h))); if(maxMin < 1) maxMin = 1; if(maxMin > 5) maxMin = 5; } DEBUG_SLIDER(stderr, "Slider::adjustScale: maxMaj:%d maxMin:%d scaleStep:%f\n", maxMaj, maxMin, mstep); d_maxMajor = maxMaj; d_maxMinor = maxMin; if(hasUserScale()) d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor, mstep, log()); else d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor, log()); // update(); updateGeometry(); } //------------------------------------------------------------ //.F Slider::resizeEvent // Qt resize event // //.u Parameters //.p QResizeEvent *e // //.u Syntax //.f void Slider::resizeEvent(QResizeEvent *e) //------------------------------------------------------------ void Slider::resizeEvent(QResizeEvent *e) { SliderBase::resizeEvent(e); adjustSize(e->size()); } void Slider::setScale(double vmin, double vmax, int logarithmic) { ScaleIf::setScale(vmin, vmax, logarithmic); // Must adjust the scale. adjustScale(); } void Slider::setScale(double vmin, double vmax, double step, int logarithmic) { ScaleIf::setScale(vmin, vmax, step, logarithmic); // Must adjust the scale. adjustScale(); } void Slider::setScale(const ScaleDiv &s) { ScaleIf::setScale(s); // Must adjust the scale. adjustScale(); } void Slider::setScaleMaxMajor(int ticks) { ScaleIf::setScaleMaxMajor(ticks); // Must adjust the scale. adjustScale(); } void Slider::setScaleMaxMinor(int ticks) { ScaleIf::setScaleMaxMinor(ticks); // Must adjust the scale. adjustScale(); } void Slider::setScaleBackBone(bool v) { ScaleIf::setScaleBackBone(v); // Must adjust the scale. adjustScale(); } //------------------------------------------------------------ //.- //.F Slider::valueChange // Notify change of value // //.u Syntax //.f void Slider::valueChange() // //------------------------------------------------------------ void Slider::valueChange() { update(); // HACK // In direct mode let the inherited classes (this) call these in their valueChange() methods, // so that they may be called BEFORE valueChanged signal is emitted by the setPosition() call above. // ScrDirect mode only happens once upon press with a modifier. After that, another mode is set. // Hack: Since valueChange() is NOT called if nothing changed, in that case these are called for us by the SliderBase. if(d_scrollMode == ScrDirect) { processSliderPressed(id()); emit sliderPressed(value(), id()); } // Emits valueChanged if tracking enabled. SliderBase::valueChange(); } //------------------------------------------------------------ //.- //.F Slider::rangeChange // Notify change of range // //.u Description // //.u Syntax //.f void Slider::rangeChange() // //------------------------------------------------------------ void Slider::rangeChange() { if (!hasUserScale()) d_scale.setScale(minValue(), maxValue(), d_maxMajor, d_maxMinor); SliderBase::rangeChange(); // repaint(); update(); } //------------------------------------------------------------ // //.F Slider::setMargins // Set distances between the widget's border and // internals. // //.u Syntax //.f void Slider::setMargins(int hor, int vert) // //.u Parameters //.p int hor, int vert -- Margins // //------------------------------------------------------------ void Slider::setMargins(int hor, int vert) { d_xMargin = MusECore::qwtMax(0, hor); d_yMargin = MusECore::qwtMax(0, vert); resize(this->size()); } //------------------------------------------------------------ // //.F Slider::sizeHint // Return a recommended size // //.u Syntax //.f QSize Slider::sizeHint() const // //.u Note // The return value of sizeHint() depends on the font and the // scale. //------------------------------------------------------------ QSize Slider::sizeHint() const { int w = 40; int h = 40; const QFontMetrics fm = fontMetrics(); int msWidth = 0, msHeight = 0; if (d_scalePos != None) { msWidth = d_scale.maxWidth(fm, false); msHeight = d_scale.maxHeight(fm); switch(d_orient) { case Qt::Vertical: { h = vertical_hint; const int smw = msWidth + d_scaleDist; switch(d_scalePos) { case Left: case Right: w = 2*d_xMargin + d_thumbWidth + smw + 2; break; case InsideVertical: { const int aw = smw > d_thumbWidth ? smw : d_thumbWidth; w = 2*d_xMargin + aw + 2; } break; case Top: case Bottom: case InsideHorizontal: case None: break; } } break; case Qt::Horizontal: { w = horizontal_hint; const int smh = msHeight + d_scaleDist; switch(d_scalePos) { case Top: case Bottom: h = 2*d_yMargin + d_thumbWidth + smh; break; case InsideHorizontal: { const int ah = smh > d_thumbWidth ? smh : d_thumbWidth; h = 2*d_yMargin + ah; } break; case Left: case Right: case InsideVertical: case None: break; } } break; } } else { // no scale switch(d_orient) { case Qt::Vertical: w = 16; h = vertical_hint; break; case Qt::Horizontal: h = 16; w = horizontal_hint; break; } } return QSize(w, h); } //--------------------------------------------------------- // setOrientation //--------------------------------------------------------- void Slider::setOrientation(Qt::Orientation o) { d_orient = o; ScaleDraw::OrientationX so = ScaleDraw::Bottom; switch(d_orient) { case Qt::Vertical: switch(d_scalePos) { case Right: so = ScaleDraw::Right; break; case Left: so = ScaleDraw::Left; break; case InsideVertical: so = ScaleDraw::InsideVertical; break; case Bottom: case Top: case InsideHorizontal: case None: break; } break; case Qt::Horizontal: switch(d_scalePos) { case Bottom: so = ScaleDraw::Bottom; break; case Top: so = ScaleDraw::Top; break; case InsideHorizontal: so = ScaleDraw::InsideHorizontal; break; case Right: case Left: case InsideVertical: case None: break; } break; } d_scale.setGeometry(0, 0, 40, so); if (d_orient == Qt::Vertical) { setMinimumSize(10,20); } else { setMinimumSize(20,10); } QRect r = geometry(); setGeometry(r.x(), r.y(), r.height(), r.width()); update(); } Qt::Orientation Slider::orientation() const { return d_orient; } int Slider::scaleEndpointsMargin() const { const QFontMetrics fm = fontMetrics(); const int fh = fm.ascent() + 2; const int fh2 = fh / 2; const int margin2 = d_thumbHalf > fh2 ? d_thumbHalf : fh2; return d_yMargin + margin2; } double Slider::lineStep() const { return 1.0; } double Slider::pageStep() const { return 1.0; } void Slider::setLineStep(double) { } void Slider::setPageStep(double) { } } // namespace MusEGui