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:
@@ -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;
|
||||
}
|
||||
@@ -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><p>Copyright (C) 2013 maintech GmbH, Otto-Hahn-Str. 15, 97204 Höchberg, Germany<br>
|
||||
Written by Christian Daniel.</p>
|
||||
<p>Many thanks to the osmocom developer team - especially horizon, Hoernchen &amp; tnt.</p>
|
||||
<p>SDRangelove itself is licensed as "GPL2+" with the added exception, that plugins using only header files from the "include"-subdirectory and not from the "include-gpl"-subdirectory do not count as derived works.</p>
|
||||
<p>The following rules apply to the SDRangelove main application and libsdrbase:<br>
|
||||
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 <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.</p>
|
||||
<p>For the license of installed plugins, look into the plugin list.</p></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>
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>&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>&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();
|
||||
}
|
||||
@@ -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 & 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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user