335 lines
7.4 KiB
C++
Executable File
335 lines
7.4 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* SpinBox, that corrects values to a valid value that fits minimum() + n * singleStep() = value
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
*
|
|
* Created by Malte Diers DER LOSER, NLSE, 2018-05-07
|
|
*/
|
|
|
|
#include "lts_multi_range_spinbox.h"
|
|
|
|
#include <QEvent>
|
|
#include <QWheelEvent>
|
|
#include <cmath>
|
|
|
|
namespace LtsWidgets
|
|
{
|
|
|
|
LtsMultiRangeSpinBox::LtsMultiRangeSpinBox(QWidget *parent)
|
|
: QSpinBox(parent)
|
|
{
|
|
m_curVal = minimum();
|
|
|
|
}
|
|
|
|
/*!
|
|
* \brief LtsSpinBoxNew::validate
|
|
* \param input
|
|
* \param pos
|
|
* \brief only used if enter pressed
|
|
* \return
|
|
*/
|
|
|
|
QValidator::State LtsMultiRangeSpinBox::validate(QString &input, int &pos) const
|
|
{
|
|
// QIntValidator validator;
|
|
|
|
// int minimumVal = minimum();
|
|
// int maximumVal = maximum();
|
|
// validator.setBottom(minimum());
|
|
// validator.setTop(maximum());
|
|
// QValidator::State state = validator.validate(input, pos);
|
|
// if (state == QValidator::Invalid ||
|
|
// state == QValidator::Intermediate)
|
|
// {
|
|
// return state;
|
|
// }
|
|
// // Now we're sure, it's an int. Therefore toInt() will always be okay:
|
|
// int value = input.toInt();
|
|
// value -= minimum();
|
|
// return (value % singleStep() == 0) ? QValidator::Acceptable : QValidator::Intermediate;
|
|
return QValidator::Acceptable;
|
|
}
|
|
|
|
void LtsMultiRangeSpinBox::fixup(QString &str) const
|
|
{
|
|
|
|
// QSpinBox::fixup(str);
|
|
|
|
// if (singleStep() == 1)
|
|
// {
|
|
// return;
|
|
// }
|
|
// bool bOk = false;
|
|
// int value = str.toInt(&bOk);
|
|
// if (!bOk)
|
|
// {
|
|
// return;
|
|
// }
|
|
// fixupValue(value);
|
|
|
|
// str = QString::number(value);
|
|
}
|
|
|
|
QValidator::State LtsMultiRangeSpinBox::validateAll(QString &input, int &pos)
|
|
{
|
|
for(QPair<int,int> 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;
|
|
|
|
//return validate(input, pos);
|
|
}
|
|
/*!
|
|
* \brief LtsSpinBoxNew::setGaps
|
|
* \param gaps
|
|
* \author Niklas Schmidt
|
|
*/
|
|
QVector<QPair<int,int>> LtsWidgets::LtsMultiRangeSpinBox::sortRanges(const QVector<QPair<int, int> > &ranges)
|
|
{
|
|
QVector<QPair<int, int>> rangesEditable = ranges;
|
|
QVector<QPair<int, int>> result;
|
|
std::sort(rangesEditable.begin(), rangesEditable.end());
|
|
QVector<QPair<int, int>>::iterator it = rangesEditable.begin();
|
|
QPair<int,int> 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<QPair<int, int>> &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<int,int> &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<int,int> 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<int,int> 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)
|
|
{
|
|
/*!
|
|
Check if the new value is lower or higher the past value
|
|
Example: Gap between 50 and 100. Value changed from 100 to 99 requested
|
|
So the new value is lower so the SpinBox need to be corrected down to 49
|
|
!*/
|
|
|
|
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)
|
|
{
|
|
/*!
|
|
Check if the new value is lower or higher the past value
|
|
Example: Gap between 50 and 100. Value changed from 100 to 99 requested
|
|
So the new value is lower so the SpinBox need to be corrected down to 49
|
|
!*/
|
|
|
|
|
|
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
|