+/************************************************************************\r
+ ************************************************************************\r
+ FAUST Architecture File\r
+ Copyright (C) 2003-2011 GRAME, Centre National de Creation Musicale\r
+ ---------------------------------------------------------------------\r
+ This Architecture section is free software; you can redistribute it\r
+ and/or modify it under the terms of the GNU General Public License\r
+ as published by the Free Software Foundation; either version 3 of\r
+ the License, or (at your option) any later version.\r
+\r
+ This program is distributed in the hope that it will be useful,\r
+ but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+ GNU General Public License for more details.\r
+\r
+ You should have received a copy of the GNU General Public License\r
+ along with this program; If not, see <http://www.gnu.org/licenses/>.\r
+\r
+ ************************************************************************\r
+ ************************************************************************/\r
+#ifndef __faustqt__\r
+#define __faustqt__\r
+\r
+#include <cassert>\r
+#include <cmath>\r
+#include <fstream>\r
+#include <iostream>\r
+#include <list>\r
+#include <map>\r
+#include <set>\r
+#include <vector>\r
+#include <stack>\r
+\r
+#include <QApplication>\r
+#include <QCheckBox>\r
+#include <QColormap>\r
+#include <QDial>\r
+#include <QDoubleSpinBox>\r
+#include <QGroupBox>\r
+#include <QHBoxLayout>\r
+#include <QLayout>\r
+#include <QMouseEvent>\r
+#include <QObject>\r
+#include <QPainter>\r
+#include <QProgressBar>\r
+#include <QPushButton>\r
+#include <QRadialGradient>\r
+#include <QSlider>\r
+#include <QStyle>\r
+#include <QTabWidget>\r
+#include <QTimer>\r
+#include <QToolTip>\r
+#include <QVBoxLayout>\r
+#include <QWheelEvent>\r
+#include <QWidget>\r
+#include <QtGui>\r
+\r
+#include "GUI.h"\r
+\r
+//----------------------------------\r
+\r
+// for compatibility\r
+#define minValue minimum\r
+#define maxValue maximum\r
+\r
+\r
+using namespace std;\r
+\r
+\r
+//==============================BEGIN QSYNTHKNOB=====================================\r
+//\r
+// qsynthknob and qsynthDialVokiStyle borrowed from qsynth-0.3.3 by Rui Nuno Capela\r
+// This widget is based on a design by Thorsten Wilms,\r
+// implemented by Chris Cannam in Rosegarden,\r
+// adapted for QSynth by Pedro Lopez-Cabanillas,\r
+// improved for Qt4 by David Garcia Garzon.\r
+//\r
+\r
+#define DIAL_MIN (0.25 * M_PI)\r
+#define DIAL_MAX (1.75 * M_PI)\r
+#define DIAL_RANGE (DIAL_MAX - DIAL_MIN)\r
+\r
+class qsynthDialVokiStyle : public QCommonStyle\r
+{\r
+public:\r
+ qsynthDialVokiStyle() {};\r
+ virtual ~qsynthDialVokiStyle() {};\r
+\r
+ virtual void drawComplexControl(ComplexControl cc, const QStyleOptionComplex *opt, QPainter *p, const QWidget *widget = 0) const\r
+ {\r
+ if (cc != QStyle::CC_Dial)\r
+ {\r
+ QCommonStyle::drawComplexControl(cc, opt, p, widget);\r
+ return;\r
+ }\r
+\r
+ const QStyleOptionSlider *dial = qstyleoption_cast<const QStyleOptionSlider *>(opt);\r
+ if (dial == NULL)\r
+ return;\r
+\r
+ double angle = DIAL_MIN // offset\r
+ + (DIAL_RANGE *\r
+ (double(dial->sliderValue - dial->minimum) /\r
+ (double(dial->maximum - dial->minimum))));\r
+ int degrees = int(angle * 180.0 / M_PI);\r
+ int side = dial->rect.width() < dial->rect.height() ? dial->rect.width() : dial->rect.height();\r
+ int xcenter = dial->rect.width() / 2;\r
+ int ycenter = dial->rect.height() / 2;\r
+ int notchWidth = 1 + side / 400;\r
+ int pointerWidth = 2 + side / 30;\r
+ int scaleShadowWidth = 1 + side / 100;\r
+ int knobBorderWidth = 0;\r
+ int ns = dial->tickInterval;\r
+ int numTicks = 1 + (dial->maximum + ns - dial->minimum) / ns;\r
+ int indent = int(0.15 * side) + 2;\r
+ int knobWidth = side - 2 * indent;\r
+ int shineFocus = knobWidth / 4;\r
+ int shineCenter = knobWidth / 5;\r
+ int shineExtension = shineCenter * 4;\r
+ int shadowShift = shineCenter * 2;\r
+ int meterWidth = side - 2 * scaleShadowWidth;\r
+\r
+ QPalette pal = opt->palette;\r
+ QColor knobColor = pal.mid().color();\r
+ QColor borderColor = knobColor.light();\r
+ QColor meterColor = (dial->state & State_Enabled) ?\r
+ QColor("orange") : pal.mid().color();\r
+ // pal.highlight().color() : pal.mid().color();\r
+ QColor background = pal.window().color();\r
+\r
+ p->save();\r
+ p->setRenderHint(QPainter::Antialiasing, true);\r
+\r
+ // The bright metering bit...\r
+\r
+ QConicalGradient meterShadow(xcenter, ycenter, -90);\r
+ meterShadow.setColorAt(0, meterColor.dark());\r
+ meterShadow.setColorAt(0.5, meterColor);\r
+ meterShadow.setColorAt(1.0, meterColor.light().light());\r
+ p->setBrush(meterShadow);\r
+ p->setPen(Qt::transparent);\r
+ p->drawPie(xcenter - meterWidth / 2, ycenter - meterWidth / 2,\r
+ meterWidth, meterWidth, (180 + 45) * 16, -(degrees - 45) * 16);\r
+\r
+ // Knob projected shadow\r
+ QRadialGradient projectionGradient(\r
+ xcenter + shineCenter, ycenter + shineCenter,\r
+ shineExtension, xcenter + shadowShift, ycenter + shadowShift);\r
+ projectionGradient.setColorAt(0, QColor( 0, 0, 0, 100));\r
+ projectionGradient.setColorAt(1, QColor(200, 0, 0, 10));\r
+ QBrush shadowBrush(projectionGradient);\r
+ p->setBrush(shadowBrush);\r
+ p->drawEllipse(xcenter - shadowShift, ycenter - shadowShift,\r
+ knobWidth, knobWidth);\r
+\r
+ // Knob body and face...\r
+\r
+ QPen pen;\r
+ pen.setColor(knobColor);\r
+ pen.setWidth(knobBorderWidth);\r
+ p->setPen(pen);\r
+\r
+ QRadialGradient gradient(\r
+ xcenter - shineCenter, ycenter - shineCenter,\r
+ shineExtension, xcenter - shineFocus, ycenter - shineFocus);\r
+ gradient.setColorAt(0.2, knobColor.light().light());\r
+ gradient.setColorAt(0.5, knobColor);\r
+ gradient.setColorAt(1.0, knobColor.dark(150));\r
+ QBrush knobBrush(gradient);\r
+ p->setBrush(knobBrush);\r
+ p->drawEllipse(xcenter - knobWidth / 2, ycenter - knobWidth / 2,\r
+ knobWidth, knobWidth);\r
+\r
+ // Tick notches...\r
+\r
+ p->setBrush(Qt::NoBrush);\r
+\r
+ if (dial->subControls & QStyle::SC_DialTickmarks)\r
+ {\r
+ pen.setColor(pal.dark().color());\r
+ pen.setWidth(notchWidth);\r
+ p->setPen(pen);\r
+ double hyp = double(side - scaleShadowWidth) / 2.0;\r
+ double len = hyp / 4;\r
+ for (int i = 0; i < numTicks; ++i) {\r
+ int div = numTicks;\r
+ if (div > 1) --div;\r
+ bool internal = (i != 0 && i != numTicks - 1);\r
+ double angle = DIAL_MIN\r
+ + (DIAL_MAX - DIAL_MIN) * i / div;\r
+ double dir = (internal ? -1 : len);\r
+ double sinAngle = sin(angle);\r
+ double cosAngle = cos(angle);\r
+ double x0 = xcenter - (hyp - len) * sinAngle;\r
+ double y0 = ycenter + (hyp - len) * cosAngle;\r
+ double x1 = xcenter - (hyp + dir) * sinAngle;\r
+ double y1 = ycenter + (hyp + dir) * cosAngle;\r
+ p->drawLine(QLineF(x0, y0, x1, y1));\r
+ }\r
+ }\r
+\r
+ // Shadowing...\r
+\r
+ // Knob shadow...\r
+ if (knobBorderWidth > 0) {\r
+ QLinearGradient inShadow(xcenter - side / 4, ycenter - side / 4,\r
+ xcenter + side / 4, ycenter + side / 4);\r
+ inShadow.setColorAt(0.0, borderColor.light());\r
+ inShadow.setColorAt(1.0, borderColor.dark());\r
+ p->setPen(QPen(QBrush(inShadow), knobBorderWidth * 7 / 8));\r
+ p->drawEllipse(xcenter - side / 2 + indent,\r
+ ycenter - side / 2 + indent,\r
+ side - 2 * indent, side - 2 * indent);\r
+ }\r
+\r
+ // Scale shadow...\r
+ QLinearGradient outShadow(xcenter - side / 3, ycenter - side / 3,\r
+ xcenter + side / 3, ycenter + side / 3);\r
+ outShadow.setColorAt(0.0, background.dark().dark());\r
+ outShadow.setColorAt(1.0, background.light().light());\r
+ p->setPen(QPen(QBrush(outShadow), scaleShadowWidth));\r
+ p->drawArc(xcenter - side / 2 + scaleShadowWidth / 2,\r
+ ycenter - side / 2 + scaleShadowWidth / 2,\r
+ side - scaleShadowWidth, side - scaleShadowWidth, -45 * 16, 270 * 16);\r
+\r
+ // Pointer notch...\r
+\r
+ double hyp = double(side) / 2.0;\r
+ double len = hyp - indent - 1;\r
+\r
+ double x = xcenter - len * sin(angle);\r
+ double y = ycenter + len * cos(angle);\r
+\r
+ QColor pointerColor = pal.dark().color();\r
+ pen.setColor((dial->state & State_Enabled) ? pointerColor.dark(140) : pointerColor);\r
+ pen.setWidth(pointerWidth + 2);\r
+ p->setPen(pen);\r
+ p->drawLine(QLineF(xcenter, ycenter, x, y));\r
+ pen.setColor((dial->state & State_Enabled) ? pointerColor.light() : pointerColor.light(140));\r
+ pen.setWidth(pointerWidth);\r
+ p->setPen(pen);\r
+ p->drawLine(QLineF(xcenter - 1, ycenter - 1, x - 1, y - 1));\r
+\r
+ // done\r
+ p->restore();\r
+ }\r
+\r
+};\r
+//\r
+//===============================END QSYNTHKNOB======================================\r
+\r
+\r
+//==============================BEGIN DISPLAYS===================================\r
+//\r
+// This section constains displays, passive QT widgets that displays values in\r
+// different ways, in particular bargraphs\r
+//\r
+\r
+/**\r
+ * An abstract widget that display a value in a range\r
+ */\r
+class AbstractDisplay : public QWidget\r
+{\r
+ protected :\r
+ float fMin;\r
+ float fMax;\r
+ float fValue;\r
+\r
+ public:\r
+\r
+ AbstractDisplay (float lo, float hi) : fMin(lo), fMax(hi), fValue(lo)\r
+ {\r
+ }\r
+\r
+ /**\r
+ * set the range of displayed values\r
+ */\r
+ virtual void setRange(float lo, float hi)\r
+ {\r
+ fMin = lo;\r
+ fMax = hi;\r
+ }\r
+\r
+ /**\r
+ * set the value to be displayed\r
+ */\r
+ virtual void setValue(float v)\r
+ {\r
+ if (v < fMin) v = fMin;\r
+ else if (v > fMax) v = fMax;\r
+\r
+ if (v != fValue) {\r
+ fValue = v;\r
+ update();\r
+ }\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ * Displays dB values using a scale of colors\r
+ */\r
+class dbAbstractDisplay : public AbstractDisplay\r
+{\r
+ protected :\r
+\r
+ float fScaleMin;\r
+ float fScaleMax;\r
+ vector<int> fLevel;\r
+ vector<QBrush> fBrush;\r
+\r
+\r
+ /**\r
+ * Convert a dB value into a scale between 0 and 1 (following IEC standard ?)\r
+ */\r
+ float dB2Scale ( float dB ) const\r
+ {\r
+ float fScale = 1.0f;\r
+\r
+ /*if (dB < -70.0f)\r
+ fScale = 0.0f;\r
+ else*/ if (dB < -60.0f)\r
+ fScale = (dB + 70.0f) * 0.0025f;\r
+ else if (dB < -50.0f)\r
+ fScale = (dB + 60.0f) * 0.005f + 0.025f;\r
+ else if (dB < -40.0)\r
+ fScale = (dB + 50.0f) * 0.0075f + 0.075f;\r
+ else if (dB < -30.0f)\r
+ fScale = (dB + 40.0f) * 0.015f + 0.15f;\r
+ else if (dB < -20.0f)\r
+ fScale = (dB + 30.0f) * 0.02f + 0.3f;\r
+ else if (dB < -0.001f || dB > 0.001f) /* if (dB < 0.0f) */\r
+ fScale = (dB + 20.0f) * 0.025f + 0.5f;\r
+\r
+ return fScale;\r
+ }\r
+\r
+\r
+ /**\r
+ * Create the scale of colors used to paint the bargraph in relation to the levels\r
+ * The parameter x indicates the direction of the gradient. x=1 means an horizontal\r
+ * gradient typically used by a vertical bargraph, and x=0 a vertical gradient.\r
+ */\r
+ void initLevelsColors(int x)\r
+ {\r
+ int alpha = 200;\r
+ { // level until -10 dB\r
+ QColor c(40, 160, 40, alpha);\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+\r
+ fLevel.push_back(-10);\r
+ fBrush.push_back(QBrush(g));\r
+ }\r
+\r
+ { // level until -6 dB\r
+ QColor c(160, 220, 20, alpha);\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+\r
+ fLevel.push_back(-6);\r
+ fBrush.push_back(QBrush(g));\r
+ }\r
+\r
+ { // level until -3 dB\r
+ QColor c(220, 220, 20, alpha);\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+\r
+ fLevel.push_back(-3);\r
+ fBrush.push_back(QBrush(g));\r
+ }\r
+\r
+ { // level until -0 dB\r
+ QColor c(240, 160, 20, alpha);\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+\r
+ fLevel.push_back(0);\r
+ fBrush.push_back(QBrush(g));\r
+ }\r
+\r
+ { // until 10 dB (and over because last one)\r
+ QColor c(240, 0, 20, alpha); // ColorOver\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+\r
+ fLevel.push_back(+10);\r
+ fBrush.push_back(QBrush(g));\r
+ }\r
+\r
+ }\r
+\r
+ public:\r
+\r
+ dbAbstractDisplay(float lo, float hi) : AbstractDisplay(lo,hi)\r
+ {\r
+ }\r
+\r
+ /**\r
+ * set the range of displayed values\r
+ */\r
+ virtual void setRange(float lo, float hi)\r
+ {\r
+ AbstractDisplay::setRange(lo, hi);\r
+ fScaleMin = dB2Scale(fMin);\r
+ fScaleMax = dB2Scale(fMax);\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ * Small rectangular LED display which color changes with the level in dB\r
+ */\r
+class dbLED : public dbAbstractDisplay\r
+{\r
+ protected:\r
+\r
+ /**\r
+ * Draw the LED using a color depending of its value in dB\r
+ */\r
+ virtual void paintEvent ( QPaintEvent *)\r
+ {\r
+ QPainter painter(this);\r
+ painter.drawRect(rect());\r
+\r
+ if (fValue <= fLevel[0]) {\r
+\r
+ // interpolate the first color on the alpha channel\r
+ QColor c(40, 160, 40) ;\r
+ float a = (fValue-fMin)/(fLevel[0]-fMin);\r
+ c.setAlphaF(a);\r
+ painter.fillRect(rect(), c);\r
+\r
+ } else {\r
+\r
+ // find the minimal level > value\r
+ int l = fLevel.size()-1; while (fValue < fLevel[l] && l > 0) l--;\r
+ painter.fillRect(rect(), fBrush[l]);\r
+ }\r
+ }\r
+\r
+ public:\r
+\r
+ dbLED(float lo, float hi) : dbAbstractDisplay(lo,hi)\r
+ {\r
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\r
+ initLevelsColors(1);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(16, 8);\r
+ }\r
+};\r
+/**\r
+ * Small rectangular LED display which intensity (alpha channel) changes according to the value\r
+ */\r
+class LED : public AbstractDisplay\r
+{\r
+ QColor fColor;\r
+\r
+ protected:\r
+\r
+ /**\r
+ * Draw the LED using a transparency depending of its value\r
+ */\r
+ virtual void paintEvent ( QPaintEvent *)\r
+ {\r
+ QPainter painter(this);\r
+ painter.drawRect(rect());\r
+ // interpolate the first color on the alpha channel\r
+ QColor c = fColor ;\r
+ float a = (fValue-fMin)/(fMax-fMin);\r
+ c.setAlphaF(a);\r
+ painter.fillRect(rect(), c);\r
+ }\r
+\r
+ public:\r
+\r
+ LED(float lo, float hi) : AbstractDisplay(lo,hi), fColor("yellow")\r
+ {\r
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(16, 8);\r
+ }\r
+};\r
+\r
+\r
+\r
+/**\r
+ * A simple bargraph that detect automatically its direction\r
+ */\r
+class linBargraph : public AbstractDisplay\r
+{\r
+ protected :\r
+ QBrush fBrush;\r
+\r
+ /**\r
+ * No scale implemented yet\r
+ */\r
+ void paintScale(QPainter* painter) const\r
+ {\r
+ painter->drawRect(0,0,width(),height());\r
+ }\r
+\r
+ /**\r
+ * The length of the rectangle is proportional to the value\r
+ */\r
+ void paintContent (QPainter* painter) const\r
+ {\r
+ int w = width();\r
+ int h = height();\r
+ float v = (fValue-fMin)/(fMax-fMin);\r
+\r
+ if (h>w) {\r
+ // draw vertical rectangle\r
+ painter->fillRect(0,(1-v)*h,w, v*h, fBrush);\r
+ } else {\r
+ // draw horizontal rectangle\r
+ painter->fillRect(0, 0, h, v*w, fBrush);\r
+ }\r
+\r
+ }\r
+\r
+ virtual void paintEvent ( QPaintEvent *)\r
+ {\r
+ QPainter painter(this);\r
+ paintContent(&painter);\r
+ paintScale(&painter);\r
+ }\r
+\r
+ public:\r
+\r
+ linBargraph(float lo, float hi) : AbstractDisplay(lo,hi)\r
+ {\r
+ // compute the brush that will be used to\r
+ // paint the value\r
+ QColor c(0xffa500); // orange\r
+ int x = int(height() < width()); // gradient direction\r
+ QLinearGradient g(0,0,x,1-x);\r
+ g.setCoordinateMode(QGradient::ObjectBoundingMode);\r
+ g.setColorAt(0.0, c.lighter());\r
+ g.setColorAt(0.2, c);\r
+ g.setColorAt(0.8, c);\r
+ g.setColorAt(0.9, c.darker(120));\r
+ fBrush = QBrush(g);\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ * A simple vertical bargraph\r
+ */\r
+class linVerticalBargraph : public linBargraph\r
+{\r
+ public:\r
+\r
+ linVerticalBargraph(float lo, float hi) : linBargraph(lo,hi)\r
+ {\r
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(16, 128);\r
+ }\r
+};\r
+\r
+\r
+\r
+/**\r
+ * A simple horizontal bargraph\r
+ */\r
+class linHorizontalBargraph : public linBargraph\r
+{\r
+ public:\r
+\r
+ linHorizontalBargraph(float lo, float hi) : linBargraph(lo,hi)\r
+ {\r
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(128, 16);\r
+ }\r
+};\r
+\r
+\r
+\r
+\r
+/**\r
+ * A dB Bargraph with a scale of colors\r
+ */\r
+class dbBargraph : public dbAbstractDisplay\r
+{\r
+ QBrush fBackColor;\r
+\r
+ protected :\r
+\r
+ // These two abstract methods are implemented\r
+ // according to the vertical or horizontal direction\r
+ // in dbVerticalBargraph and dbHorizontalBargraph\r
+ virtual void paintMark(QPainter* painter, float v) const = 0;\r
+ virtual int paintSegment (QPainter* painter, int pos, float v, const QBrush& b) const = 0;\r
+\r
+ /**\r
+ * Draw the logarithmic scale\r
+ */\r
+ void paintScale(QPainter* painter) const\r
+ {\r
+ painter->fillRect(0,0,width(),height(), fBackColor);\r
+ painter->save();\r
+ painter->setPen(QColor(0x6699aa)); //0xffa500));\r
+ for (float v = -10; v > fMin; v -= 10) paintMark(painter, v);\r
+ for (float v = -6; v < fMax; v += 3) paintMark(painter, v);\r
+ painter->restore();\r
+ }\r
+\r
+\r
+ /**\r
+ * Draw the content using colored segments\r
+ */\r
+ void paintContent (QPainter* painter) const\r
+ {\r
+ int l = fLevel.size();\r
+\r
+ float p = -1; // fake value indicates to start from border\r
+ int n = 0;\r
+ // paint all the full segments < fValue\r
+ for (n=0; (n < l) && (fValue > fLevel[n]); n++) {\r
+ p = paintSegment(painter, p, fLevel[n], fBrush[n]);\r
+ }\r
+ // paint the last segment\r
+ if (n == l) n = n-1;\r
+ p=paintSegment(painter, p, fValue, fBrush[n]);\r
+\r
+ painter->drawRect(0,0,width(),height());\r
+ }\r
+\r
+\r
+ virtual void paintEvent ( QPaintEvent *)\r
+ {\r
+ QPainter painter(this);\r
+ paintScale(&painter);\r
+ paintContent(&painter);\r
+ }\r
+\r
+ public:\r
+\r
+ dbBargraph(float lo, float hi) : dbAbstractDisplay(lo,hi)\r
+ {\r
+\r
+ QFont f = this->font();\r
+ f.setPointSize(6);\r
+ this->setFont(f);\r
+\r
+ fBackColor = QBrush(QColor(20,20,20));\r
+ }\r
+};\r
+\r
+\r
+/**\r
+ * Vertical dB Bargraph\r
+ */\r
+class dbVerticalBargraph : public dbBargraph\r
+{\r
+ protected:\r
+ /**\r
+ * Convert a dB value into a vertical position\r
+ */\r
+ float dB2y (float dB) const\r
+ {\r
+ float s0 = fScaleMin;\r
+ float s1 = fScaleMax;\r
+ float sx = dB2Scale(dB);\r
+ int h = height();\r
+\r
+ return h - h*(s0-sx)/(s0-s1);\r
+ }\r
+\r
+ /**\r
+ * Paint a vertical graduation mark\r
+ */\r
+ virtual void paintMark(QPainter* painter, float v) const\r
+ {\r
+ int n = 10;\r
+ int y = dB2y(v);\r
+ QRect r(0,y-n,width()-1,2*n);\r
+ if (v > 0.0) {\r
+ painter->drawText(r, Qt::AlignRight|Qt::AlignVCenter, QString::number(v).prepend('+'));\r
+ } else {\r
+ painter->drawText(r, Qt::AlignRight|Qt::AlignVCenter, QString::number(v));\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Paint a color segment\r
+ */\r
+ virtual int paintSegment (QPainter* painter, int pos, float v, const QBrush& b) const\r
+ {\r
+ if (pos == -1) pos = height();\r
+ float y = dB2y(v);\r
+ painter->fillRect(0, y, width(), pos-y+1, b);\r
+ return y;\r
+ }\r
+\r
+\r
+ public:\r
+\r
+ dbVerticalBargraph(float lo, float hi) : dbBargraph(lo,hi)\r
+ {\r
+ setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);\r
+ initLevelsColors(1);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(18, 256);\r
+ }\r
+};\r
+\r
+/**\r
+ * Horizontal dB Bargraph\r
+ */\r
+class dbHorizontalBargraph : public dbBargraph\r
+{\r
+\r
+ protected:\r
+\r
+ /**\r
+ * Convert a dB value into an horizontal position\r
+ */\r
+ float dB2x (float dB) const\r
+ {\r
+ float s0 = fScaleMin;\r
+ float s1 = fScaleMax;\r
+ float sx = dB2Scale(dB);\r
+ int w = width();\r
+\r
+ return w - w*(s1-sx)/(s1-s0);\r
+ }\r
+\r
+ /**\r
+ * Paint an horizontal graduation mark\r
+ */\r
+ void paintMark(QPainter* painter, float v) const\r
+ {\r
+ int n = 10;\r
+ int x = dB2x(v);\r
+ QRect r(x-n,0,2*n, height());\r
+ painter->drawText(r, Qt::AlignHCenter|Qt::AlignVCenter, QString::number(v));\r
+ }\r
+\r
+ /**\r
+ * Paint a horizontal color segment\r
+ */\r
+ int paintSegment (QPainter* painter, int pos, float v, const QBrush& b) const\r
+ {\r
+ if (pos == -1) pos = 0;\r
+ float x = dB2x(v);\r
+ painter->fillRect(pos, 0, x-pos, height(), b);\r
+ return x;\r
+ }\r
+\r
+\r
+ public:\r
+\r
+ dbHorizontalBargraph(float lo, float hi) : dbBargraph(lo,hi)\r
+ {\r
+ setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);\r
+ initLevelsColors(0);\r
+ }\r
+\r
+ virtual QSize sizeHint () const\r
+ {\r
+ return QSize(256, 18);\r
+ }\r
+\r
+};\r
+\r
+//\r
+//===============================END DISPLAYS====================================\r
+\r
+//============================= BEGIN GROUP LABEL METADATA===========================\r
+// Unlike widget's label, metadata inside group's label are not extracted directly by\r
+// the Faust compiler. Therefore they must be extracted within the architecture file\r
+//-----------------------------------------------------------------------------------\r
+//\r
+\r
+/**\r
+ * rmWhiteSpaces(): Remove the leading and trailing white spaces of a string\r
+ * (but not those in the middle of the string)\r
+ */\r
+static string rmWhiteSpaces(const string& s)\r
+{\r
+ size_t i = s.find_first_not_of(" \t");\r
+ size_t j = s.find_last_not_of(" \t");\r
+ if ( (i != string::npos) && (j != string::npos) ) {\r
+ return s.substr(i, 1+j-i);\r
+ } else {\r
+ return "";\r
+ }\r
+}\r
+\r
+/**\r
+ * Extracts metdata from a label : 'vol [unit: dB]' -> 'vol' + metadata(unit=dB)\r
+ */\r
+static void extractMetadata(const string& fulllabel, string& label, map<string, string>& metadata)\r
+{\r
+ enum {kLabel, kEscape1, kEscape2, kEscape3, kKey, kValue};\r
+ int state = kLabel; int deep = 0;\r
+ string key, value;\r
+\r
+ for (unsigned int i=0; i < fulllabel.size(); i++) {\r
+ char c = fulllabel[i];\r
+ switch (state) {\r
+ case kLabel :\r
+ assert (deep == 0);\r
+ switch (c) {\r
+ case '\\' : state = kEscape1; break;\r
+ case '[' : state = kKey; deep++; break;\r
+ default : label += c;\r
+ }\r
+ break;\r
+\r
+ case kEscape1 :\r
+ label += c;\r
+ state = kLabel;\r
+ break;\r
+\r
+ case kEscape2 :\r
+ key += c;\r
+ state = kKey;\r
+ break;\r
+\r
+ case kEscape3 :\r
+ value += c;\r
+ state = kValue;\r
+ break;\r
+\r
+ case kKey :\r
+ assert (deep > 0);\r
+ switch (c) {\r
+ case '\\' : state = kEscape2;\r
+ break;\r
+\r
+ case '[' : deep++;\r
+ key += c;\r
+ break;\r
+\r
+ case ':' : if (deep == 1) {\r
+ state = kValue;\r
+ } else {\r
+ key += c;\r
+ }\r
+ break;\r
+ case ']' : deep--;\r
+ if (deep < 1) {\r
+ metadata[rmWhiteSpaces(key)] = "";\r
+ state = kLabel;\r
+ key="";\r
+ value="";\r
+ } else {\r
+ key += c;\r
+ }\r
+ break;\r
+ default : key += c;\r
+ }\r
+ break;\r
+\r
+ case kValue :\r
+ assert (deep > 0);\r
+ switch (c) {\r
+ case '\\' : state = kEscape3;\r
+ break;\r
+\r
+ case '[' : deep++;\r
+ value += c;\r
+ break;\r
+\r
+ case ']' : deep--;\r
+ if (deep < 1) {\r
+ metadata[rmWhiteSpaces(key)]=rmWhiteSpaces(value);\r
+ state = kLabel;\r
+ key="";\r
+ value="";\r
+ } else {\r
+ value += c;\r
+ }\r
+ break;\r
+ default : value += c;\r
+ }\r
+ break;\r
+\r
+ default :\r
+ cerr << "ERROR unrecognized state " << state << endl;\r
+ }\r
+ }\r
+ label = rmWhiteSpaces(label);\r
+}\r
+//\r
+//============================= END GROUP LABEL METADATA===========================\r
+\r
+\r
+/******************************************************************************\r
+*******************************************************************************\r
+\r
+ IMPLEMENTATION OF GUI ITEMS\r
+ (QT 4.3 for FAUST)\r
+\r
+*******************************************************************************\r
+*******************************************************************************/\r
+\r
+\r
+class uiButton : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ public :\r
+ QAbstractButton* fButton;\r
+\r
+ uiButton (GUI* ui, float* zone, QAbstractButton* b) : uiItem(ui, zone), fButton(b) {}\r
+\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fButton->setDown( v > 0.0 );\r
+ }\r
+\r
+ public slots :\r
+ void pressed() { modifyZone(1.0); }\r
+ void released() { modifyZone(0.0); }\r
+};\r
+\r
+\r
+class uiCheckButton : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ public :\r
+ QCheckBox* fCheckBox;\r
+\r
+ uiCheckButton (GUI* ui, float* zone, QCheckBox* b) : uiItem(ui, zone), fCheckBox(b) {}\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fCheckBox->setCheckState( (v < 0.5) ? Qt::Unchecked : Qt::Checked );\r
+ }\r
+\r
+ public slots :\r
+ void setState(int v) { modifyZone(float(v>0)); }\r
+};\r
+\r
+\r
+class uiSlider : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ int faust2qt(float x) { return int(0.5 + (x-fMin)/fStep); }\r
+ float qt2faust (int v) { return fMin + v*fStep; }\r
+ int optimalTick() {\r
+ float x=fStep;\r
+ while((fMax-fMin)/x > 50) x*=10;\r
+ while((fMax-fMin)/x < 10) x/=2;\r
+ return faust2qt(fMin+x);\r
+ }\r
+\r
+ public :\r
+ QSlider* fSlider;\r
+ float fCur;\r
+ float fMin;\r
+ float fMax;\r
+ float fStep;\r
+\r
+ uiSlider (GUI* ui, float* zone, QSlider* slider, float cur, float lo, float hi, float step)\r
+ : uiItem(ui, zone), fSlider(slider), fCur(cur), fMin(lo), fMax(hi), fStep(step)\r
+ {\r
+ fSlider->setMinimum(0);\r
+ fSlider->setMaximum(faust2qt(fMax));\r
+ fSlider->setValue(faust2qt(fCur));\r
+ fSlider->setTickInterval(optimalTick());\r
+ *fZone = fCur;\r
+ }\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fSlider->setValue(faust2qt(v));\r
+ }\r
+\r
+ public slots :\r
+ void setValue(int v) { modifyZone(qt2faust(v)); }\r
+};\r
+\r
+\r
+class uiKnob : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ int faust2qt(float x) { return int(0.5 + (x-fMin)/fStep); }\r
+ float qt2faust (int v) { return fMin + v*fStep; }\r
+ int optimalTick() {\r
+ float x=fStep;\r
+ while((fMax-fMin)/x > 50) x*=10;\r
+ while((fMax-fMin)/x < 10) x/=2;\r
+ return faust2qt(fMin+x);\r
+ }\r
+\r
+ public :\r
+ QAbstractSlider* fSlider;\r
+ float fCur;\r
+ float fMin;\r
+ float fMax;\r
+ float fStep;\r
+\r
+ uiKnob (GUI* ui, float* zone, QAbstractSlider* slider, float cur, float lo, float hi, float step)\r
+ : uiItem(ui, zone), fSlider(slider), fCur(cur), fMin(lo), fMax(hi), fStep(step)\r
+ {\r
+ fSlider->setMinimum(0);\r
+ fSlider->setMaximum(faust2qt(fMax));\r
+ fSlider->setValue(faust2qt(fCur));\r
+ //fSlider->setTickInterval(optimalTick());\r
+ *fZone = fCur;\r
+ }\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fSlider->setValue(faust2qt(v));\r
+ }\r
+\r
+ public slots :\r
+ void setValue(int v) { modifyZone(qt2faust(v)); }\r
+};\r
+\r
+\r
+class uiBargraph : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ int faust2qt(float x) { return int(0.5 + (x-fMin)/(fMax-fMin)*fStep); }\r
+\r
+ public :\r
+ QProgressBar* fBar;\r
+ float fMin;\r
+ float fMax;\r
+ int fStep;\r
+\r
+ uiBargraph (GUI* ui, float* zone, QProgressBar* bar, float lo, float hi)\r
+ : uiItem(ui, zone), fBar(bar), fMin(lo), fMax(hi), fStep(1024)\r
+ {\r
+ fBar->setRange(0, fStep);\r
+ fBar->setValue(0);\r
+ *fZone = 0;\r
+ }\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ int x = faust2qt(v);\r
+ //std::cout << "update *" << fBar << " = " << x << std::endl;\r
+ fBar->setValue(x);\r
+ }\r
+};\r
+\r
+\r
+class uiBargraph2 : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ public :\r
+ AbstractDisplay* fBar;\r
+\r
+ uiBargraph2 (GUI* ui, float* zone, AbstractDisplay* bar, float lo, float hi)\r
+ : uiItem(ui, zone), fBar(bar)\r
+ {\r
+ fBar->setRange(lo, hi);\r
+ fBar->setValue(lo);\r
+ *fZone = lo;\r
+ }\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fBar->setValue(v);\r
+ }\r
+};\r
+\r
+\r
+\r
+class uiNumEntry : public QObject, public uiItem\r
+{\r
+ Q_OBJECT\r
+\r
+ public :\r
+ QDoubleSpinBox* fNumEntry;\r
+ float fCur;\r
+ float fMin;\r
+ float fMax;\r
+ float fStep;\r
+ int fDecimals;\r
+\r
+ uiNumEntry (GUI* ui, float* zone, QDoubleSpinBox* numEntry, float cur, float lo, float hi, float step)\r
+ : uiItem(ui, zone), fNumEntry(numEntry), fCur(cur), fMin(lo), fMax(hi), fStep(step)\r
+ {\r
+ fDecimals = (fStep >= 1.0) ? 0 : int(0.5+log10(1.0/fStep));\r
+\r
+ fNumEntry->setMinimum(fMin);\r
+ fNumEntry->setMaximum(fMax);\r
+ fNumEntry->setSingleStep(fStep);\r
+ fNumEntry->setDecimals(fDecimals);\r
+ fNumEntry->setValue(fCur);\r
+ *fZone = fCur;\r
+ }\r
+\r
+\r
+ virtual void reflectZone()\r
+ {\r
+ float v = *fZone;\r
+ fCache = v;\r
+ fNumEntry->setValue(v);\r
+ }\r
+\r
+ public slots :\r
+ void setValue(double v) {\r
+ modifyZone(float(v));\r
+ }\r
+};\r
+\r
+\r
+\r
+\r
+/******************************************************************************\r
+*******************************************************************************\r
+\r
+ IMPLEMENTATION OF THE USER INTERFACE\r
+ (QT 4.3 for FAUST)\r
+\r
+*******************************************************************************\r
+*******************************************************************************/\r
+\r
+\r
+class QTGUI : public QObject, public GUI\r
+{\r
+ Q_OBJECT\r
+ QApplication fAppl;\r
+ QTimer* fTimer;\r
+ QStyle* fStyle;\r
+ string gGroupTooltip;\r
+ stack<QWidget* > fGroupStack;\r
+\r
+ map<float*, float> fGuiSize; // map widget zone with widget size coef\r
+ map<float*, string> fTooltip; // map widget zone with tooltip strings\r
+ map<float*, string> fUnit; // map widget zone to unit string (i.e. "dB")\r
+ set<float*> fKnobSet; // set of widget zone to be knobs\r
+ set<float*> fLedSet; // set of widget zone to be LEDs\r
+\r
+\r
+ /**\r
+ * Format tooltip string by replacing some white spaces by\r
+ * return characters so that line width doesn't exceed n.\r
+ * Limitation : long words exceeding n are not cut\r
+ */\r
+ virtual string formatTooltip(int n, const string& tt)\r
+ {\r
+ string ss = tt; // ss string we are going to format\r
+ int lws = 0; // last white space encountered\r
+ int lri = 0; // last return inserted\r
+ for (int i=0; i< (int)tt.size(); i++) {\r
+ if (tt[i] == ' ') lws = i;\r
+ if (((i-lri) >= n) && (lws > lri)) {\r
+ // insert return here\r
+ ss[lws] = '\n';\r
+ lri = lws;\r
+ }\r
+ }\r
+ return ss;\r
+ }\r
+\r
+\r
+ /**\r
+ * Analyses the widget zone metadata declarations and takes\r
+ * appropriate actions\r
+ */\r
+ virtual void declare(float* zone, const char* key, const char* value)\r
+ {\r
+ if (zone == 0) {\r
+ // special zone 0 means group metadata\r
+ if (strcmp(key,"tooltip")==0) {\r
+ // only group tooltip are currently implemented\r
+ gGroupTooltip = formatTooltip(30, value);\r
+ }\r
+ } else {\r
+ if (strcmp(key,"size")==0) {\r
+ fGuiSize[zone]=atof(value);\r
+ }\r
+ else if (strcmp(key,"tooltip")==0) {\r
+ fTooltip[zone] = formatTooltip(30, value) ;\r
+ }\r
+ else if (strcmp(key,"unit")==0) {\r
+ fUnit[zone] = value ;\r
+ }\r
+ else if (strcmp(key,"style")==0) {\r
+ // else if ((strcmp(key,"style")==0) || (strcmp(key,"type")==0)) {\r
+ if (strcmp(value,"knob") == 0) {\r
+ fKnobSet.insert(zone);\r
+ } else if (strcmp(value,"led") == 0) {\r
+ fLedSet.insert(zone);\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ bool isTabContext()\r
+ {\r
+ return fGroupStack.empty() || ((!fGroupStack.empty()) && (dynamic_cast<QTabWidget*>(fGroupStack.top()) != 0));\r
+ }\r
+\r
+ void insert(const char* label, QWidget* widget)\r
+ {\r
+ if (fStyle) widget->setStyle(fStyle);\r
+ if (!fGroupStack.empty()) {\r
+ QWidget* mother = fGroupStack.top();\r
+ QTabWidget* tab = dynamic_cast<QTabWidget*>(mother);\r
+ if (tab) {\r
+ tab->addTab(widget,label);\r
+ } else {\r
+ widget->setParent(mother);\r
+ mother->layout()->addWidget(widget);\r
+ }\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Analyses a full label and activates the relevant options. returns a simplified\r
+ * label (without options) and an amount of stack adjustement (in case additional\r
+ * containers were pushed on the stack).\r
+ */\r
+\r
+ int checkLabelOptions(QWidget* widget, const string& fullLabel, string& simplifiedLabel)\r
+ {\r
+ map<string, string> metadata;\r
+ extractMetadata(fullLabel, simplifiedLabel, metadata);\r
+\r
+ if (metadata.count("tooltip")) {\r
+ widget->setToolTip(metadata["tooltip"].c_str());\r
+ }\r
+ if (metadata["option"] == "detachable") {\r
+ //openHandleBox(simplifiedLabel.c_str());\r
+ return 1;\r
+ }\r
+\r
+ // no adjustement of the stack needed\r
+ return 0;\r
+ }\r
+\r
+ /**\r
+ * Check if a tooltip is associated to a zone and add it to the corresponding widget\r
+ */\r
+ void checkForTooltip(float* zone, QWidget* widget)\r
+ {\r
+ if (fTooltip.count(zone)) {\r
+ widget->setToolTip(fTooltip[zone].c_str());\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Check if a knob is required\r
+ */\r
+ bool isKnob(float* zone)\r
+ {\r
+ return fKnobSet.count(zone) > 0;\r
+ }\r
+\r
+ void openBox(const char* fulllabel, QLayout* layout)\r
+ {\r
+ map<string, string> metadata;\r
+ string label;\r
+ extractMetadata(fulllabel, label, metadata);\r
+ layout->setMargin(5);\r
+ QWidget* box;\r
+\r
+ if (isTabContext()) {\r
+ box = new QWidget();\r
+ // set background color\r
+ QPalette pal = box->palette();\r
+ pal.setColor(box->backgroundRole(), QColor::fromRgb(150, 150, 150) );\r
+ box->setPalette(pal);\r
+\r
+ } else if (label.size()>0) {\r
+ QGroupBox* group = new QGroupBox();\r
+ group->setTitle(label.c_str());\r
+ box = group;\r
+ } else {\r
+ // no label here we use simple widget\r
+ layout->setMargin(0);\r
+ box = new QWidget();\r
+ }\r
+\r
+ box->setLayout(layout);\r
+/* if (metadata.count("tooltip")) {\r
+ box->setToolTip(metadata["tooltip"].c_str());\r
+ }*/\r
+ if (gGroupTooltip != string()) {\r
+ box->setToolTip(gGroupTooltip.c_str());\r
+ gGroupTooltip = string();\r
+ }\r
+ insert(label.c_str(), box);\r
+ fGroupStack.push(box);\r
+ }\r
+\r
+ void openTab(const char* label)\r
+ {\r
+ QTabWidget* group = new QTabWidget();\r
+ if (fStyle) group->setStyle(fStyle);\r
+ insert(label, group);\r
+ fGroupStack.push(group);\r
+ }\r
+\r
+\r
+ public slots :\r
+ void update() {\r
+ //std::cout << '.' << std::endl;\r
+ updateAllZones();\r
+ }\r
+\r
+ public:\r
+\r
+ QTGUI(int argc, char* argv[], QStyle* style = 0) : fAppl(argc, argv), fTimer(0), fStyle(style){\r
+ //fGroupStack.push(new QMainWindow());\r
+ }\r
+\r
+ virtual ~QTGUI() {}\r
+\r
+ virtual void run()\r
+ {\r
+ if (fTimer == 0) {\r
+ fTimer = new QTimer(this);\r
+ QObject::connect(fTimer, SIGNAL(timeout()), this, SLOT(update()));\r
+ fTimer->start(100);\r
+ }\r
+#if 1\r
+ fAppl.setStyleSheet(\r
+\r
+// BUTTONS\r
+ "QPushButton {"\r
+ "background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,"\r
+ "stop: 0 #B0B0B0, stop: 1 #404040);"\r
+ "border: 2px solid grey;"\r
+ "border-radius: 6px;"\r
+ "margin-top: 1ex;"\r
+ "}"\r
+\r
+ "QPushButton:hover {"\r
+ "border: 2px solid orange;"\r
+ "}"\r
+\r
+ "QPushButton:pressed {"\r
+ //"border: 1px solid orange;"\r
+ "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 #404040, stop: 1 #B0B0B0);"\r
+ "}"\r
+// GROUPS\r
+ "QGroupBox {"\r
+ "background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 1,"\r
+ "stop: 0 #A0A0A0, stop: 1 #202020);"\r
+ "border: 2px solid gray;"\r
+ "border-radius: 5px;"\r
+ "margin-top: 1ex;"\r
+ "font-size:7pt;"\r
+ "font-weight:bold;"\r
+ //"color: dark grey;"\r
+ "color: white;"\r
+ "}"\r
+\r
+ "QGroupBox::title {"\r
+ "subcontrol-origin: margin;"\r
+ "subcontrol-position: top center;" /* position at the top center */\r
+ "padding: 0 5px;"\r
+ "}"\r
+// SLIDERS\r
+ // horizontal sliders\r
+ "QSlider::groove:vertical {"\r
+ "background: red;"\r
+ "position: absolute;" /* absolutely position 4px from the left and right of the widget. setting margins on the widget should work too... */\r
+ "left: 13px; right: 13px;"\r
+ "}"\r
+\r
+ "QSlider::handle:vertical {"\r
+ "height: 40px;"\r
+ "width: 30px;"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);"\r
+ "margin: 0 -5px; /* expand outside the groove */"\r
+ "border-radius: 5px;"\r
+ "}"\r
+\r
+ "QSlider::add-page:vertical {"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,"\r
+ "stop: 0 yellow, stop : 0.5 orange);"\r
+ "}"\r
+\r
+ "QSlider::sub-page:vertical {"\r
+ "background: grey;"\r
+ "}"\r
+\r
+ // horizontal sliders\r
+\r
+ "QSlider::groove:horizontal {"\r
+ "background: red;"\r
+ "position: absolute;" /* absolutely position 4px from the left and right of the widget. setting margins on the widget should work too... */\r
+ "top: 14px; bottom: 14px;"\r
+ "}"\r
+\r
+ "QSlider::handle:horizontal {"\r
+ "width: 40px;"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,"\r
+ "stop: 0 #AAAAAA, stop : 0.05 #0A0A0A, stop: 0.3 #101010, stop : 0.90 #AAAAAA, stop: 0.91 #000000);"\r
+ "margin: -5px 0; /* expand outside the groove */"\r
+ "border-radius: 5px;"\r
+ "}"\r
+\r
+ "QSlider::sub-page:horizontal {"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 yellow, stop : 0.5 orange);"\r
+ "}"\r
+\r
+ "QSlider::add-page:horizontal {"\r
+ "background: grey;"\r
+ "}"\r
+\r
+// TABS\r
+ //TabWidget and TabBar\r
+ "QTabWidget::pane {" /* The tab widget frame */\r
+ //"border-top: 2px solid #C2C7CB;"\r
+ "border-top: 2px solid orange;"\r
+ "background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 #A0A0A0, stop: 1 #202020);"\r
+ "}"\r
+\r
+ "QTabWidget::tab-bar {"\r
+ "left: 5px;" /* move to the right by 5px */\r
+ "}"\r
+\r
+ /* Style the tab using the tab sub-control. Note that\r
+ it reads QTabBar _not_ QTabWidget */\r
+ "QTabBar::tab {"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 #909090, stop: 0.4 #888888,"\r
+ "stop: 0.5 #808080, stop: 1.0 #909090);"\r
+ "border: 2px solid #808080;"\r
+ //"border-bottom-color: #C2C7CB;" /* same as the pane color */\r
+ "border-bottom-color: orange;" /* same as the pane color */\r
+ "border-top-left-radius: 4px;"\r
+ "border-top-right-radius: 4px;"\r
+ "min-width: 8ex;"\r
+ "padding: 2px;"\r
+ "}"\r
+\r
+ "QTabBar::tab:selected, QTabBar::tab:hover {"\r
+ "background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,"\r
+ "stop: 0 #D0D0D0, stop: 0.4 #A0A0A0,"\r
+ "stop: 0.5 #808080, stop: 1.0 #A0A0A0);"\r
+ //"stop: 0.5 #A0A0A0, stop: 1.0 #C0C0C0);"\r
+ //"stop: 0 #fafafa, stop: 0.4 #f4f4f4,"\r
+ //"stop: 0.5 #e7e7e7, stop: 1.0 #fafafa);"\r
+ //"border-bottom-color: orange;" /* same as the pane color */\r
+ "}"\r
+\r
+ "QTabBar::tab:selected {"\r
+ "border-color: orange;"\r
+ "border-bottom-color: #A0A0A0;" /* same as pane color */\r
+ "}"\r
+\r
+ "QTabBar::tab:!selected {"\r
+ " margin-top: 2px;" /* make non-selected tabs look smaller */\r
+ "}"\r
+ );\r
+#endif\r
+ fAppl.exec();\r
+ stop();\r
+\r
+ }\r
+\r
+\r
+ // ------------------------- Groups -----------------------------------\r
+\r
+ virtual void openHorizontalBox(const char* label) { \r
+ openBox(label, new QHBoxLayout());\r
+ }\r
+\r
+ virtual void openVerticalBox(const char* label) {\r
+ openBox(label, new QVBoxLayout());\r
+ }\r
+\r
+ virtual void openFrameBox(const char* ) { }\r
+ virtual void openTabBox(const char* label) { \r
+ openTab(label);\r
+ }\r
+\r
+ virtual void closeBox()\r
+ {\r
+ QWidget* group = fGroupStack.top();\r
+ fGroupStack.pop();\r
+ if (fGroupStack.empty()) { group->show(); }\r
+ }\r
+\r
+ // ------------------------- active widgets -----------------------------------\r
+\r
+ virtual void addButton(const char* label , float* zone)\r
+ {\r
+ QAbstractButton* w = new QPushButton(label);\r
+ uiButton* c = new uiButton(this, zone, w);\r
+\r
+ insert(label, w);\r
+ QObject::connect(w, SIGNAL(pressed()), c, SLOT(pressed()));\r
+ QObject::connect(w, SIGNAL(released()), c, SLOT(released()));\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ virtual void addToggleButton(const char* , float* )\r
+ {}\r
+\r
+ virtual void addCheckButton(const char* label , float* zone)\r
+ {\r
+ QCheckBox* w = new QCheckBox(label);\r
+ uiCheckButton* c = new uiCheckButton(this, zone, w);\r
+\r
+ insert(label, w);\r
+ QObject::connect(w, SIGNAL(stateChanged(int)), c, SLOT(setState(int)));\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ virtual void addNumEntry(const char* label, float* zone, float init, float min, float max, float step)\r
+ {\r
+ if (isKnob(zone)) {\r
+ addVerticalKnob(label, zone, init, min, max, step);\r
+ return;\r
+ }\r
+ //insert(label, new QDoubleSpinBox());\r
+ if (label && label[0]) openVerticalBox(label);\r
+ QDoubleSpinBox* w = new QDoubleSpinBox();\r
+ uiNumEntry* c = new uiNumEntry(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ w->setSuffix(fUnit[zone].c_str());\r
+ QObject::connect(w, SIGNAL(valueChanged(double)), c, SLOT(setValue(double)));\r
+ if (label && label[0]) closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ // special num entry without buttons\r
+ virtual void addNumDisplay(const char* label, float* zone, float init, float min, float max, float step)\r
+ {\r
+ //insert(label, new QDoubleSpinBox());\r
+ if (label && label[0]) openVerticalBox(label);\r
+ QDoubleSpinBox* w = new QDoubleSpinBox();\r
+ w->setAlignment(Qt::AlignHCenter);\r
+#if 1\r
+ w->setStyleSheet(\r
+ "QDoubleSpinBox {"\r
+ "border: 2px solid orange;"\r
+ "border-radius: 5px;"\r
+ "}"\r
+ );\r
+#endif\r
+ uiNumEntry* c = new uiNumEntry(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ w->setButtonSymbols(QAbstractSpinBox::NoButtons);\r
+ w->setSuffix(fUnit[zone].c_str());\r
+ QObject::connect(w, SIGNAL(valueChanged(double)), c, SLOT(setValue(double)));\r
+ if (label && label[0]) closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+\r
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // KNOBS\r
+ //\r
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+\r
+ virtual void addVerticalKnob(const char* label , float* zone, float init, float min, float max, float step)\r
+ {\r
+ openVerticalBox(label);\r
+ QAbstractSlider* w = new QDial(); //qsynthKnob();\r
+ uiKnob* c = new uiKnob(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ w->setStyle(new qsynthDialVokiStyle());\r
+ QObject::connect(w, SIGNAL(valueChanged(int)), c, SLOT(setValue(int)));\r
+ addNumDisplay(0, zone, init, min, max, step);\r
+\r
+ // compute the size of the knob+display\r
+ int width = int(64*pow(2,fGuiSize[zone]));\r
+ int height = int(100*pow(2,fGuiSize[zone]));\r
+ fGroupStack.top()->setMinimumSize(width,height);\r
+ fGroupStack.top()->setMaximumSize(width,height);\r
+\r
+ closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ virtual void addHorizontalKnob(const char* label , float* zone, float init, float min, float max, float step)\r
+ {\r
+ openHorizontalBox(label);\r
+ QAbstractSlider* w = new QDial(); //new qsynthKnob();\r
+ uiKnob* c = new uiKnob(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ w->setStyle(new qsynthDialVokiStyle());\r
+ QObject::connect(w, SIGNAL(valueChanged(int)), c, SLOT(setValue(int)));\r
+ addNumDisplay(0, zone, init, min, max, step);\r
+ closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+ //\r
+ // SLIDERS\r
+ //\r
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////\r
+\r
+ virtual void addVerticalSlider(const char* label , float* zone, float init, float min, float max, float step)\r
+ {\r
+ if (isKnob(zone)) {\r
+ addVerticalKnob(label, zone, init, min, max, step);\r
+ return;\r
+ }\r
+ openVerticalBox(label);\r
+ QSlider* w = new QSlider(Qt::Vertical);\r
+ w->setMinimumHeight(160);\r
+ w->setMinimumWidth(34);\r
+ //w->setTickPosition(QSlider::TicksBothSides);\r
+ uiSlider* c = new uiSlider(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ QObject::connect(w, SIGNAL(valueChanged(int)), c, SLOT(setValue(int)));\r
+ addNumDisplay(0, zone, init, min, max, step);\r
+ closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ virtual void addHorizontalSlider(const char* label , float* zone, float init, float min, float max, float step)\r
+ {\r
+ if (isKnob(zone)) {\r
+ addHorizontalKnob(label, zone, init, min, max, step);\r
+ return;\r
+ }\r
+ openHorizontalBox(label);\r
+ QSlider* w = new QSlider(Qt::Horizontal);\r
+ w->setMinimumHeight(34);\r
+ w->setMinimumWidth(160);\r
+ //w->setTickPosition(QSlider::TicksBothSides);\r
+ uiSlider* c = new uiSlider(this, zone, w, init, min, max, step);\r
+ insert(label, w);\r
+ QObject::connect(w, SIGNAL(valueChanged(int)), c, SLOT(setValue(int)));\r
+ addNumDisplay(0, zone, init, min, max, step);\r
+ closeBox();\r
+ checkForTooltip(zone, w);\r
+ }\r
+\r
+ // ------------------------- passive widgets -----------------------------------\r
+\r
+ virtual void addNumDisplay(const char*, float*, int)\r
+ {}\r
+\r
+ virtual void addTextDisplay(const char*, float*, const char* [], float, float)\r
+ {}\r
+\r
+ virtual void addHorizontalBargraph(const char* label , float* zone, float min, float max)\r
+ {\r
+ AbstractDisplay* bargraph;\r
+ openVerticalBox(label);\r
+ bool db = (fUnit[zone] == "dB");\r
+\r
+ if (fLedSet.count(zone)) {\r
+ if (db) {\r
+ bargraph = new dbLED(min, max);\r
+ } else {\r
+ bargraph = new LED(min,max);\r
+ }\r
+ } else {\r
+ if (db) {\r
+ bargraph = new dbHorizontalBargraph(min, max);\r
+ } else {\r
+ bargraph = new linHorizontalBargraph(min, max);\r
+ }\r
+ }\r
+\r
+ new uiBargraph2(this, zone, bargraph, min, max);\r
+ insert(label, bargraph);\r
+ closeBox();\r
+ checkForTooltip(zone, bargraph);\r
+ }\r
+\r
+ virtual void addVerticalBargraph(const char* label , float* zone, float min, float max)\r
+ {\r
+ AbstractDisplay* bargraph;\r
+ openVerticalBox(label);\r
+ bool db = (fUnit[zone] == "dB");\r
+\r
+ if (fLedSet.count(zone)) {\r
+ if (db) {\r
+ bargraph = new dbLED(min, max);\r
+ } else {\r
+ bargraph = new LED(min,max);\r
+ }\r
+ } else {\r
+ if (db) {\r
+ bargraph = new dbVerticalBargraph(min, max);\r
+ } else {\r
+ bargraph = new linVerticalBargraph(min, max);\r
+ }\r
+ }\r
+ new uiBargraph2(this, zone, bargraph, min, max);\r
+ insert(label, bargraph);\r
+ closeBox();\r
+ checkForTooltip(zone, bargraph);\r
+ }\r
+\r
+};\r
+\r
+#endif\r