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