Esempio n. 1
0
QSize MultiLayer::arrangeLayers(bool userSize) {
  const QRect rect = canvas->geometry();

  gsl_vector *xTopR = gsl_vector_calloc(
      graphs);  // ratio between top axis + title and canvas height
  gsl_vector *xBottomR =
      gsl_vector_calloc(graphs);  // ratio between bottom axis and canvas height
  gsl_vector *yLeftR = gsl_vector_calloc(graphs);
  gsl_vector *yRightR = gsl_vector_calloc(graphs);
  gsl_vector *maxXTopHeight =
      gsl_vector_calloc(rows);  // maximum top axis + title height in a row
  gsl_vector *maxXBottomHeight =
      gsl_vector_calloc(rows);  // maximum bottom axis height in a row
  gsl_vector *maxYLeftWidth =
      gsl_vector_calloc(cols);  // maximum left axis width in a column
  gsl_vector *maxYRightWidth =
      gsl_vector_calloc(cols);  // maximum right axis width in a column
  gsl_vector *Y = gsl_vector_calloc(rows);
  gsl_vector *X = gsl_vector_calloc(cols);

  int i;
  for (i = 0; i < graphs;
       i++) {  // calculate scales/canvas dimensions reports for each layer and
               // stores them in the above vectors
    Graph *gr = (Graph *)graphsList.at(i);
    QwtPlot *plot = gr->plotWidget();
    QwtPlotLayout *plotLayout = plot->plotLayout();
    QRect cRect = plotLayout->canvasRect();
    double ch = (double)cRect.height();
    double cw = (double)cRect.width();

    QRect tRect = plotLayout->titleRect();
    QwtScaleWidget *scale = (QwtScaleWidget *)plot->axisWidget(QwtPlot::xTop);

    int topHeight = 0;
    if (!tRect.isNull()) topHeight += tRect.height() + plotLayout->spacing();
    if (scale) {
      QRect sRect = plotLayout->scaleRect(QwtPlot::xTop);
      topHeight += sRect.height();
    }
    gsl_vector_set(xTopR, i, double(topHeight) / ch);

    scale = (QwtScaleWidget *)plot->axisWidget(QwtPlot::xBottom);
    if (scale) {
      QRect sRect = plotLayout->scaleRect(QwtPlot::xBottom);
      gsl_vector_set(xBottomR, i, double(sRect.height()) / ch);
    }

    scale = (QwtScaleWidget *)plot->axisWidget(QwtPlot::yLeft);
    if (scale) {
      QRect sRect = plotLayout->scaleRect(QwtPlot::yLeft);
      gsl_vector_set(yLeftR, i, double(sRect.width()) / cw);
    }

    scale = (QwtScaleWidget *)plot->axisWidget(QwtPlot::yRight);
    if (scale) {
      QRect sRect = plotLayout->scaleRect(QwtPlot::yRight);
      gsl_vector_set(yRightR, i, double(sRect.width()) / cw);
    }

    // calculate max scales/canvas dimensions ratio for each line and column and
    // stores them to vectors
    int row = i / cols;
    if (row >= rows) row = rows - 1;

    int col = i % cols;

    double aux = gsl_vector_get(xTopR, i);
    double old_max = gsl_vector_get(maxXTopHeight, row);
    if (aux >= old_max) gsl_vector_set(maxXTopHeight, row, aux);

    aux = gsl_vector_get(xBottomR, i);
    if (aux >= gsl_vector_get(maxXBottomHeight, row))
      gsl_vector_set(maxXBottomHeight, row, aux);

    aux = gsl_vector_get(yLeftR, i);
    if (aux >= gsl_vector_get(maxYLeftWidth, col))
      gsl_vector_set(maxYLeftWidth, col, aux);

    aux = gsl_vector_get(yRightR, i);
    if (aux >= gsl_vector_get(maxYRightWidth, col))
      gsl_vector_set(maxYRightWidth, col, aux);
  }

  double c_heights = 0.0;
  for (i = 0; i < rows; i++) {
    gsl_vector_set(Y, i, c_heights);
    c_heights += 1 + gsl_vector_get(maxXTopHeight, i) +
                 gsl_vector_get(maxXBottomHeight, i);
  }

  double c_widths = 0.0;
  for (i = 0; i < cols; i++) {
    gsl_vector_set(X, i, c_widths);
    c_widths += 1 + gsl_vector_get(maxYLeftWidth, i) +
                gsl_vector_get(maxYRightWidth, i);
  }

  if (!userSize) {
    l_canvas_width = int(
        (rect.width() - (cols - 1) * colsSpace - right_margin - left_margin) /
        c_widths);
    l_canvas_height = int(
        (rect.height() - (rows - 1) * rowsSpace - top_margin - bottom_margin) /
        c_heights);
  }

  QSize size = QSize(l_canvas_width, l_canvas_height);

  for (i = 0; i < graphs; i++) {
    int row = i / cols;
    if (row >= rows) row = rows - 1;

    int col = i % cols;

    // calculate sizes and positions for layers
    const int w = int(l_canvas_width * (1 + gsl_vector_get(yLeftR, i) +
                                        gsl_vector_get(yRightR, i)));
    const int h = int(l_canvas_height * (1 + gsl_vector_get(xTopR, i) +
                                         gsl_vector_get(xBottomR, i)));

    int x = left_margin + col * colsSpace;
    if (hor_align == HCenter)
      x += int(l_canvas_width *
               (gsl_vector_get(X, col) + gsl_vector_get(maxYLeftWidth, col) -
                gsl_vector_get(yLeftR, i)));
    else if (hor_align == Left)
      x += int(l_canvas_width * gsl_vector_get(X, col));
    else if (hor_align == Right)
      x +=
          int(l_canvas_width *
              (gsl_vector_get(X, col) + gsl_vector_get(maxYLeftWidth, col) -
               gsl_vector_get(yLeftR, i) + gsl_vector_get(maxYRightWidth, col) -
               gsl_vector_get(yRightR, i)));

    int y = top_margin + row * rowsSpace;
    if (vert_align == VCenter)
      y += int(l_canvas_height *
               (gsl_vector_get(Y, row) + gsl_vector_get(maxXTopHeight, row) -
                gsl_vector_get(xTopR, i)));
    else if (vert_align == Top)
      y += int(l_canvas_height * gsl_vector_get(Y, row));
    else if (vert_align == Bottom)
      y += int(l_canvas_height *
               (gsl_vector_get(Y, row) + gsl_vector_get(maxXTopHeight, row) -
                gsl_vector_get(xTopR, i) +
                +gsl_vector_get(maxXBottomHeight, row) -
                gsl_vector_get(xBottomR, i)));

    // resizes and moves layers
    Graph *gr = (Graph *)graphsList.at(i);
    bool autoscaleFonts = false;
    if (!userSize) {  // When the user specifies the layer canvas size, the
                      // window is resized
      // and the fonts must be scaled accordingly. If the size is calculated
      // automatically we don't rescale the fonts in order to prevent problems
      // with too small fonts when the user adds new layers or when removing
      // layers

      autoscaleFonts = gr->autoscaleFonts();  // save user settings
      gr->setAutoscaleFonts(false);
    }

    gr->setGeometry(QRect(x, y, w, h));
    gr->plotWidget()->resize(QSize(w, h));

    if (!userSize)
      gr->setAutoscaleFonts(autoscaleFonts);  // restore user settings
  }

  // free memory
  gsl_vector_free(maxXTopHeight);
  gsl_vector_free(maxXBottomHeight);
  gsl_vector_free(maxYLeftWidth);
  gsl_vector_free(maxYRightWidth);
  gsl_vector_free(xTopR);
  gsl_vector_free(xBottomR);
  gsl_vector_free(yLeftR);
  gsl_vector_free(yRightR);
  gsl_vector_free(X);
  gsl_vector_free(Y);
  return size;
}
/*!
  Paint the contents of a QwtPlot instance into a given rectangle.

  \param plot Plot to be rendered
  \param painter Painter
  \param plotRect Bounding rectangle

  \sa renderDocument(), renderTo(), QwtPainter::setRoundingAlignment()
*/
void QwtPlotRenderer::render( QwtPlot *plot,
    QPainter *painter, const QRectF &plotRect ) const
{
    if ( painter == 0 || !painter->isActive() ||
            !plotRect.isValid() || plot->size().isNull() )
    {
        return;
    }

    if ( !( d_data->discardFlags & DiscardBackground ) )
        QwtPainter::drawBackgound( painter, plotRect, plot );

    /*
      The layout engine uses the same methods as they are used
      by the Qt layout system. Therefore we need to calculate the
      layout in screen coordinates and paint with a scaled painter.
     */
    QTransform transform;
    transform.scale(
        double( painter->device()->logicalDpiX() ) / plot->logicalDpiX(),
        double( painter->device()->logicalDpiY() ) / plot->logicalDpiY() );

    QRectF layoutRect = transform.inverted().mapRect( plotRect );

    if ( !( d_data->discardFlags & DiscardBackground ) )
    {
        // subtract the contents margins

        int left, top, right, bottom;
        plot->getContentsMargins( &left, &top, &right, &bottom );
        layoutRect.adjust( left, top, -right, -bottom );
    }

    QwtPlotLayout *layout = plot->plotLayout();

    int baseLineDists[QwtAxis::PosCount];
    int canvasMargins[QwtAxis::PosCount];

    for ( int axisPos = 0; axisPos < QwtAxis::PosCount; axisPos++ )
    {
        canvasMargins[ axisPos ] = layout->canvasMargin( axisPos );

        if ( d_data->layoutFlags & FrameWithScales )
        {
            const QwtAxisId axisId( axisPos, QWT_DUMMY_ID );

            QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
            if ( scaleWidget )
            {
                baseLineDists[ axisPos ] = scaleWidget->margin();
                scaleWidget->setMargin( 0 );
            }

            if ( !plot->isAxisVisible( axisId ) )
            {
                int left = 0;
                int right = 0;
                int top = 0;
                int bottom = 0;

                // When we have a scale the frame is painted on
                // the position of the backbone - otherwise we
                // need to introduce a margin around the canvas

                switch( axisPos )
                {
                    case QwtAxis::yLeft:
                        layoutRect.adjust( 1, 0, 0, 0 );
                        break;
                    case QwtAxis::yRight:
                        layoutRect.adjust( 0, 0, -1, 0 );
                        break;
                    case QwtAxis::xTop:
                        layoutRect.adjust( 0, 1, 0, 0 );
                        break;
                    case QwtAxis::xBottom:
                        layoutRect.adjust( 0, 0, 0, -1 );
                        break;
                }
                layoutRect.adjust( left, top, right, bottom );
            }
        }
    }

    // Calculate the layout for the document.

    QwtPlotLayout::Options layoutOptions = QwtPlotLayout::IgnoreScrollbars;

    if ( ( d_data->layoutFlags & FrameWithScales ) ||
        ( d_data->discardFlags & DiscardCanvasFrame ) )
    {
        layoutOptions |= QwtPlotLayout::IgnoreFrames;
    } 


    if ( d_data->discardFlags & DiscardLegend )
        layoutOptions |= QwtPlotLayout::IgnoreLegend;

    if ( d_data->discardFlags & DiscardTitle )
        layoutOptions |= QwtPlotLayout::IgnoreTitle;

    if ( d_data->discardFlags & DiscardFooter )
        layoutOptions |= QwtPlotLayout::IgnoreFooter;

    layout->update( plot, layoutRect, layoutOptions );

    // canvas

    QwtScaleMapTable mapTable = buildCanvasMaps( plot, layout->canvasRect() );
    if ( updateCanvasMargins( plot, layout->canvasRect(), mapTable ) )
    {
        // recalculate maps and layout, when the margins
        // have been changed

        layout->update( plot, layoutRect, layoutOptions );
        mapTable = buildCanvasMaps( plot, layout->canvasRect() );
    }

    // now start painting

    painter->save();
    painter->setWorldTransform( transform, true );

    renderCanvas( plot, painter, layout->canvasRect(), mapTable );

    if ( !( d_data->discardFlags & DiscardTitle )
        && ( !plot->titleLabel()->text().isEmpty() ) )
    {
        renderTitle( plot, painter, layout->titleRect() );
    }

    if ( !( d_data->discardFlags & DiscardFooter )
        && ( !plot->footerLabel()->text().isEmpty() ) )
    {
        renderFooter( plot, painter, layout->footerRect() );
    }

    if ( !( d_data->discardFlags & DiscardLegend )
        && plot->legend() && !plot->legend()->isEmpty() )
    {
        renderLegend( plot, painter, layout->legendRect() );
    }

    for ( int axisPos = 0; axisPos < QwtAxis::PosCount; axisPos++ )
    {
        for ( int i = 0; i < plot->axesCount( i ); i++ )
        {
            const QwtAxisId axisId( axisPos, i );

            QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
            if ( scaleWidget )
            {
                int baseDist = scaleWidget->margin();

                int startDist, endDist;
                scaleWidget->getBorderDistHint( startDist, endDist );

                renderScale( plot, painter, axisId, startDist, endDist,
                    baseDist, layout->scaleRect( axisId ) );
            }
        }
    }

    painter->restore();

    // restore all setting to their original attributes.
    for ( int axisPos = 0; axisPos < QwtAxis::PosCount; axisPos++ )
    {
        if ( d_data->layoutFlags & FrameWithScales )
        {
            const QwtAxisId axisId( axisPos, QWT_DUMMY_ID );

            QwtScaleWidget *scaleWidget = plot->axisWidget( axisId );
            if ( scaleWidget  )
                scaleWidget->setMargin( baseLineDists[axisPos] );
        }

        layout->setCanvasMargin( canvasMargins[axisPos] );
    }

    layout->invalidate();

}