git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
553
deps/juce/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp
vendored
Normal file
553
deps/juce/extras/AudioPluginHost/Source/Plugins/IOConfigurationWindow.cpp
vendored
Normal file
@ -0,0 +1,553 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#include <JuceHeader.h>
|
||||
#include "../UI/GraphEditorPanel.h"
|
||||
#include "InternalPlugins.h"
|
||||
#include "../UI/MainHostWindow.h"
|
||||
#include "IOConfigurationWindow.h"
|
||||
|
||||
|
||||
//==============================================================================
|
||||
struct NumberedBoxes : public TableListBox,
|
||||
private TableListBoxModel,
|
||||
private Button::Listener
|
||||
{
|
||||
struct Listener
|
||||
{
|
||||
virtual ~Listener() {}
|
||||
|
||||
virtual void addColumn() = 0;
|
||||
virtual void removeColumn() = 0;
|
||||
virtual void columnSelected (int columnId) = 0;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
plusButtonColumnId = 128,
|
||||
minusButtonColumnId = 129
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
NumberedBoxes (Listener& listenerToUse, bool canCurrentlyAddColumn, bool canCurrentlyRemoveColumn)
|
||||
: TableListBox ("NumberedBoxes", this),
|
||||
listener (listenerToUse),
|
||||
canAddColumn (canCurrentlyAddColumn),
|
||||
canRemoveColumn (canCurrentlyRemoveColumn)
|
||||
{
|
||||
auto& tableHeader = getHeader();
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
tableHeader.addColumn (String (i + 1), i + 1, 40);
|
||||
|
||||
setHeaderHeight (0);
|
||||
setRowHeight (40);
|
||||
getHorizontalScrollBar().setAutoHide (false);
|
||||
}
|
||||
|
||||
void setSelected (int columnId)
|
||||
{
|
||||
if (auto* button = dynamic_cast<TextButton*> (getCellComponent (columnId, 0)))
|
||||
button->setToggleState (true, NotificationType::dontSendNotification);
|
||||
}
|
||||
|
||||
void setCanAddColumn (bool canCurrentlyAdd)
|
||||
{
|
||||
if (canCurrentlyAdd != canAddColumn)
|
||||
{
|
||||
canAddColumn = canCurrentlyAdd;
|
||||
|
||||
if (auto* button = dynamic_cast<TextButton*> (getCellComponent (plusButtonColumnId, 0)))
|
||||
button->setEnabled (true);
|
||||
}
|
||||
}
|
||||
|
||||
void setCanRemoveColumn (bool canCurrentlyRemove)
|
||||
{
|
||||
if (canCurrentlyRemove != canRemoveColumn)
|
||||
{
|
||||
canRemoveColumn = canCurrentlyRemove;
|
||||
|
||||
if (auto* button = dynamic_cast<TextButton*> (getCellComponent (minusButtonColumnId, 0)))
|
||||
button->setEnabled (true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
Listener& listener;
|
||||
bool canAddColumn, canRemoveColumn;
|
||||
|
||||
//==============================================================================
|
||||
int getNumRows() override { return 1; }
|
||||
void paintCell (Graphics&, int, int, int, int, bool) override {}
|
||||
void paintRowBackground (Graphics& g, int, int, int, bool) override { g.fillAll (Colours::grey); }
|
||||
|
||||
Component* refreshComponentForCell (int, int columnId, bool,
|
||||
Component* existingComponentToUpdate) override
|
||||
{
|
||||
auto* textButton = dynamic_cast<TextButton*> (existingComponentToUpdate);
|
||||
|
||||
if (textButton == nullptr)
|
||||
textButton = new TextButton();
|
||||
|
||||
textButton->setButtonText (getButtonName (columnId));
|
||||
textButton->setConnectedEdges (Button::ConnectedOnLeft | Button::ConnectedOnRight |
|
||||
Button::ConnectedOnTop | Button::ConnectedOnBottom);
|
||||
|
||||
const bool isPlusMinusButton = (columnId == plusButtonColumnId || columnId == minusButtonColumnId);
|
||||
|
||||
if (isPlusMinusButton)
|
||||
{
|
||||
textButton->setEnabled (columnId == plusButtonColumnId ? canAddColumn : canRemoveColumn);
|
||||
}
|
||||
else
|
||||
{
|
||||
textButton->setRadioGroupId (1, NotificationType::dontSendNotification);
|
||||
textButton->setClickingTogglesState (true);
|
||||
|
||||
auto busColour = Colours::green.withRotatedHue (static_cast<float> (columnId) / 5.0f);
|
||||
textButton->setColour (TextButton::buttonColourId, busColour);
|
||||
textButton->setColour (TextButton::buttonOnColourId, busColour.withMultipliedBrightness (2.0f));
|
||||
}
|
||||
|
||||
textButton->addListener (this);
|
||||
|
||||
return textButton;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
String getButtonName (int columnId)
|
||||
{
|
||||
if (columnId == plusButtonColumnId) return "+";
|
||||
if (columnId == minusButtonColumnId) return "-";
|
||||
|
||||
return String (columnId);
|
||||
}
|
||||
|
||||
void buttonClicked (Button* btn) override
|
||||
{
|
||||
auto text = btn->getButtonText();
|
||||
|
||||
if (text == "+") listener.addColumn();
|
||||
if (text == "-") listener.removeColumn();
|
||||
}
|
||||
|
||||
void buttonStateChanged (Button* btn) override
|
||||
{
|
||||
auto text = btn->getButtonText();
|
||||
|
||||
if (text == "+" || text == "-")
|
||||
return;
|
||||
|
||||
if (btn->getToggleState())
|
||||
listener.columnSelected (text.getIntValue());
|
||||
}
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NumberedBoxes)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
class IOConfigurationWindow::InputOutputConfig : public Component,
|
||||
private ComboBox::Listener,
|
||||
private Button::Listener,
|
||||
private NumberedBoxes::Listener
|
||||
{
|
||||
public:
|
||||
InputOutputConfig (IOConfigurationWindow& parent, bool direction)
|
||||
: owner (parent),
|
||||
ioTitle ("ioLabel", direction ? "Input Configuration" : "Output Configuration"),
|
||||
ioBuses (*this, false, false),
|
||||
isInput (direction)
|
||||
{
|
||||
ioTitle.setFont (ioTitle.getFont().withStyle (Font::bold));
|
||||
nameLabel.setFont (nameLabel.getFont().withStyle (Font::bold));
|
||||
layoutLabel.setFont (layoutLabel.getFont().withStyle (Font::bold));
|
||||
enabledToggle.setClickingTogglesState (true);
|
||||
|
||||
layouts.addListener (this);
|
||||
enabledToggle.addListener (this);
|
||||
|
||||
addAndMakeVisible (layoutLabel);
|
||||
addAndMakeVisible (layouts);
|
||||
addAndMakeVisible (enabledToggle);
|
||||
addAndMakeVisible (ioTitle);
|
||||
addAndMakeVisible (nameLabel);
|
||||
addAndMakeVisible (name);
|
||||
addAndMakeVisible (ioBuses);
|
||||
|
||||
updateBusButtons();
|
||||
updateBusLayout();
|
||||
}
|
||||
|
||||
void paint (Graphics& g) override
|
||||
{
|
||||
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void resized() override
|
||||
{
|
||||
auto r = getLocalBounds().reduced (10);
|
||||
|
||||
ioTitle.setBounds (r.removeFromTop (14));
|
||||
r.reduce (10, 0);
|
||||
r.removeFromTop (16);
|
||||
|
||||
ioBuses.setBounds (r.removeFromTop (60));
|
||||
|
||||
{
|
||||
auto label = r.removeFromTop (24);
|
||||
nameLabel.setBounds (label.removeFromLeft (100));
|
||||
enabledToggle.setBounds (label.removeFromRight (80));
|
||||
name.setBounds (label);
|
||||
}
|
||||
|
||||
{
|
||||
auto label = r.removeFromTop (24);
|
||||
layoutLabel.setBounds (label.removeFromLeft (100));
|
||||
layouts.setBounds (label);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void updateBusButtons()
|
||||
{
|
||||
if (auto* plugin = owner.getAudioProcessor())
|
||||
{
|
||||
auto& header = ioBuses.getHeader();
|
||||
header.removeAllColumns();
|
||||
|
||||
const int n = plugin->getBusCount (isInput);
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
header.addColumn ("", i + 1, 40);
|
||||
|
||||
header.addColumn ("+", NumberedBoxes::plusButtonColumnId, 20);
|
||||
header.addColumn ("-", NumberedBoxes::minusButtonColumnId, 20);
|
||||
|
||||
ioBuses.setCanAddColumn (plugin->canAddBus (isInput));
|
||||
ioBuses.setCanRemoveColumn (plugin->canRemoveBus (isInput));
|
||||
}
|
||||
|
||||
ioBuses.setSelected (currentBus + 1);
|
||||
}
|
||||
|
||||
void updateBusLayout()
|
||||
{
|
||||
if (auto* plugin = owner.getAudioProcessor())
|
||||
{
|
||||
if (auto* bus = plugin->getBus (isInput, currentBus))
|
||||
{
|
||||
name.setText (bus->getName(), NotificationType::dontSendNotification);
|
||||
|
||||
int i;
|
||||
for (i = 1; i < AudioChannelSet::maxChannelsOfNamedLayout; ++i)
|
||||
if ((layouts.indexOfItemId(i) == -1) != bus->supportedLayoutWithChannels (i).isDisabled())
|
||||
break;
|
||||
|
||||
// supported layouts have changed
|
||||
if (i < AudioChannelSet::maxChannelsOfNamedLayout)
|
||||
{
|
||||
layouts.clear();
|
||||
|
||||
for (i = 1; i < AudioChannelSet::maxChannelsOfNamedLayout; ++i)
|
||||
{
|
||||
auto set = bus->supportedLayoutWithChannels (i);
|
||||
|
||||
if (! set.isDisabled())
|
||||
layouts.addItem (set.getDescription(), i);
|
||||
}
|
||||
}
|
||||
|
||||
layouts.setSelectedId (bus->getLastEnabledLayout().size());
|
||||
|
||||
const bool canBeDisabled = bus->isNumberOfChannelsSupported (0);
|
||||
|
||||
if (canBeDisabled != enabledToggle.isEnabled())
|
||||
enabledToggle.setEnabled (canBeDisabled);
|
||||
|
||||
enabledToggle.setToggleState (bus->isEnabled(), NotificationType::dontSendNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void comboBoxChanged (ComboBox* combo) override
|
||||
{
|
||||
if (combo == &layouts)
|
||||
{
|
||||
if (auto* p = owner.getAudioProcessor())
|
||||
{
|
||||
if (auto* bus = p->getBus (isInput, currentBus))
|
||||
{
|
||||
auto selectedNumChannels = layouts.getSelectedId();
|
||||
|
||||
if (selectedNumChannels != bus->getLastEnabledLayout().size())
|
||||
{
|
||||
if (isPositiveAndBelow (selectedNumChannels, AudioChannelSet::maxChannelsOfNamedLayout)
|
||||
&& bus->setCurrentLayoutWithoutEnabling (bus->supportedLayoutWithChannels (selectedNumChannels)))
|
||||
{
|
||||
if (auto* config = owner.getConfig (! isInput))
|
||||
config->updateBusLayout();
|
||||
|
||||
owner.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void buttonClicked (Button*) override {}
|
||||
|
||||
void buttonStateChanged (Button* btn) override
|
||||
{
|
||||
if (btn == &enabledToggle && enabledToggle.isEnabled())
|
||||
{
|
||||
if (auto* p = owner.getAudioProcessor())
|
||||
{
|
||||
if (auto* bus = p->getBus (isInput, currentBus))
|
||||
{
|
||||
if (bus->isEnabled() != enabledToggle.getToggleState())
|
||||
{
|
||||
bool success = enabledToggle.getToggleState() ? bus->enable()
|
||||
: bus->setCurrentLayout (AudioChannelSet::disabled());
|
||||
|
||||
if (success)
|
||||
{
|
||||
updateBusLayout();
|
||||
|
||||
if (auto* config = owner.getConfig (! isInput))
|
||||
config->updateBusLayout();
|
||||
|
||||
owner.update();
|
||||
}
|
||||
else
|
||||
{
|
||||
enabledToggle.setToggleState (! enabledToggle.getToggleState(),
|
||||
NotificationType::dontSendNotification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
void addColumn() override
|
||||
{
|
||||
if (auto* p = owner.getAudioProcessor())
|
||||
{
|
||||
if (p->canAddBus (isInput))
|
||||
{
|
||||
if (p->addBus (isInput))
|
||||
{
|
||||
updateBusButtons();
|
||||
updateBusLayout();
|
||||
|
||||
if (auto* config = owner.getConfig (! isInput))
|
||||
{
|
||||
config->updateBusButtons();
|
||||
config->updateBusLayout();
|
||||
}
|
||||
}
|
||||
|
||||
owner.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void removeColumn() override
|
||||
{
|
||||
if (auto* p = owner.getAudioProcessor())
|
||||
{
|
||||
if (p->getBusCount (isInput) > 1 && p->canRemoveBus (isInput))
|
||||
{
|
||||
if (p->removeBus (isInput))
|
||||
{
|
||||
currentBus = jmin (p->getBusCount (isInput) - 1, currentBus);
|
||||
|
||||
updateBusButtons();
|
||||
updateBusLayout();
|
||||
|
||||
if (auto* config = owner.getConfig (! isInput))
|
||||
{
|
||||
config->updateBusButtons();
|
||||
config->updateBusLayout();
|
||||
}
|
||||
|
||||
owner.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void columnSelected (int columnId) override
|
||||
{
|
||||
const int newBus = columnId - 1;
|
||||
|
||||
if (currentBus != newBus)
|
||||
{
|
||||
currentBus = newBus;
|
||||
ioBuses.setSelected (currentBus + 1);
|
||||
updateBusLayout();
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
IOConfigurationWindow& owner;
|
||||
Label ioTitle, name;
|
||||
Label nameLabel { "nameLabel", "Bus Name:" };
|
||||
Label layoutLabel { "layoutLabel", "Channel Layout:" };
|
||||
ToggleButton enabledToggle { "Enabled" };
|
||||
ComboBox layouts;
|
||||
NumberedBoxes ioBuses;
|
||||
bool isInput;
|
||||
int currentBus = 0;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InputOutputConfig)
|
||||
};
|
||||
|
||||
|
||||
IOConfigurationWindow::IOConfigurationWindow (AudioProcessor& p)
|
||||
: AudioProcessorEditor (&p),
|
||||
title ("title", p.getName())
|
||||
{
|
||||
setOpaque (true);
|
||||
|
||||
title.setFont (title.getFont().withStyle (Font::bold));
|
||||
addAndMakeVisible (title);
|
||||
|
||||
{
|
||||
ScopedLock renderLock (p.getCallbackLock());
|
||||
p.suspendProcessing (true);
|
||||
p.releaseResources();
|
||||
}
|
||||
|
||||
if (p.getBusCount (true) > 0 || p.canAddBus (true))
|
||||
{
|
||||
inConfig.reset (new InputOutputConfig (*this, true));
|
||||
addAndMakeVisible (inConfig.get());
|
||||
}
|
||||
|
||||
if (p.getBusCount (false) > 0 || p.canAddBus (false))
|
||||
{
|
||||
outConfig.reset (new InputOutputConfig (*this, false));
|
||||
addAndMakeVisible (outConfig.get());
|
||||
}
|
||||
|
||||
currentLayout = p.getBusesLayout();
|
||||
setSize (400, (inConfig != nullptr && outConfig != nullptr ? 160 : 0) + 200);
|
||||
}
|
||||
|
||||
IOConfigurationWindow::~IOConfigurationWindow()
|
||||
{
|
||||
if (auto* graph = getGraph())
|
||||
{
|
||||
if (auto* p = getAudioProcessor())
|
||||
{
|
||||
ScopedLock renderLock (graph->getCallbackLock());
|
||||
|
||||
graph->suspendProcessing (true);
|
||||
graph->releaseResources();
|
||||
|
||||
p->prepareToPlay (graph->getSampleRate(), graph->getBlockSize());
|
||||
p->suspendProcessing (false);
|
||||
|
||||
graph->prepareToPlay (graph->getSampleRate(), graph->getBlockSize());
|
||||
graph->suspendProcessing (false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IOConfigurationWindow::paint (Graphics& g)
|
||||
{
|
||||
g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
|
||||
}
|
||||
|
||||
void IOConfigurationWindow::resized()
|
||||
{
|
||||
auto r = getLocalBounds().reduced (10);
|
||||
|
||||
title.setBounds (r.removeFromTop (14));
|
||||
r.reduce (10, 0);
|
||||
|
||||
if (inConfig != nullptr)
|
||||
inConfig->setBounds (r.removeFromTop (160));
|
||||
|
||||
if (outConfig != nullptr)
|
||||
outConfig->setBounds (r.removeFromTop (160));
|
||||
}
|
||||
|
||||
void IOConfigurationWindow::update()
|
||||
{
|
||||
auto nodeID = getNodeID();
|
||||
|
||||
if (auto* graph = getGraph())
|
||||
if (nodeID != AudioProcessorGraph::NodeID())
|
||||
graph->disconnectNode (nodeID);
|
||||
|
||||
if (auto* graphEditor = getGraphEditor())
|
||||
if (auto* panel = graphEditor->graphPanel.get())
|
||||
panel->updateComponents();
|
||||
}
|
||||
|
||||
AudioProcessorGraph::NodeID IOConfigurationWindow::getNodeID() const
|
||||
{
|
||||
if (auto* graph = getGraph())
|
||||
for (auto* node : graph->getNodes())
|
||||
if (node->getProcessor() == getAudioProcessor())
|
||||
return node->nodeID;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
MainHostWindow* IOConfigurationWindow::getMainWindow() const
|
||||
{
|
||||
auto& desktop = Desktop::getInstance();
|
||||
|
||||
for (int i = desktop.getNumComponents(); --i >= 0;)
|
||||
if (auto* mainWindow = dynamic_cast<MainHostWindow*> (desktop.getComponent(i)))
|
||||
return mainWindow;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GraphDocumentComponent* IOConfigurationWindow::getGraphEditor() const
|
||||
{
|
||||
if (auto* mainWindow = getMainWindow())
|
||||
return mainWindow->graphHolder.get();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
AudioProcessorGraph* IOConfigurationWindow::getGraph() const
|
||||
{
|
||||
if (auto* graphEditor = getGraphEditor())
|
||||
if (auto* panel = graphEditor->graph.get())
|
||||
return &panel->graph;
|
||||
|
||||
return nullptr;
|
||||
}
|
Reference in New Issue
Block a user