@@ -81,13 +81,21 @@ QWidget* MidiOptionsDelegate::createEditor(QWidget* parent,
8181 // * clicking an option or pressing Enter on a selected option toggles it,
8282 // closes the list view and commits the updated data
8383 // * pressing Space on a selected option toggles it, list remains open
84- // * clicking outside the listview closes it, and another click causing the
84+ // * clicking outside the list view closes it, and another click causing the
8585 // combobox to lose focus closes that and commits pending changes
8686 connect (pComboBox,
8787 QOverload<int >::of (&QComboBox::activated),
8888 this ,
8989 &MidiOptionsDelegate::commitAndCloseEditor);
9090
91+ // Uncheck other exclusive options whenever one is checked, whether by
92+ // clicking, pressing Enter, or toggling with Space (which keeps the list
93+ // open and doesn't emit activated()).
94+ connect (pModel,
95+ &QStandardItemModel::itemChanged,
96+ this ,
97+ &MidiOptionsDelegate::slotItemChanged);
98+
9199 return pComboBox;
92100}
93101
@@ -161,21 +169,46 @@ void MidiOptionsDelegate::commitAndCloseEditor(int index) {
161169 DEBUG_ASSERT (pItem);
162170 if (pItem->isCheckable ()) {
163171 pItem->setCheckState (pItem->checkState () == Qt::Checked ? Qt::Unchecked : Qt::Checked);
164- // TODO Concurrent option scan be selected. Implement a compatibility
165- // matrix and uncheck all options that are incompatible with the last
166- // checked option. Store initial check state for/in each item and
167- // hook up to QStandardItemModel::itemChanged()
168172 } else {
169173 // Clear was selected. Uncheck all other items
170174 for (int row = 0 ; row < pModel->rowCount () - 1 ; row++) {
171175 if (row == index) { // Actually it's the last item, but this is safer.
172176 continue ;
173177 }
174- pItem = pModel->item (row, 0 );
175- pItem ->setCheckState (Qt::Unchecked);
178+ auto * pOtherItem = pModel->item (row, 0 );
179+ pOtherItem ->setCheckState (Qt::Unchecked);
176180 }
177181 }
178182
179183 emit commitData (pComboBox);
180184 emit closeEditor (pComboBox);
181185}
186+
187+ void MidiOptionsDelegate::slotItemChanged (QStandardItem* pItem) {
188+ // Return if we unchecked an item
189+ if (!pItem || !pItem->isCheckable () || pItem->checkState () != Qt::Checked) {
190+ return ;
191+ }
192+ auto option = static_cast <MidiOption>(pItem->data ().toUInt ());
193+ // Nothing to do for non-exclusive options
194+ if (!midiOptionIsExclusive (option)) {
195+ return ;
196+ }
197+
198+ // This is an exclusive option, so uncheck all other exclusive options,
199+ // but keep state of "modifiers" (Invert, SoftTakeover).
200+ // This happens on the fly so it covers toggling items with Spacebar,
201+ // as well as clicks committed via activated().
202+ const auto * pModel = qobject_cast<QStandardItemModel*>(pItem->model ());
203+ DEBUG_ASSERT (pModel);
204+ for (int row = 0 ; row < pModel->rowCount () - 1 ; row++) {
205+ auto * pOtherItem = pModel->item (row, 0 );
206+ if (pOtherItem == pItem || !pOtherItem->isCheckable ()) {
207+ continue ;
208+ }
209+ auto otherOption = static_cast <MidiOption>(pOtherItem->data ().toUInt ());
210+ if (midiOptionIsExclusive (otherOption)) {
211+ pOtherItem->setCheckState (Qt::Unchecked);
212+ }
213+ }
214+ }
0 commit comments