Skip to content

Commit ee41410

Browse files
committed
Quantum style changes in preparation for new plugins
Signed-off-by: falkTX <[email protected]>
1 parent 0b67fb4 commit ee41410

File tree

2 files changed

+320
-3
lines changed

2 files changed

+320
-3
lines changed

opengl/Quantum.cpp

Lines changed: 275 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -726,14 +726,31 @@ bool QuantumMixerSlider::onMotion(const MotionEvent& ev)
726726

727727
// --------------------------------------------------------------------------------------------------------------------
728728

729+
static constexpr const char* kQuantumLabelLvlGain = "Lvl Gain";
730+
729731
QuantumGainReductionMeter::QuantumGainReductionMeter(NanoSubWidget* const parent, const QuantumTheme& t)
730732
: NanoSubWidget(parent),
731-
theme(t)
733+
theme(t),
734+
label(const_cast<char*>(kQuantumLabelLvlGain))
732735
{
733736
loadSharedResources();
734737
setSize(QuantumMetrics(t).gainReductionMeter);
735738
}
736739

740+
QuantumGainReductionMeter::~QuantumGainReductionMeter()
741+
{
742+
if (label != nullptr && label != kQuantumLabelLvlGain)
743+
std::free(label);
744+
}
745+
746+
void QuantumGainReductionMeter::setLabel(const char* const label2)
747+
{
748+
if (label != nullptr && label != kQuantumLabelLvlGain)
749+
std::free(label);
750+
751+
label = label2 != nullptr ? strdup(label2) : nullptr;
752+
}
753+
737754
void QuantumGainReductionMeter::setValue(const float value2)
738755
{
739756
if (d_isEqual(value, value2))
@@ -832,8 +849,8 @@ void QuantumGainReductionMeter::onNanoDisplay()
832849
text(width * 0.5f, height - theme.textHeight * 0.5f + theme.borderSize, valuestr, nullptr);
833850

834851
// top label
835-
fontSize(theme.fontSize * 2 /3);
836-
text(width * 0.5f, verticalReservedHeight, "Lvl Gain", nullptr);
852+
fontSize(theme.fontSize * 2 / 3);
853+
text(width * 0.5f, verticalReservedHeight, label, nullptr);
837854
}
838855

839856
// --------------------------------------------------------------------------------------------------------------------
@@ -1153,6 +1170,261 @@ void QuantumLevelMeter::onNanoDisplay()
11531170

11541171
// --------------------------------------------------------------------------------------------------------------------
11551172

