BogaudioModules

BogaudioModules for VCV Rack
Log | Files | Refs | README | LICENSE

commit 8934b2dc7c0e9b0ad692f4823391ec943904bec1
parent 3156cbf6756d8b429b90af2641dec9b17ef070f2
Author: Matt Demanett <matt@demanett.net>
Date:   Wed, 20 Oct 2021 00:07:04 -0400

Rack2: nightmode, take 2.

Diffstat:
Msrc/Blank3.cpp | 31+++++++++++++++----------------
Msrc/Blank3.hpp | 2+-
Msrc/Blank6.cpp | 32++++++++++++++++----------------
Msrc/Blank6.hpp | 2+-
Msrc/Mono.cpp | 67+++++++++++++++++++++++++++++++++++++++++++------------------------
Msrc/Pressor.cpp | 30+++++++++++++++++++++---------
Msrc/Reftone.cpp | 24+++++++++++++++++++-----
Msrc/VU.cpp | 62++++++++++++++++++++++++++++++++------------------------------
Msrc/Walk2.cpp | 12+++++-------
Msrc/analyzer_base.cpp | 12++++++------
Msrc/analyzer_base.hpp | 7++++---
Msrc/mixer.cpp | 30+++++++++++++++++++++---------
Msrc/mixer.hpp | 8++++++--
Msrc/widgets.cpp | 170++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Msrc/widgets.hpp | 44++++++++++++++++++++++++++++++++++++++++----
15 files changed, 343 insertions(+), 190 deletions(-)

