On Mon, Jul 21, 2014 at 4:37 PM, Pierre Gronlier <[email protected]> wrote:
> Hello,
>
> I added the feature I wanted on the branch 0.2.x.
>
> You should find the proposed code modification here
> https://github.com/ticapix/pulseview/commit/0a0c00eb31224db4f287769fe9171cd8e83c791d
In case it's easier than the merging the git branch from github, here
is the proposed patch.
>
> This code add a right-click selection to automatically move the
> cursors to the closest edge on each side of the selection on the
> corresponding digital trace.
> For example, on the screenshot, my selected area that I draw from
> top-left to bottom-right, moves the cursors on the closest edge on the
> left for D3 and closest edge on the right for D5. It allows fast
> timing measurement between edges on different traces.
>
> What is the process to get it validated and pushed into the sigrok repo ?
>
> Thanks,
>
> On Fri, Jul 18, 2014 at 10:00 AM, Pierre Gronlier <[email protected]> wrote:
>> Hi,
>>
>> I would like to add the following feature to pulseview:
>> - when I left click on the Viewport, I would like to access the logic
>> data of the selected Trace and calculate the time between the last
>> signal change to the next signal change.
>>
>> From the viewport mousePressEvent, how to:
>> - know which line/trace was selected (I guess it's based on the y()
>> pixel position of the click or maybe from the SelectableItem class
>> from which Trace and LogicSignal inherit from ?)
>> - know the time (I guess it's based on the x() pixel position of the
>> click or should I expose new methods on the Ruler class ?)
>> - access the logic data to search for my signal changes (I guess it's
>> in LogicSignal, no ?)
>>
>> Any partial guidance for any of the previous points will help me.
>>
>> Thank you,
>>
>> --
>> Pierre Gronlier
>
>
>
> --
> Pierre Gronlier
--
Pierre Gronlier
diff --git a/pv/view/view.cpp b/pv/view/view.cpp
index d117489..ea2c075 100644
--- a/pv/view/view.cpp
+++ b/pv/view/view.cpp
@@ -42,7 +42,9 @@
#include "pv/sigsession.h"
#include "pv/data/logic.h"
#include "pv/data/logicsnapshot.h"
+#include "pv/view/logicsignal.h"
+using boost::dynamic_pointer_cast;
using boost::shared_ptr;
using boost::weak_ptr;
using pv::data::SignalData;
@@ -107,6 +109,9 @@ View::View(SigSession &session, QWidget *parent) :
connect(_header, SIGNAL(signals_moved()),
this, SLOT(on_signals_moved()));
+ connect(_viewport, SIGNAL(traces_selected()),
+ this, SLOT(traces_selected()));
+
connect(_header, SIGNAL(selection_changed()),
_ruler, SLOT(clear_selection()));
connect(_ruler, SIGNAL(selection_changed()),
@@ -535,5 +540,98 @@ void View::on_geometry_updated()
update_layout();
}
+bool View::find_edge_selection(QPoint pos, int direction, float* edge)
+{
+ const vector< shared_ptr<Trace> > traces(get_traces());
+
+ int prev_y = 0;
+ BOOST_FOREACH(const shared_ptr<Trace> t, traces) {
+ assert(t);
+ shared_ptr<view::LogicSignal> sig = dynamic_pointer_cast<view::LogicSignal>(t);
+ if (sig == 0)
+ continue;
+ if (!sig->probe()->enabled)
+ continue;
+ if (!(prev_y <= pos.y() && pos.y() < sig->get_y())) {
+ prev_y = sig->get_y();
+ continue;
+ }
+ prev_y = sig->get_y();
+
+ const deque< shared_ptr<pv::data::LogicSnapshot> > &snapshots = sig->logic_data()->get_snapshots();
+ if (snapshots.empty())
+ continue;
+
+ const shared_ptr<pv::data::LogicSnapshot> &snapshot = snapshots.front();
+
+ double samplerate = sig->logic_data()->samplerate();
+
+ // Show sample rate as 1Hz when it is unknown
+ if (samplerate == 0.0)
+ samplerate = 1.0;
+
+ int left = 0;
+ int right = _viewport->width();
+
+ assert(right >= left);
+
+ const double pixels_offset = offset() / scale(); // pixel = second / (second/pixel)
+ const double start_time = sig->logic_data()->get_start_time(); // second
+ const int64_t last_sample = snapshot->get_sample_count() - 1; // sample
+ const double samples_per_pixel = samplerate * scale(); // sample/pixel = sample/second * second/pixel
+ const double start = samplerate * (offset() - start_time); // sample = sample/second * second
+ const double end = start + samples_per_pixel * (right - left); // sample
+
+ vector<pv::data::LogicSnapshot::EdgePair> edges;
+ int index = sig->probe()->index;
+ const float Oversampling = 2.0f;
+
+ snapshot->get_subsampled_edges(edges,
+ min(max((int64_t)floor(start), (int64_t)0), last_sample),
+ min(max((int64_t)ceil(end), (int64_t)0), last_sample),
+ samples_per_pixel / Oversampling, index);
+
+ if (edges.size() < 2)
+ continue;
+
+ if (direction > 0) {
+ for (vector<pv::data::LogicSnapshot::EdgePair>::const_iterator i =
+ edges.begin(); i != edges.end(); ++i) {
+ float x = ((*i).first / samples_per_pixel - pixels_offset) + left;
+ if (x < pos.x())
+ continue;
+ *edge = x;
+ return TRUE;
+ }
+ } else {
+ for (vector<pv::data::LogicSnapshot::EdgePair>::const_reverse_iterator i =
+ edges.rbegin(); i != edges.rend(); ++i) {
+ float x = ((*i).first / samples_per_pixel - pixels_offset) + left;
+ if (x > pos.x())
+ continue;
+ *edge = x;
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+void View::traces_selected()
+{
+ float edge; // in pixel
+ if (find_edge_selection(_viewport->get_selection_from(), -1 /* to the left */, &edge)) {
+ _cursors.first()->set_time(edge * scale() + offset());
+ } else {
+ _cursors.first()->set_time(offset());
+ }
+ if (find_edge_selection(_viewport->get_selection_to(), +1 /* to the right */, &edge)) {
+ _cursors.second()->set_time(edge * scale() + offset());
+ } else {
+ _cursors.second()->set_time(_viewport->width() * scale() + offset());
+ }
+ _viewport->update();
+}
+
} // namespace view
} // namespace pv
diff --git a/pv/view/view.h b/pv/view/view.h
index 0661637..0409da6 100644
--- a/pv/view/view.h
+++ b/pv/view/view.h
@@ -165,6 +165,8 @@ private:
const boost::shared_ptr<pv::view::Trace> &a,
const boost::shared_ptr<pv::view::Trace> &b);
+ bool find_edge_selection(QPoint pos, int direction, float* edge);
+
private:
bool eventFilter(QObject *object, QEvent *event);
@@ -186,6 +188,7 @@ private slots:
void on_geometry_updated();
+ void traces_selected();
private:
SigSession &_session;
diff --git a/pv/view/viewport.cpp b/pv/view/viewport.cpp
index 3b06cf9..26896c2 100644
--- a/pv/view/viewport.cpp
+++ b/pv/view/viewport.cpp
@@ -38,7 +38,8 @@ namespace view {
Viewport::Viewport(View &parent) :
QWidget(&parent),
- _view(parent)
+ _view(parent),
+ _on_selection(FALSE)
{
setMouseTracking(true);
setAutoFillBackground(true);
@@ -55,6 +56,16 @@ Viewport::Viewport(View &parent) :
on_signals_changed();
}
+QPoint Viewport::get_selection_from() const
+{
+ return _selected_area.from;
+}
+
+QPoint Viewport::get_selection_to() const
+{
+ return _selected_area.to;
+}
+
int Viewport::get_total_height() const
{
int h = 0;
@@ -93,6 +104,9 @@ void Viewport::paintEvent(QPaintEvent*)
if (_view.cursors_shown())
_view.cursors().draw_viewport_foreground(p, rect());
+ if (_on_selection) {
+ p.fillRect(QRect(_selected_area.from, _selected_area.to).normalized(), QColor(0, 183, 235, 100));
+ }
p.end();
}
@@ -102,6 +116,30 @@ void Viewport::mousePressEvent(QMouseEvent *event)
_mouse_down_point = event->pos();
_mouse_down_offset = _view.offset();
+ if (event->buttons() & Qt::RightButton) {
+ _on_selection = TRUE;
+ _selected_area.from = event->pos();
+ }
+}
+
+void Viewport::mouseReleaseEvent(QMouseEvent *event)
+{
+ assert(event);
+
+ _mouse_down_point = event->pos();
+ _mouse_down_offset = _view.offset();
+ if (_on_selection) {
+ _on_selection = FALSE;
+ // normalize that 'from' is on the left side of the selection
+ // and 'to' on the right side
+ if (_selected_area.from.x() <= event->pos().x()) {
+ _selected_area.to = event->pos();
+ } else {
+ _selected_area.to = _selected_area.from;
+ _selected_area.from = event->pos();
+ }
+ traces_selected();
+ }
}
void Viewport::mouseMoveEvent(QMouseEvent *event)
@@ -115,6 +153,10 @@ void Viewport::mouseMoveEvent(QMouseEvent *event)
(_mouse_down_point - event->pos()).x() *
_view.scale());
}
+ if (_on_selection) {
+ _selected_area.to = event->pos();
+ update();
+ }
}
void Viewport::mouseDoubleClickEvent(QMouseEvent *event)
diff --git a/pv/view/viewport.h b/pv/view/viewport.h
index 0474b7e..548271b 100644
--- a/pv/view/viewport.h
+++ b/pv/view/viewport.h
@@ -41,12 +41,15 @@ public:
explicit Viewport(View &parent);
int get_total_height() const;
+ QPoint get_selection_from() const;
+ QPoint get_selection_to() const;
protected:
void paintEvent(QPaintEvent *event);
private:
void mousePressEvent(QMouseEvent *event);
+ void mouseReleaseEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseDoubleClickEvent(QMouseEvent * event);
void wheelEvent(QWheelEvent *event);
@@ -55,11 +58,20 @@ private slots:
void on_signals_changed();
void on_signals_moved();
+signals:
+ void traces_selected();
+
private:
View &_view;
QPoint _mouse_down_point;
double _mouse_down_offset;
+ bool _on_selection;
+ struct {
+ QPoint from;
+ QPoint to;
+ } _selected_area;
+
};
} // namespace view
------------------------------------------------------------------------------
Want fast and easy access to all the code in your enterprise? Index and
search up to 200,000 lines of code with a free copy of Black Duck
Code Sight - the same software that powers the world's largest code
search on Ohloh, the Black Duck Open Hub! Try it now.
http://p.sf.net/sfu/bds
_______________________________________________
sigrok-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sigrok-devel