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(); }