├── appicon.ico ├── flexiplot.rc ├── images ├── graph.png ├── icon.png ├── 04_maps.png ├── Connect.png ├── list-add.png ├── piechart.ico ├── scatter.png ├── settings.png ├── Disconnect.png ├── edit-clear.png ├── help-about.png ├── kcoloredit.png ├── linechart.ico ├── document-new.png ├── document-save.png ├── transform-move.png ├── view-statistics.png ├── application-exit.png ├── document-save-as.png ├── format-text-bold.png ├── format-text-italic.png ├── system-lock-screen.png ├── utilities-terminal.png ├── window-duplicate.png ├── document-open-folder.png ├── document-open-recent.png ├── media-playback-start.png ├── media-playback-stop.png ├── format-text-underline.png └── view-split-left-right.png ├── data.qrc ├── widgets ├── abstractwidget.cpp ├── helper.h ├── plotitem.cpp ├── flexipieslice.h ├── plotitem.h ├── abstractwidget.h ├── mapper.h ├── TemplateWidget.cpp ├── flexipieslice.cpp ├── gmapwidget.h ├── helper.cpp ├── mapper.cpp ├── TemplateWidget.h ├── xychartplotitem.h ├── scatterchart.h ├── piechart.h ├── bargraph.h ├── linechart.h ├── mapper.ui ├── gmapwidget.cpp ├── xychartplotitem.cpp ├── linegraph.h ├── piechart.cpp ├── bargraph.cpp ├── plotter.ui └── linegraph.ui ├── .gitignore ├── aboutdialog.h ├── main.cpp ├── aboutdialog.cpp ├── todo.md ├── index.html ├── settings.h ├── config.h ├── debugtools.h ├── terminal.h ├── icons.qrc ├── main.js ├── config.cpp ├── FlexiPlot.pro ├── README.md ├── mainwindow.h ├── aboutdialog.ui ├── settings.cpp ├── debugtools.cpp ├── terminal.cpp ├── terminal.ui ├── debugtools.ui ├── settings.ui └── mainwindow.ui /appicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/appicon.ico -------------------------------------------------------------------------------- /flexiplot.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "appicon.ico" -------------------------------------------------------------------------------- /images/graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/graph.png -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/icon.png -------------------------------------------------------------------------------- /images/04_maps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/04_maps.png -------------------------------------------------------------------------------- /images/Connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/Connect.png -------------------------------------------------------------------------------- /images/list-add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/list-add.png -------------------------------------------------------------------------------- /images/piechart.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/piechart.ico -------------------------------------------------------------------------------- /images/scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/scatter.png -------------------------------------------------------------------------------- /images/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/settings.png -------------------------------------------------------------------------------- /images/Disconnect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/Disconnect.png -------------------------------------------------------------------------------- /images/edit-clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/edit-clear.png -------------------------------------------------------------------------------- /images/help-about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/help-about.png -------------------------------------------------------------------------------- /images/kcoloredit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/kcoloredit.png -------------------------------------------------------------------------------- /images/linechart.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/linechart.ico -------------------------------------------------------------------------------- /images/document-new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/document-new.png -------------------------------------------------------------------------------- /images/document-save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/document-save.png -------------------------------------------------------------------------------- /images/transform-move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/transform-move.png -------------------------------------------------------------------------------- /images/view-statistics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/view-statistics.png -------------------------------------------------------------------------------- /images/application-exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/application-exit.png -------------------------------------------------------------------------------- /images/document-save-as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/document-save-as.png -------------------------------------------------------------------------------- /images/format-text-bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/format-text-bold.png -------------------------------------------------------------------------------- /images/format-text-italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/format-text-italic.png -------------------------------------------------------------------------------- /images/system-lock-screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/system-lock-screen.png -------------------------------------------------------------------------------- /images/utilities-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/utilities-terminal.png -------------------------------------------------------------------------------- /images/window-duplicate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/window-duplicate.png -------------------------------------------------------------------------------- /images/document-open-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/document-open-folder.png -------------------------------------------------------------------------------- /images/document-open-recent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/document-open-recent.png -------------------------------------------------------------------------------- /images/media-playback-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/media-playback-start.png -------------------------------------------------------------------------------- /images/media-playback-stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/media-playback-stop.png -------------------------------------------------------------------------------- /images/format-text-underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/format-text-underline.png -------------------------------------------------------------------------------- /images/view-split-left-right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xcoder123/FlexiPlot/HEAD/images/view-split-left-right.png -------------------------------------------------------------------------------- /data.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | index.html 4 | main.js 5 | 6 | 7 | -------------------------------------------------------------------------------- /widgets/abstractwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "abstractwidget.h" 2 | 3 | AbstractWidget::AbstractWidget(QWidget *parent) 4 | :QWidget(parent) 5 | { 6 | } 7 | 8 | 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.user 2 | *.user 3 | SerialPlot.pro.user.15 4 | SerialPlot.pro.user 5 | *.0-pre1 6 | SerialPlot.pro.user.3.2-pre1 7 | *.15 8 | FlexiPlot.pro.user.3.2-pre1 -------------------------------------------------------------------------------- /widgets/helper.h: -------------------------------------------------------------------------------- 1 | #ifndef HELPER_H 2 | #define HELPER_H 3 | 4 | //#include "linegraph.h" 5 | #include "linechart.h" 6 | #include "bargraph.h" 7 | #include "piechart.h" 8 | #include "scatterchart.h" 9 | 10 | class Helper 11 | { 12 | public: 13 | Helper(); 14 | 15 | static bool validPacket(QString packet, int type=0); 16 | }; 17 | 18 | #endif // HELPER_H 19 | -------------------------------------------------------------------------------- /aboutdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef ABOUTDIALOG_H 2 | #define ABOUTDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class AboutDialog; 8 | } 9 | 10 | class AboutDialog : public QDialog 11 | { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit AboutDialog(QWidget *parent = 0); 16 | ~AboutDialog(); 17 | 18 | private: 19 | Ui::AboutDialog *ui; 20 | }; 21 | 22 | #endif // ABOUTDIALOG_H 23 | -------------------------------------------------------------------------------- /widgets/plotitem.cpp: -------------------------------------------------------------------------------- 1 | #include "plotitem.h" 2 | 3 | PlotItem::PlotItem(QwtPlot *plot, QString name) 4 | { 5 | curve = new QwtPlotCurve(name); 6 | 7 | curve->attach(plot); 8 | this->name = name; 9 | } 10 | 11 | void PlotItem::addData(QPointF p, QColor color) 12 | { 13 | points.push_back(p); 14 | this->color = color; 15 | } 16 | 17 | void PlotItem::deleteFirst() 18 | { 19 | points.takeFirst(); 20 | } 21 | 22 | void PlotItem::clear() 23 | { 24 | points.clear(); 25 | } 26 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "mainwindow.h" 2 | #include 3 | 4 | int main(int argc, char *argv[]) 5 | { 6 | QApplication a(argc, argv); 7 | 8 | QCoreApplication::setOrganizationName("Morf"); 9 | QCoreApplication::setOrganizationDomain("morf.lv"); 10 | QCoreApplication::setApplicationName("FlexiPlot"); 11 | 12 | MainWindow w; 13 | w.show(); 14 | 15 | if(argc > 1) 16 | w.openDash(QString::fromLatin1(argv[1])); 17 | 18 | return a.exec(); 19 | } 20 | -------------------------------------------------------------------------------- /widgets/flexipieslice.h: -------------------------------------------------------------------------------- 1 | #ifndef FLEXIPIESLICE_H 2 | #define FLEXIPIESLICE_H 3 | 4 | #include 5 | #include 6 | 7 | QT_CHARTS_USE_NAMESPACE 8 | 9 | class FlexiPieSlice : public QPieSlice 10 | { 11 | Q_OBJECT 12 | 13 | public: 14 | FlexiPieSlice(QString label, qreal value); 15 | void setExplodeOnHover(bool b) { explodeOnHover = b; } 16 | 17 | public: 18 | QBrush originalBrush(); 19 | 20 | public Q_SLOTS: 21 | void showHighlight(bool show); 22 | 23 | private: 24 | QBrush m_originalBrush; 25 | bool explodeOnHover; 26 | 27 | }; 28 | 29 | #endif // FLEXIPIESLICE_H 30 | -------------------------------------------------------------------------------- /widgets/plotitem.h: -------------------------------------------------------------------------------- 1 | #ifndef PLOTITEM_H 2 | #define PLOTITEM_H 3 | 4 | #include 5 | #include 6 | 7 | class PlotItem 8 | { 9 | public: 10 | PlotItem(QwtPlot * plot, QString name); 11 | QwtPlotCurve* getCurve() { return curve; } 12 | void addData(QPointF p, QColor color); 13 | QVector getData() { return points; } 14 | QColor getColor() { return color; } 15 | void deleteFirst(); 16 | void clear(); 17 | 18 | private: 19 | QwtPlotCurve* curve; 20 | QString name; 21 | QVector points; 22 | QColor color; 23 | }; 24 | 25 | #endif // PLOTITEM_H 26 | -------------------------------------------------------------------------------- /aboutdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "aboutdialog.h" 2 | #include "ui_aboutdialog.h" 3 | 4 | AboutDialog::AboutDialog(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::AboutDialog) 7 | { 8 | ui->setupUi(this); 9 | 10 | 11 | connect(ui->closeBtn, SIGNAL(clicked(bool)), this, SLOT(close())); 12 | 13 | 14 | ui->basedLbl->setText(QString("Based on Qt %1 ( Build Arch: %2)").arg(QT_VERSION_STR).arg(QSysInfo::buildCpuArchitecture()) ); 15 | ui->builtLbl->setText("Built on " + QString::fromLocal8Bit( __DATE__ ) + " " + QString::fromLocal8Bit(__TIME__)); 16 | } 17 | 18 | AboutDialog::~AboutDialog() 19 | { 20 | delete ui; 21 | } 22 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # TO-DO list 2 | 3 | - Scatter Plot (done) 4 | - Scatter Plot show/hide series 5 | - Line Chart logarithmic axis 6 | - Instructions with Qt Help Assistent 7 | - Languages 8 | - Arduino Library 9 | - Map Widget 10 | - Temperature widget 11 | - Speed-o-meter type widget 12 | - Data Table 13 | - Save dashboard picture 14 | - Save widget picture 15 | - "Are you sure dialog" when closing widget 16 | - Multiple serial ports??? (maybe) 17 | - Line Chart add a margin to calculated range 18 | - Forbid entering whitespace for widget IDs **(Important)** 19 | 20 | ## Future improvements 21 | - Timestamp in Line Charts with QtCharts module (currently impossible, due to Qt limitations) 22 | 23 | -------------------------------------------------------------------------------- /widgets/abstractwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef ABSTRACTWIDGET_H 2 | #define ABSTRACTWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | class AbstractWidget : public QWidget 9 | { 10 | public: 11 | AbstractWidget(QWidget *parent); 12 | virtual void reset() = 0; 13 | virtual void serialPacket(QStringList packet) = 0; 14 | virtual QString getId() = 0; 15 | 16 | virtual int type() const = 0; 17 | 18 | virtual void xmlStream(QXmlStreamWriter *writer) = 0; 19 | virtual void xmlParse(QXmlStreamReader* xml) = 0; 20 | 21 | 22 | public slots: 23 | virtual void setId(QString str) = 0; 24 | 25 | }; 26 | 27 | #endif // ABSTRACTWIDGET_H 28 | -------------------------------------------------------------------------------- /widgets/mapper.h: -------------------------------------------------------------------------------- 1 | #ifndef MAPPER_H 2 | #define MAPPER_H 3 | 4 | #include 5 | #include "abstractwidget.h" 6 | #include "config.h" 7 | 8 | 9 | namespace Ui { 10 | class Mapper; 11 | } 12 | 13 | class Mapper : public AbstractWidget 14 | { 15 | Q_OBJECT 16 | 17 | public: 18 | explicit Mapper(QWidget *parent = 0); 19 | ~Mapper(); 20 | 21 | void reset(); 22 | void serialPacket(QStringList packet); 23 | QString getId(); 24 | 25 | void xmlStream(QXmlStreamWriter *writer); 26 | void xmlParse(QXmlStreamReader* xml); 27 | 28 | public slots: 29 | void setId(QString str); 30 | 31 | private: 32 | Ui::Mapper *ui; 33 | 34 | QString id; 35 | }; 36 | 37 | #endif // MAPPER_H 38 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /widgets/TemplateWidget.cpp: -------------------------------------------------------------------------------- 1 | #include "templatewidget.h" 2 | 3 | TemplateWidget::TemplateWidget(QWidget *parent) : 4 | AbstractWidget(parent) 5 | { 6 | } 7 | 8 | bool TemplateWidget::validPacket(QString packet) 9 | { 10 | return true; 11 | } 12 | 13 | void TemplateWidget::reset() 14 | { 15 | 16 | } 17 | 18 | void TemplateWidget::serialPacket(QStringList packet) 19 | { 20 | 21 | } 22 | 23 | void TemplateWidget::xmlStream(QXmlStreamWriter *writer) 24 | { 25 | 26 | } 27 | 28 | void TemplateWidget::xmlParse(QXmlStreamReader *xml) 29 | { 30 | 31 | } 32 | 33 | void TemplateWidget::setId(QString str) 34 | { 35 | id = str; 36 | } 37 | 38 | void TemplateWidget::setTitle(QString str) 39 | { 40 | 41 | } 42 | 43 | 44 | TemplateWidget::~TemplateWidget() 45 | { 46 | delete ui; 47 | } 48 | -------------------------------------------------------------------------------- /settings.h: -------------------------------------------------------------------------------- 1 | #ifndef SETTINGS_H 2 | #define SETTINGS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | namespace Ui { 13 | class Settings; 14 | } 15 | 16 | class Settings : public QDialog 17 | { 18 | Q_OBJECT 19 | 20 | public: 21 | explicit Settings(QWidget *parent = 0); 22 | ~Settings(); 23 | 24 | 25 | signals: 26 | void settingsChanged(); 27 | 28 | private slots: 29 | void loadSettings(); 30 | void saveSettings(); 31 | void backgroundColor(); 32 | 33 | 34 | private: 35 | Ui::Settings *ui; 36 | 37 | QColor currentBackgroundColor; 38 | }; 39 | 40 | #endif // SETTINGS_H 41 | -------------------------------------------------------------------------------- /widgets/flexipieslice.cpp: -------------------------------------------------------------------------------- 1 | #include "flexipieslice.h" 2 | 3 | 4 | QT_CHARTS_USE_NAMESPACE 5 | 6 | FlexiPieSlice::FlexiPieSlice(QString label, qreal value) 7 | : QPieSlice(label, value) 8 | { 9 | connect(this, SIGNAL(hovered(bool)), this, SLOT(showHighlight(bool))); 10 | } 11 | 12 | QBrush FlexiPieSlice::originalBrush() 13 | { 14 | return m_originalBrush; 15 | } 16 | 17 | void FlexiPieSlice::showHighlight(bool show) 18 | { 19 | if (show) { 20 | QBrush brush = this->brush(); 21 | m_originalBrush = brush; 22 | brush.setColor(brush.color().lighter()); 23 | setBrush(brush); 24 | if(explodeOnHover) 25 | setExploded(true); 26 | } else { 27 | setBrush(m_originalBrush); 28 | if(explodeOnHover) 29 | setExploded(false); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | 13 | class Config : public QObject 14 | { 15 | Q_OBJECT 16 | public: 17 | static Config* getInstance(); 18 | void destroyInstance(); 19 | 20 | bool getUnsavedChanges(); 21 | void setUnsavedChanges(bool bb); 22 | 23 | void setCurrentOpenedFile(QString file) { currentOpenedFile = file; } 24 | QString getCurrentOpenedFile() { return currentOpenedFile; } 25 | 26 | signals: 27 | void savedStatusChanged(bool); 28 | 29 | private: 30 | Config(); 31 | static Config* m_pInstance; 32 | bool unsavedChanges; 33 | QReadWriteLock saveChangesMutex; 34 | QString currentOpenedFile; 35 | }; 36 | 37 | #endif // CONFIG_H 38 | -------------------------------------------------------------------------------- /debugtools.h: -------------------------------------------------------------------------------- 1 | #ifndef DEBUGTOOLS_H 2 | #define DEBUGTOOLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace Ui { 11 | class DebugTools; 12 | } 13 | 14 | class DebugTools : public QDialog 15 | { 16 | Q_OBJECT 17 | 18 | public: 19 | explicit DebugTools(QWidget *parent = 0); 20 | ~DebugTools(); 21 | 22 | private: 23 | void saveHistory(); 24 | void loadHistory(); 25 | 26 | private slots: 27 | void sendPacket(); 28 | void sentHistoryListItemDoubleClicked(); 29 | void sentHistoryListItemClicked(); 30 | void clear(); 31 | 32 | void exampleItemSelected(); 33 | 34 | protected: 35 | bool eventFilter(QObject *obj, QEvent *e); 36 | 37 | signals: 38 | void packetSent(QByteArray packet); 39 | 40 | private: 41 | Ui::DebugTools *ui; 42 | }; 43 | 44 | #endif // DEBUGTOOLS_H 45 | -------------------------------------------------------------------------------- /widgets/gmapwidget.h: -------------------------------------------------------------------------------- 1 | #ifndef GMAPWIDGET_H 2 | #define GMAPWIDGET_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class GMapWidget : public QWebView 12 | { 13 | Q_OBJECT 14 | public: 15 | explicit GMapWidget(QWidget *parent = 0); 16 | 17 | public slots: 18 | void addMarker(float lat, float lng, QString name); 19 | 20 | void setGMapCenter(const QString &location); 21 | void setGMapCenter(const QPointF &pos); 22 | void setGMapCenter(qreal lat, qreal lng); 23 | 24 | void setGMapZoom(int zoomLevel); 25 | 26 | void loadMap(); 27 | 28 | private slots: 29 | void slotNetworkReply(QNetworkReply *reply); 30 | void slotLoadFinished(bool ok); 31 | 32 | private: 33 | void runScript(const QString &script); 34 | 35 | private: 36 | QNetworkAccessManager *m_accessManager; 37 | bool m_initMap; 38 | }; 39 | 40 | #endif // GMAPWIDGET_H 41 | -------------------------------------------------------------------------------- /widgets/helper.cpp: -------------------------------------------------------------------------------- 1 | #include "helper.h" 2 | 3 | Helper::Helper() 4 | { 5 | 6 | } 7 | 8 | bool Helper::validPacket(QString packet, int type) 9 | { 10 | if(packet.isEmpty()) 11 | return false; 12 | 13 | if(type == 0) //check for any object 14 | { 15 | return LineChart::validPacket(packet) || BarGraph::validPacket(packet) || PieChart::validPacket(packet) 16 | || ScatterChart::validPacket(packet); 17 | } 18 | else 19 | { 20 | bool packetValid = false; 21 | switch(type) { 22 | case LineChart::Type: packetValid = LineChart::validPacket(packet); break; 23 | case BarGraph::Type: packetValid = BarGraph::validPacket(packet); break; 24 | case PieChart::Type: packetValid = PieChart::validPacket(packet); break; 25 | case ScatterChart::Type: packetValid = ScatterChart::validPacket(packet); break; 26 | default: packetValid = false; 27 | } 28 | 29 | return packetValid; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /terminal.h: -------------------------------------------------------------------------------- 1 | #ifndef TERMINAL_H 2 | #define TERMINAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include "widgets/helper.h" 17 | 18 | namespace Ui { 19 | class Terminal; 20 | } 21 | 22 | class Terminal : public QDialog 23 | { 24 | Q_OBJECT 25 | 26 | public: 27 | explicit Terminal(QWidget *parent = 0); 28 | ~Terminal(); 29 | 30 | enum DataFinalizeType { NO_LINE_END, NL_END, CR_END, BOTH_NL_CR_END }; 31 | 32 | void appendOutput(QByteArray data); 33 | void appendOutput(QString data); 34 | 35 | private: 36 | void saveHistory(); 37 | void loadHistory(); 38 | 39 | private slots: 40 | void sendInput(); 41 | void sentCmdListItemClicked(); 42 | void sentCmdListItemDoubleClicked(); 43 | void clear(); 44 | 45 | protected: 46 | bool eventFilter(QObject *obj, QEvent *e); 47 | 48 | signals: 49 | void writeToSerial(QByteArray data); 50 | 51 | private: 52 | Ui::Terminal *ui; 53 | }; 54 | 55 | #endif // TERMINAL_H 56 | -------------------------------------------------------------------------------- /widgets/mapper.cpp: -------------------------------------------------------------------------------- 1 | #include "mapper.h" 2 | #include "ui_mapper.h" 3 | 4 | Mapper::Mapper(QWidget *parent) : 5 | AbstractWidget(parent), 6 | ui(new Ui::Mapper) 7 | { 8 | ui->setupUi(this); 9 | 10 | connect(ui->locEdit, SIGNAL(textEdited(QString)), ui->mapWidget, SLOT(setGMapCenter(QString))); 11 | } 12 | 13 | void Mapper::reset() 14 | { 15 | 16 | } 17 | 18 | void Mapper::serialPacket(QStringList packet) 19 | { 20 | 21 | } 22 | 23 | QString Mapper::getId() 24 | { 25 | return id; 26 | } 27 | 28 | void Mapper::xmlParse(QXmlStreamReader *xml) 29 | { 30 | 31 | } 32 | 33 | void Mapper::xmlStream(QXmlStreamWriter *writer) 34 | { 35 | 36 | } 37 | 38 | void Mapper::setId(QString str) 39 | { 40 | id = str; 41 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg("Sample map plot").arg(str)); 42 | // this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(ui->titleEdit->text()).arg(str)); 43 | 44 | // ui->idEdit->blockSignals(true); 45 | // ui->idEdit->setText( str ); 46 | // ui->idEdit->blockSignals(false); 47 | 48 | Config::getInstance()->setUnsavedChanges(true); 49 | } 50 | 51 | Mapper::~Mapper() 52 | { 53 | delete ui; 54 | } 55 | -------------------------------------------------------------------------------- /widgets/TemplateWidget.h: -------------------------------------------------------------------------------- 1 | #ifndef TEMPLATEWIDGET_H 2 | #define TEMPLATEWIDGET_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | 23 | #include "plotitem.h" 24 | #include "config.h" 25 | #include "abstractwidget.h" 26 | 27 | namespace Ui { 28 | class TemplateWidget; 29 | } 30 | 31 | class TemplateWidget : public AbstractWidget 32 | { 33 | Q_OBJECT 34 | 35 | public: 36 | enum {Type = 3 /* must be unique */ }; 37 | 38 | int type() const 39 | { 40 | return Type; 41 | } 42 | 43 | explicit TemplateWidget(QWidget *parent = 0); 44 | ~TemplateWidget(); 45 | 46 | void serialPacket(QStringList packet); 47 | QString getId() { return id; } 48 | 49 | void reset(); 50 | void xmlStream(QXmlStreamWriter *writer); 51 | void xmlParse(QXmlStreamReader* xml); 52 | 53 | static bool validPacket(QString packet); 54 | 55 | public slots: 56 | void setId(QString str); 57 | void setTitle(QString str); 58 | 59 | private: 60 | QString id; 61 | }; 62 | 63 | #endif // TEMPLATEWIDGET_H 64 | -------------------------------------------------------------------------------- /widgets/xychartplotitem.h: -------------------------------------------------------------------------------- 1 | #ifndef XYCHARTPLOTITEM_H 2 | #define XYCHARTPLOTITEM_H 3 | 4 | #include 5 | #include 6 | 7 | struct xy_items_max_min_values_t { 8 | QPointF maxValues; 9 | QPointF minValues; 10 | }; 11 | 12 | class XYChartPlotItem 13 | { 14 | public: 15 | enum UpdateType { 16 | UPDATE_MANUAL, //Points are passed to series only when update() method is invoked 17 | UPDATE_INSTANTLY //Points are instantly passed to the series 18 | }; 19 | 20 | public: 21 | XYChartPlotItem(QXYSeries *m_series, QString name, UpdateType updateType = UPDATE_MANUAL); 22 | 23 | void addData(QPointF p); 24 | QVector getData() { return points; } 25 | 26 | void setColor(QColor color); 27 | QColor getColor() { return color; } 28 | bool isColorSet() { return colorIsSet; } 29 | 30 | void deleteFirst(); 31 | void clear(); 32 | 33 | QXYSeries *series() { return m_series; } 34 | 35 | QPointF maxValues(); 36 | QPointF minValues(); 37 | 38 | void setSamplingSize(int size) { m_samplingSize = size; } 39 | int samplingSize() { return m_samplingSize; } 40 | 41 | void update(); 42 | 43 | static xy_items_max_min_values_t getMaxMinValues(QHash items); 44 | 45 | private: 46 | QString name; 47 | QVector points; 48 | QColor color; 49 | QXYSeries *m_series; 50 | 51 | bool colorIsSet; 52 | 53 | int m_samplingSize; 54 | 55 | UpdateType updateType; 56 | 57 | 58 | }; 59 | 60 | #endif // XYCHARTPLOTITEM_H 61 | -------------------------------------------------------------------------------- /icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/icon.png 4 | images/media-playback-start.png 5 | images/media-playback-stop.png 6 | images/Connect.png 7 | images/Disconnect.png 8 | images/settings.png 9 | images/application-exit.png 10 | images/help-about.png 11 | images/list-add.png 12 | images/document-open-folder.png 13 | images/document-save.png 14 | images/document-save-as.png 15 | images/document-new.png 16 | images/kcoloredit.png 17 | images/view-split-left-right.png 18 | images/window-duplicate.png 19 | images/04_maps.png 20 | images/graph.png 21 | images/utilities-terminal.png 22 | images/view-statistics.png 23 | images/transform-move.png 24 | images/system-lock-screen.png 25 | images/format-text-bold.png 26 | images/format-text-italic.png 27 | images/format-text-underline.png 28 | images/piechart.ico 29 | images/linechart.ico 30 | appicon.ico 31 | images/edit-clear.png 32 | images/document-open-recent.png 33 | images/scatter.png 34 | 35 | 36 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | // main var 2 | var map; 3 | var markers = []; 4 | var infowindow = new google.maps.InfoWindow({}); 5 | 6 | // main init function 7 | function initialize() { 8 | var myOptions = { 9 | center:new google.maps.LatLng(51.508742,-0.120850), 10 | zoom: 12, 11 | mapTypeId: google.maps.MapTypeId.ROADMAP 12 | }; 13 | 14 | map = new google.maps.Map(document.getElementById("map_canvas"), myOptions); 15 | 16 | newMarker(37.09024, -95.712891, 'trialhead0'); 17 | } 18 | 19 | // custom functions 20 | function setGMapCenter(lat, lng) 21 | { 22 | map.setCenter(new google.maps.LatLng(lat, lng)); 23 | } 24 | 25 | function setGMapZoom(zoom) 26 | { 27 | map.setZoom(zoom); 28 | } 29 | 30 | 31 | function newMarker(_lat, _lng, _name) 32 | { 33 | var lat = parseFloat(_lat ); 34 | var lng = parseFloat( _lng ); 35 | var name = _name; 36 | 37 | var myLatlng = new google.maps.LatLng(lat, lng); 38 | 39 | var contentString = "

