]> sigrok.org Git - pulseview.git/blobdiff - pv/views/trace/logicsignal.cpp
Fix for "fill logic signal high areas" feature
[pulseview.git] / pv / views / trace / logicsignal.cpp
index 438e4e21c1f6a6c639543897cb65f35362e9a746..a5d0a5987774436e178b0e3f250ce46633538d7d 100644 (file)
@@ -57,6 +57,8 @@ using sigrok::Trigger;
 using sigrok::TriggerMatch;
 using sigrok::TriggerMatchType;
 
+using pv::data::LogicSegment;
+
 namespace pv {
 namespace views {
 namespace trace {
@@ -178,10 +180,10 @@ 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<pv::data::LogicSegment> segment = get_logic_segment_to_paint();
+       shared_ptr<LogicSegment> segment = get_logic_segment_to_paint();
        if (!segment || (segment->get_sample_count() == 0))
                return;
 
@@ -208,6 +210,11 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp)
                samples_per_pixel / Oversampling, base_->index());
        assert(edges.size() >= 2);
 
+       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
        GlobalSettings settings;
        const bool show_sampling_points =
@@ -215,25 +222,57 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp)
                (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();
-       }
+
+       // Check whether we need to fill the high areas
+       const bool fill_high_areas =
+               settings.value(GlobalSettings::Key_View_FillSignalHighAreas).toBool();
+       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;
@@ -255,6 +294,19 @@ 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_);
+
+               const QColor fill_color = QColor::fromRgba(settings.value(
+                       GlobalSettings::Key_View_FillSignalHighAreaColor).value<uint32_t>());
+               p.setPen(fill_color);
+               p.setBrush(fill_color);
+               p.drawRects((const QRectF*)(high_rects.data()), high_rects.size());
+       }
+
        p.setPen(EdgeColor);
        p.drawLines(edge_lines, edge_count);
        delete[] edge_lines;
@@ -320,49 +372,31 @@ void LogicSignal::paint_fore(QPainter &p, ViewItemPaintParams &pp)
        }
 }
 
-void LogicSignal::hover_point_changed(const QPoint &hp)
+vector<LogicSegment::EdgePair> LogicSignal::get_nearest_level_changes(uint64_t sample_pos)
 {
-       Signal::hover_point_changed(hp);
-
        assert(base_);
        assert(owner_);
 
-       if ((!base_->enabled()) || (hp.x() == 0))
-               return;
-
-       // Ignore if mouse cursor is not hovering over this trace
-       const int y = get_visual_y();
-       const pair<int, int> extents = v_extents();
-       if ((hp.y() < (y + extents.first)) || ((hp.y() > (y + extents.second))))
-               return;
+       if (sample_pos == 0)
+               return vector<LogicSegment::EdgePair>();
 
-       shared_ptr<pv::data::LogicSegment> segment = get_logic_segment_to_paint();
+       shared_ptr<LogicSegment> segment = get_logic_segment_to_paint();
        if (!segment || (segment->get_sample_count() == 0))
-               return;
-
-       double samplerate = segment->samplerate();
-
-       // Show sample rate as 1Hz when it is unknown
-       if (samplerate == 0.0)
-               samplerate = 1.0;
+               return vector<LogicSegment::EdgePair>();
 
        const View *view = owner_->view();
        assert(view);
-       const double scale = view->scale();
-       const double pixels_offset =
-               ((view->offset() - segment->start_time()) / scale).convert_to<double>();
-       const double samples_per_pixel = samplerate * scale;
+       const double samples_per_pixel = base_->get_samplerate() * view->scale();
 
-       const uint64_t sample_pos = (uint64_t)max(
-               (hp.x() + pixels_offset) * samples_per_pixel, 0.0);
-
-       vector<data::LogicSegment::EdgePair> edges;
+       vector<LogicSegment::EdgePair> edges;
 
        segment->get_surrounding_edges(edges, sample_pos,
                samples_per_pixel / Oversampling, base_->index());
 
        if (edges.empty())
-               return;
+               return vector<LogicSegment::EdgePair>();
+
+       return edges;
 }
 
 void LogicSignal::paint_caps(QPainter &p, QLineF *const lines,