]> sigrok.org Git - pulseview.git/blobdiff - pv/views/trace/view.cpp
Implement MathSignal
[pulseview.git] / pv / views / trace / view.cpp
index ee4a4042fdc072a5de65a089ad0b29c874745167..47cb96b2da3ce6c2125a39472928e8e1a63cb1b0 100644 (file)
 
 #include <libsigrokcxx/libsigrokcxx.hpp>
 
-#include "analogsignal.hpp"
-#include "header.hpp"
-#include "logicsignal.hpp"
-#include "ruler.hpp"
-#include "signal.hpp"
-#include "tracegroup.hpp"
-#include "triggermarker.hpp"
 #include "view.hpp"
-#include "viewport.hpp"
 
+#include "pv/globalsettings.hpp"
 #include "pv/metadata_obj.hpp"
+#include "pv/session.hpp"
+#include "pv/util.hpp"
 #include "pv/data/logic.hpp"
 #include "pv/data/logicsegment.hpp"
 #include "pv/data/signalbase.hpp"
 #include "pv/devices/device.hpp"
-#include "pv/globalsettings.hpp"
-#include "pv/session.hpp"
-#include "pv/util.hpp"
+#include "pv/views/trace/mathsignal.hpp"
+#include "pv/views/trace/analogsignal.hpp"
+#include "pv/views/trace/header.hpp"
+#include "pv/views/trace/logicsignal.hpp"
+#include "pv/views/trace/ruler.hpp"
+#include "pv/views/trace/signal.hpp"
+#include "pv/views/trace/tracegroup.hpp"
+#include "pv/views/trace/triggermarker.hpp"
+#include "pv/views/trace/viewport.hpp"
 
 #ifdef ENABLE_DECODE
-#include "decodetrace.hpp"
+#include "pv/views/trace/decodetrace.hpp"
 #endif
 
 using pv::data::SignalBase;
@@ -286,7 +287,7 @@ void View::reset_view_state()
        zero_offset_ = 0;
        custom_zero_offset_set_ = false;
        updating_scroll_ = false;
-       settings_restored_ = false;
+       restoring_state_ = false;
        always_zoom_to_fit_ = false;
        tick_period_ = 0;
        tick_prefix_ = pv::util::SIPrefix::yocto;
@@ -300,10 +301,8 @@ void View::reset_view_state()
        grabbed_widget_ = nullptr;
        hover_point_ = QPoint(-1, -1);
        scroll_needs_defaults_ = true;
-       saved_v_offset_ = 0;
        scale_at_acq_start_ = 0;
        offset_at_acq_start_ = 0;
-       suppress_zoom_to_fit_after_acq_ = false;
 
        show_cursors_ = false;
        cursor_state_changed(show_cursors_);
@@ -314,6 +313,8 @@ void View::reset_view_state()
 
        // Make sure the standard bar's segment selector is in sync
        set_segment_display_mode(segment_display_mode_);
+
+       scrollarea_->verticalScrollBar()->setRange(-100000000, 100000000);
 }
 
 Session& View::session()
@@ -365,6 +366,10 @@ void View::add_signalbase(const shared_ptr<data::SignalBase> signalbase)
                signal = shared_ptr<Signal>(new AnalogSignal(session_, signalbase));
                break;
 
+       case SignalBase::MathChannel:
+               signal = shared_ptr<Signal>(new MathSignal(session_, signalbase));
+               break;
+
        default:
                qDebug() << "Unknown signalbase type:" << signalbase->type();
                assert(false);
@@ -541,14 +546,12 @@ void View::restore_settings(QSettings &settings)
        }
 
        if (settings.contains("v_offset")) {
+               // Note: see eventFilter() for additional information
                saved_v_offset_ = settings.value("v_offset").toInt();
-               set_v_offset(saved_v_offset_);
                scroll_needs_defaults_ = false;
-               // Note: see eventFilter() for additional information
        }
 
-       settings_restored_ = true;
-       suppress_zoom_to_fit_after_acq_ = true;
+       restoring_state_ = true;
 
        // Update the ruler so that it uses the new scale
        calculate_tick_spacing();
