From: Joel Holdsworth Date: Wed, 5 Sep 2012 11:19:24 +0000 (+0100) Subject: Add initial scrolling support with a QAbstractScrollArea X-Git-Tag: pulseview-0.1.0~311 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=adb4b10cf99ca7c257b2f749bff90b67286d9992;p=pulseview.git Add initial scrolling support with a QAbstractScrollArea --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 5ae27aab..5fc8b6a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 ) diff --git a/mainwindow.cpp b/mainwindow.cpp index 865d6e2a..54cc39ec 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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); } diff --git a/mainwindow.h b/mainwindow.h index 811ea15e..6a1e52ca 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -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; diff --git a/sigsession.cpp b/sigsession.cpp index 16b84f14..47d9585b 100644 --- a/sigsession.cpp +++ b/sigsession.cpp @@ -97,6 +97,11 @@ vector< shared_ptr >& SigSession::get_signals() return _signals; } +boost::shared_ptr SigSession::get_data() +{ + return _logic_data; +} + void SigSession::data_feed_in(const struct sr_dev_inst *sdi, struct sr_datafeed_packet *packet) { diff --git a/sigsession.h b/sigsession.h index bf262bbf..f6b1d8e4 100644 --- a/sigsession.h +++ b/sigsession.h @@ -53,6 +53,8 @@ public: std::vector< boost::shared_ptr >& get_signals(); + boost::shared_ptr 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 index 00000000..4f2436cc --- /dev/null +++ b/sigview.cpp @@ -0,0 +1,179 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 +#include + +#include + +#include +#include + +#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 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 sig_data = _session.get_data(); + if(sig_data) { + deque< shared_ptr > &snapshots = + sig_data->get_snapshots(); + BOOST_FOREACH(shared_ptr 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 index 00000000..cc7b78af --- /dev/null +++ b/sigview.h @@ -0,0 +1,83 @@ +/* + * This file is part of the sigrok project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * 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 + +#include + +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 diff --git a/sigviewport.cpp b/sigviewport.cpp index 1ec93129..6bb0d00e 100644 --- a/sigviewport.cpp +++ b/sigviewport.cpp @@ -22,6 +22,7 @@ #include "sigsession.h" #include "signal.h" +#include "sigview.h" #include "extdef.h" @@ -35,12 +36,7 @@ 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 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 > &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 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 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(); -} diff --git a/sigviewport.h b/sigviewport.h index 0846ca51..12f6b7c5 100644 --- a/sigviewport.h +++ b/sigviewport.h @@ -27,18 +27,14 @@ 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;