Show relative time of flags on hover
authorjaseg <git@jaseg.net>
Mon, 10 Jun 2019 03:56:32 +0000 (12:56 +0900)
committerUwe Hermann <uwe@hermann-uwe.de>
Fri, 5 Jul 2019 20:49:08 +0000 (22:49 +0200)
With this change, when the mouse hovers over any flag or cursor, the
flags change labels to show their time relative to the item being
hovered over. When hovering over the interval label of a cursor pair,
the relative time to the nearest end of the interval is shown. While
pressing shift, the regular labels are shown again.

16 files changed:
pv/views/trace/cursorpair.cpp
pv/views/trace/cursorpair.hpp
pv/views/trace/flag.cpp
pv/views/trace/flag.hpp
pv/views/trace/marginwidget.cpp
pv/views/trace/ruler.cpp
pv/views/trace/ruler.hpp
pv/views/trace/timeitem.hpp
pv/views/trace/timemarker.cpp
pv/views/trace/timemarker.hpp
pv/views/trace/triggermarker.cpp
pv/views/trace/triggermarker.hpp
pv/views/trace/view.cpp
pv/views/trace/view.hpp
pv/views/trace/viewwidget.cpp
pv/views/trace/viewwidget.hpp

index b940090ac8b68861d95ab5e16dec80f630b8cebc..f58db8fafd4ebf97b0221d1ea87d2911188e3508 100644 (file)
@@ -84,11 +84,24 @@ void CursorPair::set_time(const pv::util::Timestamp& time)
        second_->set_time(time + delta);
 }
 
+const pv::util::Timestamp CursorPair::time() const
+{
+       return (first_->time() + second_->time()) / 2.0f;
+}
+
 float CursorPair::get_x() const
 {
        return (first_->get_x() + second_->get_x()) / 2.0f;
 }
 
