1 /************************************************************************
2 ************************************************************************
3 FAUST Architecture File
4 Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale
5 ---------------------------------------------------------------------
6 This Architecture section is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 3 of
9 the License, or (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; If not, see <http://www.gnu.org/licenses/>.
19 ************************************************************************
20 ************************************************************************/
34 #include <QApplication>
38 #include <QDoubleSpinBox>
40 #include <QHBoxLayout>
42 #include <QMouseEvent>
45 #include <QProgressBar>
46 #include <QPushButton>
47 #include <QRadialGradient>
53 #include <QVBoxLayout>
54 #include <QWheelEvent>
60 //----------------------------------
63 #define minValue minimum
64 #define maxValue maximum
70 //==============================BEGIN QSYNTHKNOB=====================================
72 // qsynthknob and qsynthDialVokiStyle borrowed from qsynth-0.3.3 by Rui Nuno Capela
73 // This widget is based on a design by Thorsten Wilms,
74 // implemented by Chris Cannam in Rosegarden,
75 // adapted for QSynth by Pedro Lopez-Cabanillas,
76 // improved for Qt4 by David Garcia Garzon.
79 #define DIAL_MIN (0.25 * M_PI)
80 #define DIAL_MAX (1.75 * M_PI)
81 #define DIAL_RANGE (DIAL_MAX - DIAL_MIN)
83 class qsynthDialVokiStyle
: public QCommonStyle
86 qsynthDialVokiStyle() {};
87 virtual ~qsynthDialVokiStyle() {};
89 virtual void drawComplexControl(ComplexControl cc
, const QStyleOptionComplex
*opt
, QPainter
*p
, const QWidget
*widget
= 0) const
91 if (cc
!= QStyle::CC_Dial
)
93 QCommonStyle::drawComplexControl(cc
, opt
, p
, widget
);
97 const QStyleOptionSlider
*dial
= qstyleoption_cast
<const QStyleOptionSlider
*>(opt
);
101 double angle
= DIAL_MIN
// offset
103 (double(dial
->sliderValue
- dial
->minimum
) /
104 (double(dial
->maximum
- dial
->minimum
))));
105 int degrees
= int(angle
* 180.0 / M_PI
);
106 int side
= dial
->rect
.width() < dial
->rect
.height() ? dial
->rect
.width() : dial
->rect
.height();
107 int xcenter
= dial
->rect
.width() / 2;
108 int ycenter
= dial
->rect
.height() / 2;
109 int notchWidth
= 1 + side
/ 400;
110 int pointerWidth
= 2 + side
/ 30;
111 int scaleShadowWidth
= 1 + side
/ 100;
112 int knobBorderWidth
= 0;
113 int ns
= dial
->tickInterval
;
114 int numTicks
= 1 + (dial
->maximum
+ ns
- dial
->minimum
) / ns
;
115 int indent
= int(0.15 * side
) + 2;
116 int knobWidth
= side
- 2 * indent
;
117 int shineFocus
= knobWidth
/ 4;
118 int shineCenter
= knobWidth
/ 5;
119 int shineExtension
= shineCenter
* 4;
120 int shadowShift
= shineCenter
* 2;
121 int meterWidth
= side
- 2 * scaleShadowWidth
;
123 QPalette pal
= opt
->palette
;
124 QColor knobColor
= pal
.mid().color();
125 QColor borderColor
= knobColor
.light();
126 QColor meterColor
= (dial
->state
& State_Enabled
) ?
127 QColor("orange") : pal
.mid().color();
128 // pal.highlight().color() : pal.mid().color();
129 QColor background
= pal
.window().color();
132 p
->setRenderHint(QPainter::Antialiasing
, true);
134 // The bright metering bit...
136 QConicalGradient
meterShadow(xcenter
, ycenter
, -90);
137 meterShadow
.setColorAt(0, meterColor
.dark());
138 meterShadow
.setColorAt(0.5, meterColor
);
139 meterShadow
.setColorAt(1.0, meterColor
.light().light());
140 p
->setBrush(meterShadow
);
141 p
->setPen(Qt::transparent
);
142 p
->drawPie(xcenter
- meterWidth
/ 2, ycenter
- meterWidth
/ 2,
143 meterWidth
, meterWidth
, (180 + 45) * 16, -(degrees
- 45) * 16);
145 // Knob projected shadow
146 QRadialGradient
projectionGradient(
147 xcenter
+ shineCenter
, ycenter
+ shineCenter
,
148 shineExtension
, xcenter
+ shadowShift
, ycenter
+ shadowShift
);
149 projectionGradient
.setColorAt(0, QColor( 0, 0, 0, 100));
150 projectionGradient
.setColorAt(1, QColor(200, 0, 0, 10));
151 QBrush
shadowBrush(projectionGradient
);
152 p
->setBrush(shadowBrush
);
153 p
->drawEllipse(xcenter
- shadowShift
, ycenter
- shadowShift
,
154 knobWidth
, knobWidth
);
156 // Knob body and face...
159 pen
.setColor(knobColor
);
160 pen
.setWidth(knobBorderWidth
);
163 QRadialGradient
gradient(
164 xcenter
- shineCenter
, ycenter
- shineCenter
,
165 shineExtension
, xcenter
- shineFocus
, ycenter
- shineFocus
);
166 gradient
.setColorAt(0.2, knobColor
.light().light());
167 gradient
.setColorAt(0.5, knobColor
);
168 gradient
.setColorAt(1.0, knobColor
.dark(150));
169 QBrush
knobBrush(gradient
);
170 p
->setBrush(knobBrush
);
171 p
->drawEllipse(xcenter
- knobWidth
/ 2, ycenter
- knobWidth
/ 2,
172 knobWidth
, knobWidth
);
176 p
->setBrush(Qt::NoBrush
);
178 if (dial
->subControls
& QStyle::SC_DialTickmarks
)
180 pen
.setColor(pal
.dark().color());
181 pen
.setWidth(notchWidth
);
183 double hyp
= double(side
- scaleShadowWidth
) / 2.0;
184 double len
= hyp
/ 4;
185 for (int i
= 0; i
< numTicks
; ++i
) {
188 bool internal
= (i
!= 0 && i
!= numTicks
- 1);
189 double angle
= DIAL_MIN
190 + (DIAL_MAX
- DIAL_MIN
) * i
/ div
;
191 double dir
= (internal
? -1 : len
);
192 double sinAngle
= sin(angle
);
193 double cosAngle
= cos(angle
);
194 double x0
= xcenter
- (hyp
- len
) * sinAngle
;
195 double y0
= ycenter
+ (hyp
- len
) * cosAngle
;
196 double x1
= xcenter
- (hyp
+ dir
) * sinAngle
;
197 double y1
= ycenter
+ (hyp
+ dir
) * cosAngle
;
198 p
->drawLine(QLineF(x0
, y0
, x1
, y1
));
205 if (knobBorderWidth
> 0) {
206 QLinearGradient
inShadow(xcenter
- side
/ 4, ycenter
- side
/ 4,
207 xcenter
+ side
/ 4, ycenter
+ side
/ 4);
208 inShadow
.setColorAt(0.0, borderColor
.light());
209 inShadow
.setColorAt(1.0, borderColor
.dark());
210 p
->setPen(QPen(QBrush(inShadow
), knobBorderWidth
* 7 / 8));
211 p
->drawEllipse(xcenter
- side
/ 2 + indent
,
212 ycenter
- side
/ 2 + indent
,
213 side
- 2 * indent
, side
- 2 * indent
);
217 QLinearGradient
outShadow(xcenter
- side
/ 3, ycenter
- side
/ 3,
218 xcenter
+ side
/ 3, ycenter
+ side
/ 3);
219 outShadow
.setColorAt(0.0, background
.dark().dark());
220 outShadow
.setColorAt(1.0, background
.light().light());
221 p
->setPen(QPen(QBrush(outShadow
), scaleShadowWidth
));
222 p
->drawArc(xcenter
- side
/ 2 + scaleShadowWidth
/ 2,
223 ycenter
- side
/ 2 + scaleShadowWidth
/ 2,
224 side
- scaleShadowWidth
, side
- scaleShadowWidth
, -45 * 16, 270 * 16);
228 double hyp
= double(side
) / 2.0;
229 double len
= hyp
- indent
- 1;
231 double x
= xcenter
- len
* sin(angle
);
232 double y
= ycenter
+ len
* cos(angle
);
234 QColor pointerColor
= pal
.dark().color();
235 pen
.setColor((dial
->state
& State_Enabled
) ? pointerColor
.dark(140) : pointerColor
);
236 pen
.setWidth(pointerWidth
+ 2);
238 p
->drawLine(QLineF(xcenter
, ycenter
, x
, y
));
239 pen
.setColor((dial
->state
& State_Enabled
) ? pointerColor
.light() : pointerColor
.light(140));
240 pen
.setWidth(pointerWidth
);
242 p
->drawLine(QLineF(xcenter
- 1, ycenter
- 1, x
- 1, y
- 1));
250 //===============================END QSYNTHKNOB======================================
253 //==============================BEGIN DISPLAYS===================================
255 // This section constains displays, passive QT widgets that displays values in
256 // different ways, in particular bargraphs
260 * An abstract widget that display a value in a range
262 class AbstractDisplay
: public QWidget
271 AbstractDisplay (float lo
, float hi
) : fMin(lo
), fMax(hi
), fValue(lo
)
276 * set the range of displayed values
278 virtual void setRange(float lo
, float hi
)
285 * set the value to be displayed
287 virtual void setValue(float v
)
289 if (v
< fMin
) v
= fMin
;
290 else if (v
> fMax
) v
= fMax
;
301 * Displays dB values using a scale of colors
303 class dbAbstractDisplay
: public AbstractDisplay
310 vector
<QBrush
> fBrush
;
314 * Convert a dB value into a scale between 0 and 1 (following IEC standard ?)
316 float dB2Scale ( float dB
) const
322 else*/ if (dB
< -60.0f
)
323 fScale
= (dB
+ 70.0f
) * 0.0025f
;
324 else if (dB
< -50.0f
)
325 fScale
= (dB
+ 60.0f
) * 0.005f
+ 0.025f
;
327 fScale
= (dB
+ 50.0f
) * 0.0075f
+ 0.075f
;
328 else if (dB
< -30.0f
)
329 fScale
= (dB
+ 40.0f
) * 0.015f
+ 0.15f
;
330 else if (dB
< -20.0f
)
331 fScale
= (dB
+ 30.0f
) * 0.02f
+ 0.3f
;
332 else if (dB
< -0.001f
|| dB
> 0.001f
) /* if (dB < 0.0f) */
333 fScale
= (dB
+ 20.0f
) * 0.025f
+ 0.5f
;
340 * Create the scale of colors used to paint the bargraph in relation to the levels
341 * The parameter x indicates the direction of the gradient. x=1 means an horizontal
342 * gradient typically used by a vertical bargraph, and x=0 a vertical gradient.
344 void initLevelsColors(int x
)
347 { // level until -10 dB
348 QColor
c(40, 160, 40, alpha
);
349 QLinearGradient
g(0,0,x
,1-x
);
350 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
351 g
.setColorAt(0.0, c
.lighter());
352 g
.setColorAt(0.2, c
);
353 g
.setColorAt(0.8, c
);
354 g
.setColorAt(0.9, c
.darker(120));
356 fLevel
.push_back(-10);
357 fBrush
.push_back(QBrush(g
));
360 { // level until -6 dB
361 QColor
c(160, 220, 20, alpha
);
362 QLinearGradient
g(0,0,x
,1-x
);
363 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
364 g
.setColorAt(0.0, c
.lighter());
365 g
.setColorAt(0.2, c
);
366 g
.setColorAt(0.8, c
);
367 g
.setColorAt(0.9, c
.darker(120));
369 fLevel
.push_back(-6);
370 fBrush
.push_back(QBrush(g
));
373 { // level until -3 dB
374 QColor
c(220, 220, 20, alpha
);
375 QLinearGradient
g(0,0,x
,1-x
);
376 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
377 g
.setColorAt(0.0, c
.lighter());
378 g
.setColorAt(0.2, c
);
379 g
.setColorAt(0.8, c
);
380 g
.setColorAt(0.9, c
.darker(120));
382 fLevel
.push_back(-3);
383 fBrush
.push_back(QBrush(g
));
386 { // level until -0 dB
387 QColor
c(240, 160, 20, alpha
);
388 QLinearGradient
g(0,0,x
,1-x
);
389 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
390 g
.setColorAt(0.0, c
.lighter());
391 g
.setColorAt(0.2, c
);
392 g
.setColorAt(0.8, c
);
393 g
.setColorAt(0.9, c
.darker(120));
396 fBrush
.push_back(QBrush(g
));
399 { // until 10 dB (and over because last one)
400 QColor
c(240, 0, 20, alpha
); // ColorOver
401 QLinearGradient
g(0,0,x
,1-x
);
402 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
403 g
.setColorAt(0.0, c
.lighter());
404 g
.setColorAt(0.2, c
);
405 g
.setColorAt(0.8, c
);
406 g
.setColorAt(0.9, c
.darker(120));
408 fLevel
.push_back(+10);
409 fBrush
.push_back(QBrush(g
));
416 dbAbstractDisplay(float lo
, float hi
) : AbstractDisplay(lo
,hi
)
421 * set the range of displayed values
423 virtual void setRange(float lo
, float hi
)
425 AbstractDisplay::setRange(lo
, hi
);
426 fScaleMin
= dB2Scale(fMin
);
427 fScaleMax
= dB2Scale(fMax
);
433 * Small rectangular LED display which color changes with the level in dB
435 class dbLED
: public dbAbstractDisplay
440 * Draw the LED using a color depending of its value in dB
442 virtual void paintEvent ( QPaintEvent
*)
444 QPainter
painter(this);
445 painter
.drawRect(rect());
447 if (fValue
<= fLevel
[0]) {
449 // interpolate the first color on the alpha channel
450 QColor
c(40, 160, 40) ;
451 float a
= (fValue
-fMin
)/(fLevel
[0]-fMin
);
453 painter
.fillRect(rect(), c
);
457 // find the minimal level > value
458 int l
= fLevel
.size()-1; while (fValue
< fLevel
[l
] && l
> 0) l
--;
459 painter
.fillRect(rect(), fBrush
[l
]);
465 dbLED(float lo
, float hi
) : dbAbstractDisplay(lo
,hi
)
467 setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
471 virtual QSize
sizeHint () const
477 * Small rectangular LED display which intensity (alpha channel) changes according to the value
479 class LED
: public AbstractDisplay
486 * Draw the LED using a transparency depending of its value
488 virtual void paintEvent ( QPaintEvent
*)
490 QPainter
painter(this);
491 painter
.drawRect(rect());
492 // interpolate the first color on the alpha channel
494 float a
= (fValue
-fMin
)/(fMax
-fMin
);
496 painter
.fillRect(rect(), c
);
501 LED(float lo
, float hi
) : AbstractDisplay(lo
,hi
), fColor("yellow")
503 setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Fixed
);
506 virtual QSize
sizeHint () const
515 * A simple bargraph that detect automatically its direction
517 class linBargraph
: public AbstractDisplay
523 * No scale implemented yet
525 void paintScale(QPainter
* painter
) const
527 painter
->drawRect(0,0,width(),height());
531 * The length of the rectangle is proportional to the value
533 void paintContent (QPainter
* painter
) const
537 float v
= (fValue
-fMin
)/(fMax
-fMin
);
540 // draw vertical rectangle
541 painter
->fillRect(0,(1-v
)*h
,w
, v
*h
, fBrush
);
543 // draw horizontal rectangle
544 painter
->fillRect(0, 0, h
, v
*w
, fBrush
);
549 virtual void paintEvent ( QPaintEvent
*)
551 QPainter
painter(this);
552 paintContent(&painter
);
553 paintScale(&painter
);
558 linBargraph(float lo
, float hi
) : AbstractDisplay(lo
,hi
)
560 // compute the brush that will be used to
562 QColor
c(0xffa500); // orange
563 int x
= int(height() < width()); // gradient direction
564 QLinearGradient
g(0,0,x
,1-x
);
565 g
.setCoordinateMode(QGradient::ObjectBoundingMode
);
566 g
.setColorAt(0.0, c
.lighter());
567 g
.setColorAt(0.2, c
);
568 g
.setColorAt(0.8, c
);
569 g
.setColorAt(0.9, c
.darker(120));
576 * A simple vertical bargraph
578 class linVerticalBargraph
: public linBargraph
582 linVerticalBargraph(float lo
, float hi
) : linBargraph(lo
,hi
)
584 setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Preferred
);
587 virtual QSize
sizeHint () const
589 return QSize(16, 128);
596 * A simple horizontal bargraph
598 class linHorizontalBargraph
: public linBargraph
602 linHorizontalBargraph(float lo
, float hi
) : linBargraph(lo
,hi
)
604 setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
607 virtual QSize
sizeHint () const
609 return QSize(128, 16);
617 * A dB Bargraph with a scale of colors
619 class dbBargraph
: public dbAbstractDisplay
625 // These two abstract methods are implemented
626 // according to the vertical or horizontal direction
627 // in dbVerticalBargraph and dbHorizontalBargraph
628 virtual void paintMark(QPainter
* painter
, float v
) const = 0;
629 virtual int paintSegment (QPainter
* painter
, int pos
, float v
, const QBrush
& b
) const = 0;
632 * Draw the logarithmic scale
634 void paintScale(QPainter
* painter
) const
636 painter
->fillRect(0,0,width(),height(), fBackColor
);
638 painter
->setPen(QColor(0x6699aa)); //0xffa500));
639 for (float v
= -10; v
> fMin
; v
-= 10) paintMark(painter
, v
);
640 for (float v
= -6; v
< fMax
; v
+= 3) paintMark(painter
, v
);
646 * Draw the content using colored segments
648 void paintContent (QPainter
* painter
) const
650 int l
= fLevel
.size();
652 float p
= -1; // fake value indicates to start from border
654 // paint all the full segments < fValue
655 for (n
=0; (n
< l
) && (fValue
> fLevel
[n
]); n
++) {
656 p
= paintSegment(painter
, p
, fLevel
[n
], fBrush
[n
]);
658 // paint the last segment
660 p
=paintSegment(painter
, p
, fValue
, fBrush
[n
]);
662 painter
->drawRect(0,0,width(),height());
666 virtual void paintEvent ( QPaintEvent
*)
668 QPainter
painter(this);
669 paintScale(&painter
);
670 paintContent(&painter
);
675 dbBargraph(float lo
, float hi
) : dbAbstractDisplay(lo
,hi
)
678 QFont f
= this->font();
682 fBackColor
= QBrush(QColor(20,20,20));
688 * Vertical dB Bargraph
690 class dbVerticalBargraph
: public dbBargraph
694 * Convert a dB value into a vertical position
696 float dB2y (float dB
) const
698 float s0
= fScaleMin
;
699 float s1
= fScaleMax
;
700 float sx
= dB2Scale(dB
);
703 return h
- h
*(s0
-sx
)/(s0
-s1
);
707 * Paint a vertical graduation mark
709 virtual void paintMark(QPainter
* painter
, float v
) const
713 QRect
r(0,y
-n
,width()-1,2*n
);
715 painter
->drawText(r
, Qt::AlignRight
|Qt::AlignVCenter
, QString::number(v
).prepend('+'));
717 painter
->drawText(r
, Qt::AlignRight
|Qt::AlignVCenter
, QString::number(v
));
722 * Paint a color segment
724 virtual int paintSegment (QPainter
* painter
, int pos
, float v
, const QBrush
& b
) const
726 if (pos
== -1) pos
= height();
728 painter
->fillRect(0, y
, width(), pos
-y
+1, b
);
735 dbVerticalBargraph(float lo
, float hi
) : dbBargraph(lo
,hi
)
737 setSizePolicy(QSizePolicy::Fixed
, QSizePolicy::Preferred
);
741 virtual QSize
sizeHint () const
743 return QSize(18, 256);
748 * Horizontal dB Bargraph
750 class dbHorizontalBargraph
: public dbBargraph
756 * Convert a dB value into an horizontal position
758 float dB2x (float dB
) const
760 float s0
= fScaleMin
;
761 float s1
= fScaleMax
;
762 float sx
= dB2Scale(dB
);
765 return w
- w
*(s1
-sx
)/(s1
-s0
);
769 * Paint an horizontal graduation mark
771 void paintMark(QPainter
* painter
, float v
) const
775 QRect
r(x
-n
,0,2*n
, height());
776 painter
->drawText(r
, Qt::AlignHCenter
|Qt::AlignVCenter
, QString::number(v
));
780 * Paint a horizontal color segment
782 int paintSegment (QPainter
* painter
, int pos
, float v
, const QBrush
& b
) const
784 if (pos
== -1) pos
= 0;
786 painter
->fillRect(pos
, 0, x
-pos
, height(), b
);
793 dbHorizontalBargraph(float lo
, float hi
) : dbBargraph(lo
,hi
)
795 setSizePolicy(QSizePolicy::Preferred
, QSizePolicy::Fixed
);
799 virtual QSize
sizeHint () const
801 return QSize(256, 18);
807 //===============================END DISPLAYS====================================
809 //============================= BEGIN GROUP LABEL METADATA===========================
810 // Unlike widget's label, metadata inside group's label are not extracted directly by
811 // the Faust compiler. Therefore they must be extracted within the architecture file
812 //-----------------------------------------------------------------------------------
816 * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string
817 * (but not those in the middle of the string)
819 static string
rmWhiteSpaces(const string
& s
)
821 size_t i
= s
.find_first_not_of(" \t");
822 size_t j
= s
.find_last_not_of(" \t");
823 if ( (i
!= string::npos
) && (j
!= string::npos
) ) {
824 return s
.substr(i
, 1+j
-i
);
831 * Extracts metdata from a label : 'vol [unit: dB]' -> 'vol' + metadata(unit=dB)
833 static void extractMetadata(const string
& fulllabel
, string
& label
, map
<string
, string
>& metadata
)
835 enum {kLabel
, kEscape1
, kEscape2
, kEscape3
, kKey
, kValue
};
836 int state
= kLabel
; int deep
= 0;
839 for (unsigned int i
=0; i
< fulllabel
.size(); i
++) {
840 char c
= fulllabel
[i
];
845 case '\\' : state
= kEscape1
; break;
846 case '[' : state
= kKey
; deep
++; break;
847 default : label
+= c
;
869 case '\\' : state
= kEscape2
;
876 case ':' : if (deep
== 1) {
884 metadata
[rmWhiteSpaces(key
)] = "";
899 case '\\' : state
= kEscape3
;
908 metadata
[rmWhiteSpaces(key
)]=rmWhiteSpaces(value
);
916 default : value
+= c
;
921 cerr
<< "ERROR unrecognized state " << state
<< endl
;
924 label
= rmWhiteSpaces(label
);
927 //============================= END GROUP LABEL METADATA===========================
930 /******************************************************************************
931 *******************************************************************************
933 IMPLEMENTATION OF GUI ITEMS
936 *******************************************************************************
937 *******************************************************************************/
940 class uiButton
: public QObject
, public uiItem
945 QAbstractButton
* fButton
;
947 uiButton (GUI
* ui
, float* zone
, QAbstractButton
* b
) : uiItem(ui
, zone
), fButton(b
) {}
950 virtual void reflectZone()
954 fButton
->setDown( v
> 0.0 );
958 void pressed() { modifyZone(1.0); }
959 void released() { modifyZone(0.0); }
963 class uiCheckButton
: public QObject
, public uiItem
968 QCheckBox
* fCheckBox
;
970 uiCheckButton (GUI
* ui
, float* zone
, QCheckBox
* b
) : uiItem(ui
, zone
), fCheckBox(b
) {}
972 virtual void reflectZone()
976 fCheckBox
->setCheckState( (v
< 0.5) ? Qt::Unchecked
: Qt::Checked
);
980 void setState(int v
) { modifyZone(float(v
>0)); }
984 class uiSlider
: public QObject
, public uiItem
988 int faust2qt(float x
) { return int(0.5 + (x
-fMin
)/fStep
); }
989 float qt2faust (int v
) { return fMin
+ v
*fStep
; }
992 while((fMax
-fMin
)/x
> 50) x
*=10;
993 while((fMax
-fMin
)/x
< 10) x
/=2;
994 return faust2qt(fMin
+x
);
1004 uiSlider (GUI
* ui
, float* zone
, QSlider
* slider
, float cur
, float lo
, float hi
, float step
)
1005 : uiItem(ui
, zone
), fSlider(slider
), fCur(cur
), fMin(lo
), fMax(hi
), fStep(step
)
1007 fSlider
->setMinimum(0);
1008 fSlider
->setMaximum(faust2qt(fMax
));
1009 fSlider
->setValue(faust2qt(fCur
));
1010 fSlider
->setTickInterval(optimalTick());
1014 virtual void reflectZone()
1018 fSlider
->setValue(faust2qt(v
));
1022 void setValue(int v
) { modifyZone(qt2faust(v
)); }
1026 class uiKnob
: public QObject
, public uiItem
1030 int faust2qt(float x
) { return int(0.5 + (x
-fMin
)/fStep
); }
1031 float qt2faust (int v
) { return fMin
+ v
*fStep
; }
1034 while((fMax
-fMin
)/x
> 50) x
*=10;
1035 while((fMax
-fMin
)/x
< 10) x
/=2;
1036 return faust2qt(fMin
+x
);
1040 QAbstractSlider
* fSlider
;
1046 uiKnob (GUI
* ui
, float* zone
, QAbstractSlider
* slider
, float cur
, float lo
, float hi
, float step
)
1047 : uiItem(ui
, zone
), fSlider(slider
), fCur(cur
), fMin(lo
), fMax(hi
), fStep(step
)
1049 fSlider
->setMinimum(0);
1050 fSlider
->setMaximum(faust2qt(fMax
));
1051 fSlider
->setValue(faust2qt(fCur
));
1052 //fSlider->setTickInterval(optimalTick());
1056 virtual void reflectZone()
1060 fSlider
->setValue(faust2qt(v
));
1064 void setValue(int v
) { modifyZone(qt2faust(v
)); }
1068 class uiBargraph
: public QObject
, public uiItem
1072 int faust2qt(float x
) { return int(0.5 + (x
-fMin
)/(fMax
-fMin
)*fStep
); }
1080 uiBargraph (GUI
* ui
, float* zone
, QProgressBar
* bar
, float lo
, float hi
)
1081 : uiItem(ui
, zone
), fBar(bar
), fMin(lo
), fMax(hi
), fStep(1024)
1083 fBar
->setRange(0, fStep
);
1088 virtual void reflectZone()
1092 int x
= faust2qt(v
);
1093 //std::cout << "update *" << fBar << " = " << x << std::endl;
1099 class uiBargraph2
: public QObject
, public uiItem
1104 AbstractDisplay
* fBar
;
1106 uiBargraph2 (GUI
* ui
, float* zone
, AbstractDisplay
* bar
, float lo
, float hi
)
1107 : uiItem(ui
, zone
), fBar(bar
)
1109 fBar
->setRange(lo
, hi
);
1114 virtual void reflectZone()
1124 class uiNumEntry
: public QObject
, public uiItem
1129 QDoubleSpinBox
* fNumEntry
;
1136 uiNumEntry (GUI
* ui
, float* zone
, QDoubleSpinBox
* numEntry
, float cur
, float lo
, float hi
, float step
)
1137 : uiItem(ui
, zone
), fNumEntry(numEntry
), fCur(cur
), fMin(lo
), fMax(hi
), fStep(step
)
1139 fDecimals
= (fStep
>= 1.0) ? 0 : int(0.5+log10(1.0/fStep
));
1141 fNumEntry
->setMinimum(fMin
);
1142 fNumEntry
->setMaximum(fMax
);
1143 fNumEntry
->setSingleStep(fStep
);
1144 fNumEntry
->setDecimals(fDecimals
);
1145 fNumEntry
->setValue(fCur
);
1150 virtual void reflectZone()
1154 fNumEntry
->setValue(v
);
1158 void setValue(double v
) {
1159 modifyZone(float(v
));
1166 /******************************************************************************
1167 *******************************************************************************
1169 IMPLEMENTATION OF THE USER INTERFACE
1172 *******************************************************************************
1173 *******************************************************************************/
1176 class QTGUI
: public QObject
, public GUI
1182 string gGroupTooltip
;
1183 stack
<QWidget
* > fGroupStack
;
1185 map
<float*, float> fGuiSize
; // map widget zone with widget size coef
1186 map
<float*, string
> fTooltip
; // map widget zone with tooltip strings
1187 map
<float*, string
> fUnit
; // map widget zone to unit string (i.e. "dB")
1188 set
<float*> fKnobSet
; // set of widget zone to be knobs
1189 set
<float*> fLedSet
; // set of widget zone to be LEDs
1193 * Format tooltip string by replacing some white spaces by
1194 * return characters so that line width doesn't exceed n.
1195 * Limitation : long words exceeding n are not cut
1197 virtual string
formatTooltip(int n
, const string
& tt
)
1199 string ss
= tt
; // ss string we are going to format
1200 int lws
= 0; // last white space encountered
1201 int lri
= 0; // last return inserted
1202 for (int i
=0; i
< (int)tt
.size(); i
++) {
1203 if (tt
[i
] == ' ') lws
= i
;
1204 if (((i
-lri
) >= n
) && (lws
> lri
)) {
1205 // insert return here
1215 * Analyses the widget zone metadata declarations and takes
1216 * appropriate actions
1218 virtual void declare(float* zone
, const char* key
, const char* value
)
1221 // special zone 0 means group metadata
1222 if (strcmp(key
,"tooltip")==0) {
1223 // only group tooltip are currently implemented
1224 gGroupTooltip
= formatTooltip(30, value
);
1227 if (strcmp(key
,"size")==0) {
1228 fGuiSize
[zone
]=atof(value
);
1230 else if (strcmp(key
,"tooltip")==0) {
1231 fTooltip
[zone
] = formatTooltip(30, value
) ;
1233 else if (strcmp(key
,"unit")==0) {
1234 fUnit
[zone
] = value
;
1236 else if (strcmp(key
,"style")==0) {
1237 // else if ((strcmp(key,"style")==0) || (strcmp(key,"type")==0)) {
1238 if (strcmp(value
,"knob") == 0) {
1239 fKnobSet
.insert(zone
);
1240 } else if (strcmp(value
,"led") == 0) {
1241 fLedSet
.insert(zone
);
1249 return fGroupStack
.empty() || ((!fGroupStack
.empty()) && (dynamic_cast<QTabWidget
*>(fGroupStack
.top()) != 0));
1252 void insert(const char* label
, QWidget
* widget
)
1254 if (fStyle
) widget
->setStyle(fStyle
);
1255 if (!fGroupStack
.empty()) {
1256 QWidget
* mother
= fGroupStack
.top();
1257 QTabWidget
* tab
= dynamic_cast<QTabWidget
*>(mother
);
1259 tab
->addTab(widget
,label
);
1261 widget
->setParent(mother
);
1262 mother
->layout()->addWidget(widget
);
1268 * Analyses a full label and activates the relevant options. returns a simplified
1269 * label (without options) and an amount of stack adjustement (in case additional
1270 * containers were pushed on the stack).
1273 int checkLabelOptions(QWidget
* widget
, const string
& fullLabel
, string
& simplifiedLabel
)
1275 map
<string
, string
> metadata
;
1276 extractMetadata(fullLabel
, simplifiedLabel
, metadata
);
1278 if (metadata
.count("tooltip")) {
1279 widget
->setToolTip(metadata
["tooltip"].c_str());
1281 if (metadata
["option"] == "detachable") {
1282 //openHandleBox(simplifiedLabel.c_str());
1286 // no adjustement of the stack needed
1291 * Check if a tooltip is associated to a zone and add it to the corresponding widget
1293 void checkForTooltip(float* zone
, QWidget
* widget
)
1295 if (fTooltip
.count(zone
)) {
1296 widget
->setToolTip(fTooltip
[zone
].c_str());
1301 * Check if a knob is required
1303 bool isKnob(float* zone
)
1305 return fKnobSet
.count(zone
) > 0;
1308 void openBox(const char* fulllabel
, QLayout
* layout
)
1310 map
<string
, string
> metadata
;
1312 extractMetadata(fulllabel
, label
, metadata
);
1313 layout
->setMargin(5);
1316 if (isTabContext()) {
1317 box
= new QWidget();
1318 // set background color
1319 QPalette pal
= box
->palette();
1320 pal
.setColor(box
->backgroundRole(), QColor::fromRgb(150, 150, 150) );
1321 box
->setPalette(pal
);
1323 } else if (label
.size()>0) {
1324 QGroupBox
* group
= new QGroupBox();
1325 group
->setTitle(label
.c_str());
1328 // no label here we use simple widget
1329 layout
->setMargin(0);
1330 box
= new QWidget();
1333 box
->setLayout(layout
);
1334 /* if (metadata.count("tooltip")) {
1335 box->setToolTip(metadata["tooltip"].c_str());
1337 if (gGroupTooltip
!= string()) {
1338 box
->setToolTip(gGroupTooltip
.c_str());
1339 gGroupTooltip
= string();
1341 insert(label
.c_str(), box
);
1342 fGroupStack
.push(box
);
1345 void openTab(const char* label
)
1347 QTabWidget
* group
= new QTabWidget();
1348 if (fStyle
) group
->setStyle(fStyle
);
1349 insert(label
, group
);
1350 fGroupStack
.push(group
);
1356 //std::cout << '.' << std::endl;
1362 QTGUI(int argc
, char* argv
[], QStyle
* style
= 0) : fAppl(argc
, argv
), fTimer(0), fStyle(style
){
1363 //fGroupStack.push(new QMainWindow());
1371 fTimer
= new QTimer(this);
1372 QObject::connect(fTimer
, SIGNAL(timeout()), this, SLOT(update()));
1376 fAppl
.setStyleSheet(
1380 "background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,"
1381 "stop: 0 #B0B0B0, stop: 1 #404040);"
1382 "border: 2px solid grey;"
1383 "border-radius: 6px;"
1387 "QPushButton:hover {"
1388 "border: 2px solid orange;"
1391 "QPushButton:pressed {"
1392 //"border: 1px solid orange;"
1393 "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1394 "stop: 0 #404040, stop: 1 #B0B0B0);"
1398 "background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,"
1399 "stop: 0 #A0A0A0, stop: 1 #202020);"
1400 "border: 2px solid gray;"
1401 "border-radius: 5px;"
1405 //"color: dark grey;"
1409 "QGroupBox::title {"
1410 "subcontrol-origin: margin;"
1411 "subcontrol-position: top center;" /* position at the top center */
1415 // horizontal sliders
1416 "QSlider::groove:vertical {"
1418 "position: absolute;" /* absolutely position 4px from the left and right of the widget. setting margins on the widget should work too... */
1419 "left: 13px; right: 13px;"
1422 "QSlider::handle:vertical {"
1425 "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1426 "stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);"
1427 "margin: 0 -5px; /* expand outside the groove */"
1428 "border-radius: 5px;"
1431 "QSlider::add-page:vertical {"
1432 "background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,"
1433 "stop: 0 yellow, stop : 0.5 orange);"
1436 "QSlider::sub-page:vertical {"
1440 // horizontal sliders
1442 "QSlider::groove:horizontal {"
1444 "position: absolute;" /* absolutely position 4px from the left and right of the widget. setting margins on the widget should work too... */
1445 "top: 14px; bottom: 14px;"
1448 "QSlider::handle:horizontal {"
1450 "background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,"
1451 "stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);"
1452 "margin: -5px 0; /* expand outside the groove */"
1453 "border-radius: 5px;"
1456 "QSlider::sub-page:horizontal {"
1457 "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1458 "stop: 0 yellow, stop : 0.5 orange);"
1461 "QSlider::add-page:horizontal {"
1466 //TabWidget and TabBar
1467 "QTabWidget::pane {" /* The tab widget frame */
1468 //"border-top: 2px solid #C2C7CB;"
1469 "border-top: 2px solid orange;"
1470 "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1471 "stop: 0 #A0A0A0, stop: 1 #202020);"
1474 "QTabWidget::tab-bar {"
1475 "left: 5px;" /* move to the right by 5px */
1478 /* Style the tab using the tab sub-control. Note that
1479 it reads QTabBar _not_ QTabWidget */
1481 "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1482 "stop: 0 #909090, stop: 0.4 #888888,"
1483 "stop: 0.5 #808080, stop: 1.0 #909090);"
1484 "border: 2px solid #808080;"
1485 //"border-bottom-color: #C2C7CB;" /* same as the pane color */
1486 "border-bottom-color: orange;" /* same as the pane color */
1487 "border-top-left-radius: 4px;"
1488 "border-top-right-radius: 4px;"
1493 "QTabBar::tab:selected, QTabBar::tab:hover {"
1494 "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"
1495 "stop: 0 #D0D0D0, stop: 0.4 #A0A0A0,"
1496 "stop: 0.5 #808080, stop: 1.0 #A0A0A0);"
1497 //"stop: 0.5 #A0A0A0, stop: 1.0 #C0C0C0);"
1498 //"stop: 0 #fafafa, stop: 0.4 #f4f4f4,"
1499 //"stop: 0.5 #e7e7e7, stop: 1.0 #fafafa);"
1500 //"border-bottom-color: orange;" /* same as the pane color */
1503 "QTabBar::tab:selected {"
1504 "border-color: orange;"
1505 "border-bottom-color: #A0A0A0;" /* same as pane color */
1508 "QTabBar::tab:!selected {"
1509 " margin-top: 2px;" /* make non-selected tabs look smaller */
1519 // ------------------------- Groups -----------------------------------
1521 virtual void openHorizontalBox(const char* label
) {
1522 openBox(label
, new QHBoxLayout());
1525 virtual void openVerticalBox(const char* label
) {
1526 openBox(label
, new QVBoxLayout());
1529 virtual void openFrameBox(const char* ) { }
1530 virtual void openTabBox(const char* label
) {
1534 virtual void closeBox()
1536 QWidget
* group
= fGroupStack
.top();
1538 if (fGroupStack
.empty()) { group
->show(); }
1541 // ------------------------- active widgets -----------------------------------
1543 virtual void addButton(const char* label
, float* zone
)
1545 QAbstractButton
* w
= new QPushButton(label
);
1546 uiButton
* c
= new uiButton(this, zone
, w
);
1549 QObject::connect(w
, SIGNAL(pressed()), c
, SLOT(pressed()));
1550 QObject::connect(w
, SIGNAL(released()), c
, SLOT(released()));
1551 checkForTooltip(zone
, w
);
1554 virtual void addToggleButton(const char* , float* )
1557 virtual void addCheckButton(const char* label
, float* zone
)
1559 QCheckBox
* w
= new QCheckBox(label
);
1560 uiCheckButton
* c
= new uiCheckButton(this, zone
, w
);
1563 QObject::connect(w
, SIGNAL(stateChanged(int)), c
, SLOT(setState(int)));
1564 checkForTooltip(zone
, w
);
1567 virtual void addNumEntry(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1570 addVerticalKnob(label
, zone
, init
, min
, max
, step
);
1573 //insert(label, new QDoubleSpinBox());
1574 if (label
&& label
[0]) openVerticalBox(label
);
1575 QDoubleSpinBox
* w
= new QDoubleSpinBox();
1576 uiNumEntry
* c
= new uiNumEntry(this, zone
, w
, init
, min
, max
, step
);
1578 w
->setSuffix(fUnit
[zone
].c_str());
1579 QObject::connect(w
, SIGNAL(valueChanged(double)), c
, SLOT(setValue(double)));
1580 if (label
&& label
[0]) closeBox();
1581 checkForTooltip(zone
, w
);
1584 // special num entry without buttons
1585 virtual void addNumDisplay(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1587 //insert(label, new QDoubleSpinBox());
1588 if (label
&& label
[0]) openVerticalBox(label
);
1589 QDoubleSpinBox
* w
= new QDoubleSpinBox();
1590 w
->setAlignment(Qt::AlignHCenter
);
1594 "border: 2px solid orange;"
1595 "border-radius: 5px;"
1599 uiNumEntry
* c
= new uiNumEntry(this, zone
, w
, init
, min
, max
, step
);
1601 w
->setButtonSymbols(QAbstractSpinBox::NoButtons
);
1602 w
->setSuffix(fUnit
[zone
].c_str());
1603 QObject::connect(w
, SIGNAL(valueChanged(double)), c
, SLOT(setValue(double)));
1604 if (label
&& label
[0]) closeBox();
1605 checkForTooltip(zone
, w
);
1609 //////////////////////////////////////////////////////////////////////////////////////////////////////////
1613 //////////////////////////////////////////////////////////////////////////////////////////////////////////
1615 virtual void addVerticalKnob(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1617 openVerticalBox(label
);
1618 QAbstractSlider
* w
= new QDial(); //qsynthKnob();
1619 uiKnob
* c
= new uiKnob(this, zone
, w
, init
, min
, max
, step
);
1621 w
->setStyle(new qsynthDialVokiStyle());
1622 QObject::connect(w
, SIGNAL(valueChanged(int)), c
, SLOT(setValue(int)));
1623 addNumDisplay(0, zone
, init
, min
, max
, step
);
1625 // compute the size of the knob+display
1626 int width
= int(64*pow(2,fGuiSize
[zone
]));
1627 int height
= int(100*pow(2,fGuiSize
[zone
]));
1628 fGroupStack
.top()->setMinimumSize(width
,height
);
1629 fGroupStack
.top()->setMaximumSize(width
,height
);
1632 checkForTooltip(zone
, w
);
1635 virtual void addHorizontalKnob(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1637 openHorizontalBox(label
);
1638 QAbstractSlider
* w
= new QDial(); //new qsynthKnob();
1639 uiKnob
* c
= new uiKnob(this, zone
, w
, init
, min
, max
, step
);
1641 w
->setStyle(new qsynthDialVokiStyle());
1642 QObject::connect(w
, SIGNAL(valueChanged(int)), c
, SLOT(setValue(int)));
1643 addNumDisplay(0, zone
, init
, min
, max
, step
);
1645 checkForTooltip(zone
, w
);
1648 //////////////////////////////////////////////////////////////////////////////////////////////////////////
1652 //////////////////////////////////////////////////////////////////////////////////////////////////////////
1654 virtual void addVerticalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1657 addVerticalKnob(label
, zone
, init
, min
, max
, step
);
1660 openVerticalBox(label
);
1661 QSlider
* w
= new QSlider(Qt::Vertical
);
1662 w
->setMinimumHeight(160);
1663 w
->setMinimumWidth(34);
1664 //w->setTickPosition(QSlider::TicksBothSides);
1665 uiSlider
* c
= new uiSlider(this, zone
, w
, init
, min
, max
, step
);
1667 QObject::connect(w
, SIGNAL(valueChanged(int)), c
, SLOT(setValue(int)));
1668 addNumDisplay(0, zone
, init
, min
, max
, step
);
1670 checkForTooltip(zone
, w
);
1673 virtual void addHorizontalSlider(const char* label
, float* zone
, float init
, float min
, float max
, float step
)
1676 addHorizontalKnob(label
, zone
, init
, min
, max
, step
);
1679 openHorizontalBox(label
);
1680 QSlider
* w
= new QSlider(Qt::Horizontal
);
1681 w
->setMinimumHeight(34);
1682 w
->setMinimumWidth(160);
1683 //w->setTickPosition(QSlider::TicksBothSides);
1684 uiSlider
* c
= new uiSlider(this, zone
, w
, init
, min
, max
, step
);
1686 QObject::connect(w
, SIGNAL(valueChanged(int)), c
, SLOT(setValue(int)));
1687 addNumDisplay(0, zone
, init
, min
, max
, step
);
1689 checkForTooltip(zone
, w
);
1692 // ------------------------- passive widgets -----------------------------------
1694 virtual void addNumDisplay(const char*, float*, int)
1697 virtual void addTextDisplay(const char*, float*, const char* [], float, float)
1700 virtual void addHorizontalBargraph(const char* label
, float* zone
, float min
, float max
)
1702 AbstractDisplay
* bargraph
;
1703 openVerticalBox(label
);
1704 bool db
= (fUnit
[zone
] == "dB");
1706 if (fLedSet
.count(zone
)) {
1708 bargraph
= new dbLED(min
, max
);
1710 bargraph
= new LED(min
,max
);
1714 bargraph
= new dbHorizontalBargraph(min
, max
);
1716 bargraph
= new linHorizontalBargraph(min
, max
);
1720 new uiBargraph2(this, zone
, bargraph
, min
, max
);
1721 insert(label
, bargraph
);
1723 checkForTooltip(zone
, bargraph
);
1726 virtual void addVerticalBargraph(const char* label
, float* zone
, float min
, float max
)
1728 AbstractDisplay
* bargraph
;
1729 openVerticalBox(label
);
1730 bool db
= (fUnit
[zone
] == "dB");
1732 if (fLedSet
.count(zone
)) {
1734 bargraph
= new dbLED(min
, max
);
1736 bargraph
= new LED(min
,max
);
1740 bargraph
= new dbVerticalBargraph(min
, max
);
1742 bargraph
= new linVerticalBargraph(min
, max
);
1745 new uiBargraph2(this, zone
, bargraph
, min
, max
);
1746 insert(label
, bargraph
);
1748 checkForTooltip(zone
, bargraph
);