BogaudioModules

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

commit ba923d458c30856f8d46ff96f873606f028afb88
parent e998c7fe673adf8a3156e382bf83f7f75b0c7089
Author: Matt Demanett <matt@demanett.net>
Date:   Sun, 17 Nov 2019 01:50:47 -0500

Refactor context menus; turn option groups into submenus.

Diffstat:
Msrc/AD.cpp | 37++++++++++++-------------------------
Msrc/ADSR.cpp | 37++++++++++++-------------------------
Msrc/AddrSeq.cpp | 51+++++++++++++++++++++------------------------------
Msrc/Analyzer.cpp | 27++++-----------------------
Msrc/AnalyzerXL.cpp | 159+++++++++++++++++--------------------------------------------------------------
Msrc/FMOp.cpp | 21+--------------------
Msrc/Manual.cpp | 11+++--------
Msrc/Mix4.cpp | 33+++++++--------------------------
Msrc/Mix8.cpp | 29+++++------------------------
Msrc/Noise.cpp | 32++++++--------------------------
Msrc/SampleHold.cpp | 86+++++++++++++++++++++++++++++--------------------------------------------------
Msrc/UMix.cpp | 46++++------------------------------------------
Msrc/Walk2.cpp | 83+++++++++++++++----------------------------------------------------------------
Msrc/addressable_sequence.hpp | 42++----------------------------------------
Msrc/bogaudio.hpp | 1+
Msrc/disable_output_limit.hpp | 25+++----------------------
Asrc/menu.hpp | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/trigger_on_load.hpp | 23+++++------------------
18 files changed, 222 insertions(+), 578 deletions(-)

