Add markers by right-clicking a graph

This commit is contained in:
Jan Käberich 2021-05-14 20:34:23 +02:00
parent 93f5eba6a8
commit ba3527d7b6
16 changed files with 253 additions and 91 deletions

View File

@ -6,6 +6,7 @@
#include <QSettings> #include <QSettings>
#include <functional> #include <functional>
#include "unit.h" #include "unit.h"
#include "tracemarker.h"
using namespace std; using namespace std;
@ -263,11 +264,13 @@ void Trace::setColor(QColor color) {
void Trace::addMarker(TraceMarker *m) void Trace::addMarker(TraceMarker *m)
{ {
markers.insert(m); markers.insert(m);
connect(m, &TraceMarker::dataFormatChanged, this, &Trace::markerFormatChanged);
emit markerAdded(m); emit markerAdded(m);
} }
void Trace::removeMarker(TraceMarker *m) void Trace::removeMarker(TraceMarker *m)
{ {
disconnect(m, &TraceMarker::dataFormatChanged, this, &Trace::markerFormatChanged);
markers.erase(m); markers.erase(m);
emit markerRemoved(m); emit markerRemoved(m);
} }

View File

@ -160,6 +160,7 @@ signals:
void colorChanged(Trace *t); void colorChanged(Trace *t);
void markerAdded(TraceMarker *m); void markerAdded(TraceMarker *m);
void markerRemoved(TraceMarker *m); void markerRemoved(TraceMarker *m);
void markerFormatChanged(TraceMarker *m);
private: private:
QString _name; QString _name;

View File

@ -10,6 +10,7 @@
#include <QMenu> #include <QMenu>
#include <QActionGroup> #include <QActionGroup>
#include <QApplication> #include <QApplication>
#include "preferences.h"
using namespace std; using namespace std;
@ -46,10 +47,13 @@ TraceMarker::~TraceMarker()
void TraceMarker::assignTrace(Trace *t) void TraceMarker::assignTrace(Trace *t)
{ {
bool firstAssignment = false;
if(parentTrace) { if(parentTrace) {
// remove connection from previous parent trace // remove connection from previous parent trace
parentTrace->removeMarker(this); parentTrace->removeMarker(this);
disconnect(parentTrace, &Trace::deleted, this, nullptr); disconnect(parentTrace, &Trace::deleted, this, nullptr);
} else {
firstAssignment = true;
} }
parentTrace = t; parentTrace = t;
if(!getSupportedTypes().count(type)) { if(!getSupportedTypes().count(type)) {
@ -63,16 +67,29 @@ void TraceMarker::assignTrace(Trace *t)
connect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted); connect(parentTrace, &Trace::deleted, this, &TraceMarker::parentTraceDeleted);
connect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged); connect(parentTrace, &Trace::dataChanged, this, &TraceMarker::traceDataChanged);
connect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol); connect(parentTrace, &Trace::colorChanged, this, &TraceMarker::updateSymbol);
connect(parentTrace, &Trace::typeChanged, [=](){ connect(parentTrace, &Trace::typeChanged, this, &TraceMarker::domainChanged);
emit domainChanged(); connect(parentTrace, &Trace::typeChanged, this, &TraceMarker::checkDeltaMarker);
checkDeltaMarker();
});
constrainPosition(); constrainPosition();
updateSymbol(); updateSymbol();
parentTrace->addMarker(this); parentTrace->addMarker(this);
for(auto m : helperMarkers) { for(auto m : helperMarkers) {
m->assignTrace(t); m->assignTrace(t);
} }
if(firstAssignment) {
// Marker was just created and this is the first assignment to a trace.
// Use display format on graph from preferences
auto p = Preferences::getInstance();
if(p.General.markerDefault.showDataOnGraphs) {
if(p.General.markerDefault.showAllData) {
for(auto f : applicableFormats()) {
formatGraph.insert(f);
}
} else {
formatGraph.insert(applicableFormats().front());
}
}
}
constrainFormat(); constrainFormat();
update(); update();
emit traceChanged(this); emit traceChanged(this);
@ -122,19 +139,19 @@ std::vector<TraceMarker::Format> TraceMarker::formats()
return ret; return ret;
} }
std::set<TraceMarker::Format> TraceMarker::applicableFormats() std::vector<TraceMarker::Format> TraceMarker::applicableFormats()
{ {
std::set<Format> ret; std::vector<Format> ret;
if(isTimeDomain()) { if(isTimeDomain()) {
switch(type) { switch(type) {
case Type::Manual: case Type::Manual:
case Type::Delta: case Type::Delta:
ret.insert(Format::dB); ret.push_back(Format::dB);
ret.insert(Format::RealImag); ret.push_back(Format::RealImag);
if(parentTrace) { if(parentTrace) {
auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real(); auto step = parentTrace->sample(parentTrace->index(position), Trace::SampleType::TimeStep).y.real();
if(!isnan(step)) { if(!isnan(step)) {
ret.insert(Format::Impedance); ret.push_back(Format::Impedance);
} }
} }
break; break;
@ -148,36 +165,36 @@ std::set<TraceMarker::Format> TraceMarker::applicableFormats()
case Type::Maximum: case Type::Maximum:
case Type::Minimum: case Type::Minimum:
case Type::PeakTable: case Type::PeakTable:
ret.insert(Format::dB); ret.push_back(Format::dB);
ret.insert(Format::dBAngle); ret.push_back(Format::dBAngle);
ret.insert(Format::RealImag); ret.push_back(Format::RealImag);
if(parentTrace) { if(parentTrace) {
if(parentTrace->isReflection()) { if(parentTrace->isReflection()) {
ret.insert(Format::Impedance); ret.push_back(Format::Impedance);
} }
if(!isnan(parentTrace->getNoise(parentTrace->minX()))) { if(!isnan(parentTrace->getNoise(parentTrace->minX()))) {
ret.insert(Format::Noise); ret.push_back(Format::Noise);
} }
} }
break; break;
case Type::Bandpass: case Type::Bandpass:
ret.insert(Format::CenterBandwidth); ret.push_back(Format::CenterBandwidth);
ret.insert(Format::InsertionLoss); ret.push_back(Format::InsertionLoss);
break; break;
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
ret.insert(Format::Cutoff); ret.push_back(Format::Cutoff);
ret.insert(Format::InsertionLoss); ret.push_back(Format::InsertionLoss);
break; break;
case Type::PhaseNoise: case Type::PhaseNoise:
ret.insert(Format::PhaseNoise); ret.push_back(Format::PhaseNoise);
ret.insert(Format::dB); ret.push_back(Format::dB);
break; break;
case Type::TOI: case Type::TOI:
ret.insert(Format::TOI); ret.push_back(Format::TOI);
ret.insert(Format::AvgTone); ret.push_back(Format::AvgTone);
ret.insert(Format::AvgModulationProduct); ret.push_back(Format::AvgModulationProduct);
break; break;
case Type::Last: case Type::Last:
break; break;
@ -490,6 +507,7 @@ void TraceMarker::updateContextmenu()
} }
contextmenu.clear(); contextmenu.clear();
contextmenu.addSection("Marker");
auto typemenu = contextmenu.addMenu("Type"); auto typemenu = contextmenu.addMenu("Type");
auto typegroup = new QActionGroup(&contextmenu); auto typegroup = new QActionGroup(&contextmenu);
@ -534,9 +552,14 @@ void TraceMarker::updateContextmenu()
} else { } else {
formatGraph.erase(f); formatGraph.erase(f);
} }
emit dataFormatChanged(this);
}); });
graph->addAction(setFormatAction); graph->addAction(setFormatAction);
} }
auto deleteAction = new QAction("Delete");
connect(deleteAction, &QAction::triggered, this, &TraceMarker::deleteLater);
contextmenu.addAction(deleteAction);
} }
std::set<TraceMarker::Type> TraceMarker::getSupportedTypes() std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
@ -554,16 +577,18 @@ std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
supported.insert(Type::Minimum); supported.insert(Type::Minimum);
supported.insert(Type::Delta); supported.insert(Type::Delta);
supported.insert(Type::PeakTable); supported.insert(Type::PeakTable);
if(!parentTrace->isReflection()) {
supported.insert(Type::Lowpass);
supported.insert(Type::Highpass);
supported.insert(Type::Bandpass);
}
if(parentTrace->isLive()) { if(parentTrace->isLive()) {
switch(parentTrace->liveParameter()) { switch(parentTrace->liveParameter()) {
case Trace::LiveParameter::S11: case Trace::LiveParameter::S11:
case Trace::LiveParameter::S12: case Trace::LiveParameter::S12:
case Trace::LiveParameter::S21: case Trace::LiveParameter::S21:
case Trace::LiveParameter::S22: case Trace::LiveParameter::S22:
// special VNA marker types // no special marker types for VNA yet
supported.insert(Type::Lowpass);
supported.insert(Type::Highpass);
supported.insert(Type::Bandpass);
break; break;
case Trace::LiveParameter::Port1: case Trace::LiveParameter::Port1:
case Trace::LiveParameter::Port2: case Trace::LiveParameter::Port2:
@ -595,15 +620,20 @@ void TraceMarker::constrainPosition()
void TraceMarker::constrainFormat() void TraceMarker::constrainFormat()
{ {
auto vec = applicableFormats();
// check format // check format
if(!applicableFormats().count(formatTable)) { if(std::find(vec.begin(), vec.end(), formatTable) == vec.end()) {
setTableFormat(*applicableFormats().begin()); setTableFormat(vec.front());
} }
std::set<Format> toErase;
for(auto f : formatGraph) { for(auto f : formatGraph) {
if(!applicableFormats().count(f)) { if(std::find(vec.begin(), vec.end(), f) == vec.end()) {
formatGraph.erase(f); toErase.insert(f);
} }
} }
for(auto f : toErase) {
formatGraph.erase(f);
}
} }
TraceMarker *TraceMarker::bestDeltaCandidate() TraceMarker *TraceMarker::bestDeltaCandidate()
@ -741,14 +771,15 @@ void TraceMarker::setTableFormat(TraceMarker::Format f)
return; return;
} }
if(!applicableFormats().count(f)) { auto vec = applicableFormats();
if(std::find(vec.begin(), vec.end(), f) == vec.end()) {
// can't use requested format for this type of marker // can't use requested format for this type of marker
qWarning() << "Requested marker format" << formatToString(f) << "(not applicable for type" << typeToString(type) <<")"; qWarning() << "Requested marker format" << formatToString(f) << "(not applicable for type" << typeToString(type) <<")";
return; return;
} }
formatTable = f; formatTable = f;
emit dataChanged(this); emit dataFormatChanged(this);
} }
std::set<TraceMarker::Format> TraceMarker::getGraphDisplayFormats() const std::set<TraceMarker::Format> TraceMarker::getGraphDisplayFormats() const

