Implement segment display mode handling and update notifications

This commit is contained in:
Soeren Apel 2017-11-07 10:56:25 +01:00
parent aa8da126bb
commit 7daebd054e
10 changed files with 189 additions and 39 deletions

View File

@ -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<pv::data::AnalogSegment> > &segments =
base_->analog_data()->analog_segments();
if (segments.empty())
shared_ptr<pv::data::AnalogSegment> segment = get_analog_segment_to_paint();
if (!segment)
return;
shared_ptr<pv::data::AnalogSegment> 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,20 +530,10 @@ 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<pv::data::LogicSegment> > &segments =
base_->logic_data()->logic_segments();
if (segments.empty())
shared_ptr<pv::data::LogicSegment> segment = get_logic_segment_to_paint();
if (!segment)
return;
shared_ptr<pv::data::LogicSegment> segment;
try {
segment = segments.at(current_segment_);
} catch (out_of_range) {
qDebug() << "Current logic segment out of range for signal" << base_->name();
return;
}
double samplerate = segment->samplerate();
// Show sample rate as 1Hz when it is unknown
@ -666,6 +647,52 @@ void AnalogSignal::paint_logic_caps(QPainter &p, QLineF *const lines,
p.drawLines(lines, line - lines);
}
shared_ptr<pv::data::AnalogSegment> AnalogSignal::get_analog_segment_to_paint() const
{
shared_ptr<pv::data::AnalogSegment> segment;
const deque< shared_ptr<pv::data::AnalogSegment> > &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<pv::data::LogicSegment> AnalogSignal::get_logic_segment_to_paint() const
{
shared_ptr<pv::data::LogicSegment> segment;
const deque< shared_ptr<pv::data::LogicSegment> > &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};

View File

@ -145,6 +145,9 @@ private:
bool level, double samples_per_pixel, double pixels_offset,
float x_offset, float y_offset);
shared_ptr<pv::data::AnalogSegment> get_analog_segment_to_paint() const;
shared_ptr<pv::data::LogicSegment> get_logic_segment_to_paint() const;
/**
* Computes the scale factor from the scale index and vdiv settings.
*/

View File

@ -192,19 +192,10 @@ 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<pv::data::LogicSegment> > &segments =
base_->logic_data()->logic_segments();
if (segments.empty())
shared_ptr<pv::data::LogicSegment> segment = get_logic_segment_to_paint();
if (!segment)
return;
shared_ptr<pv::data::LogicSegment> segment;
try {
segment = segments.at(current_segment_);
} catch (out_of_range) {
qDebug() << "Current logic segment out of range for signal" << base_->name();
return;
}
double samplerate = segment->samplerate();
// Show sample rate as 1Hz when it is unknown
@ -355,6 +346,30 @@ void LogicSignal::paint_caps(QPainter &p, QLineF *const lines,
p.drawLines(lines, line - lines);
}
shared_ptr<pv::data::LogicSegment> LogicSignal::get_logic_segment_to_paint() const
{
shared_ptr<pv::data::LogicSegment> segment;
const deque< shared_ptr<pv::data::LogicSegment> > &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"),

View File

@ -120,6 +120,8 @@ private:
bool level, double samples_per_pixel, double pixels_offset,
float x_offset, float y_offset);
shared_ptr<pv::data::LogicSegment> get_logic_segment_to_paint() const;
void init_trigger_actions(QWidget *parent);
const vector<int32_t> get_trigger_types() const;

View File

@ -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

View File

@ -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<QAction*> multi_segment_actions_;

View File

@ -51,6 +51,7 @@ const QColor Trace::DarkGrayBGColour = QColor(0, 0, 0, 15 * 255 / 100);
Trace::Trace(shared_ptr<data::SignalBase> 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 */

View File

@ -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<data::SignalBase> base_;
QPen axis_pen_;
SegmentDisplayMode segment_display_mode_;
private:
pv::widgets::Popup *popup_;
QFormLayout *popup_form_;

View File

@ -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> 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<data::DecodeSignal> 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> 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;
switch (segment_display_mode_) {
case Trace::ShowLastSegmentOnly:
case Trace::ShowSingleSegmentOnly:
current_segment_ = segment - 1;
for (shared_ptr<Signal> signal : signals_)
signal->set_current_segment(current_segment_);
viewport_->update();
break;
for (shared_ptr<Signal> signal : signals_)
signal->set_current_segment(current_segment_);
viewport_->update();
case Trace::ShowAllSegments:
case Trace::ShowAccumulatedIntensity:
default:
break;
}
}
void View::perform_delayed_view_update()

View File

@ -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_;