]> sigrok.org Git - pulseview.git/commitdiff
Add initial scrolling support with a QAbstractScrollArea
authorJoel Holdsworth <redacted>
Wed, 5 Sep 2012 11:19:24 +0000 (12:19 +0100)
committerJoel Holdsworth <redacted>
Thu, 6 Sep 2012 12:47:43 +0000 (13:47 +0100)
CMakeLists.txt
mainwindow.cpp
mainwindow.h
sigsession.cpp
sigsession.h
sigview.cpp [new file with mode: 0644]
sigview.h [new file with mode: 0644]
sigviewport.cpp
sigviewport.h

index 5ae27aab7647e44ee74852959d852b03c1fce73a..5fc8b6a22c0d5f0288acf6e430ab80dd54c3b1c3 100644 (file)
@@ -26,6 +26,7 @@ set(pulseview_SOURCES
        signaldata.cpp
        sigsession.cpp
        signal.cpp
+       sigview.cpp
        sigviewport.cpp
 )
 
@@ -34,6 +35,7 @@ set(pulseview_HEADERS
        mainwindow.h
        samplingbar.h
        sigsession.h
+       sigview.h
        sigviewport.h
 )
 
index 865d6e2a876e72f9f3fd90865c7c91bc6d8c5799..54cc39ecea17cfe9d0fc412981d40e62f5db1fd0 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
 #include "about.h"
 #include "mainwindow.h"
 #include "samplingbar.h"
-#include "sigviewport.h"
+#include "sigview.h"
 
 extern "C" {
 /* __STDC_FORMAT_MACROS is required for PRIu64 and friends (in C++). */
@@ -138,7 +138,7 @@ void MainWindow::setup_ui()
        _menu_view->setTitle(QApplication::translate("MainWindow", "&View", 0, QApplication::UnicodeUTF8));
        _menu_help->setTitle(QApplication::translate("MainWindow", "&Help", 0, QApplication::UnicodeUTF8));
 
-       _view = new SigViewport(_session, this);
+       _view = new SigView(_session, this);
        _vertical_layout->addWidget(_view);
 }
 
index 811ea15e1a5c73aa9ae129386666db130af0a95c..6a1e52ca2d8ddd3a5e3264f3bd37f842a5081cb3 100644 (file)
@@ -26,7 +26,7 @@
 #include "sigsession.h"
 
 class SamplingBar;
-class SigViewport;
+class SigView;
 
 namespace Ui {
 class MainWindow;
@@ -53,7 +53,7 @@ private:
 private:
 
        SigSession _session;
-       SigViewport *_view;
+       SigView *_view;
 
        QAction *_action_open;
        QAction *_action_view_zoom_in;
index 16b84f1487348871fa6af367278a2284433a998d..47d9585b999cfd9fe263a29097f3f24b7582481d 100644 (file)
@@ -97,6 +97,11 @@ vector< shared_ptr<Signal> >& SigSession::get_signals()
        return _signals;
 }
 