1173+
QuantumStereoLevelMeter::QuantumStereoLevelMeter(NanoTopLevelWidget* const parent, const QuantumTheme& t)
1174+
: NanoSubWidget(parent),
1175+
app(parent->getApp()),
1176+
theme(t)
1177+
{
1178+
loadSharedResources();
1179+
setSize(QuantumMetrics(t).stereoLevelMeter);
1180+
app.addIdleCallback(this);
1181+
}
1182+
1183+
QuantumStereoLevelMeter::QuantumStereoLevelMeter(NanoSubWidget* const parent, const QuantumTheme& t)
1184+
: NanoSubWidget(parent),
1185+
app(parent->getApp()),
1186+
theme(t)
1187+
{
1188+
loadSharedResources();
1189+
setSize(QuantumMetrics(t).stereoLevelMeter);
1190+
app.addIdleCallback(this);
1191+
}
1192+
1193+
void QuantumStereoLevelMeter::setRange(const float min, const float max)
1194+
{
1195+
minimum = min;
1196+
maximum = max;
1197+
repaint();
1198+
}
1199+
1200+
void QuantumStereoLevelMeter::setValueL(const float value)
1201+
{
1202+
if (value >= falloffL)
1203+
{
1204+
falloffL = value;
1205+
lastTimeL = timeL = app.getTime();
1206+
}
1207+
1208+
if (d_isEqual(valueL, value))
1209+
return;
1210+
1211+
valueL = value;
1212+
1213+
repaint();
1214+
}
1215+
1216+
void QuantumStereoLevelMeter::setValueR(const float value)
1217+
{
1218+
if (value >= falloffR)
1219+
{
1220+
falloffR = value;
1221+
lastTimeR = timeR = app.getTime();
1222+
}
1223+
1224+
if (d_isEqual(valueR, value))
1225+
return;
1226+
1227+
valueR = value;
1228+
1229+
repaint();
1230+
}
1231+
1232+
void QuantumStereoLevelMeter::setValues(const float l, const float r)
1233+
{
1234+
falloffL = valueL = l;
1235+
falloffR = valueR = r;
1236+
lastTimeL = timeL = lastTimeR = timeR = 0;
1237+
repaint();
1238+
}
1239+
1240+
void QuantumStereoLevelMeter::onNanoDisplay()
1241+
{
1242+
const float verticalReservedHeight = theme.textHeight;
1243+
const float usableMeterHeight = getHeight() - verticalReservedHeight;
1244+
const float centerX = static_cast<float>(getWidth()) / 2;
1245+
1246+
beginPath();
1247+
rect(0, verticalReservedHeight, getWidth(), usableMeterHeight);
1248+
fillColor(theme.widgetBackgroundColor);
1249+
fill();
1250+
1251+
float value;
1252+
char valuestr[32] = {};
1253+
1254+
const float meterChannelWidth = theme.textHeight - theme.borderSize * 2;
1255+
const float meterChannelHeight = usableMeterHeight - theme.borderSize * 2;
1256+
1257+
const float pxl = theme.borderSize;
1258+
const float pxr = theme.borderSize * 5 + meterChannelWidth;
1259+
1260+
// alternate background
1261+
fillColor(Color(theme.windowBackgroundColor, theme.widgetBackgroundColor, 0.75f));
1262+
1263+
beginPath();
1264+
rect(pxl,
1265+
theme.borderSize + verticalReservedHeight,
1266+
meterChannelWidth, meterChannelHeight);
1267+
fill();
1268+
1269+
beginPath();
1270+
rect(pxr,
1271+
theme.borderSize + verticalReservedHeight,
1272+
meterChannelWidth, meterChannelHeight);
1273+
fill();
1274+
1275+
// fake spacer
1276+
fillColor(Color(theme.widgetBackgroundColor, theme.windowBackgroundColor, 0.5f));
1277+
1278+
beginPath();
1279+
rect(pxr - theme.borderSize * 3, verticalReservedHeight,
1280+
theme.borderSize * 2, meterChannelHeight + theme.borderSize * 2);
1281+
fill();
1282+
1283+
// left channel
1284+
value = normalizedLevelMeterValue(valueL);
1285+
1286+
if (d_isNotZero(value))
1287+
{
1288+
beginPath();
1289+
rect(pxl,
1290+
theme.borderSize + verticalReservedHeight + meterChannelHeight * (1.f - value),
1291+
meterChannelWidth, meterChannelHeight * value);
1292+
fillColor(theme.levelMeterColor);
1293+
fill();
1294+
1295+
std::snprintf(valuestr, sizeof(valuestr)-1, "%.0f", valueL);
1296+
}
1297+
else
1298+
{
1299+
std::strncpy(valuestr, "-inf", sizeof(valuestr)-1);
1300+
}
1301+
1302+
fillColor(theme.textLightColor);
1303+
fontSize(theme.fontSize * 2 / 3);
1304+
textAlign(ALIGN_CENTER|ALIGN_BOTTOM);
1305+
text(pxl + meterChannelWidth / 2,
1306+
verticalReservedHeight, valuestr, nullptr);
1307+
1308+
if (d_isNotEqual(valueL, falloffL))
1309+
{
1310+
value = normalizedLevelMeterValue(falloffL);
1311+
const float y = theme.borderSize + verticalReservedHeight + meterChannelHeight * (1.f - value);
1312+
1313+
beginPath();
1314+
moveTo(pxl, y);
1315+
lineTo(pxl + meterChannelWidth, y);
1316+
strokeColor(theme.levelMeterColor);
1317+
strokeWidth(theme.borderSize);
1318+
stroke();
1319+
}
1320+
1321+
// right channel
1322+
value = normalizedLevelMeterValue(valueR);
1323+
1324+
if (d_isNotZero(value))
1325+
{
1326+
beginPath();
1327+
rect(pxr,
1328+
theme.borderSize + verticalReservedHeight + meterChannelHeight * (1.f - value),
1329+
meterChannelWidth, meterChannelHeight * value);
1330+
fillColor(theme.levelMeterColor);
1331+
fill();
1332+
1333+
std::snprintf(valuestr, sizeof(valuestr)-1, "%.0f", valueR);
1334+
}
1335+
else
1336+
{
1337+
std::strncpy(valuestr, "-inf", sizeof(valuestr)-1);
1338+
}
1339+
1340+
fillColor(theme.textLightColor);
1341+
fontSize(theme.fontSize * 2 / 3);
1342+
textAlign(ALIGN_CENTER|ALIGN_BOTTOM);
1343+
text(pxr + meterChannelWidth / 2,
1344+
verticalReservedHeight, valuestr, nullptr);
1345+
1346+
if (d_isNotEqual(valueR, falloffR))
1347+
{
1348+
value = normalizedLevelMeterValue(falloffR);
1349+
const float y = theme.borderSize + verticalReservedHeight + meterChannelHeight * (1.f - value);
1350+
1351+
beginPath();
1352+
moveTo(pxr, y);
1353+
lineTo(pxr + meterChannelWidth, y);
1354+
strokeColor(theme.levelMeterColor);
1355+
strokeWidth(theme.borderSize);
1356+
stroke();
1357+
}
1358+
1359+
// helper lines with labels
1360+
constexpr const float db2 = 1.f - normalizedLevelMeterValue(-2);
1361+
constexpr const float db5 = 1.f - normalizedLevelMeterValue(-5);
1362+
constexpr const float db10 = 1.f - normalizedLevelMeterValue(-10);
1363+
constexpr const float db20 = 1.f - normalizedLevelMeterValue(-20);
1364+
constexpr const float db30 = 1.f - normalizedLevelMeterValue(-30);
1365+
constexpr const float db40 = 1.f - normalizedLevelMeterValue(-40);
1366+
constexpr const float db50 = 1.f - normalizedLevelMeterValue(-50);
1367+
fillColor(theme.textLightColor);
1368+
fontSize(theme.fontSize);
1369+
textAlign(ALIGN_CENTER|ALIGN_MIDDLE);
1370+
const float yOffset = theme.borderSize + verticalReservedHeight;
1371+
text(centerX, yOffset + usableMeterHeight * db2, "- 2 -", nullptr);
1372+
text(centerX, yOffset + usableMeterHeight * db5, "- 5 -", nullptr);
1373+
text(centerX, yOffset + usableMeterHeight * db10, "- 10 -", nullptr);
1374+
text(centerX, yOffset + usableMeterHeight * db20, "- 20 -", nullptr);
1375+
text(centerX, yOffset + usableMeterHeight * db30, "- 30 -", nullptr);
1376+
text(centerX, yOffset + usableMeterHeight * db40, "- 40 -", nullptr);
1377+
text(centerX, yOffset + usableMeterHeight * db50, "- 50 -", nullptr);
1378+
}
1379+
1380+
void QuantumStereoLevelMeter::idleCallback()
1381+
{
1382+
const double time = app.getTime(); // in seconds
1383+
1384+
// TESTING
1385+
DISTRHO_SAFE_ASSERT_RETURN(falloffL >= valueL,);
1386+
DISTRHO_SAFE_ASSERT_RETURN(falloffR >= valueR,);
1387+
1388+
constexpr const double secondsToWaitForFalloffStart = 2;
1389+
constexpr const double falloffDbPerSecond = 8.6;
1390+
1391+
if (d_isEqual(valueL, falloffL))
1392+
{
1393+
lastTimeL = timeL = time;
1394+
}
1395+
else
1396+
{
1397+
const double diffSinceValueSet = time - timeL;
1398+
const double diffSinceLastIdle = time - lastTimeL;
1399+
lastTimeL = time;
1400+
1401+
if (diffSinceValueSet >= secondsToWaitForFalloffStart)
1402+
{
1403+
falloffL = std::max(valueL, static_cast<float>(falloffL - falloffDbPerSecond * diffSinceLastIdle));
1404+
repaint();
1405+
}
1406+
}
1407+
1408+
if (d_isEqual(valueR, falloffR))
1409+
{
1410+
lastTimeR = timeR = time;
1411+
}
1412+
else
1413+
{
1414+
const double diffSinceValueSet = time - timeR;
1415+
const double diffSinceLastIdle = time - lastTimeR;
1416+
lastTimeR = time;
1417+
1418+
if (diffSinceValueSet >= secondsToWaitForFalloffStart)
1419+
{
1420+
falloffR = std::max(valueR, static_cast<float>(falloffR - falloffDbPerSecond * diffSinceLastIdle));
1421+
repaint();
1422+
}
1423+
}
1424+
}
1425+
1426+
// --------------------------------------------------------------------------------------------------------------------
1427+
11561428
QuantumStereoLevelMeterWithLUFS::QuantumStereoLevelMeterWithLUFS(NanoTopLevelWidget* const parent, const QuantumTheme& t)
11571429
: NanoSubWidget(parent),
11581430
app(parent->getApp()),