+const pv::util::Timestamp CursorPair::delta(const pv::util::Timestamp& other) const
+{
+       if (other < second_->time())
+               return other - first_->time();
+       else
+               return other - second_->time();
+}
+
 QPoint CursorPair::drag_point(const QRect &rect) const
 {
        return first_->drag_point(rect);
index f506c2305937dd23b62a8531461694e3c9854510..0a5ff4cb782e7bca07607b90b112587fc3a955e7 100644 (file)
@@ -76,8 +76,12 @@ public:
         */
        void set_time(const pv::util::Timestamp& time) override;
 
+       virtual const pv::util::Timestamp time() const override;
+
        float get_x() const override;
 
+       virtual const pv::util::Timestamp delta(const pv::util::Timestamp& other) const override;
+
        QPoint drag_point(const QRect &rect) const override;
 
        pv::widgets::Popup* create_popup(QWidget *parent) override;
index 64ef1047d03e6b5057753ccca7fe0a468aefee44..97b21be232888dc909fc36b4df9c573005815f39 100644 (file)
 
 #include "timemarker.hpp"
 #include "view.hpp"
+#include "ruler.hpp"
 
 #include <QColor>
 #include <QFormLayout>
 #include <QLineEdit>
 #include <QMenu>
+#include <QApplication>
 
 #include <libsigrokcxx/libsigrokcxx.hpp>
 
@@ -57,7 +59,43 @@ bool Flag::enabled() const
 
 QString Flag::get_text() const
 {
-       return text_;
+       const shared_ptr<TimeItem> ref_item = view_.get_reference_time_item();
+       if (ref_item == nullptr || ref_item.get() == this) {
+               return text_;
+       } else {
+               return Ruler::format_time_with_distance(
+                       ref_item->time(), ref_item->delta(time_),
+                       view_.tick_prefix(), view_.time_unit(), view_.tick_precision());
+       }
+}
+
+QRectF Flag::label_rect(const QRectF &rect) const
+{
+       const shared_ptr<TimeItem> ref_item = view_.get_reference_time_item();
+       if (ref_item == nullptr || ref_item.get() == this) {
+               return TimeMarker::label_rect(rect);
+
+       } else {
+               // TODO: Remove code duplication between here and cursor.cpp
+               const float x = get_x();
+
+               QFontMetrics m(QApplication::font());
+               QSize text_size = m.boundingRect(get_text()).size();
+
+               const QSizeF label_size(
+                       text_size.width() + LabelPadding.width() * 2,
+                       text_size.height() + LabelPadding.height() * 2);
+               const float top = rect.height() - label_size.height() -
+                       TimeMarker::ArrowSize - 0.5f;
+               const float height = label_size.height();
+
+               const pv::util::Timestamp& delta = ref_item->delta(time_);
+
+               if (delta >= 0)
+                       return QRectF(x, top, label_size.width(), height);
+               else
+                       return QRectF(x - label_size.width(), top, label_size.width(), height);
+       }
 }
 
 pv::widgets::Popup* Flag::create_popup(QWidget *parent)
index 4bf6ebd5db7f974a9857e733ce0b49c8cbde046f..5edf90b01ef63997595415d32e0fc6faea35c0d3 100644 (file)
@@ -60,18 +60,20 @@ public:
        /**
         * Returns true if the item is visible and enabled.
         */
-       bool enabled() const;
+       virtual bool enabled() const override;
 
        /**
         * Gets the text to show in the marker.
         */
-       QString get_text() const;
+       virtual QString get_text() const override;
 
-       pv::widgets::Popup* create_popup(QWidget *parent);
+       virtual pv::widgets::Popup* create_popup(QWidget *parent) override;
 
-       QMenu* create_header_context_menu(QWidget *parent);
+       virtual QMenu* create_header_context_menu(QWidget *parent) override;
 
-       void delete_pressed();
+       virtual void delete_pressed() override;
+
+       QRectF label_rect(const QRectF &rect) const override;
 
 private Q_SLOTS:
        void on_delete();
index 86ec069bc2370147b76b9cb16bfc606655f2cabf..c2d443651f2c740369ff0d3678d096b049ee5eaf 100644 (file)
@@ -76,6 +76,8 @@ void MarginWidget::keyPressEvent(QKeyEvent *event)
                        if (i->selected())
                                i->delete_pressed();
        }
+
+    ViewWidget::keyPressEvent(event);
 }
 
 } // namespace trace
index 09176659b55b06cb807b3157578f78051fe552bb..49cff2f14ca14633f982f266c10c3dfec29f35af 100644 (file)
@@ -186,6 +186,34 @@ vector< shared_ptr<ViewItem> > Ruler::items()
                time_items.begin(), time_items.end());
 }
 
