summaryrefslogtreecommitdiff
path: root/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/drawingml/diagram/diagramlayoutatoms.cxx')
-rw-r--r--oox/source/drawingml/diagram/diagramlayoutatoms.cxx133
1 files changed, 116 insertions, 17 deletions
diff --git a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
index 09edf0022259..247b99d0baad 100644
--- a/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
+++ b/oox/source/drawingml/diagram/diagramlayoutatoms.cxx
@@ -65,6 +65,24 @@ bool isFontUnit(sal_Int32 nUnit)
return nUnit == oox::XML_primFontSz || nUnit == oox::XML_secFontSz;
}
+/// Determines which UNO property should be set for a given constraint type.
+sal_Int32 getPropertyFromConstraint(sal_Int32 nConstraint)
+{
+ switch (nConstraint)
+ {
+ case oox::XML_lMarg:
+ return oox::PROP_TextLeftDistance;
+ case oox::XML_rMarg:
+ return oox::PROP_TextRightDistance;
+ case oox::XML_tMarg:
+ return oox::PROP_TextUpperDistance;
+ case oox::XML_bMarg:
+ return oox::PROP_TextLowerDistance;
+ }
+
+ return 0;
+}
+
/// Determines the connector shape type from a linear alg.
sal_Int32 getConnectorType(const oox::drawingml::LayoutNode* pNode)
{
@@ -246,7 +264,7 @@ void LayoutAtom::dump(int level)
pAtom->dump(level + 1);
}
-ForEachAtom::ForEachAtom(const LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) :
+ForEachAtom::ForEachAtom(LayoutNode& rLayoutNode, const Reference< XFastAttributeList >& xAttributes) :
LayoutAtom(rLayoutNode)
{
maIter.loadFromXAttr(xAttributes);
@@ -273,7 +291,7 @@ const std::vector<LayoutAtomPtr>& ChooseAtom::getChildren() const
return maEmptyChildren;
}
-ConditionAtom::ConditionAtom(const LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) :
+ConditionAtom::ConditionAtom(LayoutNode& rLayoutNode, bool isElse, const Reference< XFastAttributeList >& xAttributes) :
LayoutAtom(rLayoutNode),
mIsElse(isElse)
{
@@ -447,6 +465,21 @@ void ConstraintAtom::accept( LayoutAtomVisitor& rVisitor )
void ConstraintAtom::parseConstraint(std::vector<Constraint>& rConstraints,
bool bRequireForName) const
{
+ // Whitelist for cases where empty forName is handled.
+ if (bRequireForName)
+ {
+ switch (maConstraint.mnType)
+ {
+ case XML_sp:
+ case XML_lMarg:
+ case XML_rMarg:
+ case XML_tMarg:
+ case XML_bMarg:
+ bRequireForName = false;
+ break;
+ }
+ }
+
if (bRequireForName && maConstraint.msForName.isEmpty())
return;
@@ -464,7 +497,7 @@ void AlgAtom::accept( LayoutAtomVisitor& rVisitor )
}
void AlgAtom::layoutShape( const ShapePtr& rShape,
- const std::vector<Constraint>& rOwnConstraints ) const
+ const std::vector<Constraint>& rOwnConstraints )
{
// Algorithm result may depend on the parent constraints as well.
std::vector<Constraint> aMergedConstraints;
@@ -860,6 +893,18 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if (rShape->getChildren().empty() || rShape->getSize().Width == 0 || rShape->getSize().Height == 0)
break;
+ // Parse constraints, only self spacing from height as a start.
+ double fSpaceFromConstraint = 0;
+ for (const auto& rConstr : rConstraints)
+ {
+ if (rConstr.mnRefType == XML_h)
+ {
+ if (rConstr.mnType == XML_sp && rConstr.msForName.isEmpty())
+ fSpaceFromConstraint = rConstr.mfFactor;
+ }
+ }
+ bool bSpaceFromConstraints = fSpaceFromConstraint != 0;
+
const sal_Int32 nDir = maMap.count(XML_grDir) ? maMap.find(XML_grDir)->second : XML_tL;
sal_Int32 nIncX = 1;
sal_Int32 nIncY = 1;
@@ -871,38 +916,67 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
case XML_bR: nIncX = -1; nIncY = -1; break;
}
- // TODO: get values from constraints
sal_Int32 nCount = rShape->getChildren().size();
- double fSpace = 0.3;
+ // Defaults in case not provided by constraints.
+ double fSpace = bSpaceFromConstraints ? fSpaceFromConstraint : 0.3;
double fAspectRatio = 0.54; // diagram should not spill outside, earlier it was 0.6
sal_Int32 nCol = 1;
sal_Int32 nRow = 1;
- for ( ; nRow<nCount; nRow++)
+ double fChildAspectRatio = rShape->getChildren()[0]->getAspectRatio();
+ if (nCount <= fChildAspectRatio)
+ // Child aspect ratio request (width/height) is N, and we have at most N shapes.
+ // This means we don't need multiple columns.
+ nRow = nCount;
+ else
{
- nCol = (nCount+nRow-1) / nRow;
- const double fShapeHeight = rShape->getSize().Height;
- const double fShapeWidth = rShape->getSize().Width;
- if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio)
- break;
+ for ( ; nRow<nCount; nRow++)
+ {
+ nCol = (nCount+nRow-1) / nRow;
+ const double fShapeHeight = rShape->getSize().Height;
+ const double fShapeWidth = rShape->getSize().Width;
+ if ((fShapeHeight / nCol) / (fShapeWidth / nRow) >= fAspectRatio)
+ break;
+ }
}
SAL_INFO("oox.drawingml", "Snake layout grid: " << nCol << "x" << nRow);
sal_Int32 nWidth = rShape->getSize().Width / (nCol + (nCol-1)*fSpace);
- const awt::Size aChildSize(nWidth, nWidth * fAspectRatio);
+ awt::Size aChildSize(nWidth, nWidth * fAspectRatio);
+ if (nCol == 1 && nRow > 1)
+ {
+ // We have a single column, so count the height based on the parent height, not
+ // based on width.
+ // Space occurs inside children; also double amount of space is needed outside (on
+ // both sides), if the factor comes from a constraint.
+ sal_Int32 nNumSpaces = -1;
+ if (bSpaceFromConstraints)
+ nNumSpaces += 4;
+ sal_Int32 nHeight
+ = rShape->getSize().Height / (nRow + (nRow + nNumSpaces) * fSpace);
+
+ if (fChildAspectRatio > 1)
+ {
+ // Shrink width if the aspect ratio requires it.
+ nWidth = std::min(rShape->getSize().Width,
+ static_cast<sal_Int32>(nHeight * fChildAspectRatio));
+ aChildSize = awt::Size(nWidth, nHeight);
+ }
+ }
awt::Point aCurrPos(0, 0);
if (nIncX == -1)
aCurrPos.X = rShape->getSize().Width - aChildSize.Width;
if (nIncY == -1)
aCurrPos.Y = rShape->getSize().Height - aChildSize.Height;
+ else if (bSpaceFromConstraints)
+ // Initial vertical offset to have upper spacing (outside, so double amount).
+ aCurrPos.Y = aChildSize.Height * fSpace * 2;
sal_Int32 nStartX = aCurrPos.X;
sal_Int32 nColIdx = 0,index = 0;
- sal_Int32 num = rShape->getChildren().size();
-
const sal_Int32 aContDir = maMap.count(XML_contDir) ? maMap.find(XML_contDir)->second : XML_sameDir;
switch(aContDir)
@@ -922,7 +996,7 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if(++nColIdx == nCol) // condition for next row
{
// if last row, then position children according to number of shapes.
- if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol)
+ if((index+1)%nCol!=0 && (index+1)>=3 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol)
// position first child of last row
aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2;
else
@@ -961,10 +1035,10 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
if(++nColIdx == nCol) // condition for next row
{
// if last row, then position children according to number of shapes.
- if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2==0)
+ if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2==0)
// position first child of last row
aCurrPos.X -= aChildSize.Width*3/2;
- else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && num!=nRow*nCol && ((index/nCol)+1)%2!=0)
+ else if((index+1)%nCol!=0 && (index+1)>=4 && ((index+1)/nCol+1)==nRow && nCount!=nRow*nCol && ((index/nCol)+1)%2!=0)
aCurrPos.X = nStartX + (nIncX * (aChildSize.Width + fSpace*aChildSize.Width))/2;
else if(((index/nCol)+1)%2!=0)
aCurrPos.X = nStartX;
@@ -997,6 +1071,29 @@ void AlgAtom::layoutShape( const ShapePtr& rShape,
case XML_tx:
{
// adjust text alignment
+
+ // Parse constraints, only self margins as a start.
+ for (const auto& rConstr : rConstraints)
+ {
+ if (rConstr.mnRefType == XML_w)
+ {
+ if (!rConstr.msForName.isEmpty())
+ continue;
+
+ sal_Int32 nProperty = getPropertyFromConstraint(rConstr.mnType);
+ if (!nProperty)
+ continue;
+
+ // PowerPoint takes size as points, but gives margin as MMs.
+ double fFactor = convertPointToMms(rConstr.mfFactor);
+
+ // DrawingML works in EMUs, UNO API works in MM100s.
+ sal_Int32 nValue = rShape->getSize().Width * fFactor / EMU_PER_HMM;
+
+ rShape->getShapeProperties().setProperty(nProperty, nValue);
+ }
+ }
+
// TODO: adjust text size to fit shape
TextBodyPtr pTextBody = rShape->getTextBody();
if (!pTextBody ||
@@ -1220,6 +1317,8 @@ bool LayoutNode::setupShape( const ShapePtr& rShape, const dgm::Point* pPresNode
" processing shape type "
<< rShape->getCustomShapeProperties()->getShapePresetType()
<< " for layout node named \"" << msName << "\"");
+ if (pPresNode->mpShape)
+ rShape->getFillProperties().assignUsed(pPresNode->mpShape->getFillProperties());
}
// TODO(Q1): apply styling & coloring - take presentation