1 // padthv1widget_param.cpp
2 //
3 /****************************************************************************
4    Copyright (C) 2012-2021, 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 "padthv1widget_param.h"
23 
24 #include <QLabel>
25 #include <QLineEdit>
26 #include <QComboBox>
27 #include <QRadioButton>
28 #include <QCheckBox>
29 
30 #include <QGridLayout>
31 #include <QMouseEvent>
32 
33 #include <cmath>
34 
35 
36 // Integer value round.
iroundf(float x)37 inline int iroundf(float x) { return int(x < 0.0f ? x - 0.5f : x + 0.5f); }
38 
39 
40 //-------------------------------------------------------------------------
41 // padthv1widget_param_style - Custom widget style.
42 //
43 
44 #include <QProxyStyle>
45 #include <QPainter>
46 #include <QIcon>
47 
48 
49 class padthv1widget_param_style : public QProxyStyle
50 {
51 public:
52 
53 	// Constructor.
padthv1widget_param_style()54 	padthv1widget_param_style() : QProxyStyle()
55 	{
56 		m_icon.addPixmap(
57 			QPixmap(":/images/ledOff.png"), QIcon::Normal, QIcon::Off);
58 		m_icon.addPixmap(
59 			QPixmap(":/images/ledOn.png"), QIcon::Normal, QIcon::On);
60 	}
61 
62 
63 	// Hints override.
styleHint(StyleHint hint,const QStyleOption * option,const QWidget * widget,QStyleHintReturn * retdata) const64 	int styleHint(StyleHint hint, const QStyleOption *option,
65 		const QWidget *widget, QStyleHintReturn *retdata) const
66 	{
67 		if (hint == QStyle::SH_UnderlineShortcut)
68 			return 0;
69 		else
70 			return QProxyStyle::styleHint(hint, option, widget, retdata);
71 	}
72 
73 	// Paint job.
drawPrimitive(PrimitiveElement element,const QStyleOption * option,QPainter * painter,const QWidget * widget) const74 	void drawPrimitive(PrimitiveElement element,
75 		const QStyleOption *option,
76 		QPainter *painter, const QWidget *widget) const
77 	{
78 		if (element == PE_IndicatorRadioButton ||
79 			element == PE_IndicatorCheckBox) {
80 			const QRect& rect = option->rect;
81 			if (option->state & State_Enabled) {
82 				if (option->state & State_On)
83 					m_icon.paint(painter, rect,
84 						Qt::AlignCenter, QIcon::Normal, QIcon::On);
85 				else
86 			//	if (option->state & State_Off)
87 					m_icon.paint(painter, rect,
88 						Qt::AlignCenter, QIcon::Normal, QIcon::Off);
89 			} else {
90 				m_icon.paint(painter, rect,
91 					Qt::AlignCenter, QIcon::Disabled, QIcon::Off);
92 			}
93 		}
94 		else
95 		QProxyStyle::drawPrimitive(element, option, painter, widget);
96 	}
97 
98 	// Spiced up text margins
drawItemText(QPainter * painter,const QRect & rectangle,int alignment,const QPalette & palette,bool enabled,const QString & text,QPalette::ColorRole textRole) const99 	void drawItemText(QPainter *painter, const QRect& rectangle,
100 		int alignment, const QPalette& palette, bool enabled,
101 		const QString& text, QPalette::ColorRole textRole) const
102 	{
103 		QRect rect = rectangle;
104 		rect.setLeft(rect.left() - 4);
105 		rect.setRight(rect.right() + 4);
106 		QProxyStyle::drawItemText(painter, rect,
107 			alignment, palette, enabled, text, textRole);
108 	}
109 
addRef()110 	static void addRef ()
111 		{ if (++g_iRefCount == 1) g_pStyle = new padthv1widget_param_style(); }
112 
releaseRef()113 	static void releaseRef ()
114 		{ if (--g_iRefCount == 0) { delete g_pStyle; g_pStyle = nullptr; } }
115 
getRef()116 	static padthv1widget_param_style *getRef ()
117 		{ return g_pStyle; }
118 
119 private:
120 
121 	QIcon m_icon;
122 
123 	static padthv1widget_param_style *g_pStyle;
124 	static unsigned int g_iRefCount;
125 };
126 
127 
128 padthv1widget_param_style *padthv1widget_param_style::g_pStyle = nullptr;
129 unsigned int padthv1widget_param_style::g_iRefCount = 0;
130 
131 
132 //-------------------------------------------------------------------------
133 // padthv1widget_param - Custom composite widget.
134 //
135 
136 // Constructor.
padthv1widget_param(QWidget * pParent)137 padthv1widget_param::padthv1widget_param ( QWidget *pParent ) : QWidget(pParent)
138 {
139 	const QFont& font = QWidget::font();
140 	const QFont font2(font.family(), font.pointSize() - 2);
141 	QWidget::setFont(font2);
142 
143 	m_fValue = 0.0f;
144 
145 	m_fMinimum = 0.0f;
146 	m_fMaximum = 1.0f;
147 
148 	m_fScale = 1.0f;
149 
150 	resetDefaultValue();
151 
152 	QWidget::setMaximumSize(QSize(52, 72));
153 
154 	QGridLayout *pGridLayout = new QGridLayout();
155 	pGridLayout->setContentsMargins(0, 0, 0, 0);
156 	pGridLayout->setSpacing(0);
157 	QWidget::setLayout(pGridLayout);
158 }
159 
160 
161 // Accessors.
setText(const QString & sText)162 void padthv1widget_param::setText ( const QString& sText )
163 {
164 	setValue(sText.toFloat());
165 }
166 
167 
text(void) const168 QString padthv1widget_param::text (void) const
169 {
170 	return QString::number(value());
171 }
172 
173 
setValue(float fValue)174 void padthv1widget_param::setValue ( float fValue )
175 {
176 	QPalette pal;
177 
178 	if (m_iDefaultValue == 0) {
179 		m_fDefaultValue = fValue;
180 		m_iDefaultValue++;
181 	}
182 	else
183 	if (QWidget::isEnabled()
184 		&& ::fabsf(fValue - m_fDefaultValue) > 0.0001f) {
185 		pal.setColor(QPalette::Base,
186 			(pal.window().color().value() < 0x7f
187 				? QColor(Qt::darkYellow).darker()
188 				: QColor(Qt::yellow).lighter()));
189 	}
190 
191 	QWidget::setPalette(pal);
192 
193 	if (::fabsf(fValue - m_fValue) > 0.0001f) {
194 		m_fValue = fValue;
195 		emit valueChanged(m_fValue);
196 	}
197 }
198 
199 
value(void) const200 float padthv1widget_param::value (void) const
201 {
202 	return m_fValue;
203 }
204 
205 
valueText(void) const206 QString padthv1widget_param::valueText (void) const
207 {
208 	return QString::number(value());
209 }
210 
211 
setMaximum(float fMaximum)212 void padthv1widget_param::setMaximum ( float fMaximum )
213 {
214 	m_fMaximum = fMaximum;
215 }
216 
maximum(void) const217 float padthv1widget_param::maximum (void) const
218 {
219 	return m_fMaximum;
220 }
221 
222 
setMinimum(float fMinimum)223 void padthv1widget_param::setMinimum ( float fMinimum )
224 {
225 	m_fMinimum = fMinimum;
226 }
227 
minimum(void) const228 float padthv1widget_param::minimum (void) const
229 {
230 	return m_fMinimum;
231 }
232 
233 
resetDefaultValue(void)234 void padthv1widget_param::resetDefaultValue (void)
235 {
236 	m_fDefaultValue = 0.0f;
237 	m_iDefaultValue = 0;
238 }
239 
240 
isDefaultValue(void) const241 bool padthv1widget_param::isDefaultValue (void) const
242 {
243 	return (m_iDefaultValue > 0);
244 }
245 
246 
setDefaultValue(float fDefaultValue)247 void padthv1widget_param::setDefaultValue ( float fDefaultValue )
248 {
249 	m_fDefaultValue = fDefaultValue;
250 	m_iDefaultValue++;
251 }
252 
253 
defaultValue(void) const254 float padthv1widget_param::defaultValue (void) const
255 {
256 	return m_fDefaultValue;
257 }
258 
259 
260 // Mouse behavior event handler.
mousePressEvent(QMouseEvent * pMouseEvent)261 void padthv1widget_param::mousePressEvent ( QMouseEvent *pMouseEvent )
262 {
263 	if (pMouseEvent->button() == Qt::MiddleButton) {
264 		if (m_iDefaultValue < 1) {
265 			m_fDefaultValue = 0.5f * (maximum() + minimum());
266 			m_iDefaultValue++;
267 		}
268 		setValue(m_fDefaultValue);
269 	}
270 
271 	QWidget::mousePressEvent(pMouseEvent);
272 }
273 
274 
275 // Scale multiplier accessors.
setScale(float fScale)276 void padthv1widget_param::setScale ( float fScale )
277 {
278 	m_fScale = fScale;
279 }
280 
281 
scale(void) const282 float padthv1widget_param::scale (void) const
283 {
284 	return m_fScale;
285 }
286 
287 
288 // Scale/value converters.
scaleFromValue(float fValue) const289 float padthv1widget_param::scaleFromValue ( float fValue ) const
290 {
291 	return (m_fScale * fValue);
292 }
293 
294 
valueFromScale(float fScale) const295 float padthv1widget_param::valueFromScale ( float fScale ) const
296 {
297 	return (fScale / m_fScale);
298 }
299 
300 
301 //-------------------------------------------------------------------------
302 // padthv1widget_dial - A better QDial widget.
303 
304 padthv1widget_dial::DialMode
305 padthv1widget_dial::g_dialMode = padthv1widget_dial::DefaultMode;
306 
307 // Set knob dial mode behavior.
setDialMode(DialMode dialMode)308 void padthv1widget_dial::setDialMode ( DialMode dialMode )
309 	{ g_dialMode = dialMode; }
310 
dialMode(void)311 padthv1widget_dial::DialMode padthv1widget_dial::dialMode (void)
312 	{ return g_dialMode; }
313 
314 
315 // Constructor.
padthv1widget_dial(QWidget * pParent)316 padthv1widget_dial::padthv1widget_dial ( QWidget *pParent )
317 	: QDial(pParent), m_bMousePressed(false), m_fLastDragValue(0.0f)
318 {
319 }
320 
321 
322 // Mouse angle determination.
mouseAngle(const QPoint & pos)323 float padthv1widget_dial::mouseAngle ( const QPoint& pos )
324 {
325 	const float dx = pos.x() - (width() >> 1);
326 	const float dy = (height() >> 1) - pos.y();
327 	return 180.0f * ::atan2f(dx, dy) / float(M_PI);
328 }
329 
330 
331 // Alternate mouse behavior event handlers.
mousePressEvent(QMouseEvent * pMouseEvent)332 void padthv1widget_dial::mousePressEvent ( QMouseEvent *pMouseEvent )
333 {
334 	if (g_dialMode == DefaultMode) {
335 		QDial::mousePressEvent(pMouseEvent);
336 	} else if (pMouseEvent->button() == Qt::LeftButton) {
337 		m_bMousePressed = true;
338 		m_posMouse = pMouseEvent->pos();
339 		m_fLastDragValue = float(value());
340 		emit sliderPressed();
341 	}
342 }
343 
344 
mouseMoveEvent(QMouseEvent * pMouseEvent)345 void padthv1widget_dial::mouseMoveEvent ( QMouseEvent *pMouseEvent )
346 {
347 	if (g_dialMode == DefaultMode) {
348 		QDial::mouseMoveEvent(pMouseEvent);
349 		return;
350 	}
351 
352 	if (!m_bMousePressed)
353 		return;
354 
355 	const QPoint& pos = pMouseEvent->pos();
356 	const int dx = pos.x() - m_posMouse.x();
357 	const int dy = pos.y() - m_posMouse.y();
358 	float fAngleDelta =  mouseAngle(pos) - mouseAngle(m_posMouse);
359 	int iNewValue = value();
360 
361 	switch (g_dialMode)	{
362 	case LinearMode:
363 		iNewValue = int(m_fLastDragValue) + dx - dy;
364 		break;
365 	case AngularMode:
366 	default:
367 		// Forget about the drag origin to be robust on full rotations
368 		if (fAngleDelta > +180.0f) fAngleDelta -= 360.0f;
369 		else
370 		if (fAngleDelta < -180.0f) fAngleDelta += 360.0f;
371 		m_fLastDragValue += float(maximum() - minimum()) * fAngleDelta / 270.0f;
372 		if (m_fLastDragValue > float(maximum()))
373 			m_fLastDragValue = float(maximum());
374 		else
375 		if (m_fLastDragValue < float(minimum()))
376 			m_fLastDragValue = float(minimum());
377 		m_posMouse = pos;
378 		iNewValue = int(m_fLastDragValue + 0.5f);
379 		break;
380 	}
381 
382 	setValue(iNewValue);
383 	update();
384 
385 	emit sliderMoved(value());
386 }
387 
388 
mouseReleaseEvent(QMouseEvent * pMouseEvent)389 void padthv1widget_dial::mouseReleaseEvent ( QMouseEvent *pMouseEvent )
390 {
391 	if (g_dialMode == DefaultMode
392 		&& pMouseEvent->button() != Qt::MiddleButton) {
393 		QDial::mouseReleaseEvent(pMouseEvent);
394 	} else if (m_bMousePressed) {
395 		m_bMousePressed = false;
396 	}
397 }
398 
399 
400 //-------------------------------------------------------------------------
401 // padthv1widget_knob - Custom knob/dial widget.
402 //
403 
404 // Constructor.
padthv1widget_knob(QWidget * pParent)405 padthv1widget_knob::padthv1widget_knob ( QWidget *pParent ) : padthv1widget_param(pParent)
406 {
407 	m_pLabel = new QLabel();
408 	m_pLabel->setAlignment(Qt::AlignCenter);
409 
410 	m_pDial = new padthv1widget_dial();
411 	m_pDial->setNotchesVisible(true);
412 	m_pDial->setMaximumSize(QSize(48, 48));
413 
414 	QGridLayout *pGridLayout
415 		= static_cast<QGridLayout *> (padthv1widget_param::layout());
416 	pGridLayout->addWidget(m_pLabel, 0, 0, 1, 3);
417 	pGridLayout->addWidget(m_pDial,  1, 0, 1, 3);
418 	pGridLayout->setAlignment(m_pDial, Qt::AlignVCenter | Qt::AlignHCenter);
419 
420 	QObject::connect(m_pDial,
421 		SIGNAL(valueChanged(int)),
422 		SLOT(dialValueChanged(int)));
423 }
424 
425 
setText(const QString & sText)426 void padthv1widget_knob::setText ( const QString& sText )
427 {
428 	m_pLabel->setText(sText);
429 }
430 
431 
text(void) const432 QString padthv1widget_knob::text (void) const
433 {
434 	return m_pLabel->text();
435 }
436 
437 
setValue(float fValue)438 void padthv1widget_knob::setValue ( float fValue )
439 {
440 	const bool bDialBlock = m_pDial->blockSignals(true);
441 	m_pDial->setValue(scaleFromValue(fValue));
442 	padthv1widget_param::setValue(fValue);
443 	m_pDial->blockSignals(bDialBlock);
444 }
445 
446 
setMaximum(float fMaximum)447 void padthv1widget_knob::setMaximum ( float fMaximum )
448 {
449 	padthv1widget_param::setMaximum(fMaximum);
450 	m_pDial->setMaximum(scaleFromValue(fMaximum));
451 }
452 
453 
setMinimum(float fMinimum)454 void padthv1widget_knob::setMinimum ( float fMinimum )
455 {
456 	padthv1widget_param::setMinimum(fMinimum);
457 	m_pDial->setMinimum(scaleFromValue(fMinimum));
458 }
459 
460 
461 // Scale-step accessors.
setSingleStep(float fSingleStep)462 void padthv1widget_knob::setSingleStep ( float fSingleStep )
463 {
464 	m_pDial->setSingleStep(scaleFromValue(fSingleStep));
465 }
466 
467 
singleStep(void) const468 float padthv1widget_knob::singleStep (void) const
469 {
470 	return valueFromScale(m_pDial->singleStep());
471 }
472 
473 
474 // Dial change slot.
dialValueChanged(int iDialValue)475 void padthv1widget_knob::dialValueChanged ( int iDialValue )
476 {
477 	setValue(valueFromScale(iDialValue));
478 }
479 
480 
481 //-------------------------------------------------------------------------
482 // padthv1widget_edit - A better QDoubleSpinBox widget.
483 
484 padthv1widget_edit::EditMode
485 padthv1widget_edit::g_editMode = padthv1widget_edit::DefaultMode;
486 
487 // Set spin-box edit mode behavior.
setEditMode(EditMode editMode)488 void padthv1widget_edit::setEditMode ( EditMode editMode )
489 	{ g_editMode = editMode; }
490 
editMode(void)491 padthv1widget_edit::EditMode padthv1widget_edit::editMode (void)
492 	{ return g_editMode; }
493 
494 
495 // Constructor.
padthv1widget_edit(QWidget * pParent)496 padthv1widget_edit::padthv1widget_edit ( QWidget *pParent )
497 	: QDoubleSpinBox(pParent), m_iTextChanged(0)
498 {
499 	QObject::connect(QDoubleSpinBox::lineEdit(),
500 		SIGNAL(textChanged(const QString&)),
501 		SLOT(lineEditTextChanged(const QString&)));
502 	QObject::connect(this,
503 		SIGNAL(editingFinished()),
504 		SLOT(spinBoxEditingFinished()));
505 	QObject::connect(this,
506 		SIGNAL(valueChanged(double)),
507 		SLOT(spinBoxValueChanged(double)));
508 }
509 
510 
511 // Alternate value change behavior handlers.
lineEditTextChanged(const QString &)512 void padthv1widget_edit::lineEditTextChanged ( const QString& )
513 {
514 	if (g_editMode == DeferredMode)
515 		++m_iTextChanged;
516 }
517 
518 
spinBoxEditingFinished(void)519 void padthv1widget_edit::spinBoxEditingFinished (void)
520 {
521 	if (g_editMode == DeferredMode) {
522 		m_iTextChanged = 0;
523 		emit valueChangedEx(QDoubleSpinBox::value());
524 	}
525 }
526 
527 
spinBoxValueChanged(double spinValue)528 void padthv1widget_edit::spinBoxValueChanged ( double spinValue )
529 {
530 	if (g_editMode != DeferredMode || m_iTextChanged == 0)
531 		emit valueChangedEx(spinValue);
532 }
533 
534 
535 // Inherited/override methods.
validate(QString & sText,int & iPos) const536 QValidator::State padthv1widget_edit::validate ( QString& sText, int& iPos ) const
537 {
538 	const QValidator::State state
539 		= QDoubleSpinBox::validate(sText, iPos);
540 
541 	if (state == QValidator::Acceptable
542 		&& g_editMode == DeferredMode
543 		&& m_iTextChanged == 0)
544 		return QValidator::Intermediate;
545 
546 	return state;
547 }
548 
549 
550 //-------------------------------------------------------------------------
551 // padthv1widget_spin - Custom knob/spin-box widget.
552 //
553 
554 // Constructor.
padthv1widget_spin(QWidget * pParent)555 padthv1widget_spin::padthv1widget_spin ( QWidget *pParent )
556 	: padthv1widget_knob(pParent)
557 {
558 	m_pSpinBox = new padthv1widget_edit();
559 	m_pSpinBox->setAccelerated(true);
560 	m_pSpinBox->setAlignment(Qt::AlignCenter);
561 
562 	const QFontMetrics fm(padthv1widget_knob::font());
563 	m_pSpinBox->setMaximumHeight(fm.height() + 6);
564 
565 	QGridLayout *pGridLayout
566 		= static_cast<QGridLayout *> (padthv1widget_knob::layout());
567 	pGridLayout->addWidget(m_pSpinBox, 2, 1, 1, 1);
568 
569 	setScale(100.0f);
570 
571 	setMinimum(0.0f);
572 	setMaximum(1.0f);
573 
574 	setDecimals(1);
575 
576 	QObject::connect(m_pSpinBox,
577 		SIGNAL(valueChangedEx(double)),
578 		SLOT(spinBoxValueChanged(double)));
579 }
580 
581 
582 // Virtual accessors.
setValue(float fValue)583 void padthv1widget_spin::setValue ( float fValue )
584 {
585 	const bool bSpinBlock = m_pSpinBox->blockSignals(true);
586 	m_pSpinBox->setValue(scaleFromValue(fValue));
587 	padthv1widget_knob::setValue(fValue);
588 	m_pSpinBox->blockSignals(bSpinBlock);
589 }
590 
591 
setMaximum(float fMaximum)592 void padthv1widget_spin::setMaximum ( float fMaximum )
593 {
594 	m_pSpinBox->setMaximum(scaleFromValue(fMaximum));
595 	padthv1widget_knob::setMaximum(fMaximum);
596 }
597 
598 
setMinimum(float fMinimum)599 void padthv1widget_spin::setMinimum ( float fMinimum )
600 {
601 	m_pSpinBox->setMinimum(scaleFromValue(fMinimum));
602 	padthv1widget_knob::setMinimum(fMinimum);
603 }
604 
605 
valueText(void) const606 QString padthv1widget_spin::valueText (void) const
607 {
608 	return QString::number(m_pSpinBox->value(), 'f', 1);
609 }
610 
611 
612 // Internal widget slots.
spinBoxValueChanged(double spinValue)613 void padthv1widget_spin::spinBoxValueChanged ( double spinValue )
614 {
615 	padthv1widget_knob::setValue(valueFromScale(float(spinValue)));
616 }
617 
618 
619 // Special value text (minimum)
setSpecialValueText(const QString & sText)620 void padthv1widget_spin::setSpecialValueText ( const QString& sText )
621 {
622 	m_pSpinBox->setSpecialValueText(sText);
623 }
624 
625 
specialValueText(void) const626 QString padthv1widget_spin::specialValueText (void) const
627 {
628 	return m_pSpinBox->specialValueText();
629 }
630 
631 
isSpecialValue(void) const632 bool padthv1widget_spin::isSpecialValue (void) const
633 {
634 	return (m_pSpinBox->minimum() >= m_pSpinBox->value());
635 }
636 
637 
638 // Decimal digits allowed.
setDecimals(int iDecimals)639 void padthv1widget_spin::setDecimals ( int iDecimals )
640 {
641 	m_pSpinBox->setDecimals(iDecimals);
642 	m_pSpinBox->setSingleStep(::powf(10.0f, - float(iDecimals)));
643 
644 	setSingleStep(0.1f);
645 }
646 
decimals(void) const647 int padthv1widget_spin::decimals (void) const
648 {
649 	return m_pSpinBox->decimals();
650 }
651 
652 
653 //-------------------------------------------------------------------------
654 // padthv1widget_combo - Custom knob/combo-box widget.
655 //
656 
657 // Constructor.
padthv1widget_combo(QWidget * pParent)658 padthv1widget_combo::padthv1widget_combo ( QWidget *pParent )
659 	: padthv1widget_knob(pParent)
660 {
661 	m_pComboBox = new QComboBox();
662 
663 	const QFontMetrics fm(padthv1widget_knob::font());
664 	m_pComboBox->setMaximumHeight(fm.height() + 6);
665 
666 	QGridLayout *pGridLayout
667 		= static_cast<QGridLayout *> (padthv1widget_knob::layout());
668 	pGridLayout->addWidget(m_pComboBox, 2, 0, 1, 3);
669 
670 //	setScale(1.0f);
671 
672 	QObject::connect(m_pComboBox,
673 		SIGNAL(activated(int)),
674 		SLOT(comboBoxValueChanged(int)));
675 }
676 
677 
678 // Virtual accessors.
setValue(float fValue)679 void padthv1widget_combo::setValue ( float fValue )
680 {
681 	const bool bComboBlock = m_pComboBox->blockSignals(true);
682 	m_pComboBox->setCurrentIndex(iroundf(fValue));
683 	padthv1widget_knob::setValue(fValue);
684 	m_pComboBox->blockSignals(bComboBlock);
685 }
686 
687 
valueText(void) const688 QString padthv1widget_combo::valueText (void) const
689 {
690 	return m_pComboBox->currentText();
691 }
692 
693 
694 // Special combo-box mode accessors.
insertItems(int iIndex,const QStringList & items)695 void padthv1widget_combo::insertItems ( int iIndex, const QStringList& items )
696 {
697 	m_pComboBox->insertItems(iIndex, items);
698 
699 	setMinimum(0.0f);
700 
701 	const int iItemCount = m_pComboBox->count();
702 	if (iItemCount > 0)
703 		setMaximum(float(iItemCount - 1));
704 	else
705 		setMaximum(1.0f);
706 
707 	setSingleStep(1.0f);
708 }
709 
710 
clear(void)711 void padthv1widget_combo::clear (void)
712 {
713 	m_pComboBox->clear();
714 
715 	setMinimum(0.0f);
716 	setMaximum(1.0f);
717 
718 	setSingleStep(1.0f);
719 }
720 
721 
722 // Internal widget slots.
comboBoxValueChanged(int iComboValue)723 void padthv1widget_combo::comboBoxValueChanged ( int iComboValue )
724 {
725 	padthv1widget_knob::setValue(float(iComboValue));
726 }
727 
728 
729 // Reimplemented mouse-wheel stepping.
wheelEvent(QWheelEvent * pWheelEvent)730 void padthv1widget_combo::wheelEvent ( QWheelEvent *pWheelEvent )
731 {
732 	const int delta
733 		= (pWheelEvent->angleDelta().y() / 120);
734 	if (delta) {
735 		float fValue = value() + float(delta);
736 		if (fValue < minimum())
737 			fValue = minimum();
738 		else
739 		if (fValue > maximum())
740 			fValue = maximum();
741 		setValue(fValue);
742 	}
743 }
744 
745 
746 //-------------------------------------------------------------------------
747 // padthv1widget_radio - Custom radio/button widget.
748 //
749 
750 // Constructor.
padthv1widget_radio(QWidget * pParent)751 padthv1widget_radio::padthv1widget_radio ( QWidget *pParent )
752 	: padthv1widget_param(pParent), m_group(this)
753 {
754 	padthv1widget_param_style::addRef();
755 #if 0
756 	padthv1widget_param::setStyleSheet(
757 	//	"QRadioButton::indicator { width: 16px; height: 16px; }"
758 		"QRadioButton::indicator::unchecked { image: url(:/images/ledOff.png); }"
759 		"QRadioButton::indicator::checked   { image: url(:/images/ledOn.png);  }"
760 	);
761 #endif
762 
763 	QObject::connect(&m_group,
764 	#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
765 		SIGNAL(idClicked(int)),
766 	#else
767 		SIGNAL(buttonClicked(int)),
768 	#endif
769 		SLOT(radioGroupValueChanged(int)));
770 }
771 
772 
773 // Destructor.
~padthv1widget_radio(void)774 padthv1widget_radio::~padthv1widget_radio (void)
775 {
776 	padthv1widget_param_style::releaseRef();
777 }
778 
779 
780 // Virtual accessors.
setValue(float fValue)781 void padthv1widget_radio::setValue ( float fValue )
782 {
783 	const int iRadioValue = iroundf(fValue);
784 	QRadioButton *pRadioButton
785 		= static_cast<QRadioButton *> (m_group.button(iRadioValue));
786 	if (pRadioButton) {
787 		const bool bRadioBlock = pRadioButton->blockSignals(true);
788 		padthv1widget_param::setValue(float(iRadioValue));
789 		pRadioButton->setChecked(true);
790 		pRadioButton->blockSignals(bRadioBlock);
791 	}
792 }
793 
794 
valueText(void) const795 QString padthv1widget_radio::valueText (void) const
796 {
797 	QString sValueText;
798 	const int iRadioValue = iroundf(value());
799 	QRadioButton *pRadioButton
800 		= static_cast<QRadioButton *> (m_group.button(iRadioValue));
801 	if (pRadioButton)
802 		sValueText = pRadioButton->text();
803 	return sValueText;
804 }
805 
806 
807 // Special combo-box mode accessors.
insertItems(int iIndex,const QStringList & items)808 void padthv1widget_radio::insertItems ( int iIndex, const QStringList& items )
809 {
810 	const QFont& font = padthv1widget_param::font();
811 	const QFont font1(font.family(), font.pointSize() - 1);
812 
813 	QGridLayout *pGridLayout
814 		= static_cast<QGridLayout *> (padthv1widget_param::layout());
815 	const QString sToolTipMask(padthv1widget_param::toolTip() + ": %1");
816 	QStringListIterator iter(items);
817 	while (iter.hasNext()) {
818 		const QString& sValueText = iter.next();
819 		QRadioButton *pRadioButton = new QRadioButton(sValueText);
820 		pRadioButton->setStyle(padthv1widget_param_style::getRef());
821 		pRadioButton->setFont(font1);
822 		pRadioButton->setToolTip(sToolTipMask.arg(sValueText));
823 		pGridLayout->addWidget(pRadioButton, iIndex, 0);
824 		m_group.addButton(pRadioButton, iIndex);
825 		++iIndex;
826 	}
827 
828 	setMinimum(0.0f);
829 
830 	const QList<QAbstractButton *> list = m_group.buttons();
831 	const int iRadioCount = list.count();
832 	if (iRadioCount > 0)
833 		setMaximum(float(iRadioCount - 1));
834 	else
835 		setMaximum(1.0f);
836 }
837 
838 
clear(void)839 void padthv1widget_radio::clear (void)
840 {
841 	const QList<QAbstractButton *> list = m_group.buttons();
842 	QListIterator<QAbstractButton *> iter(list);
843 	while (iter.hasNext()) {
844 		QRadioButton *pRadioButton
845 			= static_cast<QRadioButton *> (iter.next());
846 		if (pRadioButton)
847 			m_group.removeButton(pRadioButton);
848 	}
849 
850 	setMinimum(0.0f);
851 	setMaximum(1.0f);
852 }
853 
854 
radioGroupValueChanged(int iRadioValue)855 void padthv1widget_radio::radioGroupValueChanged ( int iRadioValue )
856 {
857 	padthv1widget_param::setValue(float(iRadioValue));
858 }
859 
860 
861 //-------------------------------------------------------------------------
862 // padthv1widget_check - Custom check-box widget.
863 //
864 
865 // Constructor.
padthv1widget_check(QWidget * pParent)866 padthv1widget_check::padthv1widget_check ( QWidget *pParent )
867 	: padthv1widget_param(pParent)
868 {
869 	padthv1widget_param_style::addRef();
870 #if 0
871 	padthv1widget_param::setStyleSheet(
872 	//	"QCheckBox::indicator { width: 16px; height: 16px; }"
873 		"QCheckBox::indicator::unchecked { image: url(:/images/ledOff.png); }"
874 		"QCheckBox::indicator::checked   { image: url(:/images/ledOn.png);  }"
875 	);
876 #endif
877 	m_pCheckBox = new QCheckBox();
878 	m_pCheckBox->setStyle(padthv1widget_param_style::getRef());
879 
880 	m_alignment = Qt::AlignHCenter | Qt::AlignVCenter;
881 
882 	QGridLayout *pGridLayout
883 		= static_cast<QGridLayout *> (padthv1widget_param::layout());
884 	pGridLayout->addWidget(m_pCheckBox, 0, 0);
885 	pGridLayout->setAlignment(m_pCheckBox, m_alignment);
886 
887 	padthv1widget_param::setMaximumSize(QSize(72, 72));
888 
889 	QObject::connect(m_pCheckBox,
890 		SIGNAL(toggled(bool)),
891 		SLOT(checkBoxValueChanged(bool)));
892 }
893 
894 
895 // Destructor.
~padthv1widget_check(void)896 padthv1widget_check::~padthv1widget_check (void)
897 {
898 	padthv1widget_param_style::releaseRef();
899 }
900 
901 
902 // Accessors.
setText(const QString & sText)903 void padthv1widget_check::setText ( const QString& sText )
904 {
905 	m_pCheckBox->setText(sText);
906 }
907 
908 
text(void) const909 QString padthv1widget_check::text (void) const
910 {
911 	return m_pCheckBox->text();
912 }
913 
914 
setAlignment(Qt::Alignment alignment)915 void padthv1widget_check::setAlignment ( Qt::Alignment alignment )
916 {
917 	m_alignment = alignment;
918 
919 	QLayout *pLayout = padthv1widget_param::layout();
920 	if (pLayout)
921 		pLayout->setAlignment(m_pCheckBox, m_alignment);
922 }
923 
924 
alignment(void) const925 Qt::Alignment padthv1widget_check::alignment (void) const
926 {
927 	return m_alignment;
928 }
929 
930 
931 // Virtual accessors.
setValue(float fValue)932 void padthv1widget_check::setValue ( float fValue )
933 {
934 	const bool bCheckValue = (fValue > 0.5f * (maximum() + minimum()));
935 	const bool bCheckBlock = m_pCheckBox->blockSignals(true);
936 	padthv1widget_param::setValue(bCheckValue ? maximum() : minimum());
937 	m_pCheckBox->setChecked(bCheckValue);
938 	m_pCheckBox->blockSignals(bCheckBlock);
939 }
940 
941 
checkBoxValueChanged(bool bCheckValue)942 void padthv1widget_check::checkBoxValueChanged ( bool bCheckValue )
943 {
944 	padthv1widget_param::setValue(bCheckValue ? maximum() : minimum());
945 }
946 
947 
948 //-------------------------------------------------------------------------
949 // padthv1widget_group - Custom checkable group-box widget.
950 //
951 
952 // Constructor.
padthv1widget_group(QWidget * pParent)953 padthv1widget_group::padthv1widget_group ( QWidget *pParent )
954 	: QGroupBox(pParent)
955 {
956 	padthv1widget_param_style::addRef();
957 #if 0
958 	QGroupBox::setStyleSheet(
959 	//	"QGroupBox::indicator { width: 16px; height: 16px; }"
960 		"QGroupBox::indicator::unchecked { image: url(:/images/ledOff.png); }"
961 		"QGroupBox::indicator::checked   { image: url(:/images/ledOn.png);  }"
962 		);
963 #endif
964 	QGroupBox::setStyle(padthv1widget_param_style::getRef());
965 
966 	m_pParam = new padthv1widget_param(this);
967 	m_pParam->setToolTip(QGroupBox::toolTip());
968 	m_pParam->setValue(0.5f); // HACK: half-way on.
969 
970 	QObject::connect(m_pParam,
971 		 SIGNAL(valueChanged(float)),
972 		 SLOT(paramValueChanged(float)));
973 
974 	QObject::connect(this,
975 		 SIGNAL(toggled(bool)),
976 		 SLOT(groupBoxValueChanged(bool)));
977 }
978 
979 
980 // Destructor.
~padthv1widget_group(void)981 padthv1widget_group::~padthv1widget_group (void)
982 {
983 	padthv1widget_param_style::releaseRef();
984 
985 	delete m_pParam;
986 }
987 
988 
989 // Accessors.
setToolTip(const QString & sToolTip)990 void padthv1widget_group::setToolTip ( const QString& sToolTip )
991 {
992 	m_pParam->setToolTip(sToolTip);
993 }
994 
995 
toolTip(void) const996 QString padthv1widget_group::toolTip (void) const
997 {
998 	return m_pParam->toolTip();
999 }
1000 
1001 
param(void) const1002 padthv1widget_param *padthv1widget_group::param (void) const
1003 {
1004 	return m_pParam;
1005 }
1006 
1007 
1008 // Virtual accessors.
paramValueChanged(float fValue)1009 void padthv1widget_group::paramValueChanged ( float fValue )
1010 {
1011 	const float fMaximum = m_pParam->maximum();
1012 	const float fMinimum = m_pParam->minimum();
1013 
1014 	const bool bGroupValue = (fValue > 0.5f * (fMaximum + fMinimum));
1015 	const bool bGroupBlock = QGroupBox::blockSignals(true);
1016 	QGroupBox::setChecked(bGroupValue);
1017 	QGroupBox::blockSignals(bGroupBlock);
1018 }
1019 
1020 
groupBoxValueChanged(bool bGroupValue)1021 void padthv1widget_group::groupBoxValueChanged ( bool bGroupValue )
1022 {
1023 	const float fMaximum = m_pParam->maximum();
1024 	const float fMinimum = m_pParam->minimum();
1025 
1026 	m_pParam->setValue(bGroupValue ? fMaximum : fMinimum);
1027 }
1028 
1029 
1030 // end of padthv1widget_param.cpp
1031