Implement hidable rows
authorSoeren Apel <soeren@apelpie.net>
Tue, 24 Dec 2019 14:27:17 +0000 (15:27 +0100)
committerSoeren Apel <soeren@apelpie.net>
Wed, 1 Jan 2020 12:15:21 +0000 (13:15 +0100)
pv/data/decode/row.cpp
pv/data/decode/row.hpp
pv/globalsettings.cpp
pv/globalsettings.hpp
pv/views/trace/decodetrace.cpp
pv/views/trace/decodetrace.hpp
pv/views/trace/view.cpp
pv/views/trace/view.hpp

index 12951556390c15f2a0ed5e2e647365cb567fb675..31e4cc8e9add3233cb3f3296554d1d224da5b770 100644 (file)
@@ -35,7 +35,8 @@ Row::Row() :
 Row::Row(int index, const Decoder* decoder, const srd_decoder_annotation_row* row) :
        index_(index),
        decoder_(decoder),
-       row_(row)
+       row_(row),
+       visible_(true)
 {
 }
 
@@ -74,6 +75,16 @@ int Row::index() const
        return index_;
 }
 
+bool Row::visible() const
+{
+       return visible_;
+}
+
+void Row::set_visible(bool visible)
+{
+       visible_ = visible;
+}
+
 bool Row::operator<(const Row& other) const
 {
        return (decoder_ < other.decoder_) ||
index 25e6fcc492863f90ac97b2ae23a9a73d3b51a39c..9d7992e8ceb0f71b2dd6c80c99a63149079007cd 100644 (file)
@@ -48,6 +48,9 @@ public:
        const QString class_name() const;
        int index() const;
 
+       bool visible() const;
+       void set_visible(bool visible);
+
        bool operator<(const Row& other) const;
        bool operator==(const Row& other) const;
 
@@ -55,6 +58,7 @@ private:
        int index_;
        const Decoder* decoder_;
        const srd_decoder_annotation_row* row_;
+       bool visible_;
 };
 
 }  // namespace decode
index b648d5da4e6d1fe388eb69052272dd3044edd0ae..4b7936565625157ac4cfb420efe85c856bba46e8 100644 (file)
@@ -68,13 +68,13 @@ const QString GlobalSettings::Key_Log_NotifyOfStacktrace = "Log_NotifyOfStacktra
 
 vector<GlobalSettingsInterface*> GlobalSettings::callbacks_;
 bool GlobalSettings::tracking_ = false;
+bool GlobalSettings::is_dark_theme_ = false;
 map<QString, QVariant> GlobalSettings::tracked_changes_;
 QString GlobalSettings::default_style_;
 QPalette GlobalSettings::default_palette_;
 
 GlobalSettings::GlobalSettings() :
-       QSettings(),
-       is_dark_theme_(false)
+       QSettings()
 {
        beginGroup("Settings");
 }
index bc2a4acd795c8d2bab594eccfd84474e006ce609..6902a097406edb187c53c5effc7c550aa26e4165 100644 (file)
@@ -89,7 +89,7 @@ public:
        void set_bright_theme_default_colors();
        void set_dark_theme_default_colors();
 
-       bool current_theme_is_dark();
+       static bool current_theme_is_dark();
        void apply_theme();
 
        static void add_change_handler(GlobalSettingsInterface *cb);
@@ -132,7 +132,7 @@ private:
        static QString default_style_;
        static QPalette default_palette_;
 
-       bool is_dark_theme_;
+       static bool is_dark_theme_;
 };
 
 } // namespace pv
index 3555d57635ec28588abbaa6d5a83781320baffcf..8cddcd4510f7f38f6e887ec94b463326385a1d34 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #include <QAction>
 #include <QApplication>
 #include <QClipboard>
+#include <QCheckBox>
 #include <QComboBox>
 #include <QFileDialog>
 #include <QFormLayout>
