RangeSlider
This commit is contained in:
266
libs/widgets/rangeslider.cpp
Normal file
266
libs/widgets/rangeslider.cpp
Normal file
@@ -0,0 +1,266 @@
|
||||
#include "rangeslider.h"
|
||||
#include "qad_types.h"
|
||||
#include <QPalette>
|
||||
|
||||
|
||||
RangeSlider::RangeSlider(QWidget * parent)
|
||||
: QWidget(parent),
|
||||
m_minimum(0),
|
||||
m_maximum(100),
|
||||
m_lowerValue(0),
|
||||
m_upperValue(100),
|
||||
mFirstHandlePressed(false),
|
||||
mSecondHandlePressed(false),
|
||||
orientation(Qt::Horizontal),
|
||||
m_mode(DoubleHandles)
|
||||
{init();}
|
||||
|
||||
|
||||
RangeSlider::RangeSlider(Qt::Orientation ori, Mode m, QWidget * parent)
|
||||
: QWidget(parent),
|
||||
m_minimum(0),
|
||||
m_maximum(100),
|
||||
m_lowerValue(0),
|
||||
m_upperValue(100),
|
||||
mFirstHandlePressed(false),
|
||||
mSecondHandlePressed(false),
|
||||
orientation(ori),
|
||||
m_mode(m)
|
||||
{init();}
|
||||
|
||||
|
||||
void RangeSlider::init() {
|
||||
setMouseTracking(true);
|
||||
scHandleSideLength = 16*lineThickness();
|
||||
scSliderBarHeight = 8*lineThickness();
|
||||
scLeftRightMargin = 2*lineThickness();
|
||||
}
|
||||
|
||||
void RangeSlider::paintEvent(QPaintEvent *) {
|
||||
QPainter painter(this);
|
||||
// Background
|
||||
QRectF backgroundRect;
|
||||
if(orientation == Qt::Horizontal)
|
||||
backgroundRect = QRectF(scLeftRightMargin, (height() - scSliderBarHeight) / 2, width() - scLeftRightMargin * 2, scSliderBarHeight);
|
||||
else
|
||||
backgroundRect = QRectF((width() - scSliderBarHeight) / 2, scLeftRightMargin, scSliderBarHeight, height() - scLeftRightMargin*2);
|
||||
|
||||
QPen pen(palette().color(QPalette::Disabled, QPalette::Text));
|
||||
painter.setPen(pen);
|
||||
if (isEnabled()) {
|
||||
painter.setBrush(palette().color(QPalette::Active, QPalette::Base));
|
||||
} else {
|
||||
painter.setBrush(palette().color(QPalette::Disabled, QPalette::Base));
|
||||
}
|
||||
painter.drawRect(backgroundRect);
|
||||
|
||||
// First value handle rect
|
||||
painter.setPen(pen);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setBrush(palette().color(QPalette::Active, QPalette::Button));
|
||||
QRectF leftHandleRect = firstHandleRect();
|
||||
if(m_mode.testFlag(LeftHandle))
|
||||
painter.drawEllipse(leftHandleRect);
|
||||
|
||||
// Second value handle rect
|
||||
QRectF rightHandleRect = secondHandleRect();
|
||||
if(m_mode.testFlag(RightHandle))
|
||||
painter.drawEllipse(rightHandleRect);
|
||||
|
||||
// Handles
|
||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||
QRectF selectedRect(backgroundRect);
|
||||
if(orientation == Qt::Horizontal) {
|
||||
selectedRect.setLeft((m_mode.testFlag(LeftHandle) ? leftHandleRect.right() : leftHandleRect.left()) + 0.5);
|
||||
selectedRect.setRight((m_mode.testFlag(RightHandle) ? rightHandleRect.left() : rightHandleRect.right()) - 0.5);
|
||||
} else {
|
||||
selectedRect.setTop((m_mode.testFlag(LeftHandle) ? leftHandleRect.bottom() : leftHandleRect.top()) + 0.5);
|
||||
selectedRect.setBottom((m_mode.testFlag(RightHandle) ? rightHandleRect.top() : rightHandleRect.bottom()) - 0.5);
|
||||
}
|
||||
if (isEnabled()) {
|
||||
painter.setBrush(palette().color(QPalette::Active, QPalette::Highlight));
|
||||
} else {
|
||||
painter.setBrush(palette().color(QPalette::Disabled, QPalette::Text));
|
||||
}
|
||||
painter.drawRect(selectedRect);
|
||||
}
|
||||
|
||||
|
||||
QRectF RangeSlider::firstHandleRect() const {
|
||||
float percentage = (m_lowerValue - m_minimum) * 1.0 / interval();
|
||||
return handleRect(percentage * validLength() + scLeftRightMargin);
|
||||
}
|
||||
|
||||
|
||||
QRectF RangeSlider::secondHandleRect() const {
|
||||
float percentage = (m_upperValue - m_minimum) * 1.0 / interval();
|
||||
return handleRect(percentage * validLength() + scLeftRightMargin + (m_mode.testFlag(LeftHandle) ? scHandleSideLength : 0));
|
||||
}
|
||||
|
||||
|
||||
QRectF RangeSlider::handleRect(int value) const {
|
||||
if(orientation == Qt::Horizontal)
|
||||
return QRect(value, (height()-scHandleSideLength) / 2, scHandleSideLength, scHandleSideLength);
|
||||
else
|
||||
return QRect((width()-scHandleSideLength) / 2, value, scHandleSideLength, scHandleSideLength);
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::mousePressEvent(QMouseEvent* e) {
|
||||
if(e->buttons() & Qt::LeftButton) {
|
||||
int posCheck, posMax, posValue, firstHandleRectPosValue, secondHandleRectPosValue;
|
||||
posCheck = (orientation == Qt::Horizontal) ? e->pos().y() : e->pos().x();
|
||||
posMax = (orientation == Qt::Horizontal) ? height() : width();
|
||||
posValue = (orientation == Qt::Horizontal) ? e->pos().x() : e->pos().y();
|
||||
firstHandleRectPosValue = (orientation == Qt::Horizontal) ? firstHandleRect().x() : firstHandleRect().y();
|
||||
secondHandleRectPosValue = (orientation == Qt::Horizontal) ? secondHandleRect().x() : secondHandleRect().y();
|
||||
|
||||
mSecondHandlePressed = secondHandleRect().contains(e->pos());
|
||||
mFirstHandlePressed = !mSecondHandlePressed && firstHandleRect().contains(e->pos());
|
||||
if(mFirstHandlePressed) {
|
||||
mDelta = posValue - (firstHandleRectPosValue + scHandleSideLength / 2);
|
||||
} else if(mSecondHandlePressed) {
|
||||
mDelta = posValue - (secondHandleRectPosValue + scHandleSideLength / 2);
|
||||
}
|
||||
if(posCheck >= 2 && posCheck <= posMax - 2) {
|
||||
int step = interval() / 10 < 1 ? 1 : interval() / 10;
|
||||
if(posValue < firstHandleRectPosValue)
|
||||
setLowerValue(m_lowerValue - step);
|
||||
else if(((posValue > firstHandleRectPosValue + scHandleSideLength) || !m_mode.testFlag(LeftHandle))
|
||||
&& ((posValue < secondHandleRectPosValue) || !m_mode.testFlag(RightHandle)))
|
||||
{
|
||||
if(m_mode.testFlag(DoubleHandles)) {
|
||||
if(posValue - (firstHandleRectPosValue + scHandleSideLength) <
|
||||
(secondHandleRectPosValue - (firstHandleRectPosValue + scHandleSideLength)) / 2) {
|
||||
setLowerValue((m_lowerValue + step < m_upperValue) ? m_lowerValue + step : m_upperValue);
|
||||
} else {
|
||||
setUpperValue((m_upperValue - step > m_lowerValue) ? m_upperValue - step : m_lowerValue);
|
||||
}
|
||||
} else if(m_mode.testFlag(LeftHandle)) {
|
||||
setLowerValue((m_lowerValue + step < m_upperValue) ? m_lowerValue + step : m_upperValue);
|
||||
} else if(m_mode.testFlag(RightHandle)) {
|
||||
setUpperValue((m_upperValue - step > m_lowerValue) ? m_upperValue - step : m_lowerValue);
|
||||
}
|
||||
}
|
||||
else if(posValue > secondHandleRectPosValue + scHandleSideLength)
|
||||
setUpperValue(m_upperValue + step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::mouseMoveEvent(QMouseEvent* e) {
|
||||
if(e->buttons() & Qt::LeftButton) {
|
||||
int posValue, firstHandleRectPosValue, secondHandleRectPosValue;
|
||||
posValue = (orientation == Qt::Horizontal) ? e->pos().x() : e->pos().y();
|
||||
firstHandleRectPosValue = (orientation == Qt::Horizontal) ? firstHandleRect().x() : firstHandleRect().y();
|
||||
secondHandleRectPosValue = (orientation == Qt::Horizontal) ? secondHandleRect().x() : secondHandleRect().y();
|
||||
if(mFirstHandlePressed && m_mode.testFlag(LeftHandle)) {
|
||||
if(posValue - mDelta + scHandleSideLength / 2 <= secondHandleRectPosValue) {
|
||||
setLowerValue((posValue - mDelta - scLeftRightMargin - scHandleSideLength / 2) * 1.0 / validLength() * interval() + m_minimum);
|
||||
} else {
|
||||
setLowerValue(m_upperValue);
|
||||
}
|
||||
} else if(mSecondHandlePressed && m_mode.testFlag(RightHandle)) {
|
||||
if(firstHandleRectPosValue + scHandleSideLength * (m_mode.testFlag(DoubleHandles) ? 1.5 : 0.5) <= posValue - mDelta) {
|
||||
setUpperValue((posValue - mDelta - scLeftRightMargin - scHandleSideLength / 2 - (m_mode.testFlag(DoubleHandles) ? scHandleSideLength : 0)) * 1.0 / validLength() * interval() + m_minimum);
|
||||
} else {
|
||||
setUpperValue(m_lowerValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::mouseReleaseEvent(QMouseEvent *) {
|
||||
mFirstHandlePressed = false;
|
||||
mSecondHandlePressed = false;
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::changeEvent(QEvent * e) {
|
||||
if(e->type() == QEvent::EnabledChange) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QSize RangeSlider::minimumSizeHint() const {
|
||||
return QSize(scHandleSideLength * 2 + scLeftRightMargin * 2, scHandleSideLength);
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setLowerValue(int value) {
|
||||
if(value > m_maximum) value = m_maximum;
|
||||
if(value < m_minimum) value = m_minimum;
|
||||
m_lowerValue = value;
|
||||
emit lowerValueChanged(m_lowerValue);
|
||||
emit valueChanged(m_lowerValue, m_upperValue);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setUpperValue(int value) {
|
||||
if(value > m_maximum) value = m_maximum;
|
||||
if(value < m_minimum) value = m_minimum;
|
||||
m_upperValue = value;
|
||||
emit upperValueChanged(m_upperValue);
|
||||
emit valueChanged(m_lowerValue, m_upperValue);
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setMinimum(int minimum) {
|
||||
if(minimum <= m_maximum) {
|
||||
m_minimum = minimum;
|
||||
} else {
|
||||
int oldMax = m_maximum;
|
||||
m_minimum = oldMax;
|
||||
m_maximum = minimum;
|
||||
}
|
||||
update();
|
||||
setLowerValue(m_minimum);
|
||||
setUpperValue(m_maximum);
|
||||
emit minimumChanged(m_maximum);
|
||||
emit rangeChanged(m_minimum, m_maximum);
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setMaximum(int maximum) {
|
||||
if(maximum >= m_minimum) {
|
||||
m_maximum = maximum;
|
||||
} else {
|
||||
int oldMin = m_minimum;
|
||||
m_maximum = oldMin;
|
||||
m_minimum = maximum;
|
||||
}
|
||||
update();
|
||||
setLowerValue(m_minimum);
|
||||
setUpperValue(m_maximum);
|
||||
emit maximumChanged(m_maximum);
|
||||
emit rangeChanged(m_minimum, m_maximum);
|
||||
}
|
||||
|
||||
|
||||
int RangeSlider::validLength() const {
|
||||
int len = (orientation == Qt::Horizontal) ? width() : height();
|
||||
return len - scLeftRightMargin * 2 - scHandleSideLength * (m_mode.testFlag(DoubleHandles) ? 2 : 1);
|
||||
}
|
||||
|
||||
|
||||
int RangeSlider::interval() const {
|
||||
return m_maximum - m_minimum;
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setRange(int minimum, int maximum) {
|
||||
setMinimum(minimum);
|
||||
setMaximum(maximum);
|
||||
}
|
||||
|
||||
|
||||
void RangeSlider::setMode(Mode m) {
|
||||
m_mode = m;
|
||||
update();
|
||||
emit modeChanged(m_mode);
|
||||
}
|
||||
Reference in New Issue
Block a user