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 b940090..f58db8f 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 f506c23..0a5ff4c 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 64ef104..97b21be 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 4bf6ebd..5edf90b 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 86ec069..c2d4436 100644 (file)
@@ -76,6 +76,8 @@ void MarginWidget::keyPressEvent(QKeyEvent *event)
                        if (i->selected())
                                i->delete_pressed();
        }
+
+    ViewWidget::keyPressEvent(event);
 }
 
 } // namespace trace
index 0917665..49cff2f 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 bfab766..3a3ada5 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 ba85825..f53dda8 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 3249d3d..c547d63 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 28bcd73..327a498 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 3311f35..ee1aa15 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 a97fefb..c81fd47 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 4b95a80..22f23cc 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 8f59b02..ad28a82 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 499471b..d46182e 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 0e01256..e7da1db 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_;