diff --git a/openhantek/src/sispinbox.cpp b/openhantek/src/sispinbox.cpp
new file mode 100644
index 0000000..287ce62
--- /dev/null
+++ b/openhantek/src/sispinbox.cpp
@@ -0,0 +1,175 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// OpenHantek
+// sispinbox.cpp
+//
+// Copyright (C) 2012 Oliver Haag
+// oliver.haag@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+#include
+#include
+
+
+#include "sispinbox.h"
+
+#include "helper.h"
+
+
+////////////////////////////////////////////////////////////////////////////////
+// class OpenHantekMainWindow
+/// \brief Initializes the SiSpinBox internals.
+/// \param parent The parent widget.
+SiSpinBox::SiSpinBox(QWidget *parent) : QDoubleSpinBox(parent) {
+ this->init();
+}
+
+/// \brief Initializes the SiSpinBox, allowing the user to choose the unit.
+/// \param unit The unit shown for the value in the spin box.
+/// \param parent The parent widget.
+SiSpinBox::SiSpinBox(Helper::Unit unit, QWidget *parent) : QDoubleSpinBox(parent) {
+ this->init();
+
+ this->setUnit(unit);
+}
+
+/// \brief Cleans up the main window.
+SiSpinBox::~SiSpinBox() {
+}
+
+/// \brief Validates the text after user input.
+/// \param input The content of the text box.
+/// \param pos The position of the cursor in the text box.
+/// \return Validity of the current text.
+QValidator::State SiSpinBox::validate(QString &input, int &pos) const {
+ Q_UNUSED(pos);
+
+ bool ok;
+ double value = Helper::stringToValue(input, this->unit, &ok);
+
+ if(!ok)
+ return QValidator::Invalid;
+
+ if(input == this->textFromValue(value))
+ return QValidator::Acceptable;
+ return QValidator::Intermediate;
+}
+
+/// \brief Parse value from input text.
+/// \param text The content of the text box.
+/// \return Value in base unit.
+double SiSpinBox::valueFromText(const QString &text) const {
+ return Helper::stringToValue(text, this->unit);
+}
+
+/// \brief Get string representation of value.
+/// \param val Value in base unit.
+/// \return String representation containing value and (prefix+)unit.
+QString SiSpinBox::textFromValue(double val) const {
+ return Helper::valueToString(val, this->unit, -1) + this->unitPostfix;
+}
+
+/// \brief Fixes the text after the user finished changing it.
+/// \param input The content of the text box.
+void SiSpinBox::fixup(QString &input) const {
+ bool ok;
+ double value = Helper::stringToValue(input, this->unit, &ok);
+
+ if(!ok)
+ value = this->value();
+
+ input = this->textFromValue(value);
+}
+
+/// \brief Increase/decrease the values in fixed steps.
+/// \param steps The number of steps, positive means increase.
+void SiSpinBox::stepBy(int steps) {
+ double stepsSpan = this->steps.last() / this->steps.first();
+ int stepsCount = this->steps.size() - 1;
+
+ if(!this->steppedTo) { // No step done directly before this one, so we need to check where we are
+ // Get how often the steps have to be fully ran through
+ int stepsFully = (int) floor(log(this->value() / this->steps.first()) / log(stepsSpan));
+ // And now the remaining multiple
+ double stepMultiple = this->value() / pow(stepsSpan, stepsFully);
+ // Now get the neighbours of the current value from our steps list
+ int remainingSteps = 0;
+ for(; remainingSteps <= stepsCount; ++remainingSteps) {
+ if(this->steps[remainingSteps] > stepMultiple)
+ break;
+ }
+ if(remainingSteps > 0) // Shouldn't happen, but double may have rounding errors
+ --remainingSteps;
+ this->stepId = stepsFully * stepsCount + remainingSteps;
+ // We need to do one step less down if we are inbetween two of them since our step is lower than the value
+ if(steps < 0 && this->steps[remainingSteps] < stepMultiple)
+ ++this->stepId;
+ }
+
+ this->stepId += steps;
+ int stepsId = this->stepId % stepsCount;
+ if(stepsId < 0)
+ stepsId += stepsCount;
+ double value = pow(stepsSpan, floor((double) this->stepId / stepsCount)) * this->steps[stepsId];
+ this->setValue(value);
+ value = this->value();
+ this->steppedTo = true;
+}
+
+/// \brief Set the unit for this spin box.
+/// \param unit The unit shown for the value in the spin box.
+/// \return true on success, false on invalid unit.
+bool SiSpinBox::setUnit(Helper::Unit unit) {
+ if((unsigned int) unit >= Helper::UNIT_COUNT)
+ return false;
+
+ this->unit = unit;
+ return true;
+}
+
+/// \brief Set the unit postfix for this spin box.
+/// \param postfix the string shown after the unit in the spin box.
+void SiSpinBox::setUnitPostfix(const QString &postfix) {
+ this->unitPostfix = postfix;
+}
+
+/// \brief Set the steps the spin box will take.
+/// \param steps The steps, will be extended with the ratio from the start after the last element.
+void SiSpinBox::setSteps(const QList &steps) {
+ this->steps = steps;
+}
+
+/// \brief Generic initializations.
+void SiSpinBox::init() {
+ this->setMinimum(1e-12);
+ this->setMaximum(1e12);
+ this->setValue(1.0);
+ this->setDecimals(DBL_MAX_10_EXP + DBL_DIG); // Disable automatic rounding
+ this->unit = unit;
+ this->steps << 1.0 << 2.0 << 5.0 << 10.0;
+
+ this->steppedTo = false;
+ this->stepId = 0;
+
+ connect(this, SIGNAL(valueChanged(double)), this, SLOT(resetSteppedTo()));
+}
+
+/// \brief Resets the ::steppedTo flag after the value has been changed.
+void SiSpinBox::resetSteppedTo() {
+ this->steppedTo = false;
+}
diff --git a/openhantek/src/sispinbox.h b/openhantek/src/sispinbox.h
new file mode 100644
index 0000000..6f9f655
--- /dev/null
+++ b/openhantek/src/sispinbox.h
@@ -0,0 +1,76 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// OpenHantek
+/// \file sispinbox.h
+/// \brief Declares the SiSpinBox class.
+//
+// Copyright (C) 2010, 2011 Oliver Haag
+// oliver.haag@gmail.com
+//
+// This program is free software: you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation, either version 3 of the License, or (at your option)
+// any later version.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program. If not, see .
+//
+////////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef SISPINBOX_H
+#define SISPINBOX_H
+
+
+#include
+#include
+
+#include "helper.h"
+
+
+////////////////////////////////////////////////////////////////////////////////
+/// \class SiSpinBox sispinbox.h
+/// \brief A spin box with SI prefix support.
+/// This spin box supports the SI prefixes (k/M/G/T) after its value and allows
+/// floating point values. The step size is increasing in an exponential way, to
+/// keep the percentual difference between the steps at equal levels.
+class SiSpinBox : public QDoubleSpinBox
+{
+ Q_OBJECT
+
+ public:
+ explicit SiSpinBox(QWidget *parent = 0);
+ SiSpinBox(Helper::Unit unit, QWidget *parent = 0);
+ ~SiSpinBox();
+
+ QValidator::State validate(QString &input, int &pos) const;
+ double valueFromText(const QString &text) const;
+ QString textFromValue(double val) const;
+ void fixup(QString &input) const;
+ void stepBy(int steps);
+ bool setUnit(Helper::Unit unit);
+ void setUnitPostfix(const QString &postfix);
+ void setSteps(const QList &steps);
+
+ private:
+ void init();
+
+ Helper::Unit unit; ///< The SI unit used for this spin box
+ QString unitPostfix; ///< Shown after the unit
+ QList steps; ///< The steps, begins from start after last element
+
+ bool steppedTo; ///< true, if the current value was reached using stepBy
+ int stepId; ///< The index of the last step reached using stepBy
+
+ signals:
+
+ private slots:
+ void resetSteppedTo();
+};
+
+#endif