#pragma once #include "JuceHeader.h" // Visual styling for BEAMGRID: black UI with teal accents. A single HUE knob // rotates the hue of every saturated colour on the UI via a shared LookAndFeel. class BeamgridLookAndFeel : public juce::LookAndFeel_V4 { public: BeamgridLookAndFeel() { setColour (juce::Slider::rotarySliderFillColourId, tealBase); setColour (juce::Slider::rotarySliderOutlineColourId, juce::Colours::black.brighter (0.18f)); setColour (juce::Slider::textBoxTextColourId, juce::Colours::lightgrey); setColour (juce::Slider::textBoxOutlineColourId, juce::Colours::transparentBlack); setColour (juce::Label::textColourId, juce::Colours::lightgrey); } // Base palette (used at 12 o'clock / zero hue rotation). static const juce::Colour tealBase; static const juce::Colour peakBase; // Hue rotation in turns (-0.5 .. +0.5); 0 = original colours. float hueTurns = 0.0f; void setHueTurns (float turns) noexcept { hueTurns = turns; } juce::Colour transform (juce::Colour c) const noexcept { return c.withRotatedHue (hueTurns); } juce::Colour getTeal() const noexcept { return transform (tealBase); } juce::Colour getPeak() const noexcept { return transform (peakBase); } void drawRotarySlider (juce::Graphics& g, int x, int y, int w, int h, float pos, float startAngle, float endAngle, juce::Slider& slider) override { const auto bounds = juce::Rectangle (x, y, w, h).toFloat().reduced (6.0f); const auto centre = bounds.getCentre(); const auto radius = juce::jmin (bounds.getWidth(), bounds.getHeight()) * 0.5f; const float thickness = 5.0f; // Background track arc. juce::Path track; track.addArc (centre.x - radius, centre.y - radius, radius * 2.0f, radius * 2.0f, startAngle, endAngle, thickness); g.setColour (slider.findColour (juce::Slider::rotarySliderOutlineColourId)); g.strokePath (track, juce::PathStrokeType (thickness)); // Filled value arc (teal, hue-rotated). const float angle = startAngle + pos * (endAngle - startAngle); juce::Path value; value.addArc (centre.x - radius, centre.y - radius, radius * 2.0f, radius * 2.0f, startAngle, angle, thickness); g.setColour (getTeal()); g.strokePath (value, juce::PathStrokeType (thickness)); // Pointer line. juce::Path pointer; const float pointerLen = radius * 0.78f; pointer.addLineSegment (juce::Line (centre.x, centre.y, centre.x + std::sin (angle) * pointerLen, centre.y - std::cos (angle) * pointerLen), 2.0f); g.setColour (juce::Colours::white); g.strokePath (pointer, juce::PathStrokeType (2.5f)); } };