@@ -85,6 +86,8 @@ namespace trace {
 
 const QColor DecodeTrace::ErrorBgColor = QColor(0xEF, 0x29, 0x29);
 const QColor DecodeTrace::NoDecodeColor = QColor(0x88, 0x8A, 0x85);
+const uint8_t DecodeTrace::ExpansionAreaHeaderAlpha = 10 * 255 / 100;
+const uint8_t DecodeTrace::ExpansionAreaAlpha = 5 * 255 / 100;
 
 const int DecodeTrace::ArrowSize = 6;
 const double DecodeTrace::EndCapWidth = 5;
@@ -100,7 +103,8 @@ DecodeTrace::DecodeTrace(pv::Session &session,
        session_(session),
        max_visible_rows_(0),
        delete_mapper_(this),
-       show_hide_mapper_(this)
+       show_hide_mapper_(this),
+       row_show_hide_mapper_(this)
 {
        decode_signal_ = dynamic_pointer_cast<data::DecodeSignal>(base_);
 
@@ -140,6 +144,8 @@ DecodeTrace::DecodeTrace(pv::Session &session,
                this, SLOT(on_delete_decoder(int)));
        connect(&show_hide_mapper_, SIGNAL(mapped(int)),
                this, SLOT(on_show_hide_decoder(int)));
+       connect(&row_show_hide_mapper_, SIGNAL(mapped(int)),
+               this, SLOT(on_show_hide_row(int)));
 
        connect(&delayed_trace_updater_, SIGNAL(timeout()),
                this, SLOT(on_delayed_trace_update()));
@@ -159,8 +165,14 @@ DecodeTrace::~DecodeTrace()
 {
        GlobalSettings::remove_change_handler(this);
 
-       for (RowData& r : rows_)
+       for (RowData& r : rows_) {
+               for (QCheckBox* cb : r.selectors)
+                       delete cb;
+
+               delete r.selector_container;
+               delete r.header_container;
                delete r.container;
+       }
 }
 
 bool DecodeTrace::enabled() const
@@ -214,8 +226,8 @@ void DecodeTrace::paint_mid(QPainter &p, ViewItemPaintParams &pp)
        int y = get_visual_y();
 
        for (RowData& r : rows_) {
-               // If an entire decoder is hidden, we don't want to fetch annotations
-               if (!r.decode_row.decoder()->shown()) {
+               // If the row is hidden, we don't want to fetch annotations
+               if ((!r.decode_row.decoder()->shown()) || (!r.decode_row.visible())) {
                        r.currently_visible = false;
                        continue;
                }
@@ -570,14 +582,14 @@ void DecodeTrace::mouse_left_press_event(const QMouseEvent* event)
                                r.expanding = true;
                                r.anim_shape = 0;
                                r.container->setVisible(true);
+                               QApplication::processEvents();
+                               r.expanded_height = 5 * default_row_height_ + r.container->size().height();
                        }
 
                        r.animation_step = 0;
                        r.anim_height = r.height;
 
-                       r.container->move(2 * ArrowSize,
-                               get_row_y(&r) + default_row_height_);
-
+                       update_expanded_rows();
                        animation_timer_.start();
                }
        }
@@ -1175,9 +1187,25 @@ void DecodeTrace::update_rows()
 
        QFontMetrics m(QApplication::font());
 
+       QPalette header_palette = owner_->view()->palette();
+       QPalette selector_palette = owner_->view()->palette();
+
+       if (GlobalSettings::current_theme_is_dark()) {
+               header_palette.setColor(QPalette::Background,
+                       QColor(255, 255, 255, ExpansionAreaHeaderAlpha));
+               selector_palette.setColor(QPalette::Background,
+                       QColor(255, 255, 255, ExpansionAreaAlpha));
+       } else {
+               header_palette.setColor(QPalette::Background,
+                       QColor(0, 0, 0, ExpansionAreaHeaderAlpha));
+               selector_palette.setColor(QPalette::Background,
+                       QColor(0, 0, 0, ExpansionAreaAlpha));
+       }
+
        for (RowData& r : rows_)
                r.exists = false;
 
+       unsigned int row_id = 0;
        for (const Row& decode_row : decode_signal_->get_rows()) {
                // Find row in our list
                auto r_it = find_if(rows_.begin(), rows_.end(),
@@ -1189,14 +1217,16 @@ void DecodeTrace::update_rows()
                        RowData nr;
                        nr.decode_row = decode_row;
                        nr.height = default_row_height_;
-                       nr.expanded_height = 5*default_row_height_;
+                       nr.expanded_height = default_row_height_;
                        nr.currently_visible = false;
                        nr.expand_marker_highlighted = false;
                        nr.expanding = false;
                        nr.expanded = false;
                        nr.collapsing = false;
                        nr.expand_marker_shape = default_marker_shape_;
-                       nr.container = new QWidget(owner_->view()->viewport());
+                       nr.container = new QWidget(owner_->view()->scrollarea());
+                       nr.header_container = new QWidget(nr.container);
+                       nr.selector_container = new QWidget(nr.container);
 
                        rows_.push_back(nr);
                        r = &rows_.back();
@@ -1211,6 +1241,44 @@ void DecodeTrace::update_rows()
                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++;
        }
 
        // Remove any rows that no longer exist, obeying that iterators are invalidated
@@ -1220,7 +1288,13 @@ void DecodeTrace::update_rows()
 
                for (unsigned int i = 0; i < rows_.size(); i++)
                        if (!rows_[i].exists) {
+                               for (QCheckBox* cb : rows_[i].selectors)
+                                       delete cb;
+
+                               delete rows_[i].selector_container;
+                               delete rows_[i].header_container;
                                delete rows_[i].container;
+
                                rows_.erase(rows_.begin() + i);
                                any_exists = true;
                                break;
@@ -1228,6 +1302,42 @@ void DecodeTrace::update_rows()
        } while (any_exists);
 }
 
+void DecodeTrace::set_row_expanded(RowData* r)
+{
+       r->height = r->expanded_height;
+       r->expanding = false;
+       r->expanded = true;
+
+       // For details on this, see on_animation_timer()
+       r->expand_marker_shape.setPoint(0, 0, 0);
+       r->expand_marker_shape.setPoint(1, ArrowSize, ArrowSize);
+       r->expand_marker_shape.setPoint(2, 2*ArrowSize, 0);
+
+       r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(),
+               r->height - 2 * default_row_height_);
+}
+
+void DecodeTrace::set_row_collapsed(RowData* r)
+{
+       r->height = default_row_height_;
+       r->collapsing = false;
+       r->expanded = false;
+       r->expand_marker_shape = default_marker_shape_;
+       r->container->setVisible(false);
+
+       r->container->resize(owner_->view()->viewport()->width() - r->container->pos().x(),
+               r->height - 2 * default_row_height_);
+}
+
+void DecodeTrace::update_expanded_rows()
+{
+       for (RowData& r : rows_) {
+
+               r.container->move(2 * ArrowSize,
+                       get_row_y(&r) + default_row_height_);
+       }
+}
+
 void DecodeTrace::on_setting_changed(const QString &key, const QVariant &value)
 {
        Trace::on_setting_changed(key, value);
@@ -1344,8 +1454,21 @@ void DecodeTrace::on_show_hide_decoder(int index)
                owner_->extents_changed(false, true);
        }
 
-       if (owner_)
-               owner_->row_item_appearance_changed(false, true);
+       owner_->row_item_appearance_changed(false, true);
+}
+
+void DecodeTrace::on_show_hide_row(int index)
+{
+       if (index >= (int)rows_.size())
+               return;
+
+       set_row_collapsed(&rows_[index]);
+       rows_[index].decode_row.set_visible(!rows_[index].decode_row.visible());
+
+       // Force re-calculation of the trace height, see paint_mid()
+       max_visible_rows_ = 0;
+       owner_->extents_changed(false, true);
+       owner_->row_item_appearance_changed(false, true);
 }
 
 void DecodeTrace::on_copy_annotation_to_clipboard()
