bool GraphComponent::keyPressed (const KeyPress& key)
{
    if (key.isKeyCode (KeyPress::leftKey))
    {
        for (int i = 0; i < selectedNodes.getNumSelected (); i++)
        {
            GraphNodeComponent* selected = selectedNodes.getSelectedItem (i);
            if (selected != inputs && selected != outputs)
                selected->setTopLeftPosition (selected->getX() - 1, selected->getY());
        }
    }
    else if (key.isKeyCode (KeyPress::rightKey))
    {
        for (int i = 0; i < selectedNodes.getNumSelected (); i++)
        {
            GraphNodeComponent* selected = selectedNodes.getSelectedItem (i);
            if (selected != inputs && selected != outputs)
                selected->setTopLeftPosition (selected->getX() + 1, selected->getY());
        }
    }
    else if (key.isKeyCode (KeyPress::upKey))
    {
        for (int i = 0; i < selectedNodes.getNumSelected (); i++)
        {
            GraphNodeComponent* selected = selectedNodes.getSelectedItem (i);
            if (selected != inputs && selected != outputs)
                selected->setTopLeftPosition (selected->getX(), selected->getY() - 1);
        }
    }
    else if (key.isKeyCode (KeyPress::downKey))
    {
        for (int i = 0; i < selectedNodes.getNumSelected (); i++)
        {
            GraphNodeComponent* selected = selectedNodes.getSelectedItem (i);
            if (selected != inputs && selected != outputs)
                selected->setTopLeftPosition (selected->getX(), selected->getY() + 1);
        }
    }
    else if (key.isKeyCode (KeyPress::deleteKey))
    {
        closeSelectedPlugins ();
    }
    else
    {
        return Component::keyPressed (key);
    }

    return true;
}
void GraphComponent::nodeMoved (GraphNodeComponent* node, const int deltaX, const int deltaY)
{
//    DBG ("GraphComponent::nodeMoved " + String (deltaX) + " " + String (deltaY));

    jassert (node != 0);

    for (int i = 0; i < selectedNodes.getNumSelected (); i++)
    {
        GraphNodeComponent* selected = selectedNodes.getSelectedItem (i);
        if (selected
            && selected != node
            && ! selected->isLocked ())
        {
            BasePlugin* plugin = (BasePlugin*) selected->getUserData ();
            if (plugin)
            {
                int x = selected->getX() + deltaX;
                int y = selected->getY() + deltaY;

                x = jmax (0, jmin (getWidth () - selected->getWidth(), x));
                y = jmax (0, jmin (getHeight () - selected->getHeight(), y));
            
                plugin->setValue (PROP_GRAPHXPOS, x);
                plugin->setValue (PROP_GRAPHYPOS, y);
                
                selected->setTopLeftPosition (x, y);
            }
        }
    }

    BasePlugin* plugin = (BasePlugin*) node->getUserData ();
    if (plugin)
    {
        plugin->setValue (PROP_GRAPHXPOS, node->getX());
        plugin->setValue (PROP_GRAPHYPOS, node->getY());
    }

    Viewport* parent = findParentComponentOfClass ((Viewport*) 0);
    if (parent)
    {
        parent->notifyComponentChanged ();
    }
}
//==============================================================================
bool GraphComponent::createPluginNode (BasePlugin* plugin)
{
    if (plugin)
    {
        DBG ("GraphComponent::createPluginNode");
 
        GraphNodeComponent* component;
        addAndMakeVisible (component = new GraphNodeComponent());
        component->setNodeListener (this);

        // set common data
        component->setUserData (plugin);
        component->setUniqueID (plugin->getUniqueHash());
        component->setText (plugin->getInstanceName ());
        component->setLeftToRight (leftToRight);
        component->setNodeColour (Colour::fromString (plugin->getValue (PROP_GRAPHCOLOUR, T("0xff808080"))));

        // read properties
        // int maxPortCount = jmax (plugin->getNumInputs () + plugin->getNumMidiInputs (),
        //                          plugin->getNumOutputs () + plugin->getNumMidiOutputs ());
                                 
        // TODO - if (maxPortCount * portWidth > defaultNodeWidth) ...
        int pluginType = plugin->getType();

      setNodeDisplayName(plugin, component, plugin->getInstanceName());

        int wasLocked = plugin->getIntValue (PROP_GRAPHLOCKED, -1);
        if (wasLocked < 0)  wasLocked = 0;
        int wasSelected = plugin->getIntValue (PROP_GRAPHSELECTED, 0);
        int xPos = plugin->getIntValue (PROP_GRAPHXPOS, -1);
        int yPos = plugin->getIntValue (PROP_GRAPHYPOS, -1);
        int wSize = plugin->getIntValue (PROP_GRAPHWSIZE, defaultNodeWidth);
        int hSize = plugin->getIntValue (PROP_GRAPHHSIZE, defaultNodeHeight);

        // input plugin
        if (pluginType == JOST_PLUGINTYPE_INPUT)
        {
            inputs = component;
            if (xPos < 0)       xPos = leftToRight ? 2 : (getWidth () - wSize) / 2;
            if (yPos < 0)       yPos = leftToRight ? (getHeight() - hSize) / 2 : 2;
        }
        // output plugin
        else if (pluginType == JOST_PLUGINTYPE_OUTPUT)
        {
            outputs = component;
            if (xPos < 0)       xPos = leftToRight ? getWidth () - wSize - 2 : (getWidth () - wSize) / 2;
            if (yPos < 0)       yPos = leftToRight ? (getHeight() - hSize) / 2 : getHeight() - hSize - 2;
        }
        // generic plugin
        else
        {
            if (xPos < 0)       xPos = getBounds().getCentreX();
            if (yPos < 0)       yPos = getBounds().getCentreY();
//            pluginTooltip = plugin->getFile ().getFullPathName ();
        }

//        component->setBounds (xPos, yPos, wSize, hSize);
      component->setTopLeftPosition (xPos, yPos);
        component->setLocked (wasLocked);
        component->setVisible (true);
        if (wasSelected) selectedNodes.addToSelection (component);

        plugin->setValue (PROP_GRAPHXPOS, xPos);
        plugin->setValue (PROP_GRAPHYPOS, yPos);

        // restore audio input / output ports
        if (pluginType != JOST_PLUGINTYPE_INPUT)
            for (int j = 0; j < plugin->getNumInputs (); j++)
                component->addInputConnector (JOST_LINKTYPE_AUDIO); // audio cable

        if (pluginType != JOST_PLUGINTYPE_OUTPUT)
            for (int j = 0; j < plugin->getNumOutputs (); j++)
                component->addOutputConnector (JOST_LINKTYPE_AUDIO); // audio cable

        // restore midi input / output ports
        if (pluginType != JOST_PLUGINTYPE_INPUT)
            for (int j = 0; j < plugin->getNumMidiInputs (); j++)
                component->addInputConnector (JOST_LINKTYPE_MIDI); // midi cable

        if (pluginType != JOST_PLUGINTYPE_OUTPUT)
            for (int j = 0; j < plugin->getNumMidiOutputs (); j++)
                component->addOutputConnector (JOST_LINKTYPE_MIDI); // midi cable

        nodes.add (component);

        Viewport* parent = findParentComponentOfClass ((Viewport*) 0);
        if (parent)
        {
            parent->notifyComponentChanged ();
        }

        return true;
    }

    return false;
}