Changeset - a035648d9d3b
[Not reviewed]
barplot
0 3 0
Hasan Yavuz Ă–ZDERYA - 8 years ago 2017-10-25 16:36:34
hy@ozderya.net
added secondary plot menu
3 files changed with 95 insertions and 12 deletions:
0 comments (0 inline, 0 general)
src/mainwindow.cpp
Show inline comments
 
@@ -14,74 +14,75 @@
 
  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>
 
#include <QTextStream>
 
#include <QMenu>
 
#include <QDesktopServices>
 
#include <QMap>
 
#include <QtDebug>
 
#include <qwt_plot.h>
 
#include <limits.h>
 
#include <cmath>
 
#include <iostream>
 

	
 
#include <plot.h>
 
#include <barplot.h>
 

	
 
#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),
 
    barPlot(&channelMan),
 
    secondaryPlot(NULL),
 
    snapshotMan(this, &channelMan),
 
    commandPanel(&serialPort),
 
    dataFormatPanel(&serialPort, &channelMan, &recorder),
 
    recordPanel(&recorder, &channelMan),
 
    updateCheckDialog(this)
 
{
 
    ui->setupUi(this);
 

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

	
 
    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());
 
    ui->menuBar->insertMenu(ui->menuHelp->menuAction(), snapshotMan.menu());
 
    ui->menuBar->insertMenu(ui->menuHelp->menuAction(), commandPanel.menu());
 

	
 
@@ -89,97 +90,98 @@ MainWindow::MainWindow(QWidget *parent) 
 
            {
 
                this->ui->tabWidget->setCurrentWidget(&commandPanel);
 
                this->ui->tabWidget->showTabs();
 
            });
 

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

	
 
    setupAboutDialog();
 

	
 
    // init view menu
 
    for (auto a : plotMan->menuActions())
 
    {
 
        ui->menuView->addAction(a);
 
    }
 

	
 
    ui->menuView->addSeparator();
 

	
 
    QMenu* tbMenu = ui->menuView->addMenu("Toolbars");
 
    tbMenu->addAction(ui->plotToolBar->toggleViewAction());
 
    tbMenu->addAction(portControl.toolBar()->toggleViewAction());
 

	
 
    // init UI signals
 

	
 
    // Secondary plot menu signals
 
    connect(ui->actionBarPlot, &QAction::triggered,
 
            this, &MainWindow::showBarPlot);
 

	
 
    // Help menu signals
 
    QObject::connect(ui->actionHelpAbout, &QAction::triggered,
 
              &aboutDialog, &QWidget::show);
 

	
 
    QObject::connect(ui->actionCheckUpdate, &QAction::triggered,
 
              &updateCheckDialog, &QWidget::show);
 

	
 
    QObject::connect(ui->actionReportBug, &QAction::triggered,
 
                     [](){QDesktopServices::openUrl(QUrl(BUG_REPORT_URL));});
 

	
 
    // File menu signals
 
    QObject::connect(ui->actionExportCsv, &QAction::triggered,
 
                     this, &MainWindow::onExportCsv);
 

	
 
    QObject::connect(ui->actionSaveSettings, &QAction::triggered,
 
                     this, &MainWindow::onSaveSettings);
 

	
 
    QObject::connect(ui->actionLoadSettings, &QAction::triggered,
 
                     this, &MainWindow::onLoadSettings);
 

	
 
    ui->actionQuit->setShortcutContext(Qt::ApplicationShortcut);
 

	
 
    QObject::connect(ui->actionQuit, &QAction::triggered,
 
                     this, &MainWindow::close);
 

	
 
    // port control signals
 
    QObject::connect(&portControl, &PortControl::portToggled,
 
                     this, &MainWindow::onPortToggled);
 

	
 
    // 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);
 

	
 
    // secondary (bar) plot signals
 
    connect(&plotControlPanel, &PlotControlPanel::yScaleChanged,
 
            &barPlot, &BarPlot::setYAxis);
 

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

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

	
 
    // init port signals
 
    QObject::connect(&(this->serialPort), SIGNAL(error(QSerialPort::SerialPortError)),
 
                     this, SLOT(onPortError(QSerialPort::SerialPortError)));
 

	
 
    // 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);
 

	
 
    QObject::connect(ui->actionPause, &QAction::triggered,
 
@@ -248,50 +250,48 @@ MainWindow::MainWindow(QWidget *parent) 
 
    QObject::connect(ui->actionDemoMode, &QAction::toggled,
 
                     this, &MainWindow::enableDemo);
 

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

	
 
    // load default settings
 
    QSettings settings("serialplot", "serialplot");
 
    loadAllSettings(&settings);
 

	
 
    // ensure command panel has 1 command if none loaded
 
    if (!commandPanel.numOfCommands())
 
    {
 
        commandPanel.newCommandAction()->trigger();
 
    }
 

	
 
    // Important: This should be after newCommandAction is triggered
 
    // (above) we don't want user to be greeted with command panel on
 
    // the very first run.
 
    connect(commandPanel.newCommandAction(), &QAction::triggered, [this]()
 
            {
 
                this->ui->tabWidget->setCurrentWidget(&commandPanel);
 
                this->ui->tabWidget->showTabs();
 
            });
 

	
 
    ui->splitter->addWidget(&barPlot);
 
}
 

	
 
