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