Files
serumalt/Source/PluginEditor.h
T
biggy a50666355c feat(gui): add knob value popup, tooltips, tab cycling, and layout system
Add a floating value label near the cursor while dragging a knob, giving
immediate feedback without altering slider behaviour. Inherit
SettableTooltipClient on ToggleButton so setTooltip works consistently
with knobs and combos.

Introduce a shared layout constants namespace in PluginEditor so every
panel, row and control position derives from one spacing system. Add
tooltips to all knobs, combos, toggles, and buttons. Add Tab/Shift+Tab
tab cycling via keyPressed, with a TooltipWindow for hover hints.
2026-09-09 13:24:40 +02:00

133 lines
4.6 KiB
C++

#pragma once
#include <JuceHeader.h>
#include "PluginProcessor.h"
#include "GUI/SerumLookAndFeel.h"
#include "GUI/Knob.h"
#include "GUI/Slider.h"
#include "GUI/ToggleButton.h"
#include "GUI/Display.h"
#include "GUI/Panel.h"
#include "GUI/WaveformDisplay.h"
#include "GUI/FilterDisplay.h"
#include "GUI/EnvelopeDisplay.h"
#include "GUI/LFODisplay.h"
namespace serum
{
// ===========================================================================
// SerumAlt editor: dark vector GUI with a tabbed layout, real-time
// visualisations, RAVE, macro controls and preset-scale (75%..200%) scaling.
// ===========================================================================
class PluginEditor : public juce::AudioProcessorEditor,
public juce::Timer
{
public:
explicit PluginEditor (SerumAltAudioProcessor& p);
~PluginEditor() override;
void paint (juce::Graphics&) override;
void resized() override;
void timerCallback() override;
bool keyPressed (const juce::KeyPress& key) override;
void setTab (int index);
private:
SerumAltAudioProcessor& processor;
SerumLookAndFeel laf;
static constexpr int kBaseW = 1120;
static constexpr int kBaseH = 740;
juce::Component root;
// --- tooltips ---
juce::TooltipWindow tooltipWindow;
// --- top bar ---
std::unique_ptr<juce::Drawable> logo;
juce::ComboBox presetCombo;
juce::ComboBox scaleCombo;
ToggleButton raveButton;
Knob masterKnob;
Display masterDisplay;
// --- tabs ---
juce::TextButton tabOsc, tabFilter, tabMod, tabFx, tabMacro;
juce::Component oscView, filterView, modView, fxView, macroView;
int currentTab = 0;
// --- OSC ---
Panel oscAPanel { "Oscillator A" }, oscBPanel { "Oscillator B" };
Panel subPanel { "Sub" }, noisePanel { "Noise" };
WaveformDisplay oscAWave, oscBWave;
std::vector<juce::Component*> oscAComponents, oscBComponents;
// --- FILTER ---
Panel filter1Panel { "Filter 1" }, filter2Panel { "Filter 2" }, routingPanel { "Routing" };
FilterDisplay filter1Display, filter2Display;
// --- MOD ---
std::array<Panel, kNumEnvelopes> envPanels { { Panel ("Env 1 (Amp)"), Panel ("Env 2 (Filter)"),
Panel ("Env 3"), Panel ("Env 4") } };
std::array<EnvelopeDisplay, kNumEnvelopes> envDisplays;
std::array<Panel, kNumLfos> lfoPanels { { Panel ("LFO 1"), Panel ("LFO 2"), Panel ("LFO 3"), Panel ("LFO 4") } };
std::array<LFODisplay, kNumLfos> lfoDisplays;
Panel matrixPanel { "Modulation Matrix" };
juce::ComboBox modSourceCombo, modTargetCombo;
Knob modDepthKnob { "Depth" };
ToggleButton modBipolarToggle;
juce::TextButton modAddButton, modRemoveButton, modClearButton;
juce::TextEditor modList;
// --- FX ---
std::array<Panel, kNumFxSlots> fxPanels;
std::array<juce::ComboBox*, kNumFxSlots> fxTypeCombos;
std::array<std::vector<Knob*>, kNumFxSlots> fxKnobs;
std::array<juce::TextButton*, kNumFxSlots> fxUp, fxDown;
// --- MACRO ---
std::array<Panel, kNumMacros> macroPanels;
std::array<Knob*, kNumMacros> macroKnobs;
Panel macroAssignPanel { "Macro Assignments" };
juce::ComboBox macroAssignTarget;
juce::ComboBox macroAssignIndex;
Knob macroDepthKnob { "Depth" };
juce::TextButton macroAssignButton, macroClearButton;
juce::TextEditor macroList;
// --- attachments ---
std::vector<std::unique_ptr<juce::AudioProcessorValueTreeState::SliderAttachment>> sliderAttachments;
std::vector<std::unique_ptr<juce::AudioProcessorValueTreeState::ComboBoxAttachment>> comboAttachments;
int currentScaleIndex = -1;
// --- helpers ---
Knob* makeKnob (juce::Component* parent, const juce::String& name, const juce::String& paramId,
std::function<juce::String (float)> fmt = {}, const juce::String& tooltip = {});
juce::ComboBox* makeCombo (juce::Component* parent, const juce::String& paramId, const juce::StringArray& items,
const juce::String& tooltip = {});
ToggleButton* makeToggle (juce::Component* parent, const juce::String& label, const juce::String& paramId,
const juce::String& tooltip = {});
void cycleTab (int delta);
void buildTopBar();
void buildOscTab();
void buildFilterTab();
void buildModTab();
void buildFxTab();
void buildMacroTab();
void swapFxSlots (int a, int b);
void applyUiScale();
void updateVisuals();
void updateModList();
void updateMacroList();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginEditor)
};
} // namespace serum