#include "lts_multi_range_spinbox.h" #include #include #include namespace LtsWidgets { LtsMultiRangeSpinBox::LtsMultiRangeSpinBox(QWidget *parent) : QSpinBox(parent) { m_curVal = minimum(); } QValidator::State LtsMultiRangeSpinBox::validate(QString &input, int &pos) const { return QValidator::Acceptable; } void LtsMultiRangeSpinBox::fixup(QString &str) const { } QValidator::State LtsMultiRangeSpinBox::validateAll(QString &input, int &pos) { for(QPair range : qAsConst(m_rangesList)) { QIntValidator validator(range.first, range.second); QValidator::State valState = validator.validate(input, pos); if (valState == QValidator::Acceptable) { return valState; } } return QValidator::Invalid; } QVector> LtsWidgets::LtsMultiRangeSpinBox::sortRanges(const QVector > &ranges) { QVector> rangesEditable = ranges; QVector> result; std::sort(rangesEditable.begin(), rangesEditable.end()); QVector>::iterator it = rangesEditable.begin(); QPair current = *(it)++; while (it != rangesEditable.end()) { if (current.second > it->first) current.second = std::max(current.second, it->second); else { result.push_back(current); current = *(it); } ++it; } result.push_back(current); return result; } void LtsMultiRangeSpinBox::setRanges(const QVector> &ranges) { if(ranges.empty()) return; m_rangesList = sortRanges(ranges); QSpinBox::setMaximum(m_rangesList.last().second); QSpinBox::setMinimum(m_rangesList.first().first); QStringList rangeStrings; rangeStrings.reserve(m_rangesList.size()); for (const QPair &range : qAsConst(m_rangesList)) rangeStrings << tr("%1-%2%3").arg(range.first).arg(range.second).arg(suffix()); setToolTip(tr("Ranges:\n%1").arg(rangeStrings.join(QStringLiteral(",\n")))); } void LtsMultiRangeSpinBox::setRange(int min, int max) { setRanges({{min,max}}); } void LtsMultiRangeSpinBox::setMinimum(int min) { auto ranges = m_rangesList; ranges.first().first = min; setRanges(ranges); } void LtsMultiRangeSpinBox::setMaximum(int max) { auto ranges = m_rangesList; ranges.last().second = max; setRanges(ranges); } int LtsMultiRangeSpinBox::fixupValue(int value) const { int nearestValue = INT_MAX; for(QPair range : m_rangesList) { if(std::abs(range.first - value) < std::abs(nearestValue - value)) nearestValue = range.first; if(std::abs(range.second - value) < std::abs(nearestValue - value)) nearestValue = range.second; } value = nearestValue; int buffer = value; int remainder = (value - minimum()) % singleStep(); if (2 * remainder > singleStep()) { value += singleStep(); } value -= remainder; if(buffer + singleStep() > value + singleStep()) { value+= singleStep(); } if (value > maximum()) { value -= singleStep(); } return value; } int LtsMultiRangeSpinBox::fixupValue(int value, bool higher) const { int nearestValue = INT_MAX; for(QPair range : m_rangesList) { if(std::abs(range.first - value) < std::abs(nearestValue - value)) { if(higher) { if(range.second < value) continue; } else if(range.second > value) continue; nearestValue = range.first; } if(std::abs(range.second - value) < std::abs(nearestValue - value)) { if(higher) { if(range.second < value) continue; } else if(range.second > value) continue; nearestValue = range.second; } } value = nearestValue; int curVal = value; int remainder = (value - minimum()) % singleStep(); if (2 * remainder > singleStep()) { value += singleStep(); } value -= remainder; if(curVal + singleStep() > value + singleStep()) { value+= singleStep(); } if (value > maximum()) { value -= singleStep(); } return value; } void LtsMultiRangeSpinBox::focusOutEvent(QFocusEvent *event) { QSpinBox::focusOutEvent(event); QString value = QString::number(this->value()); int length = value.length(); QValidator::State valState = validateAll(value, length); if(valState == QValidator::State::Invalid) { this->setValue(fixupValue(value.toInt())); } } void LtsMultiRangeSpinBox::wheelEvent(QWheelEvent *event) { QSpinBox::wheelEvent(event); QString valueStr = QString::number(this->value()); int length = valueStr.length(); QValidator::State valState = validateAll(valueStr, length); if(valState == QValidator::State::Invalid) { if(this->value() < m_curVal) { m_curVal = fixupValue(this->value(), false); setValue(m_curVal); } else { m_curVal = fixupValue(this->value(), true); setValue(m_curVal); } } } void LtsMultiRangeSpinBox::mousePressEvent(QMouseEvent *event) { QSpinBox::mousePressEvent(event); QString valueStr = QString::number(this->value()); int length = valueStr.length(); QValidator::State valState = validateAll(valueStr, length); if(valState == QValidator::State::Invalid) { if(this->value() < m_curVal) { m_curVal = fixupValue(this->value(), false); setValue(m_curVal); } else { m_curVal = fixupValue(this->value(), true); setValue(m_curVal); } } } void LtsMultiRangeSpinBox::keyPressEvent(QKeyEvent *event) { QSpinBox::keyPressEvent(event); QString value = QString::number(this->value()); int length = value.length(); QValidator::State valState = validateAll(value, length); if(valState == QValidator::State::Invalid) { setValue(fixupValue(value.toInt())); } } }