View File

@ -43,7 +43,7 @@ public:
static QString formatToString(Format f); static QString formatToString(Format f);
static Format formatFromString(QString s); static Format formatFromString(QString s);
static std::vector<Format> formats(); static std::vector<Format> formats();
std::set<Format> applicableFormats(); std::vector<Format> applicableFormats();
QString readableData(Format format = Format::Last); QString readableData(Format format = Format::Last);
QString readableSettings(); QString readableSettings();
@ -116,6 +116,7 @@ signals:
void traceChanged(TraceMarker *m); void traceChanged(TraceMarker *m);
void beginRemoveHelperMarkers(TraceMarker *m); void beginRemoveHelperMarkers(TraceMarker *m);
void endRemoveHelperMarkers(TraceMarker *m); void endRemoveHelperMarkers(TraceMarker *m);
void dataFormatChanged(TraceMarker *m);
private slots: private slots:
void parentTraceDeleted(Trace *t); void parentTraceDeleted(Trace *t);

View File

@ -13,6 +13,7 @@ TraceMarkerModel::TraceMarkerModel(TraceModel &model, QObject *parent)
: QAbstractItemModel(parent), : QAbstractItemModel(parent),
model(model) model(model)
{ {
model.setMarkerModel(this);
markers.clear(); markers.clear();
root = new TraceMarker(this); root = new TraceMarker(this);
} }