MainWindow::~MainWindow()
 
{
 
    if (serialPort.isOpen())
 
    {
 
        serialPort.close();
 
    }
 

	
 
    delete plotMan;
 

	
 
    delete ui;
 
    ui = NULL; // we check if ui is deleted in messageHandler
 
}
 

	
 
void MainWindow::closeEvent(QCloseEvent * event)
 
{
 
    // save snapshots
 
    if (!snapshotMan.isAllSaved())
 
    {
 
        auto clickedButton = QMessageBox::warning(
 
            this, "Closing SerialPlot",
 
            "There are un-saved snapshots. If you close you will loose the data.",
 
            QMessageBox::Discard, QMessageBox::Cancel);
 
@@ -464,48 +464,88 @@ 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);
 
        }
 
    }
 
    else
 
    {
 
        dataFormatPanel.enableDemo(false);
 
        ui->actionDemoMode->setChecked(false);
 
    }
 
}
 

	
 
void MainWindow::showSecondary(QWidget* wid)
 
{
 
    if (secondaryPlot != NULL)
 
    {
 
        secondaryPlot->deleteLater();
 
    }
 

	
 
    secondaryPlot = wid;
 
    ui->splitter->addWidget(wid);
 
}
 

	
 
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);
 
        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);
 
    }
 
    else
 
    {
 
        Snapshot* snapshot = snapshotMan.makeSnapshot();
 
        snapshot->save(fileName);
 
        delete snapshot;
 
    }
 
}
 

	
 
PlotViewSettings MainWindow::viewSettings() const
 
{
 
    return plotMan->viewSettings();
 
}
 

	
src/mainwindow.h
Show inline comments
 
@@ -23,99 +23,106 @@
 
#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 "snapshotmanager.h"
 
#include "plotmanager.h"
 
#include "barplot.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;
 
    PlotManager* plotMan;
 
    BarPlot barPlot;
 
    QWidget* secondaryPlot;
 
    SnapshotManager snapshotMan;
 
    DataRecorder recorder;       // operated by `recordPanel`
 

	
 
    QLabel spsLabel;
 
    CommandPanel commandPanel;
 
    DataFormatPanel dataFormatPanel;
 
    RecordPanel recordPanel;
 
    PlotControlPanel plotControlPanel;
 
    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 onPortError(QSerialPort::SerialPortError error);
 

	
 
    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/mainwindow.ui
Show inline comments
 
