From 57d267a663b5d7d58eb5865847140c49ccca73f3 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 14 Nov 2021 18:35:00 -0500 Subject: [PATCH] Handle bound components in menus (#5402) I was super careful to make sure my menus lived less long than the thises they bound, but in a close editor case I am out of luck. Tnanks to the TAP folks, especially daniel, I learned to use juce::Component::SafePointer<> which does what I need. See discussion in #5401 and the forum post linked there for more Closes #5401 --- src/surge-xt/gui/SurgeGUIEditor.cpp | 38 ++++--------------- .../gui/SurgeGUIEditorValueCallbacks.cpp | 16 +++----- src/surge-xt/gui/SurgeJUCEHelpers.h | 34 +++++++++++++++++ .../gui/overlays/ModulationEditor.cpp | 6 ++- .../gui/widgets/ModulationSourceButton.cpp | 3 +- src/surge-xt/gui/widgets/PatchSelector.cpp | 3 +- .../gui/widgets/XMLConfiguredMenus.cpp | 20 ++++++---- src/surge-xt/gui/widgets/XMLConfiguredMenus.h | 1 + 8 files changed, 68 insertions(+), 53 deletions(-) diff --git a/src/surge-xt/gui/SurgeGUIEditor.cpp b/src/surge-xt/gui/SurgeGUIEditor.cpp index 3fe44c1f8be..e0694ce211d 100644 --- a/src/surge-xt/gui/SurgeGUIEditor.cpp +++ b/src/surge-xt/gui/SurgeGUIEditor.cpp @@ -1969,7 +1969,7 @@ void SurgeGUIEditor::effectSettingsBackgroundClick(int whichScene, Surge::Widget if (!juce::PopupMenu::dismissAllActiveMenus()) { - fxGridMenu.showMenuAsync(juce::PopupMenu::Options(), [c](int i) { c->endHover(); }); + fxGridMenu.showMenuAsync(juce::PopupMenu::Options(), Surge::GUI::makeEndHoverCallback(c)); } } @@ -2046,12 +2046,7 @@ void SurgeGUIEditor::showZoomMenu(const juce::Point &where, if (!juce::PopupMenu::dismissAllActiveMenus()) { auto m = makeZoomMenu(where, true); - m.showMenuAsync(optionsForPosition(where), [launchFrom](int i) { - if (launchFrom) - { - launchFrom->endHover(); - } - }); + m.showMenuAsync(optionsForPosition(where), Surge::GUI::makeEndHoverCallback(launchFrom)); } } @@ -2061,12 +2056,7 @@ void SurgeGUIEditor::showMPEMenu(const juce::Point &where, if (!juce::PopupMenu::dismissAllActiveMenus()) { auto m = makeMpeMenu(where, true); - m.showMenuAsync(optionsForPosition(where), [launchFrom](int i) { - if (launchFrom) - { - launchFrom->endHover(); - } - }); + m.showMenuAsync(optionsForPosition(where), Surge::GUI::makeEndHoverCallback(launchFrom)); } } void SurgeGUIEditor::showLfoMenu(const juce::Point &where, @@ -2075,12 +2065,7 @@ void SurgeGUIEditor::showLfoMenu(const juce::Point &where, if (!juce::PopupMenu::dismissAllActiveMenus()) { auto m = makeLfoMenu(where); - m.showMenuAsync(optionsForPosition(where), [launchFrom](int i) { - if (launchFrom) - { - launchFrom->endHover(); - } - }); + m.showMenuAsync(optionsForPosition(where), Surge::GUI::makeEndHoverCallback(launchFrom)); } } @@ -2103,12 +2088,7 @@ void SurgeGUIEditor::showTuningMenu(const juce::Point &where, { auto m = makeTuningMenu(where, true); - m.showMenuAsync(optionsForPosition(where), [launchFrom](int i) { - if (launchFrom) - { - launchFrom->endHover(); - } - }); + m.showMenuAsync(optionsForPosition(where), Surge::GUI::makeEndHoverCallback(launchFrom)); } } @@ -2338,12 +2318,8 @@ void SurgeGUIEditor::showSettingsMenu(const juce::Point &where, if (!juce::PopupMenu::dismissAllActiveMenus()) { - settingsMenu.showMenuAsync(optionsForPosition(where), [launchFrom](int i) { - if (launchFrom != nullptr) - { - launchFrom->endHover(); - } - }); + settingsMenu.showMenuAsync(optionsForPosition(where), + Surge::GUI::makeEndHoverCallback(launchFrom)); } } diff --git a/src/surge-xt/gui/SurgeGUIEditorValueCallbacks.cpp b/src/surge-xt/gui/SurgeGUIEditorValueCallbacks.cpp index 169c772c0bb..98ad308b1fa 100644 --- a/src/surge-xt/gui/SurgeGUIEditorValueCallbacks.cpp +++ b/src/surge-xt/gui/SurgeGUIEditorValueCallbacks.cpp @@ -490,7 +490,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c if (!juce::PopupMenu::dismissAllActiveMenus()) { contextMenu.showMenuAsync(optionsForPosition(cwhere), - [control](int i) { control->endHover(); }); + Surge::GUI::makeEndHoverCallback(control)); } return 1; } @@ -537,7 +537,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c if (!juce::PopupMenu::dismissAllActiveMenus()) { contextMenu.showMenuAsync(optionsForPosition(cwhere), - [control](int i) { control->endHover(); }); + Surge::GUI::makeEndHoverCallback(control)); } return 1; } @@ -1028,7 +1028,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c if (!juce::PopupMenu::dismissAllActiveMenus()) { contextMenu.showMenuAsync(juce::PopupMenu::Options(), - [control](int opt) { control->endHover(); }); + Surge::GUI::makeEndHoverCallback(control)); } return 1; } @@ -2234,7 +2234,7 @@ int32_t SurgeGUIEditor::controlModifierClicked(Surge::GUI::IComponentTagValue *c if (!juce::PopupMenu::dismissAllActiveMenus()) { contextMenu.showMenuAsync(juce::PopupMenu::Options(), - [control](int i) { control->endHover(); }); + Surge::GUI::makeEndHoverCallback(control)); } return 1; } @@ -2448,12 +2448,8 @@ void SurgeGUIEditor::valueChanged(Surge::GUI::IComponentTagValue *control) auto launchFrom = control; if (!juce::PopupMenu::dismissAllActiveMenus()) { - m.showMenuAsync(juce::PopupMenu::Options(), [launchFrom](int i) { - if (launchFrom) - { - launchFrom->endHover(); - } - }); + m.showMenuAsync(juce::PopupMenu::Options(), + Surge::GUI::makeEndHoverCallback(launchFrom)); } } diff --git a/src/surge-xt/gui/SurgeJUCEHelpers.h b/src/surge-xt/gui/SurgeJUCEHelpers.h index 2d852d2dc20..c43d031091c 100644 --- a/src/surge-xt/gui/SurgeJUCEHelpers.h +++ b/src/surge-xt/gui/SurgeJUCEHelpers.h @@ -17,11 +17,45 @@ #define SURGE_XT_JUCEHELPERS_H #include "juce_gui_basics/juce_gui_basics.h" +#include "SurgeGUICallbackInterfaces.h" namespace Surge { namespace GUI { + +template +inline std::function makeAsyncCallback(T *that, std::function cb) +{ + return [safethat = juce::Component::SafePointer(that), cb](int x) { + if (safethat) + cb(safethat, x); + }; +} + +template inline std::function makeEndHoverCallback(T *that) +{ + return [safethat = juce::Component::SafePointer(that)](int x) { + if (safethat) + { + safethat->endHover(); + } + }; +} + +template <> +inline std::function makeEndHoverCallback(Surge::GUI::IComponentTagValue *that) +{ + return + [safethat = juce::Component::SafePointer(that->asJuceComponent())](int x) { + if (safethat) + { + auto igtv = dynamic_cast(safethat.getComponent()); + if (igtv) + igtv->endHover(); + } + }; +} struct WheelAccumulationHelper { float accum{0}; diff --git a/src/surge-xt/gui/overlays/ModulationEditor.cpp b/src/surge-xt/gui/overlays/ModulationEditor.cpp index 4b5a92f489a..7244b59a5d5 100644 --- a/src/surge-xt/gui/overlays/ModulationEditor.cpp +++ b/src/surge-xt/gui/overlays/ModulationEditor.cpp @@ -22,6 +22,7 @@ #include "widgets/MenuCustomComponents.h" #include "widgets/ModulatableSlider.h" #include "widgets/MultiSwitch.h" +#include "SurgeJUCEHelpers.h" namespace Surge { @@ -697,7 +698,7 @@ void ModulationSideControls::valueChanged(GUI::IComponentTagValue *c) }); if (!juce::PopupMenu::dismissAllActiveMenus()) { - men.showMenuAsync(juce::PopupMenu::Options(), [this](int) { filterW->endHover(); }); + men.showMenuAsync(juce::PopupMenu::Options(), GUI::makeEndHoverCallback(filterW.get())); } } break; @@ -712,7 +713,8 @@ void ModulationSideControls::valueChanged(GUI::IComponentTagValue *c) men.addItem("Coming soon!", [this]() {}); if (!juce::PopupMenu::dismissAllActiveMenus()) { - men.showMenuAsync(juce::PopupMenu::Options(), [this](int) { addSourceW->endHover(); }); + men.showMenuAsync(juce::PopupMenu::Options(), + GUI::makeEndHoverCallback(addSourceW.get())); } } break; diff --git a/src/surge-xt/gui/widgets/ModulationSourceButton.cpp b/src/surge-xt/gui/widgets/ModulationSourceButton.cpp index 3fb09a10d2c..da4a62bca44 100644 --- a/src/surge-xt/gui/widgets/ModulationSourceButton.cpp +++ b/src/surge-xt/gui/widgets/ModulationSourceButton.cpp @@ -21,6 +21,7 @@ #include "SurgeGUIEditor.h" #include "SurgeImage.h" #include "SurgeGUIUtils.h" +#include "SurgeJUCEHelpers.h" namespace Surge { @@ -323,7 +324,7 @@ void ModulationSourceButton::mouseDown(const juce::MouseEvent &event) if (!juce::PopupMenu::dismissAllActiveMenus()) { - menu.showMenuAsync(juce::PopupMenu::Options(), [this](int) { endHover(); }); + menu.showMenuAsync(juce::PopupMenu::Options(), Surge::GUI::makeEndHoverCallback(this)); } return; } diff --git a/src/surge-xt/gui/widgets/PatchSelector.cpp b/src/surge-xt/gui/widgets/PatchSelector.cpp index 5948c836917..e02cba28c2a 100644 --- a/src/surge-xt/gui/widgets/PatchSelector.cpp +++ b/src/surge-xt/gui/widgets/PatchSelector.cpp @@ -24,6 +24,7 @@ #include "overlays/PatchStoreDialog.h" #include "PatchDB.h" #include "fmt/core.h" +#include "SurgeJUCEHelpers.h" namespace Surge { @@ -266,7 +267,7 @@ void PatchSelector::mouseDown(const juce::MouseEvent &e) if (!juce::PopupMenu::dismissAllActiveMenus()) { menu.showMenuAsync(juce::PopupMenu::Options(), - [this](int) { this->endHover(); }); + Surge::GUI::makeEndHoverCallback(this)); } } diff --git a/src/surge-xt/gui/widgets/XMLConfiguredMenus.cpp b/src/surge-xt/gui/widgets/XMLConfiguredMenus.cpp index 7df1512f44d..99984bfc043 100644 --- a/src/surge-xt/gui/widgets/XMLConfiguredMenus.cpp +++ b/src/surge-xt/gui/widgets/XMLConfiguredMenus.cpp @@ -324,6 +324,8 @@ OscillatorMenu::OscillatorMenu() #endif } +OscillatorMenu::~OscillatorMenu() = default; + void OscillatorMenu::paint(juce::Graphics &g) { bg->draw(g, 1.0); @@ -374,10 +376,11 @@ void OscillatorMenu::mouseDown(const juce::MouseEvent &event) if (!juce::PopupMenu::dismissAllActiveMenus()) { - menu.showMenuAsync(juce::PopupMenu::Options(), [this](int) { - isHovered = false; - repaint(); - }); + menu.showMenuAsync(juce::PopupMenu::Options(), + Surge::GUI::makeAsyncCallback(this, [](auto *that, int) { + that->isHovered = false; + that->repaint(); + })); } } @@ -486,10 +489,11 @@ void FxMenu::mouseDown(const juce::MouseEvent &event) if (!juce::PopupMenu::dismissAllActiveMenus()) { - menu.showMenuAsync(juce::PopupMenu::Options(), [this](int i) { - isHovered = false; - repaint(); - }); + menu.showMenuAsync(juce::PopupMenu::Options(), + Surge::GUI::makeAsyncCallback(this, [](auto *that, int) { + that->isHovered = false; + that->repaint(); + })); } } diff --git a/src/surge-xt/gui/widgets/XMLConfiguredMenus.h b/src/surge-xt/gui/widgets/XMLConfiguredMenus.h index 1e7365c9288..ddccbaf7e6c 100644 --- a/src/surge-xt/gui/widgets/XMLConfiguredMenus.h +++ b/src/surge-xt/gui/widgets/XMLConfiguredMenus.h @@ -118,6 +118,7 @@ struct OscillatorMenu : public juce::Component, public WidgetBaseMixin { OscillatorMenu(); + ~OscillatorMenu(); void loadSnapshot(int type, TiXmlElement *e, int idx) override; Surge::GUI::IComponentTagValue *asControlValueInterface() override { return this; };