View File

@ -242,3 +242,13 @@ void TraceModel::addSAData(const Protocol::SpectrumAnalyzerResult& d, const Prot
} }
} }
} }
TraceMarkerModel *TraceModel::getMarkerModel() const
{
return markerModel;
}
void TraceModel::setMarkerModel(TraceMarkerModel *value)
{
markerModel = value;
}

View File

@ -7,6 +7,8 @@
#include "Device/device.h" #include "Device/device.h"
#include "savable.h" #include "savable.h"
class TraceMarkerModel;
class TraceModel : public QAbstractTableModel, public Savable class TraceModel : public QAbstractTableModel, public Savable
{ {
Q_OBJECT Q_OBJECT
@ -40,6 +42,9 @@ public:
virtual nlohmann::json toJSON() override; virtual nlohmann::json toJSON() override;
virtual void fromJSON(nlohmann::json j) override; virtual void fromJSON(nlohmann::json j) override;
TraceMarkerModel *getMarkerModel() const;
void setMarkerModel(TraceMarkerModel *value);
signals: signals:
void SpanChanged(double fmin, double fmax); void SpanChanged(double fmin, double fmax);
void traceAdded(Trace *t); void traceAdded(Trace *t);
@ -54,6 +59,7 @@ public slots:
private: private:
std::vector<Trace*> traces; std::vector<Trace*> traces;
TraceMarkerModel *markerModel;
}; };
#endif // TRACEMODEL_H #endif // TRACEMODEL_H

