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 49b9467c1642737a1a995df5adcb622e2bbddfa1..237ca7f059f1e589dac4dd9e6f6bc29120a6e3c5 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 933eb8fff33e0c3aaf2ed255dc2a6e00bc5b8754..562584c2f903fdde8f93b0bbd32005bc58c1673b 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 9d450df6b69af06e1dcc9a0830f036c9b18c3f23..1dc66a32b8eef8bd622c199e75f9ddf09872dd65 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 8e7e0b676d435c26d05e6dca9f1cfea142a6c469..98f55ddb06fb72ebac091263abb65c062e87bfc5 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 5035bfc83bffc9962f8a7d06d782c1fae5dcd232..3a9fea910d26febacb20cba1d156fc2486210cbc 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;