opengl/Quantum.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ struct QuantumMetrics
7575
Size<uint> gainReductionMeter;
7676
Size<uint> knob;
7777
Size<uint> mixerSlider;
78+
Size<uint> stereoLevelMeter;
7879
Size<uint> stereoLevelMeterWithLufs;
7980
Size<uint> valueMeterHorizontal;
8081
Size<uint> valueMeterVertical;
@@ -101,6 +102,8 @@ struct QuantumMetrics
101102
theme.textHeight * 3 / 2),
102103
mixerSlider(theme.textHeight * 2,
103104
theme.textHeight * 4),
105+
stereoLevelMeter(theme.textHeight * 2 + theme.borderSize * 2,
106+
theme.textHeight * 4),
104107
stereoLevelMeterWithLufs(theme.textHeight * 4 + theme.borderSize * 4,
105108
theme.textHeight * 4),
106109
valueMeterHorizontal(theme.textHeight * 4,
@@ -347,11 +350,19 @@ class QuantumMixerSlider : public NanoSubWidget,
347350
class QuantumGainReductionMeter : public NanoSubWidget
348351
{
349352
const QuantumTheme& theme;
353+
char* label;
350354
float value = 0.f;
351355

352356
public:
353357
explicit QuantumGainReductionMeter(NanoSubWidget* parent, const QuantumTheme& theme);
358+
~QuantumGainReductionMeter() override;
354359

360+
inline const char* getLabel() const noexcept
361+
{
362+
return label;
363+
}
364+
365+
void setLabel(const char* label);
355366
void setValue(float value);
356367

357368
protected:
@@ -480,6 +491,40 @@ class QuantumLevelMeter : public QuantumValueMeter
480491

481492
// --------------------------------------------------------------------------------------------------------------------
482493

494+
class QuantumStereoLevelMeter : public NanoSubWidget,
495+
public IdleCallback
496+
{
497+
Application& app;
498+
const QuantumTheme& theme;
499+
float valueL = 0.f;
500+
float valueR = 0.f;
501+
float minimum = 0.f;
502+
float maximum = 1.f;
503+
float falloffL = 0.f;
504+
float falloffR = 0.f;
505+
double timeL = 0.0;
506+
double timeR = 0.0;
507+
double lastTimeL = 0.0;
508+
double lastTimeR = 0.0;
509+
510+
public:
511+
explicit QuantumStereoLevelMeter(NanoTopLevelWidget* parent, const QuantumTheme& theme);
512+
explicit QuantumStereoLevelMeter(NanoSubWidget* parent, const QuantumTheme& theme);
513+
514+
void setRange(float min, float max);
515+
void setValueL(float value);
516+
void setValueR(float value);
517+
void setValues(float l, float r);
518+
519+
protected:
520+
void onNanoDisplay() override;
521+
void idleCallback() override;
522+
523+
DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(QuantumStereoLevelMeter)
524+
};
525+
526+
// --------------------------------------------------------------------------------------------------------------------
527+
483528
class QuantumStereoLevelMeterWithLUFS : public NanoSubWidget,
484529
public IdleCallback
485530
{

0 commit comments

Comments
 (0)