X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fpopups%2Fchannels.cpp;h=ecdc59a35466cd82f378cd1393f5f366bb091ccf;hp=cbe9a2a2eb4fd7bd6b0ddb828739381261c5b597;hb=HEAD;hpb=3b6c4a1fe75289e56be6bc2a5d1b9e24ccdd1744 diff --git a/pv/popups/channels.cpp b/pv/popups/channels.cpp index cbe9a2a2..ce2e8e98 100644 --- a/pv/popups/channels.cpp +++ b/pv/popups/channels.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "channels.hpp" @@ -41,6 +42,7 @@ using std::out_of_range; using std::shared_ptr; using std::unordered_set; using std::vector; +using std::weak_ptr; using pv::data::SignalBase; using pv::data::Logic; @@ -57,12 +59,16 @@ Channels::Channels(Session &session, QWidget *parent) : Popup(parent), session_(session), updating_channels_(false), - enable_all_channels_(tr("Enable All"), this), - disable_all_channels_(tr("Disable All"), this), - enable_all_logic_channels_(tr("Enable only logic"), this), - enable_all_analog_channels_(tr("Enable only analog"), this), - enable_all_named_channels_(tr("Enable only named"), this), - enable_all_changing_channels_(tr("Enable only changing"), this), + enable_all_channels_(tr("All"), this), + disable_all_channels_(tr("All"), this), + enable_all_logic_channels_(tr("Logic"), this), + disable_all_logic_channels_(tr("Logic"), this), + enable_all_analog_channels_(tr("Analog"), this), + disable_all_analog_channels_(tr("Analog"), this), + enable_all_named_channels_(tr("Named"), this), + disable_all_unnamed_channels_(tr("Unnamed"), this), + enable_all_changing_channels_(tr("Changing"), this), + disable_all_non_changing_channels_(tr("Non-changing"), this), check_box_mapper_(this) { // Create the layout @@ -75,18 +81,18 @@ Channels::Channels(Session &session, QWidget *parent) : map, shared_ptr > signal_map; unordered_set< shared_ptr > sigs; - for (const shared_ptr b : session_.signalbases()) + for (const shared_ptr& b : session_.signalbases()) sigs.insert(b); for (const shared_ptr &sig : sigs) signal_map[sig->channel()] = sig; // Populate channel groups - for (auto entry : device->channel_groups()) { + for (auto& entry : device->channel_groups()) { const shared_ptr group = entry.second; // Make a set of signals and remove these signals from the signal map vector< shared_ptr > group_sigs; - for (auto channel : group->channels()) { + for (auto& channel : group->channels()) { const auto iter = signal_map.find(channel); if (iter == signal_map.end()) @@ -101,7 +107,7 @@ Channels::Channels(Session &session, QWidget *parent) : // Make a vector of the remaining channels vector< shared_ptr > global_analog_sigs, global_logic_sigs; - for (auto channel : device->channels()) { + for (auto& channel : device->channels()) { const map, shared_ptr >:: const_iterator iter = signal_map.find(channel); @@ -122,31 +128,50 @@ Channels::Channels(Session &session, QWidget *parent) : connect(&enable_all_channels_, SIGNAL(clicked()), this, SLOT(enable_all_channels())); connect(&disable_all_channels_, SIGNAL(clicked()), this, SLOT(disable_all_channels())); connect(&enable_all_logic_channels_, SIGNAL(clicked()), this, SLOT(enable_all_logic_channels())); + connect(&disable_all_logic_channels_, SIGNAL(clicked()), this, SLOT(disable_all_logic_channels())); connect(&enable_all_analog_channels_, SIGNAL(clicked()), this, SLOT(enable_all_analog_channels())); + connect(&disable_all_analog_channels_, SIGNAL(clicked()), this, SLOT(disable_all_analog_channels())); connect(&enable_all_named_channels_, SIGNAL(clicked()), this, SLOT(enable_all_named_channels())); + connect(&disable_all_unnamed_channels_, SIGNAL(clicked()), this, SLOT(disable_all_unnamed_channels())); connect(&enable_all_changing_channels_, SIGNAL(clicked()), this, SLOT(enable_all_changing_channels())); - - buttons_bar_.setRowMinimumHeight(0, 2 * QFontMetrics(QApplication::font()).height()); - buttons_bar_.addWidget(&enable_all_channels_, 1, 0); - buttons_bar_.addWidget(&disable_all_channels_, 1, 1); - buttons_bar_.addWidget(&enable_all_logic_channels_, 2, 0); - buttons_bar_.addWidget(&enable_all_analog_channels_, 2, 1); - buttons_bar_.addWidget(&enable_all_named_channels_, 2, 2); - buttons_bar_.addWidget(&enable_all_changing_channels_, 2, 3); - - layout_.addRow(&buttons_bar_); + connect(&disable_all_non_changing_channels_, SIGNAL(clicked()), + this, SLOT(disable_all_non_changing_channels())); + + QLabel *label1 = new QLabel(tr("Disable: ")); + filter_buttons_bar_.addWidget(label1, 0, 0); + filter_buttons_bar_.addWidget(&disable_all_channels_, 0, 1); + filter_buttons_bar_.addWidget(&disable_all_logic_channels_, 0, 2); + filter_buttons_bar_.addWidget(&disable_all_analog_channels_, 0, 3); + filter_buttons_bar_.addWidget(&disable_all_unnamed_channels_, 0, 4); + filter_buttons_bar_.addWidget(&disable_all_non_changing_channels_, 0, 5); + + QLabel *label2 = new QLabel(tr("Enable: ")); + filter_buttons_bar_.addWidget(label2, 1, 0); + filter_buttons_bar_.addWidget(&enable_all_channels_, 1, 1); + filter_buttons_bar_.addWidget(&enable_all_logic_channels_, 1, 2); + filter_buttons_bar_.addWidget(&enable_all_analog_channels_, 1, 3); + filter_buttons_bar_.addWidget(&enable_all_named_channels_, 1, 4); + filter_buttons_bar_.addWidget(&enable_all_changing_channels_, 1, 5); + + layout_.addItem(new QSpacerItem(0, 15, QSizePolicy::Expanding, QSizePolicy::Expanding)); + layout_.addRow(&filter_buttons_bar_); // Connect the check-box signal mapper +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + connect(&check_box_mapper_, SIGNAL(mappedObject(QObject*)), + this, SLOT(on_channel_checked(QObject*))); +#else connect(&check_box_mapper_, SIGNAL(mapped(QWidget*)), this, SLOT(on_channel_checked(QWidget*))); +#endif } void Channels::set_all_channels(bool set) { updating_channels_ = true; - for (auto entry : check_box_signal_map_) { + for (auto& entry : check_box_signal_map_) { QCheckBox *cb = entry.first; const shared_ptr sig = entry.second; assert(sig); @@ -158,19 +183,39 @@ void Channels::set_all_channels(bool set) updating_channels_ = false; } -void Channels::set_all_channels_conditionally( +void Channels::enable_channels_conditionally( function)> cond_func) { updating_channels_ = true; - for (auto entry : check_box_signal_map_) { + for (auto& entry : check_box_signal_map_) { QCheckBox *cb = entry.first; const shared_ptr sig = entry.second; assert(sig); - const bool state = cond_func(sig); - sig->set_enabled(state); - cb->setChecked(state); + if (cond_func(sig)) { + sig->set_enabled(true); + cb->setChecked(true); + } + } + + updating_channels_ = false; +} + +void Channels::disable_channels_conditionally( + function)> cond_func) +{ + updating_channels_ = true; + + for (auto& entry : check_box_signal_map_) { + QCheckBox *cb = entry.first; + const shared_ptr sig = entry.second; + assert(sig); + + if (cond_func(sig)) { + sig->set_enabled(false); + cb->setChecked(false); + } } updating_channels_ = false; @@ -188,49 +233,98 @@ void Channels::populate_group(shared_ptr group, if (group) binding = make_shared(group); + QHBoxLayout* group_layout = new QHBoxLayout(); + layout_.addRow(group_layout); + // Create a title if the group is going to have any content if ((!sigs.empty() || (binding && !binding->properties().empty())) && group) { QLabel *label = new QLabel( QString("

%1

").arg(group->name().c_str())); - layout_.addRow(label); + group_layout->addWidget(label); group_label_map_[group] = label; } // Create the channel group grid - QGridLayout *const channel_grid = create_channel_group_grid(sigs); - layout_.addRow(channel_grid); - - // Create the channel group options - if (binding) { - binding->add_properties_to_form(&layout_, true); - group_bindings_.push_back(binding); - } -} - -QGridLayout* Channels::create_channel_group_grid( - const vector< shared_ptr > sigs) -{ int row = 0, col = 0; QGridLayout *const grid = new QGridLayout(); + vector group_checkboxes, this_row; for (const shared_ptr& sig : sigs) { assert(sig); QCheckBox *const checkbox = new QCheckBox(sig->display_name()); check_box_mapper_.setMapping(checkbox, checkbox); - connect(checkbox, SIGNAL(toggled(bool)), - &check_box_mapper_, SLOT(map())); + connect(checkbox, SIGNAL(toggled(bool)), &check_box_mapper_, SLOT(map())); grid->addWidget(checkbox, row, col); + group_checkboxes.push_back(checkbox); + this_row.push_back(checkbox); + check_box_signal_map_[checkbox] = sig; - if (++col >= 8) + weak_ptr weak_sig(sig); + connect(checkbox, &QCheckBox::toggled, + [weak_sig](bool state) { + auto sig = weak_sig.lock(); + assert(sig); + sig->set_enabled(state); + }); + + if ((++col >= 8 || &sig == &sigs.back())) { + // Show buttons if there's more than one row + if (sigs.size() > 8) { + QPushButton *row_enable_button = new QPushButton(tr("All"), this); + grid->addWidget(row_enable_button, row, 8); + connect(row_enable_button, &QPushButton::clicked, row_enable_button, + [this_row]() { + for (QCheckBox *box : this_row) + box->setChecked(true); + }); + + QPushButton *row_disable_button = new QPushButton(tr("None"), this); + connect(row_disable_button, &QPushButton::clicked, row_disable_button, + [this_row]() { + for (QCheckBox *box : this_row) + box->setChecked(false); + }); + grid->addWidget(row_disable_button, row, 9); + } + + this_row.clear(); col = 0, row++; + } + } + layout_.addRow(grid); + + if (sigs.size() > 1) { + // Create enable all/none buttons + QPushButton *btn_enable_all, *btn_disable_all; + + btn_enable_all = new QPushButton(tr("All")); + btn_disable_all = new QPushButton(tr("None")); + group_layout->addWidget(btn_enable_all); + group_layout->addWidget(btn_disable_all); + + connect(btn_enable_all, &QPushButton::clicked, btn_enable_all, + [group_checkboxes](){ + for (QCheckBox *box: group_checkboxes) + box->setChecked(true); + }); + + connect(btn_disable_all, &QPushButton::clicked, btn_disable_all, + [group_checkboxes](){ + for (QCheckBox *box: group_checkboxes) + box->setChecked(false); + }); } - return grid; + // Create the channel group options + if (binding) { + binding->add_properties_to_form(&layout_, true); + group_bindings_.push_back(binding); + } } void Channels::showEvent(QShowEvent *event) @@ -241,20 +335,18 @@ void Channels::showEvent(QShowEvent *event) assert(device); // Update group labels - for (auto entry : device->channel_groups()) { + for (auto& entry : device->channel_groups()) { const shared_ptr group = entry.second; - try { - QLabel* label = group_label_map_.at(group); + if (group_label_map_.count(group) > 0) { + QLabel* label = group_label_map_[group]; label->setText(QString("

%1

").arg(group->name().c_str())); - } catch (out_of_range&) { - // Do nothing } } updating_channels_ = true; - for (auto entry : check_box_signal_map_) { + for (auto& entry : check_box_signal_map_) { QCheckBox *cb = entry.first; const shared_ptr sig = entry.second; assert(sig); @@ -267,7 +359,11 @@ void Channels::showEvent(QShowEvent *event) updating_channels_ = false; } +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +void Channels::on_channel_checked(QObject *widget) +#else void Channels::on_channel_checked(QWidget *widget) +#endif { if (updating_channels_) return; @@ -298,25 +394,43 @@ void Channels::disable_all_channels() void Channels::enable_all_logic_channels() { - set_all_channels_conditionally([](const shared_ptr signal) + enable_channels_conditionally([](const shared_ptr signal) + { return signal->type() == SignalBase::LogicChannel; }); +} + +void Channels::disable_all_logic_channels() +{ + disable_channels_conditionally([](const shared_ptr signal) { return signal->type() == SignalBase::LogicChannel; }); } void Channels::enable_all_analog_channels() { - set_all_channels_conditionally([](const shared_ptr signal) + enable_channels_conditionally([](const shared_ptr signal) + { return signal->type() == SignalBase::AnalogChannel; }); +} + +void Channels::disable_all_analog_channels() +{ + disable_channels_conditionally([](const shared_ptr signal) { return signal->type() == SignalBase::AnalogChannel; }); } void Channels::enable_all_named_channels() { - set_all_channels_conditionally([](const shared_ptr signal) + enable_channels_conditionally([](const shared_ptr signal) { return signal->name() != signal->internal_name(); }); } +void Channels::disable_all_unnamed_channels() +{ + disable_channels_conditionally([](const shared_ptr signal) + { return signal->name() == signal->internal_name(); }); +} + void Channels::enable_all_changing_channels() { - set_all_channels_conditionally([](const shared_ptr signal) + enable_channels_conditionally([](const shared_ptr signal) { // Never enable channels without sample data if (!signal->has_samples()) @@ -347,5 +461,38 @@ void Channels::enable_all_changing_channels() }); } +void Channels::disable_all_non_changing_channels() +{ + disable_channels_conditionally([](const shared_ptr signal) + { + // Always disable channels without sample data + if (!signal->has_samples()) + return true; + + // Non-logic channels are considered to always have a signal + if (signal->type() != SignalBase::LogicChannel) + return false; + + const shared_ptr logic = signal->logic_data(); + assert(logic); + + // If any of the segments has edges, leave this channel enabled + for (shared_ptr segment : logic->logic_segments()) { + vector edges; + + segment->get_subsampled_edges(edges, + 0, segment->get_sample_count() - 1, + LogicSegment::MipMapScaleFactor, + signal->index()); + + if (edges.size() > 2) + return false; + } + + // No edges detected in any of the segments + return true; + }); +} + } // namespace popups } // namespace pv