#pragma once #include #include "PluginProcessor.h" #include "PresetManager.h" #include "GUI/AmbivalenceUI.h" #include "GUI/DecayCurveViz.h" // ----------------------------------------------------------------------------- // EditorContent // ----------------------------------------------------------------------------- // Holds every UI element of the editor and is the only component that gets a // zoom transform applied. The top-level AudioProcessorEditor stays // untransformed and is sized to exactly fit the transformed content, so the // host always sees a window that matches what the plugin draws (no double // scaling, no clipped / blank margins at any zoom level). // ----------------------------------------------------------------------------- class EditorContent : public juce::Component { public: explicit EditorContent(FDNReverbAudioProcessor& p, AmbivalenceLookAndFeel& laf); void paint(juce::Graphics&) override; void resized() override; void setProMode(bool pro); // --- zoom --- static constexpr float kDefaultZoom = 1.5f; float currentZoom{ kDefaultZoom }; float uiScale{ 1.0f }; // derived from getWidth()/W, applied to every child bounds std::function onZoomChange; AmbivalenceLookAndFeel* lookAndFeel{ nullptr }; // --- common --- DecayCurveViz decayCurveViz; VUMeter vuIn, vuOut; juce::Label titleLabel; juce::Label labelMetricsTitle; juce::Label labelD50Caption, labelD50Value; juce::Label labelC50Caption, labelC50Value; juce::Label labelC80Caption, labelC80Value; juce::Label labelEDTCaption, labelEDTValue; juce::Label statusLabel; juce::TextButton zoomButton; juce::TextButton proModeButton; juce::TextButton erSoloButton; std::unique_ptr proModeAttachment; std::unique_ptr erSoloAttachment; bool proMode{ false }; // --- Normal Mode --- ArcKnob kPreDelay, kRoomSize, kDecay; ArcKnob kHFDamp, kLFAbsorb; ArcKnob kDiffusion, kModAmt, kModRate; ArcKnob kStereoW; ArcKnob kERLevel, kSaturation; ArcKnob kWet, kDry; ArcKnob kDuckAmt, kDuckThr, kDuckAtt, kDuckRel; ArcKnob kLoCutNorm, kHiCutNorm; // --- ProMode panel --- std::array kRTBands; juce::Label satTypeLabel; juce::ComboBox satTypeCombo; std::unique_ptr satTypeAttachment; ArcKnob kTiltLow, kTiltMid, kTiltHigh; ArcKnob kLoCutPro, kHiCutPro; // --- preset UI --- juce::TextButton presetPrevButton; juce::ComboBox presetCombo; juce::TextButton presetNextButton; juce::TextButton presetSaveButton; juce::TextButton presetLoadButton; juce::TextButton presetDeleteButton; // --- layout constants --- static constexpr int W = 900; static constexpr int H = 450; static constexpr int PAD = 8; static constexpr int KNOB_W = 64; static constexpr int KNOB_H = 72; static constexpr int KNOB_LBL_H = 14; static constexpr int UNIT_H = 88; static constexpr int ROW1_GAP = 18; static constexpr int STATUS_H = 16; // Fixed X of the preset panel // DUCKING end (616) + gap(16) = 632 static constexpr int PRESET_PANEL_X = 632; void updatePanelVisibility(); void showZoomMenu(); void setZoomLevel(float scale); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(EditorContent) }; // ----------------------------------------------------------------------------- // Editor // ----------------------------------------------------------------------------- class FDNReverbEditor : public juce::AudioProcessorEditor, private juce::Timer { public: explicit FDNReverbEditor(FDNReverbAudioProcessor&); ~FDNReverbEditor() override; void paint(juce::Graphics&) override; void resized() override; private: void timerCallback() override; // --- Preset UI helpers --- void refreshPresetCombo(); void savePresetWithDialog(); void deleteCurrentPreset(); FDNReverbAudioProcessor& audioProcessor; AmbivalenceLookAndFeel laf; std::unique_ptr content; std::unique_ptr presetManager; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(FDNReverbEditor) };