From 9c5ad894006d2d9a66da91833fcc17e1b8456845 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 12 Jan 2024 16:40:39 -0500 Subject: [PATCH] Dyanmic Deactivation of Widgets; Use in RingMod (#981) Knobs and Menu Items get dynamic deactivation as an option. The ring modulator uses this. --- docs/nightlychangelog.md | 1 + src/LayoutEngine.h | 4 ++ src/XTWidgets.h | 117 +++++++++++++++++++++++++++++++++-- src/fxconfig/RingModulator.h | 14 ++++- 4 files changed, 131 insertions(+), 5 deletions(-) diff --git a/docs/nightlychangelog.md b/docs/nightlychangelog.md index 5b3e4cb..d5e12c7 100644 --- a/docs/nightlychangelog.md +++ b/docs/nightlychangelog.md @@ -11,5 +11,6 @@ A small fix release after 2.2.1 - Some tweaks to the ringmod, including changing display when connecting and disconnecting - FX sidechains participate in neighbor inputs +- RingMod deactivates useless controls when sideband attached diff --git a/src/LayoutEngine.h b/src/LayoutEngine.h index be917c6..b46ac9c 100644 --- a/src/LayoutEngine.h +++ b/src/LayoutEngine.h @@ -60,6 +60,8 @@ struct LayoutItem bool dynamicLabel{false}; std::function dynLabelFn{nullptr}; + std::function dynamicDeactivateFn{nullptr}; + static LayoutItem createLCDArea(float ht) { auto res = LayoutItem(); @@ -284,6 +286,7 @@ template struct LayoutEngine } if (knob) { + knob->dynamicDeactivateFn = lay.dynamicDeactivateFn; w->addChild(knob->asWidget()); auto boxx0 = lay.xcmm - lc::columnWidth_MM * 0.5 - halfSize; auto boxy0 = lay.ycmm + 8.573 + halfSize - 5; @@ -560,6 +563,7 @@ template struct LayoutEngine rack::Vec(xpos, ypos), rack::Vec(width, height), module, lay.parId); wid->upcaseDisplay = false; wid->centerDisplay = true; + wid->dynamicDeactivateFn = lay.dynamicDeactivateFn; if (sd == 0) { diff --git a/src/XTWidgets.h b/src/XTWidgets.h index 938784a..dfc4a2d 100644 --- a/src/XTWidgets.h +++ b/src/XTWidgets.h @@ -308,6 +308,9 @@ struct ModulatableKnob { virtual void setIsModEditing(bool b) = 0; virtual rack::Widget *asWidget() = 0; + + bool deactivated{false}; + std::function dynamicDeactivateFn{nullptr}; }; struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant, ModulatableKnob @@ -388,6 +391,9 @@ struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant void drawRing(NVGcontext *vg) { + if (deactivated) + return; + float radius = rack::mm2px(ringWidth_MM * 2 + knobSize_MM) * 0.5; nvgBeginPath(vg); nvgArc(vg, box.size.x * 0.5, box.size.y * 0.5, radius, minAngle - M_PI_2, maxAngle - M_PI_2, @@ -400,6 +406,9 @@ struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant void drawValueRing(NVGcontext *vg) { + if (deactivated) + return; + if (isModEditing) return; auto *pq = getParamQuantity(); @@ -455,12 +464,15 @@ struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant BufferedDrawFunctionWidget *bw{nullptr}, *bwValue{nullptr}, *bwShadow{nullptr}; void onChange(const ChangeEvent &e) override; void onStyleChanged() override { setupWidgets(); } + + std::shared_ptr ptrSvg; void setupWidgets() { auto compDir = style()->skinAssetDir() + "/components"; - setSvg( - rack::Svg::load(rack::asset::plugin(pluginInstance, compDir + "/" + knobPointerAsset))); + ptrSvg = + rack::Svg::load(rack::asset::plugin(pluginInstance, compDir + "/" + knobPointerAsset)); + setSvg(ptrSvg); bg->setSvg(rack::Svg::load( rack::asset::plugin(pluginInstance, compDir + "/" + knobBackgroundAsset))); // bg->visible = false; @@ -532,6 +544,19 @@ struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant nvgRestore(vg); } + void setDeactivated(bool isDA) + { + deactivated = isDA; + + bw->dirty = true; + bwValue->dirty = true; + + bwShadow->dirty = true; + + sw->setVisible(!deactivated); + fb->dirty = true; + } + float priorMDA{0}; bool priorBip{false}; void step() override @@ -550,9 +575,66 @@ struct KnobN : public rack::componentlibrary::RoundKnob, style::StyleParticipant bwValue->dirty = true; priorBip = bip; } + + if (dynamicDeactivateFn) + { + auto xtm = static_cast(module); + auto oda = deactivated; + auto nda = dynamicDeactivateFn(xtm); + if (oda != nda) + { + setDeactivated(nda); + } + } } rack::componentlibrary::RoundKnob::step(); } + + void onHover(const HoverEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onHover(e); + } + void onButton(const ButtonEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onButton(e); + } + + void onDragStart(const DragStartEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onDragStart(e); + } + void onDragEnd(const DragEndEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onDragEnd(e); + } + + void onDragMove(const DragMoveEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onDragMove(e); + } + + void onDragLeave(const DragLeaveEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onDragLeave(e); + } + + void onHoverScroll(const HoverScrollEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onHoverScroll(e); + } + + void onLeave(const LeaveEvent &e) override + { + if (!deactivated) + rack::componentlibrary::RoundKnob::onLeave(e); + } }; struct Knob9 : KnobN @@ -1616,7 +1698,9 @@ struct PlotAreaMenuItem : public rack::app::Knob, style::StyleParticipant static constexpr float padTop_MM = 1.4; static constexpr float padBot_MM = 1.6; BufferedDrawFunctionWidget *bdw{nullptr}; - std::function transformLabel; + std::function transformLabel{nullptr}; + bool deactivated{false}; + std::function dynamicDeactivateFn{nullptr}; std::function onShowMenu = []() {}; bool upcaseDisplay{true}; bool centerDisplay{false}; @@ -1655,7 +1739,10 @@ struct PlotAreaMenuItem : public rack::app::Knob, style::StyleParticipant pv = transformLabel(pv); nvgBeginPath(vg); - nvgFillColor(vg, style()->getColor(style::XTStyle::PLOT_CONTROL_TEXT)); + if (deactivated) + nvgFillColor(vg, style()->getColor(style::XTStyle::PLOT_MARKS)); + else + nvgFillColor(vg, style()->getColor(style::XTStyle::PLOT_CONTROL_TEXT)); nvgFontFaceId(vg, style()->fontIdBold(vg)); nvgFontSize(vg, layout::LayoutConstants::labelSize_pt * 96 / 72); if (centerDisplay) @@ -1689,8 +1776,17 @@ struct PlotAreaMenuItem : public rack::app::Knob, style::StyleParticipant Widget::onChange(e); } + void onHover(const HoverEvent &e) override + { + if (!deactivated) + rack::app::Knob::onHover(e); + } + void onAction(const ActionEvent &e) override { + if (deactivated) + return; + onShowMenu(); e.consume(this); } @@ -1710,6 +1806,19 @@ struct PlotAreaMenuItem : public rack::app::Knob, style::StyleParticipant cacheString = pv; } } + + if (dynamicDeactivateFn) + { + auto xtm = static_cast(module); + + auto oda = deactivated; + auto nda = dynamicDeactivateFn(xtm); + if (oda != nda) + { + deactivated = nda; + bdw->dirty = true; + } + } } rack::Knob::step(); } diff --git a/src/fxconfig/RingModulator.h b/src/fxconfig/RingModulator.h index 950283c..b0cff89 100644 --- a/src/fxconfig/RingModulator.h +++ b/src/fxconfig/RingModulator.h @@ -48,7 +48,7 @@ template <> FXConfig::layout_t FXConfig::getLayout() typedef RingModulatorEffect rm_t; // clang-format off - return { + FXConfig::layout_t res = { {LayoutItem::KNOB12, "FREQUENCY", rm_t::rm_carrier_freq, colC, row1}, {LayoutItem::KNOB9, "BIAS", rm_t::rm_diode_fwdbias, col[0], row2}, @@ -75,6 +75,18 @@ template <> FXConfig::layout_t FXConfig::getLayout() LayoutItem::createRightMenuItem("Voices", rm_t::rm_unison_voices) }; // clang-format on + + // this indexing is a bit of a hack + res[0].dynamicDeactivateFn = [](auto m) { + auto fxm = static_cast *>(m); + auto &p = fxm->fxstorage->p[RingModulatorEffect::rm_carrier_shape]; + return p.val.i == p.val_max.i; + }; + res[13].dynamicDeactivateFn = res[0].dynamicDeactivateFn; + res[16].dynamicDeactivateFn = res[0].dynamicDeactivateFn; + res[17].dynamicDeactivateFn = res[0].dynamicDeactivateFn; + + return res; } template <> void FXConfig::configSpecificParams(FX *m)