diff --git a/src/Blank3.cpp b/src/Blank3.cpp @@ -17,47 +17,51 @@ void Blank3::processAll(const ProcessArgs& args) { } } -struct Blank3Display : OpaqueWidget { +struct Blank3Display : DisplayWidget { Blank3* _module; const char* _text; std::string _fontPath; Blank3Display(Blank3* module, const char* text) - : _module(module) + : DisplayWidget(module) + , _module(module) , _text(text) , _fontPath(asset::plugin(pluginInstance, "res/fonts/audiowide.ttf")) { } - void draw(const DrawArgs& args) override { - std::shared_ptr<Font> font = APP->window->loadFont(_fontPath); - + void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override { const Skins& skins = Skins::skins(); std::string skin = skins.defaultKey(); bool haveLevel = false; float level = 0.0f; - if (_module && !_module->isBypassed()) { + if (lit) { haveLevel = _module->_level; level = _module->_level; skin = _module->_skin; } NVGcolor textColor = nvgRGBA(0x33, 0x33, 0x33, 0xff); - // NVGcolor bgTextColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); NVGcolor bgColor = nvgRGBA(0xdd, 0xdd, 0xdd, 0xff); const char* pathStroke = skins.skinCssValue(skin, "path-stroke"); if (pathStroke) { textColor = Skins::cssColorToNVGColor(pathStroke, textColor); } - const char* backgroundFill = skins.skinCssValue(skin, "background-fill"); - if (backgroundFill) { - bgColor = Skins::cssColorToNVGColor(backgroundFill, bgColor); - } NVGcolor bgTextColor = nvgRGBAf(0.5f * (textColor.r + bgColor.r), 0.5f * (textColor.g + bgColor.g), 0.5f * (textColor.b + bgColor.b), 1.0f); + const int split = 65; + drawText(args, 0, 0, box.size.x, split - 10, haveLevel, level, textColor, bgTextColor); + drawText(args, 0, split, box.size.x, box.size.y, haveLevel, level, textColor, bgTextColor); + drawText(args, 0, split - 10, box.size.x / 2 - 5, 10, haveLevel, level, textColor, bgTextColor); + drawText(args, box.size.x / 2 + 5, split - 10, box.size.x, 10, haveLevel, level, textColor, bgTextColor); + } + void drawText(const DrawArgs& args, int sx, int sy, int sw, int sh, bool haveLevel, float level, const NVGcolor& textColor, const NVGcolor& bgTextColor) { + std::shared_ptr<Font> font = APP->window->loadFont(_fontPath); float offsetX = box.size.x / 2.0f; float offsetY = box.size.y / 2.0f; nvgSave(args.vg); + nvgScissor(args.vg, 0, 0, box.size.x, box.size.y); + nvgIntersectScissor(args.vg, sx, sy, sw, sh); nvgTranslate(args.vg, offsetX, offsetY); nvgRotate(args.vg, M_PI/2.0f); nvgTranslate(args.vg, -offsetY, offsetX); @@ -69,7 +73,6 @@ struct Blank3Display : OpaqueWidget { nvgText(args.vg, 0, 0, _text, NULL); } else { - nvgGlobalTint(args.vg, color::WHITE); nvgFillColor(args.vg, bgTextColor); nvgText(args.vg, 0, 0, _text, NULL); if (level > 0.0001f) { @@ -77,10 +80,6 @@ struct Blank3Display : OpaqueWidget { nvgText(args.vg, 0, 0, _text, NULL); } } - nvgBeginPath(args.vg); - nvgRect(args.vg, 55, -20, 10, 10); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); nvgRestore(args.vg); } }; diff --git a/src/Blank3.hpp b/src/Blank3.hpp @@ -30,7 +30,7 @@ struct Blank3 : BGModule { Blank3() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); - configInput(IN_INPUT, "Signal"); + configInput(IN_INPUT, "Easter egg"); sampleRateChange(); } diff --git a/src/Blank6.cpp b/src/Blank6.cpp @@ -17,47 +17,52 @@ void Blank6::processAll(const ProcessArgs& args) { } } -struct Blank6Display : OpaqueWidget { +struct Blank6Display : DisplayWidget { Blank6* _module; const char* _text; std::string _fontPath; Blank6Display(Blank6* module, const char* text) - : _module(module) + : DisplayWidget(module) + , _module(module) , _text(text) , _fontPath(asset::plugin(pluginInstance, "res/fonts/audiowide.ttf")) { } - void draw(const DrawArgs& args) override { - std::shared_ptr<Font> font = APP->window->loadFont(_fontPath); - + void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override { const Skins& skins = Skins::skins(); std::string skin = skins.defaultKey(); bool haveLevel = false; float level = 0.0f; - if (_module && !_module->isBypassed()) { + if (lit) { haveLevel = _module->_level; level = _module->_level; skin = _module->_skin; } NVGcolor textColor = nvgRGBA(0x33, 0x33, 0x33, 0xff); - // NVGcolor bgTextColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); NVGcolor bgColor = nvgRGBA(0xdd, 0xdd, 0xdd, 0xff); const char* pathStroke = skins.skinCssValue(skin, "path-stroke"); if (pathStroke) { textColor = Skins::cssColorToNVGColor(pathStroke, textColor); } - const char* backgroundFill = skins.skinCssValue(skin, "background-fill"); - if (backgroundFill) { - bgColor = Skins::cssColorToNVGColor(backgroundFill, bgColor); - } NVGcolor bgTextColor = nvgRGBAf(0.5f * (textColor.r + bgColor.r), 0.5f * (textColor.g + bgColor.g), 0.5f * (textColor.b + bgColor.b), 1.0f); + const int split = 107; + drawText(args, 0, 0, box.size.x, split - 10, haveLevel, level, textColor, bgTextColor); + drawText(args, 0, split, box.size.x, box.size.y, haveLevel, level, textColor, bgTextColor); + drawText(args, 0, split - 10, box.size.x / 2 - 5, 10, haveLevel, level, textColor, bgTextColor); + drawText(args, box.size.x / 2 + 5, split - 10, box.size.x, 10, haveLevel, level, textColor, bgTextColor); + } + + void drawText(const DrawArgs& args, int sx, int sy, int sw, int sh, bool haveLevel, float level, const NVGcolor& textColor, const NVGcolor& bgTextColor) { + std::shared_ptr<Font> font = APP->window->loadFont(_fontPath); float offsetX = box.size.x / 2.0f; float offsetY = box.size.y / 2.0f; nvgSave(args.vg); + nvgScissor(args.vg, 0, 0, box.size.x, box.size.y); + nvgIntersectScissor(args.vg, sx, sy, sw, sh); nvgTranslate(args.vg, offsetX, offsetY); nvgRotate(args.vg, M_PI/2.0f); nvgTranslate(args.vg, -offsetY, offsetX); @@ -69,7 +74,6 @@ struct Blank6Display : OpaqueWidget { nvgText(args.vg, 0, 0, _text, NULL); } else { - nvgGlobalTint(args.vg, color::WHITE); nvgFillColor(args.vg, bgTextColor); nvgText(args.vg, 0, 0, _text, NULL); if (level > 0.0001f) { @@ -77,10 +81,6 @@ struct Blank6Display : OpaqueWidget { nvgText(args.vg, 0, 0, _text, NULL); } } - nvgBeginPath(args.vg); - nvgRect(args.vg, 97, -20, 10, 10); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); nvgRestore(args.vg); } }; diff --git a/src/Blank6.hpp b/src/Blank6.hpp @@ -30,7 +30,7 @@ struct Blank6 : BGModule { Blank6() { config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS); - configInput(IN_INPUT, "Signal"); + configInput(IN_INPUT, "Easter egg"); sampleRateChange(); } diff --git a/src/Mono.cpp b/src/Mono.cpp @@ -55,7 +55,7 @@ void Mono::processAll(const ProcessArgs& args) { } struct MonoWidget : BGModuleWidget { - struct ChannelsDisplay : OpaqueWidget { + struct ChannelsDisplay : LightEmittingWidget<OpaqueWidget> { const NVGcolor inactiveBgColor = nvgRGBA(0xaa, 0xaa, 0xaa, 0xff); const NVGcolor activeBgColor = nvgRGBA(0x66, 0x66, 0x66, 0xff); Mono* _module; @@ -63,35 +63,42 @@ struct MonoWidget : BGModuleWidget { ChannelsDisplay(Mono* module) : _module(module) { } + bool isLit() override { + return _module && !_module->isBypassed(); + } + void draw(const DrawArgs& args) override { nvgSave(args.vg); for (int i = 0; i < _module->maxChannels; ++i) { nvgBeginPath(args.vg); - if (!_module || _module->isBypassed() || i >= _module->_activeChannels) { + if (i >= _module->_activeChannels) { + nvgCircle(args.vg, (i % 4) * 10 + 5.0f, (i / 4) * 10 + 5.0f, 3.2f); nvgFillColor(args.vg, inactiveBgColor); + nvgFill(args.vg); } - else { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); - nvgFillColor(args.vg, activeBgColor); - nvgRestore(args.vg); - } - nvgCircle(args.vg, (i % 4) * 10 + 5.0f, (i / 4) * 10 + 5.0f, 3.2f); - nvgFill(args.vg); + } + nvgRestore(args.vg); + } - if (_module && !_module->isBypassed() && _module->_channelLevels[i] > 0.0f) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); - nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(_module->_channelLevels[i]))); + void drawLit(const DrawArgs& args) override { + nvgSave(args.vg); + for (int i = 0; i < _module->maxChannels; ++i) { + nvgBeginPath(args.vg); + if (i < _module->_activeChannels) { + nvgCircle(args.vg, (i % 4) * 10 + 5.0f, (i / 4) * 10 + 5.0f, 3.2f); + nvgFillColor(args.vg, activeBgColor); nvgFill(args.vg); - nvgRestore(args.vg); + if (_module->_channelLevels[i] > 0.0f) { + nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(_module->_channelLevels[i]))); + nvgFill(args.vg); + } } } nvgRestore(args.vg); } }; - struct CompressionDisplay : OpaqueWidget { + struct CompressionDisplay : LightEmittingWidget<OpaqueWidget> { struct Level { float db; NVGcolor color; @@ -111,7 +118,21 @@ struct MonoWidget : BGModuleWidget { } } + bool isLit() override { + return _module && !_module->isBypassed(); + } + void draw(const DrawArgs& args) override { + nvgSave(args.vg); + for (int i = 0; i < 35; i += 5) { + drawBox(args, i); + nvgFillColor(args.vg, bgColor); + nvgFill(args.vg); + } + nvgRestore(args.vg); + } + + void drawLit(const DrawArgs& args) override { float compressionDb = 0.0f; if (_module && !_module->isBypassed()) { compressionDb = _module->_compressionDb; @@ -120,21 +141,19 @@ struct MonoWidget : BGModuleWidget { nvgSave(args.vg); for (int i = 0; i < 35; i += 5) { const Level& l = _levels.at(i / 5); - - nvgBeginPath(args.vg); - nvgRect(args.vg, 3, i + 1, 5, 4); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); if (compressionDb > l.db) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i); nvgFillColor(args.vg, l.color); nvgFill(args.vg); - nvgRestore(args.vg); } } nvgRestore(args.vg); } + + void drawBox(const DrawArgs& args, int offset) { + nvgBeginPath(args.vg); + nvgRect(args.vg, 3, offset + 1, 5, 4); + } }; static constexpr int hp = 3; diff --git a/src/Pressor.cpp b/src/Pressor.cpp @@ -192,7 +192,7 @@ void Pressor::processChannel(const ProcessArgs& args, int c) { } struct PressorWidget : BGModuleWidget { - struct CompressionDisplay : OpaqueWidget { + struct CompressionDisplay : LightEmittingWidget<OpaqueWidget> { struct Level { float db; NVGcolor color; @@ -212,7 +212,21 @@ struct PressorWidget : BGModuleWidget { } } + bool isLit() override { + return _module && !_module->isBypassed(); + } + void draw(const DrawArgs& args) override { + nvgSave(args.vg); + for (int i = 0; i < 80; i += 5) { + drawBox(args, i); + nvgFillColor(args.vg, bgColor); + nvgFill(args.vg); + } + nvgRestore(args.vg); + } + + void drawLit(const DrawArgs& args) override { float compressionDb = 0.0f; if (_module && !_module->isBypassed()) { compressionDb = _module->_compressionDb; @@ -221,21 +235,19 @@ struct PressorWidget : BGModuleWidget { nvgSave(args.vg); for (int i = 0; i < 80; i += 5) { const Level& l = _levels.at(i / 5); - - nvgBeginPath(args.vg); - nvgRect(args.vg, 3, i + 1, 5, 4); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); if (compressionDb > l.db) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i); nvgFillColor(args.vg, l.color); nvgFill(args.vg); - nvgRestore(args.vg); } } nvgRestore(args.vg); } + + void drawBox(const DrawArgs& args, int offset) { + nvgBeginPath(args.vg); + nvgRect(args.vg, 3, offset + 1, 5, 4); + } }; static constexpr int hp = 15; diff --git a/src/Reftone.cpp b/src/Reftone.cpp @@ -34,7 +34,7 @@ void Reftone::processAll(const ProcessArgs& args) { } } -struct ReftoneDisplay : TransparentWidget { +struct ReftoneDisplay : DisplayWidget { const NVGcolor _textColor = nvgRGBA(0x00, 0xff, 0x00, 0xee); Reftone* _module; @@ -45,13 +45,16 @@ struct ReftoneDisplay : TransparentWidget { Reftone* module, Vec size ) - : _module(module) + : DisplayWidget(module) + , _module(module) , _size(size) , _fontPath(asset::plugin(pluginInstance, "res/fonts/inconsolata-bold.ttf")) { } void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; + void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override; void drawBackground(const DrawArgs& args); void drawText(const DrawArgs& args, const char* s, float x, float y, int size); void drawCenteredText(const DrawArgs& args, const char* s, float y, int size); @@ -59,11 +62,23 @@ struct ReftoneDisplay : TransparentWidget { }; void ReftoneDisplay::draw(const DrawArgs& args) { + if (!isLit()) { + drawOnce(args, isScreenshot(), false); + } +} + +void ReftoneDisplay::drawLit(const DrawArgs& args) { + if (isLit()) { + drawOnce(args, false, true); + } +} + +void ReftoneDisplay::drawOnce(const DrawArgs& args, bool screenshot, bool lit) { int mPitch = 9; int mOctave = 4; float mFine = 0.0f; float mFrequency = 440.0f; - if (_module) { + if (!screenshot) { mPitch = _module->_pitch; mOctave = _module->_octave; mFine = _module->_fine; @@ -132,11 +147,10 @@ void ReftoneDisplay::draw(const DrawArgs& args) { } nvgSave(args.vg); - if (_module && _module->isBypassed()) { + if (!screenshot && !lit) { drawBackground(args); } else { - nvgGlobalTint(args.vg, color::WHITE); drawBackground(args); if (sharpFlat) { drawText(args, pitch, 3, 20, 28); diff --git a/src/VU.cpp b/src/VU.cpp @@ -58,7 +58,7 @@ void VU::processAll(const ProcessArgs& args) { _rPeakLevel = rPeak; } -struct VUDisplay : OpaqueWidget { +struct VUDisplay : LightEmittingWidget<OpaqueWidget> { struct Level { float db; NVGcolor color; @@ -76,62 +76,64 @@ struct VUDisplay : OpaqueWidget { } } + bool isLit() override { + return _module && !_module->isBypassed(); + } + void draw(const DrawArgs& args) override { - float lDb = -100.0f; - float rDb = -100.0f; - float lPeakDb = -100.0f; - float rPeakDb = -100.0f; - if (_module && !_module->isBypassed()) { - lDb = amplitudeToDecibels(_module->_lLevel); - rDb = amplitudeToDecibels(_module->_rLevel); - lPeakDb = amplitudeToDecibels(_module->_lPeakLevel); - rPeakDb = amplitudeToDecibels(_module->_rPeakLevel); + nvgSave(args.vg); + for (int i = 0; i < 180; i += 5) { + drawBox(args, i, true); + nvgFillColor(args.vg, bgColor); + nvgFill(args.vg); + + drawBox(args, i, false); + nvgFillColor(args.vg, bgColor); + nvgFill(args.vg); } + nvgRestore(args.vg); + } + + void drawLit(const DrawArgs& args) override { + assert(_module); + float lDb = amplitudeToDecibels(_module->_lLevel); + float rDb = amplitudeToDecibels(_module->_rLevel); + float lPeakDb = amplitudeToDecibels(_module->_lPeakLevel); + float rPeakDb = amplitudeToDecibels(_module->_rPeakLevel); nvgSave(args.vg); for (int i = 0; i < 180; i += 5) { const Level& l = _levels.at(i / 5); - nvgBeginPath(args.vg); - nvgRect(args.vg, 3, i + 1, 5, 4); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); if (lPeakDb > l.db && lPeakDb < l.db + 2.0f) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i, true); nvgFillColor(args.vg, nvgRGBA(0x00, 0xdd, 0xff, 0xff)); nvgFill(args.vg); - nvgRestore(args.vg); } if (lDb > l.db) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i, true); nvgFillColor(args.vg, l.color); nvgFill(args.vg); - nvgRestore(args.vg); } - nvgBeginPath(args.vg); - nvgRect(args.vg, 10, i + 1, 5, 4); - nvgFillColor(args.vg, bgColor); - nvgFill(args.vg); if (rPeakDb > l.db && rPeakDb < l.db + 2.0f) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i, false); nvgFillColor(args.vg, nvgRGBA(0x00, 0xdd, 0xff, 0xff)); nvgFill(args.vg); - nvgRestore(args.vg); } if (rDb > l.db) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); + drawBox(args, i, false); nvgFillColor(args.vg, l.color); nvgFill(args.vg); - nvgRestore(args.vg); } } nvgRestore(args.vg); } + + void drawBox(const DrawArgs& args, int offset, bool left) { + nvgBeginPath(args.vg); + nvgRect(args.vg, left ? 3 : 10, offset + 1, 5, 4); + } }; struct VUWidget : BGModuleWidget { diff --git a/src/Walk2.cpp b/src/Walk2.cpp @@ -169,7 +169,7 @@ void Walk2::processAll(const ProcessArgs& args) { _historyStep %= _historySteps; } -struct Walk2Display : TransparentWidget { +struct Walk2Display : DisplayWidget { const int _insetAround = 4; const NVGcolor _axisColor = nvgRGBA(0xff, 0xff, 0xff, 0x70); @@ -186,7 +186,8 @@ struct Walk2Display : TransparentWidget { Walk2* module, Vec size ) - : _module(module) + : DisplayWidget(module) + , _module(module) , _size(size) , _drawSize(2 * (_size.x - 2 * _insetAround), 2 * (_size.y - 2 * _insetAround)) , _midX(_insetAround + _drawSize.x/2) @@ -225,13 +226,10 @@ struct Walk2Display : TransparentWidget { } } - void draw(const DrawArgs& args) override { + void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override { float strokeWidth = std::max(1.0f, 3.0f - getZoom()); nvgSave(args.vg); - if (_module && !_module->isBypassed()) { - nvgGlobalTint(args.vg, color::WHITE); - } drawBackground(args); nvgScissor(args.vg, _insetAround, _insetAround, _drawSize.x / 2, _drawSize.y / 2); if (_module && _module->_zoomOut) { @@ -249,7 +247,7 @@ struct Walk2Display : TransparentWidget { } drawAxes(args, strokeWidth); - if (_module && !_module->isBypassed()) { + if (lit) { switch (_module->_traceColor) { case Walk2::ORANGE_TRACE_COLOR: { _traceColor = nvgRGBA(0xff, 0x80, 0x00, 0xee); diff --git a/src/analyzer_base.cpp b/src/analyzer_base.cpp @@ -453,8 +453,9 @@ void AnalyzerDisplay::channelLabel(int channel, std::string label) { _channelLabels[channel] = label; } -void AnalyzerDisplay::draw(const DrawArgs& args) { - if (_module) { +void AnalyzerDisplay::drawOnce(const DrawArgs& args, bool screenshot, bool lit) { + if (!screenshot) { + assert(_module); _module->_core._channelsMutex.lock(); } @@ -462,7 +463,7 @@ void AnalyzerDisplay::draw(const DrawArgs& args) { AmplitudePlot amplitudePlot = DECIBELS_80_AP; float rangeMinHz = 0.0f; float rangeMaxHz = 0.0f; - if (_module) { + if (!screenshot) { frequencyPlot = _module->_frequencyPlot; amplitudePlot = _module->_amplitudePlot; rangeMinHz = _module->_rangeMinHz; @@ -485,10 +486,9 @@ void AnalyzerDisplay::draw(const DrawArgs& args) { } nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); drawBackground(args); nvgScissor(args.vg, _insetAround, _insetAround, _size.x - _insetAround, _size.y - _insetAround); - if (!_module || _module->isBypassed()) { + if (isScreenshot() || !lit) { drawYAxis(args, strokeWidth, amplitudePlot); drawXAxis(args, strokeWidth, frequencyPlot, rangeMinHz, rangeMaxHz); } @@ -524,7 +524,7 @@ void AnalyzerDisplay::draw(const DrawArgs& args) { } nvgRestore(args.vg); - if (_module) { + if (!screenshot) { _module->_core._channelsMutex.unlock(); } } diff --git a/src/analyzer_base.hpp b/src/analyzer_base.hpp @@ -178,7 +178,7 @@ struct AnalyzerBaseWidget : BGModuleWidget { void addAmplitudePlotContextMenu(Menu* menu, bool linearOption = true); }; -struct AnalyzerDisplay : TransparentWidget, AnalyzerTypes { +struct AnalyzerDisplay : DisplayWidget, AnalyzerTypes { struct BinsReader { BinsReader() {} virtual ~BinsReader() {} @@ -240,7 +240,8 @@ struct AnalyzerDisplay : TransparentWidget, AnalyzerTypes { Vec size, bool drawInset ) - : _module(module) + : DisplayWidget(module) + , _module(module) , _size(size) , _graphSize(_size.x - _insetLeft - _insetRight, _size.y - _insetTop - _insetBottom) , _drawInset(drawInset) @@ -268,7 +269,7 @@ struct AnalyzerDisplay : TransparentWidget, AnalyzerTypes { void setChannelBinsReaderFactory(int channel, BinsReaderFactory brf); void displayChannel(int channel, bool display); void channelLabel(int channel, std::string label); - void draw(const DrawArgs& args) override; + void drawOnce(const DrawArgs& args, bool screenshot, bool lit) override; void drawBackground(const DrawArgs& args); virtual void drawHeader(const DrawArgs& args, float rangeMinHz, float rangeMaxHz); void drawYAxis(const DrawArgs& args, float strokeWidth, AmplitudePlot plot); diff --git a/src/mixer.cpp b/src/mixer.cpp @@ -112,13 +112,18 @@ void MuteButton::onButton(const event::Button& e) { } } +bool MuteButton::isLit() { + return module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f; +} + void MuteButton::draw(const DrawArgs& args) { - nvgSave(args.vg); - if (module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f) { - nvgGlobalTint(args.vg, color::WHITE); + if (!isLit()) { + ToggleButton::draw(args); } +} + +void MuteButton::drawLit(const DrawArgs& args) { ToggleButton::draw(args); - nvgRestore(args.vg); } @@ -176,13 +181,20 @@ void SoloMuteButton::onChange(const event::Change& e) { ParamWidget::onChange(e); } +bool SoloMuteButton::isLit() { + return module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f; +} + void SoloMuteButton::draw(const DrawArgs& args) { - nvgSave(args.vg); - if (module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f) { - nvgGlobalTint(args.vg, color::WHITE); + if (!isLit() || !getParamQuantity() || getParamQuantity()->getValue() < 1.0f) { + ParamWidget::draw(args); + } +} + +void SoloMuteButton::drawLit(const DrawArgs& args) { + if (getParamQuantity() && getParamQuantity()->getValue() >= 1.0f) { + ParamWidget::draw(args); } - ParamWidget::draw(args); - nvgRestore(args.vg); } diff --git a/src/mixer.hpp b/src/mixer.hpp @@ -71,17 +71,19 @@ struct DimmableMixerWidget : LinearCVMixerWidget { void contextMenu(Menu* menu) override; }; -struct MuteButton : ToggleButton { +struct MuteButton : LightEmittingWidget<ToggleButton> { MuteButton() { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/button_18px_0.svg"))); addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/button_18px_1_orange.svg"))); } void onButton(const event::Button& e) override; + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; }; -struct SoloMuteButton : ParamWidget { +struct SoloMuteButton : LightEmittingWidget<ParamWidget> { std::vector<std::shared_ptr<Svg>> _frames; SvgWidget* _svgWidget; // deleted elsewhere. CircularShadow* shadow = NULL; @@ -89,7 +91,9 @@ struct SoloMuteButton : ParamWidget { SoloMuteButton(); void onButton(const event::Button& e) override; void onChange(const event::Change& e) override; + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; }; struct DimSwitchQuantity : SwitchQuantity { diff --git a/src/widgets.cpp b/src/widgets.cpp @@ -6,6 +6,30 @@ using namespace bogaudio; using namespace bogaudio::dsp; +DisplayWidget::DisplayWidget(Module* module) : _module(module) { +} + +bool DisplayWidget::isLit() { + return _module && !_module->isBypassed(); +} + +bool DisplayWidget::isScreenshot() { + return !_module; +} + +void DisplayWidget::draw(const DrawArgs& args) { + if (!isLit()) { + drawOnce(args, isScreenshot(), false); + } +} + +void DisplayWidget::drawLit(const DrawArgs& args) { + if (isLit()) { + drawOnce(args, false, true); + } +} + + std::string SkinnableWidget::skinSVG(const std::string& base, const std::string& skin) { std::string s = skin; if (s == "default") { @@ -20,6 +44,7 @@ std::string SkinnableWidget::skinSVG(const std::string& base, const std::string& return svg; } + Screw::Screw() { skinChanged("default"); } @@ -227,16 +252,20 @@ void IndicatorKnob::redraw() { onChange(c); } -void IndicatorKnob::draw(const DrawArgs& args) { - nvgSave(args.vg); - if (module && !module->isBypassed() && getParamQuantity() && +bool IndicatorKnob::isLit() { + return module && !module->isBypassed() && getParamQuantity() && (getParamQuantity()->getValue() < -0.01f || getParamQuantity()->getValue() > 0.01f) && - (!w->_drawColorsCB || w->_drawColorsCB())) - { - nvgGlobalTint(args.vg, color::WHITE); + (!w->_drawColorsCB || w->_drawColorsCB()); +} + +void IndicatorKnob::draw(const DrawArgs& args) { + if (!isLit()) { + Knob::draw(args); } +} + +void IndicatorKnob::drawLit(const DrawArgs& args) { Knob::draw(args); - nvgRestore(args.vg); } void IndicatorKnob::skinChanged(const std::string& skin) { @@ -252,6 +281,7 @@ void IndicatorKnob::skinChanged(const std::string& skin) { fb->dirty = true; } + Port24::Port24() { setSvg(APP->window->loadSvg(asset::plugin(pluginInstance, skinSVG("port").c_str()))); box.size = Vec(24, 24); @@ -349,13 +379,18 @@ IndicatorButtonGreen9::IndicatorButtonGreen9() { addFrame(APP->window->loadSvg(asset::plugin(pluginInstance, "res/button_9px_1_green.svg"))); } +bool IndicatorButtonGreen9::isLit() { + return module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f; +} + void IndicatorButtonGreen9::draw(const DrawArgs& args) { - nvgSave(args.vg); - if (module && !module->isBypassed() && getParamQuantity() && getParamQuantity()->getValue() > 0.0f) { - nvgGlobalTint(args.vg, color::WHITE); + if (!isLit()) { + SvgSwitch::draw(args); } +} + +void IndicatorButtonGreen9::drawLit(const DrawArgs& args) { SvgSwitch::draw(args); - nvgRestore(args.vg); } @@ -495,15 +530,19 @@ void InvertingIndicatorButton::onChange(const event::Change& e) { ParamWidget::onChange(e); } +bool InvertingIndicatorButton::isLit() { + return module && !module->isBypassed() && getParamQuantity() && + (getParamQuantity()->getValue() < -0.01f || getParamQuantity()->getValue() > 0.01f); +} + void InvertingIndicatorButton::draw(const DrawArgs& args) { - nvgSave(args.vg); - if (module && !module->isBypassed() && getParamQuantity() && - (getParamQuantity()->getValue() < -0.01f || getParamQuantity()->getValue() > 0.01f)) - { - nvgGlobalTint(args.vg, color::WHITE); + if (!isLit()) { + ParamWidget::draw(args); } +} + +void InvertingIndicatorButton::drawLit(const DrawArgs& args) { ParamWidget::draw(args); - nvgRestore(args.vg); } @@ -521,16 +560,18 @@ NVGcolor bogaudio::decibelsToColor(float db) { } -void VUSlider::draw(const DrawArgs& args) { - float level = 0.0f; - if (getParamQuantity()) { - level = getParamQuantity()->getValue(); - } - else { - float minDb = -60.0f; - float maxDb = 6.0f; - level = fabsf(minDb) / (maxDb - minDb); +bool VUSlider::isLit() { + float db = _vuLevel ? *_vuLevel : 0.0f; + bool stereo = false; + float stereoDb = 0.0f; + if (_stereoVuLevel) { + stereo = true; + stereoDb = *_stereoVuLevel; } + return module && !module->isBypassed() && (db > 0.0f || (stereo && stereoDb > 0.0f)); +} + +void VUSlider::draw(const DrawArgs& args) { nvgSave(args.vg); { @@ -545,7 +586,7 @@ void VUSlider::draw(const DrawArgs& args) { nvgSave(args.vg); { - nvgTranslate(args.vg, 0, (box.size.y - 13.0f) * (1.0f - level)); + drawTranslate(args); nvgBeginPath(args.vg); nvgRoundedRect(args.vg, 0, 0, 18, 13, 1.5); nvgFillColor(args.vg, nvgRGBA(0x77, 0x77, 0x77, 0xff)); @@ -565,39 +606,54 @@ void VUSlider::draw(const DrawArgs& args) { nvgRoundedRect(args.vg, 2, 4, 14, 5, 1.0); nvgFillColor(args.vg, nvgRGBA(0xaa, 0xaa, 0xaa, 0xff)); nvgFill(args.vg); + } + nvgRestore(args.vg); +} + +void VUSlider::drawLit(const DrawArgs& args) { + float db = _vuLevel ? *_vuLevel : 0.0f; + bool stereo = false; + float stereoDb = 0.0f; + if (_stereoVuLevel) { + stereo = true; + stereoDb = *_stereoVuLevel; + } - float db = _vuLevel ? *_vuLevel : 0.0f; - bool stereo = false; - float stereoDb = 0.0f; - if (_stereoVuLevel) { - stereo = true; - stereoDb = *_stereoVuLevel; + nvgSave(args.vg); + drawTranslate(args); + if (db > 0.0f) { + nvgSave(args.vg); + nvgBeginPath(args.vg); + if (stereo) { + nvgRoundedRect(args.vg, 2, 4, stereo ? 7 : 14, 5, 1.0); } - if (module && !module->isBypassed()) { - if (db > 0.0f) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); - nvgBeginPath(args.vg); - if (stereo) { - nvgRoundedRect(args.vg, 2, 4, stereo ? 7 : 14, 5, 1.0); - } - else { - nvgRoundedRect(args.vg, 2, 4, 14, 5, 1.0); - } - nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(db))); - nvgFill(args.vg); - nvgRestore(args.vg); - } - if (stereo && stereoDb > 0.0f) { - nvgSave(args.vg); - nvgGlobalTint(args.vg, color::WHITE); - nvgBeginPath(args.vg); - nvgRoundedRect(args.vg, 9, 4, 7, 5, 1.0); - nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(stereoDb))); - nvgFill(args.vg); - nvgRestore(args.vg); - } + else { + nvgRoundedRect(args.vg, 2, 4, 14, 5, 1.0); } + nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(db))); + nvgFill(args.vg); + nvgRestore(args.vg); + } + if (stereo && stereoDb > 0.0f) { + nvgSave(args.vg); + nvgBeginPath(args.vg); + nvgRoundedRect(args.vg, 9, 4, 7, 5, 1.0); + nvgFillColor(args.vg, decibelsToColor(amplitudeToDecibels(stereoDb))); + nvgFill(args.vg); + nvgRestore(args.vg); } nvgRestore(args.vg); } + +void VUSlider::drawTranslate(const DrawArgs& args) { + float level = 0.0f; + if (getParamQuantity()) { + level = getParamQuantity()->getValue(); + } + else { + float minDb = -60.0f; + float maxDb = 6.0f; + level = fabsf(minDb) / (maxDb - minDb); + } + nvgTranslate(args.vg, 0, (box.size.y - 13.0f) * (1.0f - level)); +} diff --git a/src/widgets.hpp b/src/widgets.hpp @@ -11,6 +11,32 @@ extern Plugin *pluginInstance; namespace bogaudio { +template <class BASE> +struct LightEmittingWidget : BASE { + virtual bool isLit() = 0; + + void drawLayer(const typename BASE::DrawArgs& args, int layer) override { + if (layer == 1 && isLit()) { + drawLit(args); + } + BASE::drawLayer(args, layer); + } + + virtual void drawLit(const typename BASE::DrawArgs& args) {} +}; + +struct DisplayWidget : LightEmittingWidget<OpaqueWidget> { + Module* _module = NULL; + + DisplayWidget(Module* module); + + bool isLit() override; + virtual bool isScreenshot(); + void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; + virtual void drawOnce(const DrawArgs& args, bool screenshot, bool lit) = 0; +}; + struct SkinnableWidget : SkinChangeListener { void skinChanged(const std::string& skin) override {} std::string skinSVG(const std::string& base, const std::string& skin = "default"); @@ -59,7 +85,7 @@ struct Knob68 : BGKnob { Knob68(); }; -struct IndicatorKnob : Knob, SkinnableWidget { +struct IndicatorKnob : LightEmittingWidget<Knob>, SkinnableWidget { struct IKWidget : widget::Widget { float _angle = 0.0f; NVGcolor _color = nvgRGBA(0x00, 0x00, 0x00, 0x00); @@ -82,7 +108,9 @@ struct IndicatorKnob : Knob, SkinnableWidget { inline void setDrawColorsCallback(std::function<bool()> fn) { w->_drawColorsCB = fn; } inline void setUnipolarCallback(std::function<bool()> fn) { w->_unipolarCB = fn; } void redraw(); + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; void skinChanged(const std::string& skin) override; }; @@ -139,12 +167,15 @@ struct ToggleButton18 : ToggleButton { ToggleButton18(); }; -struct IndicatorButtonGreen9 : SvgSwitch { +struct IndicatorButtonGreen9 : LightEmittingWidget<SvgSwitch> { IndicatorButtonGreen9(); + + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; }; -struct InvertingIndicatorButton : ParamWidget { +struct InvertingIndicatorButton : LightEmittingWidget<ParamWidget> { struct IIBWidget : widget::Widget { int _dim; NVGcolor _color = nvgRGBA(0x00, 0x00, 0x00, 0x00); @@ -169,7 +200,9 @@ struct InvertingIndicatorButton : ParamWidget { void onDoubleClick(const event::DoubleClick& e) override {} void onButton(const event::Button& e) override; void onChange(const event::Change& e) override; + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; }; struct InvertingIndicatorButton9 : InvertingIndicatorButton { @@ -182,7 +215,7 @@ struct InvertingIndicatorButton18 : InvertingIndicatorButton { NVGcolor decibelsToColor(float db); -struct VUSlider : SliderKnob { +struct VUSlider : LightEmittingWidget<SliderKnob> { const float slideHeight = 13.0f; float* _vuLevel = NULL; float* _stereoVuLevel = NULL; @@ -197,7 +230,10 @@ struct VUSlider : SliderKnob { inline void setStereoVULevel(float* level) { _stereoVuLevel = level; } + bool isLit() override; void draw(const DrawArgs& args) override; + void drawLit(const DrawArgs& args) override; + void drawTranslate(const DrawArgs& args); }; struct VUSlider151 : VUSlider {