X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fview%2Fview.cpp;h=8e48ae444582ffd96b9f3d5af407dcd28b3abe17;hp=fd8781d642f06fff22f1ef2250e7fa6cfd05a6c6;hb=d6128866e740f496a1bb3c9636e188648507fc3a;hpb=4b0af0b67fe57e0880bcb8aa13b4fa807f3aaac0 diff --git a/pv/view/view.cpp b/pv/view/view.cpp index fd8781d6..8e48ae44 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -32,6 +32,8 @@ #include #include +#include + #include #include #include @@ -40,12 +42,13 @@ #include -#include "decodetrace.hpp" +#include "analogsignal.hpp" #include "header.hpp" #include "logicsignal.hpp" #include "ruler.hpp" #include "signal.hpp" #include "tracegroup.hpp" +#include "triggermarker.hpp" #include "view.hpp" #include "viewport.hpp" @@ -55,15 +58,20 @@ #include "pv/data/logicsegment.hpp" #include "pv/util.hpp" +#ifdef ENABLE_DECODE +#include "decodetrace.hpp" +#endif + using boost::shared_lock; using boost::shared_mutex; using pv::data::SignalData; using pv::data::Segment; -using pv::util::format_time; using pv::util::TimeUnit; using pv::util::Timestamp; +using std::back_inserter; +using std::copy_if; using std::deque; using std::dynamic_pointer_cast; using std::inserter; @@ -71,6 +79,7 @@ using std::list; using std::lock_guard; using std::max; using std::make_pair; +using std::make_shared; using std::min; using std::pair; using std::set; @@ -103,13 +112,14 @@ View::View(Session &session, QWidget *parent) : updating_scroll_(false), sticky_scrolling_(false), // Default setting is set in MainWindow::setup_ui() always_zoom_to_fit_(false), - tick_period_(0.0), + tick_period_(0), tick_prefix_(pv::util::SIPrefix::yocto), tick_precision_(0), time_unit_(util::TimeUnit::Time), show_cursors_(false), cursors_(new CursorPair(*this)), next_flag_text_('A'), + trigger_markers_(), hover_point_(-1, -1) { connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), @@ -203,6 +213,10 @@ vector< shared_ptr > View::time_items() const items.push_back(cursors_); items.push_back(cursors_->first()); items.push_back(cursors_->second()); + + for (auto trigger_marker : trigger_markers_) + items.push_back(trigger_marker); + return items; } @@ -275,12 +289,12 @@ void View::set_tick_precision(unsigned tick_precision) } } -double View::tick_period() const +const pv::util::Timestamp& View::tick_period() const { return tick_period_; } -void View::set_tick_period(double tick_period) +void View::set_tick_period(const pv::util::Timestamp& tick_period) { if (tick_period_ != tick_period) { tick_period_ = tick_period; @@ -345,24 +359,12 @@ void View::zoom_one_to_one() if (visible_data.empty()) return; - double samplerate = 0.0; - for (const shared_ptr d : visible_data) { - assert(d); - const vector< shared_ptr > segments = - d->segments(); - for (const shared_ptr &s : segments) - samplerate = max(samplerate, s->samplerate()); - } - - if (samplerate == 0.0) - return; - assert(viewport_); const int w = viewport_->width(); if (w <= 0) return; - set_zoom(1.0 / samplerate, w / 2); + set_zoom(1.0 / session_.get_samplerate(), w / 2); } void View::set_scale_offset(double scale, const Timestamp& offset) @@ -395,8 +397,7 @@ void View::set_scale_offset(double scale, const Timestamp& offset) set< shared_ptr > View::get_visible_data() const { - shared_lock lock(session().signals_mutex()); - const unordered_set< shared_ptr > &sigs(session().signals()); + const unordered_set< shared_ptr > sigs(session().signals()); // Make a set of all the visible data objects set< shared_ptr > visible_data; @@ -411,8 +412,7 @@ pair View::get_time_extents() const { boost::optional left_time, right_time; const set< shared_ptr > visible_data = get_visible_data(); - for (const shared_ptr d : visible_data) - { + for (const shared_ptr d : visible_data) { const vector< shared_ptr > segments = d->segments(); for (const shared_ptr &s : segments) { @@ -441,6 +441,33 @@ void View::enable_sticky_scrolling(bool state) sticky_scrolling_ = state; } +void View::enable_coloured_bg(bool state) +{ + const vector> items( + list_by_type()); + + for (shared_ptr i : items) { + // Can't cast to Trace because it's abstract, so we need to + // check for any derived classes individually + + shared_ptr a = dynamic_pointer_cast(i); + if (a) + a->set_coloured_bg(state); + + shared_ptr l = dynamic_pointer_cast(i); + if (l) + l->set_coloured_bg(state); + +#ifdef ENABLE_DECODE + shared_ptr d = dynamic_pointer_cast(i); + if (d) + d->set_coloured_bg(state); +#endif + } + + viewport_->update(); +} + bool View::cursors_shown() const { return show_cursors_; @@ -471,8 +498,10 @@ void View::add_flag(const Timestamp& time) { flags_.push_back(shared_ptr(new Flag(*this, time, QString("%1").arg(next_flag_text_)))); + next_flag_text_ = (next_flag_text_ >= 'Z') ? 'A' : (next_flag_text_ + 1); + time_item_appearance_changed(true, true); } @@ -505,22 +534,38 @@ void View::update_viewport() header_->update(); } -void View::restack_all_row_items() +void View::restack_all_trace_tree_items() { // Make a list of owners that is sorted from deepest first - const auto owners = list_row_item_owners(); - vector< RowItemOwner* > sorted_owners(owners.begin(), owners.end()); + const vector> items( + list_by_type()); + set< TraceTreeItemOwner* > owners; + for (const auto &r : items) + owners.insert(r->owner()); + vector< TraceTreeItemOwner* > sorted_owners(owners.begin(), owners.end()); sort(sorted_owners.begin(), sorted_owners.end(), - [](const RowItemOwner* a, const RowItemOwner *b) { + [](const TraceTreeItemOwner* a, const TraceTreeItemOwner *b) { return a->depth() > b->depth(); }); // Restack the items recursively for (auto &o : sorted_owners) o->restack_items(); + // Re-assign background colors + bool next_bgcolour_state = 0; + + for (auto &o : sorted_owners) + next_bgcolour_state = o->reassign_bgcolour_states(next_bgcolour_state); + // Animate the items to their destination - for (const auto &r : *this) - r->animate_to_layout_v_offset(); + for (const auto &i : items) + i->animate_to_layout_v_offset(); +} + +void View::trigger_event(util::Timestamp location) +{ + trigger_markers_.push_back(shared_ptr( + new TriggerMarker(*this, location))); } void View::get_scroll_layout(double &length, Timestamp &offset) const @@ -557,11 +602,19 @@ void View::calculate_tick_spacing() QFontMetrics m(QApplication::font()); + // Copies of the member variables with the same name, used in the calculation + // and written back afterwards, so that we don't emit signals all the time + // during the calculation. + pv::util::Timestamp tick_period = tick_period_; + pv::util::SIPrefix tick_prefix = tick_prefix_; + unsigned tick_precision = tick_precision_; + do { const double min_period = scale_ * min_width; const int order = (int)floorf(log10f(min_period)); - const double order_decimal = pow(10.0, order); + const pv::util::Timestamp order_decimal = + pow(pv::util::Timestamp(10), order); // Allow for a margin of error so that a scale unit of 1 can be used. // Otherwise, for a SU of 1 the tick period will almost always be below @@ -572,29 +625,33 @@ void View::calculate_tick_spacing() unsigned int unit = 0; do { - tp_with_margin = order_decimal * (ScaleUnits[unit++] + tp_margin); + tp_with_margin = order_decimal.convert_to() * + (ScaleUnits[unit++] + tp_margin); } while (tp_with_margin < min_period && unit < countof(ScaleUnits)); - set_tick_period(order_decimal * ScaleUnits[unit - 1]); - set_tick_prefix(static_cast( - (order - pv::util::exponent(pv::util::SIPrefix::yocto)) / 3)); + tick_period = order_decimal * ScaleUnits[unit - 1]; + tick_prefix = static_cast( + (order - pv::util::exponent(pv::util::SIPrefix::yocto)) / 3); // Precision is the number of fractional digits required, not // taking the prefix into account (and it must never be negative) - set_tick_precision(std::max((int)ceil(log10f(1 / tick_period_)), 0)); + tick_precision = std::max(ceil(log10(1 / tick_period)).convert_to(), 0); - tick_period_width = tick_period_ / scale_; + tick_period_width = (tick_period / scale_).convert_to(); - const QString label_text = - format_time(max_time, tick_prefix_, time_unit_, tick_precision_); + const QString label_text = Ruler::format_time_with_distance( + tick_period, max_time, tick_prefix, time_unit_, tick_precision); label_width = m.boundingRect(0, 0, INT_MAX, INT_MAX, Qt::AlignLeft | Qt::AlignTop, label_text).width() + MinValueSpacing; min_width += SpacingIncrement; - } while (tick_period_width < label_width); + + set_tick_period(tick_period); + set_tick_prefix(tick_prefix); + set_tick_precision(tick_precision); } void View::update_scroll() @@ -609,7 +666,7 @@ void View::update_scroll() get_scroll_layout(length, offset); length = max(length - areaSize.width(), 0.0); - int major_tick_distance = tick_period_ / scale_; + int major_tick_distance = (tick_period_ / scale_).convert_to(); horizontalScrollBar()->setPageStep(areaSize.width() / 2); horizontalScrollBar()->setSingleStep(major_tick_distance); @@ -661,15 +718,15 @@ QRectF View::label_rect(const QRectF &rect) return QRectF(); } -RowItemOwner* View::find_prevalent_trace_group( +TraceTreeItemOwner* View::find_prevalent_trace_group( const shared_ptr &group, const unordered_map, shared_ptr > &signal_map) { assert(group); - unordered_set owners; - vector owner_list; + unordered_set owners; + vector owner_list; // Make a set and a list of all the owners for (const auto &channel : group->channels()) { @@ -677,18 +734,18 @@ RowItemOwner* View::find_prevalent_trace_group( if (iter == signal_map.end()) continue; - RowItemOwner *const o = (*iter).second->owner(); + TraceTreeItemOwner *const o = (*iter).second->owner(); owner_list.push_back(o); owners.insert(o); } // Iterate through the list of owners, and find the most prevalent size_t max_prevalence = 0; - RowItemOwner *prevalent_owner = nullptr; - for (RowItemOwner *owner : owners) { + TraceTreeItemOwner *prevalent_owner = nullptr; + for (TraceTreeItemOwner *owner : owners) { const size_t prevalence = std::count_if( owner_list.begin(), owner_list.end(), - [&](RowItemOwner *o) { return o == owner; }); + [&](TraceTreeItemOwner *o) { return o == owner; }); if (prevalence > max_prevalence) { max_prevalence = prevalence; prevalent_owner = owner; @@ -706,8 +763,7 @@ vector< shared_ptr > View::extract_new_traces_for_channels( { vector< shared_ptr > filtered_traces; - for (const auto &channel : channels) - { + for (const auto &channel : channels) { const auto map_iter = signal_map.find(channel); if (map_iter == signal_map.end()) continue; @@ -728,8 +784,7 @@ void View::determine_time_unit() { // Check whether we know the sample rate and hence can use time as the unit if (time_unit_ == util::TimeUnit::Samples) { - shared_lock lock(session().signals_mutex()); - const unordered_set< shared_ptr > &sigs(session().signals()); + const unordered_set< shared_ptr > sigs(session().signals()); // Check all signals but... for (const shared_ptr signal : sigs) { @@ -771,9 +826,9 @@ bool View::eventFilter(QObject *object, QEvent *event) return QObject::eventFilter(object, event); } -bool View::viewportEvent(QEvent *e) +bool View::viewportEvent(QEvent *event) { - switch(e->type()) { + switch (event->type()) { case QEvent::Paint: case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: @@ -784,9 +839,8 @@ bool View::viewportEvent(QEvent *e) case QEvent::TouchUpdate: case QEvent::TouchEnd: return false; - default: - return QAbstractScrollArea::viewportEvent(e); + return QAbstractScrollArea::viewportEvent(event); } } @@ -814,8 +868,8 @@ void View::time_item_appearance_changed(bool label, bool content) void View::extents_changed(bool horz, bool vert) { sticky_events_ |= - (horz ? RowItemHExtentsChanged : 0) | - (vert ? RowItemVExtentsChanged : 0); + (horz ? TraceTreeItemHExtentsChanged : 0) | + (vert ? TraceTreeItemVExtentsChanged : 0); lazy_event_handler_.start(); } @@ -853,21 +907,25 @@ void View::v_scroll_value_changed() void View::signals_changed() { - vector< shared_ptr > new_top_level_items; + using sigrok::Channel; + + vector< shared_ptr > new_top_level_items; - const auto device = session_.device(); - if (!device) + if (!session_.device()) return; - shared_ptr sr_dev = device->device(); + shared_ptr sr_dev = session_.device()->device(); assert(sr_dev); + const vector< shared_ptr > channels( + sr_dev->channels()); // Make a list of traces that are being added, and a list of traces // that are being removed - const set> prev_traces = list_by_type(); + const vector> prev_trace_list = list_by_type(); + const set> prev_traces( + prev_trace_list.begin(), prev_trace_list.end()); - shared_lock lock(session_.signals_mutex()); - const unordered_set< shared_ptr > &sigs(session_.signals()); + const unordered_set< shared_ptr > sigs(session_.signals()); set< shared_ptr > traces(sigs.begin(), sigs.end()); @@ -894,15 +952,14 @@ void View::signals_changed() signal_map[sig->channel()] = sig; // Populate channel groups - for (auto entry : sr_dev->channel_groups()) - { + for (auto entry : sr_dev->channel_groups()) { const shared_ptr &group = entry.second; if (group->channels().size() <= 1) continue; // Find best trace group to add to - RowItemOwner *owner = find_prevalent_trace_group( + TraceTreeItemOwner *owner = find_prevalent_trace_group( group, signal_map); // If there is no trace group, create one @@ -933,16 +990,37 @@ void View::signals_changed() offset += extents.second; } + // Assign proper vertical offsets to each channel in the group + new_trace_group->restack_items(); + // If this is a new group, enqueue it in the new top level // items list if (!new_traces_in_group.empty() && new_trace_group) new_top_level_items.push_back(new_trace_group); } + // Enqueue the remaining logic channels in a group + vector< shared_ptr > logic_channels; + copy_if(channels.begin(), channels.end(), back_inserter(logic_channels), + [](const shared_ptr& c) { + return c->type() == sigrok::ChannelType::LOGIC; }); + + const vector< shared_ptr > non_grouped_logic_signals = + extract_new_traces_for_channels(logic_channels, signal_map, add_traces); + + if (non_grouped_logic_signals.size() > 0) { + const shared_ptr non_grouped_trace_group( + make_shared()); + for (shared_ptr trace : non_grouped_logic_signals) + non_grouped_trace_group->add_child_item(trace); + + non_grouped_trace_group->restack_items(); + new_top_level_items.push_back(non_grouped_trace_group); + } + // Enqueue the remaining channels as free ungrouped traces const vector< shared_ptr > new_top_level_signals = - extract_new_traces_for_channels(sr_dev->channels(), - signal_map, add_traces); + extract_new_traces_for_channels(channels, signal_map, add_traces); new_top_level_items.insert(new_top_level_items.end(), new_top_level_signals.begin(), new_top_level_signals.end()); @@ -952,23 +1030,22 @@ void View::signals_changed() // Remove any removed traces for (shared_ptr trace : remove_traces) { - RowItemOwner *const owner = trace->owner(); + TraceTreeItemOwner *const owner = trace->owner(); assert(owner); owner->remove_child_item(trace); } // Add and position the pending top levels items for (auto item : new_top_level_items) { + // Position the item after the last item or at the top if there is none + int offset = v_extents().second; + add_child_item(item); + item->force_to_v_offset(offset); - // Position the item after the last present item - int offset = v_extents().second; const pair extents = item->v_extents(); if (item->enabled()) - offset += -extents.first; - item->force_to_v_offset(offset); - if (item->enabled()) - offset += extents.second; + offset += (extents.second - extents.first); } update_layout(); @@ -979,9 +1056,12 @@ void View::signals_changed() void View::capture_state_updated(int state) { - if (state == Session::Running) + if (state == Session::Running) { set_time_unit(util::TimeUnit::Samples); + trigger_markers_.clear(); + } + if (state == Session::Stopped) { // After acquisition has stopped we need to re-calculate the ticks once // as it's otherwise done when the user pans or zooms, which is too late @@ -1033,10 +1113,10 @@ void View::perform_delayed_view_update() void View::process_sticky_events() { - if (sticky_events_ & RowItemHExtentsChanged) + if (sticky_events_ & TraceTreeItemHExtentsChanged) update_layout(); - if (sticky_events_ & RowItemVExtentsChanged) { - restack_all_row_items(); + if (sticky_events_ & TraceTreeItemVExtentsChanged) { + restack_all_trace_tree_items(); update_scroll(); } @@ -1046,7 +1126,9 @@ void View::process_sticky_events() void View::on_hover_point_changed() { - for (shared_ptr r : *this) + const vector> trace_tree_items( + list_by_type()); + for (shared_ptr r : trace_tree_items) r->hover_point_changed(); }