diff --git a/icons/trigger-scrolling.svg b/icons/trigger-scrolling.svg
new file mode 100644
index 00000000..730aa729
--- /dev/null
+++ b/icons/trigger-scrolling.svg
@@ -0,0 +1,16 @@
+
+
+
diff --git a/pulseview.qrc b/pulseview.qrc
index 9acd3fac..76c6ffa0 100644
--- a/pulseview.qrc
+++ b/pulseview.qrc
@@ -35,6 +35,7 @@
icons/trigger-marker-rising.svg
icons/trigger-none.svg
icons/trigger-rising.svg
+ icons/trigger-scrolling.svg
icons/view-displaymode-last_complete_segment.svg
icons/view-displaymode-last_segment.svg
icons/view-displaymode-single_segment.svg
diff --git a/pv/mainwindow.hpp b/pv/mainwindow.hpp
index aa325e73..bcd787f2 100644
--- a/pv/mainwindow.hpp
+++ b/pv/mainwindow.hpp
@@ -179,6 +179,7 @@ private Q_SLOTS:
QIcon icon_grey_;
QShortcut *view_sticky_scrolling_shortcut_;
+ QShortcut *view_trigger_scrolling_shortcut_;
QShortcut *view_show_sampling_points_shortcut_;
QShortcut *view_show_analog_minor_grid_shortcut_;
QShortcut *view_colored_bg_shortcut_;
diff --git a/pv/views/trace/standardbar.cpp b/pv/views/trace/standardbar.cpp
index 22697506..7cff4bfb 100644
--- a/pv/views/trace/standardbar.cpp
+++ b/pv/views/trace/standardbar.cpp
@@ -41,6 +41,7 @@ StandardBar::StandardBar(Session &session, QWidget *parent,
action_view_zoom_in_(new QAction(this)),
action_view_zoom_out_(new QAction(this)),
action_view_zoom_fit_(new QAction(this)),
+ action_view_trigger_scrolling_(new QAction(this)),
action_view_show_cursors_(new QAction(this)),
segment_display_mode_selector_(new QToolButton(this)),
action_sdm_last_(new QAction(this)),
@@ -74,6 +75,14 @@ StandardBar::StandardBar(Session &session, QWidget *parent,
connect(action_view_zoom_fit_, SIGNAL(triggered(bool)),
this, SLOT(on_actionViewZoomFit_triggered(bool)));
+ action_view_trigger_scrolling_->setCheckable(true);
+ action_view_trigger_scrolling_->setText(tr("Scroll to &Trigger"));
+ action_view_trigger_scrolling_->setIcon(QIcon::fromTheme("trigger-scrolling",
+ QIcon(":/icons/trigger-scrolling.svg")));
+ action_view_trigger_scrolling_->setShortcut(QKeySequence(Qt::Key_T));
+ connect(action_view_trigger_scrolling_, SIGNAL(triggered(bool)),
+ this, SLOT(on_actionViewScrollToTrigger_triggered(bool)));
+
action_view_show_cursors_->setCheckable(true);
action_view_show_cursors_->setIcon(QIcon(":/icons/show-cursors.svg"));
action_view_show_cursors_->setShortcut(QKeySequence(Qt::Key_C));
@@ -125,6 +134,9 @@ StandardBar::StandardBar(Session &session, QWidget *parent,
connect(view_, SIGNAL(always_zoom_to_fit_changed(bool)),
this, SLOT(on_always_zoom_to_fit_changed(bool)));
+ connect(view_, SIGNAL(trigger_scrolling_changed(bool)),
+ this, SLOT(on_trigger_scrolling_changed(bool)));
+
connect(view_, SIGNAL(cursor_state_changed(bool)),
this, SLOT(on_cursor_state_changed(bool)));
@@ -143,6 +155,7 @@ void StandardBar::add_toolbar_widgets()
addAction(action_view_zoom_in_);
addAction(action_view_zoom_out_);
addAction(action_view_zoom_fit_);
+ addAction(action_view_trigger_scrolling_);
addSeparator();
addAction(action_view_show_cursors_);
multi_segment_actions_.push_back(addSeparator());
@@ -198,6 +211,11 @@ void StandardBar::on_actionViewZoomFit_triggered(bool checked)
view_->zoom_fit(checked);
}
+void StandardBar::on_actionViewScrollToTrigger_triggered(bool checked)
+{
+ view_->trigger_scrolling(checked);
+}
+
void StandardBar::on_actionViewShowCursors_triggered()
{
const bool show = action_view_show_cursors_->isChecked();
@@ -228,6 +246,11 @@ void StandardBar::on_always_zoom_to_fit_changed(bool state)
action_view_zoom_fit_->setChecked(state);
}
+void StandardBar::on_trigger_scrolling_changed(bool state)
+{
+ action_view_trigger_scrolling_->setChecked(state);
+}
+
void StandardBar::on_new_segment(int new_segment_id)
{
if (new_segment_id > 0) {
diff --git a/pv/views/trace/standardbar.hpp b/pv/views/trace/standardbar.hpp
index 9c27f43e..4a20d759 100644
--- a/pv/views/trace/standardbar.hpp
+++ b/pv/views/trace/standardbar.hpp
@@ -72,6 +72,7 @@ class StandardBar : public QToolBar
QAction *const action_view_zoom_in_;
QAction *const action_view_zoom_out_;
QAction *const action_view_zoom_fit_;
+ QAction *const action_view_trigger_scrolling_;
QAction *const action_view_show_cursors_;
QToolButton *segment_display_mode_selector_;
@@ -90,6 +91,7 @@ protected Q_SLOTS:
void on_actionViewZoomOut_triggered();
void on_actionViewZoomFit_triggered(bool checked);
+ void on_actionViewScrollToTrigger_triggered(bool checked);
void on_actionViewShowCursors_triggered();
void on_cursor_state_changed(bool show);
@@ -99,6 +101,7 @@ protected Q_SLOTS:
void on_actionSDMSingle_triggered();
void on_always_zoom_to_fit_changed(bool state);
+ void on_trigger_scrolling_changed(bool state);
void on_new_segment(int new_segment_id);
void on_segment_changed(int segment_id);
diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp
index f2a3335e..02d79488 100644
--- a/pv/views/trace/view.cpp
+++ b/pv/views/trace/view.cpp
@@ -233,6 +233,7 @@ void View::reset_view_state()
updating_scroll_ = false;
settings_restored_ = false;
always_zoom_to_fit_ = false;
+ trigger_scrolling_ = false;
tick_period_ = 0;
tick_prefix_ = pv::util::SIPrefix::yocto;
tick_precision_ = 0;
@@ -709,9 +710,20 @@ void View::zoom_fit(bool gui_state)
set_scale_offset(scale.convert_to(), extents.first);
}
+void View::trigger_scrolling(bool gui_state)
+{
+ trigger_scrolling_ = gui_state;
+ trigger_scrolling_changed(gui_state);
+
+ // Try to update view right away
+ if (trigger_scrolling_) {
+ scroll_to_trigger();
+ }
+}
+
void View::set_scale_offset(double scale, const Timestamp& offset)
{
- // Disable sticky scrolling / always zoom to fit when acquisition runs
+ // Disable sticky scrolling / always zoom to fit / trigger scrolling when acquisition runs
// and user drags the viewport
if ((scale_ == scale) && (offset_ != offset) &&
(session_.get_capture_state() == Session::Running)) {
@@ -725,6 +737,11 @@ void View::set_scale_offset(double scale, const Timestamp& offset)
always_zoom_to_fit_ = false;
always_zoom_to_fit_changed(false);
}
+
+ if (trigger_scrolling_) {
+ trigger_scrolling_ = false;
+ trigger_scrolling_changed(false);
+ }
}
set_scale(scale);
@@ -1226,6 +1243,39 @@ void View::set_scroll_default()
set_v_offset(extents.first);
}
+void View::scroll_to_trigger() {
+ const pair extents = get_time_extents();
+
+ const QSize areaSize = viewport_->size();
+ const Timestamp view_time_width = areaSize.width() * scale_;
+ const auto trigger_time_max = extents.second - view_time_width;
+ // Jump back if user is scrolled to the right for some reason
+ const auto trigger_time_min = offset_ > trigger_time_max ? view_time_width : offset_ + view_time_width;
+
+ // Intuitively the markers would be sorted,
+ // but I'm not sure the threads guarantees that,
+ // either way, with this kind of dumb search it doesn't matter too much
+ // as it will still find some appropriate event to jump to
+ for (auto it = trigger_markers_.rbegin(); it != trigger_markers_.rend(); it++)
+ {
+ const auto marker = (*it);
+ if (marker->time() > trigger_time_max)
+ {
+ continue;
+ }
+
+ if (marker->time() > trigger_time_min)
+ {
+ set_zero_position(marker->time());
+ set_offset(marker->time(), true);
+ ruler_->update();
+ }
+ break;
+ }
+
+ // TODO actually disable triggers until view is filled
+}
+
void View::determine_if_header_was_shrunk()
{
const int header_pane_width =
@@ -1495,12 +1545,16 @@ void View::h_scroll_value_changed(int value)
if (updating_scroll_)
return;
- // Disable sticky scrolling when user moves the horizontal scroll bar
+ // Disable sticky scrolling / trigger scrolling when user moves the horizontal scroll bar
// during a running acquisition
if (sticky_scrolling_ && (session_.get_capture_state() == Session::Running)) {
sticky_scrolling_ = false;
sticky_scrolling_changed(false);
}
+ if (trigger_scrolling_ && (session_.get_capture_state() == Session::Running)) {
+ trigger_scrolling_ = false;
+ trigger_scrolling_changed(false);
+ }
const int range = scrollarea_->horizontalScrollBar()->maximum();
if (range < MaxScrollValue)
@@ -1815,8 +1869,9 @@ void View::perform_delayed_view_update()
length = max(length - areaSize.width(), 0.0);
set_offset(scale_ * length);
+ } else if (trigger_scrolling_) {
+ scroll_to_trigger();
}
-
determine_time_unit();
update_scroll();
ruler_->update();
diff --git a/pv/views/trace/view.hpp b/pv/views/trace/view.hpp
index a0e6f6bc..5b412a74 100644
--- a/pv/views/trace/view.hpp
+++ b/pv/views/trace/view.hpp
@@ -247,6 +247,7 @@ class View : public ViewBase, public TraceTreeItemOwner, public GlobalSettingsIn
void zoom(double steps, int offset);
void zoom_fit(bool gui_state);
+ void trigger_scrolling(bool gui_state);
/**
* Sets the scale and offset.
@@ -350,6 +351,7 @@ class View : public ViewBase, public TraceTreeItemOwner, public GlobalSettingsIn
void scale_changed();
void sticky_scrolling_changed(bool state);
+ void trigger_scrolling_changed(bool state);
void always_zoom_to_fit_changed(bool state);
@@ -403,6 +405,8 @@ public Q_SLOTS:
void set_scroll_default();
+ void scroll_to_trigger();
+
void determine_if_header_was_shrunk();
void resize_header_to_fit();
@@ -532,6 +536,7 @@ private Q_SLOTS:
bool header_was_shrunk_;
bool sticky_scrolling_;
+ bool trigger_scrolling_;
bool colored_bg_;
bool always_zoom_to_fit_;