1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2026-06-09 09:25:07 -04:00

git clone git://git.osmocom.org/sdrangelove.git

This commit is contained in:
Hexameron
2014-05-18 16:52:39 +01:00
commit 7d3bfb26fc
203 changed files with 27958 additions and 0 deletions
+14
View File
@@ -0,0 +1,14 @@
#include "gui/aboutdialog.h"
#include "ui_aboutdialog.h"
AboutDialog::AboutDialog(QWidget* parent) :
QDialog(parent),
ui(new Ui::AboutDialog)
{
ui->setupUi(this);
}
AboutDialog::~AboutDialog()
{
delete ui;
}
+161
View File
@@ -0,0 +1,161 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>484</width>
<height>503</height>
</rect>
</property>
<property name="windowTitle">
<string>About SDRangelove</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::Panel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Sunken</enum>
</property>
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../resources/res.qrc">:/logo.png</pixmap>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>&lt;p&gt;Copyright (C) 2013 maintech GmbH, Otto-Hahn-Str. 15, 97204 Höchberg, Germany&lt;br&gt;
Written by Christian Daniel.&lt;/p&gt;
&lt;p&gt;Many thanks to the osmocom developer team - especially horizon, Hoernchen &amp;amp; tnt.&lt;/p&gt;
&lt;p&gt;SDRangelove itself is licensed as &quot;GPL2+&quot; with the added exception, that plugins using only header files from the &quot;include&quot;-subdirectory and not from the &quot;include-gpl&quot;-subdirectory do not count as derived works.&lt;/p&gt;
&lt;p&gt;The following rules apply to the SDRangelove main application and libsdrbase:&lt;br&gt;
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 2 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.
You should have received a copy of the GNU General Public License along with this program. If not, see &lt;a href=&quot;http://www.gnu.org/licenses/&quot;&gt;http://www.gnu.org/licenses/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the license of installed plugins, look into the plugin list.&lt;/p&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AboutDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+26
View File
@@ -0,0 +1,26 @@
#include "gui/addpresetdialog.h"
#include "ui_addpresetdialog.h"
AddPresetDialog::AddPresetDialog(const QStringList& groups, const QString& group, QWidget* parent) :
QDialog(parent),
ui(new Ui::AddPresetDialog)
{
ui->setupUi(this);
ui->group->addItems(groups);
ui->group->lineEdit()->setText(group);
}
AddPresetDialog::~AddPresetDialog()
{
delete ui;
}
QString AddPresetDialog::group() const
{
return ui->group->lineEdit()->text();
}
QString AddPresetDialog::description() const
{
return ui->description->text();
}
+121
View File
@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AddPresetDialog</class>
<widget class="QDialog" name="AddPresetDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>324</width>
<height>204</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Preset Description</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>&amp;Group</string>
</property>
<property name="buddy">
<cstring>group</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="group">
<property name="editable">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>&amp;Description</string>
</property>
<property name="buddy">
<cstring>description</cstring>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="description"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>description</tabstop>
<tabstop>buttonBox</tabstop>
<tabstop>group</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>AddPresetDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>257</x>
<y>194</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>203</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>AddPresetDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>314</x>
<y>194</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>203</y>
</hint>
</hints>
</connection>
</connections>
</ui>
@@ -0,0 +1,77 @@
#include <QPainter>
#include <QColorDialog>
#include "gui/basicchannelsettingswidget.h"
#include "dsp/channelmarker.h"
#include "ui_basicchannelsettingswidget.h"
BasicChannelSettingsWidget::BasicChannelSettingsWidget(ChannelMarker* marker, QWidget* parent) :
QWidget(parent),
ui(new Ui::BasicChannelSettingsWidget),
m_channelMarker(marker)
{
ui->setupUi(this);
ui->title->setText(m_channelMarker->getTitle());
paintColor();
ui->red->setValue(m_channelMarker->getColor().red());
ui->green->setValue(m_channelMarker->getColor().green());
ui->blue->setValue(m_channelMarker->getColor().blue());
}
BasicChannelSettingsWidget::~BasicChannelSettingsWidget()
{
delete ui;
}
void BasicChannelSettingsWidget::on_title_textChanged(const QString& text)
{
m_channelMarker->setTitle(text);
}
void BasicChannelSettingsWidget::on_colorBtn_clicked()
{
QColor c = m_channelMarker->getColor();
c = QColorDialog::getColor(c, this, tr("Select Color for Channel"));
if(c.isValid()) {
m_channelMarker->setColor(c);
paintColor();
ui->red->setValue(m_channelMarker->getColor().red());
ui->green->setValue(m_channelMarker->getColor().green());
ui->blue->setValue(m_channelMarker->getColor().blue());
}
}
void BasicChannelSettingsWidget::paintColor()
{
QColor c(m_channelMarker->getColor());
QPixmap pm(24, 24);
pm.fill(c);
ui->colorBtn->setIcon(pm);
ui->color->setText(tr("#%1%2%3")
.arg(c.red(), 2, 16, QChar('0'))
.arg(c.green(), 2, 16, QChar('0'))
.arg(c.blue(), 2, 16, QChar('0')));
}
void BasicChannelSettingsWidget::on_red_valueChanged(int value)
{
QColor c(m_channelMarker->getColor());
c.setRed(value);
m_channelMarker->setColor(c);
paintColor();
}
void BasicChannelSettingsWidget::on_green_valueChanged(int value)
{
QColor c(m_channelMarker->getColor());
c.setGreen(value);
m_channelMarker->setColor(c);
paintColor();
}
void BasicChannelSettingsWidget::on_blue_valueChanged(int value)
{
QColor c(m_channelMarker->getColor());
c.setBlue(value);
m_channelMarker->setColor(c);
paintColor();
}
+107
View File
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>BasicChannelSettingsWidget</class>
<widget class="QWidget" name="BasicChannelSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>149</width>
<height>116</height>
</rect>
</property>
<property name="windowTitle">
<string>Title &amp; Color</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="margin">
<number>2</number>
</property>
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Title</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QLineEdit" name="title"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Color</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="colorBtn">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="color">
<property name="text">
<string>#ff0000</string>
</property>
</widget>
</item>
<item row="2" column="1" colspan="2">
<widget class="QSlider" name="red">
<property name="maximum">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="1" colspan="2">
<widget class="QSlider" name="green">
<property name="maximum">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="1" colspan="2">
<widget class="QSlider" name="blue">
<property name="maximum">
<number>255</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>title</tabstop>
<tabstop>colorBtn</tabstop>
<tabstop>red</tabstop>
<tabstop>green</tabstop>
<tabstop>blue</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+21
View File
@@ -0,0 +1,21 @@
#include <QPainter>
#include "gui/buttonswitch.h"
ButtonSwitch::ButtonSwitch(QWidget* parent) :
QToolButton(parent)
{
setCheckable(true);
m_originalPalette = palette();
connect(this, SIGNAL(toggled(bool)), this, SLOT(onToggled(bool)));
}
void ButtonSwitch::onToggled(bool checked)
{
if(checked) {
QPalette p = m_originalPalette;
p.setColor(QPalette::Button, QColor(0x80, 0x46, 0x00));
setPalette(p);
} else {
setPalette(m_originalPalette);
}
}
+36
View File
@@ -0,0 +1,36 @@
#include <QBoxLayout>
#include <QSpacerItem>
#include <QPainter>
#include <QResizeEvent>
#include "gui/channelwindow.h"
#include "gui/rollupwidget.h"
ChannelWindow::ChannelWindow(QWidget* parent) :
QScrollArea(parent)
{
m_container = new QWidget(this);
m_layout = new QBoxLayout(QBoxLayout::TopToBottom, m_container);
setWidget(m_container);
setWidgetResizable(true);
setBackgroundRole(QPalette::Base);
m_layout->setMargin(3);
m_layout->setSpacing(3);
}
void ChannelWindow::addRollupWidget(QWidget* rollupWidget)
{
rollupWidget->setParent(m_container);
m_container->layout()->addWidget(rollupWidget);
}
void ChannelWindow::resizeEvent(QResizeEvent* event)
{
if(event->size().height() > event->size().width()) {
m_layout->setDirection(QBoxLayout::TopToBottom);
m_layout->setAlignment(Qt::AlignTop);
} else {
m_layout->setDirection(QBoxLayout::LeftToRight);
m_layout->setAlignment(Qt::AlignLeft);
}
QScrollArea::resizeEvent(event);
}
+478
View File
@@ -0,0 +1,478 @@
#include <QPainter>
#include <QMouseEvent>
#include "gui/glscope.h"
#include "dsp/dspengine.h"
#ifdef _WIN32
static double log2f(double n)
{
return log(n) / log(2.0);
}
#endif
GLScope::GLScope(QWidget* parent) :
QGLWidget(parent),
m_dataChanged(false),
m_configChanged(true),
m_mode(ModeIQ),
m_orientation(Qt::Horizontal),
m_displayTrace(&m_rawTrace),
m_oldTraceSize(-1),
m_sampleRate(0),
m_dspEngine(NULL),
m_scopeVis(NULL),
m_amp(1.0),
m_timeBase(1),
m_timeOfsProMill(0),
m_triggerChannel(ScopeVis::TriggerFreeRun)
{
setAttribute(Qt::WA_OpaquePaintEvent);
connect(&m_timer, SIGNAL(timeout()), this, SLOT(tick()));
m_timer.start(50);
}
GLScope::~GLScope()
{
if(m_dspEngine != NULL) {
m_dspEngine->removeSink(m_scopeVis);
delete m_scopeVis;
}
}
void GLScope::setDSPEngine(DSPEngine* dspEngine)
{
if((m_dspEngine == NULL) && (dspEngine != NULL)) {
m_dspEngine = dspEngine;
m_scopeVis = new ScopeVis(this);
m_dspEngine->addSink(m_scopeVis);
}
}
void GLScope::setAmp(Real amp)
{
m_amp = amp;
update();
}
void GLScope::setTimeBase(int timeBase)
{
m_timeBase = timeBase;
update();
}
void GLScope::setTimeOfsProMill(int timeOfsProMill)
{
m_timeOfsProMill = timeOfsProMill;
update();
}
void GLScope::setMode(Mode mode)
{
m_mode = mode;
m_dataChanged = true;
update();
}
void GLScope::setOrientation(Qt::Orientation orientation)
{
m_orientation = orientation;
m_configChanged = true;
update();
}
void GLScope::newTrace(const std::vector<Complex>& trace, int sampleRate)
{
if(!m_mutex.tryLock(2))
return;
if(m_dataChanged) {
m_mutex.unlock();
return;
}
m_rawTrace = trace;
m_sampleRate = sampleRate;
m_dataChanged = true;
m_mutex.unlock();
}
void GLScope::initializeGL()
{
glDisable(GL_DEPTH_TEST);
}
void GLScope::resizeGL(int width, int height)
{
glViewport(0, 0, width, height);
m_configChanged = true;
}
void GLScope::paintGL()
{
if(!m_mutex.tryLock(2))
return;
if(m_configChanged)
applyConfig();
handleMode();
if(m_displayTrace->size() != m_oldTraceSize) {
m_oldTraceSize = m_displayTrace->size();
emit traceSizeChanged(m_displayTrace->size());
}
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix();
glScalef(2.0, -2.0, 1.0);
glTranslatef(-0.50, -0.5, 0);
// I
// draw rect around
glPushMatrix();
glTranslatef(m_glScopeRect1.x(), m_glScopeRect1.y(), 0);
glScalef(m_glScopeRect1.width(), m_glScopeRect1.height(), 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0f);
glColor4f(1, 1, 1, 0.5);
glBegin(GL_LINE_LOOP);
glVertex2f(1, 1);
glVertex2f(0, 1);
glVertex2f(0, 0);
glVertex2f(1, 0);
glEnd();
glDisable(GL_BLEND);
// paint grid
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0f);
glColor4f(1, 1, 1, 0.05f);
for(int i = 1; i < 10; i++) {
glBegin(GL_LINE_LOOP);
glVertex2f(0, i * 0.1);
glVertex2f(1, i * 0.1);
glEnd();
}
for(int i = 1; i < 10; i++) {
glBegin(GL_LINE_LOOP);
glVertex2f(i * 0.1, 0);
glVertex2f(i * 0.1, 1);
glEnd();
}
glPopMatrix();
if(m_triggerChannel == ScopeVis::TriggerChannelI) {
glPushMatrix();
glTranslatef(m_glScopeRect1.x(), m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0, 0);
glScalef(m_glScopeRect1.width(), -(m_glScopeRect1.height() / 2) * m_amp1, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(0, 1, 0, 0.3f);
glBegin(GL_LINE_LOOP);
glVertex2f(0, m_triggerLevelHigh);
glVertex2f(1, m_triggerLevelHigh);
glEnd();
glColor4f(0, 0.8f, 0.0, 0.3f);
glBegin(GL_LINE_LOOP);
glVertex2f(0, m_triggerLevelLow);
glVertex2f(1, m_triggerLevelLow);
glEnd();
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
if(m_displayTrace->size() > 0) {
glPushMatrix();
glTranslatef(m_glScopeRect1.x(), m_glScopeRect1.y() + m_glScopeRect1.height() / 2.0, 0);
glScalef(m_glScopeRect1.width() * (float)m_timeBase / (float)(m_displayTrace->size() - 1), -(m_glScopeRect1.height() / 2) * m_amp1, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(1, 1, 0, 0.4f);
int start = m_timeOfsProMill * (m_displayTrace->size() - (m_displayTrace->size() / m_timeBase)) / 1000;
int end = start + m_displayTrace->size() / m_timeBase;
if(end - start < 2)
start--;
float posLimit = 1.0 / m_amp1;
float negLimit = -1.0 / m_amp1;
glBegin(GL_LINE_STRIP);
for(int i = start; i < end; i++) {
float v = (*m_displayTrace)[i].real() + m_ofs1;
if(v > posLimit)
v = posLimit;
else if(v < negLimit)
v = negLimit;
glVertex2f(i - start, v);
}
glEnd();
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
// Q
// draw rect around
glPushMatrix();
glTranslatef(m_glScopeRect2.x(), m_glScopeRect2.y(), 0);
glScalef(m_glScopeRect2.width(), m_glScopeRect2.height(), 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0f);
glColor4f(1, 1, 1, 0.5);
glBegin(GL_LINE_LOOP);
glVertex2f(1, 1);
glVertex2f(0, 1);
glVertex2f(0, 0);
glVertex2f(1, 0);
glEnd();
glDisable(GL_BLEND);
// paint grid
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(1.0f);
glColor4f(1, 1, 1, 0.05f);
for(int i = 1; i < 10; i++) {
glBegin(GL_LINE_LOOP);
glVertex2f(0, i * 0.1);
glVertex2f(1, i * 0.1);
glEnd();
}
for(int i = 1; i < 10; i++) {
glBegin(GL_LINE_LOOP);
glVertex2f(i * 0.1, 0);
glVertex2f(i * 0.1, 1);
glEnd();
}
glPopMatrix();
if(m_triggerChannel == ScopeVis::TriggerChannelQ) {
glPushMatrix();
glTranslatef(m_glScopeRect2.x(), m_glScopeRect2.y() + m_glScopeRect2.height() / 2.0, 0);
glScalef(m_glScopeRect2.width(), -(m_glScopeRect2.height() / 2) * m_amp2, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(0, 1, 0, 0.3f);
glBegin(GL_LINE_LOOP);
glVertex2f(0, m_triggerLevelHigh);
glVertex2f(1, m_triggerLevelHigh);
glEnd();
glColor4f(0, 0.8f, 0.0, 0.3f);
glBegin(GL_LINE_LOOP);
glVertex2f(0, m_triggerLevelLow);
glVertex2f(1, m_triggerLevelLow);
glEnd();
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
if(m_displayTrace->size() > 0) {
glPushMatrix();
glTranslatef(m_glScopeRect2.x(), m_glScopeRect2.y() + m_glScopeRect2.height() / 2.0, 0);
glScalef(m_glScopeRect2.width() * (float)m_timeBase / (float)(m_displayTrace->size() - 1), -(m_glScopeRect2.height() / 2) * m_amp2, 1);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glLineWidth(1.0f);
glColor4f(1, 1, 0, 0.4f);
int start = m_timeOfsProMill * (m_displayTrace->size() - (m_displayTrace->size() / m_timeBase)) / 1000;
int end = start + m_displayTrace->size() / m_timeBase;
if(end - start < 2)
start--;
float posLimit = 1.0 / m_amp2;
float negLimit = -1.0 / m_amp2;
glBegin(GL_LINE_STRIP);
for(int i = start; i < end; i++) {
float v = (*m_displayTrace)[i].imag();
if(v > posLimit)
v = posLimit;
else if(v < negLimit)
v = negLimit;
glVertex2f(i - start, v);
}
glEnd();
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
glPopMatrix();
m_dataChanged = false;
m_mutex.unlock();
}
void GLScope::mousePressEvent(QMouseEvent* event)
{
#if 0
int x = event->x() - 10;
int y = event->y() - 10;
Real time;
Real amplitude;
ScopeVis::TriggerChannel channel;
if((x < 0) || (x >= width() - 20))
return;
if((y < 0) || (y >= height() - 20))
return;
if((m_sampleRate != 0) && (m_timeBase != 0) && (width() > 20))
time = ((Real)x * (Real)m_displayTrace->size()) / ((Real)m_sampleRate * (Real)m_timeBase * (Real)(width() - 20));
else time = -1.0;
if(y < (height() - 30) / 2) {
channel = ScopeVis::TriggerChannelI;
if((m_amp != 0) && (height() > 30))
amplitude = 2.0 * ((height() - 30) * 0.25 - (Real)y) / (m_amp * (height() - 30) / 2.0);
else amplitude = -1;
} else if(y > (height() - 30) / 2 + 10) {
y -= 10 + (height() - 30) / 2;
channel = ScopeVis::TriggerChannelQ;
if((m_amp != 0) && (height() > 30))
amplitude = 2.0 * ((height() - 30) * 0.25 - (Real)y) / (m_amp * (height() - 30) / 2.0);
else amplitude = -1;
} else {
channel = ScopeVis::TriggerFreeRun;
}
if(m_dspEngine != NULL) {
qDebug("amp %f", amplitude);
m_triggerLevelHigh = amplitude + 0.01 / m_amp;
m_triggerLevelLow = amplitude - 0.01 / m_amp;
if(m_triggerLevelHigh > 1.0)
m_triggerLevelHigh = 1.0;
else if(m_triggerLevelHigh < -1.0)
m_triggerLevelHigh = -1.0;
if(m_triggerLevelLow > 1.0)
m_triggerLevelLow = 1.0;
else if(m_triggerLevelLow < -1.0)
m_triggerLevelLow = -1.0;
m_scopeVis->configure(m_dspEngine->getMessageQueue(), channel, m_triggerLevelHigh, m_triggerLevelLow);
m_triggerChannel = channel;
m_changed = true;
update();
}
#endif
}
void GLScope::handleMode()
{
switch(m_mode) {
case ModeIQ:
m_displayTrace = &m_rawTrace;
m_amp1 = m_amp;
m_amp2 = m_amp;
m_ofs1 = 0.0;
m_ofs2 = 0.0;
break;
case ModeMagLinPha: {
m_mathTrace.resize(m_rawTrace.size());
std::vector<Complex>::iterator dst = m_mathTrace.begin();
for(std::vector<Complex>::const_iterator src = m_rawTrace.begin(); src != m_rawTrace.end(); ++src)
*dst++ = Complex(abs(*src), arg(*src) / M_PI);
m_displayTrace = &m_mathTrace;
m_amp1 = m_amp;
m_amp2 = 1.0;
m_ofs1 = -1.0 / m_amp1;
m_ofs2 = 0.0;
break;
}
case ModeMagdBPha: {
m_mathTrace.resize(m_rawTrace.size());
std::vector<Complex>::iterator dst = m_mathTrace.begin();
Real mult = (10.0f / log2f(10.0f));
for(std::vector<Complex>::const_iterator src = m_rawTrace.begin(); src != m_rawTrace.end(); ++src) {
Real v = src->real() * src->real() + src->imag() * src->imag();
v = (96.0 + (mult * log2f(v))) / 96.0;
*dst++ = Complex(v, arg(*src) / M_PI);
}
m_displayTrace = &m_mathTrace;
m_amp1 = 2.0 * m_amp;
m_amp2 = 1.0;
m_ofs1 = -1.0 / m_amp1;
m_ofs2 = 0.0;
break;
}
case ModeDerived12: {
if(m_rawTrace.size() > 3) {
m_mathTrace.resize(m_rawTrace.size() - 3);
std::vector<Complex>::iterator dst = m_mathTrace.begin();
for(uint i = 3; i < m_rawTrace.size() ; i++) {
*dst++ = Complex(
abs(m_rawTrace[i] - m_rawTrace[i - 1]),
abs(m_rawTrace[i] - m_rawTrace[i - 1]) - abs(m_rawTrace[i - 2] - m_rawTrace[i - 3]));
}
m_displayTrace = &m_mathTrace;
m_amp1 = m_amp;
m_amp2 = m_amp;
m_ofs1 = -1.0 / m_amp1;
m_ofs2 = 0.0;
}
break;
}
case ModeCyclostationary: {
if(m_rawTrace.size() > 2) {
m_mathTrace.resize(m_rawTrace.size() - 2);
std::vector<Complex>::iterator dst = m_mathTrace.begin();
for(uint i = 2; i < m_rawTrace.size() ; i++)
*dst++ = Complex(abs(m_rawTrace[i] - conj(m_rawTrace[i - 1])), 0);
m_displayTrace = &m_mathTrace;
m_amp1 = m_amp;
m_amp2 = m_amp;
m_ofs1 = -1.0 / m_amp1;
m_ofs2 = 0.0;
}
break;
}
}
}
void GLScope::applyConfig()
{
m_configChanged = false;
if(m_orientation == Qt::Vertical) {
m_glScopeRect1 = QRectF(
(float)10 / (float)width(),
(float)10 / (float)height(),
(float)(width() - 10 - 10) / (float)width(),
(float)((height() - 10 - 10 - 10) / 2) / (float)height()
);
m_glScopeRect2 = QRectF(
(float)10 / (float)width(),
(float)(10 + 10 + (height() - 10 - 10 - 10) / 2) / (float)height(),
(float)(width() - 10 - 10) / (float)width(),
(float)((height() - 10 - 10 - 10) / 2) / (float)height()
);
} else {
m_glScopeRect1 = QRectF(
(float)10 / (float)width(),
(float)10 / (float)height(),
(float)((width() - 10 - 10 - 10) / 2) / (float)width(),
(float)(height() - 10 - 10) / (float)height()
);
m_glScopeRect2 = QRectF(
(float)(10 + 10 + ((width() - 10 - 10 - 10) / 2)) / (float)width(),
(float)10 / (float)height(),
(float)((width() - 10 - 10 - 10) / 2) / (float)width(),
(float)(height() - 10 - 10) / (float)height()
);
}
}
void GLScope::tick()
{
if(m_dataChanged)
update();
}
File diff suppressed because it is too large Load Diff
+210
View File
@@ -0,0 +1,210 @@
#include "gui/glspectrumgui.h"
#include "dsp/fftwindow.h"
#include "dsp/spectrumvis.h"
#include "gui/glspectrum.h"
#include "util/simpleserializer.h"
#include "ui_glspectrumgui.h"
GLSpectrumGUI::GLSpectrumGUI(QWidget* parent) :
QWidget(parent),
ui(new Ui::GLSpectrumGUI),
m_messageQueue(NULL),
m_spectrumVis(NULL),
m_glSpectrum(NULL),
m_fftSize(1024),
m_fftOverlap(10),
m_fftWindow(FFTWindow::Hamming),
m_refLevel(0),
m_powerRange(100),
m_decay(0),
m_displayWaterfall(false),
m_invertedWaterfall(false),
m_displayMaxHold(true),
m_displayHistogram(true),
m_displayGrid(true),
m_invert(false)
{
ui->setupUi(this);
for(int ref = 0; ref >= -95; ref -= 5)
ui->refLevel->addItem(QString("%1").arg(ref));
for(int range = 100; range >= 5; range -= 5)
ui->levelRange->addItem(QString("%1").arg(range));
}
GLSpectrumGUI::~GLSpectrumGUI()
{
delete ui;
}
void GLSpectrumGUI::setBuddies(MessageQueue* messageQueue, SpectrumVis* spectrumVis, GLSpectrum* glSpectrum)
{
m_messageQueue = messageQueue;
m_spectrumVis = spectrumVis;
m_glSpectrum = glSpectrum;
applySettings();
}
void GLSpectrumGUI::resetToDefaults()
{
m_fftSize = 1024;
m_fftOverlap = 10;
m_fftWindow = FFTWindow::Hamming;
m_refLevel = 0;
m_powerRange = 100;
m_decay = 0;
m_displayWaterfall = false;
m_invertedWaterfall = false;
m_displayMaxHold = true;
m_displayHistogram = true;
m_displayGrid = true;
m_invert = false;
applySettings();
}
QByteArray GLSpectrumGUI::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_fftSize);
s.writeS32(2, m_fftOverlap);
s.writeS32(3, m_fftWindow);
s.writeReal(4, m_refLevel);
s.writeReal(5, m_powerRange);
s.writeBool(6, m_displayWaterfall);
s.writeBool(7, m_invertedWaterfall);
s.writeBool(8, m_displayMaxHold);
s.writeBool(9, m_displayHistogram);
s.writeS32(10, m_decay);
s.writeBool(11, m_displayGrid);
s.writeBool(12, m_invert);
return s.final();
}
bool GLSpectrumGUI::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
d.readS32(1, &m_fftSize, 1024);
d.readS32(2, &m_fftOverlap, 10);
d.readS32(3, &m_fftWindow, FFTWindow::Hamming);
d.readReal(4, &m_refLevel, 0);
d.readReal(5, &m_powerRange, 100);
d.readBool(6, &m_displayWaterfall, true);
d.readBool(7, &m_invertedWaterfall, false);
d.readBool(8, &m_displayMaxHold, false);
d.readBool(9, &m_displayHistogram, true);
d.readS32(10, &m_decay, 0);
d.readBool(11, &m_displayGrid, true);
d.readBool(12, &m_invert, false);
applySettings();
return true;
} else {
resetToDefaults();
return false;
}
}
void GLSpectrumGUI::applySettings()
{
ui->fftWindow->setCurrentIndex(m_fftWindow);
for(int i = 0; i < 6; i++) {
if(m_fftSize == (1 << (i + 7))) {
ui->fftSize->setCurrentIndex(i);
break;
}
}
ui->refLevel->setCurrentIndex(-m_refLevel / 5);
ui->levelRange->setCurrentIndex((100 - m_powerRange) / 5);
ui->decay->setCurrentIndex(m_decay + 2);
ui->waterfall->setChecked(m_displayWaterfall);
ui->maxHold->setChecked(m_displayMaxHold);
ui->histogram->setChecked(m_displayHistogram);
ui->invert->setChecked(m_invert);
ui->grid->setChecked(m_displayGrid);
m_glSpectrum->setDisplayWaterfall(m_displayWaterfall);
m_glSpectrum->setInvertedWaterfall(m_invertedWaterfall);
m_glSpectrum->setDisplayMaxHold(m_displayMaxHold);
m_glSpectrum->setDisplayHistogram(m_displayHistogram);
m_glSpectrum->setDecay(m_decay);
m_glSpectrum->setInvertedWaterfall(m_invert);
m_glSpectrum->setDisplayGrid(m_displayGrid);
m_spectrumVis->configure(m_messageQueue, m_fftSize, m_fftOverlap, (FFTWindow::Function)m_fftWindow);
}
void GLSpectrumGUI::on_fftWindow_currentIndexChanged(int index)
{
m_fftWindow = index;
if(m_spectrumVis == NULL)
return;
m_spectrumVis->configure(m_messageQueue, m_fftSize, m_fftOverlap, (FFTWindow::Function)m_fftWindow);
}
void GLSpectrumGUI::on_fftSize_currentIndexChanged(int index)
{
m_fftSize = 1 << (7 + index);
if(m_spectrumVis != NULL)
m_spectrumVis->configure(m_messageQueue, m_fftSize, m_fftOverlap, (FFTWindow::Function)m_fftWindow);
}
void GLSpectrumGUI::on_refLevel_currentIndexChanged(int index)
{
m_refLevel = 0 - index * 5;
if(m_glSpectrum != NULL)
m_glSpectrum->setReferenceLevel(m_refLevel);
}
void GLSpectrumGUI::on_levelRange_currentIndexChanged(int index)
{
m_powerRange = 100 - index * 5;
if(m_glSpectrum != NULL)
m_glSpectrum->setPowerRange(m_powerRange);
}
void GLSpectrumGUI::on_decay_currentIndexChanged(int index)
{
m_decay = index - 2;
if(m_glSpectrum != NULL)
m_glSpectrum->setDecay(m_decay);
}
void GLSpectrumGUI::on_waterfall_toggled(bool checked)
{
m_displayWaterfall = checked;
if(m_glSpectrum != NULL)
m_glSpectrum->setDisplayWaterfall(m_displayWaterfall);
}
void GLSpectrumGUI::on_histogram_toggled(bool checked)
{
m_displayHistogram = checked;
if(m_glSpectrum != NULL)
m_glSpectrum->setDisplayHistogram(m_displayHistogram);
}
void GLSpectrumGUI::on_maxHold_toggled(bool checked)
{
m_displayMaxHold = checked;
if(m_glSpectrum != NULL)
m_glSpectrum->setDisplayMaxHold(m_displayMaxHold);
}
void GLSpectrumGUI::on_invert_toggled(bool checked)
{
m_invert = checked;
if(m_glSpectrum != NULL)
m_glSpectrum->setInvertedWaterfall(m_invert);
}
void GLSpectrumGUI::on_grid_toggled(bool checked)
{
m_displayGrid = checked;
if(m_glSpectrum != NULL)
m_glSpectrum->setDisplayGrid(m_displayGrid);
}
+476
View File
@@ -0,0 +1,476 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>GLSpectrumGUI</class>
<widget class="QWidget" name="GLSpectrumGUI">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>215</width>
<height>94</height>
</rect>
</property>
<property name="windowTitle">
<string>Oscilloscope</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="1,1,1,1">
<property name="margin">
<number>2</number>
</property>
<property name="spacing">
<number>3</number>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_17">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Window</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_18">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>FFT Size</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_19">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Ref (dB)</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_20">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Range (dB)</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="fftWindow">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>FFT window function</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>Bartlett</string>
</property>
</item>
<item>
<property name="text">
<string>Blackman-Harris</string>
</property>
</item>
<item>
<property name="text">
<string>Flat Top</string>
</property>
</item>
<item>
<property name="text">
<string>Hamming</string>
</property>
</item>
<item>
<property name="text">
<string>Hanning</string>
</property>
</item>
<item>
<property name="text">
<string>Rectangle</string>
</property>
</item>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="fftSize">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>FFT window function</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>128</string>
</property>
</item>
<item>
<property name="text">
<string>256</string>
</property>
</item>
<item>
<property name="text">
<string>512</string>
</property>
</item>
<item>
<property name="text">
<string>1024</string>
</property>
</item>
<item>
<property name="text">
<string>2048</string>
</property>
</item>
<item>
<property name="text">
<string>4096</string>
</property>
</item>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="refLevel">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>FFT window function</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QComboBox" name="levelRange">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>FFT window function</string>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Decay</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QComboBox" name="decay">
<property name="sizePolicy">
<sizepolicy hsizetype="Ignored" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip">
<string>FFT window function</string>
</property>
<property name="currentIndex">
<number>0</number>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContents</enum>
</property>
<item>
<property name="text">
<string>-2</string>
</property>
</item>
<item>
<property name="text">
<string>-1</string>
</property>
</item>
<item>
<property name="text">
<string>normal</string>
</property>
</item>
<item>
<property name="text">
<string>+1</string>
</property>
</item>
<item>
<property name="text">
<string>+2</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1" colspan="3">
<layout class="QHBoxLayout" name="controlBtns">
<property name="spacing">
<number>3</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="ButtonSwitch" name="waterfall">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Display waterfall</string>
</property>
<property name="text">
<string>Waterfall</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/waterfall.png</normaloff>:/waterfall.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="histogram">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Display phosphor effect spectrum</string>
</property>
<property name="text">
<string>Histogram</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/histogram.png</normaloff>:/histogram.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="maxHold">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Display live spectrum</string>
</property>
<property name="text">
<string>Max Hold</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/maxhold.png</normaloff>:/maxhold.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="invert">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Exchange waterfall and histogram</string>
</property>
<property name="text">
<string>Inv</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/invertspectrum.png</normaloff>:/invertspectrum.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="ButtonSwitch" name="grid">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="toolTip">
<string>Toggle the scale grid</string>
</property>
<property name="text">
<string>Grid</string>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/grid.png</normaloff>:/grid.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>fftWindow</tabstop>
<tabstop>fftSize</tabstop>
<tabstop>refLevel</tabstop>
<tabstop>levelRange</tabstop>
<tabstop>decay</tabstop>
<tabstop>waterfall</tabstop>
<tabstop>histogram</tabstop>
<tabstop>maxHold</tabstop>
<tabstop>invert</tabstop>
<tabstop>grid</tabstop>
</tabstops>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections/>
</ui>
+56
View File
@@ -0,0 +1,56 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QPainter>
#include "gui/indicator.h"
void Indicator::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setPen(Qt::black);
painter.setBrush(m_color);
painter.drawRect(0, 0, 18, 15);
painter.drawText(0, 0, 19, 16, Qt::AlignCenter | Qt::AlignHCenter, m_text);
}
QSize Indicator::sizeHint() const
{
return QSize(20, 16);
}
Indicator::Indicator(const QString& text, QWidget* parent) :
QWidget(parent),
m_color(Qt::gray),
m_text(text)
{
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
QFont f = font();
f.setBold(true);
f.setPixelSize(8);
setFont(f);
}
void Indicator::setColor(const QColor& color)
{
if(m_color != color) {
m_color = color;
update();
}
}
+42
View File
@@ -0,0 +1,42 @@
#include "gui/pluginsdialog.h"
#include "mainwindow.h"
#include "ui_pluginsdialog.h"
PluginsDialog::PluginsDialog(PluginManager* pluginManager, QWidget* parent) :
QDialog(parent),
ui(new Ui::PluginsDialog)
{
ui->setupUi(this);
const PluginManager::Plugins& plugins = pluginManager->getPlugins();
for(PluginManager::Plugins::const_iterator it = plugins.constBegin(); it != plugins.constEnd(); ++it) {
QStringList sl;
const PluginDescriptor& desc = it->plugin->getPluginDescriptor();
sl.append(desc.displayedName);
sl.append(desc.version);
if(desc.licenseIsGPL)
sl.append(tr("YES"));
else sl.append("no");
QTreeWidgetItem* pluginItem = new QTreeWidgetItem(ui->tree, sl);
sl.clear();
sl.append(tr("Copyright: %1").arg(desc.copyright));
QTreeWidgetItem* item = new QTreeWidgetItem(pluginItem, sl);
item->setFirstColumnSpanned(true);
sl.clear();
sl.append(tr("Website: %1").arg(desc.website));
item = new QTreeWidgetItem(pluginItem, sl);
item->setFirstColumnSpanned(true);
sl.clear();
sl.append(tr("Source Code: %1").arg(desc.sourceCodeURL));
item = new QTreeWidgetItem(pluginItem, sl);
item->setFirstColumnSpanned(true);
}
ui->tree->resizeColumnToContents(0);
ui->tree->resizeColumnToContents(1);
ui->tree->resizeColumnToContents(2);
}
PluginsDialog::~PluginsDialog()
{
delete ui;
}
+67
View File
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PluginsDialog</class>
<widget class="QDialog" name="PluginsDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Loaded Plugins</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeWidget" name="tree">
<column>
<property name="text">
<string>Name</string>
</property>
</column>
<column>
<property name="text">
<string>Version</string>
</property>
</column>
<column>
<property name="text">
<string>GPL</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PluginsDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+55
View File
@@ -0,0 +1,55 @@
#include <QTreeWidgetItem>
#include "gui/preferencesdialog.h"
#include "ui_preferencesdialog.h"
#include "audio/audiodeviceinfo.h"
PreferencesDialog::PreferencesDialog(AudioDeviceInfo* audioDeviceInfo, QWidget* parent) :
QDialog(parent),
ui(new Ui::PreferencesDialog),
m_audioDeviceInfo(audioDeviceInfo)
{
ui->setupUi(this);
const AudioDeviceInfo::Devices& devices = audioDeviceInfo->getDevices();
QTreeWidgetItem* api;
QStringList sl;
sl.append(tr("Default (use first suitable device)"));
api = new QTreeWidgetItem(ui->audioTree, sl, ATDefault);
api->setFirstColumnSpanned(true);
for(AudioDeviceInfo::Devices::const_iterator it = devices.begin(); it != devices.end(); ++it) {
int apiIndex;
sl.clear();
for(apiIndex = 0; apiIndex < ui->audioTree->topLevelItemCount(); ++apiIndex) {
if(ui->audioTree->topLevelItem(apiIndex)->text(0) == it->api)
break;
}
if(apiIndex >= ui->audioTree->topLevelItemCount()) {
sl.append(it->api);
api = new QTreeWidgetItem(ui->audioTree, sl, ATInterface);
api->setExpanded(true);
api->setFirstColumnSpanned(true);
sl.clear();
} else {
api = ui->audioTree->topLevelItem(apiIndex);
}
sl.append(it->name);
new QTreeWidgetItem(api, sl, ATDevice);
}
if(ui->audioTree->currentItem() == NULL)
ui->audioTree->setCurrentItem(ui->audioTree->topLevelItem(0));
ui->tabWidget->setCurrentIndex(0);
}
PreferencesDialog::~PreferencesDialog()
{
delete ui;
}
void PreferencesDialog::accept()
{
QDialog::accept();
}
+109
View File
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PreferencesDialog</class>
<widget class="QDialog" name="PreferencesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Receiver Hardware</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTreeWidget" name="treeWidget">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Audio Output</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTreeWidget" name="audioTree">
<column>
<property name="text">
<string notr="true">Device</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>buttonBox</tabstop>
<tabstop>tabWidget</tabstop>
<tabstop>treeWidget</tabstop>
<tabstop>audioTree</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PreferencesDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PreferencesDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+29
View File
@@ -0,0 +1,29 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "gui/presetitem.h"
PresetItem::PresetItem(QTreeWidgetItem* parent, const QStringList& strings, quint64 frequency, int type) :
QTreeWidgetItem(parent, strings, type),
m_frequency(frequency)
{
}
bool PresetItem::operator<(const QTreeWidgetItem& other) const
{
return m_frequency < ((const PresetItem&)other).m_frequency;
}
+348
View File
@@ -0,0 +1,348 @@
#include <QEvent>
#include <QPainter>
#include <QMouseEvent>
#include "gui/rollupwidget.h"
#include "ui_glspectrumgui.h"
RollupWidget::RollupWidget(QWidget* parent) :
QWidget(parent)
{
setMinimumSize(250, 150);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
setBackgroundRole(QPalette::Window);
setAutoFillBackground(false);
setAttribute(Qt::WA_OpaquePaintEvent, true);
m_titleColor = palette().highlight().color();
}
QByteArray RollupWidget::saveState(int version) const
{
QByteArray state;
QDataStream stream(&state, QIODevice::WriteOnly);
int count = 0;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL)
count++;
}
stream << VersionMarker;
stream << version;
stream << count;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL) {
stream << r->objectName();
if(r->isHidden())
stream << (int)0;
else stream << (int)1;
}
}
return state;
}
bool RollupWidget::restoreState(const QByteArray& state, int version)
{
if(state.isEmpty())
return false;
QByteArray sd = state;
QDataStream stream(&sd, QIODevice::ReadOnly);
int marker, v;
stream >> marker;
stream >> v;
if((stream.status() != QDataStream::Ok) || (marker != VersionMarker) || (v != version))
return false;
int count;
stream >> count;
if(stream.status() != QDataStream::Ok)
return false;
for(int i = 0; i < count; ++i) {
QString name;
int visible;
stream >> name;
stream >> visible;
if(stream.status() != QDataStream::Ok)
return false;
for(int j = 0; j < children().count(); ++j) {
QWidget* r = qobject_cast<QWidget*>(children()[j]);
if(r != NULL) {
if(r->objectName() == name) {
if(visible)
r->show();
else r->hide();
break;
}
}
}
}
return true;
}
void RollupWidget::setTitleColor(const QColor& c)
{
m_titleColor = c;
update();
}
int RollupWidget::arrangeRollups()
{
QFontMetrics fm(font());
int pos = fm.height() + 4;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL) {
pos += fm.height() + 2;
if(!r->isHidden()) {
r->move(2, pos + 3);
int h = 0;
if(r->hasHeightForWidth())
h = r->heightForWidth(width() - 4);
else h = r->sizeHint().height();
r->resize(width() - 4, h);
pos += r->height() + 5;
}
}
}
setMinimumHeight(pos);
setMaximumHeight(pos);
return pos;
}
void RollupWidget::paintEvent(QPaintEvent*)
{
QPainter p(this);
QColor frame = palette().highlight().color();
// Eigenbau
QFontMetrics fm(font());
p.setRenderHint(QPainter::Antialiasing, true);
// Ecken
p.setPen(Qt::NoPen);
p.setBrush(palette().base());
p.drawRect(0, 0, 5, 5);
p.drawRect(width() - 5, 0, 5, 5);
p.drawRect(0, height() - 5, 5, 5);
p.drawRect(width() - 5, height() - 5, 5, 5);
// Rahmen
p.setPen(frame);
p.setBrush(palette().window());
QRectF r(rect());
r.adjust(0.5, 0.5, -0.5, -0.5);
p.drawRoundedRect(r, 3.0, 3.0, Qt::AbsoluteSize);
// Titel-Hintergrund
p.setPen(Qt::NoPen);
p.setBrush(m_titleColor);
QPainterPath path;
path.moveTo(1.5, fm.height() + 2.5);
path.lineTo(width() - 1.5, fm.height() + 2.5);
path.lineTo(width() - 1.5, 3.5);
path.arcTo(QRectF(width() - 3.5, 0, 2.5, 2.5), 270, -90);
path.lineTo(3.5, 1.5);
path.arcTo(QRectF(1.5, 2.5, 2.5, 2.5), 90, 90);
p.drawPath(path);
// Titel-Abschlusslinie
p.setPen(frame);
p.drawLine(QPointF(0.5, 2 + fm.height() + 1.5), QPointF(width() - 1.5, 2 + fm.height() + 1.5));
// Aktiv-Button links
p.setPen(QPen(palette().windowText().color(), 1.0));
p.setBrush(palette().light());
p.drawRoundedRect(QRectF(3.5, 3.5, fm.ascent(), fm.ascent()), 2.0, 2.0, Qt::AbsoluteSize);
// Schließen-Button rechts
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(QPen(palette().windowText().color(), 1.0));
p.setBrush(palette().light());
r = QRectF(width() - 3.5 - fm.ascent(), 3.5, fm.ascent(), fm.ascent());
p.drawRoundedRect(r, 2.0, 2.0, Qt::AbsoluteSize);
p.setPen(QPen(palette().windowText().color(), 1.5));
p.drawLine(r.topLeft() + QPointF(1, 1), r.bottomRight() + QPointF(-1, -1));
p.drawLine(r.bottomLeft() + QPointF(1, -1), r.topRight() + QPointF(-1, 1));
// Titel
p.setPen(palette().highlightedText().color());
p.drawText(QRect(2 + fm.height(), 2, width() - 4 - 2 * fm.height(), fm.height()),
fm.elidedText(windowTitle(), Qt::ElideMiddle, width() - 4 - 2 * fm.height(), 0));
// Rollups
int pos = fm.height() + 4;
const QObjectList& c = children();
QObjectList::ConstIterator w = c.begin();
QObjectList::ConstIterator n = c.begin();
for(n = c.begin(); n != c.end(); ++n) {
if(qobject_cast<QWidget*>(*n) != NULL)
break;
}
for(w = n; w != c.end(); w = n) {
if(n != c.end())
++n;
for(; n != c.end(); ++n) {
if(qobject_cast<QWidget*>(*n) != NULL)
break;
}
pos += paintRollup(qobject_cast<QWidget*>(*w), pos, &p, n == c.end(), frame);
}
}
int RollupWidget::paintRollup(QWidget* rollup, int pos, QPainter* p, bool last, const QColor& frame)
{
QFontMetrics fm(font());
int height = 1;
// Titel-Abschlusslinie
if(!rollup->isHidden()) {
p->setPen(palette().dark().color());
p->drawLine(QPointF(1.5, pos + fm.height() + 1.5), QPointF(width() - 1.5, pos + fm.height() + 1.5));
p->setPen(palette().light().color());
p->drawLine(QPointF(1.5, pos + fm.height() + 2.5), QPointF(width() - 1.5, pos + fm.height() + 2.5));
height += 2;
} else {
if(!last) {
p->setPen(frame);
p->drawLine(QPointF(1.5, pos + fm.height() + 1.5), QPointF(width() - 1.5, pos + fm.height() + 1.5));
height++;
}
}
// Titel
p->setPen(palette().windowText().color());
p->drawText(QRect(2 + fm.height(), pos, width() - 4 - fm.height(), fm.height()),
fm.elidedText(rollup->windowTitle(), Qt::ElideMiddle, width() - 4 - fm.height(), 0));
height += fm.height();
// Ausklapp-Icon
p->setPen(palette().windowText().color());
p->setBrush(palette().windowText());
if(!rollup->isHidden()) {
QPolygonF a;
a.append(QPointF(3.5, pos + 2));
a.append(QPointF(3.5 + fm.ascent(), pos + 2));
a.append(QPointF(3.5 + fm.ascent() / 2.0, pos + fm.height() - 2));
p->drawPolygon(a);
} else {
QPolygonF a;
a.append(QPointF(3.5, pos + 2));
a.append(QPointF(3.5, pos + fm.height() - 2));
a.append(QPointF(3.5 + fm.ascent(), pos + fm.height() / 2));
p->drawPolygon(a);
}
// Inhalt
if(!rollup->isHidden() && (!last)) {
// Rollup-Abschlusslinie
p->setPen(frame);
p->drawLine(QPointF(1.5, pos + fm.height() + rollup->height() + 6.5),
QPointF(width() - 1.5, pos + fm.height() + rollup->height() + 6.5));
height += rollup->height() + 4;
}
return height;
}
void RollupWidget::resizeEvent(QResizeEvent* size)
{
arrangeRollups();
QWidget::resizeEvent(size);
}
void RollupWidget::mousePressEvent(QMouseEvent* event)
{
QFontMetrics fm(font());
// menu box left
if(QRectF(3.5, 3.5, fm.ascent(), fm.ascent()).contains(event->pos())) {
emit customContextMenuRequested(event->pos());
return;
}
// close button right
if(QRectF(width() - 3.5 - fm.ascent(), 3.5, fm.ascent(), fm.ascent()).contains(event->pos())) {
close();
return;
}
// check if we need to change a rollup widget
int pos = fm.height() + 4;
for(int i = 0; i < children().count(); ++i) {
QWidget* r = qobject_cast<QWidget*>(children()[i]);
if(r != NULL) {
if((event->y() >= pos) && (event->y() < (pos + fm.height() + 3))) {
if(r->isHidden()) {
r->show();
//emit widgetRolled(r, true);
} else {
r->hide();
//emit widgetRolled(r, false);
}
arrangeRollups();
repaint();
return;
} else {
pos += fm.height() + 2;
if(!r->isHidden())
pos += r->height() + 5;
}
}
}
}
void RollupWidget::mouseDoubleClickEvent(QMouseEvent* event)
{
QFontMetrics fm(font());
// menu box left
if(QRectF(3.5, 3.5, fm.ascent(), fm.ascent()).contains(event->pos())) {
emit menuDoubleClickEvent();
return;
}
}
bool RollupWidget::event(QEvent* event)
{
if(event->type() == QEvent::ChildAdded) {
((QChildEvent*)event)->child()->installEventFilter(this);
arrangeRollups();
} else if(event->type() == QEvent::ChildRemoved) {
((QChildEvent*)event)->child()->removeEventFilter(this);
arrangeRollups();
}
return QWidget::event(event);
}
bool RollupWidget::eventFilter(QObject* object, QEvent* event)
{
if(event->type() == QEvent::Show) {
if(children().contains(object)) {
arrangeRollups();
emit widgetRolled(qobject_cast<QWidget*>(object), true);
}
} else if(event->type() == QEvent::Hide) {
if(children().contains(object)) {
arrangeRollups();
emit widgetRolled(qobject_cast<QWidget*>(object), false);
}
} else if(event->type() == QEvent::WindowTitleChange) {
if(children().contains(object))
repaint();
}
return QWidget::eventFilter(object, event);
}
+129
View File
@@ -0,0 +1,129 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QPainter>
#include "gui/scale.h"
Scale::Scale(QWidget* parent) :
QWidget(parent)
{
}
void Scale::setOrientation(Qt::Orientation orientation)
{
m_orientation = orientation;
m_scaleEngine.setOrientation(orientation);
m_scaleEngine.setFont(font());
QFontMetrics fm(font());
switch(m_orientation) {
case Qt::Horizontal:
m_scaleEngine.setSize(width());
setMinimumWidth(0);
setMaximumWidth(QWIDGETSIZE_MAX);
setMinimumHeight(3 + fontMetrics().ascent());
setMaximumHeight(3 + fontMetrics().ascent());
break;
case Qt::Vertical:
m_scaleEngine.setSize(height());
setMinimumWidth(30);
setMaximumWidth(30);
setMinimumHeight(0);
setMaximumHeight(QWIDGETSIZE_MAX);
break;
}
}
void Scale::setRange(Unit::Physical physicalUnit, float rangeMin, float rangeMax)
{
m_scaleEngine.setRange(physicalUnit, rangeMin, rangeMax);
update();
}
void Scale::paintEvent(QPaintEvent*)
{
QPainter painter(this);
const ScaleEngine::TickList& tickList = m_scaleEngine.getTickList();
QFontMetricsF fontMetrics(font());
const ScaleEngine::Tick* tick;
int i;
float bottomLine;
switch(m_orientation) {
case Qt::Horizontal: {
painter.setPen(Qt::black);
// Zwischenlinien für x-Achse zeichnen
for(i = 0; i < tickList.count(); i++) {
tick = &tickList[i];
if(!tick->major)
painter.drawLine(QLineF(tick->pos, 0, tick->pos, 1));
}
// Skala am Rand zeichnen
painter.drawLine(QLineF(0, 0, width() - 1, 0));
// Hauptlinien und Beschriftung für x-Achse zeichnen
for(i = 0; i < tickList.count(); i++) {
tick = &tickList[i];
if(tick->major) {
painter.drawLine(QLineF(tick->pos - 1, 0, tick->pos - 1, 3));
if(tick->textSize > 0) {
painter.drawText(QPointF(tick->textPos, 3 + fontMetrics.ascent()), tick->text);
}
}
}
break;
}
case Qt::Vertical: {
bottomLine = height() - 1;
painter.setPen(Qt::black);
// Zwischenlinien für y-Achse zeichnen
for(i = 0; i < tickList.count(); i++) {
tick = &tickList[i];
if(!tick->major)
painter.drawLine(QLineF(width() - 2, bottomLine - tick->pos, width() - 1, bottomLine - tick->pos));
}
// Skala am Rand zeichnen
painter.drawLine(QLineF(width() - 1, 0, width() - 1, height() - 1));
// Hauptlinien und Beschriftung für y-Achse zeichnen
for(i = 0; i < tickList.count(); i++) {
tick = &tickList[i];
if(tick->major) {
painter.drawLine(QLineF(width() - 4, bottomLine - tick->pos, width() - 1, bottomLine - tick->pos));
if(tick->textSize > 0)
painter.drawText(QPointF(width() - 4 - tick->textSize, bottomLine - tick->textPos), tick->text);
}
}
}
}
}
void Scale::resizeEvent(QResizeEvent*)
{
switch(m_orientation) {
case Qt::Horizontal:
m_scaleEngine.setSize(width());
break;
case Qt::Vertical:
m_scaleEngine.setSize(height());
break;
}
}
+569
View File
@@ -0,0 +1,569 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <math.h>
#include <QFontMetrics>
#include <QDataStream>
#include "gui/scaleengine.h"
/*
static double trunc(double d)
{
return (d > 0) ? floor(d) : ceil(d);
}
*/
QString ScaleEngine::formatTick(double value, int decimalPlaces, bool fancyTime)
{
if((m_physicalUnit != Unit::Time) || (!fancyTime) || 1) {
return QString("%1").arg(value, 0, 'f', decimalPlaces);
} else {
QString str;
double orig = fabs(value);
double tmp;
if(orig >= 86400.0) {
tmp = floor(value / 86400.0);
str = QString("%1.").arg(tmp, 0, 'f', 0);
value -= tmp * 86400.0;
if(value < 0.0)
value *= -1.0;
}
if(orig >= 3600.0) {
tmp = floor(value / 3600.0);
str += QString("%1:").arg(tmp, 2, 'f', 0, QChar('0'));
value -= tmp * 3600.0;
if(value < 0.0)
value *= -1.0;
}
if(orig >= 60.0) {
tmp = floor(value / 60.0);
str += QString("%1:").arg(tmp, 2, 'f', 0, QChar('0'));
value -= tmp * 60.0;
if(value < 0.0)
value *= -1.0;
}
tmp = value;
str += QString("%1").arg(tmp, 2, 'f', decimalPlaces, QChar('0'));
return str;
}
}
void ScaleEngine::calcCharSize()
{
QFontMetricsF fontMetrics(m_font);
if(m_orientation == Qt::Vertical) {
m_charSize = fontMetrics.height();
} else {
QString str("012345679.,-");
int i;
float size;
float max = 0.0f;
for(i = 0; i < str.length(); i++) {
size = fontMetrics.width(QString(str[i]));
if(size > max)
max = size;
}
m_charSize = max;
}
}
void ScaleEngine::calcScaleFactor()
{
double median;
median = ((m_rangeMax - m_rangeMin) / 2.0) + m_rangeMin;
m_scale = 1.0;
switch(m_physicalUnit) {
case Unit::None:
m_unitStr.clear();
break;
case Unit::Frequency:
if(median < 1000.0) {
m_unitStr = QObject::tr("Hz");
} else if(median < 1000000.0) {
m_unitStr = QObject::tr("kHz");
m_scale = 1000.0;
} else if(median < 1000000000.0) {
m_unitStr = QObject::tr("MHz");
m_scale = 1000000.0;
} else if(median < 1000000000000.0){
m_unitStr = QObject::tr("GHz");
m_scale = 1000000000.0;
} else {
m_unitStr = QObject::tr("THz");
m_scale = 1000000000000.0;
}
break;
case Unit::Information:
if(median < 1024.0) {
m_unitStr = QObject::tr("Bytes");
} else if(median < 1048576.0) {
m_unitStr = QObject::tr("KiBytes");
m_scale = 1024.0;
} else if(median < 1073741824.0) {
m_unitStr = QObject::tr("MiBytes");
m_scale = 1048576.0;
} else if(median < 1099511627776.0) {
m_unitStr = QObject::tr("GiBytes");
m_scale = 1073741824.0;
} else if(median < 1125899906842624.0) {
m_unitStr = QObject::tr("TiBytes");
m_scale = 1099511627776.0;
} else {
m_unitStr = QObject::tr("PiBytes");
m_scale = 1125899906842624.0;
}
break;
case Unit::Percent:
m_unitStr = QString("%");
break;
case Unit::Decibel:
m_unitStr = QString("dB");
break;
case Unit::DecibelMilliWatt:
m_unitStr = QString("dBm");
break;
case Unit::DecibelMicroVolt:
m_unitStr = QString("dBµV");
break;
case Unit::AngleDegrees:
m_unitStr = QString("°");
case Unit::Time:
if(median < 0.001) {
m_unitStr = QString("µs");
m_scale = 0.000001;
} else if(median < 1.0) {
m_unitStr = QString("ms");
m_scale = 0.001;
} else {
m_unitStr = QString("s");
}
break;
}
}
double ScaleEngine::calcMajorTickUnits(double distance, int* retDecimalPlaces)
{
double sign;
double log10x;
double exponent;
double base;
int decimalPlaces;
if(distance == 0.0)
return 0.0;
sign = (distance > 0.0) ? 1.0 : -1.0;
log10x = log10(fabs(distance));
exponent = floor(log10x);
base = pow(10.0, log10x - exponent);
decimalPlaces = (int)(-exponent);
/*
if((m_physicalUnit == Unit::Time) && (distance >= 1.0)) {
if(retDecimalPlaces != NULL)
*retDecimalPlaces = 0;
if(distance < 1.0)
return 1.0;
else if(distance < 5.0)
return 5.0;
else if(distance < 10.0)
return 10.0;
else if(distance < 15.0)
return 15.0;
else if(distance < 30.0)
return 30.0;
else if(distance < 60.0)
return 60.0;
else if(distance < 5.0 * 60.0)
return 5.0 * 60.0;
else if(distance < 10.0 * 60.0)
return 10.0 * 60.0;
else if(distance < 15.0 * 60.0)
return 15.0 * 60.0;
else if(distance < 30.0 * 60.0)
return 30.0 * 60.0;
else if(distance < 3600.0)
return 3600.0;
else if(distance < 2.0 * 3600.0)
return 2.0 * 3600.0;
else if(distance < 3.0 * 3600.0)
return 3.0 * 3600.0;
else if(distance < 6.0 * 3600.0)
return 6.0 * 3600.0;
else if(distance < 12.0 * 3600.0)
return 12.0 * 3600.0;
else if(distance < 86000.0)
return 86000.0;
else if(distance < 2.0 * 86000.0)
return 2.0 * 86000.0;
else if(distance < 7.0 * 86000.0)
return 7.0 * 86000.0;
else if(distance < 10.0 * 86000.0)
return 10.0 * 86000.0;
else if(distance < 30.0 * 86000.0)
return 30.0 * 86000.0;
else return 90.0 * 86000.0;
} else {*/
if(base <= 1.0) {
base = 1.0;
} else if(base <= 2.0) {
base = 2.0;
} else if(base <= 2.5) {
base = 2.5;
if(decimalPlaces >= 0)
decimalPlaces++;
} else if(base <= 5.0) {
base = 5.0;
} else {
base = 10.0;
}/*
}*/
if(retDecimalPlaces != NULL) {
if(decimalPlaces < 0)
decimalPlaces = 0;
*retDecimalPlaces = decimalPlaces;
}
return sign * base * pow(10.0, exponent);
}
int ScaleEngine::calcTickTextSize()
{
int tmp;
int tickLen;
int decimalPlaces;
tickLen = 1;
tmp = formatTick(m_rangeMin / m_scale, 0).length();
if(tmp > tickLen)
tickLen = tmp;
tmp = formatTick(m_rangeMax / m_scale, 0).length();
if(tmp > tickLen)
tickLen = tmp;
calcMajorTickUnits((m_rangeMax - m_rangeMin) / m_scale, &decimalPlaces);
return tickLen + decimalPlaces + 1;
}
void ScaleEngine::forceTwoTicks()
{
Tick tick;
QFontMetricsF fontMetrics(m_font);
m_tickList.clear();
tick.major = true;
tick.pos = getPosFromValue(m_rangeMin);
tick.text = formatTick(m_rangeMin / m_scale, m_decimalPlaces);
tick.textSize = fontMetrics.boundingRect(tick.text).width();
if(m_orientation == Qt::Vertical)
tick.textPos = tick.pos - fontMetrics.ascent() / 2;
else tick.textPos = tick.pos - fontMetrics.boundingRect(tick.text).width() / 2;
m_tickList.append(tick);
tick.pos = getPosFromValue(m_rangeMax);
tick.text = formatTick(m_rangeMax / m_scale, m_decimalPlaces);
tick.textSize = fontMetrics.boundingRect(tick.text).width();
if(m_orientation == Qt::Vertical)
tick.textPos = tick.pos - fontMetrics.ascent() / 2;
else tick.textPos = tick.pos - fontMetrics.boundingRect(tick.text).width() / 2;
m_tickList.append(tick);
}
void ScaleEngine::reCalc()
{
float majorTickSize;
double rangeMinScaled;
double rangeMaxScaled;
int maxNumMajorTicks;
int numMajorTicks;
int step;
int skip;
double value;
double value2;
int i;
int j;
Tick tick;
float pos;
QString str;
QFontMetricsF fontMetrics(m_font);
float endPos;
float lastEndPos;
bool done;
if(!m_recalc)
return;
m_recalc = false;
m_tickList.clear();
calcScaleFactor();
rangeMinScaled = m_rangeMin / m_scale;
rangeMaxScaled = m_rangeMax / m_scale;
if(m_orientation == Qt::Vertical) {
maxNumMajorTicks = (int)(m_size / (fontMetrics.lineSpacing() * 1.3f));
} else {
majorTickSize = (calcTickTextSize() + 2) * m_charSize;
if(majorTickSize != 0.0)
maxNumMajorTicks = (int)(m_size / majorTickSize);
else maxNumMajorTicks = 20;
}
m_majorTickValueDistance = calcMajorTickUnits((rangeMaxScaled - rangeMinScaled) / maxNumMajorTicks, &m_decimalPlaces);
numMajorTicks = (int)((rangeMaxScaled - rangeMinScaled) / m_majorTickValueDistance);
if(numMajorTicks == 0) {
forceTwoTicks();
return;
}
if(maxNumMajorTicks > 0)
m_numMinorTicks = (int)(m_size / (maxNumMajorTicks * fontMetrics.height()));
else m_numMinorTicks = 0;
if(m_numMinorTicks < 1)
m_numMinorTicks = 0;
else if(m_numMinorTicks < 2)
m_numMinorTicks = 1;
else if(m_numMinorTicks < 5)
m_numMinorTicks = 2;
else if(m_numMinorTicks < 10)
m_numMinorTicks = 5;
else m_numMinorTicks = 10;
m_firstMajorTickValue = floor(rangeMinScaled / m_majorTickValueDistance) * m_majorTickValueDistance;
skip = 0;
if(rangeMinScaled == rangeMaxScaled)
return;
while(true) {
m_tickList.clear();
step = 0;
lastEndPos = -100000000;
done = true;
for(i = 0; true; i++) {
value = majorTickValue(i);
for(j = 1; j < m_numMinorTicks; j++) {
value2 = value + minorTickValue(j);
if(value2 < rangeMinScaled)
continue;
if(value2 > rangeMaxScaled)
break;
pos = getPosFromValue((value + minorTickValue(j)) * m_scale);
if((pos >= 0) && (pos < m_size)) {
tick.pos = pos;
tick.major = false;
tick.textPos = -1;
tick.textSize = -1;
tick.text.clear();
}
m_tickList.append(tick);
}
pos = getPosFromValue(value * m_scale);
if(pos < 0.0)
continue;
if(pos >= m_size)
break;
tick.pos = pos;
tick.major = true;
tick.textPos = -1;
tick.textSize = -1;
tick.text.clear();
if(step % (skip + 1) != 0) {
m_tickList.append(tick);
step++;
continue;
}
step++;
str = formatTick(value, m_decimalPlaces);
tick.text = str;
tick.textSize = fontMetrics.boundingRect(tick.text).width();
if(m_orientation == Qt::Vertical) {
tick.textPos = pos - fontMetrics.ascent() / 2;
endPos = tick.textPos + fontMetrics.ascent();
} else {
tick.textPos = pos - fontMetrics.boundingRect(tick.text).width() / 2;
endPos = tick.textPos + tick.textSize;
}
if(lastEndPos >= tick.textPos) {
done = false;
break;
} else {
lastEndPos = endPos;
}
m_tickList.append(tick);
}
if(done)
break;
skip++;
}
// make sure we have at least two major ticks with numbers
numMajorTicks = 0;
for(i = 0; i < m_tickList.count(); i++) {
tick = m_tickList.at(i);
if(tick.major)
numMajorTicks++;
}
if(numMajorTicks < 2)
forceTwoTicks();
}
double ScaleEngine::majorTickValue(int tick)
{
return m_firstMajorTickValue + (tick * m_majorTickValueDistance);
}
double ScaleEngine::minorTickValue(int tick)
{
if(m_numMinorTicks < 1)
return 0.0;
return (m_majorTickValueDistance * tick) / m_numMinorTicks;
}
ScaleEngine::ScaleEngine() :
m_orientation(Qt::Horizontal),
m_physicalUnit(Unit::None),
m_rangeMin(-1.0),
m_rangeMax(1.0),
m_recalc(true)
{
}
void ScaleEngine::setOrientation(Qt::Orientation orientation)
{
m_orientation = orientation;
m_recalc = true;
}
void ScaleEngine::setFont(const QFont& font)
{
m_font = font;
m_recalc = true;
calcCharSize();
}
void ScaleEngine::setSize(float size)
{
if(size > 0.0f) {
m_size = size;
} else {
m_size = 1.0f;
}
m_recalc = true;
}
void ScaleEngine::setRange(Unit::Physical physicalUnit, float rangeMin, float rangeMax)
{
double tmpRangeMin;
double tmpRangeMax;
/*
if(rangeMin < rangeMax) {
tmpRangeMin = rangeMin;
tmpRangeMax = rangeMax;
} else if(rangeMin > rangeMax) {
tmpRangeMin = rangeMax;
tmpRangeMax = rangeMin;
} else {
tmpRangeMin = rangeMin * 0.99;
tmpRangeMax = rangeMin * 1.01 + 0.01;
}
*/
tmpRangeMin = rangeMin;
tmpRangeMax = rangeMax;
if((tmpRangeMin != m_rangeMin) || (tmpRangeMax != m_rangeMax) || (m_physicalUnit != physicalUnit)) {
m_physicalUnit = physicalUnit;
m_rangeMin = tmpRangeMin;
m_rangeMax = tmpRangeMax;
m_recalc = true;
}
}
float ScaleEngine::getPosFromValue(double value)
{
return ((value - m_rangeMin) / (m_rangeMax - m_rangeMin)) * (m_size - 1.0);
}
float ScaleEngine::getValueFromPos(double pos)
{
return ((pos * (m_rangeMax - m_rangeMin)) / (m_size - 1.0)) + m_rangeMin;
}
const ScaleEngine::TickList& ScaleEngine::getTickList()
{
reCalc();
return m_tickList;
}
QString ScaleEngine::getRangeMinStr()
{
if(m_unitStr.length() > 0)
return QString("%1 %2").arg(formatTick(m_rangeMin / m_scale, m_decimalPlaces, false)).arg(m_unitStr);
else return QString("%1").arg(formatTick(m_rangeMin / m_scale, m_decimalPlaces, false));
}
QString ScaleEngine::getRangeMaxStr()
{
if(m_unitStr.length() > 0)
return QString("%1 %2").arg(formatTick(m_rangeMax / m_scale, m_decimalPlaces, false)).arg(m_unitStr);
else return QString("%1").arg(formatTick(m_rangeMax / m_scale, m_decimalPlaces, false));
}
float ScaleEngine::getScaleWidth()
{
float max;
float len;
int i;
reCalc();
max = 0.0f;
for(i = 0; i < m_tickList.count(); i++) {
len = m_tickList[i].textSize;
if(len > max)
max = len;
}
return max;
}
+185
View File
@@ -0,0 +1,185 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include "gui/scopewindow.h"
#include "ui_scopewindow.h"
#include "util/simpleserializer.h"
ScopeWindow::ScopeWindow(DSPEngine* dspEngine, QWidget* parent) :
QWidget(parent),
ui(new Ui::ScopeWindow),
m_sampleRate(0),
m_timeBase(1)
{
ui->setupUi(this);
ui->scope->setDSPEngine(dspEngine);
}
ScopeWindow::~ScopeWindow()
{
delete ui;
}
void ScopeWindow::setSampleRate(int sampleRate)
{
m_sampleRate = sampleRate;
on_scope_traceSizeChanged(0);
}
void ScopeWindow::resetToDefaults()
{
m_displayData = GLScope::ModeIQ;
m_displayOrientation = Qt::Horizontal;
m_timeBase = 1;
m_timeOffset = 0;
m_amplification = 0;
applySettings();
}
QByteArray ScopeWindow::serialize() const
{
SimpleSerializer s(1);
s.writeS32(1, m_displayData);
s.writeS32(2, m_displayOrientation);
s.writeS32(3, m_timeBase);
s.writeS32(4, m_timeOffset);
s.writeS32(5, m_amplification);
return s.final();
}
bool ScopeWindow::deserialize(const QByteArray& data)
{
SimpleDeserializer d(data);
if(!d.isValid()) {
resetToDefaults();
return false;
}
if(d.getVersion() == 1) {
d.readS32(1, &m_displayData, GLScope::ModeIQ);
d.readS32(2, &m_displayOrientation, Qt::Horizontal);
d.readS32(3, &m_timeBase, 1);
d.readS32(4, &m_timeOffset, 0);
d.readS32(5, &m_amplification, 0);
if(m_timeBase < 0)
m_timeBase = 1;
applySettings();
return true;
} else {
resetToDefaults();
return false;
}
}
void ScopeWindow::on_amp_valueChanged(int value)
{
static qreal amps[11] = { 0.2, 0.1, 0.05, 0.02, 0.01, 0.005, 0.002, 0.001, 0.0005, 0.0002, 0.0001 };
ui->ampText->setText(tr("%1\n/div").arg(amps[value], 0, 'f', 4));
ui->scope->setAmp(0.2 / amps[value]);
m_amplification = value;
}
void ScopeWindow::on_scope_traceSizeChanged(int)
{
qreal t = (ui->scope->getTraceSize() * 0.1 / m_sampleRate) / (qreal)m_timeBase;
if(t < 0.000001)
ui->timeText->setText(tr("%1\nns/div").arg(t * 1000000000.0));
else if(t < 0.001)
ui->timeText->setText(tr("%1\nµs/div").arg(t * 1000000.0));
else if(t < 1.0)
ui->timeText->setText(tr("%1\nms/div").arg(t * 1000.0));
else ui->timeText->setText(tr("%1\ns/div").arg(t * 1.0));
}
void ScopeWindow::on_time_valueChanged(int value)
{
m_timeBase = value;
on_scope_traceSizeChanged(0);
ui->scope->setTimeBase(m_timeBase);
}
void ScopeWindow::on_timeOfs_valueChanged(int value)
{
m_timeOffset = value;
ui->scope->setTimeOfsProMill(value);
}
void ScopeWindow::on_displayMode_currentIndexChanged(int index)
{
m_displayData = index;
switch(index) {
case 0: // i+q
ui->scope->setMode(GLScope::ModeIQ);
break;
case 1: // mag(lin)+pha
ui->scope->setMode(GLScope::ModeMagLinPha);
break;
case 2: // mag(dB)+pha
ui->scope->setMode(GLScope::ModeMagdBPha);
break;
case 3: // derived1+derived2
ui->scope->setMode(GLScope::ModeDerived12);
break;
case 4: // clostationary
ui->scope->setMode(GLScope::ModeCyclostationary);
break;
default:
break;
}
}
void ScopeWindow::on_horizView_clicked()
{
m_displayOrientation = Qt::Horizontal;
if(ui->horizView->isChecked()) {
ui->vertView->setChecked(false);
ui->scope->setOrientation(Qt::Horizontal);
} else {
ui->horizView->setChecked(true);
}
}
void ScopeWindow::on_vertView_clicked()
{
m_displayOrientation = Qt::Vertical;
if(ui->vertView->isChecked()) {
ui->horizView->setChecked(false);
ui->scope->setOrientation(Qt::Vertical);
} else {
ui->vertView->setChecked(true);
ui->scope->setOrientation(Qt::Vertical);
}
}
void ScopeWindow::applySettings()
{
ui->displayMode->setCurrentIndex(m_displayData);
if(m_displayOrientation == Qt::Horizontal) {
ui->scope->setOrientation(Qt::Horizontal);
ui->horizView->setChecked(true);
ui->vertView->setChecked(false);
} else {
ui->scope->setOrientation(Qt::Vertical);
ui->horizView->setChecked(false);
ui->vertView->setChecked(true);
}
ui->time->setValue(m_timeBase);
ui->timeOfs->setValue(m_timeOffset);
ui->amp->setValue(m_amplification);
}
+320
View File
@@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScopeWindow</class>
<widget class="QWidget" name="ScopeWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>798</width>
<height>149</height>
</rect>
</property>
<property name="windowTitle">
<string>Oscilloscope</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<widget class="GLScope" name="scope" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>2</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Data</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="displayMode">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="sizeAdjustPolicy">
<enum>QComboBox::AdjustToContentsOnFirstShow</enum>
</property>
<item>
<property name="text">
<string>I+Q Level (linear)</string>
</property>
</item>
<item>
<property name="text">
<string>Magnitude (linear) + Phase</string>
</property>
</item>
<item>
<property name="text">
<string>Magnitude (dB) + Phase</string>
</property>
</item>
<item>
<property name="text">
<string>Derived 1st + 2nd order</string>
</property>
</item>
<item>
<property name="text">
<string>Cyclostationary</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QToolButton" name="horizView">
<property name="toolTip">
<string>Horizontal display arrangement</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/horizontal.png</normaloff>:/horizontal.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="vertView">
<property name="toolTip">
<string>Vertical display arrangement</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/res.qrc">
<normaloff>:/vertical.png</normaloff>:/vertical.png</iconset>
</property>
<property name="iconSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Time</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="time">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="pageStep">
<number>5</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>5</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="timeText">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0.1000
/div</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="timeOfs">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="pageStep">
<number>10</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::NoTicks</enum>
</property>
<property name="tickInterval">
<number>50</number>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Amp</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="amp">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>8</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="tickPosition">
<enum>QSlider::TicksBelow</enum>
</property>
<property name="tickInterval">
<number>1</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="ampText">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>0.2000
/div</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>GLScope</class>
<extends>QWidget</extends>
<header>gui/glscope.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/res.qrc"/>
</resources>
<connections/>
</ui>
+427
View File
@@ -0,0 +1,427 @@
///////////////////////////////////////////////////////////////////////////////////
// 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 <http://www.gnu.org/licenses/>. //
///////////////////////////////////////////////////////////////////////////////////
#include <QPainter>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QKeyEvent>
#include "gui/valuedial.h"
ValueDial::ValueDial(QWidget* parent) :
QWidget(parent),
m_animationState(0)
{
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);
m_background.setColorAt(0.0, QColor(0x40, 0x40, 0x40));
m_background.setColorAt(0.1, QColor(0xc0, 0xc0, 0xc0));
m_background.setColorAt(0.2, QColor(0xf0, 0xf0, 0xf0));
m_background.setColorAt(0.5, QColor(0xff, 0xff, 0xff));
m_background.setColorAt(0.8, QColor(0xd0, 0xd0, 0xd0));
m_background.setColorAt(0.9, QColor(0xa0, 0xa0, 0xa0));
m_background.setColorAt(1.0, QColor(0x40, 0x40, 0x40));
m_value = 0;
m_valueMin = 0;
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 ValueDial::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_digitWidth + 2);
setFixedHeight(m_digitHeight * 2 + 2);
}
void ValueDial::setValue(quint64 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 ValueDial::setValueRange(uint numDigits, quint64 min, quint64 max)
{
m_numDigits = numDigits;
m_numDecimalPoints = m_numDigits / 3;
m_valueMin = min;
m_valueMax = max;
if(m_value < min)
setValue(min);
else if(m_value > max)
setValue(max);
setFixedWidth((m_numDigits + m_numDecimalPoints) * m_digitWidth + 2);
}
quint64 ValueDial::findExponent(int digit)
{
quint64 e = 1;
int d = (m_numDigits + m_numDecimalPoints) - digit;
d = d - (d / 4) - 1;
for(int i = 0; i < d; i++)
e *= 10;
return e;
}
QChar ValueDial::digitNeigh(QChar c, bool dir)
{
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 ValueDial::formatText(quint64 value)
{
QString str = QString("%1").arg(value, m_numDigits, 10, QChar('0'));
for(int i = 0; i < m_numDecimalPoints; i++)
str.insert(m_numDigits - 3 - 3 * i, ".");
return str;
}
void ValueDial::paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.setPen(Qt::black);
painter.setBrush(m_background);
painter.drawRect(0, 0, width() - 1, height() - 1);
painter.setPen(QColor(0x20, 0x20, 0x20));
painter.setBrush(Qt::NoBrush);
for(int i = 1; i < m_numDigits + m_numDecimalPoints; i++) {
painter.setPen(QColor(0x20, 0x20, 0x20));
painter.drawLine(1 + i * m_digitWidth, 1, 1 + i * m_digitWidth, height() - 1);
painter.setPen(QColor(0x00, 0x00, 0x00, 0x20));
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(QColor(0x00, 0x00, 0x00, 0x20));
painter.drawLine(1, 1, 1, height() - 1);
painter.drawLine(width() - 2, 1, width() - 2, height() - 1);
if(m_hightlightedDigit >= 0) {
painter.setPen(Qt::NoPen);
painter.setBrush(QColor(0xff, 0x00, 0x00, 0x20));
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(QColor(0x10, 0x10, 0x10));
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(QColor(0x00, 0x00, 0x00));
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(QColor(0x10, 0x10, 0x10));
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(QColor(0x10, 0x10, 0x10));
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(QColor(0x00, 0x00, 0x00));
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(QColor(0x10, 0x10, 0x10));
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(QColor(0x00, 0x00, 0x00));
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 ValueDial::mousePressEvent(QMouseEvent* event)
{
int i;
i = (event->x() - 1) / m_digitWidth;
if(m_text[i] == QChar('.')) {
i++;
if(i > m_numDigits + m_numDecimalPoints)
return;
}
m_cursor = i;
m_cursorState = true;
m_blinkTimer.start(400);
update();
}
void ValueDial::mouseMoveEvent(QMouseEvent* event)
{
int i;
i = (event->x() - 1) / m_digitWidth;
if(m_text[i] == QChar('.'))
i = -1;
if(i != m_hightlightedDigit) {
m_hightlightedDigit = i;
update();
}
}
void ValueDial::wheelEvent(QWheelEvent* event)
{
int i;
i = (event->x() - 1) / m_digitWidth;
if(m_text[i] != QChar('.'))
m_hightlightedDigit = i;
else
return;
if(m_cursor >= 0) {
m_cursor = -1;
m_blinkTimer.stop();
update();
}
quint64 e = findExponent(m_hightlightedDigit);
if(m_animationState == 0) {
if(event->delta() < 0) {
if(event->modifiers() & Qt::ShiftModifier)
e *= 5;
if(m_value < e)
m_valueNew = m_valueMin;
else m_valueNew = m_value - e;
} else {
if(event->modifiers() & Qt::ShiftModifier)
e *= 5;
if(m_valueMax - m_value < e)
m_valueNew = m_valueMax;
else m_valueNew = m_value + e;
}
setValue(m_valueNew);
emit changed(m_valueNew);
}
}
void ValueDial::leaveEvent(QEvent*)
{
if(m_hightlightedDigit != -1) {
m_hightlightedDigit = -1;
update();
}
}
void ValueDial::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)
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 < 0)
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_cursor--;
m_cursorState = true;
update();
return;
}
} else if(value->key() == Qt::Key_Up) {
quint64 e = findExponent(m_cursor);
if(value->modifiers() & Qt::ShiftModifier)
e *= 5;
if(m_animationState != 0)
m_value = m_valueNew;
if(m_valueMax - m_value < e)
m_valueNew = m_valueMax;
else m_valueNew = m_value + e;
setValue(m_valueNew);
emit changed(m_valueNew);
} else if(value->key() == Qt::Key_Down) {
quint64 e = findExponent(m_cursor);
if(value->modifiers() & Qt::ShiftModifier)
e *= 5;
if(m_animationState != 0)
m_value = m_valueNew;
if(m_value < e)
m_valueNew = m_valueMin;
else m_valueNew = 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_cursor++;
if(m_cursor >= m_numDigits + m_numDecimalPoints) {
m_cursor = -1;
m_blinkTimer.stop();
} else {
m_cursorState = true;
}
update();
}
}
void ValueDial::focusInEvent(QFocusEvent*)
{
if(m_cursor == -1) {
m_cursor = 0;
m_cursorState = true;
m_blinkTimer.start(400);
update();
}
}
void ValueDial::focusOutEvent(QFocusEvent*)
{
m_cursor = -1;
m_blinkTimer.stop();
update();
}
void ValueDial::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 ValueDial::blink()
{
if(m_cursor >= 0) {
m_cursorState = !m_cursorState;
update();
}
}