X-Git-Url: https://git.quassel-irc.org/?a=blobdiff_plain;f=src%2Fcontrib%2Flibqxt-2007-10-24%2Fsrc%2Fgui%2Fqxtspanslider.cpp;fp=src%2Fcontrib%2Flibqxt-2007-10-24%2Fsrc%2Fgui%2Fqxtspanslider.cpp;h=90844755e8a6a0b27a407c119f665a12d685a35f;hb=a634acadbcf6017474f68a3eaf7cb632660e9e49;hp=0000000000000000000000000000000000000000;hpb=cd122ca8e0d2c0ffc5397e0a813c75d791a7e6e3;p=quassel.git diff --git a/src/contrib/libqxt-2007-10-24/src/gui/qxtspanslider.cpp b/src/contrib/libqxt-2007-10-24/src/gui/qxtspanslider.cpp new file mode 100644 index 00000000..90844755 --- /dev/null +++ b/src/contrib/libqxt-2007-10-24/src/gui/qxtspanslider.cpp @@ -0,0 +1,561 @@ +/**************************************************************************** +** +** Copyright (C) Qxt Foundation. Some rights reserved. +** +** This file is part of the QxtGui module of the Qt eXTension library +** +** This library is free software; you can redistribute it and/or modify it +** under the terms of th Common Public License, version 1.0, as published by +** IBM. +** +** This file is provided "AS IS", without WARRANTIES OR CONDITIONS OF ANY +** KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY +** WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR +** FITNESS FOR A PARTICULAR PURPOSE. +** +** You should have received a copy of the CPL along with this file. +** See the LICENSE file and the cpl1.0.txt file included with the source +** distribution for more information. If you did not receive a copy of the +** license, contact the Qxt Foundation. +** +** +** +****************************************************************************/ +#include "qxtspanslider.h" +#include "qxtspanslider_p.h" +#include +#include +#include +#include +#include + +QxtSpanSliderPrivate::QxtSpanSliderPrivate() + : lower(0), + upper(0), + offset(0), + position(0), + lastPressed(NoHandle), + mainControl(LowerHandle), + lowerPressed(QStyle::SC_None), + upperPressed(QStyle::SC_None) +{} + +// TODO: get rid of this in Qt 4.3 +void QxtSpanSliderPrivate::initStyleOption(QStyleOptionSlider* option, SpanHandle handle) const +{ + if (!option) + return; + + const QSlider* p = &qxt_p(); + option->initFrom(p); + option->subControls = QStyle::SC_None; + option->activeSubControls = QStyle::SC_None; + option->orientation = p->orientation(); + option->maximum = p->maximum(); + option->minimum = p->minimum(); + option->tickPosition = p->tickPosition(); + option->tickInterval = p->tickInterval(); + option->upsideDown = (p->orientation() == Qt::Horizontal) ? + (p->invertedAppearance() != (option->direction == Qt::RightToLeft)) : (!p->invertedAppearance()); + option->direction = Qt::LeftToRight; // we use the upsideDown option instead + option->sliderPosition = (handle == LowerHandle ? lower : upper); + option->sliderValue = (handle == LowerHandle ? lower : upper); + option->singleStep = p->singleStep(); + option->pageStep = p->pageStep(); + if (p->orientation() == Qt::Horizontal) + option->state |= QStyle::State_Horizontal; +} + +int QxtSpanSliderPrivate::pixelPosToRangeValue(int pos) const +{ + QStyleOptionSlider opt; + initStyleOption(&opt); + + int sliderMin = 0; + int sliderMax = 0; + int sliderLength = 0; + const QSlider* p = &qxt_p(); + const QRect gr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p); + const QRect sr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, p); + if (p->orientation() == Qt::Horizontal) + { + sliderLength = sr.width(); + sliderMin = gr.x(); + sliderMax = gr.right() - sliderLength + 1; + } + else + { + sliderLength = sr.height(); + sliderMin = gr.y(); + sliderMax = gr.bottom() - sliderLength + 1; + } + return QStyle::sliderValueFromPosition(p->minimum(), p->maximum(), pos - sliderMin, + sliderMax - sliderMin, opt.upsideDown); +} + +void QxtSpanSliderPrivate::handleMousePress(const QPoint& pos, QStyle::SubControl& control, int value, SpanHandle handle) +{ + QStyleOptionSlider opt; + initStyleOption(&opt, handle); + QSlider* p = &qxt_p(); + const QStyle::SubControl oldControl = control; + control = p->style()->hitTestComplexControl(QStyle::CC_Slider, &opt, pos, p); + const QRect sr = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, p); + if (control == QStyle::SC_SliderHandle) + { + position = value; + offset = pick(pos - sr.topLeft()); + lastPressed = handle; + p->setSliderDown(true); + } + if (control != oldControl) + p->update(sr); +} + +void QxtSpanSliderPrivate::setupPainter(QPainter* painter, Qt::Orientation orientation, qreal x1, qreal y1, qreal x2, qreal y2) const +{ + QColor highlight = qxt_p().palette().color(QPalette::Highlight); + QLinearGradient gradient(x1, y1, x2, y2); + gradient.setColorAt(0, highlight.dark(120)); + gradient.setColorAt(1, highlight.light(108)); + painter->setBrush(gradient); + + if (orientation == Qt::Horizontal) + painter->setPen(QPen(highlight.dark(130), 0)); + else + painter->setPen(QPen(highlight.dark(150), 0)); +} + +void QxtSpanSliderPrivate::drawSpan(QStylePainter* painter, const QRect& rect) const +{ + QStyleOptionSlider opt; + initStyleOption(&opt); + const QSlider* p = &qxt_p(); + + // area + QRect groove = p->style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, p); + if (opt.orientation == Qt::Horizontal) + groove.adjust(0, 0, -1, 0); + else + groove.adjust(0, 0, 0, -1); + + // pen & brush + painter->setPen(QPen(p->palette().color(QPalette::Dark).light(110), 0)); + if (opt.orientation == Qt::Horizontal) + setupPainter(painter, opt.orientation, groove.center().x(), groove.top(), groove.center().x(), groove.bottom()); + else + setupPainter(painter, opt.orientation, groove.left(), groove.center().y(), groove.right(), groove.center().y()); + + // draw groove +#if QT_VERSION >= 0x040200 + painter->drawRect(rect.intersected(groove)); +#else // QT_VERSION < 0x040200 + painter->drawRect(rect.intersect(groove)); +#endif // QT_VERSION +} + +void QxtSpanSliderPrivate::drawHandle(QStylePainter* painter, SpanHandle handle) const +{ + QStyleOptionSlider opt; + initStyleOption(&opt, handle); + opt.subControls = QStyle::SC_SliderHandle; + QStyle::SubControl pressed = (handle == LowerHandle ? lowerPressed : upperPressed); + if (pressed == QStyle::SC_SliderHandle) + { + opt.activeSubControls = pressed; + opt.state |= QStyle::State_Sunken; + } + painter->drawComplexControl(QStyle::CC_Slider, opt); +} + +void QxtSpanSliderPrivate::triggerAction(QAbstractSlider::SliderAction action, bool main) +{ + int value = 0; + bool up = false; + const int min = qxt_p().minimum(); + const int max = qxt_p().maximum(); + const SpanHandle altControl = (mainControl == LowerHandle ? UpperHandle : LowerHandle); + switch (action) + { + case QAbstractSlider::SliderSingleStepAdd: + if ((main && mainControl == UpperHandle) || (!main && altControl == UpperHandle)) + { + value = qBound(min, upper + qxt_p().singleStep(), max); + up = true; + break; + } + value = qBound(min, lower + qxt_p().singleStep(), max); + break; + case QAbstractSlider::SliderSingleStepSub: + if ((main && mainControl == UpperHandle) || (!main && altControl == UpperHandle)) + { + value = qBound(min, upper - qxt_p().singleStep(), max); + up = true; + break; + } + value = qBound(min, lower - qxt_p().singleStep(), max); + break; + case QAbstractSlider::SliderToMinimum: + value = min; + if ((main && mainControl == UpperHandle) || (!main && altControl == UpperHandle)) + up = true; + break; + case QAbstractSlider::SliderToMaximum: + value = max; + if ((main && mainControl == UpperHandle) || (!main && altControl == UpperHandle)) + up = true; + break; + default: + qWarning("QxtSpanSliderPrivate::triggerAction: Unknown action"); + break; + } + + if (!up) + { + if (value > upper) + { + swapControls(); + qxt_p().setUpperValue(value); + } + else + { + qxt_p().setLowerValue(value); + } + } + else + { + if (value < lower) + { + swapControls(); + qxt_p().setLowerValue(value); + } + else + { + qxt_p().setUpperValue(value); + } + } +} + +void QxtSpanSliderPrivate::swapControls() +{ + qSwap(lower, upper); + qSwap(lowerPressed, upperPressed); + lastPressed = (lastPressed == LowerHandle ? UpperHandle : LowerHandle); + mainControl = (mainControl == LowerHandle ? UpperHandle : LowerHandle); +} + +void QxtSpanSliderPrivate::updateRange(int min, int max) +{ + Q_UNUSED(min); + Q_UNUSED(max); + // setSpan() takes care of keeping span in range + qxt_p().setSpan(lower, upper); +} + +/*! + \class QxtSpanSlider QxtSpanSlider + \ingroup QxtGui + \brief A QSlider with two handles. + + QxtSpanSlider is a slider with two handles. QxtSpanSlider is + handy for letting user to choose an span between min/max. + + The span color is calculated based on \b QPalette::Highlight. + + The keys are bound according to the following table: + + + + + + + + + + +
OrientationKeyHandle
Qt::HorizontalQt::Key_Leftlower
Qt::HorizontalQt::Key_Rightlower
Qt::HorizontalQt::Key_Upupper
Qt::HorizontalQt::Key_Downupper
Qt::VerticalQt::Key_Uplower
Qt::VerticalQt::Key_Downlower
Qt::VerticalQt::Key_Leftupper
Qt::VerticalQt::Key_Rightupper
+ + Keys are bound by the time the slider is created. A key is bound + to same handle for the lifetime of the slider. So even if the handle + representation might change from lower to upper, the same key binding + remains. + + \image html qxtspanslider.png "QxtSpanSlider in Plastique style." + + \note QxtSpanSlider inherits \b QSlider for implementation specific + reasons. Adjusting any single handle specific properties like +
    +
  • \b QAbstractSlider::sliderPosition
  • +
  • \b QAbstractSlider::value
  • +