+void Ruler::item_hover(const shared_ptr<ViewItem> &item, QPoint pos)
+{
+       Q_UNUSED(pos);
+       hover_item_ = dynamic_pointer_cast<TimeItem>(item);
+}
+
+shared_ptr<TimeItem> Ruler::get_reference_item()
+{
+       if (mouse_modifiers_ & Qt::ShiftModifier)
+               return nullptr;
+
+       if (hover_item_ != nullptr)
+               return hover_item_;
+
+       shared_ptr<TimeItem> found(nullptr);
+       const vector< shared_ptr<TimeItem> > items(view_.time_items());
+       for (auto i = items.rbegin(); i != items.rend(); i++) {
+               if ((*i)->enabled() && (*i)->selected()) {
+                       if (found == nullptr)
+                               found = *i;
+                       else
+                               return nullptr; // Return null if multiple items are selected
+               }
+       }
+
+       return found;
+}
+
 shared_ptr<ViewItem> Ruler::get_mouse_over_item(const QPoint &pt)
 {
        const vector< shared_ptr<TimeItem> > items(view_.time_items());
@@ -197,7 +225,7 @@ shared_ptr<ViewItem> Ruler::get_mouse_over_item(const QPoint &pt)
 
 void Ruler::mouseDoubleClickEvent(QMouseEvent *event)
 {
-       view_.add_flag(get_absolute_time_from_x_pos(event->x()));
+       hover_item_ = view_.add_flag(get_absolute_time_from_x_pos(event->x()));
 }
 
 void Ruler::paintEvent(QPaintEvent*)
@@ -350,7 +378,7 @@ void Ruler::invalidate_tick_position_cache()
 
 void Ruler::on_createMarker()
 {
-       view_.add_flag(get_absolute_time_from_x_pos(mouse_down_point_.x()));
+       hover_item_ = view_.add_flag(get_absolute_time_from_x_pos(mouse_down_point_.x()));
 }
 
 void Ruler::on_setZeroPosition()
index bfab766619d135c7d251a2863c7e9078c102ee81..3a3ada528c7c32d1435e48e5ae19b1416bb94ad3 100644 (file)
@@ -123,9 +123,12 @@ public:
        pv::util::Timestamp get_ruler_time_from_absolute_time(const pv::util::Timestamp& abs_time) const;
        pv::util::Timestamp get_absolute_time_from_ruler_time(const pv::util::Timestamp& ruler_time) const;
 
+       shared_ptr<TimeItem> get_reference_item();
+
 protected:
        virtual void contextMenuEvent(QContextMenuEvent *event) override;
        void resizeEvent(QResizeEvent*) override;
+       virtual void item_hover(const shared_ptr<ViewItem> &item, QPoint pos) override;
 
 private:
        /**
@@ -190,6 +193,8 @@ private:
         */
        boost::optional<TickPositions> tick_position_cache_;
 
+       shared_ptr<TimeItem> hover_item_;
+
        uint32_t context_menu_x_pos_;
 };
 
index ba858254f786aadf0477a61bfc495d1a53dd786e..f53dda84ebc2efb019ab423aba02d6756961dad8 100644 (file)
@@ -49,8 +49,12 @@ public:
         */
        virtual void set_time(const pv::util::Timestamp& time) = 0;
 
+       virtual const pv::util::Timestamp time() const = 0;
+
        virtual float get_x() const = 0;
 
+       virtual const pv::util::Timestamp delta(const pv::util::Timestamp& other) const = 0;
+
        /**
         * Drags the item to a delta relative to the drag point.
         * @param delta the offset from the drag point.
index 3249d3da77daaa7cfaf40960fcddc38fc970ea7e..c547d63a7ecbcea528c6372d1f70782d44ae44d5 100644 (file)
@@ -54,7 +54,7 @@ TimeMarker::TimeMarker(
 {
 }
 
-const pv::util::Timestamp& TimeMarker::time() const
+const pv::util::Timestamp TimeMarker::time() const
 {
        return time_;
 }
@@ -77,6 +77,11 @@ float TimeMarker::get_x() const
        return roundf(((time_ - view_.offset()) / view_.scale()).convert_to<float>()) + 0.5f;
 }
 
+const pv::util::Timestamp TimeMarker::delta(const pv::util::Timestamp& other) const
+{
+       return other - time_;
+}
+
 QPoint TimeMarker::drag_point(const QRect &rect) const
 {
        (void)rect;
index 28bcd73aba40c327662a6e47beaf43aea2006bdc..327a498ffe964295d876eb6ea40d38ddb50557f4 100644 (file)
@@ -65,7 +65,7 @@ public:
        /**
         * Gets the time of the marker.
         */
