+ vscrollbar->setPageStep(areaSize.height());
+ vscrollbar->setSingleStep(areaSize.height() / 8);
+
+ const pair<int, int> extents = v_extents();
+
+ // Don't change the scrollbar range if there are no traces
+ if (extents.first != extents.second)
+ vscrollbar->setRange(extents.first - areaSize.height(),
+ extents.second);
+
+ if (scroll_needs_defaults_)
+ set_scroll_default();
+}
+
+void View::reset_scroll()
+{
+ scrollarea_.verticalScrollBar()->setRange(0, 0);
+}
+
+void View::set_scroll_default()
+{
+ assert(viewport_);
+
+ const QSize areaSize = viewport_->size();
+
+ const pair<int, int> extents = v_extents();
+ const int trace_height = extents.second - extents.first;
+
+ // Do all traces fit in the view?
+ if (areaSize.height() >= trace_height)
+ // Center all traces vertically
+ set_v_offset(extents.first -
+ ((areaSize.height() - trace_height) / 2));
+ else
+ // Put the first trace at the top, letting the bottom ones overflow
+ set_v_offset(extents.first);
+
+ // If we're not sure whether setting the defaults worked as
+ // the window wasn't set up entirely yet, we want to be called
+ // again later to make sure
+ scroll_needs_defaults_ = !size_finalized_;
+}
+
+void View::update_layout()
+{
+ scrollarea_.setViewportMargins(
+ header_->sizeHint().width() - Header::BaselineOffset,
+ ruler_->sizeHint().height(), 0, 0);
+ ruler_->setGeometry(viewport_->x(), 0,
+ viewport_->width(), ruler_->extended_size_hint().height());
+ header_->setGeometry(0, viewport_->y(),
+ header_->extended_size_hint().width(), viewport_->height());
+ update_scroll();
+}
+
+TraceTreeItemOwner* View::find_prevalent_trace_group(
+ const shared_ptr<sigrok::ChannelGroup> &group,
+ const unordered_map<shared_ptr<data::SignalBase>, shared_ptr<Signal> >
+ &signal_map)
+{
+ assert(group);
+
+ unordered_set<TraceTreeItemOwner*> owners;
+ vector<TraceTreeItemOwner*> owner_list;
+
+ // Make a set and a list of all the owners
+ for (const auto &channel : group->channels()) {
+ for (auto entry : signal_map) {
+ if (entry.first->channel() == channel) {
+ TraceTreeItemOwner *const o = (entry.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;
+ TraceTreeItemOwner *prevalent_owner = nullptr;
+ for (TraceTreeItemOwner *owner : owners) {
+ const size_t prevalence = std::count_if(
+ owner_list.begin(), owner_list.end(),
+ [&](TraceTreeItemOwner *o) { return o == owner; });
+ if (prevalence > max_prevalence) {
+ max_prevalence = prevalence;
+ prevalent_owner = owner;
+ }
+ }
+
+ return prevalent_owner;
+}
+
+vector< shared_ptr<Trace> > View::extract_new_traces_for_channels(
+ const vector< shared_ptr<sigrok::Channel> > &channels,
+ const unordered_map<shared_ptr<data::SignalBase>, shared_ptr<Signal> >
+ &signal_map,
+ set< shared_ptr<Trace> > &add_list)
+{
+ vector< shared_ptr<Trace> > filtered_traces;
+
+ for (const auto &channel : channels) {
+ for (auto entry : signal_map) {
+ if (entry.first->channel() == channel) {
+ shared_ptr<Trace> trace = entry.second;
+ const auto list_iter = add_list.find(trace);
+ if (list_iter == add_list.end())
+ continue;
+
+ filtered_traces.push_back(trace);
+ add_list.erase(list_iter);
+ }
+ }
+ }
+
+ return filtered_traces;
+}
+
+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) {
+ // Check all signals but...
+ for (const shared_ptr<Signal> signal : signals_) {
+ const shared_ptr<SignalData> data = signal->data();
+
+ // ...only check first segment of each
+ const vector< shared_ptr<Segment> > segments = data->segments();
+ if (!segments.empty())
+ if (segments[0]->samplerate()) {
+ set_time_unit(util::TimeUnit::Time);
+ break;
+ }
+ }
+ }