LibreVNA/Software/PC_Application/Traces/traceplot.cpp

286 lines
7.9 KiB
C++
Raw Normal View History

#include "traceplot.h"
#include "tracemarker.h"
#include "preferences.h"
#include <QPainter>
#include <QMimeData>
#include <QDebug>
std::set<TracePlot*> TracePlot::plots;
using namespace std;
TracePlot::TracePlot(TraceModel &model, QWidget *parent)
: QWidget(parent),
model(model),
selectedMarker(nullptr),
dropPending(false),
dropTrace(nullptr)
{
contextmenu = new QMenu();
markedForDeletion = false;
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
lastUpdate = QTime::currentTime();
sweep_fmin = std::numeric_limits<double>::lowest();
sweep_fmax = std::numeric_limits<double>::max();
// get notified when the span changes
connect(&model, &TraceModel::SpanChanged, this, qOverload<double, double>(&TracePlot::updateSpan));
plots.insert(this);
2020-11-23 05:24:49 +08:00
cursorLabel = new QLabel("Test", this);
cursorLabel->setStyleSheet("color: white;");
auto font = cursorLabel->font();
font.setPixelSize(12);
cursorLabel->setFont(font);
cursorLabel->hide();
setMouseTracking(true);
setAcceptDrops(true);
}
TracePlot::~TracePlot()
{
plots.erase(this);
delete contextmenu;
2020-11-23 05:24:49 +08:00
delete cursorLabel;
}
void TracePlot::enableTrace(Trace *t, bool enabled)
{
if(traces[t] != enabled) {
traces[t] = enabled;
if(enabled) {
// connect signals
connect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot);
connect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot);
connect(t, &Trace::markerAdded, this, &TracePlot::markerAdded);
connect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved);
} else {
// disconnect from notifications
disconnect(t, &Trace::dataChanged, this, &TracePlot::triggerReplot);
disconnect(t, &Trace::visibilityChanged, this, &TracePlot::triggerReplot);
disconnect(t, &Trace::markerAdded, this, &TracePlot::markerAdded);
disconnect(t, &Trace::markerRemoved, this, &TracePlot::markerRemoved);
}
updateContextMenu();
replot();
}
}
void TracePlot::mouseDoubleClickEvent(QMouseEvent *) {
emit doubleClicked(this);
}
void TracePlot::updateSpan(double min, double max)
{
sweep_fmin = min;
sweep_fmax = max;
triggerReplot();
}
void TracePlot::initializeTraceInfo()
{
// Populate already present traces
auto tvect = model.getTraces();
for(auto t : tvect) {
newTraceAvailable(t);
}
// connect notification of traces added at later point
connect(&model, &TraceModel::traceAdded, this, &TracePlot::newTraceAvailable);
}
void TracePlot::contextMenuEvent(QContextMenuEvent *event)
{
contextmenu->exec(event->globalPos());
if(markedForDeletion) {
emit deleted(this);
delete this;
}
}
void TracePlot::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event)
auto pref = Preferences::getInstance();
QPainter p(this);
// p.setRenderHint(QPainter::Antialiasing);
// fill background
p.setBackground(QBrush(pref.General.graphColors.background));
p.fillRect(0, 0, width(), height(), QBrush(pref.General.graphColors.background));
// show names of active traces
QFont font = p.font();
font.setPixelSize(12);
p.setFont(font);
int x = 1;
for(auto t : traces) {
if(!t.second || !t.first->isVisible()) {
continue;
}
auto textArea = QRect(x, 0, width() - x, marginTop);
QRect usedArea;
p.setPen(t.first->color());
p.drawText(textArea, 0, t.first->name() + " ", &usedArea);
x += usedArea.width();
if(x >= width()) {
// used up all available space
break;
}
}
p.setViewport(marginLeft, marginTop, width() - marginLeft - marginRight, height() - marginTop - marginBottom);
p.setWindow(0, 0, width() - marginLeft - marginRight, height() - marginTop - marginBottom);
draw(p);
}
void TracePlot::mousePressEvent(QMouseEvent *event)
{
auto clickPoint = event->pos() - QPoint(marginLeft, marginTop);
// check if click was near a marker
unsigned int closestDistance = numeric_limits<unsigned int>::max();
TraceMarker *closestMarker = nullptr;
for(auto t : traces) {
if(!t.second) {
// this trace is disabled, skip
continue;
}
auto markers = t.first->getMarkers();
for(auto m : markers) {
if(!m->isMovable()) {
continue;
}
2020-11-23 04:25:41 +08:00
auto markerPoint = markerToPixel(m);
if(markerPoint.isNull()) {
// invalid, skip
continue;
}
auto diff = markerPoint - clickPoint;
unsigned int distance = diff.x() * diff.x() + diff.y() * diff.y();
if(distance < closestDistance) {
closestDistance = distance;
closestMarker = m;
}
}
}
if(closestDistance <= 400) {
selectedMarker = closestMarker;
} else {
selectedMarker = nullptr;
}
}
2020-11-23 05:24:49 +08:00
void TracePlot::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event)
2020-11-23 05:24:49 +08:00
selectedMarker = nullptr;
}
void TracePlot::mouseMoveEvent(QMouseEvent *event)
{
2020-11-23 05:24:49 +08:00
auto clickPoint = event->pos() - QPoint(marginLeft, marginTop);
if(selectedMarker) {
2020-11-23 04:25:41 +08:00
auto trace = selectedMarker->getTrace();
selectedMarker->setPosition(nearestTracePoint(trace, clickPoint));
2020-11-23 05:24:49 +08:00
cursorLabel->hide();
} else {
auto text = mouseText(clickPoint);
if(!text.isEmpty()) {
cursorLabel->setText(text);
cursorLabel->adjustSize();
cursorLabel->move(event->pos() + QPoint(15, 0));
cursorLabel->show();
} else {
cursorLabel->hide();
}
}
}
2020-11-23 05:24:49 +08:00
void TracePlot::leaveEvent(QEvent *event)
{
Q_UNUSED(event);
cursorLabel->hide();
selectedMarker = nullptr;
}
void TracePlot::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat("trace/pointer")) {
auto data = event->mimeData()->data("trace/pointer");
QDataStream stream(&data, QIODevice::ReadOnly);
quintptr dropPtr;
stream >> dropPtr;
auto trace = (Trace*) dropPtr;
if(supported(trace)) {
event->acceptProposedAction();
dropPending = true;
dropTrace = trace;
}
}
triggerReplot();
}
void TracePlot::dropEvent(QDropEvent *event)
{
if(dropTrace) {
traceDropped(dropTrace, event->pos() - - QPoint(marginLeft, marginTop));
}
dropPending = false;
dropTrace = nullptr;
}
void TracePlot::dragLeaveEvent(QDragLeaveEvent *event)
{
Q_UNUSED(event)
dropPending = false;
dropTrace = nullptr;
triggerReplot();
}
std::set<TracePlot *> TracePlot::getPlots()
{
return plots;
}
void TracePlot::newTraceAvailable(Trace *t)
{
if(supported(t)) {
traces[t] = false;
connect(t, &Trace::deleted, this, &TracePlot::traceDeleted);
connect(t, &Trace::nameChanged, this, &TracePlot::updateContextMenu);
connect(t, &Trace::typeChanged, this, &TracePlot::updateContextMenu);
}
updateContextMenu();
}
void TracePlot::traceDeleted(Trace *t)
{
enableTrace(t, false);
traces.erase(t);
updateContextMenu();
triggerReplot();
}
void TracePlot::triggerReplot()
{
auto now = QTime::currentTime();
if (lastUpdate.msecsTo(now) >= MinUpdateInterval) {
lastUpdate = now;
2020-11-02 05:56:31 +08:00
replot();
}
}
void TracePlot::markerAdded(TraceMarker *m)
{
connect(m, &TraceMarker::dataChanged, this, &TracePlot::triggerReplot);
2020-10-20 23:03:49 +08:00
connect(m, &TraceMarker::symbolChanged, this, &TracePlot::triggerReplot);
triggerReplot();
}
2020-10-20 23:03:49 +08:00
void TracePlot::markerRemoved(TraceMarker *m)
{
2020-10-20 23:03:49 +08:00
disconnect(m, &TraceMarker::dataChanged, this, &TracePlot::triggerReplot);
disconnect(m, &TraceMarker::symbolChanged, this, &TracePlot::triggerReplot);
triggerReplot();
}