From 88a2597864920ecdbe66cf0cd4b8172bdabb2263 Mon Sep 17 00:00:00 2001 From: Soeren Apel Date: Sun, 19 Apr 2020 15:44:58 +0200 Subject: [PATCH] Add row colors and some fixes --- pv/data/decode/annotation.cpp | 13 ++++++++ pv/data/decode/annotation.hpp | 2 ++ pv/data/decode/rowdata.cpp | 10 +++++- pv/data/decode/rowdata.hpp | 2 ++ pv/data/decodesignal.cpp | 23 ++++++++++++++ pv/views/tabular_decoder/model.cpp | 51 +++++++++++++++++++++++------- pv/views/tabular_decoder/view.cpp | 31 +++++++++++++++--- pv/views/tabular_decoder/view.hpp | 7 +++- pv/views/trace/decodetrace.cpp | 3 ++ 9 files changed, 124 insertions(+), 18 deletions(-) diff --git a/pv/data/decode/annotation.cpp b/pv/data/decode/annotation.cpp index 829bdbaf..fe0350d0 100644 --- a/pv/data/decode/annotation.cpp +++ b/pv/data/decode/annotation.cpp @@ -66,6 +66,11 @@ Annotation& Annotation::operator=(Annotation&& a) return *this; } +const RowData* Annotation::row_data() const +{ + return data_; +} + const Row* Annotation::row() const { return data_->row(); @@ -94,6 +99,14 @@ const QString Annotation::ann_class_name() const return QString(ann_class->name); } +const QString Annotation::ann_class_description() const +{ + const AnnotationClass* ann_class = + data_->row()->decoder()->get_ann_class_by_id(ann_class_id_); + + return QString(ann_class->description); +} + const vector* Annotation::annotations() const { return texts_; diff --git a/pv/data/decode/annotation.hpp b/pv/data/decode/annotation.hpp index cf20a48b..fa514908 100644 --- a/pv/data/decode/annotation.hpp +++ b/pv/data/decode/annotation.hpp @@ -48,6 +48,7 @@ public: Annotation(Annotation&& a); Annotation& operator=(Annotation&& a); + const RowData* row_data() const; const Row* row() const; uint64_t start_sample() const; @@ -55,6 +56,7 @@ public: Class ann_class_id() const; const QString ann_class_name() const; + const QString ann_class_description() const; const vector* annotations() const; const QString longest_annotation() const; diff --git a/pv/data/decode/rowdata.cpp b/pv/data/decode/rowdata.cpp index fc635b24..0434e1c0 100644 --- a/pv/data/decode/rowdata.cpp +++ b/pv/data/decode/rowdata.cpp @@ -95,13 +95,21 @@ void RowData::get_annotation_subset( } } +const deque& RowData::annotations() const +{ + return annotations_; +} + const Annotation* RowData::emplace_annotation(srd_proto_data *pdata) { const srd_proto_data_annotation *const pda = (const srd_proto_data_annotation*)pdata->data; Annotation::Class ann_class_id = (Annotation::Class)(pda->ann_class); - // Look up the longest annotation text to see if we have it in storage + // Look up the longest annotation text to see if we have it in storage. + // This implies that if the longest text is the same, the shorter texts + // are expected to be the same, too. PDs that violate this assumption + // should be considered broken. const char* const* ann_texts = (char**)pda->ann_text; const QString ann0 = QString::fromUtf8(ann_texts[0]); vector* storage_entry = &(ann_texts_[ann0]); diff --git a/pv/data/decode/rowdata.hpp b/pv/data/decode/rowdata.hpp index f01aa3ca..ff59d31a 100644 --- a/pv/data/decode/rowdata.hpp +++ b/pv/data/decode/rowdata.hpp @@ -66,6 +66,8 @@ public: void get_annotation_subset(deque &dest, uint64_t start_sample, uint64_t end_sample) const; + const deque& annotations() const; + const Annotation* emplace_annotation(srd_proto_data *pdata); private: diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp index 6f0e0fa7..77784de0 100644 --- a/pv/data/decodesignal.cpp +++ b/pv/data/decodesignal.cpp @@ -1460,6 +1460,29 @@ void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signa deque& all_annotations = ds->segments_[ds->current_segment_id_].all_annotations; all_annotations.emplace_back(ann); + + // When emplace_annotation() inserts instead of appends an annotation, + // the pointers in all_annotations that follow the inserted annotation and + // point to annotations for this row are off by one and must be updated + if (&(row_data.annotations().back()) != ann) { + // Search backwards until we find the annotation we just added + auto row_it = row_data.annotations().end(); + auto all_it = all_annotations.end(); + do { + all_it--; + if ((*all_it)->row_data() == &row_data) + row_it--; + } while (&(*row_it) != ann); + + // Update the annotation addresses for this row's annotations until the end + do { + if ((*all_it)->row_data() == &row_data) { + *all_it = &(*row_it); + row_it++; + } + all_it++; + } while (all_it != all_annotations.end()); + } } void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) diff --git a/pv/views/tabular_decoder/model.cpp b/pv/views/tabular_decoder/model.cpp index e54fda8c..66fabf5a 100644 --- a/pv/views/tabular_decoder/model.cpp +++ b/pv/views/tabular_decoder/model.cpp @@ -34,12 +34,16 @@ AnnotationCollectionModel::AnnotationCollectionModel(QObject* parent) : prev_segment_(0), prev_last_row_(0) { + GlobalSettings::add_change_handler(this); + theme_is_dark_ = GlobalSettings::current_theme_is_dark(); + // TBD Maybe use empty columns as indentation levels to indicate stacked decoders - header_data_.emplace_back(tr("Start Sample")); // Column #0 - header_data_.emplace_back(tr("Start Time")); // Column #1 - header_data_.emplace_back(tr("Ann Row Name")); // Column #2 - header_data_.emplace_back(tr("Ann Class Name")); // Column #3 - header_data_.emplace_back(tr("Value")); // Column #4 + header_data_.emplace_back(tr("Sample")); // Column #0 + header_data_.emplace_back(tr("Time")); // Column #1 + header_data_.emplace_back(tr("Decoder")); // Column #2 + header_data_.emplace_back(tr("Ann Row")); // Column #3 + header_data_.emplace_back(tr("Ann Class")); // Column #4 + header_data_.emplace_back(tr("Value")); // Column #5 } QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) const @@ -47,20 +51,28 @@ QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) con if (!index.isValid()) return QVariant(); - if (role == Qt::DisplayRole) { - const Annotation* ann = - static_cast(index.internalPointer()); + const Annotation* ann = + static_cast(index.internalPointer()); + if (role == Qt::DisplayRole) { switch (index.column()) { case 0: return QVariant((qulonglong)ann->start_sample()); // Column #0, Start Sample case 1: return QVariant(0/*(qulonglong)ann->start_sample()*/); // Column #1, Start Time - case 2: return QVariant(ann->row()->title()); // Column #2, Ann Row Name - case 3: return QVariant(ann->ann_class_name()); // Column #3, Ann Class Name - case 4: return QVariant(ann->longest_annotation()); // Column #4, Value + case 2: return QVariant(ann->row()->decoder()->name()); // Column #2, Decoder + case 3: return QVariant(ann->row()->description()); // Column #3, Ann Row + case 4: return QVariant(ann->ann_class_description()); // Column #4, Ann Class + case 5: return QVariant(ann->longest_annotation()); // Column #5, Value default: return QVariant(); } } + if (role == Qt::BackgroundRole) { + if (theme_is_dark_) + return QBrush(ann->dark_color()); + else + return QBrush(ann->bright_color()); + } + return QVariant(); } @@ -121,6 +133,13 @@ int AnnotationCollectionModel::columnCount(const QModelIndex& parent_idx) const void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment) { + if (!signal) { + all_annotations_ = nullptr; + dataChanged(QModelIndex(), QModelIndex()); + layoutChanged(); + return; + } + all_annotations_ = signal->get_all_annotations_by_segment(current_segment); if (!all_annotations_ || all_annotations_->empty()) { @@ -147,6 +166,16 @@ void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signa prev_last_row_ = new_row_count; } +void AnnotationCollectionModel::on_setting_changed(const QString &key, const QVariant &value) +{ + (void)key; + (void)value; + + // We don't really care about the actual setting, we just update the + // flag that indicates whether we are using a bright or dark color theme + theme_is_dark_ = GlobalSettings::current_theme_is_dark(); +} + } // namespace tabular_decoder } // namespace views } // namespace pv diff --git a/pv/views/tabular_decoder/view.cpp b/pv/views/tabular_decoder/view.cpp index 4f4c6238..1f79be03 100644 --- a/pv/views/tabular_decoder/view.cpp +++ b/pv/views/tabular_decoder/view.cpp @@ -57,7 +57,7 @@ QSize QCustomTableView::minimumSizeHint() const int width = 0; for (int i = 0; i < horizontalHeader()->count(); i++) if (!horizontalHeader()->isSectionHidden(i)) - width += horizontalHeader()->sectionSizeHint(i); + width += horizontalHeader()->sectionSize(i); size.setWidth(width + (horizontalHeader()->count() * 1)); @@ -128,7 +128,9 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) : const int font_height = QFontMetrics(QApplication::font()).height(); table_view_->verticalHeader()->setDefaultSectionSize((font_height * 5) / 4); - table_view_->horizontalHeader()->setSectionResizeMode(model_->columnCount() - 1, QHeaderView::Stretch); + table_view_->horizontalHeader()->setStretchLastSection(true); + table_view_->horizontalHeader()->setCascadingSectionResizes(true); + table_view_->horizontalHeader()->setSectionsMovable(true); table_view_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); parent->setSizePolicy(table_view_->sizePolicy()); @@ -162,12 +164,16 @@ void View::add_decode_signal(shared_ptr signal) connect(signal.get(), SIGNAL(name_changed(const QString&)), this, SLOT(on_signal_name_changed(const QString&))); + + // Note: At time of initial creation, decode signals have no decoders so we + // need to watch for decoder stacking events + connect(signal.get(), SIGNAL(decoder_stacked(void*)), this, SLOT(on_decoder_stacked(void*))); connect(signal.get(), SIGNAL(decoder_removed(void*)), this, SLOT(on_decoder_removed(void*))); - // Add the top-level decoder provided by this signal + // Add the top-level decoder provided by an already-existing signal auto stack = signal->decoder_stack(); if (!stack.empty()) { shared_ptr& dec = stack.at(0); @@ -274,6 +280,7 @@ void View::save_data() const void View::on_selected_decoder_changed(int index) { if (signal_) { + disconnect(signal_, SIGNAL(signal_color_changed())); disconnect(signal_, SIGNAL(new_annotations())); disconnect(signal_, SIGNAL(decode_reset())); } @@ -289,6 +296,7 @@ void View::on_selected_decoder_changed(int index) signal_ = ds.get(); if (signal_) { + connect(signal_, SIGNAL(color_changed(QColor)), this, SLOT(on_signal_color_changed(QColor))); connect(signal_, SIGNAL(new_annotations()), this, SLOT(on_new_annotations())); connect(signal_, SIGNAL(decode_reset()), this, SLOT(on_decoder_reset())); } @@ -317,6 +325,13 @@ void View::on_signal_name_changed(const QString &name) } } +void View::on_signal_color_changed(const QColor &color) +{ + (void)color; + + table_view_->update(); +} + void View::on_new_annotations() { if (!delayed_view_updater_.isActive()) @@ -344,8 +359,14 @@ void View::on_decoder_stacked(void* decoder) assert(signal); - if (signal == signal_) - update_data(); + const shared_ptr& dec = signal->decoder_stack().at(0); + int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get())); + + if (index == -1) { + // Add the decoder to the list + QString title = QString("%1 (%2)").arg(signal->name(), d->name()); + decoder_selector_->addItem(title, QVariant::fromValue((void*)d)); + } } void View::on_decoder_removed(void* decoder) diff --git a/pv/views/tabular_decoder/view.hpp b/pv/views/tabular_decoder/view.hpp index 8e1dfa41..a6bd9ea3 100644 --- a/pv/views/tabular_decoder/view.hpp +++ b/pv/views/tabular_decoder/view.hpp @@ -25,6 +25,7 @@ #include #include +#include "pv/globalsettings.hpp" #include "pv/views/viewbase.hpp" #include "pv/data/decodesignal.hpp" @@ -35,7 +36,7 @@ namespace views { namespace tabular_decoder { -class AnnotationCollectionModel : public QAbstractTableModel +class AnnotationCollectionModel : public QAbstractTableModel, public GlobalSettingsInterface { Q_OBJECT @@ -57,11 +58,14 @@ public: void set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment); + void on_setting_changed(const QString &key, const QVariant &value) override; + private: vector header_data_; const deque* all_annotations_; uint32_t prev_segment_; uint64_t prev_last_row_; + bool theme_is_dark_; }; @@ -106,6 +110,7 @@ private: private Q_SLOTS: void on_selected_decoder_changed(int index); void on_signal_name_changed(const QString &name); + void on_signal_color_changed(const QColor &color); void on_new_annotations(); void on_decoder_reset(); diff --git a/pv/views/trace/decodetrace.cpp b/pv/views/trace/decodetrace.cpp index f175bd49..53998b2e 100644 --- a/pv/views/trace/decodetrace.cpp +++ b/pv/views/trace/decodetrace.cpp @@ -1493,6 +1493,9 @@ void DecodeTrace::on_color_changed(const QColor &color) { for (DecodeTraceRow& r : rows_) r.decode_row->set_base_color(color); + + if (owner_) + owner_->row_item_appearance_changed(false, true); } void DecodeTrace::on_new_annotations() -- 2.30.2