View File

@ -5,6 +5,7 @@
#include <QMimeData> #include <QMimeData>
#include <QDebug> #include <QDebug>
#include "unit.h" #include "unit.h"
#include "tracemarkermodel.h"
std::set<TracePlot*> TracePlot::plots; std::set<TracePlot*> TracePlot::plots;
@ -21,6 +22,8 @@ TracePlot::TracePlot(TraceModel &model, QWidget *parent)
markedForDeletion = false; markedForDeletion = false;
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lastUpdate = QTime::currentTime(); lastUpdate = QTime::currentTime();
replotTimer.setSingleShot(true);
connect(&replotTimer, &QTimer::timeout, this, qOverload<>(&TracePlot::update));
sweep_fmin = std::numeric_limits<double>::lowest(); sweep_fmin = std::numeric_limits<double>::lowest();
sweep_fmax = std::numeric_limits<double>::max(); sweep_fmax = std::numeric_limits<double>::max();
// get notified when the span changes // get notified when the span changes
@ -52,6 +55,7 @@ void TracePlot::enableTrace(Trace *t, bool enabled)
// connect signals // connect signals
connect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot); connect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot);
connect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot); connect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot);
connect(t, &Trace::markerFormatChanged, this, &TracePlot::triggerReplot);
connect(t, &Trace::markerAdded, this, &TracePlot::markerAdded); connect(t, &Trace::markerAdded, this, &TracePlot::markerAdded);
connect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved); connect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved);
connect(t, &Trace::typeChanged, this, &TracePlot::checkIfStillSupported); connect(t, &Trace::typeChanged, this, &TracePlot::checkIfStillSupported);
@ -59,6 +63,7 @@ void TracePlot::enableTrace(Trace *t, bool enabled)
// disconnect from notifications // disconnect from notifications
disconnect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot); disconnect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot);
disconnect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot); disconnect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot);
disconnect(t, &Trace::markerFormatChanged, this, &TracePlot::triggerReplot);
disconnect(t, &Trace::markerAdded, this, &TracePlot::markerAdded); disconnect(t, &Trace::markerAdded, this, &TracePlot::markerAdded);
disconnect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved); disconnect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved);
disconnect(t, &Trace::typeChanged, this, &TracePlot::checkIfStillSupported); disconnect(t, &Trace::typeChanged, this, &TracePlot::checkIfStillSupported);
@ -101,6 +106,7 @@ void TracePlot::contextMenuEvent(QContextMenuEvent *event)
} else { } else {
// no marker, contextmenu of graph // no marker, contextmenu of graph
menu = contextmenu; menu = contextmenu;
contextmenuClickpoint = event->pos();
} }
menu->exec(event->globalPos()); menu->exec(event->globalPos());
if(markedForDeletion) { if(markedForDeletion) {
@ -183,7 +189,11 @@ void TracePlot::paintEvent(QPaintEvent *event)
void TracePlot::mousePressEvent(QMouseEvent *event) void TracePlot::mousePressEvent(QMouseEvent *event)
{ {
selectedMarker = markerAtPosition(event->pos(), true); if(event->buttons() == Qt::LeftButton) {
selectedMarker = markerAtPosition(event->pos(), true);
} else {
selectedMarker = nullptr;
}
} }
void TracePlot::mouseReleaseEvent(QMouseEvent *event) void TracePlot::mouseReleaseEvent(QMouseEvent *event)
@ -259,6 +269,39 @@ TraceMarker *TracePlot::markerAtPosition(QPoint p, bool onlyMovable)
} }
} }
void TracePlot::createMarkerAtPosition(QPoint p)
{
// transate from point in absolute coordinates to this widget
p -= QPoint(marginLeft, marginTop);
double closestDistance = std::numeric_limits<double>::max();
Trace *trace = nullptr;
double xpos;
for(auto t : traces) {
if(!t.second) {
// trace not enabled, skip
continue;
}
double distance;
auto x = nearestTracePoint(t.first, p, &distance);
if(distance < closestDistance) {
trace = t.first;
xpos = x;
closestDistance = distance;
}
}
if(!trace) {
// failed to find trace (should not happen)
return;
}
auto markerModel = model.getMarkerModel();
auto marker = markerModel->createDefaultMarker();
marker->assignTrace(trace);
marker->setPosition(xpos);
markerModel->addMarker(marker);
}
void TracePlot::dragEnterEvent(QDragEnterEvent *event) void TracePlot::dragEnterEvent(QDragEnterEvent *event)
{ {
if (event->mimeData()->hasFormat("trace/pointer")) { if (event->mimeData()->hasFormat("trace/pointer")) {
@ -322,6 +365,8 @@ void TracePlot::triggerReplot()
if (lastUpdate.msecsTo(now) >= MinUpdateInterval) { if (lastUpdate.msecsTo(now) >= MinUpdateInterval) {
lastUpdate = now; lastUpdate = now;
replot(); replot();
} else {
replotTimer.start(MinUpdateInterval);
} }
} }

View File

@ -44,12 +44,14 @@ protected:
virtual bool supported(Trace *t) = 0; virtual bool supported(Trace *t) = 0;
std::map<Trace*, bool> traces; std::map<Trace*, bool> traces;
QMenu *contextmenu; QMenu *contextmenu;
QPoint contextmenuClickpoint; // mouse coordinates when the contextmenu was invoked
QTime lastUpdate; QTime lastUpdate;
QTimer replotTimer;
bool markedForDeletion; bool markedForDeletion;
static std::set<TracePlot*> plots; static std::set<TracePlot*> plots;
virtual QPoint markerToPixel(TraceMarker *m) = 0; virtual QPoint markerToPixel(TraceMarker *m) = 0;
virtual double nearestTracePoint(Trace *t, QPoint pixel) = 0; virtual double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) = 0;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
@ -57,6 +59,8 @@ protected:
TraceMarker *markerAtPosition(QPoint p, bool onlyMovable = false); TraceMarker *markerAtPosition(QPoint p, bool onlyMovable = false);
void createMarkerAtPosition(QPoint p);
// handle trace drops // handle trace drops
virtual bool dropSupported(Trace *t) = 0; virtual bool dropSupported(Trace *t) = 0;
void dragEnterEvent(QDragEnterEvent *event) override; void dragEnterEvent(QDragEnterEvent *event) override;

View File

@ -94,7 +94,7 @@ QPoint TraceSmithChart::markerToPixel(TraceMarker *m)
return ret; return ret;
} }
double TraceSmithChart::nearestTracePoint(Trace *t, QPoint pixel) double TraceSmithChart::nearestTracePoint(Trace *t, QPoint pixel, double *distance)
{ {
double closestDistance = numeric_limits<double>::max(); double closestDistance = numeric_limits<double>::max();
unsigned int closestIndex = 0; unsigned int closestIndex = 0;
@ -112,6 +112,9 @@ double TraceSmithChart::nearestTracePoint(Trace *t, QPoint pixel)
closestIndex = i; closestIndex = i;
} }
} }
if(distance) {
*distance = closestDistance;
}
return t->sample(closestIndex).x; return t->sample(closestIndex).x;
} }
@ -264,47 +267,13 @@ QString TraceSmithChart::mouseText(QPoint pos)
} }
} }
//void TraceSmithChart::paintEvent(QPaintEvent * /* the event */)
//{
// auto pref = Preferences::getInstance();
// QPainter painter(this);
// painter.setRenderHint(QPainter::Antialiasing);
// painter.setBackground(QBrush(pref.General.graphColors.background));
// painter.fillRect(0, 0, width(), height(), QBrush(pref.General.graphColors.background));
// double side = qMin(width(), height()) * screenUsage;
// //painter.setViewport((width()-side)/2, (height()-side)/2, side, side);
// //painter.setWindow(-smithCoordMax, -smithCoordMax, 2*smithCoordMax, 2*smithCoordMax);
// plotToPixelXOffset = width()/2;
// plotToPixelYOffset = height()/2;
// plotToPixelXScale = side/2;
// plotToPixelYScale = -side/2;
// draw(painter, 2*smithCoordMax/side);
//}
void TraceSmithChart::updateContextMenu() void TraceSmithChart::updateContextMenu()
{ {
contextmenu->clear();
contextmenu->clear(); contextmenu->clear();
auto setup = new QAction("Setup...", contextmenu); auto setup = new QAction("Setup...", contextmenu);
connect(setup, &QAction::triggered, this, &TraceSmithChart::axisSetupDialog); connect(setup, &QAction::triggered, this, &TraceSmithChart::axisSetupDialog);
contextmenu->addAction(setup); contextmenu->addAction(setup);
contextmenu->addSection("Traces");
// Populate context menu
for(auto t : traces) {
auto action = new QAction(t.first->name(), contextmenu);
action->setCheckable(true);
if(t.second) {
action->setChecked(true);
}
connect(action, &QAction::toggled, [=](bool active) {
enableTrace(t.first, active);
});
contextmenu->addAction(action);
}
contextmenu->addSeparator(); contextmenu->addSeparator();
auto image = new QAction("Save image...", contextmenu); auto image = new QAction("Save image...", contextmenu);
contextmenu->addAction(image); contextmenu->addAction(image);
@ -320,6 +289,39 @@ void TraceSmithChart::updateContextMenu()
filename += ".png"; filename += ".png";
grab().save(filename); grab().save(filename);
}); });
auto createMarker = contextmenu->addAction("Add marker here");
bool activeTraces = false;
for(auto t : traces) {
if(t.second) {
activeTraces = true;
break;
}
}
if(!activeTraces) {
createMarker->setEnabled(false);
}
connect(createMarker, &QAction::triggered, [=](){
createMarkerAtPosition(contextmenuClickpoint);
});
contextmenu->addSection("Traces");
// Populate context menu
for(auto t : traces) {
if(!supported(t.first)) {
continue;
}
auto action = new QAction(t.first->name(), contextmenu);
action->setCheckable(true);
if(t.second) {
action->setChecked(true);
}
connect(action, &QAction::toggled, [=](bool active) {
enableTrace(t.first, active);
});
contextmenu->addAction(action);
}
contextmenu->addSeparator(); contextmenu->addSeparator();
auto close = new QAction("Close", contextmenu); auto close = new QAction("Close", contextmenu);
contextmenu->addAction(close); contextmenu->addAction(close);

