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