using namespace pv::data::decode;
vector<Annotation> a_block;
- int prev_ann_pos = INT_MIN;
+ int p_end = INT_MIN;
double samples_per_pixel, pixels_offset;
tie(pixels_offset, samples_per_pixel) =
get_pixels_offset_samples_per_pixel();
+ // Sort the annotations by start sample so that decoders
+ // can't confuse us by creating annotations out of order
+ stable_sort(annotations.begin(), annotations.end(),
+ [](const Annotation &a, const Annotation &b) {
+ return a.start_sample() < b.start_sample(); });
+
// Gather all annotations that form a visual "block" and draw them as such
for (const Annotation &a : annotations) {
- const int end = a.end_sample() / samples_per_pixel - pixels_offset;
- const int delta = end - prev_ann_pos;
+ const int a_start = a.start_sample() / samples_per_pixel - pixels_offset;
+ const int a_end = a.end_sample() / samples_per_pixel - pixels_offset;
+ const int a_width = a_end - a_start;
+
+ const int delta = a_end - p_end;
- // Some annotations are in reverse order, so we cannot
- // simply check for delta > 1
- if (abs(delta) > 1) {
- // Block was broken, draw it
- if (a_block.size() == 1)
+ bool a_is_separate = false;
+
+ // Annotation wider than the threshold for a useful label width?
+ if (a_width > 20) {
+ for (const QString &ann_text : a.annotations()) {
+ const int w = p.boundingRect(QRectF(), 0, ann_text).width();
+ // Annotation wide enough to fit a label? Don't put it in a block then
+ if (w <= a_width) {
+ a_is_separate = true;
+ break;
+ }
+ }
+ }
+
+ // Were the previous and this annotation more than a pixel apart?
+ if ((abs(delta) > 1) || a_is_separate) {
+ // Block was broken, draw annotations that form the current block
+ if (a_block.size() == 1) {
draw_annotation(a_block.front(), p, h, pp, y, base_colour);
+ }
else
- if (a_block.size() > 0)
- draw_annotation_block(a_block, p, h, y, base_colour);
+ draw_annotation_block(a_block, p, h, y, base_colour);
a_block.clear();
}
- a_block.push_back(a);
- prev_ann_pos = end;
+ if (a_is_separate) {
+ draw_annotation(a, p, h, pp, y, base_colour);
+ // Next annotation must start a new block. delta will be > 1
+ // because we set p_end to INT_MIN but that's okay since
+ // a_block will be empty, so nothing will be drawn
+ p_end = INT_MIN;
+ } else {
+ a_block.push_back(a);
+ p_end = a_end;
+ }
}
if (a_block.size() == 1)
if (a.start_sample() == a.end_sample())
draw_instant(a, p, fill, outline, h, start, y);
else
- draw_range(a, p, fill, outline, h, start, end, y);
+ draw_range(a, p, fill, outline, h, start, end, y, pp);
}
void DecodeTrace::draw_annotation_block(
{
using namespace pv::data::decode;
+ if (annotations.empty())
+ return;
+
double samples_per_pixel, pixels_offset;
tie(pixels_offset, samples_per_pixel) =
get_pixels_offset_samples_per_pixel();
void DecodeTrace::draw_range(const pv::data::decode::Annotation &a, QPainter &p,
QColor fill, QColor outline, int h, double start,
- double end, int y) const
+ double end, int y, const ViewItemPaintParams &pp) const
{
const double top = y + .5 - h / 2;
const double bottom = y + .5 + h / 2;
if (annotations.empty())
return;
- QRectF rect(start + cap_width, y - h / 2,
- end - start - cap_width * 2, h);
+ const int ann_start = start + cap_width;
+ const int ann_end = end - cap_width;
+
+ const int real_start = std::max(ann_start, pp.left());
+ const int real_end = std::min(ann_end, pp.right());
+
+ const int real_width = real_end - real_start;
+
+ QRectF rect(real_start, y - h / 2, real_width, h);
if (rect.width() <= 4)
return;