Treeview for markers, added peak table function

This commit is contained in:
Jan Käberich 2020-11-03 00:37:06 +01:00
parent 8d71cd6541
commit 3358861114
9 changed files with 307 additions and 106 deletions

View File

@ -7,14 +7,14 @@ MarkerWidget::MarkerWidget(TraceMarkerModel &model, QWidget *parent) :
model(model) model(model)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->tableView->setModel(&model); ui->treeView->setModel(&model);
ui->tableView->setItemDelegateForColumn(TraceMarkerModel::ColIndexTrace, new MarkerTraceDelegate); ui->treeView->setItemDelegateForColumn(TraceMarkerModel::ColIndexTrace, new MarkerTraceDelegate);
ui->tableView->setItemDelegateForColumn(TraceMarkerModel::ColIndexType, new MarkerTypeDelegate); ui->treeView->setItemDelegateForColumn(TraceMarkerModel::ColIndexType, new MarkerTypeDelegate);
ui->tableView->setItemDelegateForColumn(TraceMarkerModel::ColIndexSettings, new MarkerSettingsDelegate); ui->treeView->setItemDelegateForColumn(TraceMarkerModel::ColIndexSettings, new MarkerSettingsDelegate);
ui->tableView->setColumnWidth(TraceMarkerModel::ColIndexNumber, 21); ui->treeView->setColumnWidth(TraceMarkerModel::ColIndexNumber, 80);
ui->tableView->setColumnWidth(TraceMarkerModel::ColIndexTrace, 80); ui->treeView->setColumnWidth(TraceMarkerModel::ColIndexTrace, 80);
ui->tableView->setColumnWidth(TraceMarkerModel::ColIndexType, 150); ui->treeView->setColumnWidth(TraceMarkerModel::ColIndexType, 150);
connect(&model.getModel(), &TraceModel::traceAdded, this, &MarkerWidget::updatePersistentEditors); connect(&model.getModel(), &TraceModel::traceAdded, this, &MarkerWidget::updatePersistentEditors);
connect(&model.getModel(), &TraceModel::traceRemoved, this, &MarkerWidget::updatePersistentEditors); connect(&model.getModel(), &TraceModel::traceRemoved, this, &MarkerWidget::updatePersistentEditors);
@ -23,15 +23,22 @@ MarkerWidget::MarkerWidget(TraceMarkerModel &model, QWidget *parent) :
MarkerWidget::~MarkerWidget() MarkerWidget::~MarkerWidget()
{ {
delete ui->tableView->itemDelegateForColumn(TraceMarkerModel::ColIndexTrace); delete ui->treeView->itemDelegateForColumn(TraceMarkerModel::ColIndexTrace);
delete ui->tableView->itemDelegateForColumn(TraceMarkerModel::ColIndexType); delete ui->treeView->itemDelegateForColumn(TraceMarkerModel::ColIndexType);
delete ui->tableView->itemDelegateForColumn(TraceMarkerModel::ColIndexSettings); delete ui->treeView->itemDelegateForColumn(TraceMarkerModel::ColIndexSettings);
delete ui; delete ui;
} }
void MarkerWidget::on_bDelete_clicked() void MarkerWidget::on_bDelete_clicked()
{ {
model.removeMarker(ui->tableView->currentIndex().row()); auto marker = model.markerFromIndex(ui->treeView->currentIndex());
if(!marker || marker->getParent()) {
// can't delete child markers directly
return;
}
model.removeMarker(marker);
marker->blockSignals(true);
delete marker;
} }
void MarkerWidget::on_bAdd_clicked() void MarkerWidget::on_bAdd_clicked()
@ -48,8 +55,8 @@ void MarkerWidget::updatePersistentEditors()
auto columns = {TraceMarkerModel::ColIndexTrace, TraceMarkerModel::ColIndexType}; auto columns = {TraceMarkerModel::ColIndexTrace, TraceMarkerModel::ColIndexType};
for(auto c : columns) { for(auto c : columns) {
auto index = model.index(i, c); auto index = model.index(i, c);
ui->tableView->closePersistentEditor(index); ui->treeView->closePersistentEditor(index);
ui->tableView->openPersistentEditor(index); ui->treeView->openPersistentEditor(index);
} }
} }
} }

View File

@ -15,22 +15,16 @@
</property> </property>
<layout class="QHBoxLayout" name="horizontalLayout"> <layout class="QHBoxLayout" name="horizontalLayout">
<item> <item>
<widget class="QTableView" name="tableView"> <widget class="QTreeView" name="treeView">
<property name="selectionBehavior"> <property name="itemsExpandable">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<attribute name="horizontalHeaderMinimumSectionSize">
<number>21</number>
</attribute>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool> <bool>true</bool>
</attribute> </property>
<attribute name="verticalHeaderVisible"> <property name="animated">
<bool>false</bool> <bool>true</bool>
</attribute> </property>
<attribute name="verticalHeaderDefaultSectionSize"> <property name="expandsOnDoubleClick">
<number>21</number> <bool>true</bool>
</attribute> </property>
</widget> </widget>
</item> </item>
<item> <item>

