void QUProfileController::drawGrid(QPainter & p)
{
    if( ! m_vars.showGrid-> get()) return;
    p.save();

    // text is outside of the plot area, so disable clipping
    p.setClipping(false);

    int labelFontHeight = m_labelFontMetrics-> height();
    //    int captionFontHeight = m_captionFontMetrics-> height();

    QColor captionColor( 0, 0, 128);

    // y axis labels
    int textGap = 2;
    p.setFont ( m_labelFont);
    p.setPen( QColor(100,100,100));
    for( auto label : m_vertLabels) {
        double yy = m_y2 - label.centerPix;
        p.drawText( QRectF( m_x2 + textGap, yy, 1, 1),
                    Qt::AlignVCenter | Qt::TextDontClip | Qt::AlignLeft,
                    label.txt1
                    );
    }

    // x axis labels
    for( Plot2dLabelers::LabelEntry & label : m_horizLabels) {
        double xx = m_x1 + label.centerPix;
        p.drawText( QRectF( xx, m_y2 + labelFontHeight / 2.0, 1, 1),
                    Qt::AlignCenter | Qt::TextDontClip,
                    label.txt1
                    );
    }

    // draw the grid lines
    // ===================
    p.setRenderHint( p.Antialiasing, false);
    //    p.setClipping( false);
    p.setClipRect( m_x1, m_y1, m_x2 - m_x1, m_y2 - m_y1);
    p.setClipping(true);
    p.setPen( QPen(QColor(255,0,0,20), 1.0));

    // draw horizontal lines
    for( auto label : m_vertLabels) {
        double yy = m_y2 - label.centerPix;
        p.drawLine( QPointF(m_x1, yy), QPointF(m_x2, yy));
    }

    // draw vertical lines
    for( auto label : m_horizLabels) {
        double xx = m_x1 + label.centerPix;
        p.drawLine( QPointF(xx, m_y1), QPointF(xx, m_y2));
    }

    // highlight 0 axes
    p.setPen( QPen(QColor(255,0,0, 128), 1.0));
    double x0 = ttx1( 0);
    double y0 = tty1( 0);
    p.drawLine( QPointF( x0, m_y1), QPointF( x0, m_y2));
    p.drawLine( QPointF( m_x1, y0), QPointF( m_x2, y0));

    // draw the surrounding rectangle
    p.setClipping( false);
    p.setPen( QPen( QColor( 255,70,70,128), 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin));
    p.drawRect( m_x1, m_y1, m_x2-m_x1, m_y2-m_y1);

    // put the painter in the original state
    p.restore();
}
GraphicsPortItem::GraphicsPortItem(GraphicsClientItemsClient *client_, const QString &fullPortName_, int style_, QFont font_, int padding, QGraphicsItem *parent) :
    QGraphicsPathItem(parent),
    client(client_),
    fullPortName(fullPortName_),
    shortPortName(fullPortName.split(":")[1]),
    dataType(client->getPortType(fullPortName)),
    isInput(client->getPortFlags(fullPortName) & JackPortIsInput),
    style(style_),
    font(font_),
    showMenu(false)
{
    bool gradient = false;
    QColor captionColor(0xfc, 0xf9, 0xc2);
    setPen(QPen(QBrush(Qt::black), 2));
    setBrush(QBrush(captionColor));
    setFlags(QGraphicsItem::ItemSendsScenePositionChanges);
    setCursor(Qt::ArrowCursor);
    font.setStyleStrategy(QFont::PreferAntialias);
    QFontMetrics fontMetrics(font);
    int portPadding = padding;

    QGraphicsSimpleTextItem *portTextItem = new QGraphicsSimpleTextItem(shortPortName, this);
    portTextItem->setFont(font);
    portTextItem->setPos(portPadding, 0);
    portRect = portTextItem->boundingRect().adjusted(-portPadding, -portPadding, portPadding, portPadding).translated(portTextItem->pos());

    QPainterPath portPath;
    if (style == 0) {
        portPath = portPath.united(EllipsePath(portRect));
    } else if (style == 1) {
        portPath = portPath.united(SpeechBubblePath(portRect, portRect.height() / 4, portRect.height() / 4, Qt::AbsoluteSize));
    } else if (style == 2) {
        portPath = portPath.united(RoundedRectanglePath(portRect, portPadding + fontMetrics.height() / 2, portPadding + fontMetrics.height() / 2));
    } else if (style == 3) {
        portPath = portPath.united(RectanglePath(portRect));
    }
    setPath(portPath);

    // register the port registration callback at the jack server:
    QObject::connect(client, SIGNAL(portRegistered(QString,QString,int)), this, SLOT(onPortRegistered(QString,QString,int)), Qt::QueuedConnection);
    QObject::connect(client, SIGNAL(portUnregistered(QString,QString,int)), this, SLOT(onPortUnregistered(QString,QString,int)), Qt::QueuedConnection);
    QObject::connect(client, SIGNAL(portConnected(QString,QString)), this, SLOT(onPortConnected(QString,QString)), Qt::QueuedConnection);
    QObject::connect(client, SIGNAL(portDisconnected(QString,QString)), this, SLOT(onPortDisconnected(QString,QString)), Qt::QueuedConnection);

    if (gradient) {
        QLinearGradient gradient(portRect.topLeft(), portRect.bottomRight());
        gradient.setColorAt(0, Qt::white);
        gradient.setColorAt(1, QColor("wheat"));
        setBrush(QBrush(gradient));
    }

    // create the context menu:
    connectMenu = contextMenu.addMenu("Connect");
    disconnectMenu = contextMenu.addMenu("Disconnect");
    // create the entries in connect- and disconnect-menus, as well as graphical representations of existing connections:
    QStringList connectedPorts = client->getConnectedPorts(fullPortName);
    QSet<QString> connectedPortsSet;
    for (int i = 0; i < connectedPorts.size(); i++) {
        // create an entry in the disconnect-menu:
        QAction *action = disconnectMenu->addAction(connectedPorts[i]);
        action->setData(connectedPorts[i]);
        QObject::connect(action, SIGNAL(triggered()), this, SLOT(onDisconnectAction()));
        mapPortNamesToActions[connectedPorts[i]] = action;
        connectedPortsSet.insert(connectedPorts[i]);
        // create a graphical representation of the connection:
        if (isInput) {
            client->getPortConnectionItem(connectedPorts[i], fullPortName)->setPos(fullPortName, getConnectionScenePos());
        } else {
            client->getPortConnectionItem(fullPortName, connectedPorts[i])->setPos(fullPortName, getConnectionScenePos());
        }
    }
    // get all available ports that can be connected to this:
    QStringList connectablePorts = client->getPorts(0, dataType.toAscii().data(), isInput ? JackPortIsOutput : JackPortIsInput);
    for (int i = 0; i < connectablePorts.size(); i++) {
        // skip ports that are already connected:
        if (!connectedPortsSet.contains(connectablePorts[i])) {
            // create an entry in the connect-menu:
            QAction *action = connectMenu->addAction(connectablePorts[i]);
            action->setData(connectablePorts[i]);
            QObject::connect(action, SIGNAL(triggered()), this, SLOT(onConnectAction()));
            mapPortNamesToActions[connectablePorts[i]] = action;
        }
    }
    disconnectMenu->setEnabled(disconnectMenu->actions().size());
    connectMenu->setEnabled(connectMenu->actions().size());
}