action_view_zoom_out_(new QAction(this)),
action_view_zoom_fit_(new QAction(this)),
action_view_zoom_one_to_one_(new QAction(this)),
+ action_view_sticky_scrolling_(new QAction(this)),
action_view_show_cursors_(new QAction(this)),
action_about_(new QAction(this))
#ifdef ENABLE_DECODE
return action_view_zoom_one_to_one_;
}
+QAction* MainWindow::action_view_sticky_scrolling() const
+{
+ return action_view_sticky_scrolling_;
+}
+
QAction* MainWindow::action_view_show_cursors() const
{
return action_view_show_cursors_;
QString::fromUtf8("actionViewZoomOneToOne"));
menu_view->addAction(action_view_zoom_one_to_one_);
+ menu_file->addSeparator();
+
+ action_view_sticky_scrolling_->setCheckable(true);
+ action_view_sticky_scrolling_->setChecked(true);
+ action_view_sticky_scrolling_->setShortcut(QKeySequence(Qt::Key_R));
+ action_view_sticky_scrolling_->setObjectName(
+ QString::fromUtf8("actionViewStickyScrolling"));
+ action_view_sticky_scrolling_->setText(tr("Sticky Sc&rolling"));
+ menu_view->addAction(action_view_sticky_scrolling_);
+
+ view_->enable_sticky_scrolling(action_view_sticky_scrolling_->isChecked());
+
menu_view->addSeparator();
action_view_show_cursors_->setCheckable(true);
SLOT(capture_state_changed(int)));
connect(&session_, SIGNAL(device_selected()), this,
SLOT(device_selected()));
+
+ // Setup view_ events
+ connect(view_, SIGNAL(sticky_scrolling_changed(bool)), this,
+ SLOT(sticky_scrolling_changed(bool)));
+
}
void MainWindow::select_init_device() {
view_->zoom_one_to_one();
}
+void MainWindow::on_actionViewStickyScrolling_triggered()
+{
+ view_->enable_sticky_scrolling(action_view_sticky_scrolling_->isChecked());
+}
+
void MainWindow::on_actionViewShowCursors_triggered()
{
assert(view_);
dlg.exec();
}
+void MainWindow::sticky_scrolling_changed(bool state)
+{
+ action_view_sticky_scrolling_->setChecked(state);
+}
+
void MainWindow::add_decoder(srd_decoder *decoder)
{
#ifdef ENABLE_DECODE
QAction* action_view_zoom_out() const;
QAction* action_view_zoom_fit() const;
QAction* action_view_zoom_one_to_one() const;
+ QAction* action_view_sticky_scrolling() const;
QAction* action_view_show_cursors() const;
QAction* action_about() const;
void on_actionViewZoomOneToOne_triggered();
+ void on_actionViewStickyScrolling_triggered();
+
void on_actionViewShowCursors_triggered();
void on_actionAbout_triggered();
void capture_state_changed(int state);
void device_selected();
+ void sticky_scrolling_changed(bool state);
+
private:
DeviceManager &device_manager_;
QAction *const action_view_zoom_out_;
QAction *const action_view_zoom_fit_;
QAction *const action_view_zoom_one_to_one_;
+ QAction *const action_view_sticky_scrolling_;
QAction *const action_view_show_cursors_;
QAction *const action_about_;
add_decoder_button->setMenu(main_window_.menu_decoder_add());
#endif
- // Setup the menu
+ // Setup the burger menu
QMenu *const menu = new QMenu(this);
+ QMenu *const menu_view = new QMenu;
+ menu_view->setTitle(tr("&View"));
+ menu_view->addAction(main_window.action_view_sticky_scrolling());
+
QMenu *const menu_help = new QMenu;
menu_help->setTitle(tr("&Help"));
menu_help->addAction(main_window.action_about());
+ menu->addAction(menu_view->menuAction());
+ menu->addSeparator();
menu->addAction(menu_help->menuAction());
menu->addSeparator();
menu->addAction(main_window.action_quit());
const double View::MinScale = 1e-15;
const int View::MaxScrollValue = INT_MAX / 2;
+const int View::MaxViewAutoUpdateRate = 25; // No more than 25 Hz
const int View::ScaleUnits[3] = {1, 2, 5};
scale_(1e-3),
offset_(0),
updating_scroll_(false),
+ sticky_scrolling_(false), // Default setting is set in MainWindow::setup_ui()
tick_period_(0.0),
tick_prefix_(0),
show_cursors_(false),
this, SLOT(process_sticky_events()));
lazy_event_handler_.setSingleShot(true);
+ connect(&delayed_view_updater_, SIGNAL(timeout()),
+ this, SLOT(perform_delayed_view_update()));
+ delayed_view_updater_.setSingleShot(true);
+ delayed_view_updater_.setInterval(1000 / MaxViewAutoUpdateRate);
+
setViewport(viewport_);
viewport_->installEventFilter(this);
void View::set_scale_offset(double scale, double offset)
{
+ // Disable sticky scrolling when acquisition runs and user drags the viewport
+ if ((scale_ == scale) && (offset_ != offset) &&
+ sticky_scrolling_ && (session_.get_capture_state() == Session::Running)) {
+ sticky_scrolling_ = false;
+ sticky_scrolling_changed(false);
+ }
+
scale_ = scale;
offset_ = offset;
return make_pair(left_time, right_time);
}
+void View::enable_sticky_scrolling(bool state)
+{
+ sticky_scrolling_ = state;
+}
+
bool View::cursors_shown() const
{
return show_cursors_;
if (updating_scroll_)
return;
+ // Disable sticky 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);
+ }
+
const int range = horizontalScrollBar()->maximum();
if (range < MaxScrollValue)
offset_ = scale_ * value;
void View::data_updated()
{
- // Update the scroll bars
- update_scroll();
+ if (sticky_scrolling_) {
+ if (!delayed_view_updater_.isActive())
+ delayed_view_updater_.start();
+ } else {
+ update_scroll();
+ ruler_->update();
+ viewport_->update();
+ }
+}
+
+void View::perform_delayed_view_update()
+{
+ if (sticky_scrolling_) {
+ // Make right side of the view sticky
+ double length = 0, offset;
+ get_scroll_layout(length, offset);
+
+ const QSize areaSize = viewport_->size();
+ length = max(length - areaSize.width(), 0.0);
+
+ offset_ = scale_ * length;
+ }
- // Repaint the view
+ update_scroll();
+ ruler_->update();
viewport_->update();
}
static const double MinScale;
static const int MaxScrollValue;
+ static const int MaxViewAutoUpdateRate;
static const int ScaleUnits[3];
std::pair<double, double> get_time_extents() const;
+ /**
+ * Enables or disables sticky scrolling, i.e. the view always shows
+ * the most recent samples when capturing data.
+ */
+ void enable_sticky_scrolling(bool state);
+
/**
* Returns true if cursors are displayed. false otherwise.
*/
void scale_offset_changed();
+ void sticky_scrolling_changed(bool state);
+
private:
void get_scroll_layout(double &length, double &offset) const;
void signals_changed();
void data_updated();
+ void perform_delayed_view_update();
+
void process_sticky_events();
void on_hover_point_changed();
double offset_;
bool updating_scroll_;
+ bool sticky_scrolling_;
+ QTimer delayed_view_updater_;
double tick_period_;
unsigned int tick_prefix_;