void ContentWindowGraphicsItem::drawMovieControls_( QPainter* painter )
{
    ContentWindowManagerPtr contentWindowManager = getContentWindowManager();

    float buttonWidth, buttonHeight;
    getButtonDimensions(buttonWidth, buttonHeight);

    QPen pen;

    if( contentWindowManager->getContent()->getType() == CONTENT_TYPE_MOVIE &&
        g_configuration->getOptions()->getShowMovieControls( ))
    {
        // play/pause
        QRectF playPauseRect(coordinates_.x() + coordinates_.width()/2 - buttonWidth, coordinates_.y() + coordinates_.height() - buttonHeight,
                              buttonWidth, buttonHeight);
        pen.setColor(QColor(contentWindowManager->getControlState() & STATE_PAUSED ? 128 :200,0,0));
        painter->setPen(pen);
        painter->fillRect(playPauseRect, pen.color());

        // loop
        QRectF loopRect(coordinates_.x() + coordinates_.width()/2, coordinates_.y() + coordinates_.height() - buttonHeight,
                        buttonWidth, buttonHeight);
        pen.setColor(QColor(0,contentWindowManager->getControlState() & STATE_LOOP ? 200 :128,0));
        painter->setPen(pen);
        painter->fillRect(loopRect, pen.color());
    }
}
void DisplayGroupManager::removeContentWindowManager(ContentWindowManagerPtr contentWindowManager, DisplayGroupInterface * source)
{
    DisplayGroupInterface::removeContentWindowManager(contentWindowManager, source);

    if(source != this)
    {
        // Notify the (local) pixel stream source of the deletion of the window so the source can be removed too
        if (contentWindowManager->getContent()->getType() == CONTENT_TYPE_PIXEL_STREAM)
        {
            const QString& uri = contentWindowManager->getContent()->getURI();
            closePixelStream(uri);
            emit(pixelStreamViewClosed(uri));
        }

        // set null display group in content window manager object
        contentWindowManager->setDisplayGroupManager(DisplayGroupManagerPtr());

        sendDisplayGroup();
    }
}
void ContentWindowGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent * event)
{
    resizing_ = false;
    moving_ = false;

    ContentWindowManagerPtr contentWindow = getContentWindowManager();

    if( contentWindow )
    {
        contentWindow->getContent()->blockAdvance( false );

        if (selected())
        {
            contentWindow->getInteractionDelegate().mouseReleaseEvent(event);
        }
    }

    QGraphicsItem::mouseReleaseEvent(event);
}
void DisplayGroupManager::addContentWindowManager(ContentWindowManagerPtr contentWindowManager, DisplayGroupInterface * source)
{
    DisplayGroupInterface::addContentWindowManager(contentWindowManager, source);

    if(source != this)
    {
        // set display group in content window manager object
        contentWindowManager->setDisplayGroupManager(shared_from_this());

        sendDisplayGroup();

        if (contentWindowManager->getContent()->getType() != CONTENT_TYPE_PIXEL_STREAM)
        {
            // TODO initialize all content dimensions on creation so we can remove this procedure
            // make sure we have its dimensions so we can constrain its aspect ratio
            sendContentsDimensionsRequest();
        }
    }
}
void ContentWindowGraphicsItem::drawTextLabel_( QPainter* painter )
{
    ContentWindowManagerPtr contentWindowManager = getContentWindowManager();

    float buttonWidth, buttonHeight;
    getButtonDimensions(buttonWidth, buttonHeight);

    const float fontSize = 24.;

    QFont font;
    font.setPixelSize(fontSize);
    painter->setFont(font);

    // color the text black
    QPen pen;
    pen.setColor(QColor(0,0,0));
    painter->setPen(pen);

    // scale the text size down to the height of the graphics view
    // and, calculate the bounding rectangle for the text based on this scale
    // the dimensions of the view need to be corrected for the tiled display aspect ratio
    // recall the tiled display UI is only part of the graphics view since we show it at the correct aspect ratio
    // TODO refactor this for clarity!
    float viewWidth = (float)scene()->views()[0]->width();
    float viewHeight = (float)scene()->views()[0]->height();

    const float tiledDisplayAspect = g_configuration->getAspectRatio();

    if(viewWidth / viewHeight > tiledDisplayAspect)
    {
        viewWidth = viewHeight * tiledDisplayAspect;
    }
    else if(viewWidth / viewHeight <= tiledDisplayAspect)
    {
        viewHeight = viewWidth / tiledDisplayAspect;
    }

    float verticalTextScale = 1. / viewHeight;
    float horizontalTextScale = viewHeight / viewWidth * verticalTextScale;

    painter->scale(horizontalTextScale, verticalTextScale);

    QRectF textBoundingRect = QRectF(coordinates_.x() / horizontalTextScale,
                                     coordinates_.y() / verticalTextScale,
                                     coordinates_.width() / horizontalTextScale,
                                     coordinates_.height() / verticalTextScale);

    // get the label and render it
    QString label(contentWindowManager->getContent()->getURI());
    QString labelSection = label.section("/", -1, -1).prepend(" ");
    painter->drawText(textBoundingRect, Qt::AlignLeft | Qt::AlignTop, labelSection);

    // draw window info at smaller scale
    verticalTextScale *= 0.5;
    horizontalTextScale *= 0.5;

    painter->scale(0.5, 0.5);

    textBoundingRect = QRectF((coordinates_.x()+buttonWidth) / horizontalTextScale,
                               coordinates_.y() / verticalTextScale,
                              (coordinates_.width()-buttonWidth) / horizontalTextScale,
                               coordinates_.height() / verticalTextScale);

    QString coordinatesLabel = QString(" (") + QString::number(coordinates_.x(), 'f', 2) + QString(" ,") +
                                               QString::number(coordinates_.y(), 'f', 2) + QString(", ") +
                                               QString::number(coordinates_.width(), 'f', 2) + QString(", ") +
                                               QString::number(coordinates_.height(), 'f', 2) + QString(")\n");
    QString zoomCenterLabel = QString(" zoom = ") + QString::number(zoom_, 'f', 2) + QString(" @ (") +
                              QString::number(centerX_, 'f', 2) + QString(", ") +
                              QString::number(centerY_, 'f', 2) + QString(")");
    QString interactionLabel = QString(" x: ") +
            QString::number(latestEvent_.mouseX, 'f', 2) +
            QString(" y: ") + QString::number(latestEvent_.mouseY, 'f', 2) +
            QString(" mouseLeft: ") + QString::number((int) latestEvent_.mouseLeft, 'b', 1) +
            QString(" mouseMiddle: ") + QString::number((int) latestEvent_.mouseMiddle, 'b', 1) +
            QString(" mouseRight: ") + QString::number((int) latestEvent_.mouseRight, 'b', 1);

    QString windowInfoLabel = coordinatesLabel + zoomCenterLabel + interactionLabel;
    painter->drawText(textBoundingRect, Qt::AlignLeft | Qt::AlignBottom, windowInfoLabel);
}
void ContentWindowGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent * event)
{
    // on Mac we've seen that mouse events can go to the wrong graphics item
    // this is due to the bug: https://bugreports.qt.nokia.com/browse/QTBUG-20493
    // here we ignore the event if it shouldn't have been sent to us, which ensures
    // it will go to the correct item...
    if(boundingRect().contains(event->pos()) == false)
    {
        event->ignore();
        return;
    }

    // button dimensions
    float buttonWidth, buttonHeight;
    getButtonDimensions(buttonWidth, buttonHeight);

    // item rectangle and event position
    QRectF r = boundingRect();
    QPointF eventPos = event->pos();

    // check to see if user clicked on the close button
    if(fabs((r.x()+r.width()) - eventPos.x()) <= buttonWidth &&
       fabs(r.y() - eventPos.y()) <= buttonHeight)
    {
        close();

        return;
    }

    // move to the front of the GUI display
    moveToFront();

    ContentWindowManagerPtr contentWindow = getContentWindowManager();
    if (!contentWindow)
        return;

    if (selected())
    {
        contentWindow->getInteractionDelegate().mousePressEvent(event);
        return;
    }

    contentWindow->getContent()->blockAdvance( true );

    // check to see if user clicked on the resize button
    if(fabs((r.x()+r.width()) - eventPos.x()) <= buttonWidth &&
       fabs((r.y()+r.height()) - eventPos.y()) <= buttonHeight)
    {
        resizing_ = true;
    }
    // check to see if user clicked on the fullscreen button
    else if(fabs(r.x() - eventPos.x()) <= buttonWidth &&
            fabs((r.y()+r.height()) - eventPos.y()) <= buttonHeight)
    {
        toggleFullscreen();
    }
    else if(fabs(((r.x()+r.width())/2) - eventPos.x() - buttonWidth) <= buttonWidth &&
            fabs((r.y()+r.height()) - eventPos.y()) <= buttonHeight &&
            g_configuration->getOptions()->getShowMovieControls( ))
    {
        contentWindow->setControlState( ControlState(contentWindow->getControlState() ^ STATE_PAUSED) );
    }
    else if(fabs(((r.x()+r.width())/2) - eventPos.x()) <= buttonWidth &&
            fabs((r.y()+r.height()) - eventPos.y()) <= buttonHeight &&
            g_configuration->getOptions()->getShowMovieControls( ))
    {
        contentWindow->setControlState( ControlState(contentWindow->getControlState() ^ STATE_LOOP) );
    }
    else
        moving_ = true;

    QGraphicsItem::mousePressEvent(event);
}