Initial commit
This commit is contained in:
139
PluginEditor.h
Normal file
139
PluginEditor.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
#include <JuceHeader.h>
|
||||
class TwoOscAudioProcessor;
|
||||
|
||||
// ===== Retro 70s LookAndFeel for rotary knobs =====
|
||||
class RetroLookAndFeel : public juce::LookAndFeel_V4
|
||||
{
|
||||
public:
|
||||
RetroLookAndFeel()
|
||||
{
|
||||
setColour (juce::Slider::textBoxTextColourId, juce::Colours::white.withAlpha (0.9f));
|
||||
setColour (juce::Slider::textBoxOutlineColourId, juce::Colours::transparentBlack);
|
||||
}
|
||||
|
||||
void drawRotarySlider (juce::Graphics& g, int x, int y, int w, int h,
|
||||
float sliderPosProportional,
|
||||
float /*rotaryStartAngle*/, float /*rotaryEndAngle*/,
|
||||
juce::Slider& /*slider*/) override
|
||||
{
|
||||
const float size = (float) juce::jmin (w, h);
|
||||
const float r = size * 0.5f;
|
||||
const juce::Point<float> c { x + w * 0.5f, y + h * 0.5f };
|
||||
const float bezelR = r * 0.98f;
|
||||
const float faceR = r * 0.78f;
|
||||
const float capR = r * 0.46f;
|
||||
|
||||
// SW -> SE 270° clockwise sweep (min at bottom-left)
|
||||
const float start = juce::MathConstants<float>::pi * 0.75f; // 135°
|
||||
const float sweep = juce::MathConstants<float>::pi * 1.5f; // 270°
|
||||
const float ang = start + sliderPosProportional * sweep;
|
||||
|
||||
g.setColour (juce::Colour::fromRGB (12,12,12));
|
||||
g.fillEllipse (c.x - bezelR, c.y - bezelR, bezelR*2, bezelR*2);
|
||||
g.setColour (juce::Colours::white.withAlpha (0.06f));
|
||||
g.drawEllipse (c.x - bezelR, c.y - bezelR, bezelR*2, bezelR*2, 1.2f);
|
||||
|
||||
juce::ColourGradient faceGrad (juce::Colour::fromRGB (34,34,34), c.x, c.y - faceR,
|
||||
juce::Colour::fromRGB (22,22,22), c.x, c.y + faceR, false);
|
||||
g.setGradientFill (faceGrad);
|
||||
g.fillEllipse (c.x - faceR, c.y - faceR, faceR*2, faceR*2);
|
||||
|
||||
g.setColour (juce::Colours::white.withAlpha (0.25f));
|
||||
const int ticks = 9;
|
||||
for (int i = 0; i < ticks; ++i)
|
||||
{
|
||||
const float t = (float) i / (ticks - 1);
|
||||
const float aa = start + t * sweep;
|
||||
const float r1 = faceR * 0.92f, r2 = faceR * 1.04f;
|
||||
g.drawLine (c.x + r1*std::cos(aa), c.y + r1*std::sin(aa),
|
||||
c.x + r2*std::cos(aa), c.y + r2*std::sin(aa),
|
||||
(i % 2 == 0) ? 1.5f : 1.0f);
|
||||
}
|
||||
|
||||
juce::ColourGradient capGrad (juce::Colour::fromRGB (210,210,210), c.x - capR*0.4f, c.y - capR*0.6f,
|
||||
juce::Colour::fromRGB (160,160,160), c.x + capR*0.6f, c.y + capR*0.6f, true);
|
||||
g.setGradientFill (capGrad);
|
||||
g.fillEllipse (c.x - capR, c.y - capR, capR*2, capR*2);
|
||||
|
||||
g.setColour (juce::Colours::white.withAlpha (0.95f));
|
||||
juce::Point<float> tip { c.x + faceR*0.9f * std::cos (ang), c.y + faceR*0.9f * std::sin (ang) };
|
||||
juce::Point<float> inner { c.x + (capR+2.0f) * std::cos (ang), c.y + (capR+2.0f) * std::sin (ang) };
|
||||
g.drawLine (inner.x, inner.y, tip.x, tip.y, juce::jlimit (1.2f, 2.0f, r * 0.06f));
|
||||
}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
||||
class TwoOscAudioProcessorEditor : public juce::AudioProcessorEditor
|
||||
{
|
||||
public:
|
||||
explicit TwoOscAudioProcessorEditor (TwoOscAudioProcessor&);
|
||||
~TwoOscAudioProcessorEditor() override;
|
||||
|
||||
void paint (juce::Graphics&) override;
|
||||
void resized() override;
|
||||
|
||||
private:
|
||||
TwoOscAudioProcessor& processor;
|
||||
|
||||
// Header
|
||||
juce::Label title;
|
||||
|
||||
// Preset header: display + button that opens flyout menu
|
||||
juce::Label presetDisplay; // shows "Category - Name"
|
||||
juce::TextButton browseBtn { "Browse…" };
|
||||
|
||||
// Controls
|
||||
juce::ComboBox oscA, oscB;
|
||||
juce::Slider mix, detune, cutoff, reso, envAmt;
|
||||
juce::Slider aA, dA, sA, rA, aF, dF, sF, rF;
|
||||
juce::Slider masterGain;
|
||||
|
||||
// NEW: LFO controls
|
||||
juce::Slider lfoRate, lfoDepth; // lfoDepth mapped to lfoToCut (octaves)
|
||||
|
||||
// Captions above knobs
|
||||
juce::Label lOscA, lOscB;
|
||||
juce::Label lMix, lDetune, lCutoff, lReso, lEnv;
|
||||
juce::Label lAA, lDA, lSA, lRA, lAF, lDF, lSF, lRF, lMaster;
|
||||
juce::Label lLfoRate, lLfoDepth;
|
||||
|
||||
using CA = juce::AudioProcessorValueTreeState::ComboBoxAttachment;
|
||||
using SA = juce::AudioProcessorValueTreeState::SliderAttachment;
|
||||
|
||||
std::unique_ptr<CA> aOscA, aOscB;
|
||||
std::unique_ptr<SA> aMix, aDetune, aCutoff, aReso, aEnv;
|
||||
std::unique_ptr<SA> aAA, aDA, aSA, aRA, aAF, aDF, aSF, aRF;
|
||||
std::unique_ptr<SA> aMaster;
|
||||
|
||||
// NEW: attachments for LFO
|
||||
std::unique_ptr<SA> aLfoRate, aLfoDepth;
|
||||
|
||||
RetroLookAndFeel retroLNF;
|
||||
|
||||
// Helpers
|
||||
void styleKnob (juce::Slider& s);
|
||||
void styleLabel (juce::Label& l);
|
||||
void addLabeled (juce::Component& c, juce::Label& label, const juce::String& text);
|
||||
void showPresetPopup();
|
||||
void updatePresetDisplay();
|
||||
|
||||
// Uniform sizing / spacing (smaller UI)
|
||||
static constexpr int knobSize = 60; // was 72
|
||||
static constexpr int headerH = 48; // was 56
|
||||
static constexpr int captionH = 16;
|
||||
static constexpr int gap = 10; // was 12
|
||||
|
||||
// Bounds of the framed "preset information screen" (drawn in paint)
|
||||
juce::Rectangle<int> presetBarBounds;
|
||||
|
||||
// Background group rectangles (drawn in paint, set in resized)
|
||||
juce::Rectangle<int> groupCutResBounds; // Cutoff + Reso
|
||||
juce::Rectangle<int> groupMixDetBounds; // Mix + Detune
|
||||
juce::Rectangle<int> groupAmpBounds; // Amp A/D/S/R
|
||||
juce::Rectangle<int> groupLfoBounds; // LFO Rate + Depth
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TwoOscAudioProcessorEditor)
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user