diff --git a/src/AD.cpp b/src/AD.cpp @@ -166,35 +166,22 @@ struct ADWidget : ModuleWidget { addChild(createLight<SmallLight<GreenLight>>(linearLightPosition, module, AD::LINEAR_LIGHT)); } - struct InvertMenuItem : MenuItem { - AD* _module; - - InvertMenuItem(AD* module, const char* label, int offset) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - if (_module->_invert < 0.0f) { - _module->_invert = 1.0f; - } - else { - _module->_invert = -1.0f; - } - } - - void step() override { - MenuItem::step(); - rightText = _module->_invert == -1.0f ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { AD* m = dynamic_cast<AD*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new InvertMenuItem(m, "Invert output", -1)); + menu->addChild(new OptionMenuItem( + "Invert output", + [m]() { return m->_invert == -1.0f; }, + [m]() { + if (m->_invert < 0.0f) { + m->_invert = 1.0f; + } + else { + m->_invert = -1.0f; + } + } + )); } }; diff --git a/src/ADSR.cpp b/src/ADSR.cpp @@ -144,35 +144,22 @@ struct ADSRWidget : ModuleWidget { addChild(createLight<SmallLight<GreenLight>>(linearLightPosition, module, ADSR::LINEAR_LIGHT)); } - struct InvertMenuItem : MenuItem { - ADSR* _module; - - InvertMenuItem(ADSR* module, const char* label, int offset) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - if (_module->_invert < 0.0f) { - _module->_invert = 1.0f; - } - else { - _module->_invert = -1.0f; - } - } - - void step() override { - MenuItem::step(); - rightText = _module->_invert == -1.0f ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { ADSR* m = dynamic_cast<ADSR*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new InvertMenuItem(m, "Invert output", -1)); + menu->addChild(new OptionMenuItem( + "Invert output", + [m]() { return m->_invert == -1.0f; }, + [m]() { + if (m->_invert < 0.0f) { + m->_invert = 1.0f; + } + else { + m->_invert = -1.0f; + } + } + )); } }; diff --git a/src/AddrSeq.cpp b/src/AddrSeq.cpp @@ -157,27 +157,17 @@ struct AddrSeqWidget : AddressableSequenceModuleWidget { addChild(createLight<SmallLight<GreenLight>>(out8LightPosition, module, AddrSeq::OUT8_LIGHT)); } - struct RangeMenuItem : MenuItem { - AddrSeq* _module; - float _offset, _scale; - - RangeMenuItem(AddrSeq* module, const char* label, float offset, float scale) - : _module(module) - , _offset(offset) - , _scale(scale) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_rangeOffset = _offset; - _module->_rangeScale = _scale; - } - - void step() override { - MenuItem::step(); - rightText = (_module->_rangeOffset == _offset && _module->_rangeScale == _scale) ? "✔" : ""; - } + struct RangeOptionMenuItem : OptionMenuItem { + RangeOptionMenuItem(AddrSeq* module, const char* label, float offset, float scale) + : OptionMenuItem( + label, + [=]() { return module->_rangeOffset == offset && module->_rangeScale == scale; }, + [=]() { + module->_rangeOffset = offset; + module->_rangeScale = scale; + } + ) + {} }; void appendContextMenu(Menu* menu) override { @@ -185,15 +175,16 @@ struct AddrSeqWidget : AddressableSequenceModuleWidget { AddrSeq* m = dynamic_cast<AddrSeq*>(module); assert(m); - menu->addChild(new MenuLabel()); - menu->addChild(new RangeMenuItem(m, "Range: +/-10V", 0.0f, 10.0f)); - menu->addChild(new RangeMenuItem(m, "Range: +/-5V", 0.0f, 5.0f)); - menu->addChild(new RangeMenuItem(m, "Range: +/-3V", 0.0f, 3.0f)); - menu->addChild(new RangeMenuItem(m, "Range: +/-1V", 0.0f, 1.0f)); - menu->addChild(new RangeMenuItem(m, "Range: 0V-10V", 1.0f, 5.0f)); - menu->addChild(new RangeMenuItem(m, "Range: 0V-5V", 1.0f, 2.5f)); - menu->addChild(new RangeMenuItem(m, "Range: 0V-3V", 1.0f, 1.5f)); - menu->addChild(new RangeMenuItem(m, "Range: 0V-1V", 1.0f, 0.5f)); + OptionsMenuItem* mi = new OptionsMenuItem("Range"); + mi->addItem(RangeOptionMenuItem(m, "+/-10V", 0.0f, 10.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-5V", 0.0f, 5.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-3V", 0.0f, 3.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-1V", 0.0f, 1.0f)); + mi->addItem(RangeOptionMenuItem(m, "0V-10V", 1.0f, 5.0f)); + mi->addItem(RangeOptionMenuItem(m, "0V-5V", 1.0f, 2.5f)); + mi->addItem(RangeOptionMenuItem(m, "0V-3V", 1.0f, 1.5f)); + mi->addItem(RangeOptionMenuItem(m, "0V-1V", 1.0f, 0.5f)); + menu->addChild(mi); } }; diff --git a/src/Analyzer.cpp b/src/Analyzer.cpp @@ -153,34 +153,15 @@ struct AnalyzerWidget : ModuleWidget { addChild(createLight<SmallLight<GreenLight>>(windowKaiserLightPosition, module, Analyzer::WINDOW_KAISER_LIGHT)); } - struct RangeDbMenuItem : MenuItem { - Analyzer* _module; - const float _rangeDb; - - RangeDbMenuItem(Analyzer* module, const char* label, float rangeDb) - : _module(module) - , _rangeDb(rangeDb) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_rangeDb = _rangeDb; - } - - void step() override { - MenuItem::step(); - rightText = _module->_rangeDb == _rangeDb ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { Analyzer* a = dynamic_cast<Analyzer*>(module); assert(a); menu->addChild(new MenuLabel()); - menu->addChild(new RangeDbMenuItem(a, "Amplitude: to -60dB", 80.0f)); - menu->addChild(new RangeDbMenuItem(a, "Amplitude: to -120dB", 140.0f)); + OptionsMenuItem* mi = new OptionsMenuItem("Amplitude range"); + mi->addItem(OptionMenuItem("To -60dB", [a]() { return a->_rangeDb == 80.0f; }, [a]() { a->_rangeDb = 80.0f; })); + mi->addItem(OptionMenuItem("To -120dB", [a]() { return a->_rangeDb == 140.0f; }, [a]() { a->_rangeDb = 140.0f; })); + menu->addChild(mi); } }; diff --git a/src/AnalyzerXL.cpp b/src/AnalyzerXL.cpp @@ -173,143 +173,50 @@ struct AnalyzerXLWidget : ModuleWidget { addInput(createInput<Port24>(signalhInputPosition, module, AnalyzerXL::SIGNALH_INPUT)); } - struct RangeMenuItem : MenuItem { - AnalyzerXL* _module; - const float _range; + void appendContextMenu(Menu* menu) override { + AnalyzerXL* a = dynamic_cast<AnalyzerXL*>(module); + assert(a); - RangeMenuItem(AnalyzerXL* module, const char* label, float range) - : _module(module) - , _range(range) + menu->addChild(new MenuLabel()); { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_range = _range; + OptionsMenuItem* mi = new OptionsMenuItem("Frequency range"); + mi->addItem(OptionMenuItem("Lower 25%", [a]() { return a->_range == -0.75f; }, [a]() { a->_range = -0.75f; })); + mi->addItem(OptionMenuItem("Lower 50%", [a]() { return a->_range == -0.5f; }, [a]() { a->_range = -0.5f; })); + mi->addItem(OptionMenuItem("Full", [a]() { return a->_range == 0.0f; }, [a]() { a->_range = 0.0f; })); + mi->addItem(OptionMenuItem("Upper 50%", [a]() { return a->_range == 0.5f; }, [a]() { a->_range = 0.5f; })); + mi->addItem(OptionMenuItem("Upper 25%", [a]() { return a->_range == 0.75f; }, [a]() { a->_range = 0.75f; })); + menu->addChild(mi); } - - void step() override { - MenuItem::step(); - rightText = _module->_range == _range ? "✔" : ""; - } - }; - - struct RangeDbMenuItem : MenuItem { - AnalyzerXL* _module; - const float _rangeDb; - - RangeDbMenuItem(AnalyzerXL* module, const char* label, float rangeDb) - : _module(module) - , _rangeDb(rangeDb) { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_rangeDb = _rangeDb; + OptionsMenuItem* mi = new OptionsMenuItem("Amplitude range"); + mi->addItem(OptionMenuItem("To -60dB", [a]() { return a->_rangeDb == 80.0f; }, [a]() { a->_rangeDb = 80.0f; })); + mi->addItem(OptionMenuItem("To -120dB", [a]() { return a->_rangeDb == 140.0f; }, [a]() { a->_rangeDb = 140.0f; })); + menu->addChild(mi); } - - void step() override { - MenuItem::step(); - rightText = _module->_rangeDb == _rangeDb ? "✔" : ""; - } - }; - - struct SmoothMenuItem : MenuItem { - AnalyzerXL* _module; - const float _smooth; - - SmoothMenuItem(AnalyzerXL* module, const char* label, float smooth) - : _module(module) - , _smooth(smooth) { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_smooth = _smooth; + OptionsMenuItem* mi = new OptionsMenuItem("Smoothing"); + mi->addItem(OptionMenuItem("None", [a]() { return a->_smooth == 0.0f; }, [a]() { a->_smooth = 0.0f; })); + mi->addItem(OptionMenuItem("10ms", [a]() { return a->_smooth == 0.01f; }, [a]() { a->_smooth = 0.01f; })); + mi->addItem(OptionMenuItem("50ms", [a]() { return a->_smooth == 0.05f; }, [a]() { a->_smooth = 0.05f; })); + mi->addItem(OptionMenuItem("100ms", [a]() { return a->_smooth == 0.1f; }, [a]() { a->_smooth = 0.1f; })); + mi->addItem(OptionMenuItem("250ms", [a]() { return a->_smooth == 0.25f; }, [a]() { a->_smooth = 0.25f; })); + mi->addItem(OptionMenuItem("500ms", [a]() { return a->_smooth == 0.5f; }, [a]() { a->_smooth = 0.5f; })); + menu->addChild(mi); } - - void step() override { - MenuItem::step(); - rightText = _module->_smooth == _smooth ? "✔" : ""; - } - }; - - struct QualityMenuItem : MenuItem { - AnalyzerXL* _module; - const AnalyzerCore::Quality _quality; - - QualityMenuItem(AnalyzerXL* module, const char* label, AnalyzerCore::Quality quality) - : _module(module) - , _quality(quality) { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_quality = _quality; - } - - void step() override { - MenuItem::step(); - rightText = _module->_quality == _quality ? "✔" : ""; + OptionsMenuItem* mi = new OptionsMenuItem("Quality"); + mi->addItem(OptionMenuItem("Good", [a]() { return a->_quality == AnalyzerCore::QUALITY_GOOD; }, [a]() { a->_quality = AnalyzerCore::QUALITY_GOOD; })); + mi->addItem(OptionMenuItem("High", [a]() { return a->_quality == AnalyzerCore::QUALITY_HIGH; }, [a]() { a->_quality = AnalyzerCore::QUALITY_HIGH; })); + mi->addItem(OptionMenuItem("Ultra", [a]() { return a->_quality == AnalyzerCore::QUALITY_ULTRA; }, [a]() { a->_quality = AnalyzerCore::QUALITY_ULTRA; })); + menu->addChild(mi); } - }; - - struct WindowMenuItem : MenuItem { - AnalyzerXL* _module; - const AnalyzerCore::Window _window; - - WindowMenuItem(AnalyzerXL* module, const char* label, AnalyzerCore::Window window) - : _module(module) - , _window(window) { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_window = _window; - } - - void step() override { - MenuItem::step(); - rightText = _module->_window == _window ? "✔" : ""; + OptionsMenuItem* mi = new OptionsMenuItem("Window"); + mi->addItem(OptionMenuItem("Kaiser", [a]() { return a->_window == AnalyzerCore::WINDOW_KAISER; }, [a]() { a->_window = AnalyzerCore::WINDOW_KAISER; })); + mi->addItem(OptionMenuItem("Hamming", [a]() { return a->_window == AnalyzerCore::WINDOW_HAMMING; }, [a]() { a->_window = AnalyzerCore::WINDOW_HAMMING; })); + mi->addItem(OptionMenuItem("None", [a]() { return a->_window == AnalyzerCore::WINDOW_NONE; }, [a]() { a->_window = AnalyzerCore::WINDOW_NONE; })); + menu->addChild(mi); } - }; - - void appendContextMenu(Menu* menu) override { - AnalyzerXL* a = dynamic_cast<AnalyzerXL*>(module); - assert(a); - - menu->addChild(new MenuLabel()); - menu->addChild(new RangeMenuItem(a, "Frequency: lower 25%", -0.75f)); - menu->addChild(new RangeMenuItem(a, "Frequency: lower 50%", -0.5f)); - menu->addChild(new RangeMenuItem(a, "Frequency: full", 0.0f)); - menu->addChild(new RangeMenuItem(a, "Frequency: upper 50%", 0.5f)); - menu->addChild(new RangeMenuItem(a, "Frequency: upper 25%", 0.75f)); - - menu->addChild(new MenuLabel()); - menu->addChild(new RangeDbMenuItem(a, "Amplitude: to -60dB", 80.0f)); - menu->addChild(new RangeDbMenuItem(a, "Amplitude: to -120dB", 140.0f)); - - menu->addChild(new MenuLabel()); - menu->addChild(new SmoothMenuItem(a, "Smooth: none", 0.0f)); - menu->addChild(new SmoothMenuItem(a, "Smooth: 10ms", 0.01f)); - menu->addChild(new SmoothMenuItem(a, "Smooth: 50ms", 0.05f)); - menu->addChild(new SmoothMenuItem(a, "Smooth: 100ms", 0.1f)); - menu->addChild(new SmoothMenuItem(a, "Smooth: 250ms", 0.25f)); - menu->addChild(new SmoothMenuItem(a, "Smooth: 500ms", 0.5f)); - - menu->addChild(new MenuLabel()); - menu->addChild(new QualityMenuItem(a, "Quality: good", AnalyzerCore::QUALITY_GOOD)); - menu->addChild(new QualityMenuItem(a, "Quality: high", AnalyzerCore::QUALITY_HIGH)); - menu->addChild(new QualityMenuItem(a, "Quality: ultra", AnalyzerCore::QUALITY_ULTRA)); - - menu->addChild(new MenuLabel()); - menu->addChild(new WindowMenuItem(a, "Window: Kaiser", AnalyzerCore::WINDOW_KAISER)); - menu->addChild(new WindowMenuItem(a, "Window: Hamming", AnalyzerCore::WINDOW_HAMMING)); - menu->addChild(new WindowMenuItem(a, "Window: none", AnalyzerCore::WINDOW_NONE)); } }; diff --git a/src/FMOp.cpp b/src/FMOp.cpp @@ -326,30 +326,11 @@ struct FMOpWidget : ModuleWidget { addChild(createLight<SmallLight<GreenLight>>(envToDepthLightPosition, module, FMOp::ENV_TO_DEPTH_LIGHT)); } - struct LinearLevelMenuItem : MenuItem { - FMOp* _module; - - LinearLevelMenuItem(FMOp* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_linearLevel = !_module->_linearLevel; - } - - void step() override { - MenuItem::step(); - rightText = _module->_linearLevel ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { FMOp* fmop = dynamic_cast<FMOp*>(module); assert(fmop); menu->addChild(new MenuLabel()); - menu->addChild(new LinearLevelMenuItem(fmop, "Linear level response")); + menu->addChild(new BoolOptionMenuItem("Linear level response", [fmop]() { return &fmop->_linearLevel; })); } }; diff --git a/src/Manual.cpp b/src/Manual.cpp @@ -32,7 +32,9 @@ void Manual::processChannel(const ProcessArgs& args, int _c) { struct ManualWidget : TriggerOnLoadModuleWidget { static constexpr int hp = 3; - ManualWidget(Manual* module) { + ManualWidget(Manual* module) + : TriggerOnLoadModuleWidget("Trigger on load") + { setModule(module); box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); @@ -70,13 +72,6 @@ struct ManualWidget : TriggerOnLoadModuleWidget { addOutput(createOutput<Port24>(out7OutputPosition, module, Manual::OUT7_OUTPUT)); addOutput(createOutput<Port24>(out8OutputPosition, module, Manual::OUT8_OUTPUT)); } - - void appendContextMenu(Menu* menu) override { - TriggerOnLoadModule* m = dynamic_cast<TriggerOnLoadModule*>(module); - assert(m); - menu->addChild(new MenuLabel()); - menu->addChild(new TriggerOnLoadMenuItem(m, "Trigger on load")); - } }; Model* modelManual = bogaudio::createModel<Manual, ManualWidget>("Bogaudio-Manual", "MANUAL", "Button controlled gates / triggers", "Utility"); diff --git a/src/Mix4.cpp b/src/Mix4.cpp @@ -190,36 +190,17 @@ struct Mix4Widget : ModuleWidget { addParam(slider); } - struct PolySpreadMenuItem : MenuItem { - Mix4* _module; - int _offset; - - PolySpreadMenuItem(Mix4* module, const char* label, int offset) - : _module(module) - , _offset(offset) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_polyChannelOffset = _offset; - } - - void step() override { - MenuItem::step(); - rightText = _module->_polyChannelOffset == _offset ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { Mix4* m = dynamic_cast<Mix4*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: none", -1)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 1-4", 0)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 5-8", 4)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 9-12", 4)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 13-16", 4)); + OptionsMenuItem* mi = new OptionsMenuItem("Input 1 poly spread"); + mi->addItem(OptionMenuItem("None", [m]() { return m->_polyChannelOffset == -1; }, [m]() { m->_polyChannelOffset = -1; })); + mi->addItem(OptionMenuItem("Channels 1-4", [m]() { return m->_polyChannelOffset == 0; }, [m]() { m->_polyChannelOffset = 0; })); + mi->addItem(OptionMenuItem("Channels 5-8", [m]() { return m->_polyChannelOffset == 4; }, [m]() { m->_polyChannelOffset = 4; })); + mi->addItem(OptionMenuItem("Channels 9-12", [m]() { return m->_polyChannelOffset == 8; }, [m]() { m->_polyChannelOffset = 8; })); + mi->addItem(OptionMenuItem("Channels 13-16", [m]() { return m->_polyChannelOffset == 12; }, [m]() { m->_polyChannelOffset = 12; })); + menu->addChild(mi); } }; diff --git a/src/Mix8.cpp b/src/Mix8.cpp @@ -242,34 +242,15 @@ struct Mix8Widget : ModuleWidget { addParam(slider); } - struct PolySpreadMenuItem : MenuItem { - Mix8* _module; - int _offset; - - PolySpreadMenuItem(Mix8* module, const char* label, int offset) - : _module(module) - , _offset(offset) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_polyChannelOffset = _offset; - } - - void step() override { - MenuItem::step(); - rightText = _module->_polyChannelOffset == _offset ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { Mix8* m = dynamic_cast<Mix8*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: none", -1)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 1-8", 0)); - menu->addChild(new PolySpreadMenuItem(m, "Input 1 poly spread: channels 9-16", 8)); + OptionsMenuItem* mi = new OptionsMenuItem("Input 1 poly spread"); + mi->addItem(OptionMenuItem("None", [m]() { return m->_polyChannelOffset == -1; }, [m]() { m->_polyChannelOffset = -1; })); + mi->addItem(OptionMenuItem("Channels 1-8", [m]() { return m->_polyChannelOffset == 0; }, [m]() { m->_polyChannelOffset = 0; })); + mi->addItem(OptionMenuItem("Channels 9-16", [m]() { return m->_polyChannelOffset == 8; }, [m]() { m->_polyChannelOffset = 8; })); + menu->addChild(mi); } }; diff --git a/src/Noise.cpp b/src/Noise.cpp @@ -91,41 +91,21 @@ struct NoiseWidget : ModuleWidget { addOutput(createOutput<Port24>(absOutputPosition, module, Noise::ABS_OUTPUT)); } - struct ChannelMenuItemX : MenuItem { + struct ChannelsMenuItem : MenuItem { Noise* _module; - int _channels; - ChannelMenuItemX(Noise* module, const char* label, int channels) - : _module(module) - , _channels(channels) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_noiseChannels = _channels; - } - - void step() override { - MenuItem::step(); - this->rightText = _module->_noiseChannels == _channels ? "✔" : ""; - } - }; - - struct ChannelsMenuItemX : MenuItem { - Noise* _module; - - ChannelsMenuItemX(Noise* module, const char* label) : _module(module) { + ChannelsMenuItem(Noise* module, const char* label) : _module(module) { this->text = label; } Menu* createChildMenu() override { Menu* menu = new Menu; - menu->addChild(new ChannelMenuItemX(_module, "Monophonic", 1)); + Noise* m = _module; + menu->addChild(new OptionMenuItem("Monophonic", [m]() { return m->_noiseChannels == 1; }, [m]() { m->_noiseChannels = 1; })); for (int i = 2; i <= BGModule::maxChannels; i++) { char s[10]; snprintf(s, 10, "%d", i); - menu->addChild(new ChannelMenuItemX(_module, s, i)); + menu->addChild(new OptionMenuItem(s, [m, i]() { return m->_noiseChannels == i; }, [m, i]() { m->_noiseChannels = i; })); } return menu; } @@ -143,7 +123,7 @@ struct NoiseWidget : ModuleWidget { assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new ChannelsMenuItemX(m, "Polyphony channels")); + menu->addChild(new ChannelsMenuItem(m, "Polyphony channels")); } }; diff --git a/src/SampleHold.cpp b/src/SampleHold.cpp @@ -191,67 +191,43 @@ struct SampleHoldWidget : ModuleWidget { addChild(createLight<SmallLight<GreenLight>>(invert2LightPosition, module, SampleHold::INVERT2_LIGHT)); } - struct NoiseTypeMenuItem : MenuItem { - SampleHold* _module; - SampleHold::NoiseType _noiseType; - - NoiseTypeMenuItem(SampleHold* module, const char* label, SampleHold::NoiseType noiseType) - : _module(module) - , _noiseType(noiseType) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_noiseType = _noiseType; - } - - void step() override { - MenuItem::step(); - rightText = _module->_noiseType == _noiseType ? "✔" : ""; - } - }; - - struct RangeMenuItem : MenuItem { - SampleHold* _module; - float _offset, _scale; - - RangeMenuItem(SampleHold* module, const char* label, float offset, float scale) - : _module(module) - , _offset(offset) - , _scale(scale) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_rangeOffset = _offset; - _module->_rangeScale = _scale; - } - - void step() override { - MenuItem::step(); - rightText = (_module->_rangeOffset == _offset && _module->_rangeScale == _scale) ? "✔" : ""; - } + struct RangeOptionMenuItem : OptionMenuItem { + RangeOptionMenuItem(SampleHold* module, const char* label, float offset, float scale) + : OptionMenuItem( + label, + [=]() { return module->_rangeOffset == offset && module->_rangeScale == scale; }, + [=]() { + module->_rangeOffset = offset; + module->_rangeScale = scale; + } + ) + {} }; void appendContextMenu(Menu* menu) override { SampleHold* m = dynamic_cast<SampleHold*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new NoiseTypeMenuItem(m, "Normal noise: blue", SampleHold::BLUE_NOISE_TYPE)); - menu->addChild(new NoiseTypeMenuItem(m, "Normal noise: white", SampleHold::WHITE_NOISE_TYPE)); - menu->addChild(new NoiseTypeMenuItem(m, "Normal noise: pink", SampleHold::PINK_NOISE_TYPE)); - menu->addChild(new NoiseTypeMenuItem(m, "Normal noise: red", SampleHold::RED_NOISE_TYPE)); - menu->addChild(new MenuLabel()); - menu->addChild(new RangeMenuItem(m, "Normal range: +/-10V", 0.0f, 10.0f)); - menu->addChild(new RangeMenuItem(m, "Normal range: +/-5V", 0.0f, 5.0f)); - menu->addChild(new RangeMenuItem(m, "Normal range: +/-3V", 0.0f, 3.0f)); - menu->addChild(new RangeMenuItem(m, "Normal range: +/-1V", 0.0f, 1.0f)); - menu->addChild(new RangeMenuItem(m, "Normal range: 0V-10V", 1.0f, 5.0f)); - menu->addChild(new RangeMenuItem(m, "Normal range: 0V-5V", 1.0f, 2.5f)); - menu->addChild(new RangeMenuItem(m, "Normal range: 0V-3V", 1.0f, 1.5f)); - menu->addChild(new RangeMenuItem(m, "Normal range: 0V-1V", 1.0f, 0.5f)); + { + OptionsMenuItem* mi = new OptionsMenuItem("Normal noise"); + mi->addItem(OptionMenuItem("Blue", [m]() { return m->_noiseType == SampleHold::BLUE_NOISE_TYPE; }, [m]() { m->_noiseType = SampleHold::BLUE_NOISE_TYPE; })); + mi->addItem(OptionMenuItem("White", [m]() { return m->_noiseType == SampleHold::WHITE_NOISE_TYPE; }, [m]() { m->_noiseType = SampleHold::WHITE_NOISE_TYPE; })); + mi->addItem(OptionMenuItem("Pink", [m]() { return m->_noiseType == SampleHold::PINK_NOISE_TYPE; }, [m]() { m->_noiseType = SampleHold::PINK_NOISE_TYPE; })); + mi->addItem(OptionMenuItem("Red", [m]() { return m->_noiseType == SampleHold::RED_NOISE_TYPE; }, [m]() { m->_noiseType = SampleHold::RED_NOISE_TYPE; })); + menu->addChild(mi); + } + { + OptionsMenuItem* mi = new OptionsMenuItem("Normal range"); + mi->addItem(RangeOptionMenuItem(m, "+/-10V", 0.0f, 10.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-5V", 0.0f, 5.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-3V", 0.0f, 3.0f)); + mi->addItem(RangeOptionMenuItem(m, "+/-1V", 0.0f, 1.0f)); + mi->addItem(RangeOptionMenuItem(m, "0V-10V", 1.0f, 5.0f)); + mi->addItem(RangeOptionMenuItem(m, "0V-5V", 1.0f, 2.5f)); + mi->addItem(RangeOptionMenuItem(m, "0V-3V", 1.0f, 1.5f)); + mi->addItem(RangeOptionMenuItem(m, "0V-1V", 1.0f, 0.5f)); + menu->addChild(mi); + } } }; diff --git a/src/UMix.cpp b/src/UMix.cpp @@ -122,50 +122,12 @@ struct UMixWidget : ModuleWidget { addOutput(createOutput<Port24>(outOutputPosition, module, UMix::OUT_OUTPUT)); } - struct AverageMenuItem : MenuItem { - UMix* _module; - - AverageMenuItem(UMix* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_sum = !_module->_sum; - } - - void step() override { - MenuItem::step(); - rightText = !_module->_sum ? "✔" : ""; - } - }; - - struct CVModeMenuItem : MenuItem { - UMix* _module; - - CVModeMenuItem(UMix* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_cvMode = !_module->_cvMode; - } - - void step() override { - MenuItem::step(); - rightText = _module->_cvMode ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { - UMix* umix = dynamic_cast<UMix*>(module); - assert(umix); + UMix* m = dynamic_cast<UMix*>(module); + assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new AverageMenuItem(umix, "Average")); - menu->addChild(new CVModeMenuItem(umix, "CV mode")); + menu->addChild(new OptionMenuItem("Average", [m]() { return !m->_sum; }, [m]() { m->_sum = !m->_sum; })); + menu->addChild(new BoolOptionMenuItem("CV mode", [m]() { return &m->_cvMode; })); } }; diff --git a/src/Walk2.cpp b/src/Walk2.cpp @@ -485,79 +485,26 @@ struct Walk2Widget : ModuleWidget { addOutput(createOutput<Port24>(distanceOutputPosition, module, Walk2::DISTANCE_OUTPUT)); } - struct ZoomOutMenuItem : MenuItem { - Walk2* _module; - const bool _zoomOut; + void appendContextMenu(Menu* menu) override { + Walk2* m = dynamic_cast<Walk2*>(module); + assert(m); - ZoomOutMenuItem(Walk2* module, const char* label, bool zoomOut) - : _module(module) - , _zoomOut(zoomOut) + menu->addChild(new MenuLabel()); { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_zoomOut = _zoomOut; - } - - void step() override { - MenuItem::step(); - rightText = _module->_zoomOut == _zoomOut ? "✔" : ""; - } - }; - - struct GridMenuItem : MenuItem { - Walk2* _module; - - GridMenuItem(Walk2* module, const char* label) : _module(module) { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_drawGrid = !_module->_drawGrid; - } - - void step() override { - MenuItem::step(); - rightText = _module->_drawGrid ? "✔" : ""; + OptionsMenuItem* mi = new OptionsMenuItem("Display range"); + mi->addItem(OptionMenuItem("+/-5V", [m]() { return m->_zoomOut == false; }, [m]() { m->_zoomOut = false; })); + mi->addItem(OptionMenuItem("+/-10V", [m]() { return m->_zoomOut == true; }, [m]() { m->_zoomOut = true; })); + menu->addChild(mi); } - }; - - struct ColorMenuItem : MenuItem { - Walk2* _module; - const Walk2::TraceColor _color; - - ColorMenuItem(Walk2* module, const char* label, Walk2::TraceColor color) - : _module(module) - , _color(color) + menu->addChild(new BoolOptionMenuItem("Show grid", [m]() { return &m->_drawGrid; })); { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_traceColor = _color; - } - - void step() override { - MenuItem::step(); - rightText = _module->_traceColor == _color ? "✔" : ""; + OptionsMenuItem* mi = new OptionsMenuItem("Trace color"); + mi->addItem(OptionMenuItem("Green", [m]() { return m->_traceColor == Walk2::GREEN_TRACE_COLOR; }, [m]() { m->_traceColor = Walk2::GREEN_TRACE_COLOR; })); + mi->addItem(OptionMenuItem("Orange", [m]() { return m->_traceColor == Walk2::ORANGE_TRACE_COLOR; }, [m]() { m->_traceColor = Walk2::ORANGE_TRACE_COLOR; })); + mi->addItem(OptionMenuItem("Red", [m]() { return m->_traceColor == Walk2::RED_TRACE_COLOR; }, [m]() { m->_traceColor = Walk2::RED_TRACE_COLOR; })); + mi->addItem(OptionMenuItem("Blue", [m]() { return m->_traceColor == Walk2::BLUE_TRACE_COLOR; }, [m]() { m->_traceColor = Walk2::BLUE_TRACE_COLOR; })); + menu->addChild(mi); } - }; - - void appendContextMenu(Menu* menu) override { - Walk2* w = dynamic_cast<Walk2*>(module); - assert(w); - - menu->addChild(new MenuLabel()); - menu->addChild(new ZoomOutMenuItem(w, "Display range: +/-5V", false)); - menu->addChild(new ZoomOutMenuItem(w, "Display range: +/-10V", true)); - menu->addChild(new MenuLabel()); - menu->addChild(new GridMenuItem(w, "Show grid")); - menu->addChild(new MenuLabel()); - menu->addChild(new ColorMenuItem(w, "Trace color: green", Walk2::GREEN_TRACE_COLOR)); - menu->addChild(new ColorMenuItem(w, "Trace color: orange", Walk2::ORANGE_TRACE_COLOR)); - menu->addChild(new ColorMenuItem(w, "Trace color: red", Walk2::RED_TRACE_COLOR)); - menu->addChild(new ColorMenuItem(w, "Trace color: blue", Walk2::BLUE_TRACE_COLOR)); } }; diff --git a/src/addressable_sequence.hpp b/src/addressable_sequence.hpp @@ -37,50 +37,12 @@ struct AddressableSequenceModule : BGModule { }; struct AddressableSequenceModuleWidget : ModuleWidget { - struct SelectOnClockMenuItem : MenuItem { - AddressableSequenceModule* _module; - - SelectOnClockMenuItem(AddressableSequenceModule* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_selectOnClock = !_module->_selectOnClock; - } - - void step() override { - MenuItem::step(); - rightText = _module->_selectOnClock ? "✔" : ""; - } - }; - - struct TriggeredSelectMenuItem : MenuItem { - AddressableSequenceModule* _module; - - TriggeredSelectMenuItem(AddressableSequenceModule* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_triggeredSelect = !_module->_triggeredSelect; - } - - void step() override { - MenuItem::step(); - rightText = _module->_triggeredSelect ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { AddressableSequenceModule* m = dynamic_cast<AddressableSequenceModule*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new SelectOnClockMenuItem(m, "Select on clock mode")); - menu->addChild(new TriggeredSelectMenuItem(m, "Triggered select mode")); + menu->addChild(new BoolOptionMenuItem("Select on clock mode", [m]() { return &m->_selectOnClock; })); + menu->addChild(new BoolOptionMenuItem("Triggered select mode", [m]() { return &m->_triggeredSelect; })); } }; diff --git a/src/bogaudio.hpp b/src/bogaudio.hpp @@ -10,6 +10,7 @@ #include "rack.hpp" #include "module.hpp" +#include "menu.hpp" #include "param_quantities.hpp" #include "rack_overrides.hpp" #include "widgets.hpp" diff --git a/src/disable_output_limit.hpp b/src/disable_output_limit.hpp @@ -12,30 +12,11 @@ struct DisableOutputLimitModule : BGModule { }; struct DisableOutputLimitModuleWidget : ModuleWidget { - struct DisableOutputLimitMenuItem : MenuItem { - DisableOutputLimitModule* _module; - - DisableOutputLimitMenuItem(DisableOutputLimitModule* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_disableOutputLimit = !_module->_disableOutputLimit; - } - - void step() override { - MenuItem::step(); - rightText = _module->_disableOutputLimit ? "✔" : ""; - } - }; - void appendContextMenu(Menu* menu) override { - DisableOutputLimitModule* dolm = dynamic_cast<DisableOutputLimitModule*>(module); - assert(dolm); + DisableOutputLimitModule* m = dynamic_cast<DisableOutputLimitModule*>(module); + assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new DisableOutputLimitMenuItem(dolm, "Disable output limit")); + menu->addChild(new BoolOptionMenuItem("Disable output limit", [m]() { return &m->_disableOutputLimit; })); } }; diff --git a/src/menu.hpp b/src/menu.hpp @@ -0,0 +1,57 @@ +#pragma once + +#include "rack.hpp" + +using namespace rack; + +namespace bogaudio { + +struct OptionMenuItem : MenuItem { + std::function<bool()> _check; + std::function<void()> _set; + + OptionMenuItem(const char* label, std::function<bool()> check, std::function<void()> set) + : _check(check) + , _set(set) + { + this->text = label; + } + + void onAction(const event::Action& e) override { + _set(); + } + + void step() override { + MenuItem::step(); + rightText = _check() ? "✔" : ""; + } +}; + +struct BoolOptionMenuItem : OptionMenuItem { + BoolOptionMenuItem(const char* label, std::function<bool*()> get) + : OptionMenuItem(label, [=]() { return *(get()); }, [=]() { bool* b = get(); *b = !*b; }) + {} +}; + +struct OptionsMenuItem : MenuItem { + std::vector<OptionMenuItem> _items; + + OptionsMenuItem(const char* label) { + this->text = label; + this->rightText = "▸"; + } + + void addItem(const OptionMenuItem& item) { + _items.push_back(item); + } + + Menu* createChildMenu() override { + Menu* menu = new Menu; + for (const OptionMenuItem& item : _items) { + menu->addChild(new OptionMenuItem(item)); + } + return menu; + } +}; + +} // namespace bogaudio diff --git a/src/trigger_on_load.hpp b/src/trigger_on_load.hpp @@ -17,30 +17,17 @@ struct TriggerOnLoadModule : BGModule { }; struct TriggerOnLoadModuleWidget : ModuleWidget { - struct TriggerOnLoadMenuItem : MenuItem { - TriggerOnLoadModule* _module; + std::string _menuItemLabel; - TriggerOnLoadMenuItem(TriggerOnLoadModule* module, const char* label) - : _module(module) - { - this->text = label; - } - - void onAction(const event::Action& e) override { - _module->_triggerOnLoad = !_module->_triggerOnLoad; - } - - void step() override { - MenuItem::step(); - rightText = _module->_triggerOnLoad ? "✔" : ""; - } - }; + TriggerOnLoadModuleWidget(const char* menuItemLabel = "Resume loop on load") + : _menuItemLabel(menuItemLabel) + {} void appendContextMenu(Menu* menu) override { TriggerOnLoadModule* m = dynamic_cast<TriggerOnLoadModule*>(module); assert(m); menu->addChild(new MenuLabel()); - menu->addChild(new TriggerOnLoadMenuItem(m, "Resume loop on load")); + menu->addChild(new BoolOptionMenuItem(_menuItemLabel.c_str(), [m]() { return &m->_triggerOnLoad; })); } };