From: Soeren Apel Date: Tue, 7 Nov 2017 09:56:25 +0000 (+0100) Subject: Implement segment display mode handling and update notifications X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=7daebd054e65a244dce36933cbf173b8d7532a09;p=pulseview.git Implement segment display mode handling and update notifications --- diff --git a/pv/views/trace/analogsignal.cpp b/pv/views/trace/analogsignal.cpp index cddf59c1..90e441e0 100644 --- a/pv/views/trace/analogsignal.cpp +++ b/pv/views/trace/analogsignal.cpp @@ -268,19 +268,10 @@ void AnalogSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp) if ((display_type_ == DisplayAnalog) || (display_type_ == DisplayBoth)) { paint_grid(p, y, pp.left(), pp.right()); - const deque< shared_ptr > &segments = - base_->analog_data()->analog_segments(); - if (segments.empty()) + shared_ptr segment = get_analog_segment_to_paint(); + if (!segment) return; - shared_ptr segment; - try { - segment = segments.at(current_segment_); - } catch (out_of_range) { - qDebug() << "Current analog segment out of range for signal" << base_->name(); - return; - } - const double pixels_offset = pp.pixels_offset(); const double samplerate = max(1.0, segment->samplerate()); const pv::util::Timestamp& start_time = segment->start_time(); @@ -539,19 +530,9 @@ void AnalogSignal::paint_logic_mid(QPainter &p, ViewItemPaintParams &pp) const float high_offset = y - ph + signal_margin + 0.5f; const float low_offset = y + nh - signal_margin - 0.5f; - const deque< shared_ptr > &segments = - base_->logic_data()->logic_segments(); - - if (segments.empty()) - return; - - shared_ptr segment; - try { - segment = segments.at(current_segment_); - } catch (out_of_range) { - qDebug() << "Current logic segment out of range for signal" << base_->name(); + shared_ptr segment = get_logic_segment_to_paint(); + if (!segment) return; - } double samplerate = segment->samplerate(); @@ -666,6 +647,52 @@ void AnalogSignal::paint_logic_caps(QPainter &p, QLineF *const lines, p.drawLines(lines, line - lines); } +shared_ptr AnalogSignal::get_analog_segment_to_paint() const +{ + shared_ptr segment; + + const deque< shared_ptr > &segments = + base_->analog_data()->analog_segments(); + + if (!segments.empty()) { + if (segment_display_mode_ == ShowLastSegmentOnly) + segment = segments.back(); + + if (segment_display_mode_ == ShowSingleSegmentOnly) { + try { + segment = segments.at(current_segment_); + } catch (out_of_range) { + qDebug() << "Current analog segment out of range for signal" << base_->name(); + } + } + } + + return segment; +} + +shared_ptr AnalogSignal::get_logic_segment_to_paint() const +{ + shared_ptr segment; + + const deque< shared_ptr > &segments = + base_->logic_data()->logic_segments(); + + if (!segments.empty()) { + if (segment_display_mode_ == ShowLastSegmentOnly) + segment = segments.back(); + + if (segment_display_mode_ == ShowSingleSegmentOnly) { + try { + segment = segments.at(current_segment_); + } catch (out_of_range) { + qDebug() << "Current logic segment out of range for signal" << base_->name(); + } + } + } + + return segment; +} + float AnalogSignal::get_resolution(int scale_index) { const float seq[] = {1.0f, 2.0f, 5.0f}; diff --git a/pv/views/trace/analogsignal.hpp b/pv/views/trace/analogsignal.hpp index af29c5e2..a66fb9e2 100644 --- a/pv/views/trace/analogsignal.hpp +++ b/pv/views/trace/analogsignal.hpp @@ -145,6 +145,9 @@ private: bool level, double samples_per_pixel, double pixels_offset, float x_offset, float y_offset); + shared_ptr get_analog_segment_to_paint() const; + shared_ptr get_logic_segment_to_paint() const; + /** * Computes the scale factor from the scale index and vdiv settings. */ diff --git a/pv/views/trace/logicsignal.cpp b/pv/views/trace/logicsignal.cpp index e5361716..4a3a80a7 100644 --- a/pv/views/trace/logicsignal.cpp +++ b/pv/views/trace/logicsignal.cpp @@ -192,18 +192,9 @@ void LogicSignal::paint_mid(QPainter &p, ViewItemPaintParams &pp) const float high_offset = y - signal_height_ + 0.5f; const float low_offset = y + 0.5f; - const deque< shared_ptr > &segments = - base_->logic_data()->logic_segments(); - if (segments.empty()) - return; - - shared_ptr segment; - try { - segment = segments.at(current_segment_); - } catch (out_of_range) { - qDebug() << "Current logic segment out of range for signal" << base_->name(); + shared_ptr segment = get_logic_segment_to_paint(); + if (!segment) return; - } double samplerate = segment->samplerate(); @@ -355,6 +346,30 @@ void LogicSignal::paint_caps(QPainter &p, QLineF *const lines, p.drawLines(lines, line - lines); } +shared_ptr LogicSignal::get_logic_segment_to_paint() const +{ + shared_ptr segment; + + const deque< shared_ptr > &segments = + base_->logic_data()->logic_segments(); + + if (!segments.empty()) { + if (segment_display_mode_ == ShowLastSegmentOnly) { + segment = segments.back(); + } + + if (segment_display_mode_ == ShowSingleSegmentOnly) { + try { + segment = segments.at(current_segment_); + } catch (out_of_range) { + qDebug() << "Current logic segment out of range for signal" << base_->name(); + } + } + } + + return segment; +} + void LogicSignal::init_trigger_actions(QWidget *parent) { trigger_none_ = new QAction(*get_icon(":/icons/trigger-none.svg"), diff --git a/pv/views/trace/logicsignal.hpp b/pv/views/trace/logicsignal.hpp index 9899260a..4a52d379 100644 --- a/pv/views/trace/logicsignal.hpp +++ b/pv/views/trace/logicsignal.hpp @@ -120,6 +120,8 @@ private: bool level, double samples_per_pixel, double pixels_offset, float x_offset, float y_offset); + shared_ptr get_logic_segment_to_paint() const; + void init_trigger_actions(QWidget *parent); const vector get_trigger_types() const; diff --git a/pv/views/trace/standardbar.cpp b/pv/views/trace/standardbar.cpp index d773a5c1..6363e2ec 100644 --- a/pv/views/trace/standardbar.cpp +++ b/pv/views/trace/standardbar.cpp @@ -91,6 +91,10 @@ StandardBar::StandardBar(Session &session, QWidget *parent, this, SLOT(on_new_segment(int))); connect(segment_selector_, SIGNAL(valueChanged(int)), view_, SLOT(on_segment_changed(int))); + connect(view_, SIGNAL(segment_changed(int)), + this, SLOT(on_segment_changed(int))); + connect(view_, SIGNAL(segment_display_mode_changed(bool)), + this, SLOT(on_segment_display_mode_changed(bool))); connect(view_, SIGNAL(always_zoom_to_fit_changed(bool)), this, SLOT(on_always_zoom_to_fit_changed(bool))); @@ -125,6 +129,8 @@ void StandardBar::show_multi_segment_ui(const bool state) { for (QAction* action : multi_segment_actions_) action->setVisible(state); + + on_segment_display_mode_changed(view_->segment_is_selectable()); } QAction* StandardBar::action_view_zoom_in() const @@ -195,6 +201,18 @@ void StandardBar::on_new_segment(int new_segment_id) show_multi_segment_ui(false); } +void StandardBar::on_segment_changed(int segment_id) +{ + // This is called when the current segment was changed + // by other parts of the UI, e.g. the view itself + segment_selector_->setValue(segment_id); +} + +void StandardBar::on_segment_display_mode_changed(bool segment_selectable) +{ + segment_selector_->setReadOnly(!segment_selectable); +} + } // namespace trace } // namespace views } // namespace pv diff --git a/pv/views/trace/standardbar.hpp b/pv/views/trace/standardbar.hpp index 8640b4c9..e1394372 100644 --- a/pv/views/trace/standardbar.hpp +++ b/pv/views/trace/standardbar.hpp @@ -89,6 +89,8 @@ protected Q_SLOTS: void on_always_zoom_to_fit_changed(bool state); void on_new_segment(int new_segment_id); + void on_segment_changed(int segment_id); + void on_segment_display_mode_changed(bool segment_selectable); private: vector multi_segment_actions_; diff --git a/pv/views/trace/trace.cpp b/pv/views/trace/trace.cpp index f9bd87e1..b5fc0b1b 100644 --- a/pv/views/trace/trace.cpp +++ b/pv/views/trace/trace.cpp @@ -51,6 +51,7 @@ const QColor Trace::DarkGrayBGColour = QColor(0, 0, 0, 15 * 255 / 100); Trace::Trace(shared_ptr channel) : base_(channel), axis_pen_(AxisPen), + segment_display_mode_(ShowLastSegmentOnly), // Will be overwritten by View popup_(nullptr), popup_form_(nullptr) { @@ -242,6 +243,14 @@ void Trace::set_colour(QColor colour) base_->set_colour(colour); } +void Trace::set_segment_display_mode(SegmentDisplayMode mode) +{ + segment_display_mode_ = mode; + + if (owner_) + owner_->row_item_appearance_changed(true, true); +} + void Trace::on_name_changed(const QString &text) { /* This event handler is called by SignalBase when the name was changed there */ diff --git a/pv/views/trace/trace.hpp b/pv/views/trace/trace.hpp index 407592de..75705226 100644 --- a/pv/views/trace/trace.hpp +++ b/pv/views/trace/trace.hpp @@ -63,6 +63,19 @@ class Trace : public TraceTreeItem { Q_OBJECT +public: + /** + * Allowed values for the multi-segment display mode. + * + * Note: Consider @ref View::set_segment_display_mode when updating the list. + */ + enum SegmentDisplayMode { + ShowLastSegmentOnly = 1, + ShowSingleSegmentOnly, + ShowAllSegments, + ShowAccumulatedIntensity + }; + private: static const QPen AxisPen; static const int LabelHitPadding; @@ -89,6 +102,11 @@ public: */ virtual void set_colour(QColor colour); + /** + * Configures the segment display mode to use. + */ + virtual void set_segment_display_mode(SegmentDisplayMode mode); + /** * Paints the signal label. * @param p the QPainter to paint into. @@ -146,6 +164,8 @@ protected: shared_ptr base_; QPen axis_pen_; + SegmentDisplayMode segment_display_mode_; + private: pv::widgets::Popup *popup_; QFormLayout *popup_form_; diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index 07919c28..e26e8fc2 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -125,6 +125,8 @@ bool CustomScrollArea::viewportEvent(QEvent *event) View::View(Session &session, bool is_main_view, QWidget *parent) : ViewBase(session, is_main_view, parent), splitter_(new QSplitter()), + segment_display_mode_(Trace::ShowLastSegmentOnly), + segment_selectable_(false), scale_(1e-3), offset_(0), updating_scroll_(false), @@ -255,6 +257,8 @@ void View::add_signal(const shared_ptr signal) ViewBase::add_signalbase(signal->base()); signals_.insert(signal); + signal->set_segment_display_mode(segment_display_mode_); + connect(signal->base().get(), SIGNAL(name_changed(const QString&)), this, SLOT(on_signal_name_changed())); } @@ -271,6 +275,8 @@ void View::add_decode_signal(shared_ptr signal) new DecodeTrace(session_, signal, decode_traces_.size())); decode_traces_.push_back(d); + d->set_segment_display_mode(segment_display_mode_); + connect(signal.get(), SIGNAL(name_changed(const QString&)), this, SLOT(on_signal_name_changed())); } @@ -477,6 +483,26 @@ void View::set_time_unit(pv::util::TimeUnit time_unit) } } +bool View::segment_is_selectable() const +{ + return segment_selectable_; +} + +void View::set_segment_display_mode(Trace::SegmentDisplayMode mode) +{ + for (shared_ptr signal : signals_) + signal->set_segment_display_mode(mode); + + viewport_->update(); + + segment_selectable_ = true; + + if (mode == Trace::ShowSingleSegmentOnly) + segment_selectable_ = false; + + segment_display_mode_changed(segment_selectable_); +} + void View::zoom(double steps) { zoom(steps, viewport_->width() / 2); @@ -1386,16 +1412,25 @@ void View::capture_state_updated(int state) void View::on_new_segment(int new_segment_id) { on_segment_changed(new_segment_id); + segment_changed(new_segment_id); } void View::on_segment_changed(int segment) { - current_segment_ = segment - 1; - - for (shared_ptr signal : signals_) - signal->set_current_segment(current_segment_); + switch (segment_display_mode_) { + case Trace::ShowLastSegmentOnly: + case Trace::ShowSingleSegmentOnly: + current_segment_ = segment - 1; + for (shared_ptr signal : signals_) + signal->set_current_segment(current_segment_); + viewport_->update(); + break; - viewport_->update(); + case Trace::ShowAllSegments: + case Trace::ShowAccumulatedIntensity: + default: + break; + } } void View::perform_delayed_view_update() diff --git a/pv/views/trace/view.hpp b/pv/views/trace/view.hpp index 8fd7e968..da05691f 100644 --- a/pv/views/trace/view.hpp +++ b/pv/views/trace/view.hpp @@ -37,6 +37,7 @@ #include "cursorpair.hpp" #include "flag.hpp" +#include "trace.hpp" #include "tracetreeitemowner.hpp" using std::list; @@ -190,6 +191,14 @@ public: */ unsigned int depth() const; + /** + * Returns whether the currently shown segment can be influenced + * (selected) or not. + */ + bool segment_is_selectable() const; + + void set_segment_display_mode(Trace::SegmentDisplayMode mode); + void zoom(double steps); void zoom(double steps, int offset); @@ -295,6 +304,12 @@ Q_SIGNALS: /// Emitted when the time_unit changed. void time_unit_changed(); + /// Emitted when the currently selected segment changed + void segment_changed(int segment_id); + + /// Emitted when the multi-segment display mode changed + void segment_display_mode_changed(bool segment_selectable); + public Q_SLOTS: void trigger_event(util::Timestamp location); @@ -424,6 +439,10 @@ private: /// The ID of the currently displayed segment int current_segment_; + Trace::SegmentDisplayMode segment_display_mode_; + + /// Signals whether the user can change the currently shown segment. + bool segment_selectable_; /// The view time scale in seconds per pixel. double scale_;