Changeset - 68f79a7c6762
[Not reviewed]
stream
0 22 0
Hasan Yavuz ÖZDERYA - 8 years ago 2018-05-15 22:18:39
hy@ozderya.net
integrated almost all code to to use new Stream class, plotting doesn't work yet

building works, needs major cleanup
22 files changed with 206 insertions and 167 deletions:
0 comments (0 inline, 0 general)
CMakeLists.txt
Show inline comments
 
#
 
# Copyright © 2017 Hasan Yavuz Özderya
 
# Copyright © 2018 Hasan Yavuz Özderya
 
#
 
# This file is part of serialplot.
 
#
 
# serialplot is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# serialplot is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
#
 

	
 
cmake_minimum_required(VERSION 3.2.2)
 

	
 
project(serialplot)
 

	
 
set(PROGRAM_NAME ${CMAKE_PROJECT_NAME} CACHE STRING "Output program name")
 
set(PROGRAM_DISPLAY_NAME "SerialPlot" CACHE STRING "Display name (menus etc) of the program")
 

	
 
@@ -82,67 +82,70 @@ qt5_wrap_ui(UI_FILES
 
  src/recordpanel.ui
 
  src/numberformatbox.ui
 
  src/endiannessbox.ui
 
  src/binarystreamreadersettings.ui
 
  src/asciireadersettings.ui
 
  src/framedreadersettings.ui
 
  src/updatecheckdialog.ui
 
  )
 

	
 
if (WIN32)
 
  qt5_add_resources(RES_FILES misc/icons.qrc misc/winicons.qrc)
 
else (WIN32)
 
  qt5_add_resources(RES_FILES misc/icons.qrc)
 
endif (WIN32)
 

	
 
