]> sigrok.org Git - pulseview.git/blame - pv/view/decodetrace.cpp
Trace: Introduce hover_point_changed()
[pulseview.git] / pv / view / decodetrace.cpp
CommitLineData
55d3603d
JH
1/*
2 * This file is part of the PulseView 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
21extern "C" {
22#include <libsigrokdecode/libsigrokdecode.h>
23}
24
06bb4e6a
JH
25#include <extdef.h>
26
a855d71e 27#include <boost/functional/hash.hpp>
b213ef09 28
c51482b3 29#include <QAction>
d7c0ca4a 30#include <QApplication>
4e5a4405
JH
31#include <QComboBox>
32#include <QFormLayout>
33#include <QLabel>
b213ef09 34#include <QMenu>
ce94e4fd 35#include <QPushButton>
c51482b3 36
b9329558 37#include "decodetrace.h"
55d3603d 38
06bb4e6a 39#include <pv/sigsession.h>
6e89374a 40#include <pv/data/decoderstack.h>
7491a29f 41#include <pv/data/decode/decoder.h>
5dfeb70f
JH
42#include <pv/data/logic.h>
43#include <pv/data/logicsnapshot.h>
06e810f2 44#include <pv/data/decode/annotation.h>
4e5a4405 45#include <pv/view/logicsignal.h>
e0fc5810 46#include <pv/view/view.h>
204bae45 47#include <pv/widgets/decodergroupbox.h>
ce94e4fd 48#include <pv/widgets/decodermenu.h>
119aff65 49
f9abf97e 50using std::dynamic_pointer_cast;
819f4c25 51using std::list;
7f8517f6 52using std::make_pair;
819f4c25
JH
53using std::max;
54using std::map;
55using std::min;
7f8517f6 56using std::pair;
f9abf97e 57using std::shared_ptr;
819f4c25 58using std::vector;
55d3603d
JH
59
60namespace pv {
61namespace view {
62
b9329558 63const QColor DecodeTrace::DecodeColours[4] = {
06bb4e6a
JH
64 QColor(0xEF, 0x29, 0x29), // Red
65 QColor(0xFC, 0xE9, 0x4F), // Yellow
66 QColor(0x8A, 0xE2, 0x34), // Green
67 QColor(0x72, 0x9F, 0xCF) // Blue
68};
69
b9329558 70const QColor DecodeTrace::ErrorBgColour = QColor(0xEF, 0x29, 0x29);
5dfeb70f 71const QColor DecodeTrace::NoDecodeColour = QColor(0x88, 0x8A, 0x85);
ad50ac1a 72
88908838 73const int DecodeTrace::ArrowSize = 4;
06e810f2
JH
74const double DecodeTrace::EndCapWidth = 5;
75const int DecodeTrace::DrawPadding = 100;
76
287d607f
JH
77const QColor DecodeTrace::Colours[16] = {
78 QColor(0xEF, 0x29, 0x29),
79 QColor(0xF6, 0x6A, 0x32),
80 QColor(0xFC, 0xAE, 0x3E),
81 QColor(0xFB, 0xCA, 0x47),
82 QColor(0xFC, 0xE9, 0x4F),
83 QColor(0xCD, 0xF0, 0x40),
84 QColor(0x8A, 0xE2, 0x34),
85 QColor(0x4E, 0xDC, 0x44),
86 QColor(0x55, 0xD7, 0x95),
87 QColor(0x64, 0xD1, 0xD2),
88 QColor(0x72, 0x9F, 0xCF),
89 QColor(0xD4, 0x76, 0xC4),
90 QColor(0x9D, 0x79, 0xB9),
91 QColor(0xAD, 0x7F, 0xA8),
92 QColor(0xC2, 0x62, 0x9B),
93 QColor(0xD7, 0x47, 0x6F)
94};
95
96const QColor DecodeTrace::OutlineColours[16] = {
97 QColor(0x77, 0x14, 0x14),
98 QColor(0x7B, 0x35, 0x19),
99 QColor(0x7E, 0x57, 0x1F),
100 QColor(0x7D, 0x65, 0x23),
101 QColor(0x7E, 0x74, 0x27),
102 QColor(0x66, 0x78, 0x20),
103 QColor(0x45, 0x71, 0x1A),
104 QColor(0x27, 0x6E, 0x22),
105 QColor(0x2A, 0x6B, 0x4A),
106 QColor(0x32, 0x68, 0x69),
107 QColor(0x39, 0x4F, 0x67),
108 QColor(0x6A, 0x3B, 0x62),
109 QColor(0x4E, 0x3C, 0x5C),
110 QColor(0x56, 0x3F, 0x54),
111 QColor(0x61, 0x31, 0x4D),
112 QColor(0x6B, 0x23, 0x37)
06e810f2
JH
113};
114
b9329558 115DecodeTrace::DecodeTrace(pv::SigSession &session,
f9abf97e 116 std::shared_ptr<pv::data::DecoderStack> decoder_stack, int index) :
83c23cc9 117 Trace(QString::fromUtf8(
27e8df22 118 decoder_stack->stack().front()->decoder()->name)),
83c23cc9 119 _session(session),
613d097c 120 _decoder_stack(decoder_stack),
ef40ad83
SA
121 _text_height(0),
122 _row_height(0),
dd048a7e
JH
123 _delete_mapper(this),
124 _show_hide_mapper(this)
55d3603d 125{
6e89374a 126 assert(_decoder_stack);
e0fc5810 127
06bb4e6a 128 _colour = DecodeColours[index % countof(DecodeColours)];
9cef9567 129
6e89374a 130 connect(_decoder_stack.get(), SIGNAL(new_decode_data()),
9cef9567 131 this, SLOT(on_new_decode_data()));
613d097c
JH
132 connect(&_delete_mapper, SIGNAL(mapped(int)),
133 this, SLOT(on_delete_decoder(int)));
dd048a7e
JH
134 connect(&_show_hide_mapper, SIGNAL(mapped(int)),
135 this, SLOT(on_show_hide_decoder(int)));
55d3603d
JH
136}
137
b9329558 138bool DecodeTrace::enabled() const
55d3603d
JH
139{
140 return true;
141}
142
f9abf97e 143const std::shared_ptr<pv::data::DecoderStack>& DecodeTrace::decoder() const
b6b267bb 144{
6e89374a 145 return _decoder_stack;
b6b267bb
JH
146}
147
b9329558 148void DecodeTrace::set_view(pv::view::View *view)
e0fc5810
JH
149{
150 assert(view);
151 Trace::set_view(view);
152}
153
b9329558 154void DecodeTrace::paint_back(QPainter &p, int left, int right)
fe08b6e8 155{
5dfeb70f 156 Trace::paint_back(p, left, right);
fe08b6e8
JH
157 paint_axis(p, get_y(), left, right);
158}
159
b9329558 160void DecodeTrace::paint_mid(QPainter &p, int left, int right)
55d3603d 161{
f9101a91 162 using namespace pv::data::decode;
9472f447 163
d7c0ca4a 164 QFontMetrics m(QApplication::font());
ef40ad83
SA
165 _text_height = m.boundingRect(QRect(), 0, "Tg").height();
166 _row_height = (_text_height * 6) / 4;
167 const int annotation_height = (_text_height * 5) / 4;
5dfeb70f
JH
168
169 assert(_decoder_stack);
170 const QString err = _decoder_stack->error_message();
171 if (!err.isEmpty())
172 {
7f8517f6 173 draw_unresolved_period(p, annotation_height, left, right);
5b8b1e47 174 draw_error(p, err, left, right);
5dfeb70f
JH
175 return;
176 }
177
f9101a91 178 // Iterate through the rows
5dfeb70f 179 assert(_view);
f9101a91 180 int y = get_y();
7f8517f6 181 pair<uint64_t, uint64_t> sample_range = get_sample_range(left, right);
5dfeb70f 182
6e89374a 183 assert(_decoder_stack);
dd048a7e 184 const vector<Row> rows(_decoder_stack->get_visible_rows());
7f8517f6
SA
185
186 _cur_row_headings.clear();
bf51365c 187 for (size_t i = 0; i < rows.size(); i++)
92421299 188 {
bf51365c 189 const Row &row = rows[i];
287d607f
JH
190
191 size_t base_colour = 0x13579BDF;
192 boost::hash_combine(base_colour, this);
193 boost::hash_combine(base_colour, row.decoder());
194 boost::hash_combine(base_colour, row.row());
195 base_colour >>= 16;
196
f9101a91
JH
197 vector<Annotation> annotations;
198 _decoder_stack->get_annotation_subset(annotations, row,
7f8517f6 199 sample_range.first, sample_range.second);
f9101a91 200 if (!annotations.empty()) {
d9aecf1f 201 for (const Annotation &a : annotations)
f9101a91 202 draw_annotation(a, p, get_text_colour(),
7f8517f6 203 annotation_height, left, right, y,
287d607f 204 base_colour);
ef40ad83 205 y += _row_height;
88908838
JH
206
207 _cur_row_headings.push_back(row.title());
f9101a91 208 }
7e674e43 209 }
5dfeb70f 210
f9101a91 211 // Draw the hatching
7f8517f6 212 draw_unresolved_period(p, annotation_height, left, right);
55d3603d
JH
213}
214
88908838
JH
215void DecodeTrace::paint_fore(QPainter &p, int left, int right)
216{
217 using namespace pv::data::decode;
218
219 (void)right;
220
ef40ad83 221 assert(_row_height);
88908838
JH
222
223 for (size_t i = 0; i < _cur_row_headings.size(); i++)
224 {
ef40ad83 225 const int y = i * _row_height + get_y();
88908838
JH
226
227 p.setPen(QPen(Qt::NoPen));
228 p.setBrush(QApplication::palette().brush(QPalette::WindowText));
229
230 if (i != 0)
231 {
232 const QPointF points[] = {
233 QPointF(left, y - ArrowSize),
234 QPointF(left + ArrowSize, y),
235 QPointF(left, y + ArrowSize)
236 };
237 p.drawPolygon(points, countof(points));
238 }
239
ef40ad83
SA
240 const QRect r(left + ArrowSize * 2, y - _row_height / 2,
241 right - left, _row_height);
88908838
JH
242 const QString h(_cur_row_headings[i]);
243 const int f = Qt::AlignLeft | Qt::AlignVCenter |
244 Qt::TextDontClip;
245
246 // Draw the outline
247 p.setPen(QApplication::palette().color(QPalette::Base));
248 for (int dx = -1; dx <= 1; dx++)
249 for (int dy = -1; dy <= 1; dy++)
250 if (dx != 0 && dy != 0)
251 p.drawText(r.translated(dx, dy), f, h);
252
253 // Draw the text
254 p.setPen(QApplication::palette().color(QPalette::WindowText));
255 p.drawText(r, f, h);
256 }
257}
258
b9329558 259void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
4e5a4405 260{
613d097c
JH
261 using pv::data::decode::Decoder;
262
4e5a4405
JH
263 assert(form);
264 assert(parent);
6e89374a 265 assert(_decoder_stack);
4e5a4405 266
7491a29f 267 // Add the standard options
4e5a4405
JH
268 Trace::populate_popup_form(parent, form);
269
7491a29f
JH
270 // Add the decoder options
271 _bindings.clear();
6ac6242b 272 _channel_selectors.clear();
dd048a7e 273 _decoder_forms.clear();
4e5a4405 274
613d097c 275 const list< shared_ptr<Decoder> >& stack = _decoder_stack->stack();
4e5a4405 276
5069084a
JH
277 if (stack.empty())
278 {
279 QLabel *const l = new QLabel(
280 tr("<p><i>No decoders in the stack</i></p>"));
281 l->setAlignment(Qt::AlignCenter);
282 form->addRow(l);
283 }
284 else
285 {
f46e495e 286 auto iter = stack.cbegin();
5069084a
JH
287 for (int i = 0; i < (int)stack.size(); i++, iter++) {
288 shared_ptr<Decoder> dec(*iter);
289 create_decoder_form(i, dec, parent, form);
290 }
291
292 form->addRow(new QLabel(
8bd26d8b 293 tr("<i>* Required channels</i>"), parent));
5069084a 294 }
4e5a4405 295
ce94e4fd 296 // Add stacking button
ce94e4fd
JH
297 pv::widgets::DecoderMenu *const decoder_menu =
298 new pv::widgets::DecoderMenu(parent);
7491a29f
JH
299 connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
300 this, SLOT(on_stack_decoder(srd_decoder*)));
301
302 QPushButton *const stack_button =
303 new QPushButton(tr("Stack Decoder"), parent);
ce94e4fd
JH
304 stack_button->setMenu(decoder_menu);
305
306 QHBoxLayout *stack_button_box = new QHBoxLayout;
307 stack_button_box->addWidget(stack_button, 0, Qt::AlignRight);
308 form->addRow(stack_button_box);
4e5a4405
JH
309}
310
b9329558 311QMenu* DecodeTrace::create_context_menu(QWidget *parent)
c51482b3
JH
312{
313 QMenu *const menu = Trace::create_context_menu(parent);
314
315 menu->addSeparator();
316
317 QAction *const del = new QAction(tr("Delete"), this);
a2d21018 318 del->setShortcuts(QKeySequence::Delete);
c51482b3
JH
319 connect(del, SIGNAL(triggered()), this, SLOT(on_delete()));
320 menu->addAction(del);
321
322 return menu;
323}
324
287d607f 325void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a,
7f8517f6 326 QPainter &p, QColor text_color, int h, int left, int right, int y,
287d607f 327 size_t base_colour) const
06e810f2 328{
7f8517f6
SA
329 const double samples_per_pixel = get_samples_per_pixel();
330 const double pixels_offset = get_pixels_offset();
331
06e810f2
JH
332 const double start = a.start_sample() / samples_per_pixel -
333 pixels_offset;
334 const double end = a.end_sample() / samples_per_pixel -
335 pixels_offset;
287d607f
JH
336
337 const size_t colour = (base_colour + a.format()) % countof(Colours);
338 const QColor &fill = Colours[colour];
339 const QColor &outline = OutlineColours[colour];
06e810f2
JH
340
341 if (start > right + DrawPadding || end < left - DrawPadding)
342 return;
343
344 if (a.start_sample() == a.end_sample())
345 draw_instant(a, p, fill, outline, text_color, h,
346 start, y);
347 else
348 draw_range(a, p, fill, outline, text_color, h,
349 start, end, y);
350}
351
352void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p,
353 QColor fill, QColor outline, QColor text_color, int h, double x, int y) const
354{
355 const QString text = a.annotations().empty() ?
356 QString() : a.annotations().back();
ea86bc4d 357 const double w = min((double)p.boundingRect(QRectF(), 0, text).width(),
06e810f2
JH
358 0.0) + h;
359 const QRectF rect(x - w / 2, y - h / 2, w, h);
360
361 p.setPen(outline);
362 p.setBrush(fill);
363 p.drawRoundedRect(rect, h / 2, h / 2);
364
365 p.setPen(text_color);
366 p.drawText(rect, Qt::AlignCenter | Qt::AlignVCenter, text);
367}
368
369void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p,
370 QColor fill, QColor outline, QColor text_color, int h, double start,
371 double end, int y) const
372{
373 const double top = y + .5 - h / 2;
374 const double bottom = y + .5 + h / 2;
375 const vector<QString> annotations = a.annotations();
376
377 p.setPen(outline);
378 p.setBrush(fill);
379
380 // If the two ends are within 1 pixel, draw a vertical line
381 if (start + 1.0 > end)
382 {
383 p.drawLine(QPointF(start, top), QPointF(start, bottom));
384 return;
385 }
386
387 const double cap_width = min((end - start) / 4, EndCapWidth);
388
389 QPointF pts[] = {
390 QPointF(start, y + .5f),
391 QPointF(start + cap_width, top),
392 QPointF(end - cap_width, top),
393 QPointF(end, y + .5f),
394 QPointF(end - cap_width, bottom),
395 QPointF(start + cap_width, bottom)
396 };
397
398 p.drawConvexPolygon(pts, countof(pts));
399
400 if (annotations.empty())
401 return;
402
403 QRectF rect(start + cap_width, y - h / 2,
404 end - start - cap_width * 2, h);
0f290e9b
JH
405 if (rect.width() <= 4)
406 return;
407
06e810f2
JH
408 p.setPen(text_color);
409
410 // Try to find an annotation that will fit
411 QString best_annotation;
412 int best_width = 0;
413
d9aecf1f 414 for (const QString &a : annotations) {
06e810f2
JH
415 const int w = p.boundingRect(QRectF(), 0, a).width();
416 if (w <= rect.width() && w > best_width)
417 best_annotation = a, best_width = w;
418 }
419
420 if (best_annotation.isEmpty())
421 best_annotation = annotations.back();
422
423 // If not ellide the last in the list
424 p.drawText(rect, Qt::AlignCenter, p.fontMetrics().elidedText(
425 best_annotation, Qt::ElideRight, rect.width()));
426}
427
b9329558 428void DecodeTrace::draw_error(QPainter &p, const QString &message,
ad50ac1a
JH
429 int left, int right)
430{
431 const int y = get_y();
432
433 p.setPen(ErrorBgColour.darker());
434 p.setBrush(ErrorBgColour);
435
436 const QRectF bounding_rect =
437 QRectF(left, INT_MIN / 2 + y, right - left, INT_MAX);
438 const QRectF text_rect = p.boundingRect(bounding_rect,
439 Qt::AlignCenter, message);
440 const float r = text_rect.height() / 4;
441
442 p.drawRoundedRect(text_rect.adjusted(-r, -r, r, r), r, r,
443 Qt::AbsoluteSize);
444
445 p.setPen(get_text_colour());
446 p.drawText(text_rect, message);
447}
448
5dfeb70f 449void DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left,
7f8517f6 450 int right) const
5dfeb70f
JH
451{
452 using namespace pv::data;
453 using pv::data::decode::Decoder;
454
455 assert(_decoder_stack);
456
457 shared_ptr<Logic> data;
458 shared_ptr<LogicSignal> logic_signal;
459
460 const list< shared_ptr<Decoder> > &stack = _decoder_stack->stack();
461
6ac6242b 462 // We get the logic data of the first channel in the list.
5dfeb70f
JH
463 // This works because we are currently assuming all
464 // LogicSignals have the same data/snapshot
d9aecf1f 465 for (const shared_ptr<Decoder> &dec : stack)
8bd26d8b
UH
466 if (dec && !dec->channels().empty() &&
467 ((logic_signal = (*dec->channels().begin()).second)) &&
7aa09b00 468 ((data = logic_signal->logic_data())))
5dfeb70f
JH
469 break;
470
471 if (!data || data->get_snapshots().empty())
472 return;
473
474 const shared_ptr<LogicSnapshot> snapshot =
475 data->get_snapshots().front();
476 assert(snapshot);
477 const int64_t sample_count = (int64_t)snapshot->get_sample_count();
478 if (sample_count == 0)
479 return;
480
481 const int64_t samples_decoded = _decoder_stack->samples_decoded();
482 if (sample_count == samples_decoded)
483 return;
484
485 const int y = get_y();
7f8517f6
SA
486
487 const double samples_per_pixel = get_samples_per_pixel();
488 const double pixels_offset = get_pixels_offset();
489
5dfeb70f
JH
490 const double start = max(samples_decoded /
491 samples_per_pixel - pixels_offset, left - 1.0);
492 const double end = min(sample_count / samples_per_pixel -
493 pixels_offset, right + 1.0);
494 const QRectF no_decode_rect(start, y - h/2 + 0.5, end - start, h);
495
496 p.setPen(QPen(Qt::NoPen));
497 p.setBrush(Qt::white);
498 p.drawRect(no_decode_rect);
499
500 p.setPen(NoDecodeColour);
501 p.setBrush(QBrush(NoDecodeColour, Qt::Dense6Pattern));
502 p.drawRect(no_decode_rect);
503}
504
7f8517f6
SA
505double DecodeTrace::get_pixels_offset() const
506{
507 assert(_view);
508 assert(_decoder_stack);
509
510 const double scale = _view->scale();
511 assert(scale > 0);
512
513 return (_view->offset() - _decoder_stack->get_start_time()) / scale;
514}
515
516double DecodeTrace::get_samples_per_pixel() const
517{
518 assert(_view);
519 assert(_decoder_stack);
520
521 const double scale = _view->scale();
522 assert(scale > 0);
523
524 double samplerate = _decoder_stack->samplerate();
525
526 // Show sample rate as 1Hz when it is unknown
527 if (samplerate == 0.0)
528 samplerate = 1.0;
529
530 return samplerate * scale;
531}
532
533pair<uint64_t, uint64_t> DecodeTrace::get_sample_range(int x_start, int x_end) const
534{
535 assert(_view);
536 assert(_decoder_stack);
537
538 const double samples_per_pixel = get_samples_per_pixel();
539 const double pixels_offset = get_pixels_offset();
540
541 uint64_t start, end;
542
543 start = (uint64_t)max((x_start + pixels_offset) * samples_per_pixel, 0.0);
544 end = (uint64_t)max((x_end + pixels_offset) * samples_per_pixel, 0.0);
545
546 return make_pair(start, end);
547}
548
9555ca8b
SA
549void DecodeTrace::hover_point_changed()
550{
551}
552
613d097c
JH
553void DecodeTrace::create_decoder_form(int index,
554 shared_ptr<data::decode::Decoder> &dec, QWidget *parent,
555 QFormLayout *form)
7491a29f 556{
8bd26d8b 557 const GSList *l;
7491a29f
JH
558
559 assert(dec);
560 const srd_decoder *const decoder = dec->decoder();
561 assert(decoder);
562
204bae45 563 pv::widgets::DecoderGroupBox *const group =
27e8df22
JH
564 new pv::widgets::DecoderGroupBox(
565 QString::fromUtf8(decoder->name));
dd048a7e 566 group->set_decoder_visible(dec->shown());
613d097c
JH
567
568 _delete_mapper.setMapping(group, index);
569 connect(group, SIGNAL(delete_decoder()), &_delete_mapper, SLOT(map()));
570
dd048a7e
JH
571 _show_hide_mapper.setMapping(group, index);
572 connect(group, SIGNAL(show_hide_decoder()),
573 &_show_hide_mapper, SLOT(map()));
574
204bae45
JH
575 QFormLayout *const decoder_form = new QFormLayout;
576 group->add_layout(decoder_form);
7491a29f 577
8bd26d8b
UH
578 // Add the mandatory channels
579 for(l = decoder->channels; l; l = l->next) {
580 const struct srd_channel *const pdch =
581 (struct srd_channel *)l->data;
6ac6242b 582 QComboBox *const combo = create_channel_selector(parent, dec, pdch);
7491a29f 583 connect(combo, SIGNAL(currentIndexChanged(int)),
6ac6242b 584 this, SLOT(on_channel_selected(int)));
204bae45 585 decoder_form->addRow(tr("<b>%1</b> (%2) *")
8bd26d8b
UH
586 .arg(QString::fromUtf8(pdch->name))
587 .arg(QString::fromUtf8(pdch->desc)), combo);
7491a29f 588
6ac6242b
ML
589 const ChannelSelector s = {combo, dec, pdch};
590 _channel_selectors.push_back(s);
7491a29f
JH
591 }
592
8bd26d8b
UH
593 // Add the optional channels
594 for(l = decoder->opt_channels; l; l = l->next) {
595 const struct srd_channel *const pdch =
596 (struct srd_channel *)l->data;
6ac6242b 597 QComboBox *const combo = create_channel_selector(parent, dec, pdch);
7491a29f 598 connect(combo, SIGNAL(currentIndexChanged(int)),
6ac6242b 599 this, SLOT(on_channel_selected(int)));
204bae45 600 decoder_form->addRow(tr("<b>%1</b> (%2)")
8bd26d8b
UH
601 .arg(QString::fromUtf8(pdch->name))
602 .arg(QString::fromUtf8(pdch->desc)), combo);
7491a29f 603
6ac6242b
ML
604 const ChannelSelector s = {combo, dec, pdch};
605 _channel_selectors.push_back(s);
7491a29f
JH
606 }
607
608 // Add the options
609 shared_ptr<prop::binding::DecoderOptions> binding(
610 new prop::binding::DecoderOptions(_decoder_stack, dec));
204bae45 611 binding->add_properties_to_form(decoder_form, true);
7491a29f
JH
612
613 _bindings.push_back(binding);
204bae45
JH
614
615 form->addRow(group);
dd048a7e 616 _decoder_forms.push_back(group);
7491a29f
JH
617}
618
6ac6242b 619QComboBox* DecodeTrace::create_channel_selector(
7491a29f 620 QWidget *parent, const shared_ptr<data::decode::Decoder> &dec,
8bd26d8b 621 const srd_channel *const pdch)
4e5a4405 622{
7491a29f
JH
623 assert(dec);
624
4e5a4405
JH
625 const vector< shared_ptr<Signal> > sigs = _session.get_signals();
626
6e89374a 627 assert(_decoder_stack);
6ac6242b 628 const auto channel_iter = dec->channels().find(pdch);
4e5a4405
JH
629
630 QComboBox *selector = new QComboBox(parent);
631
632 selector->addItem("-", qVariantFromValue((void*)NULL));
633
6ac6242b 634 if (channel_iter == dec->channels().end())
4e5a4405
JH
635 selector->setCurrentIndex(0);
636
637 for(size_t i = 0; i < sigs.size(); i++) {
638 const shared_ptr<view::Signal> s(sigs[i]);
639 assert(s);
640
641 if (dynamic_pointer_cast<LogicSignal>(s) && s->enabled())
642 {
643 selector->addItem(s->get_name(),
644 qVariantFromValue((void*)s.get()));
6ac6242b 645 if ((*channel_iter).second == s)
4e5a4405
JH
646 selector->setCurrentIndex(i + 1);
647 }
648 }
649
650 return selector;
651}
652
6ac6242b 653void DecodeTrace::commit_decoder_channels(shared_ptr<data::decode::Decoder> &dec)
4e5a4405 654{
7491a29f 655 assert(dec);
4e5a4405 656
6ac6242b 657 map<const srd_channel*, shared_ptr<LogicSignal> > channel_map;
4e5a4405
JH
658 const vector< shared_ptr<Signal> > sigs = _session.get_signals();
659
6ac6242b 660 for (const ChannelSelector &s : _channel_selectors)
4e5a4405 661 {
7491a29f
JH
662 if(s._decoder != dec)
663 break;
664
4e5a4405 665 const LogicSignal *const selection =
7491a29f
JH
666 (LogicSignal*)s._combo->itemData(
667 s._combo->currentIndex()).value<void*>();
4e5a4405 668
d9aecf1f 669 for (shared_ptr<Signal> sig : sigs)
7491a29f 670 if(sig.get() == selection) {
6ac6242b 671 channel_map[s._pdch] =
7491a29f 672 dynamic_pointer_cast<LogicSignal>(sig);
4e5a4405
JH
673 break;
674 }
675 }
676
6ac6242b 677 dec->set_channels(channel_map);
7491a29f
JH
678}
679
6ac6242b 680void DecodeTrace::commit_channels()
7491a29f
JH
681{
682 assert(_decoder_stack);
d9aecf1f 683 for (shared_ptr<data::decode::Decoder> dec : _decoder_stack->stack())
6ac6242b 684 commit_decoder_channels(dec);
7491a29f
JH
685
686 _decoder_stack->begin_decode();
4e5a4405
JH
687}
688
b9329558 689void DecodeTrace::on_new_decode_data()
9cef9567
JH
690{
691 if (_view)
692 _view->update_viewport();
693}
694
b9329558 695void DecodeTrace::delete_pressed()
5ed1adf5
JH
696{
697 on_delete();
698}
699
b9329558 700void DecodeTrace::on_delete()
c51482b3
JH
701{
702 _session.remove_decode_signal(this);
703}
704
6ac6242b 705void DecodeTrace::on_channel_selected(int)
4e5a4405 706{
6ac6242b 707 commit_channels();
4e5a4405
JH
708}
709
7491a29f
JH
710void DecodeTrace::on_stack_decoder(srd_decoder *decoder)
711{
712 assert(decoder);
713 assert(_decoder_stack);
714 _decoder_stack->push(shared_ptr<data::decode::Decoder>(
715 new data::decode::Decoder(decoder)));
716 _decoder_stack->begin_decode();
37fd11b1
JH
717
718 create_popup_form();
7491a29f
JH
719}
720
613d097c
JH
721void DecodeTrace::on_delete_decoder(int index)
722{
723 _decoder_stack->remove(index);
724
725 // Update the popup
726 create_popup_form();
727
728 _decoder_stack->begin_decode();
729}
730
dd048a7e
JH
731void DecodeTrace::on_show_hide_decoder(int index)
732{
733 using pv::data::decode::Decoder;
734
735 const list< shared_ptr<Decoder> > stack(_decoder_stack->stack());
736
737 // Find the decoder in the stack
f46e495e 738 auto iter = stack.cbegin();
dd048a7e
JH
739 for(int i = 0; i < index; i++, iter++)
740 assert(iter != stack.end());
741
742 shared_ptr<Decoder> dec = *iter;
743 assert(dec);
744
745 const bool show = !dec->shown();
746 dec->show(show);
747
748 assert(index < (int)_decoder_forms.size());
749 _decoder_forms[index]->set_decoder_visible(show);
750
751 _view->update_viewport();
752}
753
55d3603d
JH
754} // namespace view
755} // namespace pv