#include "Knob.h" Knob::Knob (const juce::String& title, juce::AudioProcessorValueTreeState& apvts, const juce::String& paramID, float defaultValue, std::function formatFn, const juce::String& tooltip) : format (std::move (formatFn)) { nameLabel.setText (title, juce::dontSendNotification); nameLabel.setJustificationType (juce::Justification::centred); nameLabel.setFont (juce::Font (juce::FontOptions (11.0f, juce::Font::bold))); nameLabel.setColour (juce::Label::textColourId, juce::Colour (0xFFB8CCCC)); nameLabel.setInterceptsMouseClicks (false, false); addAndMakeVisible (nameLabel); valueLabel.setJustificationType (juce::Justification::centred); valueLabel.setFont (juce::Font (juce::FontOptions (11.0f, juce::Font::bold))); valueLabel.setColour (juce::Label::textColourId, juce::Colour (0xFF3CE0C8)); valueLabel.setInterceptsMouseClicks (false, false); addAndMakeVisible (valueLabel); slider.setSliderStyle (juce::Slider::RotaryHorizontalVerticalDrag); slider.setTextBoxStyle (juce::Slider::NoTextBox, true, 0, 0); slider.setDoubleClickReturnValue (true, defaultValue); slider.setWantsKeyboardFocus (true); slider.setScrollWheelEnabled (true); slider.setTooltip (tooltip); slider.onValueChange = [this] { updateValueLabel(); }; addAndMakeVisible (slider); attachment = std::make_unique (apvts, paramID, slider); updateValueLabel(); } void Knob::setScaleFactor (float scale) { scaleFactor = scale; resized(); } void Knob::updateValueLabel() { valueLabel.setText (format (slider.getValue()), juce::dontSendNotification); } void Knob::paint (juce::Graphics& g) { auto b = slider.getBounds().toFloat(); auto shadow = b.translated (0.0f, b.getHeight() * 0.05f).expanded (b.getWidth() * 0.05f); auto shadowCentre = shadow.getCentre().withY (shadow.getCentre().getY() + b.getHeight() * 0.4f); auto grad = juce::ColourGradient (juce::Colour (0x60000000), shadowCentre, juce::Colour (0x00000000), shadowCentre.translated (shadow.getWidth() * 0.7f, 0.0f), true); grad.addColour (0.55f, juce::Colour (0x20000000)); g.setGradientFill (grad); g.fillEllipse (shadow); } void Knob::resized() { auto bounds = getLocalBounds(); const float s = scaleFactor; const int nameH = juce::roundToInt (18.0f * s); const int valueH = juce::roundToInt (16.0f * s); const int maxKnobSize = juce::roundToInt (84.0f * s); bounds.removeFromTop (juce::roundToInt (15.0f * s)); auto nameArea = bounds.removeFromTop (nameH); bounds.removeFromBottom (juce::roundToInt (10.0f * s)); auto valueArea = bounds.removeFromBottom (valueH); nameLabel.setBounds (nameArea); valueLabel.setBounds (valueArea); nameLabel.setFont (juce::Font (juce::FontOptions (juce::roundToInt (11.0f * s), juce::Font::bold))); valueLabel.setFont (juce::Font (juce::FontOptions (juce::roundToInt (11.0f * s), juce::Font::bold))); const int knobSize = jmin (bounds.getWidth(), bounds.getHeight(), maxKnobSize); slider.setBounds (bounds.getCentreX() - knobSize / 2, bounds.getCentreY() - knobSize / 2, knobSize, knobSize); }