]> sigrok.org Git - sigrok-qt.git/blob - channelform.cpp
.gitignore: Add missing entries.
[sigrok-qt.git] / channelform.cpp
1 /*
2  * This file is part of the sigrok project.
3  *
4  * Copyright (C) 2010 Uwe Hermann <uwe@hermann-uwe.de>
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 <QDebug>
22 #include "channelform.h"
23 #include "ui_channelform.h"
24 #include <stdint.h>
25
26 extern uint8_t *sample_buffer;
27
28 /* WHEEL_DELTA was introduced in Qt 4.6, earlier versions don't have it. */
29 #ifndef WHEEL_DELTA
30 #define WHEEL_DELTA 120
31 #endif
32
33 static QColor channelColors[] = {
34         QColor(0x00, 0x00, 0x00), /* Black */
35         QColor(0x96, 0x4B, 0x00), /* Brown */
36         QColor(0xFF, 0x00, 0x00), /* Red */
37         QColor(0xFF, 0xA5, 0x00), /* Orange */
38         QColor(0xFF, 0xFF, 0x00), /* Yellow */
39         QColor(0x9A, 0xCD, 0x32), /* Green */
40         QColor(0x64, 0x95, 0xED), /* Blue */
41         QColor(0xEE, 0x82, 0xEE), /* Violet */
42         QColor(0xA0, 0xA0, 0xA0), /* Gray */
43         QColor(0xFF, 0xFF, 0xFF), /* White */
44 };
45
46 /* TODO: Should move elsewhere. */
47 static int getbit(uint8_t *buf, int numbyte, int chan)
48 {
49         if (chan < 8) {
50                 return ((buf[numbyte] & (1 << chan))) >> chan;
51         } else if (chan >= 8 && chan < 16) {
52                 return ((buf[numbyte + 1] & (1 << (chan - 8)))) >> (chan - 8);
53         } else {
54                 /* Error. Currently only 8bit and 16bit LAs are supported. */
55                 return -1;
56         }
57 }
58
59 ChannelForm::ChannelForm(QWidget *parent) :
60         QWidget(parent),
61         m_ui(new Ui::ChannelForm)
62 {
63         m_ui->setupUi(this);
64
65         channelNumber = -1;
66         numSamples = 0;
67         sampleStart = 0;
68         sampleEnd = 0;
69         scaleFactor = 2.0;
70         scrollBarValue = 0;
71         painterPath = new QPainterPath();
72 }
73
74 ChannelForm::~ChannelForm()
75 {
76         delete m_ui;
77 }
78
79 void ChannelForm::changeEvent(QEvent *e)
80 {
81         QWidget::changeEvent(e);
82
83         switch (e->type()) {
84         case QEvent::LanguageChange:
85                 m_ui->retranslateUi(this);
86                 break;
87         default:
88                 break;
89         }
90 }
91
92 void ChannelForm::generatePainterPath(void)
93 {
94         int scaleFactor;
95         double old_x, current_x;
96         int current_y, oldval, newval, x_change_visible;
97         int low = m_ui->renderAreaWidget->height() - 2, high = 20;
98         int ch = getChannelNumber();
99         uint64_t ss, se;
100
101         if (sample_buffer == NULL)
102                 return;
103
104         scaleFactor = getScaleFactor();
105
106         delete painterPath;
107         painterPath = new QPainterPath();
108
109         old_x = current_x = (-getScrollBarValue() % stepSize);
110
111         ss = (getScrollBarValue() + current_x) * scaleFactor / stepSize;
112         se = ss + (getScaleFactor() * width()) * stepSize;
113         if (se > getNumSamples()) /* Do this _after_ calculating 'step'! */
114                 se = getNumSamples();
115
116         oldval = getbit(sample_buffer, ss, ch);
117         current_y = (oldval) ? high : low;
118         painterPath->moveTo(current_x, current_y);
119
120         // qDebug() << "generatePainterPath() for ch" << getChannelNumber()
121         //       << "(" << ss << " - " << se << ")";
122
123         for (uint64_t i = ss; i < se; i += scaleFactor) {
124                 /* Process the samples shown in this step. */
125                 for (uint64_t j = 0; (j < scaleFactor) && (i + j < se); j++) {
126                         newval = getbit(sample_buffer, i + j, ch);
127                         x_change_visible = current_x > old_x;
128                         if (oldval != newval && x_change_visible) {
129                                 painterPath->lineTo(current_x, current_y);
130                                 current_y = (newval) ? high : low;
131                                 painterPath->lineTo(current_x, current_y);
132                                 old_x = current_x;
133                                 oldval = newval;
134                         }
135                         current_x += (double)stepSize / (double)scaleFactor;
136                 }
137         }
138         current_x += stepSize;
139         painterPath->lineTo(current_x, current_y);
140
141         /* Force a redraw. */
142         update();
143 }
144
145 void ChannelForm::resizeEvent(QResizeEvent *event)
146 {
147         /* Avoid compiler warnings. */
148         (void)event;
149
150         stepSize = width() / 100;
151
152         if (stepSize <= 1)
153                 stepSize = width() / 50;
154
155         if (stepSize <= 1)
156                 stepSize = width() / 20;
157
158         /* Quick hack to force a redraw upon resize. */
159         generatePainterPath();
160 }
161
162 void ChannelForm::paintEvent(QPaintEvent *event)
163 {
164         int tickStart;
165         // qDebug() << "Paint event on ch" << getChannelNumber();
166
167         // QPainter p(m_ui->renderAreaWidget);
168         QPainter p(this);
169
170         /* Avoid compiler warnings. */
171         (void)event;
172
173         if (sample_buffer == NULL)
174                 return;
175
176         QPen penChannel(getChannelColor(), 1, Qt::SolidLine, Qt::SquareCap,
177                         Qt::BevelJoin);
178         p.setPen(penChannel);
179         p.fillRect(0, 0, this->width(), 5, getChannelColor());
180         p.fillRect(0, 5, 5, this->height(), getChannelColor());
181         p.translate(0, 5);
182
183         QPen penGraph(QColor(0, 0, 0), 1, Qt::SolidLine, Qt::SquareCap,
184                  Qt::BevelJoin);
185         p.setPen(penGraph);
186
187         // p.fillRect(0, 0, this->width(), this->height(), QColor(Qt::gray));
188         p.setRenderHint(QPainter::Antialiasing, false);
189
190         // p.scale(getZoomFactor(), 1.0);
191         p.drawPath(*painterPath);
192
193         if (stepSize > 0) {
194                 if (stepSize > 1) {
195                         /* Draw minor ticks. */
196                         tickStart = -getScrollBarValue() % stepSize;
197                         for (int i = tickStart; i < width(); i += stepSize)
198                                 p.drawLine(i, 12, i, 15);
199                 }
200
201                 /* Draw major ticks every 10 minor tick. */
202                 tickStart = -getScrollBarValue() % (stepSize*10);
203                 for (int i = tickStart; i < width(); i += stepSize * 10) {
204                         p.drawText(i, 10, QString::number((i + getScrollBarValue()) / stepSize * getScaleFactor()));
205                         p.drawLine(i, 11, i, 17);
206                 }
207         }
208 }
209
210 void ChannelForm::wheelEvent(QWheelEvent *event)
211 {
212         float scaleFactorNew;
213
214         if ((event->delta() / WHEEL_DELTA) == 1)
215                 scaleFactorNew = getScaleFactor() * 2;
216         else if ((event->delta() / WHEEL_DELTA) == -1)
217                 scaleFactorNew = getScaleFactor() / 2;
218         else
219                 scaleFactorNew = getScaleFactor();
220
221         if (scaleFactorNew < 1)
222                 scaleFactorNew = 1;
223
224         setScaleFactor(scaleFactorNew);
225
226         /* TODO: Config option to scroll (instead of scale) via the wheel. */
227 }
228
229 void ChannelForm::setChannelColor(QColor color)
230 {
231         channelColor = color;
232
233         /* Set color of the channel name QLineEdit. */
234         QLineEdit *l = m_ui->channelLineEdit;
235         QPalette p = QPalette(QApplication::palette());
236         p.setColor(QPalette::Base, channelColor);
237         l->setPalette(p);
238 }
239
240 QColor ChannelForm::getChannelColor(void)
241 {
242         return channelColor;
243 }
244
245 void ChannelForm::setChannelNumber(int c)
246 {
247         if (channelNumber < 0) {
248                 /* Set a default color for this channel. */
249                 /* FIXME: Channel color should be dependent on the selected LA. */
250                 setChannelColor(channelColors[c % (ARRAY_SIZE(channelColors))]);
251         }
252         channelNumber = c;
253
254         /* Set title of the channel name QLineEdit. */
255         QLineEdit *l = m_ui->channelLineEdit;
256         l->setText(QString(tr("Channel %1")).arg(channelNumber));
257 }
258
259 int ChannelForm::getChannelNumber(void)
260 {
261         return channelNumber;
262 }
263
264 void ChannelForm::setNumSamples(uint64_t s)
265 {
266         numSamples = s;
267 }
268
269 uint64_t ChannelForm::getNumSamples(void)
270 {
271         return numSamples;
272 }
273
274 uint64_t ChannelForm::getNumSamplesVisible(void)
275 {
276         return (width() / stepSize) * scaleFactor;
277 }
278
279 int ChannelForm::getStepSize(void)
280 {
281         return stepSize;
282 }
283
284 void ChannelForm::setSampleStart(uint64_t s)
285 {
286         sampleStart = s;
287
288         emit(sampleStartChanged(sampleStart));
289         emit(sampleStartChanged(QString::number(sampleStart)));
290 }
291
292 uint64_t ChannelForm::getSampleStart(void)
293 {
294         return sampleStart;
295 }
296
297 void ChannelForm::setSampleEnd(uint64_t e)
298 {
299         sampleEnd = e;
300
301         emit(sampleEndChanged(sampleEnd));
302         emit(sampleEndChanged(QString::number(sampleEnd)));
303 }
304
305 uint64_t ChannelForm::getSampleEnd(void)
306 {
307         return sampleEnd;
308 }
309
310 void ChannelForm::setScaleFactor(float z)
311 {
312         scaleFactor = z;
313
314         emit(scaleFactorChanged(scaleFactor));
315         emit(scaleFactorChanged(QString::number(scaleFactor)));
316 }
317
318 float ChannelForm::getScaleFactor(void)
319 {
320         return scaleFactor;
321 }
322
323 int ChannelForm::getScrollBarValue(void)
324 {
325         return scrollBarValue;
326 }
327
328 void ChannelForm::setScrollBarValue(int value)
329 {
330         if (scrollBarValue == value)
331                 return;
332
333         // qDebug("Re-generating ch%d (value = %d)", getChannelNumber(), value);
334
335         scrollBarValue = value;
336         generatePainterPath();
337 }