@@ -580,6 +583,9 @@ void View::set_scale(double scale)
 {
        if (scale_ != scale) {
                scale_ = scale;
+
+               update_view_range_metaobject();
+
                scale_changed();
        }
 }
@@ -590,20 +596,7 @@ void View::set_offset(const pv::util::Timestamp& offset, bool force_update)
                offset_ = offset;
                ruler_offset_ = offset_ + zero_offset_;
 
-               const int w = viewport_->width();
-               if (w > 0) {
-                       const double samplerate = session_.get_samplerate();
-                       // Note: sample_num = time * samplerate
-                       // Note: samples_per_pixel = samplerate * scale
-                       int64_t start_sample = (offset_ * samplerate).convert_to<int64_t>();
-                       int64_t end_sample = (offset_ * samplerate).convert_to<int64_t>() +
-                               (w * session_.get_samplerate() * scale_);
-
-                       MetadataObject* md_obj =
-                               session_.metadata_obj_manager()->find_object_by_type(MetadataObjMainViewRange);
-                       md_obj->set_value(MetadataValueStartSample, QVariant((qlonglong)start_sample));
-                       md_obj->set_value(MetadataValueEndSample, QVariant((qlonglong)end_sample));
-               }
+               update_view_range_metaobject();
 
                offset_changed();
        }
@@ -789,7 +782,7 @@ void View::set_segment_display_mode(Trace::SegmentDisplayMode mode)
        for (const shared_ptr<Signal>& signal : signals_)
                signal->set_segment_display_mode(mode);
 
