1 // samplv1widget_controls.cpp
2 //
3 /****************************************************************************
4 Copyright (C) 2012-2019, rncbc aka Rui Nuno Capela. All rights reserved.
5
6 This program is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 *****************************************************************************/
21
22 #include "samplv1widget_controls.h"
23
24 #include "samplv1_controls.h"
25 #include "samplv1_config.h"
26
27 #include <QItemDelegate>
28 #include <QHeaderView>
29 #include <QSpinBox>
30 #include <QLineEdit>
31 #include <QComboBox>
32
33
34 //----------------------------------------------------------------------------
35 // samplv1widget_controls::ItemDelegate -- Custom (tree) list item delegate.
36
37 class samplv1widget_controls::ItemDelegate : public QItemDelegate
38 {
39 public:
40
41 // ctor.
42 ItemDelegate(QObject *pParent = 0);
43
44 // QItemDelegate interface...
45 QSize sizeHint(
46 const QStyleOptionViewItem& option,
47 const QModelIndex& index) const;
48
49 QWidget *createEditor(QWidget *pParent,
50 const QStyleOptionViewItem& option,
51 const QModelIndex& index) const;
52
53 void setEditorData(QWidget *pEditor,
54 const QModelIndex& index) const;
55
56 void setModelData(QWidget *pEditor,
57 QAbstractItemModel *pModel,
58 const QModelIndex& index) const;
59 };
60
61
62 //----------------------------------------------------------------------------
63 // MIDI Controller Names - Default controller names hash map.
64
controllerNames(void)65 const samplv1widget_controls::Names& samplv1widget_controls::controllerNames (void)
66 {
67 static struct
68 {
69 unsigned short param;
70 const char *name;
71
72 } s_controllers[] = {
73
74 { 0, QT_TR_NOOP("Bank Select (coarse)") },
75 { 1, QT_TR_NOOP("Modulation Wheel (coarse)") },
76 { 2, QT_TR_NOOP("Breath Controller (coarse)") },
77 { 4, QT_TR_NOOP("Foot Pedal (coarse)") },
78 { 5, QT_TR_NOOP("Portamento Time (coarse)") },
79 { 6, QT_TR_NOOP("Data Entry (coarse)") },
80 { 7, QT_TR_NOOP("Volume (coarse)") },
81 { 8, QT_TR_NOOP("Balance (coarse)") },
82 { 10, QT_TR_NOOP("Pan Position (coarse)") },
83 { 11, QT_TR_NOOP("Expression (coarse)") },
84 { 12, QT_TR_NOOP("Effect Control 1 (coarse)") },
85 { 13, QT_TR_NOOP("Effect Control 2 (coarse)") },
86 { 16, QT_TR_NOOP("General Purpose Slider 1") },
87 { 17, QT_TR_NOOP("General Purpose Slider 2") },
88 { 18, QT_TR_NOOP("General Purpose Slider 3") },
89 { 19, QT_TR_NOOP("General Purpose Slider 4") },
90 { 32, QT_TR_NOOP("Bank Select (fine)") },
91 { 33, QT_TR_NOOP("Modulation Wheel (fine)") },
92 { 34, QT_TR_NOOP("Breath Controller (fine)") },
93 { 36, QT_TR_NOOP("Foot Pedal (fine)") },
94 { 37, QT_TR_NOOP("Portamento Time (fine)") },
95 { 38, QT_TR_NOOP("Data Entry (fine)") },
96 { 39, QT_TR_NOOP("Volume (fine)") },
97 { 40, QT_TR_NOOP("Balance (fine)") },
98 { 42, QT_TR_NOOP("Pan Position (fine)") },
99 { 43, QT_TR_NOOP("Expression (fine)") },
100 { 44, QT_TR_NOOP("Effect Control 1 (fine)") },
101 { 45, QT_TR_NOOP("Effect Control 2 (fine)") },
102 { 64, QT_TR_NOOP("Hold Pedal (on/off)") },
103 { 65, QT_TR_NOOP("Portamento (on/off)") },
104 { 66, QT_TR_NOOP("Sustenuto Pedal (on/off)") },
105 { 67, QT_TR_NOOP("Soft Pedal (on/off)") },
106 { 68, QT_TR_NOOP("Legato Pedal (on/off)") },
107 { 69, QT_TR_NOOP("Hold 2 Pedal (on/off)") },
108 { 70, QT_TR_NOOP("Sound Variation") },
109 { 71, QT_TR_NOOP("Sound Timbre") },
110 { 72, QT_TR_NOOP("Sound Release Time") },
111 { 73, QT_TR_NOOP("Sound Attack Time") },
112 { 74, QT_TR_NOOP("Sound Brightness") },
113 { 75, QT_TR_NOOP("Sound Control 6") },
114 { 76, QT_TR_NOOP("Sound Control 7") },
115 { 77, QT_TR_NOOP("Sound Control 8") },
116 { 78, QT_TR_NOOP("Sound Control 9") },
117 { 79, QT_TR_NOOP("Sound Control 10") },
118 { 80, QT_TR_NOOP("General Purpose Button 1 (on/off)") },
119 { 81, QT_TR_NOOP("General Purpose Button 2 (on/off)") },
120 { 82, QT_TR_NOOP("General Purpose Button 3 (on/off)") },
121 { 83, QT_TR_NOOP("General Purpose Button 4 (on/off)") },
122 { 91, QT_TR_NOOP("Effects Level") },
123 { 92, QT_TR_NOOP("Tremulo Level") },
124 { 93, QT_TR_NOOP("Chorus Level") },
125 { 94, QT_TR_NOOP("Celeste Level") },
126 { 95, QT_TR_NOOP("Phaser Level") },
127 { 96, QT_TR_NOOP("Data Button Increment") },
128 { 97, QT_TR_NOOP("Data Button Decrement") },
129 { 98, QT_TR_NOOP("Non-Registered Parameter (fine)") },
130 { 99, QT_TR_NOOP("Non-Registered Parameter (coarse)") },
131 {100, QT_TR_NOOP("Registered Parameter (fine)") },
132 {101, QT_TR_NOOP("Registered Parameter (coarse)") },
133 {120, QT_TR_NOOP("All Sound Off") },
134 {121, QT_TR_NOOP("All Controllers Off") },
135 {122, QT_TR_NOOP("Local Keyboard (on/off)") },
136 {123, QT_TR_NOOP("All Notes Off") },
137 {124, QT_TR_NOOP("Omni Mode Off") },
138 {125, QT_TR_NOOP("Omni Mode On") },
139 {126, QT_TR_NOOP("Mono Operation") },
140 {127, QT_TR_NOOP("Poly Operation") },
141
142 { 0, nullptr }
143 };
144
145 static Names s_controllerNames;
146
147 // Pre-load controller-names hash table...
148 if (s_controllerNames.isEmpty()) {
149 for (int i = 0; s_controllers[i].name; ++i) {
150 s_controllerNames.insert(s_controllers[i].param,
151 QObject::tr(s_controllers[i].name, "controllerName"));
152 }
153 }
154
155 return s_controllerNames;
156 }
157
158
159 //----------------------------------------------------------------------------
160 // MIDI RPN Names - Default RPN names hash map.
161
rpnNames(void)162 const samplv1widget_controls::Names& samplv1widget_controls::rpnNames (void)
163 {
164 static struct
165 {
166 unsigned short param;
167 const char *name;
168
169 } s_rpns[] = {
170
171 { 0, QT_TR_NOOP("Pitch Bend Sensitivity") },
172 { 1, QT_TR_NOOP("Fine Tune") },
173 { 2, QT_TR_NOOP("Coarse Tune") },
174 { 3, QT_TR_NOOP("Tuning Program") },
175 { 4, QT_TR_NOOP("Tuning Bank") },
176
177 { 0, nullptr }
178 };
179
180 static Names s_rpnNames;
181
182 if (s_rpnNames.isEmpty()) {
183 // Pre-load RPN-names hash table...
184 for (int i = 0; s_rpns[i].name; ++i) {
185 s_rpnNames.insert(s_rpns[i].param,
186 QObject::tr(s_rpns[i].name, "rpnName"));
187 }
188 }
189
190 return s_rpnNames;
191 }
192
193
194 //----------------------------------------------------------------------------
195 // MIDI NRPN Names - Default NRPN names hash map.
196
nrpnNames(void)197 const samplv1widget_controls::Names& samplv1widget_controls::nrpnNames (void)
198 {
199 static struct
200 {
201 unsigned short param;
202 const char *name;
203
204 } s_nrpns[] = {
205
206 { 136, QT_TR_NOOP("Vibrato Rate") },
207 { 137, QT_TR_NOOP("Vibrato Depth") },
208 { 138, QT_TR_NOOP("Vibrato Delay") },
209 { 160, QT_TR_NOOP("Filter Cutoff") },
210 { 161, QT_TR_NOOP("Filter Resonance") },
211 { 227, QT_TR_NOOP("EG Attack") },
212 { 228, QT_TR_NOOP("EG Decay") },
213 { 230, QT_TR_NOOP("EG Release") },
214
215 // GS Drum NRPN map...
216 { 2560, QT_TR_NOOP("Drum Filter Cutoff") },
217 { 2688, QT_TR_NOOP("Drum Filter Resonance") },
218 { 2816, QT_TR_NOOP("Drum EG Attack") },
219 { 2944, QT_TR_NOOP("Drum EG Decay") },
220 { 3072, QT_TR_NOOP("Drum Pitch Coarse") },
221 { 3200, QT_TR_NOOP("Drum Pitch Fine") },
222 { 3328, QT_TR_NOOP("Drum Level") },
223 { 3584, QT_TR_NOOP("Drum Pan") },
224 { 3712, QT_TR_NOOP("Drum Reverb Send") },
225 { 3840, QT_TR_NOOP("Drum Chorus Send") },
226 { 3968, QT_TR_NOOP("Drum Variation Send") },
227
228 { 0, nullptr }
229 };
230
231 static struct
232 {
233 unsigned char note;
234 const char *name;
235
236 } s_drums[] = {
237
238 // GM Drum note map...
239 { 35, QT_TR_NOOP("Acoustic Bass Drum") },
240 { 36, QT_TR_NOOP("Bass Drum 1") },
241 { 37, QT_TR_NOOP("Side Stick") },
242 { 38, QT_TR_NOOP("Acoustic Snare") },
243 { 39, QT_TR_NOOP("Hand Clap") },
244 { 40, QT_TR_NOOP("Electric Snare") },
245 { 41, QT_TR_NOOP("Low Floor Tom") },
246 { 42, QT_TR_NOOP("Closed Hi-Hat") },
247 { 43, QT_TR_NOOP("High Floor Tom") },
248 { 44, QT_TR_NOOP("Pedal Hi-Hat") },
249 { 45, QT_TR_NOOP("Low Tom") },
250 { 46, QT_TR_NOOP("Open Hi-Hat") },
251 { 47, QT_TR_NOOP("Low-Mid Tom") },
252 { 48, QT_TR_NOOP("Hi-Mid Tom") },
253 { 49, QT_TR_NOOP("Crash Cymbal 1") },
254 { 50, QT_TR_NOOP("High Tom") },
255 { 51, QT_TR_NOOP("Ride Cymbal 1") },
256 { 52, QT_TR_NOOP("Chinese Cymbal") },
257 { 53, QT_TR_NOOP("Ride Bell") },
258 { 54, QT_TR_NOOP("Tambourine") },
259 { 55, QT_TR_NOOP("Splash Cymbal") },
260 { 56, QT_TR_NOOP("Cowbell") },
261 { 57, QT_TR_NOOP("Crash Cymbal 2") },
262 { 58, QT_TR_NOOP("Vibraslap") },
263 { 59, QT_TR_NOOP("Ride Cymbal 2") },
264 { 60, QT_TR_NOOP("Hi Bongo") },
265 { 61, QT_TR_NOOP("Low Bongo") },
266 { 62, QT_TR_NOOP("Mute Hi Conga") },
267 { 63, QT_TR_NOOP("Open Hi Conga") },
268 { 64, QT_TR_NOOP("Low Conga") },
269 { 65, QT_TR_NOOP("High Timbale") },
270 { 66, QT_TR_NOOP("Low Timbale") },
271 { 67, QT_TR_NOOP("High Agogo") },
272 { 68, QT_TR_NOOP("Low Agogo") },
273 { 69, QT_TR_NOOP("Cabasa") },
274 { 70, QT_TR_NOOP("Maracas") },
275 { 71, QT_TR_NOOP("Short Whistle") },
276 { 72, QT_TR_NOOP("Long Whistle") },
277 { 73, QT_TR_NOOP("Short Guiro") },
278 { 74, QT_TR_NOOP("Long Guiro") },
279 { 75, QT_TR_NOOP("Claves") },
280 { 76, QT_TR_NOOP("Hi Wood Block") },
281 { 77, QT_TR_NOOP("Low Wood Block") },
282 { 78, QT_TR_NOOP("Mute Cuica") },
283 { 79, QT_TR_NOOP("Open Cuica") },
284 { 80, QT_TR_NOOP("Mute Triangle") },
285 { 81, QT_TR_NOOP("Open Triangle") },
286
287 { 0, nullptr }
288 };
289
290 static Names s_nrpnNames;
291
292 if (s_nrpnNames.isEmpty()) {
293 // Pre-load NRPN-names hash table...
294 const QString sDrumNrpnName("%1 (%2)");
295 for (int i = 0; s_nrpns[i].name; ++i) {
296 const unsigned short param = s_nrpns[i].param;
297 const QString& sName = QObject::tr(s_nrpns[i].name, "nrpnName");
298 if (param < 2560) {
299 s_nrpnNames.insert(param, sName);
300 } else {
301 for (int j = 0; s_drums[j].name; ++j) {
302 const unsigned char note = s_drums[j].note;
303 s_nrpnNames.insert(param + note,
304 sDrumNrpnName.arg(sName).arg(note));
305 }
306 }
307 }
308 }
309
310 return s_nrpnNames;
311 }
312
313
314 //----------------------------------------------------------------------------
315 // MIDI Control-14 Names - Default controller names hash map.
316
control14Names(void)317 const samplv1widget_controls::Names& samplv1widget_controls::control14Names (void)
318 {
319 static struct
320 {
321 unsigned short param;
322 const char *name;
323
324 } s_control14s[] = {
325
326 { 1, QT_TR_NOOP("Modulation Wheel (14bit)") },
327 { 2, QT_TR_NOOP("Breath Controller (14bit)") },
328 { 4, QT_TR_NOOP("Foot Pedal (14bit)") },
329 { 5, QT_TR_NOOP("Portamento Time (14bit)") },
330 { 7, QT_TR_NOOP("Volume (14bit)") },
331 { 8, QT_TR_NOOP("Balance (14bit)") },
332 { 10, QT_TR_NOOP("Pan Position (14bit)") },
333 { 11, QT_TR_NOOP("Expression (14bit)") },
334 { 12, QT_TR_NOOP("Effect Control 1 (14bit)") },
335 { 13, QT_TR_NOOP("Effect Control 2 (14bit)") },
336 { 16, QT_TR_NOOP("General Purpose Slider 1 (14bit)") },
337 { 17, QT_TR_NOOP("General Purpose Slider 2 (14bit)") },
338 { 18, QT_TR_NOOP("General Purpose Slider 3 (14bit)") },
339 { 19, QT_TR_NOOP("General Purpose Slider 4 (14bit)") },
340
341 { 0, nullptr }
342 };
343
344 static Names s_control14Names;
345
346 if (s_control14Names.isEmpty()) {
347 // Pre-load controller-names hash table...
348 for (int i = 0; s_control14s[i].name; ++i) {
349 s_control14Names.insert(s_control14s[i].param,
350 QObject::tr(s_control14s[i].name, "control14Name"));
351 }
352 }
353
354 return s_control14Names;
355 }
356
357
358 //----------------------------------------------------------------------------
359 // MIDI Controller Names general helpers.
360
361 static
controlParamComboBox(samplv1_controls::Type ctype,QWidget * pParent)362 QComboBox *controlParamComboBox (
363 samplv1_controls::Type ctype, QWidget *pParent )
364 {
365 QComboBox *pComboBox = new QComboBox(pParent);
366
367 samplv1widget_controls::Names map;
368
369 int iParamMin = 0;
370 int iParamMax = iParamMin;
371
372 switch(ctype) {
373 case samplv1_controls::CC:
374 iParamMin = 0;
375 iParamMax = 128;
376 map = samplv1widget_controls::controllerNames();
377 break;
378 case samplv1_controls::RPN:
379 map = samplv1widget_controls::rpnNames();
380 break;
381 case samplv1_controls::NRPN:
382 map = samplv1widget_controls::nrpnNames();
383 break;
384 case samplv1_controls::CC14:
385 iParamMin = 1;
386 iParamMax = 32;
387 map = samplv1widget_controls::control14Names();
388 // Fall thru...
389 default:
390 break;
391 }
392
393 const bool bEditable = (iParamMin >= iParamMax);
394 pComboBox->setEditable(bEditable);
395 pComboBox->setInsertPolicy(QComboBox::NoInsert);
396
397 const QString sMask("%1 - %2");
398 if (bEditable) {
399 samplv1widget_controls::Names::ConstIterator iter
400 = map.constBegin();
401 const samplv1widget_controls::Names::ConstIterator& iter_end
402 = map.constEnd();
403 for ( ; iter != iter_end; ++iter) {
404 const unsigned short param = iter.key();
405 pComboBox->addItem(sMask.arg(param).arg(iter.value()), int(param));
406 }
407 } else {
408 for (int iParam = iParamMin; iParam < iParamMax; ++iParam) {
409 const unsigned short param = iParam;
410 pComboBox->addItem(sMask.arg(param).arg(map.value(param)), iParam);
411 }
412 }
413
414 return pComboBox;
415 }
416
417
418 static
controlParamName(samplv1_controls::Type ctype,unsigned short param)419 QString controlParamName (
420 samplv1_controls::Type ctype, unsigned short param )
421 {
422 samplv1widget_controls::Names map;
423
424 switch(ctype) {
425 case samplv1_controls::CC:
426 map = samplv1widget_controls::controllerNames();
427 break;
428 case samplv1_controls::RPN:
429 map = samplv1widget_controls::rpnNames();
430 break;
431 case samplv1_controls::NRPN:
432 map = samplv1widget_controls::nrpnNames();
433 break;
434 case samplv1_controls::CC14:
435 map = samplv1widget_controls::control14Names();
436 // Fall thru...
437 default:
438 break;
439 }
440
441 const QString sMask("%1 - %2");
442 samplv1widget_controls::Names::ConstIterator iter = map.constFind(param);
443 if (iter == map.constEnd())
444 return QString::number(param);
445 else
446 return sMask.arg(param).arg(iter.value());
447 }
448
449
450 //----------------------------------------------------------------------------
451 // samplv1widget_controls::ItemDelegate -- Custom (tree) list item delegate.
452
453 // ctor.
ItemDelegate(QObject * pParent)454 samplv1widget_controls::ItemDelegate::ItemDelegate ( QObject *pParent )
455 : QItemDelegate(pParent)
456 {
457 }
458
459
460 // QItemDelegate interface...
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const461 QSize samplv1widget_controls::ItemDelegate::sizeHint (
462 const QStyleOptionViewItem& option, const QModelIndex& index ) const
463 {
464 const int x = (index.column() == 1 ? 32 : 4); // Type is special.
465 return QItemDelegate::sizeHint(option, index) + QSize(x, 4);
466 }
467
468
createEditor(QWidget * pParent,const QStyleOptionViewItem &,const QModelIndex & index) const469 QWidget *samplv1widget_controls::ItemDelegate::createEditor ( QWidget *pParent,
470 const QStyleOptionViewItem& /*option*/, const QModelIndex& index ) const
471 {
472 QWidget *pEditor = nullptr;
473
474 switch (index.column()) {
475 case 0: // Channel.
476 {
477 QSpinBox *pSpinBox = new QSpinBox(pParent);
478 pSpinBox->setMinimum(0);
479 pSpinBox->setMaximum(16);
480 pSpinBox->setSpecialValueText(tr("Auto"));
481 pEditor = pSpinBox;
482 break;
483 }
484
485 case 1: // Type.
486 {
487 QComboBox *pComboBox = new QComboBox(pParent);
488 pComboBox->setEditable(false);
489 pComboBox->addItem(
490 samplv1_controls::textFromType(samplv1_controls::CC));
491 pComboBox->addItem(
492 samplv1_controls::textFromType(samplv1_controls::RPN));
493 pComboBox->addItem(
494 samplv1_controls::textFromType(samplv1_controls::NRPN));
495 pComboBox->addItem(
496 samplv1_controls::textFromType(samplv1_controls::CC14));
497 pEditor = pComboBox;
498 break;
499 }
500
501 case 2: // Parameter.
502 {
503 const QModelIndex& ctype_index = index.sibling(index.row(), 1);
504 const QString& sType = ctype_index.data().toString();
505 const samplv1_controls::Type ctype
506 = samplv1_controls::typeFromText(sType);
507 pEditor = controlParamComboBox(ctype, pParent);
508 break;
509 }
510
511 case 3: // Subject.
512 {
513 QComboBox *pComboBox = new QComboBox(pParent);
514 pComboBox->setEditable(false);
515 for (uint32_t i = 0; i < samplv1::NUM_PARAMS; ++i)
516 pComboBox->addItem(
517 samplv1_param::paramName(samplv1::ParamIndex(i)));
518 pEditor = pComboBox;
519 break;
520 }
521
522 default:
523 break;
524 }
525
526 #ifdef CONFIG_DEBUG_0
527 qDebug("samplv1widget_controls::ItemDelegate::createEditor(%p, %d, %d) = %p",
528 pParent, index.row(), index.column(), pEditor);
529 #endif
530
531 return pEditor;
532 }
533
534
setEditorData(QWidget * pEditor,const QModelIndex & index) const535 void samplv1widget_controls::ItemDelegate::setEditorData (
536 QWidget *pEditor, const QModelIndex& index ) const
537 {
538 #ifdef CONFIG_DEBUG_0
539 qDebug("samplv1widget_controls::ItemDelegate::setEditorData(%p, %d, %d)",
540 pEditor, index.row(), index.column());
541 #endif
542
543 switch (index.column()) {
544 case 0: // Channel.
545 {
546 const int iChannel = index.data().toInt();
547 // = index.model()->data(index, Qt::DisplayRole).toInt();
548 QSpinBox *pSpinBox = qobject_cast<QSpinBox *> (pEditor);
549 if (pSpinBox) pSpinBox->setValue(iChannel);
550 break;
551 }
552
553 case 1: // Type.
554 {
555 const QString& sText = index.data().toString();
556 // = index.model()->data(index, Qt::DisplayRole).toString();
557 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
558 if (pComboBox) {
559 const int iIndex = pComboBox->findText(sText);
560 if (iIndex >= 0)
561 pComboBox->setCurrentIndex(iIndex);
562 else
563 pComboBox->setCurrentIndex(0);
564 }
565 break;
566 }
567
568 case 2: // Parameter.
569 {
570 const int iParam = index.data(Qt::UserRole).toInt();
571 // = index.model()->data(index, Qt::DisplayRole).toString();
572 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
573 if (pComboBox) {
574 const int iIndex = pComboBox->findData(iParam);
575 if (iIndex >= 0)
576 pComboBox->setCurrentIndex(iIndex);
577 else
578 pComboBox->setEditText(index.data().toString());
579 }
580 break;
581 }
582
583 case 3: // Subject.
584 {
585 const int iIndex = index.data(Qt::UserRole).toInt();
586 // = index.model()->data(index, Qt::DisplayRole).toInt();
587 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
588 if (pComboBox) pComboBox->setCurrentIndex(iIndex);
589 break;
590 }
591
592 default:
593 break;
594 }
595 }
596
597
setModelData(QWidget * pEditor,QAbstractItemModel * pModel,const QModelIndex & index) const598 void samplv1widget_controls::ItemDelegate::setModelData ( QWidget *pEditor,
599 QAbstractItemModel *pModel, const QModelIndex& index ) const
600 {
601 #ifdef CONFIG_DEBUG_0
602 qDebug("samplv1widget_controls_item_delegate::setModelData(%p, %d, %d)",
603 pEditor, index.row(), index.column());
604 #endif
605
606 switch (index.column()) {
607 case 0: // Channel.
608 {
609 QSpinBox *pSpinBox = qobject_cast<QSpinBox *> (pEditor);
610 if (pSpinBox) {
611 const int iChannel = pSpinBox->value();
612 const QString& sText
613 = (iChannel > 0 ? QString::number(iChannel) : tr("Auto"));
614 pModel->setData(index, sText);
615 }
616 break;
617 }
618
619 case 1: // Type.
620 {
621 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
622 if (pComboBox) {
623 const QString& sType = pComboBox->currentText();
624 pModel->setData(index, sType);
625 }
626 break;
627 }
628
629 case 2: // Parameter.
630 {
631 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
632 if (pComboBox) {
633 const int iIndex = pComboBox->currentIndex();
634 QString sText;
635 int iParam;
636 if (iIndex >= 0) {
637 sText = pComboBox->itemText(iIndex);
638 iParam = pComboBox->itemData(iIndex).toInt();
639 } else {
640 sText = pComboBox->currentText();
641 iParam = sText.toInt();
642 }
643 pModel->setData(index, sText);
644 pModel->setData(index, iParam, Qt::UserRole);
645 }
646 break;
647 }
648
649 case 3: // Subject.
650 {
651 QComboBox *pComboBox = qobject_cast<QComboBox *> (pEditor);
652 if (pComboBox) {
653 const int iIndex = pComboBox->currentIndex();
654 pModel->setData(index,
655 samplv1_param::paramName(samplv1::ParamIndex(iIndex)));
656 pModel->setData(index, iIndex, Qt::UserRole);
657 }
658 break;
659 }
660
661 default:
662 break;
663 }
664
665 // Done.
666 }
667
668
669 //----------------------------------------------------------------------------
670 // samplv1widget_controls -- UI wrapper form.
671
672 // ctor.
samplv1widget_controls(QWidget * pParent)673 samplv1widget_controls::samplv1widget_controls ( QWidget *pParent )
674 : QTreeWidget(pParent)
675 {
676 QTreeWidget::setColumnCount(4);
677
678 QTreeWidget::setRootIsDecorated(false);
679 QTreeWidget::setAlternatingRowColors(true);
680 QTreeWidget::setUniformRowHeights(true);
681 QTreeWidget::setAllColumnsShowFocus(false);
682
683 QTreeWidget::setSelectionBehavior(QAbstractItemView::SelectRows);
684 QTreeWidget::setSelectionMode(QAbstractItemView::SingleSelection);
685
686 QHeaderView *pHeaderView = QTreeWidget::header();
687 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
688 pHeaderView->setResizeMode(QHeaderView::ResizeToContents);
689 #else
690 pHeaderView->setSectionResizeMode(QHeaderView::ResizeToContents);
691 #endif
692 // pHeaderView->hide();
693
694 QTreeWidget::setItemDelegate(new ItemDelegate(this));
695
696 QObject::connect(this,
697 SIGNAL(itemChanged(QTreeWidgetItem *, int)),
698 SLOT(itemChangedSlot(QTreeWidgetItem *, int)));
699 }
700
701
702 // dtor.
~samplv1widget_controls(void)703 samplv1widget_controls::~samplv1widget_controls (void)
704 {
705 }
706
707
708 // utilities.
loadControls(samplv1_controls * pControls)709 void samplv1widget_controls::loadControls ( samplv1_controls *pControls )
710 {
711 QTreeWidget::clear();
712
713 const QIcon icon(":/images/samplv1_control.png");
714 QList<QTreeWidgetItem *> items;
715 const samplv1_controls::Map& map = pControls->map();
716 samplv1_controls::Map::ConstIterator iter = map.constBegin();
717 const samplv1_controls::Map::ConstIterator& iter_end = map.constEnd();
718 for ( ; iter != iter_end; ++iter) {
719 const samplv1_controls::Key& key = iter.key();
720 const samplv1_controls::Type ctype = key.type();
721 const unsigned short channel = key.channel();
722 const samplv1_controls::Data& data = iter.value();
723 const samplv1::ParamIndex index = samplv1::ParamIndex(data.index);
724 QTreeWidgetItem *pItem = new QTreeWidgetItem(this);
725 // pItem->setIcon(0, icon);
726 pItem->setText(0, (channel > 0 ? QString::number(channel) : tr("Auto")));
727 pItem->setText(1, samplv1_controls::textFromType(ctype));
728 pItem->setText(2, controlParamName(ctype, key.param));
729 pItem->setData(2, Qt::UserRole, int(key.param));
730 pItem->setIcon(3, icon);
731 pItem->setText(3, samplv1_param::paramName(index));
732 pItem->setData(3, Qt::UserRole, data.index);
733 pItem->setData(3, Qt::UserRole + 1, data.flags);
734 pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
735 items.append(pItem);
736 }
737 QTreeWidget::addTopLevelItems(items);
738 QTreeWidget::expandAll();
739 }
740
741
saveControls(samplv1_controls * pControls)742 void samplv1widget_controls::saveControls ( samplv1_controls *pControls )
743 {
744 pControls->clear();
745
746 const int iItemCount = QTreeWidget::topLevelItemCount();
747 for (int iItem = 0 ; iItem < iItemCount; ++iItem) {
748 QTreeWidgetItem *pItem = QTreeWidget::topLevelItem(iItem);
749 const unsigned short channel
750 = pItem->text(0).toInt();
751 const samplv1_controls::Type ctype
752 = samplv1_controls::typeFromText(pItem->text(1));
753 samplv1_controls::Key key;
754 key.status = ctype | (channel & 0x1f);
755 key.param = pItem->data(2, Qt::UserRole).toInt();
756 samplv1_controls::Data data;
757 data.index = pItem->data(3, Qt::UserRole).toInt();
758 data.flags = pItem->data(3, Qt::UserRole + 1).toInt();
759 pControls->add_control(key, data);
760 }
761 }
762
763
764 // slots.
addControlItem(void)765 void samplv1widget_controls::addControlItem (void)
766 {
767 QTreeWidget::setFocus();
768
769 QTreeWidgetItem *pItem = newControlItem();
770 if (pItem) {
771 QTreeWidget::setCurrentItem(pItem);
772 QTreeWidget::editItem(pItem, 0);
773 }
774 }
775
776
777 // factory methods.
newControlItem(void)778 QTreeWidgetItem *samplv1widget_controls::newControlItem (void)
779 {
780 QTreeWidgetItem *pItem = new QTreeWidgetItem();
781 const QIcon icon(":/images/samplv1_control.png");
782 const samplv1_controls::Type ctype = samplv1_controls::CC;
783 // pItem->setIcon(0, icon);
784 pItem->setText(0, tr("Auto"));
785 pItem->setText(1, samplv1_controls::textFromType(ctype));
786 pItem->setText(2, controlParamName(ctype, 0));
787 pItem->setData(2, Qt::UserRole, 0);
788 pItem->setIcon(3, icon);
789 pItem->setText(3, samplv1_param::paramName(samplv1::ParamIndex(0)));
790 pItem->setData(3, Qt::UserRole, 0);
791 pItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
792 QTreeWidget::addTopLevelItem(pItem);
793
794 return pItem;
795 }
796
797
itemChangedSlot(QTreeWidgetItem * pItem,int column)798 void samplv1widget_controls::itemChangedSlot (
799 QTreeWidgetItem *pItem, int column )
800 {
801 if (column == 1) {
802 const bool bBlockSignals = QTreeWidget::blockSignals(true);
803 const QString& sType = pItem->text(1);
804 const samplv1_controls::Type ctype
805 = samplv1_controls::typeFromText(sType);
806 const int iParam = pItem->data(2, Qt::UserRole).toInt();
807 pItem->setText(2, controlParamName(ctype, iParam));
808 QTreeWidget::blockSignals(bBlockSignals);
809 }
810 }
811
812
813 // end of samplv1widget_controls.cpp
814