diff --git a/libs/widgets/plugin/qad_widgets.cpp b/libs/widgets/plugin/qad_widgets.cpp index 23a0812..4d045bd 100644 --- a/libs/widgets/plugin/qad_widgets.cpp +++ b/libs/widgets/plugin/qad_widgets.cpp @@ -16,6 +16,7 @@ #include "evalspinboxplugin.h" #include "imageviewplugin.h" #include "scroll_spin_boxplugin.h" +#include "rangesliderplugin.h" QADWidgets::QADWidgets(QObject * parent): QObject(parent) { @@ -36,6 +37,7 @@ QADWidgets::QADWidgets(QObject * parent): QObject(parent) { m_widgets.append(new EvalSpinBoxPlugin(this)); m_widgets.append(new ImageViewPlugin(this)); m_widgets.append(new ScrollSpinBoxPlugin(this)); + m_widgets.append(new RangeSliderPlugin(this)); } diff --git a/libs/widgets/plugin/rangesliderplugin.cpp b/libs/widgets/plugin/rangesliderplugin.cpp new file mode 100644 index 0000000..e8e743a --- /dev/null +++ b/libs/widgets/plugin/rangesliderplugin.cpp @@ -0,0 +1,69 @@ +#include "rangeslider.h" +#include "rangesliderplugin.h" +#include + + +RangeSliderPlugin::RangeSliderPlugin(QObject * parent): QObject(parent) { + m_initialized = false; +} + + +void RangeSliderPlugin::initialize(QDesignerFormEditorInterface * /* core */) { + if (m_initialized) + return; + + // Add extension registrations, etc. here + + m_initialized = true; +} + + +bool RangeSliderPlugin::isInitialized() const { + return m_initialized; +} + + +QWidget * RangeSliderPlugin::createWidget(QWidget * parent) { + return new RangeSlider(parent); +} + + +QString RangeSliderPlugin::name() const { + return QLatin1String("RangeSlider"); +} + + +QString RangeSliderPlugin::group() const { + return QLatin1String("Input Widgets"); +} + + +QIcon RangeSliderPlugin::icon() const { + return QIcon(); +} + + +QString RangeSliderPlugin::toolTip() const { + return QLatin1String("Range Slider"); +} + + +QString RangeSliderPlugin::whatsThis() const { + return QLatin1String("Range Slider"); +} + + +bool RangeSliderPlugin::isContainer() const { + return false; +} + + +QString RangeSliderPlugin::domXml() const { + return QLatin1String("\n\n"); +} + + +QString RangeSliderPlugin::includeFile() const { + return QLatin1String("rangeslider.h"); +} + diff --git a/libs/widgets/plugin/rangesliderplugin.h b/libs/widgets/plugin/rangesliderplugin.h new file mode 100644 index 0000000..b53d297 --- /dev/null +++ b/libs/widgets/plugin/rangesliderplugin.h @@ -0,0 +1,36 @@ +#ifndef RANGESLIDERPLUGIN_H +#define RANGESLIDERPLUGIN_H + +#include +#if QT_VERSION >= 0x050000 +# include +#else +# include +#endif + +class RangeSliderPlugin: public QObject, public QDesignerCustomWidgetInterface +{ + Q_OBJECT + Q_INTERFACES(QDesignerCustomWidgetInterface) + +public: + RangeSliderPlugin(QObject * parent = 0); + + bool isContainer() const; + bool isInitialized() const; + QIcon icon() const; + QString domXml() const; + QString group() const; + QString includeFile() const; + QString name() const; + QString toolTip() const; + QString whatsThis() const; + QWidget * createWidget(QWidget * parent); + void initialize(QDesignerFormEditorInterface * core); + +private: + bool m_initialized; + +}; + +#endif // RANGESLIDERPLUGIN_H diff --git a/libs/widgets/rangeslider.cpp b/libs/widgets/rangeslider.cpp new file mode 100644 index 0000000..aeea159 --- /dev/null +++ b/libs/widgets/rangeslider.cpp @@ -0,0 +1,266 @@ +#include "rangeslider.h" +#include "qad_types.h" +#include + + +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); +} diff --git a/libs/widgets/rangeslider.h b/libs/widgets/rangeslider.h new file mode 100644 index 0000000..d25cf16 --- /dev/null +++ b/libs/widgets/rangeslider.h @@ -0,0 +1,92 @@ +#ifndef RANGESLIDER_H +#define RANGESLIDER_H + +#include +#include +#include +#include "qad_widgets_export.h" + + +class QAD_WIDGETS_EXPORT RangeSlider : public QWidget +{ + Q_OBJECT + Q_FLAGS(Mode) + Q_PROPERTY(int minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY(int maximum READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY(int lowerValue READ lowerValue WRITE setLowerValue NOTIFY lowerValueChanged) + Q_PROPERTY(int upperValue READ upperValue WRITE setUpperValue NOTIFY upperValueChanged) + Q_PROPERTY(Mode mode READ mode WRITE setMode NOTIFY modeChanged) + +public: + enum ModeEnum { + NoHandle = 0x0, + LeftHandle = 0x1, + RightHandle = 0x2, + DoubleHandles = LeftHandle | RightHandle + }; + Q_DECLARE_FLAGS(Mode, ModeEnum) + + RangeSlider(QWidget* parent = Q_NULLPTR); + RangeSlider(Qt::Orientation ori, Mode m = DoubleHandles, QWidget * parent = Q_NULLPTR); + + + int minimum() const {return m_minimum;} + int maximum() const {return m_maximum;} + int lowerValue() const {return m_lowerValue;} + int upperValue() const {return m_upperValue;} + QPair value() const {return QPair(m_lowerValue, m_upperValue);} + Mode mode() const {return m_mode;} + +protected: + QSize minimumSizeHint() const override; + void paintEvent(QPaintEvent *) override; + void mousePressEvent(QMouseEvent * e) override; + void mouseMoveEvent(QMouseEvent* e) override; + void mouseReleaseEvent(QMouseEvent *) override; + void changeEvent(QEvent * e) override; + + QRectF firstHandleRect() const; + QRectF secondHandleRect() const; + QRectF handleRect(int value) const; + +signals: + void lowerValueChanged(int value); + void upperValueChanged(int value); + void valueChanged(int lower_value, int upper_value); + void rangeChanged(int min, int max); + void minimumChanged(int minimum); + void maximumChanged(int maximum); + void modeChanged(Mode m); + +public slots: + void setLowerValue(int value); + void setUpperValue(int value); + void setMinimum(int minimum); + void setMaximum(int maximum); + void setRange(int minimum, int maximum); + void setMode(Mode m); + +private: + Q_DISABLE_COPY(RangeSlider) + float currentPercentage(); + int validLength() const; + int interval() const; + void init(); + + int m_minimum; + int m_maximum; + int m_lowerValue; + int m_upperValue; + bool mFirstHandlePressed; + bool mSecondHandlePressed; + int mDelta; + Qt::Orientation orientation; + Mode m_mode; + int scHandleSideLength; + int scSliderBarHeight; + int scLeftRightMargin; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(RangeSlider::Mode) + +#endif //RANGESLIDER_H