summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
authorGrzegorz Araminowicz <g.araminowicz@gmail.com>2017-07-13 18:39:42 +0200
committerJan Holesovsky <kendy@collabora.com>2017-07-20 10:03:08 +0200
commit47e52b47845265ba126c30eba149e90689538b93 (patch)
treef3a40b2341470a29906d3196dee43fb7afee7201 /oox
parent21f28f94744b4378ba45b1361870592dd7cfabb2 (diff)
SmartArt: more layout work
* basic layout algorithms implementation * change layouting order to "from top" Change-Id: I8ef397fa0e39bb6d8cda2d1387b663980f134a59
Diffstat (limited to 'oox')
-rw-r--r--oox/source/drawingml/diagram/diagram.cxx6
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.cxx201
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.hxx3
-rwxr-xr-xoox/source/drawingml/diagram/layoutatomvisitors.cxx40
-rwxr-xr-xoox/source/drawingml/diagram/layoutatomvisitors.hxx14
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