void ProcessorPortGraphicsItem::paint(QPainter* p, const QStyleOptionGraphicsItem* options,
                                      QWidget* widget) {
    p->save();
    p->setBrush(Qt::NoBrush);
    p->setRenderHint(QPainter::Antialiasing, true);

    QColor bottomColor(40, 40, 40);
    p->setPen(QPen(bottomColor, lineWidth_));

    uvec3 color = port_->getColorCode();

    QRectF portRect(QPointF(-size_, size_) / 2, QPointF(size_, -size_) / 2);
    QLinearGradient portGrad(portRect.topLeft(), portRect.bottomLeft());
    portGrad.setColorAt(0.0f,
                        QColor(std::min(255u, color.r * 6 / 10), 
                        std::min(255u, color.g * 6 / 10),
                        std::min(255u, color.b * 6 / 10)));
    portGrad.setColorAt(0.3f, QColor(color.r, color.g, color.b));
    portGrad.setColorAt(1.0f, QColor(color.r, color.g, color.b));
    p->setBrush(portGrad);
    p->drawRect(portRect);

    if (port_->isConnected()) {
        if (up_) {
            p->drawRect(portRect.adjusted(3, -3, -3, -0));
        } else {
            p->drawRect(portRect.adjusted(3, 0, -3, 3));
        }
    }

    p->restore();
}
void GraphicsClientItem::initItem()
{
    // delete all children (except the inner item):
    QList<QGraphicsItem*> children = childItems();
    for (int i = 0; i < children.size(); i++) {
        if (children[i] != controlsItem) {
            if (GraphicsPortItem *portItem = dynamic_cast<GraphicsPortItem*>(children[i])) {
                portItem->deleteLater();
            } else {
                delete children[i];
            }
        }
    }

    bool gradient = false;
    QFont commandsFont = font;
    commandsFont.setBold(true);
    commandsFont.setStyleStrategy(QFont::PreferAntialias);
    QFontMetrics fontMetrics(font);
    int portPadding = fontMetrics.height() / 3;
    int padding = fontMetrics.height() + portPadding * 2;

    QGraphicsSimpleTextItem *textItem = new QGraphicsSimpleTextItem(clientName, this);
    textItem->setFont(font);
    textItem->setPos(padding, padding);
    QStringList inputPorts = clientItemsClient->getPorts(QString(QRegExp::escape(clientName) + ":.*").toAscii().data(), 0, JackPortIsInput);
    QList<GraphicsPortItem*> inputPortItems;
    int inputPortsWidth = -portPadding;
    int minimumInputPortWidth = 0;
    for (int i = 0; i < inputPorts.size(); i++) {
        inputPortItems.append(new GraphicsPortItem(clientItemsClient, inputPorts[i], 3, font, portPadding, this));
        if (isMacroItem()) {
            QPen pen = inputPortItems.back()->pen();
            pen.setColor(QColor("steelblue"));
            inputPortItems.back()->setPen(pen);
        }
        inputPortsWidth += inputPortItems[i]->getRect().width() + portPadding;
        if ((i == 0) || (inputPortItems[i]->getRect().width() < minimumInputPortWidth)) {
            minimumInputPortWidth = inputPortItems[i]->getRect().width();
        }
    }
    QStringList outputPorts = clientItemsClient->getPorts(QString(QRegExp::escape(clientName) + ":.*").toAscii().data(), 0, JackPortIsOutput);
    QList<GraphicsPortItem*> outputPortItems;
    int outputPortsWidth = -portPadding;
    int minimumOutputPortWidth = 0;
    for (int i = 0; i < outputPorts.size(); i++) {
        outputPortItems.append(new GraphicsPortItem(clientItemsClient, outputPorts[i], 3, font, portPadding, this));
        if (isMacroItem()) {
            QPen pen = outputPortItems.back()->pen();
            pen.setColor(QColor("steelblue"));
            outputPortItems.back()->setPen(pen);
        }
        outputPortsWidth += outputPortItems[i]->getRect().width() + portPadding;
        if ((i == 0) || (outputPortItems[i]->getRect().width() < minimumOutputPortWidth)) {
            minimumOutputPortWidth = outputPortItems[i]->getRect().width();
        }
    }

    rect = (textItem->boundingRect().translated(textItem->pos())).adjusted(-padding, -padding, padding, padding);
//    if (rect.width() < inputPortsWidth + (portPadding - minimumInputPortWidth) * 2) {
//        rect.setWidth(inputPortsWidth + (portPadding - minimumInputPortWidth) * 2);
//    }
//    if (rect.width() < outputPortsWidth + (portPadding - minimumOutputPortWidth) * 2) {
//        rect.setWidth(outputPortsWidth + (portPadding - minimumOutputPortWidth) * 2);
//    }
    if (rect.width() < inputPortsWidth) {
        rect.setWidth(inputPortsWidth);
    }
    if (rect.width() < outputPortsWidth) {
        rect.setWidth(outputPortsWidth);
    }
    if (gradient) {
        QLinearGradient gradient(rect.topLeft(), rect.bottomRight());
        gradient.setColorAt(0, Qt::white);
        gradient.setColorAt(1, QColor(0xfc, 0xf9, 0xc2));//QColor("royalblue").lighter());
        setBrush(QBrush(gradient));
    }

    QPainterPath bodyPath;
    if (clientStyle == 0) {
        bodyPath = EllipsePath(rect);
    } else if (clientStyle == 1) {
        bodyPath = SpeechBubblePath(rect, rect.height() / 4, rect.height() / 4, Qt::AbsoluteSize);
    } else if (clientStyle == 2){
        bodyPath = RoundedRectanglePath(rect, padding + fontMetrics.height(), padding + fontMetrics.height());
    } else if (clientStyle == 3) {
        bodyPath = RectanglePath(rect);
    }

    for (int i = 0, x = (inputPortsWidth > rect.width() ? (rect.width() - inputPortsWidth) / 2 : 0); i < inputPorts.size(); i++) {
        GraphicsPortItem *portItem = inputPortItems[i];
        portItem->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
        portItem->setPos(x, 0);
        QRectF portRect(portItem->getRect().translated(portItem->pos()));

        QPainterPath portPath;
        portPath.addRect(QRectF(portRect.topLeft(), 0.5 * (portRect.topRight() + portRect.bottomRight())));
        int portStyle = (portItem->isAudioType() ? audioPortStyle : midiPortStyle);
        if (portStyle == 0) {
            portPath += EllipsePath(portRect);
        } else if (portStyle == 1) {
            portPath += SpeechBubblePath(portRect, 0.7, 0.7);
        } else if (portStyle == 2) {
            portPath += RoundedRectanglePath(portRect, portPadding + fontMetrics.height() / 2, portPadding + fontMetrics.height() / 2);
        } else if (portStyle == 3) {
            portPath += RectanglePath(portRect);
        }
        bodyPath -= portPath;

        x += portRect.width() + portPadding;
    }
    for (int i = 0, x = (outputPortsWidth > rect.width() ? (rect.width() - outputPortsWidth) / 2 : 0); i < outputPorts.size(); i++) {
        GraphicsPortItem *portItem = outputPortItems[i];
        portItem->setFlag(QGraphicsItem::ItemStacksBehindParent, true);
        portItem->setPos(x, rect.height() - fontMetrics.height());
        QRectF portRect(portItem->getRect().translated(portItem->pos()));

        QPainterPath portPath;
        portPath.addRect(QRectF(0.5 * (portRect.topLeft() + portRect.bottomLeft()), portRect.bottomRight()));
        int portStyle = (portItem->isAudioType() ? audioPortStyle : midiPortStyle);
        if (portStyle == 0) {
            portPath += EllipsePath(portRect);
        } else if (portStyle == 1) {
            portPath += SpeechBubblePath(portRect, 0.7, 0.7);
        } else if (portStyle == 2) {
            portPath += RoundedRectanglePath(portRect, portPadding + fontMetrics.height() / 2, portPadding + fontMetrics.height() / 2);
        } else if (portStyle == 3) {
            portPath += RectanglePath(portRect);
        }
        bodyPath -= portPath;

        x += portRect.width() + portPadding;
    }
    QPainterPath combinedPath = bodyPath;

    setPath(combinedPath);
}