|
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127 |
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2013 - Raw Material Software Ltd.
-
- Permission is granted to use this software under the terms of either:
- a) the GPL v2 (or any later version)
- b) the Affero GPL v3
-
- Details of these licenses can be found at: www.gnu.org/licenses
-
- JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
- ------------------------------------------------------------------------------
-
- To release a closed-source product which uses JUCE, commercial licenses are
- available: visit www.juce.com for more information.
-
- ==============================================================================
- */
-
- #include "GraphEditorPanel.h"
- #include "InternalFilters.h"
-
-
- //==============================================================================
- PluginWindow::PluginWindow (GraphEditorPanel* const p,
- Component* const pluginEditor,
- AudioProcessorGraph::Node* const o,
- WindowFormatType t)
- : DocumentWindow (pluginEditor->getName(), Colours::lightblue,
- DocumentWindow::minimiseButton | DocumentWindow::closeButton),
- owner (o),
- type (t),
- panel (p)
- {
- setSize (400, 300);
-
- setContentOwned (pluginEditor, true);
- setUsingNativeTitleBar (true);
-
- setTopLeftPosition (owner->properties.getWithDefault ("uiLastX", Random::getSystemRandom().nextInt (500)),
- owner->properties.getWithDefault ("uiLastY", Random::getSystemRandom().nextInt (500)));
- setVisible (true);
-
- panel->activePluginWindows.add (this);
- }
-
- //==============================================================================
- class ProcessorProgramPropertyComp : public PropertyComponent,
- private AudioProcessorListener
- {
- public:
- ProcessorProgramPropertyComp (const String& name, AudioProcessor& p, int index_)
- : PropertyComponent (name),
- owner (p),
- index (index_)
- {
- owner.addListener (this);
- }
-
- ~ProcessorProgramPropertyComp()
- {
- owner.removeListener (this);
- }
-
- void refresh() { }
- void audioProcessorChanged (AudioProcessor*) { }
- void audioProcessorParameterChanged (AudioProcessor*, int, float) { }
-
- private:
- AudioProcessor& owner;
- const int index;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProcessorProgramPropertyComp)
- };
-
- class ProgramAudioProcessorEditor : public AudioProcessorEditor
- {
- public:
- ProgramAudioProcessorEditor (AudioProcessor* const p)
- : AudioProcessorEditor (p)
- {
- jassert (p != nullptr);
- setOpaque (true);
-
- addAndMakeVisible (panel);
-
- Array<PropertyComponent*> programs;
-
- const int numPrograms = p->getNumPrograms();
- int totalHeight = 0;
-
- for (int i = 0; i < numPrograms; ++i)
- {
- String name (p->getProgramName (i).trim());
-
- if (name.isEmpty())
- name = "Unnamed";
-
- ProcessorProgramPropertyComp* const pc = new ProcessorProgramPropertyComp (name, *p, i);
- programs.add (pc);
- totalHeight += pc->getPreferredHeight();
- }
-
- panel.addProperties (programs);
-
- setSize (400, jlimit (25, 400, totalHeight));
- }
-
- void paint (Graphics& g)
- {
- g.fillAll (Colours::grey);
- }
-
- void resized()
- {
- panel.setBounds (getLocalBounds());
- }
-
- private:
- PropertyPanel panel;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramAudioProcessorEditor)
- };
-
- PluginWindow::~PluginWindow()
- {
- panel->activePluginWindows.removeFirstMatchingValue (this);
- clearContentComponent();
- }
-
- void PluginWindow::moved()
- {
- owner->properties.set ("uiLastX", getX());
- owner->properties.set ("uiLastY", getY());
- }
-
- void PluginWindow::closeButtonPressed()
- {
- delete this;
- }
-
- //==============================================================================
- class PinComponent : public Component,
- public SettableTooltipClient
- {
- public:
- PinComponent (FilterGraph& graph_,
- const uint32 filterID_, const int index_, const bool isInput_)
- : filterID (filterID_),
- index (index_),
- isInput (isInput_),
- graph (graph_)
- {
- if (const AudioProcessorGraph::Node::Ptr node = graph.getNodeForId (filterID_))
- {
- String tip;
-
- if (index_ == FilterGraph::midiChannelNumber)
- {
- tip = isInput ? "MIDI Input" : "MIDI Output";
- }
- else
- {
- if (isInput)
- tip = node->getProcessor()->getInputChannelName (index_);
- else
- tip = node->getProcessor()->getOutputChannelName (index_);
-
- if (tip.isEmpty())
- tip = (isInput ? "Input " : "Output ") + String (index_ + 1);
- }
-
- setTooltip (tip);
- }
-
- setSize (16, 16);
- }
-
- void paint (Graphics& g)
- {
- const float w = (float) getWidth();
- const float h = (float) getHeight();
-
- Path p;
- p.addEllipse (w * 0.25f, h * 0.25f, w * 0.5f, h * 0.5f);
-
- p.addRectangle (w * 0.4f, isInput ? (0.5f * h) : 0.0f, w * 0.2f, h * 0.5f);
-
- g.setColour (index == FilterGraph::midiChannelNumber ? Colours::red : Colours::green);
- g.fillPath (p);
- }
-
- void mouseDown (const MouseEvent& e)
- {
- getGraphPanel()->beginConnectorDrag (isInput ? 0 : filterID,
- index,
- isInput ? filterID : 0,
- index,
- e);
- }
-
- void mouseDrag (const MouseEvent& e)
- {
- getGraphPanel()->dragConnector (e);
- }
-
- void mouseUp (const MouseEvent& e)
- {
- getGraphPanel()->endDraggingConnector (e);
- }
-
- const uint32 filterID;
- const int index;
- const bool isInput;
-
- private:
- FilterGraph& graph;
-
- GraphEditorPanel* getGraphPanel() const noexcept
- {
- return findParentComponentOfClass<GraphEditorPanel>();
- }
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PinComponent)
- };
-
- //==============================================================================
- class FilterComponent : public Component
- {
- public:
- FilterComponent (FilterGraph& graph_,
- const uint32 filterID_)
- : graph (graph_),
- filterID (filterID_),
- numInputs (0),
- numOutputs (0),
- pinSize (16),
- font (13.0f, Font::bold),
- numIns (0),
- numOuts (0)
- {
- shadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 3, Point<int> (0, 1)));
- setComponentEffect (&shadow);
-
- setSize (150, 60);
- }
-
- ~FilterComponent()
- {
- deleteAllChildren();
- }
-
- void mouseDown (const MouseEvent& e)
- {
- originalPos = localPointToGlobal (Point<int>());
-
- toFront (true);
-
- if (e.mods.isPopupMenu())
- {
- PopupMenu m;
- m.addItem (1, "Delete this filter");
- m.addItem (2, "Disconnect all pins");
- m.addSeparator();
- m.addItem (3, "Show plugin UI");
- m.addItem (4, "Show all programs");
- m.addItem (5, "Show all parameters");
- m.addItem (6, "Test state save/load");
-
- const int r = m.show();
-
- if (r == 1)
- {
- graph.removeFilter (filterID);
- return;
- }
- else if (r == 2)
- {
- graph.disconnectFilter (filterID);
- }
- else
- {
- if (AudioProcessorGraph::Node::Ptr f = graph.getNodeForId (filterID))
- {
- AudioProcessor* const processor = f->getProcessor();
- jassert (processor != nullptr);
-
- if (r == 6)
- {
- MemoryBlock state;
- processor->getStateInformation (state);
- processor->setStateInformation (state.getData(), (int) state.getSize());
- }
- else
- {
- PluginWindow::WindowFormatType type = processor->hasEditor() ? PluginWindow::Normal
- : PluginWindow::Generic;
-
- switch (r)
- {
- case 4: type = PluginWindow::Programs; break;
- case 5: type = PluginWindow::Parameters; break;
-
- default: break;
- };
-
- if (PluginWindow* const w = getGraphPanel()->getWindowFor (f, type))
- w->toFront (true);
- }
- }
- }
- }
- }
-
- void mouseDrag (const MouseEvent& e)
- {
- if (! e.mods.isPopupMenu())
- {
- Point<int> pos (originalPos + Point<int> (e.getDistanceFromDragStartX(), e.getDistanceFromDragStartY()));
-
- if (getParentComponent() != nullptr)
- pos = getParentComponent()->getLocalPoint (nullptr, pos);
-
- graph.setNodePosition (filterID,
- (pos.getX() + getWidth() / 2) / (double) getParentWidth(),
- (pos.getY() + getHeight() / 2) / (double) getParentHeight());
-
- getGraphPanel()->updateComponents();
- }
- }
-
- void mouseUp (const MouseEvent& e)
- {
- if (e.mouseWasClicked() && e.getNumberOfClicks() == 2)
- {
- if (const AudioProcessorGraph::Node::Ptr f = graph.getNodeForId (filterID))
- if (PluginWindow* const w = getGraphPanel()->getWindowFor (f, PluginWindow::Normal))
- w->toFront (true);
- }
- else if (! e.mouseWasClicked())
- {
- graph.setChangedFlag (true);
- }
- }
-
- bool hitTest (int x, int y)
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- if (getChildComponent(i)->getBounds().contains (x, y))
- return true;
-
- return x >= 3 && x < getWidth() - 6 && y >= pinSize && y < getHeight() - pinSize;
- }
-
- void paint (Graphics& g)
- {
- g.setColour (Colours::lightgrey);
-
- const int x = 4;
- const int y = pinSize;
- const int w = getWidth() - x * 2;
- const int h = getHeight() - pinSize * 2;
-
- g.fillRect (x, y, w, h);
-
- g.setColour (Colours::black);
- g.setFont (font);
- g.drawFittedText (getName(), getLocalBounds().reduced (4, 2), Justification::centred, 2);
-
- g.setColour (Colours::grey);
- g.drawRect (x, y, w, h);
- }
-
- void resized()
- {
- for (int i = 0; i < getNumChildComponents(); ++i)
- {
- if (PinComponent* const pc = dynamic_cast <PinComponent*> (getChildComponent(i)))
- {
- const int total = pc->isInput ? numIns : numOuts;
- const int index = pc->index == FilterGraph::midiChannelNumber ? (total - 1) : pc->index;
-
- pc->setBounds (proportionOfWidth ((1 + index) / (total + 1.0f)) - pinSize / 2,
- pc->isInput ? 0 : (getHeight() - pinSize),
- pinSize, pinSize);
- }
- }
- }
-
- void getPinPos (const int index, const bool isInput, float& x, float& y)
- {
- for (int i = 0; i < getNumChildComponents(); ++i)
- {
- if (PinComponent* const pc = dynamic_cast <PinComponent*> (getChildComponent(i)))
- {
- if (pc->index == index && isInput == pc->isInput)
- {
- x = getX() + pc->getX() + pc->getWidth() * 0.5f;
- y = getY() + pc->getY() + pc->getHeight() * 0.5f;
- break;
- }
- }
- }
- }
-
- void update()
- {
- const AudioProcessorGraph::Node::Ptr f (graph.getNodeForId (filterID));
-
- if (f == nullptr)
- {
- delete this;
- return;
- }
-
- numIns = f->getProcessor()->getNumInputChannels();
- if (f->getProcessor()->acceptsMidi())
- ++numIns;
-
- numOuts = f->getProcessor()->getNumOutputChannels();
- if (f->getProcessor()->producesMidi())
- ++numOuts;
-
- int w = 100;
- int h = 60;
-
- w = jmax (w, (jmax (numIns, numOuts) + 1) * 20);
-
- const int textWidth = font.getStringWidth (f->getProcessor()->getName());
- w = jmax (w, 16 + jmin (textWidth, 300));
- if (textWidth > 300)
- h = 100;
-
- setSize (w, h);
-
- setName (f->getProcessor()->getName());
-
- {
- double x, y;
- graph.getNodePosition (filterID, x, y);
- setCentreRelative ((float) x, (float) y);
- }
-
- if (numIns != numInputs || numOuts != numOutputs)
- {
- numInputs = numIns;
- numOutputs = numOuts;
-
- deleteAllChildren();
-
- int i;
- for (i = 0; i < f->getProcessor()->getNumInputChannels(); ++i)
- addAndMakeVisible (new PinComponent (graph, filterID, i, true));
-
- if (f->getProcessor()->acceptsMidi())
- addAndMakeVisible (new PinComponent (graph, filterID, FilterGraph::midiChannelNumber, true));
-
- for (i = 0; i < f->getProcessor()->getNumOutputChannels(); ++i)
- addAndMakeVisible (new PinComponent (graph, filterID, i, false));
-
- if (f->getProcessor()->producesMidi())
- addAndMakeVisible (new PinComponent (graph, filterID, FilterGraph::midiChannelNumber, false));
-
- resized();
- }
- }
-
- FilterGraph& graph;
- const uint32 filterID;
- int numInputs, numOutputs;
-
- private:
- int pinSize;
- Point<int> originalPos;
- Font font;
- int numIns, numOuts;
- DropShadowEffect shadow;
-
- GraphEditorPanel* getGraphPanel() const noexcept
- {
- return findParentComponentOfClass<GraphEditorPanel>();
- }
-
- FilterComponent (const FilterComponent&);
- FilterComponent& operator= (const FilterComponent&);
- };
-
- //==============================================================================
- class ConnectorComponent : public Component,
- public SettableTooltipClient
- {
- public:
- ConnectorComponent (FilterGraph& graph_)
- : sourceFilterID (0),
- destFilterID (0),
- sourceFilterChannel (0),
- destFilterChannel (0),
- graph (graph_),
- lastInputX (0),
- lastInputY (0),
- lastOutputX (0),
- lastOutputY (0)
- {
- setAlwaysOnTop (true);
- }
-
- void setInput (const uint32 sourceFilterID_, const int sourceFilterChannel_)
- {
- if (sourceFilterID != sourceFilterID_ || sourceFilterChannel != sourceFilterChannel_)
- {
- sourceFilterID = sourceFilterID_;
- sourceFilterChannel = sourceFilterChannel_;
- update();
- }
- }
-
- void setOutput (const uint32 destFilterID_, const int destFilterChannel_)
- {
- if (destFilterID != destFilterID_ || destFilterChannel != destFilterChannel_)
- {
- destFilterID = destFilterID_;
- destFilterChannel = destFilterChannel_;
- update();
- }
- }
-
- void dragStart (int x, int y)
- {
- lastInputX = (float) x;
- lastInputY = (float) y;
- resizeToFit();
- }
-
- void dragEnd (int x, int y)
- {
- lastOutputX = (float) x;
- lastOutputY = (float) y;
- resizeToFit();
- }
-
- void update()
- {
- float x1, y1, x2, y2;
- getPoints (x1, y1, x2, y2);
-
- if (lastInputX != x1
- || lastInputY != y1
- || lastOutputX != x2
- || lastOutputY != y2)
- {
- resizeToFit();
- }
- }
-
- void resizeToFit()
- {
- float x1, y1, x2, y2;
- getPoints (x1, y1, x2, y2);
-
- const juce::Rectangle<int> newBounds ((int) jmin (x1, x2) - 4,
- (int) jmin (y1, y2) - 4,
- (int) std::abs (x1 - x2) + 8,
- (int) std::abs (y1 - y2) + 8);
-
- if (newBounds != getBounds())
- setBounds (newBounds);
- else
- resized();
-
- repaint();
- }
-
- void getPoints (float& x1, float& y1, float& x2, float& y2) const
- {
- x1 = lastInputX;
- y1 = lastInputY;
- x2 = lastOutputX;
- y2 = lastOutputY;
-
- if (GraphEditorPanel* const hostPanel = getGraphPanel())
- {
- if (FilterComponent* srcFilterComp = hostPanel->getComponentForFilter (sourceFilterID))
- srcFilterComp->getPinPos (sourceFilterChannel, false, x1, y1);
-
- if (FilterComponent* dstFilterComp = hostPanel->getComponentForFilter (destFilterID))
- dstFilterComp->getPinPos (destFilterChannel, true, x2, y2);
- }
- }
-
- void paint (Graphics& g)
- {
- if (sourceFilterChannel == FilterGraph::midiChannelNumber
- || destFilterChannel == FilterGraph::midiChannelNumber)
- {
- g.setColour (Colours::red);
- }
- else
- {
- g.setColour (Colours::green);
- }
-
- g.fillPath (linePath);
- }
-
- bool hitTest (int x, int y)
- {
- if (hitPath.contains ((float) x, (float) y))
- {
- double distanceFromStart, distanceFromEnd;
- getDistancesFromEnds (x, y, distanceFromStart, distanceFromEnd);
-
- // avoid clicking the connector when over a pin
- return distanceFromStart > 7.0 && distanceFromEnd > 7.0;
- }
-
- return false;
- }
-
- void mouseDown (const MouseEvent&)
- {
- dragging = false;
- }
-
- void mouseDrag (const MouseEvent& e)
- {
- if ((! dragging) && ! e.mouseWasClicked())
- {
- dragging = true;
-
- graph.removeConnection (sourceFilterID, sourceFilterChannel, destFilterID, destFilterChannel);
-
- double distanceFromStart, distanceFromEnd;
- getDistancesFromEnds (e.x, e.y, distanceFromStart, distanceFromEnd);
- const bool isNearerSource = (distanceFromStart < distanceFromEnd);
-
- getGraphPanel()->beginConnectorDrag (isNearerSource ? 0 : sourceFilterID,
- sourceFilterChannel,
- isNearerSource ? destFilterID : 0,
- destFilterChannel,
- e);
- }
- else if (dragging)
- {
- getGraphPanel()->dragConnector (e);
- }
- }
-
- void mouseUp (const MouseEvent& e)
- {
- if (dragging)
- getGraphPanel()->endDraggingConnector (e);
- }
-
- void resized()
- {
- float x1, y1, x2, y2;
- getPoints (x1, y1, x2, y2);
-
- lastInputX = x1;
- lastInputY = y1;
- lastOutputX = x2;
- lastOutputY = y2;
-
- x1 -= getX();
- y1 -= getY();
- x2 -= getX();
- y2 -= getY();
-
- linePath.clear();
- linePath.startNewSubPath (x1, y1);
- linePath.cubicTo (x1, y1 + (y2 - y1) * 0.33f,
- x2, y1 + (y2 - y1) * 0.66f,
- x2, y2);
-
- PathStrokeType wideStroke (8.0f);
- wideStroke.createStrokedPath (hitPath, linePath);
-
- PathStrokeType stroke (2.5f);
- stroke.createStrokedPath (linePath, linePath);
-
- const float arrowW = 5.0f;
- const float arrowL = 4.0f;
-
- Path arrow;
- arrow.addTriangle (-arrowL, arrowW,
- -arrowL, -arrowW,
- arrowL, 0.0f);
-
- arrow.applyTransform (AffineTransform::identity
- .rotated (float_Pi * 0.5f - (float) atan2 (x2 - x1, y2 - y1))
- .translated ((x1 + x2) * 0.5f,
- (y1 + y2) * 0.5f));
-
- linePath.addPath (arrow);
- linePath.setUsingNonZeroWinding (true);
- }
-
- uint32 sourceFilterID, destFilterID;
- int sourceFilterChannel, destFilterChannel;
-
- private:
- FilterGraph& graph;
- float lastInputX, lastInputY, lastOutputX, lastOutputY;
- Path linePath, hitPath;
- bool dragging;
-
- GraphEditorPanel* getGraphPanel() const noexcept
- {
- return findParentComponentOfClass<GraphEditorPanel>();
- }
-
- void getDistancesFromEnds (int x, int y, double& distanceFromStart, double& distanceFromEnd) const
- {
- float x1, y1, x2, y2;
- getPoints (x1, y1, x2, y2);
-
- distanceFromStart = juce_hypot (x - (x1 - getX()), y - (y1 - getY()));
- distanceFromEnd = juce_hypot (x - (x2 - getX()), y - (y2 - getY()));
- }
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ConnectorComponent)
- };
-
-
- //==============================================================================
- GraphEditorPanel::GraphEditorPanel (FilterGraph& graph_)
- : graph (graph_)
- {
- graph.addChangeListener (this);
- setOpaque (true);
- }
-
- GraphEditorPanel::~GraphEditorPanel()
- {
- graph.removeChangeListener (this);
- draggingConnector = nullptr;
- deleteAllChildren();
- }
-
- void GraphEditorPanel::paint (Graphics& g)
- {
- g.fillAll (Colours::white);
- }
-
- void GraphEditorPanel::mouseDown (const MouseEvent& e)
- {
- if (e.mods.isPopupMenu())
- {
- PopupMenu m;
-
- if (MainHostWindow* const mainWindow = findParentComponentOfClass<MainHostWindow>())
- {
- mainWindow->addPluginsToMenu (m);
-
- const int r = m.show();
-
- createNewPlugin (mainWindow->getChosenType (r), e.x, e.y);
- }
- }
- }
-
- void GraphEditorPanel::createNewPlugin (const PluginDescription* desc, int x, int y)
- {
- graph.addFilter (desc, x / (double) getWidth(), y / (double) getHeight());
- }
-
- FilterComponent* GraphEditorPanel::getComponentForFilter (const uint32 filterID) const
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- if (FilterComponent* const fc = dynamic_cast <FilterComponent*> (getChildComponent (i)))
- if (fc->filterID == filterID)
- return fc;
- }
-
- return nullptr;
- }
-
- ConnectorComponent* GraphEditorPanel::getComponentForConnection (const AudioProcessorGraph::Connection& conn) const
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- if (ConnectorComponent* const c = dynamic_cast <ConnectorComponent*> (getChildComponent (i)))
- if (c->sourceFilterID == conn.sourceNodeId
- && c->destFilterID == conn.destNodeId
- && c->sourceFilterChannel == conn.sourceChannelIndex
- && c->destFilterChannel == conn.destChannelIndex)
- return c;
- }
-
- return nullptr;
- }
-
- PinComponent* GraphEditorPanel::findPinAt (const int x, const int y) const
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- if (FilterComponent* fc = dynamic_cast <FilterComponent*> (getChildComponent (i)))
- {
- if (PinComponent* pin = dynamic_cast <PinComponent*> (fc->getComponentAt (x - fc->getX(),
- y - fc->getY())))
- return pin;
- }
- }
-
- return nullptr;
- }
-
- void GraphEditorPanel::resized()
- {
- updateComponents();
- }
-
- void GraphEditorPanel::changeListenerCallback (ChangeBroadcaster*)
- {
- updateComponents();
- }
-
- void GraphEditorPanel::updateComponents()
- {
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- if (FilterComponent* const fc = dynamic_cast <FilterComponent*> (getChildComponent (i)))
- fc->update();
- }
-
- for (int i = getNumChildComponents(); --i >= 0;)
- {
- ConnectorComponent* const cc = dynamic_cast <ConnectorComponent*> (getChildComponent (i));
-
- if (cc != nullptr && cc != draggingConnector)
- {
- if (graph.getConnectionBetween (cc->sourceFilterID, cc->sourceFilterChannel,
- cc->destFilterID, cc->destFilterChannel) == nullptr)
- {
- delete cc;
- }
- else
- {
- cc->update();
- }
- }
- }
-
- for (int i = graph.getNumFilters(); --i >= 0;)
- {
- const AudioProcessorGraph::Node::Ptr f (graph.getNode (i));
-
- if (getComponentForFilter (f->nodeId) == 0)
- {
- FilterComponent* const comp = new FilterComponent (graph, f->nodeId);
- addAndMakeVisible (comp);
- comp->update();
- }
- }
-
- for (int i = graph.getNumConnections(); --i >= 0;)
- {
- const AudioProcessorGraph::Connection* const c = graph.getConnection (i);
-
- if (getComponentForConnection (*c) == 0)
- {
- ConnectorComponent* const comp = new ConnectorComponent (graph);
- addAndMakeVisible (comp);
-
- comp->setInput (c->sourceNodeId, c->sourceChannelIndex);
- comp->setOutput (c->destNodeId, c->destChannelIndex);
- }
- }
- }
-
- void GraphEditorPanel::beginConnectorDrag (const uint32 sourceFilterID, const int sourceFilterChannel,
- const uint32 destFilterID, const int destFilterChannel,
- const MouseEvent& e)
- {
- draggingConnector = dynamic_cast <ConnectorComponent*> (e.originalComponent);
-
- if (draggingConnector == nullptr)
- draggingConnector = new ConnectorComponent (graph);
-
- draggingConnector->setInput (sourceFilterID, sourceFilterChannel);
- draggingConnector->setOutput (destFilterID, destFilterChannel);
-
- addAndMakeVisible (draggingConnector);
- draggingConnector->toFront (false);
-
- dragConnector (e);
- }
-
- void GraphEditorPanel::dragConnector (const MouseEvent& e)
- {
- const MouseEvent e2 (e.getEventRelativeTo (this));
-
- if (draggingConnector != nullptr)
- {
- draggingConnector->setTooltip (String::empty);
-
- int x = e2.x;
- int y = e2.y;
-
- if (PinComponent* const pin = findPinAt (x, y))
- {
- uint32 srcFilter = draggingConnector->sourceFilterID;
- int srcChannel = draggingConnector->sourceFilterChannel;
- uint32 dstFilter = draggingConnector->destFilterID;
- int dstChannel = draggingConnector->destFilterChannel;
-
- if (srcFilter == 0 && ! pin->isInput)
- {
- srcFilter = pin->filterID;
- srcChannel = pin->index;
- }
- else if (dstFilter == 0 && pin->isInput)
- {
- dstFilter = pin->filterID;
- dstChannel = pin->index;
- }
-
- if (graph.canConnect (srcFilter, srcChannel, dstFilter, dstChannel))
- {
- x = pin->getParentComponent()->getX() + pin->getX() + pin->getWidth() / 2;
- y = pin->getParentComponent()->getY() + pin->getY() + pin->getHeight() / 2;
-
- draggingConnector->setTooltip (pin->getTooltip());
- }
- }
-
- if (draggingConnector->sourceFilterID == 0)
- draggingConnector->dragStart (x, y);
- else
- draggingConnector->dragEnd (x, y);
- }
- }
-
- void GraphEditorPanel::endDraggingConnector (const MouseEvent& e)
- {
- if (draggingConnector == nullptr)
- return;
-
- draggingConnector->setTooltip (String::empty);
-
- const MouseEvent e2 (e.getEventRelativeTo (this));
-
- uint32 srcFilter = draggingConnector->sourceFilterID;
- int srcChannel = draggingConnector->sourceFilterChannel;
- uint32 dstFilter = draggingConnector->destFilterID;
- int dstChannel = draggingConnector->destFilterChannel;
-
- draggingConnector = nullptr;
-
- if (PinComponent* const pin = findPinAt (e2.x, e2.y))
- {
- if (srcFilter == 0)
- {
- if (pin->isInput)
- return;
-
- srcFilter = pin->filterID;
- srcChannel = pin->index;
- }
- else
- {
- if (! pin->isInput)
- return;
-
- dstFilter = pin->filterID;
- dstChannel = pin->index;
- }
-
- graph.addConnection (srcFilter, srcChannel, dstFilter, dstChannel);
- }
- }
-
- //==============================================================================
- PluginWindow* GraphEditorPanel::getWindowFor (AudioProcessorGraph::Node* const node,
- PluginWindow::WindowFormatType type)
- {
- jassert (node != nullptr);
-
- for (int i = activePluginWindows.size(); --i >= 0;)
- if (activePluginWindows.getUnchecked(i)->owner == node
- && activePluginWindows.getUnchecked(i)->type == type)
- return activePluginWindows.getUnchecked(i);
-
- AudioProcessor* processor = node->getProcessor();
- AudioProcessorEditor* ui = nullptr;
-
- if (type == PluginWindow::Normal)
- {
- ui = processor->createEditorIfNeeded();
-
- if (ui == nullptr)
- type = PluginWindow::Generic;
- }
-
- if (ui == nullptr)
- {
- if (type == PluginWindow::Generic || type == PluginWindow::Parameters)
- ui = new GenericAudioProcessorEditor (processor);
- else if (type == PluginWindow::Programs)
- ui = new ProgramAudioProcessorEditor (processor);
- }
-
- if (ui != nullptr)
- {
- if (AudioPluginInstance* const plugin = dynamic_cast<AudioPluginInstance*> (processor))
- ui->setName (plugin->getName());
-
- return new PluginWindow (this, ui, node, type);
- }
-
- return nullptr;
- }
-
- void GraphEditorPanel::closeCurrentlyOpenWindowsFor (const uint32 nodeId)
- {
- for (int i = activePluginWindows.size(); --i >= 0;)
- if (activePluginWindows.getUnchecked(i)->owner->nodeId == nodeId)
- delete activePluginWindows.getUnchecked (i);
- }
-
- void GraphEditorPanel::closeAllCurrentlyOpenWindows()
- {
- if (activePluginWindows.size() > 0)
- {
- for (int i = activePluginWindows.size(); --i >= 0;)
- delete activePluginWindows.getUnchecked (i);
-
- Component dummyModalComp;
- dummyModalComp.enterModalState();
- MessageManager::getInstance()->runDispatchLoopUntil (50);
- }
- }
-
-
- //==============================================================================
- class TooltipBar : public Component,
- private Timer
- {
- public:
- TooltipBar()
- {
- startTimer (100);
- }
-
- void paint (Graphics& g)
- {
- g.setFont (Font (getHeight() * 0.7f, Font::bold));
- g.setColour (Colours::black);
- g.drawFittedText (tip, 10, 0, getWidth() - 12, getHeight(), Justification::centredLeft, 1);
- }
-
- void timerCallback()
- {
- Component* const underMouse = Desktop::getInstance().getMainMouseSource().getComponentUnderMouse();
- TooltipClient* const ttc = dynamic_cast <TooltipClient*> (underMouse);
-
- String newTip;
-
- if (ttc != nullptr && ! (underMouse->isMouseButtonDown() || underMouse->isCurrentlyBlockedByAnotherModalComponent()))
- newTip = ttc->getTooltip();
-
- if (newTip != tip)
- {
- tip = newTip;
- repaint();
- }
- }
-
- private:
- String tip;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipBar)
- };
-
- //==============================================================================
- GraphDocumentComponent::GraphDocumentComponent (FilterGraph& g)
- : graph (g)
- {
- addAndMakeVisible (graphPanel = new GraphEditorPanel (graph));
-
- addAndMakeVisible (keyboardComp = new MidiKeyboardComponent (keyState,
- MidiKeyboardComponent::horizontalKeyboard));
-
- addAndMakeVisible (statusBar = new TooltipBar());
-
- graphPanel->updateComponents();
-
- graph.setPanel(graphPanel);
- }
-
- GraphDocumentComponent::~GraphDocumentComponent()
- {
- graph.setPanel(nullptr);
-
- deleteAllChildren();
- }
-
- void GraphDocumentComponent::resized()
- {
- const int keysHeight = 60;
- const int statusHeight = 20;
-
- graphPanel->setBounds (0, 0, getWidth(), getHeight() - keysHeight);
- statusBar->setBounds (0, getHeight() - keysHeight - statusHeight, getWidth(), statusHeight);
- keyboardComp->setBounds (0, getHeight() - keysHeight, getWidth(), keysHeight);
- }
-
- void GraphDocumentComponent::createNewPlugin (const PluginDescription* desc, int x, int y)
- {
- graphPanel->createNewPlugin (desc, x, y);
- }
-
- void GraphDocumentComponent::closeAllCurrentlyOpenWindows()
- {
- graphPanel->closeAllCurrentlyOpenWindows();
- }
-
- MidiKeyboardState* GraphDocumentComponent::getMidiState() noexcept
- {
- return &keyState;
- }
|