From 710c2a1896fbac968c82f2d1257aaabd10a48cc8 Mon Sep 17 00:00:00 2001 From: jaseg Date: Mon, 10 Jun 2019 12:56:32 +0900 Subject: [PATCH] Show relative time of flags on hover 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. --- pv/views/trace/cursorpair.cpp | 13 +++++++++++ pv/views/trace/cursorpair.hpp | 4 ++++ pv/views/trace/flag.cpp | 40 +++++++++++++++++++++++++++++++- pv/views/trace/flag.hpp | 12 ++++++---- pv/views/trace/marginwidget.cpp | 2 ++ pv/views/trace/ruler.cpp | 32 +++++++++++++++++++++++-- pv/views/trace/ruler.hpp | 5 ++++ pv/views/trace/timeitem.hpp | 4 ++++ pv/views/trace/timemarker.cpp | 7 +++++- pv/views/trace/timemarker.hpp | 4 +++- pv/views/trace/triggermarker.cpp | 11 ++++++++- pv/views/trace/triggermarker.hpp | 4 ++++ pv/views/trace/view.cpp | 23 +++++++++++------- pv/views/trace/view.hpp | 4 +++- pv/views/trace/viewwidget.cpp | 19 +++++++++++++++ pv/views/trace/viewwidget.hpp | 4 ++++ 16 files changed, 168 insertions(+), 20 deletions(-) diff --git a/pv/views/trace/cursorpair.cpp b/pv/views/trace/cursorpair.cpp index b940090a..f58db8fa 100644 --- a/pv/views/trace/cursorpair.cpp +++ b/pv/views/trace/cursorpair.cpp @@ -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); diff --git a/pv/views/trace/cursorpair.hpp b/pv/views/trace/cursorpair.hpp index f506c230..0a5ff4cb 100644 --- a/pv/views/trace/cursorpair.hpp +++ b/pv/views/trace/cursorpair.hpp @@ -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; diff --git a/pv/views/trace/flag.cpp b/pv/views/trace/flag.cpp index 64ef1047..97b21be2 100644 --- a/pv/views/trace/flag.cpp +++ b/pv/views/trace/flag.cpp @@ -19,11 +19,13 @@ #include "timemarker.hpp" #include "view.hpp" +#include "ruler.hpp" #include #include #include #include +#include #include @@ -57,7 +59,43 @@ bool Flag::enabled() const QString Flag::get_text() const { - return text_; + const shared_ptr 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 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) diff --git a/pv/views/trace/flag.hpp b/pv/views/trace/flag.hpp index 4bf6ebd5..5edf90b0 100644 --- a/pv/views/trace/flag.hpp +++ b/pv/views/trace/flag.hpp @@ -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(); diff --git a/pv/views/trace/marginwidget.cpp b/pv/views/trace/marginwidget.cpp index 86ec069b..c2d44365 100644 --- a/pv/views/trace/marginwidget.cpp +++ b/pv/views/trace/marginwidget.cpp @@ -76,6 +76,8 @@ void MarginWidget::keyPressEvent(QKeyEvent *event) if (i->selected()) i->delete_pressed(); } + + ViewWidget::keyPressEvent(event); } } // namespace trace diff --git a/pv/views/trace/ruler.cpp b/pv/views/trace/ruler.cpp index 09176659..49cff2f1 100644 --- a/pv/views/trace/ruler.cpp +++ b/pv/views/trace/ruler.cpp @@ -186,6 +186,34 @@ vector< shared_ptr > Ruler::items() time_items.begin(), time_items.end()); } +void Ruler::item_hover(const shared_ptr &item, QPoint pos) +{ + Q_UNUSED(pos); + hover_item_ = dynamic_pointer_cast(item); +} + +shared_ptr Ruler::get_reference_item() +{ + if (mouse_modifiers_ & Qt::ShiftModifier) + return nullptr; + + if (hover_item_ != nullptr) + return hover_item_; + + shared_ptr found(nullptr); + const vector< shared_ptr > 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 Ruler::get_mouse_over_item(const QPoint &pt) { const vector< shared_ptr > items(view_.time_items()); @@ -197,7 +225,7 @@ shared_ptr 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() diff --git a/pv/views/trace/ruler.hpp b/pv/views/trace/ruler.hpp index bfab7666..3a3ada52 100644 --- a/pv/views/trace/ruler.hpp +++ b/pv/views/trace/ruler.hpp @@ -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 get_reference_item(); + protected: virtual void contextMenuEvent(QContextMenuEvent *event) override; void resizeEvent(QResizeEvent*) override; + virtual void item_hover(const shared_ptr &item, QPoint pos) override; private: /** @@ -190,6 +193,8 @@ private: */ boost::optional tick_position_cache_; + shared_ptr hover_item_; + uint32_t context_menu_x_pos_; }; diff --git a/pv/views/trace/timeitem.hpp b/pv/views/trace/timeitem.hpp index ba858254..f53dda84 100644 --- a/pv/views/trace/timeitem.hpp +++ b/pv/views/trace/timeitem.hpp @@ -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. diff --git a/pv/views/trace/timemarker.cpp b/pv/views/trace/timemarker.cpp index 3249d3da..c547d63a 100644 --- a/pv/views/trace/timemarker.cpp +++ b/pv/views/trace/timemarker.cpp @@ -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()) + 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; diff --git a/pv/views/trace/timemarker.hpp b/pv/views/trace/timemarker.hpp index 28bcd73a..327a498f 100644 --- a/pv/views/trace/timemarker.hpp +++ b/pv/views/trace/timemarker.hpp @@ -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. diff --git a/pv/views/trace/triggermarker.cpp b/pv/views/trace/triggermarker.cpp index 3311f350..ee1aa15a 100644 --- a/pv/views/trace/triggermarker.cpp +++ b/pv/views/trace/triggermarker.cpp @@ -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(); } +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; diff --git a/pv/views/trace/triggermarker.hpp b/pv/views/trace/triggermarker.hpp index a97fefb0..c81fd470 100644 --- a/pv/views/trace/triggermarker.hpp +++ b/pv/views/trace/triggermarker.hpp @@ -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. diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index 4b95a806..22f23ccf 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -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 > View::time_items() const return items; } +shared_ptr View::get_reference_time_item() +{ + return ruler_->get_reference_item(); +} + double View::scale() const { return scale_; @@ -749,10 +754,10 @@ pair 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 View::cursors() const return cursors_; } -void View::add_flag(const Timestamp& time) +shared_ptr View::add_flag(const Timestamp& time) { - flags_.push_back(make_shared(*this, time, - QString("%1").arg(next_flag_text_))); + shared_ptr flag = make_shared( + *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) diff --git a/pv/views/trace/view.hpp b/pv/views/trace/view.hpp index 8f59b029..ad28a829 100644 --- a/pv/views/trace/view.hpp +++ b/pv/views/trace/view.hpp @@ -156,6 +156,8 @@ public: */ vector< shared_ptr > time_items() const; + shared_ptr 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 add_flag(const pv::util::Timestamp& time); /** * Removes a flag from the list. diff --git a/pv/views/trace/viewwidget.cpp b/pv/views/trace/viewwidget.cpp index 499471b9..d46182e4 100644 --- a/pv/views/trace/viewwidget.cpp +++ b/pv/views/trace/viewwidget.cpp @@ -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(); } diff --git a/pv/views/trace/viewwidget.hpp b/pv/views/trace/viewwidget.hpp index 0e012560..e7da1dbd 100644 --- a/pv/views/trace/viewwidget.hpp +++ b/pv/views/trace/viewwidget.hpp @@ -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 mouse_down_item_; -- 2.30.2