diff options
Diffstat (limited to 'oox/source/drawingml/diagram/diagramlayoutatoms.cxx')
-rw-r--r-- | oox/source/drawingml/diagram/diagramlayoutatoms.cxx | 133 |
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 |