Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

qwt_plot_layout.cpp

00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- ***************************** 00002 * Qwt Widget Library 00003 * Copyright (C) 1997 Josef Wilgen 00004 * Copyright (C) 2002 Uwe Rathmann 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the Qwt License, Version 1.0 00008 *****************************************************************************/ 00009 00010 // vim: expandtab 00011 00012 #include <qlabel.h> 00013 #include "qwt_rect.h" 00014 #include "qwt_text.h" 00015 #include "qwt_plot_canvas.h" 00016 #include "qwt_scale.h" 00017 #include "qwt_legend.h" 00018 #include "qwt_plot_layout.h" 00019 00020 class QwtPlotLayoutData 00021 { 00022 friend class QwtPlotLayout; 00023 00024 protected: 00025 QwtPlotLayoutData(); 00026 ~QwtPlotLayoutData(); 00027 00028 void init(const QwtPlot *, const QRect &rect); 00029 00030 struct t_legendData 00031 { 00032 int frameWidth; 00033 int vScrollBarWidth; 00034 int hScrollBarHeight; 00035 QSize hint; 00036 } legend; 00037 00038 struct t_titleData 00039 { 00040 const QwtText *text; 00041 int frameWidth; 00042 } title; 00043 00044 struct t_scaleData 00045 { 00046 bool isEnabled; 00047 const QwtScale *scale; 00048 QFont scaleFont; 00049 int start; 00050 int end; 00051 int baseLineOffset; 00052 int tickOffset; 00053 int dimWithoutTitle; 00054 } scale[QwtPlot::axisCnt]; 00055 00056 struct t_canvasData 00057 { 00058 int frameWidth; 00059 } canvas; 00060 }; 00061 00066 QwtPlotLayout::QwtPlotLayout(): 00067 d_margin(0), 00068 d_spacing(5), 00069 d_alignCanvasToScales(FALSE) 00070 { 00071 setLegendPosition(QwtPlot::Bottom); 00072 setCanvasMargin(4); 00073 d_layoutData = new QwtPlotLayoutData; 00074 00075 invalidate(); 00076 } 00077 00079 QwtPlotLayout::~QwtPlotLayout() 00080 { 00081 delete d_layoutData; 00082 } 00083 00093 void QwtPlotLayout::setMargin(int margin) 00094 { 00095 if ( margin < 0 ) 00096 margin = 0; 00097 d_margin = margin; 00098 } 00099 00106 int QwtPlotLayout::margin() const 00107 { 00108 return d_margin; 00109 } 00110 00124 void QwtPlotLayout::setCanvasMargin(int margin, int axis) 00125 { 00126 if ( margin < -1 ) 00127 margin = -1; 00128 00129 if ( axis == -1 ) 00130 { 00131 for (axis = 0; axis < QwtPlot::axisCnt; axis++) 00132 d_canvasMargin[axis] = margin; 00133 } 00134 else if ( axis >= 0 || axis < QwtPlot::axisCnt ) 00135 d_canvasMargin[axis] = margin; 00136 } 00137 00143 int QwtPlotLayout::canvasMargin(int axis) const 00144 { 00145 if ( axis < 0 || axis >= QwtPlot::axisCnt ) 00146 return 0; 00147 00148 return d_canvasMargin[axis]; 00149 } 00150 00151 00165 void QwtPlotLayout::setAlignCanvasToScales(bool alignCanvasToScales) 00166 { 00167 d_alignCanvasToScales = alignCanvasToScales; 00168 } 00169 00180 bool QwtPlotLayout::alignCanvasToScales() const 00181 { 00182 return d_alignCanvasToScales; 00183 } 00184 00193 void QwtPlotLayout::setSpacing(int spacing) 00194 { 00195 d_spacing = QMAX(0, spacing); 00196 } 00197 00202 int QwtPlotLayout::spacing() const 00203 { 00204 return d_spacing; 00205 } 00206 00221 void QwtPlotLayout::setLegendPosition(QwtPlot::Position pos, double ratio) 00222 { 00223 if ( ratio > 1.0 ) 00224 ratio = 1.0; 00225 00226 switch(pos) 00227 { 00228 case QwtPlot::Top: 00229 case QwtPlot::Bottom: 00230 if ( ratio <= 0.0 ) 00231 ratio = 0.33; 00232 d_legendRatio = ratio; 00233 d_legendPos = pos; 00234 break; 00235 case QwtPlot::Left: 00236 case QwtPlot::Right: 00237 if ( ratio <= 0.0 ) 00238 ratio = 0.5; 00239 d_legendRatio = ratio; 00240 d_legendPos = pos; 00241 break; 00242 default: 00243 break; 00244 } 00245 } 00246 00255 void QwtPlotLayout::setLegendPosition(QwtPlot::Position pos) 00256 { 00257 setLegendPosition(pos, 0.0); 00258 } 00259 00266 QwtPlot::Position QwtPlotLayout::legendPosition() const 00267 { 00268 return d_legendPos; 00269 } 00270 00271 #ifndef QWT_NO_COMPAT 00272 00288 void QwtPlotLayout::setLegendPos(int pos, double ratio) 00289 { 00290 setLegendPosition(QwtPlot::Position(pos), ratio); 00291 } 00292 00300 int QwtPlotLayout::legendPos() const 00301 { 00302 return d_legendPos; 00303 } 00304 00305 #endif // !QWT_NO_COMPAT 00306 00318 void QwtPlotLayout::setLegendRatio(double ratio) 00319 { 00320 setLegendPosition(legendPosition(), ratio); 00321 } 00322 00328 double QwtPlotLayout::legendRatio() const 00329 { 00330 return d_legendRatio; 00331 } 00332 00338 const QRect &QwtPlotLayout::titleRect() const 00339 { 00340 return d_titleRect; 00341 } 00342 00348 const QRect &QwtPlotLayout::legendRect() const 00349 { 00350 return d_legendRect; 00351 } 00352 00359 const QRect &QwtPlotLayout::scaleRect(int axis) const 00360 { 00361 if ( axis < 0 || axis >= QwtPlot::axisCnt ) 00362 { 00363 static QRect dummyRect; 00364 return dummyRect; 00365 } 00366 return d_scaleRect[axis]; 00367 } 00368 00374 const QRect &QwtPlotLayout::canvasRect() const 00375 { 00376 return d_canvasRect; 00377 } 00378 00383 void QwtPlotLayout::invalidate() 00384 { 00385 d_titleRect = d_legendRect = d_canvasRect = QRect(); 00386 for (int axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00387 d_scaleRect[axis] = QRect(); 00388 } 00389 00395 QSize QwtPlotLayout::minimumSizeHint(const QwtPlot *plot) const 00396 { 00397 class ScaleData 00398 { 00399 public: 00400 ScaleData() 00401 { 00402 w = h = minLeft = minRight = tickOffset = 0; 00403 } 00404 00405 int w; 00406 int h; 00407 int minLeft; 00408 int minRight; 00409 int tickOffset; 00410 } scaleData[QwtPlot::axisCnt]; 00411 00412 int canvasBorder[QwtPlot::axisCnt]; 00413 00414 int axis; 00415 for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00416 { 00417 const QwtScale *scl = plot->axis(axis); 00418 if ( scl ) 00419 { 00420 ScaleData &sd = scaleData[axis]; 00421 00422 const QSize hint = scl->minimumSizeHint(); 00423 sd.w = hint.width(); 00424 sd.h = hint.height(); 00425 scl->minBorderDist(sd.minLeft, sd.minRight); 00426 sd.tickOffset = scl->baseLineDist() + 00427 scl->scaleDraw()->majTickLength(); 00428 } 00429 00430 canvasBorder[axis] = plot->canvas()->frameWidth() + 00431 d_canvasMargin[axis] + 1; 00432 00433 } 00434 00435 00436 for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00437 { 00438 ScaleData &sd = scaleData[axis]; 00439 if ( sd.w && (axis == QwtPlot::xBottom || axis == QwtPlot::xTop) ) 00440 { 00441 if ( (sd.minLeft > canvasBorder[QwtPlot::yLeft]) 00442 && scaleData[QwtPlot::yLeft].w ) 00443 { 00444 int shiftLeft = sd.minLeft - canvasBorder[QwtPlot::yLeft]; 00445 if ( shiftLeft > scaleData[QwtPlot::yLeft].w ) 00446 shiftLeft = scaleData[QwtPlot::yLeft].w; 00447 00448 sd.w -= shiftLeft; 00449 } 00450 if ( (sd.minRight > canvasBorder[QwtPlot::yRight]) 00451 && scaleData[QwtPlot::yRight].w ) 00452 { 00453 int shiftRight = sd.minRight - canvasBorder[QwtPlot::yRight]; 00454 if ( shiftRight > scaleData[QwtPlot::yRight].w ) 00455 shiftRight = scaleData[QwtPlot::yRight].w; 00456 00457 sd.w -= shiftRight; 00458 } 00459 } 00460 00461 if ( sd.h && (axis == QwtPlot::yLeft || axis == QwtPlot::yRight) ) 00462 { 00463 if ( (sd.minLeft > canvasBorder[QwtPlot::xBottom]) && 00464 scaleData[QwtPlot::xBottom].h ) 00465 { 00466 int shiftBottom = sd.minLeft - canvasBorder[QwtPlot::xBottom]; 00467 if ( shiftBottom > scaleData[QwtPlot::xBottom].tickOffset ) 00468 shiftBottom = scaleData[QwtPlot::xBottom].tickOffset; 00469 00470 sd.h -= shiftBottom; 00471 } 00472 if ( (sd.minLeft > canvasBorder[QwtPlot::xTop]) && 00473 scaleData[QwtPlot::xTop].h ) 00474 { 00475 int shiftTop = sd.minRight - canvasBorder[QwtPlot::xTop]; 00476 if ( shiftTop > scaleData[QwtPlot::xTop].tickOffset ) 00477 shiftTop = scaleData[QwtPlot::xTop].tickOffset; 00478 00479 sd.h -= shiftTop; 00480 } 00481 } 00482 } 00483 00484 const QwtPlotCanvas *canvas = plot->canvas(); 00485 00486 int w = scaleData[QwtPlot::yLeft].w + scaleData[QwtPlot::yRight].w 00487 + QMAX(scaleData[QwtPlot::xBottom].w, scaleData[QwtPlot::xTop].w) 00488 + 2 * (canvas->frameWidth() + 1); 00489 int h = scaleData[QwtPlot::xBottom].h + scaleData[QwtPlot::xTop].h 00490 + QMAX(scaleData[QwtPlot::yLeft].h, scaleData[QwtPlot::yRight].h) 00491 + 2 * (canvas->frameWidth() + 1); 00492 00493 const QLabel *title = plot->titleLabel(); 00494 if (title && !title->text().isEmpty()) 00495 { 00496 // If only QwtPlot::yLeft or QwtPlot::yRight is showing, 00497 // we center on the plot canvas. 00498 const bool centerOnCanvas = plot->axis(QwtPlot::yLeft) == 0 00499 || plot->axis(QwtPlot::yRight) == 0; 00500 00501 int titleW = w; 00502 if ( centerOnCanvas ) 00503 { 00504 titleW -= scaleData[QwtPlot::yLeft].w 00505 + scaleData[QwtPlot::yRight].w; 00506 } 00507 00508 int titleH = title->heightForWidth(titleW); 00509 if ( titleH > titleW ) // Compensate for a long title 00510 { 00511 w = titleW = titleH; 00512 if ( centerOnCanvas ) 00513 { 00514 w += scaleData[QwtPlot::yLeft].w 00515 + scaleData[QwtPlot::yRight].w; 00516 } 00517 00518 titleH = title->heightForWidth(titleW); 00519 } 00520 h += titleH + d_spacing; 00521 } 00522 00523 // Compute the legend contribution 00524 00525 const QwtLegend *legend = plot->legend(); 00526 if ( legend && !legend->isEmpty() ) 00527 { 00528 if ( d_legendPos == QwtPlot::Left || d_legendPos == QwtPlot::Right ) 00529 { 00530 int legendW = legend->sizeHint().width(); 00531 int legendH = legend->heightForWidth(legendW); 00532 00533 if ( legend->frameWidth() > 0 ) 00534 w += d_spacing; 00535 00536 if ( legendH > h ) 00537 legendW += legend->verticalScrollBar()->sizeHint().height(); 00538 00539 if ( d_legendRatio < 1.0 ) 00540 legendW = QMIN(legendW, int(w / (1.0 - d_legendRatio))); 00541 00542 w += legendW; 00543 } 00544 else // QwtPlot::Top, QwtPlot::Bottom 00545 { 00546 int legendW = QMIN(legend->sizeHint().width(), w); 00547 int legendH = legend->heightForWidth(legendW); 00548 00549 if ( legend->frameWidth() > 0 ) 00550 h += d_spacing; 00551 00552 if ( d_legendRatio < 1.0 ) 00553 legendH = QMIN(legendH, int(h / (1.0 - d_legendRatio))); 00554 00555 h += legendH; 00556 } 00557 } 00558 00559 w += 2 * d_margin; 00560 h += 2 * d_margin; 00561 00562 return QSize( w, h ); 00563 } 00564 00572 QRect QwtPlotLayout::layoutLegend(int options, 00573 const QRect &rect) const 00574 { 00575 const QSize hint(d_layoutData->legend.hint); 00576 00577 int dim; 00578 if ( d_legendPos == QwtPlot::Left || d_legendPos == QwtPlot::Right ) 00579 { 00580 // We don't allow vertical legends to take more than 00581 // half of the available space. 00582 00583 dim = QMIN(hint.width(), int(rect.width() * d_legendRatio)); 00584 00585 if ( !(options & IgnoreScrollbars) ) 00586 { 00587 if ( hint.height() > rect.height() ) 00588 { 00589 // The legend will need additional 00590 // space for the vertical scrollbar. 00591 00592 dim += d_layoutData->legend.vScrollBarWidth; 00593 } 00594 } 00595 } 00596 else 00597 { 00598 dim = QMIN(hint.height(), int(rect.height() * d_legendRatio)); 00599 dim = QMAX(dim, d_layoutData->legend.hScrollBarHeight); 00600 } 00601 00602 QRect legendRect = rect; 00603 switch(d_legendPos) 00604 { 00605 case QwtPlot::Left: 00606 legendRect.setWidth(dim); 00607 break; 00608 case QwtPlot::Right: 00609 legendRect.setX(rect.right() - dim + 1); 00610 legendRect.setWidth(dim); 00611 break; 00612 case QwtPlot::Top: 00613 legendRect.setHeight(dim); 00614 break; 00615 case QwtPlot::Bottom: 00616 legendRect.setY(rect.bottom() - dim + 1); 00617 legendRect.setHeight(dim); 00618 break; 00619 } 00620 00621 return legendRect; 00622 } 00623 00630 QRect QwtPlotLayout::alignLegend(const QRect &canvasRect, 00631 const QRect &legendRect) const 00632 { 00633 QRect alignedRect = legendRect; 00634 00635 if ( d_legendPos == QwtPlot::Bottom || d_legendPos == QwtPlot::Top ) 00636 { 00637 if ( d_layoutData->legend.hint.width() < canvasRect.width() ) 00638 { 00639 alignedRect.setX(canvasRect.x()); 00640 alignedRect.setWidth(canvasRect.width()); 00641 } 00642 } 00643 else 00644 { 00645 if ( d_layoutData->legend.hint.height() < canvasRect.height() ) 00646 { 00647 alignedRect.setY(canvasRect.y()); 00648 alignedRect.setHeight(canvasRect.height()); 00649 } 00650 } 00651 00652 return alignedRect; 00653 } 00654 00664 void QwtPlotLayout::expandLineBreaks(int options, const QRect &rect, 00665 int &dimTitle, int dimAxis[QwtPlot::axisCnt]) const 00666 { 00667 dimTitle = 0; 00668 for ( int i = 0; i < QwtPlot::axisCnt; i++ ) 00669 dimAxis[i] = 0; 00670 00671 bool done = FALSE; 00672 while (!done) 00673 { 00674 done = TRUE; 00675 00676 // the size for the 4 axis depend on each other. Expanding 00677 // the height of a horizontal axis will shrink the height 00678 // for the vertical axis, shrinking the height of a vertical 00679 // axis will result in a line break what will expand the 00680 // width and results in shrinking the width of a horizontal 00681 // axis what might result in a line break of a horizontal 00682 // axis ... . So we loop as long until no size changes. 00683 00684 if ( d_layoutData->title.text) 00685 { 00686 int w = rect.width(); 00687 00688 if ( d_layoutData->scale[QwtPlot::yLeft].isEnabled 00689 != d_layoutData->scale[QwtPlot::yRight].isEnabled ) 00690 { 00691 // center to the canvas 00692 w -= dimAxis[QwtPlot::yLeft] + dimAxis[QwtPlot::yRight]; 00693 } 00694 00695 int d = d_layoutData->title.text->heightForWidth(w); 00696 if ( !(options & IgnoreFrames) ) 00697 d += 2 * d_layoutData->title.frameWidth; 00698 00699 if ( d > dimTitle ) 00700 { 00701 dimTitle = d; 00702 done = FALSE; 00703 } 00704 } 00705 00706 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00707 { 00708 int backboneOffset = d_canvasMargin[axis]; 00709 if ( !(options & IgnoreFrames) ) 00710 backboneOffset += d_layoutData->canvas.frameWidth; 00711 00712 const struct QwtPlotLayoutData::t_scaleData &scaleData = 00713 d_layoutData->scale[axis]; 00714 00715 if (scaleData.isEnabled) 00716 { 00717 int length; 00718 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) 00719 { 00720 length = rect.width() - dimAxis[QwtPlot::yLeft] 00721 - dimAxis[QwtPlot::yRight]; 00722 length += QMIN(dimAxis[QwtPlot::yLeft], 00723 scaleData.start - backboneOffset); 00724 length += QMIN(dimAxis[QwtPlot::yRight], 00725 scaleData.end - backboneOffset); 00726 } 00727 else // QwtPlot::yLeft, QwtPlot::yRight 00728 { 00729 length = rect.height() - dimAxis[QwtPlot::xTop] 00730 - dimAxis[QwtPlot::xBottom]; 00731 00732 if ( dimAxis[QwtPlot::xBottom] > 0 ) 00733 { 00734 length += QMIN( 00735 d_layoutData->scale[QwtPlot::xBottom].tickOffset, 00736 scaleData.start - backboneOffset); 00737 } 00738 if ( dimAxis[QwtPlot::xTop] > 0 ) 00739 { 00740 length += QMIN( 00741 d_layoutData->scale[QwtPlot::xTop].tickOffset, 00742 scaleData.end - backboneOffset); 00743 } 00744 00745 if ( dimTitle > 0 ) 00746 length -= dimTitle + d_spacing; 00747 } 00748 00749 int d = scaleData.dimWithoutTitle; 00750 if ( !scaleData.scale->title().isEmpty() ) 00751 { 00752 d += scaleData.scale->titleHeightForWidth(length); 00753 } 00754 00755 if ( options & AlignScales ) 00756 d -= scaleData.baseLineOffset; 00757 00758 if ( d > dimAxis[axis] ) 00759 { 00760 dimAxis[axis] = d; 00761 done = FALSE; 00762 } 00763 } 00764 } 00765 } 00766 } 00767 00773 void QwtPlotLayout::alignScales(int options, 00774 QRect &canvasRect, QRect scaleRect[QwtPlot::axisCnt]) const 00775 { 00776 int axis; 00777 00778 int backboneOffset[QwtPlot::axisCnt]; 00779 for (axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00780 { 00781 backboneOffset[axis] = 0; 00782 if ( !d_alignCanvasToScales ) 00783 backboneOffset[axis] += d_canvasMargin[axis]; 00784 if ( !(options & IgnoreFrames) ) 00785 backboneOffset[axis] += d_layoutData->canvas.frameWidth; 00786 } 00787 00788 for (axis = 0; axis < QwtPlot::axisCnt; axis++ ) 00789 { 00790 if ( !scaleRect[axis].isValid() ) 00791 continue; 00792 00793 const int startDist = d_layoutData->scale[axis].start; 00794 const int endDist = d_layoutData->scale[axis].end; 00795 00796 QRect &axisRect = scaleRect[axis]; 00797 00798 if ( axis == QwtPlot::xTop || axis == QwtPlot::xBottom ) 00799 { 00800 const int leftOffset = backboneOffset[QwtPlot::yLeft] - startDist; 00801 00802 if ( scaleRect[QwtPlot::yLeft].isValid() ) 00803 { 00804 int minLeft = scaleRect[QwtPlot::yLeft].left(); 00805 int left = axisRect.left() + leftOffset; 00806 axisRect.setLeft(QMAX(left, minLeft)); 00807 } 00808 else 00809 { 00810 if ( d_alignCanvasToScales ) 00811 { 00812 canvasRect.setLeft(QMAX(canvasRect.left(), 00813 axisRect.left() - leftOffset)); 00814 } 00815 else 00816 { 00817 if ( leftOffset > 0 ) 00818 axisRect.setLeft(axisRect.left() + leftOffset); 00819 } 00820 } 00821 00822 const int rightOffset = backboneOffset[QwtPlot::yRight] - endDist; 00823 00824 if ( scaleRect[QwtPlot::yRight].isValid() ) 00825 { 00826 int maxRight = scaleRect[QwtPlot::yRight].right(); 00827 int right = axisRect.right() - rightOffset; 00828 axisRect.setRight(QMIN(right, maxRight)); 00829 } 00830 else 00831 { 00832 if ( d_alignCanvasToScales ) 00833 { 00834 canvasRect.setRight( QMIN(canvasRect.right(), 00835 axisRect.right() + rightOffset) ); 00836 } 00837 else 00838 { 00839 if ( rightOffset > 0 ) 00840 axisRect.setRight(axisRect.right() - rightOffset); 00841 } 00842 } 00843 } 00844 else // QwtPlot::yLeft, QwtPlot::yRight 00845 { 00846 const int bottomOffset = 00847 backboneOffset[QwtPlot::xBottom] - startDist; 00848 00849 if ( scaleRect[QwtPlot::xBottom].isValid() ) 00850 { 00851 int maxBottom = scaleRect[QwtPlot::xBottom].top() + 00852 d_layoutData->scale[QwtPlot::xBottom].tickOffset; 00853 00854 int bottom = axisRect.bottom() - bottomOffset; 00855 axisRect.setBottom(QMIN(bottom, maxBottom)); 00856 } 00857 else 00858 { 00859 if ( d_alignCanvasToScales ) 00860 { 00861 canvasRect.setBottom(QMIN(canvasRect.bottom(), 00862 axisRect.bottom() + bottomOffset)); 00863 } 00864 else 00865 { 00866 if ( bottomOffset > 0 ) 00867 axisRect.setBottom(axisRect.bottom() - bottomOffset); 00868 } 00869 } 00870 00871 const int topOffset = backboneOffset[QwtPlot::xTop] - endDist; 00872 00873 if ( scaleRect[QwtPlot::xTop].isValid() ) 00874 { 00875 int minTop = scaleRect[QwtPlot::xTop].bottom() - 00876 d_layoutData->scale[QwtPlot::xTop].tickOffset; 00877 00878 int top = axisRect.top() + topOffset; 00879 axisRect.setTop(QMAX(top, minTop)); 00880 } 00881 else 00882 { 00883 if ( d_alignCanvasToScales ) 00884 { 00885 canvasRect.setTop(QMAX(canvasRect.top(), 00886 axisRect.top() + - topOffset)); 00887 } 00888 else 00889 { 00890 if ( topOffset > 0 ) 00891 axisRect.setTop(axisRect.top() + topOffset); 00892 } 00893 } 00894 } 00895 } 00896 } 00897 00910 void QwtPlotLayout::activate(const QwtPlot *plot, 00911 const QRect &plotRect, int options) 00912 { 00913 invalidate(); 00914 00915 QRect rect(plotRect); // undistributed rest of the plot rect 00916 00917 if ( !(options & IgnoreMargin) ) 00918 { 00919 // subtract the margin 00920 00921 rect.setRect( 00922 rect.x() + d_margin, 00923 rect.y() + d_margin, 00924 rect.width() - 2 * d_margin, 00925 rect.height() - 2 * d_margin 00926 ); 00927 } 00928 00929 // We extract all layout relevant data from the widgets, 00930 // filter them through pfilter and save them to d_layoutData. 00931 00932 d_layoutData->init(plot, rect); 00933 00934 if (!(options & IgnoreLegend) 00935 && plot->legend() && !plot->legend()->isEmpty() ) 00936 { 00937 d_legendRect = layoutLegend(options, rect); 00938 00939 // subtract d_legendRect from rect 00940 00941 const QRegion region(rect); 00942 rect = region.subtract(d_legendRect).boundingRect(); 00943 00944 if ( d_layoutData->legend.frameWidth && 00945 !(options & IgnoreFrames ) ) 00946 { 00947 // In case of a frame we have to insert a spacing. 00948 // Otherwise the leading of the font separates 00949 // legend and scale/canvas 00950 00951 switch(d_legendPos) 00952 { 00953 case QwtPlot::Left: 00954 rect.setLeft(rect.left() + d_spacing); 00955 break; 00956 case QwtPlot::Right: 00957 rect.setRight(rect.right() - d_spacing); 00958 break; 00959 case QwtPlot::Top: 00960 rect.setTop(rect.top() + d_spacing); 00961 break; 00962 case QwtPlot::Bottom: 00963 rect.setBottom(rect.bottom() - d_spacing); 00964 break; 00965 } 00966 } 00967 } 00968 00969 /* 00970 +---+-----------+---+ 00971 | Title | 00972 +---+-----------+---+ 00973 | | Axis | | 00974 +---+-----------+---+ 00975 | A | | A | 00976 | x | Canvas | x | 00977 | i | | i | 00978 | s | | s | 00979 +---+-----------+---+ 00980 | | Axis | | 00981 +---+-----------+---+ 00982 */ 00983 00984 00985 // axes and title include text labels. The height of each 00986 // label depends on its line breaks, that depend on the width 00987 // for the label. A line break in a horizontal text will reduce 00988 // the available width for vertical texts and vice versa. 00989 // expandLineBreaks finds the height/width for title and axes 00990 // including all line breaks. 00991 00992 int dimTitle, dimAxes[QwtPlot::axisCnt]; 00993 expandLineBreaks(options, rect, dimTitle, dimAxes); 00994 00995 if (dimTitle > 0 ) 00996 { 00997 d_titleRect = QRect(rect.x(), rect.y(), 00998 rect.width(), dimTitle); 00999 01000 if ( d_layoutData->scale[QwtPlot::yLeft].isEnabled != 01001 d_layoutData->scale[QwtPlot::yRight].isEnabled ) 01002 { 01003 // if only one of the y axes is missing we align 01004 // the title centered to the canvas 01005 01006 d_titleRect.setX(rect.x() + dimAxes[QwtPlot::yLeft]); 01007 d_titleRect.setWidth(rect.width() 01008 - dimAxes[QwtPlot::yLeft] - dimAxes[QwtPlot::yRight]); 01009 } 01010 01011 // subtract title 01012 rect.setTop(rect.top() + dimTitle + d_spacing); 01013 } 01014 01015 d_canvasRect.setRect( 01016 rect.x() + dimAxes[QwtPlot::yLeft], 01017 rect.y() + dimAxes[QwtPlot::xTop], 01018 rect.width() - dimAxes[QwtPlot::yRight] - dimAxes[QwtPlot::yLeft], 01019 rect.height() - dimAxes[QwtPlot::xBottom] - dimAxes[QwtPlot::xTop]); 01020 01021 for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ ) 01022 { 01023 // set the rects for the axes 01024 01025 if ( dimAxes[axis] ) 01026 { 01027 int dim = dimAxes[axis]; 01028 QRect &scaleRect = d_scaleRect[axis]; 01029 01030 scaleRect = d_canvasRect; 01031 switch(axis) 01032 { 01033 case QwtPlot::yLeft: 01034 scaleRect.setX(d_canvasRect.left() - dim); 01035 scaleRect.setWidth(dim); 01036 break; 01037 case QwtPlot::yRight: 01038 scaleRect.setX(d_canvasRect.right() + 1); 01039 scaleRect.setWidth(dim); 01040 break; 01041 case QwtPlot::xBottom: 01042 scaleRect.setY(d_canvasRect.bottom() + 1); 01043 scaleRect.setHeight(dim); 01044 break; 01045 case QwtPlot::xTop: 01046 scaleRect.setY(d_canvasRect.top() - dim); 01047 scaleRect.setHeight(dim); 01048 break; 01049 } 01050 scaleRect = scaleRect.normalize(); 01051 } 01052 } 01053 01054 // +---+-----------+---+ 01055 // | <- Axis -> | 01056 // +-^-+-----------+-^-+ 01057 // | | | | | | 01058 // | | | | 01059 // | A | | A | 01060 // | x | Canvas | x | 01061 // | i | | i | 01062 // | s | | s | 01063 // | | | | 01064 // | | | | | | 01065 // +-V-+-----------+-V-+ 01066 // | <- Axis -> | 01067 // +---+-----------+---+ 01068 01069 // The ticks of the axes - not the labels above - should 01070 // be aligned to the canvas. So we try to use the empty 01071 // corners to extend the axes, so that the label texts 01072 // left/right of the min/max ticks are moved into them. 01073 01074 alignScales(options, d_canvasRect, d_scaleRect); 01075 01076 if (!d_legendRect.isEmpty() ) 01077 { 01078 // We prefer to align the legend to the canvas - not to 01079 // the complete plot - if possible. 01080 01081 d_legendRect = alignLegend(d_canvasRect, d_legendRect); 01082 } 01083 } 01084 01085 QwtPlotLayoutData::QwtPlotLayoutData() 01086 { 01087 title.text = NULL; 01088 } 01089 01090 QwtPlotLayoutData::~QwtPlotLayoutData() 01091 { 01092 delete title.text; 01093 } 01094 01095 /* 01096 Extract all layout relevant data from the plot components 01097 */ 01098 01099 void QwtPlotLayoutData::init(const QwtPlot *plot, const QRect &rect) 01100 { 01101 // legend 01102 01103 legend.frameWidth = plot->legend()->frameWidth(); 01104 legend.vScrollBarWidth = 01105 plot->legend()->verticalScrollBar()->sizeHint().width(); 01106 legend.hScrollBarHeight = 01107 plot->legend()->horizontalScrollBar()->sizeHint().height(); 01108 01109 const QSize hint = plot->legend()->sizeHint(); 01110 01111 int w = QMIN(hint.width(), rect.width()); 01112 int h = plot->legend()->heightForWidth(w); 01113 if ( h == 0 ) 01114 h = hint.height(); 01115 01116 if ( h > rect.height() ) 01117 w += legend.vScrollBarWidth; 01118 01119 legend.hint = QSize(w, h); 01120 01121 // title 01122 01123 title.frameWidth = 0; 01124 delete title.text; 01125 title.text = NULL; 01126 01127 if (plot->titleLabel() && !plot->titleLabel()->text().isEmpty()) 01128 { 01129 const QLabel *label = plot->titleLabel(); 01130 title.text = QwtText::makeText(label->text(), label->textFormat(), 01131 label->alignment(), label->font()); 01132 title.frameWidth = plot->titleLabel()->frameWidth(); 01133 } 01134 01135 // scales 01136 01137 for (int axis = 0; axis < QwtPlot::axisCnt; axis++ ) 01138 { 01139 const QwtScale *sd = plot->axis(axis); 01140 if ( sd ) 01141 { 01142 scale[axis].isEnabled = TRUE; 01143 01144 scale[axis].scale = sd; 01145 01146 scale[axis].scaleFont = sd->font(); 01147 01148 scale[axis].start = sd->startBorderDist(); 01149 scale[axis].end = sd->endBorderDist(); 01150 01151 scale[axis].baseLineOffset = sd->baseLineDist(); 01152 scale[axis].tickOffset = sd->baseLineDist() + 01153 (int)sd->scaleDraw()->majTickLength(); 01154 01155 scale[axis].dimWithoutTitle = sd->dimForLength( 01156 QCOORD_MAX, scale[axis].scaleFont); 01157 01158 if ( !sd->title().isEmpty() ) 01159 { 01160 scale[axis].dimWithoutTitle -= 01161 sd->titleHeightForWidth(QCOORD_MAX); 01162 } 01163 } 01164 else 01165 { 01166 scale[axis].isEnabled = FALSE; 01167 scale[axis].start = 0; 01168 scale[axis].end = 0; 01169 scale[axis].baseLineOffset = 0; 01170 scale[axis].tickOffset = 0; 01171 scale[axis].dimWithoutTitle = 0; 01172 } 01173 } 01174 01175 // canvas 01176 01177 canvas.frameWidth = plot->canvas()->frameWidth(); 01178 }

Generated on Tue Nov 16 21:12:20 2004 for Qwt User's Guide by doxygen 1.3.8