mirror of
https://codeberg.org/armin/justasample.git
synced 2026-09-01 04:10:48 +02:00
219 lines
7.8 KiB
C++
219 lines
7.8 KiB
C++
|
|
/*
|
||
|
|
==============================================================================
|
||
|
|
|
||
|
|
FXModule.cpp
|
||
|
|
Created: 28 Dec 2023 8:09:18pm
|
||
|
|
Author: binya
|
||
|
|
|
||
|
|
==============================================================================
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include <JuceHeader.h>
|
||
|
|
|
||
|
|
#include "FxModule.h"
|
||
|
|
|
||
|
|
FxModule::FxModule(FxDragTarget* fxChain, APVTS& apvts, const juce::String& fxName, PluginParameters::FxTypes effectType, const juce::String& fxEnabledParameter, Component& displayComponent) :
|
||
|
|
fxChain(fxChain), apvts(apvts), fxType(effectType), nameLabel("", fxName), mixControl(juce::Slider::RotaryVerticalDrag, juce::Slider::NoTextBox),
|
||
|
|
enablementAttachment(apvts, fxEnabledParameter, fxEnabled), display(displayComponent),
|
||
|
|
dragIcon(getOutlineFromSVG(BinaryData::IconDrag_svg))
|
||
|
|
{
|
||
|
|
nameLabel.setInterceptsMouseClicks(false, false);
|
||
|
|
addAndMakeVisible(&nameLabel);
|
||
|
|
|
||
|
|
fxEnabled.onStateChange = [&] {
|
||
|
|
display.setEnabled(fxEnabled.getToggleState());
|
||
|
|
for (auto rotary : rotaryReferences)
|
||
|
|
rotary->setEnabled(fxEnabled.getToggleState());
|
||
|
|
for (auto& label : labels)
|
||
|
|
label->setEnabled(fxEnabled.getToggleState());
|
||
|
|
};
|
||
|
|
fxEnabled.onStateChange(); // Set the initial state
|
||
|
|
fxEnabled.setHelpText("Toggle " + fxName.toLowerCase());
|
||
|
|
addAndMakeVisible(&fxEnabled);
|
||
|
|
|
||
|
|
addAndMakeVisible(&displayComponent);
|
||
|
|
|
||
|
|
setRepaintsOnMouseActivity(true);
|
||
|
|
addMouseListener(this, true);
|
||
|
|
setHelpText(fxName + " module");
|
||
|
|
|
||
|
|
setBufferedToImage(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
FxModule::FxModule(FxDragTarget* fxChain, APVTS& apvts, const juce::String& fxName, PluginParameters::FxTypes effectType, const juce::String& fxEnabledParameter, const juce::String& mixControlParameter, Component& displayComponent) :
|
||
|
|
FxModule(fxChain, apvts, fxName, effectType, fxEnabledParameter, displayComponent)
|
||
|
|
{
|
||
|
|
setupRotary(mixControl, false);
|
||
|
|
mixControl.getProperties().set(ComponentProps::ROTARY_UNIT, "%");
|
||
|
|
mixControlAttachment = std::make_unique<CustomRotaryAttachment>(apvts, mixControlParameter, mixControl);
|
||
|
|
}
|
||
|
|
|
||
|
|
juce::Slider* FxModule::addRotary(const juce::String& parameter, const juce::String& label, juce::Point<float> position, float width, const juce::String& unit)
|
||
|
|
{
|
||
|
|
auto rotary = std::make_unique<CustomRotary>();
|
||
|
|
CustomRotary* rawRotaryPtr = rotary.get();
|
||
|
|
|
||
|
|
auto attachment = std::make_unique<CustomRotaryAttachment>(apvts, parameter, *rawRotaryPtr);
|
||
|
|
attachments.push_back(std::move(attachment));
|
||
|
|
|
||
|
|
setupRotary(*rotary);
|
||
|
|
rotary->getProperties().set(ComponentProps::ROTARY_UNIT, unit);
|
||
|
|
addAndMakeVisible(rawRotaryPtr);
|
||
|
|
rotaries.push_back(std::move(rotary));
|
||
|
|
|
||
|
|
auto rotaryLabel = std::make_unique<juce::Label>("", label);
|
||
|
|
rotaryLabel->setInterceptsMouseClicks(false, false);
|
||
|
|
rotaryLabel->setJustificationType(juce::Justification::centredBottom);
|
||
|
|
rotaryLabel->setEnabled(fxEnabled.getToggleState());
|
||
|
|
addAndMakeVisible(rotaryLabel.get());
|
||
|
|
labels.push_back(std::move(rotaryLabel));
|
||
|
|
|
||
|
|
rotaryPositions.push_back(position);
|
||
|
|
rotaryWidths.push_back(width);
|
||
|
|
|
||
|
|
return rawRotaryPtr;
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::setupRotary(CustomRotary& rotary, bool useTextbox)
|
||
|
|
{
|
||
|
|
rotary.setSliderStyle(juce::Slider::RotaryVerticalDrag);
|
||
|
|
rotary.setMouseDragSensitivity(150);
|
||
|
|
if (useTextbox)
|
||
|
|
rotary.setTextBoxStyle(juce::Slider::TextBoxBelow, false, 0, 0);
|
||
|
|
rotary.addMouseListener(this, true); // We need this to pass drag events through the labels
|
||
|
|
rotary.setEnabled(fxEnabled.getToggleState());
|
||
|
|
addAndMakeVisible(rotary);
|
||
|
|
|
||
|
|
rotaryReferences.push_back(&rotary);
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::paint(juce::Graphics& g)
|
||
|
|
{
|
||
|
|
auto colors = getTheme();
|
||
|
|
auto bounds = getLocalBounds();
|
||
|
|
|
||
|
|
g.setColour(colors.background);
|
||
|
|
g.fillAll();
|
||
|
|
|
||
|
|
// Draw the drag icon
|
||
|
|
auto header = bounds.toFloat().removeFromTop(scalef(Layout::fxModuleHeader));
|
||
|
|
if (header.contains(getMouseXYRelative().toFloat()))
|
||
|
|
{
|
||
|
|
g.setColour(colors.darkerSlate);
|
||
|
|
header.removeFromTop(scalef(25.f));
|
||
|
|
auto iconBounds = header.removeFromTop(scalef(28.f));
|
||
|
|
g.fillPath(dragIcon, dragIcon.getTransformToScaleToFit(iconBounds.toFloat(), true));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::resized()
|
||
|
|
{
|
||
|
|
auto bounds = getLocalBounds().toFloat();
|
||
|
|
|
||
|
|
// Header
|
||
|
|
auto mixPad = scale(43.f) * Layout::rotaryPadding;
|
||
|
|
auto header = bounds.removeFromTop(scale(Layout::fxModuleHeader)).reduced(scale(21.f), scale(15.f) - mixPad);
|
||
|
|
|
||
|
|
fxEnabled.setBounds(header.removeFromRight(scale(43.f)).reduced(0.f, mixPad).toNearestInt());
|
||
|
|
header.removeFromRight(scale(20.f) - mixPad);
|
||
|
|
if (mixControlAttachment)
|
||
|
|
mixControl.setBounds(header.removeFromRight(scale(43.f) + 2 * mixPad).toNearestInt());
|
||
|
|
header.removeFromRight(scale(20.f) - mixPad);
|
||
|
|
nameLabel.setBounds(header.reduced(0.f, mixPad).toNearestInt());
|
||
|
|
nameLabel.setFont(getInriaSans().withHeight(scalef(41.4f)));
|
||
|
|
|
||
|
|
// Controls
|
||
|
|
display.setBounds(bounds.removeFromTop(scale(103.f)).toNearestInt());
|
||
|
|
|
||
|
|
bounds.reduce(0.f, scale(27.5f));
|
||
|
|
|
||
|
|
for (size_t i = 0; i < rotaries.size(); i++)
|
||
|
|
{
|
||
|
|
auto* rotary = rotaries[i].get();
|
||
|
|
auto [xPos, yPos] = rotaryPositions[i];
|
||
|
|
auto width = rotaryWidths[i];
|
||
|
|
auto padding = Layout::rotaryPadding * scale(width);
|
||
|
|
|
||
|
|
rotary->setBounds(juce::Rectangle<float>(bounds.getX() + scale(xPos), bounds.getY() + scale(yPos), scale(width), scale(width) * Layout::rotaryHeightRatio).expanded(padding).toNearestInt());
|
||
|
|
|
||
|
|
auto* label = labels[i].get();
|
||
|
|
auto labelBounds = juce::Rectangle<float>(bounds.getX() + scale(xPos), bounds.getY() + scale(yPos) - scale(width) * 0.45f, scale(width), scale(width * 0.356f)).expanded(width, 0.f);
|
||
|
|
label->setFont(getInriaSans().withHeight(scale(width) * 0.356f));
|
||
|
|
label->setBounds(labelBounds.toNearestInt());
|
||
|
|
}
|
||
|
|
|
||
|
|
if (mixControlAttachment)
|
||
|
|
mixControl.sendLookAndFeelChange();
|
||
|
|
for (auto& rotary : rotaries)
|
||
|
|
rotary->sendLookAndFeelChange();
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::enablementChanged()
|
||
|
|
{
|
||
|
|
setInterceptsMouseClicks(isEnabled(), isEnabled());
|
||
|
|
repaint();
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::mouseDown(const juce::MouseEvent& event)
|
||
|
|
{
|
||
|
|
// We pass the events on the rotary number labels through to the rotary
|
||
|
|
auto parent = event.originalComponent->getParentComponent();
|
||
|
|
for (auto rotary : rotaryReferences)
|
||
|
|
if (parent == rotary)
|
||
|
|
rotary->mouseDown(event.getEventRelativeTo(rotary));
|
||
|
|
}
|
||
|
|
|
||
|
|
//==============================================================================
|
||
|
|
void FxModule::mouseUp(const juce::MouseEvent& event)
|
||
|
|
{
|
||
|
|
if (dragging)
|
||
|
|
{
|
||
|
|
dragging = false;
|
||
|
|
fxChain->dragEnded();
|
||
|
|
repaint();
|
||
|
|
}
|
||
|
|
|
||
|
|
auto parent = event.originalComponent->getParentComponent();
|
||
|
|
for (auto rotary : rotaryReferences)
|
||
|
|
if (parent == rotary)
|
||
|
|
rotary->mouseUp(event.getEventRelativeTo(rotary));
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::mouseMove(const juce::MouseEvent& /*event*/)
|
||
|
|
{
|
||
|
|
auto header = getLocalBounds().toFloat().removeFromTop(scale(Layout::fxModuleHeader));
|
||
|
|
auto mouseInHeader = header.contains(getMouseXYRelative().toFloat());
|
||
|
|
|
||
|
|
if (mouseInHeader)
|
||
|
|
setMouseCursor(juce::MouseCursor::DraggingHandCursor);
|
||
|
|
else
|
||
|
|
setMouseCursor(juce::MouseCursor::NormalCursor);
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::mouseDrag(const juce::MouseEvent& event)
|
||
|
|
{
|
||
|
|
auto header = getLocalBounds().toFloat().removeFromTop(scale(Layout::fxModuleHeader));
|
||
|
|
auto mouseInHeader = header.contains(getMouseXYRelative().toFloat());
|
||
|
|
|
||
|
|
if (!dragging && event.eventComponent == this && mouseInHeader)
|
||
|
|
{
|
||
|
|
dragging = true;
|
||
|
|
fxChain->dragStarted(this, event);
|
||
|
|
repaint();
|
||
|
|
}
|
||
|
|
|
||
|
|
auto parent = event.originalComponent->getParentComponent();
|
||
|
|
for (auto rotary : rotaryReferences)
|
||
|
|
if (parent == rotary)
|
||
|
|
rotary->mouseDrag(event.getEventRelativeTo(rotary));
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::mouseEnter(const juce::MouseEvent&)
|
||
|
|
{
|
||
|
|
repaint();
|
||
|
|
}
|
||
|
|
|
||
|
|
void FxModule::mouseExit(const juce::MouseEvent&)
|
||
|
|
{
|
||
|
|
repaint();
|
||
|
|
}
|