@@ -1486,11 +1609,8 @@ void DecodeTrace::on_animation_timer()
                                r.height = r.anim_height;
                                r.anim_shape += ArrowSize / (float)AnimationDurationInTicks;
                                animation_finished = false;
-                       } else {
-                               r.height = std::min(r.height, r.expanded_height);
-                               r.expanding = false;
-                               r.expanded = true;
-                       }
+                       } else
+                               set_row_expanded(&r);
                }
 
                if (r.collapsing) {
@@ -1499,13 +1619,8 @@ void DecodeTrace::on_animation_timer()
                                r.height = r.anim_height;
                                r.anim_shape -= ArrowSize / (float)AnimationDurationInTicks;
                                animation_finished = false;
-                       } else {
-                               r.height = std::max(r.height, default_row_height_);
-                               r.collapsing = false;
-                               r.expanded = false;
-                               r.expand_marker_shape = default_marker_shape_;
-                               r.container->setVisible(false);
-                       }
+                       } else
+                               set_row_collapsed(&r);
                }
 
                // The expansion marker shape switches between
@@ -1515,16 +1630,13 @@ void DecodeTrace::on_animation_timer()
                r.expand_marker_shape.setPoint(0, 0, -ArrowSize + r.anim_shape);
                r.expand_marker_shape.setPoint(1, ArrowSize, r.anim_shape);
                r.expand_marker_shape.setPoint(2, 2*r.anim_shape, ArrowSize - r.anim_shape);
