824 lines
22 KiB
C++
Executable File
824 lines
22 KiB
C++
Executable File
|
|
|
|
|
|
|
|
|
|
|
|
#include "lts_range_slider.h"
|
|
|
|
|
|
#include <QDebug>
|
|
#include <QMouseEvent>
|
|
#include <QKeyEvent>
|
|
#include <QStyleOptionSlider>
|
|
#include <QStylePainter>
|
|
#include <QStyle>
|
|
#include <QToolTip>
|
|
|
|
namespace LtsWidgets
|
|
{
|
|
|
|
class LtsRangeSliderPrivate
|
|
{
|
|
Q_DECLARE_PUBLIC(LtsRangeSlider)
|
|
protected:
|
|
LtsRangeSlider *const q_ptr;
|
|
public:
|
|
|
|
|
|
enum Handle
|
|
{
|
|
NoHandle = 0x0,
|
|
MinimumHandle = 0x1,
|
|
MaximumHandle = 0x2
|
|
};
|
|
Q_DECLARE_FLAGS(Handles, Handle)
|
|
|
|
explicit LtsRangeSliderPrivate(LtsRangeSlider &object);
|
|
void init();
|
|
|
|
|
|
|
|
|
|
|
|
Handle handleAtPos(const QPoint &pos, QRect &handleRect) const;
|
|
|
|
|
|
int pixelPosToRangeValue(int pos) const;
|
|
int pixelPosFromRangeValue(int val) const;
|
|
|
|
|
|
void drawMinimumSlider(QStylePainter *painter) const;
|
|
void drawMaximumSlider(QStylePainter *painter) const;
|
|
|
|
|
|
int m_minimumValue = 0;
|
|
int m_maximumValue = 100;
|
|
|
|
|
|
int m_minimumPosition = 0;
|
|
int m_maximumPosition = 100;
|
|
|
|
|
|
QStyle::SubControl m_minimumSliderSelected = QStyle::SC_None;
|
|
QStyle::SubControl m_maximumSliderSelected = QStyle::SC_None;
|
|
|
|
|
|
|
|
int m_subclassClickOffset = 0;
|
|
|
|
|
|
|
|
int m_subclassPosition = 0;
|
|
|
|
|
|
float m_subclassWidth = 0;
|
|
|
|
LtsRangeSliderPrivate::Handles m_selectedHandles = {};
|
|
|
|
|
|
|
|
bool m_symmetricMoves = false;
|
|
|
|
QString m_handleToolTip;
|
|
|
|
private:
|
|
Q_DISABLE_COPY(LtsRangeSliderPrivate)
|
|
};
|
|
|
|
|
|
LtsRangeSliderPrivate::LtsRangeSliderPrivate(LtsRangeSlider &object)
|
|
: q_ptr(&object)
|
|
{}
|
|
|
|
|
|
void LtsRangeSliderPrivate::init()
|
|
{
|
|
Q_Q(LtsRangeSlider);
|
|
m_minimumValue = q->minimum();
|
|
m_maximumValue = q->maximum();
|
|
m_minimumPosition = q->minimum();
|
|
m_maximumPosition = q->maximum();
|
|
q->connect(q, &LtsRangeSlider::rangeChanged, q, &LtsRangeSlider::onRangeChanged);
|
|
}
|
|
|
|
|
|
LtsRangeSliderPrivate::Handle LtsRangeSliderPrivate::handleAtPos(const QPoint &pos, QRect &handleRect)const
|
|
{
|
|
Q_Q(const LtsRangeSlider);
|
|
|
|
QStyleOptionSlider option;
|
|
q->initStyleOption(&option);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
option.sliderPosition = m_minimumPosition;
|
|
option.sliderValue = m_minimumValue;
|
|
|
|
QStyle::SubControl minimumControl = q->style()->hitTestComplexControl(
|
|
QStyle::CC_Slider, &option, pos, q);
|
|
QRect minimumHandleRect = q->style()->subControlRect(
|
|
QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
|
|
|
|
|
|
option.sliderPosition = m_maximumPosition;
|
|
option.sliderValue = m_maximumValue;
|
|
|
|
QStyle::SubControl maximumControl = q->style()->hitTestComplexControl(QStyle::CC_Slider, &option, pos, q);
|
|
QRect maximumHandleRect = q->style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderHandle, q);
|
|
|
|
|
|
if (minimumControl == QStyle::SC_SliderHandle &&
|
|
maximumControl == QStyle::SC_SliderHandle)
|
|
{
|
|
int minDist = 0;
|
|
int maxDist = 0;
|
|
if (q->orientation() == Qt::Horizontal)
|
|
{
|
|
minDist = pos.x() - minimumHandleRect.left();
|
|
maxDist = maximumHandleRect.right() - pos.x();
|
|
}
|
|
else
|
|
{
|
|
minDist = minimumHandleRect.bottom() - pos.y();
|
|
maxDist = pos.y() - maximumHandleRect.top();
|
|
}
|
|
Q_ASSERT(minDist >= 0 && maxDist >= 0);
|
|
minimumControl = minDist < maxDist ? minimumControl : QStyle::SC_None;
|
|
}
|
|
|
|
if (maximumControl == QStyle::SC_SliderHandle)
|
|
{
|
|
handleRect = maximumHandleRect;
|
|
return MaximumHandle;
|
|
}
|
|
else if (minimumControl == QStyle::SC_SliderHandle)
|
|
{
|
|
handleRect = minimumHandleRect;
|
|
return MinimumHandle;
|
|
}
|
|
|
|
handleRect = minimumHandleRect.united(maximumHandleRect);
|
|
return NoHandle;
|
|
}
|
|
|
|
|
|
|
|
|
|
int LtsRangeSliderPrivate::pixelPosToRangeValue(int pos) const
|
|
{
|
|
Q_Q(const LtsRangeSlider);
|
|
QStyleOptionSlider option;
|
|
q->initStyleOption(&option);
|
|
|
|
QRect gr = q->style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderGroove,
|
|
q);
|
|
QRect sr = q->style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderHandle,
|
|
q);
|
|
int sliderMin, sliderMax, sliderLength;
|
|
if (option.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(q->minimum(),
|
|
q->maximum(),
|
|
pos - sliderMin,
|
|
sliderMax - sliderMin,
|
|
option.upsideDown);
|
|
}
|
|
|
|
|
|
int LtsRangeSliderPrivate::pixelPosFromRangeValue(int val) const
|
|
{
|
|
Q_Q(const LtsRangeSlider);
|
|
QStyleOptionSlider option;
|
|
q->initStyleOption(&option);
|
|
|
|
QRect gr = q->style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderGroove,
|
|
q);
|
|
QRect sr = q->style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderHandle,
|
|
q);
|
|
int sliderMin, sliderMax, sliderLength;
|
|
if (option.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::sliderPositionFromValue(q->minimum(),
|
|
q->maximum(),
|
|
val,
|
|
sliderMax - sliderMin,
|
|
option.upsideDown) + sliderMin;
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSliderPrivate::drawMinimumSlider(QStylePainter *painter) const
|
|
{
|
|
Q_Q(const LtsRangeSlider);
|
|
QStyleOptionSlider option;
|
|
q->initMinimumSliderStyleOption(&option);
|
|
|
|
option.subControls = QStyle::SC_SliderHandle;
|
|
option.sliderValue = m_minimumValue;
|
|
option.sliderPosition = m_minimumPosition;
|
|
if (q->isMinimumSliderDown())
|
|
{
|
|
option.activeSubControls = QStyle::SC_SliderHandle;
|
|
option.state |= QStyle::State_Sunken;
|
|
}
|
|
#ifdef Q_OS_MAC
|
|
|
|
QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
|
|
QStyle::SC_SliderHandle, q);
|
|
painter->setClipRect(clip);
|
|
#endif
|
|
painter->drawComplexControl(QStyle::CC_Slider, option);
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSliderPrivate::drawMaximumSlider(QStylePainter *painter) const
|
|
{
|
|
Q_Q(const LtsRangeSlider);
|
|
QStyleOptionSlider option;
|
|
q->initMaximumSliderStyleOption(&option);
|
|
|
|
option.subControls = QStyle::SC_SliderHandle;
|
|
option.sliderValue = m_maximumValue;
|
|
option.sliderPosition = m_maximumPosition;
|
|
if (q->isMaximumSliderDown())
|
|
{
|
|
option.activeSubControls = QStyle::SC_SliderHandle;
|
|
option.state |= QStyle::State_Sunken;
|
|
}
|
|
#ifdef Q_OS_MAC
|
|
|
|
QRect clip = q->style()->subControlRect(QStyle::CC_Slider, &option,
|
|
QStyle::SC_SliderHandle, q);
|
|
painter->setClipRect(clip);
|
|
#endif
|
|
painter->drawComplexControl(QStyle::CC_Slider, option);
|
|
}
|
|
|
|
|
|
LtsRangeSlider::LtsRangeSlider(Qt::Orientation o,
|
|
QWidget *parent)
|
|
: QSlider(o, parent)
|
|
, d_ptr(new LtsRangeSliderPrivate(*this))
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
d->init();
|
|
}
|
|
|
|
|
|
LtsRangeSlider::LtsRangeSlider(LtsRangeSliderPrivate *impl, Qt::Orientation o,
|
|
QWidget *parent)
|
|
: QSlider(o, parent)
|
|
, d_ptr(impl)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
d->init();
|
|
}
|
|
|
|
|
|
LtsRangeSlider::~LtsRangeSlider()
|
|
{
|
|
}
|
|
|
|
|
|
int LtsRangeSlider::minimumValue() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_minimumValue;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setMinimumValue(int min)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
setValues(min, qMax(d->m_maximumValue, min));
|
|
}
|
|
|
|
|
|
int LtsRangeSlider::maximumValue() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_maximumValue;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setMaximumValue(int max)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
setValues(qMin(d->m_minimumValue, max), max);
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setValues(int min, int max)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
const int minValue = qBound(minimum(), qMin(min, max), maximum());
|
|
const int maxValue = qBound(minimum(), qMax(min, max), maximum());
|
|
bool emitMinValChanged = (minValue != d->m_minimumValue);
|
|
bool emitMaxValChanged = (maxValue != d->m_maximumValue);
|
|
|
|
d->m_minimumValue = minValue;
|
|
d->m_maximumValue = maxValue;
|
|
|
|
bool emitMinPosChanged = (minValue != d->m_minimumPosition);
|
|
bool emitMaxPosChanged = (maxValue != d->m_maximumPosition);
|
|
d->m_minimumPosition = minValue;
|
|
d->m_maximumPosition = maxValue;
|
|
|
|
if (isSliderDown())
|
|
{
|
|
if (emitMinPosChanged || emitMaxPosChanged)
|
|
emit positionsChanged(d->m_minimumPosition, d->m_maximumPosition);
|
|
if (emitMinPosChanged)
|
|
emit minimumPositionChanged(d->m_minimumPosition);
|
|
if (emitMaxPosChanged)
|
|
emit maximumPositionChanged(d->m_maximumPosition);
|
|
}
|
|
if (emitMinValChanged || emitMaxValChanged)
|
|
emit valuesChanged(d->m_minimumValue, d->m_maximumValue);
|
|
|
|
if (emitMinValChanged)
|
|
emit minimumValueChanged(d->m_minimumValue);
|
|
|
|
if (emitMaxValChanged)
|
|
emit maximumValueChanged(d->m_maximumValue);
|
|
|
|
if (emitMinPosChanged || emitMaxPosChanged ||
|
|
emitMinValChanged || emitMaxValChanged)
|
|
update();
|
|
}
|
|
|
|
|
|
int LtsRangeSlider::minimumPosition() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_minimumPosition;
|
|
}
|
|
|
|
|
|
int LtsRangeSlider::maximumPosition() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_maximumPosition;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setMinimumPosition(int min)
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
setPositions(min, qMax(min, d->m_maximumPosition));
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setMaximumPosition(int max)
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
setPositions(qMin(d->m_minimumPosition, max), max);
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setPositions(int min, int max)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
const int minPosition = qBound(minimum(), qMin(min, max), maximum());
|
|
const int maxPosition = qBound(minimum(), qMax(min, max), maximum());
|
|
|
|
bool emitMinPosChanged = (minPosition != d->m_minimumPosition);
|
|
bool emitMaxPosChanged = (maxPosition != d->m_maximumPosition);
|
|
|
|
if (!emitMinPosChanged && !emitMaxPosChanged)
|
|
return;
|
|
|
|
d->m_minimumPosition = minPosition;
|
|
d->m_maximumPosition = maxPosition;
|
|
|
|
if (!hasTracking())
|
|
update();
|
|
|
|
if (isSliderDown())
|
|
{
|
|
if (emitMinPosChanged)
|
|
emit minimumPositionChanged(d->m_minimumPosition);
|
|
if (emitMaxPosChanged)
|
|
emit maximumPositionChanged(d->m_maximumPosition);
|
|
if (emitMinPosChanged || emitMaxPosChanged)
|
|
emit positionsChanged(d->m_minimumPosition, d->m_maximumPosition);
|
|
}
|
|
if (hasTracking())
|
|
{
|
|
triggerAction(SliderMove);
|
|
setValues(d->m_minimumPosition, d->m_maximumPosition);
|
|
}
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setSymmetricMoves(bool symmetry)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
d->m_symmetricMoves = symmetry;
|
|
}
|
|
|
|
|
|
bool LtsRangeSlider::symmetricMoves() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_symmetricMoves;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::onRangeChanged(int minimum, int maximum)
|
|
{
|
|
Q_UNUSED(minimum);
|
|
Q_UNUSED(maximum);
|
|
Q_D(LtsRangeSlider);
|
|
setValues(d->m_minimumValue, d->m_maximumValue);
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSlider::paintEvent(QPaintEvent *)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
QStyleOptionSlider option;
|
|
initStyleOption(&option);
|
|
|
|
QStylePainter painter(this);
|
|
|
|
|
|
|
|
|
|
painter.setPen(Qt::lightGray);
|
|
if (option.orientation == Qt::Horizontal)
|
|
{
|
|
painter.drawLine(option.rect.left(), option.rect.top(), option.rect.left(), option.rect.bottom());
|
|
painter.drawRect(option.rect.left(), option.rect.center().y() - 1, option.rect.right() - option.rect.left(), 3);
|
|
painter.drawLine(option.rect.right(), option.rect.top(), option.rect.right(), option.rect.bottom());
|
|
}
|
|
else
|
|
{
|
|
painter.drawLine(option.rect.left(), option.rect.top(), option.rect.right(), option.rect.top());
|
|
painter.drawRect(option.rect.center().x() - 1, option.rect.top(), 3, option.rect.top() - option.rect.bottom());
|
|
painter.drawLine(option.rect.center().x(), option.rect.top(), option.rect.center().x(), option.rect.bottom());
|
|
painter.drawLine(option.rect.left(), option.rect.bottom(), option.rect.right(), option.rect.bottom());
|
|
}
|
|
|
|
|
|
option.subControls = QStyle::SC_SliderGroove;
|
|
|
|
|
|
|
|
option.sliderValue = minimum() - maximum();
|
|
option.sliderPosition = minimum() - maximum();
|
|
option.subControls &= ~QStyle::SC_SliderGroove;
|
|
painter.drawComplexControl(QStyle::CC_Slider, option);
|
|
option.subControls |= QStyle::SC_SliderGroove;
|
|
|
|
option.sliderPosition = d->m_minimumPosition;
|
|
const QRect lr = style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderHandle,
|
|
this);
|
|
|
|
option.sliderPosition = d->m_maximumPosition;
|
|
const QRect ur = style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderHandle,
|
|
this);
|
|
|
|
QRect sr = style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderGroove,
|
|
this);
|
|
QRect rangeBox;
|
|
if (option.orientation == Qt::Horizontal)
|
|
{
|
|
rangeBox = QRect(QPoint(qMin(lr.center().x(), ur.center().x()), sr.center().y() - 2),
|
|
QPoint(qMax(lr.center().x(), ur.center().x()), sr.center().y() + 1));
|
|
}
|
|
else
|
|
{
|
|
rangeBox = QRect(QPoint(sr.center().x() - 2, qMin(lr.center().y(), ur.center().y())),
|
|
QPoint(sr.center().x() + 1, qMax(lr.center().y(), ur.center().y())));
|
|
}
|
|
|
|
|
|
|
|
|
|
QRect groove = style()->subControlRect(QStyle::CC_Slider,
|
|
&option,
|
|
QStyle::SC_SliderGroove,
|
|
this);
|
|
groove.adjust(0, 0, -1, 0);
|
|
|
|
|
|
|
|
QColor highlight = palette().color(QPalette::Normal, QPalette::Highlight);
|
|
QLinearGradient gradient;
|
|
if (option.orientation == Qt::Horizontal)
|
|
gradient = QLinearGradient(groove.center().x(), groove.top(), groove.center().x(), groove.bottom());
|
|
else
|
|
gradient = QLinearGradient(groove.left(), groove.center().y(), groove.right(), groove.center().y());
|
|
|
|
|
|
|
|
|
|
|
|
gradient.setColorAt(0, highlight.darker(120));
|
|
gradient.setColorAt(1, highlight.lighter(160));
|
|
|
|
painter.setPen(QPen(highlight.darker(150), 0));
|
|
painter.setBrush(gradient);
|
|
painter.drawRect(rangeBox.intersected(groove));
|
|
|
|
|
|
|
|
|
|
if (isMinimumSliderDown())
|
|
{
|
|
painter.setClipRect(ur);
|
|
d->drawMaximumSlider(&painter);
|
|
painter.setClipRect(lr);
|
|
d->drawMinimumSlider(&painter);
|
|
}
|
|
else
|
|
{
|
|
painter.setClipRect(lr);
|
|
d->drawMinimumSlider(&painter);
|
|
painter.setClipRect(ur);
|
|
d->drawMaximumSlider(&painter);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSlider::mousePressEvent(QMouseEvent *ev)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
if (minimum() == maximum() || (ev->buttons() ^ ev->button()))
|
|
{
|
|
ev->ignore();
|
|
return;
|
|
}
|
|
int mepos = orientation() == Qt::Horizontal ? ev->pos().x() : ev->pos().y();
|
|
|
|
QStyleOptionSlider option;
|
|
initStyleOption(&option);
|
|
|
|
QRect handleRect;
|
|
LtsRangeSliderPrivate::Handle handle_ = d->handleAtPos(ev->pos(), handleRect);
|
|
|
|
if (handle_ != LtsRangeSliderPrivate::NoHandle)
|
|
{
|
|
if (ev->buttons() == Qt::RightButton)
|
|
{
|
|
d->m_subclassPosition = (d->m_minimumPosition + d->m_maximumPosition) / 2.;
|
|
d->m_subclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_subclassPosition);
|
|
d->m_subclassWidth = (d->m_maximumPosition - d->m_minimumPosition) / 2.;
|
|
|
|
setSliderDown(true);
|
|
if (!isMinimumSliderDown() || !isMaximumSliderDown())
|
|
{
|
|
d->m_selectedHandles = QFlags<LtsRangeSliderPrivate::Handle>(LtsRangeSliderPrivate::MinimumHandle) |
|
|
QFlags<LtsRangeSliderPrivate::Handle>(LtsRangeSliderPrivate::MaximumHandle);
|
|
QRect sr = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);
|
|
update(handleRect.united(sr));
|
|
}
|
|
ev->accept();
|
|
return;
|
|
}
|
|
|
|
d->m_subclassPosition = (handle_ == LtsRangeSliderPrivate::MinimumHandle) ? d->m_minimumPosition : d->m_maximumPosition;
|
|
|
|
|
|
d->m_subclassClickOffset = mepos - (orientation() == Qt::Horizontal ? handleRect.left() : handleRect.top());
|
|
|
|
setSliderDown(true);
|
|
|
|
if (d->m_selectedHandles != handle_)
|
|
{
|
|
d->m_selectedHandles = handle_;
|
|
update(handleRect);
|
|
}
|
|
|
|
ev->accept();
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
QStyle::SubControl control = style()->hitTestComplexControl(QStyle::CC_Slider, &option, ev->pos(), this);
|
|
QRect sr = style()->subControlRect(QStyle::CC_Slider, &option, QStyle::SC_SliderGroove, this);
|
|
int minCenter = (orientation() == Qt::Horizontal ? handleRect.left() : handleRect.top());
|
|
int maxCenter = (orientation() == Qt::Horizontal ? handleRect.right() : handleRect.bottom());
|
|
if (control == QStyle::SC_SliderGroove && mepos > minCenter && mepos < maxCenter)
|
|
{
|
|
|
|
d->m_subclassPosition = (d->m_minimumPosition + d->m_maximumPosition) / 2.;
|
|
d->m_subclassClickOffset = mepos - d->pixelPosFromRangeValue(d->m_subclassPosition);
|
|
d->m_subclassWidth = (d->m_maximumPosition - d->m_minimumPosition) / 2.;
|
|
|
|
setSliderDown(true);
|
|
if (!isMinimumSliderDown() || !isMaximumSliderDown())
|
|
{
|
|
d->m_selectedHandles = QFlags<LtsRangeSliderPrivate::Handle>(LtsRangeSliderPrivate::MinimumHandle) |
|
|
QFlags<LtsRangeSliderPrivate::Handle>(LtsRangeSliderPrivate::MaximumHandle);
|
|
update(handleRect.united(sr));
|
|
}
|
|
ev->accept();
|
|
return;
|
|
}
|
|
ev->ignore();
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSlider::mouseMoveEvent(QMouseEvent *ev)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
if (!d->m_selectedHandles)
|
|
{
|
|
ev->ignore();
|
|
return;
|
|
}
|
|
int mepos = orientation() == Qt::Horizontal ? ev->pos().x() : ev->pos().y();
|
|
|
|
QStyleOptionSlider option;
|
|
initStyleOption(&option);
|
|
|
|
|
|
if (isMinimumSliderDown() && isMaximumSliderDown())
|
|
{
|
|
int newPosition = d->pixelPosToRangeValue(mepos);
|
|
int newMinPosition = newPosition - static_cast<int>(d->m_subclassWidth);
|
|
int newMaxPosition = newPosition + static_cast<int>(d->m_subclassWidth + .5);
|
|
|
|
if (newMinPosition < minimum())
|
|
{
|
|
newMinPosition = minimum();
|
|
newMaxPosition = newMinPosition + (d->m_maximumPosition - d->m_minimumPosition);
|
|
}
|
|
else if (newMaxPosition > maximum())
|
|
{
|
|
newMaxPosition = maximum();
|
|
newMinPosition = newMaxPosition - (d->m_maximumPosition - d->m_minimumPosition);
|
|
}
|
|
setPositions(newMinPosition, newMaxPosition);
|
|
ev->accept();
|
|
return;
|
|
}
|
|
|
|
const int m = style()->pixelMetric(QStyle::PM_MaximumDragDistance, &option, this);
|
|
|
|
int newPosition = d->pixelPosToRangeValue(mepos - d->m_subclassClickOffset);
|
|
|
|
if (m >= 0)
|
|
{
|
|
const QRect r = rect().adjusted(-m, -m, m, m);
|
|
if (!r.contains(ev->pos()))
|
|
newPosition = d->m_subclassPosition;
|
|
}
|
|
|
|
|
|
if (isMinimumSliderDown() && !isMaximumSliderDown())
|
|
{
|
|
double newMinPos = qMin(newPosition, d->m_maximumPosition);
|
|
setPositions(newMinPos, d->m_maximumPosition + (d->m_symmetricMoves ? d->m_minimumPosition - newMinPos : 0));
|
|
}
|
|
|
|
else if (isMaximumSliderDown() && !isMinimumSliderDown())
|
|
{
|
|
double newMaxPos = qMax(d->m_minimumPosition, newPosition);
|
|
setPositions(d->m_minimumPosition - (d->m_symmetricMoves ? newMaxPos - d->m_maximumPosition : 0), newMaxPos);
|
|
}
|
|
ev->accept();
|
|
}
|
|
|
|
|
|
|
|
void LtsRangeSlider::mouseReleaseEvent(QMouseEvent *ev)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
QSlider::mouseReleaseEvent(ev);
|
|
|
|
setSliderDown(false);
|
|
d->m_selectedHandles = {};
|
|
|
|
update();
|
|
}
|
|
|
|
|
|
bool LtsRangeSlider::isMinimumSliderDown() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_selectedHandles & LtsRangeSliderPrivate::MinimumHandle;
|
|
}
|
|
|
|
|
|
bool LtsRangeSlider::isMaximumSliderDown() const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_selectedHandles & LtsRangeSliderPrivate::MaximumHandle;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::initMinimumSliderStyleOption(QStyleOptionSlider *option) const
|
|
{
|
|
initStyleOption(option);
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::initMaximumSliderStyleOption(QStyleOptionSlider *option) const
|
|
{
|
|
initStyleOption(option);
|
|
}
|
|
|
|
|
|
QString LtsRangeSlider::handleToolTip()const
|
|
{
|
|
Q_D(const LtsRangeSlider);
|
|
return d->m_handleToolTip;
|
|
}
|
|
|
|
|
|
void LtsRangeSlider::setHandleToolTip(const QString &toolTip)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
d->m_handleToolTip = toolTip;
|
|
}
|
|
|
|
|
|
bool LtsRangeSlider::event(QEvent *event)
|
|
{
|
|
Q_D(LtsRangeSlider);
|
|
switch (event->type())
|
|
{
|
|
case QEvent::ToolTip:
|
|
{
|
|
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
|
|
QStyleOptionSlider opt;
|
|
|
|
opt.sliderPosition = d->m_minimumPosition;
|
|
opt.sliderValue = d->m_minimumValue;
|
|
initStyleOption(&opt);
|
|
QStyle::SubControl hoveredControl = style()->hitTestComplexControl(QStyle::CC_Slider, &opt, helpEvent->pos(), this);
|
|
if (!d->m_handleToolTip.isEmpty() && hoveredControl == QStyle::SC_SliderHandle)
|
|
{
|
|
QToolTip::showText(helpEvent->globalPos(), d->m_handleToolTip.arg(minimumValue()));
|
|
event->accept();
|
|
return true;
|
|
}
|
|
|
|
opt.sliderPosition = d->m_maximumPosition;
|
|
opt.sliderValue = d->m_maximumValue;
|
|
initStyleOption(&opt);
|
|
hoveredControl = style()->hitTestComplexControl(QStyle::CC_Slider, &opt, helpEvent->pos(), this);
|
|
if (!d->m_handleToolTip.isEmpty() && hoveredControl == QStyle::SC_SliderHandle)
|
|
{
|
|
QToolTip::showText(helpEvent->globalPos(), d->m_handleToolTip.arg(maximumValue()));
|
|
event->accept();
|
|
return true;
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return QSlider::event(event);
|
|
}
|
|
|
|
}
|