#pragma once #include #include "ui/SequencerMatrix.h" class MonostepAudioProcessor; class EditorLookAndFeel final : public juce::LookAndFeel_V4 { public: EditorLookAndFeel(); void drawRotarySlider (juce::Graphics&, int x, int y, int w, int h, float sliderPos, float rotaryStartAngle, float rotaryEndAngle, juce::Slider&) override; void drawToggleButton (juce::Graphics&, juce::ToggleButton&, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override; void drawButtonBackground (juce::Graphics&, juce::Button&, const juce::Colour& backgroundColour, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override; void drawButtonText (juce::Graphics&, juce::TextButton&, bool shouldDrawButtonAsHighlighted, bool shouldDrawButtonAsDown) override; void drawComboBox (juce::Graphics&, int width, int height, bool isMouseButtonDown, int buttonX, int buttonY, int buttonW, int buttonH, juce::ComboBox&) override; juce::Font getComboBoxFont (juce::ComboBox&) override; void drawPopupMenuBackground (juce::Graphics&, int width, int height) override; void drawPopupMenuItem (juce::Graphics&, const juce::Rectangle& area, bool isSeparator, bool isActive, bool isHighlighted, bool isTicked, bool hasSubMenu, const juce::String& text, const juce::String& shortcutKeyText, const juce::Drawable* icon, const juce::Colour* textColour) override; juce::Font getPopupMenuFont() override; }; class Knob final : public juce::Component { public: explicit Knob (const juce::String& title); juce::Slider& getSlider() { return slider; } void attach (juce::AudioProcessorValueTreeState& apvts, const juce::String& paramId) { attachment = std::make_unique (apvts, paramId, slider); } void setFormat (std::function formatFn) { format = std::move (formatFn); updateValueLabel(); } void setOnValueChanged (std::function valueChangedFn) { customOnValueChange = std::move (valueChangedFn); } void setDragSensitivity (int pixels) { slider.setMouseDragSensitivity (pixels); } void resized() override; private: void updateValueLabel(); juce::Slider slider; juce::Label titleLabel; juce::Label valueLabel; std::unique_ptr attachment; std::function format; std::function customOnValueChange; }; class ChoiceBar final : public juce::Component, public juce::AudioProcessorValueTreeState::Listener { public: ChoiceBar (juce::AudioProcessorValueTreeState& apvts, const juce::String& paramId, const juce::StringArray& choices); ChoiceBar (const juce::StringArray& choices, std::function onSelected); ~ChoiceBar() override; void parameterChanged (const juce::String&, float) override; void setManualHandler (std::function handler) { manualHandler = std::move (handler); } void setSelectedIndex (int index) { index = juce::jlimit (0, juce::jmax (0, buttons.size() - 1), index); for (int i = 0; i < buttons.size(); ++i) buttons[i]->setToggleState (i == index, juce::dontSendNotification); } void resized() override; private: void refreshFromParam(); void setIndex (int index); juce::AudioProcessorValueTreeState* apvts = nullptr; juce::String paramId; std::function manualHandler; juce::OwnedArray buttons; }; class StepPanel final : public juce::Component { public: explicit StepPanel (MonostepAudioProcessor& processor); void setSelectedStep (int stepIdx); void refresh(); std::function onStepSelected; void resized() override; private: void clearPattern(); MonostepAudioProcessor& processor; int selectedStep = 0; bool updating = false; juce::Label titleLabel; juce::Label noteLabel; juce::Label gateLabel; Knob fineKnob; juce::TextButton prevButton; juce::TextButton nextButton; juce::TextButton clearButton; juce::TextButton shiftLeftButton; juce::TextButton shiftRightButton; juce::Label toolsCaption; juce::ComboBox presetCombo; juce::TextButton randomizeButton; juce::Label randomizeCaption; enum RandomGroup { RandomPattern, RandomOsc, RandomFilter, RandomEnv, RandomSeq, RandomFx, RandomGroupCount }; juce::ToggleButton randomizeToggles[RandomGroupCount]; juce::ToggleButton retrigToggle; std::unique_ptr retrigAttachment; juce::TextButton resetFineButton; }; class MonostepAudioProcessorEditor final : public juce::AudioProcessorEditor, public juce::Timer { public: explicit MonostepAudioProcessorEditor (MonostepAudioProcessor& processor); ~MonostepAudioProcessorEditor() override; void paint (juce::Graphics&) override; void resized() override; void timerCallback() override; private: void paintContent (juce::Graphics&); class ContentComponent final : public juce::Component { public: explicit ContentComponent (MonostepAudioProcessorEditor& owner) : ownerRef (owner) {} void paint (juce::Graphics& g) override { ownerRef.paintContent (g); } private: MonostepAudioProcessorEditor& ownerRef; }; MonostepAudioProcessor& processorRef; ContentComponent content; static constexpr int baseWidth = 1280; static constexpr int baseHeight = 780; float zoomFactor = 1.0f; void setZoomFactor (float newZoom); std::unique_ptr lnf; std::vector> attachments; Knob lengthKnob; Knob swingKnob; Knob rootKnob; Knob gateKnob; Knob masterKnob; Knob coarseKnob; Knob coarseKnob2; Knob detuneKnob; Knob mixKnob; Knob fineKnob1; Knob fineKnob2; Knob cutoffKnob; Knob resKnob; Knob glideKnob; Knob attackKnob; Knob decayKnob; Knob sustainKnob; Knob releaseKnob; Knob fAttackKnob; Knob fDecayKnob; Knob fSustainKnob; Knob fReleaseKnob; Knob fAmountKnob; Knob driveKnob; Knob ringKnob; Knob delayTimeKnob; Knob delayStrengthKnob; Knob reverbRoomKnob; Knob reverbStrengthKnob; Knob reverbDiffusionKnob; juce::ToggleButton delaySyncToggle; std::unique_ptr delaySyncAttachment; Knob accentKnob; ChoiceBar rateBar; ChoiceBar octaveBar; ChoiceBar zoomBar; juce::ComboBox wave1Box; juce::ComboBox wave2Box; juce::ComboBox filterTypeBox; std::unique_ptr wave1Attachment; std::unique_ptr wave2Attachment; std::unique_ptr filterTypeAttachment; SequencerMatrix matrix; StepPanel stepPanel; int lastPlayStep = -1; void refreshEditor(); };