X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fview%2Fview.cpp;h=fdb9354b9315cefe4c4a06d23b00a879db7bab82;hp=42b22258dd59d2b0079ef6e1246b9382832e1166;hb=818f617924d2ed393cadd362fdafbd9d4288848f;hpb=ef454ad5cf454ae2da91b45219e1be2e010d8312 diff --git a/pv/view/view.cpp b/pv/view/view.cpp index 42b22258..fdb9354b 100644 --- a/pv/view/view.cpp +++ b/pv/view/view.cpp @@ -84,7 +84,7 @@ namespace pv { namespace view { const double View::MaxScale = 1e9; -const double View::MinScale = 1e-15; +const double View::MinScale = 1e-12; const int View::MaxScrollValue = INT_MAX / 2; const int View::MaxViewAutoUpdateRate = 25; // No more than 25 Hz with sticky scrolling @@ -104,6 +104,7 @@ View::View(Session &session, QWidget *parent) : always_zoom_to_fit_(false), tick_period_(0.0), tick_prefix_(0), + tick_precision_(0), time_unit_(util::Time), show_cursors_(false), cursors_(new CursorPair(*this)), @@ -118,7 +119,7 @@ View::View(Session &session, QWidget *parent) : connect(&session_, SIGNAL(signals_changed()), this, SLOT(signals_changed())); connect(&session_, SIGNAL(capture_state_changed(int)), - this, SLOT(data_updated())); + this, SLOT(capture_state_updated(int))); connect(&session_, SIGNAL(data_received()), this, SLOT(data_updated())); connect(&session_, SIGNAL(frame_ended()), @@ -236,6 +237,11 @@ unsigned int View::tick_prefix() const return tick_prefix_; } +unsigned int View::tick_precision() const +{ + return tick_precision_; +} + double View::tick_period() const { return tick_period_; @@ -487,10 +493,16 @@ void View::set_zoom(double scale, int offset) void View::calculate_tick_spacing() { - const double SpacingIncrement = 32.0f; - const double MinValueSpacing = 32.0f; + const double SpacingIncrement = 10.0f; + const double MinValueSpacing = 25.0f; + + // Figure out the highest numeric value visible on a label + const QSize areaSize = viewport_->size(); + const double max_time = max(fabs(offset_), + fabs(offset_ + scale_ * areaSize.width())); - double min_width = SpacingIncrement, typical_width; + double min_width = SpacingIncrement; + double label_width, tick_period_width; QFontMetrics m(QApplication::font()); @@ -500,23 +512,37 @@ void View::calculate_tick_spacing() const int order = (int)floorf(log10f(min_period)); const double order_decimal = pow(10.0, 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 + // the min_period by a small amount - and thus skipped in favor of 2. + // Note: margin assumes that SU[0] and SU[1] contain the smallest values + double tp_margin = (ScaleUnits[0] + ScaleUnits[1]) / 2.0; + double tp_with_margin; unsigned int unit = 0; do { - tick_period_ = order_decimal * ScaleUnits[unit++]; - } while (tick_period_ < min_period && - unit < countof(ScaleUnits)); + tp_with_margin = order_decimal * (ScaleUnits[unit++] + tp_margin); + } while (tp_with_margin < min_period && unit < countof(ScaleUnits)); + tick_period_ = order_decimal * ScaleUnits[unit - 1]; tick_prefix_ = (order - pv::util::FirstSIPrefixPower) / 3; - typical_width = m.boundingRect(0, 0, INT_MAX, INT_MAX, - Qt::AlignLeft | Qt::AlignTop, - format_time(offset_, tick_prefix_, time_unit_)).width() + + // Precision is the number of fractional digits required, not + // taking the prefix into account (and it must never be negative) + tick_precision_ = std::max((int)ceil(log10f(1 / tick_period_)), 0); + + tick_period_width = tick_period_ / scale_; + + const QString label_text = + format_time(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 (typical_width > tick_period_ / scale_); + } while (tick_period_width < label_width); } void View::update_scroll() @@ -647,22 +673,23 @@ vector< shared_ptr > View::extract_new_traces_for_channels( void View::determine_time_unit() { - time_unit_ = util::Samples; - - shared_lock lock(session().signals_mutex()); - const unordered_set< shared_ptr > &sigs(session().signals()); - - // Check all signals but... - for (const shared_ptr signal : sigs) { - const shared_ptr data = signal->data(); - - // ...only check first segment of each - const vector< shared_ptr > segments = data->segments(); - if (!segments.empty()) - if (segments[0]->samplerate()) { - time_unit_ = util::Time; - break; - } + // Check whether we know the sample rate and hence can use time as the unit + if (time_unit_ == util::Samples) { + shared_lock lock(session().signals_mutex()); + const unordered_set< shared_ptr > &sigs(session().signals()); + + // Check all signals but... + for (const shared_ptr signal : sigs) { + const shared_ptr data = signal->data(); + + // ...only check first segment of each + const vector< shared_ptr > segments = data->segments(); + if (!segments.empty()) + if (segments[0]->samplerate()) { + time_unit_ = util::Time; + break; + } + } } } @@ -896,14 +923,20 @@ void View::signals_changed() viewport_->update(); } -void View::data_updated() +void View::capture_state_updated(int state) { // Reset "always zoom to fit" when we change to the stopped state - if (always_zoom_to_fit_ && (session_.get_capture_state() == Session::Stopped)) { + if (always_zoom_to_fit_ && (state == Session::Stopped)) { always_zoom_to_fit_ = false; always_zoom_to_fit_changed(false); } + if (state == Session::Running) + time_unit_ = util::Samples; +} + +void View::data_updated() +{ if (always_zoom_to_fit_ || sticky_scrolling_) { if (!delayed_view_updater_.isActive()) delayed_view_updater_.start();