File indexing completed on 2024-12-22 04:17:48
0001 /*************************************************************************** 0002 * * 0003 * copyright : (C) 2007 The University of Toronto * 0004 * netterfield@astro.utoronto.ca * 0005 * * 0006 * This program is free software; you can redistribute it and/or modify * 0007 * it under the terms of the GNU General Public License as published by * 0008 * the Free Software Foundation; either version 2 of the License, or * 0009 * (at your option) any later version. * 0010 * * 0011 ***************************************************************************/ 0012 0013 #include "viewgridlayout.h" 0014 0015 #include "view.h" 0016 #include "viewitem.h" 0017 #include "plotitem.h" 0018 #include "layoutboxitem.h" 0019 #include "sharedaxisboxitem.h" 0020 #include "formatgridhelper.h" 0021 0022 #include <QDebug> 0023 0024 // 0 off, 1 On 0025 #define DEBUG_LAYOUT 0 0026 #define DEBUG_PLOT_STANDARDIZATION 0 0027 #define DEBUG_SHAREDAXIS 0 0028 0029 // What factor should be used to determine "close" plot sizes. 0030 #define PLOT_STANDARDIZATION_FACTOR .2 0031 0032 namespace Kst { 0033 0034 ViewGridLayout::ViewGridLayout(ViewItem *parent) 0035 : QObject(parent), 0036 _enabled(false), 0037 _rowCount(0), 0038 _columnCount(0), 0039 _shareX(false), 0040 _shareY(false) { 0041 _spacing = parent->layoutSpacing(); 0042 _margin = parent->layoutMargins(); 0043 } 0044 0045 0046 ViewGridLayout::~ViewGridLayout() { 0047 } 0048 0049 0050 ViewItem *ViewGridLayout::parentItem() const { 0051 return qobject_cast<ViewItem*>(parent()); 0052 } 0053 0054 0055 void ViewGridLayout::addViewItem(ViewItem *viewItem, int row, int column) { 0056 addViewItem(viewItem, row, column, 1, 1); 0057 } 0058 0059 0060 void ViewGridLayout::addViewItem(ViewItem *viewItem, int row, int column, int rowSpan, int columnSpan) { 0061 LayoutItem item; 0062 item.viewItem = viewItem; 0063 item.row = row; 0064 item.column = column; 0065 item.rowSpan = rowSpan; 0066 item.columnSpan = columnSpan; 0067 item.transform = viewItem->transform(); 0068 item.position = viewItem->pos(); 0069 item.rect = viewItem->rect(); 0070 0071 //Update the row/column counts... 0072 int maxRow = row + rowSpan; 0073 int maxColumn = column + columnSpan; 0074 0075 _rowCount = maxRow > _rowCount ? maxRow : _rowCount; 0076 _columnCount = maxColumn > _columnCount ? maxColumn : _columnCount; 0077 0078 //FIXME these could be consolidated 0079 _items.append(item); 0080 _itemInfos.insert(viewItem, item); 0081 _itemLayouts.insert(qMakePair(item.row, item.column), item); 0082 } 0083 0084 0085 int ViewGridLayout::rowCount() const { 0086 return _rowCount; 0087 } 0088 0089 0090 int ViewGridLayout::columnCount() const { 0091 return _columnCount; 0092 } 0093 0094 0095 qreal ViewGridLayout::plotLabelMarginWidth(const PlotItem *plotItem) const { 0096 if (_itemInfos.contains(plotItem)) { 0097 LayoutItem item = _itemInfos.value(plotItem); 0098 if (_plotMarginWidth.contains(item.columnSpan)) 0099 return _plotMarginWidth.value(item.columnSpan).labelMargin; 0100 } 0101 0102 return 0.0; 0103 } 0104 0105 0106 qreal ViewGridLayout::plotLabelMarginHeight(const PlotItem *plotItem) const { 0107 if (_itemInfos.contains(plotItem)) { 0108 LayoutItem item = _itemInfos.value(plotItem); 0109 if (_plotMarginHeight.contains(item.rowSpan)) 0110 return _plotMarginHeight.value(item.rowSpan).labelMargin; 0111 } 0112 0113 return 0.0; 0114 } 0115 0116 0117 qreal ViewGridLayout::plotAxisMarginWidth(const PlotItem *plotItem) const { 0118 if (_itemInfos.contains(plotItem)) { 0119 LayoutItem item = _itemInfos.value(plotItem); 0120 if (_plotMarginWidth.contains(item.columnSpan)) 0121 return _plotMarginWidth.value(item.columnSpan).axisMargin; 0122 } 0123 0124 return 0.0; 0125 } 0126 0127 0128 qreal ViewGridLayout::plotAxisMarginHeight(const PlotItem *plotItem) const { 0129 if (_itemInfos.contains(plotItem)) { 0130 LayoutItem item = _itemInfos.value(plotItem); 0131 if (_plotMarginHeight.contains(item.rowSpan)) 0132 return _plotMarginHeight.value(item.rowSpan).axisMargin; 0133 } 0134 0135 return 0.0; 0136 } 0137 0138 0139 bool ViewGridLayout::isEnabled() const { 0140 return _enabled; 0141 } 0142 0143 0144 void ViewGridLayout::setEnabled(bool enabled) { 0145 _enabled = enabled; 0146 emit enabledChanged(_enabled); 0147 } 0148 0149 0150 void ViewGridLayout::reset() { 0151 foreach (const LayoutItem &item, _items) { 0152 item.viewItem->setTransform(item.transform); 0153 item.viewItem->setPos(item.position); 0154 item.viewItem->setViewRect(item.rect); 0155 } 0156 } 0157 0158 0159 void ViewGridLayout::sharePlots(ViewItem *item, QPainter *painter, bool creation) { 0160 Q_ASSERT(item); 0161 Q_ASSERT(item->view()); 0162 0163 // Gather all children of the SharedAxisBoxItem. 0164 QList<ViewItem*> viewItems; 0165 QList<QGraphicsItem*> list = item->QGraphicsItem::childItems(); 0166 if (list.isEmpty()) 0167 return; //not added to undostack 0168 0169 foreach (QGraphicsItem *graphicsItem, list) { 0170 ViewItem *viewItem = dynamic_cast<ViewItem*>(graphicsItem); 0171 if (!viewItem || viewItem->hasStaticGeometry() || !viewItem->allowsLayout() || viewItem->parentItem() != item) 0172 continue; 0173 viewItems.append(viewItem); 0174 } 0175 0176 if (viewItems.isEmpty()) 0177 return; //not added to undostack 0178 0179 0180 ViewGridLayout *layout = new ViewGridLayout(item); 0181 0182 FormatGridHelper grid(viewItems); 0183 0184 int n_views = viewItems.size(); 0185 for (int i_view = 0; i_view<n_views; i_view++) { 0186 ViewItem *v = viewItems.at(i_view); 0187 struct AutoFormatRC rc = grid.rcList.at(i_view); 0188 layout->addViewItem(v, rc.row, rc.col, 1, 1); 0189 } 0190 layout->apply(); 0191 0192 layout->shareAxis(painter, creation); 0193 0194 } 0195 0196 0197 void ViewGridLayout::standardizePlotMargins(ViewItem *item, QPainter *painter) { 0198 QList<PlotItem*> plotItems; 0199 if (item->view()) { 0200 QList<QGraphicsItem*> list = item->view()->items(); 0201 foreach (QGraphicsItem *item, list) { 0202 ViewItem *viewItem = dynamic_cast<ViewItem*>(item); 0203 if (!viewItem || !viewItem->isVisible()) 0204 continue; 0205 if (PlotItem *plotItem = qobject_cast<PlotItem*>(viewItem)) { 0206 plotItems.append(plotItem); 0207 } 0208 } 0209 } 0210 0211 #if DEBUG_PLOT_STANDARDIZATION 0212 qDebug() << "Ready to standarize" << plotItems.count() << "plots"; 0213 #endif 0214 0215 QMap<int, qreal> leftMarginWidths; 0216 QMap<int, qreal> rightMarginWidths; 0217 QMap<int, qreal> topMarginWidths; 0218 QMap<int, qreal> bottomMarginHeights; 0219 foreach (PlotItem* plotItem, plotItems) { 0220 plotItem->calculateBorders(painter); 0221 if (leftMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] < plotItem->leftMarginSize()) { 0222 leftMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] = plotItem->leftMarginSize(); 0223 } 0224 if (rightMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] < plotItem->rightMarginSize()) { 0225 rightMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] = plotItem->rightMarginSize(); 0226 } 0227 if (topMarginWidths[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] < plotItem->topMarginSize()) { 0228 topMarginWidths[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] = plotItem->topMarginSize(); 0229 } 0230 if (bottomMarginHeights[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] < plotItem->bottomMarginSize()) { 0231 bottomMarginHeights[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] = plotItem->bottomMarginSize(); 0232 } 0233 } 0234 0235 #if DEBUG_PLOT_STANDARDIZATION 0236 qDebug() << "Maximum left margin widths" << leftMarginWidths; 0237 qDebug() << "Maximum right margin widths" << rightMarginWidths; 0238 qDebug() << "Maximum top margin widths" << topMarginWidths; 0239 qDebug() << "Maximum bottom margin heights" << bottomMarginHeights; 0240 #endif 0241 0242 0243 foreach (PlotItem* plotItem, plotItems) { 0244 0245 #if DEBUG_PLOT_STANDARDIZATION 0246 qDebug() << "Margin left width is " << plotItem->leftMarginSize() << "setting to" << leftMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->leftMarginSize(); 0247 qDebug() << "Margin right width is " << plotItem->rightMarginSize() << "setting to" << rightMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->rightMarginSize(); 0248 qDebug() << "Margin top width is " << plotItem->topMarginSize() << "setting to" << topMarginWidths[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->topMarginSize(); 0249 qDebug() << "Margin bottom height is " << plotItem->bottomMarginSize() << "setting to" << bottomMarginHeights[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->bottomMarginSize(); 0250 #endif 0251 0252 qreal leftPadding = leftMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->leftMarginSize(); 0253 qreal rightPadding = rightMarginWidths[floor(plotItem->width()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->rightMarginSize(); 0254 qreal topPadding = topMarginWidths[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->topMarginSize(); 0255 qreal bottomPadding = bottomMarginHeights[floor(plotItem->height()*PLOT_STANDARDIZATION_FACTOR)] - plotItem->bottomMarginSize(); 0256 0257 plotItem->setPadding(leftPadding, rightPadding, topPadding, bottomPadding); 0258 } 0259 } 0260 0261 0262 void ViewGridLayout::apply() { 0263 updatePlotMargins(); 0264 0265 //For now we divide up equally... can do stretch factors and such later... 0266 0267 QSizeF layoutSize(parentItem()->width() - _margin.width() * 2, 0268 parentItem()->height() - _margin.height() * 2); 0269 0270 QPointF layoutTopLeft = parentItem()->rect().topLeft(); 0271 layoutTopLeft += QPointF(_margin.width(), _margin.height()); 0272 0273 QRectF layoutRect(layoutTopLeft, layoutSize); 0274 0275 qreal itemWidth = layoutSize.width() / columnCount(); 0276 qreal itemHeight = layoutSize.height() / rowCount(); 0277 0278 #if DEBUG_LAYOUT 0279 qDebug() << "layouting" << _items.count() 0280 << "itemWidth:" << itemWidth 0281 << "itemHeight:" << itemHeight 0282 << endl; 0283 #endif 0284 0285 PlotItem *plot = 0; 0286 foreach (const LayoutItem &item, _items) { 0287 QPointF topLeft(itemWidth * item.column, itemHeight * item.row); 0288 QSizeF size(itemWidth * item.columnSpan, itemHeight * item.rowSpan); 0289 topLeft += layoutTopLeft; 0290 0291 QRectF itemRect(topLeft, size); 0292 0293 if (itemRect.top() != layoutRect.top()) 0294 itemRect.setTop(itemRect.top() + _spacing.height() / 2); 0295 if (itemRect.left() != layoutRect.left()) 0296 itemRect.setLeft(itemRect.left() + _spacing.width() / 2); 0297 if (itemRect.bottom() != layoutRect.bottom()) 0298 itemRect.setBottom(itemRect.bottom() - _spacing.height() / 2); 0299 if (itemRect.right() != layoutRect.right()) 0300 itemRect.setRight(itemRect.right() - _spacing.width() / 2); 0301 0302 item.viewItem->resetTransform(); 0303 item.viewItem->setPos(itemRect.topLeft()); 0304 0305 if (item.viewItem->fixedSize()) { 0306 itemRect.setBottom(itemRect.top() + item.viewItem->rect().height()); 0307 itemRect.setRight(itemRect.left() + item.viewItem->rect().width()); 0308 } else if (item.viewItem->lockAspectRatio()) { 0309 qreal newHeight = itemRect.height(); 0310 qreal newWidth = itemRect.width(); 0311 0312 qreal aspectRatio = item.viewItem->rect().width() / item.viewItem->rect().height(); 0313 if ((newWidth / newHeight) > aspectRatio) { 0314 // newWidth is too large. Use newHeight as key. 0315 newWidth = newHeight * aspectRatio; 0316 } else { 0317 // newHeight is either too large, or perfect. use newWidth as key. 0318 newHeight = newWidth / aspectRatio; 0319 } 0320 itemRect.setBottom(itemRect.top() + newHeight); 0321 itemRect.setRight(itemRect.left() + newWidth); 0322 } 0323 item.viewItem->setViewRect(QRectF(QPoint(0,0), itemRect.size())); 0324 0325 if (PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem)) { 0326 plot = plotItem; 0327 emit plotItem->updatePlotRect(); 0328 } 0329 0330 #if DEBUG_LAYOUT 0331 qDebug() << "layout" 0332 << "row:" << item.row 0333 << "column:" << item.column 0334 << "rowSpan:" << item.rowSpan 0335 << "columnSpan:" << item.columnSpan 0336 << "itemRect:" << itemRect 0337 << endl; 0338 #endif 0339 } 0340 if (plot) { 0341 plot->setPlotBordersDirty(true); 0342 } 0343 } 0344 0345 0346 void ViewGridLayout::shareAxis(QPainter *painter, bool creation) { 0347 0348 SharedAxisBoxItem *shareBox = qobject_cast<SharedAxisBoxItem*>(parentItem()); 0349 if (!shareBox) { 0350 return; 0351 } 0352 0353 if (creation) { 0354 calculateSharing(); 0355 updateSharedAxis(); 0356 shareBox->setXAxisShared(_shareX); 0357 shareBox->setYAxisShared(_shareY); 0358 } else { 0359 _shareX = shareBox->isXAxisShared(); 0360 _shareY = shareBox->isYAxisShared(); 0361 unshareAxis(); 0362 updateSharedAxis(); 0363 } 0364 0365 // Determine area of layout. Minimal spacing on SharedAxisBoxItems. 0366 QSizeF layoutSize(parentItem()->width() - 1, parentItem()->height() - 1); 0367 QPointF layoutTopLeft = parentItem()->rect().topLeft(); 0368 layoutTopLeft += QPointF(0, 1); 0369 0370 QRectF layoutRect(layoutTopLeft, layoutSize); 0371 0372 QMap<int, int> leftLabelBounds; 0373 QMap<int, int> rightLabelBounds; 0374 QMap<int, int> topLabelBounds; 0375 QMap<int, int> bottomLabelBounds; 0376 0377 #if DEBUG_SHAREDAXIS 0378 qDebug() << "Creating Shared Axis Layout in rect " << layoutRect 0379 << "rowCount" << rowCount() << "columnCount" << columnCount(); 0380 #endif 0381 0382 foreach (const LayoutItem &item, _items) { 0383 if (PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem)) { 0384 plotItem->calculateBorders(painter); 0385 if (plotItem->leftMarginSize() > leftLabelBounds[item.column]) { 0386 leftLabelBounds[item.column] = plotItem->leftMarginSize(); 0387 } 0388 if (plotItem->rightMarginSize() > rightLabelBounds[item.column]) { 0389 rightLabelBounds[item.column] = plotItem->rightMarginSize(); 0390 } 0391 if (plotItem->topMarginSize() > topLabelBounds[item.row]) { 0392 topLabelBounds[item.row] = plotItem->topMarginSize(); 0393 } 0394 if (plotItem->bottomMarginSize() > bottomLabelBounds[item.row]) { 0395 bottomLabelBounds[item.row] = plotItem->bottomMarginSize(); 0396 } 0397 } 0398 } 0399 0400 // Adjust to make sure there is sufficient room for the tiedzoom box. 0401 if (topLabelBounds[0] < parentItem()->tiedZoomSize().height()) { 0402 topLabelBounds[0] = parentItem()->tiedZoomSize().height(); 0403 } 0404 if (rightLabelBounds[columnCount()] < parentItem()->tiedZoomSize().width()) { 0405 rightLabelBounds[columnCount()] = parentItem()->tiedZoomSize().width(); 0406 } 0407 0408 #if DEBUG_SHAREDAXIS 0409 qDebug() << "Calculated maximum bounds for labels."; 0410 qDebug() << "Left bounds by column" << leftLabelBounds; 0411 qDebug() << "Right bounds by column" << rightLabelBounds; 0412 qDebug() << "Top bounds by row" << topLabelBounds; 0413 qDebug() << "Bottom bounds by row" << bottomLabelBounds; 0414 #endif 0415 0416 bool blockMode = false; 0417 bool rowMode = false; 0418 bool colMode = false; 0419 0420 #if DEBUG_SHAREDAXIS 0421 qDebug() << "Calculated sharing modes" << "sharing X = " << _shareX << "sharing Y = " << _shareY; 0422 #endif 0423 0424 if (_shareX && _shareY) { 0425 #if DEBUG_SHAREDAXIS 0426 qDebug() << "Sharing X & Y, one block, all projectionRect's inside frame"; 0427 #endif 0428 blockMode = true; 0429 } else if (_shareX) { 0430 if (columnCount() == 1) { 0431 #if DEBUG_SHAREDAXIS 0432 qDebug() << "Sharing only X, one column, use block logic"; 0433 #endif 0434 blockMode = true; 0435 } else { 0436 #if DEBUG_SHAREDAXIS 0437 qDebug() << "Sharing only X, multiple columns, use block for each column, columns divide space equally - number of columns" << columnCount(); 0438 #endif 0439 colMode = true; 0440 } 0441 } else if (_shareY) { 0442 if (rowCount() == 1) { 0443 #if DEBUG_SHAREDAXIS 0444 qDebug() << "Sharing only Y, one row, use block logic"; 0445 #endif 0446 blockMode = true; 0447 } else { 0448 #if DEBUG_SHAREDAXIS 0449 qDebug() << "Sharing only Y, multiple rows, use block for each row, rows divide space equally - number of rows" << rowCount(); 0450 #endif 0451 rowMode = true; 0452 } 0453 } 0454 0455 int totalProjWidth; 0456 int totalProjHeight; 0457 0458 if (blockMode) { 0459 totalProjWidth = (layoutRect.width() - leftLabelBounds[0]) - rightLabelBounds[columnCount() - 1]; 0460 totalProjHeight = (layoutRect.height() - topLabelBounds[0]) - bottomLabelBounds[rowCount() - 1]; 0461 } else if (rowMode) { 0462 int totalHeight = 0; 0463 for (int i = 0; i < rowCount(); i++) { 0464 totalHeight += topLabelBounds[i] + bottomLabelBounds[i]; 0465 } 0466 totalProjWidth = layoutRect.width() - leftLabelBounds[0] - rightLabelBounds[columnCount() - 1]; 0467 totalProjHeight = layoutRect.height() - totalHeight; 0468 0469 } else if (colMode) { 0470 int totalWidth = 0; 0471 for (int i = 0; i < columnCount(); i++) { 0472 totalWidth += leftLabelBounds[i] + rightLabelBounds[i]; 0473 } 0474 totalProjWidth = layoutRect.width() - totalWidth; 0475 totalProjHeight = layoutRect.height() - topLabelBounds[0] - bottomLabelBounds[rowCount() - 1]; 0476 } else { 0477 return; 0478 } 0479 0480 int columnProjWidth = totalProjWidth / (columnCount()); 0481 int rowProjHeight = totalProjHeight / (rowCount()); 0482 0483 QMap<int, QMap<int, int> > cellHeights; 0484 QMap<int, QMap<int, int> > cellWidths; 0485 0486 foreach (const LayoutItem &item, _items) { 0487 if (PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem)) { 0488 int width = columnProjWidth; 0489 if (plotItem->leftLabelDetails()->isVisible()) { 0490 width += leftLabelBounds[item.column]; 0491 } 0492 if (plotItem->rightLabelDetails()->isVisible()) { 0493 width += rightLabelBounds[item.column]; 0494 } 0495 cellWidths[item.row][item.column] = width; 0496 0497 int height = rowProjHeight; 0498 if (plotItem->topLabelDetails()->isVisible()) { 0499 height += topLabelBounds[item.row]; 0500 } 0501 if (plotItem->bottomLabelDetails()->isVisible()) { 0502 height += bottomLabelBounds[item.row]; 0503 } 0504 cellHeights[item.row][item.column] = height; 0505 } 0506 } 0507 0508 #if DEBUG_SHAREDAXIS 0509 qDebug() << "Calculated Total projectRect values - width = " << totalProjWidth << " height = " << totalProjHeight; 0510 qDebug() << "Column Projection Width" << columnProjWidth << "Row Projection Height" << rowProjHeight; 0511 qDebug() << "Calculated cell widths (row x column)" << cellWidths; 0512 qDebug() << "Calculated cell heights (row x column)" << cellHeights; 0513 #endif 0514 0515 foreach (const LayoutItem &item, _items) { 0516 int columnStart = 0; 0517 for (int i = 0; i < item.column; i++) { 0518 columnStart += cellWidths[item.row][i]; 0519 } 0520 0521 int rowStart = 0; 0522 for (int i = 0; i < item.row; i++) { 0523 rowStart += cellHeights[i][item.column]; 0524 } 0525 0526 QPointF itemTopLeft(columnStart, rowStart); 0527 itemTopLeft += layoutTopLeft; 0528 QSizeF itemSize(cellWidths[item.row][item.column], cellHeights[item.row][item.column]); 0529 QRectF itemRect(itemTopLeft, itemSize); 0530 0531 if (PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem)) { 0532 if (plotItem->leftLabelDetails()->isVisible()) { 0533 plotItem->setLeftPadding(leftLabelBounds[item.column] - plotItem->leftMarginSize()); 0534 } 0535 if (plotItem->rightLabelDetails()->isVisible()) { 0536 plotItem->setRightPadding(rightLabelBounds[item.column] - plotItem->rightMarginSize()); 0537 } 0538 if (plotItem->topLabelDetails()->isVisible()) { 0539 plotItem->setTopPadding(topLabelBounds[item.row] - plotItem->topMarginSize()); 0540 } 0541 if (plotItem->bottomLabelDetails()->isVisible()) { 0542 plotItem->setBottomPadding(bottomLabelBounds[item.row] - plotItem->bottomMarginSize()); 0543 } 0544 } 0545 0546 item.viewItem->resetTransform(); 0547 item.viewItem->setPos(itemRect.topLeft()); 0548 item.viewItem->setViewRect(QRectF(QPoint(0,0), itemRect.size())); 0549 0550 if (PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem)) { 0551 emit plotItem->updatePlotRect(); 0552 } 0553 0554 #if DEBUG_SHAREDAXIS 0555 qDebug() << "Shared Axis Plot item details:" 0556 << "row:" << item.row 0557 << "column:" << item.column 0558 << "itemRect:" << itemRect 0559 << endl; 0560 #endif 0561 } 0562 } 0563 0564 0565 void ViewGridLayout::updatePlotMargins() { 0566 _plotMarginWidth.clear(); 0567 _plotMarginHeight.clear(); 0568 foreach (const LayoutItem &item, _items) { 0569 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0570 0571 if (!plotItem) 0572 continue; 0573 0574 { 0575 qreal labelMargin = plotItem->labelMarginWidth(); 0576 qreal axisMargin = plotItem->axisMarginWidth(); 0577 0578 if (_plotMarginWidth.contains(item.columnSpan)) { 0579 labelMargin = qMax(labelMargin, _plotMarginWidth.value(item.columnSpan).labelMargin); 0580 axisMargin = qMax(axisMargin, _plotMarginWidth.value(item.columnSpan).axisMargin); 0581 } 0582 0583 PlotMargins marginsForColumnSpan; 0584 marginsForColumnSpan.labelMargin = labelMargin; 0585 marginsForColumnSpan.axisMargin = axisMargin; 0586 _plotMarginWidth.insert(item.columnSpan, marginsForColumnSpan); 0587 } 0588 0589 { 0590 qreal labelMargin = plotItem->labelMarginHeight(); 0591 qreal axisMargin = plotItem->axisMarginHeight(); 0592 0593 if (_plotMarginHeight.contains(item.rowSpan)) { 0594 labelMargin = qMax(labelMargin, _plotMarginHeight.value(item.rowSpan).labelMargin); 0595 axisMargin = qMax(axisMargin, _plotMarginHeight.value(item.rowSpan).axisMargin); 0596 } 0597 0598 PlotMargins marginsForRowSpan; 0599 marginsForRowSpan.labelMargin = labelMargin; 0600 marginsForRowSpan.axisMargin = axisMargin; 0601 _plotMarginHeight.insert(item.rowSpan, marginsForRowSpan); 0602 } 0603 } 0604 } 0605 0606 0607 void ViewGridLayout::unshareAxis() { 0608 foreach (const LayoutItem &item, _items) { 0609 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0610 0611 if (!plotItem) 0612 continue; 0613 0614 plotItem->setLabelsVisible(true); 0615 plotItem->update(); 0616 } 0617 } 0618 0619 0620 void ViewGridLayout::updateSharedAxis() { 0621 if (!_shareX && !_shareY) { 0622 return; 0623 } 0624 foreach (const LayoutItem &item, _items) { 0625 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0626 0627 if (!plotItem) 0628 continue; 0629 0630 //same horizontal range and same row/rowspan 0631 //same vertical range and same col/colspan 0632 if (_shareX) { 0633 shareAxisWithPlotAbove(item); 0634 shareAxisWithPlotBelow(item); 0635 } 0636 if (_shareY) { 0637 shareAxisWithPlotToLeft(item); 0638 shareAxisWithPlotToRight(item); 0639 } 0640 } 0641 } 0642 0643 0644 void ViewGridLayout::calculateSharing() { 0645 bool xMatch = true; 0646 bool yMatch = true; 0647 0648 bool first = true; 0649 0650 qreal xStart = 0.0, xStop = 0.0; 0651 qreal yStart = 0.0, yStop = 0.0; 0652 0653 foreach (const LayoutItem &item, _items) { 0654 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0655 0656 if (!plotItem) 0657 continue; 0658 0659 if (first) { 0660 xStart = plotItem->projectionRect().left(); 0661 xStop = plotItem->projectionRect().right(); 0662 yStart = plotItem->projectionRect().top(); 0663 yStop = plotItem->projectionRect().bottom(); 0664 first = false; 0665 } else { 0666 if (xMatch && (plotItem->projectionRect().left() != xStart || plotItem->projectionRect().right() != xStop)) { 0667 xMatch = false; 0668 } 0669 if (yMatch && (plotItem->projectionRect().top() != yStart || plotItem->projectionRect().bottom() != yStop)) { 0670 yMatch = false; 0671 } 0672 } 0673 } 0674 if (xMatch || yMatch) { 0675 _shareX = xMatch; 0676 _shareY = yMatch; 0677 } else { 0678 _shareX = true; 0679 _shareY = true; 0680 } 0681 } 0682 0683 // static function 0684 void ViewGridLayout::updateProjections(ViewItem *item, bool forceXShare, bool forceYShare) { 0685 bool xMatch = true; 0686 bool yMatch = true; 0687 0688 bool first = true; 0689 0690 qreal xStart = 0.0, xStop = 0.0; 0691 qreal yStart = 0.0, yStop = 0.0; 0692 qreal xMin = 0.0, xMax = 0.0, yMin = 0.0, yMax = 0.0; 0693 0694 QList<ViewItem*> viewItems; 0695 QList<QGraphicsItem*> list = item->QGraphicsItem::childItems(); 0696 if (list.isEmpty()) 0697 return; //not added to undostack 0698 0699 foreach (QGraphicsItem *graphicsItem, list) { 0700 ViewItem *viewItem = dynamic_cast<ViewItem*>(graphicsItem); 0701 if (!viewItem || viewItem->hasStaticGeometry() || !viewItem->allowsLayout() || viewItem->parentItem() != item) 0702 continue; 0703 0704 PlotItem *plotItem = qobject_cast<PlotItem*>(viewItem); 0705 0706 if (!plotItem) 0707 continue; 0708 0709 if (first) { 0710 xStart = plotItem->projectionRect().left(); 0711 xStop = plotItem->projectionRect().right(); 0712 yStart = plotItem->projectionRect().top(); 0713 yStop = plotItem->projectionRect().bottom(); 0714 xMin = xStart; 0715 xMax = xStop; 0716 yMin = yStart; 0717 yMax = yStop; 0718 first = false; 0719 } else { 0720 if (xMatch && (plotItem->projectionRect().left() != xStart || plotItem->projectionRect().right() != xStop)) { 0721 xMatch = false; 0722 } 0723 if (yMatch && (plotItem->projectionRect().top() != yStart || plotItem->projectionRect().bottom() != yStop)) { 0724 yMatch = false; 0725 } 0726 if (xMin > plotItem->projectionRect().left()) { 0727 xMin = plotItem->projectionRect().left(); 0728 } 0729 if (xMax < plotItem->projectionRect().right()) { 0730 xMax = plotItem->projectionRect().right(); 0731 } 0732 if (yMin > plotItem->projectionRect().top()) { 0733 yMin = plotItem->projectionRect().top(); 0734 } 0735 if (yMax < plotItem->projectionRect().bottom()) { 0736 yMax = plotItem->projectionRect().bottom(); 0737 } 0738 } 0739 } 0740 0741 xMatch = xMatch || forceXShare; 0742 yMatch = yMatch || forceYShare; 0743 0744 if (!xMatch && !yMatch) { 0745 xMatch = true; 0746 yMatch = true; 0747 } 0748 0749 QRectF projectionRect(QPointF(xMin, yMin), QPointF(xMax, yMax)); 0750 0751 foreach (QGraphicsItem *graphicsItem, list) { 0752 ViewItem *viewItem = dynamic_cast<ViewItem*>(graphicsItem); 0753 if (!viewItem || viewItem->hasStaticGeometry() || !viewItem->allowsLayout() || viewItem->parentItem() != item) 0754 continue; 0755 0756 if (PlotItem *plotItem = qobject_cast<PlotItem*>(viewItem)) { 0757 if (xMatch && yMatch) { 0758 plotItem->zoomFixedExpression(projectionRect, true); 0759 } else if (xMatch) { 0760 plotItem->zoomXRange(projectionRect, true); 0761 } else if (yMatch) { 0762 plotItem->zoomYRange(projectionRect, true); 0763 } 0764 } 0765 } 0766 } 0767 0768 0769 void ViewGridLayout::shareAxisWithPlotToLeft(LayoutItem item) { 0770 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0771 0772 QPair<int, int> key = qMakePair(item.row, item.column - 1); 0773 if (!_itemLayouts.contains(key)) { 0774 plotItem->setLeftSuppressed(false); 0775 setSpacing(QSizeF(spacing().width(), spacing().height())); 0776 return; 0777 } 0778 0779 LayoutItem left = _itemLayouts.value(key); 0780 PlotItem *leftItem = qobject_cast<PlotItem*>(left.viewItem); 0781 if (!leftItem) { 0782 plotItem->setLeftSuppressed(false); 0783 setSpacing(QSizeF(spacing().width(), spacing().height())); 0784 return; 0785 } 0786 0787 if (item.rowSpan == left.rowSpan && item.columnSpan == left.columnSpan) { 0788 plotItem->setLeftSuppressed(true); 0789 leftItem->setRightSuppressed(true); 0790 setSpacing(QSizeF(0.0, spacing().height())); 0791 } 0792 } 0793 0794 0795 void ViewGridLayout::shareAxisWithPlotToRight(LayoutItem item) { 0796 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0797 0798 QPair<int, int> key = qMakePair(item.row, item.column + 1); 0799 if (!_itemLayouts.contains(key)) { 0800 plotItem->setRightSuppressed(false); 0801 setSpacing(QSizeF(spacing().width(), spacing().height())); 0802 return; 0803 } 0804 0805 0806 LayoutItem right = _itemLayouts.value(key); 0807 PlotItem *rightItem = qobject_cast<PlotItem*>(right.viewItem); 0808 if (!rightItem) { 0809 plotItem->setRightSuppressed(false); 0810 setSpacing(QSizeF(spacing().width(), spacing().height())); 0811 return; 0812 } 0813 0814 if (item.rowSpan == right.rowSpan && item.columnSpan == right.columnSpan) { 0815 plotItem->setRightSuppressed(true); 0816 rightItem->setLeftSuppressed(true); 0817 setSpacing(QSizeF(0.0, spacing().height())); 0818 } 0819 } 0820 0821 0822 void ViewGridLayout::shareAxisWithPlotAbove(LayoutItem item) { 0823 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0824 0825 QPair<int, int> key = qMakePair(item.row - 1, item.column); 0826 if (!_itemLayouts.contains(key)) { 0827 plotItem->setTopSuppressed(false); 0828 setSpacing(QSizeF(spacing().width(), spacing().height())); 0829 return; 0830 } 0831 0832 LayoutItem top = _itemLayouts.value(key); 0833 PlotItem *topItem = qobject_cast<PlotItem*>(top.viewItem); 0834 if (!topItem) { 0835 plotItem->setTopSuppressed(false); 0836 setSpacing(QSizeF(spacing().width(), spacing().height())); 0837 return; 0838 } 0839 0840 if (item.rowSpan == top.rowSpan && item.columnSpan == top.columnSpan) { 0841 plotItem->setTopSuppressed(true); 0842 topItem->setBottomSuppressed(true); 0843 setSpacing(QSizeF(spacing().width(), 0.0)); 0844 } 0845 } 0846 0847 0848 void ViewGridLayout::shareAxisWithPlotBelow(LayoutItem item) { 0849 PlotItem *plotItem = qobject_cast<PlotItem*>(item.viewItem); 0850 0851 QPair<int, int> key = qMakePair(item.row + 1, item.column); 0852 if (!_itemLayouts.contains(key)) { 0853 plotItem->setBottomSuppressed(false); 0854 setSpacing(QSizeF(spacing().width(), spacing().height())); 0855 return; 0856 } 0857 0858 LayoutItem bottom = _itemLayouts.value(key); 0859 PlotItem *bottomItem = qobject_cast<PlotItem*>(bottom.viewItem); 0860 if (!bottomItem) { 0861 plotItem->setBottomSuppressed(false); 0862 setSpacing(QSizeF(spacing().width(), spacing().height())); 0863 return; 0864 } 0865 0866 if (item.rowSpan == bottom.rowSpan && item.columnSpan == bottom.columnSpan) { 0867 plotItem->setBottomSuppressed(true); 0868 bottomItem->setTopSuppressed(true); 0869 setSpacing(QSizeF(spacing().width(), 0.0)); 0870 } 0871 } 0872 0873 } 0874 0875 // vim: ts=2 sw=2 et