]> sigrok.org Git - pulseview.git/blobdiff - pv/views/trace/view.cpp
Implement expansion marker animation and its infrastructure
[pulseview.git] / pv / views / trace / view.cpp
index f1d7aa3dfca872a29bc81f5c0c2c444e4a34e03e..e72770f07eabe7481f2f48b95a1cf0f86a15816d 100644 (file)
@@ -124,13 +124,14 @@ bool CustomScrollArea::viewportEvent(QEvent *event)
        }
 }
 
-View::View(Session &session, bool is_main_view, QWidget *parent) :
+View::View(Session &session, bool is_main_view, QMainWindow *parent) :
        ViewBase(session, is_main_view, parent),
 
        // Note: Place defaults in View::reset_view_state(), not here
        splitter_(new QSplitter()),
        header_was_shrunk_(false),  // The splitter remains unchanged after a reset, so this goes here
-       sticky_scrolling_(false)  // Default setting is set in MainWindow::setup_ui()
+       sticky_scrolling_(false),  // Default setting is set in MainWindow::setup_ui()
+       scroll_needs_defaults_(true)
 {
        QVBoxLayout *root_layout = new QVBoxLayout(this);
        root_layout->setContentsMargins(0, 0, 0, 0);
@@ -205,11 +206,33 @@ View::View(Session &session, bool is_main_view, QWidget *parent) :
                this, SLOT(process_sticky_events()));
        lazy_event_handler_.setSingleShot(true);
 
