22 #include <libsigrokdecode/libsigrokdecode.h>
33 #include <unordered_set>
35 #include <boost/thread/locks.hpp>
37 #include <QApplication>
39 #include <QFontMetrics>
40 #include <QMouseEvent>
43 #include <libsigrokcxx/libsigrokcxx.hpp>
62 using boost::shared_lock;
63 using boost::shared_mutex;
70 using std::back_inserter;
73 using std::dynamic_pointer_cast;
76 using std::lock_guard;
79 using std::make_shared;
83 using std::set_difference;
84 using std::shared_ptr;
85 using std::unordered_map;
86 using std::unordered_set;
105 ruler_(new
Ruler(*this)),
106 header_(new
Header(*this)),
109 updating_scroll_(false),
110 sticky_scrolling_(false),
111 always_zoom_to_fit_(false),
116 show_cursors_(false),
118 next_flag_text_(
'A'),
122 connect(horizontalScrollBar(), SIGNAL(valueChanged(
int)),
124 connect(verticalScrollBar(), SIGNAL(valueChanged(
int)),
129 connect(&
session_, SIGNAL(capture_state_changed(
int)),
131 connect(&
session_, SIGNAL(data_received()),
133 connect(&
session_, SIGNAL(frame_ended()),
137 ruler_, SLOT(clear_selection()));
139 header_, SLOT(clear_selection()));
161 ruler_->installEventFilter(
this);
162 header_->installEventFilter(
this);
208 const vector<shared_ptr<Flag>> f(
flags());
209 vector<shared_ptr<TimeItem>> items(f.begin(), f.end());
212 items.push_back(
cursors_->second());
215 items.push_back(trigger_marker);
248 return -verticalScrollBar()->sliderPosition();
253 verticalScrollBar()->setSliderPosition(offset);
337 const Timestamp delta = extents.second - extents.first;
356 if (visible_data.empty())
397 const unordered_set< shared_ptr<Signal> > sigs(
session().signals());
400 set< shared_ptr<SignalData> > visible_data;
401 for (
const shared_ptr<Signal> sig : sigs)
403 visible_data.insert(sig->data());
410 boost::optional<Timestamp> left_time, right_time;
412 for (
const shared_ptr<SignalData> d : visible_data) {
413 const vector< shared_ptr<Segment> > segments =
415 for (
const shared_ptr<Segment> &s : segments) {
416 double samplerate = s->samplerate();
417 samplerate = (samplerate <= 0.0) ? 1.0 : samplerate;
419 const Timestamp start_time = s->start_time();
420 left_time = left_time ?
421 min(*left_time, start_time) :
423 right_time = right_time ?
424 max(*right_time, start_time + d->max_sample_count() / samplerate) :
425 start_time + d->max_sample_count() / samplerate;
429 if (!left_time || !right_time)
430 return make_pair(0, 0);
432 assert(*left_time < *right_time);
433 return make_pair(*left_time, *right_time);
443 const vector<shared_ptr<TraceTreeItem>> items(
444 list_by_type<TraceTreeItem>());
446 for (shared_ptr<TraceTreeItem> i : items) {
450 shared_ptr<AnalogSignal> a = dynamic_pointer_cast<
AnalogSignal>(i);
454 shared_ptr<LogicSignal> l = dynamic_pointer_cast<
LogicSignal>(i);
458 shared_ptr<DecodeTrace> d = dynamic_pointer_cast<
DecodeTrace>(i);
494 flags_.push_back(shared_ptr<Flag>(
new Flag(*
this, time,
513 [](
const shared_ptr<Flag> &a,
const shared_ptr<Flag> &b) {
514 return a->time() < b->time();
535 const vector<shared_ptr<TraceTreeItem>> items(
536 list_by_type<TraceTreeItem>());
537 set< TraceTreeItemOwner* > owners;
538 for (
const auto &r : items)
539 owners.insert(r->owner());
540 vector< TraceTreeItemOwner* > sorted_owners(owners.begin(), owners.end());
541 sort(sorted_owners.begin(), sorted_owners.end(),
543 return a->
depth() > b->depth(); });
546 for (
auto &o : sorted_owners)
550 bool next_bgcolour_state = 0;
552 for (
auto &o : sorted_owners)
553 next_bgcolour_state = o->reassign_bgcolour_states(next_bgcolour_state);
556 for (
const auto &i : items)
557 i->animate_to_layout_v_offset();
569 length = ((extents.second - extents.first) /
scale_).convert_to<
double>();
587 const double SpacingIncrement = 10.0f;
588 const double MinValueSpacing = 40.0f;
591 const QSize areaSize =
viewport_->size();
595 double min_width = SpacingIncrement;
596 double label_width, tick_period_width;
598 QFontMetrics m(QApplication::font());
608 const double min_period =
scale_ * min_width;
610 const int order = (int)floorf(log10f(min_period));
619 double tp_with_margin;
620 unsigned int unit = 0;
623 tp_with_margin = order_decimal.convert_to<
double>() *
627 tick_period = order_decimal *
ScaleUnits[unit - 1];
633 tick_precision = std::max(ceil(log10(1 / tick_period)).convert_to<int>(), 0);
635 tick_period_width = (tick_period /
scale_).convert_to<double>();
638 tick_period, max_time, tick_prefix,
time_unit_, tick_precision);
640 label_width = m.boundingRect(0, 0, INT_MAX, INT_MAX,
641 Qt::AlignLeft | Qt::AlignTop, label_text).width() +
644 min_width += SpacingIncrement;
645 }
while (tick_period_width < label_width);
656 const QSize areaSize =
viewport_->size();
662 length = max(length - areaSize.width(), 0.0);
666 horizontalScrollBar()->setPageStep(areaSize.width() / 2);
667 horizontalScrollBar()->setSingleStep(major_tick_distance);
672 horizontalScrollBar()->setRange(0, length);
673 horizontalScrollBar()->setSliderPosition(offset.convert_to<
double>());
676 horizontalScrollBar()->setSliderPosition(
683 verticalScrollBar()->setPageStep(areaSize.height());
684 verticalScrollBar()->setSingleStep(areaSize.height() / 8);
686 const pair<int, int> extents =
v_extents();
687 verticalScrollBar()->setRange(extents.first - (areaSize.height() / 2),
688 extents.second - (areaSize.height() / 2));
717 const shared_ptr<sigrok::ChannelGroup> &group,
718 const unordered_map<shared_ptr<sigrok::Channel>, shared_ptr<Signal> >
723 unordered_set<TraceTreeItemOwner*> owners;
724 vector<TraceTreeItemOwner*> owner_list;
727 for (
const auto &channel : group->channels()) {
728 const auto iter = signal_map.find(channel);
729 if (iter == signal_map.end())
733 owner_list.push_back(o);
738 size_t max_prevalence = 0;
741 const size_t prevalence = std::count_if(
742 owner_list.begin(), owner_list.end(),
744 if (prevalence > max_prevalence) {
745 max_prevalence = prevalence;
746 prevalent_owner = owner;
750 return prevalent_owner;
754 const vector< shared_ptr<sigrok::Channel> > &channels,
755 const unordered_map<shared_ptr<sigrok::Channel>, shared_ptr<Signal> >
757 set< shared_ptr<Trace> > &add_list)
759 vector< shared_ptr<Trace> > filtered_traces;
761 for (
const auto &channel : channels) {
762 const auto map_iter = signal_map.find(channel);
763 if (map_iter == signal_map.end())
766 shared_ptr<Trace> trace = (*map_iter).second;
767 const auto list_iter = add_list.find(trace);
768 if (list_iter == add_list.end())
771 filtered_traces.push_back(trace);
772 add_list.erase(list_iter);
775 return filtered_traces;
782 const unordered_set< shared_ptr<Signal> > sigs(
session().signals());
785 for (
const shared_ptr<Signal> signal : sigs) {
786 const shared_ptr<SignalData> data = signal->data();
789 const vector< shared_ptr<Segment> > segments = data->segments();
790 if (!segments.empty())
791 if (segments[0]->samplerate()) {
801 const QEvent::Type type =
event->type();
802 if (type == QEvent::MouseMove) {
804 const QMouseEvent *
const mouse_event = (QMouseEvent*)event;
807 else if (
object ==
ruler_)
816 }
else if (type == QEvent::Leave) {
821 return QObject::eventFilter(
object, event);
828 case QEvent::MouseButtonPress:
829 case QEvent::MouseButtonRelease:
830 case QEvent::MouseButtonDblClick:
831 case QEvent::MouseMove:
833 case QEvent::TouchBegin:
834 case QEvent::TouchUpdate:
835 case QEvent::TouchEnd:
838 return QAbstractScrollArea::viewportEvent(e);
883 const int range = horizontalScrollBar()->maximum();
905 using sigrok::Channel;
907 vector< shared_ptr<TraceTreeItem> > new_top_level_items;
913 shared_ptr<sigrok::Device> sr_dev = device->device();
916 const vector< shared_ptr<Channel> > channels(
921 const vector<shared_ptr<Trace>> prev_trace_list = list_by_type<Trace>();
922 const set<shared_ptr<Trace>> prev_traces(
923 prev_trace_list.begin(), prev_trace_list.end());
927 set< shared_ptr<Trace> > traces(sigs.begin(), sigs.end());
930 const vector< shared_ptr<DecodeTrace> > decode_traces(
931 session().get_decode_signals());
932 traces.insert(decode_traces.begin(), decode_traces.end());
935 set< shared_ptr<Trace> > add_traces;
936 set_difference(traces.begin(), traces.end(),
937 prev_traces.begin(), prev_traces.end(),
938 inserter(add_traces, add_traces.begin()));
940 set< shared_ptr<Trace> > remove_traces;
941 set_difference(prev_traces.begin(), prev_traces.end(),
942 traces.begin(), traces.end(),
943 inserter(remove_traces, remove_traces.begin()));
946 unordered_map<shared_ptr<sigrok::Channel>, shared_ptr<Signal> >
948 for (
const shared_ptr<Signal> &sig : sigs)
949 signal_map[sig->channel()] = sig;
952 for (
auto entry : sr_dev->channel_groups()) {
953 const shared_ptr<sigrok::ChannelGroup> &group = entry.second;
955 if (group->channels().size() <= 1)
963 shared_ptr<TraceGroup> new_trace_group;
966 owner = new_trace_group.get();
971 const vector< shared_ptr<Trace> > new_traces_in_group =
973 signal_map, add_traces);
976 const pair<int, int> prev_v_extents = owner->
v_extents();
977 int offset = prev_v_extents.second - prev_v_extents.first;
978 for (shared_ptr<Trace> trace : new_traces_in_group) {
982 const pair<int, int> extents = trace->v_extents();
983 if (trace->enabled())
984 offset += -extents.first;
985 trace->force_to_v_offset(offset);
986 if (trace->enabled())
987 offset += extents.second;
992 if (!new_traces_in_group.empty() && new_trace_group)
993 new_top_level_items.push_back(new_trace_group);
997 vector< shared_ptr<Channel> > logic_channels;
998 copy_if(channels.begin(), channels.end(), back_inserter(logic_channels),
999 [](
const shared_ptr<Channel>& c) {
1000 return c->type() == sigrok::ChannelType::LOGIC; });
1001 const vector< shared_ptr<Trace> > non_grouped_logic_signals =
1003 signal_map, add_traces);
1004 const shared_ptr<TraceGroup> non_grouped_trace_group(
1005 make_shared<TraceGroup>());
1006 for (shared_ptr<Trace> trace : non_grouped_logic_signals)
1007 non_grouped_trace_group->add_child_item(trace);
1008 new_top_level_items.push_back(non_grouped_trace_group);
1011 const vector< shared_ptr<Trace> > new_top_level_signals =
1013 signal_map, add_traces);
1014 new_top_level_items.insert(new_top_level_items.end(),
1015 new_top_level_signals.begin(), new_top_level_signals.end());
1018 new_top_level_items.insert(new_top_level_items.end(),
1019 add_traces.begin(), add_traces.end());
1022 for (shared_ptr<Trace> trace : remove_traces) {
1029 for (
auto item : new_top_level_items) {
1034 const pair<int, int> extents = item->v_extents();
1035 if (item->enabled())
1036 offset += -extents.first;
1037 item->force_to_v_offset(offset);
1038 if (item->enabled())
1039 offset += extents.second;
1093 const QSize areaSize =
viewport_->size();
1094 length = max(length - areaSize.width(), 0.0);
1120 const vector<shared_ptr<TraceTreeItem>> trace_tree_items(
1121 list_by_type<TraceTreeItem>());
1122 for (shared_ptr<TraceTreeItem> r : trace_tree_items)
1123 r->hover_point_changed();
std::shared_ptr< CursorPair > cursors() const
void determine_time_unit()
void set_tick_period(const pv::util::Timestamp &tick_period)
QRectF label_rect(const QRectF &rect)
int owner_visual_v_offset() const
void restack_all_trace_tree_items()
static const pv::util::Timestamp MaxScale
std::pair< int, int > v_extents() const
pv::util::SIPrefix tick_prefix() const
void paint_label(QPainter &p, const QRect &rect, bool hover)
double scale_
The view time scale in seconds per pixel.
std::list< std::shared_ptr< Flag > > flags_
void set_scale_offset(double scale, const pv::util::Timestamp &offset)
pv::util::Timestamp offset_
The view time offset in seconds.
static const int ScaleUnits[3]
std::vector< std::shared_ptr< Flag > > flags() const
void v_scroll_value_changed()
void row_item_appearance_changed(bool label, bool content)
void set_scale(double scale)
TraceTreeItemOwner * find_prevalent_trace_group(const std::shared_ptr< sigrok::ChannelGroup > &group, const std::unordered_map< std::shared_ptr< sigrok::Channel >, std::shared_ptr< Signal > > &signal_map)
void set_zoom(double scale, int offset)
unsigned int tick_precision() const
void time_item_appearance_changed(bool label, bool content)
void process_sticky_events()
static const pv::util::Timestamp MinScale
void extents_changed(bool horz, bool vert)
int exponent(SIPrefix prefix)
Returns the exponent that corresponds to a given prefix.
const std::unordered_set< std::shared_ptr< view::Signal > > signals() const
void on_hover_point_changed()
static QString format_time_with_distance(const pv::util::Timestamp &distance, const pv::util::Timestamp &t, pv::util::SIPrefix prefix=pv::util::SIPrefix::unspecified, pv::util::TimeUnit unit=pv::util::TimeUnit::Time, unsigned precision=0, bool sign=true)
void calculate_tick_spacing()
bool viewportEvent(QEvent *e)
static const int MaxScrollValue
unsigned int tick_precision_
bool eventFilter(QObject *object, QEvent *event)
void tick_prefix_changed()
Emitted when the tick_prefix changed.
void perform_delayed_view_update()
void trigger_event(util::Timestamp location)
void set_tick_precision(unsigned tick_precision)
QTimer lazy_event_handler_
std::shared_ptr< devices::Device > device() const
void get_scroll_layout(double &length, pv::util::Timestamp &offset) const
util::TimeUnit time_unit() const
void time_unit_changed()
Emitted when the time_unit changed.
QSize extended_size_hint() const
const QPoint & hover_point() const
static std::vector< std::shared_ptr< Trace > > extract_new_traces_for_channels(const std::vector< std::shared_ptr< sigrok::Channel > > &channels, const std::unordered_map< std::shared_ptr< sigrok::Channel >, std::shared_ptr< Signal > > &signal_map, std::set< std::shared_ptr< Trace > > &add_list)
double get_samplerate() const
void scale_changed()
Emitted when the scale changed.
void set_time_unit(pv::util::TimeUnit time_unit)
bool cursors_shown() const
void tick_precision_changed()
Emitted when the tick_precision changed.
std::pair< pv::util::Timestamp, pv::util::Timestamp > get_time_extents() const
std::vector< std::shared_ptr< TriggerMarker > > trigger_markers_
capture_state get_capture_state() const
void set_coloured_bg(bool state)
void add_child_item(std::shared_ptr< TraceTreeItem > item)
void set_tick_prefix(pv::util::SIPrefix tick_prefix)
void set_v_offset(int offset)
std::shared_ptr< CursorPair > cursors_
void show_cursors(bool show=true)
void zoom_fit(bool gui_state)
std::vector< std::shared_ptr< TimeItem > > time_items() const
void offset_changed()
Emitted when the offset changed.
void enable_sticky_scrolling(bool state)
void sticky_scrolling_changed(bool state)
void resizeEvent(QResizeEvent *e)
virtual pv::view::View * view()
void set_offset(const pv::util::Timestamp &offset)
util::TimeUnit time_unit_
unsigned int sticky_events_
pv::util::SIPrefix tick_prefix_
unsigned int depth() const
void enable_coloured_bg(bool state)
const pv::util::Timestamp & offset() const
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 24 >, boost::multiprecision::et_off > Timestamp
Timestamp type providing yoctosecond resolution.
const pv::util::Timestamp & tick_period() const
virtual unsigned int depth() const =0
void capture_state_updated(int state)
void add_flag(const pv::util::Timestamp &time)
std::set< std::shared_ptr< pv::data::SignalData > > get_visible_data() const
void hover_point_changed()
View(Session &session, QWidget *parent=0)
void h_scroll_value_changed(int value)
void remove_flag(std::shared_ptr< Flag > flag)
void remove_child_item(std::shared_ptr< TraceTreeItem > item)
pv::util::Timestamp tick_period_
static const int MaxViewAutoUpdateRate
QTimer delayed_view_updater_
void tick_period_changed()
Emitted when the tick_period changed.
void always_zoom_to_fit_changed(bool state)