From 45d60826570352a3e4fc8dabf6e65551a23b31c2 Mon Sep 17 00:00:00 2001 From: Armin Date: Thu, 13 Aug 2026 14:55:33 +0200 Subject: [PATCH] Reorder filter dropdown: list LP 48dB below LP 24dB Keep the parameter choice indices stable (so saved projects, .cfl files and presets stay correct) and only reorder the displayed menu via explicit item IDs plus a new IndexedComboBoxAttachment, since the stock JUCE ComboBoxAttachment hard-maps choice index to menu position. --- Source/PluginEditor.cpp | 16 ++++++++++++-- Source/PluginEditor.h | 46 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/Source/PluginEditor.cpp b/Source/PluginEditor.cpp index 7aa4480..1725ab3 100644 --- a/Source/PluginEditor.cpp +++ b/Source/PluginEditor.cpp @@ -622,8 +622,20 @@ MainContentComponent::MainContentComponent(ChromaFlockProcessor& p) setupParam(phaseOffsetKnob, phaseOffsetAttach, "phaseOffset", "PHASE"); setupLabel(filterLabel, "FILTER"); - setupCB(filterTypeBox, filterTypeAttach, "filterType", {"LP 12dB", "LP 24dB", "Band Pass", "High Pass", "Notch", - "Band Pass 24", "High Pass 24", "Notch 24", "LP 48dB"}); + // Display order differs from the parameter's index order: LP 48dB is shown + // directly under LP 24dB. itemIds are (paramIndex + 1) so the underlying + // choice index (and therefore saved state / presets) stays meaningful. + setupCombo(filterTypeBox); + filterTypeBox.addItem("LP 12dB", 1); + filterTypeBox.addItem("LP 24dB", 2); + filterTypeBox.addItem("LP 48dB", 9); + filterTypeBox.addItem("Band Pass", 3); + filterTypeBox.addItem("High Pass", 4); + filterTypeBox.addItem("Notch", 5); + filterTypeBox.addItem("Band Pass 24", 6); + filterTypeBox.addItem("High Pass 24", 7); + filterTypeBox.addItem("Notch 24", 8); + filterTypeAttach = std::make_unique(processorRef.apvts, "filterType", filterTypeBox); setupParam(filterCutoffKnob, filterCutoffAttach, "filterCutoff", "CUTOFF"); setupParam(filterResKnob, filterResAttach, "filterRes", "RES"); setupParam(filterEnvAmtKnob, filterEnvAmtAttach, "filterEnvAmt", "ENV AMT"); diff --git a/Source/PluginEditor.h b/Source/PluginEditor.h index 33ca245..4620adc 100644 --- a/Source/PluginEditor.h +++ b/Source/PluginEditor.h @@ -214,9 +214,53 @@ private: using SliderAttachment = juce::AudioProcessorValueTreeState::SliderAttachment; using ComboBoxAttachment = juce::AudioProcessorValueTreeState::ComboBoxAttachment; + // Maps a 0-based parameter choice index to a ComboBox itemId (index + 1) + // so the dropdown can be displayed in an order that differs from the + // parameter's index order (e.g. LP 48dB listed under LP 24dB). This keeps + // stored parameter indices meaningful while only reordering the menu. + class IndexedComboBoxAttachment : public juce::AudioProcessorValueTreeState::Listener, + private juce::ComboBox::Listener { + public: + IndexedComboBoxAttachment (juce::AudioProcessorValueTreeState& stateToUse, + const juce::String& paramID, + juce::ComboBox& comboToUse) + : state (stateToUse), paramId (paramID), combo (comboToUse) { + combo.addListener (this); + state.addParameterListener (paramId, this); + auto* p = state.getParameter (paramId); + combo.setSelectedId (1 + juce::roundToInt (p->getValue() * (combo.getNumItems() - 1)), + juce::dontSendNotification); + } + + ~IndexedComboBoxAttachment() override { + combo.removeListener (this); + state.removeParameterListener (paramId, this); + } + + void parameterChanged (const juce::String& parameterID, float newValue) override { + if (parameterID == paramId) + combo.setSelectedId (1 + juce::roundToInt (newValue * (combo.getNumItems() - 1)), + juce::dontSendNotification); + } + + void comboBoxChanged (juce::ComboBox* cb) override { + if (cb != &combo) + return; + auto* p = state.getParameter (paramId); + int index = combo.getSelectedId() - 1; + p->setValueNotifyingHost (static_cast (index) / (combo.getNumItems() - 1)); + } + + private: + juce::AudioProcessorValueTreeState& state; + juce::String paramId; + juce::ComboBox& combo; + }; + std::unique_ptr osc1OctAttach, osc1SemiAttach, osc1FineAttach, osc1LevelAttach; std::unique_ptr osc2OctAttach, osc2SemiAttach, osc2FineAttach, osc2LevelAttach, phaseOffsetAttach; - std::unique_ptr osc1WaveAttach, osc2WaveAttach, filterTypeAttach; + std::unique_ptr osc1WaveAttach, osc2WaveAttach; + std::unique_ptr filterTypeAttach; std::unique_ptr octaveTransposeAttach, semitoneTransposeAttach; std::unique_ptr filterCutoffAttach, filterResAttach, filterEnvAmtAttach, keyTrackAttach; std::unique_ptr envAttackAttach, envDecayAttach, envSustainAttach, envReleaseAttach;