View File

@ -26,7 +26,7 @@ protected:
QPoint dataToPixel(Trace::Data d); QPoint dataToPixel(Trace::Data d);
std::complex<double> pixelToData(QPoint p); std::complex<double> pixelToData(QPoint p);
QPoint markerToPixel(TraceMarker *m) override; QPoint markerToPixel(TraceMarker *m) override;
double nearestTracePoint(Trace *t, QPoint pixel) override; double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
virtual bool xCoordinateVisible(double x); virtual bool xCoordinateVisible(double x);
//void paintEvent(QPaintEvent *event) override; //void paintEvent(QPaintEvent *event) override;

View File

@ -229,6 +229,38 @@ void TraceXYPlot::updateContextMenu()
auto setup = new QAction("Axis setup...", contextmenu); auto setup = new QAction("Axis setup...", contextmenu);
connect(setup, &QAction::triggered, this, &TraceXYPlot::axisSetupDialog); connect(setup, &QAction::triggered, this, &TraceXYPlot::axisSetupDialog);
contextmenu->addAction(setup); contextmenu->addAction(setup);
contextmenu->addSeparator();
auto image = new QAction("Save image...", contextmenu);
contextmenu->addAction(image);
connect(image, &QAction::triggered, [=]() {
auto filename = QFileDialog::getSaveFileName(nullptr, "Save plot image", "", "PNG image files (*.png)", nullptr, QFileDialog::DontUseNativeDialog);
if(filename.isEmpty()) {
// aborted selection
return;
}
if(filename.endsWith(".png")) {
filename.chop(4);
}
filename += ".png";
grab().save(filename);
});
auto createMarker = contextmenu->addAction("Add marker here");
bool activeTraces = false;
for(auto t : traces) {
if(t.second) {
activeTraces = true;
break;
}
}
if(!activeTraces) {
createMarker->setEnabled(false);
}
connect(createMarker, &QAction::triggered, [=](){
createMarkerAtPosition(contextmenuClickpoint);
});
for(int axis = 0;axis < 2;axis++) { for(int axis = 0;axis < 2;axis++) {
if(YAxis[axis].type == YAxisType::Disabled) { if(YAxis[axis].type == YAxisType::Disabled) {
continue; continue;
@ -255,21 +287,7 @@ void TraceXYPlot::updateContextMenu()
contextmenu->addAction(action); contextmenu->addAction(action);
} }
} }
contextmenu->addSeparator();
auto image = new QAction("Save image...", contextmenu);
contextmenu->addAction(image);
connect(image, &QAction::triggered, [=]() {
auto filename = QFileDialog::getSaveFileName(nullptr, "Save plot image", "", "PNG image files (*.png)", nullptr, QFileDialog::DontUseNativeDialog);
if(filename.isEmpty()) {
// aborted selection
return;
}
if(filename.endsWith(".png")) {
filename.chop(4);
}
filename += ".png";
grab().save(filename);
});
contextmenu->addSeparator(); contextmenu->addSeparator();
auto close = new QAction("Close", contextmenu); auto close = new QAction("Close", contextmenu);
contextmenu->addAction(close); contextmenu->addAction(close);
@ -902,7 +920,7 @@ QPoint TraceXYPlot::markerToPixel(TraceMarker *m)
return plotValueToPixel(plotPoint, 0); return plotValueToPixel(plotPoint, 0);
} }
double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel) double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel, double *distance)
{ {
if(!tracesAxis[0].count(t)) { if(!tracesAxis[0].count(t)) {
// trace not enabled // trace not enabled
@ -927,6 +945,9 @@ double TraceXYPlot::nearestTracePoint(Trace *t, QPoint pixel)
if(XAxis.type == XAxisType::Distance) { if(XAxis.type == XAxisType::Distance) {
closestXpos = t->distanceToTime(closestXpos); closestXpos = t->distanceToTime(closestXpos);
} }
if(distance) {
*distance = closestDistance;
}
return closestXpos; return closestXpos;
} }

View File

@ -76,7 +76,7 @@ private:
QPoint plotValueToPixel(QPointF plotValue, int Yaxis); QPoint plotValueToPixel(QPointF plotValue, int Yaxis);
QPointF pixelToPlotValue(QPoint pixel, int YAxis); QPointF pixelToPlotValue(QPoint pixel, int YAxis);
QPoint markerToPixel(TraceMarker *m) override; QPoint markerToPixel(TraceMarker *m) override;
double nearestTracePoint(Trace *t, QPoint pixel) override; double nearestTracePoint(Trace *t, QPoint pixel, double *distance = nullptr) override;
virtual bool xCoordinateVisible(double x); virtual bool xCoordinateVisible(double x);
void traceDropped(Trace *t, QPoint position) override; void traceDropped(Trace *t, QPoint position) override;
QString mouseText(QPoint pos) override; QString mouseText(QPoint pos) override;

View File

@ -82,6 +82,10 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
ui->GeneralSCPIEnabled->setEnabled(false); ui->GeneralSCPIEnabled->setEnabled(false);
} }
connect(ui->GeneralMarkerDataGraph, &QCheckBox::toggled, [=](bool enabled) {
ui->GeneralMarkerDataGraphAll->setEnabled(enabled);
});
// Page selection // Page selection
connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) { connect(ui->treeWidget, &QTreeWidget::currentItemChanged, [=](QTreeWidgetItem *current, QTreeWidgetItem *) {
auto name = current->text(0); auto name = current->text(0);
@ -128,6 +132,8 @@ PreferencesDialog::PreferencesDialog(Preferences *pref, QWidget *parent) :
p->General.graphColors.background = ui->GeneralGraphBackground->getColor(); p->General.graphColors.background = ui->GeneralGraphBackground->getColor();
p->General.graphColors.axis = ui->GeneralGraphAxis->getColor(); p->General.graphColors.axis = ui->GeneralGraphAxis->getColor();
p->General.graphColors.divisions = ui->GeneralGraphDivisions->getColor(); p->General.graphColors.divisions = ui->GeneralGraphDivisions->getColor();
p->General.markerDefault.showDataOnGraphs = ui->GeneralMarkerDataGraph->isChecked();
p->General.markerDefault.showAllData = ui->GeneralMarkerDataGraphAll->isChecked();
p->General.SCPI.enabled = ui->GeneralSCPIEnabled->isChecked(); p->General.SCPI.enabled = ui->GeneralSCPIEnabled->isChecked();
p->General.SCPI.port = ui->GeneralSCPIPort->value(); p->General.SCPI.port = ui->GeneralSCPIPort->value();
accept(); accept();
@ -184,6 +190,8 @@ void PreferencesDialog::setInitialGUIState()
ui->GeneralGraphBackground->setColor(p->General.graphColors.background); ui->GeneralGraphBackground->setColor(p->General.graphColors.background);
ui->GeneralGraphAxis->setColor(p->General.graphColors.axis); ui->GeneralGraphAxis->setColor(p->General.graphColors.axis);
ui->GeneralGraphDivisions->setColor(p->General.graphColors.divisions); ui->GeneralGraphDivisions->setColor(p->General.graphColors.divisions);
ui->GeneralMarkerDataGraph->setChecked(p->General.markerDefault.showDataOnGraphs);
ui->GeneralMarkerDataGraphAll->setChecked(p->General.markerDefault.showAllData);
ui->GeneralSCPIEnabled->setChecked(p->General.SCPI.enabled); ui->GeneralSCPIEnabled->setChecked(p->General.SCPI.enabled);
ui->GeneralSCPIPort->setValue(p->General.SCPI.port); ui->GeneralSCPIPort->setValue(p->General.SCPI.port);

View File

@ -56,6 +56,10 @@ public:
QColor axis; QColor axis;
QColor divisions; QColor divisions;
} graphColors; } graphColors;
struct {
bool showDataOnGraphs;
bool showAllData;
} markerDefault;
struct { struct {
bool enabled; bool enabled;
int port; int port;
@ -72,7 +76,7 @@ private:
QString name; QString name;
QVariant def; QVariant def;
}; };
const std::array<SettingDescription, 27> descr = {{ const std::array<SettingDescription, 29> descr = {{
{&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true}, {&Startup.ConnectToFirstDevice, "Startup.ConnectToFirstDevice", true},
{&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false}, {&Startup.RememberSweepSettings, "Startup.RememberSweepSettings", false},
{&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0}, {&Startup.DefaultSweep.start, "Startup.DefaultSweep.start", 1000000.0},
@ -98,6 +102,8 @@ private:
{&General.graphColors.background, "General.graphColors.background", QColor(Qt::black)}, {&General.graphColors.background, "General.graphColors.background", QColor(Qt::black)},
{&General.graphColors.axis, "General.graphColors.axis", QColor(Qt::white)}, {&General.graphColors.axis, "General.graphColors.axis", QColor(Qt::white)},
{&General.graphColors.divisions, "General.graphColors.divisions", QColor(Qt::gray)}, {&General.graphColors.divisions, "General.graphColors.divisions", QColor(Qt::gray)},
{&General.markerDefault.showDataOnGraphs, "General.MarkerDefault.ShowDataOnGraphs", true},
{&General.markerDefault.showAllData, "General.MarkerDefault.ShowAllData", false},
{&General.SCPI.enabled, "General.SCPI.enabled", true}, {&General.SCPI.enabled, "General.SCPI.enabled", true},
{&General.SCPI.port, "General.SCPI.port", 19542}, {&General.SCPI.port, "General.SCPI.port", 19542},
}}; }};

View File

@ -587,6 +587,29 @@
</layout> </layout>
</widget> </widget>
</item> </item>
<item>
<widget class="QGroupBox" name="groupBox_9">
<property name="title">
<string>Marker Default Behavior</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QCheckBox" name="GeneralMarkerDataGraph">
<property name="text">
<string>Show data on graphs</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="GeneralMarkerDataGraphAll">
<property name="text">
<string>Show data in all available formats</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="groupBox_8"> <widget class="QGroupBox" name="groupBox_8">
<property name="title"> <property name="title">