+boost::shared_ptr<LogicData> SigSession::get_data()
+{
+       return _logic_data;
+}
+
 void SigSession::data_feed_in(const struct sr_dev_inst *sdi,
        struct sr_datafeed_packet *packet)
 {
index bf262bbf6cc675c7a8136e6cb72f139995538cf0..f6b1d8e4951e0e021b2f3e76851ce525af44a888 100644 (file)
@@ -53,6 +53,8 @@ public:
        std::vector< boost::shared_ptr<Signal> >&
                get_signals();
 
+       boost::shared_ptr<LogicData> get_data();
+
 private:
        void data_feed_in(const struct sr_dev_inst *sdi,
                struct sr_datafeed_packet *packet);
diff --git a/sigview.cpp b/sigview.cpp
new file mode 100644 (file)
index 0000000..4f2436c
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * This file is part of the sigrok project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <assert.h>
+#include <math.h>
+
+#include <boost/foreach.hpp>
+
+#include <QEvent>
+#include <QScrollBar>
+
+#include "sigview.h"
+
+#include "logicdata.h"
+#include "logicdatasnapshot.h"
+#include "sigsession.h"
+#include "sigviewport.h"
+
+using namespace boost;
+using namespace std;
+
+const double SigView::MaxScale = 1e9;
+const double SigView::MinScale = 1e-15;
+
+const int SigView::LabelMarginWidth = 70;
+const int SigView::RulerHeight = 30;
+
+SigView::SigView(SigSession &session, QWidget *parent) :
+       QAbstractScrollArea(parent),
+       _session(session),
+       _viewport(new SigViewport(*this)),
+       _data_length(0),
+       _scale(1e-6),
+       _offset(0),
+       _v_offset(0)
+{
+       connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
+               this, SLOT(h_scroll_value_changed(int)));
+       connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
+               this, SLOT(v_scroll_value_changed(int)));
+       connect(&_session, SIGNAL(data_updated()),
+               this, SLOT(data_updated()));
+       setViewport(_viewport);
+}
+
+double SigView::scale() const
+{
+       return _scale;
+}
+
+double SigView::offset() const
+{
+       return _offset;
+}
+
+int SigView::v_offset() const
+{
+       return _v_offset;
+}
+
+void SigView::zoom(double steps)
+{
+       zoom(steps, (width() - LabelMarginWidth) / 2);
+}
+
+void SigView::set_scale_offset(double scale, double offset)
+{
+       _scale = scale;
+       _offset = offset;
+       update_scroll();
+       _viewport->update();
+}
+
+void SigView::update_scroll()
+{
+       assert(_viewport);
+
+       const QSize areaSize = _viewport->size();
+
+       // Set the horizontal scroll bar
+       double length = 0, offset = 0;
+       const shared_ptr<SignalData> sig_data = _session.get_data();
+       if(sig_data) {
+               length = _data_length /
+                       (sig_data->get_samplerate() * _scale);
+               offset = _offset / _scale;
+       }
+
+       horizontalScrollBar()->setPageStep(areaSize.width());
+       horizontalScrollBar()->setRange(0,
+               max((int)(length - areaSize.width()), 0));
+       horizontalScrollBar()->setSliderPosition(offset);
+
+       // Set the vertical scrollbar
+       verticalScrollBar()->setPageStep(areaSize.height());
+       verticalScrollBar()->setRange(0,
+               _viewport->get_total_height() - areaSize.height());
+}
+
+void SigView::zoom(double steps, int offset)
+{
+       const double cursor_offset = _offset + _scale * offset;
+       _scale *= pow(3.0/2.0, -steps);
+       _scale = max(min(_scale, MaxScale), MinScale);
+       _offset = cursor_offset - _scale * offset;
+       _viewport->update();
+       update_scroll();
+}
+
+bool SigView::viewportEvent(QEvent *e)
+{
+       switch(e->type()) {
+       case QEvent::Paint:
+       case QEvent::MouseButtonPress:
+       case QEvent::MouseButtonRelease:
+       case QEvent::MouseButtonDblClick:
+       case QEvent::MouseMove:
+       case QEvent::Wheel:
+               return false;
+
+       default:
+               return QAbstractScrollArea::viewportEvent(e);
+       }
+}
+
+void SigView::resizeEvent(QResizeEvent *e)
+{
+       update_scroll();
+}
+
+void SigView::h_scroll_value_changed(int value)
+{
+       _offset = _scale * value;
+       _viewport->update();
+}
+
+void SigView::v_scroll_value_changed(int value)
+{
+       _v_offset = value;
+       _viewport->update();
+}
+
+void SigView::data_updated()
+{
+       // Get the new data length
+       _data_length = 0;
+       shared_ptr<LogicData> sig_data = _session.get_data();
+       if(sig_data) {
+               deque< shared_ptr<LogicDataSnapshot> > &snapshots =
+                       sig_data->get_snapshots();
+               BOOST_FOREACH(shared_ptr<LogicDataSnapshot> s, snapshots)
+                       if(s)
+                               _data_length = max(_data_length,
+                                       s->get_sample_count());
+       }
+
+       // Update the scroll bars
+       update_scroll();
+
+       // Repaint the view
+       _viewport->update();
+}
diff --git a/sigview.h b/sigview.h
new file mode 100644 (file)
index 0000000..cc7b78a
--- /dev/null
+++ b/sigview.h
@@ -0,0 +1,83 @@
+/*
+ * This file is part of the sigrok project.
+ *
+ * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef SIGVIEW_H
+#define SIGVIEW_H
+
+#include <stdint.h>
+
+#include <QAbstractScrollArea>
+
+class SigSession;
+class SigViewport;
+
+class SigView : public QAbstractScrollArea {
+       Q_OBJECT
+
+private:
+       static const double MaxScale;
+       static const double MinScale;
+
+       static const int LabelMarginWidth;
+       static const int RulerHeight;
+
+public:
+       explicit SigView(SigSession &session, QWidget *parent = 0);
+
+       double scale() const;
+       double offset() const;
+       int v_offset() const;
+
+       void zoom(double steps);
+
+       void set_scale_offset(double scale, double offset);
+
+private:
+       void update_scroll();
+
+       void zoom(double steps, int offset);
+
+private:
+       bool viewportEvent(QEvent *e);
+
+       void resizeEvent(QResizeEvent *e);
+
+private slots:
+       void h_scroll_value_changed(int value);
+       void v_scroll_value_changed(int value);
+
+       void data_updated();
+
+private:
+       SigSession &_session;
+
+       SigViewport *_viewport;
+
+       uint64_t _data_length;
+
+       double _scale;
+       double _offset;
+
+       int _v_offset;
+
+       friend class SigViewport;
+};
+
+#endif // SIGVIEW_H
index 1ec931296f85faa8e263131a701034cd9ff7657f..6bb0d00e2cf9983649032435a78420c3e361d32b 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "sigsession.h"
 #include "signal.h"
+#include "sigview.h"
 
 #include "extdef.h"
 
 using namespace boost;
 using namespace std;
 
-const double SigViewport::MaxScale = 1e9;
-const double SigViewport::MinScale = 1e-15;
-
 const int SigViewport::SignalHeight = 50;
-const int SigViewport::LabelMarginWidth = 70;
-const int SigViewport::RulerHeight = 30;
 
 const int SigViewport::MinorTickSubdivision = 4;
 const int SigViewport::ScaleUnits[3] = {1, 2, 5};
@@ -49,22 +45,24 @@ const QString SigViewport::SIPrefixes[9] =
        {"f", "p", "n", QChar(0x03BC), "m", "", "k", "M", "G"};
 const int SigViewport::FirstSIPrefixPower = -15;
 
-SigViewport::SigViewport(SigSession &session, QWidget *parent) :
-       QGLWidget(parent),
-        _session(session),
-       _scale(1e-6),
-       _offset(0)
+SigViewport::SigViewport(SigView &parent) :
+       QGLWidget(&parent),
+        _view(parent)
 {
-       connect(&_session, SIGNAL(data_updated()),
-               this, SLOT(data_updated()));
-
        setMouseTracking(true);
        setAutoFillBackground(false);
 }
 
-void SigViewport::zoom(double steps)
+int SigViewport::get_total_height() const
 {
-       zoom(steps, (width() - LabelMarginWidth) / 2);
+       int height = 0;
+       BOOST_FOREACH(const shared_ptr<Signal> s,
+               _view._session.get_signals()) {
+               assert(s);
+               height += SignalHeight;
+       }
+
+       return height;
 }
 
 void SigViewport::initializeGL()
@@ -81,7 +79,7 @@ void SigViewport::paintEvent(QPaintEvent *event)
        int offset;
 
        const vector< shared_ptr<Signal> > &sigs =
-               _session.get_signals();
+               _view._session.get_signals();
 
        // Prepare for OpenGL rendering
        makeCurrent();
@@ -95,16 +93,16 @@ void SigViewport::paintEvent(QPaintEvent *event)
 
        // Plot the signal
        glEnable(GL_SCISSOR_TEST);
-       glScissor(LabelMarginWidth, 0, width(), height());
-       offset = RulerHeight;
+       glScissor(SigView::LabelMarginWidth, 0, width(), height());
+       offset = SigView::RulerHeight - _view.v_offset();
        BOOST_FOREACH(const shared_ptr<Signal> s, sigs)
        {
                assert(s);
 
-               const QRect signal_rect(LabelMarginWidth, offset,
-                       width() - LabelMarginWidth, SignalHeight);
+               const QRect signal_rect(SigView::LabelMarginWidth, offset,
+                       width() - SigView::LabelMarginWidth, SignalHeight);
 
-               s->paint(*this, signal_rect, _scale, _offset);
+               s->paint(*this, signal_rect, _view.scale(), _view.offset());
 
                offset += SignalHeight;
        }
@@ -119,13 +117,13 @@ void SigViewport::paintEvent(QPaintEvent *event)
        painter.setRenderHint(QPainter::Antialiasing);
 
        // Paint the labels
-       offset = RulerHeight;
+       offset = SigView::RulerHeight - _view.v_offset();
        BOOST_FOREACH(const shared_ptr<Signal> s, sigs)
        {
                assert(s);
 
                const QRect label_rect(0, offset,
-                       LabelMarginWidth, SignalHeight);
+                       SigView::LabelMarginWidth, SignalHeight);
                s->paint_label(painter, label_rect);
 
                offset += SignalHeight;
@@ -137,17 +135,12 @@ void SigViewport::paintEvent(QPaintEvent *event)
        painter.end();
 }
 
-void SigViewport::data_updated()
-{
-       update();
-}
-
 void SigViewport::mousePressEvent(QMouseEvent *event)
 {
        assert(event);
 
        _mouse_down_point = event->pos();
-       _mouse_down_offset = _offset;
+       _mouse_down_offset = _view.offset();
 }
 
 void SigViewport::mouseMoveEvent(QMouseEvent *event)
@@ -156,8 +149,10 @@ void SigViewport::mouseMoveEvent(QMouseEvent *event)
 
        if(event->buttons() & Qt::LeftButton)
        {
-               _offset = _mouse_down_offset + (_mouse_down_point - event->pos()).x() * _scale;
-               update();
+               _view.set_scale_offset(_view.scale(),
+                       _mouse_down_offset +
+                       (_mouse_down_point - event->pos()).x() *
+                       _view.scale());
        }
 }
 
@@ -169,7 +164,8 @@ void SigViewport::mouseReleaseEvent(QMouseEvent *event)
 void SigViewport::wheelEvent(QWheelEvent *event)
 {
        assert(event);
-       zoom(event->delta() / 120, event->x() - LabelMarginWidth);
+       _view.zoom(event->delta() / 120, event->x() -
+               SigView::LabelMarginWidth);
 }
 
 void SigViewport::setup_viewport(int width, int height)
@@ -185,7 +181,7 @@ void SigViewport::paint_ruler(QPainter &p)
 {
        const double MinSpacing = 80;
 
-       const double min_period = _scale * MinSpacing;
+       const double min_period = _view.scale() * MinSpacing;
 
        const int order = (int)floorf(log10f(min_period));
        const double order_decimal = pow(10, order);
@@ -209,8 +205,10 @@ void SigViewport::paint_ruler(QPainter &p)
        p.setPen(Qt::black);
 
        const double minor_tick_period = tick_period / MinorTickSubdivision;
-       const double first_major_division = floor(_offset / tick_period);
-       const double first_minor_division = ceil(_offset / minor_tick_period);
+       const double first_major_division =
+               floor(_view.offset() / tick_period);
+       const double first_minor_division =
+               ceil(_view.offset() / minor_tick_period);
        const double t0 = first_major_division * tick_period;
 
        int division = (int)round(first_minor_division -
@@ -218,7 +216,8 @@ void SigViewport::paint_ruler(QPainter &p)
        while(1)
        {
                const double t = t0 + division * minor_tick_period;
-               const double x = (t - _offset) / _scale + LabelMarginWidth;
+               const double x = (t - _view.offset()) / _view.scale() +
+                       SigView::LabelMarginWidth;
 
                if(x >= width())
                        break;
@@ -231,23 +230,16 @@ void SigViewport::paint_ruler(QPainter &p)
                        ts << (t / order_decimal) << SIPrefixes[prefix] << "s";
                        p.drawText(x, 0, 0, text_height, Qt::AlignCenter | Qt::AlignTop |
                                Qt::TextDontClip, s);
-                       p.drawLine(x, text_height, x, RulerHeight);
+                       p.drawLine(x, text_height, x, SigView::RulerHeight);
                }
                else
                {
                        // Draw a minor tick
-                       p.drawLine(x, (text_height + RulerHeight) / 2, x, RulerHeight);
+                       p.drawLine(x,
+                               (text_height + SigView::RulerHeight) / 2, x,
+                               SigView::RulerHeight);
                }
 
                division++;
        }
 }
-
-void SigViewport::zoom(double steps, int offset)
-{
-       const double cursor_offset = _offset + _scale * offset;
-       _scale *= pow(3.0/2.0, -steps);
-       _scale = max(min(_scale, MaxScale), MinScale);
-       _offset = cursor_offset - _scale * offset;
-       update();
-}
index 0846ca51a6f78209fc8ebec326db7882c8a4cc06..12f6b7c555f25644e2a6e8e15409601253652a4f 100644 (file)
 class QPainter;
 class QPaintEvent;
 class SigSession;
+class SigView;
 
 class SigViewport : public QGLWidget
 {
        Q_OBJECT
 
 private:
-       static const double MaxScale;
-       static const double MinScale;
-
        static const int SignalHeight;
-       static const int LabelMarginWidth;
-       static const int RulerHeight;
 
        static const int MinorTickSubdivision;
        static const int ScaleUnits[3];
@@ -47,12 +43,11 @@ private:
        static const int FirstSIPrefixPower;
 
 public:
-       explicit SigViewport(SigSession &session, QWidget *parent = 0);
+       explicit SigViewport(SigView &parent);
 
-       void zoom(double steps);
+       int get_total_height() const;
 
 protected:
-
        void initializeGL();
 
        void resizeGL(int width, int height);
@@ -70,16 +65,8 @@ private:
 
        void paint_ruler(QPainter &p);
 
-       void zoom(double steps, int offset);
-
-private slots:
-       void data_updated();
-
 private:
-       SigSession &_session;
-
-       double _scale;
-       double _offset;
+       SigView &_view;
 
        QPoint _mouse_down_point;
        double _mouse_down_offset;