+ has no effect. However, all slider specific properties like +
    +
  • \b QAbstractSlider::invertedAppearance
  • +
  • \b QAbstractSlider::invertedControls
  • +
  • \b QAbstractSlider::minimum
  • +
  • \b QAbstractSlider::maximum
  • +
  • \b QAbstractSlider::orientation
  • +
  • \b QAbstractSlider::pageStep
  • +
  • \b QAbstractSlider::singleStep
  • +
  • \b QSlider::tickInterval
  • +
  • \b QSlider::tickPosition
  • +
+ are taken into consideration. + */ + +/*! + \fn QxtSpanSlider::lowerValueChanged(int lower) + + This signal is emitted whenever the lower value has changed. + */ + +/*! + \fn QxtSpanSlider::upperValueChanged(int upper) + + This signal is emitted whenever the upper value has changed. + */ + +/*! + \fn QxtSpanSlider::spanChanged(int lower, int upper) + + This signal is emitted whenever the span has changed. + */ + +/*! + Constructs a new QxtSpanSlider with \a parent. + */ +QxtSpanSlider::QxtSpanSlider(QWidget* parent) : QSlider(parent) +{ + QXT_INIT_PRIVATE(QxtSpanSlider); + connect(this, SIGNAL(rangeChanged(int, int)), &qxt_d(), SLOT(updateRange(int, int))); +} + +/*! + Constructs a new QxtSpanSlider with \a orientation and \a parent. + */ +QxtSpanSlider::QxtSpanSlider(Qt::Orientation orientation, QWidget* parent) : QSlider(orientation, parent) +{ + QXT_INIT_PRIVATE(QxtSpanSlider); + connect(this, SIGNAL(rangeChanged(int, int)), &qxt_d(), SLOT(updateRange(int, int))); +} + +/*! + Destructs the slider. + */ +QxtSpanSlider::~QxtSpanSlider() +{} + +/*! + \property QxtSpanSlider::lowerValue + \brief This property holds the lower value of the span + */ +int QxtSpanSlider::lowerValue() const +{ + return qMin(qxt_d().lower, qxt_d().upper); +} + +void QxtSpanSlider::setLowerValue(int lower) +{ + setSpan(lower, qxt_d().upper); +} + +/*! + \property QxtSpanSlider::upperValue + \brief This property holds the upper value of the span + */ +int QxtSpanSlider::upperValue() const +{ + return qMax(qxt_d().lower, qxt_d().upper); +} + +void QxtSpanSlider::setUpperValue(int upper) +{ + setSpan(qxt_d().lower, upper); +} + +/*! + Sets the span from \a lower to \a upper. + \sa upperValue, lowerValue + */ +void QxtSpanSlider::setSpan(int lower, int upper) +{ + const int low = qBound(minimum(), qMin(lower, upper), maximum()); + const int upp = qBound(minimum(), qMax(lower, upper), maximum()); + if (low != qxt_d().lower || upp != qxt_d().upper) + { + if (low != qxt_d().lower) + { + qxt_d().lower = low; + emit lowerValueChanged(low); + } + if (upp != qxt_d().upper) + { + qxt_d().upper = upp; + emit upperValueChanged(upp); + } + emit spanChanged(qxt_d().lower, qxt_d().upper); + update(); + } +} + +void QxtSpanSlider::keyPressEvent(QKeyEvent* event) +{ + QSlider::keyPressEvent(event); + + bool main = true; + SliderAction action = SliderNoAction; + switch (event->key()) + { + case Qt::Key_Left: + main = (orientation() == Qt::Horizontal); + action = !invertedAppearance() ? SliderSingleStepSub : SliderSingleStepAdd; + break; + case Qt::Key_Right: + main = (orientation() == Qt::Horizontal); + action = !invertedAppearance() ? SliderSingleStepAdd : SliderSingleStepSub; + break; + case Qt::Key_Up: + main = (orientation() == Qt::Vertical); + action = invertedControls() ? SliderSingleStepSub : SliderSingleStepAdd; + break; + case Qt::Key_Down: + main = (orientation() == Qt::Vertical); + action = invertedControls() ? SliderSingleStepAdd : SliderSingleStepSub; + break; + case Qt::Key_Home: + main = (qxt_d().mainControl == QxtSpanSliderPrivate::LowerHandle); + action = SliderToMinimum; + break; + case Qt::Key_End: + main = (qxt_d().mainControl == QxtSpanSliderPrivate::UpperHandle); + action = SliderToMaximum; + break; + default: + event->ignore(); + break; + } + + if (action) + qxt_d().triggerAction(action, main); +} + +void QxtSpanSlider::mousePressEvent(QMouseEvent* event) +{ + if (minimum() == maximum() || (event->buttons() ^ event->button())) + { + event->ignore(); + return; + } + + qxt_d().handleMousePress(event->pos(), qxt_d().upperPressed, qxt_d().upper, QxtSpanSliderPrivate::UpperHandle); + if (qxt_d().upperPressed != QStyle::SC_SliderHandle) + qxt_d().handleMousePress(event->pos(), qxt_d().lowerPressed, qxt_d().lower, QxtSpanSliderPrivate::LowerHandle); + + event->accept(); +} + +void QxtSpanSlider::mouseMoveEvent(QMouseEvent* event) +{ + if (qxt_d().lowerPressed != QStyle::SC_SliderHandle && qxt_d().upperPressed != QStyle::SC_SliderHandle) + { + event->ignore(); + return; + } + + QStyleOptionSlider opt; + qxt_d().initStyleOption(&opt); + const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &opt, this); + int newPosition = qxt_d().pixelPosToRangeValue(qxt_d().pick(event->pos()) - qxt_d().offset); + if (m >= 0) + { + const QRect r = rect().adjusted(-m, -m, m, m); + if (!r.contains(event->pos())) + { + newPosition = qxt_d().position; + } + } + + if (qxt_d().lowerPressed == QStyle::SC_SliderHandle) + { + if (newPosition > qxt_d().upper) + { + qxt_d().swapControls(); + setUpperValue(newPosition); + } + else + { + setLowerValue(newPosition); + } + } + else if (qxt_d().upperPressed == QStyle::SC_SliderHandle) + { + if (newPosition < qxt_d().lower) + { + qxt_d().swapControls(); + setLowerValue(newPosition); + } + else + { + setUpperValue(newPosition); + } + } + event->accept(); +} + +void QxtSpanSlider::mouseReleaseEvent(QMouseEvent* event) +{ + QSlider::mouseReleaseEvent(event); + qxt_d().lowerPressed = QStyle::SC_None; + qxt_d().upperPressed = QStyle::SC_None; + update(); +} + +void QxtSpanSlider::paintEvent(QPaintEvent* event) +{ + Q_UNUSED(event); + QStylePainter painter(this); + + // ticks + QStyleOptionSlider opt; + qxt_d().initStyleOption(&opt); + opt.subControls = QStyle::SC_SliderTickmarks; + painter.drawComplexControl(QStyle::CC_Slider, opt); + + // groove + opt.sliderPosition = 0; + opt.subControls = QStyle::SC_SliderGroove; + painter.drawComplexControl(QStyle::CC_Slider, opt); + + // handle rects + opt.sliderPosition = qxt_d().lower; + const QRect lr = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + const int lrv = qxt_d().pick(lr.center()); + opt.sliderPosition = qxt_d().upper; + const QRect ur = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + const int urv = qxt_d().pick(ur.center()); + + // span + const int minv = qMin(lrv, urv); + const int maxv = qMax(lrv, urv); + const QPoint c = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this).center(); + QRect spanRect; + if (orientation() == Qt::Horizontal) + spanRect = QRect(QPoint(minv, c.y()-2), QPoint(maxv, c.y()+1)); + else + spanRect = QRect(QPoint(c.x()-2, minv), QPoint(c.x()+1, maxv)); + qxt_d().drawSpan(&painter, spanRect); + + // handles + switch (qxt_d().lastPressed) + { + case QxtSpanSliderPrivate::LowerHandle: + qxt_d().drawHandle(&painter, QxtSpanSliderPrivate::UpperHandle); + qxt_d().drawHandle(&painter, QxtSpanSliderPrivate::LowerHandle); + break; + case QxtSpanSliderPrivate::UpperHandle: + default: + qxt_d().drawHandle(&painter, QxtSpanSliderPrivate::LowerHandle); + qxt_d().drawHandle(&painter, QxtSpanSliderPrivate::UpperHandle); + break; + } +}