X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fview%2Fdecodetrace.cpp;h=161eb9668bdd2217a43e8173d396138ea2908c6e;hp=e582d1a8e2042d1ba4d4f2dd1046940bd8067990;hb=f9101a91fc942a28515872ae6c7285973bd54b91;hpb=db62bbfda512aeddca5b9d7b5960e9cf24b8859c diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp index e582d1a8..161eb966 100644 --- a/pv/view/decodetrace.cpp +++ b/pv/view/decodetrace.cpp @@ -41,14 +41,19 @@ extern "C" { #include #include #include +#include #include #include -#include #include #include -using namespace boost; -using namespace std; +using boost::dynamic_pointer_cast; +using boost::shared_ptr; +using std::list; +using std::max; +using std::map; +using std::min; +using std::vector; namespace pv { namespace view { @@ -63,9 +68,23 @@ const QColor DecodeTrace::DecodeColours[4] = { const QColor DecodeTrace::ErrorBgColour = QColor(0xEF, 0x29, 0x29); const QColor DecodeTrace::NoDecodeColour = QColor(0x88, 0x8A, 0x85); +const double DecodeTrace::EndCapWidth = 5; +const int DecodeTrace::DrawPadding = 100; + +const QColor DecodeTrace::Colours[7] = { + QColor(0xFC, 0xE9, 0x4F), // Light Butter + QColor(0xFC, 0xAF, 0x3E), // Light Orange + QColor(0xE9, 0xB9, 0x6E), // Light Chocolate + QColor(0x8A, 0xE2, 0x34), // Light Green + QColor(0x72, 0x9F, 0xCF), // Light Blue + QColor(0xAD, 0x7F, 0xA8), // Light Plum + QColor(0xEF, 0x29, 0x29) // Light Red +}; + DecodeTrace::DecodeTrace(pv::SigSession &session, boost::shared_ptr decoder_stack, int index) : - Trace(session, QString(decoder_stack->stack().front()->decoder()->name)), + Trace(session, QString::fromUtf8( + decoder_stack->stack().front()->decoder()->name)), _decoder_stack(decoder_stack), _delete_mapper(this) { @@ -103,7 +122,7 @@ void DecodeTrace::paint_back(QPainter &p, int left, int right) void DecodeTrace::paint_mid(QPainter &p, int left, int right) { - using namespace pv::view::decode; + using namespace pv::data::decode; const double scale = _view->scale(); assert(scale > 0); @@ -118,29 +137,49 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) _decoder_stack->get_start_time()) / scale; const double samples_per_pixel = samplerate * scale; + const uint64_t start_sample = (uint64_t)max((left + pixels_offset) * + samples_per_pixel, 0.0); + const uint64_t end_sample = (uint64_t)max((right + pixels_offset) * + samples_per_pixel, 0.0); + QFontMetrics m(QApplication::font()); - const int h = (m.boundingRect(QRect(), 0, "Tg").height() * 5) / 4; + const int text_height = m.boundingRect(QRect(), 0, "Tg").height(); + const int annotation_height = (text_height * 5) / 4; + const int row_height = (text_height * 6) / 4; assert(_decoder_stack); const QString err = _decoder_stack->error_message(); if (!err.isEmpty()) { draw_error(p, err, left, right); - draw_unresolved_period(p, h, left, right, samples_per_pixel, - pixels_offset); + draw_unresolved_period(p, annotation_height, left, right, + samples_per_pixel, pixels_offset); return; } + // Iterate through the rows assert(_view); - const int y = get_y(); + int y = get_y(); assert(_decoder_stack); - vector annotations(_decoder_stack->annotations()); - BOOST_FOREACH(const Annotation &a, annotations) - a.paint(p, get_text_colour(), h, left, right, - samples_per_pixel, pixels_offset, y); - draw_unresolved_period(p, h, left, right, + const vector rows(_decoder_stack->get_rows()); + BOOST_FOREACH (const Row &row, rows) + { + vector annotations; + _decoder_stack->get_annotation_subset(annotations, row, + start_sample, end_sample); + if (!annotations.empty()) { + BOOST_FOREACH(const Annotation &a, annotations) + draw_annotation(a, p, get_text_colour(), + annotation_height, left, right, + samples_per_pixel, pixels_offset, y); + y += row_height; + } + } + + // Draw the hatching + draw_unresolved_period(p, annotation_height, left, right, samples_per_pixel, pixels_offset); } @@ -210,6 +249,102 @@ QMenu* DecodeTrace::create_context_menu(QWidget *parent) return menu; } +void DecodeTrace::draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, + QColor text_color, int h, int left, int right, double samples_per_pixel, + double pixels_offset, int y) const +{ + const double start = a.start_sample() / samples_per_pixel - + pixels_offset; + const double end = a.end_sample() / samples_per_pixel - + pixels_offset; + const QColor fill = Colours[(a.format() * (countof(Colours) / 2 + 1)) % + countof(Colours)]; + const QColor outline(fill.darker()); + + if (start > right + DrawPadding || end < left - DrawPadding) + return; + + if (a.start_sample() == a.end_sample()) + draw_instant(a, p, fill, outline, text_color, h, + start, y); + else + draw_range(a, p, fill, outline, text_color, h, + start, end, y); +} + +void DecodeTrace::draw_instant(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double x, int y) const +{ + const QString text = a.annotations().empty() ? + QString() : a.annotations().back(); + const double w = min(p.boundingRect(QRectF(), 0, text).width(), + 0.0) + h; + const QRectF rect(x - w / 2, y - h / 2, w, h); + + p.setPen(outline); + p.setBrush(fill); + p.drawRoundedRect(rect, h / 2, h / 2); + + p.setPen(text_color); + p.drawText(rect, Qt::AlignCenter | Qt::AlignVCenter, text); +} + +void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double start, + double end, int y) const +{ + const double top = y + .5 - h / 2; + const double bottom = y + .5 + h / 2; + const vector annotations = a.annotations(); + + p.setPen(outline); + p.setBrush(fill); + + // If the two ends are within 1 pixel, draw a vertical line + if (start + 1.0 > end) + { + p.drawLine(QPointF(start, top), QPointF(start, bottom)); + return; + } + + const double cap_width = min((end - start) / 4, EndCapWidth); + + QPointF pts[] = { + QPointF(start, y + .5f), + QPointF(start + cap_width, top), + QPointF(end - cap_width, top), + QPointF(end, y + .5f), + QPointF(end - cap_width, bottom), + QPointF(start + cap_width, bottom) + }; + + p.drawConvexPolygon(pts, countof(pts)); + + if (annotations.empty()) + return; + + QRectF rect(start + cap_width, y - h / 2, + end - start - cap_width * 2, h); + p.setPen(text_color); + + // Try to find an annotation that will fit + QString best_annotation; + int best_width = 0; + + BOOST_FOREACH(const QString &a, annotations) { + const int w = p.boundingRect(QRectF(), 0, a).width(); + if (w <= rect.width() && w > best_width) + best_annotation = a, best_width = w; + } + + if (best_annotation.isEmpty()) + best_annotation = annotations.back(); + + // If not ellide the last in the list + p.drawText(rect, Qt::AlignCenter, p.fontMetrics().elidedText( + best_annotation, Qt::ElideRight, rect.width())); +} + void DecodeTrace::draw_error(QPainter &p, const QString &message, int left, int right) { @@ -294,7 +429,8 @@ void DecodeTrace::create_decoder_form(int index, assert(decoder); pv::widgets::DecoderGroupBox *const group = - new pv::widgets::DecoderGroupBox(decoder->name); + new pv::widgets::DecoderGroupBox( + QString::fromUtf8(decoder->name)); _delete_mapper.setMapping(group, index); connect(group, SIGNAL(delete_decoder()), &_delete_mapper, SLOT(map()));