-       uint32_t last_segment = session_.get_segment_count() - 1;
+       uint32_t last_segment = session_.get_highest_segment_id();
 
        switch (mode) {
        case Trace::ShowLastSegmentOnly:
@@ -866,21 +859,31 @@ void View::zoom_fit(bool gui_state)
 void View::focus_on_range(uint64_t start_sample, uint64_t end_sample)
 {
        assert(viewport_);
-       const int w = viewport_->width();
+       const uint64_t w = viewport_->width();
        if (w <= 0)
                return;
 
        const double samplerate = session_.get_samplerate();
+       const double samples_per_pixel = samplerate * scale_;
+       const uint64_t viewport_samples = w * samples_per_pixel;
 
        const uint64_t sample_delta = (end_sample - start_sample);
 
        // Note: We add 20% margin on the left and 5% on the right
-       const Timestamp delta = (sample_delta * 1.25) / samplerate;
-
-       const Timestamp scale = max(min(delta / w, MaxScale), MinScale);
-       const Timestamp offset = (start_sample - sample_delta * 0.20) / samplerate;
-
-       set_scale_offset(scale.convert_to<double>(), offset);
+       const uint64_t ext_sample_delta = sample_delta * 1.25;
+
+       // Check if we can keep the zoom level and just center the supplied range
+       if (viewport_samples >= ext_sample_delta) {
+               // Note: offset is the left edge of the view so to center, we subtract half the view width
+               const int64_t sample_offset = (start_sample + (sample_delta / 2) - (viewport_samples / 2));
+               const Timestamp offset = sample_offset / samplerate;
+               set_scale_offset(scale_, offset);
+       } else {
+               const Timestamp offset = (start_sample - sample_delta * 0.20) / samplerate;
+               const Timestamp delta = ext_sample_delta / samplerate;
+               const Timestamp scale = max(min(delta / w, MaxScale), MinScale);
+               set_scale_offset(scale.convert_to<double>(), offset);
+       }
 }
 
 void View::set_scale_offset(double scale, const Timestamp& offset)
@@ -888,7 +891,7 @@ void View::set_scale_offset(double scale, const Timestamp& offset)
        // Disable sticky scrolling / always zoom to fit when acquisition runs
        // and user drags the viewport
        if ((scale_ == scale) && (offset_ != offset) &&
-                       (session_.get_capture_state() == Session::Running)) {
+               (session_.get_capture_state() == Session::Running)) {
 
                if (sticky_scrolling_) {
                        sticky_scrolling_ = false;
@@ -930,7 +933,9 @@ pair<Timestamp, Timestamp> View::get_time_extents() const
        if (signals_.size() == 0)
                return make_pair(0, 0);
 
-       data.push_back(signals_.front()->data());
+       for (shared_ptr<Signal> s : signals_)
+               if (s->data() && (s->data()->segments().size() > 0))
+                       data.push_back(s->data());
 
        for (const shared_ptr<SignalData>& d : data) {
                const vector< shared_ptr<Segment> > segments = d->segments();
@@ -1427,6 +1432,8 @@ void View::resize_header_to_fit()
 void View::update_layout()
 {
        update_scroll();
+
+       update_view_range_metaobject();
 }
 
 TraceTreeItemOwner* View::find_prevalent_trace_group(
@@ -1565,7 +1572,7 @@ bool View::eventFilter(QObject *object, QEvent *event)
                // resized to their final sizes.
                update_layout();
 
-               if (settings_restored_)
+               if (restoring_state_)
                        determine_if_header_was_shrunk();
                else
                        resize_header_to_fit();
@@ -1575,10 +1582,8 @@ bool View::eventFilter(QObject *object, QEvent *event)
                        scroll_needs_defaults_ = false;
                }
 
-               if (saved_v_offset_) {
+               if (restoring_state_)
                        set_v_offset(saved_v_offset_);
-                       saved_v_offset_ = 0;
-               }
        }
 
        return QObject::eventFilter(object, event);
@@ -1606,6 +1611,31 @@ void View::resizeEvent(QResizeEvent* event)
        update_layout();
 }
 
+void View::update_view_range_metaobject() const
+{
+       const int w = viewport_->width();
+       if (w > 0) {
+               const double samplerate = session_.get_samplerate();
+               // Note: sample_num = time * samplerate
+               // Note: samples_per_pixel = samplerate * scale
+               const int64_t start_sample = (offset_ * samplerate).convert_to<int64_t>();
+               const int64_t end_sample = (offset_ * samplerate).convert_to<int64_t>() +
+                       (w * session_.get_samplerate() * scale_);
+
+               MetadataObject* md_obj =
+                       session_.metadata_obj_manager()->find_object_by_type(MetadataObjMainViewRange);
+
+               const int64_t old_start_sample = md_obj->value(MetadataValueStartSample).toLongLong();
+               const int64_t old_end_sample = md_obj->value(MetadataValueEndSample).toLongLong();
+
+               if (start_sample != old_start_sample)
+                       md_obj->set_value(MetadataValueStartSample, QVariant((qlonglong)start_sample));
+
+               if (end_sample != old_end_sample)
+                       md_obj->set_value(MetadataValueEndSample, QVariant((qlonglong)end_sample));
+       }
+}
+
 void View::update_hover_point()
 {
        // Determine signal that the mouse cursor is hovering over
@@ -1963,13 +1993,14 @@ void View::capture_state_updated(int state)
                // the main view of this session (other trace views may be used for
                // zooming and we don't want to mess them up)
                bool state = settings.value(GlobalSettings::Key_View_ZoomToFitDuringAcq).toBool();
-               if (is_main_view_ && state) {
+               if (is_main_view_ && state && !restoring_state_) {
                        always_zoom_to_fit_ = true;
                        always_zoom_to_fit_changed(always_zoom_to_fit_);
                }
 
                // Enable sticky scrolling if the setting is enabled
-               sticky_scrolling_ = settings.value(GlobalSettings::Key_View_StickyScrolling).toBool();
+               sticky_scrolling_ = !restoring_state_ &&
+                       settings.value(GlobalSettings::Key_View_StickyScrolling).toBool();
 
                // Reset all traces to segment 0
                current_segment_ = 0;
@@ -1995,12 +2026,13 @@ void View::capture_state_updated(int state)
                // Only perform zoom-to-fit if the user hasn't altered the viewport and
                // we didn't restore settings in the meanwhile
                if (zoom_to_fit_after_acq &&
-                       !suppress_zoom_to_fit_after_acq_ &&
+                       !restoring_state_ &&
                        (scale_ == scale_at_acq_start_) &&
-                       (offset_ == offset_at_acq_start_))
+                       (sticky_scrolling_ || (offset_ == offset_at_acq_start_))) {
                        zoom_fit(false);  // We're stopped, so the GUI state doesn't matter
+               }
 
-               suppress_zoom_to_fit_after_acq_ = false;
+               restoring_state_ = false;
        }
 }