#include "ToggleButton.h" namespace serum { ToggleButton::ToggleButton (const juce::String& lbl) : label (lbl) { setRepaintsOnMouseActivity (true); } void ToggleButton::attach (juce::AudioProcessorValueTreeState& apvts, const juce::String& paramId) { attachment.reset(); if (auto* param = apvts.getParameter (paramId)) { attachment = std::make_unique (*param, [this] (float newValue) { setToggleState (newValue > 0.5f); }); attachment->sendInitialUpdate(); } } void ToggleButton::setToggleState (bool s) { if (state == s) return; state = s; repaint(); } void ToggleButton::paint (juce::Graphics& g) { const auto bounds = getLocalBounds().toFloat(); const float ledSize = juce::jmin (bounds.getHeight() - 16.0f, 16.0f); const juce::Rectangle led ((bounds.getWidth() - ledSize) * 0.5f, 4.0f, ledSize, ledSize); const bool live = isEnabled(); const bool hovered = live && isMouseOverOrDragging(); if (state) { // Hover brightens the halo, disabled dims it, so the three states are // distinguishable without relying on colour alone. const float halo = live ? (hovered ? 0.55f : 0.35f) : 0.15f; g.setColour (onColour.withAlpha (halo)); g.fillEllipse (led.expanded (6.0f)); g.setColour (live ? onColour : onColour.withAlpha (0.4f)); } else { g.setColour (hovered ? theme::textDim : theme::outline); } g.fillEllipse (led); g.setColour (state ? juce::Colours::black : theme::textDim); g.drawEllipse (led, live ? (hovered ? 1.6f : 1.0f) : 0.8f); const auto labelColour = ! live ? theme::outline : (state ? theme::text : (hovered ? theme::text : theme::textDim)); g.setColour (labelColour); g.setFont (juce::Font (11.0f)); g.drawText (label, 0, (int) (led.getBottom() + 2), getWidth(), 14, juce::Justification::centred, false); } void ToggleButton::mouseDown (const juce::MouseEvent&) { const bool newState = ! state; if (onClick) { onClick (newState); } else if (attachment != nullptr) { attachment->setValueAsCompleteGesture (newState ? 1.0f : 0.0f); } setToggleState (newState); } } // namespace serum