From: Joel Holdsworth Date: Fri, 27 Dec 2013 11:44:36 +0000 (+0000) Subject: Moved annotation painting code into DecodeTrace, and moved Annotation in pv::data... X-Git-Tag: pulseview-0.2.0~181 X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=06e810f29b6e9e3fe8ba8aba5d3823375da9bbb2;p=pulseview.git Moved annotation painting code into DecodeTrace, and moved Annotation in pv::data::decode namespace. --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 443dea6a..b24b9711 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,7 @@ set(pulseview_SOURCES pv/data/logicsnapshot.cpp pv/data/signaldata.cpp pv/data/snapshot.cpp + pv/data/decode/annotation.cpp pv/data/decode/decoder.cpp pv/dialogs/about.cpp pv/dialogs/connect.cpp @@ -142,7 +143,6 @@ set(pulseview_SOURCES pv/view/tracepalette.cpp pv/view/view.cpp pv/view/viewport.cpp - pv/view/decode/annotation.cpp pv/widgets/colourbutton.cpp pv/widgets/colourpopup.cpp pv/widgets/decodergroupbox.cpp diff --git a/pv/data/decode/annotation.cpp b/pv/data/decode/annotation.cpp new file mode 100644 index 00000000..6a30921e --- /dev/null +++ b/pv/data/decode/annotation.cpp @@ -0,0 +1,73 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2012 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +extern "C" { +#include +} + +#include "annotation.h" + +using namespace std; + +namespace pv { +namespace data { +namespace decode { + +Annotation::Annotation(const srd_proto_data *const pdata) : + _start_sample(pdata->start_sample), + _end_sample(pdata->end_sample) +{ + assert(pdata); + const srd_proto_data_annotation *const pda = + (const srd_proto_data_annotation*)pdata->data; + assert(pda); + + _format = pda->ann_format; + + const char *const *annotations = (char**)pda->ann_text; + while(*annotations) { + _annotations.push_back(QString(*annotations)); + annotations++; + } +} + +uint64_t Annotation::start_sample() const +{ + return _start_sample; +} + +uint64_t Annotation::end_sample() const +{ + return _end_sample; +} + +int Annotation::format() const +{ + return _format; +} + +const std::vector& Annotation::annotations() const +{ + return _annotations; +} + +} // namespace decode +} // namespace data +} // namespace pv diff --git a/pv/data/decode/annotation.h b/pv/data/decode/annotation.h new file mode 100644 index 00000000..0d7fd5d5 --- /dev/null +++ b/pv/data/decode/annotation.h @@ -0,0 +1,55 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2013 Joel Holdsworth + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H +#define PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H + +#include + +#include + +struct srd_proto_data; + +namespace pv { +namespace data { +namespace decode { + +class Annotation +{ +public: + Annotation(const srd_proto_data *const pdata); + + uint64_t start_sample() const; + uint64_t end_sample() const; + int format() const; + const std::vector& annotations() const; + +private: + uint64_t _start_sample; + uint64_t _end_sample; + int _format; + std::vector _annotations; +}; + +} // namespace decode +} // namespace data +} // namespace pv + +#endif // PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H diff --git a/pv/data/decoderstack.cpp b/pv/data/decoderstack.cpp index e588ad6b..c2ae9116 100644 --- a/pv/data/decoderstack.cpp +++ b/pv/data/decoderstack.cpp @@ -32,8 +32,8 @@ #include #include #include +#include #include -#include using namespace boost; using namespace std; @@ -94,7 +94,7 @@ int64_t DecoderStack::samples_decoded() const return _samples_decoded; } -const vector DecoderStack::annotations() const +const vector DecoderStack::annotations() const { lock_guard lock(_mutex); return _annotations; @@ -229,7 +229,7 @@ void DecoderStack::decode_proc(shared_ptr data) void DecoderStack::annotation_callback(srd_proto_data *pdata, void *decoder) { - using namespace pv::view::decode; + using pv::data::decode::Annotation; assert(pdata); assert(decoder); diff --git a/pv/data/decoderstack.h b/pv/data/decoderstack.h index 58dd8871..e2139f5b 100644 --- a/pv/data/decoderstack.h +++ b/pv/data/decoderstack.h @@ -43,16 +43,12 @@ namespace pv { namespace view { class LogicSignal; - -namespace decode { -class Annotation; -} - } namespace data { namespace decode { +class Annotation; class Decoder; } @@ -78,7 +74,7 @@ public: int64_t samples_decoded() const; - const std::vector annotations() const; + const std::vector annotations() const; QString error_message(); @@ -111,7 +107,7 @@ private: mutable boost::mutex _mutex; int64_t _samples_decoded; - std::vector _annotations; + std::vector _annotations; QString _error_message; boost::thread _decode_thread; diff --git a/pv/view/decode/annotation.cpp b/pv/view/decode/annotation.cpp deleted file mode 100644 index 4a110e67..00000000 --- a/pv/view/decode/annotation.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2012 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -extern "C" { -#include -} - -#include - -#include - -#include - -#include - -#include "annotation.h" - -using namespace std; - -namespace pv { -namespace view { -namespace decode { - -const double Annotation::EndCapWidth = 5; -const int Annotation::DrawPadding = 100; - -const QColor Annotation::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 -}; - -Annotation::Annotation(const srd_proto_data *const pdata) : - _start_sample(pdata->start_sample), - _end_sample(pdata->end_sample) -{ - assert(pdata); - const srd_proto_data_annotation *const pda = - (const srd_proto_data_annotation*)pdata->data; - assert(pda); - - _format = pda->ann_format; - - const char *const *annotations = (char**)pda->ann_text; - while(*annotations) { - _annotations.push_back(QString(*annotations)); - annotations++; - } -} - -uint64_t Annotation::start_sample() const -{ - return _start_sample; -} - -uint64_t Annotation::end_sample() const -{ - return _end_sample; -} - -void Annotation::paint(QPainter &p, QColor text_color, int h, - int left, int right, double samples_per_pixel, double pixels_offset, - int y) const -{ - const double start = _start_sample / samples_per_pixel - - pixels_offset; - const double end = _end_sample / samples_per_pixel - - pixels_offset; - const QColor fill = Colours[(_format * (countof(Colours) / 2 + 1)) % - countof(Colours)]; - const QColor outline(fill.darker()); - - if (start > right + DrawPadding || end < left - DrawPadding) - return; - - if (_start_sample == _end_sample) - draw_instant(p, fill, outline, text_color, h, - start, y); - else - draw_range(p, fill, outline, text_color, h, - start, end, y); -} - -void Annotation::draw_instant(QPainter &p, QColor fill, QColor outline, - QColor text_color, int h, double x, int y) const -{ - const QString text = _annotations.empty() ? - QString() : _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 Annotation::draw_range(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; - - 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())); -} - -} // namespace decode -} // namespace view -} // namespace pv diff --git a/pv/view/decode/annotation.h b/pv/view/decode/annotation.h deleted file mode 100644 index 94b7dc90..00000000 --- a/pv/view/decode/annotation.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * This file is part of the PulseView project. - * - * Copyright (C) 2013 Joel Holdsworth - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H -#define PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H - -#include - -#include - -struct srd_proto_data; - -namespace pv { -namespace view { -namespace decode { - -class Annotation -{ -private: - static const double EndCapWidth; - static const int DrawPadding; - - static const QColor Colours[7]; - -public: - Annotation(const srd_proto_data *const pdata); - - uint64_t start_sample() const; - uint64_t end_sample() const; - - void paint(QPainter &p, QColor text_colour, int text_height, int left, - int right, double samples_per_pixel, double pixels_offset, - int y) const; - -private: - void draw_instant(QPainter &p, QColor fill, QColor outline, - QColor text_color, int h, double x, int y) const; - - void draw_range(QPainter &p, QColor fill, QColor outline, - QColor text_color, int h, double start, - double end, int y) const; - -private: - uint64_t _start_sample; - uint64_t _end_sample; - int _format; - std::vector _annotations; -}; - -} // namespace decode -} // namespace view -} // namespace pv - -#endif // PULSEVIEW_PV_VIEW_DECODE_ANNOTATION_H diff --git a/pv/view/decodetrace.cpp b/pv/view/decodetrace.cpp index e582d1a8..e275a112 100644 --- a/pv/view/decodetrace.cpp +++ b/pv/view/decodetrace.cpp @@ -41,9 +41,9 @@ extern "C" { #include #include #include +#include #include #include -#include #include #include @@ -63,6 +63,19 @@ 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)), @@ -103,7 +116,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 pv::data::decode::Annotation; const double scale = _view->scale(); assert(scale > 0); @@ -137,7 +150,7 @@ void DecodeTrace::paint_mid(QPainter &p, int left, int right) assert(_decoder_stack); vector annotations(_decoder_stack->annotations()); BOOST_FOREACH(const Annotation &a, annotations) - a.paint(p, get_text_colour(), h, left, right, + draw_annotation(a, p, get_text_colour(), h, left, right, samples_per_pixel, pixels_offset, y); draw_unresolved_period(p, h, left, right, @@ -210,6 +223,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) { diff --git a/pv/view/decodetrace.h b/pv/view/decodetrace.h index 02ea023b..2df848ac 100644 --- a/pv/view/decodetrace.h +++ b/pv/view/decodetrace.h @@ -43,6 +43,7 @@ namespace data { class DecoderStack; namespace decode { +class Annotation; class Decoder; } } @@ -66,6 +67,11 @@ private: static const QColor ErrorBgColour; static const QColor NoDecodeColour; + static const double EndCapWidth; + static const int DrawPadding; + + static const QColor Colours[7]; + public: DecodeTrace(pv::SigSession &session, boost::shared_ptr decoder_stack, @@ -100,6 +106,18 @@ public: void delete_pressed(); private: + void draw_annotation(const pv::data::decode::Annotation &a, QPainter &p, + QColor text_colour, int text_height, int left, int right, + double samples_per_pixel, double pixels_offset, int y) const; + + void draw_instant(const pv::data::decode::Annotation &a, QPainter &p, + QColor fill, QColor outline, QColor text_color, int h, double x, + int y) const; + + void 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; + void draw_error(QPainter &p, const QString &message, int left, int right); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 752e809c..f167ffb1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,6 +47,7 @@ set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/data/snapshot.cpp ${PROJECT_SOURCE_DIR}/pv/data/signaldata.cpp ${PROJECT_SOURCE_DIR}/pv/data/decode/decoder.cpp + ${PROJECT_SOURCE_DIR}/pv/data/decode/annotation.cpp ${PROJECT_SOURCE_DIR}/pv/prop/int.cpp ${PROJECT_SOURCE_DIR}/pv/prop/property.cpp ${PROJECT_SOURCE_DIR}/pv/prop/string.cpp @@ -67,7 +68,6 @@ set(pulseview_TEST_SOURCES ${PROJECT_SOURCE_DIR}/pv/view/tracepalette.cpp ${PROJECT_SOURCE_DIR}/pv/view/view.cpp ${PROJECT_SOURCE_DIR}/pv/view/viewport.cpp - ${PROJECT_SOURCE_DIR}/pv/view/decode/annotation.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/colourbutton.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/colourpopup.cpp ${PROJECT_SOURCE_DIR}/pv/widgets/decodergroupbox.cpp