#include "lts_spinbox.h" #include namespace LtsWidgets { LtsSpinBox::LtsSpinBox(QWidget* parent) : QSpinBox(parent) {} QValidator::State LtsSpinBox::validate(QString& input, int& pos) const { QIntValidator validator; for (auto range : m_validRanges) { validator.setBottom(range.first); validator.setTop(range.second); QValidator::State state = validator.validate(input, pos); if (state == QValidator::Invalid || state == QValidator::Intermediate) return state; } int value = input.toInt(); value -= minimum(); return (value % singleStep() == 0) ? QValidator::Acceptable : QValidator::Intermediate; } void LtsSpinBox::fixup(QString& str) const { QSpinBox::fixup(str); if (singleStep() == 1) return; bool bOk; int value = str.toInt(&bOk); if (!bOk) return; int remainder = (value - minimum()) % singleStep(); if (2 * remainder > singleStep()) value += singleStep(); value -= remainder; if (value > maximum()) value -= singleStep(); str = QString::number(value); } bool LtsSpinBox::setExclusionRanges(const QVector>& exclusionRanges, bool preserveCurrentValues) { bool retVal = true; auto newExclusions = exclusionRanges; if (preserveCurrentValues) newExclusions += m_exclusions; for (auto& elem : newExclusions) { if (elem.first > elem.second) { int tmp = elem.first; elem.first = elem.second; elem.second = tmp; } } std::sort(newExclusions.begin(), newExclusions.end(), [](const QPair& a, const QPair& b) { return a.first < b.first; }); for (int i = 0; i < newExclusions.size() - 1; ++i) { if (newExclusions[i].second >= newExclusions[i + 1].first) { retVal = false; break; } } if (!retVal || newExclusions[0].first <= minimum() || newExclusions[newExclusions.size() - 1].second >= maximum()) { if (!preserveCurrentValues) m_exclusions.clear(); return false; } m_exclusions = exclusionRanges; m_validRanges.clear(); if (m_exclusions[0].first - 1 > minimum()) m_validRanges.append({minimum(), m_exclusions[0].first - 1}); for (int i = 0; i < m_exclusions.size() - 1; ++i) { if (m_exclusions[i].second + 1 < m_exclusions[i + 1].first - 1) m_validRanges.append({m_exclusions[i].second + 1, m_exclusions[i + 1].first - 1}); } if (m_exclusions[m_exclusions.size() - 1].second + 1 < maximum()) m_validRanges.append({m_exclusions[0].first - 1, maximum()}); return true; } bool LtsSpinBox::addExclusionRange(int min, int max) { return setExclusionRanges({{min, max}}, true); } void LtsSpinBox::clearExclusionRanges() { m_exclusions.clear(); } LtsDoubleSpinBox::LtsDoubleSpinBox(QWidget* parent) : QDoubleSpinBox(parent) {} QValidator::State LtsDoubleSpinBox::validate(QString& input, int& pos) const { QDoubleValidator validator; validator.setBottom(minimum()); validator.setTop(maximum()); QValidator::State state = validator.validate(input, pos); if (state == QValidator::Invalid || state == QValidator::Intermediate) return state; double value = input.toDouble(); value -= minimum(); return qFuzzyCompare(std::fmod(value, singleStep()), 0.0) ? QValidator::Acceptable : QValidator::Intermediate; } void LtsDoubleSpinBox::fixup(QString& str) const { QDoubleSpinBox::fixup(str); if (qFuzzyCompare(singleStep(), pow(10, decimals()))) return; bool bOk; double value = str.toDouble(&bOk); if (!bOk) return; double remainder = std::fmod(value - minimum(), singleStep()); if (2 * remainder > singleStep()) value += singleStep(); value -= remainder; if (value > maximum()) value -= singleStep(); str = QString::number(value, 'f', decimals()); } } // namespace LtsWidgets