AnalogSignal/LogicSignal: Internally cache settings used for painting
[pulseview.git] / pv / views / trace / logicsignal.cpp
index 6a9bf432a07157c2a2e7713e60dbd7972c8abd8f..f9ab16f102cdf5328613d81957a5d4563602d07e 100644 (file)
@@ -117,8 +117,14 @@ LogicSignal::LogicSignal(
 
        base_->set_color(SignalColors[base->index() % countof(SignalColors)]);
 
-       GlobalSettings gs;
-       signal_height_ = gs.value(GlobalSettings::Key_View_DefaultLogicHeight).toInt();
+       GlobalSettings settings;
+       signal_height_ = settings.value(GlobalSettings::Key_View_DefaultLogicHeight).toInt();
+       show_sampling_points_ =
+               settings.value(GlobalSettings::Key_View_ShowSamplingPoints).toBool();
+       fill_high_areas_ =
+               settings.value(GlobalSettings::Key_View_FillSignalHighAreas).toBool();
+       high_fill_color_ = QColor::fromRgba(settings.value(
+               GlobalSettings::Key_View_FillSignalHighAreaColor).value<uint32_t>());
 
        /* Populate this channel's trigger setting with whatever we
         * find in the current session trigger, if anything. */
@@ -180,8 +186,8 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp)
        if (!base_->enabled())
                return;
 
-       const float high_offset = y - signal_height_ + 0.5f;
        const float low_offset = y + 0.5f;
+       const float high_offset = low_offset - signal_height_;
 
        shared_ptr<LogicSegment> segment = get_logic_segment_to_paint();
        if (!segment || (segment->get_sample_count() == 0))
@@ -210,32 +216,62 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp)
                samples_per_pixel / Oversampling, base_->index());
        assert(edges.size() >= 2);
 
-       // Check whether we need to paint the sampling points
-       GlobalSettings settings;
-       const bool show_sampling_points =
-               settings.value(GlobalSettings::Key_View_ShowSamplingPoints).toBool() &&
-               (samples_per_pixel < 0.25);
+       const float first_sample_x =
+               pp.left() + (edges.front().first / samples_per_pixel - pixels_offset);
+       const float last_sample_x =
+               pp.left() + (edges.back().first / samples_per_pixel - pixels_offset);
 
+       // Check whether we need to paint the sampling points
+       const bool show_sampling_points = show_sampling_points_ && (samples_per_pixel < 0.25);
        vector<QRectF> sampling_points;
-       float sampling_point_x = 0.0f;
+       float sampling_point_x = first_sample_x;
        int64_t sampling_point_sample = start_sample;
        const int w = 2;
 
-       if (show_sampling_points) {
+       if (show_sampling_points)
                sampling_points.reserve(end_sample - start_sample + 1);
-               sampling_point_x = (edges.cbegin()->first / samples_per_pixel - pixels_offset) + pp.left();
-       }
+
+       vector<QRectF> high_rects;
+       float rising_edge_x;
+       bool rising_edge_seen = false;
 
        // Paint the edges
        const unsigned int edge_count = edges.size() - 2;
        QLineF *const edge_lines = new QLineF[edge_count];
        line = edge_lines;
 
+       if (edges.front().second) {
+               // Beginning of trace is high
+               rising_edge_x = first_sample_x;
+               rising_edge_seen = true;
+       }
+
        for (auto i = edges.cbegin() + 1; i != edges.cend() - 1; i++) {
-               const float x = ((*i).first / samples_per_pixel -
-                       pixels_offset) + pp.left();
+               // Note: multiple edges occupying a single pixel are represented by an edge
+               // with undefined logic level. This means that only the first falling edge
+               // after a rising edge corresponds to said rising edge - and vice versa. If
+               // more edges with the same logic level follow, they denote multiple edges.
+
+               const float x = pp.left() + ((*i).first / samples_per_pixel - pixels_offset);
                *line++ = QLineF(x, high_offset, x, low_offset);
 
+               if (fill_high_areas_) {
+                       // Any edge terminates a high area
+                       if (rising_edge_seen) {
+                               const int width = x - rising_edge_x;
+                               if (width > 0)
+                                       high_rects.emplace_back(rising_edge_x, high_offset,
+                                               width, signal_height_);
+                               rising_edge_seen = false;
+                       }
+
+                       // Only rising edges start high areas
+                       if ((*i).second) {
+                               rising_edge_x = x;
+                               rising_edge_seen = true;
+                       }
+               }
+
                if (show_sampling_points)
                        while (sampling_point_sample < (*i).first) {
                                const float y = (*i).second ? low_offset : high_offset;
@@ -257,6 +293,17 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp)
                        sampling_point_x += pixels_per_sample;
                };
 
+       if (fill_high_areas_) {
+               // Add last high rectangle if the signal is still high at the end of the trace
+               if (rising_edge_seen && (edges.cend() - 1)->second)
+                       high_rects.emplace_back(rising_edge_x, high_offset,
+                               last_sample_x - rising_edge_x, signal_height_);
+
+               p.setPen(high_fill_color_);
+               p.setBrush(high_fill_color_);
+               p.drawRects((const QRectF*)(high_rects.data()), high_rects.size());
+       }
+
        p.setPen(EdgeColor);
        p.drawLines(edge_lines, edge_count);
        delete[] edge_lines;
@@ -533,7 +580,7 @@ void LogicSignal::populate_popup_form(QWidget *parent, QFormLayout *form)
 
                // Only allow triggers to be changed when we're stopped
                if (session_.get_capture_state() != Session::Stopped)
-                       for (QAction* action : trigger_bar_->findChildren<QAction*>())
+                       for (QAction* action : trigger_bar_->findChildren<QAction*>())  // clazy:exclude=range-loop
                                action->setEnabled(false);
 
                form->addRow(tr("Trigger"), trigger_bar_);
@@ -600,6 +647,20 @@ const QPixmap* LogicSignal::get_pixmap(const char *path)
        return pixmap_cache_.take(path);
 }
 
+void LogicSignal::on_setting_changed(const QString &key, const QVariant &value)
+{
+       Signal::on_setting_changed(key, value);
+
+       if (key == GlobalSettings::Key_View_ShowSamplingPoints)
+               show_sampling_points_ = value.toBool();
+
+       if (key == GlobalSettings::Key_View_FillSignalHighAreas)
+               fill_high_areas_ = value.toBool();
+
+       if (key == GlobalSettings::Key_View_FillSignalHighAreaColor)
+               high_fill_color_ = QColor::fromRgba(value.value<uint32_t>());
+}
+
 void LogicSignal::on_trigger()
 {
        QAction *action;