-       const pv::util::Timestamp& time() const;
+       virtual const pv::util::Timestamp time() const override;
 
        /**
         * Sets the time of the marker.
@@ -74,6 +74,8 @@ public:
 
        float get_x() const override;
 
+       virtual const pv::util::Timestamp delta(const pv::util::Timestamp& other) const override;
+
        /**
         * Gets the arrow-tip point of the time marker.
         * @param rect the rectangle of the ruler area.
index 3311f3502ba2d92540939a3ad9c5102550d07dda..ee1aa15adfb70025f03ba7c57978eeff0d0cba52 100644 (file)
@@ -52,15 +52,24 @@ bool TriggerMarker::is_draggable(QPoint pos) const
 void TriggerMarker::set_time(const pv::util::Timestamp& time)
 {
        time_ = time;
-
        view_.time_item_appearance_changed(true, true);
 }
 
+const pv::util::Timestamp TriggerMarker::time() const
+{
+       return time_;
+}
+
 float TriggerMarker::get_x() const
 {
        return ((time_ - view_.offset()) / view_.scale()).convert_to<float>();
 }
 
+const pv::util::Timestamp TriggerMarker::delta(const pv::util::Timestamp& other) const
+{
+       return other - time_;
+}
+
 QPoint TriggerMarker::drag_point(const QRect &rect) const
 {
        (void)rect;
index a97fefb0d3faf8c571e347f6b7ddfa240c31af39..c81fd47065fa24a27e0521febe9ff909a1c22e1e 100644 (file)
@@ -67,8 +67,12 @@ public:
         */
        void set_time(const pv::util::Timestamp& time) override;
 
+       virtual const pv::util::Timestamp time() const override;
+
        float get_x() const override;
 
+       virtual const pv::util::Timestamp delta(const pv::util::Timestamp& other) const override;
+
        /**
         * Gets the arrow-tip point of the time marker.
         * @param rect the rectangle of the ruler area.
index 4b95a806a490cf492ad33cb6e2b537b5f8744165..22f23ccfbca737d00efa00c22ed07075560c9184 100644 (file)
@@ -129,7 +129,7 @@ View::View(Session &session, bool is_main_view, QWidget *parent) :
 
        // Note: Place defaults in View::reset_view_state(), not here
        splitter_(new QSplitter()),
-       header_was_shrunk_(false),  // The splitter remains unchanged after a reset, so this goes here
+       header_was_shrunk_(false),      // The splitter remains unchanged after a reset, so this goes here
        sticky_scrolling_(false)  // Default setting is set in MainWindow::setup_ui()
 {
        QVBoxLayout *root_layout = new QVBoxLayout(this);
@@ -168,8 +168,8 @@ View::View(Session &session, bool is_main_view, QWidget *parent) :
        splitter_->setHandleWidth(1);  // Don't show a visible rubber band
        splitter_->setCollapsible(0, false);  // Prevent the header from collapsing
        splitter_->setCollapsible(1, false);  // Prevent the traces from collapsing
-       splitter_->setStretchFactor(0, 0);  // Prevent the panes from being resized
-       splitter_->setStretchFactor(1, 1);  // when the entire view is resized
+       splitter_->setStretchFactor(0, 0);      // Prevent the panes from being resized
+       splitter_->setStretchFactor(1, 1);      // when the entire view is resized
        splitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
 
        viewport_->installEventFilter(this);
@@ -443,6 +443,11 @@ vector< shared_ptr<TimeItem> > View::time_items() const
        return items;
 }
 
+shared_ptr<TimeItem> View::get_reference_time_item()
+{
+       return ruler_->get_reference_item();
+}
+
 double View::scale() const
 {
        return scale_;
@@ -749,10 +754,10 @@ pair<Timestamp, Timestamp> View::get_time_extents() const
                        const Timestamp start_time = s->start_time();
                        left_time = left_time ?
                                min(*left_time, start_time) :
-                                               start_time;
+                                                               start_time;
                        right_time = right_time ?
                                max(*right_time, start_time + d->max_sample_count() / samplerate) :
-                                                start_time + d->max_sample_count() / samplerate;
+                                                                start_time + d->max_sample_count() / samplerate;
                }
        }
 
@@ -832,15 +837,17 @@ shared_ptr<CursorPair> View::cursors() const
        return cursors_;
 }
 
-void View::add_flag(const Timestamp& time)
+shared_ptr<Flag> View::add_flag(const Timestamp& time)
 {
-       flags_.push_back(make_shared<Flag>(*this, time,
-               QString("%1").arg(next_flag_text_)));
+       shared_ptr<Flag> flag = make_shared<Flag>(
+                       *this, time, QString("%1").arg(next_flag_text_));
+       flags_.push_back(flag);
 
        next_flag_text_ = (next_flag_text_ >= 'Z') ? 'A' :
                (next_flag_text_ + 1);
 
        time_item_appearance_changed(true, true);
+       return flag;
 }
 
 void View::remove_flag(shared_ptr<Flag> flag)
index 8f59b02927cd62c218d1d84c2603e124c326a69e..ad28a829096039be703c02f627cd0c246fc98df0 100644 (file)
@@ -156,6 +156,8 @@ public:
         */
        vector< shared_ptr<TimeItem> > time_items() const;
 
