X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fviews%2Ftrace%2Fview.cpp;h=54c6fae6561cc70fac0dd661a61c1e1be879e15e;hp=e68c16a8dc6013634e2add3f90025a4d25e84dda;hb=581724de334181fc5338f1efa87954264cf90520;hpb=47cf8590e122f72132af3674c15054a35360385c diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index e68c16a8..54c6fae6 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -241,6 +241,7 @@ void View::reset_view_state() cursors_ = make_shared(*this); next_flag_text_ = 'A'; trigger_markers_.clear(); + hover_widget_ = nullptr; hover_point_ = QPoint(-1, -1); scroll_needs_defaults_ = true; saved_v_offset_ = 0; @@ -347,6 +348,11 @@ const Viewport* View::viewport() const return viewport_; } +const Ruler* View::ruler() const +{ + return ruler_; +} + void View::save_settings(QSettings &settings) const { settings.setValue("scale", scale_); @@ -860,81 +866,110 @@ const QPoint& View::hover_point() const return hover_point_; } +const QWidget* View::hover_widget() const +{ + return hover_widget_; +} + int64_t View::get_nearest_level_change(const QPoint &p) { + // Is snapping disabled? if (snap_distance_ == 0) return -1; - shared_ptr signal = signal_under_mouse_cursor_; + struct entry_t { + entry_t(shared_ptr s) : + signal(s), delta(numeric_limits::max()), sample(-1), is_dense(false) {} + shared_ptr signal; + int64_t delta; + int64_t sample; + bool is_dense; + }; - vector nearest_edges; - int64_t nearest_sample = -1; + vector list; - if (signal) { - // Determine nearest edge from specific signal + // Create list of signals to consider + if (signal_under_mouse_cursor_) + list.emplace_back(signal_under_mouse_cursor_); + else + for (shared_ptr s : signals_) { + if (!s->enabled()) + continue; + + list.emplace_back(s); + } + // Get data for listed signals + for (entry_t &e : list) { // Calculate sample number from cursor position - const double samples_per_pixel = signal->base()->get_samplerate() * scale(); + const double samples_per_pixel = e.signal->base()->get_samplerate() * scale(); const int64_t x_offset = offset().convert_to() / scale(); const int64_t sample_num = max(((x_offset + p.x()) * samples_per_pixel), 0.0); - nearest_edges = signal->get_nearest_level_changes(sample_num); - - if (nearest_edges.size() != 2) - return -1; + vector edges = + e.signal->get_nearest_level_changes(sample_num); - // We received absolute sample numbers, make them relative - const int64_t left_sample_delta = sample_num - nearest_edges.front().first; - const int64_t right_sample_delta = nearest_edges.back().first - sample_num - 1; + if (edges.empty()) + continue; - const int64_t left_delta = left_sample_delta / samples_per_pixel; - const int64_t right_delta = right_sample_delta / samples_per_pixel; + // Check first edge + const int64_t first_sample_delta = abs(sample_num - edges.front().first); + const int64_t first_delta = first_sample_delta / samples_per_pixel; + e.delta = first_delta; + e.sample = edges.front().first; - // Only use closest left or right edge if they're close to the cursor - if ((left_delta < right_delta) && (left_delta <= snap_distance_)) - nearest_sample = nearest_edges.front().first; - if ((left_delta >= right_delta) && (right_delta <= snap_distance_)) - nearest_sample = nearest_edges.back().first; - } else { - // Determine nearest edge from all signals + // Check second edge if available + if (edges.size() == 2) { + // Note: -1 because this is usually the right edge and sample points are left-aligned + const int64_t second_sample_delta = abs(sample_num - edges.back().first - 1); + const int64_t second_delta = second_sample_delta / samples_per_pixel; - int64_t nearest_delta = numeric_limits::max(); - for (shared_ptr s : signals_) { - if (!s->enabled()) - continue; + // If both edges are too close, we mark this signal as being dense + if ((first_delta + second_delta) <= snap_distance_) + e.is_dense = true; - // Calculate sample number from cursor position - const double samples_per_pixel = s->base()->get_samplerate() * scale(); - const int64_t x_offset = offset().convert_to() / scale(); - const int64_t sample_num = max(((x_offset + p.x()) * samples_per_pixel), 0.0); + if (second_delta < first_delta) { + e.delta = second_delta; + e.sample = edges.back().first; + } + } + } - vector edges = - s->get_nearest_level_changes(sample_num); + // Look for the best match: non-dense first, then dense + entry_t *match = nullptr; - if (edges.size() != 2) - continue; + for (entry_t &e : list) { + if (e.delta > snap_distance_ || e.is_dense) + continue; - // We received absolute sample numbers, make them relative - const int64_t left_sample_delta = sample_num - edges.front().first; - const int64_t right_sample_delta = edges.back().first - sample_num - 1; + if (match) { + if (e.delta < match->delta) + match = &e; + } else + match = &e; + } - const int64_t left_delta = left_sample_delta / samples_per_pixel; - const int64_t right_delta = right_sample_delta / samples_per_pixel; + if (!match) { + for (entry_t &e : list) { + if (!e.is_dense) + continue; - if ((left_delta < nearest_delta) || (right_delta < nearest_delta)) { - nearest_delta = min(left_delta, right_delta); + if (match) { + if (e.delta < match->delta) + match = &e; + } else + match = &e; + } + } - if (nearest_delta <= snap_distance_) - nearest_sample = (nearest_delta == left_delta) ? - edges.front().first : edges.back().first; + if (match) { + // Somewhat ugly hack to make TimeItem::drag_by() work + signal_under_mouse_cursor_ = match->signal; - // Somewhat ugly hack to make TimeItem::drag_by() work - signal_under_mouse_cursor_ = s; - } - } + return match->sample; } - return nearest_sample; + return -1; } void View::restack_all_trace_tree_items() @@ -1300,14 +1335,14 @@ bool View::eventFilter(QObject *object, QEvent *event) const QEvent::Type type = event->type(); if (type == QEvent::MouseMove) { + if (object) + hover_widget_ = qobject_cast(object); + const QMouseEvent *const mouse_event = (QMouseEvent*)event; if (object == viewport_) hover_point_ = mouse_event->pos(); else if (object == ruler_) - // Adjust the hover point's y coordinate so that it's relative to - // the top of the viewport. The result may be negative. - hover_point_ = QPoint(mouse_event->pos().x(), - mouse_event->pos().y() - ruler_->sizeHint().height()); + hover_point_ = mouse_event->pos(); else if (object == header_) hover_point_ = QPoint(0, mouse_event->y()); else @@ -1358,7 +1393,7 @@ void View::contextMenuEvent(QContextMenuEvent *event) QMenu *menu = r->create_view_context_menu(this, pos); if (menu) - menu->exec(event->globalPos()); + menu->popup(event->globalPos()); } void View::resizeEvent(QResizeEvent* event) @@ -1374,13 +1409,15 @@ void View::update_hover_point() { // Determine signal that the mouse cursor is hovering over signal_under_mouse_cursor_.reset(); - for (shared_ptr s : signals_) { - const pair extents = s->v_extents(); - const int top = s->get_visual_y() + extents.first; - const int btm = s->get_visual_y() + extents.second; - if ((hover_point_.y() >= top) && (hover_point_.y() <= btm) - && s->base()->enabled()) - signal_under_mouse_cursor_ = s; + if (hover_widget_ == this) { + for (shared_ptr s : signals_) { + const pair extents = s->v_extents(); + const int top = s->get_visual_y() + extents.first; + const int btm = s->get_visual_y() + extents.second; + if ((hover_point_.y() >= top) && (hover_point_.y() <= btm) + && s->base()->enabled()) + signal_under_mouse_cursor_ = s; + } } // Update all trace tree items @@ -1390,7 +1427,7 @@ void View::update_hover_point() r->hover_point_changed(hover_point_); // Notify any other listeners - hover_point_changed(hover_point_); + hover_point_changed(hover_widget_, hover_point_); } void View::row_item_appearance_changed(bool label, bool content)