+       // Set up local keyboard shortcuts
+       zoom_in_shortcut_ = new QShortcut(QKeySequence(Qt::Key_Plus), this,
+                       SLOT(on_zoom_in_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+       zoom_in_shortcut_->setAutoRepeat(false);
+
+       zoom_out_shortcut_ = new QShortcut(QKeySequence(Qt::Key_Minus), this,
+               SLOT(on_zoom_out_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+       zoom_out_shortcut_->setAutoRepeat(false);
+
+       zoom_in_shortcut_2_ = new QShortcut(QKeySequence(Qt::Key_Up), this,
+               SLOT(on_zoom_in_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+       zoom_out_shortcut_2_ = new QShortcut(QKeySequence(Qt::Key_Down), this,
+               SLOT(on_zoom_out_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+
+       home_shortcut_ = new QShortcut(QKeySequence(Qt::Key_Home), this,
+               SLOT(on_scroll_to_start_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+       home_shortcut_->setAutoRepeat(false);
+
+       end_shortcut_ = new QShortcut(QKeySequence(Qt::Key_End), this,
+               SLOT(on_scroll_to_end_shortcut_triggered()), nullptr, Qt::WidgetWithChildrenShortcut);
+       end_shortcut_->setAutoRepeat(false);
+
        // Trigger the initial event manually. The default device has signals
        // which were created before this object came into being
        signals_changed();
 
-       // make sure the transparent widgets are on the top
+       // Make sure the transparent widgets are on the top
        ruler_->raise();
        header_->raise();
 
@@ -221,6 +244,11 @@ View::~View()
        GlobalSettings::remove_change_handler(this);
 }
 
+ViewType View::get_type() const
+{
+       return ViewTypeTrace;
+}
+
 void View::reset_view_state()
 {
        ViewBase::reset_view_state();
@@ -275,9 +303,22 @@ unordered_set< shared_ptr<Signal> > View::signals() const
        return signals_;
 }
 
+shared_ptr<Signal> View::get_signal_by_signalbase(shared_ptr<data::SignalBase> base) const
+{
+       shared_ptr<Signal> ret_val;
+
+       for (const shared_ptr<Signal> s : signals_)
+               if (s->base() == base) {
+                       ret_val = s;
+                       break;
+               }
+
+       return ret_val;
+}
+
 void View::clear_signals()
 {
-       ViewBase::clear_signalbases();
+       ViewBase::clear_signals();
        signals_.clear();
 }
 
@@ -296,11 +337,14 @@ void View::add_signal(const shared_ptr<Signal> signal)
 #ifdef ENABLE_DECODE
 void View::clear_decode_signals()
 {
+       ViewBase::clear_decode_signals();
        decode_traces_.clear();
 }
 
 void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
 {
+       ViewBase::add_decode_signal(signal);
+
        shared_ptr<DecodeTrace> d(
                new DecodeTrace(session_, signal, decode_traces_.size()));
        decode_traces_.push_back(d);
@@ -320,6 +364,8 @@ void View::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
                        signals_changed();
                        return;
                }
+
+       ViewBase::remove_decode_signal(signal);
 }
 #endif
 
@@ -362,12 +408,6 @@ void View::save_settings(QSettings &settings) const
        settings.setValue("splitter_state", splitter_->saveState());
        settings.setValue("segment_display_mode", segment_display_mode_);
 
-       {
-               stringstream ss;
-               boost::archive::text_oarchive oa(ss);
-               oa << boost::serialization::make_nvp("ruler_shift", ruler_shift_);
-               settings.setValue("ruler_shift", QString::fromStdString(ss.str()));
-       }
        {
                stringstream ss;
                boost::archive::text_oarchive oa(ss);
@@ -390,20 +430,6 @@ void View::restore_settings(QSettings &settings)
        if (settings.contains("scale"))
                set_scale(settings.value("scale").toDouble());
 
-       if (settings.contains("ruler_shift")) {
-               util::Timestamp shift;
-               stringstream ss;
-               ss << settings.value("ruler_shift").toString().toStdString();
-
-               try {
-                       boost::archive::text_iarchive ia(ss);
-                       ia >> boost::serialization::make_nvp("ruler_shift", shift);
-                       ruler_shift_ = shift;
-               } catch (boost::archive::archive_exception&) {
-                       qDebug() << "Could not restore the view ruler shift";
-               }
-       }
-
        if (settings.contains("offset")) {
                util::Timestamp offset;
                stringstream ss;
@@ -480,7 +506,7 @@ void View::set_offset(const pv::util::Timestamp& offset, bool force_update)
 {
        if ((offset_ != offset) || force_update) {
                offset_ = offset;
-               ruler_offset_ = offset_ + ruler_shift_;
+               ruler_offset_ = offset_ + zero_offset_;
                offset_changed();
        }
 }
@@ -495,9 +521,9 @@ const Timestamp& View::ruler_offset() const
        return ruler_offset_;
 }
 
-void View::set_zero_position(pv::util::Timestamp& position)
+void View::set_zero_position(const pv::util::Timestamp& position)
 {
-       ruler_shift_ = -position;
+       zero_offset_ = -position;
 
        // Force an immediate update of the offsets
        set_offset(offset_, true);
@@ -506,13 +532,18 @@ void View::set_zero_position(pv::util::Timestamp& position)
 
 void View::reset_zero_position()
 {
-       ruler_shift_ = 0;
+       zero_offset_ = 0;
 
        // Force an immediate update of the offsets
        set_offset(offset_, true);
        ruler_->update();
 }
 
+pv::util::Timestamp View::zero_offset() const
+{
+       return zero_offset_;
+}
+
 int View::owner_visual_v_offset() const
 {
        return -scrollarea_->verticalScrollBar()->sliderPosition();
@@ -525,6 +556,18 @@ void View::set_v_offset(int offset)
        viewport_->update();
 }
 
+void View::set_h_offset(int offset)
+{
+       scrollarea_->horizontalScrollBar()->setSliderPosition(offset);
+       header_->update();
+       viewport_->update();
+}
+
+int View::get_h_scrollbar_maximum() const
+{
+       return scrollarea_->horizontalScrollBar()->maximum();
+}
+
 unsigned int View::depth() const
 {
        return 0;
@@ -778,26 +821,6 @@ pair<Timestamp, Timestamp> View::get_time_extents() const
        return make_pair(*left_time, *right_time);
 }
 
-void View::enable_show_sampling_points(bool state)
-{
-       (void)state;
-
-       viewport_->update();
-}
-
-void View::enable_show_analog_minor_grid(bool state)
-{
-       (void)state;
-
-       viewport_->update();
-}
-
-void View::enable_colored_bg(bool state)
-{
-       colored_bg_ = state;
-       viewport_->update();
-}
-
 bool View::colored_bg() const
 {
        return colored_bg_;
@@ -810,22 +833,36 @@ bool View::cursors_shown() const
 
 void View::show_cursors(bool show)
 {
-       show_cursors_ = show;
-       cursor_state_changed(show);
+       if (show_cursors_ != show) {
+               show_cursors_ = show;
+
+               cursor_state_changed(show);
+               ruler_->update();
+               viewport_->update();
+       }
+}
+
+void View::set_cursors(pv::util::Timestamp& first, pv::util::Timestamp& second)
+{
+       assert(cursors_);
+
+       cursors_->first()->set_time(first);
+       cursors_->second()->set_time(second);
+
        ruler_->update();
        viewport_->update();
 }
 
 void View::centre_cursors()
 {
-       if (cursors_) {
-               const double time_width = scale_ * viewport_->width();
-               cursors_->first()->set_time(offset_ + time_width * 0.4);
-               cursors_->second()->set_time(offset_ + time_width * 0.6);
+       assert(cursors_);
 
-               ruler_->update();
-               viewport_->update();
-       }
+       const double time_width = scale_ * viewport_->width();
+       cursors_->first()->set_time(offset_ + time_width * 0.4);
+       cursors_->second()->set_time(offset_ + time_width * 0.6);
+
+       ruler_->update();
+       viewport_->update();
 }
 
 shared_ptr<CursorPair> View::cursors() const
@@ -833,15 +870,17 @@ shared_ptr<CursorPair> View::cursors() const
        return cursors_;
 }
 
-void View::add_flag(const Timestamp& time)
+shared_ptr<Flag> View::add_flag(const Timestamp& time)
 {
-       flags_.push_back(make_shared<Flag>(*this, time,
-               QString("%1").arg(next_flag_text_)));
+       shared_ptr<Flag> flag =
+               make_shared<Flag>(*this, time, QString("%1").arg(next_flag_text_));
+       flags_.push_back(flag);
 
        next_flag_text_ = (next_flag_text_ >= 'Z') ? 'A' :
                (next_flag_text_ + 1);
 
        time_item_appearance_changed(true, true);
+       return flag;
 }
 
 void View::remove_flag(shared_ptr<Flag> flag)
@@ -1001,13 +1040,22 @@ int View::header_width() const
 
 void View::on_setting_changed(const QString &key, const QVariant &value)
 {
+       GlobalSettings settings;
+
+       if (key == GlobalSettings::Key_View_ColoredBG) {
+               colored_bg_ = settings.value(GlobalSettings::Key_View_ColoredBG).toBool();
+               viewport_->update();
+       }
+
+       if ((key == GlobalSettings::Key_View_ShowSamplingPoints) ||
+          (key == GlobalSettings::Key_View_ShowAnalogMinorGrid))
+               viewport_->update();
+
        if (key == GlobalSettings::Key_View_TriggerIsZeroTime)
                on_settingViewTriggerIsZeroTime_changed(value);
 
-       if (key == GlobalSettings::Key_View_SnapDistance) {
-               GlobalSettings settings;
+       if (key == GlobalSettings::Key_View_SnapDistance)
                snap_distance_ = settings.value(GlobalSettings::Key_View_SnapDistance).toInt();
-       }
 }
 
 void View::trigger_event(int segment_id, util::Timestamp location)
@@ -1215,7 +1263,8 @@ void View::set_scroll_default()
 
 void View::determine_if_header_was_shrunk()
 {
-       const int header_pane_width = splitter_->sizes().front();
+       const int header_pane_width =
+               splitter_->sizes().front();  // clazy:exclude=detaching-temporary
 
        // Allow for a slight margin of error so that we also accept
        // slight differences when e.g. a label name change increased
@@ -1234,7 +1283,7 @@ void View::resize_header_to_fit()
        // splitter to the maximum allowed position.
 
        int splitter_area_width = 0;
-       for (int w : splitter_->sizes())
+       for (int w : splitter_->sizes())  // clazy:exclude=range-loop
                splitter_area_width += w;
 
        // Make sure the header has enough horizontal space to show all labels fully
@@ -1333,6 +1382,7 @@ void View::determine_time_unit()
 bool View::eventFilter(QObject *object, QEvent *event)
 {
        const QEvent::Type type = event->type();
+
        if (type == QEvent::MouseMove) {
 
                if (object)
@@ -1350,6 +1400,15 @@ bool View::eventFilter(QObject *object, QEvent *event)
 
                update_hover_point();
 
+       } else if (type == QEvent::MouseButtonPress) {
+               const QMouseEvent *const mouse_event = (QMouseEvent*)event;
+               if ((object == viewport_) && (mouse_event->button() & Qt::LeftButton)) {
+                       // Send event to all trace tree items
+                       const vector<shared_ptr<TraceTreeItem>> trace_tree_items(
+                               list_by_type<TraceTreeItem>());
+                       for (const shared_ptr<TraceTreeItem>& r : trace_tree_items)
+                               r->mouse_left_press_event(mouse_event);
+               }
        } else if (type == QEvent::Leave) {
                hover_point_ = QPoint(-1, -1);
                update_hover_point();
@@ -1476,6 +1535,26 @@ void View::on_splitter_moved()
                resize_header_to_fit();
 }
 
+void View::on_zoom_in_shortcut_triggered()
+{
+       zoom(1);
+}
+
+void View::on_zoom_out_shortcut_triggered()
+{
+       zoom(-1);
+}
+
+void View::on_scroll_to_start_shortcut_triggered()
+{
+       set_h_offset(0);
+}
+
+void View::on_scroll_to_end_shortcut_triggered()
+{
+       set_h_offset(get_h_scrollbar_maximum());
+}
+
 void View::h_scroll_value_changed(int value)
 {
        if (updating_scroll_)
@@ -1695,6 +1774,7 @@ void View::capture_state_updated(int state)
                set_time_unit(util::TimeUnit::Samples);
 
                trigger_markers_.clear();
+               set_zero_position(0);
 
                scale_at_acq_start_ = scale_;
                offset_at_acq_start_ = offset_;