+void AnalogSignal::update_conversion_type()
+{
+ base_->set_conversion_type(conversion_type_);
+
+ if (owner_)
+ owner_->row_item_appearance_changed(false, true);
+}
+
+void AnalogSignal::perform_autoranging(bool force_update)
+{
+ const deque< shared_ptr<pv::data::AnalogSegment> > &segments =
+ base_->analog_data()->analog_segments();
+
+ if (segments.empty())
+ return;
+
+ static double prev_min = 0, prev_max = 0;
+ double min = 0, max = 0;
+
+ for (shared_ptr<pv::data::AnalogSegment> segment : segments) {
+ pair<double, double> mm = segment->get_min_max();
+ min = std::min(min, mm.first);
+ max = std::max(max, mm.second);
+ }
+
+ if ((min == prev_min) && (max == prev_max) && !force_update)
+ return;
+
+ prev_min = min;
+ prev_max = max;
+
+ // Use all divs for the positive range if there are no negative values
+ if ((min == 0) && (neg_vdivs_ > 0)) {
+ pos_vdivs_ += neg_vdivs_;
+ neg_vdivs_ = 0;
+ }
+
+ // Split up the divs if there are negative values but no negative divs
+ if ((min < 0) && (neg_vdivs_ == 0)) {
+ neg_vdivs_ = pos_vdivs_ / 2;
+ pos_vdivs_ -= neg_vdivs_;
+ }
+
+ double min_value_per_div;
+ if ((pos_vdivs_ > 0) && (neg_vdivs_ > 0))
+ min_value_per_div = std::max(max / pos_vdivs_, -min / neg_vdivs_);
+ else if (pos_vdivs_ > 0)
+ min_value_per_div = max / pos_vdivs_;
+ else
+ min_value_per_div = -min / neg_vdivs_;
+
+ // Find first scale value that is bigger than the value we need
+ for (int i = MinScaleIndex; i < MaxScaleIndex; i++)
+ if (get_resolution(i) > min_value_per_div) {
+ scale_index_ = i;
+ break;
+ }
+
+ update_scale();
+}
+
+void AnalogSignal::populate_popup_form(QWidget *parent, QFormLayout *form)
+{
+ // Add the standard options
+ Signal::populate_popup_form(parent, form);
+
+ QFormLayout *const layout = new QFormLayout;
+
+ // Add the number of vdivs
+ QSpinBox *pvdiv_sb = new QSpinBox(parent);
+ pvdiv_sb->setRange(0, MaximumVDivs);
+ pvdiv_sb->setValue(pos_vdivs_);
+ connect(pvdiv_sb, SIGNAL(valueChanged(int)),
+ this, SLOT(on_pos_vdivs_changed(int)));
+ layout->addRow(tr("Number of pos vertical divs"), pvdiv_sb);
+
+ QSpinBox *nvdiv_sb = new QSpinBox(parent);
+ nvdiv_sb->setRange(0, MaximumVDivs);
+ nvdiv_sb->setValue(neg_vdivs_);
+ connect(nvdiv_sb, SIGNAL(valueChanged(int)),
+ this, SLOT(on_neg_vdivs_changed(int)));
+ layout->addRow(tr("Number of neg vertical divs"), nvdiv_sb);
+
+ // Add the vertical resolution
+ resolution_cb_ = new QComboBox(parent);
+
+ for (int i = MinScaleIndex; i < MaxScaleIndex; i++) {
+ const QString label = QString("%1").arg(get_resolution(i));
+ resolution_cb_->insertItem(0, label, QVariant(i));
+ }
+
+ int cur_idx = resolution_cb_->findData(QVariant(scale_index_));
+ resolution_cb_->setCurrentIndex(cur_idx);
+
+ connect(resolution_cb_, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(on_resolution_changed(int)));
+
+ QGridLayout *const vdiv_layout = new QGridLayout;
+ QLabel *const vdiv_unit = new QLabel(tr("V/div"));
+ vdiv_layout->addWidget(resolution_cb_, 0, 0);
+ vdiv_layout->addWidget(vdiv_unit, 0, 1);
+
+ layout->addRow(tr("Vertical resolution"), vdiv_layout);
+
+ // Add the autoranging checkbox
+ QCheckBox* autoranging_cb = new QCheckBox();
+ autoranging_cb->setCheckState(autoranging_ ? Qt::Checked : Qt::Unchecked);
+
+ connect(autoranging_cb, SIGNAL(stateChanged(int)),
+ this, SLOT(on_autoranging_changed(int)));
+
+ layout->addRow(tr("Autoranging"), autoranging_cb);
+
+ // Add the conversion type dropdown
+ conversion_cb_ = new QComboBox();
+
+ conversion_cb_->addItem("none", data::SignalBase::NoConversion);
+ conversion_cb_->addItem("to logic via threshold", data::SignalBase::A2LConversionByTreshold);
+ conversion_cb_->addItem("to logic via schmitt-trigger", data::SignalBase::A2LConversionBySchmittTrigger);
+
+ cur_idx = conversion_cb_->findData(QVariant(conversion_type_));
+ conversion_cb_->setCurrentIndex(cur_idx);
+
+ layout->addRow(tr("Conversion"), conversion_cb_);
+
+ connect(conversion_cb_, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(on_conversion_changed(int)));
+
+ // Add the display type dropdown
+ display_type_cb_ = new QComboBox();
+
+ display_type_cb_->addItem(tr("Analog"), DisplayAnalog);
+ display_type_cb_->addItem(tr("Converted"), DisplayConverted);
+ display_type_cb_->addItem(tr("Both"), DisplayBoth);
+
+ cur_idx = display_type_cb_->findData(QVariant(display_type_));
+ display_type_cb_->setCurrentIndex(cur_idx);
+
+ layout->addRow(tr("Traces to show:"), display_type_cb_);
+
+ connect(display_type_cb_, SIGNAL(currentIndexChanged(int)),
+ this, SLOT(on_display_type_changed(int)));
+
+ form->addRow(layout);
+}
+
+void AnalogSignal::on_samples_added()
+{
+ perform_autoranging();
+
+ if (owner_) {
+ // Call order is important, otherwise the lazy event handler won't work
+ owner_->extents_changed(false, true);
+ owner_->row_item_appearance_changed(false, true);
+ }
+}
+
+void AnalogSignal::on_pos_vdivs_changed(int vdivs)
+{
+ pos_vdivs_ = vdivs;
+
+ if (autoranging_)
+ perform_autoranging(true);
+
+ if (owner_) {
+ // Call order is important, otherwise the lazy event handler won't work
+ owner_->extents_changed(false, true);
+ owner_->row_item_appearance_changed(false, true);
+ }
+}
+
+void AnalogSignal::on_neg_vdivs_changed(int vdivs)
+{
+ neg_vdivs_ = vdivs;
+
+ if (autoranging_)
+ perform_autoranging(true);
+
+ if (owner_) {
+ // Call order is important, otherwise the lazy event handler won't work
+ owner_->extents_changed(false, true);
+ owner_->row_item_appearance_changed(false, true);
+ }
+}
+
+void AnalogSignal::on_resolution_changed(int index)
+{
+ scale_index_ = resolution_cb_->itemData(index).toInt();
+ update_scale();
+
+ if (owner_)
+ owner_->row_item_appearance_changed(false, true);
+}
+
+void AnalogSignal::on_autoranging_changed(int state)
+{
+ autoranging_ = (state == Qt::Checked);
+
+ if (autoranging_)
+ perform_autoranging(true);
+
+ if (owner_) {
+ // Call order is important, otherwise the lazy event handler won't work
+ owner_->extents_changed(false, true);
+ owner_->row_item_appearance_changed(false, true);
+ }
+}
+
+void AnalogSignal::on_conversion_changed(int index)
+{
+ data::SignalBase::ConversionType old_conv_type = conversion_type_;
+
+ conversion_type_ = (data::SignalBase::ConversionType)(conversion_cb_->itemData(index).toInt());
+
+ if (conversion_type_ != old_conv_type) {
+ base_->set_conversion_type(conversion_type_);
+ update_conversion_type();
+ }
+}
+
+void AnalogSignal::on_display_type_changed(int index)
+{
+ display_type_ = (DisplayType)(display_type_cb_->itemData(index).toInt());
+
+ if (owner_)
+ owner_->row_item_appearance_changed(false, true);
+}
+
+} // namespace TraceView
+} // namespace views