Bug 697 - Wishlist: show pulse width time as mouse rollover
Summary: Wishlist: show pulse width time as mouse rollover
Status: CONFIRMED
Alias: None
Product: PulseView
Classification: Unclassified
Component: Data display (show other bugs)
Version: unreleased development snapshot
Hardware: All All
: Normal normal
Target Milestone: PulseView 0.6.0
Assignee: Nobody
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-11-06 16:36 CET by leonerd
Modified: 2019-05-20 11:11 CEST (History)
3 users (show)



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description leonerd 2015-11-06 16:36:41 CET
A feature I find really useful on Saleae's Logic software is that by simply moving the mouse over the trace view, whenever the mouse is within a LOW or HIGH section of the trace, it shows the duration of that pulse, in both units of ns/µs/ms/s, and an implied frequency that would be, in GHz/MHz/kHz/Hz/etc... It'd be nice to have something similar here.

I'm happy to have a go at implementing it, but to do that I'd need answers to a number of PV-architectural questions:

1) How to attach code to a "on mouse movement" event

2) How to convert from an onscreen coordinate (e.g. where the mouse is) to a trace object and timestamp, and vice versa.

3) How to enquire of the trace at that timestamp, what state it is in and where the next transition edges are, forwards and backwards

4) How to draw text or graphical shapes to the screen, and how to remove them again afterwards

If I could obtain answers to these questions, then I'll A) write up some (wiki?) documentation to assist others in future, and B) add this feature as a patch.
Comment 1 Soeren Apel 2015-11-06 22:35:53 CET
That's actually my favourite feature of the entire Saleae GUI and I'm glad you want to work on it :)

As for your questions:

1) The main class related to the display of data and the "core" user interface is the View (view/view.cpp). It derives from QAbstractScrollArea, so keep in mind that a lot of useful Qt features are already available in the background. That said, PV already offers View::on_hover_point_changed() which is executed once every time the mouse cursor is moved while over the view.
Looking at the code there will show you that the call is trickling down to all visible items however, so putting such "measurement" logic into the View would be odd.

All traces that you can see in the view are inheriting from RowItem which provides an empty hover_point_changed() that can be overriden in AnalogSignal, LogicSignal or DecodeTrace - the latter doing just that to implement tool tips that show the content of the annotation the cursor is hovering above. I suggest you start introducing hover_point_changed() to LogicSignal and look at how the DecodeTrace class figures out the position of the mouse cursor. It's pretty much all there already :)

2) see above

3) Now that's one of the tricky parts. If you look at LogicSignal::paint_mid() you'll notice that the data is stored in segments which you can ask to tell you about the edges contained in a certain sample range. Sure, you could start with your mouse cursor position and continously extend the range outwards until you find the next edge. That would work with what you currently have, just be rather inefficient. If you want a quick-'n-dirty solution, I'd go for this. The proper way however would be to extend the LogicSegment class (data/LogicSegment.cpp) with a function that returns an std::pair<uint64_t, uint64_t> with the previous and next edge from a given sample number. Not too difficult to do using brute force: LogicSegment derives from Segment which keeps all the samples in a vector (data_). Take unit_size_ into account and you can do a linear search.

The difficult part starts when you want it to be fast. LogicSegment creates mipmaps of the data to speed up display - ideally, those would be used to find the prev/next edges, too. That's for later, though.

4) You'd draw the lines/arrows/labels in one of the paint methods of LogicSignal, ideally by creating a method of your own that you call in paint_fore(). As the paint methods are however only called when the object is to be redrawn, you need to force a redraw when... yes, when? If you do it every time the mouse cursor moves a pixel, there'll be performance issues. So this means that in on_hover_point_changed() you should only force a redraw when you know you want to show something else than is currently shown. That's another tricky part :)

One way to solve this is:

on_hover_point_changed()
{
   old_prev_next_edges = current_prev_next_edges

   sample_pos = figure_out_sample_pos()
   current_prev_next_edges = get_prev_next_edges(sample_pos)

   if (old_prev_next_edges != current_prev_next_edges)
   {
      cursor_pos = get_mouse_cursor_pos()
      coordinates = determine_rect_from_prev_next_edge_and_height(cursor_pos)
      update(coordinates) *
   }
}

(* see http://doc.qt.io/qt-4.8/qwidget.html#update)

As for the actual drawing routines you can check the paint methods that are already there or http://doc.qt.io/qt-4.8/qpainter.html

If there's anything else, just ask away on here or IRC :)
Comment 2 Miklos Marton 2019-05-20 10:45:12 CEST
Hello all,

I would like to warm up this topic. 

How would it sounds to you if this behavior would be implemented with the current cursors?

I have started to add a context menu to the cursors header.
Similar to the Saleae Logic we could add a "Show digital instantaneous measurement" to this menu which would make the cursors to track the mouse.
Comment 3 Miklos Marton 2019-05-20 11:11:08 CEST
Hello all,

I would like to warm up this topic. 

How would it sounds to you if this behavior would be implemented with the current cursor pair?

I have started to add a context menu to the cursors header:
https://github.com/sigrokproject/pulseview/pull/15

Similar to the Saleae Logic we could add a "Show digital instantaneous measurement" to this menu which would make the cursors to track the mouse.

Any concerns/recommendations on this one?