| 
							- /*
 -   ==============================================================================
 - 
 -    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;
 - }
 
 
  |