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

Reply via email to