@@ -80,116 +80,128 @@
 
         <number>4</number>
 
        </property>
 
        <property name="bottomMargin">
 
         <number>4</number>
 
        </property>
 
        <item>
 
         <widget class="QPlainTextEdit" name="ptLog">
 
          <property name="readOnly">
 
           <bool>true</bool>
 
          </property>
 
         </widget>
 
        </item>
 
       </layout>
 
      </widget>
 
     </widget>
 
    </item>
 
   </layout>
 
  </widget>
 
  <widget class="QMenuBar" name="menuBar">
 
   <property name="geometry">
 
    <rect>
 
     <x>0</x>
 
     <y>0</y>
 
     <width>653</width>
 
     <height>24</height>
 
     <height>23</height>
 
    </rect>
 
   </property>
 
   <widget class="QMenu" name="menuHelp">
 
    <property name="title">
 
     <string>&amp;Help</string>
 
    </property>
 
    <addaction name="actionDemoMode"/>
 
    <addaction name="actionReportBug"/>
 
    <addaction name="actionCheckUpdate"/>
 
    <addaction name="actionHelpAbout"/>
 
   </widget>
 
   <widget class="QMenu" name="menuFile">
 
    <property name="title">
 
     <string>&amp;File</string>
 
    </property>
 
    <addaction name="actionSaveSettings"/>
 
    <addaction name="actionLoadSettings"/>
 
    <addaction name="actionExportCsv"/>
 
    <addaction name="separator"/>
 
    <addaction name="actionQuit"/>
 
   </widget>
 
   <widget class="QMenu" name="menuView">
 
    <property name="title">
 
     <string>&amp;View</string>
 
    </property>
 
   </widget>
 
   <widget class="QMenu" name="menuSecondary">
 
    <property name="title">
 
     <string>Secondary</string>
 
    </property>
 
    <addaction name="actionBarPlot"/>
 
    <addaction name="separator"/>
 
    <addaction name="actionVertical"/>
 
    <addaction name="actionHorizontal"/>
 
   </widget>
 
   <addaction name="menuFile"/>
 
   <addaction name="menuView"/>
 
   <addaction name="menuSecondary"/>
 
   <addaction name="menuHelp"/>
 
  </widget>
 
  <widget class="QToolBar" name="plotToolBar">
 
   <property name="windowTitle">
 
    <string>Plot Toolbar</string>
 
   </property>
 
   <attribute name="toolBarArea">
 
    <enum>TopToolBarArea</enum>
 
   </attribute>
 
   <attribute name="toolBarBreak">
 
    <bool>false</bool>
 
   </attribute>
 
   <addaction name="actionPause"/>
 
   <addaction name="actionClear"/>
 
  </widget>
 
  <widget class="QStatusBar" name="statusBar"/>
 
  <action name="actionPause">
 
   <property name="checkable">
 
    <bool>true</bool>
 
   </property>
 
   <property name="checked">
 
    <bool>false</bool>
 
   </property>
 
   <property name="icon">
 
    <iconset theme="player_pause"/>
 
    <iconset theme="player_pause">
 
     <normaloff>.</normaloff>.</iconset>
 
   </property>
 
   <property name="text">
 
    <string>Pause</string>
 
   </property>
 
   <property name="toolTip">
 
    <string>Pause Plotting</string>
 
   </property>
 
   <property name="shortcut">
 
    <string>P</string>
 
   </property>
 
  </action>
 
  <action name="actionClear">
 
   <property name="icon">
 
    <iconset theme="editclear"/>
 
    <iconset theme="editclear">
 
     <normaloff>.</normaloff>.</iconset>
 
   </property>
 
   <property name="text">
 
    <string>Clear</string>
 
   </property>
 
   <property name="shortcut">
 
    <string>Ctrl+K</string>
 
   </property>
 
  </action>
 
  <action name="actionHelpAbout">
 
   <property name="text">
 
    <string>&amp;About</string>
 
   </property>
 
  </action>
 
  <action name="actionDemoMode">
 
   <property name="checkable">
 
    <bool>true</bool>
 
   </property>
 
   <property name="text">
 
    <string>&amp;Demo Mode</string>
 
   </property>
 
   <property name="toolTip">
 
    <string>Toggle Demo Mode</string>
 
   </property>
 
  </action>
 
@@ -217,37 +229,61 @@
 
    <string>Report a Bug on SerialPlot Website</string>
 
   </property>
 
  </action>
 
  <action name="actionSaveSettings">
 
   <property name="text">
 
    <string>&amp;Save Settings</string>
 
   </property>
 
   <property name="toolTip">
 
    <string>Save Settings to a File</string>
 
   </property>
 
  </action>
 
  <action name="actionLoadSettings">
 
   <property name="text">
 
    <string>&amp;Load Settings</string>
 
   </property>
 
   <property name="toolTip">
 
    <string>Load Settings from a File</string>
 
   </property>
 
  </action>
 
  <action name="actionCheckUpdate">
 
   <property name="text">
 
    <string>&amp;Check Update</string>
 
   </property>
 
  </action>
 
  <action name="actionBarPlot">
 
   <property name="checkable">
 
    <bool>true</bool>
 
   </property>
 
   <property name="text">
 
    <string>Bar Plot</string>
 
   </property>
 
  </action>
 
  <action name="actionVertical">
 
   <property name="checkable">
 
    <bool>true</bool>
 
   </property>
 
   <property name="text">
 
    <string>Vertical</string>
 
   </property>
 
  </action>
 
  <action name="actionHorizontal">
 
   <property name="checkable">
 
    <bool>true</bool>
 
   </property>
 
   <property name="text">
 
    <string>Horizontal</string>
 
   </property>
 
  </action>
 
 </widget>
 
 <layoutdefault spacing="6" margin="11"/>
 
 <customwidgets>
 
  <customwidget>
 
   <class>HidableTabWidget</class>
 
   <extends>QTabWidget</extends>
 
   <header>hidabletabwidget.h</header>
 
   <container>1</container>
 
  </customwidget>
 
 </customwidgets>
 
 <resources/>
 
 <connections/>
 
</ui>
0 comments (0 inline, 0 general)