]> sigrok.org Git - pulseview.git/blobdiff - pv/views/trace/view.cpp
Session: Fix issue #67 by improving error handling
[pulseview.git] / pv / views / trace / view.cpp
index 43853359540baf83859d3abd69fffde9254e9b22..33d8b0a44aa7ed9530adb4b4349439d8f9cc1c49 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;
@@ -91,7 +92,7 @@ namespace views {
 namespace trace {
 
 const Timestamp View::MaxScale("1e9");
-const Timestamp View::MinScale("1e-12");
+const Timestamp View::MinScale("1e-14");
 
 const int View::MaxScrollValue = INT_MAX / 2;
 
@@ -358,13 +359,17 @@ void View::add_signalbase(const shared_ptr<data::SignalBase> signalbase)
 
        switch (signalbase->type()) {
        case SignalBase::LogicChannel:
-               signal = shared_ptr<Signal>(new LogicSignal(session_, session_.device(), signalbase));
+               signal = shared_ptr<Signal>(new LogicSignal(session_, signalbase));
                break;
 
        case SignalBase::AnalogChannel:
                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);
@@ -777,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:
@@ -854,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)
@@ -905,7 +920,7 @@ vector< shared_ptr<SignalData> > View::get_visible_data() const
        vector< shared_ptr<SignalData> > visible_data;
        for (const shared_ptr<Signal>& sig : signals_)
                if (sig->enabled())
-                       visible_data.push_back(sig->data());
+                       visible_data.push_back(sig->base()->data());
 
        return visible_data;
 }
@@ -918,9 +933,9 @@ pair<Timestamp, Timestamp> View::get_time_extents() const
        if (signals_.size() == 0)
                return make_pair(0, 0);
 
-       for (shared_ptr<Signal> s : signals_)
-               if (s->data()->segments().size() > 0)
-                       data.push_back(s->data());
+       for (const shared_ptr<Signal>& s : signals_)
+               if (s->base()->data() && (s->base()->data()->segments().size() > 0))
+                       data.push_back(s->base()->data());
 
        for (const shared_ptr<SignalData>& d : data) {
                const vector< shared_ptr<Segment> > segments = d->segments();
@@ -1487,7 +1502,7 @@ void View::determine_time_unit()
        if (time_unit_ == util::TimeUnit::Samples) {
                // Check all signals but...
                for (const shared_ptr<Signal>& signal : signals_) {
-                       const shared_ptr<SignalData> data = signal->data();
+                       const shared_ptr<SignalData> data = signal->base()->data();
 
                        // ...only check first segment of each
                        const vector< shared_ptr<Segment> > segments = data->segments();
@@ -1515,7 +1530,11 @@ bool View::eventFilter(QObject *object, QEvent *event)
                else if (object == ruler_)
                        hover_point_ = mouse_event->pos();
                else if (object == header_)
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+                       hover_point_ = QPoint(0, mouse_event->pos().y());
+#else
                        hover_point_ = QPoint(0, mouse_event->y());
+#endif
                else
                        hover_point_ = QPoint(-1, -1);
 
@@ -1579,10 +1598,22 @@ void View::contextMenuEvent(QContextMenuEvent *event)
        QPoint pos = event->pos() - QPoint(0, ruler_->sizeHint().height());
 
        const shared_ptr<ViewItem> r = viewport_->get_mouse_over_item(pos);
-       if (!r)
-               return;
 
-       QMenu *menu = r->create_view_context_menu(this, pos);
+       QMenu* menu = nullptr;
+
+       if (!r) {
+               context_menu_x_pos_ = pos.x();
+
+               // No view item under cursor, use generic menu
+               menu = new QMenu(this);
+
+               QAction *const create_marker_here = new QAction(tr("Create marker here"), this);
+               connect(create_marker_here, SIGNAL(triggered()), this, SLOT(on_create_marker_here()));
+               menu->addAction(create_marker_here);
+       } else {
+               menu = r->create_view_context_menu(this, pos);
+       }
+
        if (menu)
                menu->popup(event->globalPos());
 }
@@ -2052,6 +2083,13 @@ void View::on_segment_changed(int segment)
        }
 }
 
+void View::on_create_marker_here()
+{
+       const QPoint p = ruler_->mapFrom(this, QPoint(context_menu_x_pos_, 0));
+
+       add_flag(ruler_->get_absolute_time_from_x_pos(p.x()));
+}
+
 void View::on_settingViewTriggerIsZeroTime_changed(const QVariant new_value)
 {
        (void)new_value;