Add row colors and some fixes
authorSoeren Apel <soeren@apelpie.net>
Sun, 19 Apr 2020 13:44:58 +0000 (15:44 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Sun, 3 May 2020 15:20:55 +0000 (17:20 +0200)
pv/data/decode/annotation.cpp
pv/data/decode/annotation.hpp
pv/data/decode/rowdata.cpp
pv/data/decode/rowdata.hpp
pv/data/decodesignal.cpp
pv/views/tabular_decoder/model.cpp
pv/views/tabular_decoder/view.cpp
pv/views/tabular_decoder/view.hpp
pv/views/trace/decodetrace.cpp

index 829bdbaf9a700b645f9fb55d6b7bdf0a725855ca..fe0350d03b1643a4aedba1623a27ba23981c83b0 100644 (file)
@@ -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<QString>* Annotation::annotations() const
 {
        return texts_;
index cf20a48b20ae132032f14acddf7e68a957c0698a..fa5149086c230fcfb790f07d2a3c38cc229ecd0c 100644 (file)
@@ -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<QString>* annotations() const;
        const QString longest_annotation() const;
index fc635b2452db765e7bd8896b6d6e6c474abc36da..0434e1c0d8aad7a2d93e2ecf26555377ff6fb62f 100644 (file)
@@ -95,13 +95,21 @@ void RowData::get_annotation_subset(
        }
 }
 
+const deque<Annotation>& 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<QString>* storage_entry = &(ann_texts_[ann0]);
index f01aa3ca81c2f71a24c61dc71f7b1d1ba67f7139..ff59d31a0f18d4767f5a3fb946b0a3e839777721 100644 (file)
@@ -66,6 +66,8 @@ public:
        void get_annotation_subset(deque<const pv::data::decode::Annotation*> &dest,
                uint64_t start_sample, uint64_t end_sample) const;
 
+       const deque<Annotation>& annotations() const;
+
        const Annotation* emplace_annotation(srd_proto_data *pdata);
 
 private:
index 6f0e0fa7c50594632bf3305d3a01a56179f21f43..77784de07f84dcdce9431ef03fc634de56aed02e 100644 (file)
@@ -1460,6 +1460,29 @@ void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signa
        deque<const Annotation*>& 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)
index e54fda8c82f096617e681ab4ecddea904fa34ae1..66fabf5ac1534817781ebe07a453bbdbc2bedaad 100644 (file)
@@ -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<const Annotation*>(index.internalPointer());
+       const Annotation* ann =
+               static_cast<const Annotation*>(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
index 4f4c6238b02927e6d699417b4ea6184a3b196d1a..1f79be033bf1432ca472f63b0cbe19d1ceb67bc8 100644 (file)
@@ -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<data::DecodeSignal> 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<Decoder>& 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<Decoder>& 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)
index 8e1dfa4179432ce96891e4ccce2e929ceaa89178..a6bd9ea3c613d353b33afd1a93061a2008fbd57d 100644 (file)
@@ -25,6 +25,7 @@
 #include <QTableView>
 #include <QToolButton>
 
+#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<QVariant> header_data_;
        const deque<const Annotation*>* 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();
index f175bd49046617a0a35d5a65f6533d4226525eec..53998b2ea7a0dc30f0728fdc9d895dd557425127 100644 (file)
@@ -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()