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