mirror of
https://codeberg.org/armin/saftpumpe.git
synced 2026-09-01 04:10:46 +02:00
159 lines
6.3 KiB
C++
159 lines
6.3 KiB
C++
#pragma once
|
|
#include "PluginProcessor.h"
|
|
#include <juce_audio_processors/juce_audio_processors.h>
|
|
|
|
class SaftpumpeEditor : public juce::AudioProcessorEditor,
|
|
public juce::Timer,
|
|
public juce::ComboBox::Listener {
|
|
public:
|
|
SaftpumpeEditor(SaftpumpeProcessor&);
|
|
~SaftpumpeEditor() override;
|
|
|
|
void paint(juce::Graphics&) override;
|
|
void resized() override;
|
|
void timerCallback() override;
|
|
void comboBoxChanged(juce::ComboBox* box) override;
|
|
void mouseUp(const juce::MouseEvent& event) override;
|
|
|
|
private:
|
|
SaftpumpeProcessor& processorRef;
|
|
|
|
float uiScale = 1.0f;
|
|
|
|
// Dark industrial palette
|
|
juce::Colour bezelColour{0xff0a0a0c};
|
|
juce::Colour faceplateTop{0xff222226};
|
|
juce::Colour faceplateBot{0xff161618};
|
|
juce::Colour knobLight{0xff72727a};
|
|
juce::Colour knobDark{0xff3a3a40};
|
|
juce::Colour grooveDark{0xff111114};
|
|
juce::Colour greenLed{0xff00e676};
|
|
juce::Colour redLed{0xffe63333};
|
|
juce::Colour amberLed{0xffe6a600};
|
|
juce::Colour textColour{0xffb0b0b6};
|
|
juce::Colour textDim{0xff6a6a70};
|
|
juce::Colour textBright{0xffe0e0e4};
|
|
juce::Colour accentLine{0xff00e676};
|
|
juce::Colour lcdBg{0xff080c08};
|
|
juce::Colour lcdText{0xff00cc66};
|
|
|
|
juce::Slider thresholdSlider, ratioSlider, attackSlider, releaseSlider;
|
|
juce::Slider kneeSlider, makeupSlider, mixSlider, autoReleaseSlider;
|
|
|
|
juce::Label thresholdLabel, ratioLabel, attackLabel, releaseLabel;
|
|
juce::Label kneeLabel, makeupLabel, mixLabel, autoReleaseLabel;
|
|
|
|
// LCD value displays
|
|
juce::Label thresholdLCD, ratioLCD, attackLCD, releaseLCD;
|
|
juce::Label kneeLCD, makeupLCD, mixLCD, autoReleaseLCD;
|
|
|
|
juce::ComboBox zoomBox;
|
|
juce::Label zoomLabel;
|
|
juce::ComboBox presetBox;
|
|
juce::Label presetLabel;
|
|
|
|
juce::ToggleButton bypassButton;
|
|
juce::Label bypassLabel;
|
|
|
|
using SliderAttachment = juce::AudioProcessorValueTreeState::SliderAttachment;
|
|
using ButtonAttachment = juce::AudioProcessorValueTreeState::ButtonAttachment;
|
|
|
|
std::unique_ptr<SliderAttachment> thresholdAttachment, ratioAttachment, attackAttachment;
|
|
std::unique_ptr<SliderAttachment> releaseAttachment, kneeAttachment, makeupAttachment;
|
|
std::unique_ptr<SliderAttachment> mixAttachment, autoReleaseAttachment;
|
|
std::unique_ptr<ButtonAttachment> bypassAttachment;
|
|
|
|
juce::Rectangle<float> meterArea;
|
|
juce::Rectangle<float> scopeArea;
|
|
juce::Rectangle<float> zoomArea;
|
|
juce::Rectangle<float> rowBounds[2];
|
|
juce::Rectangle<float> knobBounds[8];
|
|
juce::Point<float> knobCentre[8];
|
|
float knobRadius = 0.0f;
|
|
|
|
struct PeakHold {
|
|
float peak = 0.0f;
|
|
double peakTime = 0.0;
|
|
static constexpr double holdMs = 1000.0;
|
|
} grPeak, inPeak, outPeak;
|
|
|
|
void computeLayout();
|
|
void drawKnob(juce::Graphics& g, juce::Rectangle<float> bounds, float normalizedValue,
|
|
float arcFillFrac);
|
|
void drawLCD(juce::Graphics& g, juce::Rectangle<float> bounds, const juce::String& text);
|
|
void drawMeter(juce::Graphics& g, juce::Rectangle<float> bounds,
|
|
float level, float minDb, float maxDb, bool isGainReduction);
|
|
void drawPeakHold(juce::Graphics& g, juce::Rectangle<float> bounds,
|
|
float peakNorm, bool fromTop = false);
|
|
void drawScope(juce::Graphics& g, juce::Rectangle<float> bounds);
|
|
void drawSpectrum(juce::Graphics& g, juce::Rectangle<float> bounds);
|
|
void drawScrew(juce::Graphics& g, float cx, float cy, float radius);
|
|
|
|
static constexpr float startAngle = juce::MathConstants<float>::pi * 0.75f;
|
|
static constexpr float endAngle = juce::MathConstants<float>::pi * 2.25f;
|
|
|
|
juce::String formatValue(int idx, float val);
|
|
|
|
struct Preset {
|
|
const char* name;
|
|
float threshold, ratio, attack, release, knee, makeup, mix, autoRelease;
|
|
};
|
|
static const std::vector<Preset>& getPresets();
|
|
void applyPreset(int index);
|
|
|
|
juce::Rectangle<float> presetArea;
|
|
juce::Rectangle<float> bypassArea;
|
|
|
|
struct NoDotLookAndFeel : juce::LookAndFeel_V4 {
|
|
void drawRotarySlider(juce::Graphics&, int, int, int, int,
|
|
float, float, float, juce::Slider&) override {}
|
|
} lnf;
|
|
|
|
struct ToggleSwitchLNF : juce::LookAndFeel_V4 {
|
|
void drawToggleButton(juce::Graphics& g, juce::ToggleButton& btn,
|
|
bool hover, bool /*isDown*/) override {
|
|
auto bounds = btn.getLocalBounds().toFloat();
|
|
float s = bounds.getHeight() / 16.0f;
|
|
float w = bounds.getWidth();
|
|
float h = bounds.getHeight();
|
|
float cornerR = h * 0.3f;
|
|
|
|
// Groove
|
|
g.setColour(juce::Colour(0xff111114));
|
|
g.fillRoundedRectangle(bounds, cornerR);
|
|
g.setColour(juce::Colours::black.withAlpha(0.5f));
|
|
g.drawRoundedRectangle(bounds.expanded(0.5f), cornerR, 1.0f);
|
|
|
|
// Slider handle
|
|
bool on = btn.getToggleState();
|
|
float handleW = w * 0.42f;
|
|
float handleH = h * 0.72f;
|
|
float handleX = on ? (bounds.getRight() - handleW - 3.0f * s) : (bounds.getX() + 3.0f * s);
|
|
float handleY = bounds.getY() + (h - handleH) / 2.0f;
|
|
auto handleBounds = juce::Rectangle<float>(handleX, handleY, handleW, handleH);
|
|
|
|
// Handle shadow
|
|
g.setColour(juce::Colours::black.withAlpha(0.4f));
|
|
g.fillRoundedRectangle(handleBounds.translated(0, 1.0f), cornerR * 0.6f);
|
|
|
|
// Handle body
|
|
juce::Colour handleCol = on ? juce::Colour(0xff00e676) : juce::Colour(0xff4a4a50);
|
|
if (hover) handleCol = handleCol.brighter(0.15f);
|
|
g.setColour(handleCol);
|
|
g.fillRoundedRectangle(handleBounds, cornerR * 0.6f);
|
|
|
|
// Handle highlight
|
|
g.setColour(juce::Colours::white.withAlpha(on ? 0.2f : 0.08f));
|
|
g.fillRoundedRectangle(handleBounds.withHeight(handleH * 0.4f).translated(0, 1.0f), cornerR * 0.4f);
|
|
|
|
// LED glow when bypass active
|
|
if (on) {
|
|
g.setColour(juce::Colour(0xff00e676).withAlpha(0.15f));
|
|
g.fillEllipse(bounds.getCentreX() - w * 0.5f, bounds.getCentreY() - h * 0.6f,
|
|
w * 1.0f, h * 1.2f);
|
|
}
|
|
}
|
|
} toggleLnf;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(SaftpumpeEditor)
|
|
};
|