+       shared_ptr<TimeItem> get_reference_time_item();
+
        /**
         * Returns the view time scale in seconds per pixel.
         */
@@ -298,7 +300,7 @@ public:
        /**
         * Adds a new flag at a specified time.
         */
-       void add_flag(const pv::util::Timestamp& time);
+       shared_ptr<Flag> add_flag(const pv::util::Timestamp& time);
 
        /**
         * Removes a flag from the list.
index 499471b91001bf3488d4b893cac0591548b7ad07..d46182e449e67d5f3d0e7a71a063fb746a948144 100644 (file)
@@ -284,10 +284,27 @@ void ViewWidget::mouseReleaseEvent(QMouseEvent *event)
        mouse_down_item_ = nullptr;
 }
 
+void ViewWidget::keyReleaseEvent(QKeyEvent *event)
+{
+       // Update mouse_modifiers_ also if modifiers change, but pointer doesn't move
+       if (mouse_point_.x() >= 0 && mouse_point_.y() >= 0) // mouse is inside
+               mouse_modifiers_ = event->modifiers();
+       update();
+}
+
+void ViewWidget::keyPressEvent(QKeyEvent *event)
+{
+       // Update mouse_modifiers_ also if modifiers change, but pointer doesn't move
+       if (mouse_point_.x() >= 0 && mouse_point_.y() >= 0) // mouse is inside
+               mouse_modifiers_ = event->modifiers();
+       update();
+}
+
 void ViewWidget::mouseMoveEvent(QMouseEvent *event)
 {
        assert(event);
        mouse_point_ = event->pos();
+       mouse_modifiers_ = event->modifiers();
 
        if (!event->buttons())
                item_hover(get_mouse_over_item(event->pos()), event->pos());
@@ -327,6 +344,8 @@ void ViewWidget::mouseMoveEvent(QMouseEvent *event)
 void ViewWidget::leaveEvent(QEvent*)
 {
        mouse_point_ = QPoint(-1, -1);
+       mouse_modifiers_ = Qt::NoModifier;
+       item_hover(nullptr, QPoint());
        update();
 }
 
index 0e012560859e7aa939fe746d1ebe55660d751add..e7da1dbd25cbec17da10ae49e1aa8b30b5e20c97 100644 (file)
@@ -133,6 +133,9 @@ protected:
        void mouseReleaseEvent(QMouseEvent *event);
        void mouseMoveEvent(QMouseEvent *event);
 
+       void keyPressEvent(QKeyEvent *event);
+       void keyReleaseEvent(QKeyEvent *event);
+
        void leaveEvent(QEvent *event);
 
 public Q_SLOTS:
@@ -144,6 +147,7 @@ Q_SIGNALS:
 protected:
        pv::views::trace::View &view_;
        QPoint mouse_point_;
+       Qt::KeyboardModifiers mouse_modifiers_;
        QPoint mouse_down_point_;
        pv::util::Timestamp mouse_down_offset_;
        shared_ptr<ViewItem> mouse_down_item_;