diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -54,8 +54,10 @@ else (BUILD_QWT)
endif (QWT_USE_STATIC)
endif (BUILD_QWT)
+include(BuildQColorWidgets)
+
# includes
-include_directories("./src" ${QWT_INCLUDE_DIR})
+include_directories("./src" ${QWT_INCLUDE_DIR} ${QCW_INCLUDE_DIR})
# wrap UI and resource files
qt5_wrap_ui(UI_FILES
@@ -103,6 +105,7 @@ add_executable(${PROGRAM_NAME} WIN32
src/tooltipfilter.cpp
src/sneakylineedit.cpp
src/channelmanager.cpp
+ src/channelinfomodel.cpp
src/framebufferseries.cpp
src/numberformatbox.cpp
src/endiannessbox.cpp
@@ -122,7 +125,7 @@ add_executable(${PROGRAM_NAME} WIN32
)
# Use the Widgets module from Qt 5.
-target_link_libraries(${PROGRAM_NAME} ${QWT_LIBRARY})
+target_link_libraries(${PROGRAM_NAME} ${QWT_LIBRARY} ${QCW_LIBRARY})
qt5_use_modules(${PROGRAM_NAME} Widgets SerialPort)
if (BUILD_QWT)
diff --git a/cmake/modules/BuildQColorWidgets.cmake b/cmake/modules/BuildQColorWidgets.cmake
new file mode 100644
--- /dev/null
+++ b/cmake/modules/BuildQColorWidgets.cmake
@@ -0,0 +1,31 @@
+#
+# Copyright © 2017 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 .
+#
+
+include(ExternalProject)
+
+ExternalProject_Add(QCW
+ PREFIX qcw
+ GIT_REPOSITORY https://github.com/mbasaglia/Qt-Color-Widgets
+ PATCH_COMMAND patch -t -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/qt_5_2_moc_creation_namespace_fix.diff
+ UPDATE_COMMAND ""
+ INSTALL_COMMAND "")
+
+ExternalProject_Get_Property(QCW binary_dir source_dir)
+set(QCW_LIBRARY ${binary_dir}/libColorWidgets-qt5.a)
+set(QCW_INCLUDE_DIR ${source_dir}/include)
diff --git a/cmake/modules/BuildQwt.cmake b/cmake/modules/BuildQwt.cmake
--- a/cmake/modules/BuildQwt.cmake
+++ b/cmake/modules/BuildQwt.cmake
@@ -28,7 +28,8 @@ ExternalProject_Add(QWT
-e "s/QWT_CONFIG\\s*\\+=\\s*QwtSvg/#&/"
-e "s/QWT_CONFIG\\s*\\+=\\s*QwtOpenGL/#&/"
-e "s|QWT_INSTALL_PREFIX\\s*=.*|QWT_INSTALL_PREFIX = |"
- /qwtconfig.pri
+ /qwtconfig.pri
+ UPDATE_COMMAND ""
CONFIGURE_COMMAND qmake /qwt.pro
)
diff --git a/cmake/modules/qt_5_2_moc_creation_namespace_fix.diff b/cmake/modules/qt_5_2_moc_creation_namespace_fix.diff
new file mode 100644
--- /dev/null
+++ b/cmake/modules/qt_5_2_moc_creation_namespace_fix.diff
@@ -0,0 +1,39 @@
+diff --git a/include/color_dialog.hpp b/include/color_dialog.hpp
+index 5c7653d..895215c 100644
+--- a/include/color_dialog.hpp
++++ b/include/color_dialog.hpp
+@@ -30,6 +30,8 @@
+
+ class QAbstractButton;
+
++using namespace color_widgets;
++
+ namespace color_widgets {
+
+ class QCP_EXPORT ColorDialog : public QDialog
+diff --git a/include/color_list_widget.hpp b/include/color_list_widget.hpp
+index 282bea5..7d8e0c5 100644
+--- a/include/color_list_widget.hpp
++++ b/include/color_list_widget.hpp
+@@ -25,6 +25,8 @@
+ #include "abstract_widget_list.hpp"
+ #include "color_wheel.hpp"
+
++using namespace color_widgets;
++
+ namespace color_widgets {
+
+ class QCP_EXPORT ColorListWidget : public AbstractWidgetList
+diff --git a/include/color_selector.hpp b/include/color_selector.hpp
+index db817d5..48b374d 100644
+--- a/include/color_selector.hpp
++++ b/include/color_selector.hpp
+@@ -25,6 +25,8 @@
+ #include "color_preview.hpp"
+ #include "color_wheel.hpp"
+
++using namespace color_widgets;
++
+ namespace color_widgets {
+
+ /**
diff --git a/src/channelinfomodel.cpp b/src/channelinfomodel.cpp
new file mode 100644
--- /dev/null
+++ b/src/channelinfomodel.cpp
@@ -0,0 +1,380 @@
+/*
+ Copyright © 2017 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 .
+*/
+
+#include "channelinfomodel.h"
+#include "setting_defines.h"
+
+#define NUMOF_COLORS (32)
+
+const QColor colors[NUMOF_COLORS] =
+{
+ QColor("#ff0056"),
+ QColor("#7e2dd2"),
+ QColor("#00ae7e"),
+ QColor("#fe8900"),
+ QColor("#ff937e"),
+ QColor("#6a826c"),
+ QColor("#ff029d"),
+ QColor("#00b917"),
+ QColor("#7a4782"),
+ QColor("#85a900"),
+ QColor("#a42400"),
+ QColor("#683d3b"),
+ QColor("#bdc6ff"),
+ QColor("#263400"),
+ QColor("#bdd393"),
+ QColor("#d5ff00"),
+ QColor("#9e008e"),
+ QColor("#001544"),
+ QColor("#c28c9f"),
+ QColor("#ff74a3"),
+ QColor("#01d0ff"),
+ QColor("#004754"),
+ QColor("#e56ffe"),
+ QColor("#788231"),
+ QColor("#0e4ca1"),
+ QColor("#91d0cb"),
+ QColor("#be9970"),
+ QColor("#968ae8"),
+ QColor("#bb8800"),
+ QColor("#43002c"),
+ QColor("#deff74"),
+ QColor("#00ffc6")
+};
+
+ChannelInfoModel::ChannelInfoModel(unsigned numberOfChannels, QObject* parent) :
+ QAbstractTableModel(parent)
+{
+ _numOfChannels = 0;
+ setNumOfChannels(numberOfChannels);
+}
+
+ChannelInfoModel::ChannelInfoModel(const ChannelInfoModel& other) :
+ ChannelInfoModel(other.rowCount(), other.parent())
+{
+ for (int i = 0; i < other.rowCount(); i++)
+ {
+ setData(index(i, COLUMN_NAME),
+ other.data(other.index(i, COLUMN_NAME), Qt::EditRole),
+ Qt::EditRole);
+ setData(index(i, COLUMN_NAME),
+ other.data(other.index(i, COLUMN_NAME), Qt::ForegroundRole),
+ Qt::ForegroundRole);
+ setData(index(i, COLUMN_VISIBILITY),
+ other.data(other.index(i, COLUMN_VISIBILITY), Qt::CheckStateRole),
+ Qt::CheckStateRole);
+ }
+}
+
+ChannelInfoModel::ChannelInfoModel(const QStringList& channelNames) :
+ ChannelInfoModel(channelNames.length(), NULL)
+{
+ for (int i = 0; i < channelNames.length(); i++)
+ {
+ setData(index(i, COLUMN_NAME), channelNames[i], Qt::EditRole);
+ }
+}
+
+ChannelInfoModel::ChannelInfo::ChannelInfo(unsigned index)
+{
+ name = tr("Channel %1").arg(index + 1);
+ visibility = true;
+ color = colors[index % NUMOF_COLORS];
+}
+
+QString ChannelInfoModel::name(unsigned i)
+{
+ return infos[i].name;
+}
+
+QColor ChannelInfoModel::color(unsigned i)
+{
+ return infos[i].color;
+}
+
+bool ChannelInfoModel::isVisible(unsigned i)
+{
+ return infos[i].visibility;
+}
+
+int ChannelInfoModel::rowCount(const QModelIndex &parent) const
+{
+ return _numOfChannels;
+}
+
+int ChannelInfoModel::columnCount(const QModelIndex & parent) const
+{
+ return COLUMN_COUNT;
+}
+
+Qt::ItemFlags ChannelInfoModel::flags(const QModelIndex &index) const
+{
+ if (index.column() == COLUMN_NAME)
+ {
+ return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable;
+ }
+ else if (index.column() == COLUMN_VISIBILITY)
+ {
+ return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren | Qt::ItemIsSelectable;
+ }
+
+ return Qt::NoItemFlags;
+}
+
+QVariant ChannelInfoModel::data(const QModelIndex &index, int role) const
+{
+ // check index
+ if (index.row() >= (int) _numOfChannels || index.row() < 0)
+ {
+ return QVariant();
+ }
+
+ // get color
+ if (role == Qt::ForegroundRole)
+ {
+ return infos[index.row()].color;
+ }
+
+ // get name
+ if (index.column() == COLUMN_NAME)
+ {
+ if (role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ return QVariant(infos[index.row()].name);
+ }
+ } // get visibility
+ else if (index.column() == COLUMN_VISIBILITY)
+ {
+ if (role == Qt::CheckStateRole)
+ {
+ bool visible = infos[index.row()].visibility;
+ return visible ? Qt::Checked : Qt::Unchecked;
+ }
+ }
+
+ return QVariant();
+}
+
+QVariant ChannelInfoModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal)
+ {
+ if (role == Qt::DisplayRole)
+ {
+ if (section == COLUMN_NAME)
+ {
+ return tr("Channel");
+ }
+ else if (section == COLUMN_VISIBILITY)
+ {
+ return tr("Visible");
+ }
+ }
+ }
+ else // vertical
+ {
+ if (section < (int) _numOfChannels && role == Qt::DisplayRole)
+ {
+ return QString::number(section + 1);
+ }
+ }
+
+ return QVariant();
+}
+
+bool ChannelInfoModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ // check index
+ if (index.row() >= (int) _numOfChannels || index.row() < 0)
+ {
+ return false;
+ }
+
+ // set color
+ if (role == Qt::ForegroundRole)
+ {
+ infos[index.row()].color = value.value();
+ emit dataChanged(index, index, QVector({Qt::ForegroundRole}));
+ return true;
+ }
+
+ // set name
+ if (index.column() == COLUMN_NAME)
+ {
+ if (role == Qt::DisplayRole || role == Qt::EditRole)
+ {
+ infos[index.row()].name = value.toString();
+ emit dataChanged(index, index, QVector({role}));
+ return true;
+ }
+ } // set visibility
+ else if (index.column() == COLUMN_VISIBILITY)
+ {
+ if (role == Qt::CheckStateRole)
+ {
+ bool checked = value.toInt() == Qt::Checked;
+ infos[index.row()].visibility = checked;
+ emit dataChanged(index, index, QVector({role}));
+ return true;
+ }
+ }
+
+ // invalid index/role
+ return false;
+}
+
+void ChannelInfoModel::setNumOfChannels(unsigned number)
+{
+ if (number == _numOfChannels) return;
+
+ bool isInserting = number > _numOfChannels;
+ if (isInserting)
+ {
+ beginInsertRows(QModelIndex(), _numOfChannels, number-1);
+ }
+ else
+ {
+ beginRemoveRows(QModelIndex(), number, _numOfChannels-1);
+ }
+
+ // we create channel info but never remove channel info to
+ // remember user entered info
+ if ((int) number > infos.length())
+ {
+ for (unsigned ci = _numOfChannels; ci < number; ci++)
+ {
+ infos.append(ChannelInfo(ci));
+ }
+ }
+
+ // make sure newly available channels are visible, we don't
+ // remember visibility option intentionally so that user doesn't
+ // get confused
+ if (number > _numOfChannels)
+ {
+ for (unsigned ci = _numOfChannels; ci < number; ci++)
+ {
+ infos[ci].visibility = true;
+ }
+ }
+
+ _numOfChannels = number;
+
+ if (isInserting)
+ {
+ endInsertRows();
+ }
+ else
+ {
+ endRemoveRows();
+ }
+}
+
+void ChannelInfoModel::resetInfos()
+{
+ beginResetModel();
+ for (unsigned ci = 0; (int) ci < infos.length(); ci++)
+ {
+ infos[ci] = ChannelInfo(ci);
+ }
+ endResetModel();
+}
+
+void ChannelInfoModel::resetNames()
+{
+ beginResetModel();
+ for (unsigned ci = 0; (int) ci < infos.length(); ci++)
+ {
+ infos[ci].name = ChannelInfo(ci).name;
+ }
+ endResetModel();
+}
+
+void ChannelInfoModel::resetColors()
+{
+ beginResetModel();
+ for (unsigned ci = 0; (int) ci < infos.length(); ci++)
+ {
+ infos[ci].color = ChannelInfo(ci).color;
+ }
+ endResetModel();
+}
+
+void ChannelInfoModel::resetVisibility()
+{
+ beginResetModel();
+ for (unsigned ci = 0; (int) ci < infos.length(); ci++)
+ {
+ infos[ci].visibility = true;
+ }
+ endResetModel();
+}
+
+void ChannelInfoModel::saveSettings(QSettings* settings)
+{
+ settings->beginGroup(SettingGroup_Channels);
+ settings->beginWriteArray(SG_Channels_Channel);
+
+ // save all channel information regardless of current number of channels
+ for (unsigned ci = 0; (int) ci < infos.length(); ci++)
+ {
+ settings->setArrayIndex(ci);
+ settings->setValue(SG_Channels_Name, infos[ci].name);
+ settings->setValue(SG_Channels_Color, infos[ci].color);
+ settings->setValue(SG_Channels_Visible, infos[ci].visibility);
+ }
+
+ settings->endArray();
+ settings->endGroup();
+}
+
+void ChannelInfoModel::loadSettings(QSettings* settings)
+{
+ settings->beginGroup(SettingGroup_Channels);
+ unsigned size = settings->beginReadArray(SG_Channels_Channel);
+
+ for (unsigned ci = 0; ci < size; ci++)
+ {
+ settings->setArrayIndex(ci);
+
+ ChannelInfo chanInfo(ci);
+ chanInfo.name = settings->value(SG_Channels_Name, chanInfo.name).toString();
+ chanInfo.color = settings->value(SG_Channels_Color, chanInfo.color).value();
+ chanInfo.visibility = settings->value(SG_Channels_Visible, true).toBool();
+
+ if ((int) ci < infos.size())
+ {
+ infos[ci] = chanInfo;
+
+ if (ci < _numOfChannels)
+ {
+ auto roles = QVector({
+ Qt::DisplayRole, Qt::EditRole, Qt::ForegroundRole, Qt::CheckStateRole});
+ emit dataChanged(index(ci, 0), index(ci, COLUMN_COUNT-1), roles);
+ }
+ }
+ else
+ {
+ infos.append(chanInfo);
+ }
+ }
+
+ settings->endArray();
+ settings->endGroup();
+}
diff --git a/src/channelinfomodel.h b/src/channelinfomodel.h
new file mode 100644
--- /dev/null
+++ b/src/channelinfomodel.h
@@ -0,0 +1,91 @@
+/*
+ Copyright © 2017 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 .
+*/
+
+#ifndef CHANNELINFOMODEL_H
+#define CHANNELINFOMODEL_H
+
+#include
+#include
+#include
+#include
+
+class ChannelInfoModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ enum ChannelInfoColumn
+ {
+ COLUMN_NAME = 0,
+ COLUMN_VISIBILITY,
+ COLUMN_COUNT
+ };
+
+ explicit ChannelInfoModel(unsigned numberOfChannels, QObject *parent = 0);
+ ChannelInfoModel(const ChannelInfoModel& other);
+ explicit ChannelInfoModel(const QStringList& channelNames);
+
+ QString name (unsigned i);
+ QColor color (unsigned i);
+ bool isVisible(unsigned i);
+
+ // implemented from QAbstractItemModel
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+
+ void setNumOfChannels(unsigned number);
+ /// Stores all channel info into a `QSettings`
+ void saveSettings(QSettings* settings);
+ /// Loads all channel info from a `QSettings`.
+ void loadSettings(QSettings* settings);
+
+public slots:
+ /// reset all channel info (names, color etc.)
+ void resetInfos();
+ /// reset all channel names
+ void resetNames();
+ /// reset all channel colors
+ void resetColors();
+ /// reset visibility
+ void resetVisibility();
+
+private:
+ struct ChannelInfo
+ {
+ explicit ChannelInfo(unsigned index);
+
+ QString name;
+ bool visibility;
+ QColor color;
+ };
+
+ unsigned _numOfChannels; ///< @note this is not necessarily the length of `infos`
+
+ /**
+ * Channel info is added here but never removed so that we can
+ * remember user entered info (names, colors etc.).
+ */
+ QList infos;
+};
+
+#endif // CHANNELINFOMODEL_H
diff --git a/src/channelmanager.cpp b/src/channelmanager.cpp
--- a/src/channelmanager.cpp
+++ b/src/channelmanager.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -17,30 +17,27 @@
along with serialplot. If not, see .
*/
-#include
#include
+#include
+
#include "channelmanager.h"
#include "setting_defines.h"
ChannelManager::ChannelManager(unsigned numberOfChannels, unsigned numberOfSamples, QObject *parent) :
- QObject(parent)
+ QObject(parent),
+ _infoModel(numberOfChannels)
{
_numOfChannels = numberOfChannels;
_numOfSamples = numberOfSamples;
- QStringList channelNamesList;
-
for (unsigned int i = 0; i < numberOfChannels; i++)
{
channelBuffers.append(new FrameBuffer(numberOfSamples));
- channelNamesList << QString("Channel %1").arg(i+1);
}
- _channelNames.setStringList(channelNamesList);
-
- connect(&_channelNames, &QStringListModel::dataChanged,
- this, &ChannelManager::onChannelNameDataChange);
+ connect(&_infoModel, &ChannelInfoModel::dataChanged,
+ this, &ChannelManager::onChannelInfoChanged);
}
ChannelManager::~ChannelManager()
@@ -71,7 +68,6 @@ void ChannelManager::setNumOfChannels(un
for (unsigned int i = 0; i < number - oldNum; i++)
{
channelBuffers.append(new FrameBuffer(_numOfSamples));
- addChannelName(QString("Channel %1").arg(oldNum+i+1));
}
}
else if(number < oldNum)
@@ -80,10 +76,12 @@ void ChannelManager::setNumOfChannels(un
for (unsigned int i = oldNum-1; i > number-1; i--)
{
delete channelBuffers.takeLast();
- _channelNames.removeRow(i);
}
}
+ _numOfChannels = number;
+ _infoModel.setNumOfChannels(number);
+
emit numOfChannelsChanged(number);
}
@@ -104,39 +102,62 @@ FrameBuffer* ChannelManager::channelBuff
return channelBuffers[channel];
}
-QStringListModel* ChannelManager::channelNames()
+ChannelInfoModel* ChannelManager::infoModel()
{
- return &_channelNames;
+ return &_infoModel;
}
QString ChannelManager::channelName(unsigned channel)
{
- return _channelNames.data(_channelNames.index(channel, 0), Qt::DisplayRole).toString();
+ return _infoModel.data(_infoModel.index(channel, ChannelInfoModel::COLUMN_NAME),
+ Qt::DisplayRole).toString();
}
-void ChannelManager::setChannelName(unsigned channel, QString name)
+QStringList ChannelManager::channelNames()
{
- _channelNames.setData(_channelNames.index(channel, 0), QVariant(name), Qt::DisplayRole);
+ QStringList list;
+ for (unsigned ci = 0; ci < _numOfChannels; ci++)
+ {
+ list << channelName(ci);
+ }
+ return list;
}
-void ChannelManager::addChannelName(QString name)
+void ChannelManager::onChannelInfoChanged(const QModelIndex & topLeft,
+ const QModelIndex & bottomRight,
+ const QVector & roles)
{
- _channelNames.insertRow(_channelNames.rowCount());
- setChannelName(_channelNames.rowCount()-1, name);
-}
-
-void ChannelManager::onChannelNameDataChange(const QModelIndex & topLeft,
- const QModelIndex & bottomRight,
- const QVector & roles)
-{
- Q_UNUSED(roles);
int start = topLeft.row();
int end = bottomRight.row();
+ int col = topLeft.column();
- // TODO: maybe check `roles` parameter, can't think of a reason for current use case
- for (int i = start; i <= end; i++)
+ for (int ci = start; ci <= end; ci++)
{
- emit channelNameChanged(i, channelName(i));
+ for (auto role : roles)
+ {
+ switch (role)
+ {
+ case Qt::EditRole:
+ if (col == ChannelInfoModel::COLUMN_NAME)
+ {
+ emit channelNameChanged(ci, channelName(ci));
+ }
+ break;
+ case Qt::ForegroundRole:
+ if (col == ChannelInfoModel::COLUMN_NAME)
+ {
+ // TODO: emit channel color changed
+ }
+ break;
+ case Qt::CheckStateRole:
+ if (col == ChannelInfoModel::COLUMN_VISIBILITY)
+ {
+ // TODO: emit visibility
+ }
+ break;
+ }
+ }
+ // emit channelNameChanged(i, channelName(i));
}
}
@@ -147,26 +168,10 @@ void ChannelManager::addChannelData(unsi
void ChannelManager::saveSettings(QSettings* settings)
{
- settings->beginGroup(SettingGroup_Channels);
- settings->beginWriteArray(SG_Channels_Channel);
- for (unsigned i = 0; i < numOfChannels(); i++)
- {
- settings->setArrayIndex(i);
- settings->setValue(SG_Channels_Name, channelName(i));
- }
- settings->endArray();
- settings->endGroup();
+ _infoModel.saveSettings(settings);
}
void ChannelManager::loadSettings(QSettings* settings)
{
- settings->beginGroup(SettingGroup_Channels);
- settings->beginReadArray(SG_Channels_Channel);
- for (unsigned i = 0; i < numOfChannels(); i++)
- {
- settings->setArrayIndex(i);
- setChannelName(i, settings->value(SG_Channels_Name, channelName(i)).toString());
- }
- settings->endArray();
- settings->endGroup();
+ _infoModel.loadSettings(settings);
}
diff --git a/src/channelmanager.h b/src/channelmanager.h
--- a/src/channelmanager.h
+++ b/src/channelmanager.h
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -21,12 +21,13 @@
#define CHANNELMANAGER_H
#include
-#include
+#include
#include
#include
#include
#include "framebuffer.h"
+#include "channelinfomodel.h"
class ChannelManager : public QObject
{
@@ -38,12 +39,16 @@ public:
unsigned numOfChannels();
unsigned numOfSamples();
FrameBuffer* channelBuffer(unsigned channel);
- QStringListModel* channelNames();
+ // QStringListModel* channelNames();
QString channelName(unsigned channel);
/// Stores channel names into a `QSettings`
void saveSettings(QSettings* settings);
/// Loads channel names from a `QSettings`.
void loadSettings(QSettings* settings);
+ /// Returns a model that manages channel information (name, color etc)
+ ChannelInfoModel* infoModel();
+ /// Returns a list of channel names
+ QStringList channelNames();
signals:
void numOfChannelsChanged(unsigned value);
@@ -53,21 +58,21 @@ signals:
public slots:
void setNumOfChannels(unsigned number);
void setNumOfSamples(unsigned number);
- void setChannelName(unsigned channel, QString name);
void addChannelData(unsigned channel, double* data, unsigned size);
private:
unsigned _numOfChannels;
unsigned _numOfSamples;
QList channelBuffers;
- QStringListModel _channelNames;
+ // QStringListModel _channelNames;
+ ChannelInfoModel _infoModel;
void addChannelName(QString name); ///< appends a new channel name at the end of list
private slots:
- void onChannelNameDataChange(const QModelIndex & topLeft,
- const QModelIndex & bottomRight,
- const QVector & roles = QVector ());
+ void onChannelInfoChanged(const QModelIndex & topLeft,
+ const QModelIndex & bottomRight,
+ const QVector & roles = QVector ());
};
#endif // CHANNELMANAGER_H
diff --git a/src/main.cpp b/src/main.cpp
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2015 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -24,7 +24,6 @@
#include "tooltipfilter.h"
#include "version.h"
-
MainWindow* pMainWindow;
void messageHandler(QtMsgType type, const QMessageLogContext &context,
@@ -50,5 +49,6 @@ int main(int argc, char *argv[])
qDebug() << "Revision" << VERSION_REVISION;
w.show();
+
return a.exec();
}
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -66,7 +66,7 @@ MainWindow::MainWindow(QWidget *parent)
{
ui->setupUi(this);
- plotMan = new PlotManager(ui->plotArea);
+ plotMan = new PlotManager(ui->plotArea, channelMan.infoModel());
ui->tabWidget->insertTab(0, &portControl, "Port");
ui->tabWidget->insertTab(1, &dataFormatPanel, "Data Format");
@@ -172,7 +172,7 @@ MainWindow::MainWindow(QWidget *parent)
connect(&channelMan, &ChannelManager::channelNameChanged,
this, &MainWindow::onChannelNameChanged);
- plotControlPanel.setChannelNamesModel(channelMan.channelNames());
+ plotControlPanel.setChannelInfoModel(channelMan.infoModel());
// init curve list
for (unsigned int i = 0; i < numOfChannels; i++)
@@ -376,7 +376,7 @@ void MainWindow::onChannelNameChanged(un
// since `onNumOfChannelsChanged` slot will update curve list.
if (channel < plotMan->numOfCurves()) // check if channel exists in curve list
{
- plotMan->setTitle(channel, name);
+ // plotMan->setTitle(channel, name);
}
}
@@ -463,6 +463,11 @@ void MainWindow::messageHandler(QtMsgTyp
{
ui->statusBar->showMessage(msg, 5000);
}
+
+ if (type == QtFatalMsg)
+ {
+ __builtin_trap();
+ }
}
void MainWindow::saveAllSettings(QSettings* settings)
diff --git a/src/plot.h b/src/plot.h
--- a/src/plot.h
+++ b/src/plot.h
@@ -37,28 +37,14 @@ class Plot : public QwtPlot
{
Q_OBJECT
+ friend class PlotManager;
+
public:
Plot(QWidget* parent = 0);
~Plot();
static QColor makeColor(unsigned int channelIndex);
-private:
- bool isAutoScaled;
- double yMin, yMax;
- int symbolSize;
- Zoomer zoomer;
- ScaleZoomer sZoomer;
- QwtPlotGrid grid;
- PlotSnapshotOverlay* snapshotOverlay;
- QwtPlotLegendItem legend;
- QwtPlotTextLabel demoIndicator;
-
- /// update the display of symbols depending on `symbolSize`
- void updateSymbols();
- void resetAxes();
- void resizeEvent(QResizeEvent * event);
-
public slots:
void showGrid(bool show = true);
void showMinorGrid(bool show = true);
@@ -77,6 +63,24 @@ public slots:
void onNumOfSamplesChanged(unsigned value);
+protected:
+ /// update the display of symbols depending on `symbolSize`
+ void updateSymbols();
+
+private:
+ bool isAutoScaled;
+ double yMin, yMax;
+ int symbolSize;
+ Zoomer zoomer;
+ ScaleZoomer sZoomer;
+ QwtPlotGrid grid;
+ PlotSnapshotOverlay* snapshotOverlay;
+ QwtPlotLegendItem legend;
+ QwtPlotTextLabel demoIndicator;
+
+ void resetAxes();
+ void resizeEvent(QResizeEvent * event);
+
private slots:
void unzoomed();
void onXScaleChanged();
diff --git a/src/plotcontrolpanel.cpp b/src/plotcontrolpanel.cpp
--- a/src/plotcontrolpanel.cpp
+++ b/src/plotcontrolpanel.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -23,6 +23,7 @@
#include
+#include "color_selector.hpp"
#include "plotcontrolpanel.h"
#include "ui_plotcontrolpanel.h"
#include "setting_defines.h"
@@ -41,7 +42,12 @@ Q_DECLARE_METATYPE(Range);
PlotControlPanel::PlotControlPanel(QWidget *parent) :
QWidget(parent),
- ui(new Ui::PlotControlPanel)
+ ui(new Ui::PlotControlPanel),
+ resetAct(tr("Reset"), this),
+ resetNamesAct(tr("Reset Names"), this),
+ resetColorsAct(tr("Reset Colors"), this),
+ showAllAct(tr("Show All"), this),
+ resetMenu(tr("Reset Menu"), this)
{
ui->setupUi(this);
@@ -92,6 +98,18 @@ PlotControlPanel::PlotControlPanel(QWidg
QObject::connect(ui->cbRangePresets, SIGNAL(activated(int)),
this, SLOT(onRangeSelected()));
+
+ // color selector starts disabled until a channel is selected
+ ui->colorSelector->setColor(QColor(0,0,0,0));
+ ui->colorSelector->setDisplayMode(color_widgets::ColorPreview::AllAlpha);
+ ui->colorSelector->setDisabled(true);
+
+ // reset button
+ resetMenu.addAction(&resetNamesAct);
+ resetMenu.addAction(&resetColorsAct);
+ resetMenu.addAction(&showAllAct);
+ resetAct.setMenu(&resetMenu);
+ ui->tbReset->setDefaultAction(&resetAct);
}
PlotControlPanel::~PlotControlPanel()
@@ -204,9 +222,77 @@ void PlotControlPanel::onRangeSelected()
ui->cbAutoScale->setChecked(false);
}
-void PlotControlPanel::setChannelNamesModel(QAbstractItemModel * model)
+void PlotControlPanel::setChannelInfoModel(ChannelInfoModel* model)
{
- ui->lvChannelNames->setModel(model);
+ ui->tvChannelInfo->setModel(model);
+
+ // channel color selector
+ connect(ui->tvChannelInfo->selectionModel(), &QItemSelectionModel::currentRowChanged,
+ [this](const QModelIndex ¤t, const QModelIndex &previous)
+ {
+ // TODO: duplicate with below lambda
+ QColor color(0,0,0,0); // transparent
+
+ if (current.isValid())
+ {
+ ui->colorSelector->setEnabled(true);
+ auto model = ui->tvChannelInfo->model();
+ color = model->data(current, Qt::ForegroundRole).value();
+ }
+ else
+ {
+ ui->colorSelector->setDisabled(true);
+ }
+
+ // temporarily block signals because `setColor` emits `colorChanged`
+ bool wasBlocked = ui->colorSelector->blockSignals(true);
+ ui->colorSelector->setColor(color);
+ ui->colorSelector->blockSignals(wasBlocked);
+ });
+
+ connect(ui->tvChannelInfo->selectionModel(), &QItemSelectionModel::selectionChanged,
+ [this](const QItemSelection & selected, const QItemSelection & deselected)
+ {
+ if (!selected.length())
+ {
+ ui->colorSelector->setDisabled(true);
+
+ // temporarily block signals because `setColor` emits `colorChanged`
+ bool wasBlocked = ui->colorSelector->blockSignals(true);
+ ui->colorSelector->setColor(QColor(0,0,0,0));
+ ui->colorSelector->blockSignals(wasBlocked);
+ }
+ });
+
+ connect(ui->colorSelector, &color_widgets::ColorSelector::colorChanged,
+ [this](QColor color)
+ {
+ auto index = ui->tvChannelInfo->selectionModel()->currentIndex();
+ ui->tvChannelInfo->model()->setData(index, color, Qt::ForegroundRole);
+ });
+
+ connect(model, &QAbstractItemModel::dataChanged,
+ [this](const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector & roles = QVector ())
+ {
+ auto current = ui->tvChannelInfo->selectionModel()->currentIndex();
+
+ // no current selection
+ if (!current.isValid()) return;
+
+ auto mod = ui->tvChannelInfo->model();
+ QColor color = mod->data(current, Qt::ForegroundRole).value();
+
+ // temporarily block signals because `setColor` emits `colorChanged`
+ bool wasBlocked = ui->colorSelector->blockSignals(true);
+ ui->colorSelector->setColor(color);
+ ui->colorSelector->blockSignals(wasBlocked);
+ });
+
+ // reset actions
+ connect(&resetAct, &QAction::triggered, model, &ChannelInfoModel::resetInfos);
+ connect(&resetNamesAct, &QAction::triggered, model, &ChannelInfoModel::resetNames);
+ connect(&resetColorsAct, &QAction::triggered, model, &ChannelInfoModel::resetColors);
+ connect(&showAllAct, &QAction::triggered, model, &ChannelInfoModel::resetVisibility);
}
void PlotControlPanel::saveSettings(QSettings* settings)
diff --git a/src/plotcontrolpanel.h b/src/plotcontrolpanel.h
--- a/src/plotcontrolpanel.h
+++ b/src/plotcontrolpanel.h
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -21,8 +21,11 @@
#define PLOTCONTROLPANEL_H
#include
-#include
#include
+#include
+#include
+
+#include "channelinfomodel.h"
namespace Ui {
class PlotControlPanel;
@@ -41,7 +44,7 @@ public:
double yMax();
double yMin();
- void setChannelNamesModel(QAbstractItemModel * model);
+ void setChannelInfoModel(ChannelInfoModel* model);
/// Stores plot settings into a `QSettings`
void saveSettings(QSettings* settings);
@@ -60,6 +63,9 @@ private:
/// User can disable this setting in the checkbox
bool warnNumOfSamples;
+ QAction resetAct, resetNamesAct, resetColorsAct, showAllAct;
+ QMenu resetMenu;
+
/// Show a confirmation dialog before setting #samples to a big value
bool askNSConfirmation(int value);
diff --git a/src/plotcontrolpanel.ui b/src/plotcontrolpanel.ui
--- a/src/plotcontrolpanel.ui
+++ b/src/plotcontrolpanel.ui
@@ -15,28 +15,112 @@
-
-
-
-
-
-
- font-weight: bold;
-
-
- Channel Names:
-
-
-
- -
-
-
-
- 16777215
- 170
-
-
-
-
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 3
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 300
+ 170
+
+
+
+ QAbstractItemView::SingleSelection
+
+
+ QAbstractItemView::SelectRows
+
+
+
+ -
+
+
+ QLayout::SetMaximumSize
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 20
+ 20
+
+
+
+
+ 20
+ 20
+
+
+ tbReset
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 1
+ 20
+
+
+
+
+ -
+
+
+ Reset
+
+
+ QToolButton::MenuButtonPopup
+
+
+ Qt::NoArrow
+
+
+
+
+
+
+ tbReset
+ horizontalLayoutWidget
+ tvChannelInfo
+
-
@@ -48,7 +132,7 @@
-
- QFormLayout::AllNonFixedFieldsGrow
+ QFormLayout::FieldsStayAtSizeHint
-
@@ -159,8 +243,32 @@
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 1
+ 20
+
+
+
+
+
+
+ color_widgets::ColorSelector
+ QWidget
+
+ 1
+
+
diff --git a/src/plotmanager.cpp b/src/plotmanager.cpp
--- a/src/plotmanager.cpp
+++ b/src/plotmanager.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -18,13 +18,14 @@
*/
#include
+#include "qwt_symbol.h"
#include "plot.h"
#include "plotmanager.h"
#include "utils.h"
#include "setting_defines.h"
-PlotManager::PlotManager(QWidget* plotArea, QObject *parent) :
+PlotManager::PlotManager(QWidget* plotArea, ChannelInfoModel* infoModel, QObject *parent) :
QObject(parent),
_plotArea(plotArea),
showGridAction("&Grid", this),
@@ -38,6 +39,7 @@ PlotManager::PlotManager(QWidget* plotAr
_yMin = 0;
_yMax = 1;
isDemoShown = false;
+ _infoModel = infoModel;
// initalize layout and single widget
isMulti = false;
@@ -85,6 +87,21 @@ PlotManager::PlotManager(QWidget* plotAr
this, &PlotManager::showLegend);
connect(&showMultiAction, SELECT::OVERLOAD_OF(&QAction::triggered),
this, &PlotManager::setMulti);
+
+ // connect to channel info model
+ if (_infoModel != NULL) // TODO: remove when snapshots have 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()
@@ -103,6 +120,46 @@ PlotManager::~PlotManager()
if (scrollArea != NULL) delete scrollArea;
}
+void PlotManager::onChannelInfoChanged(const QModelIndex &topLeft,
+ const QModelIndex &bottomRight,
+ const QVector &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();
+ 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);
+ if (visible)
+ {
+ plotWidgets[ci]->replot();
+ }
+ }
+ }
+
+ // replot single widget
+ if (!isMulti)
+ {
+ plotWidgets[0]->updateSymbols();
+ plotWidgets[0]->updateLegend();
+ replot();
+ }
+}
+
void PlotManager::setMulti(bool enabled)
{
if (enabled == isMulti) return;
@@ -219,7 +276,8 @@ void PlotManager::_addCurve(QwtPlotCurve
curves.append(curve);
unsigned index = curves.size()-1;
- curve->setPen(Plot::makeColor(index));
+ auto color = _infoModel->color(index);
+ curve->setPen(color);
// create the plot for the curve if we are on multi display
Plot* plot;
diff --git a/src/plotmanager.h b/src/plotmanager.h
--- a/src/plotmanager.h
+++ b/src/plotmanager.h
@@ -1,5 +1,5 @@
/*
- Copyright © 2016 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -30,13 +30,14 @@
#include
#include "plot.h"
#include "framebufferseries.h"
+#include "channelinfomodel.h"
class PlotManager : public QObject
{
Q_OBJECT
public:
- explicit PlotManager(QWidget* plotArea, QObject *parent = 0);
+ explicit PlotManager(QWidget* plotArea, ChannelInfoModel* infoModel = NULL, QObject *parent = 0);
~PlotManager();
/// Add a new curve with title and buffer. A color is
/// automatically chosen for curve.
@@ -77,6 +78,7 @@ private:
QScrollArea* scrollArea;
QList curves;
QList plotWidgets;
+ ChannelInfoModel* _infoModel;
bool isDemoShown;
bool _autoScaled;
double _yMin;
@@ -104,6 +106,10 @@ private slots:
void showLegend(bool show = true);
void unzoom();
void darkBackground(bool enabled = true);
+
+ void onChannelInfoChanged(const QModelIndex & topLeft,
+ const QModelIndex & bottomRight,
+ const QVector & roles = QVector ());
};
#endif // PLOTMANAGER_H
diff --git a/src/setting_defines.h b/src/setting_defines.h
--- a/src/setting_defines.h
+++ b/src/setting_defines.h
@@ -70,6 +70,8 @@ const char SG_CustomFrame_DebugMode[] =
// channel manager keys
const char SG_Channels_Channel[] = "channel";
const char SG_Channels_Name[] = "name";
+const char SG_Channels_Color[] = "color";
+const char SG_Channels_Visible[] = "visible";
// plot settings keys
const char SG_Plot_NumOfSamples[] = "numOfSamples";
diff --git a/src/snapshot.cpp b/src/snapshot.cpp
--- a/src/snapshot.cpp
+++ b/src/snapshot.cpp
@@ -24,8 +24,9 @@
#include "snapshot.h"
#include "snapshotview.h"
-Snapshot::Snapshot(QMainWindow* parent, QString name) :
+Snapshot::Snapshot(QMainWindow* parent, QString name, ChannelInfoModel infoModel) :
QObject(parent),
+ cInfoModel(infoModel),
_showAction(this),
_deleteAction("&Delete", this)
{
@@ -106,14 +107,14 @@ void Snapshot::setName(QString name)
emit nameChanged(this);
}
-void Snapshot::setChannelNames(QStringList names)
+ChannelInfoModel* Snapshot::infoModel()
{
- _channelNames = names;
+ return &cInfoModel;
}
QString Snapshot::channelName(unsigned channel)
{
- return _channelNames[channel];
+ return cInfoModel.name(channel);
}
void Snapshot::save(QString fileName)
diff --git a/src/snapshot.h b/src/snapshot.h
--- a/src/snapshot.h
+++ b/src/snapshot.h
@@ -27,6 +27,8 @@
#include
#include
+#include "channelinfomodel.h"
+
class SnapshotView;
class Snapshot : public QObject
@@ -34,7 +36,7 @@ class Snapshot : public QObject
Q_OBJECT
public:
- Snapshot(QMainWindow* parent, QString name);
+ Snapshot(QMainWindow* parent, QString name, ChannelInfoModel infoModel);
~Snapshot();
QVector> data;
@@ -43,8 +45,8 @@ public:
QString name();
QString displayName(); ///< `name()` plus '*' if snapshot is not saved
+ ChannelInfoModel* infoModel();
void setName(QString name);
- void setChannelNames(QStringList names); // must be called when setting data!
QString channelName(unsigned channel);
void save(QString fileName); ///< save snapshot data as CSV
@@ -56,7 +58,7 @@ signals:
private:
QString _name;
- QStringList _channelNames;
+ ChannelInfoModel cInfoModel;
QAction _showAction;
QAction _deleteAction;
QMainWindow* mainWindow;
diff --git a/src/snapshotmanager.cpp b/src/snapshotmanager.cpp
--- a/src/snapshotmanager.cpp
+++ b/src/snapshotmanager.cpp
@@ -1,5 +1,5 @@
/*
- Copyright © 2015 Hasan Yavuz Özderya
+ Copyright © 2017 Hasan Yavuz Özderya
This file is part of serialplot.
@@ -63,7 +63,7 @@ SnapshotManager::~SnapshotManager()
Snapshot* SnapshotManager::makeSnapshot()
{
QString name = QTime::currentTime().toString("'Snapshot ['HH:mm:ss']'");
- auto snapshot = new Snapshot(_mainWindow, name);
+ auto snapshot = new Snapshot(_mainWindow, name, *(_channelMan->infoModel()));
unsigned numOfChannels = _channelMan->numOfChannels();
unsigned numOfSamples = _channelMan->numOfSamples();
@@ -76,7 +76,6 @@ Snapshot* SnapshotManager::makeSnapshot(
snapshot->data[ci][i] = QPointF(i, _channelMan->channelBuffer(ci)->sample(i));
}
}
- snapshot->setChannelNames(_channelMan->channelNames()->stringList());
return snapshot;
}
@@ -189,9 +188,11 @@ void SnapshotManager::loadSnapshotFromFi
lineNum++;
}
- auto snapshot = new Snapshot(_mainWindow, QFileInfo(fileName).baseName());
+ ChannelInfoModel channelInfo(channelNames);
+
+ auto snapshot = new Snapshot(
+ _mainWindow, QFileInfo(fileName).baseName(), ChannelInfoModel(channelNames));
snapshot->data = data;
- snapshot->setChannelNames(channelNames);
addSnapshot(snapshot, false);
}
diff --git a/src/snapshotview.cpp b/src/snapshotview.cpp
--- a/src/snapshotview.cpp
+++ b/src/snapshotview.cpp
@@ -29,7 +29,7 @@ SnapshotView::SnapshotView(QWidget *pare
ui->setupUi(this);
- plotMan = new PlotManager(ui->plotArea);
+ plotMan = new PlotManager(ui->plotArea, snapshot->infoModel());
ui->menuSnapshot->insertAction(ui->actionClose, snapshot->deleteAction());
this->setWindowTitle(snapshot->displayName());