add_executable(${PROGRAM_NAME} WIN32
 
  src/main.cpp
 
  src/mainwindow.cpp
 
  src/portcontrol.cpp
 
  src/plot.cpp
 
  src/zoomer.cpp
 
  src/scrollzoomer.cpp
 
  src/scrollbar.cpp
 
  src/hidabletabwidget.cpp
 
  src/framebuffer.cpp
 
  src/scalepicker.cpp
 
  src/scalezoomer.cpp
 
  src/portlist.cpp
 
  src/snapshot.cpp
 
  src/snapshotview.cpp
 
  src/snapshotmanager.cpp
 
  src/plotsnapshotoverlay.cpp
 
  src/commandpanel.cpp
 
  src/commandwidget.cpp
 
  src/commandedit.cpp
 
  src/dataformatpanel.cpp
 
  src/plotcontrolpanel.cpp
 
  src/recordpanel.cpp
 
  src/datarecorder.cpp
 
  src/tooltipfilter.cpp
 
  src/sneakylineedit.cpp
 
  src/channelmanager.cpp
 
  src/stream.cpp
 
  src/streamchannel.cpp
 
  src/channelinfomodel.cpp
 
  src/ringbuffer.cpp
 
  src/ringbuffer.cpp
 
  src/indexbuffer.cpp
 
  src/framebufferseries.cpp
 
  src/numberformatbox.cpp
 
  src/endiannessbox.cpp
 
  src/abstractreader.cpp
 
  src/binarystreamreader.cpp
 
  src/binarystreamreadersettings.cpp
 
  src/asciireader.cpp
 
  src/asciireadersettings.cpp
 
  src/demoreader.cpp
 
  src/framedreader.cpp
 
  src/framedreadersettings.cpp
 
  src/plotmanager.cpp
 
  src/plotmenu.cpp
 
  src/barplot.cpp
 
  src/barchart.cpp
 
  src/barscaledraw.cpp
 
  src/numberformat.cpp
 
  src/updatechecker.cpp
 
  src/versionnumber.cpp
 
  src/updatecheckdialog.cpp
 
  src/samplepack.cpp
 
  src/source.cpp
 
  src/sink.cpp
 
  misc/windows_icon.rc
src/barchart.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QPalette>
 
#include <qwt_scale_map.h>
 

	
 
#include "barchart.h"
 

	
 
BarChart::BarChart(ChannelManager* channelMan)
 
BarChart::BarChart(const Stream* stream)
 
{
 
    _channelMan = channelMan;
 
    _stream = stream;
 
    setSpacing(0);
 
}
 

	
 
void BarChart::resample()
 
{
 
    setSamples(chartData());
 
}
 

	
 
QVector<double> BarChart::chartData() const
 
{
 
    unsigned numChannels = _channelMan->numOfChannels();
 
    unsigned numOfSamples = _channelMan->numOfSamples();
 
    unsigned numChannels = _stream->numChannels();
 
    unsigned numSamples = _stream->numSamples();
 
    QVector<double> data(numChannels);
 
    for (unsigned i = 0; i < numChannels; i++)
 
    {
 
        data[i] = _channelMan->channelBuffer(i)->sample(numOfSamples-1);
 
        data[i] = _stream->channel(i)->yData()->sample(numSamples-1);
 
    }
 
    return data;
 
}
 

	
 
QwtColumnSymbol* BarChart::specialSymbol(int sampleIndex, const QPointF& sample) const
 
{
 
    unsigned numChannels = _channelMan->numOfChannels();
 
    unsigned numChannels = _stream->numChannels();
 
    if (sampleIndex < 0 || sampleIndex > (int) numChannels)
 
    {
 
        return NULL;
 
    }
 

	
 
    auto info = _channelMan->infoModel();
 
    auto color = info->color(sampleIndex);
 
    auto color = _stream->channel(sampleIndex)->color();
 

	
 
    QwtColumnSymbol* symbol = new QwtColumnSymbol(QwtColumnSymbol::Box);
 
    symbol->setLineWidth(1);
 
    symbol->setFrameStyle(QwtColumnSymbol::Plain);
 
    symbol->setPalette(QPalette(color));
 

	
 
    return symbol;
 
}
 

	
 
void BarChart::drawSample(
 
        QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
        const QRectF &canvasRect, const QwtInterval &boundingInterval,
 
        int index, const QPointF &sample ) const
 
{
 
    QwtPlotBarChart::drawSample(painter, xMap, yMap, canvasRect, boundingInterval, index, sample);
 

	
 
    // calculate bar size
 
    const double barWidth = sampleWidth(xMap, canvasRect.width(),
 
                                        boundingInterval.width(), sample.y());
 
    const double x = xMap.transform( sample.x() );
 
    const double x1 = x - 0.5 * barWidth;
 
    // const double x2 = x + 0.5 * barWidth;
 

	
 
    const double y1 = yMap.transform(baseline());
src/barchart.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef BARCHART_H
 
#define BARCHART_H
 

	
 
#include <qwt_plot_barchart.h>
 
#include <qwt_column_symbol.h>
 
#include "channelmanager.h"
 
#include "stream.h"
 

	
 
class BarChart : public QwtPlotBarChart
 
{
 
public:
 
    explicit BarChart(ChannelManager* channelMan);
 
    explicit BarChart(const Stream* stream);
 

	
 
    void resample();
 
    QwtColumnSymbol* specialSymbol(int sampleIndex, const QPointF&) const;
 

	
 
    void drawSample(
 
        QPainter *painter, const QwtScaleMap &xMap, const QwtScaleMap &yMap,
 
        const QRectF &canvasRect, const QwtInterval &boundingInterval,
 
        int index, const QPointF &sample ) const;
 

	
 
private:
 
    ChannelManager* _channelMan;
 
    const Stream* _stream;
 

	
 
    QVector<double> chartData() const;
 
};
 

	
 

	
 
#endif // BARCHART_H
src/barplot.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "barplot.h"
 
#include "barscaledraw.h"
 
#include "utils.h"
 

	
 
BarPlot::BarPlot(ChannelManager* channelMan, PlotMenu* menu, QWidget* parent) :
 
    QwtPlot(parent), _menu(menu), barChart(channelMan)
 
BarPlot::BarPlot(Stream* stream, PlotMenu* menu, QWidget* parent) :
 
    QwtPlot(parent), _menu(menu), barChart(stream)
 
{
 
    _channelMan = channelMan;
 
    _stream = stream;
 
    barChart.attach(this);
 
    setAxisMaxMinor(QwtPlot::xBottom, 0);
 
    setAxisScaleDraw(QwtPlot::xBottom, new BarScaleDraw(channelMan));
 
    setAxisScaleDraw(QwtPlot::xBottom, new BarScaleDraw(stream));
 

	
 
    update();
 
    connect(_channelMan, &ChannelManager::dataAdded, this, &BarPlot::update);
 
    connect(_channelMan, &ChannelManager::numOfChannelsChanged, this, &BarPlot::update);
 
    connect(_stream, &Stream::dataAdded, this, &BarPlot::update);
 
    connect(_stream, &Stream::numChannelsChanged, this, &BarPlot::update);
 

	
 
    // connect to menu
 
    connect(&menu->darkBackgroundAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &BarPlot::darkBackground);
 
    darkBackground(menu->darkBackgroundAction.isChecked());
 
}
 

	
 
void BarPlot::update()
 
{
 
    // Note: -0.99 is used instead of -1 to handle the case of `numOfChannels==1`
 
    setAxisScale(QwtPlot::xBottom, 0, _channelMan->numOfChannels()-0.99, 1);
 
    setAxisScale(QwtPlot::xBottom, 0, _stream->numChannels()-0.99, 1);
 
    barChart.resample();
 
    replot();
 
}
 

	
 
void BarPlot::setYAxis(bool autoScaled, double yMin, double yMax)
 
{
 
    if (autoScaled)
 
    {
 
        setAxisAutoScale(QwtPlot::yLeft);
 
    }
 
    else
 
    {
 
        setAxisScale(QwtPlot::yLeft, yMin, yMax);
 
    }
 
}
 

	
 

	
 
void BarPlot::darkBackground(bool enabled)
 
{
 
    if (enabled)
 
    {
 
        setCanvasBackground(QBrush(Qt::black));
 
    }
 
    else
src/barplot.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef BARPLOT_H
 
#define BARPLOT_H
 

	
 
#include <qwt_plot.h>
 

	
 
#include "channelmanager.h"
 
#include "stream.h"
 
#include "plotmenu.h"
 
#include "barchart.h"
 

	
 
class BarPlot : public QwtPlot
 
{
 
    Q_OBJECT
 

	
 
public:
 
    explicit BarPlot(ChannelManager* channelMan,
 
    explicit BarPlot(Stream* stream,
 
                     PlotMenu* menu,
 
                     QWidget* parent = 0);
 

	
 
public slots:
 
    /// Set the Y axis
 
    void setYAxis(bool autoScaled, double yMin = 0, double yMax = 1);
 
    /// Enable/disable dark background
 
    void darkBackground(bool enabled);
 

	
 
private:
 
    ChannelManager* _channelMan;
 
    Stream* _stream;
 
    PlotMenu* _menu;
 
    BarChart barChart;
 

	
 
    QVector<double> chartData() const;
 

	
 
private slots:
 
    void update();
 
};
 

	
 
#endif // BARPLOT_H
src/barscaledraw.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "barscaledraw.h"
 

	
 
#include <QtDebug>
 

	
 
BarScaleDraw::BarScaleDraw(ChannelManager* channelMan)
 
BarScaleDraw::BarScaleDraw(const Stream* stream)
 
{
 
    _channelMan = channelMan;
 
    _stream = stream;
 
    enableComponent(Backbone, false);
 
    setLabelRotation(-90);
 
    setLabelAlignment(Qt::AlignLeft | Qt::AlignVCenter);
 

	
 
    QObject::connect(_channelMan, &ChannelManager::channelNameChanged,
 
    QObject::connect(_stream, &Stream::channelNameChanged,
 
            [this]()
 
            {
 
                invalidateCache();
 
            });
 
}
 

	
 
QwtText BarScaleDraw::label(double value) const
 
{
 
    int index = value;
 
    unsigned numChannels = _channelMan->numOfChannels();
 
    unsigned numChannels = _stream->numChannels();
 

	
 
    if (index >=0 && index < (int) numChannels)
 
    {
 
        return _channelMan->channelName(index);
 
        return _stream->channel(index)->name();
 
    }
 
    else
 
    {
 
        return QString("");
 
    }
 
}
src/barscaledraw.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef BARSCALEDRAW_H
 
#define BARSCALEDRAW_H
 

	
 
#include <QStringList>
 
#include <qwt_scale_draw.h>
 
#include <qwt_text.h>
 

	
 
#include "channelmanager.h"
 
#include "stream.h"
 

	
 
class BarScaleDraw : public QwtScaleDraw
 
{
 
public:
 
    explicit BarScaleDraw(ChannelManager* channelMan);
 
    explicit BarScaleDraw(const Stream* stream);
 
    QwtText label(double value) const;
 

	
 
private:
 
    ChannelManager* _channelMan;
 
    const Stream* _stream;
 
};
 

	
 
#endif // BARSCALEDRAW_H
src/dataformatpanel.cpp
Show inline comments
 
@@ -62,102 +62,101 @@ DataFormatPanel::DataFormatPanel(QSerial
 
            });
 

	
 
    connect(ui->rbFramed, &QRadioButton::toggled, [this](bool checked)
 
            {
 
                if (checked) selectReader(&framedReader);
 
            });
 

	
 
    // re-purpose numofchannels settings from actual reader settings to demo reader
 
    connect(this, &DataFormatPanel::numOfChannelsChanged,
 
            &demoReader, &DemoReader::setNumOfChannels);
 
}
 

	
 
DataFormatPanel::~DataFormatPanel()
 
{
 
    delete ui;
 
}
 

	
 
unsigned DataFormatPanel::numChannels() const
 
{
 
    return currentReader->numChannels();
 
}
 

	
 
Source* DataFormatPanel::activeSource()
 
{
 
    return &currentReader;
 
    return currentReader;
 
}
 

	
 
void DataFormatPanel::pause(bool enabled)
 
{
 
    paused = enabled;
 
    currentReader->pause(enabled);
 
    demoReader.pause(enabled);
 
}
 

	
 
void DataFormatPanel::enableDemo(bool enabled)
 
{
 
    if (enabled)
 
    {
 
        demoReader.enable();
 
        connect(&demoReader, &DemoReader::samplesPerSecondChanged,
 
                this, &DataFormatPanel::samplesPerSecondChanged);
 
        emit sourceChanged(&demoreader);
 
        emit sourceChanged(&demoReader);
 
    }
 
    else
 
    {
 
        demoReader.enable(false);
 
        disconnect(&demoReader, 0, this, 0);
 
        emit sourceChanged(currentReader);
 
    }
 
    demoEnabled = enabled;
 
}
 

	
 
void DataFormatPanel::selectReader(AbstractReader* reader)
 
{
 
    currentReader->enable(false);
 
    reader->enable();
 

	
 
    // re-connect signals
 
    disconnect(currentReader, 0, this, 0);
 
    connect(reader, SIGNAL(numOfChannelsChanged(unsigned)),
 
            this, SIGNAL(numOfChannelsChanged(unsigned)));
 
    connect(reader, SIGNAL(samplesPerSecondChanged(unsigned)),
 
            this, SIGNAL(samplesPerSecondChanged(unsigned)));
 

	
 
    // switch the settings widget
 
    ui->horizontalLayout->removeWidget(currentReader->settingsWidget());
 
    currentReader->settingsWidget()->hide();
 
    ui->horizontalLayout->addWidget(reader->settingsWidget(), 1);
 
    reader->settingsWidget()->show();
 

	
 
    // notify if number of channels is different
 
    if (currentReader->numOfChannels() != reader->numOfChannels())
 
    if (currentReader->numChannels() != reader->numChannels())
 
    {
 
        emit numOfChannelsChanged(reader->numOfChannels());
 
        emit numOfChannelsChanged(reader->numChannels());
 
    }
 

	
 
    reader->pause(paused);
 
    reader->recording = currentReader->recording;
 

	
 
    currentReader = reader;
 
    emit sourceChanged(currentReader);
 
}
 

	
 
void DataFormatPanel::saveSettings(QSettings* settings)
 
{
 
    settings->beginGroup(SettingGroup_DataFormat);
 

	
 
    // save selected format
 
    QString format;
 
    if (currentReader == &bsReader)
 
    {
 
        format = "binary";
 
    }
 
    else if (currentReader == &asciiReader)
 
    {
 
        format = "ascii";
 
    }
 
    else // framed reader
 
    {
 
        format = "custom";
 
    }
 
    settings->setValue(SG_DataFormat_Format, format);
src/demoreader.h
Show inline comments
 
@@ -32,35 +32,39 @@
 
 * currently selected actual readers settings widget.
 
 *
 
 * This reader should not be enabled when port is open!
 
 */
 
class DemoReader : public AbstractReader
 
{
 
    Q_OBJECT
 

	
 
public:
 
    explicit DemoReader(QIODevice* device, QObject* parent = 0);
 

	
 
    /// Demo reader is an exception so this function returns NULL
 
    QWidget* settingsWidget();
 

	
 
    unsigned numChannels() const;
 

	
 
    void enable(bool enabled = true);
 

	
 
public slots:
 
    void pause(bool);
 

	
 
    /// Sets the number of channels, this doesn't trigger a `numOfChannelsChanged` signal.
 
    void setNumOfChannels(unsigned value);
 

	
 
signals:
 
    // TODO: added for build only, remove later
 
    void samplesPerSecondChanged(unsigned);
 

	
 
private:
 
    bool paused;
 
    unsigned _numChannels;
 
    QTimer timer;
 
    int count;
 

	
 
private slots:
 
    void demoTimerTimeout();
 
};
 

	
 
#endif // DEMOREADER_H
src/framebufferseries.cpp
Show inline comments
 
/*
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <math.h>
 
#include "framebufferseries.h"
 

	
 
FrameBufferSeries::FrameBufferSeries(FrameBuffer* buffer)
 
FrameBufferSeries::FrameBufferSeries(const FrameBuffer* buffer)
 
{
 
    xAsIndex = true;
 
    _xmin = 0;
 
    _xmax = 1;
 
    _buffer = buffer;
 
    int_index_start = 0;
 
    int_index_end = _buffer->size();
 
}
 

	
 
void FrameBufferSeries::setXAxis(bool asIndex, double xmin, double xmax)
 
{
 
    xAsIndex = asIndex;
 
    _xmin = xmin;
 
    _xmax = xmax;
 
}
 

	
 
size_t FrameBufferSeries::size() const
 
{
 
    return int_index_end - int_index_start;
 
}
 

	
 
QPointF FrameBufferSeries::sample(size_t i) const
 
{
 
    i += int_index_start;
src/mainwindow.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "mainwindow.h"
 
#include "ui_mainwindow.h"
 
#include <QByteArray>
 
#include <QApplication>
 
#include <QFileDialog>
 
#include <QMessageBox>
 
#include <QFile>
 
@@ -39,59 +39,58 @@
 

	
 
#include "framebufferseries.h"
 
#include "utils.h"
 
#include "defines.h"
 
#include "version.h"
 
#include "setting_defines.h"
 

	
 
#if defined(Q_OS_WIN) && defined(QT_STATIC)
 
#include <QtPlugin>
 
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
 
#endif
 

	
 
const QMap<int, QString> panelSettingMap({
 
        {0, "Port"},
 
        {1, "DataFormat"},
 
        {2, "Plot"},
 
        {3, "Commands"}
 
    });
 

	
 
MainWindow::MainWindow(QWidget *parent) :
 
    QMainWindow(parent),
 
    ui(new Ui::MainWindow),
 
    aboutDialog(this),
 
    portControl(&serialPort),
 
    channelMan(1, 1, this),
 
    secondaryPlot(NULL),
 
    snapshotMan(this, &channelMan),
 
    snapshotMan(this, &stream),
 
    commandPanel(&serialPort),
 
    dataFormatPanel(&serialPort, &channelMan, &recorder),
 
    recordPanel(&recorder, &channelMan),
 
    dataFormatPanel(&serialPort),
 
    recordPanel(&stream),
 
    updateCheckDialog(this)
 
{
 
    ui->setupUi(this);
 

	
 
    plotMan = new PlotManager(ui->plotArea, &plotMenu, channelMan.infoModel());
 
    plotMan = new PlotManager(ui->plotArea, &plotMenu, &stream);
 

	
 
    ui->tabWidget->insertTab(0, &portControl, "Port");
 
    ui->tabWidget->insertTab(1, &dataFormatPanel, "Data Format");
 
    ui->tabWidget->insertTab(2, &plotControlPanel, "Plot");
 
    ui->tabWidget->insertTab(3, &commandPanel, "Commands");
 
    ui->tabWidget->insertTab(4, &recordPanel, "Record");
 
    ui->tabWidget->setCurrentIndex(0);
 
    auto tbPortControl = portControl.toolBar();
 
    addToolBar(tbPortControl);
 
    addToolBar(recordPanel.toolbar());
 

	
 
    ui->plotToolBar->addAction(snapshotMan.takeSnapshotAction());
 
    menuBar()->insertMenu(ui->menuHelp->menuAction(), snapshotMan.menu());
 
    menuBar()->insertMenu(ui->menuHelp->menuAction(), commandPanel.menu());
 

	
 
    connect(&commandPanel, &CommandPanel::focusRequested, [this]()
 
            {
 
                this->ui->tabWidget->setCurrentWidget(&commandPanel);
 
                this->ui->tabWidget->showTabs();
 
            });
 

	
 
    tbPortControl->setObjectName("tbPortControl");
 
    ui->plotToolBar->setObjectName("tbPlot");
 

	
 
@@ -158,106 +157,80 @@ MainWindow::MainWindow(QWidget *parent) 
 

	
 
    // plot control signals
 
    connect(&plotControlPanel, &PlotControlPanel::numOfSamplesChanged,
 
            this, &MainWindow::onNumOfSamplesChanged);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::numOfSamplesChanged,
 
            plotMan, &PlotManager::setNumOfSamples);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::yScaleChanged,
 
            plotMan, &PlotManager::setYAxis);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::xScaleChanged,
 
            plotMan, &PlotManager::setXAxis);
 

	
 
    connect(&plotControlPanel, &PlotControlPanel::plotWidthChanged,
 
            plotMan, &PlotManager::setPlotWidth);
 

	
 
    // plot toolbar signals
 
    QObject::connect(ui->actionClear, SIGNAL(triggered(bool)),
 
                     this, SLOT(clearPlot()));
 

	
 
    QObject::connect(snapshotMan.takeSnapshotAction(), &QAction::triggered,
 
                     plotMan, &PlotManager::flashSnapshotOverlay);
 

	
 
    // init data format and reader
 
    QObject::connect(&channelMan, &ChannelManager::dataAdded,
 
                     plotMan, &PlotManager::replot);
 

	
 
    QObject::connect(ui->actionPause, &QAction::triggered,
 
                     &channelMan, &ChannelManager::pause);
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordStarted,
 
                     &dataFormatPanel, &DataFormatPanel::startRecording);
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordStopped,
 
                     &dataFormatPanel, &DataFormatPanel::stopRecording);
 
                     &stream, &Stream::pause);
 

	
 
    QObject::connect(ui->actionPause, &QAction::triggered,
 
                     [this](bool enabled)
 
                     {
 
                         if (enabled && !recordPanel.recordPaused())
 
                         {
 
                             dataFormatPanel.pause(true);
 
                         }
 
                         else
 
                         {
 
                             dataFormatPanel.pause(false);
 
                         }
 
                     });
 

	
 
    QObject::connect(&recordPanel, &RecordPanel::recordPausedChanged,
 
                     [this](bool enabled)
 
                     {
 
                         if (ui->actionPause->isChecked() && enabled)
 
                         {
 
                             dataFormatPanel.pause(false);
 
                         }
 
                     });
 

	
 
    connect(&serialPort, &QIODevice::aboutToClose,
 
            &recordPanel, &RecordPanel::onPortClose);
 

	
 
    // init data arrays and plot
 
    numOfSamples = plotControlPanel.numOfSamples();
 
    unsigned numOfChannels = dataFormatPanel.numOfChannels();
 

	
 
    channelMan.setNumOfSamples(numOfSamples);
 
    channelMan.setNumOfChannels(dataFormatPanel.numOfChannels());
 

	
 
    connect(&dataFormatPanel, &DataFormatPanel::numOfChannelsChanged,
 
            &channelMan, &ChannelManager::setNumOfChannels);
 

	
 
    connect(&channelMan, &ChannelManager::numOfChannelsChanged,
 
            this, &MainWindow::onNumOfChannelsChanged);
 

	
 
    plotControlPanel.setChannelInfoModel(channelMan.infoModel());
 

	
 
    // init curve list
 
    for (unsigned int i = 0; i < numOfChannels; i++)
 
    {
 
        plotMan->addCurve(channelMan.channelName(i), channelMan.channelBuffer(i));
 
    }
 
    stream.setNumSamples(numOfSamples);
 
    plotControlPanel.setChannelInfoModel(stream.infoModel());
 

	
 
    // init scales
 
    plotMan->setYAxis(plotControlPanel.autoScale(),
 
                      plotControlPanel.yMin(), plotControlPanel.yMax());
 
    plotMan->setXAxis(plotControlPanel.xAxisAsIndex(),
 
                      plotControlPanel.xMin(), plotControlPanel.xMax());
 
    plotMan->setNumOfSamples(numOfSamples);
 
    plotMan->setPlotWidth(plotControlPanel.plotWidth());
 

	
 
    // Init sps (sample per second) counter
 
    spsLabel.setText("0sps");
 
    spsLabel.setToolTip("samples per second (per channel)");
 
    ui->statusBar->addPermanentWidget(&spsLabel);
 
    QObject::connect(&dataFormatPanel,
 
                     &DataFormatPanel::samplesPerSecondChanged,
 
                     this, &MainWindow::onSpsChanged);
 

	
 
    // init demo
 
    QObject::connect(ui->actionDemoMode, &QAction::toggled,
 
                     this, &MainWindow::enableDemo);
 

	
 
    QObject::connect(ui->actionDemoMode, &QAction::toggled,
 
                     plotMan, &PlotManager::showDemoIndicator);
 

	
 
@@ -349,80 +322,56 @@ Try fixing the permissions of file: %1, 
 

	
 
void MainWindow::setupAboutDialog()
 
{
 
    Ui_AboutDialog uiAboutDialog;
 
    uiAboutDialog.setupUi(&aboutDialog);
 

	
 
    QObject::connect(uiAboutDialog.pbAboutQt, &QPushButton::clicked,
 
                     [](){ QApplication::aboutQt();});
 

	
 
    QString aboutText = uiAboutDialog.lbAbout->text();
 
    aboutText.replace("$VERSION_STRING$", VERSION_STRING);
 
    aboutText.replace("$VERSION_REVISION$", VERSION_REVISION);
 
    uiAboutDialog.lbAbout->setText(aboutText);
 
}
 

	
 
void MainWindow::onPortToggled(bool open)
 
{
 
    // make sure demo mode is disabled
 
    if (open && isDemoRunning()) enableDemo(false);
 
    ui->actionDemoMode->setEnabled(!open);
 
}
 

	
 
void MainWindow::clearPlot()
 
{
 
    for (unsigned ci = 0; ci < channelMan.numOfChannels(); ci++)
 
    {
 
        channelMan.channelBuffer(ci)->clear();
 
    }
 
    stream.clear();
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onNumOfSamplesChanged(int value)
 
{
 
    numOfSamples = value;
 
    channelMan.setNumOfSamples(value);
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onNumOfChannelsChanged(unsigned value)
 
{
 
    unsigned int oldNum = plotMan->numOfCurves();
 
    unsigned numOfChannels = value;
 

	
 
    if (numOfChannels > oldNum)
 
    {
 
        // add new channels
 
        for (unsigned int i = oldNum; i < numOfChannels; i++)
 
        {
 
            plotMan->addCurve(channelMan.channelName(i), channelMan.channelBuffer(i));
 
        }
 
    }
 
    else if(numOfChannels < oldNum)
 
    {
 
        plotMan->removeCurves(oldNum - numOfChannels);
 
    }
 

	
 
    stream.setNumSamples(value);
 
    plotMan->replot();
 
}
 

	
 
void MainWindow::onSpsChanged(unsigned sps)
 
{
 
    spsLabel.setText(QString::number(sps) + "sps");
 
}
 

	
 
bool MainWindow::isDemoRunning()
 
{
 
    return ui->actionDemoMode->isChecked();
 
}
 

	
 
void MainWindow::enableDemo(bool enabled)
 
{
 
    if (enabled)
 
    {
 
        if (!serialPort.isOpen())
 
        {
 
            dataFormatPanel.enableDemo(true);
 
        }
 
        else
 
        {
 
            ui->actionDemoMode->setChecked(false);
 
@@ -442,49 +391,49 @@ void MainWindow::showSecondary(QWidget* 
 
        secondaryPlot->deleteLater();
 
    }
 

	
 
    secondaryPlot = wid;
 
    ui->splitter->addWidget(wid);
 
    ui->splitter->setStretchFactor(0, 1);
 
    ui->splitter->setStretchFactor(1, 0);
 
}
 

	
 
void MainWindow::hideSecondary()
 
{
 
    if (secondaryPlot == NULL)
 
    {
 
        qFatal("Secondary plot doesn't exist!");
 
    }
 

	
 
    secondaryPlot->deleteLater();
 
    secondaryPlot = NULL;
 
}
 

	
 
void MainWindow::showBarPlot(bool show)
 
{
 
    if (show)
 
    {
 
        auto plot = new BarPlot(&channelMan, &plotMenu);
 
        auto plot = new BarPlot(&stream, &plotMenu);
 
        plot->setYAxis(plotControlPanel.autoScale(),
 
                       plotControlPanel.yMin(),
 
                       plotControlPanel.yMax());
 
        connect(&plotControlPanel, &PlotControlPanel::yScaleChanged,
 
                plot, &BarPlot::setYAxis);
 
        showSecondary(plot);
 
    }
 
    else
 
    {
 
        hideSecondary();
 
    }
 
}
 

	
 
void MainWindow::onExportCsv()
 
{
 
    bool wasPaused = ui->actionPause->isChecked();
 
    ui->actionPause->setChecked(true); // pause plotting
 

	
 
    QString fileName = QFileDialog::getSaveFileName(this, tr("Export CSV File"));
 

	
 
    if (fileName.isNull())  // user canceled export
 
    {
 
        ui->actionPause->setChecked(wasPaused);
 
    }
 
@@ -526,62 +475,62 @@ void MainWindow::messageHandler(QtMsgTyp
 
        case QtFatalMsg:
 
            logString = "[Fatal] " + msg;
 
            break;
 
    }
 

	
 
    if (ui != NULL) ui->ptLog->appendPlainText(logString);
 
    std::cerr << logString.toStdString() << std::endl;
 

	
 
    if (type != QtDebugMsg && ui != NULL)
 
    {
 
        ui->statusBar->showMessage(msg, 5000);
 
    }
 

	
 
    if (type == QtFatalMsg)
 
    {
 
        __builtin_trap();
 
    }
 
}
 

	
 
void MainWindow::saveAllSettings(QSettings* settings)
 
{
 
    saveMWSettings(settings);
 
    portControl.saveSettings(settings);
 
    dataFormatPanel.saveSettings(settings);
 
    channelMan.saveSettings(settings);
 
    stream.saveSettings(settings);
 
    plotControlPanel.saveSettings(settings);
 
    plotMenu.saveSettings(settings);
 
    commandPanel.saveSettings(settings);
 
    recordPanel.saveSettings(settings);
 
    updateCheckDialog.saveSettings(settings);
 
}
 

	
 
void MainWindow::loadAllSettings(QSettings* settings)
 
{
 
    loadMWSettings(settings);
 
    portControl.loadSettings(settings);
 
    dataFormatPanel.loadSettings(settings);
 
    channelMan.loadSettings(settings);
 
    stream.loadSettings(settings);
 
    plotControlPanel.loadSettings(settings);
 
    plotMenu.loadSettings(settings);
 
    commandPanel.loadSettings(settings);
 
    recordPanel.loadSettings(settings);
 
    updateCheckDialog.loadSettings(settings);
 
}
 

	
 
void MainWindow::saveMWSettings(QSettings* settings)
 
{
 
    // save window geometry
 
    settings->beginGroup(SettingGroup_MainWindow);
 
    settings->setValue(SG_MainWindow_Size, size());
 
    settings->setValue(SG_MainWindow_Pos, pos());
 
    // save active panel
 
    settings->setValue(SG_MainWindow_ActivePanel,
 
                       panelSettingMap.value(ui->tabWidget->currentIndex()));
 
    // save panel minimization
 
    settings->setValue(SG_MainWindow_HidePanels,
 
                       ui->tabWidget->hideAction.isChecked());
 
    // save window maximized state
 
    settings->setValue(SG_MainWindow_Maximized,
 
                       bool(windowState() & Qt::WindowMaximized));
 
    // save toolbar/dockwidgets state
 
    settings->setValue(SG_MainWindow_State, saveState());
src/mainwindow.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef MAINWINDOW_H
 
#define MAINWINDOW_H
 

	
 
#include <QMainWindow>
 
#include <QButtonGroup>
 
#include <QLabel>
 
#include <QString>
 
#include <QVector>
 
#include <QList>
 
#include <QSerialPort>
 
#include <QSignalMapper>
 
#include <QTimer>
 
#include <QColor>
 
#include <QtGlobal>
 
#include <QSettings>
 
#include <qwt_plot_curve.h>
 

	
 
#include "portcontrol.h"
 
#include "commandpanel.h"
 
#include "dataformatpanel.h"
 
#include "plotcontrolpanel.h"
 
#include "recordpanel.h"
 
#include "ui_about_dialog.h"
 
#include "framebuffer.h"
 
#include "channelmanager.h"
 
#include "stream.h"
 
#include "snapshotmanager.h"
 
#include "plotmanager.h"
 
#include "plotmenu.h"
 
#include "datarecorder.h"
 
#include "updatecheckdialog.h"
 

	
 
namespace Ui {
 
class MainWindow;
 
}
 

	
 
class MainWindow : public QMainWindow
 
{
 
    Q_OBJECT
 

	
 
public:
 
    explicit MainWindow(QWidget *parent = 0);
 
    ~MainWindow();
 

	
 
    PlotViewSettings viewSettings() const;
 

	
 
    void messageHandler(QtMsgType type, const QMessageLogContext &context,
 
                        const QString &msg);
 

	
 
private:
 
    Ui::MainWindow *ui;
 

	
 
    QDialog aboutDialog;
 
    void setupAboutDialog();
 

	
 
    QSerialPort serialPort;
 
    PortControl portControl;
 

	
 
    unsigned int numOfSamples;
 

	
 
    QList<QwtPlotCurve*> curves;
 
    ChannelManager channelMan;
 
    // ChannelManager channelMan;
 
    Stream stream;
 
    PlotManager* plotMan;
 
    QWidget* secondaryPlot;
 
    SnapshotManager snapshotMan;
 
    DataRecorder recorder;       // operated by `recordPanel`
 

	
 
    QLabel spsLabel;
 
    CommandPanel commandPanel;
 
    DataFormatPanel dataFormatPanel;
 
    RecordPanel recordPanel;
 
    PlotControlPanel plotControlPanel;
 
    PlotMenu plotMenu;
 
    UpdateCheckDialog updateCheckDialog;
 

	
 
    /// Returns true if demo is running
 
    bool isDemoRunning();
 
    /// Display a secondary plot in the splitter, removing and
 
    /// deleting previous one if it exists
 
    void showSecondary(QWidget* wid);
 
    /// Hide secondary plot
 
    void hideSecondary();
 
    /// Stores settings for all modules
 
    void saveAllSettings(QSettings* settings);
 
    /// Load settings for all modules
 
    void loadAllSettings(QSettings* settings);
 
    /// Stores main window settings into a `QSettings`
 
    void saveMWSettings(QSettings* settings);
 
    /// Loads main window settings from a `QSettings`
 
    void loadMWSettings(QSettings* settings);
 

	
 
    /// `QWidget::closeEvent` handler
 
    void closeEvent(QCloseEvent * event);
 

	
 
private slots:
 
    void onPortToggled(bool open);
 

	
 
    void onNumOfSamplesChanged(int value);
 
    void onNumOfChannelsChanged(unsigned value);
 

	
 
    void clearPlot();
 
    void onSpsChanged(unsigned sps);
 
    void enableDemo(bool enabled);
 
    void showBarPlot(bool show);
 

	
 
    void onExportCsv();
 
    void onSaveSettings();
 
    void onLoadSettings();
 
};
 

	
 
#endif // MAINWINDOW_H
src/plotmanager.cpp
Show inline comments
 
@@ -10,124 +10,177 @@
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <algorithm>
 
#include <QMetaEnum>
 
#include <QtDebug>
 
#include "qwt_symbol.h"
 

	
 
#include "plot.h"
 
#include "plotmanager.h"
 
#include "utils.h"
 
#include "setting_defines.h"
 

	
 
PlotManager::PlotManager(QWidget* plotArea, PlotMenu* menu,
 
                         const Stream* stream, QObject* parent) :
 
    QObject(parent)
 
{
 
    construct(plotArea, menu);
 
    _stream = stream;
 
    if (_stream == NULL) return;
 

	
 
    // connect to ChannelInfoModel
 
    infoModel = _stream->infoModel();
 
    connect(infoModel, &QAbstractItemModel::dataChanged,
 
                this, &PlotManager::onChannelInfoChanged);
 
    connect(infoModel, &QAbstractItemModel::modelReset,
 
            [this]()
 
            {
 
                onChannelInfoChanged(infoModel->index(0, 0), // start
 
                                     infoModel->index(infoModel->rowCount()-1, 0), // end
 
                                     {}); // roles ignored
 
            });
 

	
 

	
 
    connect(stream, &Stream::numChannelsChanged, this, &PlotManager::onNumChannelsChanged);
 
    connect(stream, &Stream::dataAdded, this, &PlotManager::replot);
 

	
 
    // add initial curves if any?
 
    for (unsigned int i = 0; i < stream->numChannels(); i++)
 
    {
 
        addCurve(stream->channel(i)->name(), stream->channel(i)->yData());
 
    }
 

	
 
}
 

	
 
PlotManager::PlotManager(QWidget* plotArea, PlotMenu* menu,
 
                         Snapshot* snapshot, QObject *parent) :
 
    QObject(parent)
 
{
 
    construct(plotArea, menu);
 

	
 
    setNumOfSamples(snapshot->numSamples());
 
    setPlotWidth(snapshot->numSamples());
 

	
 
    for (unsigned ci = 0; ci < snapshot->numChannels(); ci++)
 
    {
 
        addCurve(snapshot->channelName(ci), snapshot->data[ci]);
 
    }
 

	
 
    infoModel = snapshot->infoModel();
 
    connect(infoModel, &QAbstractItemModel::dataChanged,
 
            this, &PlotManager::onChannelInfoChanged);
 
}
 

	
 
void PlotManager::construct(QWidget* plotArea, PlotMenu* menu)
 
{
 
    _menu = menu;
 
    _plotArea = plotArea;
 
    _autoScaled = true;
 
    _yMin = 0;
 
    _yMax = 1;
 
    _xAxisAsIndex = true;
 
    isDemoShown = false;
 
    _stream = stream;
 
    _numOfSamples = 1;
 
    _plotWidth = 1;
 
    showSymbols = Plot::ShowSymbolsAuto;
 
    emptyPlot = NULL;
 

	
 
    // initalize layout and single widget
 
    isMulti = false;
 
    scrollArea = NULL;
 
    setupLayout(isMulti);
 
    addPlotWidget();
 

	
 
    // connect to  menu
 
    connect(menu, &PlotMenu::symbolShowChanged, this, &PlotManager:: setSymbols);
 

	
 
    connect(&menu->showGridAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &PlotManager::showGrid);
 
    connect(&menu->showMinorGridAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &PlotManager::showMinorGrid);
 
    connect(&menu->darkBackgroundAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &PlotManager::darkBackground);
 
    connect(&menu->showLegendAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &PlotManager::showLegend);
 
    connect(&menu->showMultiAction, SELECT<bool>::OVERLOAD_OF(&QAction::toggled),
 
            this, &PlotManager::setMulti);
 
    connect(&menu->unzoomAction, &QAction::triggered,
 
            this, &PlotManager::unzoom);
 

	
 
    // initial settings from menu actions
 
    showGrid(menu->showGridAction.isChecked());
 
    showMinorGrid(menu->showMinorGridAction.isChecked());
 
    darkBackground(menu->darkBackgroundAction.isChecked());
 
    showLegend(menu->showLegendAction.isChecked());
 
    setMulti(menu->showMultiAction.isChecked());
 

	
 
    // connect to channel info model
 
    if (_stream != NULL)
 
    {
 
        auto infoModel = _stream->infoModel();
 
        connect(infoModel, &QAbstractItemModel::dataChanged,
 
                this, &PlotManager::onChannelInfoChanged);
 

	
 
        connect(infoModel, &QAbstractItemModel::modelReset,
 
                [this]()
 
                {
 
                    onChannelInfoChanged(infoModel->index(0, 0), // start
 
                                         infoModel->index(infoModel->rowCount()-1, 0), // end
 
                                         {}); // roles ignored
 
                });
 
    }
 
}
 

	
 
PlotManager::~PlotManager()
 
{
 
    while (curves.size())
 
    {
 
        delete curves.takeLast();
 
    }
 

	
 
    // remove all widgets
 
    while (plotWidgets.size())
 
    {
 
        delete plotWidgets.takeLast();
 
    }
 

	
 
    if (scrollArea != NULL) delete scrollArea;
 
    if (emptyPlot != NULL) delete emptyPlot;
 
}
 

	
 
void PlotManager::onNumChannelsChanged(unsigned value)
 
{
 
    unsigned int oldNum = numOfCurves();
 
    unsigned numOfChannels = value;
 

	
 
    if (numOfChannels > oldNum)
 
    {
 
        // add new channels
 
        for (unsigned int i = oldNum; i < numOfChannels; i++)
 
        {
 
            addCurve(_stream->channel(i)->name(), _stream->channel(i)->yData());
 
        }
 
    }
 
    else if(numOfChannels < oldNum)
 
    {
 
        removeCurves(oldNum - numOfChannels);
 
    }
 

	
 
    replot();
 
}
 

	
 
void PlotManager::onChannelInfoChanged(const QModelIndex &topLeft,
 
                                       const QModelIndex &bottomRight,
 
                                       const QVector<int> &roles)
 
{
 
    int start = topLeft.row();
 
    int end = bottomRight.row();
 

	
 
    for (int ci = start; ci <= end; ci++)
 
    {
 
        QString name = topLeft.sibling(ci, ChannelInfoModel::COLUMN_NAME).data(Qt::EditRole).toString();
 
        QColor color = topLeft.sibling(ci, ChannelInfoModel::COLUMN_NAME).data(Qt::ForegroundRole).value<QColor>();
 
        bool visible = topLeft.sibling(ci, ChannelInfoModel::COLUMN_VISIBILITY).data(Qt::CheckStateRole).toBool();
 

	
 
        curves[ci]->setTitle(name);
 
        curves[ci]->setPen(color);
 
        curves[ci]->setVisible(visible);
 
        curves[ci]->setItemAttribute(QwtPlotItem::Legend, visible);
 

	
 
        // replot only updated widgets
 
        if (isMulti)
 
        {
 
            plotWidgets[ci]->updateSymbols(); // required for color change
 
            plotWidgets[ci]->updateLegend(curves[ci]);
 
            plotWidgets[ci]->setVisible(visible);
 
@@ -255,71 +308,71 @@ Plot* PlotManager::addPlotWidget()
 

	
 
    plot->darkBackground(_menu->darkBackgroundAction.isChecked());
 
    plot->showGrid(_menu->showGridAction.isChecked());
 
    plot->showMinorGrid(_menu->showMinorGridAction.isChecked());
 
    plot->showLegend(_menu->showLegendAction.isChecked());
 
    plot->setSymbols(_menu->showSymbols());
 

	
 
    plot->showDemoIndicator(isDemoShown);
 
    plot->setYAxis(_autoScaled, _yMin, _yMax);
 
    plot->setNumOfSamples(_numOfSamples);
 

	
 
    plot->setPlotWidth(_plotWidth);
 
    if (_xAxisAsIndex)
 
    {
 
        plot->setXAxis(0, _numOfSamples);
 
    }
 
    else
 
    {
 
        plot->setXAxis(_xMin, _xMax);
 
    }
 

	
 
    return plot;
 
}
 

	
 
void PlotManager::addCurve(QString title, FrameBuffer* buffer)
 
void PlotManager::addCurve(QString title, const FrameBuffer* buffer)
 
{
 
    auto curve = new QwtPlotCurve(title);
 
    auto series = new FrameBufferSeries(buffer);
 
    series->setXAxis(_xAxisAsIndex, _xMin, _xMax);
 
    curve->setSamples(series);
 
    _addCurve(curve);
 
}
 

	
 
void PlotManager::addCurve(QString title, QVector<QPointF> data)
 
{
 
    auto curve = new QwtPlotCurve(title);
 
    curve->setSamples(data);
 
    _addCurve(curve);
 
}
 

	
 
void PlotManager::_addCurve(QwtPlotCurve* curve)
 
{
 
    // store and init the curve
 
    curves.append(curve);
 

	
 
    unsigned index = curves.size()-1;
 
    auto color = _stream->channel(index)->color();
 
    auto color = infoModel->color(index);
 
    curve->setPen(color);
 

	
 
    // create the plot for the curve if we are on multi display
 
    Plot* plot;
 
    if (isMulti)
 
    {
 
        // create a new plot widget
 
        plot = addPlotWidget();
 
    }
 
    else
 
    {
 
        plot = plotWidgets[0];
 
    }
 

	
 
    // show the curve
 
    curve->attach(plot);
 
    plot->replot();
 
}
 

	
 
void PlotManager::removeCurves(unsigned number)
 
{
 
    for (unsigned i = 0; i < number; i++)
 
    {
 
        if (!curves.isEmpty())
src/plotmanager.h
Show inline comments
 
@@ -11,109 +11,117 @@
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef PLOTMANAGER_H
 
#define PLOTMANAGER_H
 

	
 
#include <QObject>
 
#include <QWidget>
 
#include <QScrollArea>
 
#include <QVBoxLayout>
 
#include <QList>
 
#include <QSettings>
 
#include <QMenu>
 

	
 
#include <qwt_plot_curve.h>
 
#include "plot.h"
 
#include "framebufferseries.h"
 
#include "stream.h"
 
#include "snapshot.h"
 
#include "plotmenu.h"
 

	
 
class PlotManager : public QObject
 
{
 
    Q_OBJECT
 

	
 
public:
 
    explicit PlotManager(QWidget* plotArea, PlotMenu* menu,
 
                         const Stream* stream = NULL,
 
                         QObject *parent = 0);
 
    explicit PlotManager(QWidget* plotArea, PlotMenu* menu,
 
                         Snapshot* snapshot,
 
                         QObject *parent = 0);
 
    ~PlotManager();
 
    /// Add a new curve with title and buffer. A color is
 
    /// automatically chosen for curve.
 
    void addCurve(QString title, FrameBuffer* buffer);
 
    void addCurve(QString title, const FrameBuffer* buffer);
 
    /// Alternative of `addCurve` for static curve data (snapshots).
 
    void addCurve(QString title, QVector<QPointF> data);
 
    /// Removes curves from the end
 
    void removeCurves(unsigned number);
 
    /// Returns current number of curves known by plot manager
 
    unsigned numOfCurves();
 

	
 
public slots:
 
    /// Enable/Disable multiple plot display
 
    void setMulti(bool enabled);
 
    /// Update all plot widgets
 
    void replot();
 
    /// Enable display of a "DEMO" label on each plot
 
    void showDemoIndicator(bool show = true);
 
    /// Set the Y axis
 
    void setYAxis(bool autoScaled, double yMin = 0, double yMax = 1);
 
    /// Set the X axis
 
    void setXAxis(bool asIndex, double xMin = 0 , double xMax = 1);
 
    /// Display an animation for snapshot
 
    void flashSnapshotOverlay();
 
    /// Should be called to update zoom base
 
    void setNumOfSamples(unsigned value);
 
    /// Maximum width of X axis (limit of hscroll)
 
    void setPlotWidth(double width);
 

	
 
private:
 
    bool isMulti;
 
    QWidget* _plotArea;
 
    PlotMenu* _menu;
 
    QVBoxLayout* layout; ///< layout of the `plotArea`
 
    QScrollArea* scrollArea;
 
    QList<QwtPlotCurve*> curves;
 
    QList<Plot*> plotWidgets;
 
    Plot* emptyPlot;  ///< for displaying when all channels are hidden
 
    const Stream* stream;       ///< attached stream, can be `NULL`
 
    const Stream* _stream;       ///< attached stream, can be `NULL`
 
    const ChannelInfoModel* infoModel;
 
    bool isDemoShown;
 
    bool _autoScaled;
 
    double _yMin;
 
    double _yMax;
 
    bool _xAxisAsIndex;
 
    double _xMin;
 
    double _xMax;
 
    unsigned _numOfSamples;
 
    double _plotWidth;
 
    Plot::ShowSymbols showSymbols;
 

	
 
    /// Common constructor
 
    void construct(QWidget* plotArea, PlotMenu* menu);
 
    /// Setups the layout for multi or single plot
 
    void setupLayout(bool multiPlot);
 
    /// Inserts a new plot widget to the current layout.
 
    Plot* addPlotWidget();
 
    /// Returns the plot widget that given curve is attached to
 
    Plot* plotWidget(unsigned curveIndex);
 
    /// Common part of overloaded `addCurve` functions
 
    void _addCurve(QwtPlotCurve* curve);
 
    /// Check and make sure "no visible channels" text is shown
 
    void checkNoVisChannels();
 

	
 
private slots:
 
    void showGrid(bool show = true);
 
    void showMinorGrid(bool show = true);
 
    void showLegend(bool show = true);
 
    void unzoom();
 
    void darkBackground(bool enabled = true);
 
    void setSymbols(Plot::ShowSymbols shown);
 

	
 
    void onNumChannelsChanged(unsigned value);
 
    void onChannelInfoChanged(const QModelIndex & topLeft,
 
                              const QModelIndex & bottomRight,
 
                              const QVector<int> & roles = QVector<int> ());
 
};
 

	
 
#endif // PLOTMANAGER_H
src/recordpanel.cpp
Show inline comments
 
@@ -214,49 +214,49 @@ bool RecordPanel::confirmOverwrite(QStri
 
    if (mb.clickedButton() == bCancel)
 
    {
 
        return false;
 
    }
 
    else if (mb.clickedButton() == bOverwrite)
 
    {
 
        selectedFile = fileName;
 
        return true;
 
    }
 
    else                    // select button
 
    {
 
        return selectFile();
 
    }
 
}
 

	
 
void RecordPanel::startRecording(void)
 
{
 
    QStringList channelNames;
 
    if (ui->cbHeader->isChecked())
 
    {
 
        channelNames = _stream->infoModel()->channelNames();
 
    }
 
    if (recorder.startRecording(selectedFile, getSeparator(), channelNames))
 
    {
 
        stream->connectFollower(&recorder);
 
        _stream->connectFollower(&recorder);
 
    }
 
}
 

	
 
void RecordPanel::stopRecording(void)
 
{
 
    recorder.stopRecording();
 
}
 

	
 
void RecordPanel::onPortClose()
 
{
 
    if (recordAction.isChecked() && ui->cbStopOnClose->isChecked())
 
    {
 
        stopRecording();
 
        recordAction.setChecked(false);
 
    }
 
}
 

	
 
QString RecordPanel::getSeparator() const
 
{
 
    QString sep = ui->leSeparator->text();
 
    sep.replace("\\t", "\t");
 
    return sep;
 
}
 

	
src/snapshot.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <stddef.h>
 
#include <QSaveFile>
 
#include <QTextStream>
 

	
 
#include "mainwindow.h"
 
#include "snapshot.h"
 
#include "snapshotview.h"
 
@@ -87,51 +87,66 @@ void Snapshot::onDeleteTriggered()
 
QString Snapshot::name()
 
{
 
    return _name;
 
}
 

	
 
QString Snapshot::displayName()
 
{
 
    if (_saved)
 
    {
 
        return name();
 
    }
 
    else
 
    {
 
        return name() + "*";
 
    }
 
}
 

	
 
void Snapshot::setName(QString name)
 
{
 
    _name = name;
 
    _showAction.setText(_name);
 
    emit nameChanged(this);
 
}
 

	
 
unsigned Snapshot::numChannels() const
 
{
 
    return data.size();
 
}
 

	
 
unsigned Snapshot::numSamples() const
 
{
 
    return data[0].size();
 
}
 

	
 
const ChannelInfoModel* Snapshot::infoModel() const
 
{
 
    return &cInfoModel;
 
}
 

	
 
ChannelInfoModel* Snapshot::infoModel()
 
{
 
    return &cInfoModel;
 
    return const_cast<ChannelInfoModel*>(static_cast<const Snapshot&>(*this).infoModel());
 
}
 

	
 
QString Snapshot::channelName(unsigned channel)
 
{
 
    return cInfoModel.name(channel);
 
}
 

	
 
void Snapshot::save(QString fileName)
 
{
 
    // TODO: remove code duplication (MainWindow::onExportCsv)
 
    QSaveFile file(fileName);
 

	
 
    if (file.open(QIODevice::WriteOnly | QIODevice::Text))
 
    {
 
        QTextStream fileStream(&file);
 

	
 
        unsigned numOfChannels = data.size();
 
        unsigned numOfSamples = data[0].size();
 

	
 
        // print header
 
        for (unsigned int ci = 0; ci < numOfChannels; ci++)
 
        {
 
            fileStream << channelName(ci);
 
            if (ci != numOfChannels-1) fileStream << ",";
src/snapshot.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef SNAPSHOT_H
 
#define SNAPSHOT_H
 

	
 
#include <QObject>
 
#include <QAction>
 
#include <QVector>
 
#include <QString>
 
#include <QStringList>
 

	
 
#include "channelinfomodel.h"
 

	
 
class SnapshotView;
 
class MainWindow;
 

	
 
class Snapshot : public QObject
 
{
 
    Q_OBJECT
 

	
 
public:
 
    Snapshot(MainWindow* parent, QString name, ChannelInfoModel infoModel, bool saved = false);
 
    ~Snapshot();
 

	
 
    QVector<QVector<QPointF>> data;
 
    QAction* showAction();
 
    QAction* deleteAction();
 

	
 
    QString name();
 
    QString displayName(); ///< `name()` plus '*' if snapshot is not saved
 
    unsigned numChannels() const; ///< number of channels in this snapshot
 
    unsigned numSamples() const;  ///< number of samples in every channel
 
    const ChannelInfoModel* infoModel() const;
 
    ChannelInfoModel* infoModel();
 
    void setName(QString name);
 
    QString channelName(unsigned channel);
 

	
 
    void save(QString fileName); ///< save snapshot data as CSV
 
    bool isSaved(); ///< snapshot has been saved at least once
 

	
 
signals:
 
    void deleteRequested(Snapshot*);
 
    void nameChanged(Snapshot*);
 

	
 
private:
 
    QString _name;
 
    ChannelInfoModel cInfoModel;
 
    QAction _showAction;
 
    QAction _deleteAction;
 
    MainWindow* mainWindow;
 
    SnapshotView* view;
 
    bool _saved;
 

	
 
private slots:
 
    void show();
 
    void viewClosed();
 

	
src/snapshotmanager.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QTime>
 
#include <QMenuBar>
 
#include <QKeySequence>
 
#include <QFileDialog>
 
#include <QFile>
 
#include <QVector>
 
#include <QPointF>
 
#include <QIcon>
 
#include <QtDebug>
 

	
 
#include "mainwindow.h"
 
#include "snapshotmanager.h"
 

	
 
SnapshotManager::SnapshotManager(MainWindow* mainWindow,
 
                                 ChannelManager* channelMan) :
 
                                 Stream* stream) :
 
    _menu("&Snapshots"),
 
    _takeSnapshotAction("&Take Snapshot", this),
 
    loadSnapshotAction("&Load Snapshots", this),
 
    clearAction("&Clear Snapshots", this)
 
{
 
    _mainWindow = mainWindow;
 
    _channelMan = channelMan;
 
    _stream = stream;
 

	
 
    _takeSnapshotAction.setToolTip("Take a snapshot of current plot");
 
    _takeSnapshotAction.setShortcut(QKeySequence("F5"));
 
    _takeSnapshotAction.setIcon(QIcon::fromTheme("camera"));
 
    loadSnapshotAction.setToolTip("Load snapshots from CSV files");
 
    clearAction.setToolTip("Delete all snapshots");
 
    connect(&_takeSnapshotAction, SIGNAL(triggered(bool)),
 
            this, SLOT(takeSnapshot()));
 
    connect(&clearAction, SIGNAL(triggered(bool)),
 
            this, SLOT(clearSnapshots()));
 
    connect(&loadSnapshotAction, SIGNAL(triggered(bool)),
 
            this, SLOT(loadSnapshots()));
 

	
 
    updateMenu();
 
}
 

	
 
SnapshotManager::~SnapshotManager()
 
{
 
    for (auto snapshot : snapshots)
 
    {
 
        delete snapshot;
 
    }
 
}
 

	
 
Snapshot* SnapshotManager::makeSnapshot()
 
Snapshot* SnapshotManager::makeSnapshot() const
 
{
 
    QString name = QTime::currentTime().toString("'Snapshot ['HH:mm:ss']'");
 
    auto snapshot = new Snapshot(_mainWindow, name, *(_channelMan->infoModel()));
 
    auto snapshot = new Snapshot(_mainWindow, name, *(_stream->infoModel()));
 

	
 
    unsigned numOfChannels = _channelMan->numOfChannels();
 
    unsigned numOfSamples = _channelMan->numOfSamples();
 
    unsigned numChannels = _stream->numChannels();
 
    unsigned numSamples = _stream->numSamples();
 

	
 
    for (unsigned ci = 0; ci < numOfChannels; ci++)
 
    for (unsigned ci = 0; ci < numChannels; ci++)
 
    {
 
        snapshot->data.append(QVector<QPointF>(numOfSamples));
 
        for (unsigned i = 0; i < numOfSamples; i++)
 
        snapshot->data.append(QVector<QPointF>(numSamples));
 
        auto x = _stream->channel(ci)->xData();
 
        auto y = _stream->channel(ci)->yData();
 
        for (unsigned i = 0; i < numSamples; i++)
 
        {
 
            snapshot->data[ci][i] = QPointF(i, _channelMan->channelBuffer(ci)->sample(i));
 
            snapshot->data[ci][i] = QPointF(x->sample(i), y->sample(i));
 
        }
 
    }
 

	
 
    return snapshot;
 
}
 

	
 
void SnapshotManager::takeSnapshot()
 
{
 
    addSnapshot(makeSnapshot());
 
}
 

	
 
void SnapshotManager::addSnapshot(Snapshot* snapshot, bool update_menu)
 
{
 
    snapshots.append(snapshot);
 
    QObject::connect(snapshot, &Snapshot::deleteRequested,
 
                     this, &SnapshotManager::deleteSnapshot);
 
    if (update_menu) updateMenu();
 
}
 

	
 
void SnapshotManager::updateMenu()
 
{
 
    _menu.clear();
 
    _menu.addAction(&_takeSnapshotAction);
 
    _menu.addAction(&loadSnapshotAction);
src/snapshotmanager.h
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#ifndef SNAPSHOTMANAGER_H
 
#define SNAPSHOTMANAGER_H
 

	
 
#include <QObject>
 
#include <QAction>
 
#include <QMenu>
 

	
 
#include "framebuffer.h"
 
#include "channelmanager.h"
 
#include "stream.h"
 
#include "snapshot.h"
 

	
 
class MainWindow;
 

	
 
class SnapshotManager : public QObject
 
{
 
    Q_OBJECT
 

	
 
public:
 
    SnapshotManager(MainWindow* mainWindow, ChannelManager* channelMan);
 
    SnapshotManager(MainWindow* mainWindow, Stream* stream);
 
    ~SnapshotManager();
 

	
 
    QMenu* menu();
 
    QAction* takeSnapshotAction();
 

	
 
    /// Creates a dynamically allocated snapshot object but doesn't record it in snapshots list.
 
    /// @note Caller is responsible for deletion of the returned `Snapshot` object.
 
    Snapshot* makeSnapshot();
 
    Snapshot* makeSnapshot() const;
 

	
 
    bool isAllSaved(); ///< returns `true` if all snapshots are saved to a file
 

	
 
private:
 
    MainWindow* _mainWindow;
 
    ChannelManager* _channelMan;
 
    Stream* _stream;
 

	
 
    QList<Snapshot*> snapshots;
 

	
 
    QMenu _menu;
 
    QAction _takeSnapshotAction;
 
    QAction loadSnapshotAction;
 
    QAction clearAction;
 

	
 
    void addSnapshot(Snapshot* snapshot, bool update_menu=true);
 
    void updateMenu();
 

	
 
private slots:
 
    void takeSnapshot();
 
    void clearSnapshots();
 
    void deleteSnapshot(Snapshot* snapshot);
 
    void loadSnapshots();
 
    void loadSnapshotFromFile(QString fileName);
 
};
 

	
 
#endif /* SNAPSHOTMANAGER_H */
src/snapshotview.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 
  Copyright © 2018 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include "snapshotview.h"
 
#include "ui_snapshotview.h"
 

	
 
SnapshotView::SnapshotView(MainWindow* parent, Snapshot* snapshot) :
 
    QMainWindow(parent),
 
    ui(new Ui::SnapshotView),
 
    renameDialog(this),
 
    plotMenu(parent->viewSettings())
 
{
 
    _snapshot = snapshot;
 

	
 
    ui->setupUi(this);
 

	
 
    plotMan = new PlotManager(ui->plotArea, &plotMenu, snapshot->infoModel(), this);
 
    plotMan = new PlotManager(ui->plotArea, &plotMenu, snapshot, this);
 

	
 
    ui->menuSnapshot->insertAction(ui->actionClose, snapshot->deleteAction());
 
    this->setWindowTitle(snapshot->displayName());
 

	
 
    // initialize curves
 
    unsigned numOfChannels = snapshot->data.size();
 
    unsigned numOfSamples = snapshot->data[0].size();
 
    for (unsigned ci = 0; ci < numOfChannels; ci++)
 
    {
 
        plotMan->addCurve(snapshot->channelName(ci), snapshot->data[ci]);
 
    }
 
    plotMan->setNumOfSamples(numOfSamples);
 
    plotMan->setPlotWidth(numOfSamples);
 
    // unsigned numOfChannels = snapshot->data.size();
 
    // unsigned numOfSamples = snapshot->data[0].size();
 
    // for (unsigned ci = 0; ci < numOfChannels; ci++)
 
    // {
 
    //     plotMan->addCurve(snapshot->channelName(ci), snapshot->data[ci]);
 
    // }
 
    // plotMan->setNumOfSamples(numOfSamples);
 
    // plotMan->setPlotWidth(numOfSamples);
 

	
 
    renameDialog.setWindowTitle("Rename Snapshot");
 
    renameDialog.setLabelText("Enter new name:");
 
    connect(ui->actionRename, &QAction::triggered,
 
            this, &SnapshotView::showRenameDialog);
 

	
 
    connect(ui->actionSave, &QAction::triggered,
 
            this, &SnapshotView::save);
 

	
 
    // add "View" menu
 
    menuBar()->insertMenu(NULL, &plotMenu);
 
}
 

	
 
SnapshotView::~SnapshotView()
 
{
 
    for (auto curve : curves)
 
    {
 
        delete curve;
 
    }
 
    delete plotMan;
 
    delete ui;
 
}
 

	
 
void SnapshotView::closeEvent(QCloseEvent *event)
src/stream.cpp
Show inline comments
 
@@ -27,83 +27,88 @@ Stream::Stream(unsigned nc, bool x, unsi
 
    _numSamples = ns;
 
    _paused = false;
 

	
 
    // create xdata buffer
 
    _hasx = x;
 
    if (x)
 
    {
 
        xData = new RingBuffer(ns);
 
    }
 
    else
 
    {
 
        xData = new IndexBuffer(ns);
 
    }
 

	
 
    // create channels
 
    for (unsigned i = 0; i < nc; i++)
 
    {
 
        auto c = new StreamChannel(i, xData, new RingBuffer(ns), &_infoModel);
 
        channels.append(c);
 
    }
 
}
 

	
 
Stream::~Stream()
 
{
 
    // notify deletion
 
    // delete channels
 
    // TODO: notify deletion
 
    // TODO: delete channels
 
}
 

	
 
bool Stream::hasX() const
 
{
 
    return _hasx;
 
}
 

	
 
unsigned Stream::numChannels() const
 
{
 
    return channels.length();
 
}
 

	
 
unsigned Stream::numSamples() const
 
{
 
    return _numSamples;
 
}
 

	
 
const StreamChannel* Stream::channel(unsigned index) const
 
{
 
    Q_ASSERT(index < numChannels());
 
    return channels[index];
 
}
 

	
 
StreamChannel* Stream::channel(unsigned index)
 
{
 
    return const_cast<StreamChannel*>(static_cast<const Stream&>(*this).channel(index));
 
}
 

	
 
const ChannelInfoModel* Stream::infoModel() const
 
{
 
    return &_infoModel;
 
}
 

	
 
ChannelInfoModel* Stream::infoModel()
 
{
 
    return const_cast<ChannelInfoModel*>(static_cast<const Stream&>(*this).infoModel());
 
}
 

	
 
void Stream::setNumChannels(unsigned nc, bool x)
 
{
 
    unsigned oldNum = numChannels();
 
    if (oldNum == nc && x == _hasx) return;
 

	
 
    // adjust the number of channels
 
    if (nc > oldNum)
 
    {
 
        for (unsigned i = oldNum; i < nc; i++)
 
        {
 
            auto c = new StreamChannel(i, xData, new RingBuffer(_numSamples), &_infoModel);
 
            channels.append(c);
 
        }
 
    }
 
    else if (nc < oldNum)
 
    {
 
        for (unsigned i = oldNum-1; i > nc-1; i--)
 
        {
 
            delete channels.takeLast();
 
        }
 
    }
 

	
 
    // change the xdata
 
    if (x != _hasx)
src/stream.h
Show inline comments
 
@@ -38,48 +38,49 @@
 
 * Implements `Sink` class for data entry. It's expected to be
 
 * connected to a `Device` source.
 
 */
 
class Stream : public QObject, public Sink
 
{
 
    Q_OBJECT
 

	
 
public:
 
    /**
 
     * @param nc number of channels
 
     * @param x has X data input
 
     * @param ns number of samples
 
     */
 
    Stream(unsigned nc = 0, bool x = false, unsigned ns = 0);
 
    ~Stream();
 

	
 
    // implementations for `Source`
 
    virtual bool hasX() const;
 
    virtual unsigned numChannels() const;
 

	
 
    unsigned numSamples() const;
 
    const StreamChannel* channel(unsigned index) const;
 
    StreamChannel* channel(unsigned index);
 
    const ChannelInfoModel* infoModel() const;
 
    ChannelInfoModel* infoModel();
 

	
 
    /// Saves channel information
 
    void saveSettings(QSettings* settings) const;
 
    /// Load channel information
 
    void loadSettings(QSettings* settings);
 

	
 
protected:
 
    // implementations for `Sink`
 
    virtual void setNumChannels(unsigned nc, bool x);
 
    virtual void feedIn(const SamplePack& data);
 

	
 
signals:
 
    void numChannelsChanged(unsigned value);
 
    void numSamplesChanged(unsigned value);
 
    void channelAdded(const StreamChannel* chan);
 
    void channelNameChanged(unsigned channel, QString name); // TODO: does it stay?
 
    void dataAdded(); ///< emitted when data added to channel man.
 

	
 
public slots:
 
    // TODO: these won't be public
 
    // void setNumChannels(unsigned number);
 
    void setNumSamples(unsigned value);
 

	
 
    /// When paused data feed is ignored
0 comments (0 inline, 0 general)