Make cursor pair drop precision when too small
authorjaseg <git@jaseg.net>
Sun, 9 Jun 2019 10:35:20 +0000 (19:35 +0900)
committerSoeren Apel <soeren@apelpie.net>
Thu, 4 Jul 2019 21:17:27 +0000 (23:17 +0200)
Currently, often the label just displays "...". With this change, it
will gracefully drop precision and less important parts (frequency,
unit) when there's not enough space to print the full string. The full
string is still available in the tooltip appearing on hover.

pv/util.cpp
pv/views/trace/cursorpair.cpp
pv/views/trace/cursorpair.hpp
pv/views/trace/ruler.cpp
pv/views/trace/ruler.hpp

index 49b9467..237ca7f 100644 (file)
@@ -138,8 +138,9 @@ QString format_time_si(const Timestamp& v, SIPrefix prefix,
        QTextStream ts(&s);
        if (sign && !v.is_zero())
                ts << forcesign;
-       ts << qSetRealNumberPrecision(precision) << (v * multiplier) << ' '
-               << prefix << unit;
+       ts << qSetRealNumberPrecision(precision) << (v * multiplier);
+       if (!unit.isNull())
+               ts << ' ' << prefix << unit;
 
        return s;
 }
index 933eb8f..562584c 100644 (file)
@@ -129,19 +129,14 @@ void CursorPair::paint_label(QPainter &p, const QRect &rect, bool hover)
        const QColor text_color = ViewItem::select_text_color(Cursor::FillColor);
        p.setPen(text_color);
 
-       QString text = format_string();
-       text_size_ = p.boundingRect(QRectF(), 0, text).size();
-
        QRectF delta_rect(label_rect(rect));
        const int radius = delta_rect.height() / 2;
        QRectF text_rect(delta_rect.intersected(rect).adjusted(radius, 0, -radius, 0));
 
-       if (text_rect.width() < text_size_.width()) {
-               text = "...";
-               text_size_ = p.boundingRect(QRectF(), 0, text).size();
-               label_incomplete_ = true;
-       } else
-               label_incomplete_ = false;
+       QString text = format_string(text_rect.width(), [&p](const QString& s) -> qreal {
+                       return p.boundingRect(QRectF(), 0, s).width();
+               });
+       text_size_ = p.boundingRect(QRectF(), 0, text).size();
 
        if (selected()) {
                p.setBrush(Qt::transparent);
@@ -178,17 +173,50 @@ void CursorPair::paint_back(QPainter &p, ViewItemPaintParams &pp)
        p.drawRect(l, pp.top(), r - l, pp.height());
 }
 
-QString CursorPair::format_string()
+QString CursorPair::format_string(qreal max_width, std::function<qreal(const QString&)> query_size)
 {
+       constexpr int time_precision = 12;
+       constexpr int freq_precision = 4;
+
        const pv::util::SIPrefix prefix = view_.tick_prefix();
        const pv::util::Timestamp diff = abs(second_->time() - first_->time());
 
-       const QString s1 = Ruler::format_time_with_distance(
-               diff, diff, prefix, view_.time_unit(), 12, false);  /* Always use 12 precision digits */
-       const QString s2 = util::format_time_si(
-               1 / diff, pv::util::SIPrefix::unspecified, 4, "Hz", false);
+       const QString time = Ruler::format_time_with_distance(
+                       diff, diff, prefix, view_.time_unit(), time_precision, false);
+       const QString freq = util::format_time_si(
+               1 / diff, pv::util::SIPrefix::unspecified, freq_precision, "Hz", false);
+       const QString out = QString("%1 / %2").arg(time, freq);
+
+       // Try full "{time} ms / {freq} Hz" format
+       if (max_width <= 0 || query_size(out) <= max_width) {
+               label_incomplete_ = false;
+               return out;
+       }
+
+       label_incomplete_ = true;
+
+       // Try just "{time}ms" format and gradually reduce time precision down to zero
+       for (int shrinkage=0; shrinkage <= time_precision; shrinkage++) {
+               int prec = time_precision - shrinkage ;
+
+               const QString time = Ruler::format_time_with_distance(
+                       diff, diff, prefix, view_.time_unit(),
+                       prec, false);
+
+               if (query_size(time) <= max_width)
+                       return time;
+       }
+
+       // Try no trailing digits and drop the unit to at least display something. The unit should be obvious from the ruler
+       // anyway.
+       const QString bare_number = Ruler::format_time_with_distance(
+               diff, diff, prefix, view_.time_unit(),
+               0, false, false);
+       if (query_size(bare_number) <= max_width)
+               return bare_number;
 
-       return QString("%1 / %2").arg(s1, s2);
+       // Give up.
+       return "...";
 }
 
 pair<float, float> CursorPair::get_cursor_offsets() const
index 9d450df..1dc66a3 100644 (file)
@@ -102,7 +102,8 @@ public:
        /**
         * Constructs the string to display.
         */
-       QString format_string();
+       QString format_string(qreal max_width = 0, std::function<qreal(const QString&)> query_size
+                       = [](const QString& s) -> qreal { Q_UNUSED(s); return 0; });
 
        pair<float, float> get_cursor_offsets() const;
 
index 8e7e0b6..98f55dd 100644 (file)
@@ -88,7 +88,8 @@ QString Ruler::format_time_with_distance(
        pv::util::SIPrefix prefix,
        pv::util::TimeUnit unit,
        unsigned precision,
-       bool sign)
+       bool sign,
+       bool show_unit)
 {
        const unsigned limit = 60;
 
@@ -97,7 +98,7 @@ QString Ruler::format_time_with_distance(
 
        // If we have to use samples then we have no alternative formats
        if (unit == pv::util::TimeUnit::Samples)
-               return pv::util::format_time_si_adjusted(t, prefix, precision, "sa", sign);
+               return pv::util::format_time_si_adjusted(t, prefix, precision, show_unit ? "sa" : NULL, sign);
 
        // View zoomed way out -> low precision (0), big distance (>=60s)
        // -> DD:HH:MM
@@ -109,7 +110,7 @@ QString Ruler::format_time_with_distance(
        // View zoomed way in -> high precision (>3), low step size (<1s)
        // -> HH:MM:SS.mmm... or xxxx (si unit) if less than limit seconds
        if (abs(t) < limit)
-               return pv::util::format_time_si_adjusted(t, prefix, precision, "s", sign);
+               return pv::util::format_time_si_adjusted(t, prefix, precision, show_unit ? "s" : NULL, sign);
        else
                return pv::util::format_time_minutes(t, precision, sign);
 }
index 5035bfc..3a9fea9 100644 (file)
@@ -115,7 +115,8 @@ public:
                pv::util::SIPrefix prefix = pv::util::SIPrefix::unspecified,
                pv::util::TimeUnit unit = pv::util::TimeUnit::Time,
                unsigned precision = 0,
-               bool sign = true);
+               bool sign = true,
+               bool show_unit = true);
 
        pv::util::Timestamp get_absolute_time_from_x_pos(uint32_t x) const;
        pv::util::Timestamp get_ruler_time_from_x_pos(uint32_t x) const;