diff options
author | Grzegorz Araminowicz <g.araminowicz@gmail.com> | 2017-07-13 18:39:42 +0200 |
---|---|---|
committer | Jan Holesovsky <kendy@collabora.com> | 2017-07-20 10:03:08 +0200 |
commit | 47e52b47845265ba126c30eba149e90689538b93 (patch) | |
tree | f3a40b2341470a29906d3196dee43fb7afee7201 | |
parent | 21f28f94744b4378ba45b1361870592dd7cfabb2 (diff) |
SmartArt: more layout work
* basic layout algorithms implementation
* change layouting order to "from top"
Change-Id: I8ef397fa0e39bb6d8cda2d1387b663980f134a59
-rw-r--r-- | oox/source/drawingml/diagram/diagram.cxx | 6 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 201 | ||||
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.hxx | 3 | ||||
-rwxr-xr-x | oox/source/drawingml/diagram/layoutatomvisitors.cxx | 40 | ||||
-rwxr-xr-x | oox/source/drawingml/diagram/layoutatomvisitors.hxx | 14 |
5 files changed, 117 insertions, 147 deletions
diff --git a/oox/source/drawingml/diagram/diagram.cxx b/oox/source/drawingml/diagram/diagram.cxx index 533156bbfb86..175df73e9420 100644 --- a/oox/source/drawingml/diagram/diagram.cxx +++ b/oox/source/drawingml/diagram/diagram.cxx @@ -328,7 +328,11 @@ void Diagram::addTo( const ShapePtr & pParentShape ) // create Shape hierarchy ShapeCreationVisitor aCreationVisitor(pParentShape, *this); mpLayout->getNode()->setExistingShape(pParentShape); - mpLayout->getNode()->accept( aCreationVisitor ); + mpLayout->getNode()->accept(aCreationVisitor); + + // layout shapes - now all shapes are created + ShapeLayoutingVisitor aLayoutingVisitor; + mpLayout->getNode()->accept(aLayoutingVisitor); } pParentShape->setDiagramDoms( getDomsAsPropertyValues() ); } diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx index daf0edf52c5a..1bad1f0f4ece 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx @@ -149,59 +149,13 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, { case XML_composite: { - if( rShape->getChildren().empty() ) - { - rShape->setSize(awt::Size(50,50)); - break; - } - - // just put stuff below each other - const sal_Int32 nIncX=0; - const sal_Int32 nIncY=1; - - std::vector<ShapePtr>::const_iterator aCurrShape=rShape->getChildren().begin(); - const std::vector<ShapePtr>::const_iterator aLastShape=rShape->getChildren().end(); - - // find biggest shape - awt::Size aMaxSize; - while( aCurrShape != aLastShape ) - { - const awt::Size& sz=(*aCurrShape)->getSize(); - - aMaxSize.Width = std::max( - aMaxSize.Width, - sz.Width); - aMaxSize.Height = std::max( - aMaxSize.Height, - sz.Height); + // all shapes fill parent - ++aCurrShape; - } - - aCurrShape=rShape->getChildren().begin(); - const awt::Point aStartPos=(*aCurrShape)->getPosition(); - awt::Point aCurrPos=aStartPos; - awt::Size aTotalSize; - aTotalSize.Width = aMaxSize.Width; - while( aCurrShape != aLastShape ) + for (auto & aCurrShape : rShape->getChildren()) { - const awt::Size& sz=(*aCurrShape)->getSize(); - (*aCurrShape)->setPosition(aCurrPos); - (*aCurrShape)->setSize( - awt::Size(aMaxSize.Width, - sz.Height)); - - aTotalSize.Height = std::max( - aTotalSize.Height, - aCurrPos.Y + sz.Height); - - aCurrPos.X += nIncX*sz.Width; - aCurrPos.Y += nIncY*sz.Height; - - ++aCurrShape; + aCurrShape->setSize(rShape->getSize()); + aCurrShape->setChildSize(rShape->getSize()); } - - rShape->setSize(aTotalSize); break; } @@ -210,11 +164,8 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, case XML_cycle: { - if( rShape->getChildren().empty() ) - { - rShape->setSize(awt::Size(50,50)); + if (rShape->getChildren().empty()) break; - } const sal_Int32 nStartAngle=maMap.count(XML_stAng) ? maMap.find(XML_stAng)->second : 0; const sal_Int32 nSpanAngle=maMap.count(XML_spanAng) ? maMap.find(XML_spanAng)->second : 360; @@ -241,27 +192,15 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, // layout shapes const sal_Int32 nMaxDim=std::max(aMaxSize.Width,aMaxSize.Height); - awt::Size aTotalSize; aCurrShape=rShape->getChildren().begin(); for( sal_Int32 i=0; i<nShapes; ++i, ++aCurrShape ) { - const awt::Size& sz=(*aCurrShape)->getSize(); - const double r=nShapes*nMaxDim/F_2PI * 360.0/nSpanAngle; const awt::Point aCurrPos( r + r*sin( (double(i)*nSpanAngle/nShapes + nStartAngle)*F_PI180 ), r - r*cos( (double(i)*nSpanAngle/nShapes + nStartAngle)*F_PI180 ) ); (*aCurrShape)->setPosition(aCurrPos); - - aTotalSize.Width = std::max( - aTotalSize.Width, - aCurrPos.X + sz.Width); - aTotalSize.Height = std::max( - aTotalSize.Height, - aCurrPos.Y + sz.Height); } - - rShape->setSize(aTotalSize); break; } @@ -270,97 +209,103 @@ void AlgAtom::layoutShape( const ShapePtr& rShape, break; case XML_lin: - case XML_snake: { - if( rShape->getChildren().empty() ) - { - rShape->setSize(awt::Size(50,50)); + // spread childres evenly across one axis, strech across second + + if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0) break; - } - const sal_Int32 nDir=maMap.count(XML_linDir) ? maMap.find(XML_linDir)->second : XML_fromL; - const sal_Int32 nIncX=nDir==XML_fromL ? 1 : (nDir==XML_fromR ? -1 : 0); - const sal_Int32 nIncY=nDir==XML_fromT ? 1 : (nDir==XML_fromB ? -1 : 0); + const sal_Int32 nDir = maMap.count(XML_linDir) ? maMap.find(XML_linDir)->second : XML_fromL; + const sal_Int32 nIncX = nDir==XML_fromL ? 1 : (nDir==XML_fromR ? -1 : 0); + const sal_Int32 nIncY = nDir==XML_fromT ? 1 : (nDir==XML_fromB ? -1 : 0); - std::vector<ShapePtr>::const_iterator aCurrShape=rShape->getChildren().begin(); - const std::vector<ShapePtr>::const_iterator aLastShape=rShape->getChildren().end(); - const awt::Point aStartPos=(*aCurrShape)->getPosition(); - awt::Point aCurrPos=aStartPos; - awt::Size aTotalSize; - while( aCurrShape != aLastShape ) - { - const awt::Size& sz=(*aCurrShape)->getSize(); - (*aCurrShape)->setPosition(aCurrPos); + // TODO: get values from constraints + sal_Int32 nCount = rShape->getChildren().size(); + double fSpace = 0.3; - aTotalSize.Width = std::max( - aTotalSize.Width, - aCurrPos.X + sz.Width); - aTotalSize.Height = std::max( - aTotalSize.Height, - aCurrPos.Y + sz.Height); + awt::Size aChildSize = rShape->getSize(); + if (nIncX) + aChildSize.Width /= (nCount + (nCount-1)*fSpace); + if (nIncY) + aChildSize.Height /= (nCount + (nCount-1)*fSpace); - // HACK: the spacing is arbitrary - aCurrPos.X += nIncX*(sz.Width+5); - aCurrPos.Y += nIncY*(sz.Height+5); - - ++aCurrShape; + awt::Point aCurrPos = rShape->getChildren().front()->getPosition(); + for (auto & aCurrShape : rShape->getChildren()) + { + aCurrShape->setPosition(aCurrPos); + aCurrShape->setSize(aChildSize); + aCurrShape->setChildSize(aChildSize); + aCurrPos.X += nIncX * (aChildSize.Width + fSpace*aChildSize.Width); + aCurrPos.Y += nIncY * (aChildSize.Height + fSpace*aChildSize.Height); } - - rShape->setSize(aTotalSize); break; } case XML_pyra: break; - case XML_sp: - // HACK. Handled one level higher. Or rather, planned to - break; - - case XML_tx: + case XML_snake: { - TextBodyPtr pTextBody=rShape->getTextBody(); - if( !pTextBody || - pTextBody->getParagraphs().empty() || - pTextBody->getParagraphs().front()->getRuns().empty() ) - { - rShape->setSize(awt::Size(5,5)); + // find optimal grid to layout children that have fixed aspect ratio + + if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0) break; - } - // HACK - count chars & paragraphs to come up with *some* - // notion of necessary size - const sal_Int32 nHackyFontHeight=50; - const sal_Int32 nHackyFontWidth=20; - awt::Size aTotalSize; - for( size_t nPara=0; nPara<pTextBody->getParagraphs().size(); ++nPara ) + // TODO: get values from constraints + sal_Int32 nCount = rShape->getChildren().size(); + double fSpace = 0.3; + double fAspectRatio = 0.6; + + sal_Int32 nCol = 1; + sal_Int32 nRow = 1; + for ( ; nCol<nCount; nCol++) { - aTotalSize.Height += nHackyFontHeight; + nRow = (nCount+nCol-1) / nCol; + if ((rShape->getSize().Height / nRow) / (rShape->getSize().Width / nCol) >= fAspectRatio) + break; + } + SAL_INFO("oox.drawingml", "Snake layout grid: " << nCol << "x" << nRow); - sal_Int32 nLocalWidth=0; - for( size_t nRun=0; nRun<pTextBody->getParagraphs().at(nPara)->getRuns().size(); ++nRun ) - nLocalWidth += - pTextBody->getParagraphs().at(nPara)->getRuns().at(nRun)->getText().getLength() - * nHackyFontWidth; + sal_Int32 nWidth = rShape->getSize().Width / (nCol + (nCol-1)*fSpace); + const awt::Size aChildSize(nWidth, nWidth * fAspectRatio); - aTotalSize.Width = std::max( - aTotalSize.Width, - nLocalWidth); - } + awt::Point aStartPos = rShape->getChildren().front()->getPosition(); + awt::Point aCurrPos = aStartPos; + sal_Int32 nColIdx = 0; - rShape->setSize(aTotalSize); + for (auto & aCurrShape : rShape->getChildren()) + { + aCurrShape->setPosition(aCurrPos); + aCurrShape->setSize(aChildSize); + aCurrShape->setChildSize(aChildSize); + aCurrPos.X += aChildSize.Width + fSpace*aChildSize.Width; + if (++nColIdx == nCol) + { + aStartPos.Y += aChildSize.Height + fSpace*aChildSize.Height; + aCurrPos = aStartPos; + nColIdx = 0; + } + } break; } + case XML_sp: + // HACK. Handled one level higher. Or rather, planned to + break; + + case XML_tx: + // TODO: adjust text size to fit shape + break; + default: break; } SAL_INFO( "oox.drawingml", - "Layouting shape " << rName << ": (" << rShape->getPosition().X << "," - << rShape->getPosition().Y << "," << rShape->getSize().Width << "," - << rShape->getSize().Height << ")"); + "Layouting shape " << rName << ", alg type: " << mnType << ", (" + << rShape->getPosition().X << "," << rShape->getPosition().Y << "," + << rShape->getSize().Width << "," << rShape->getSize().Height << ")"); } void LayoutNode::accept( LayoutAtomVisitor& rVisitor ) diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx index 7a168528c0ec..a6123ccbd62c 100644 --- a/oox/source/drawingml/diagram/diagramlayoutatoms.hxx +++ b/oox/source/drawingml/diagram/diagramlayoutatoms.hxx @@ -242,6 +242,8 @@ public: { mpExistingShape = pShape; } const ShapePtr& getExistingShape() const { return mpExistingShape; } + std::vector<ShapePtr> & getNodeShapes() + { return mpNodeShapes; } bool setupShape( const ShapePtr& rShape, const Diagram& rDgm, @@ -252,6 +254,7 @@ private: OUString msMoveWith; OUString msStyleLabel; ShapePtr mpExistingShape; + std::vector<ShapePtr> mpNodeShapes; sal_Int32 mnChildOrder; }; diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.cxx b/oox/source/drawingml/diagram/layoutatomvisitors.cxx index ade7e4ccfec9..a580da73ff32 100755 --- a/oox/source/drawingml/diagram/layoutatomvisitors.cxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.cxx @@ -97,7 +97,9 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) if (rAtom.getExistingShape()) { - rAtom.setupShape(rAtom.getExistingShape(), mrDgm, mnCurrIdx); + // reuse existing shape + if (rAtom.setupShape(rAtom.getExistingShape(), mrDgm, mnCurrIdx)) + rAtom.getNodeShapes().push_back(rAtom.getExistingShape()); } else { @@ -117,6 +119,7 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) { pCurrParent->addChild(pShape); pCurrParent = pShape; + rAtom.getNodeShapes().push_back(pShape); } } else @@ -135,10 +138,11 @@ void ShapeCreationVisitor::visit(LayoutNode& rAtom) // restore parent mpParentShape=pPreviousParent; - // layout shapes - now all child shapes are created - ShapeLayoutingVisitor aLayoutingVisitor(pCurrParent, - rAtom.getName()); - aLayoutingVisitor.defaultVisit(rAtom); + // remove unneeded empty group shapes + pCurrParent->getChildren().erase( + std::remove_if(pCurrParent->getChildren().begin(), pCurrParent->getChildren().end(), + [] (const ShapePtr & aChild) { return aChild->getServiceName() == "com.sun.star.drawing.GroupShape" && aChild->getChildren().empty(); }), + pCurrParent->getChildren().end()); } void ShapeCreationVisitor::visit(ShapeAtom& /*rAtom*/) @@ -212,12 +216,16 @@ void ShapeLayoutingVisitor::visit(ConstraintAtom& /*rAtom*/) void ShapeLayoutingVisitor::visit(AlgAtom& rAtom) { - rAtom.layoutShape(mpParentShape, maName); + if (mbLookForAlg && mpCurrentLayoutNode) + { + for (const auto& pShape : mpCurrentLayoutNode->getNodeShapes()) + rAtom.layoutShape(pShape, mpCurrentLayoutNode->getName()); + } } -void ShapeLayoutingVisitor::visit(ForEachAtom& /*rAtom*/) +void ShapeLayoutingVisitor::visit(ForEachAtom& rAtom) { - // stop processing + defaultVisit(rAtom); } void ShapeLayoutingVisitor::visit(ConditionAtom& rAtom) @@ -230,9 +238,21 @@ void ShapeLayoutingVisitor::visit(ChooseAtom& rAtom) defaultVisit(rAtom); } -void ShapeLayoutingVisitor::visit(LayoutNode& /*rAtom*/) +void ShapeLayoutingVisitor::visit(LayoutNode& rAtom) { - // stop processing - only traverse Condition/Choose atoms + if (mbLookForAlg) + return; + + LayoutNode* pPreviousLayoutNode = mpCurrentLayoutNode; + mpCurrentLayoutNode = &rAtom; + + // process alg atoms first, nested layout nodes afterwards + mbLookForAlg = true; + defaultVisit(rAtom); + mbLookForAlg = false; + defaultVisit(rAtom); + + mpCurrentLayoutNode = pPreviousLayoutNode; } void ShapeLayoutingVisitor::visit(ShapeAtom& /*rAtom*/) diff --git a/oox/source/drawingml/diagram/layoutatomvisitors.hxx b/oox/source/drawingml/diagram/layoutatomvisitors.hxx index 28558f69bb24..3ffef36d8954 100755 --- a/oox/source/drawingml/diagram/layoutatomvisitors.hxx +++ b/oox/source/drawingml/diagram/layoutatomvisitors.hxx @@ -72,9 +72,10 @@ public: class ShapeLayoutingVisitor : public LayoutAtomVisitor { - ShapePtr mpParentShape; - OUString maName; + LayoutNode* mpCurrentLayoutNode; + bool mbLookForAlg; + void defaultVisit(LayoutAtom& rAtom); virtual void visit(ConstraintAtom& rAtom) override; virtual void visit(AlgAtom& rAtom) override; virtual void visit(ForEachAtom& rAtom) override; @@ -84,13 +85,10 @@ class ShapeLayoutingVisitor : public LayoutAtomVisitor virtual void visit(ShapeAtom& rAtom) override; public: - ShapeLayoutingVisitor(const ShapePtr& rParentShape, - const OUString& rName) : - mpParentShape(rParentShape), - maName(rName) + ShapeLayoutingVisitor() : + mpCurrentLayoutNode(nullptr), + mbLookForAlg(false) {} - - void defaultVisit(LayoutAtom& rAtom); }; class ShallowPresNameVisitor : public LayoutAtomVisitor |