#include "lts_multi_range_spinbox.h" #include #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 : std::as_const(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 : std::as_const(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())); } } } // namespace LtsWidgets