View File

@ -323,7 +323,7 @@ std::vector<double> Trace::findPeakFrequencies(unsigned int maxPeaks, double min
if(dbm <= min_dbm) { if(dbm <= min_dbm) {
min_dbm = dbm; min_dbm = dbm;
} }
if((dbm <= max_dbm - minValley) && (max_dbm >= minLevel)) { if((dbm <= max_dbm - minValley) && (max_dbm >= minLevel) && frequency) {
// peak was high enough and dropped below minValley afterwards // peak was high enough and dropped below minValley afterwards
peakInfo peak; peakInfo peak;
peak.frequency = frequency; peak.frequency = frequency;
@ -331,7 +331,8 @@ std::vector<double> Trace::findPeakFrequencies(unsigned int maxPeaks, double min
peaks.push_back(peak); peaks.push_back(peak);
// reset // reset
frequency = 0.0; frequency = 0.0;
max_dbm = min_dbm = dbm; max_dbm = -200.0;
min_dbm = dbm;
} }
} }
if(peaks.size() > maxPeaks) { if(peaks.size() > maxPeaks) {

View File

@ -10,7 +10,7 @@
using namespace std; using namespace std;
TraceMarker::TraceMarker(TraceMarkerModel *model, int number) TraceMarker::TraceMarker(TraceMarkerModel *model, int number, TraceMarker *parent, QString descr)
: editingFrequeny(false), : editingFrequeny(false),
model(model), model(model),
parentTrace(nullptr), parentTrace(nullptr),
@ -18,7 +18,9 @@ TraceMarker::TraceMarker(TraceMarkerModel *model, int number)
number(number), number(number),
data(0), data(0),
type(Type::Manual), type(Type::Manual),
description(descr),
delta(nullptr), delta(nullptr),
parent(parent),
cutoffAmplitude(-3.0) cutoffAmplitude(-3.0)
{ {
@ -58,6 +60,7 @@ void TraceMarker::assignTrace(Trace *t)
m->assignTrace(t); m->assignTrace(t);
} }
update(); update();
emit traceChanged(this);
} }
Trace *TraceMarker::trace() Trace *TraceMarker::trace()
@ -84,6 +87,9 @@ QString TraceMarker::readableData()
auto phase = arg(valueDiff); auto phase = arg(valueDiff);
return Unit::ToString(freqDiff, "Hz", " kMG") + " / " + QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4); return Unit::ToString(freqDiff, "Hz", " kMG") + " / " + QString::number(toDecibel(), 'g', 4) + "db@" + QString::number(phase*180/M_PI, 'g', 4);
} }
break;
case Type::PeakTable:
return "Found " + QString::number(helperMarkers.size()) + " peaks";
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
if(parentTrace->isReflection()) { if(parentTrace->isReflection()) {
@ -123,8 +129,8 @@ QString TraceMarker::readableData()
} }
break; break;
case Type::TOI: { case Type::TOI: {
auto avgFundamental = (toDecibel() + helperMarkers[0]->toDecibel()) / 2; auto avgFundamental = (helperMarkers[0]->toDecibel() + helperMarkers[1]->toDecibel()) / 2;
auto avgDistortion = (helperMarkers[1]->toDecibel() + helperMarkers[2]->toDecibel()) / 2; auto avgDistortion = (helperMarkers[2]->toDecibel() + helperMarkers[3]->toDecibel()) / 2;
auto TOI = (3 * avgFundamental - avgDistortion) / 2; auto TOI = (3 * avgFundamental - avgDistortion) / 2;
return "Fundamental: " + Unit::ToString(avgFundamental, "dbm", " ", 3) + ", distortion: " + Unit::ToString(avgDistortion, "dbm", " ", 3) + ", TOI: "+Unit::ToString(TOI, "dbm", " ", 3); return "Fundamental: " + Unit::ToString(avgFundamental, "dbm", " ", 3) + ", distortion: " + Unit::ToString(avgDistortion, "dbm", " ", 3) + ", TOI: "+Unit::ToString(TOI, "dbm", " ", 3);
} }
@ -145,6 +151,7 @@ QString TraceMarker::readableSettings()
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
case Type::Bandpass: case Type::Bandpass:
case Type::PeakTable:
return Unit::ToString(cutoffAmplitude, "db", " ", 3); return Unit::ToString(cutoffAmplitude, "db", " ", 3);
case Type::TOI: case Type::TOI:
return "none"; return "none";
@ -153,6 +160,15 @@ QString TraceMarker::readableSettings()
} }
} }
QString TraceMarker::readableType()
{
if(parent) {
return description;
} else {
return typeToString(type);
}
}
void TraceMarker::setFrequency(double freq) void TraceMarker::setFrequency(double freq)
{ {
frequency = freq; frequency = freq;
@ -179,19 +195,23 @@ void TraceMarker::traceDataChanged()
void TraceMarker::updateSymbol() void TraceMarker::updateSymbol()
{ {
constexpr int width = 15, height = 15; if(isVisible()) {
symbol = QPixmap(width, height); constexpr int width = 15, height = 15;
symbol.fill(Qt::transparent); symbol = QPixmap(width, height);
QPainter p(&symbol); symbol.fill(Qt::transparent);
p.setRenderHint(QPainter::Antialiasing); QPainter p(&symbol);
QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)}; p.setRenderHint(QPainter::Antialiasing);
auto traceColor = parentTrace->color(); QPointF points[] = {QPointF(0,0),QPointF(width,0),QPointF(width/2,height)};
p.setPen(traceColor); auto traceColor = parentTrace->color();
p.setBrush(traceColor); p.setPen(traceColor);
p.drawConvexPolygon(points, 3); p.setBrush(traceColor);
auto brightness = traceColor.redF() * 0.299 + traceColor.greenF() * 0.587 + traceColor.blueF() * 0.114; p.drawConvexPolygon(points, 3);
p.setPen((brightness > 0.6) ? Qt::black : Qt::white); auto brightness = traceColor.redF() * 0.299 + traceColor.greenF() * 0.587 + traceColor.blueF() * 0.114;
p.drawText(QRectF(0,0,width, height*2.0/3.0), Qt::AlignCenter, QString::number(number) + suffix); p.setPen((brightness > 0.6) ? Qt::black : Qt::white);
p.drawText(QRectF(0,0,width, height*2.0/3.0), Qt::AlignCenter, QString::number(number) + suffix);
} else {
symbol = QPixmap(1,1);
}
emit symbolChanged(this); emit symbolChanged(this);
} }
@ -204,6 +224,7 @@ std::set<TraceMarker::Type> TraceMarker::getSupportedTypes()
supported.insert(Type::Maximum); supported.insert(Type::Maximum);
supported.insert(Type::Minimum); supported.insert(Type::Minimum);
supported.insert(Type::Delta); supported.insert(Type::Delta);
supported.insert(Type::PeakTable);
if(parentTrace->isLive()) { if(parentTrace->isLive()) {
switch(parentTrace->liveParameter()) { switch(parentTrace->liveParameter()) {
case Trace::LiveParameter::S11: case Trace::LiveParameter::S11:
@ -256,10 +277,12 @@ void TraceMarker::assignDeltaMarker(TraceMarker *m)
void TraceMarker::deleteHelperMarkers() void TraceMarker::deleteHelperMarkers()
{ {
emit beginRemoveHelperMarkers(this);
for(auto m : helperMarkers) { for(auto m : helperMarkers) {
delete m; delete m;
} }
helperMarkers.clear(); helperMarkers.clear();
emit endRemoveHelperMarkers(this);
} }
void TraceMarker::setType(TraceMarker::Type t) void TraceMarker::setType(TraceMarker::Type t)
@ -267,7 +290,11 @@ void TraceMarker::setType(TraceMarker::Type t)
// remove any potential helper markers // remove any potential helper markers
deleteHelperMarkers(); deleteHelperMarkers();
type = t; type = t;
vector<QString> helperSuffixes; using helper_descr = struct {
QString suffix;
QString description;
};
vector<helper_descr> required_helpers;
switch(type) { switch(type) {
case Type::Delta: case Type::Delta:
if(!delta) { if(!delta) {
@ -293,24 +320,24 @@ void TraceMarker::setType(TraceMarker::Type t)
break; break;
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
helperSuffixes = {"c"}; required_helpers = {{"c", "cutoff"}};
break; break;
case Type::Bandpass: case Type::Bandpass:
helperSuffixes = {"l", "h" ,"c"}; required_helpers = {{"l", "lower cutoff"}, {"h", "higher cutoff"} ,{"c", "center"}};
break; break;
case Type::TOI: case Type::TOI:
helperSuffixes = {"p", "l", "r"}; required_helpers = {{"p", "first peak"}, {"p", "second peak"}, {"l", "left intermodulation"}, {"r", "right intermodulation"}};
default: default:
break; break;
} }
// create helper markers // create helper markers
for(auto suffix : helperSuffixes) { for(auto h : required_helpers) {
auto helper = new TraceMarker(model); auto helper = new TraceMarker(model, number, this, h.description);
helper->suffix = suffix; helper->suffix = h.suffix;
helper->number = number;
helper->assignTrace(parentTrace); helper->assignTrace(parentTrace);
helperMarkers.push_back(helper); helperMarkers.push_back(helper);
} }
updateSymbol();
emit typeChanged(this); emit typeChanged(this);
update(); update();
} }
@ -320,10 +347,50 @@ double TraceMarker::toDecibel()
return 20*log10(abs(data)); return 20*log10(abs(data));
} }
bool TraceMarker::isVisible()
{
switch(type) {
case Type::Manual:
case Type::Delta:
case Type::Maximum:
case Type::Minimum:
return true;
default:
return false;
}
}
QString TraceMarker::getSuffix() const
{
return suffix;
}
const std::vector<TraceMarker *> &TraceMarker::getHelperMarkers() const
{
return helperMarkers;
}
TraceMarker *TraceMarker::helperMarker(unsigned int i)
{
if(i < helperMarkers.size()) {
return helperMarkers[i];
} else {
return nullptr;
}
}
TraceMarker *TraceMarker::getParent() const
{
return parent;
}
void TraceMarker::setNumber(int value) void TraceMarker::setNumber(int value)
{ {
number = value; number = value;
updateSymbol(); updateSymbol();
for(auto h : helperMarkers) {
h->setNumber(number);
}
} }
QWidget *TraceMarker::getTypeEditor(QAbstractItemDelegate *delegate) QWidget *TraceMarker::getTypeEditor(QAbstractItemDelegate *delegate)
@ -398,6 +465,7 @@ void TraceMarker::updateTypeFromEditor(QWidget *w)
} }
} }
} }
update();
} }
SIUnitEdit *TraceMarker::getSettingsEditor() SIUnitEdit *TraceMarker::getSettingsEditor()
@ -411,6 +479,7 @@ SIUnitEdit *TraceMarker::getSettingsEditor()
return new SIUnitEdit("Hz", " kMG"); return new SIUnitEdit("Hz", " kMG");
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
case Type::PeakTable:
return new SIUnitEdit("db", " "); return new SIUnitEdit("db", " ");
case Type::TOI: case Type::TOI:
return nullptr; return nullptr;
@ -433,8 +502,11 @@ void TraceMarker::adjustSettings(double value)
if(value > 0.0) { if(value > 0.0) {
value = -value; value = -value;
} }
/* no break */
case Type::PeakTable:
cutoffAmplitude = value; cutoffAmplitude = value;
} }
update();
} }
void TraceMarker::update() void TraceMarker::update()
@ -454,6 +526,20 @@ void TraceMarker::update()
case Type::Minimum: case Type::Minimum:
setFrequency(parentTrace->findExtremumFreq(false)); setFrequency(parentTrace->findExtremumFreq(false));
break; break;
case Type::PeakTable: {
deleteHelperMarkers();
auto peaks = parentTrace->findPeakFrequencies(100, cutoffAmplitude);
char suffix = 'a';
for(auto p : peaks) {
auto helper = new TraceMarker(model, number, this);
helper->suffix = suffix;
helper->assignTrace(parentTrace);
helper->setFrequency(p);
suffix++;
helperMarkers.push_back(helper);
}
}
break;
case Type::Lowpass: case Type::Lowpass:
case Type::Highpass: case Type::Highpass:
if(parentTrace->isReflection()) { if(parentTrace->isReflection()) {
@ -539,11 +625,11 @@ void TraceMarker::update()
// assign marker frequenies: // assign marker frequenies:
// this marker is the left peak, first helper the right peak. // this marker is the left peak, first helper the right peak.
// 2nd and 3rd helpers are left and right TOI peaks // 2nd and 3rd helpers are left and right TOI peaks
setFrequency(peaks[0]); helperMarkers[0]->setFrequency(peaks[0]);
helperMarkers[0]->setFrequency(peaks[1]); helperMarkers[1]->setFrequency(peaks[1]);
auto freqDiff = peaks[1] - peaks[0]; auto freqDiff = peaks[1] - peaks[0];
helperMarkers[1]->setFrequency(peaks[0] - freqDiff); helperMarkers[2]->setFrequency(peaks[0] - freqDiff);
helperMarkers[2]->setFrequency(peaks[1] + freqDiff); helperMarkers[3]->setFrequency(peaks[1] + freqDiff);
} }
break; break;
} }
@ -565,6 +651,21 @@ std::complex<double> TraceMarker::getData() const
return data; return data;
} }
bool TraceMarker::isMovable()
{
if(parent) {
// helper traces are never movable by the user
return false;
}
switch(type) {
case Type::Manual:
case Type::Delta:
return true;
default:
return false;
}
}
QPixmap &TraceMarker::getSymbol() QPixmap &TraceMarker::getSymbol()
{ {
return symbol; return symbol;

View File

@ -13,32 +13,38 @@ class TraceMarker : public QObject
{ {
Q_OBJECT; Q_OBJECT;
public: public:
TraceMarker(TraceMarkerModel *model, int number = 1); TraceMarker(TraceMarkerModel *model, int number = 1, TraceMarker *parent = nullptr, QString descr = QString());
~TraceMarker(); ~TraceMarker();
void assignTrace(Trace *t); void assignTrace(Trace *t);
Trace* trace(); Trace* trace();
QString readableData(); QString readableData();
QString readableSettings(); QString readableSettings();
QString readableType();
double getFrequency() const; double getFrequency() const;
std::complex<double> getData() const; std::complex<double> getData() const;
bool isMovable();
QPixmap& getSymbol(); QPixmap& getSymbol();
int getNumber() const; int getNumber() const;
void setNumber(int value);
bool editingFrequeny; bool editingFrequeny;
Trace *getTrace() const; Trace *getTrace() const;
void setNumber(int value);
QWidget *getTypeEditor(QAbstractItemDelegate *delegate = nullptr); QWidget *getTypeEditor(QAbstractItemDelegate *delegate = nullptr);
void updateTypeFromEditor(QWidget *c); void updateTypeFromEditor(QWidget *c);
SIUnitEdit* getSettingsEditor(); SIUnitEdit* getSettingsEditor();
void adjustSettings(double value); void adjustSettings(double value);
// Updates marker position and data on automatic markers. Should be called whenever the tracedata is complete // Updates marker position and data on automatic markers. Should be called whenever the tracedata is complete
void update(); void update();
TraceMarker *getParent() const;
const std::vector<TraceMarker *>& getHelperMarkers() const;
TraceMarker *helperMarker(unsigned int i);
QString getSuffix() const;
public slots: public slots:
void setFrequency(double freq); void setFrequency(double freq);
@ -47,6 +53,9 @@ signals:
void dataChanged(TraceMarker *m); void dataChanged(TraceMarker *m);
void symbolChanged(TraceMarker *m); void symbolChanged(TraceMarker *m);
void typeChanged(TraceMarker *m); void typeChanged(TraceMarker *m);
void traceChanged(TraceMarker *m);
void beginRemoveHelperMarkers(TraceMarker *m);
void endRemoveHelperMarkers(TraceMarker *m);
private slots: private slots:
void parentTraceDeleted(Trace *t); void parentTraceDeleted(Trace *t);
@ -61,6 +70,7 @@ private:
Maximum, Maximum,
Minimum, Minimum,
Delta, Delta,
PeakTable,
Lowpass, Lowpass,
Highpass, Highpass,
Bandpass, Bandpass,
@ -73,6 +83,7 @@ private:
case Type::Maximum: return "Maximum"; case Type::Maximum: return "Maximum";
case Type::Minimum: return "Minimum"; case Type::Minimum: return "Minimum";
case Type::Delta: return "Delta"; case Type::Delta: return "Delta";
case Type::PeakTable: return "Peak Table";
case Type::Lowpass: return "Lowpass"; case Type::Lowpass: return "Lowpass";
case Type::Highpass: return "Highpass"; case Type::Highpass: return "Highpass";
case Type::Bandpass: return "Bandpass"; case Type::Bandpass: return "Bandpass";
@ -85,6 +96,7 @@ private:
void deleteHelperMarkers(); void deleteHelperMarkers();
void setType(Type t); void setType(Type t);
double toDecibel(); double toDecibel();
bool isVisible();
TraceMarkerModel *model; TraceMarkerModel *model;
Trace *parentTrace; Trace *parentTrace;
@ -94,9 +106,11 @@ private:
QPixmap symbol; QPixmap symbol;
Type type; Type type;
QString suffix; QString suffix;
QString description;
TraceMarker *delta; TraceMarker *delta;
std::vector<TraceMarker*> helperMarkers; std::vector<TraceMarker*> helperMarkers;
TraceMarker *parent;
double cutoffAmplitude; double cutoffAmplitude;
}; };

View File

@ -5,11 +5,48 @@
#include "CustomWidgets/siunitedit.h" #include "CustomWidgets/siunitedit.h"
#include <QDebug> #include <QDebug>
static constexpr int rowHeight = 21;
TraceMarkerModel::TraceMarkerModel(TraceModel &model, QObject *parent) TraceMarkerModel::TraceMarkerModel(TraceModel &model, QObject *parent)
: QAbstractTableModel(parent), : QAbstractItemModel(parent),
model(model) model(model)
{ {
markers.clear(); markers.clear();
root = new TraceMarker(this);
}
QModelIndex TraceMarkerModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
if(parent.isValid()) {
auto parentItem = markerFromIndex(parent);
auto child = parentItem->helperMarker(row);
if(child) {
return createIndex(row, column, parentItem);
}
}
return createIndex(row, column, root);
}
QModelIndex TraceMarkerModel::parent(const QModelIndex &index) const
{
if (!index.isValid()) {
return QModelIndex();
}
auto childItem = markerFromIndex(index);
auto *parentItem = childItem->getParent();
if(parentItem) {
// find out the number of the child
auto it = find(markers.begin(), markers.end(), parentItem);
auto row = it - markers.begin();
return createIndex(row, 0, root);
} else {
// no parent
return QModelIndex();
}
} }
TraceMarker *TraceMarkerModel::createDefaultMarker() TraceMarker *TraceMarkerModel::createDefaultMarker()
@ -39,19 +76,25 @@ void TraceMarkerModel::addMarker(TraceMarker *t)
markers.push_back(t); markers.push_back(t);
endInsertRows(); endInsertRows();
connect(t, &TraceMarker::dataChanged, this, &TraceMarkerModel::markerDataChanged); connect(t, &TraceMarker::dataChanged, this, &TraceMarkerModel::markerDataChanged);
connect(t, &TraceMarker::typeChanged, this, &TraceMarkerModel::markerDataChanged);
connect(t, &TraceMarker::traceChanged, this, &TraceMarkerModel::markerDataChanged);
connect(t, &TraceMarker::beginRemoveHelperMarkers, [=](TraceMarker *m) {
auto row = find(markers.begin(), markers.end(), m) - markers.begin();
auto modelIndex = createIndex(row, 0, root);
beginRemoveRows(modelIndex, 0, m->getHelperMarkers().size() - 1);
});
connect(t, &TraceMarker::endRemoveHelperMarkers, [=](TraceMarker *m) {
markerDataChanged(m);
endRemoveRows();
});
connect(t, &TraceMarker::deleted, this, qOverload<TraceMarker*>(&TraceMarkerModel::removeMarker)); connect(t, &TraceMarker::deleted, this, qOverload<TraceMarker*>(&TraceMarkerModel::removeMarker));
emit markerAdded(t); emit markerAdded(t);
} }
void TraceMarkerModel::removeMarker(unsigned int index, bool delete_marker) void TraceMarkerModel::removeMarker(unsigned int index)
{ {
if (index < markers.size()) { if (index < markers.size()) {
beginRemoveRows(QModelIndex(), index, index); beginRemoveRows(QModelIndex(), index, index);
if(delete_marker) {
// disconnect from deleted signal prior to deleting the marker. Otherwise a second (possibly non-existent) will be erased from the list
disconnect(markers[index], &TraceMarker::deleted, this, qOverload<TraceMarker*>(&TraceMarkerModel::removeMarker));
delete markers[index];
}
markers.erase(markers.begin() + index); markers.erase(markers.begin() + index);
endRemoveRows(); endRemoveRows();
} }
@ -61,7 +104,7 @@ void TraceMarkerModel::removeMarker(TraceMarker *m)
{ {
auto it = std::find(markers.begin(), markers.end(), m); auto it = std::find(markers.begin(), markers.end(), m);
if(it != markers.end()) { if(it != markers.end()) {
removeMarker(it - markers.begin(), false); removeMarker(it - markers.begin());
} }
} }
@ -72,7 +115,12 @@ void TraceMarkerModel::markerDataChanged(TraceMarker *m)
// only update the other columns, do not override editor data // only update the other columns, do not override editor data
emit dataChanged(index(row, ColIndexData), index(row, ColIndexData)); emit dataChanged(index(row, ColIndexData), index(row, ColIndexData));
} else { } else {
emit dataChanged(index(row, ColIndexSettings), index(row, ColIndexData)); emit dataChanged(index(row, ColIndexNumber), index(row, ColIndexData));
// also update any potential helper markers
for(unsigned int i=0;i<m->getHelperMarkers().size();i++) {
auto modelIndex = createIndex(i, 0, m);
emit dataChanged(index(i, ColIndexNumber, modelIndex), index(i, ColIndexData, modelIndex));
}
} }
} }
@ -81,9 +129,13 @@ TraceMarker *TraceMarkerModel::marker(int index)
return markers.at(index); return markers.at(index);
} }
int TraceMarkerModel::rowCount(const QModelIndex &) const int TraceMarkerModel::rowCount(const QModelIndex &index) const
{ {
return markers.size(); if(!index.isValid()) {
return markers.size();
}
auto marker = markerFromIndex(index);
return marker->getHelperMarkers().size();
} }
int TraceMarkerModel::columnCount(const QModelIndex &) const int TraceMarkerModel::columnCount(const QModelIndex &) const
@ -93,29 +145,23 @@ int TraceMarkerModel::columnCount(const QModelIndex &) const
QVariant TraceMarkerModel::data(const QModelIndex &index, int role) const QVariant TraceMarkerModel::data(const QModelIndex &index, int role) const
{ {
auto marker = markers[index.row()]; auto marker = markerFromIndex(index);
switch(index.column()) { if(role == Qt::DisplayRole) {
case ColIndexNumber: switch(index.column()) {
switch(role) { case ColIndexNumber:
case Qt::DisplayRole: return QVariant((unsigned int)marker->getNumber()); break; return QString::number(marker->getNumber()) + marker->getSuffix();
} case ColIndexTrace:
case ColIndexTrace:
switch(role) {
case Qt::DisplayRole:
if(marker->getTrace()) { if(marker->getTrace()) {
return marker->getTrace()->name(); return marker->getTrace()->name();
} }
break; break;
case ColIndexType:
return marker->readableType();
case ColIndexSettings:
return marker->readableSettings();
case ColIndexData:
return marker->readableData();
} }
case ColIndexSettings:
switch(role) {
case Qt::DisplayRole: return marker->readableSettings(); break;
}
case ColIndexData:
switch(role) {
case Qt::DisplayRole: return marker->readableData(); break;
}
break;
} }
return QVariant(); return QVariant();
} }
@ -141,7 +187,7 @@ bool TraceMarkerModel::setData(const QModelIndex &index, const QVariant &value,
if((unsigned int) index.row() >= markers.size()) { if((unsigned int) index.row() >= markers.size()) {
return false; return false;
} }
auto m = markers[index.row()]; auto m = markerFromIndex(index);
switch(index.column()) { switch(index.column()) {
case ColIndexNumber: { case ColIndexNumber: {
m->setNumber(value.toInt()); m->setNumber(value.toInt());
@ -171,6 +217,11 @@ Qt::ItemFlags TraceMarkerModel::flags(const QModelIndex &index) const
case ColIndexSettings: flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable; break; case ColIndexSettings: flags |= Qt::ItemIsEnabled | Qt::ItemIsEditable; break;
case ColIndexData: flags |= Qt::ItemIsEnabled; break; case ColIndexData: flags |= Qt::ItemIsEnabled; break;
} }
auto marker = markerFromIndex(index);
if(marker->getParent()) {
// this is a helper marker -> nothing is editable
flags &= ~Qt::ItemIsEditable;
}
return (Qt::ItemFlags) flags; return (Qt::ItemFlags) flags;
} }
@ -202,10 +253,26 @@ void TraceMarkerModel::updateMarkers()
} }
} }
TraceMarker *TraceMarkerModel::markerFromIndex(const QModelIndex &index) const
{
auto m = static_cast<TraceMarker*>(index.internalPointer());
if(m == root) {
return markers[index.row()];
} else {
return m->helperMarker(index.row());
}
}
QSize MarkerTraceDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(0, rowHeight);
}
QWidget *MarkerTraceDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const QWidget *MarkerTraceDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const
{ {
auto model = (TraceMarkerModel*) index.model(); auto model = (TraceMarkerModel*) index.model();
auto c = new QComboBox(parent); auto c = new QComboBox(parent);
c->setMaximumHeight(rowHeight);
connect(c, qOverload<int>(&QComboBox::currentIndexChanged), [c](int) { connect(c, qOverload<int>(&QComboBox::currentIndexChanged), [c](int) {
c->clearFocus(); c->clearFocus();
}); });
@ -218,8 +285,7 @@ QWidget *MarkerTraceDelegate::createEditor(QWidget *parent, const QStyleOptionVi
void MarkerTraceDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const void MarkerTraceDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{ {
auto model = (TraceMarkerModel*) index.model(); auto marker = static_cast<const TraceMarkerModel*>(index.model())->markerFromIndex(index);
auto marker = model->getMarkers()[index.row()];
auto c = (QComboBox*) editor; auto c = (QComboBox*) editor;
for(int i=0;i<c->count();i++) { for(int i=0;i<c->count();i++) {
if(qvariant_cast<Trace*>(c->itemData(i)) == marker->trace()) { if(qvariant_cast<Trace*>(c->itemData(i)) == marker->trace()) {
@ -236,13 +302,18 @@ void MarkerTraceDelegate::setModelData(QWidget *editor, QAbstractItemModel *mode
markerModel->setData(index, c->itemData(c->currentIndex())); markerModel->setData(index, c->itemData(c->currentIndex()));
} }
QSize MarkerSettingsDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(0, rowHeight);
}
QWidget *MarkerSettingsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const QWidget *MarkerSettingsDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ {
auto model = (TraceMarkerModel*) index.model(); auto marker = static_cast<const TraceMarkerModel*>(index.model())->markerFromIndex(index);
auto marker = model->getMarkers()[index.row()];
marker->editingFrequeny = true; marker->editingFrequeny = true;
auto e = marker->getSettingsEditor(); auto e = marker->getSettingsEditor();
if(e) { if(e) {
e->setMaximumHeight(rowHeight);
e->setParent(parent); e->setParent(parent);
connect(e, &SIUnitEdit::valueUpdated, this, &MarkerSettingsDelegate::commitData); connect(e, &SIUnitEdit::valueUpdated, this, &MarkerSettingsDelegate::commitData);
} }
@ -252,25 +323,28 @@ QWidget *MarkerSettingsDelegate::createEditor(QWidget *parent, const QStyleOptio
void MarkerSettingsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const void MarkerSettingsDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{ {
auto markerModel = (TraceMarkerModel*) model; auto markerModel = (TraceMarkerModel*) model;
auto marker = markerModel->getMarkers()[index.row()]; auto marker = markerModel->markerFromIndex(index);
marker->editingFrequeny = false; marker->editingFrequeny = false;
auto si = (SIUnitEdit*) editor; auto si = (SIUnitEdit*) editor;
markerModel->setData(index, si->value()); markerModel->setData(index, si->value());
} }
QSize MarkerTypeDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
return QSize(0, rowHeight);
}
QWidget *MarkerTypeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const QWidget *MarkerTypeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{ {
auto model = (TraceMarkerModel*) index.model(); auto marker = static_cast<const TraceMarkerModel*>(index.model())->markerFromIndex(index);
auto marker = model->getMarkers()[index.row()];
auto editor = marker->getTypeEditor(const_cast<MarkerTypeDelegate*>(this)); auto editor = marker->getTypeEditor(const_cast<MarkerTypeDelegate*>(this));
editor->setMaximumHeight(rowHeight);
editor->setParent(parent); editor->setParent(parent);
// connect(editor, &QWidget::focusC)
return editor; return editor;
} }
void MarkerTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const void MarkerTypeDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{ {
auto markerModel = (TraceMarkerModel*) model; auto marker = static_cast<const TraceMarkerModel*>(index.model())->markerFromIndex(index);
auto marker = markerModel->getMarkers()[index.row()];
marker->updateTypeFromEditor(editor); marker->updateTypeFromEditor(editor);
} }

View File

@ -10,6 +10,7 @@
class MarkerTraceDelegate : public QStyledItemDelegate class MarkerTraceDelegate : public QStyledItemDelegate
{ {
Q_OBJECT; Q_OBJECT;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override; QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
void setEditorData(QWidget * editor, const QModelIndex & index) const override; void setEditorData(QWidget * editor, const QModelIndex & index) const override;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override; void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
@ -18,6 +19,7 @@ class MarkerTraceDelegate : public QStyledItemDelegate
class MarkerTypeDelegate : public QStyledItemDelegate class MarkerTypeDelegate : public QStyledItemDelegate
{ {
Q_OBJECT; Q_OBJECT;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override; QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override; void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
}; };
@ -25,11 +27,12 @@ class MarkerTypeDelegate : public QStyledItemDelegate
class MarkerSettingsDelegate : public QStyledItemDelegate class MarkerSettingsDelegate : public QStyledItemDelegate
{ {
Q_OBJECT; Q_OBJECT;
QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override;
QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override; QWidget *createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override; void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
}; };
class TraceMarkerModel : public QAbstractTableModel class TraceMarkerModel : public QAbstractItemModel
{ {
Q_OBJECT Q_OBJECT
public: public:
@ -44,6 +47,8 @@ public:
ColIndexLast, ColIndexLast,
}; };
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override; QVariant data(const QModelIndex &index, int role) const override;
@ -57,10 +62,11 @@ public:
std::vector<TraceMarker*> getMarkers(Trace *t); std::vector<TraceMarker*> getMarkers(Trace *t);
TraceModel& getModel(); TraceModel& getModel();
void updateMarkers(); void updateMarkers();
TraceMarker *markerFromIndex(const QModelIndex &index) const;
public slots: public slots:
void addMarker(TraceMarker *t); void addMarker(TraceMarker *t);
void removeMarker(unsigned int index, bool delete_marker = true); void removeMarker(unsigned int index);
void removeMarker(TraceMarker *m); void removeMarker(TraceMarker *m);
@ -72,7 +78,7 @@ private slots:
private: private:
std::vector<TraceMarker*> markers; std::vector<TraceMarker*> markers;
TraceModel &model; TraceModel &model;
TraceMarker *root;
}; };
#endif // TRACEMARKERMODEL_H #endif // TRACEMARKERMODEL_H

View File

@ -40,6 +40,9 @@ void TraceSmithChart::mousePressEvent(QMouseEvent *event)
for(auto t : traces) { for(auto t : traces) {
auto markers = t.first->getMarkers(); auto markers = t.first->getMarkers();
for(auto m : markers) { for(auto m : markers) {
if(!m->isMovable()) {
continue;
}
auto S = m->getData(); auto S = m->getData();
auto markerPoint = plotToPixel(S); auto markerPoint = plotToPixel(S);
auto yDiff = abs(markerPoint.y() - clickPoint.y()); auto yDiff = abs(markerPoint.y() - clickPoint.y());

View File

@ -580,9 +580,7 @@ void TraceXYPlot::markerDataChanged(TraceMarker *m)
void TraceXYPlot::markerSymbolChanged(TraceMarker *m) void TraceXYPlot::markerSymbolChanged(TraceMarker *m)
{ {
auto qwtMarker = markers[m]; auto qwtMarker = markers[m];
auto old_sym = qwtMarker->symbol();
qwtMarker->setSymbol(nullptr); qwtMarker->setSymbol(nullptr);
delete old_sym;
QwtSymbol *sym=new QwtSymbol; QwtSymbol *sym=new QwtSymbol;
sym->setPixmap(m->getSymbol()); sym->setPixmap(m->getSymbol());
@ -597,6 +595,9 @@ void TraceXYPlot::clicked(const QPointF pos)
unsigned int closestDistance = numeric_limits<unsigned int>::max(); unsigned int closestDistance = numeric_limits<unsigned int>::max();
TraceMarker *closestMarker = nullptr; TraceMarker *closestMarker = nullptr;
for(auto m : markers) { for(auto m : markers) {
if(!m.first->isMovable()) {
continue;
}
auto markerPoint = drawPicker->plotToPixel(m.second->value()); auto markerPoint = drawPicker->plotToPixel(m.second->value());
auto yDiff = abs(markerPoint.y() - clickPoint.y()); auto yDiff = abs(markerPoint.y() - clickPoint.y());
auto xDiff = abs(markerPoint.x() - clickPoint.x()); auto xDiff = abs(markerPoint.x() - clickPoint.x());