-
-               r.container->resize(owner_->view()->viewport()->width() - r.container->pos().x(),
-                       r.height - 2 * default_row_height_);
        }
 
        if (animation_finished)
                animation_timer_.stop();
 
-       if (owner_)
-               owner_->row_item_appearance_changed(false, true);
+       owner_->extents_changed(false, true);
+       owner_->row_item_appearance_changed(false, true);
 }
 
 } // namespace trace
index 662562c371984ade791a71aecbf6dfc8b46b6e72..42ceb2a5e906404ee9e259d12f2571525fc0db0a 100644 (file)
@@ -28,7 +28,7 @@
 #include <vector>
 
 #include <QColor>
-#include <QComboBox>
+#include <QCheckBox>
 #include <QPolygon>
 #include <QPushButton>
 #include <QSignalMapper>
@@ -83,6 +83,9 @@ struct RowData {
        float anim_height, anim_shape;
 
        QWidget* container;
+       QWidget* header_container;
+       QWidget* selector_container;
+       vector<QCheckBox*> selectors;
 };
 
 class DecodeTrace : public Trace
@@ -92,6 +95,8 @@ class DecodeTrace : public Trace
 private:
        static const QColor ErrorBgColor;
        static const QColor NoDecodeColor;
+       static const uint8_t ExpansionAreaHeaderAlpha;
+       static const uint8_t ExpansionAreaAlpha;
 
        static const int ArrowSize;
        static const double EndCapWidth;
@@ -211,6 +216,18 @@ private:
 
        void update_rows();
 
+       /**
+        * Sets row r to expanded state without forcing an update of the view
+        */
+       void set_row_expanded(RowData* r);
+
+       /**
+        * Sets row r to collapsed state without forcing an update of the view
+        */
+       void set_row_collapsed(RowData* r);
+
+       void update_expanded_rows();
+
 private Q_SLOTS:
        void on_setting_changed(const QString &key, const QVariant &value);
 
@@ -233,6 +250,7 @@ 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_copy_annotation_to_clipboard();
 
@@ -268,7 +286,7 @@ private:
        int min_useful_label_width_;
        bool always_show_all_rows_;
 
-       QSignalMapper delete_mapper_, show_hide_mapper_;
+       QSignalMapper delete_mapper_, show_hide_mapper_, row_show_hide_mapper_;
 
        QTimer delayed_trace_updater_, animation_timer_;
 
index e72770f07eabe7481f2f48b95a1cf0f86a15816d..ea1c290c8dccf95774d3e9805b77b4c7b8e656bb 100644 (file)
@@ -394,6 +394,11 @@ const Viewport* View::viewport() const
        return viewport_;
 }
 
+QAbstractScrollArea* View::scrollarea() const
+{
+       return scrollarea_;
+}
+
 const Ruler* View::ruler() const
 {
        return ruler_;
index 7fe2bf720181a04b3523efbed7f6e93b78c116a2..d79db4d487a6228ba2e24fb8ba502914154f932f 100644 (file)
@@ -149,6 +149,8 @@ public:
        Viewport* viewport();
        const Viewport* viewport() const;
 
+       QAbstractScrollArea* scrollarea() const;
+
        const Ruler* ruler() const;
 
        virtual void save_settings(QSettings &settings) const;