From e317f3762c3b18fdcf09dd417e09b434abe82f77 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 17 May 2017 19:36:36 +0200 Subject: [PATCH] ValueDialZ: new value dial that handles negative values. Application in TCPsrc plugin --- CMakeLists.txt | 2 + plugins/channelrx/tcpsrc/tcpsrcgui.cpp | 24 +- plugins/channelrx/tcpsrc/tcpsrcgui.h | 3 +- plugins/channelrx/tcpsrc/tcpsrcgui.ui | 40 +- sdrbase/gui/valuedial.h | 158 +++---- sdrbase/gui/valuedialz.cpp | 621 +++++++++++++++++++++++++ sdrbase/gui/valuedialz.h | 83 ++++ sdrbase/sdrbase.pro | 2 + 8 files changed, 800 insertions(+), 133 deletions(-) create mode 100644 sdrbase/gui/valuedialz.cpp create mode 100644 sdrbase/gui/valuedialz.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9f5d206..08525c2d1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,7 @@ set(sdrbase_SOURCES sdrbase/gui/scale.cpp sdrbase/gui/scaleengine.cpp sdrbase/gui/valuedial.cpp + sdrbase/gui/valuedialz.cpp sdrbase/dsp/devicesamplesource.cpp sdrbase/dsp/devicesamplesink.cpp @@ -285,6 +286,7 @@ set(sdrbase_HEADERS sdrbase/gui/scale.h sdrbase/gui/scaleengine.h sdrbase/gui/valuedial.h + sdrbase/gui/valuedialz.h sdrbase/dsp/devicesamplesource.h sdrbase/dsp/devicesamplesink.h diff --git a/plugins/channelrx/tcpsrc/tcpsrcgui.cpp b/plugins/channelrx/tcpsrc/tcpsrcgui.cpp index f88f989bf..7ff551243 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcgui.cpp +++ b/plugins/channelrx/tcpsrc/tcpsrcgui.cpp @@ -207,7 +207,7 @@ TCPSrcGUI::TCPSrcGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget* m_deviceAPI->addThreadedSink(m_threadedChannelizer); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::GrayGold)); - ui->deltaFrequency->setValueRange(7, 0U, 9999999U); + ui->deltaFrequency->setValueRange(false, 7, -9999999, 9999999); ui->glSpectrum->setCenterFrequency(0); ui->glSpectrum->setSampleRate(ui->sampleRate->text().toInt()); @@ -282,8 +282,7 @@ void TCPSrcGUI::applySettings() int boost = ui->boost->value(); setTitleColor(m_channelMarker.getColor()); - ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); - ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); + ui->deltaFrequency->setValue(m_channelMarker.getCenterFrequency()); ui->sampleRate->setText(QString("%1").arg(outputSampleRate, 0)); ui->rfBandwidth->setText(QString("%1").arg(rfBandwidth, 0)); ui->tcpPort->setText(QString("%1").arg(tcpPort)); @@ -332,24 +331,9 @@ void TCPSrcGUI::applySettings() } } -void TCPSrcGUI::on_deltaMinus_toggled(bool minus) +void TCPSrcGUI::on_deltaFrequency_changed(qint64 value) { - int deltaFrequency = m_channelMarker.getCenterFrequency(); - bool minusDelta = (deltaFrequency < 0); - - if (minus ^ minusDelta) // sign change - { - m_channelMarker.setCenterFrequency(-deltaFrequency); - } -} - -void TCPSrcGUI::on_deltaFrequency_changed(quint64 value) -{ - if (ui->deltaMinus->isChecked()) { - m_channelMarker.setCenterFrequency(-value); - } else { - m_channelMarker.setCenterFrequency(value); - } + m_channelMarker.setCenterFrequency(value); } void TCPSrcGUI::on_sampleFormat_currentIndexChanged(int index) diff --git a/plugins/channelrx/tcpsrc/tcpsrcgui.h b/plugins/channelrx/tcpsrc/tcpsrcgui.h index 2146508d8..4fc71e369 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcgui.h +++ b/plugins/channelrx/tcpsrc/tcpsrcgui.h @@ -42,8 +42,7 @@ public: private slots: void channelMarkerChanged(); - void on_deltaFrequency_changed(quint64 value); - void on_deltaMinus_toggled(bool minus); + void on_deltaFrequency_changed(qint64 value); void on_sampleFormat_currentIndexChanged(int index); void on_sampleRate_textEdited(const QString& arg1); void on_rfBandwidth_textEdited(const QString& arg1); diff --git a/plugins/channelrx/tcpsrc/tcpsrcgui.ui b/plugins/channelrx/tcpsrc/tcpsrcgui.ui index 1cc78fd3f..860de0afb 100644 --- a/plugins/channelrx/tcpsrc/tcpsrcgui.ui +++ b/plugins/channelrx/tcpsrc/tcpsrcgui.ui @@ -149,29 +149,7 @@ 2 - - - Frequency shift direction - - - ... - - - - :/plus.png - :/minus.png - - - - true - - - false - - - - - + 0 @@ -457,12 +435,6 @@
gui/rollupwidget.h
1 - - ValueDial - QWidget -
gui/valuedial.h
- 1 -
GLSpectrum QWidget @@ -475,6 +447,12 @@
gui/glspectrumgui.h
1
+ + ValueDialZ + QWidget +
gui/valuedialz.h
+ 1 +
sampleFormat @@ -484,8 +462,6 @@ applyBtn connections - - - + diff --git a/sdrbase/gui/valuedial.h b/sdrbase/gui/valuedial.h index ed09906d3..f78d8d6bb 100644 --- a/sdrbase/gui/valuedial.h +++ b/sdrbase/gui/valuedial.h @@ -1,79 +1,79 @@ -/////////////////////////////////////////////////////////////////////////////////// -// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // -// written by Christian Daniel // -// // -// 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 as version 3 of the License, or // -// // -// 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 V3 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 "gui/colormapper.h" -#include "util/export.h" - -class SDRANGEL_API ValueDial : public QWidget { - Q_OBJECT - -public: - ValueDial(QWidget* parent = NULL, ColorMapper colorMapper = ColorMapper(ColorMapper::Normal)); - - void setValue(quint64 value); - void setValueRange(uint numDigits, quint64 min, quint64 max); - void setFont(const QFont& font); - void setBold(bool bold); - void setColorMapper(ColorMapper colorMapper); - quint64 getValue() const { return m_value; } - quint64 getValueNew() const { return m_valueNew; } - -signals: - void changed(quint64 value); - -private: - QLinearGradient m_background; - int m_numDigits; - int m_numDecimalPoints; - int m_digitWidth; - int m_digitHeight; - int m_hightlightedDigit; - int m_cursor; - bool m_cursorState; - quint64 m_value; - quint64 m_valueMax; - quint64 m_valueMin; - QString m_text; - - quint64 m_valueNew; - QString m_textNew; - int m_animationState; - QTimer m_animationTimer; - QTimer m_blinkTimer; - - ColorMapper m_colorMapper; - - quint64 findExponent(int digit); - QChar digitNeigh(QChar c, bool dir); - QString formatText(quint64 value); - - void paintEvent(QPaintEvent*); - - void mousePressEvent(QMouseEvent*); - void mouseMoveEvent(QMouseEvent*); - void wheelEvent(QWheelEvent*); - void leaveEvent(QEvent*); - void keyPressEvent(QKeyEvent*); - void focusInEvent(QFocusEvent*); - void focusOutEvent(QFocusEvent*); - -private slots: - void animate(); - void blink(); -}; +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany // +// written by Christian Daniel // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 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 "gui/colormapper.h" +#include "util/export.h" + +class SDRANGEL_API ValueDial : public QWidget { + Q_OBJECT + +public: + ValueDial(QWidget* parent = NULL, ColorMapper colorMapper = ColorMapper(ColorMapper::Normal)); + + void setValue(quint64 value); + void setValueRange(uint numDigits, quint64 min, quint64 max); + void setFont(const QFont& font); + void setBold(bool bold); + void setColorMapper(ColorMapper colorMapper); + quint64 getValue() const { return m_value; } + quint64 getValueNew() const { return m_valueNew; } + +signals: + void changed(quint64 value); + +private: + QLinearGradient m_background; + int m_numDigits; + int m_numDecimalPoints; + int m_digitWidth; + int m_digitHeight; + int m_hightlightedDigit; + int m_cursor; + bool m_cursorState; + quint64 m_value; + quint64 m_valueMax; + quint64 m_valueMin; + QString m_text; + + quint64 m_valueNew; + QString m_textNew; + int m_animationState; + QTimer m_animationTimer; + QTimer m_blinkTimer; + + ColorMapper m_colorMapper; + + quint64 findExponent(int digit); + QChar digitNeigh(QChar c, bool dir); + QString formatText(quint64 value); + + void paintEvent(QPaintEvent*); + + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + void leaveEvent(QEvent*); + void keyPressEvent(QKeyEvent*); + void focusInEvent(QFocusEvent*); + void focusOutEvent(QFocusEvent*); + +private slots: + void animate(); + void blink(); +}; diff --git a/sdrbase/gui/valuedialz.cpp b/sdrbase/gui/valuedialz.cpp new file mode 100644 index 000000000..6cb255826 --- /dev/null +++ b/sdrbase/gui/valuedialz.cpp @@ -0,0 +1,621 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// Same as ValueDial but handles optionally positive and negative numbers with // +// sign display. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 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 +#include +#include "gui/valuedialz.h" + +ValueDialZ::ValueDialZ(bool positiveOnly, QWidget* parent, ColorMapper colorMapper) : + m_positiveOnly(positiveOnly), + QWidget(parent), + m_animationState(0), + m_colorMapper(colorMapper) +{ + setAutoFillBackground(false); + setAttribute(Qt::WA_OpaquePaintEvent, true); + setAttribute(Qt::WA_NoSystemBackground, true); + setMouseTracking(true); + setFocusPolicy(Qt::StrongFocus); + + m_background.setStart(0, 0); + m_background.setFinalStop(0, 1); + m_background.setCoordinateMode(QGradient::ObjectBoundingMode); + + ColorMapper::colormap::const_iterator cmit = m_colorMapper.getDialBackgroundColorMap().begin(); + ColorMapper::colormap::const_iterator cmitEnd = m_colorMapper.getDialBackgroundColorMap().end(); + + for (; cmit != cmitEnd; ++ cmit) { + m_background.setColorAt(cmit->first, cmit->second); + } + + m_value = 0; + m_valueMin = m_positiveOnly ? 0 : -2200000; + m_valueMax = 2200000; + m_numDigits = 7; + m_numDecimalPoints = m_numDigits / 3; + m_cursor = -1; + + m_hightlightedDigit = -1; + m_text = formatText(m_value); + m_cursorState = false; + + connect(&m_animationTimer, SIGNAL(timeout()), this, SLOT(animate())); + connect(&m_blinkTimer, SIGNAL(timeout()), this, SLOT(blink())); +} + +void ValueDialZ::setFont(const QFont& font) +{ + QWidget::setFont(font); + + QFontMetrics fm(font); + m_digitWidth = fm.width('0'); + m_digitHeight = fm.ascent(); + if(m_digitWidth < m_digitHeight) + m_digitWidth = m_digitHeight; + setFixedWidth((m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) * m_digitWidth + 2); + setFixedHeight(m_digitHeight * 2 + 2); +} + +void ValueDialZ::setBold(bool bold) +{ + QFont f = font(); + f.setBold(bold); + setFont(f); +} + +void ValueDialZ::setColorMapper(ColorMapper colorMapper) +{ + m_colorMapper = colorMapper; + + ColorMapper::colormap::const_iterator cmit = m_colorMapper.getDialBackgroundColorMap().begin(); + ColorMapper::colormap::const_iterator cmitEnd = m_colorMapper.getDialBackgroundColorMap().end(); + + for (; cmit != cmitEnd; ++ cmit) { + m_background.setColorAt(cmit->first, cmit->second); + } +} + + +void ValueDialZ::setValue(qint64 value) +{ + m_valueNew = value; + + if(m_valueNew < m_valueMin) { + m_valueNew = m_valueMin; + } + else if(m_valueNew > m_valueMax) { + m_valueNew = m_valueMax; + } + + if(m_valueNew < m_value) { + m_animationState = 1; + } else if(m_valueNew > m_value) { + m_animationState = -1; + } else { + return; + } + + m_animationTimer.start(20); + m_textNew = formatText(m_valueNew); +} + +void ValueDialZ::setValueRange(bool positiveOnly, uint numDigits, qint64 min, qint64 max) +{ + m_positiveOnly = positiveOnly; + m_numDigits = numDigits; + m_numDecimalPoints = m_numDigits < 3 ? 0 : (m_numDigits%3) == 0 ? (m_numDigits/3)-1 : m_numDigits/3; + + setFixedWidth((m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) * m_digitWidth + 2); + + m_valueMin = positiveOnly ? (min < 0 ? 0 : min) : min; + m_valueMax = positiveOnly ? (max < 0 ? 0 : max) : max; + + if(m_value < m_valueMin) + { + setValue(m_valueMin); + } + else if(m_value > m_valueMax) + { + setValue(m_valueMax); + } + else + { + m_text = formatText(0); + m_textNew = m_text; + m_value = 0; + m_valueNew = m_value; + update(); + } +} + +quint64 ValueDialZ::findExponent(int digit) +{ + quint64 e = 1; + int d = (m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) - digit; + d = d - (d / 4) - 1; + for(int i = 0; i < d; i++) + e *= 10; + return e; +} + +QChar ValueDialZ::digitNeigh(QChar c, bool dir) +{ + if (c == QChar('+')) { + return QChar('-'); + } else if (c == QChar('-')) { + return QChar('+'); + } + + if(dir) + { + if(c == QChar('0')) { + return QChar('9'); + } else { + return QChar::fromLatin1(c.toLatin1() - 1); + } + } + else + { + if(c == QChar('9')) { + return QChar('0'); + } else { + return QChar::fromLatin1(c.toLatin1() + 1); + } + } +} + +QString ValueDialZ::formatText(qint64 value) +{ + QString str = QString("%1%2").arg(m_positiveOnly ? "" : value < 0 ? "-" : "+").arg(abs(value), m_numDigits, 10, QChar('0')); + + for(int i = 0; i < m_numDecimalPoints; i++) + { + int ipoint = m_numDigits + (m_positiveOnly ? 0 : 1) - 3 - 3 * i; + + if (ipoint != 0) { // do not insert leading point + str.insert(ipoint, "."); + } + } + + return str; +} + +void ValueDialZ::paintEvent(QPaintEvent*) +{ + QPainter painter(this); + + painter.setPen(Qt::black); + painter.setBrush(m_background); + + painter.drawRect(0, 0, width() - 1, height() - 1); + + painter.setPen(m_colorMapper.getBoundaryColor()); + painter.setBrush(Qt::NoBrush); + + for (int i = 1; i < m_numDigits + m_numDecimalPoints; i++) + { + painter.setPen(m_colorMapper.getBoundaryColor()); + painter.drawLine(1 + i * m_digitWidth, 1, 1 + i * m_digitWidth, height() - 1); + painter.setPen(m_colorMapper.getBoundaryAlphaColor()); + painter.drawLine(0 + i * m_digitWidth, 1, 0 + i * m_digitWidth, height() - 1); + painter.drawLine(2 + i * m_digitWidth, 1, 2 + i * m_digitWidth, height() - 1); + } + + painter.setPen(m_colorMapper.getBoundaryAlphaColor()); + painter.drawLine(1, 1, 1, height() - 1); + painter.drawLine(width() - 2, 1, width() - 2, height() - 1); + + // dial borders + painter.setPen(m_colorMapper.getDarkBorderColor()); + painter.drawLine(0, 0, width() - 2, 0); + painter.drawLine(0, height() - 1, 0, 0); + painter.setPen(m_colorMapper.getLightBorderColor()); + painter.drawLine(1, height() - 1, width() - 1, height() - 1); + painter.drawLine(width() - 1, height() - 1, width() - 1, 0); + + if (m_hightlightedDigit >= 0) + { + painter.setPen(Qt::NoPen); + painter.setBrush(m_colorMapper.getHighlightColor()); + painter.drawRect(2 + m_hightlightedDigit * m_digitWidth, 1, m_digitWidth - 1, height() - 1); + } + + if (m_animationState == 0) + { + for (int i = 0; i < m_text.length(); i++) + { + painter.setClipRect(1 + i * m_digitWidth, 1, m_digitWidth, m_digitHeight * 2); + painter.setPen(m_colorMapper.getSecondaryForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * 0.6, m_digitWidth, m_digitHeight), Qt::AlignCenter, m_text.mid(i, 1)); + + if(m_text[i] != QChar('.')) + { + painter.setPen(m_colorMapper.getForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * -0.7, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], true)); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * 1.9, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], false)); + } + } + + painter.setClipping(false); + + if ((m_cursor >= 0) && (m_cursorState)) + { + painter.setPen(Qt::NoPen); + painter.setBrush(m_colorMapper.getSecondaryForegroundColor()); + painter.drawRect(4 + m_cursor * m_digitWidth, 1 + m_digitHeight * 1.5, m_digitWidth - 5, m_digitHeight / 6); + } + } + else + { + if(m_animationState != 0) + { + for(int i = 0; i < m_text.length(); i++) + { + if(m_text[i] == m_textNew[i]) + { + painter.setClipRect(1 + i * m_digitWidth, 1, m_digitWidth, m_digitHeight * 2); + painter.setPen(m_colorMapper.getSecondaryForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * 0.6, m_digitWidth, m_digitHeight), Qt::AlignCenter, m_text.mid(i, 1)); + + if(m_text[i] != QChar('.')) + { + painter.setPen(m_colorMapper.getForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * -0.7, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], true)); + painter.drawText(QRect(1 + i * m_digitWidth, m_digitHeight * 1.9, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], false)); + } + } + else + { + int h = m_digitHeight * 0.6 + m_digitHeight * m_animationState / 2.0; + painter.setClipRect(1 + i * m_digitWidth, 1, m_digitWidth, m_digitHeight * 2); + painter.setPen(m_colorMapper.getSecondaryForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, h, m_digitWidth, m_digitHeight), Qt::AlignCenter, m_text.mid(i, 1)); + + if(m_text[i] != QChar('.')) + { + painter.setPen(m_colorMapper.getForegroundColor()); + painter.drawText(QRect(1 + i * m_digitWidth, h + m_digitHeight * -0.7, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], true)); + painter.drawText(QRect(1 + i * m_digitWidth, h + m_digitHeight * 1.9, m_digitWidth, m_digitHeight), Qt::AlignCenter, digitNeigh(m_text[i], false)); + } + } + } + } + } +} + +void ValueDialZ::mousePressEvent(QMouseEvent* event) +{ + int i; + + i = (event->x() - 1) / m_digitWidth; + + if (m_positiveOnly) + + if ((m_text[i] == QChar('.')) || (m_text[i] == QChar('+')) || (m_text[i] == QChar('-'))) + { + i++; + + if (i > m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) + { + return; + } + } + + Qt::MouseButton mouseButton = event->button(); + + if (mouseButton == Qt::RightButton) // ceil value at current digit + { + if(m_cursor >= 0) + { + m_cursor = -1; + m_blinkTimer.stop(); + update(); + } + + qint64 e = findExponent(i); + + m_valueNew = (m_value / e) * e; + setValue(m_valueNew); + emit changed(m_valueNew); + //qDebug("ValueDial::mousePressEvent: Qt::RightButton: i: %d e: %ll new: %ll", i, e, valueNew); + } + else if (mouseButton == Qt::LeftButton) // set cursor at current digit + { + m_cursor = i; + m_cursorState = true; + m_blinkTimer.start(400); + + update(); + } +} + +void ValueDialZ::mouseMoveEvent(QMouseEvent* event) +{ + int i; + + i = (event->x() - 1) / m_digitWidth; + + if(m_text[i] == QChar('.')) + { + i = -1; + } + else if ((m_text[i] == QChar('+')) || (m_text[i] != QChar('-'))) + { + i = -1; + } + + if(i != m_hightlightedDigit) + { + m_hightlightedDigit = i; + update(); + } +} + +void ValueDialZ::wheelEvent(QWheelEvent* event) +{ + int i; + + i = (event->x() - 1) / m_digitWidth; + + if ((m_text[i] != QChar('.')) && + (m_text[i] != QChar('+')) && + (m_text[i] != QChar('-'))) + { + m_hightlightedDigit = i; + } + else + { + return; + } + + if (m_cursor >= 0) + { + m_cursor = -1; + m_blinkTimer.stop(); + update(); + } + + qint64 e = findExponent(m_hightlightedDigit); + + if(m_animationState == 0) + { + if(event->delta() < 0) + { + if(event->modifiers() & Qt::ShiftModifier) { + e *= 5; + } + + m_valueNew = (m_value - e < m_valueMin) ? m_valueMin : m_value - e; + } + else + { + if(event->modifiers() & Qt::ShiftModifier) { + e *= 5; + } + + m_valueNew = (m_value + e > m_valueMax) ? m_valueMax : m_value + e; + } + + setValue(m_valueNew); + emit changed(m_valueNew); + } +} + +void ValueDialZ::leaveEvent(QEvent*) +{ + if(m_hightlightedDigit != -1) { + m_hightlightedDigit = -1; + update(); + } +} + +void ValueDialZ::keyPressEvent(QKeyEvent* value) +{ + if(m_cursor >= 0) + { + if((value->key() == Qt::Key_Return) || (value->key() == Qt::Key_Enter) || (value->key() == Qt::Key_Escape)) + { + m_cursor = -1; + m_cursorState = false; + m_blinkTimer.stop(); + update(); + return; + } + } + + if((m_cursor < 0) && (m_hightlightedDigit >= 0)) + { + m_cursor = m_hightlightedDigit; + + if (m_text[m_cursor] == QChar('.')) { + m_cursor++; + } + + if(m_cursor >= m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) { + return; + } + + m_cursorState = true; + m_blinkTimer.start(400); + update(); + } + + if(m_cursor < 0) { + return; + } + + if ((value->key() == Qt::Key_Left) || (value->key() == Qt::Key_Backspace)) + { + if(m_cursor > 0) + { + m_cursor--; + + if (m_text[m_cursor] == QChar('.')) { + m_cursor--; + } + + if (m_cursor < (m_positiveOnly ? 0 : 1)) { + m_cursor++; + } + + m_cursorState = true; + update(); + return; + } + } + else if(value->key() == Qt::Key_Right) + { + if(m_cursor < m_numDecimalPoints + m_numDigits) + { + m_cursor++; + + if (m_text[m_cursor] == QChar('.')) { + m_cursor++; + } + + if(m_cursor >= m_numDecimalPoints + m_numDigits + (m_positiveOnly ? 0 : 1)) { + m_cursor--; + } + + m_cursorState = true; + update(); + return; + } + } + else if(value->key() == Qt::Key_Up) + { + qint64 e = findExponent(m_cursor); + + if(value->modifiers() & Qt::ShiftModifier) { + e *= 5; + } + + if(m_animationState != 0) { + m_value = m_valueNew; + } + + m_valueNew = m_value + e > m_valueMax ? m_valueMax : m_value + e; + + setValue(m_valueNew); + emit changed(m_valueNew); + } + else if(value->key() == Qt::Key_Down) + { + qint64 e = findExponent(m_cursor); + + if(value->modifiers() & Qt::ShiftModifier) { + e *= 5; + } + + if(m_animationState != 0) { + m_value = m_valueNew; + } + + m_valueNew = m_value - e < m_valueMin ? m_valueMin : m_value - e; + + setValue(m_valueNew); + emit changed(m_valueNew); + } + + if(value->text().length() != 1) { + return; + } + + QChar c = value->text()[0]; + + if(c >= QChar('0') && (c <= QChar('9'))) + { + int d = c.toLatin1() - '0'; + quint64 e = findExponent(m_cursor); + quint64 v = (m_value / e) % 10; + if(m_animationState != 0) + m_value = m_valueNew; + v = m_value - v * e; + v += d * e; + setValue(v); + emit changed(m_valueNew); + m_cursor++; + + if ((m_text[m_cursor] == QChar('.')) || (m_text[m_cursor] == QChar('+')) || (m_text[m_cursor] == QChar('-'))) { + m_cursor++; + } + + if(m_cursor >= m_numDigits + m_numDecimalPoints + (m_positiveOnly ? 0 : 1)) + { + m_cursor = -1; + m_blinkTimer.stop(); + } + else + { + m_cursorState = true; + } + + update(); + } +} + +void ValueDialZ::focusInEvent(QFocusEvent*) +{ + if(m_cursor == -1) { + m_cursor = 0; + m_cursorState = true; + m_blinkTimer.start(400); + update(); + } +} + +void ValueDialZ::focusOutEvent(QFocusEvent*) +{ + m_cursor = -1; + m_blinkTimer.stop(); + update(); +} + +void ValueDialZ::animate() +{ + update(); + + if(m_animationState > 0) + m_animationState++; + else if(m_animationState < 0) + m_animationState--; + else { + m_animationTimer.stop(); + m_animationState = 0; + return; + } + + if(abs(m_animationState) >= 4) { + m_animationState = 0; + m_animationTimer.stop(); + m_value = m_valueNew; + m_text = m_textNew; + } +} + +void ValueDialZ::blink() +{ + if(m_cursor >= 0) { + m_cursorState = !m_cursorState; + update(); + } +} diff --git a/sdrbase/gui/valuedialz.h b/sdrbase/gui/valuedialz.h new file mode 100644 index 000000000..c7ad6b005 --- /dev/null +++ b/sdrbase/gui/valuedialz.h @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2017 F4EXB // +// written by Edouard Griffiths // +// // +// Same as ValueDial but handles optionally positive and negative numbers with // +// sign display. // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 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 "gui/colormapper.h" +#include "util/export.h" + +class SDRANGEL_API ValueDialZ : public QWidget { + Q_OBJECT + +public: + ValueDialZ(bool positiveOnly = true, QWidget* parent = NULL, ColorMapper colorMapper = ColorMapper(ColorMapper::Normal)); + + void setValue(qint64 value); + void setValueRange(bool positiveOnly, uint numDigits, qint64 min, qint64 max); + void setFont(const QFont& font); + void setBold(bool bold); + void setColorMapper(ColorMapper colorMapper); + qint64 getValue() const { return m_value; } + qint64 getValueNew() const { return m_valueNew; } + +signals: + void changed(qint64 value); + +private: + QLinearGradient m_background; + int m_numDigits; + int m_numDecimalPoints; + int m_digitWidth; + int m_digitHeight; + int m_hightlightedDigit; + int m_cursor; + bool m_cursorState; + qint64 m_value; + qint64 m_valueMax; + qint64 m_valueMin; + bool m_positiveOnly; + QString m_text; + + qint64 m_valueNew; + QString m_textNew; + int m_animationState; + QTimer m_animationTimer; + QTimer m_blinkTimer; + + ColorMapper m_colorMapper; + + quint64 findExponent(int digit); + QChar digitNeigh(QChar c, bool dir); + QString formatText(qint64 value); + + void paintEvent(QPaintEvent*); + + void mousePressEvent(QMouseEvent*); + void mouseMoveEvent(QMouseEvent*); + void wheelEvent(QWheelEvent*); + void leaveEvent(QEvent*); + void keyPressEvent(QKeyEvent*); + void focusInEvent(QFocusEvent*); + void focusOutEvent(QFocusEvent*); + +private slots: + void animate(); + void blink(); +}; diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro index 2c706dafd..8724b3c29 100644 --- a/sdrbase/sdrbase.pro +++ b/sdrbase/sdrbase.pro @@ -116,6 +116,7 @@ SOURCES += mainwindow.cpp\ gui/scale.cpp\ gui/scaleengine.cpp\ gui/valuedial.cpp\ + gui/valuedialz.cpp\ dsp/devicesamplesource.cpp\ dsp/devicesamplesink.cpp\ plugin/pluginapi.cpp\ @@ -222,6 +223,7 @@ HEADERS += mainwindow.h\ gui/scale.h\ gui/scaleengine.h\ gui/valuedial.h\ + gui/valuedialz.h\ dsp/devicesamplesource.h\ dsp/devicesamplesink.h\ plugin/pluginapi.h\