" + name + "

"; 40 | 41 | var marker = new google.maps.Marker({ 42 | position: myLatlng, 43 | map: map, 44 | title: "Coordinates: " + lat + " , " + lng + " | Name: " + name 45 | }); 46 | 47 | marker['infowindow'] = contentString; 48 | 49 | markers.push( marker ); 50 | //marker.setMap(map); 51 | 52 | 53 | google.maps.event.addListener(marker, 'click', function() { 54 | infowindow.setContent(this['infowindow']); 55 | infowindow.open(map, this); 56 | }); 57 | } 58 | -------------------------------------------------------------------------------- /config.cpp: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | Config* Config::m_pInstance = NULL; 4 | 5 | /********************************************************************************/ 6 | /* Config::Config() */ 7 | /********************************************************************************/ 8 | Config::Config() 9 | { 10 | unsavedChanges = false; 11 | currentOpenedFile.clear(); 12 | } 13 | 14 | 15 | void Config::setUnsavedChanges(bool bb) 16 | { 17 | saveChangesMutex.lockForWrite(); 18 | unsavedChanges = bb; 19 | emit savedStatusChanged(bb); 20 | saveChangesMutex.unlock(); 21 | } 22 | 23 | bool Config::getUnsavedChanges() 24 | { 25 | saveChangesMutex.lockForRead(); 26 | bool res = unsavedChanges; 27 | saveChangesMutex.unlock(); 28 | return res; 29 | } 30 | 31 | 32 | /********************************************************************************/ 33 | /* Config* Config::getInstance() */ 34 | /********************************************************************************/ 35 | Config* Config::getInstance() 36 | { 37 | if(NULL== m_pInstance ) 38 | { 39 | m_pInstance = new Config(); 40 | } 41 | return m_pInstance; 42 | } 43 | 44 | /********************************************************************************/ 45 | /* void Config::destroyInstance() */ 46 | /********************************************************************************/ 47 | void Config::destroyInstance() 48 | { 49 | delete m_pInstance; 50 | m_pInstance = NULL; 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /FlexiPlot.pro: -------------------------------------------------------------------------------- 1 | #------------------------------------------------- 2 | # 3 | # Project created by QtCreator 2013-10-14T22:48:52 4 | # 5 | #------------------------------------------------- 6 | 7 | QT += core gui serialport printsupport charts opengl 8 | #CONFIG += qwt 9 | 10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 11 | 12 | TARGET = FlexiPlot 13 | TEMPLATE = app 14 | 15 | RC_FILE = flexiplot.rc 16 | 17 | 18 | SOURCES += main.cpp\ 19 | mainwindow.cpp \ 20 | # widgets/plotitem.cpp \ 21 | settings.cpp \ 22 | config.cpp \ 23 | #gmapwidget.cpp \ 24 | #mapper.cpp \ 25 | widgets/abstractwidget.cpp \ 26 | terminal.cpp \ 27 | widgets/bargraph.cpp \ 28 | # widgets/linegraph.cpp \ 29 | debugtools.cpp \ 30 | widgets/helper.cpp \ 31 | widgets/piechart.cpp \ 32 | widgets/flexipieslice.cpp \ 33 | aboutdialog.cpp \ 34 | widgets/linechart.cpp \ 35 | widgets/scatterchart.cpp \ 36 | widgets/xychartplotitem.cpp 37 | 38 | HEADERS += mainwindow.h \ 39 | # widgets/plotitem.h \ 40 | settings.h \ 41 | config.h \ 42 | #gmapwidget.h \ 43 | #mapper.h \ 44 | widgets/abstractwidget.h \ 45 | terminal.h \ 46 | widgets/bargraph.h \ 47 | # widgets/linegraph.h \ 48 | debugtools.h \ 49 | widgets/helper.h \ 50 | widgets/piechart.h \ 51 | widgets/flexipieslice.h \ 52 | aboutdialog.h \ 53 | widgets/linechart.h \ 54 | widgets/scatterchart.h \ 55 | widgets/xychartplotitem.h 56 | 57 | FORMS += mainwindow.ui \ 58 | settings.ui \ 59 | widgets/mapper.ui \ 60 | terminal.ui \ 61 | widgets/bargraph.ui \ 62 | # widgets/linegraph.ui \ 63 | debugtools.ui \ 64 | widgets/piechart.ui \ 65 | aboutdialog.ui \ 66 | widgets/linechart.ui \ 67 | widgets/scatterchart.ui 68 | 69 | RESOURCES += \ 70 | icons.qrc \ 71 | data.qrc 72 | -------------------------------------------------------------------------------- /widgets/scatterchart.h: -------------------------------------------------------------------------------- 1 | #ifndef SCATTERCHART_H 2 | #define SCATTERCHART_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "config.h" 23 | #include "abstractwidget.h" 24 | #include "xychartplotitem.h" 25 | 26 | namespace Ui { 27 | class ScatterChart; 28 | } 29 | 30 | class ScatterChart : public AbstractWidget 31 | { 32 | Q_OBJECT 33 | 34 | public: 35 | enum LegendPosition {POS_TOP, POS_RIGHT, POS_BOTTOM, POS_LEFT, POS_DETACHED }; 36 | 37 | enum {Type = 4 /* must be unique */ }; 38 | 39 | int type() const 40 | { 41 | return Type; 42 | } 43 | 44 | explicit ScatterChart(QWidget *parent = 0); 45 | ~ScatterChart(); 46 | 47 | void serialPacket(QStringList packet); 48 | QString getId() { return id; } 49 | 50 | void reset(); 51 | void xmlStream(QXmlStreamWriter *writer); 52 | void xmlParse(QXmlStreamReader* xml); 53 | 54 | static bool validPacket(QString packet); 55 | 56 | public slots: 57 | void setId(QString str); 58 | void setTitle(QString str); 59 | void settingsChanged(); 60 | void markerPropertiesChanged(); 61 | void samplingSizeChanged(int value); 62 | void openGlStateChanged(); 63 | 64 | void plot(); 65 | void clear(); 66 | 67 | void savePlot(); 68 | void startStopPlotting(); 69 | 70 | private: 71 | void checkIfAnimationsAllowed(); 72 | void updateDetachedLegendLayout(); 73 | void blockAllSignals(bool b); 74 | 75 | 76 | private: 77 | Ui::ScatterChart *ui; 78 | QString id; 79 | 80 | QChart *chart; 81 | QHash items; 82 | bool doPlotting; 83 | }; 84 | 85 | #endif // SCATTERCHART_H 86 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlexiPlot 2 | 3 | Simple Qt based plotting tool for micro-controllers 4 | 5 | ## Sending Data to FlexiPlot 6 | 7 | ### Line chart 8 | 9 | Sample data sent from uC to FlexiPlot 10 | Basically, it will send a real time update of two separate data points to flexi for plotting on the same plane with ID "P0" 11 | 12 | ``` 13 | {P0|Roll|255,0,0|25|Pitch|0,255,0|56} 14 | ``` 15 | 16 | Note a packet consists of 17 | -ID of plot 18 | -Name of real time value (Roll) 19 | -Color in RGB format (Red) 20 | -Value (25) 21 | 22 | -Name of real time value 23 | -Color in RGB format 24 | -Value 25 | 26 | And you can repeat this pattern as much as you like. 27 | 28 | It also supports XY plane plotting. A sample packet for plotting quadratic: 29 | 30 | ``` 31 | {P3|Quadratic|255,0,0|-5 25 -4 16 -3 9 -2 4 -1 1 0 0 1 1 2 4 3 9 4 16 5 25} 32 | ``` 33 | 34 | ### Bar Graphs 35 | 36 | An example packet for plotting to a bar graph: 37 | Plotting with automatic color assignment 38 | ``` 39 | {P0|Jan;Feb;Mar|Jane|25 15 17|John|8 9 23} 40 | ``` 41 | 42 | P0 = ID of plot 43 | Jan;Feb:Mar = Are the columns for bar graph 44 | Jane = Is the set name for bar graph, every set expects as many values as columns 45 | 25 15 17 = Values for Jane for columsn Jan, Feb and Mar. 46 | John= Is the set name for bar graph, every set expects as many values as columns 47 | 8 9 23 = Values for John for columsn Jan, Feb and Mar. 48 | 49 | If you want to use custom set of colors, you can just specify them in the packet: 50 | ``` 51 | {P0|Jan;Feb;Mar|Jane|255,0,0|25 15 17|John|0,255,0|8 9 23} 52 | ``` 53 | 54 | 55 | # Screenshots 56 | ![image](https://cloud.githubusercontent.com/assets/7244389/24077133/c701fb1a-0c3b-11e7-8512-a02337c34b30.png) 57 | ![image](https://cloud.githubusercontent.com/assets/7244389/24076638/d2f9edaa-0c2d-11e7-811f-6b93956c5f48.png) 58 | ![image](https://cloud.githubusercontent.com/assets/7244389/24076772/1805ef0e-0c31-11e7-9859-1a62b90e2288.png) 59 | ![image](https://cloud.githubusercontent.com/assets/7244389/6420839/bc6029c6-bec1-11e4-81fd-333fa1047a5d.png) 60 | -------------------------------------------------------------------------------- /widgets/piechart.h: -------------------------------------------------------------------------------- 1 | #ifndef PIECHART_H 2 | #define PIECHART_H 3 | 4 | /*! 5 | * Packets: 6 | * {P0|Slice 1|255,0,0|value1|Slice 2|0,255,0|value2|Slice 3|0,0,255|value3} 7 | * Example: {P0|Slice 1|255,0,0|10|Slice 2|0,255,0|30|Slice 3|0,0,255|20} 8 | * 9 | * 10 | * Colors should be optional, if no color is specified for set, let QtCharts handle it. 11 | * {P0|Slice 1|value1|Slice 2|value2|Slice 3|value3} 12 | * Example: {P0|Slice 1|10|Slice 2|30|Slice 3|20} 13 | * 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | 35 | 36 | #include "flexipieslice.h" 37 | 38 | #include "config.h" 39 | #include "abstractwidget.h" 40 | 41 | namespace Ui { 42 | class PieChart; 43 | } 44 | 45 | struct pie_chart_plot_item_t { 46 | qreal value; 47 | QString name; 48 | QColor color; 49 | bool colorIsSet; 50 | }; 51 | 52 | class PieChart : public AbstractWidget 53 | { 54 | Q_OBJECT 55 | 56 | public: 57 | enum {Type = 3 }; 58 | 59 | int type() const 60 | { 61 | return Type; 62 | } 63 | 64 | enum LegendPosition {POS_TOP, POS_RIGHT, POS_BOTTOM, POS_LEFT, POS_DETACHED }; 65 | 66 | explicit PieChart(QWidget *parent = 0); 67 | ~PieChart(); 68 | 69 | void serialPacket(QStringList packet); 70 | QString getId() { return id; } 71 | 72 | void reset(); 73 | void xmlStream(QXmlStreamWriter *writer); 74 | void xmlParse(QXmlStreamReader* xml); 75 | 76 | static bool validPacket(QString packet); 77 | 78 | 79 | public slots: 80 | void setId(QString str); 81 | void setTitle(QString str); 82 | void settingsChanged(); 83 | 84 | void plot(); 85 | 86 | private: 87 | void updateDetachedLegendLayout(); 88 | void blockAllSignals(bool block); 89 | 90 | private: 91 | Ui::PieChart *ui; 92 | QString id; 93 | 94 | QList items; 95 | 96 | QChart *chart; 97 | }; 98 | 99 | #endif // PIECHART_H 100 | -------------------------------------------------------------------------------- /widgets/bargraph.h: -------------------------------------------------------------------------------- 1 | #ifndef BARGRAPH_H 2 | #define BARGRAPH_H 3 | 4 | /*! 5 | * Packets: 6 | * {P0|Column 1;Column 2;Column 3|Set Name 1|255,0,0|val_col1 val_col2 val_col3|Set Name 2|255,0,0|val_col1 val_col2 val_col3} 7 | * Example: {P0|Jan;Feb;Mar|Jane|255,0,0|25 15 17|John|255,0,0|8 9 23} 8 | * 9 | * 10 | * Colors should be optional, if no color is specified for set, let QtCharts handle it. 11 | * {P0|Column 1;Column 2;Column 3|Set Name|val1 val2 val3 val4} 12 | * 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | 25 | #include 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | #include "config.h" 35 | #include "abstractwidget.h" 36 | 37 | namespace Ui { 38 | class BarGraph; 39 | } 40 | 41 | struct bar_graph_plot_item_t { 42 | QList values; 43 | QString set_name; 44 | QColor color; 45 | bool colorIsSet; 46 | }; 47 | 48 | class BarGraph : public AbstractWidget 49 | { 50 | Q_OBJECT 51 | 52 | public: 53 | enum { Type = 2 }; 54 | int type() const 55 | { 56 | return Type; 57 | } 58 | 59 | enum BarChartType {TYPE_NORMAL, TYPE_STACKED, TYPE_PERCENT, TYPE_HORIZONTAL, TYPE_HORIZONTAL_STACKED, TYPE_HORIZONTAL_PERCENT }; 60 | enum LegendPosition {POS_TOP, POS_RIGHT, POS_BOTTOM, POS_LEFT, POS_DETACHED }; 61 | 62 | explicit BarGraph(QWidget *parent = 0); 63 | ~BarGraph(); 64 | 65 | void serialPacket(QStringList packet); 66 | QString getId() { return id; } 67 | 68 | void reset(); 69 | void xmlStream(QXmlStreamWriter *writer); 70 | void xmlParse(QXmlStreamReader* xml); 71 | 72 | static bool validPacket(QString packet); 73 | 74 | private: 75 | void updateDetachedLegendLayout(); 76 | void blockAllSignals(bool block); 77 | 78 | private slots: 79 | void legendMarkerClicked(); 80 | 81 | public slots: 82 | void setId(QString str); 83 | void setTitle(QString str); 84 | void settingsChanged(); 85 | 86 | void plot(); 87 | 88 | 89 | private: 90 | Ui::BarGraph *ui; 91 | QString id; 92 | 93 | QChart *chart; 94 | 95 | QList items; 96 | QStringList categories; 97 | 98 | bool readyToPlot; 99 | }; 100 | 101 | #endif // BARGRAPH_H 102 | -------------------------------------------------------------------------------- /mainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef MAINWINDOW_H 2 | #define MAINWINDOW_H 3 | 4 | #define MAX_RECENT_OPEN_MENU_ENTRIES 10 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | 12 | #include 13 | 14 | #include "settings.h" 15 | #include "config.h" 16 | #include "terminal.h" 17 | #include "widgets/helper.h" 18 | #include "debugtools.h" 19 | #include "aboutdialog.h" 20 | 21 | #include "widgets/abstractwidget.h" 22 | //#include "widgets/linegraph.h" 23 | #include "widgets/bargraph.h" 24 | #include "widgets/piechart.h" 25 | #include "widgets/linechart.h" 26 | #include "widgets/scatterchart.h" 27 | //#include "mapper.h" 28 | 29 | namespace Ui { 30 | class MainWindow; 31 | } 32 | 33 | 34 | 35 | 36 | class MainWindow : public QMainWindow 37 | { 38 | Q_OBJECT 39 | 40 | public: 41 | explicit MainWindow(QWidget *parent = 0); 42 | ~MainWindow(); 43 | void readSettings(); 44 | 45 | public slots: 46 | void openDash(QString fileName); 47 | 48 | private slots: 49 | void readData(); 50 | void sendData(QByteArray data); 51 | 52 | void parseData(QByteArray data); 53 | 54 | void openSerialPort(); 55 | void closeSerialPort(); 56 | 57 | void addLineGraph(); 58 | void addLineChart(); 59 | void addBarGraph(); 60 | void addPieChart(); 61 | void addScatterChart(); 62 | void addMap(); 63 | void deleteWidget(); 64 | 65 | void openSettings(); 66 | 67 | void showAbout(); 68 | 69 | void newDash(); 70 | void normalSave(); 71 | void saveAs(); 72 | void saveDash(QString fileName); 73 | void openDashDialog(); 74 | void unsavedChanges(bool bb); 75 | void settingsChanged(); 76 | 77 | void openTerminal(); 78 | 79 | void saveSerialSettings(); 80 | 81 | void lockStateChanged(bool checked); 82 | 83 | void addToRecentFiles(QString fileName); 84 | void recentFileMenuItemClicked(); 85 | void clearRecentFilesMenu(); 86 | 87 | private: 88 | void constructRecentFilesMenu(); 89 | 90 | 91 | protected: 92 | void closeEvent(QCloseEvent * e); 93 | 94 | private: 95 | Ui::MainWindow *ui; 96 | QSerialPort *serial; 97 | Settings * settings; 98 | 99 | QByteArray allData; 100 | 101 | QList widgets; 102 | 103 | int tick; 104 | int packetsDropped; 105 | 106 | Terminal * terminal; 107 | DebugTools * debugToolsDialog; 108 | 109 | QComboBox * baudrateComboBox; 110 | QComboBox * serialPortComboBox; 111 | 112 | AboutDialog about; 113 | 114 | QStringList recentFiles; 115 | }; 116 | 117 | #endif // MAINWINDOW_H 118 | -------------------------------------------------------------------------------- /widgets/linechart.h: -------------------------------------------------------------------------------- 1 | #ifndef LINECHART_H 2 | #define LINECHART_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | #include "config.h" 25 | #include "abstractwidget.h" 26 | #include "xychartplotitem.h" 27 | 28 | #define AUTO_ADD_MARGIN_PERC 1.10 //How much % extra will be added to auto determined axes values 29 | 30 | 31 | namespace Ui { 32 | class LineChart; 33 | } 34 | 35 | //struct line_graph_plot_item_t { 36 | // QList values; 37 | // QString series_name; 38 | // QColor color; 39 | // bool colorIsSet; 40 | //}; 41 | 42 | 43 | 44 | class XYChartPlotItem; 45 | 46 | class LineChart : public AbstractWidget 47 | { 48 | Q_OBJECT 49 | 50 | public: 51 | enum {Type = 1 /* must be unique */ }; 52 | enum LegendPosition {POS_TOP, POS_RIGHT, POS_BOTTOM, POS_LEFT, POS_DETACHED }; 53 | 54 | int type() const 55 | { 56 | return Type; 57 | } 58 | 59 | enum PlotType {PLOT_TIME, PLOT_XY}; 60 | 61 | explicit LineChart(QWidget *parent = 0); 62 | ~LineChart(); 63 | 64 | void serialPacket(QStringList packet); 65 | QString getId() { return id; } 66 | 67 | void reset(); 68 | void xmlStream(QXmlStreamWriter *writer); 69 | void xmlParse(QXmlStreamReader* xml); 70 | 71 | static bool validPacket(QString packet); 72 | 73 | private: 74 | void updateDetachedLegendLayout(); 75 | 76 | 77 | public slots: 78 | void setId(QString str); 79 | void setTitle(QString str); 80 | void settingsChanged(); 81 | 82 | void plot(); 83 | 84 | void clear(); 85 | 86 | private slots: 87 | void samplingSizeChanged(int value); 88 | void refreshRateChanged(int value); 89 | void setFileForWriting(); 90 | void startStopAutoWriting(bool start); 91 | void startStopPlotting(); 92 | void savePlot(); 93 | void blockAllSignals(bool block); 94 | 95 | void legendMarkerClicked(); 96 | void legendMarkerHovered(bool hovering); 97 | 98 | private: 99 | Ui::LineChart *ui; 100 | QString id; 101 | 102 | QChart *chart; 103 | QHash items; 104 | QTimer* timer; 105 | 106 | QDateTimeAxis *dateAxisX; 107 | QValueAxis* axisY; 108 | QValueAxis *axisX; 109 | 110 | QFile *autoWriteFile; 111 | QTextStream autoWriteStream; 112 | 113 | bool doPlotting; 114 | }; 115 | 116 | #endif // LINECHART_H 117 | -------------------------------------------------------------------------------- /widgets/mapper.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Mapper 4 | 5 | 6 | 7 | 0 8 | 0 9 | 461 10 | 336 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | :/images/04_maps.png:/images/04_maps.png 19 | 20 | 21 | 22 | 23 | 24 | 0 25 | 26 | 27 | 28 | Map 29 | 30 | 31 | 32 | 33 | 34 | 1 35 | 36 | 37 | <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">Sample map plot</span></p></body></html> 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | Location: 47 | 48 | 49 | 50 | 51 | 52 | 53 | Riga, Latvia 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 0 64 | 0 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Settings 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | GMapWidget 83 | QWidget 84 |
gmapwidget.h
85 | 1 86 |
87 |
88 | 89 | 90 | 91 | 92 |
93 | -------------------------------------------------------------------------------- /widgets/gmapwidget.cpp: -------------------------------------------------------------------------------- 1 | #include "gmapwidget.h" 2 | 3 | #include 4 | #include 5 | #include 6 | //http://qt-project.org/forums/viewthread/12342 <-- Source was downloaded from here, and JUST 7 | // some functionality was added as necessary, but the core is developed by steven. 8 | GMapWidget::GMapWidget(QWidget *parent) 9 | : QWebView(parent) 10 | { 11 | m_accessManager = new QNetworkAccessManager(this); 12 | m_initMap = false; 13 | 14 | connect(m_accessManager, SIGNAL(finished(QNetworkReply*)), this, SLOT(slotNetworkReply(QNetworkReply*))); 15 | 16 | connect(this, SIGNAL(loadFinished(bool)), this, SLOT(slotLoadFinished(bool))); 17 | 18 | load(QUrl("qrc:/index.html")); 19 | } 20 | 21 | void GMapWidget::loadMap() 22 | { 23 | load(QUrl("qrc:/index.html")); 24 | 25 | 26 | } 27 | 28 | // wait till the load finished signal before initializing the map trough javascript functions! 29 | // somethimes the geocoding is faster than the webview can load the google map runtime 30 | void GMapWidget::slotLoadFinished(bool ok) 31 | { 32 | if(!m_initMap && ok) { 33 | m_initMap = true; 34 | 35 | // load a default location on map init 36 | setGMapCenter("Riga, Latvia"); 37 | } 38 | } 39 | 40 | // geocode location strings to Latitude / Longitude positions 41 | void GMapWidget::setGMapCenter(const QString &location) 42 | { 43 | QUrl url("http://maps.googleapis.com/maps/api/geocode/xml"); 44 | 45 | QUrlQuery q; 46 | q.addQueryItem("address", location); 47 | q.addQueryItem("sensor", "false"); 48 | 49 | url.setQuery( q ); 50 | 51 | QNetworkRequest request(url); 52 | 53 | m_accessManager->get(request); 54 | 55 | 56 | } 57 | 58 | // overload with QPointF 59 | void GMapWidget::setGMapCenter(const QPointF &pos) 60 | { 61 | setGMapCenter(pos.x(), pos.y()); 62 | } 63 | 64 | // overload with qreal 65 | void GMapWidget::setGMapCenter(qreal lat, qreal lng) 66 | { 67 | runScript(QString("setGMapCenter(%1,%2)").arg(lat).arg(lng)); 68 | } 69 | 70 | // set a zoom level on the map 71 | void GMapWidget::setGMapZoom(int zoomLevel) 72 | { 73 | runScript(QString("setGMapZoom(%1)").arg(zoomLevel)); 74 | } 75 | 76 | void GMapWidget::addMarker(float lat, float lng, QString name) 77 | { 78 | runScript( QString("newMarker(%1,%2,'%3')").arg(lat).arg(lng).arg(name) ); 79 | } 80 | 81 | // read out a geocode xml reply from google 82 | void GMapWidget::slotNetworkReply(QNetworkReply *reply) 83 | { 84 | QXmlStreamReader reader(reply->readAll()); 85 | 86 | while(!reader.atEnd()) { 87 | 88 | reader.readNext(); 89 | 90 | if(reader.name() == "geometry") { 91 | 92 | reader.readNextStartElement(); 93 | 94 | if(reader.name() == "location") { 95 | 96 | reader.readNextStartElement(); 97 | 98 | if(reader.name() == "lat") { 99 | 100 | QPointF pos; 101 | 102 | pos.setX(reader.readElementText().toFloat()); 103 | 104 | reader.readNextStartElement(); 105 | 106 | if(reader.name() == "lng") { 107 | 108 | pos.setY(reader.readElementText().toFloat()); 109 | 110 | setGMapCenter(pos); 111 | 112 | return; 113 | } 114 | } 115 | } 116 | } 117 | } 118 | } 119 | 120 | // run a javascript function 121 | void GMapWidget::runScript(const QString &script) 122 | { 123 | page()->mainFrame()->evaluateJavaScript(script); 124 | } 125 | -------------------------------------------------------------------------------- /aboutdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | AboutDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 435 10 | 240 11 | 12 | 13 | 14 | About 15 | 16 | 17 | 18 | :/images/help-about.png:/images/help-about.png 19 | 20 | 21 | 22 | 23 | 0 24 | 10 25 | 161 26 | 151 27 | 28 | 29 | 30 | 31 | 32 | 33 | :/appicon.ico 34 | 35 | 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 170 43 | 10 44 | 260 45 | 221 46 | 47 | 48 | 49 | 50 | 51 | 52 | <html><head/><body><p><span style=" font-size:10pt; font-weight:600;">FlexiPlot Alpha 4</span></p></body></html> 53 | 54 | 55 | 56 | 57 | 58 | 59 | Based on Qt ... 60 | 61 | 62 | 63 | 64 | 65 | 66 | Built On Jan... 67 | 68 | 69 | 70 | 71 | 72 | 73 | <html><head/><body><p>Developed by Raivis Strogonovs<br/><a href="https://morf.lv"><span style=" text-decoration: underline; color:#0000ff;">https://morf.lv</span></a><br/></p><p>THE SOFTWARE IS PROVIDED &quot;AS IS&quot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.</p><p><br/></p></body></html> 74 | 75 | 76 | true 77 | 78 | 79 | true 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Qt::Horizontal 89 | 90 | 91 | 92 | 40 93 | 20 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | Close 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /settings.cpp: -------------------------------------------------------------------------------- 1 | #include "settings.h" 2 | #include "ui_settings.h" 3 | 4 | Settings::Settings(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::Settings) 7 | { 8 | ui->setupUi(this); 9 | 10 | QList ports = QSerialPortInfo::availablePorts(); 11 | 12 | foreach(QSerialPortInfo port, ports) 13 | ui->serialPort->addItem(port.portName()); 14 | 15 | foreach(qint32 baudrate, QSerialPortInfo::standardBaudRates()) 16 | ui->baudrate->addItem(QString::number( baudrate )); 17 | 18 | 19 | 20 | connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(saveSettings())); 21 | connect(ui->colorBtn, SIGNAL(clicked(bool)), this, SLOT(backgroundColor())); 22 | loadSettings(); 23 | } 24 | 25 | void Settings::backgroundColor() 26 | { 27 | currentBackgroundColor = QColorDialog::getColor(currentBackgroundColor, this); 28 | 29 | if(currentBackgroundColor.isValid()) 30 | { 31 | ui->colorBtn->setStyleSheet( "QPushButton { background-color:"+ currentBackgroundColor.name() +";\nborder: 1px solid #000; }" ); 32 | } 33 | } 34 | 35 | 36 | //SAves settings in the registry 37 | void Settings::saveSettings() 38 | { 39 | QSettings settings; 40 | settings.setValue( "Serial/port", ui->serialPort->currentText()); 41 | settings.setValue( "Serial/baudrate", ui->baudrate->currentText() ); 42 | settings.setValue( "Serial/data_bits", ui->dataBits->currentText().toInt() ); 43 | settings.setValue( "Serial/flow_control", (QSerialPort::FlowControl) ui->flowControl->currentIndex() ); 44 | switch(ui->parity->currentIndex()) 45 | { 46 | case 0: settings.setValue( "Serial/parity", QSerialPort::NoParity ); break; 47 | case 1: settings.setValue( "Serial/parity", QSerialPort::EvenParity ); break; 48 | case 2: settings.setValue( "Serial/parity", QSerialPort::OddParity ); break; 49 | case 3: settings.setValue( "Serial/parity", QSerialPort::SpaceParity ); break; 50 | case 4: settings.setValue( "Serial/parity", QSerialPort::MarkParity ); break; 51 | default: ; 52 | } 53 | 54 | switch(ui->stopBits->currentIndex()) 55 | { 56 | case 0: settings.setValue( "Serial/stop_bits", QSerialPort::OneStop ); break; 57 | case 1: settings.setValue( "Serial/stop_bits", QSerialPort::OneAndHalfStop ); break; 58 | case 2: settings.setValue( "Serial/stop_bits", QSerialPort::TwoStop ); break; 59 | default: ; 60 | } 61 | 62 | settings.setValue( "UI/tabbed", ui->tabCheckBox->isChecked() ); 63 | settings.setValue( "UI/backgroundColor", currentBackgroundColor ); 64 | 65 | emit settingsChanged(); 66 | 67 | } 68 | 69 | //loads settings from the registry 70 | void Settings::loadSettings() 71 | { 72 | QSettings settings; 73 | 74 | ui->serialPort->setCurrentText( settings.value("Serial/port").toString() ); 75 | ui->baudrate->setCurrentText( settings.value("Serial/baudrate").toString() ); 76 | ui->dataBits->setCurrentText( QString::number( settings.value("Serial/data_bits").toInt() ) ); 77 | ui->flowControl->setCurrentIndex( settings.value("Serial/flow_control").toInt() ); 78 | switch( settings.value("Serial/parity").toInt() ) 79 | { 80 | case QSerialPort::NoParity: ui->parity->setCurrentIndex(0); break; 81 | case QSerialPort::EvenParity: ui->parity->setCurrentIndex(1); break; 82 | case QSerialPort::OddParity: ui->parity->setCurrentIndex(2); break; 83 | case QSerialPort::SpaceParity: ui->parity->setCurrentIndex(3); break; 84 | case QSerialPort::MarkParity: ui->parity->setCurrentIndex(4); break; 85 | default: ; 86 | } 87 | switch(settings.value("Serial/stop_bits").toInt()) 88 | { 89 | case QSerialPort::OneStop: ui->stopBits->setCurrentIndex(0); break; 90 | case QSerialPort::OneAndHalfStop: ui->stopBits->setCurrentIndex(1); break; 91 | case QSerialPort::TwoStop: ui->stopBits->setCurrentIndex(2); break; 92 | default: ; 93 | } 94 | 95 | ui->tabCheckBox->setChecked( settings.value("UI/tabbed").toBool() ); 96 | 97 | currentBackgroundColor = QColor( settings.value( "UI/backgroundColor","#a0a0a0" ).toString() ); 98 | ui->colorBtn->setStyleSheet( "QPushButton { background-color:"+ currentBackgroundColor.name() +";\nborder: 1px solid #000; }" ); 99 | 100 | } 101 | 102 | Settings::~Settings() 103 | { 104 | delete ui; 105 | } 106 | -------------------------------------------------------------------------------- /debugtools.cpp: -------------------------------------------------------------------------------- 1 | #include "debugtools.h" 2 | #include "ui_debugtools.h" 3 | 4 | DebugTools::DebugTools(QWidget *parent) : 5 | QDialog(parent), 6 | ui(new Ui::DebugTools) 7 | { 8 | ui->setupUi(this); 9 | 10 | connect(ui->sendPacketBtn, SIGNAL(clicked(bool)), this, SLOT(sendPacket())); 11 | connect(ui->historyListWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(sentHistoryListItemClicked())); 12 | connect(ui->historyListWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(sentHistoryListItemDoubleClicked())); 13 | 14 | connect(ui->clearBtn, SIGNAL(clicked(bool)), this, SLOT(clear())); 15 | 16 | ui->packetLineEdit->installEventFilter( this ); 17 | 18 | QList sizes; 19 | sizes << 150 << 50; 20 | ui->splitter->setSizes(sizes); 21 | connect(ui->examplesTreeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)), this, SLOT(exampleItemSelected())); 22 | 23 | 24 | loadHistory(); 25 | 26 | ui->historyListWidget->scrollToBottom(); 27 | ui->historyListWidget->setCurrentRow( ui->historyListWidget->count() - 1 ); 28 | } 29 | 30 | void DebugTools::exampleItemSelected() 31 | { 32 | if( ui->examplesTreeWidget->currentItem()->parent() == NULL ) 33 | return; 34 | 35 | ui->packetLineEdit->setText( ui->examplesTreeWidget->currentItem()->text(0) ); 36 | } 37 | 38 | void DebugTools::saveHistory() 39 | { 40 | QStringList itemListStrList; 41 | for(int i=0; ihistoryListWidget->count(); i++) 42 | itemListStrList << ui->historyListWidget->item(i)->text(); 43 | 44 | QSettings settings; 45 | settings.setValue("debug_tools/history", itemListStrList ); 46 | } 47 | 48 | void DebugTools::loadHistory() 49 | { 50 | QSettings settings; 51 | QStringList savedHistoryList = settings.value("debug_tools/history", QStringList()).toStringList(); 52 | foreach(QString str, savedHistoryList ) 53 | ui->historyListWidget->addItem( str ); 54 | } 55 | 56 | void DebugTools::clear() 57 | { 58 | qDebug() << "Clearing packet injector history"; 59 | 60 | ui->packetLineEdit->clear(); 61 | ui->historyListWidget->clear(); 62 | 63 | QSettings settings; 64 | settings.setValue("debug_tools/history", QStringList() ); 65 | } 66 | 67 | bool DebugTools::eventFilter(QObject *obj, QEvent *e) 68 | { 69 | if(obj == ui->packetLineEdit) 70 | { 71 | if(e->type() == QEvent::KeyPress) 72 | { 73 | QKeyEvent * keyEvent = static_cast(e); 74 | if(keyEvent->key() == Qt::Key_Up) 75 | { 76 | if(ui->historyListWidget->count() > 0) 77 | { 78 | if(ui->packetLineEdit->text().isEmpty() == false && ui->historyListWidget->currentRow() != 0) 79 | { 80 | ui->historyListWidget->setCurrentRow( ui->historyListWidget->currentRow() - 1 ); 81 | } 82 | ui->packetLineEdit->setText( ui->historyListWidget->currentItem()->text() ); 83 | } 84 | return true; 85 | } else if(keyEvent->key() == Qt::Key_Down) 86 | { 87 | if(ui->historyListWidget->count() > 0) 88 | { 89 | if(ui->packetLineEdit->text().isEmpty() == false && ui->historyListWidget->currentRow() < ui->historyListWidget->count() - 1) 90 | { 91 | ui->historyListWidget->setCurrentRow( ui->historyListWidget->currentRow() + 1 ); 92 | } 93 | ui->packetLineEdit->setText( ui->historyListWidget->currentItem()->text() ); 94 | } 95 | return true; 96 | } 97 | } 98 | } 99 | 100 | return QDialog::eventFilter( obj, e ); 101 | } 102 | 103 | void DebugTools::sentHistoryListItemDoubleClicked() 104 | { 105 | ui->packetLineEdit->setText( ui->historyListWidget->currentItem()->text() ); 106 | sendPacket(); 107 | } 108 | 109 | void DebugTools::sentHistoryListItemClicked() 110 | { 111 | ui->packetLineEdit->setText( ui->historyListWidget->currentItem()->text() ); 112 | } 113 | 114 | 115 | void DebugTools::sendPacket() 116 | { 117 | if(ui->packetLineEdit->text().length() == 0) 118 | return; 119 | 120 | QString packet = ui->packetLineEdit->text(); 121 | packet.append("\r\n"); 122 | 123 | emit packetSent( packet.toLatin1() ); 124 | 125 | if(ui->historyListWidget->count() > 0) 126 | { 127 | if(ui->historyListWidget->item( ui->historyListWidget->count()-1 )->text() != ui->packetLineEdit->text()) 128 | ui->historyListWidget->addItem( ui->packetLineEdit->text() ); 129 | } 130 | else 131 | ui->historyListWidget->addItem( ui->packetLineEdit->text() ); 132 | 133 | ui->historyListWidget->setCurrentRow( ui->historyListWidget->count()-1 ); 134 | ui->historyListWidget->scrollToBottom(); 135 | 136 | ui->packetLineEdit->clear(); 137 | 138 | saveHistory(); 139 | } 140 | 141 | DebugTools::~DebugTools() 142 | { 143 | delete ui; 144 | } 145 | -------------------------------------------------------------------------------- /widgets/xychartplotitem.cpp: -------------------------------------------------------------------------------- 1 | #include "xychartplotitem.h" 2 | 3 | 4 | XYChartPlotItem::XYChartPlotItem(QXYSeries *m_series, QString name, UpdateType updateType ) 5 | { 6 | this->m_series = m_series; 7 | this->m_series->setName( name ); 8 | colorIsSet = false; 9 | this->name = name; 10 | this->updateType = updateType; 11 | 12 | m_samplingSize = 500; 13 | } 14 | 15 | void XYChartPlotItem::update() 16 | { 17 | m_series->replace( points ); 18 | } 19 | 20 | void XYChartPlotItem::addData(QPointF p) 21 | { 22 | switch(updateType) 23 | { 24 | case UPDATE_MANUAL: 25 | // m_series->append( p ); 26 | if(m_samplingSize == -1) 27 | { 28 | points.push_back(p); 29 | /*if(points.length() > m_samplingSize) 30 | this->deleteFirst();*/ 31 | } 32 | else 33 | { 34 | if (points.count() < m_samplingSize) 35 | { 36 | //This is fine, but it is faster for QtCharts to render if we don't have large numbers 37 | //since RT line chart can't have nice timestamp, there is no reason not to alter X with sample index 38 | // points.push_back( p ); 39 | 40 | points.push_back( QPointF(points.length(), p.y()) ); 41 | } 42 | else 43 | { 44 | QVector newPoints; 45 | for (int i = 0; i < points.count()-1; i++) 46 | newPoints.append(QPointF(i, points.at(i+1).y())); 47 | 48 | newPoints.push_back( QPointF(m_samplingSize, p.y()) ); 49 | points = newPoints; 50 | } 51 | } 52 | 53 | break; 54 | 55 | case UPDATE_INSTANTLY: 56 | points.append(p); //Do we really need this? Maybe for convinience when getting data. Double the memory though 57 | m_series->append(p); 58 | if(m_samplingSize > 0 && m_series->count() > m_samplingSize) 59 | { 60 | this->deleteFirst(); 61 | m_series->remove(0); 62 | } 63 | break; 64 | 65 | 66 | default: qWarning() << "Unknown update type"; 67 | 68 | } 69 | 70 | 71 | } 72 | 73 | void XYChartPlotItem::setColor(QColor color) 74 | { 75 | m_series->setColor( color ); 76 | colorIsSet = true; 77 | this->color = color; 78 | } 79 | 80 | void XYChartPlotItem::deleteFirst() 81 | { 82 | points.takeFirst(); 83 | } 84 | 85 | void XYChartPlotItem::clear() 86 | { 87 | points.clear(); 88 | } 89 | 90 | QPointF XYChartPlotItem::maxValues() 91 | { 92 | QPointF result; 93 | foreach(QPointF p, points) 94 | { 95 | if(result.isNull()) 96 | { 97 | result.setX(p.x()); 98 | result.setY(p.y()); 99 | } 100 | else 101 | { 102 | if(p.x() > result.x() ) 103 | result.setX(p.x()); 104 | if(p.y() > result.y() ) 105 | result.setY(p.y()); 106 | } 107 | } 108 | 109 | return result; 110 | } 111 | 112 | QPointF XYChartPlotItem::minValues() 113 | { 114 | QPointF result; 115 | foreach(QPointF p, points) 116 | { 117 | if(result.isNull()) 118 | { 119 | result.setX(p.x()); 120 | result.setY(p.y()); 121 | } 122 | else 123 | { 124 | if(p.x() < result.x() ) 125 | result.setX(p.x()); 126 | if(p.y() < result.y() ) 127 | result.setY(p.y()); 128 | } 129 | } 130 | return result; 131 | } 132 | 133 | xy_items_max_min_values_t XYChartPlotItem::getMaxMinValues(QHash items) 134 | { 135 | xy_items_max_min_values_t result; 136 | 137 | QPointF maxValues; 138 | QPointF minValues; 139 | foreach(QString key, items.keys()) 140 | { 141 | XYChartPlotItem * item = items[key]; 142 | 143 | if(!item->series()->isVisible()) 144 | continue; 145 | 146 | QPointF itemMaxValues = item->maxValues(); 147 | 148 | if(maxValues.isNull()) 149 | { 150 | maxValues.setX( itemMaxValues.x() ); 151 | maxValues.setY( itemMaxValues.y() ); 152 | } 153 | else 154 | { 155 | if(itemMaxValues.x() > maxValues.x()) 156 | maxValues.setX( itemMaxValues.x() ); 157 | if(itemMaxValues.y() > maxValues.y()) 158 | maxValues.setY( itemMaxValues.y() ); 159 | } 160 | 161 | 162 | QPointF itemMinValues = item->minValues(); 163 | if(minValues.isNull()) 164 | { 165 | minValues.setX( itemMinValues.x() ); 166 | minValues.setY( itemMinValues.y() ); 167 | } 168 | else 169 | { 170 | if(itemMinValues.x() < minValues.x()) 171 | minValues.setX( itemMinValues.x() ); 172 | if(itemMinValues.y() < minValues.y()) 173 | minValues.setY( itemMinValues.y() ); 174 | } 175 | } 176 | 177 | result.minValues = minValues; 178 | result.maxValues = maxValues; 179 | 180 | return result; 181 | } 182 | -------------------------------------------------------------------------------- /widgets/linegraph.h: -------------------------------------------------------------------------------- 1 | #ifndef PLOTTER_H 2 | #define PLOTTER_H 3 | 4 | 5 | /*! 6 | * Packets: 7 | * 8 | * Real Time Plotting: 9 | * {P0|Line Name|255,0,0|value|Other Line Name|255,0,0|value} 10 | * Example: Sample real-time packet with 3 curves XYZ 11 | * {P0|X|255,0,0|100|Y|0,255,0|150|Z|0,0,255|200} 12 | * 13 | * 14 | * Sample XY plot (supports only one curve): 15 | * {P0|Some XY plot|255,0,0|1 255 2 200 3 150 4 100} 16 | * {Plot ID|Curve name|Color|X Y X Y X Y X Y.....} 17 | * Note: If for each X value there won't be Y value, the plot will be ignored 18 | * 19 | */ 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | #include 32 | 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | 50 | 51 | #include "plotitem.h" 52 | #include "config.h" 53 | #include "abstractwidget.h" 54 | 55 | 56 | namespace Ui { 57 | class Plotter; 58 | } 59 | 60 | struct graph_t 61 | { 62 | double x; 63 | double y; 64 | QColor color; 65 | QString name; 66 | QTime xT; 67 | }; 68 | 69 | class StockTimeScaleDraw; 70 | class PlotPicker; 71 | 72 | 73 | class LineGraph : public AbstractWidget 74 | { 75 | Q_OBJECT 76 | 77 | public: 78 | enum { Type = 1 }; 79 | int type() const 80 | { 81 | // Enable the use of qgraphicsitem_cast with this item. 82 | return Type; 83 | } 84 | 85 | enum PlotType {PLOT_TIME, PLOT_XY}; 86 | 87 | explicit LineGraph(QWidget *parent = 0); 88 | ~LineGraph(); 89 | 90 | void serialPacket(QStringList packet); 91 | QString getId() { return id; } 92 | 93 | void reset(); 94 | void xmlStream(QXmlStreamWriter *writer); 95 | void xmlParse(QXmlStreamReader* xml); 96 | 97 | static bool validPacket(QString packet); 98 | 99 | public slots: 100 | void plot(); 101 | void legendChecked( const QVariant &, bool on ); 102 | void showCurve( QwtPlotItem *item, bool on ); 103 | void setId(QString str); 104 | void setTitle(QString str); 105 | void setBuffer(int value); 106 | void setRefreshRate(int ms); 107 | void setDateFormat(QString format); 108 | void setXAxisLabel(QString str); 109 | void setYAxisLabel(QString str); 110 | void typeChanged(int type); 111 | void startStopPlotting(); 112 | void settingsChanged(); 113 | void openColorDialog(); 114 | void savePlot(); 115 | void setFileForWriting(); 116 | void startStopAutoWriting(bool start); 117 | 118 | private: 119 | Ui::Plotter *ui; 120 | 121 | 122 | QHash plotItems; 123 | 124 | QwtPlotPanner *plotPanner; 125 | QwtPlotMagnifier *plotMagnifier; 126 | 127 | QString id; 128 | QTimer *timer; 129 | double x; 130 | double minX; 131 | 132 | int buffer; 133 | 134 | bool doPlotting; 135 | 136 | PlotPicker *plotPicker; 137 | 138 | QColor currentColor; 139 | 140 | QFile *autoWriteFile; 141 | QTextStream autoWriteStream; 142 | }; 143 | 144 | 145 | 146 | class StockTimeScaleDraw: public QwtScaleDraw 147 | { 148 | public: 149 | StockTimeScaleDraw(QString fmt) : format(fmt) { } 150 | 151 | virtual QwtText label(double v) const 152 | { 153 | QDateTime t = QDateTime::fromMSecsSinceEpoch(v); 154 | return t.toString(format); 155 | } 156 | private: 157 | const QString format; 158 | }; 159 | 160 | class PlotPicker : QwtPlotPicker 161 | { 162 | public: 163 | PlotPicker( QWidget *canvas, QString format ): 164 | QwtPlotPicker( canvas ) 165 | { 166 | setRubberBand( QwtPlotPicker::NoRubberBand ); 167 | setTrackerMode( QwtPlotPicker::AlwaysOn ); 168 | this->format = format; 169 | this->date = true; 170 | 171 | this->setStateMachine( new QwtPickerClickPointMachine() ); 172 | 173 | } 174 | 175 | void setFormat(QString f) { format = f; } 176 | void showDate(bool bb) { date = bb; } 177 | 178 | protected: 179 | virtual QwtText trackerTextF( const QPointF &pos ) const 180 | { 181 | 182 | const QDateTime dt = QwtDate::toDateTime( pos.x() ); 183 | 184 | QString s; 185 | 186 | if(date) 187 | { 188 | s += QDateTime::fromMSecsSinceEpoch(pos.x()).toString(format) + " | " + QString::number(pos.y()); 189 | } 190 | else 191 | s += QString::number(pos.x()) + " | " + QString::number(pos.y()); 192 | 193 | QwtText text( s ); 194 | text.setColor( Qt::white ); 195 | 196 | QColor c = rubberBandPen().color(); 197 | text.setBorderPen( QPen( c ) ); 198 | text.setBorderRadius( 2 ); 199 | c.setAlpha( 170 ); 200 | text.setBackgroundBrush( c ); 201 | 202 | return text; 203 | } 204 | 205 | 206 | 207 | private: 208 | QString format; 209 | bool date; 210 | }; 211 | 212 | 213 | 214 | #endif // PLOTTER_H 215 | -------------------------------------------------------------------------------- /terminal.cpp: -------------------------------------------------------------------------------- 1 | #include "terminal.h" 2 | #include "ui_terminal.h" 3 | 4 | 5 | Terminal::Terminal(QWidget *parent) : 6 | QDialog(parent), 7 | ui(new Ui::Terminal) 8 | { 9 | ui->setupUi(this); 10 | 11 | connect(ui->sendBtn, SIGNAL(clicked(bool)), this, SLOT(sendInput())); 12 | 13 | connect(ui->sentCmdList, SIGNAL(clicked(QModelIndex)), this, SLOT(sentCmdListItemClicked())); 14 | connect(ui->sentCmdList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(sentCmdListItemDoubleClicked())); 15 | 16 | ui->cmdEdit->installEventFilter( this ); 17 | 18 | connect(ui->clearBtn, SIGNAL(clicked(bool)), this, SLOT(clear())); 19 | 20 | loadHistory(); 21 | 22 | ui->sentCmdList->setCurrentRow( ui->sentCmdList->count() - 1 ); 23 | } 24 | 25 | void Terminal::saveHistory() 26 | { 27 | QStringList itemListStrList; 28 | for(int i=0; isentCmdList->count(); i++) 29 | itemListStrList << ui->sentCmdList->item(i)->text(); 30 | 31 | QSettings settings; 32 | settings.setValue("terminal/history", itemListStrList ); 33 | } 34 | 35 | void Terminal::loadHistory() 36 | { 37 | QSettings settings; 38 | QStringList savedHistoryList = settings.value("terminal/history", QStringList()).toStringList(); 39 | foreach(QString str, savedHistoryList ) 40 | ui->sentCmdList->addItem( str ); 41 | } 42 | 43 | void Terminal::clear() 44 | { 45 | ui->cmdEdit->clear(); 46 | ui->sentCmdList->clear(); 47 | ui->terminalBrowser->clear(); 48 | 49 | QSettings settings; 50 | settings.setValue("terminal/history", QStringList() ); 51 | } 52 | 53 | bool Terminal::eventFilter(QObject *obj, QEvent *e) 54 | { 55 | if(obj == ui->cmdEdit) 56 | { 57 | if(e->type() == QEvent::KeyPress) 58 | { 59 | QKeyEvent * keyEvent = static_cast(e); 60 | if(keyEvent->key() == Qt::Key_Up) 61 | { 62 | if(ui->sentCmdList->count() > 0) 63 | { 64 | if(ui->cmdEdit->text().isEmpty() == false && ui->sentCmdList->currentRow() != 0) 65 | { 66 | ui->sentCmdList->setCurrentRow( ui->sentCmdList->currentRow() - 1 ); 67 | } 68 | ui->cmdEdit->setText( ui->sentCmdList->currentItem()->text() ); 69 | } 70 | return true; 71 | } else if(keyEvent->key() == Qt::Key_Down) 72 | { 73 | if(ui->sentCmdList->count() > 0) 74 | { 75 | if(ui->cmdEdit->text().isEmpty() == false && ui->sentCmdList->currentRow() < ui->sentCmdList->count() - 1) 76 | { 77 | ui->sentCmdList->setCurrentRow( ui->sentCmdList->currentRow() + 1 ); 78 | } 79 | ui->cmdEdit->setText( ui->sentCmdList->currentItem()->text() ); 80 | } 81 | return true; 82 | } 83 | } 84 | } 85 | 86 | return QDialog::eventFilter( obj, e ); 87 | } 88 | 89 | void Terminal::sentCmdListItemDoubleClicked() 90 | { 91 | ui->cmdEdit->setText( ui->sentCmdList->currentItem()->text() ); 92 | sendInput(); 93 | } 94 | 95 | void Terminal::sentCmdListItemClicked() 96 | { 97 | ui->cmdEdit->setText( ui->sentCmdList->currentItem()->text() ); 98 | } 99 | 100 | void Terminal::sendInput() 101 | { 102 | if(ui->cmdEdit->text().length() == 0) 103 | return; 104 | 105 | QByteArray dataToSend = ui->cmdEdit->text().toLatin1(); 106 | 107 | switch(ui->lineEndCombobox->currentIndex()) 108 | { 109 | case NL_END: dataToSend.append('\n'); break; 110 | case CR_END: dataToSend.append('\r'); break; 111 | case BOTH_NL_CR_END: dataToSend.append("\n\r"); break; 112 | default /*NO_END*/: break; 113 | } 114 | 115 | emit writeToSerial( dataToSend ); 116 | 117 | if(ui->sentCmdList->count() > 0) 118 | { 119 | if(ui->sentCmdList->item( ui->sentCmdList->count()-1 )->text() != ui->cmdEdit->text()) 120 | ui->sentCmdList->addItem( ui->cmdEdit->text() ); 121 | } 122 | else 123 | ui->sentCmdList->addItem( ui->cmdEdit->text() ); 124 | 125 | ui->sentCmdList->setCurrentRow( ui->sentCmdList->count()-1 ); 126 | ui->sentCmdList->scrollToBottom(); 127 | 128 | ui->cmdEdit->clear(); 129 | 130 | saveHistory(); 131 | } 132 | 133 | Terminal::~Terminal() 134 | { 135 | delete ui; 136 | } 137 | 138 | void Terminal::appendOutput(QByteArray data) 139 | { 140 | appendOutput( QString(data) ); 141 | } 142 | 143 | void Terminal::appendOutput(QString data) 144 | { 145 | // ui->terminalBrowser->append( data ); 146 | 147 | if(ui->filterPlotPacketsCheckBox->isChecked()) 148 | { 149 | QString tempStr( data.mid(1,data.size()-4) ); 150 | 151 | // QRegExp rx_timeplot("[a-zA-Z0-9]+(\\|[a-zA-Z0-9 ]+\\|\\d{1,3},\\d{1,3},\\d{1,3}\\|(\\-*\\d+(\\.{0,1}\\d+)*|nan|inf))+"); 152 | // QRegExp rx_xy_plot("[a-zA-Z0-9]+\\|[a-zA-Z0-9 ]+\\|\\d{1,3},\\d{1,3},\\d{1,3}\\|(\\-*\\d+\\s\\-*\\d+\\s*)+"); 153 | if( Helper::validPacket(tempStr) ) 154 | { 155 | return; 156 | } 157 | } 158 | 159 | QTextCursor oldCursor = ui->terminalBrowser->textCursor(); 160 | int oldScrollValue = ui->terminalBrowser->verticalScrollBar()->value(); 161 | 162 | 163 | 164 | if(ui->TimeStampCheckBox->isChecked()) 165 | { 166 | ui->terminalBrowser->moveCursor (QTextCursor::End); 167 | ui->terminalBrowser->insertPlainText ( QDateTime::currentDateTime().toString("HH:mm:ss:zzz") + ": \t"); 168 | ui->terminalBrowser->moveCursor (QTextCursor::End); 169 | } 170 | 171 | if(ui->hexOutputCheckBox->isChecked()) 172 | { 173 | data = QString( data.toLatin1().toHex() ) + "\n"; 174 | data = data.toUpper(); 175 | for (int i = 2; i <= data.size(); i+=3) 176 | data.insert(i, ' '); 177 | } 178 | 179 | ui->terminalBrowser->moveCursor (QTextCursor::End); 180 | ui->terminalBrowser->insertPlainText (data); 181 | ui->terminalBrowser->moveCursor (QTextCursor::End); 182 | 183 | 184 | if(ui->autoScrollCheckBox->isChecked() == false) 185 | { 186 | ui->terminalBrowser->setTextCursor( oldCursor ); 187 | ui->terminalBrowser->verticalScrollBar()->setValue( oldScrollValue ); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /terminal.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Terminal 4 | 5 | 6 | 7 | 0 8 | 0 9 | 595 10 | 551 11 | 12 | 13 | 14 | Terminal 15 | 16 | 17 | 18 | :/images/utilities-terminal.png:/images/utilities-terminal.png 19 | 20 | 21 | 22 | 23 | 24 | 0 25 | 26 | 27 | 28 | 29 | Output: 30 | 31 | 32 | 33 | 34 | 35 | 36 | Qt::Horizontal 37 | 38 | 39 | 40 | 40 41 | 20 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | For convinience filters out all the packets sent for plotting. Clears up terminal for easier debugging even while plotting 50 | 51 | 52 | Filter Plotting Packets 53 | 54 | 55 | 56 | 57 | 58 | 59 | Auto Scroll 60 | 61 | 62 | true 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | QTextEdit::NoWrap 72 | 73 | 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | 81 | 82 | 83 | 84 | History: 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 0 93 | 0 94 | 95 | 96 | 97 | 98 | 0 99 | 120 100 | 101 | 102 | 103 | 104 | 16777215 105 | 120 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 0 114 | 115 | 116 | 117 | 118 | Input: 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | Send 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 0 138 | 139 | 140 | 141 | 142 | Clear 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 120 151 | 0 152 | 153 | 154 | 155 | 156 | No Line Ending 157 | 158 | 159 | 160 | 161 | Newline 162 | 163 | 164 | 165 | 166 | Carriage return 167 | 168 | 169 | 170 | 171 | Both Newline and Carriage Return 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | Qt::Horizontal 180 | 181 | 182 | 183 | 40 184 | 20 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | Hex Output 193 | 194 | 195 | 196 | 197 | 198 | 199 | Time Stamp 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /debugtools.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | DebugTools 4 | 5 | 6 | 7 | 0 8 | 0 9 | 704 10 | 406 11 | 12 | 13 | 14 | Debug Tools 15 | 16 | 17 | 18 | 19 | 20 | Packet Injector 21 | 22 | 23 | 24 | 25 | 26 | 27 | 0 28 | 0 29 | 30 | 31 | 32 | Qt::Horizontal 33 | 34 | 35 | 36 | 37 | 0 38 | 39 | 40 | 41 | 42 | 0 43 | 44 | 45 | 46 | 47 | History: 48 | 49 | 50 | 51 | 52 | 53 | 54 | Qt::Horizontal 55 | 56 | 57 | 58 | 40 59 | 20 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | Qt::NoFocus 68 | 69 | 70 | Clear 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 0 88 | 25 89 | 90 | 91 | 92 | Examples: 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | Packet 101 | 102 | 103 | 104 | 105 | Pie Chart 106 | 107 | 108 | 109 | :/images/piechart.ico:/images/piechart.ico 110 | 111 | 112 | 113 | {P0|Slice 1|10|Slice 2|30|Slice 3|20} 114 | 115 | 116 | 117 | 118 | {P0|Slice 1|255,0,0|10.0048|Slice 2|0,255,0|30|Slice 3|0,0,255|20} 119 | 120 | 121 | 122 | 123 | 124 | Bar Chart 125 | 126 | 127 | 128 | :/images/view-statistics.png:/images/view-statistics.png 129 | 130 | 131 | 132 | {P0|Jan;Feb;Mar|Jane|25 15 17|John|8 9 23} 133 | 134 | 135 | 136 | 137 | {P0|Jan;Feb;Mar|Jane|255,0,0|25 15 17|John|0,255,0|8 9 23} 138 | 139 | 140 | 141 | 142 | 143 | Line Chart 144 | 145 | 146 | 147 | :/images/linechart.ico:/images/linechart.ico 148 | 149 | 150 | 151 | {P0|Quadratic|255,0,0|-5 25 -4 16 -3 9 -2 4 -1 1 0 0 1 1 2 4 3 9 4 16 5 25} 152 | 153 | 154 | 155 | 156 | {P0|Roll|255,0,0|25|Pitch|0,255,0|56} 157 | 158 | 159 | 160 | 161 | {P0|Random|1 15 2 8 3 -6 4 15|Quadratic|-5 25 -4 16 -3 9 -2 4 -1 1 0 0 1 1 2 4 3 9 4 16 5 25} 162 | 163 | 164 | 165 | 166 | {P0|Random|255,0,0|1 15 2 8 3 -6 4 15|Quadratic|0,255,0|-5 25 -4 16 -3 9 -2 4 -1 1 0 0 1 1 2 4 3 9 4 16 5 25} 167 | 168 | 169 | 170 | 171 | 172 | Scatter Chart 173 | 174 | 175 | 176 | :/images/scatter.png:/images/scatter.png 177 | 178 | 179 | 180 | {P0|Random|1 1 2 2 3 3 0 6 5 4 2 3 0.5 9} 181 | 182 | 183 | 184 | 185 | {P0|Random|255,0,0|1 1 2 2 3 3 0 6 5 4 2 3 0.5 9} 186 | 187 | 188 | 189 | 190 | {P0|Random|1 1 2 2 3 3 0 6 5 4 2 3 0.5 9|Random2|5 8 6 9 2 2 4 5 6 7 3 1 5 4} 191 | 192 | 193 | 194 | 195 | {P0|Random|1 1|Random2|5 8} 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | Packet: 211 | 212 | 213 | 214 | 215 | 216 | 217 | {P0|Roll|255,0,0|25} 218 | 219 | 220 | 221 | 222 | 223 | 224 | Send 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | packetLineEdit 237 | sendPacketBtn 238 | 239 | 240 | 241 | 242 | 243 | 244 | -------------------------------------------------------------------------------- /settings.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Settings 4 | 5 | 6 | 7 | 0 8 | 0 9 | 549 10 | 329 11 | 12 | 13 | 14 | Settings 15 | 16 | 17 | 18 | :/images/settings.png:/images/settings.png 19 | 20 | 21 | 22 | 23 | 24 | Serial 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Serial Port: 33 | 34 | 35 | 36 | 37 | 38 | 39 | true 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Baudrate: 51 | 52 | 53 | 54 | 55 | 56 | 57 | true 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 0 67 | 68 | 69 | 70 | 71 | Data Bits: 72 | 73 | 74 | 75 | 76 | 77 | 78 | 3 79 | 80 | 81 | 82 | 5 83 | 84 | 85 | 86 | 87 | 6 88 | 89 | 90 | 91 | 92 | 7 93 | 94 | 95 | 96 | 97 | 8 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 0 108 | 109 | 110 | 111 | 112 | Flow Control: 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | No Flow Control 121 | 122 | 123 | 124 | 125 | Hardware Flow Control (RTS/CTS) 126 | 127 | 128 | 129 | 130 | Software Flow Control (XON/XOFF) 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 0 141 | 142 | 143 | 144 | 145 | Parity: 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | No Parity 154 | 155 | 156 | 157 | 158 | Even 159 | 160 | 161 | 162 | 163 | Odd 164 | 165 | 166 | 167 | 168 | Space 169 | 170 | 171 | 172 | 173 | Mark 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 0 184 | 185 | 186 | 187 | 188 | Stop Bits: 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | One Stop Bit 197 | 198 | 199 | 200 | 201 | One & Half Stop Bit 202 | 203 | 204 | 205 | 206 | Two Stop Bits 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | UI 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | Tabbed windows 228 | 229 | 230 | 231 | 232 | 233 | 234 | Background Color: 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | Qt::Horizontal 244 | 245 | 246 | 247 | 40 248 | 20 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 100 258 | 0 259 | 260 | 261 | 262 | PointingHandCursor 263 | 264 | 265 | 266 | QPushButton { 267 | background-color: #a0a0a0; border: 1px solid black; 268 | } 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | true 277 | 278 | 279 | false 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | Qt::Horizontal 294 | 295 | 296 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | buttonBox 308 | accepted() 309 | Settings 310 | accept() 311 | 312 | 313 | 248 314 | 254 315 | 316 | 317 | 157 318 | 274 319 | 320 | 321 | 322 | 323 | buttonBox 324 | rejected() 325 | Settings 326 | reject() 327 | 328 | 329 | 316 330 | 260 331 | 332 | 333 | 286 334 | 274 335 | 336 | 337 | 338 | 339 | 340 | -------------------------------------------------------------------------------- /mainwindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 488 10 | 440 11 | 12 | 13 | 14 | FlexiPlot[*] 15 | 16 | 17 | 18 | :/appicon.ico:/appicon.ico 19 | 20 | 21 | 22 | 23 | 24 | 25 | Qt::ScrollBarAsNeeded 26 | 27 | 28 | Qt::ScrollBarAsNeeded 29 | 30 | 31 | QMdiArea::SubWindowView 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 0 41 | 0 42 | 488 43 | 21 44 | 45 | 46 | 47 | 48 | File 49 | 50 | 51 | 52 | Open Recent 53 | 54 | 55 | 56 | :/images/document-open-recent.png:/images/document-open-recent.png 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | Serial 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Graph 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | Help 91 | 92 | 93 | 94 | 95 | 96 | Windows 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | Tools 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | TopToolBarArea 118 | 119 | 120 | false 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | :/images/application-exit.png:/images/application-exit.png 143 | 144 | 145 | Exit 146 | 147 | 148 | 149 | 150 | 151 | :/images/Connect.png:/images/Connect.png 152 | 153 | 154 | Connect 155 | 156 | 157 | Connect To Device 158 | 159 | 160 | Ctrl+F 161 | 162 | 163 | 164 | 165 | 166 | :/images/Disconnect.png:/images/Disconnect.png 167 | 168 | 169 | Disconnect 170 | 171 | 172 | Disconnect From Device 173 | 174 | 175 | Ctrl+D 176 | 177 | 178 | 179 | 180 | 181 | :/images/settings.png:/images/settings.png 182 | 183 | 184 | Settings 185 | 186 | 187 | 188 | 189 | 190 | :/images/linechart.ico:/images/linechart.ico 191 | 192 | 193 | Add Line Chart 194 | 195 | 196 | Ctrl+1 197 | 198 | 199 | 200 | 201 | 202 | :/images/help-about.png:/images/help-about.png 203 | 204 | 205 | About 206 | 207 | 208 | 209 | 210 | 211 | :/images/document-new.png:/images/document-new.png 212 | 213 | 214 | New 215 | 216 | 217 | Ctrl+N 218 | 219 | 220 | 221 | 222 | 223 | :/images/document-open-folder.png:/images/document-open-folder.png 224 | 225 | 226 | Open 227 | 228 | 229 | Ctrl+O 230 | 231 | 232 | 233 | 234 | 235 | :/images/document-save.png:/images/document-save.png 236 | 237 | 238 | Save 239 | 240 | 241 | Ctrl+S 242 | 243 | 244 | 245 | 246 | 247 | :/images/document-save-as.png:/images/document-save-as.png 248 | 249 | 250 | Save As 251 | 252 | 253 | 254 | 255 | 256 | :/images/window-duplicate.png:/images/window-duplicate.png 257 | 258 | 259 | Cascade 260 | 261 | 262 | Alt+C 263 | 264 | 265 | 266 | 267 | 268 | :/images/view-split-left-right.png:/images/view-split-left-right.png 269 | 270 | 271 | Tile 272 | 273 | 274 | Alt+T 275 | 276 | 277 | 278 | 279 | 280 | :/images/04_maps.png:/images/04_maps.png 281 | 282 | 283 | Add Map 284 | 285 | 286 | 287 | 288 | 289 | :/images/utilities-terminal.png:/images/utilities-terminal.png 290 | 291 | 292 | terminal 293 | 294 | 295 | Opens Serial Terminal 296 | 297 | 298 | 299 | 300 | 301 | :/images/view-statistics.png:/images/view-statistics.png 302 | 303 | 304 | Add Bar Graph 305 | 306 | 307 | Ctrl+2 308 | 309 | 310 | 311 | 312 | true 313 | 314 | 315 | false 316 | 317 | 318 | 319 | :/images/system-lock-screen.png:/images/system-lock-screen.png 320 | 321 | 322 | Lock Widget Position 323 | 324 | 325 | <html><head/><body><p>Lock widgets in their current size and position</p></body></html> 326 | 327 | 328 | If checked allows graphs to be moved around. Uncheck to fix them in a position 329 | 330 | 331 | Ctrl+L 332 | 333 | 334 | 335 | 336 | Debug Tools 337 | 338 | 339 | 340 | 341 | 342 | :/images/piechart.ico:/images/piechart.ico 343 | 344 | 345 | Add Pie Chart 346 | 347 | 348 | Ctrl+3 349 | 350 | 351 | 352 | 353 | Clear Menu 354 | 355 | 356 | 357 | 358 | false 359 | 360 | 361 | (empty) 362 | 363 | 364 | 365 | 366 | 367 | :/images/scatter.png:/images/scatter.png 368 | 369 | 370 | Add Scatter Chart 371 | 372 | 373 | Ctrl+4 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | -------------------------------------------------------------------------------- /widgets/piechart.cpp: -------------------------------------------------------------------------------- 1 | #include "piechart.h" 2 | #include "ui_piechart.h" 3 | 4 | QT_CHARTS_USE_NAMESPACE 5 | 6 | PieChart::PieChart(QWidget *parent) : 7 | AbstractWidget(parent), 8 | ui(new Ui::PieChart) 9 | { 10 | ui->setupUi(this); 11 | 12 | chart = new QChart(); 13 | 14 | chart->setTitle( ui->titleEdit->text() ); 15 | QFont tFont = chart->titleFont(); 16 | tFont.setPointSizeF( 15 ); 17 | tFont.setBold( true ); 18 | chart->setTitleFont( tFont ); 19 | 20 | 21 | chart->setAnimationOptions( QChart::AllAnimations ); 22 | 23 | ui->chartView->setChart( chart ); 24 | ui->chartView->setRenderHint(QPainter::Antialiasing); 25 | 26 | 27 | connect(ui->idEdit, SIGNAL(textEdited(QString)), this, SLOT(setId(QString))); 28 | connect(ui->titleEdit, SIGNAL(textEdited(QString)), this, SLOT(setTitle(QString))); 29 | 30 | connect(ui->hPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 31 | connect(ui->vPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 32 | connect(ui->sizeFactorSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 33 | connect(ui->startAngleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 34 | connect(ui->endAngleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 35 | connect(ui->holeSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 36 | connect(ui->explodeSliceCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 37 | connect(ui->animationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 38 | connect(ui->themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 39 | connect(ui->antialiasingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 40 | 41 | ui->legendDetachedParamGroup->setVisible(false); 42 | connect(ui->legendShowCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 43 | connect(ui->legendBoldCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 44 | connect(ui->legendItalicCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 45 | connect(ui->legendUnderlineCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 46 | connect(ui->legendFontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 47 | connect(ui->legendFontComboBox, SIGNAL(currentFontChanged(QFont)), this, SLOT(settingsChanged())); 48 | connect(ui->legendPositionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 49 | connect(ui->legendHPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 50 | connect(ui->legendVPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 51 | connect(ui->legendWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 52 | connect(ui->legendHeightSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 53 | 54 | connect(ui->labelArmLengthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 55 | connect(ui->labelPosComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 56 | connect(ui->showLabelsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 57 | 58 | } 59 | 60 | void PieChart::settingsChanged() 61 | { 62 | qDebug() << "Settings changed by: " << QObject::sender(); 63 | Config::getInstance()->setUnsavedChanges(true); 64 | plot(); 65 | } 66 | 67 | bool PieChart::validPacket(QString packet) 68 | { 69 | /* Regular expresion for multi column packet: 70 | * Colo Test cases: 71 | * P0|Slice 1|255,0,0|10.0048|Slice 2|0,255,0|30|Slice 3|0,0,255|20 72 | * 73 | * Regexp: 74 | * [a-zA-Z0-9]+(\|[a-zA-Z0-9 ]+\|\d{1,3},\d{1,3},\d{1,3}\|(\-*\d+(\.{0,1}\d+)*)*)+ 75 | * 76 | * 77 | * No Color Test Cases: 78 | * P0|Slice 1|10|Slice 2|30|Slice 3|20 79 | * 80 | * Regexp: 81 | * [a-zA-Z0-9]+(\|[a-zA-Z0-9 ]+\|(\-*\d+(\.{0,1}\d+)*)*)+ 82 | * 83 | */ 84 | 85 | QRegExp fullPacket("[a-zA-Z0-9]+(\\|[a-zA-Z0-9 ]+\\|\\d{1,3},\\d{1,3},\\d{1,3}\\|(\\-*\\d+(\\.{0,1}\\d+)*)*)+"); 86 | QRegExp noColorPacket("[a-zA-Z0-9]+(\\|[a-zA-Z0-9 ]+\\|(\\-*\\d+(\\.{0,1}\\d+)*)*)+"); 87 | 88 | 89 | return fullPacket.exactMatch(packet) || noColorPacket.exactMatch( packet ); 90 | } 91 | 92 | void PieChart::reset() 93 | { 94 | items.clear(); 95 | chart->removeAllSeries(); 96 | } 97 | 98 | void PieChart::serialPacket(QStringList packet) 99 | { 100 | // qDebug() << packet; 101 | 102 | items.clear(); 103 | 104 | for(int i=1; iremoveAllSeries(); 142 | 143 | chart->setAnimationOptions( (QChart::AnimationOption)ui->animationComboBox->currentIndex() ); 144 | ui->chartView->setRenderHint(QPainter::Antialiasing, ui->antialiasingCheckBox->isChecked()); 145 | 146 | //create series 147 | QPieSeries * series = new QPieSeries(); 148 | // series->setLabelsVisible(); 149 | 150 | series->setHorizontalPosition( ui->hPosSpinBox->value() ); 151 | series->setVerticalPosition( ui->vPosSpinBox->value() ); 152 | series->setPieSize( ui->sizeFactorSpinBox->value() ); 153 | series->setPieStartAngle( ui->startAngleSpinBox->value() ); 154 | series->setPieEndAngle( ui->endAngleSpinBox->value() ); 155 | series->setHoleSize( ui->holeSizeSpinBox->value() ); 156 | 157 | foreach( pie_chart_plot_item_t sliceItem, items ) 158 | { 159 | FlexiPieSlice * slice = new FlexiPieSlice( sliceItem.name, sliceItem.value ); 160 | slice->setExplodeOnHover( ui->explodeSliceCheckBox->isChecked() ); 161 | if(sliceItem.colorIsSet) 162 | { 163 | //slice->setPen(QPen(sliceItem.color, 2)); 164 | slice->setBrush(sliceItem.color); 165 | } 166 | *series << slice; 167 | } 168 | 169 | chart->addSeries(series); 170 | 171 | //Legend settings 172 | chart->legend()->setVisible(ui->legendShowCheckBox->isChecked()); 173 | 174 | if(ui->legendPositionComboBox->currentIndex() == POS_DETACHED && chart->legend()->isAttachedToChart() ) 175 | { 176 | chart->legend()->detachFromChart(); 177 | chart->legend()->setBackgroundVisible(true); 178 | chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128))); 179 | chart->legend()->setPen(QPen(QColor(192, 192, 192, 192))); 180 | 181 | ui->legendDetachedParamGroup->setVisible(true); 182 | } 183 | else if(ui->legendPositionComboBox->currentIndex() != POS_DETACHED) 184 | { 185 | chart->legend()->attachToChart(); 186 | chart->legend()->setBackgroundVisible(false); 187 | ui->legendDetachedParamGroup->setVisible(false); 188 | } 189 | 190 | switch(ui->legendPositionComboBox->currentIndex()) 191 | { 192 | case POS_TOP: chart->legend()->setAlignment(Qt::AlignTop); break; 193 | case POS_RIGHT: chart->legend()->setAlignment(Qt::AlignRight); break; 194 | case POS_BOTTOM: chart->legend()->setAlignment(Qt::AlignBottom); break; 195 | case POS_LEFT: chart->legend()->setAlignment(Qt::AlignLeft); break; 196 | case POS_DETACHED: updateDetachedLegendLayout(); break; 197 | default: chart->legend()->setAlignment(Qt::AlignBottom); 198 | } 199 | QFont lFont = ui->legendFontComboBox->currentFont(); 200 | lFont.setBold( ui->legendBoldCheckBox->isChecked() ); 201 | lFont.setItalic( ui->legendItalicCheckBox->isChecked() ); 202 | lFont.setUnderline( ui->legendUnderlineCheckBox->isChecked() ); 203 | lFont.setPointSizeF( ui->legendFontSizeSpinBox->value() ); 204 | chart->legend()->setFont( lFont ); 205 | 206 | 207 | //Label config 208 | series->setLabelsVisible( ui->showLabelsCheckBox->isChecked() ); 209 | if(ui->showLabelsCheckBox->isChecked()) 210 | { 211 | foreach( QPieSlice* slice, series->slices()) 212 | slice->setLabelArmLengthFactor( ui->labelArmLengthSpinBox->value() ); 213 | series->setLabelsPosition( (QPieSlice::LabelPosition)ui->labelPosComboBox->currentIndex() ); 214 | } 215 | 216 | //Configure theme 217 | chart->setTheme( (QChart::ChartTheme) ui->themeComboBox->currentIndex() ); 218 | QFont tFont = chart->titleFont(); 219 | tFont.setPointSizeF( 15 ); 220 | tFont.setBold( true ); 221 | chart->setTitleFont( tFont ); 222 | } 223 | 224 | void PieChart::updateDetachedLegendLayout() 225 | { 226 | chart->legend()->setGeometry(QRectF( ui->legendHPosSpinBox->value(), 227 | ui->legendVPosSpinBox->value(), 228 | ui->legendWidthSpinBox->value(), 229 | ui->legendHeightSpinBox->value())); 230 | chart->legend()->update(); 231 | } 232 | 233 | void PieChart::xmlStream(QXmlStreamWriter *writer) 234 | { 235 | writer->writeTextElement("id", this->id); 236 | writer->writeTextElement("title", ui->titleEdit->text()); 237 | 238 | writer->writeTextElement("hpos", QString::number(ui->hPosSpinBox->value()) ); 239 | writer->writeTextElement("vpos", QString::number(ui->hPosSpinBox->value()) ); 240 | writer->writeTextElement("size_factor", QString::number(ui->sizeFactorSpinBox->value()) ); 241 | writer->writeTextElement("start_angle", QString::number(ui->startAngleSpinBox->value()) ); 242 | writer->writeTextElement("end_angle", QString::number(ui->endAngleSpinBox->value()) ); 243 | writer->writeTextElement("hole_size", QString::number(ui->holeSizeSpinBox->value()) ); 244 | writer->writeTextElement("explode_slice_on_hover", QString::number(ui->explodeSliceCheckBox->isChecked()) ); 245 | writer->writeTextElement("animation", QString::number(ui->animationComboBox->currentIndex()) ); 246 | writer->writeTextElement("theme", QString::number(ui->themeComboBox->currentIndex()) ); 247 | writer->writeTextElement("antialiasing", QString::number(ui->antialiasingCheckBox->isChecked()) ); 248 | 249 | writer->writeTextElement("legend_enabled", QString::number(ui->legendShowCheckBox->isChecked()) ); 250 | writer->writeTextElement("legend_position", QString::number(ui->legendPositionComboBox->currentIndex()) ); 251 | writer->writeTextElement("legend_hpos", QString::number(ui->legendHPosSpinBox->value()) ); 252 | writer->writeTextElement("legend_vpos", QString::number(ui->legendVPosSpinBox->value()) ); 253 | writer->writeTextElement("legend_width", QString::number(ui->legendWidthSpinBox->value()) ); 254 | writer->writeTextElement("legend_height", QString::number(ui->legendHeightSpinBox->value()) ); 255 | writer->writeTextElement("legend_font", ui->legendFontComboBox->currentText() ); 256 | writer->writeTextElement("legend_bold", QString::number(ui->legendBoldCheckBox->isChecked()) ); 257 | writer->writeTextElement("legend_italic", QString::number(ui->legendItalicCheckBox->isChecked()) ); 258 | writer->writeTextElement("legend_underline", QString::number(ui->legendUnderlineCheckBox->isChecked()) ); 259 | writer->writeTextElement("legend_font_size", QString::number(ui->legendFontSizeSpinBox->value()) ); 260 | 261 | writer->writeTextElement("labels_enabled", QString::number(ui->showLabelsCheckBox->isChecked()) ); 262 | writer->writeTextElement("label_arm_length", QString::number(ui->labelArmLengthSpinBox->value()) ); 263 | writer->writeTextElement("labels_position", QString::number(ui->labelPosComboBox->currentIndex()) ); 264 | } 265 | 266 | void PieChart::xmlParse(QXmlStreamReader *xml) 267 | { 268 | blockAllSignals(true); 269 | /* Let's check that we're really getting a person. */ 270 | if(xml->tokenType() != QXmlStreamReader::StartElement && 271 | xml->name() == "Widget") { 272 | return; 273 | } 274 | 275 | /* Next element... */ 276 | xml->readNext(); 277 | 278 | while(!(xml->tokenType() == QXmlStreamReader::EndElement && xml->name() == "Widget")) 279 | { 280 | if(xml->name() == "WindowGeometry") 281 | { 282 | QXmlStreamAttributes attributes = xml->attributes(); 283 | 284 | if(attributes.hasAttribute("x") && attributes.hasAttribute("y") 285 | && attributes.hasAttribute("width") && attributes.hasAttribute("height")) 286 | { 287 | this->parentWidget()->setGeometry( 288 | attributes.value("x").toInt(), 289 | attributes.value("y").toInt(), 290 | attributes.value("width").toInt(), 291 | attributes.value("height").toInt() 292 | ); 293 | } 294 | 295 | } 296 | 297 | if(xml->name() == "id") 298 | { 299 | QString str = xml->readElementText(); 300 | id = str; 301 | ui->idEdit->setText(str); 302 | //this->setWindowTitle(QString("Plot: %1").arg(str)); 303 | } 304 | 305 | if(xml->name() == "title") 306 | { 307 | QString str = xml->readElementText(); 308 | chart->setTitle( str ); 309 | ui->titleEdit->setText(str); 310 | 311 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(ui->titleEdit->text()).arg(ui->idEdit->text())); 312 | } 313 | 314 | if(xml->name() == "hpos") 315 | { 316 | double realVal = xml->readElementText().toDouble(); 317 | ui->hPosSpinBox->setValue(realVal); 318 | } 319 | 320 | if(xml->name() == "vpos") 321 | { 322 | double realVal = xml->readElementText().toDouble(); 323 | ui->vPosSpinBox->setValue(realVal); 324 | } 325 | 326 | if(xml->name() == "size_factor") 327 | { 328 | double realVal = xml->readElementText().toDouble(); 329 | ui->sizeFactorSpinBox->setValue(realVal); 330 | } 331 | 332 | if(xml->name() == "start_angle") 333 | { 334 | double realVal = xml->readElementText().toDouble(); 335 | ui->startAngleSpinBox->setValue(realVal); 336 | } 337 | 338 | if(xml->name() == "end_angle") 339 | { 340 | double realVal = xml->readElementText().toDouble(); 341 | ui->endAngleSpinBox->setValue(realVal); 342 | } 343 | 344 | if(xml->name() == "hole_size") 345 | { 346 | double realVal = xml->readElementText().toDouble(); 347 | ui->holeSizeSpinBox->setValue(realVal); 348 | } 349 | 350 | if(xml->name() == "explode_slice_on_hover") 351 | { 352 | int intVal = xml->readElementText().toInt(); 353 | if(intVal > 0) 354 | ui->explodeSliceCheckBox->setCheckState( Qt::Checked ); 355 | else 356 | ui->explodeSliceCheckBox->setCheckState( Qt::Unchecked ); 357 | } 358 | 359 | if(xml->name() == "animation") 360 | { 361 | int intVal = xml->readElementText().toInt(); 362 | ui->animationComboBox->setCurrentIndex(intVal); 363 | } 364 | 365 | if(xml->name() == "theme") 366 | { 367 | int intVal = xml->readElementText().toInt(); 368 | ui->themeComboBox->setCurrentIndex(intVal); 369 | } 370 | 371 | if(xml->name() == "antialiasing") 372 | { 373 | int intVal = xml->readElementText().toInt(); 374 | if(intVal > 0) 375 | ui->antialiasingCheckBox->setCheckState( Qt::Checked ); 376 | else 377 | ui->antialiasingCheckBox->setCheckState( Qt::Unchecked ); 378 | } 379 | 380 | if(xml->name() == "legend_enabled") 381 | { 382 | int intVal = xml->readElementText().toInt(); 383 | if(intVal > 0) 384 | ui->legendShowCheckBox->setCheckState( Qt::Checked ); 385 | else 386 | ui->legendShowCheckBox->setCheckState( Qt::Unchecked ); 387 | } 388 | 389 | if(xml->name() == "legend_position") 390 | { 391 | int intVal = xml->readElementText().toInt(); 392 | ui->legendPositionComboBox->setCurrentIndex(intVal); 393 | // if(intVal == POS_DETACHED) 394 | // ui->legendDetachedParamGroup->setVisible(true); 395 | } 396 | 397 | if(xml->name() == "legend_hpos") 398 | { 399 | double realVal = xml->readElementText().toDouble(); 400 | ui->legendHPosSpinBox->setValue(realVal); 401 | } 402 | 403 | if(xml->name() == "legend_vpos") 404 | { 405 | double realVal = xml->readElementText().toDouble(); 406 | ui->legendVPosSpinBox->setValue(realVal); 407 | } 408 | 409 | if(xml->name() == "legend_width") 410 | { 411 | double realVal = xml->readElementText().toDouble(); 412 | ui->legendWidthSpinBox->setValue(realVal); 413 | } 414 | 415 | if(xml->name() == "legend_height") 416 | { 417 | double realVal = xml->readElementText().toDouble(); 418 | ui->legendHeightSpinBox->setValue(realVal); 419 | } 420 | 421 | if(xml->name() == "legend_font") 422 | { 423 | QString str = xml->readElementText(); 424 | ui->legendFontComboBox->setCurrentText( str ); 425 | } 426 | 427 | if(xml->name() == "legend_bold") 428 | { 429 | int intVal = xml->readElementText().toInt(); 430 | ui->legendBoldCheckBox->setChecked( (bool)intVal ); 431 | } 432 | 433 | if(xml->name() == "legend_italic") 434 | { 435 | int intVal = xml->readElementText().toInt(); 436 | ui->legendItalicCheckBox->setChecked( (bool)intVal ); 437 | } 438 | 439 | if(xml->name() == "legend_underline") 440 | { 441 | int intVal = xml->readElementText().toInt(); 442 | ui->legendUnderlineCheckBox->setChecked( (bool)intVal ); 443 | } 444 | 445 | if(xml->name() == "legend_font_size") 446 | { 447 | double realVal = xml->readElementText().toDouble(); 448 | ui->legendFontSizeSpinBox->setValue(realVal); 449 | } 450 | 451 | if(xml->name() == "labels_enabled") 452 | { 453 | int intVal = xml->readElementText().toInt(); 454 | if(intVal > 0) 455 | ui->showLabelsCheckBox->setCheckState( Qt::Checked ); 456 | else 457 | ui->showLabelsCheckBox->setCheckState( Qt::Unchecked ); 458 | } 459 | 460 | if(xml->name() == "label_arm_length") 461 | { 462 | double realVal = xml->readElementText().toDouble(); 463 | ui->labelArmLengthSpinBox->setValue(realVal); 464 | } 465 | 466 | if(xml->name() == "labels_position") 467 | { 468 | int intVal = xml->readElementText().toInt(); 469 | ui->labelPosComboBox->setCurrentIndex(intVal); 470 | } 471 | 472 | 473 | 474 | 475 | 476 | /* ...and next... */ 477 | xml->readNext(); 478 | } 479 | 480 | blockAllSignals(false); 481 | settingsChanged(); 482 | } 483 | 484 | void PieChart::setId(QString str) 485 | { 486 | id = str; 487 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(ui->titleEdit->text()).arg(str)); 488 | 489 | ui->idEdit->blockSignals(true); 490 | ui->idEdit->setText( str ); 491 | ui->idEdit->blockSignals(false); 492 | 493 | Config::getInstance()->setUnsavedChanges(true); 494 | } 495 | 496 | void PieChart::setTitle(QString str) 497 | { 498 | chart->setTitle( str ); 499 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(str).arg(id)); 500 | Config::getInstance()->setUnsavedChanges(true); 501 | } 502 | 503 | void PieChart::blockAllSignals(bool block) 504 | { 505 | ui->idEdit->blockSignals(block); 506 | ui->titleEdit->blockSignals(block); 507 | 508 | ui->hPosSpinBox->blockSignals(block); 509 | ui->vPosSpinBox->blockSignals(block); 510 | ui->sizeFactorSpinBox->blockSignals(block); 511 | ui->startAngleSpinBox->blockSignals(block); 512 | ui->endAngleSpinBox->blockSignals(block); 513 | ui->holeSizeSpinBox->blockSignals(block); 514 | ui->explodeSliceCheckBox->blockSignals(block); 515 | ui->animationComboBox->blockSignals(block); 516 | ui->themeComboBox->blockSignals(block); 517 | ui->antialiasingCheckBox->blockSignals(block); 518 | 519 | ui->legendShowCheckBox->blockSignals(block); 520 | ui->legendBoldCheckBox->blockSignals(block); 521 | ui->legendItalicCheckBox->blockSignals(block); 522 | ui->legendUnderlineCheckBox->blockSignals(block); 523 | ui->legendFontSizeSpinBox->blockSignals(block); 524 | ui->legendFontComboBox->blockSignals(block); 525 | ui->legendPositionComboBox->blockSignals(block); 526 | ui->legendHPosSpinBox->blockSignals(block); 527 | ui->legendVPosSpinBox->blockSignals(block); 528 | ui->legendWidthSpinBox->blockSignals(block); 529 | ui->legendHeightSpinBox->blockSignals(block); 530 | 531 | ui->labelArmLengthSpinBox->blockSignals(block); 532 | ui->labelPosComboBox->blockSignals(block); 533 | ui->showLabelsCheckBox->blockSignals(block); 534 | } 535 | 536 | PieChart::~PieChart() 537 | { 538 | delete ui; 539 | } 540 | -------------------------------------------------------------------------------- /widgets/bargraph.cpp: -------------------------------------------------------------------------------- 1 | #include "bargraph.h" 2 | #include "ui_bargraph.h" 3 | 4 | QT_CHARTS_USE_NAMESPACE 5 | 6 | BarGraph::BarGraph(QWidget *parent) : 7 | AbstractWidget(parent), 8 | ui(new Ui::BarGraph) 9 | { 10 | ui->setupUi(this); 11 | 12 | 13 | 14 | 15 | chart = new QChart(); 16 | 17 | 18 | chart->setTitle( ui->titleEdit->text() ); 19 | QFont tFont = chart->titleFont(); 20 | tFont.setPointSizeF( 15 ); 21 | tFont.setBold( true ); 22 | chart->setTitleFont( tFont ); 23 | 24 | chart->setAnimationOptions(QChart::SeriesAnimations); 25 | 26 | chart->createDefaultAxes(); 27 | 28 | chart->legend()->setVisible(true); 29 | chart->legend()->setAlignment(Qt::AlignBottom); 30 | 31 | // QChartView *chartView = new QChartView(chart); 32 | ui->chartView->setChart( chart ); 33 | ui->chartView->setRenderHint(QPainter::Antialiasing); 34 | 35 | // this->layout()->addWidget( chartView ); 36 | 37 | this->setWindowTitle(ui->titleEdit->text()); 38 | 39 | connect(ui->idEdit, SIGNAL(textEdited(QString)), this, SLOT(setId(QString))); 40 | connect(ui->titleEdit, SIGNAL(textEdited(QString)), this, SLOT(setTitle(QString))); 41 | connect(ui->nameXaxis, SIGNAL(textEdited(QString)), this, SLOT(settingsChanged())); 42 | connect(ui->nameYaxis, SIGNAL(textEdited(QString)), this, SLOT(settingsChanged())); 43 | 44 | connect(ui->barChartTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 45 | connect(ui->animationComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 46 | connect(ui->themeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 47 | connect(ui->antialiasingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 48 | 49 | 50 | ui->legendDetachedParamGroup->setVisible(false); 51 | connect(ui->legendShowCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 52 | connect(ui->legendBoldCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 53 | connect(ui->legendItalicCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 54 | connect(ui->legendUnderlineCheckBox, SIGNAL(clicked(bool)), this, SLOT(settingsChanged())); 55 | connect(ui->legendFontSizeSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 56 | connect(ui->legendFontComboBox, SIGNAL(currentFontChanged(QFont)), this, SLOT(settingsChanged())); 57 | connect(ui->legendPositionComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 58 | connect(ui->legendHPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 59 | connect(ui->legendVPosSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 60 | connect(ui->legendWidthSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 61 | connect(ui->legendHeightSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 62 | 63 | connect(ui->showLabelsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 64 | connect(ui->labelAngleSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 65 | connect(ui->labelFormatEdit, SIGNAL(textChanged(QString)), this, SLOT(settingsChanged())); 66 | connect(ui->labelPosComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(settingsChanged())); 67 | 68 | connect(ui->autoScaleValueAxisCheckBox, SIGNAL(stateChanged(int)), this, SLOT(settingsChanged())); 69 | connect(ui->maxValueAxisSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 70 | connect(ui->minValueAxisSpinBox, SIGNAL(valueChanged(double)), this, SLOT(settingsChanged())); 71 | 72 | 73 | readyToPlot = true; 74 | } 75 | 76 | void BarGraph::settingsChanged() 77 | { 78 | if(!readyToPlot) 79 | return; 80 | 81 | qDebug() << "Settings changed by: " << QObject::sender(); 82 | Config::getInstance()->setUnsavedChanges(true); 83 | plot(); 84 | } 85 | 86 | void BarGraph::setTitle(QString str) 87 | { 88 | chart->setTitle( str ); 89 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(str).arg(id)); 90 | Config::getInstance()->setUnsavedChanges(true); 91 | } 92 | 93 | bool BarGraph::validPacket(QString packet) 94 | { 95 | /* Regular expresion for multi column packet: 96 | * Colo Test cases: 97 | * P0|Jan;Feb;Mar|Jane|255,0,0|25 15 17|John|255,0,0|8 9 23 98 | * P0|Jan|Jane|255,0,0|25|John|255,0,0|8 99 | * Regexp: 100 | * [a-zA-Z0-9]+\|[a-zA-Z0-9 \;]+(\|[a-zA-Z0-9 ]+\|\d{1,3},\d{1,3},\d{1,3}\|(\-*\d+(\.{0,1}\d+)*\s?)*)+ 101 | * 102 | * 103 | * No Color Test Cases: 104 | * P0|Jan;Feb;Mar|Jane|25 15 17|John|8 9 23 105 | * P0|Jan|Jane|25|John|8 106 | * 107 | * Regexp: 108 | * [a-zA-Z0-9]+\|[a-zA-Z0-9 \;]+(\|[a-zA-Z0-9 ]+\|(\-*\d+(\.{0,1}\d+)*\s?)*)+ 109 | * 110 | */ 111 | QRegExp fullPacket("[a-zA-Z0-9]+\\|[a-zA-Z0-9 \\;]+(\\|[a-zA-Z0-9 ]+\\|\\d{1,3},\\d{1,3},\\d{1,3}\\|(\\-*\\d+(\\.{0,1}\\d+)*\\s?)*)+"); 112 | QRegExp noColorPacket("[a-zA-Z0-9]+\\|[a-zA-Z0-9 \\;]+(\\|[a-zA-Z0-9 ]+\\|(\\-*\\d+(\\.{0,1}\\d+)*\\s?)*)+"); 113 | 114 | // qDebug() << fullPacket.exactMatch(packet) << noColorPacket.exactMatch( packet ); 115 | 116 | return fullPacket.exactMatch(packet) || noColorPacket.exactMatch( packet ); 117 | } 118 | 119 | void BarGraph::serialPacket(QStringList packet) 120 | { 121 | // qDebug() << packet; 122 | categories = packet[1].split(";"); 123 | 124 | // qDebug() << categories; 125 | 126 | items.clear(); 127 | 128 | for(int i=2; iseries() ); 169 | qDeleteAll( chart->axes() ); 170 | 171 | chart->setAnimationOptions( (QChart::AnimationOption)ui->animationComboBox->currentIndex() ); 172 | ui->chartView->setRenderHint(QPainter::Antialiasing, ui->antialiasingCheckBox->isChecked()); 173 | 174 | QAbstractBarSeries* series; 175 | switch( ui->barChartTypeComboBox->currentIndex() ) { 176 | case TYPE_NORMAL: series = new QBarSeries(); break; 177 | case TYPE_STACKED: series = new QStackedBarSeries(); break; 178 | case TYPE_PERCENT: series = new QPercentBarSeries(); break; 179 | case TYPE_HORIZONTAL: series = new QHorizontalBarSeries(); break; 180 | case TYPE_HORIZONTAL_STACKED: series = new QHorizontalStackedBarSeries(); break; 181 | case TYPE_HORIZONTAL_PERCENT: series = new QHorizontalPercentBarSeries(); break; 182 | default: series = new QBarSeries(); 183 | } 184 | 185 | // series->setLabelsVisible( true ); 186 | 187 | foreach(bar_graph_plot_item_t item, items) 188 | { 189 | QBarSet *set = new QBarSet(item.set_name); 190 | if(item.colorIsSet) 191 | set->setColor( item.color ); 192 | set->append( item.values ); 193 | 194 | series->append( set ); 195 | } 196 | 197 | chart->addSeries(series); 198 | 199 | QBarCategoryAxis *axis = new QBarCategoryAxis(); 200 | axis->append(categories); 201 | 202 | 203 | chart->createDefaultAxes(); 204 | if( ui->barChartTypeComboBox->currentIndex() == TYPE_NORMAL || 205 | ui->barChartTypeComboBox->currentIndex() == TYPE_STACKED || 206 | ui->barChartTypeComboBox->currentIndex() == TYPE_PERCENT) 207 | { 208 | chart->setAxisX(axis, series); 209 | 210 | if(!ui->autoScaleValueAxisCheckBox->isChecked()) 211 | { 212 | QAbstractAxis *aValueAxis = chart->axes(Qt::Vertical).at(0); 213 | QValueAxis *valueAxis = qobject_cast( aValueAxis ); 214 | // qDebug() << chart->axes(Qt::Vertical).at(0) << ay << ay->max(); 215 | valueAxis->setMax( ui->maxValueAxisSpinBox->value() ); 216 | valueAxis->setMin( ui->minValueAxisSpinBox->value() ); 217 | } 218 | } 219 | else 220 | { 221 | chart->setAxisY(axis, series); 222 | 223 | if(!ui->autoScaleValueAxisCheckBox->isChecked()) 224 | { 225 | QAbstractAxis *aValueAxis = chart->axes(Qt::Horizontal).at(0); 226 | QValueAxis *valueAxis = qobject_cast( aValueAxis ); 227 | // qDebug() << chart->axes(Qt::Vertical).at(0) << ay << ay->max(); 228 | valueAxis->setMax( ui->maxValueAxisSpinBox->value() ); 229 | valueAxis->setMin( ui->minValueAxisSpinBox->value() ); 230 | } 231 | } 232 | 233 | chart->axisX()->setTitleText( ui->nameXaxis->text() ); 234 | chart->axisY()->setTitleText( ui->nameYaxis->text() ); 235 | 236 | 237 | 238 | 239 | //Legend settings 240 | chart->legend()->setVisible(ui->legendShowCheckBox->isChecked()); 241 | 242 | //Hmm I haven't figured out yet, how to temprarly hide a set in series... only to delete 243 | /*foreach(QLegendMarker* marker, chart->legend()->markers()) 244 | { 245 | disconnect(marker, SIGNAL(clicked()), this, SLOT(legendMarkerClicked())); 246 | connect(marker, SIGNAL(clicked()), this, SLOT(legendMarkerClicked())); 247 | }*/ 248 | 249 | if(ui->legendPositionComboBox->currentIndex() == POS_DETACHED && chart->legend()->isAttachedToChart() ) 250 | { 251 | chart->legend()->detachFromChart(); 252 | chart->legend()->setBackgroundVisible(true); 253 | chart->legend()->setBrush(QBrush(QColor(128, 128, 128, 128))); 254 | chart->legend()->setPen(QPen(QColor(192, 192, 192, 192))); 255 | 256 | ui->legendDetachedParamGroup->setVisible(true); 257 | } 258 | else if(ui->legendPositionComboBox->currentIndex() != POS_DETACHED) 259 | { 260 | chart->legend()->attachToChart(); 261 | chart->legend()->setBackgroundVisible(false); 262 | ui->legendDetachedParamGroup->setVisible(false); 263 | } 264 | 265 | switch(ui->legendPositionComboBox->currentIndex()) 266 | { 267 | case POS_TOP: chart->legend()->setAlignment(Qt::AlignTop); break; 268 | case POS_RIGHT: chart->legend()->setAlignment(Qt::AlignRight); break; 269 | case POS_BOTTOM: chart->legend()->setAlignment(Qt::AlignBottom); break; 270 | case POS_LEFT: chart->legend()->setAlignment(Qt::AlignLeft); break; 271 | case POS_DETACHED: updateDetachedLegendLayout(); break; 272 | default: chart->legend()->setAlignment(Qt::AlignBottom); 273 | } 274 | QFont lFont = ui->legendFontComboBox->currentFont(); 275 | lFont.setBold( ui->legendBoldCheckBox->isChecked() ); 276 | lFont.setItalic( ui->legendItalicCheckBox->isChecked() ); 277 | lFont.setUnderline( ui->legendUnderlineCheckBox->isChecked() ); 278 | lFont.setPointSizeF( ui->legendFontSizeSpinBox->value() ); 279 | chart->legend()->setFont( lFont ); 280 | 281 | 282 | //Label config 283 | series->setLabelsVisible( ui->showLabelsCheckBox->isChecked() ); 284 | if(ui->showLabelsCheckBox->isChecked()) 285 | { 286 | series->setLabelsAngle( ui->labelAngleSpinBox->value() ); 287 | series->setLabelsFormat( ui->labelFormatEdit->text() ); 288 | series->setLabelsPosition( (QAbstractBarSeries::LabelsPosition)ui->labelPosComboBox->currentIndex() ); 289 | } 290 | 291 | 292 | chart->setTheme( (QChart::ChartTheme) ui->themeComboBox->currentIndex() ); 293 | QFont tFont = chart->titleFont(); 294 | tFont.setPointSizeF( 15 ); 295 | tFont.setBold( true ); 296 | chart->setTitleFont( tFont ); 297 | 298 | 299 | 300 | 301 | } 302 | 303 | void BarGraph::updateDetachedLegendLayout() 304 | { 305 | chart->legend()->setGeometry(QRectF( ui->legendHPosSpinBox->value(), 306 | ui->legendVPosSpinBox->value(), 307 | ui->legendWidthSpinBox->value(), 308 | ui->legendHeightSpinBox->value())); 309 | chart->legend()->update(); 310 | } 311 | 312 | void BarGraph::xmlStream(QXmlStreamWriter *writer) 313 | { 314 | writer->writeTextElement("id", this->id); 315 | writer->writeTextElement("title", ui->titleEdit->text()); 316 | writer->writeTextElement("xname", ui->nameXaxis->text()); 317 | writer->writeTextElement("yname", ui->nameYaxis->text()); 318 | 319 | writer->writeTextElement("type", QString::number(ui->barChartTypeComboBox->currentIndex()) ); 320 | writer->writeTextElement("animation", QString::number(ui->animationComboBox->currentIndex()) ); 321 | writer->writeTextElement("theme", QString::number(ui->themeComboBox->currentIndex()) ); 322 | writer->writeTextElement("antialiasing", QString::number(ui->antialiasingCheckBox->isChecked()) ); 323 | 324 | writer->writeTextElement("legend_enabled", QString::number(ui->legendShowCheckBox->isChecked()) ); 325 | writer->writeTextElement("legend_position", QString::number(ui->legendPositionComboBox->currentIndex()) ); 326 | writer->writeTextElement("legend_hpos", QString::number(ui->legendHPosSpinBox->value()) ); 327 | writer->writeTextElement("legend_vpos", QString::number(ui->legendVPosSpinBox->value()) ); 328 | writer->writeTextElement("legend_width", QString::number(ui->legendWidthSpinBox->value()) ); 329 | writer->writeTextElement("legend_height", QString::number(ui->legendHeightSpinBox->value()) ); 330 | writer->writeTextElement("legend_font", ui->legendFontComboBox->currentText() ); 331 | writer->writeTextElement("legend_bold", QString::number(ui->legendBoldCheckBox->isChecked()) ); 332 | writer->writeTextElement("legend_italic", QString::number(ui->legendItalicCheckBox->isChecked()) ); 333 | writer->writeTextElement("legend_underline", QString::number(ui->legendUnderlineCheckBox->isChecked()) ); 334 | writer->writeTextElement("legend_font_size", QString::number(ui->legendFontSizeSpinBox->value()) ); 335 | 336 | writer->writeTextElement("labels_enabled", QString::number(ui->showLabelsCheckBox->isChecked()) ); 337 | writer->writeTextElement("labels_angle", QString::number(ui->labelAngleSpinBox->value()) ); 338 | writer->writeTextElement("labels_position", QString::number(ui->labelPosComboBox->currentIndex()) ); 339 | writer->writeTextElement("labels_format", ui->labelFormatEdit->text() ); 340 | 341 | writer->writeTextElement("auto_scale_value_axis", QString::number(ui->autoScaleValueAxisCheckBox->isChecked() ) ); 342 | writer->writeTextElement("min_scale_value_axis", QString::number(ui->minValueAxisSpinBox->value()) ); 343 | writer->writeTextElement("max_scale_value_axis", QString::number(ui->maxValueAxisSpinBox->value()) ); 344 | 345 | 346 | } 347 | 348 | void BarGraph::xmlParse(QXmlStreamReader *xml) 349 | { 350 | readyToPlot = false; 351 | blockAllSignals(true); 352 | /* Let's check that we're really getting a person. */ 353 | if(xml->tokenType() != QXmlStreamReader::StartElement && 354 | xml->name() == "Widget") { 355 | return; 356 | } 357 | 358 | /* Next element... */ 359 | xml->readNext(); 360 | 361 | while(!(xml->tokenType() == QXmlStreamReader::EndElement && xml->name() == "Widget")) 362 | { 363 | if(xml->name() == "WindowGeometry") 364 | { 365 | QXmlStreamAttributes attributes = xml->attributes(); 366 | 367 | if(attributes.hasAttribute("x") && attributes.hasAttribute("y") 368 | && attributes.hasAttribute("width") && attributes.hasAttribute("height")) 369 | { 370 | this->parentWidget()->setGeometry( 371 | attributes.value("x").toInt(), 372 | attributes.value("y").toInt(), 373 | attributes.value("width").toInt(), 374 | attributes.value("height").toInt() 375 | ); 376 | } 377 | 378 | } 379 | 380 | if(xml->name() == "id") 381 | { 382 | QString str = xml->readElementText(); 383 | id = str; 384 | ui->idEdit->setText(str); 385 | //this->setWindowTitle(QString("Plot: %1").arg(str)); 386 | } 387 | 388 | if(xml->name() == "title") 389 | { 390 | QString str = xml->readElementText(); 391 | chart->setTitle( str ); 392 | ui->titleEdit->setText(str); 393 | 394 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(ui->titleEdit->text()).arg(ui->idEdit->text())); 395 | } 396 | 397 | if(xml->name() == "xname") 398 | { 399 | QString str = xml->readElementText(); 400 | ui->nameXaxis->setText(str); 401 | } 402 | 403 | if(xml->name() == "yname") 404 | { 405 | QString str = xml->readElementText(); 406 | ui->nameYaxis->setText(str); 407 | } 408 | 409 | if(xml->name() == "type") 410 | { 411 | int intVal = xml->readElementText().toInt(); 412 | ui->barChartTypeComboBox->setCurrentIndex(intVal); 413 | } 414 | 415 | if(xml->name() == "animation") 416 | { 417 | int intVal = xml->readElementText().toInt(); 418 | ui->animationComboBox->setCurrentIndex(intVal); 419 | } 420 | 421 | if(xml->name() == "theme") 422 | { 423 | int intVal = xml->readElementText().toInt(); 424 | ui->themeComboBox->setCurrentIndex(intVal); 425 | } 426 | 427 | if(xml->name() == "antialiasing") 428 | { 429 | int intVal = xml->readElementText().toInt(); 430 | if(intVal > 0) 431 | ui->antialiasingCheckBox->setCheckState( Qt::Checked ); 432 | else 433 | ui->antialiasingCheckBox->setCheckState( Qt::Unchecked ); 434 | } 435 | 436 | if(xml->name() == "legend_enabled") 437 | { 438 | int intVal = xml->readElementText().toInt(); 439 | if(intVal > 0) 440 | ui->legendShowCheckBox->setCheckState( Qt::Checked ); 441 | else 442 | ui->legendShowCheckBox->setCheckState( Qt::Unchecked ); 443 | } 444 | 445 | if(xml->name() == "legend_position") 446 | { 447 | int intVal = xml->readElementText().toInt(); 448 | ui->legendPositionComboBox->setCurrentIndex(intVal); 449 | // if(intVal == POS_DETACHED) 450 | // ui->legendDetachedParamGroup->setVisible(true); 451 | } 452 | 453 | if(xml->name() == "legend_hpos") 454 | { 455 | double realVal = xml->readElementText().toDouble(); 456 | ui->legendHPosSpinBox->setValue(realVal); 457 | } 458 | 459 | if(xml->name() == "legend_vpos") 460 | { 461 | double realVal = xml->readElementText().toDouble(); 462 | ui->legendVPosSpinBox->setValue(realVal); 463 | } 464 | 465 | if(xml->name() == "legend_width") 466 | { 467 | double realVal = xml->readElementText().toDouble(); 468 | ui->legendWidthSpinBox->setValue(realVal); 469 | } 470 | 471 | if(xml->name() == "legend_height") 472 | { 473 | double realVal = xml->readElementText().toDouble(); 474 | ui->legendHeightSpinBox->setValue(realVal); 475 | } 476 | 477 | if(xml->name() == "legend_font") 478 | { 479 | QString str = xml->readElementText(); 480 | ui->legendFontComboBox->setCurrentText( str ); 481 | } 482 | 483 | if(xml->name() == "legend_bold") 484 | { 485 | int intVal = xml->readElementText().toInt(); 486 | ui->legendBoldCheckBox->setChecked( (bool)intVal ); 487 | } 488 | 489 | if(xml->name() == "legend_italic") 490 | { 491 | int intVal = xml->readElementText().toInt(); 492 | ui->legendItalicCheckBox->setChecked( (bool)intVal ); 493 | } 494 | 495 | if(xml->name() == "legend_underline") 496 | { 497 | int intVal = xml->readElementText().toInt(); 498 | ui->legendUnderlineCheckBox->setChecked( (bool)intVal ); 499 | } 500 | 501 | if(xml->name() == "legend_font_size") 502 | { 503 | double realVal = xml->readElementText().toDouble(); 504 | ui->legendFontSizeSpinBox->setValue(realVal); 505 | } 506 | 507 | if(xml->name() == "labels_enabled") 508 | { 509 | int intVal = xml->readElementText().toInt(); 510 | if(intVal > 0) 511 | ui->showLabelsCheckBox->setCheckState( Qt::Checked ); 512 | else 513 | ui->showLabelsCheckBox->setCheckState( Qt::Unchecked ); 514 | } 515 | 516 | if(xml->name() == "labels_angle") 517 | { 518 | double realVal = xml->readElementText().toDouble(); 519 | ui->labelAngleSpinBox->setValue(realVal); 520 | } 521 | 522 | if(xml->name() == "labels_position") 523 | { 524 | int intVal = xml->readElementText().toInt(); 525 | ui->labelPosComboBox->setCurrentIndex(intVal); 526 | } 527 | 528 | if(xml->name() == "labels_format") 529 | { 530 | QString str = xml->readElementText(); 531 | ui->labelFormatEdit->setText( str ); 532 | } 533 | 534 | if(xml->name() == "auto_scale_value_axis") 535 | { 536 | int intVal = xml->readElementText().toInt(); 537 | if(intVal > 0) 538 | ui->autoScaleValueAxisCheckBox->setCheckState( Qt::Checked ); 539 | else 540 | ui->autoScaleValueAxisCheckBox->setCheckState( Qt::Unchecked ); 541 | } 542 | 543 | if(xml->name() == "min_scale_value_axis") 544 | { 545 | double realVal = xml->readElementText().toDouble(); 546 | ui->minValueAxisSpinBox->setValue(realVal); 547 | } 548 | 549 | if(xml->name() == "max_scale_value_axis") 550 | { 551 | double realVal = xml->readElementText().toDouble(); 552 | ui->maxValueAxisSpinBox->setValue(realVal); 553 | } 554 | 555 | 556 | /* ...and next... */ 557 | xml->readNext(); 558 | } 559 | 560 | readyToPlot = true; 561 | blockAllSignals(false); 562 | settingsChanged(); 563 | } 564 | 565 | void BarGraph::reset() 566 | { 567 | qDeleteAll( chart->series() ); 568 | qDeleteAll( chart->axes() ); 569 | } 570 | 571 | void BarGraph::setId(QString str) 572 | { 573 | id = str; 574 | this->setWindowTitle(QString("%1 \t|\t ID: %2").arg(ui->titleEdit->text()).arg(str)); 575 | 576 | ui->idEdit->blockSignals(true); 577 | ui->idEdit->setText( str ); 578 | ui->idEdit->blockSignals(false); 579 | 580 | Config::getInstance()->setUnsavedChanges(true); 581 | 582 | } 583 | 584 | //Hmm I haven't figured out yet, how to temprarly hide a set in series... only to delete 585 | void BarGraph::legendMarkerClicked() 586 | { 587 | QLegendMarker* marker = qobject_cast(QObject::sender()); 588 | Q_ASSERT(marker); 589 | 590 | qDebug() << marker->type(); 591 | 592 | switch(marker->type()) 593 | { 594 | case QLegendMarker::LegendMarkerTypeBar: 595 | { 596 | QAbstractBarSeries * barSeries = qobject_cast( marker->series() ); 597 | Q_ASSERT(barSeries); 598 | 599 | 600 | qDebug() << barSeries->barSets().at(0); 601 | 602 | QBarLegendMarker* barMarker = qobject_cast(marker); 603 | Q_ASSERT(barMarker); 604 | qDebug() << barMarker->barset(); 605 | 606 | barSeries->take(barMarker->barset()); 607 | 608 | 609 | break; 610 | } 611 | default: qDebug() << "Unknown marker"; break; 612 | } 613 | } 614 | 615 | void BarGraph::blockAllSignals(bool block) 616 | { 617 | ui->idEdit->blockSignals(block); 618 | ui->titleEdit->blockSignals(block); 619 | ui->nameXaxis->blockSignals(block); 620 | ui->nameYaxis->blockSignals(block); 621 | 622 | ui->barChartTypeComboBox->blockSignals(block); 623 | ui->animationComboBox->blockSignals(block); 624 | ui->themeComboBox->blockSignals(block); 625 | 626 | ui->legendShowCheckBox->blockSignals(block); 627 | ui->legendBoldCheckBox->blockSignals(block); 628 | ui->legendItalicCheckBox->blockSignals(block); 629 | ui->legendUnderlineCheckBox->blockSignals(block); 630 | ui->legendFontSizeSpinBox->blockSignals(block); 631 | ui->legendFontComboBox->blockSignals(block); 632 | ui->legendPositionComboBox->blockSignals(block); 633 | ui->legendHPosSpinBox->blockSignals(block); 634 | ui->legendVPosSpinBox->blockSignals(block); 635 | ui->legendWidthSpinBox->blockSignals(block); 636 | ui->legendHeightSpinBox->blockSignals(block); 637 | 638 | ui->showLabelsCheckBox->blockSignals(block); 639 | ui->labelAngleSpinBox->blockSignals(block); 640 | ui->labelFormatEdit->blockSignals(block); 641 | ui->labelPosComboBox->blockSignals(block); 642 | 643 | ui->autoScaleValueAxisCheckBox->blockSignals(block); 644 | ui->minValueAxisSpinBox->blockSignals(block); 645 | ui->maxValueAxisSpinBox->blockSignals(block); 646 | } 647 | 648 | BarGraph::~BarGraph() 649 | { 650 | delete ui; 651 | } 652 | -------------------------------------------------------------------------------- /widgets/plotter.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Plotter 4 | 5 | 6 | 7 | 0 8 | 0 9 | 412 10 | 357 11 | 12 | 13 | 14 | Form 15 | 16 | 17 | 18 | 19 | 20 | 0 21 | 22 | 23 | 24 | Plot 25 | 26 | 27 | 28 | 29 | 30 | 31 | 0 32 | 0 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | Save current plot to CSV 43 | 44 | 45 | Save 46 | 47 | 48 | 49 | :/images/document-save.png:/images/document-save.png 50 | 51 | 52 | 53 | 54 | 55 | 56 | Qt::Horizontal 57 | 58 | 59 | 60 | 40 61 | 20 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | <html><head/><body><p>Starts/stops data collecting from Serial</p><p>When stopped, you'll be able to zoom in/out and move the graph to further inspect the data.</p></body></html> 70 | 71 | 72 | 73 | 74 | 75 | 76 | :/images/media-playback-start.png 77 | :/images/media-playback-stop.png:/images/media-playback-start.png 78 | 79 | 80 | true 81 | 82 | 83 | true 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | Settings 94 | 95 | 96 | 97 | 98 | 99 | true 100 | 101 | 102 | 103 | 104 | 0 105 | 0 106 | 230 107 | 678 108 | 109 | 110 | 111 | 112 | 113 | 114 | Basic 115 | 116 | 117 | 118 | 119 | 120 | QFormLayout::AllNonFixedFieldsGrow 121 | 122 | 123 | 124 | 125 | <html><head/><body><p>The ID of the graph, for serial thread to properly forward the incoming data from micro-controller.</p><p>You can have the same IDs if you wish, both will receive the packet from the serial thread.</p></body></html> 126 | 127 | 128 | ID: 129 | 130 | 131 | 132 | 133 | 134 | 135 | p1 136 | 137 | 138 | 139 | 140 | 141 | 142 | <html><head/><body><p>Can select the graph to plot in real time or XY plot</p><p><span style=" font-size:10pt;">Sample real-time packet with 3 curves XYZ:</span></p><p>{<span style=" color:#ff0000;">P0|X|255,0,0|100</span><span style=" color:#00ff7f;">|Y|0,255,0|150</span><span style=" color:#5555ff;">|Z|0,0,255|200</span>}</p><p>{Plot ID|Curve 1|Color|Value|Curve 2|Color|Value}</p><p><span style=" font-weight:600;">Note: color is in RGB format with comma seperating the values (R,G,B)</span></p><p><span style=" font-size:10pt;">Sample XY plot (supports only one curve):</span></p><p>{P0|Some XY plot|255,0,0|1 255 2 200 3 150 4 100}</p><p>{Plot ID|Curve name|Color|X Y X Y X Y X Y.....}</p><p><span style=" font-weight:600;">Note: If for each X value there won't be Y value, the plot will be ignored</span><br/></p></body></html> 143 | 144 | 145 | Type: 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | Time plot 154 | 155 | 156 | 157 | 158 | XY-Plot 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | Title 167 | 168 | 169 | 170 | 171 | 172 | 173 | A Simple Plotting Demonstration 174 | 175 | 176 | 177 | 178 | 179 | 180 | <html><head/><body><p>Applicable only to real time plot, basically, how many data points will be stored in the memory before deleting them. </p></body></html> 181 | 182 | 183 | Buffer 184 | 185 | 186 | 187 | 188 | 189 | 190 | 10 191 | 192 | 193 | 1000000 194 | 195 | 196 | 100 197 | 198 | 199 | 200 | 201 | 202 | 203 | <html><head/><body><p>How often the plot will be updated. You shouldn't need less than 50ms, however if you want to improve performance of the application, it is advisable to increase the refresh rate. </p></body></html> 204 | 205 | 206 | Refresh rate (ms) 207 | 208 | 209 | 210 | 211 | 212 | 213 | 10 214 | 215 | 216 | 10000 217 | 218 | 219 | 50 220 | 221 | 222 | 223 | 224 | 225 | 226 | Name of X Axis: 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | Name of Y Axis 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | Scaling 252 | 253 | 254 | 255 | 256 | 257 | QFormLayout::AllNonFixedFieldsGrow 258 | 259 | 260 | 261 | 262 | Automatically scales the graph to show all values on Y axis 263 | 264 | 265 | Auto Scaling Y 266 | 267 | 268 | true 269 | 270 | 271 | 272 | 273 | 274 | 275 | Min Y 276 | 277 | 278 | 279 | 280 | 281 | 282 | -10000000.000000000000000 283 | 284 | 285 | 10000000.000000000000000 286 | 287 | 288 | -200.000000000000000 289 | 290 | 291 | 292 | 293 | 294 | 295 | Max Y 296 | 297 | 298 | 299 | 300 | 301 | 302 | -10000000.000000000000000 303 | 304 | 305 | 10000000.000000000000000 306 | 307 | 308 | 200.000000000000000 309 | 310 | 311 | 312 | 313 | 314 | 315 | Automatically scales graph to include all X values (manual scaling works only on XY plot) 316 | 317 | 318 | Auto Scaling X 319 | 320 | 321 | true 322 | 323 | 324 | 325 | 326 | 327 | 328 | Min X 329 | 330 | 331 | 332 | 333 | 334 | 335 | -10000000.000000000000000 336 | 337 | 338 | 10000000.000000000000000 339 | 340 | 341 | -200.000000000000000 342 | 343 | 344 | 345 | 346 | 347 | 348 | -10000000.000000000000000 349 | 350 | 351 | 10000000.000000000000000 352 | 353 | 354 | 200.000000000000000 355 | 356 | 357 | 358 | 359 | 360 | 361 | Max X 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | Misc 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | <html><head/><body><p>Format of the date in real time plot. Some of the available formats: </p><p><span style=" font-weight:600;">&quot;dd:mm:yyyy | hh:mm:ss:zzz&quot;</span></p><p>Where it shows<span style=" font-weight:600;"> day:month:year | hours:minutes:seconds:milliseconds</span></p></body></html> 382 | 383 | 384 | 385 | 386 | 387 | Date Format 388 | 389 | 390 | 391 | 392 | 393 | 394 | hh:mm:ss 395 | 396 | 397 | 398 | 399 | 400 | 401 | Automatically fills the graph 402 | 403 | 404 | Auto filling 405 | 406 | 407 | true 408 | 409 | 410 | 411 | 412 | 413 | 414 | Auto Fill Opacity: 415 | 416 | 417 | 418 | 419 | 420 | 421 | 20 422 | 423 | 424 | 100 425 | 426 | 427 | 428 | 429 | 430 | 431 | Background Color: 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | Qt::Horizontal 441 | 442 | 443 | 444 | 40 445 | 20 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 50 455 | 0 456 | 457 | 458 | 459 | 460 | 50 461 | 16777215 462 | 463 | 464 | 465 | background-color:#ffffff; 466 | border: 2px solid #000; 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | Choose background color 477 | 478 | 479 | 480 | 481 | 482 | 483 | :/images/kcoloredit.png:/images/kcoloredit.png 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 0 499 | 0 500 | 501 | 502 | 503 | 504 | 0 505 | 0 506 | 507 | 508 | 509 | Auto Write 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | Will write all results directly to the file you have specified. Similar to save button, but does it instantly and automatically. Useful for when one needs to do analysis later. Results will be in CSV 518 | 519 | 520 | Write To File 521 | 522 | 523 | 524 | 525 | 526 | 527 | File: 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | true 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | :/images/document-open-folder.png:/images/document-open-folder.png 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | Specify what seperator should the save and auto file write function use 557 | 558 | 559 | Seperator: 560 | 561 | 562 | 563 | 564 | 565 | 566 | ; 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | QwtPlot 588 | QWidget 589 |
qwt_plot.h
590 | 1 591 |
592 |
593 | 594 | 595 | 596 | 597 |
598 | -------------------------------------------------------------------------------- /widgets/linegraph.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Plotter 4 | 5 | 6 | 7 | 0 8 | 0 9 | 412 10 | 357 11 | 12 | 13 | 14 | Line Chart 15 | 16 | 17 | 18 | :/images/linechart.ico:/images/linechart.ico 19 | 20 | 21 | 22 | 0 23 | 24 | 25 | 0 26 | 27 | 28 | 0 29 | 30 | 31 | 0 32 | 33 | 34 | 0 35 | 36 | 37 | 38 | 39 | 0 40 | 41 | 42 | 43 | Chart 44 | 45 | 46 | 47 | 48 | 49 | 50 | 0 51 | 0 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Save current plot to CSV 62 | 63 | 64 | Save 65 | 66 | 67 | 68 | :/images/document-save.png:/images/document-save.png 69 | 70 | 71 | 72 | 73 | 74 | 75 | Qt::Horizontal 76 | 77 | 78 | 79 | 40 80 | 20 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | <html><head/><body><p>Starts/stops data collecting from Serial</p><p>When stopped, you'll be able to zoom in/out and move the graph to further inspect the data.</p></body></html> 89 | 90 | 91 | 92 | 93 | 94 | 95 | :/images/media-playback-start.png 96 | :/images/media-playback-stop.png:/images/media-playback-start.png 97 | 98 | 99 | true 100 | 101 | 102 | true 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | Settings 113 | 114 | 115 | 116 | 117 | 118 | true 119 | 120 | 121 | 122 | 123 | 0 124 | 0 125 | 369 126 | 678 127 | 128 | 129 | 130 | 131 | 132 | 133 | Basic 134 | 135 | 136 | 137 | 138 | 139 | QFormLayout::AllNonFixedFieldsGrow 140 | 141 | 142 | 143 | 144 | <html><head/><body><p>The ID of the graph, for serial thread to properly forward the incoming data from micro-controller.</p><p>You can have the same IDs if you wish, both will receive the packet from the serial thread.</p></body></html> 145 | 146 | 147 | ID: 148 | 149 | 150 | 151 | 152 | 153 | 154 | p1 155 | 156 | 157 | 158 | 159 | 160 | 161 | <html><head/><body><p>Can select the graph to plot in real time or XY plot</p><p><span style=" font-size:10pt;">Sample real-time packet with 3 curves XYZ:</span></p><p>{<span style=" color:#ff0000;">P0|X|255,0,0|100</span><span style=" color:#00ff7f;">|Y|0,255,0|150</span><span style=" color:#5555ff;">|Z|0,0,255|200</span>}</p><p>{Plot ID|Curve 1|Color|Value|Curve 2|Color|Value}</p><p><span style=" font-weight:600;">Note: color is in RGB format with comma seperating the values (R,G,B)</span></p><p><span style=" font-size:10pt;">Sample XY plot (supports only one curve):</span></p><p>{P0|Some XY plot|255,0,0|1 255 2 200 3 150 4 100}</p><p>{Plot ID|Curve name|Color|X Y X Y X Y X Y.....}</p><p><span style=" font-weight:600;">Note: If for each X value there won't be Y value, the plot will be ignored</span><br/></p></body></html> 162 | 163 | 164 | Type: 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | Time plot 173 | 174 | 175 | 176 | 177 | XY-Plot 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | Title 186 | 187 | 188 | 189 | 190 | 191 | 192 | A Simple Plotting Demonstration 193 | 194 | 195 | 196 | 197 | 198 | 199 | <html><head/><body><p>Applicable only to real time plot, basically, how many data points will be stored in the memory before deleting them. </p></body></html> 200 | 201 | 202 | Buffer 203 | 204 | 205 | 206 | 207 | 208 | 209 | 10 210 | 211 | 212 | 1000000 213 | 214 | 215 | 100 216 | 217 | 218 | 219 | 220 | 221 | 222 | <html><head/><body><p>How often the plot will be updated. You shouldn't need less than 50ms, however if you want to improve performance of the application, it is advisable to increase the refresh rate. </p></body></html> 223 | 224 | 225 | Refresh rate (ms) 226 | 227 | 228 | 229 | 230 | 231 | 232 | 10 233 | 234 | 235 | 10000 236 | 237 | 238 | 50 239 | 240 | 241 | 242 | 243 | 244 | 245 | Name of X Axis: 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | Name of Y Axis 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | Scaling 271 | 272 | 273 | 274 | 275 | 276 | QFormLayout::AllNonFixedFieldsGrow 277 | 278 | 279 | 280 | 281 | Automatically scales the graph to show all values on Y axis 282 | 283 | 284 | Auto Scaling Y 285 | 286 | 287 | true 288 | 289 | 290 | 291 | 292 | 293 | 294 | Min Y 295 | 296 | 297 | 298 | 299 | 300 | 301 | -10000000.000000000000000 302 | 303 | 304 | 10000000.000000000000000 305 | 306 | 307 | -200.000000000000000 308 | 309 | 310 | 311 | 312 | 313 | 314 | Max Y 315 | 316 | 317 | 318 | 319 | 320 | 321 | -10000000.000000000000000 322 | 323 | 324 | 10000000.000000000000000 325 | 326 | 327 | 200.000000000000000 328 | 329 | 330 | 331 | 332 | 333 | 334 | Automatically scales graph to include all X values (manual scaling works only on XY plot) 335 | 336 | 337 | Auto Scaling X 338 | 339 | 340 | true 341 | 342 | 343 | 344 | 345 | 346 | 347 | Min X 348 | 349 | 350 | 351 | 352 | 353 | 354 | -10000000.000000000000000 355 | 356 | 357 | 10000000.000000000000000 358 | 359 | 360 | -200.000000000000000 361 | 362 | 363 | 364 | 365 | 366 | 367 | -10000000.000000000000000 368 | 369 | 370 | 10000000.000000000000000 371 | 372 | 373 | 200.000000000000000 374 | 375 | 376 | 377 | 378 | 379 | 380 | Max X 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | Misc 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | <html><head/><body><p>Format of the date in real time plot. Some of the available formats: </p><p><span style=" font-weight:600;">&quot;dd:mm:yyyy | hh:mm:ss:zzz&quot;</span></p><p>Where it shows<span style=" font-weight:600;"> day:month:year | hours:minutes:seconds:milliseconds</span></p></body></html> 401 | 402 | 403 | 404 | 405 | 406 | Date Format 407 | 408 | 409 | 410 | 411 | 412 | 413 | hh:mm:ss 414 | 415 | 416 | 417 | 418 | 419 | 420 | Automatically fills the graph 421 | 422 | 423 | Auto filling 424 | 425 | 426 | true 427 | 428 | 429 | 430 | 431 | 432 | 433 | Auto Fill Opacity: 434 | 435 | 436 | 437 | 438 | 439 | 440 | 20 441 | 442 | 443 | 100 444 | 445 | 446 | 447 | 448 | 449 | 450 | Background Color: 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | Qt::Horizontal 460 | 461 | 462 | 463 | 40 464 | 20 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 50 474 | 0 475 | 476 | 477 | 478 | 479 | 50 480 | 16777215 481 | 482 | 483 | 484 | background-color:#ffffff; 485 | border: 2px solid #000; 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | Choose background color 496 | 497 | 498 | 499 | 500 | 501 | 502 | :/images/kcoloredit.png:/images/kcoloredit.png 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 0 518 | 0 519 | 520 | 521 | 522 | 523 | 0 524 | 0 525 | 526 | 527 | 528 | Auto Write 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | Will write all results directly to the file you have specified. Similar to save button, but does it instantly and automatically. Useful for when one needs to do analysis later. Results will be in CSV 537 | 538 | 539 | Write To File 540 | 541 | 542 | 543 | 544 | 545 | 546 | File: 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | true 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | :/images/document-open-folder.png:/images/document-open-folder.png 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | Specify what seperator should the save and auto file write function use 576 | 577 | 578 | Seperator: 579 | 580 | 581 | 582 | 583 | 584 | 585 | ; 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | QwtPlot 607 | QWidget 608 |
qwt_plot.h
609 | 1 610 |
611 |
612 | 613 | 614 | 615 | 616 |
617 | --------------------------------------------------------------------------------