Add escape direction support for glue points in the preset shapes
Change-Id: I6727def5dd42ecd5dae3ddd27d2af733b5883e09 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170006 Tested-by: Jenkins Reviewed-by: Nagy Tibor <tibor.nagy.extern@allotropia.de>
This commit is contained in:
parent
a14531e413
commit
74b312d6f2
7 changed files with 152 additions and 16 deletions
|
@ -118,6 +118,7 @@ class SVXCORE_DLLPUBLIC EnhancedCustomShape2d final : public SfxItemSet
|
|||
css::uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > m_seqAdjustmentValues;
|
||||
css::uno::Sequence< css::beans::PropertyValues > m_seqHandles;
|
||||
css::uno::Sequence< css::awt::Size > m_seqSubViewSize;
|
||||
css::uno::Sequence< double > m_seqGluePointLeavingDirections;
|
||||
|
||||
bool m_bFilled : 1;
|
||||
bool m_bStroked : 1;
|
||||
|
|
|
@ -162,6 +162,18 @@ awt::Rectangle lcl_parseRectangle(std::string_view rValue)
|
|||
return aRectangle;
|
||||
}
|
||||
|
||||
sal_Int32 lcl_parseDirection(std::string_view rValue)
|
||||
{
|
||||
sal_Int32 aDirection;
|
||||
// We expect the following here: Direction
|
||||
static const char aExpectedWidthPrefix[] = "Dir = (long) ";
|
||||
assert(o3tl::starts_with(rValue, aExpectedWidthPrefix));
|
||||
sal_Int32 nIndex = strlen(aExpectedWidthPrefix);
|
||||
aDirection = o3tl::toInt32(rValue.substr(nIndex));
|
||||
|
||||
return aDirection;
|
||||
}
|
||||
|
||||
awt::Size lcl_parseSize(std::string_view rValue)
|
||||
{
|
||||
awt::Size aSize;
|
||||
|
@ -582,6 +594,73 @@ void lcl_parsePathGluePoints(std::vector<beans::PropertyValue>& rPath, std::stri
|
|||
}
|
||||
}
|
||||
|
||||
void lcl_parsePathGluePointLeavingDirectionsValues(std::vector<beans::PropertyValue>& rPath,
|
||||
std::string_view rValue)
|
||||
{
|
||||
std::vector<double> aDirection;
|
||||
sal_Int32 nLevel = 0;
|
||||
sal_Int32 nStart = 0;
|
||||
for (size_t i = 0; i < rValue.size(); ++i)
|
||||
{
|
||||
if (rValue[i] == '{')
|
||||
{
|
||||
if (!nLevel)
|
||||
nStart = i;
|
||||
nLevel++;
|
||||
}
|
||||
else if (rValue[i] == '}')
|
||||
{
|
||||
nLevel--;
|
||||
if (!nLevel)
|
||||
aDirection.push_back(lcl_parseDirection(
|
||||
rValue.substr(nStart + strlen("{ "), i - nStart - strlen(" },"))));
|
||||
}
|
||||
}
|
||||
|
||||
beans::PropertyValue aPropertyValue;
|
||||
aPropertyValue.Name = "GluePointLeavingDirections";
|
||||
aPropertyValue.Value <<= comphelper::containerToSequence(aDirection);
|
||||
rPath.push_back(aPropertyValue);
|
||||
}
|
||||
|
||||
void lcl_parsePathGluePointLeavingDirections(std::vector<beans::PropertyValue>& rPath,
|
||||
std::string_view rValue)
|
||||
{
|
||||
sal_Int32 nLevel = 0;
|
||||
bool bIgnore = false;
|
||||
sal_Int32 nStart = 0;
|
||||
for (size_t i = 0; i < rValue.size(); ++i)
|
||||
{
|
||||
if (rValue[i] == '{')
|
||||
{
|
||||
if (!nLevel)
|
||||
bIgnore = true;
|
||||
nLevel++;
|
||||
}
|
||||
else if (rValue[i] == '}')
|
||||
{
|
||||
nLevel--;
|
||||
if (!nLevel)
|
||||
bIgnore = false;
|
||||
}
|
||||
else if (rValue[i] == ',' && !bIgnore)
|
||||
{
|
||||
std::string_view aToken = rValue.substr(nStart, i - nStart);
|
||||
static const char aExpectedPrefix[] = "Value = (any) { ([]long) { ";
|
||||
if (o3tl::starts_with(aToken, aExpectedPrefix))
|
||||
{
|
||||
aToken = aToken.substr(strlen(aExpectedPrefix),
|
||||
aToken.size() - strlen(aExpectedPrefix) - strlen(" } }"));
|
||||
lcl_parsePathGluePointLeavingDirectionsValues(rPath, aToken);
|
||||
}
|
||||
else if (!o3tl::starts_with(aToken, "Name =") && !o3tl::starts_with(aToken, "Handle ="))
|
||||
SAL_WARN("oox",
|
||||
"lcl_parsePathGluePointLeavingDirections: unexpected token: " << aToken);
|
||||
nStart = i + strlen(", ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lcl_parsePathSegmentValues(std::vector<beans::PropertyValue>& rPath, std::string_view rValue)
|
||||
{
|
||||
std::vector<drawing::EnhancedCustomShapeSegment> aSegments;
|
||||
|
@ -804,6 +883,8 @@ void lcl_parsePath(std::vector<beans::PropertyValue>& rPath, std::string_view rV
|
|||
lcl_parsePathCoordinates(rPath, aToken);
|
||||
else if (o3tl::starts_with(aToken, "Name = \"GluePoints\""))
|
||||
lcl_parsePathGluePoints(rPath, aToken);
|
||||
else if (o3tl::starts_with(aToken, "Name = \"GluePointLeavingDirections\""))
|
||||
lcl_parsePathGluePointLeavingDirections(rPath, aToken);
|
||||
else if (o3tl::starts_with(aToken, "Name = \"Segments\""))
|
||||
lcl_parsePathSegments(rPath, aToken);
|
||||
else if (o3tl::starts_with(aToken, "Name = \"TextFrames\""))
|
||||
|
|
File diff suppressed because one or more lines are too long
BIN
sd/qa/unit/data/pptx/glue_point_leaving_directions.pptx
Normal file
BIN
sd/qa/unit/data/pptx/glue_point_leaving_directions.pptx
Normal file
Binary file not shown.
|
@ -128,6 +128,7 @@
|
|||
</Coordinates>
|
||||
</PropertyValue>
|
||||
<PropertyValue name="GluePoints" handle="0" propertyState="DIRECT_VALUE"/>
|
||||
<PropertyValue name="GluePointLeavingDirections" handle="0" propertyState="DIRECT_VALUE"/>
|
||||
<PropertyValue name="Segments">
|
||||
<Segments>
|
||||
<EnhancedCustomShapeSegment command="1" count="1"/>
|
||||
|
@ -211,6 +212,7 @@
|
|||
</Coordinates>
|
||||
</PropertyValue>
|
||||
<PropertyValue name="GluePoints" handle="0" propertyState="DIRECT_VALUE"/>
|
||||
<PropertyValue name="GluePointLeavingDirections" handle="0" propertyState="DIRECT_VALUE"/>
|
||||
<PropertyValue name="Segments">
|
||||
<Segments>
|
||||
<EnhancedCustomShapeSegment command="1" count="1"/>
|
||||
|
|
|
@ -546,6 +546,34 @@ CPPUNIT_TEST_FIXTURE(SdImportTest, testTdf89449)
|
|||
CPPUNIT_ASSERT_EQUAL(sal_Int32(2), nEndGlueId);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdImportTest, testGluePointLeavingDirections)
|
||||
{
|
||||
createSdImpressDoc("pptx/glue_point_leaving_directions.pptx");
|
||||
uno::Reference<beans::XPropertySet> xEllipseShape(getShapeFromPage(0, 0));
|
||||
uno::Sequence<beans::PropertyValue> aProps;
|
||||
xEllipseShape->getPropertyValue(u"CustomShapeGeometry"_ustr) >>= aProps;
|
||||
|
||||
uno::Sequence<beans::PropertyValue> aPathProps;
|
||||
for (beans::PropertyValue const& rProp : aProps)
|
||||
{
|
||||
if (rProp.Name == "Path")
|
||||
aPathProps = rProp.Value.get<uno::Sequence<beans::PropertyValue>>();
|
||||
}
|
||||
|
||||
uno::Sequence<double> seqGluePointLeavingDirections;
|
||||
for (beans::PropertyValue const& rProp : aPathProps)
|
||||
{
|
||||
if (rProp.Name == "GluePointLeavingDirections")
|
||||
{
|
||||
rProp.Value >>= seqGluePointLeavingDirections;
|
||||
}
|
||||
}
|
||||
|
||||
sal_Int32 nCountGluePointLeavingDirections = seqGluePointLeavingDirections.getLength();
|
||||
// The ellipse has 8 glue point leaving directions
|
||||
CPPUNIT_ASSERT_EQUAL(sal_Int32(8), nCountGluePointLeavingDirections);
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SdImportTest, testTdf147459)
|
||||
{
|
||||
createSdImpressDoc("pptx/tdf147459.pptx");
|
||||
|
|
|
@ -565,6 +565,7 @@ void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryIt
|
|||
static constexpr OUString sPath( u"Path"_ustr );
|
||||
static constexpr OUStringLiteral sCoordinates( u"Coordinates" );
|
||||
static constexpr OUStringLiteral sGluePoints( u"GluePoints" );
|
||||
static constexpr OUStringLiteral sGluePointLeavingDirections( u"GluePointLeavingDirections" );
|
||||
static constexpr OUStringLiteral sSegments( u"Segments" );
|
||||
static constexpr OUStringLiteral sSubViewSize( u"SubViewSize" );
|
||||
static constexpr OUStringLiteral sStretchX( u"StretchX" );
|
||||
|
@ -585,6 +586,10 @@ void EnhancedCustomShape2d::ApplyShapeAttributes( const SdrCustomShapeGeometryIt
|
|||
if ( pAny )
|
||||
*pAny >>= m_seqGluePoints;
|
||||
|
||||
// Path/GluePointLeavingDirections
|
||||
pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName(sPath, sGluePointLeavingDirections);
|
||||
if (pAny)
|
||||
*pAny >>= m_seqGluePointLeavingDirections;
|
||||
|
||||
// Path/Segments
|
||||
pAny = const_cast<SdrCustomShapeGeometryItem&>(rGeometryItem).GetPropertyValueByName( sPath, sSegments );
|
||||
|
@ -3064,19 +3069,38 @@ rtl::Reference<SdrObject> EnhancedCustomShape2d::CreateObject( bool bLineGeometr
|
|||
return pRet;
|
||||
}
|
||||
|
||||
static SdrEscapeDirection lcl_GetEscapeDirection(sal_Int32 nDirection)
|
||||
{
|
||||
switch (nDirection)
|
||||
{
|
||||
case 1: return SdrEscapeDirection::LEFT;
|
||||
case 2: return SdrEscapeDirection::RIGHT;
|
||||
case 3: return SdrEscapeDirection::TOP;
|
||||
case 4: return SdrEscapeDirection::BOTTOM;
|
||||
default: return SdrEscapeDirection::SMART;
|
||||
}
|
||||
}
|
||||
|
||||
void EnhancedCustomShape2d::ApplyGluePoints(SdrObject* pObj)
|
||||
{
|
||||
if ( !pObj )
|
||||
return;
|
||||
|
||||
for (const auto& rGluePoint : m_seqGluePoints)
|
||||
SdrEscapeDirection aDirection = SdrEscapeDirection::SMART;
|
||||
for (size_t i = 0; i < m_seqGluePoints.size(); i++)
|
||||
{
|
||||
SdrGluePoint aGluePoint;
|
||||
EnhancedCustomShapeParameterPair aGluePointPair = m_seqGluePoints[i];
|
||||
if (m_seqGluePointLeavingDirections.hasElements())
|
||||
{
|
||||
sal_Int32 aGluePointLeavingDirection = m_seqGluePointLeavingDirections[i];
|
||||
aDirection = lcl_GetEscapeDirection(aGluePointLeavingDirection);
|
||||
}
|
||||
|
||||
aGluePoint.SetPos( GetPoint( rGluePoint, !m_bOOXMLShape, true ) );
|
||||
SdrGluePoint aGluePoint;
|
||||
aGluePoint.SetPos( GetPoint( aGluePointPair, !m_bOOXMLShape, true ) );
|
||||
aGluePoint.SetPercent( false );
|
||||
aGluePoint.SetAlign( SdrAlign::VERT_TOP | SdrAlign::HORZ_LEFT );
|
||||
aGluePoint.SetEscDir( SdrEscapeDirection::SMART );
|
||||
aGluePoint.SetEscDir( aDirection );
|
||||
SdrGluePointList* pList = pObj->ForceGluePointList();
|
||||
if( pList )
|
||||
/* sal_uInt16 nId = */ pList->Insert( aGluePoint );
|
||||
|
|
Loading…
Reference in a new issue