4f2436cc5f152b08831841efc9ada481f7da48dd
[pulseview.git] / sigview.cpp
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2012 Joel Holdsworth <joel@airwebreathe.org.uk>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
19  */
20
21 #include <assert.h>
22 #include <math.h>
23
24 #include <boost/foreach.hpp>
25
26 #include <QEvent>
27 #include <QScrollBar>
28
29 #include "sigview.h"
30
31 #include "logicdata.h"
32 #include "logicdatasnapshot.h"
33 #include "sigsession.h"
34 #include "sigviewport.h"
35
36 using namespace boost;
37 using namespace std;
38
39 const double SigView::MaxScale = 1e9;
40 const double SigView::MinScale = 1e-15;
41
42 const int SigView::LabelMarginWidth = 70;
43 const int SigView::RulerHeight = 30;
44
45 SigView::SigView(SigSession &session, QWidget *parent) :
46         QAbstractScrollArea(parent),
47         _session(session),
48         _viewport(new SigViewport(*this)),
49         _data_length(0),
50         _scale(1e-6),
51         _offset(0),
52         _v_offset(0)
53 {
54         connect(horizontalScrollBar(), SIGNAL(valueChanged(int)),
55                 this, SLOT(h_scroll_value_changed(int)));
56         connect(verticalScrollBar(), SIGNAL(valueChanged(int)),
57                 this, SLOT(v_scroll_value_changed(int)));
58         connect(&_session, SIGNAL(data_updated()),
59                 this, SLOT(data_updated()));
60         setViewport(_viewport);
61 }
62
63 double SigView::scale() const
64 {
65         return _scale;
66 }
67
68 double SigView::offset() const
69 {
70         return _offset;
71 }
72
73 int SigView::v_offset() const
74 {
75         return _v_offset;
76 }
77
78 void SigView::zoom(double steps)
79 {
80         zoom(steps, (width() - LabelMarginWidth) / 2);
81 }
82
83 void SigView::set_scale_offset(double scale, double offset)
84 {
85         _scale = scale;
86         _offset = offset;
87         update_scroll();
88         _viewport->update();
89 }
90
91 void SigView::update_scroll()
92 {
93         assert(_viewport);
94
95         const QSize areaSize = _viewport->size();
96
97         // Set the horizontal scroll bar
98         double length = 0, offset = 0;
99         const shared_ptr<SignalData> sig_data = _session.get_data();
100         if(sig_data) {
101                 length = _data_length /
102                         (sig_data->get_samplerate() * _scale);
103                 offset = _offset / _scale;
104         }
105
106         horizontalScrollBar()->setPageStep(areaSize.width());
107         horizontalScrollBar()->setRange(0,
108                 max((int)(length - areaSize.width()), 0));
109         horizontalScrollBar()->setSliderPosition(offset);
110
111         // Set the vertical scrollbar
112         verticalScrollBar()->setPageStep(areaSize.height());
113         verticalScrollBar()->setRange(0,
114                 _viewport->get_total_height() - areaSize.height());
115 }
116
117 void SigView::zoom(double steps, int offset)
118 {
119         const double cursor_offset = _offset + _scale * offset;
120         _scale *= pow(3.0/2.0, -steps);
121         _scale = max(min(_scale, MaxScale), MinScale);
122         _offset = cursor_offset - _scale * offset;
123         _viewport->update();
124         update_scroll();
125 }
126
127 bool SigView::viewportEvent(QEvent *e)
128 {
129         switch(e->type()) {
130         case QEvent::Paint:
131         case QEvent::MouseButtonPress:
132         case QEvent::MouseButtonRelease:
133         case QEvent::MouseButtonDblClick:
134         case QEvent::MouseMove:
135         case QEvent::Wheel:
136                 return false;
137
138         default:
139                 return QAbstractScrollArea::viewportEvent(e);
140         }
141 }
142
143 void SigView::resizeEvent(QResizeEvent *e)
144 {
145         update_scroll();
146 }
147
148 void SigView::h_scroll_value_changed(int value)
149 {
150         _offset = _scale * value;
151         _viewport->update();
152 }
153
154 void SigView::v_scroll_value_changed(int value)
155 {
156         _v_offset = value;
157         _viewport->update();
158 }
159
160 void SigView::data_updated()
161 {
162         // Get the new data length
163         _data_length = 0;
164         shared_ptr<LogicData> sig_data = _session.get_data();
165         if(sig_data) {
166                 deque< shared_ptr<LogicDataSnapshot> > &snapshots =
167                         sig_data->get_snapshots();
168                 BOOST_FOREACH(shared_ptr<LogicDataSnapshot> s, snapshots)
169                         if(s)
170                                 _data_length = max(_data_length,
171                                         s->get_sample_count());
172         }
173
174         // Update the scroll bars
175         update_scroll();
176
177         // Repaint the view
178         _viewport->update();
179 }