From: Soeren Apel Date: Tue, 24 Dec 2019 22:13:03 +0000 (+0100) Subject: Rework decoder infrastructure X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=commitdiff_plain;h=6a26fc4417798ab21654197e105e707a14d462f0;ds=sidebyside Rework decoder infrastructure --- diff --git a/pv/binding/decoder.cpp b/pv/binding/decoder.cpp index f51f9077..80725d2a 100644 --- a/pv/binding/decoder.cpp +++ b/pv/binding/decoder.cpp @@ -54,12 +54,11 @@ Decoder::Decoder( { assert(decoder_); - const srd_decoder *const dec = decoder_->decoder(); + const srd_decoder *const dec = decoder_->get_srd_decoder(); assert(dec); for (GSList *l = dec->options; l; l = l->next) { - const srd_decoder_option *const opt = - (srd_decoder_option*)l->data; + const srd_decoder_option *const opt = (srd_decoder_option*)l->data; const QString name = QString::fromUtf8(opt->desc); @@ -115,12 +114,11 @@ Glib::VariantBase Decoder::getter(const char *id) if (iter != options.end()) val = (*iter).second; else { - assert(decoder_->decoder()); + assert(decoder_->get_srd_decoder()); // Get the default value if not - for (GSList *l = decoder_->decoder()->options; l; l = l->next) { - const srd_decoder_option *const opt = - (srd_decoder_option*)l->data; + for (GSList *l = decoder_->get_srd_decoder()->options; l; l = l->next) { + const srd_decoder_option *const opt = (srd_decoder_option*)l->data; if (strcmp(opt->id, id) == 0) { val = opt->def; break; diff --git a/pv/data/decode/annotation.cpp b/pv/data/decode/annotation.cpp index e983b0df..55caa2d7 100644 --- a/pv/data/decode/annotation.cpp +++ b/pv/data/decode/annotation.cpp @@ -24,7 +24,7 @@ extern "C" { #include #include -#include "annotation.hpp" +#include using std::vector; @@ -49,6 +49,8 @@ Annotation::Annotation(const srd_proto_data *const pdata, const Row *row) : annotations_.push_back(QString::fromUtf8(*annotations)); annotations++; } + + annotations_.shrink_to_fit(); } uint64_t Annotation::start_sample() const diff --git a/pv/data/decode/decoder.cpp b/pv/data/decode/decoder.cpp index 19f11399..3769f889 100644 --- a/pv/data/decode/decoder.cpp +++ b/pv/data/decode/decoder.cpp @@ -41,14 +41,44 @@ Decoder::Decoder(const srd_decoder *const dec) : shown_(true), decoder_inst_(nullptr) { - // Query the decoder outputs + // Query the annotation output classes uint32_t i = 0; + for (GSList *l = dec->annotations; l; l = l->next) { + char **ann_class = (char**)l->data; + char *name = ann_class[0]; + char *desc = ann_class[1]; + ann_classes_.push_back({i++, name, desc, nullptr, true}); // Visible by default + } + + // Query the binary output classes + i = 0; for (GSList *l = dec->binary; l; l = l->next) { char **bin_class = (char**)l->data; char *name = bin_class[0]; char *desc = bin_class[1]; bin_classes_.push_back({i++, name, desc}); } + + // Query the annotation rows and reference them by the classes that use them + uint32_t row_count = 0; + for (const GSList *rl = srd_decoder_->annotation_rows; rl; rl = rl->next) + row_count++; + rows_.reserve(row_count); + + i = 0; + for (const GSList *rl = srd_decoder_->annotation_rows; rl; rl = rl->next) { + const srd_decoder_annotation_row *const srd_row = (srd_decoder_annotation_row *)rl->data; + assert(srd_row); + rows_.push_back({i++, this, srd_row}); + + // FIXME PV can crash from .at() if a PD's ann classes are defined incorrectly + for (const GSList *cl = srd_row->ann_classes; cl; cl = cl->next) + ann_classes_.at((size_t)cl->data).row = &(rows_.back()); + } + + if (rows_.empty()) + // Make sure there is a row for PDs without row declarations + rows_.emplace_back(0, this); } Decoder::~Decoder() @@ -57,7 +87,7 @@ Decoder::~Decoder() g_variant_unref(option.second); } -const srd_decoder* Decoder::decoder() const +const srd_decoder* Decoder::get_srd_decoder() const { return srd_decoder_; } @@ -184,6 +214,42 @@ void Decoder::invalidate_decoder_inst() decoder_inst_ = nullptr; } +vector Decoder::get_rows() +{ + vector result; + + for (Row& row : rows_) + result.push_back(&row); + + return result; +} + +Row* Decoder::get_row_by_id(size_t id) +{ + if (id > rows_.size()) + return nullptr; + + return &(rows_[id]); +} + +vector Decoder::ann_classes() const +{ + vector result; + + for (const AnnotationClass& c : ann_classes_) + result.push_back(&c); + + return result; +} + +AnnotationClass* Decoder::get_ann_class_by_id(size_t id) +{ + if (id >= ann_classes_.size()) + return nullptr; + + return &(ann_classes_[id]); +} + uint32_t Decoder::get_binary_class_count() const { return bin_classes_.size(); diff --git a/pv/data/decode/decoder.hpp b/pv/data/decode/decoder.hpp index 282cfe55..4baf86a0 100644 --- a/pv/data/decode/decoder.hpp +++ b/pv/data/decode/decoder.hpp @@ -28,6 +28,7 @@ #include #include +#include using std::map; using std::string; @@ -49,6 +50,15 @@ namespace decode { class Decoder; +struct AnnotationClass +{ + size_t id; + char* name; + char* description; + Row* row; + bool visible; +}; + struct DecodeChannel { uint16_t id; ///< Global numerical ID for the decode channels in the stack @@ -76,7 +86,7 @@ public: virtual ~Decoder(); - const srd_decoder* decoder() const; + const srd_decoder* get_srd_decoder() const; const char* name() const; @@ -97,6 +107,12 @@ public: srd_decoder_inst* create_decoder_inst(srd_session *session); void invalidate_decoder_inst(); + vector get_rows(); + Row* get_row_by_id(size_t id); + + vector ann_classes() const; + AnnotationClass* get_ann_class_by_id(size_t id); + uint32_t get_binary_class_count() const; const DecodeBinaryClassInfo* get_binary_class(uint32_t id) const; @@ -106,6 +122,8 @@ private: bool shown_; vector channels_; + vector rows_; + vector ann_classes_; vector bin_classes_; map options_; srd_decoder_inst *decoder_inst_; diff --git a/pv/data/decode/row.cpp b/pv/data/decode/row.cpp index 31e4cc8e..72a6869f 100644 --- a/pv/data/decode/row.cpp +++ b/pv/data/decode/row.cpp @@ -27,15 +27,17 @@ namespace data { namespace decode { Row::Row() : + index_(0), decoder_(nullptr), - row_(nullptr) + srd_row_(nullptr), + visible_(true) { } -Row::Row(int index, const Decoder* decoder, const srd_decoder_annotation_row* row) : +Row::Row(uint32_t index, Decoder* decoder, const srd_decoder_annotation_row* srd_row) : index_(index), decoder_(decoder), - row_(row), + srd_row_(srd_row), visible_(true) { } @@ -45,32 +47,49 @@ const Decoder* Row::decoder() const return decoder_; } -const srd_decoder_annotation_row* Row::srd_row() const +const srd_decoder_annotation_row* Row::get_srd_row() const { - return row_; + return srd_row_; } const QString Row::title() const { - if (decoder_ && decoder_->name() && row_ && row_->desc) + if (decoder_ && decoder_->name() && srd_row_ && srd_row_->desc) return QString("%1: %2") .arg(QString::fromUtf8(decoder_->name()), - QString::fromUtf8(row_->desc)); + QString::fromUtf8(srd_row_->desc)); if (decoder_ && decoder_->name()) return QString::fromUtf8(decoder_->name()); - if (row_ && row_->desc) - return QString::fromUtf8(row_->desc); + if (srd_row_ && srd_row_->desc) + return QString::fromUtf8(srd_row_->desc); + return QString(); } -const QString Row::class_name() const +const QString Row::description() const { - if (row_ && row_->desc) - return QString::fromUtf8(row_->desc); + if (srd_row_ && srd_row_->desc) + return QString::fromUtf8(srd_row_->desc); return QString(); } -int Row::index() const +vector Row::ann_classes() const +{ + vector result; + + if (!srd_row_) + return result; + assert(decoder_); + + for (GSList *l = srd_row_->ann_classes; l; l = l->next) { + size_t class_id = (size_t)l->data; + result.push_back(decoder_->get_ann_class_by_id(class_id)); + } + + return result; +} + +uint32_t Row::index() const { return index_; } @@ -88,12 +107,12 @@ void Row::set_visible(bool visible) bool Row::operator<(const Row& other) const { return (decoder_ < other.decoder_) || - (decoder_ == other.decoder_ && row_ < other.row_); + (decoder_ == other.decoder_ && srd_row_ < other.srd_row_); } bool Row::operator==(const Row& other) const { - return ((decoder_ == other.decoder()) && (row_ == other.srd_row())); + return ((decoder_ == other.decoder()) && (srd_row_ == other.srd_row_)); } } // namespace decode diff --git a/pv/data/decode/row.hpp b/pv/data/decode/row.hpp index 9d7992e8..21f46d22 100644 --- a/pv/data/decode/row.hpp +++ b/pv/data/decode/row.hpp @@ -22,7 +22,8 @@ #include -#include "annotation.hpp" +#include +#include struct srd_decoder; struct srd_decoder_annotation_row; @@ -31,6 +32,7 @@ namespace pv { namespace data { namespace decode { +struct AnnotationClass; class Decoder; class Row @@ -38,15 +40,16 @@ class Row public: Row(); - Row(int index, const Decoder* decoder, - const srd_decoder_annotation_row* row = nullptr); + Row(uint32_t index, Decoder* decoder, + const srd_decoder_annotation_row* srd_row = nullptr); const Decoder* decoder() const; - const srd_decoder_annotation_row* srd_row() const; + const srd_decoder_annotation_row* get_srd_row() const; const QString title() const; - const QString class_name() const; - int index() const; + const QString description() const; + vector ann_classes() const; + uint32_t index() const; bool visible() const; void set_visible(bool visible); @@ -55,9 +58,9 @@ public: bool operator==(const Row& other) const; private: - int index_; - const Decoder* decoder_; - const srd_decoder_annotation_row* row_; + uint32_t index_; + Decoder* decoder_; + const srd_decoder_annotation_row* srd_row_; bool visible_; }; diff --git a/pv/data/decode/rowdata.cpp b/pv/data/decode/rowdata.cpp index d3d14f9b..c1efdde4 100644 --- a/pv/data/decode/rowdata.cpp +++ b/pv/data/decode/rowdata.cpp @@ -17,7 +17,9 @@ * along with this program; if not, see . */ -#include "rowdata.hpp" +#include +#include +#include using std::vector; @@ -25,6 +27,12 @@ namespace pv { namespace data { namespace decode { +RowData::RowData(Row* row) : + row_(row) +{ + assert(row); +} + uint64_t RowData::get_max_sample() const { if (annotations_.empty()) @@ -41,15 +49,47 @@ void RowData::get_annotation_subset( vector &dest, uint64_t start_sample, uint64_t end_sample) const { - for (const auto& annotation : annotations_) - if (annotation.end_sample() > start_sample && - annotation.start_sample() <= end_sample) - dest.push_back(annotation); + // Determine whether we must apply per-class filtering or not + bool all_ann_classes_enabled = true; + bool all_ann_classes_disabled = true; + + uint32_t max_ann_class_id = 0; + for (AnnotationClass* c : row_->ann_classes()) { + if (!c->visible) + all_ann_classes_enabled = false; + else + all_ann_classes_disabled = false; + if (c->id > max_ann_class_id) + max_ann_class_id = c->id; + } + + if (all_ann_classes_enabled) { + // No filtering, send everyting out as-is + for (const auto& annotation : annotations_) + if ((annotation.end_sample() > start_sample) && + (annotation.start_sample() <= end_sample)) + dest.push_back(annotation); + } else { + if (!all_ann_classes_disabled) { + // Filter out invisible annotation classes + vector class_visible; + class_visible.resize(max_ann_class_id + 1, 0); + for (AnnotationClass* c : row_->ann_classes()) + if (c->visible) + class_visible[c->id] = 1; + + for (const auto& annotation : annotations_) + if ((annotation.end_sample() > start_sample) && + (annotation.start_sample() <= end_sample) && + (class_visible[annotation.ann_class()])) + dest.push_back(annotation); + } + } } -void RowData::emplace_annotation(srd_proto_data *pdata, const Row *row) +void RowData::emplace_annotation(srd_proto_data *pdata) { - annotations_.emplace_back(pdata, row); + annotations_.emplace_back(pdata, row_); } } // namespace decode diff --git a/pv/data/decode/rowdata.hpp b/pv/data/decode/rowdata.hpp index 3c967ff7..0012acd4 100644 --- a/pv/data/decode/rowdata.hpp +++ b/pv/data/decode/rowdata.hpp @@ -24,7 +24,7 @@ #include -#include "annotation.hpp" +#include using std::vector; @@ -37,7 +37,7 @@ class Row; class RowData { public: - RowData() = default; + RowData(Row* row); public: uint64_t get_max_sample() const; @@ -53,10 +53,11 @@ public: vector &dest, uint64_t start_sample, uint64_t end_sample) const; - void emplace_annotation(srd_proto_data *pdata, const Row *row); + void emplace_annotation(srd_proto_data *pdata); private: vector annotations_; + const Row* row_; }; } // namespace decode diff --git a/pv/data/decodesignal.cpp b/pv/data/decodesignal.cpp index 593af02f..a66e69d9 100644 --- a/pv/data/decodesignal.cpp +++ b/pv/data/decodesignal.cpp @@ -42,6 +42,7 @@ using std::out_of_range; using std::shared_ptr; using std::unique_lock; using pv::data::decode::Annotation; +using pv::data::decode::AnnotationClass; using pv::data::decode::DecodeChannel; using pv::data::decode::Decoder; using pv::data::decode::Row; @@ -81,15 +82,13 @@ void DecodeSignal::stack_decoder(const srd_decoder *decoder, bool restart_decode assert(decoder); // Set name if this decoder is the first in the list or the name is unchanged - const srd_decoder* prev_dec = - stack_.empty() ? nullptr : stack_.back()->decoder(); - const QString prev_dec_name = - prev_dec ? QString::fromUtf8(prev_dec->name) : QString(); + const srd_decoder* prev_dec = stack_.empty() ? nullptr : stack_.back()->get_srd_decoder(); + const QString prev_dec_name = prev_dec ? QString::fromUtf8(prev_dec->name) : QString(); if ((stack_.empty()) || ((stack_.size() > 0) && (name() == prev_dec_name))) set_name(QString::fromUtf8(decoder->name)); - const shared_ptr dec = make_shared(decoder); + const shared_ptr dec = make_shared(decoder); stack_.push_back(dec); // Include the newly created decode channels in the channel lists @@ -165,7 +164,6 @@ void DecodeSignal::reset_decode(bool shutting_down) resume_decode(); // Make sure the decode thread isn't blocked by pausing - class_rows_.clear(); current_segment_id_ = 0; segments_.clear(); @@ -217,33 +215,13 @@ void DecodeSignal::begin_decode() ch.assigned_signal = nullptr; // Check that all decoders have the required channels - for (const shared_ptr& dec : stack_) + for (const shared_ptr& dec : stack_) if (!dec->have_required_channels()) { set_error_message(tr("One or more required channels " "have not been specified")); return; } - // Map out all the annotation classes - int row_index = 0; - for (const shared_ptr& dec : stack_) { - assert(dec); - const srd_decoder *const decc = dec->decoder(); - assert(dec->decoder()); - - for (const GSList *l = decc->annotation_rows; l; l = l->next) { - const srd_decoder_annotation_row *const ann_row = - (srd_decoder_annotation_row *)l->data; - assert(ann_row); - - const Row row(row_index++, dec.get(), ann_row); - - for (const GSList *ll = ann_row->ann_classes; - ll; ll = ll->next) - class_rows_[make_pair(decc, GPOINTER_TO_INT(ll->data))] = row; - } - } - // Free the logic data and its segment(s) if it needs to be updated if (logic_mux_data_invalid_) logic_mux_data_.reset(); @@ -453,57 +431,61 @@ int64_t DecodeSignal::get_decoded_sample_count(uint32_t segment_id, return result; } -vector DecodeSignal::get_rows(bool visible_only) const +vector DecodeSignal::get_rows(bool visible_only) { - lock_guard lock(output_mutex_); - - vector rows; + vector rows; - for (const shared_ptr& dec : stack_) { + for (const shared_ptr& dec : stack_) { assert(dec); if (visible_only && !dec->shown()) continue; - const srd_decoder *const decc = dec->decoder(); - assert(dec->decoder()); + for (Row* row : dec->get_rows()) + rows.push_back(row); + } - int row_index = 0; - // Add a row for the decoder if it doesn't have a row list - if (!decc->annotation_rows) - rows.emplace_back(row_index++, dec.get()); + return rows; +} - // Add the decoder rows - for (const GSList *l = decc->annotation_rows; l; l = l->next) { - const srd_decoder_annotation_row *const ann_row = - (srd_decoder_annotation_row *)l->data; - assert(ann_row); - rows.emplace_back(row_index++, dec.get(), ann_row); - } +vector DecodeSignal::get_rows(bool visible_only) const +{ + vector rows; + + for (const shared_ptr& dec : stack_) { + assert(dec); + if (visible_only && !dec->shown()) + continue; + + for (const Row* row : dec->get_rows()) + rows.push_back(row); } return rows; } -uint64_t DecodeSignal::get_annotation_count(const decode::Row &row, - uint32_t segment_id) const + +uint64_t DecodeSignal::get_annotation_count(const Row* row, uint32_t segment_id) const { if (segment_id >= segments_.size()) return 0; - const DecodeSegment *segment = &(segments_.at(segment_id)); - const map *rows = - &(segment->annotation_rows); + const DecodeSegment* segment = &(segments_.at(segment_id)); - const auto iter = rows->find(row); - if (iter != rows->end()) - return (*iter).second.get_annotation_count(); + auto row_it = segment->annotation_rows.find(row); - return 0; + const RowData* rd; + if (row_it == segment->annotation_rows.end()) { + // FIXME Use the fallback row, but how? + assert(false); + return 0; + } else + rd = &(row_it->second); + + return rd->get_annotation_count(); } -void DecodeSignal::get_annotation_subset( - vector &dest, - const decode::Row &row, uint32_t segment_id, uint64_t start_sample, +void DecodeSignal::get_annotation_subset(vector &dest, + const Row* row, uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const { lock_guard lock(output_mutex_); @@ -511,26 +493,29 @@ void DecodeSignal::get_annotation_subset( if (segment_id >= segments_.size()) return; - const DecodeSegment *segment = &(segments_.at(segment_id)); - const map *rows = &(segment->annotation_rows); + const DecodeSegment* segment = &(segments_.at(segment_id)); + + auto row_it = segment->annotation_rows.find(row); - const auto iter = rows->find(row); - if (iter != rows->end()) - (*iter).second.get_annotation_subset(dest, start_sample, end_sample); + const RowData* rd; + if (row_it == segment->annotation_rows.end()) { + // FIXME Use the fallback row, but how? + assert(false); + return; + } else + rd = &(row_it->second); + + rd->get_annotation_subset(dest, start_sample, end_sample); } -void DecodeSignal::get_annotation_subset( - vector &dest, +void DecodeSignal::get_annotation_subset(vector &dest, uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const { - // Note: We put all vectors and lists on the heap, not the stack - - const vector rows = get_rows(); - // Use forward_lists for faster merging forward_list *all_ann_list = new forward_list(); - for (const Row& row : rows) { + vector rows = get_rows(); + for (const Row* row : rows) { vector *ann_vector = new vector(); get_annotation_subset(*ann_vector, row, segment_id, start_sample, end_sample); @@ -625,8 +610,8 @@ void DecodeSignal::get_merged_binary_data_chunks_by_sample(uint32_t segment_id, } void DecodeSignal::get_merged_binary_data_chunks_by_offset(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id, uint64_t start, - uint64_t end, vector *dest) const + const Decoder* dec, uint32_t bin_class_id, uint64_t start, uint64_t end, + vector *dest) const { assert(dest != nullptr); @@ -667,7 +652,7 @@ void DecodeSignal::get_merged_binary_data_chunks_by_offset(uint32_t segment_id, } const DecodeBinaryClass* DecodeSignal::get_binary_data_class(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id) const + const Decoder* dec, uint32_t bin_class_id) const { try { const DecodeSegment *segment = &(segments_.at(segment_id)); @@ -690,10 +675,10 @@ void DecodeSignal::save_settings(QSettings &settings) const // Save decoder stack int decoder_idx = 0; - for (const shared_ptr& decoder : stack_) { + for (const shared_ptr& decoder : stack_) { settings.beginGroup("decoder" + QString::number(decoder_idx++)); - settings.setValue("id", decoder->decoder()->id); + settings.setValue("id", decoder->get_srd_decoder()->id); settings.setValue("shown", decoder->shown()); // Save decoder options @@ -701,7 +686,7 @@ void DecodeSignal::save_settings(QSettings &settings) const settings.setValue("options", (int)options.size()); - // Note: decode::Decoder::options() returns only the options + // Note: Decoder::options() returns only the options // that differ from the default. See binding::Decoder::getter() int i = 0; for (auto& option : options) { @@ -759,8 +744,7 @@ void DecodeSignal::restore_settings(QSettings &settings) continue; if (QString::fromUtf8(dec->id) == id) { - shared_ptr decoder = - make_shared(dec); + shared_ptr decoder = make_shared(dec); stack_.push_back(decoder); decoder->show(settings.value("shown", true).toBool()); @@ -872,6 +856,15 @@ uint32_t DecodeSignal::get_input_samplerate(uint32_t segment_id) const return samplerate; } +Decoder* DecodeSignal::get_decoder_by_instance(const srd_decoder *const srd_dec) +{ + for (shared_ptr& d : stack_) + if (d->get_srd_decoder() == srd_dec) + return d.get(); + + return nullptr; +} + void DecodeSignal::update_channel_list() { vector prev_channels = channels_; @@ -881,11 +874,11 @@ void DecodeSignal::update_channel_list() // Copy existing entries, create new as needed for (shared_ptr& decoder : stack_) { - const srd_decoder* srd_d = decoder->decoder(); + const srd_decoder* srd_dec = decoder->get_srd_decoder(); const GSList *l; // Mandatory channels - for (l = srd_d->channels; l; l = l->next) { + for (l = srd_dec->channels; l; l = l->next) { const struct srd_channel *const pdch = (struct srd_channel *)l->data; bool ch_added = false; @@ -908,7 +901,7 @@ void DecodeSignal::update_channel_list() } // Optional channels - for (l = srd_d->opt_channels; l; l = l->next) { + for (l = srd_dec->opt_channels; l; l = l->next) { const struct srd_channel *const pdch = (struct srd_channel *)l->data; bool ch_added = false; @@ -956,7 +949,7 @@ void DecodeSignal::update_channel_list() void DecodeSignal::commit_decoder_channels() { // Submit channel list to every decoder, containing only the relevant channels - for (shared_ptr dec : stack_) { + for (shared_ptr dec : stack_) { vector channel_list; for (decode::DecodeChannel& ch : channels_) @@ -1271,7 +1264,7 @@ void DecodeSignal::start_srd_session() if (samplerate) srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE, g_variant_new_uint64(samplerate)); - for (const shared_ptr& dec : stack_) + for (const shared_ptr& dec : stack_) dec->apply_all_options(); srd_session_start(srd_session_); @@ -1284,7 +1277,7 @@ void DecodeSignal::start_srd_session() // Create the decoders srd_decoder_inst *prev_di = nullptr; - for (const shared_ptr& dec : stack_) { + for (const shared_ptr& dec : stack_) { srd_decoder_inst *const di = dec->create_decoder_inst(srd_session_); if (!di) { @@ -1334,7 +1327,7 @@ void DecodeSignal::terminate_srd_session() if (samplerate) srd_session_metadata_set(srd_session_, SRD_CONF_SAMPLERATE, g_variant_new_uint64(samplerate)); - for (const shared_ptr& dec : stack_) + for (const shared_ptr& dec : stack_) dec->apply_all_options(); } } @@ -1347,7 +1340,7 @@ void DecodeSignal::stop_srd_session() srd_session_ = nullptr; // Mark the decoder instances as non-existant since they were deleted - for (const shared_ptr& dec : stack_) + for (const shared_ptr& dec : stack_) dec->invalidate_decoder_inst(); } } @@ -1377,32 +1370,12 @@ void DecodeSignal::create_decode_segment() segments_.emplace_back(DecodeSegment()); // Add annotation classes - for (const shared_ptr& dec : stack_) { - assert(dec); - const srd_decoder *const decc = dec->decoder(); - assert(dec->decoder()); - - int row_index = 0; - // Add a row for the decoder if it doesn't have a row list - if (!decc->annotation_rows) - (segments_.back().annotation_rows)[Row(row_index++, dec.get())] = - decode::RowData(); - - // Add the decoder rows - for (const GSList *l = decc->annotation_rows; l; l = l->next) { - const srd_decoder_annotation_row *const ann_row = - (srd_decoder_annotation_row *)l->data; - assert(ann_row); - - const Row row(row_index++, dec.get(), ann_row); - - // Add a new empty row data object - (segments_.back().annotation_rows)[row] = decode::RowData(); - } - } + for (const shared_ptr dec : stack_) + for (Row* row : dec->get_rows()) + segments_.back().annotation_rows.emplace(row, RowData(row)); // Prepare our binary output classes - for (const shared_ptr& dec : stack_) { + for (const shared_ptr& dec : stack_) { uint32_t n = dec->get_binary_class_count(); for (uint32_t i = 0; i < n; i++) @@ -1427,36 +1400,26 @@ void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signa // Get the decoder and the annotation data assert(pdata->pdo); assert(pdata->pdo->di); - const srd_decoder *const decc = pdata->pdo->di->decoder; - assert(decc); + const srd_decoder *const srd_dec = pdata->pdo->di->decoder; + assert(srd_dec); const srd_proto_data_annotation *const pda = (const srd_proto_data_annotation*)pdata->data; assert(pda); // Find the row - auto row_iter = ds->segments_.at(ds->current_segment_id_).annotation_rows.end(); - - // Try finding a better row match than the default by looking up the sub-row of this class - const auto format = pda->ann_class; - const auto r = ds->class_rows_.find(make_pair(decc, format)); - if (r != ds->class_rows_.end()) - row_iter = ds->segments_.at(ds->current_segment_id_).annotation_rows.find((*r).second); - else { - // Failing that, use the decoder as a key - for (const shared_ptr& dec : ds->decoder_stack()) - if (dec->decoder() == decc) - row_iter = ds->segments_.at(ds->current_segment_id_).annotation_rows.find(Row(0, dec.get())); - } + Decoder* dec = ds->get_decoder_by_instance(srd_dec); + assert(dec); - if (row_iter == ds->segments_.at(ds->current_segment_id_).annotation_rows.end()) { - qDebug() << "Unexpected annotation: decoder = " << decc << - ", format = " << format; - assert(false); - return; - } + AnnotationClass* ann_class = dec->get_ann_class_by_id(pda->ann_class); + assert(ann_class); + + const Row* row = ann_class->row; + + if (!row) + row = dec->get_row_by_id(0); // Add the annotation - (*row_iter).second.emplace_annotation(pdata, &((*row_iter).first)); + ds->segments_[ds->current_segment_id_].annotation_rows.at(row).emplace_annotation(pdata); } void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) @@ -1473,8 +1436,8 @@ void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) // Get the decoder and the binary data assert(pdata->pdo); assert(pdata->pdo->di); - const srd_decoder *const decc = pdata->pdo->di->decoder; - assert(decc); + const srd_decoder *const srd_dec = pdata->pdo->di->decoder; + assert(srd_dec); const srd_proto_data_binary *const pdb = (const srd_proto_data_binary*)pdata->data; assert(pdb); @@ -1484,7 +1447,8 @@ void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) DecodeBinaryClass* bin_class = nullptr; for (DecodeBinaryClass& bc : segment->binary_classes) - if ((bc.decoder->decoder() == decc) && (bc.info->bin_class_id == (uint32_t)pdb->bin_class)) + if ((bc.decoder->get_srd_decoder() == srd_dec) && + (bc.info->bin_class_id == (uint32_t)pdb->bin_class)) bin_class = &bc; if (!bin_class) { @@ -1502,13 +1466,7 @@ void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal) chunk->data.resize(pdb->size); memcpy(chunk->data.data(), pdb->data, pdb->size); - // Find decoder class instance - Decoder* dec = nullptr; - for (const shared_ptr& d : ds->decoder_stack()) - if (d->decoder() == decc) { - dec = d.get(); - break; - } + Decoder* dec = ds->get_decoder_by_instance(srd_dec); ds->new_binary_data(ds->current_segment_id_, (void*)dec, pdb->bin_class); } diff --git a/pv/data/decodesignal.hpp b/pv/data/decodesignal.hpp index f3ef9dfa..0e5d38c6 100644 --- a/pv/data/decodesignal.hpp +++ b/pv/data/decodesignal.hpp @@ -46,17 +46,18 @@ using std::pair; using std::vector; using std::shared_ptr; +using pv::data::decode::Annotation; +using pv::data::decode::DecodeBinaryClassInfo; +using pv::data::decode::DecodeChannel; +using pv::data::decode::Decoder; +using pv::data::decode::Row; +using pv::data::decode::RowData; + namespace pv { class Session; namespace data { -namespace decode { -class Annotation; -class Decoder; -class Row; -} - class Logic; class LogicSegment; class SignalBase; @@ -70,14 +71,14 @@ struct DecodeBinaryDataChunk struct DecodeBinaryClass { - const decode::Decoder* decoder; - const decode::DecodeBinaryClassInfo* info; + const Decoder* decoder; + const DecodeBinaryClassInfo* info; deque chunks; }; struct DecodeSegment { - map annotation_rows; + map annotation_rows; pv::util::Timestamp start_time; double samplerate; int64_t samples_decoded_incl, samples_decoded_excl; @@ -98,7 +99,7 @@ public: virtual ~DecodeSignal(); bool is_decode_signal() const; - const vector< shared_ptr >& decoder_stack() const; + const vector< shared_ptr >& decoder_stack() const; void stack_decoder(const srd_decoder *decoder, bool restart_decode=true); void remove_decoder(int index); @@ -111,8 +112,8 @@ public: bool is_paused() const; QString error_message() const; - const vector get_channels() const; - void auto_assign_signals(const shared_ptr dec); + const vector get_channels() const; + void auto_assign_signals(const shared_ptr dec); void assign_signal(const uint16_t channel_id, const SignalBase *signal); int get_assigned_signal_count() const; @@ -139,44 +140,42 @@ public: int64_t get_decoded_sample_count(uint32_t segment_id, bool include_processing) const; - vector get_rows(bool visible_only=false) const; + vector get_rows(bool visible_only=false); + vector get_rows(bool visible_only=false) const; - uint64_t get_annotation_count(const decode::Row &row, uint32_t segment_id) const; + uint64_t get_annotation_count(const Row* row, uint32_t segment_id) const; /** * Extracts annotations from a single row into a vector. * Note: The annotations may be unsorted and only annotations that fully * fit into the sample range are considered. */ - void get_annotation_subset( - vector &dest, - const decode::Row &row, uint32_t segment_id, uint64_t start_sample, - uint64_t end_sample) const; + void get_annotation_subset(vector &dest, const Row* row, + uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const; /** * Extracts annotations from all rows into a vector. * Note: The annotations may be unsorted and only annotations that fully * fit into the sample range are considered. */ - void get_annotation_subset( - vector &dest, - uint32_t segment_id, uint64_t start_sample, uint64_t end_sample) const; + void get_annotation_subset(vector &dest, uint32_t segment_id, + uint64_t start_sample, uint64_t end_sample) const; uint32_t get_binary_data_chunk_count(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id) const; - void get_binary_data_chunk(uint32_t segment_id, const data::decode::Decoder* dec, + const Decoder* dec, uint32_t bin_class_id) const; + void get_binary_data_chunk(uint32_t segment_id, const Decoder* dec, uint32_t bin_class_id, uint32_t chunk_id, const vector **dest, uint64_t *size); void get_merged_binary_data_chunks_by_sample(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id, + const Decoder* dec, uint32_t bin_class_id, uint64_t start_sample, uint64_t end_sample, vector *dest) const; void get_merged_binary_data_chunks_by_offset(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id, + const Decoder* dec, uint32_t bin_class_id, uint64_t start, uint64_t end, vector *dest) const; const DecodeBinaryClass* get_binary_data_class(uint32_t segment_id, - const data::decode::Decoder* dec, uint32_t bin_class_id) const; + const Decoder* dec, uint32_t bin_class_id) const; virtual void save_settings(QSettings &settings) const; @@ -186,20 +185,19 @@ private: void set_error_message(QString msg); uint32_t get_input_segment_count() const; - uint32_t get_input_samplerate(uint32_t segment_id) const; + Decoder* get_decoder_by_instance(const srd_decoder *const srd_dec); + void update_channel_list(); void commit_decoder_channels(); void mux_logic_samples(uint32_t segment_id, const int64_t start, const int64_t end); - void logic_mux_proc(); void decode_data(const int64_t abs_start_samplenum, const int64_t sample_count, const shared_ptr input_segment); - void decode_proc(); void start_srd_session(); @@ -230,7 +228,7 @@ private Q_SLOTS: private: pv::Session &session_; - vector channels_; + vector channels_; struct srd_session *srd_session_; @@ -238,9 +236,8 @@ private: uint32_t logic_mux_unit_size_; bool logic_mux_data_invalid_; - vector< shared_ptr > stack_; + vector< shared_ptr > stack_; bool stack_config_changed_; - map, decode::Row> class_rows_; vector segments_; uint32_t current_segment_id_; diff --git a/pv/dialogs/settings.cpp b/pv/dialogs/settings.cpp index 0dc6b055..9854af4f 100644 --- a/pv/dialogs/settings.cpp +++ b/pv/dialogs/settings.cpp @@ -393,7 +393,7 @@ QWidget *Settings::get_decoder_settings_form(QWidget *parent) connect(ann_export_format_, SIGNAL(textChanged(const QString&)), this, SLOT(on_dec_exportFormat_changed(const QString&))); decoder_layout->addRow(tr("Annotation export format"), ann_export_format_); - QLabel *description_1 = new QLabel(tr("%s = sample range; %d: decoder name; %c: row name; %q: use quotations marks")); + QLabel *description_1 = new QLabel(tr("%s = sample range; %d: decoder name; %r: row name; %q: use quotation marks")); description_1->setAlignment(Qt::AlignRight); decoder_layout->addRow(description_1); QLabel *description_2 = new QLabel(tr("%1: longest annotation text; %a: all annotation texts")); diff --git a/pv/globalsettings.cpp b/pv/globalsettings.cpp index 4b793656..f7df4802 100644 --- a/pv/globalsettings.cpp +++ b/pv/globalsettings.cpp @@ -130,8 +130,10 @@ void GlobalSettings::set_defaults_where_needed() if (!contains(Key_View_SnapDistance)) setValue(Key_View_SnapDistance, 15); - if (!contains(Key_Dec_ExportFormat)) - setValue(Key_Dec_ExportFormat, "%s %d: %c: %1"); + // %c was used for the row name in the past so we need to transition such users + if (!contains(Key_Dec_ExportFormat) || + value(Key_Dec_ExportFormat).toString() == "%s %d: %c: %1") + setValue(Key_Dec_ExportFormat, "%s %d: %r: %1"); // Default to 500 lines of backlog if (!contains(Key_Log_BufferSize)) diff --git a/pv/views/trace/decodetrace.cpp b/pv/views/trace/decodetrace.cpp index 8cddcd45..d4df8041 100644 --- a/pv/views/trace/decodetrace.cpp +++ b/pv/views/trace/decodetrace.cpp @@ -72,6 +72,7 @@ using std::tie; using std::vector; using pv::data::decode::Annotation; +using pv::data::decode::AnnotationClass; using pv::data::decode::Row; using pv::data::decode::DecodeChannel; using pv::data::DecodeSignal; @@ -146,6 +147,8 @@ DecodeTrace::DecodeTrace(pv::Session &session, this, SLOT(on_show_hide_decoder(int))); connect(&row_show_hide_mapper_, SIGNAL(mapped(int)), this, SLOT(on_show_hide_row(int))); + connect(&class_show_hide_mapper_, SIGNAL(mapped(QWidget*)), + this, SLOT(on_show_hide_class(QWidget*))); connect(&delayed_trace_updater_, SIGNAL(timeout()), this, SLOT(on_delayed_trace_update())); @@ -165,7 +168,7 @@ DecodeTrace::~DecodeTrace() { GlobalSettings::remove_change_handler(this); - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { for (QCheckBox* cb : r.selectors) delete cb; @@ -192,7 +195,7 @@ pair DecodeTrace::v_extents() const return make_pair(-default_row_height_, default_row_height_); unsigned int height = 0; - for (const RowData& r : rows_) + for (const DecodeTraceRow& r : rows_) if (r.currently_visible) height += r.height; @@ -220,14 +223,14 @@ void DecodeTrace::paint_mid(QPainter &p, ViewItemPaintParams &pp) sample_range.second = min((int64_t)sample_range.second, decode_signal_->get_decoded_sample_count(current_segment_, false)); - for (RowData& r : rows_) - r.currently_visible = false; visible_rows_ = 0; int y = get_visual_y(); - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { // If the row is hidden, we don't want to fetch annotations - if ((!r.decode_row.decoder()->shown()) || (!r.decode_row.visible())) { + assert(r.decode_row); + assert(r.decode_row->decoder()); + if ((!r.decode_row->decoder()->shown()) || (!r.decode_row->visible())) { r.currently_visible = false; continue; } @@ -238,12 +241,15 @@ void DecodeTrace::paint_mid(QPainter &p, ViewItemPaintParams &pp) // Show row if there are visible annotations or when user wants to see // all rows that have annotations somewhere and this one is one of them - size_t ann_count = decode_signal_->get_annotation_count(r.decode_row, current_segment_); - r.currently_visible = !annotations.empty() || (always_show_all_rows_ && (ann_count > 0)); + r.currently_visible = !annotations.empty(); + if (!r.currently_visible) { + size_t ann_count = decode_signal_->get_annotation_count(r.decode_row, current_segment_); + r.currently_visible = always_show_all_rows_ && (ann_count > 0); + } if (r.currently_visible) { draw_annotations(annotations, p, annotation_height_, pp, y, - get_row_color(r.decode_row.index()), r.title_width); + get_row_color(r.decode_row->index()), r.title_width); y += r.height; visible_rows_++; } @@ -268,7 +274,7 @@ void DecodeTrace::paint_fore(QPainter &p, ViewItemPaintParams &pp) { unsigned int y = get_visual_y(); - for (const RowData& r : rows_) { + for (const DecodeTraceRow& r : rows_) { if (!r.currently_visible) continue; @@ -288,7 +294,7 @@ void DecodeTrace::paint_fore(QPainter &p, ViewItemPaintParams &pp) const QRect text_rect(pp.left() + ArrowSize * 2, y - r.height / 2, pp.right() - pp.left(), r.height); - const QString h(r.decode_row.title()); + const QString h(r.decode_row->title()); const int f = Qt::AlignLeft | Qt::AlignVCenter | Qt::TextDontClip; @@ -316,7 +322,7 @@ void DecodeTrace::update_stack_button() // Only show decoders in the menu that can be stacked onto the last one in the stack if (!stack.empty()) { - const srd_decoder* d = stack.back()->decoder(); + const srd_decoder* d = stack.back()->get_srd_decoder(); if (d->outputs) { pv::widgets::DecoderMenu *const decoder_menu = @@ -414,9 +420,9 @@ QMenu* DecodeTrace::create_view_context_menu(QWidget *parent, QPoint &click_pos) } selected_row_ = nullptr; - const RowData* r = get_row_at_point(click_pos); + const DecodeTraceRow* r = get_row_at_point(click_pos); if (r) - selected_row_ = &(r->decode_row); + selected_row_ = r->decode_row; const View *const view = owner_->view(); assert(view); @@ -516,10 +522,10 @@ void DecodeTrace::hover_point_changed(const QPoint &hp) assert(owner_); - RowData* hover_row = get_row_at_point(hp); + DecodeTraceRow* hover_row = get_row_at_point(hp); // Row expansion marker handling - for (RowData& r : rows_) + for (DecodeTraceRow& r : rows_) r.expand_marker_highlighted = false; if (hover_row) { @@ -565,7 +571,7 @@ void DecodeTrace::hover_point_changed(const QPoint &hp) void DecodeTrace::mouse_left_press_event(const QMouseEvent* event) { // Handle row expansion marker - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { if (!r.expand_marker_highlighted) continue; @@ -941,13 +947,13 @@ QColor DecodeTrace::get_annotation_color(QColor row_color, int annotation_index) return color; } -unsigned int DecodeTrace::get_row_y(const RowData* row) const +unsigned int DecodeTrace::get_row_y(const DecodeTraceRow* row) const { assert(row); unsigned int y = get_visual_y(); - for (const RowData& r : rows_) { + for (const DecodeTraceRow& r : rows_) { if (!r.currently_visible) continue; @@ -960,11 +966,11 @@ unsigned int DecodeTrace::get_row_y(const RowData* row) const return y; } -RowData* DecodeTrace::get_row_at_point(const QPoint &point) +DecodeTraceRow* DecodeTrace::get_row_at_point(const QPoint &point) { int y = get_visual_y() - (default_row_height_ / 2); - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { if (!r.currently_visible) continue; @@ -986,7 +992,7 @@ const QString DecodeTrace::get_annotation_at_point(const QPoint &point) const pair sample_range = get_view_sample_range(point.x(), point.x() + 1); - const RowData* r = get_row_at_point(point); + const DecodeTraceRow* r = get_row_at_point(point); if (!r) return QString(); @@ -1010,7 +1016,7 @@ void DecodeTrace::create_decoder_form(int index, GlobalSettings settings; assert(dec); - const srd_decoder *const decoder = dec->decoder(); + const srd_decoder *const decoder = dec->get_srd_decoder(); assert(decoder); const bool decoder_deletable = index > 0; @@ -1151,7 +1157,7 @@ void DecodeTrace::export_annotations(vector *annotations) const const QString sample_range = QString("%1-%2") \ .arg(QString::number(ann.start_sample()), QString::number(ann.end_sample())); - const QString class_name = quote + ann.row()->class_name() + quote; + const QString row_name = quote + ann.row()->description() + quote; QString all_ann_text; for (const QString &s : ann.annotations()) @@ -1164,7 +1170,7 @@ void DecodeTrace::export_annotations(vector *annotations) const out_text = out_text.replace("%s", sample_range); out_text = out_text.replace("%d", quote + QString::fromUtf8(ann.row()->decoder()->name()) + quote); - out_text = out_text.replace("%c", class_name); + out_text = out_text.replace("%r", row_name); out_text = out_text.replace("%1", first_ann_text); out_text = out_text.replace("%a", all_ann_text); out_stream << out_text << '\n'; @@ -1181,10 +1187,8 @@ void DecodeTrace::export_annotations(vector *annotations) const msg.exec(); } -void DecodeTrace::update_rows() +void DecodeTrace::initialize_row_widgets(DecodeTraceRow* r, unsigned int row_id) { - lock_guard lock(row_modification_mutex_); - QFontMetrics m(QApplication::font()); QPalette header_palette = owner_->view()->palette(); @@ -1202,19 +1206,80 @@ void DecodeTrace::update_rows() QColor(0, 0, 0, ExpansionAreaAlpha)); } - for (RowData& r : rows_) + const int w = m.boundingRect(r->decode_row->title()).width() + RowTitleMargin; + r->title_width = w; + + r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(), + r->expanded_height - 2 * default_row_height_); + r->container->setVisible(false); + + QVBoxLayout* vlayout = new QVBoxLayout(); + r->container->setLayout(vlayout); + + // Add header container with checkbox for this row + vlayout->addWidget(r->header_container); + vlayout->setContentsMargins(0, 0, 0, 0); + vlayout->setSpacing(0); + r->header_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + r->header_container->setMinimumSize(0, default_row_height_); + r->header_container->setLayout(new QVBoxLayout()); + r->header_container->layout()->setContentsMargins(10, 2, 0, 2); + + r->header_container->setAutoFillBackground(true); + r->header_container->setPalette(header_palette); + + QCheckBox* cb = new QCheckBox(); + r->header_container->layout()->addWidget(cb); + cb->setText(tr("Show this row")); + cb->setChecked(r->decode_row->visible()); + + row_show_hide_mapper_.setMapping(cb, row_id); + connect(cb, SIGNAL(stateChanged(int)), + &row_show_hide_mapper_, SLOT(map())); + + // Add selector container + vlayout->addWidget(r->selector_container); + r->selector_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + r->selector_container->setMinimumSize(0, 3 * default_row_height_); // FIXME + r->selector_container->setLayout(new QHBoxLayout()); + + r->selector_container->setAutoFillBackground(true); + r->selector_container->setPalette(selector_palette); + + // Add all classes that can be toggled + vector ann_classes = r->decode_row->ann_classes(); + + for (const AnnotationClass* ann_class : ann_classes) { + cb = new QCheckBox(); + cb->setText(tr(ann_class->description)); + cb->setChecked(ann_class->visible); + + r->selector_container->layout()->addWidget(cb); + + cb->setProperty("ann_class_ptr", QVariant::fromValue((void*)ann_class)); + class_show_hide_mapper_.setMapping(cb, cb); + connect(cb, SIGNAL(stateChanged(int)), + &class_show_hide_mapper_, SLOT(map())); + } +} + +void DecodeTrace::update_rows() +{ + lock_guard lock(row_modification_mutex_); + + for (DecodeTraceRow& r : rows_) r.exists = false; unsigned int row_id = 0; - for (const Row& decode_row : decode_signal_->get_rows()) { + for (Row* decode_row : decode_signal_->get_rows()) { // Find row in our list auto r_it = find_if(rows_.begin(), rows_.end(), - [&](RowData& r){ return r.decode_row == decode_row; }); + [&](DecodeTraceRow& r){ return r.decode_row == decode_row; }); - RowData* r = nullptr; + DecodeTraceRow* r = nullptr; if (r_it == rows_.end()) { // Row doesn't exist yet, create and append it - RowData nr; + DecodeTraceRow nr; nr.decode_row = decode_row; nr.height = default_row_height_; nr.expanded_height = default_row_height_; @@ -1230,54 +1295,11 @@ void DecodeTrace::update_rows() rows_.push_back(nr); r = &rows_.back(); + initialize_row_widgets(r, row_id); } else r = &(*r_it); r->exists = true; - - const int w = m.boundingRect(r->decode_row.title()).width() + RowTitleMargin; - r->title_width = w; - - r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(), - r->expanded_height - 2 * default_row_height_); - r->container->setVisible(false); - - QVBoxLayout* vlayout = new QVBoxLayout(); - r->container->setLayout(vlayout); - - // Add header container with checkbox for this row - vlayout->addWidget(r->header_container); - vlayout->setContentsMargins(0, 0, 0, 0); - vlayout->setSpacing(0); - r->header_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - r->header_container->setMinimumSize(0, default_row_height_); - r->header_container->setLayout(new QVBoxLayout()); - r->header_container->layout()->setContentsMargins(10, 2, 0, 2); - - r->header_container->setAutoFillBackground(true); - r->header_container->setPalette(header_palette); - - QCheckBox* cb = new QCheckBox(); - r->header_container->layout()->addWidget(cb); - cb->setText(tr("Show this row")); - cb->setChecked(r->decode_row.visible()); - - row_show_hide_mapper_.setMapping(cb, row_id); - connect(cb, SIGNAL(stateChanged(int)), - &row_show_hide_mapper_, SLOT(map())); - - // Add selector container - vlayout->addWidget(r->selector_container); - r->selector_container->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); - r->selector_container->setMinimumSize(0, 3 * default_row_height_); // FIXME - r->selector_container->setLayout(new QVBoxLayout()); - - r->selector_container->setAutoFillBackground(true); - r->selector_container->setPalette(selector_palette); - - - // Add all classes that can be toggled - row_id++; } @@ -1302,7 +1324,7 @@ void DecodeTrace::update_rows() } while (any_exists); } -void DecodeTrace::set_row_expanded(RowData* r) +void DecodeTrace::set_row_expanded(DecodeTraceRow* r) { r->height = r->expanded_height; r->expanding = false; @@ -1315,9 +1337,11 @@ void DecodeTrace::set_row_expanded(RowData* r) r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(), r->height - 2 * default_row_height_); + + max_visible_rows_ = 0; } -void DecodeTrace::set_row_collapsed(RowData* r) +void DecodeTrace::set_row_collapsed(DecodeTraceRow* r) { r->height = default_row_height_; r->collapsing = false; @@ -1327,11 +1351,13 @@ void DecodeTrace::set_row_collapsed(RowData* r) r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(), r->height - 2 * default_row_height_); + + max_visible_rows_ = 0; } void DecodeTrace::update_expanded_rows() { - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { r.container->move(2 * ArrowSize, get_row_y(&r) + default_row_height_); @@ -1457,13 +1483,13 @@ void DecodeTrace::on_show_hide_decoder(int index) owner_->row_item_appearance_changed(false, true); } -void DecodeTrace::on_show_hide_row(int index) +void DecodeTrace::on_show_hide_row(int row_id) { - if (index >= (int)rows_.size()) + if (row_id >= (int)rows_.size()) return; - set_row_collapsed(&rows_[index]); - rows_[index].decode_row.set_visible(!rows_[index].decode_row.visible()); + set_row_collapsed(&rows_[row_id]); + rows_[row_id].decode_row->set_visible(!rows_[row_id].decode_row->visible()); // Force re-calculation of the trace height, see paint_mid() max_visible_rows_ = 0; @@ -1471,6 +1497,17 @@ void DecodeTrace::on_show_hide_row(int index) owner_->row_item_appearance_changed(false, true); } +void DecodeTrace::on_show_hide_class(QWidget* sender) +{ + void* ann_class_ptr = sender->property("ann_class_ptr").value(); + assert(ann_class_ptr); + + AnnotationClass* ann_class = (AnnotationClass*)ann_class_ptr; + ann_class->visible = !ann_class->visible; + + owner_->row_item_appearance_changed(false, true); +} + void DecodeTrace::on_copy_annotation_to_clipboard() { using namespace pv::data::decode; @@ -1480,7 +1517,7 @@ void DecodeTrace::on_copy_annotation_to_clipboard() vector *annotations = new vector(); - decode_signal_->get_annotation_subset(*annotations, *selected_row_, + decode_signal_->get_annotation_subset(*annotations, selected_row_, current_segment_, selected_sample_range_.first, selected_sample_range_.first); if (annotations->empty()) @@ -1568,7 +1605,7 @@ void DecodeTrace::on_export_row_from_here() vector *annotations = new vector(); - decode_signal_->get_annotation_subset(*annotations, *selected_row_, + decode_signal_->get_annotation_subset(*annotations, selected_row_, current_segment_, selected_sample_range_.first, selected_sample_range_.second); if (annotations->empty()) @@ -1597,7 +1634,7 @@ void DecodeTrace::on_animation_timer() { bool animation_finished = true; - for (RowData& r : rows_) { + for (DecodeTraceRow& r : rows_) { if (!(r.expanding || r.collapsing)) continue; diff --git a/pv/views/trace/decodetrace.hpp b/pv/views/trace/decodetrace.hpp index 42ceb2a5..e2624988 100644 --- a/pv/views/trace/decodetrace.hpp +++ b/pv/views/trace/decodetrace.hpp @@ -48,6 +48,8 @@ using std::pair; using std::shared_ptr; using std::vector; +using pv::data::decode::Row; + struct srd_channel; struct srd_decoder; @@ -61,6 +63,7 @@ class DecodeSignal; namespace decode { class Decoder; +class Row; } } // namespace data @@ -71,11 +74,11 @@ class DecoderGroupBox; namespace views { namespace trace { -struct RowData { +struct DecodeTraceRow { // When adding a field, make sure it's initialized properly in // DecodeTrace::update_rows() - data::decode::Row decode_row; + Row* decode_row; unsigned int height, expanded_height, title_width, animation_step; bool exists, currently_visible; bool expand_marker_highlighted, expanding, expanded, collapsing; @@ -195,9 +198,9 @@ private: QColor get_row_color(int row_index) const; QColor get_annotation_color(QColor row_color, int annotation_index) const; - unsigned int get_row_y(const RowData* row) const; + unsigned int get_row_y(const DecodeTraceRow* row) const; - RowData* get_row_at_point(const QPoint &point); + DecodeTraceRow* get_row_at_point(const QPoint &point); const QString get_annotation_at_point(const QPoint &point); @@ -214,17 +217,18 @@ private: void export_annotations(vector *annotations) const; + void initialize_row_widgets(DecodeTraceRow* r, unsigned int row_id); void update_rows(); /** * Sets row r to expanded state without forcing an update of the view */ - void set_row_expanded(RowData* r); + void set_row_expanded(DecodeTraceRow* r); /** * Sets row r to collapsed state without forcing an update of the view */ - void set_row_collapsed(RowData* r); + void set_row_collapsed(DecodeTraceRow* r); void update_expanded_rows(); @@ -250,7 +254,8 @@ private Q_SLOTS: void on_delete_decoder(int index); void on_show_hide_decoder(int index); - void on_show_hide_row(int index); + void on_show_hide_row(int row_id); + void on_show_hide_class(QWidget* sender); void on_copy_annotation_to_clipboard(); @@ -267,14 +272,14 @@ private: pv::Session &session_; shared_ptr decode_signal_; - deque rows_; + deque rows_; mutable mutex row_modification_mutex_; map channel_id_map_; // channel selector -> decode channel ID map init_state_map_; // init state selector -> decode channel ID list< shared_ptr > bindings_; - const data::decode::Row* selected_row_; + const Row* selected_row_; pair selected_sample_range_; vector decoder_forms_; @@ -286,7 +291,8 @@ private: int min_useful_label_width_; bool always_show_all_rows_; - QSignalMapper delete_mapper_, show_hide_mapper_, row_show_hide_mapper_; + QSignalMapper delete_mapper_, show_hide_mapper_; + QSignalMapper row_show_hide_mapper_, class_show_hide_mapper_; QTimer delayed_trace_updater_, animation_timer_;