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