]> sigrok.org Git - pulseview.git/blame_incremental - pv/view/decodetrace.cpp
DecodeTrace: Tidied up get_sample_range
[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 <boost/functional/hash.hpp>
28
29#include <QAction>
30#include <QApplication>
31#include <QComboBox>
32#include <QFormLayout>
33#include <QLabel>
34#include <QMenu>
35#include <QPushButton>
36#include <QToolTip>
37
38#include "decodetrace.h"
39
40#include <pv/sigsession.h>
41#include <pv/data/decoderstack.h>
42#include <pv/data/decode/decoder.h>
43#include <pv/data/logic.h>
44#include <pv/data/logicsnapshot.h>
45#include <pv/data/decode/annotation.h>
46#include <pv/view/logicsignal.h>
47#include <pv/view/view.h>
48#include <pv/view/viewport.h>
49#include <pv/widgets/decodergroupbox.h>
50#include <pv/widgets/decodermenu.h>
51
52using std::dynamic_pointer_cast;
53using std::list;
54using std::make_pair;
55using std::max;
56using std::map;
57using std::min;
58using std::pair;
59using std::shared_ptr;
60using std::vector;
61
62namespace pv {
63namespace view {
64
65const QColor DecodeTrace::DecodeColours[4] = {
66 QColor(0xEF, 0x29, 0x29), // Red
67 QColor(0xFC, 0xE9, 0x4F), // Yellow
68 QColor(0x8A, 0xE2, 0x34), // Green
69 QColor(0x72, 0x9F, 0xCF) // Blue
70};
71
72const QColor DecodeTrace::ErrorBgColour = QColor(0xEF, 0x29, 0x29);
73const QColor DecodeTrace::NoDecodeColour = QColor(0x88, 0x8A, 0x85);
74
75const int DecodeTrace::ArrowSize = 4;
76const double DecodeTrace::EndCapWidth = 5;
77const int DecodeTrace::DrawPadding = 100;
78
79const QColor DecodeTrace::Colours[16] = {
80 QColor(0xEF, 0x29, 0x29),
81 QColor(0xF6, 0x6A, 0x32),
82 QColor(0xFC, 0xAE, 0x3E),
83 QColor(0xFB, 0xCA, 0x47),
84 QColor(0xFC, 0xE9, 0x4F),
85 QColor(0xCD, 0xF0, 0x40),
86 QColor(0x8A, 0xE2, 0x34),
87 QColor(0x4E, 0xDC, 0x44),
88 QColor(0x55, 0xD7, 0x95),
89 QColor(0x64, 0xD1, 0xD2),
90 QColor(0x72, 0x9F, 0xCF),
91 QColor(0xD4, 0x76, 0xC4),
92 QColor(0x9D, 0x79, 0xB9),
93 QColor(0xAD, 0x7F, 0xA8),
94 QColor(0xC2, 0x62, 0x9B),
95 QColor(0xD7, 0x47, 0x6F)
96};
97
98const QColor DecodeTrace::OutlineColours[16] = {
99 QColor(0x77, 0x14, 0x14),
100 QColor(0x7B, 0x35, 0x19),
101 QColor(0x7E, 0x57, 0x1F),
102 QColor(0x7D, 0x65, 0x23),
103 QColor(0x7E, 0x74, 0x27),
104 QColor(0x66, 0x78, 0x20),
105 QColor(0x45, 0x71, 0x1A),
106 QColor(0x27, 0x6E, 0x22),
107 QColor(0x2A, 0x6B, 0x4A),
108 QColor(0x32, 0x68, 0x69),
109 QColor(0x39, 0x4F, 0x67),
110 QColor(0x6A, 0x3B, 0x62),
111 QColor(0x4E, 0x3C, 0x5C),
112 QColor(0x56, 0x3F, 0x54),
113 QColor(0x61, 0x31, 0x4D),
114 QColor(0x6B, 0x23, 0x37)
115};
116
117DecodeTrace::DecodeTrace(pv::SigSession &session,
118 std::shared_ptr<pv::data::DecoderStack> decoder_stack, int index) :
119 Trace(QString::fromUtf8(
120 decoder_stack->stack().front()->decoder()->name)),
121 _session(session),
122 _decoder_stack(decoder_stack),
123 _text_height(0),
124 _row_height(0),
125 _delete_mapper(this),
126 _show_hide_mapper(this)
127{
128 assert(_decoder_stack);
129
130 _colour = DecodeColours[index % countof(DecodeColours)];
131
132 connect(_decoder_stack.get(), SIGNAL(new_decode_data()),
133 this, SLOT(on_new_decode_data()));
134 connect(&_delete_mapper, SIGNAL(mapped(int)),
135 this, SLOT(on_delete_decoder(int)));
136 connect(&_show_hide_mapper, SIGNAL(mapped(int)),
137 this, SLOT(on_show_hide_decoder(int)));
138}
139
140bool DecodeTrace::enabled() const
141{
142 return true;
143}
144
145const std::shared_ptr<pv::data::DecoderStack>& DecodeTrace::decoder() const
146{
147 return _decoder_stack;
148}
149
150void DecodeTrace::set_view(pv::view::View *view)
151{
152 assert(view);
153 Trace::set_view(view);
154}
155
156void DecodeTrace::paint_back(QPainter &p, int left, int right)
157{
158 Trace::paint_back(p, left, right);
159 paint_axis(p, get_y(), left, right);
160}
161
162void DecodeTrace::paint_mid(QPainter &p, int left, int right)
163{
164 using namespace pv::data::decode;
165
166 QFontMetrics m(QApplication::font());
167 _text_height = m.boundingRect(QRect(), 0, "Tg").height();
168 _row_height = (_text_height * 6) / 4;
169 const int annotation_height = (_text_height * 5) / 4;
170
171 assert(_decoder_stack);
172 const QString err = _decoder_stack->error_message();
173 if (!err.isEmpty())
174 {
175 draw_unresolved_period(p, annotation_height, left, right);
176 draw_error(p, err, left, right);
177 return;
178 }
179
180 // Iterate through the rows
181 assert(_view);
182 int y = get_y();
183 pair<uint64_t, uint64_t> sample_range = get_sample_range(left, right);
184
185 assert(_decoder_stack);
186 const vector<Row> rows(_decoder_stack->get_visible_rows());
187
188 _visible_rows.clear();
189 for (size_t i = 0; i < rows.size(); i++)
190 {
191 const Row &row = rows[i];
192
193 size_t base_colour = 0x13579BDF;
194 boost::hash_combine(base_colour, this);
195 boost::hash_combine(base_colour, row.decoder());
196 boost::hash_combine(base_colour, row.row());
197 base_colour >>= 16;
198
199 vector<Annotation> annotations;
200 _decoder_stack->get_annotation_subset(annotations, row,
201 sample_range.first, sample_range.second);
202 if (!annotations.empty()) {
203 for (const Annotation &a : annotations)
204 draw_annotation(a, p, get_text_colour(),
205 annotation_height, left, right, y,
206 base_colour);
207 y += _row_height;
208
209 _visible_rows.push_back(rows[i]);
210 }
211 }
212
213 // Draw the hatching
214 draw_unresolved_period(p, annotation_height, left, right);
215}
216
217void DecodeTrace::paint_fore(QPainter &p, int left, int right)
218{
219 using namespace pv::data::decode;
220
221 (void)right;
222
223 assert(_row_height);
224
225 for (size_t i = 0; i < _visible_rows.size(); i++)
226 {
227 const int y = i * _row_height + get_y();
228
229 p.setPen(QPen(Qt::NoPen));
230 p.setBrush(QApplication::palette().brush(QPalette::WindowText));
231
232 if (i != 0)
233 {
234 const QPointF points[] = {
235 QPointF(left, y - ArrowSize),
236 QPointF(left + ArrowSize, y),
237 QPointF(left, y + ArrowSize)
238 };
239 p.drawPolygon(points, countof(points));
240 }
241
242 const QRect r(left + ArrowSize * 2, y - _row_height / 2,
243 right - left, _row_height);
244 const QString h(_visible_rows[i].title());
245 const int f = Qt::AlignLeft | Qt::AlignVCenter |
246 Qt::TextDontClip;
247
248 // Draw the outline
249 p.setPen(QApplication::palette().color(QPalette::Base));
250 for (int dx = -1; dx <= 1; dx++)
251 for (int dy = -1; dy <= 1; dy++)
252 if (dx != 0 && dy != 0)
253 p.drawText(r.translated(dx, dy), f, h);
254
255 // Draw the text
256 p.setPen(QApplication::palette().color(QPalette::WindowText));
257 p.drawText(r, f, h);
258 }
259}
260
261void DecodeTrace::populate_popup_form(QWidget *parent, QFormLayout *form)
262{
263 using pv::data::decode::Decoder;
264
265 assert(form);
266 assert(parent);
267 assert(_decoder_stack);
268
269 // Add the standard options
270 Trace::populate_popup_form(parent, form);
271
272 // Add the decoder options
273 _bindings.clear();
274 _channel_selectors.clear();
275 _decoder_forms.clear();
276
277 const list< shared_ptr<Decoder> >& stack = _decoder_stack->stack();
278
279 if (stack.empty())
280 {
281 QLabel *const l = new QLabel(
282 tr("<p><i>No decoders in the stack</i></p>"));
283 l->setAlignment(Qt::AlignCenter);
284 form->addRow(l);
285 }
286 else
287 {
288 auto iter = stack.cbegin();
289 for (int i = 0; i < (int)stack.size(); i++, iter++) {
290 shared_ptr<Decoder> dec(*iter);
291 create_decoder_form(i, dec, parent, form);
292 }
293
294 form->addRow(new QLabel(
295 tr("<i>* Required channels</i>"), parent));
296 }
297
298 // Add stacking button
299 pv::widgets::DecoderMenu *const decoder_menu =
300 new pv::widgets::DecoderMenu(parent);
301 connect(decoder_menu, SIGNAL(decoder_selected(srd_decoder*)),
302 this, SLOT(on_stack_decoder(srd_decoder*)));
303
304 QPushButton *const stack_button =
305 new QPushButton(tr("Stack Decoder"), parent);
306 stack_button->setMenu(decoder_menu);
307
308 QHBoxLayout *stack_button_box = new QHBoxLayout;
309 stack_button_box->addWidget(stack_button, 0, Qt::AlignRight);
310 form->addRow(stack_button_box);
311}
312
313QMenu* DecodeTrace::create_context_menu(QWidget *parent)
314{
315 QMenu *const menu = Trace::create_context_menu(parent);
316
317 menu->addSeparator();
318
319 QAction *const del = new QAction(tr("Delete"), this);
320 del->setShortcuts(QKeySequence::Delete);
321 connect(del, SIGNAL(triggered()), this, SLOT(on_delete()));
322 menu->addAction(del);
323
324 return menu;
325}
326
327void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a,
328 QPainter &p, QColor text_color, int h, int left, int right, int y,
329 size_t base_colour) const
330{
331 const double samples_per_pixel = get_samples_per_pixel();
332 const double pixels_offset = get_pixels_offset();
333
334 const double start = a.start_sample() / samples_per_pixel -
335 pixels_offset;
336 const double end = a.end_sample() / samples_per_pixel -
337 pixels_offset;
338
339 const size_t colour = (base_colour + a.format()) % countof(Colours);
340 const QColor &fill = Colours[colour];
341 const QColor &outline = OutlineColours[colour];
342
343 if (start > right + DrawPadding || end < left - DrawPadding)
344 return;
345
346 if (a.start_sample() == a.end_sample())
347 draw_instant(a, p, fill, outline, text_color, h,
348 start, y);
349 else
350 draw_range(a, p, fill, outline, text_color, h,
351 start, end, y);
352}
353
354void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p,
355 QColor fill, QColor outline, QColor text_color, int h, double x, int y) const
356{
357 const QString text = a.annotations().empty() ?
358 QString() : a.annotations().back();
359 const double w = min((double)p.boundingRect(QRectF(), 0, text).width(),
360 0.0) + h;
361 const QRectF rect(x - w / 2, y - h / 2, w, h);
362
363 p.setPen(outline);
364 p.setBrush(fill);
365 p.drawRoundedRect(rect, h / 2, h / 2);
366
367 p.setPen(text_color);
368 p.drawText(rect, Qt::AlignCenter | Qt::AlignVCenter, text);
369}
370
371void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p,
372 QColor fill, QColor outline, QColor text_color, int h, double start,
373 double end, int y) const
374{
375 const double top = y + .5 - h / 2;
376 const double bottom = y + .5 + h / 2;
377 const vector<QString> annotations = a.annotations();
378
379 p.setPen(outline);
380 p.setBrush(fill);
381
382 // If the two ends are within 1 pixel, draw a vertical line
383 if (start + 1.0 > end)
384 {
385 p.drawLine(QPointF(start, top), QPointF(start, bottom));
386 return;
387 }
388
389 const double cap_width = min((end - start) / 4, EndCapWidth);
390
391 QPointF pts[] = {
392 QPointF(start, y + .5f),
393 QPointF(start + cap_width, top),
394 QPointF(end - cap_width, top),
395 QPointF(end, y + .5f),
396 QPointF(end - cap_width, bottom),
397 QPointF(start + cap_width, bottom)
398 };
399
400 p.drawConvexPolygon(pts, countof(pts));
401
402 if (annotations.empty())
403 return;
404
405 QRectF rect(start + cap_width, y - h / 2,
406 end - start - cap_width * 2, h);
407 if (rect.width() <= 4)
408 return;
409
410 p.setPen(text_color);
411
412 // Try to find an annotation that will fit
413 QString best_annotation;
414 int best_width = 0;
415
416 for (const QString &a : annotations) {
417 const int w = p.boundingRect(QRectF(), 0, a).width();
418 if (w <= rect.width() && w > best_width)
419 best_annotation = a, best_width = w;
420 }
421
422 if (best_annotation.isEmpty())
423 best_annotation = annotations.back();
424
425 // If not ellide the last in the list
426 p.drawText(rect, Qt::AlignCenter, p.fontMetrics().elidedText(
427 best_annotation, Qt::ElideRight, rect.width()));
428}
429
430void DecodeTrace::draw_error(QPainter &p, const QString &message,
431 int left, int right)
432{
433 const int y = get_y();
434
435 p.setPen(ErrorBgColour.darker());
436 p.setBrush(ErrorBgColour);
437
438 const QRectF bounding_rect =
439 QRectF(left, INT_MIN / 2 + y, right - left, INT_MAX);
440 const QRectF text_rect = p.boundingRect(bounding_rect,
441 Qt::AlignCenter, message);
442 const float r = text_rect.height() / 4;
443
444 p.drawRoundedRect(text_rect.adjusted(-r, -r, r, r), r, r,
445 Qt::AbsoluteSize);
446
447 p.setPen(get_text_colour());
448 p.drawText(text_rect, message);
449}
450
451void DecodeTrace::draw_unresolved_period(QPainter &p, int h, int left,
452 int right) const
453{
454 using namespace pv::data;
455 using pv::data::decode::Decoder;
456
457 assert(_decoder_stack);
458
459 shared_ptr<Logic> data;
460 shared_ptr<LogicSignal> logic_signal;
461
462 const list< shared_ptr<Decoder> > &stack = _decoder_stack->stack();
463
464 // We get the logic data of the first channel in the list.
465 // This works because we are currently assuming all
466 // LogicSignals have the same data/snapshot
467 for (const shared_ptr<Decoder> &dec : stack)
468 if (dec && !dec->channels().empty() &&
469 ((logic_signal = (*dec->channels().begin()).second)) &&
470 ((data = logic_signal->logic_data())))
471 break;
472
473 if (!data || data->get_snapshots().empty())
474 return;
475
476 const shared_ptr<LogicSnapshot> snapshot =
477 data->get_snapshots().front();
478 assert(snapshot);
479 const int64_t sample_count = (int64_t)snapshot->get_sample_count();
480 if (sample_count == 0)
481 return;
482
483 const int64_t samples_decoded = _decoder_stack->samples_decoded();
484 if (sample_count == samples_decoded)
485 return;
486
487 const int y = get_y();
488
489 const double samples_per_pixel = get_samples_per_pixel();
490 const double pixels_offset = get_pixels_offset();
491
492 const double start = max(samples_decoded /
493 samples_per_pixel - pixels_offset, left - 1.0);
494 const double end = min(sample_count / samples_per_pixel -
495 pixels_offset, right + 1.0);
496 const QRectF no_decode_rect(start, y - h/2 + 0.5, end - start, h);
497
498 p.setPen(QPen(Qt::NoPen));
499 p.setBrush(Qt::white);
500 p.drawRect(no_decode_rect);
501
502 p.setPen(NoDecodeColour);
503 p.setBrush(QBrush(NoDecodeColour, Qt::Dense6Pattern));
504 p.drawRect(no_decode_rect);
505}
506
507double DecodeTrace::get_pixels_offset() const
508{
509 assert(_view);
510 assert(_decoder_stack);
511
512 const double scale = _view->scale();
513 assert(scale > 0);
514
515 return (_view->offset() - _decoder_stack->get_start_time()) / scale;
516}
517
518double DecodeTrace::get_samples_per_pixel() const
519{
520 assert(_view);
521 assert(_decoder_stack);
522
523 const double scale = _view->scale();
524 assert(scale > 0);
525
526 double samplerate = _decoder_stack->samplerate();
527
528 // Show sample rate as 1Hz when it is unknown
529 if (samplerate == 0.0)
530 samplerate = 1.0;
531
532 return samplerate * scale;
533}
534
535pair<uint64_t, uint64_t> DecodeTrace::get_sample_range(
536 int x_start, int x_end) const
537{
538 const double samples_per_pixel = get_samples_per_pixel();
539 const double pixels_offset = get_pixels_offset();
540
541 const uint64_t start = (uint64_t)max(
542 (x_start + pixels_offset) * samples_per_pixel, 0.0);
543 const uint64_t end = (uint64_t)max(
544 (x_end + pixels_offset) * samples_per_pixel, 0.0);
545
546 return make_pair(start, end);
547}
548
549int DecodeTrace::get_row_at_point(const QPoint &point)
550{
551 if (!_row_height)
552 return -1;
553
554 const int row = (point.y() - get_y() + _row_height / 2) / _row_height;
555 if (row < 0 || row >= (int)_visible_rows.size())
556 return -1;
557
558 return row;
559}
560
561const QString DecodeTrace::get_annotation_at_point(const QPoint &point)
562{
563 using namespace pv::data::decode;
564
565 if (!enabled())
566 return QString();
567
568 const pair<uint64_t, uint64_t> sample_range =
569 get_sample_range(point.x(), point.x() + 1);
570 const int row = get_row_at_point(point);
571 if (row < 0)
572 return QString();
573
574 vector<pv::data::decode::Annotation> annotations;
575
576 assert(_decoder_stack);
577 _decoder_stack->get_annotation_subset(annotations, _visible_rows[row],
578 sample_range.first, sample_range.second);
579
580 return (annotations.empty()) ?
581 QString() : annotations[0].annotations().front();
582}
583
584void DecodeTrace::hide_hover_annotation()
585{
586 QToolTip::hideText();
587}
588
589void DecodeTrace::hover_point_changed()
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->get_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 (_view)
762 _view->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 _view->update_viewport();
822}
823
824} // namespace view
825} // namespace pv