Added a new window - Temporal Graph which shows all frame IDs and the
time stamp when they came in. Shows the temporal relationship between all frames.
This commit is contained in:
+6
-3
@@ -67,7 +67,8 @@ SOURCES += main.cpp\
|
|||||||
helpwindow.cpp \
|
helpwindow.cpp \
|
||||||
blfhandler.cpp \
|
blfhandler.cpp \
|
||||||
re/sniffer/SnifferDelegate.cpp \
|
re/sniffer/SnifferDelegate.cpp \
|
||||||
connections/newconnectiondialog.cpp
|
connections/newconnectiondialog.cpp \
|
||||||
|
re/temporalgraphwindow.cpp
|
||||||
|
|
||||||
HEADERS += mainwindow.h \
|
HEADERS += mainwindow.h \
|
||||||
can_structs.h \
|
can_structs.h \
|
||||||
@@ -125,7 +126,8 @@ HEADERS += mainwindow.h \
|
|||||||
helpwindow.h \
|
helpwindow.h \
|
||||||
blfhandler.h \
|
blfhandler.h \
|
||||||
re/sniffer/SnifferDelegate.h \
|
re/sniffer/SnifferDelegate.h \
|
||||||
connections/newconnectiondialog.h
|
connections/newconnectiondialog.h \
|
||||||
|
re/temporalgraphwindow.h
|
||||||
|
|
||||||
FORMS += ui/candatagrid.ui \
|
FORMS += ui/candatagrid.ui \
|
||||||
ui/connectionwindow.ui \
|
ui/connectionwindow.ui \
|
||||||
@@ -153,7 +155,8 @@ FORMS += ui/candatagrid.ui \
|
|||||||
ui/bisectwindow.ui \
|
ui/bisectwindow.ui \
|
||||||
ui/signalviewerwindow.ui \
|
ui/signalviewerwindow.ui \
|
||||||
helpwindow.ui \
|
helpwindow.ui \
|
||||||
ui/newconnectiondialog.ui
|
ui/newconnectiondialog.ui \
|
||||||
|
ui/temporalgraphwindow.ui
|
||||||
|
|
||||||
DISTFILES +=
|
DISTFILES +=
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
snifferWindow = nullptr;
|
snifferWindow = nullptr;
|
||||||
bisectWindow = nullptr;
|
bisectWindow = nullptr;
|
||||||
signalViewerWindow = nullptr;
|
signalViewerWindow = nullptr;
|
||||||
|
temporalGraphWindow = nullptr;
|
||||||
dbcHandler = DBCHandler::getReference();
|
dbcHandler = DBCHandler::getReference();
|
||||||
bDirty = false;
|
bDirty = false;
|
||||||
inhibitFilterUpdate = false;
|
inhibitFilterUpdate = false;
|
||||||
@@ -131,6 +132,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
|||||||
connect(ui->actionCapture_Bisector, &QAction::triggered, this, &MainWindow::showBisectWindow);
|
connect(ui->actionCapture_Bisector, &QAction::triggered, this, &MainWindow::showBisectWindow);
|
||||||
connect(ui->actionSignal_Viewer, &QAction::triggered, this, &MainWindow::showSignalViewer);
|
connect(ui->actionSignal_Viewer, &QAction::triggered, this, &MainWindow::showSignalViewer);
|
||||||
connect(ui->actionSave_Continuous_Logfile, &QAction::triggered, this, &MainWindow::handleContinousLogging);
|
connect(ui->actionSave_Continuous_Logfile, &QAction::triggered, this, &MainWindow::handleContinousLogging);
|
||||||
|
connect(ui->actionTemporal_Graph, &QAction::triggered, this, &MainWindow::showTemporalGraphWindow);
|
||||||
|
|
||||||
connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames);
|
connect(CANConManager::getInstance(), &CANConManager::framesReceived, model, &CANFrameModel::addFrames);
|
||||||
|
|
||||||
@@ -226,6 +228,7 @@ void MainWindow::killEmAll()
|
|||||||
killWindow(motorctrlConfigWindow);
|
killWindow(motorctrlConfigWindow);
|
||||||
killWindow(signalViewerWindow);
|
killWindow(signalViewerWindow);
|
||||||
killWindow(connectionWindow);
|
killWindow(connectionWindow);
|
||||||
|
killWindow(temporalGraphWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
//forcefully close the window, kill it, and salt the earth
|
//forcefully close the window, kill it, and salt the earth
|
||||||
@@ -837,6 +840,19 @@ void MainWindow::showGraphingWindow()
|
|||||||
graphingWindow->show();
|
graphingWindow->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::showTemporalGraphWindow()
|
||||||
|
{
|
||||||
|
//only create an instance of the object if we dont have one. Otherwise just display the existing one.
|
||||||
|
if (!temporalGraphWindow)
|
||||||
|
{
|
||||||
|
if (!useFiltered)
|
||||||
|
temporalGraphWindow = new TemporalGraphWindow(model->getListReference());
|
||||||
|
else
|
||||||
|
temporalGraphWindow = new TemporalGraphWindow(model->getFilteredListReference());
|
||||||
|
}
|
||||||
|
temporalGraphWindow->show();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::showFrameDataAnalysis()
|
void MainWindow::showFrameDataAnalysis()
|
||||||
{
|
{
|
||||||
//only create an instance of the object if we dont have one. Otherwise just display the existing one.
|
//only create an instance of the object if we dont have one. Otherwise just display the existing one.
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "re/isotp_interpreterwindow.h"
|
#include "re/isotp_interpreterwindow.h"
|
||||||
#include "motorcontrollerconfigwindow.h"
|
#include "motorcontrollerconfigwindow.h"
|
||||||
#include "signalviewerwindow.h"
|
#include "signalviewerwindow.h"
|
||||||
|
#include "re/temporalgraphwindow.h"
|
||||||
|
|
||||||
class CANConnection;
|
class CANConnection;
|
||||||
class ConnectionWindow;
|
class ConnectionWindow;
|
||||||
@@ -81,6 +82,7 @@ private slots:
|
|||||||
void showSnifferWindow();
|
void showSnifferWindow();
|
||||||
void showBisectWindow();
|
void showBisectWindow();
|
||||||
void showSignalViewer();
|
void showSignalViewer();
|
||||||
|
void showTemporalGraphWindow();
|
||||||
void exitApp();
|
void exitApp();
|
||||||
void handleSaveDecoded();
|
void handleSaveDecoded();
|
||||||
void connectionStatusUpdated(int conns);
|
void connectionStatusUpdated(int conns);
|
||||||
@@ -159,6 +161,7 @@ private:
|
|||||||
MotorControllerConfigWindow *motorctrlConfigWindow;
|
MotorControllerConfigWindow *motorctrlConfigWindow;
|
||||||
BisectWindow* bisectWindow;
|
BisectWindow* bisectWindow;
|
||||||
SignalViewerWindow *signalViewerWindow;
|
SignalViewerWindow *signalViewerWindow;
|
||||||
|
TemporalGraphWindow *temporalGraphWindow;
|
||||||
|
|
||||||
//various private storage
|
//various private storage
|
||||||
QLabel lbStatusConnected;
|
QLabel lbStatusConnected;
|
||||||
|
|||||||
@@ -0,0 +1,381 @@
|
|||||||
|
#include "temporalgraphwindow.h"
|
||||||
|
#include "ui_temporalgraphwindow.h"
|
||||||
|
#include "helpwindow.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
QString HexTicker::getTickLabel (double tick, const QLocale& locale, QChar formatChar, int precision)
|
||||||
|
{
|
||||||
|
int valu = static_cast<int>(tick);
|
||||||
|
//qDebug() << valu;
|
||||||
|
return "0x" + QString::number(valu, 16).toUpper().rightJustified(3,'0');
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporalGraphWindow::TemporalGraphWindow(const QVector<CANFrame> *frames, QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::TemporalGraphWindow)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
setWindowFlags(Qt::Window);
|
||||||
|
|
||||||
|
readSettings();
|
||||||
|
|
||||||
|
modelFrames = frames;
|
||||||
|
|
||||||
|
ui->graphingView->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom | QCP::iSelectAxes);
|
||||||
|
|
||||||
|
ui->graphingView->xAxis->setRange(0, 8);
|
||||||
|
ui->graphingView->yAxis->setRange(0, 255);
|
||||||
|
ui->graphingView->axisRect()->setupFullAxesBox();
|
||||||
|
|
||||||
|
|
||||||
|
ui->graphingView->xAxis->setLabel("Elapsed Time");
|
||||||
|
ui->graphingView->yAxis->setLabel("ID");
|
||||||
|
ui->graphingView->xAxis->setNumberFormat("f");
|
||||||
|
ui->graphingView->xAxis->setNumberPrecision(6);
|
||||||
|
|
||||||
|
HexTicker *tick = new HexTicker;
|
||||||
|
QSharedPointer<QCPAxisTicker> sharedTicker(tick);
|
||||||
|
tick->setTickCount(10);
|
||||||
|
ui->graphingView->yAxis->setTicker(sharedTicker);
|
||||||
|
|
||||||
|
// connect slot that ties some axis selections together (especially opposite axes):
|
||||||
|
connect(ui->graphingView, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged()));
|
||||||
|
connect(ui->graphingView, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress()));
|
||||||
|
connect(ui->graphingView, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel()));
|
||||||
|
connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int)));
|
||||||
|
// make bottom and left axes transfer their ranges to top and right axes:
|
||||||
|
connect(ui->graphingView->xAxis, SIGNAL(rangeChanged(QCPRange)), ui->graphingView->xAxis2, SLOT(setRange(QCPRange)));
|
||||||
|
connect(ui->graphingView->yAxis, SIGNAL(rangeChanged(QCPRange)), ui->graphingView->yAxis2, SLOT(setRange(QCPRange)));
|
||||||
|
|
||||||
|
if (useOpenGL)
|
||||||
|
{
|
||||||
|
ui->graphingView->setAntialiasedElements(QCP::aeAll);
|
||||||
|
//ui->graphingView->setNoAntialiasingOnDrag(true);
|
||||||
|
ui->graphingView->setOpenGl(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->graphingView->setOpenGl(false);
|
||||||
|
ui->graphingView->setAntialiasedElements(QCP::aeNone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TemporalGraphWindow::~TemporalGraphWindow()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::showEvent(QShowEvent* event)
|
||||||
|
{
|
||||||
|
QDialog::showEvent(event);
|
||||||
|
installEventFilter(this);
|
||||||
|
readSettings();
|
||||||
|
generateGraph();
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event);
|
||||||
|
removeEventFilter(this);
|
||||||
|
writeSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::readSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||||
|
{
|
||||||
|
resize(settings.value("Temporal/WindowSize", QSize(800, 600)).toSize());
|
||||||
|
move(settings.value("Temporal/WindowPos", QPoint(50, 50)).toPoint());
|
||||||
|
}
|
||||||
|
useOpenGL = settings.value("Main/UseOpenGL", false).toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::writeSettings()
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
|
||||||
|
if (settings.value("Main/SaveRestorePositions", false).toBool())
|
||||||
|
{
|
||||||
|
settings.setValue("Temporal/WindowSize", size());
|
||||||
|
settings.setValue("Temporal/WindowPos", pos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::updatedFrames(int numFrames)
|
||||||
|
{
|
||||||
|
CANFrame thisFrame;
|
||||||
|
QVector<double> x, y;
|
||||||
|
bool appendedToGraph = false;
|
||||||
|
bool needReplot = false;
|
||||||
|
|
||||||
|
if (numFrames == -1) //all frames deleted. Kill the display
|
||||||
|
{
|
||||||
|
//removeAllGraphs();
|
||||||
|
//now instead of removing the graphs regenerate them which will blank them out but leave them there in case
|
||||||
|
//more traffic that matches comes in or someone otherwise loads more data
|
||||||
|
ui->graphingView->clearGraphs(); //temporarily remove the graphs from the graph view
|
||||||
|
ui->graphingView->replot(); //now, redisplay them all
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (numFrames == -2) //all new set of frames. Reset
|
||||||
|
{
|
||||||
|
//there shouldn't be any need to actually remove the graphs.
|
||||||
|
//regenerate them instead
|
||||||
|
ui->graphingView->clearGraphs(); //temporarily remove the graphs from the graph view
|
||||||
|
//needScaleSetup = true;
|
||||||
|
generateGraph();
|
||||||
|
//ui->graphingView->replot(); //now, redisplay them all
|
||||||
|
}
|
||||||
|
else //just got some new frames. See if they are relevant.
|
||||||
|
{
|
||||||
|
if (numFrames > modelFrames->count()) return;
|
||||||
|
|
||||||
|
appendedToGraph = false;
|
||||||
|
x.clear();
|
||||||
|
y.clear();
|
||||||
|
for (int i = modelFrames->count() - numFrames; i < modelFrames->count(); i++)
|
||||||
|
{
|
||||||
|
thisFrame = modelFrames->at(i);
|
||||||
|
/*
|
||||||
|
if (graphParams[j].ID == thisFrame.ID)
|
||||||
|
{
|
||||||
|
appendToGraph(graphParams[j], thisFrame, x, y);
|
||||||
|
appendedToGraph = true;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
if (appendedToGraph)
|
||||||
|
{
|
||||||
|
//graphParams[j].ref->addData(x, y);
|
||||||
|
needReplot = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needReplot)
|
||||||
|
{
|
||||||
|
if (followGraphEnd)
|
||||||
|
{
|
||||||
|
//find the current X span and maintain that span but move the end of it over to match the new end
|
||||||
|
//of the actual graph. This causes the view to move with the data to always show the end
|
||||||
|
QCPRange range = ui->graphingView->xAxis->range();
|
||||||
|
double size = range.size();
|
||||||
|
bool foundRange;
|
||||||
|
QCPRange keyRange = ui->graphingView->graph()->getKeyRange(foundRange);
|
||||||
|
if (foundRange)
|
||||||
|
{
|
||||||
|
double end, start;
|
||||||
|
end = keyRange.upper;
|
||||||
|
start = end - size;
|
||||||
|
ui->graphingView->xAxis->setRange(start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::generateGraph()
|
||||||
|
{
|
||||||
|
if (modelFrames->count() == 0) return;
|
||||||
|
qDebug() << "Regenerating the graph";
|
||||||
|
ui->graphingView->addGraph();
|
||||||
|
graph = ui->graphingView->graph();
|
||||||
|
|
||||||
|
QVector<double> x, y;
|
||||||
|
double xminval = 0, xmaxval = 0, yminval = 0, ymaxval = 0;
|
||||||
|
int frameCount = modelFrames->count();
|
||||||
|
|
||||||
|
x.reserve(frameCount);
|
||||||
|
y.reserve(frameCount);
|
||||||
|
|
||||||
|
xminval = xmaxval = modelFrames->at(0).timestamp / 1000000.0;
|
||||||
|
yminval = ymaxval = modelFrames->at(0).ID;
|
||||||
|
|
||||||
|
for (int i = 0; i < frameCount; i++)
|
||||||
|
{
|
||||||
|
x.append(modelFrames->at(i).timestamp / 1000000.0);
|
||||||
|
y.append(modelFrames->at(i).ID);
|
||||||
|
if (x[i] > xmaxval) xmaxval = x[i];
|
||||||
|
if (x[i] < xminval) xminval = x[i];
|
||||||
|
if (y[i] > ymaxval) ymaxval = y[i];
|
||||||
|
if (y[i] < yminval) yminval = y[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->graphingView->graph()->setData(x,y);
|
||||||
|
ui->graphingView->graph()->setLineStyle(QCPGraph::lsNone); //no lines
|
||||||
|
ui->graphingView->graph()->setScatterStyle(QCPScatterStyle::ssPlus);
|
||||||
|
QPen graphPen;
|
||||||
|
graphPen.setColor(Qt::blue);
|
||||||
|
graphPen.setWidth(1);
|
||||||
|
ui->graphingView->graph()->setPen(graphPen);
|
||||||
|
|
||||||
|
qDebug() << "xmin: " << xminval;
|
||||||
|
qDebug() << "xmax: " << xmaxval;
|
||||||
|
qDebug() << "ymin: " << yminval;
|
||||||
|
qDebug() << "ymax: " << ymaxval;
|
||||||
|
|
||||||
|
ui->graphingView->xAxis->setRange(xminval, xmaxval);
|
||||||
|
ui->graphingView->yAxis->setRange(yminval, ymaxval);
|
||||||
|
ui->graphingView->axisRect()->setupFullAxesBox();
|
||||||
|
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::selectionChanged()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
normally, axis base line, axis tick labels and axis labels are selectable separately, but we want
|
||||||
|
the user only to be able to select the axis as a whole, so we tie the selected states of the tick labels
|
||||||
|
and the axis base line together. However, the axis label shall be selectable individually.
|
||||||
|
|
||||||
|
The selection state of the left and right axes shall be synchronized as well as the state of the
|
||||||
|
bottom and top axes.
|
||||||
|
|
||||||
|
Further, we want to synchronize the selection of the graphs with the selection state of the respective
|
||||||
|
legend item belonging to that graph. So the user can select a graph by either clicking on the graph itself
|
||||||
|
or on its legend item.
|
||||||
|
*/
|
||||||
|
|
||||||
|
qDebug() << "SelectionChanged";
|
||||||
|
|
||||||
|
// make top and bottom axes be selected synchronously, and handle axis and tick labels as one selectable object:
|
||||||
|
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
|
||||||
|
ui->graphingView->xAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->xAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
|
||||||
|
{
|
||||||
|
ui->graphingView->xAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||||
|
ui->graphingView->xAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||||
|
}
|
||||||
|
// make left and right axes be selected synchronously, and handle axis and tick labels as one selectable object:
|
||||||
|
if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spTickLabels) ||
|
||||||
|
ui->graphingView->yAxis2->selectedParts().testFlag(QCPAxis::spAxis) || ui->graphingView->yAxis2->selectedParts().testFlag(QCPAxis::spTickLabels))
|
||||||
|
{
|
||||||
|
ui->graphingView->yAxis2->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||||
|
ui->graphingView->yAxis->setSelectedParts(QCPAxis::spAxis|QCPAxis::spTickLabels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::mousePress()
|
||||||
|
{
|
||||||
|
// if an axis is selected, only allow the direction of that axis to be dragged
|
||||||
|
// if no axis is selected, both directions may be dragged
|
||||||
|
|
||||||
|
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->axisRect()->setRangeDrag(ui->graphingView->xAxis->orientation());
|
||||||
|
}
|
||||||
|
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->axisRect()->setRangeDrag(ui->graphingView->yAxis->orientation());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->graphingView->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::mouseWheel()
|
||||||
|
{
|
||||||
|
qDebug() << "Mouse WHeel";
|
||||||
|
// if an axis is selected, only allow the direction of that axis to be zoomed
|
||||||
|
// if no axis is selected, both directions may be zoomed
|
||||||
|
|
||||||
|
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
ui->graphingView->axisRect()->setRangeZoom(ui->graphingView->xAxis->orientation());
|
||||||
|
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
ui->graphingView->axisRect()->setRangeZoom(ui->graphingView->yAxis->orientation());
|
||||||
|
else
|
||||||
|
ui->graphingView->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TemporalGraphWindow::eventFilter(QObject *obj, QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::KeyRelease) {
|
||||||
|
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||||
|
switch (keyEvent->key())
|
||||||
|
{
|
||||||
|
case Qt::Key_Plus:
|
||||||
|
zoomIn();
|
||||||
|
break;
|
||||||
|
case Qt::Key_Minus:
|
||||||
|
zoomOut();
|
||||||
|
break;
|
||||||
|
case Qt::Key_F1:
|
||||||
|
HelpWindow::getRef()->showHelp("temporalwindow.html");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// standard event processing
|
||||||
|
return QObject::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::resetView()
|
||||||
|
{
|
||||||
|
double yminval=10000000.0, ymaxval = -1000000.0;
|
||||||
|
double xminval=100000000000, xmaxval = -10000000000.0;
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < graphParams.count(); i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < graphParams[i].x.count(); j++)
|
||||||
|
{
|
||||||
|
if (graphParams[i].x[j] < xminval) xminval = graphParams[i].x[j];
|
||||||
|
if (graphParams[i].x[j] > xmaxval) xmaxval = graphParams[i].x[j];
|
||||||
|
if (graphParams[i].y[j] < yminval) yminval = graphParams[i].y[j];
|
||||||
|
if (graphParams[i].y[j] > ymaxval) ymaxval = graphParams[i].y[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->graphingView->xAxis->setRange(xminval, xmaxval);
|
||||||
|
ui->graphingView->yAxis->setRange(yminval, ymaxval);
|
||||||
|
ui->graphingView->axisRect()->setupFullAxesBox();
|
||||||
|
|
||||||
|
ui->graphingView->replot();
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::zoomIn()
|
||||||
|
{
|
||||||
|
QCPRange xrange = ui->graphingView->xAxis->range();
|
||||||
|
QCPRange yrange = ui->graphingView->yAxis->range();
|
||||||
|
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->xAxis->scaleRange(0.666, xrange.center());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->yAxis->scaleRange(0.666, yrange.center());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->graphingView->xAxis->scaleRange(0.666, xrange.center());
|
||||||
|
ui->graphingView->yAxis->scaleRange(0.666, yrange.center());
|
||||||
|
}
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemporalGraphWindow::zoomOut()
|
||||||
|
{
|
||||||
|
QCPRange xrange = ui->graphingView->xAxis->range();
|
||||||
|
QCPRange yrange = ui->graphingView->yAxis->range();
|
||||||
|
if (ui->graphingView->xAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->xAxis->scaleRange(1.5, xrange.center());
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ui->graphingView->yAxis->selectedParts().testFlag(QCPAxis::spAxis))
|
||||||
|
{
|
||||||
|
ui->graphingView->yAxis->scaleRange(1.5, yrange.center());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->graphingView->xAxis->scaleRange(1.5, xrange.center());
|
||||||
|
ui->graphingView->yAxis->scaleRange(1.5, yrange.center());
|
||||||
|
}
|
||||||
|
ui->graphingView->replot();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
#ifndef TEMPORALGRAPHWINDOW_H
|
||||||
|
#define TEMPORALGRAPHWINDOW_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include "qcustomplot.h"
|
||||||
|
#include "can_structs.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class TemporalGraphWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HexTicker : public QCPAxisTicker
|
||||||
|
{
|
||||||
|
QString getTickLabel (double tick, const QLocale& locale, QChar formatChar, int precision);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TemporalGraphWindow : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TemporalGraphWindow(const QVector<CANFrame> *, QWidget *parent = nullptr);
|
||||||
|
~TemporalGraphWindow();
|
||||||
|
void showEvent(QShowEvent*);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void updatedFrames(int);
|
||||||
|
void mousePress();
|
||||||
|
void mouseWheel();
|
||||||
|
void resetView();
|
||||||
|
void zoomIn();
|
||||||
|
void zoomOut();
|
||||||
|
void selectionChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::TemporalGraphWindow *ui;
|
||||||
|
const QVector<CANFrame> *modelFrames;
|
||||||
|
bool useOpenGL;
|
||||||
|
bool followGraphEnd;
|
||||||
|
QCPGraph *graph;
|
||||||
|
|
||||||
|
void closeEvent(QCloseEvent *event);
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
|
void readSettings();
|
||||||
|
void writeSettings();
|
||||||
|
void generateGraph();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // TEMPORALGRAPHWINDOW_H
|
||||||
@@ -282,6 +282,7 @@
|
|||||||
<addaction name="actionSniffer"/>
|
<addaction name="actionSniffer"/>
|
||||||
<addaction name="actionCapture_Bisector"/>
|
<addaction name="actionCapture_Bisector"/>
|
||||||
<addaction name="actionSignal_Viewer"/>
|
<addaction name="actionSignal_Viewer"/>
|
||||||
|
<addaction name="actionTemporal_Graph"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuSend_Frames">
|
<widget class="QMenu" name="menuSend_Frames">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@@ -497,6 +498,11 @@
|
|||||||
<string>Start Continuous Logging</string>
|
<string>Start Continuous Logging</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionTemporal_Graph">
|
||||||
|
<property name="text">
|
||||||
|
<string>Temporal Graph</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>TemporalGraphWindow</class>
|
||||||
|
<widget class="QDialog" name="TemporalGraphWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>886</width>
|
||||||
|
<height>683</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Temporal Graph</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QCustomPlot" name="graphingView" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>QCustomPlot</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>qcustomplot.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
||||||
Reference in New Issue
Block a user