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