1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <vcl/bitmap/BitmapShadowFilter.hxx>
21 #include <svx/svdoashp.hxx>
22 #include <svx/unoapi.hxx>
23 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
24 #include <com/sun/star/drawing/XShape.hpp>
25 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
26 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
27 #include <com/sun/star/beans/PropertyValue.hpp>
28 #include <com/sun/star/awt/Rectangle.hpp>
29 #include <com/sun/star/uno/XComponentContext.hpp>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/propertyvalue.hxx>
32 #include <comphelper/sequenceashashmap.hxx>
33 #include <com/sun/star/uno/Sequence.h>
34 #include <tools/helpers.hxx>
35 #include <svx/svddrag.hxx>
36 #include <svx/svddrgmt.hxx>
37 #include <svx/svdmodel.hxx>
38 #include <svx/svdpage.hxx>
39 #include <svx/svditer.hxx>
40 #include <svx/svdobj.hxx>
41 #include <svx/svdtrans.hxx>
42 #include <svx/dialmgr.hxx>
43 #include <svx/strings.hrc>
44 #include <editeng/eeitem.hxx>
45 #include <editeng/editstat.hxx>
46 #include <editeng/adjustitem.hxx>
47 #include <svx/svdoutl.hxx>
48 #include <editeng/outlobj.hxx>
49 #include <svx/sdtfchim.hxx>
50 #include <svx/EnhancedCustomShapeGeometry.hxx>
51 #include <svx/EnhancedCustomShapeTypeNames.hxx>
52 #include <svx/EnhancedCustomShape2d.hxx>
53 #include <com/sun/star/beans/PropertyValues.hpp>
54 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
55 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
56 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
57 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
58 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
59 #include <editeng/writingmodeitem.hxx>
60 #include <svx/xlineit0.hxx>
61 #include <svx/xlnclit.hxx>
62 #include <sdr/properties/customshapeproperties.hxx>
63 #include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
64 #include <svx/xlntrit.hxx>
65 #include <svx/xfillit0.hxx>
66 #include <svx/xfltrit.hxx>
67 #include <svx/xflclit.hxx>
68 #include <svx/xflgrit.hxx>
69 #include <svx/xflhtit.hxx>
70 #include <svx/xbtmpit.hxx>
71 #include <vcl/virdev.hxx>
72 #include <svx/svdview.hxx>
73 #include <svx/sdmetitm.hxx>
74 #include <svx/sdprcitm.hxx>
75 #include <svx/sdshitm.hxx>
76 #include <svx/sdsxyitm.hxx>
77 #include <svx/sdtmfitm.hxx>
78 #include <svx/sdasitm.hxx>
79 #include <basegfx/polygon/b2dpolypolygontools.hxx>
80 #include <basegfx/matrix/b2dhommatrix.hxx>
81 #include <basegfx/matrix/b2dhommatrixtools.hxx>
82 #include <basegfx/polygon/b2dpolygon.hxx>
83 #include <basegfx/polygon/b2dpolygontools.hxx>
84 #include <basegfx/range/b2drange.hxx>
85 #include <svdobjplusdata.hxx>
86 #include <sal/log.hxx>
87 #include <o3tl/string_view.hxx>
88 #include "presetooxhandleadjustmentrelations.hxx"
89 #include <editeng/frmdiritem.hxx>
91 using namespace ::com::sun::star
;
93 static void lcl_ShapeSegmentFromBinary( drawing::EnhancedCustomShapeSegment
& rSegInfo
, sal_uInt16 nSDat
)
98 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::LINETO
;
99 rSegInfo
.Count
= nSDat
& 0xff;
100 if ( !rSegInfo
.Count
)
104 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::CURVETO
;
105 rSegInfo
.Count
= nSDat
& 0xff;
106 if ( !rSegInfo
.Count
)
110 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::MOVETO
;
111 rSegInfo
.Count
= nSDat
& 0xff;
112 if ( !rSegInfo
.Count
)
116 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
;
120 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH
;
124 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO
;
125 rSegInfo
.Count
= ( nSDat
& 0xff ) / 3;
128 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE
;
129 rSegInfo
.Count
= ( nSDat
& 0xff ) / 3;
132 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ARCTO
;
133 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
136 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ARC
;
137 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
140 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
;
141 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
144 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
;
145 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
148 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX
;
149 rSegInfo
.Count
= nSDat
& 0xff;
152 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY
;
153 rSegInfo
.Count
= nSDat
& 0xff;
156 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::NOFILL
;
160 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE
;
165 rSegInfo
.Command
= drawing::EnhancedCustomShapeSegmentCommand::UNKNOWN
;
166 rSegInfo
.Count
= nSDat
;
171 static MSO_SPT
ImpGetCustomShapeType( const SdrObjCustomShape
& rCustoShape
)
173 MSO_SPT eRetValue
= mso_sptNil
;
175 OUString
aEngine( rCustoShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue() );
176 if ( aEngine
.isEmpty() || aEngine
== "com.sun.star.drawing.EnhancedCustomShapeEngine" )
179 const SdrCustomShapeGeometryItem
& rGeometryItem( rCustoShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
180 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"Type"_ustr
);
181 if ( pAny
&& ( *pAny
>>= sShapeType
) )
182 eRetValue
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
187 static bool ImpVerticalSwitch( const SdrObjCustomShape
& rCustoShape
)
190 MSO_SPT
eShapeType( ImpGetCustomShapeType( rCustoShape
) );
193 case mso_sptAccentBorderCallout90
: // 2 ortho
194 case mso_sptBorderCallout1
: // 2 diag
195 case mso_sptBorderCallout2
: // 3
205 // #i37011# create a clone with all attributes changed to shadow attributes
206 // and translation executed, too.
207 static rtl::Reference
<SdrObject
> ImpCreateShadowObjectClone(const SdrObject
& rOriginal
, const SfxItemSet
& rOriginalSet
)
209 rtl::Reference
<SdrObject
> pRetval
;
210 const bool bShadow(rOriginalSet
.Get(SDRATTR_SHADOW
).GetValue());
214 // create a shadow representing object
215 const sal_Int32
nXDist(rOriginalSet
.Get(SDRATTR_SHADOWXDIST
).GetValue());
216 const sal_Int32
nYDist(rOriginalSet
.Get(SDRATTR_SHADOWYDIST
).GetValue());
217 const ::Color
aShadowColor(rOriginalSet
.Get(SDRATTR_SHADOWCOLOR
).GetColorValue());
218 const sal_uInt16
nShadowTransparence(rOriginalSet
.Get(SDRATTR_SHADOWTRANSPARENCE
).GetValue());
219 pRetval
= rOriginal
.CloneSdrObject(rOriginal
.getSdrModelFromSdrObject());
220 DBG_ASSERT(pRetval
, "ImpCreateShadowObjectClone: Could not clone object (!)");
222 // look for used stuff
223 SdrObjListIter
aIterator(rOriginal
);
224 bool bLineUsed(false);
225 bool bAllFillUsed(false);
226 bool bSolidFillUsed(false);
227 bool bGradientFillUsed(false);
228 bool bHatchFillUsed(false);
229 bool bBitmapFillUsed(false);
231 while(aIterator
.IsMore())
233 SdrObject
* pObj
= aIterator
.Next();
234 drawing::FillStyle eFillStyle
= pObj
->GetMergedItem(XATTR_FILLSTYLE
).GetValue();
238 drawing::LineStyle eLineStyle
= pObj
->GetMergedItem(XATTR_LINESTYLE
).GetValue();
240 if(drawing::LineStyle_NONE
!= eLineStyle
)
248 if(!bSolidFillUsed
&& drawing::FillStyle_SOLID
== eFillStyle
)
250 bSolidFillUsed
= true;
251 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
253 if(!bGradientFillUsed
&& drawing::FillStyle_GRADIENT
== eFillStyle
)
255 bGradientFillUsed
= true;
256 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
258 if(!bHatchFillUsed
&& drawing::FillStyle_HATCH
== eFillStyle
)
260 bHatchFillUsed
= true;
261 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
263 if(!bBitmapFillUsed
&& drawing::FillStyle_BITMAP
== eFillStyle
)
265 bBitmapFillUsed
= true;
266 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
271 // translate to shadow coordinates
272 pRetval
->NbcMove(Size(nXDist
, nYDist
));
274 // set items as needed
275 SfxItemSet
aTempSet(rOriginalSet
);
277 // if a SvxWritingModeItem (Top->Bottom) is set the text object
278 // is creating a paraobject, but paraobjects can not be created without model. So
279 // we are preventing the crash by setting the writing mode always left to right,
280 // this is not bad since our shadow geometry does not contain text.
281 aTempSet
.Put(SvxWritingModeItem(text::WritingMode_LR_TB
, SDRATTR_TEXTDIRECTION
));
284 aTempSet
.Put(makeSdrShadowItem(false));
285 aTempSet
.Put(makeSdrShadowXDistItem(0));
286 aTempSet
.Put(makeSdrShadowYDistItem(0));
288 // line color and transparency like shadow
291 aTempSet
.Put(XLineColorItem(OUString(), aShadowColor
));
292 aTempSet
.Put(XLineTransparenceItem(nShadowTransparence
));
295 // fill color and transparency like shadow
298 aTempSet
.Put(XFillColorItem(OUString(), aShadowColor
));
299 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
302 // gradient and transparency like shadow
303 if(bGradientFillUsed
)
305 basegfx::BGradient
aGradient(rOriginalSet
.Get(XATTR_FILLGRADIENT
).GetGradientValue());
306 sal_uInt8
nStartLuminance(Color(aGradient
.GetColorStops().front().getStopColor()).GetLuminance());
307 sal_uInt8
nEndLuminance(Color(aGradient
.GetColorStops().back().getStopColor()).GetLuminance());
309 if(aGradient
.GetStartIntens() != 100)
311 nStartLuminance
= static_cast<sal_uInt8
>(nStartLuminance
* (static_cast<double>(aGradient
.GetStartIntens()) / 100.0));
314 if(aGradient
.GetEndIntens() != 100)
316 nEndLuminance
= static_cast<sal_uInt8
>(nEndLuminance
* (static_cast<double>(aGradient
.GetEndIntens()) / 100.0));
320 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetRed()) / 256),
321 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetGreen()) / 256),
322 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetBlue()) / 256));
325 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetRed()) / 256),
326 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetGreen()) / 256),
327 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetBlue()) / 256));
329 aGradient
.SetColorStops(
330 basegfx::BColorStops(
331 aStartColor
.getBColor(),
332 aEndColor
.getBColor()));
333 aTempSet
.Put(XFillGradientItem(aGradient
));
334 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
337 // hatch and transparency like shadow
340 XHatch
aHatch(rOriginalSet
.Get(XATTR_FILLHATCH
).GetHatchValue());
341 aHatch
.SetColor(aShadowColor
);
342 aTempSet
.Put(XFillHatchItem(aHatch
));
343 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
346 // bitmap and transparency like shadow
349 GraphicObject
aGraphicObject(rOriginalSet
.Get(XATTR_FILLBITMAP
).GetGraphicObject());
350 BitmapEx
aBitmapEx(aGraphicObject
.GetGraphic().GetBitmapEx());
352 if(!aBitmapEx
.IsEmpty())
354 ScopedVclPtr
<VirtualDevice
> pVirDev(VclPtr
<VirtualDevice
>::Create());
355 pVirDev
->SetOutputSizePixel(aBitmapEx
.GetSizePixel());
356 BitmapFilter::Filter(aBitmapEx
, BitmapShadowFilter(aShadowColor
));
357 pVirDev
->DrawBitmapEx(Point(), aBitmapEx
);
358 aGraphicObject
.SetGraphic(Graphic(pVirDev
->GetBitmapEx(Point(0,0), aBitmapEx
.GetSizePixel())));
361 aTempSet
.Put(XFillBitmapItem(aGraphicObject
));
362 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
365 // set attributes and paint shadow object
366 pRetval
->SetMergedItemSet( aTempSet
);
372 uno::Reference
<drawing::XCustomShapeEngine
> const & SdrObjCustomShape::GetCustomShapeEngine() const
374 if (mxCustomShapeEngine
.is())
375 return mxCustomShapeEngine
;
377 uno::Reference
<drawing::XShape
> aXShape
= GetXShapeForSdrObject(const_cast<SdrObjCustomShape
*>(this));
379 return mxCustomShapeEngine
;
381 const uno::Reference
<uno::XComponentContext
>& xContext( ::comphelper::getProcessComponentContext() );
383 OUString
aEngine(GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue());
384 static constexpr OUStringLiteral sEnhancedCustomShapeEngine
= u
"com.sun.star.drawing.EnhancedCustomShapeEngine";
385 if ( aEngine
.isEmpty() )
386 aEngine
= sEnhancedCustomShapeEngine
;
389 static constexpr OUString sCustomShape
= u
"CustomShape"_ustr
;
390 uno::Sequence
<beans::PropertyValue
> aPropValues
{ comphelper::makePropertyValue(sCustomShape
,
392 uno::Sequence
<uno::Any
> aArgument
{ uno::Any(aPropValues
) };
395 uno::Reference
<uno::XInterface
> xInterface(xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine
, aArgument
, xContext
));
397 mxCustomShapeEngine
.set(xInterface
, uno::UNO_QUERY
);
399 catch (const loader::CannotActivateFactoryException
&)
404 return mxCustomShapeEngine
;
407 const SdrObject
* SdrObjCustomShape::GetSdrObjectFromCustomShape() const
409 if ( !mXRenderedCustomShape
.is() )
411 uno::Reference
<drawing::XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
412 if ( xCustomShapeEngine
.is() )
413 const_cast<SdrObjCustomShape
*>(this)->mXRenderedCustomShape
= xCustomShapeEngine
->render();
415 SdrObject
* pRenderedCustomShape
= mXRenderedCustomShape
.is()
416 ? SdrObject::getSdrObjectFromXShape( mXRenderedCustomShape
)
418 return pRenderedCustomShape
;
421 // #i37011# Shadow geometry creation
422 const SdrObject
* SdrObjCustomShape::GetSdrObjectShadowFromCustomShape() const
424 if(!mpLastShadowGeometry
)
426 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
429 const SfxItemSet
& rOriginalSet
= GetObjectItemSet();
430 const bool bShadow(rOriginalSet
.Get( SDRATTR_SHADOW
).GetValue());
434 // create a clone with all attributes changed to shadow attributes
435 // and translation executed, too.
436 const_cast<SdrObjCustomShape
*>(this)->mpLastShadowGeometry
=
437 ImpCreateShadowObjectClone(*pSdrObject
, rOriginalSet
);
442 return mpLastShadowGeometry
.get();
445 bool SdrObjCustomShape::IsTextPath() const
447 static constexpr OUString
sTextPath( u
"TextPath"_ustr
);
448 bool bTextPathOn
= false;
449 const SdrCustomShapeGeometryItem
& rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
450 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sTextPath
, sTextPath
);
452 *pAny
>>= bTextPathOn
;
456 bool SdrObjCustomShape::UseNoFillStyle() const
460 static constexpr OUString
sType( u
"Type"_ustr
);
461 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
462 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sType
);
464 *pAny
>>= sShapeType
;
465 bRet
= !IsCustomShapeFilledByDefault( EnhancedCustomShapeTypeNames::Get( sType
) );
470 bool SdrObjCustomShape::IsMirroredX() const
472 bool bMirroredX
= false;
473 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
474 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"MirroredX"_ustr
);
476 *pAny
>>= bMirroredX
;
479 bool SdrObjCustomShape::IsMirroredY() const
481 bool bMirroredY
= false;
482 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
483 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"MirroredY"_ustr
);
485 *pAny
>>= bMirroredY
;
488 void SdrObjCustomShape::SetMirroredX( const bool bMirrorX
)
490 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
491 beans::PropertyValue aPropVal
;
492 aPropVal
.Name
= "MirroredX";
493 aPropVal
.Value
<<= bMirrorX
;
494 aGeometryItem
.SetPropertyValue( aPropVal
);
495 SetMergedItem( aGeometryItem
);
497 void SdrObjCustomShape::SetMirroredY( const bool bMirrorY
)
499 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
500 beans::PropertyValue aPropVal
;
501 aPropVal
.Name
= "MirroredY";
502 aPropVal
.Value
<<= bMirrorY
;
503 aGeometryItem
.SetPropertyValue( aPropVal
);
504 SetMergedItem( aGeometryItem
);
507 double SdrObjCustomShape::GetExtraTextRotation( const bool bPreRotation
) const
509 double fExtraTextRotateAngle
= 0.0;
512 // textPreRotateAngle might be set by macro or diagram (SmartArt) import
513 const uno::Any
* pAny
;
514 const SdrCustomShapeGeometryItem
& rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
515 pAny
= rGeometryItem
.GetPropertyValueByName(u
"TextPreRotateAngle"_ustr
);
517 *pAny
>>= fExtraTextRotateAngle
;
519 // As long as the edit engine is not able to render these text directions we
520 // emulate them by setting a suitable text pre-rotation.
521 const SvxFrameDirectionItem
& rDirectionItem
= GetMergedItem(SDRATTR_WRITINGMODE2
);
522 if (rDirectionItem
.GetValue() == SvxFrameDirection::Vertical_RL_TB90
)
523 fExtraTextRotateAngle
-= 90;
524 else if (rDirectionItem
.GetValue() == SvxFrameDirection::Vertical_LR_BT
)
525 fExtraTextRotateAngle
-=270;
529 const uno::Any
* pAny
;
530 const SdrCustomShapeGeometryItem
& rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
531 pAny
= rGeometryItem
.GetPropertyValueByName(u
"TextRotateAngle"_ustr
);
533 *pAny
>>= fExtraTextRotateAngle
;
535 return fExtraTextRotateAngle
;
538 bool SdrObjCustomShape::GetTextBounds( tools::Rectangle
& rTextBound
) const
542 uno::Reference
<drawing::XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
543 if ( xCustomShapeEngine
.is() )
545 awt::Rectangle
aR( xCustomShapeEngine
->getTextBounds() );
546 if ( aR
.Width
> 1 && aR
.Height
> 1 )
548 rTextBound
= tools::Rectangle( Point( aR
.X
, aR
.Y
), Size( aR
.Width
, aR
.Height
) );
554 basegfx::B2DPolyPolygon
SdrObjCustomShape::GetLineGeometry( const bool bBezierAllowed
) const
556 basegfx::B2DPolyPolygon aRetval
;
557 uno::Reference
<drawing::XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
558 if ( xCustomShapeEngine
.is() )
560 drawing::PolyPolygonBezierCoords aBezierCoords
= xCustomShapeEngine
->getLineGeometry();
563 aRetval
= basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( aBezierCoords
);
564 if ( !bBezierAllowed
&& aRetval
.areControlPointsUsed())
566 aRetval
= basegfx::utils::adaptiveSubdivideByAngle(aRetval
);
569 catch ( const lang::IllegalArgumentException
& )
576 std::vector
< SdrCustomShapeInteraction
> SdrObjCustomShape::GetInteractionHandles() const
578 std::vector
< SdrCustomShapeInteraction
> aRet
;
581 uno::Reference
<drawing::XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
582 if ( xCustomShapeEngine
.is() )
585 uno::Sequence
<uno::Reference
<drawing::XCustomShapeHandle
>> xInteractionHandles( xCustomShapeEngine
->getInteraction() );
586 for ( i
= 0; i
< xInteractionHandles
.getLength(); i
++ )
588 if ( xInteractionHandles
[ i
].is() )
590 SdrCustomShapeInteraction aSdrCustomShapeInteraction
;
591 aSdrCustomShapeInteraction
.xInteraction
= xInteractionHandles
[ i
];
592 aSdrCustomShapeInteraction
.aPosition
= xInteractionHandles
[ i
]->getPosition();
594 CustomShapeHandleModes nMode
= CustomShapeHandleModes::NONE
;
595 switch( ImpGetCustomShapeType( *this ) )
597 case mso_sptAccentBorderCallout90
: // 2 ortho
600 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
602 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
| CustomShapeHandleModes::ORTHO4
;
606 case mso_sptChevron
:
607 case mso_sptHomePlate
:
608 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
;
611 case mso_sptWedgeRectCallout
:
612 case mso_sptWedgeRRectCallout
:
613 case mso_sptCloudCallout
:
614 case mso_sptWedgeEllipseCallout
:
617 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
;
621 case mso_sptBorderCallout1
: // 2 diag
624 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
626 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
;
629 case mso_sptBorderCallout2
: // 3
632 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
634 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
;
637 case mso_sptCallout90
:
638 case mso_sptAccentCallout90
:
639 case mso_sptBorderCallout90
:
640 case mso_sptCallout1
:
641 case mso_sptCallout2
:
642 case mso_sptCallout3
:
643 case mso_sptAccentCallout1
:
644 case mso_sptAccentCallout2
:
645 case mso_sptAccentCallout3
:
646 case mso_sptBorderCallout3
:
647 case mso_sptAccentBorderCallout1
:
648 case mso_sptAccentBorderCallout2
:
649 case mso_sptAccentBorderCallout3
:
652 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
657 aSdrCustomShapeInteraction
.nMode
= nMode
;
658 aRet
.push_back( aSdrCustomShapeInteraction
);
663 catch( const uno::RuntimeException
& )
670 // BaseProperties section
671 #define DEFAULT_MINIMUM_SIGNED_COMPARE (sal_Int32(0x80000000))
672 #define DEFAULT_MAXIMUM_SIGNED_COMPARE (sal_Int32(0x7fffffff))
674 static sal_Int32
GetNumberOfProperties ( const SvxMSDffHandle
* pData
)
676 sal_Int32 nPropertiesNeeded
=1; // position is always needed
677 SvxMSDffHandleFlags nFlags
= pData
->nFlags
;
679 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_X
)
681 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_Y
)
683 if ( nFlags
& SvxMSDffHandleFlags::SWITCHED
)
685 if ( nFlags
& SvxMSDffHandleFlags::POLAR
)
688 if ( nFlags
& SvxMSDffHandleFlags::RADIUS_RANGE
)
690 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
692 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
696 else if ( nFlags
& SvxMSDffHandleFlags::RANGE
)
698 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
700 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
702 if ( pData
->nRangeYMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
704 if ( pData
->nRangeYMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
708 return nPropertiesNeeded
;
711 static void lcl_ShapePropertiesFromDFF( const SvxMSDffHandle
* pData
, beans::PropertyValues
& rPropValues
)
713 SvxMSDffHandleFlags nFlags
= pData
->nFlags
;
715 auto pPropValues
= rPropValues
.getArray();
719 drawing::EnhancedCustomShapeParameterPair aPosition
;
720 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition
.First
, pData
->nPositionX
, true, true );
721 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition
.Second
, pData
->nPositionY
, true, false );
722 pPropValues
[ n
].Name
= "Position";
723 pPropValues
[ n
++ ].Value
<<= aPosition
;
725 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_X
)
727 pPropValues
[ n
].Name
= "MirroredX";
728 pPropValues
[ n
++ ].Value
<<= true;
730 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_Y
)
732 pPropValues
[ n
].Name
= "MirroredY";
733 pPropValues
[ n
++ ].Value
<<= true;
735 if ( nFlags
& SvxMSDffHandleFlags::SWITCHED
)
737 pPropValues
[ n
].Name
= "Switched";
738 pPropValues
[ n
++ ].Value
<<= true;
740 if ( nFlags
& SvxMSDffHandleFlags::POLAR
)
742 drawing::EnhancedCustomShapeParameterPair aCenter
;
743 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter
.First
, pData
->nCenterX
,
744 bool( nFlags
& SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL
), true );
745 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter
.Second
, pData
->nCenterY
,
746 bool( nFlags
& SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL
), false );
747 pPropValues
[ n
].Name
= "Polar";
748 pPropValues
[ n
++ ].Value
<<= aCenter
;
749 if ( nFlags
& SvxMSDffHandleFlags::RADIUS_RANGE
)
751 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
753 drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum
;
754 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum
, pData
->nRangeXMin
,
755 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL
), true );
756 pPropValues
[ n
].Name
= "RadiusRangeMinimum";
757 pPropValues
[ n
++ ].Value
<<= aRadiusRangeMinimum
;
759 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
761 drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum
;
762 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum
, pData
->nRangeXMax
,
763 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL
), false );
764 pPropValues
[ n
].Name
= "RadiusRangeMaximum";
765 pPropValues
[ n
++ ].Value
<<= aRadiusRangeMaximum
;
769 else if ( nFlags
& SvxMSDffHandleFlags::RANGE
)
771 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
773 drawing::EnhancedCustomShapeParameter aRangeXMinimum
;
774 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum
, pData
->nRangeXMin
,
775 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL
), true );
776 pPropValues
[ n
].Name
= "RangeXMinimum";
777 pPropValues
[ n
++ ].Value
<<= aRangeXMinimum
;
779 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
781 drawing::EnhancedCustomShapeParameter aRangeXMaximum
;
782 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum
, pData
->nRangeXMax
,
783 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL
), false );
784 pPropValues
[ n
].Name
= "RangeXMaximum";
785 pPropValues
[ n
++ ].Value
<<= aRangeXMaximum
;
787 if ( pData
->nRangeYMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
789 drawing::EnhancedCustomShapeParameter aRangeYMinimum
;
790 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum
, pData
->nRangeYMin
,
791 bool( nFlags
& SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL
), true );
792 pPropValues
[ n
].Name
= "RangeYMinimum";
793 pPropValues
[ n
++ ].Value
<<= aRangeYMinimum
;
795 if ( pData
->nRangeYMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
797 drawing::EnhancedCustomShapeParameter aRangeYMaximum
;
798 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum
, pData
->nRangeYMax
,
799 bool( nFlags
& SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL
), false );
800 pPropValues
[ n
].Name
= "RangeYMaximum";
801 pPropValues
[ n
++ ].Value
<<= aRangeYMaximum
;
806 std::unique_ptr
<sdr::properties::BaseProperties
> SdrObjCustomShape::CreateObjectSpecificProperties()
808 return std::make_unique
<sdr::properties::CustomShapeProperties
>(*this);
811 SdrObjCustomShape::SdrObjCustomShape(SdrModel
& rSdrModel
)
812 : SdrTextObj(rSdrModel
)
813 , m_fObjectRotation(0.0)
814 , mbAdjustingTextFrameWidthAndHeight(false)
816 m_bClosedObj
= true; // custom shapes may be filled
820 SdrObjCustomShape::SdrObjCustomShape(SdrModel
& rSdrModel
, SdrObjCustomShape
const & rSource
)
821 : SdrTextObj(rSdrModel
, rSource
)
822 , m_fObjectRotation(0.0)
823 , mbAdjustingTextFrameWidthAndHeight(false)
825 m_bClosedObj
= true; // custom shapes may be filled
828 m_fObjectRotation
= rSource
.m_fObjectRotation
;
829 mbAdjustingTextFrameWidthAndHeight
= rSource
.mbAdjustingTextFrameWidthAndHeight
;
830 assert(!mbAdjustingTextFrameWidthAndHeight
);
831 InvalidateRenderGeometry();
834 SdrObjCustomShape::~SdrObjCustomShape()
836 // delete buffered display geometry
837 InvalidateRenderGeometry();
840 void SdrObjCustomShape::MergeDefaultAttributes( const OUString
* pType
)
842 beans::PropertyValue aPropVal
;
844 static constexpr OUString
sType( u
"Type"_ustr
);
845 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
846 if ( pType
&& !pType
->isEmpty() )
848 sal_Int32 nType
= pType
->toInt32();
850 sShapeType
= EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT
>( nType
) );
854 aPropVal
.Name
= sType
;
855 aPropVal
.Value
<<= sShapeType
;
856 aGeometryItem
.SetPropertyValue( aPropVal
);
860 uno::Any
*pAny
= aGeometryItem
.GetPropertyValueByName( sType
);
862 *pAny
>>= sShapeType
;
864 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
866 const sal_Int32
* pDefData
= nullptr;
867 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eSpType
);
868 if ( pDefCustomShape
)
869 pDefData
= pDefCustomShape
->pDefData
;
871 uno::Sequence
<drawing::EnhancedCustomShapeAdjustmentValue
> seqAdjustmentValues
;
876 static constexpr OUString
sAdjustmentValues( u
"AdjustmentValues"_ustr
);
877 const uno::Any
* pAny
= aGeometryItem
.GetPropertyValueByName( sAdjustmentValues
);
879 *pAny
>>= seqAdjustmentValues
;
880 if ( pDefCustomShape
&& pDefData
) // now check if we have to default some adjustment values
882 // first check if there are adjustment values are to be appended
883 sal_Int32 i
, nAdjustmentValues
= seqAdjustmentValues
.getLength();
884 sal_Int32 nAdjustmentDefaults
= *pDefData
++;
885 if ( nAdjustmentDefaults
> nAdjustmentValues
)
886 seqAdjustmentValues
.realloc( nAdjustmentDefaults
);
887 auto pseqAdjustmentValues
= seqAdjustmentValues
.getArray();
888 for ( i
= nAdjustmentValues
; i
< nAdjustmentDefaults
; i
++ )
890 pseqAdjustmentValues
[ i
].Value
<<= pDefData
[ i
];
891 pseqAdjustmentValues
[ i
].State
= beans::PropertyState_DIRECT_VALUE
;
893 // check if there are defaulted adjustment values that should be filled the hard coded defaults (pDefValue)
894 sal_Int32 nCount
= std::min(nAdjustmentValues
, nAdjustmentDefaults
);
895 for ( i
= 0; i
< nCount
; i
++ )
897 if ( seqAdjustmentValues
[ i
].State
!= beans::PropertyState_DIRECT_VALUE
)
899 pseqAdjustmentValues
[ i
].Value
<<= pDefData
[ i
];
900 pseqAdjustmentValues
[ i
].State
= beans::PropertyState_DIRECT_VALUE
;
904 aPropVal
.Name
= sAdjustmentValues
;
905 aPropVal
.Value
<<= seqAdjustmentValues
;
906 aGeometryItem
.SetPropertyValue( aPropVal
);
911 static constexpr OUString
sViewBox( u
"ViewBox"_ustr
);
912 const uno::Any
* pViewBox
= aGeometryItem
.GetPropertyValueByName( sViewBox
);
913 awt::Rectangle aViewBox
;
914 if ( !pViewBox
|| !(*pViewBox
>>= aViewBox
) )
916 if ( pDefCustomShape
)
920 aViewBox
.Width
= pDefCustomShape
->nCoordWidth
;
921 aViewBox
.Height
= pDefCustomShape
->nCoordHeight
;
922 aPropVal
.Name
= sViewBox
;
923 aPropVal
.Value
<<= aViewBox
;
924 aGeometryItem
.SetPropertyValue( aPropVal
);
928 static constexpr OUString
sPath( u
"Path"_ustr
);
933 static constexpr OUString
sCoordinates( u
"Coordinates"_ustr
);
934 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sCoordinates
);
935 if (!pAny
&& pDefCustomShape
&& !pDefCustomShape
->pVertices
.empty())
937 sal_Int32 i
, nCount
= pDefCustomShape
->pVertices
.size();
938 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqCoordinates( nCount
);
939 auto pseqCoordinates
= seqCoordinates
.getArray();
940 for ( i
= 0; i
< nCount
; i
++ )
942 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates
[ i
].First
, pDefCustomShape
->pVertices
[ i
].nValA
);
943 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates
[ i
].Second
, pDefCustomShape
->pVertices
[ i
].nValB
);
945 aPropVal
.Name
= sCoordinates
;
946 aPropVal
.Value
<<= seqCoordinates
;
947 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
951 static constexpr OUString
sGluePoints( u
"GluePoints"_ustr
);
952 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sGluePoints
);
953 if (!pAny
&& pDefCustomShape
&& !pDefCustomShape
->pGluePoints
.empty())
955 sal_Int32 i
, nCount
= pDefCustomShape
->pGluePoints
.size();
956 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqGluePoints( nCount
);
957 auto pseqGluePoints
= seqGluePoints
.getArray();
958 for ( i
= 0; i
< nCount
; i
++ )
960 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints
[ i
].First
, pDefCustomShape
->pGluePoints
[ i
].nValA
);
961 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints
[ i
].Second
, pDefCustomShape
->pGluePoints
[ i
].nValB
);
963 aPropVal
.Name
= sGluePoints
;
964 aPropVal
.Value
<<= seqGluePoints
;
965 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
969 static constexpr OUString
sSegments( u
"Segments"_ustr
);
970 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sSegments
);
971 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nElements
&& pDefCustomShape
->pElements
)
973 sal_Int32 i
, nCount
= pDefCustomShape
->nElements
;
974 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> seqSegments( nCount
);
975 auto pseqSegments
= seqSegments
.getArray();
976 for ( i
= 0; i
< nCount
; i
++ )
978 drawing::EnhancedCustomShapeSegment
& rSegInfo
= pseqSegments
[ i
];
979 sal_uInt16 nSDat
= pDefCustomShape
->pElements
[ i
];
980 lcl_ShapeSegmentFromBinary( rSegInfo
, nSDat
);
982 aPropVal
.Name
= sSegments
;
983 aPropVal
.Value
<<= seqSegments
;
984 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
988 static constexpr OUString
sStretchX( u
"StretchX"_ustr
);
989 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sStretchX
);
990 if ( !pAny
&& pDefCustomShape
)
992 sal_Int32 nXRef
= pDefCustomShape
->nXRef
;
993 if ( nXRef
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
995 aPropVal
.Name
= sStretchX
;
996 aPropVal
.Value
<<= nXRef
;
997 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
1002 static constexpr OUString
sStretchY( u
"StretchY"_ustr
);
1003 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sStretchY
);
1004 if ( !pAny
&& pDefCustomShape
)
1006 sal_Int32 nYRef
= pDefCustomShape
->nYRef
;
1007 if ( nYRef
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
1009 aPropVal
.Name
= sStretchY
;
1010 aPropVal
.Value
<<= nYRef
;
1011 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
1016 static constexpr OUString
sTextFrames( u
"TextFrames"_ustr
);
1017 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sTextFrames
);
1018 if (!pAny
&& pDefCustomShape
&& !pDefCustomShape
->pTextRect
.empty())
1020 sal_Int32 i
, nCount
= pDefCustomShape
->pTextRect
.size();
1021 uno::Sequence
<drawing::EnhancedCustomShapeTextFrame
> seqTextFrames( nCount
);
1022 auto pseqTextFrames
= seqTextFrames
.getArray();
1023 for (i
= 0; i
< nCount
; i
++)
1025 const SvxMSDffTextRectangles
* pRectangles
= &pDefCustomShape
->pTextRect
[i
];
1026 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames
[ i
].TopLeft
.First
, pRectangles
->nPairA
.nValA
);
1027 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames
[ i
].TopLeft
.Second
, pRectangles
->nPairA
.nValB
);
1028 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames
[ i
].BottomRight
.First
, pRectangles
->nPairB
.nValA
);
1029 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames
[ i
].BottomRight
.Second
, pRectangles
->nPairB
.nValB
);
1031 aPropVal
.Name
= sTextFrames
;
1032 aPropVal
.Value
<<= seqTextFrames
;
1033 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
1037 static constexpr OUString
sEquations( u
"Equations"_ustr
);
1038 pAny
= aGeometryItem
.GetPropertyValueByName( sEquations
);
1039 if (!pAny
&& pDefCustomShape
&& !pDefCustomShape
->pCalculation
.empty() )
1041 sal_Int32 i
, nCount
= pDefCustomShape
->pCalculation
.size();
1042 uno::Sequence
< OUString
> seqEquations( nCount
);
1043 auto pseqEquations
= seqEquations
.getArray();
1044 for (i
= 0; i
< nCount
; i
++)
1046 const SvxMSDffCalculationData
* pData
= &pDefCustomShape
->pCalculation
[i
];
1047 pseqEquations
[ i
] = EnhancedCustomShape2d::GetEquation( pData
->nFlags
, pData
->nVal
[ 0 ], pData
->nVal
[ 1 ], pData
->nVal
[ 2 ] );
1049 aPropVal
.Name
= sEquations
;
1050 aPropVal
.Value
<<= seqEquations
;
1051 aGeometryItem
.SetPropertyValue( aPropVal
);
1055 static constexpr OUString
sHandles( u
"Handles"_ustr
);
1056 pAny
= aGeometryItem
.GetPropertyValueByName( sHandles
);
1057 if (!pAny
&& pDefCustomShape
&& !pDefCustomShape
->pHandles
.empty())
1059 sal_Int32 i
, nCount
= pDefCustomShape
->pHandles
.size();
1060 uno::Sequence
<beans::PropertyValues
> seqHandles( nCount
);
1061 auto pseqHandles
= seqHandles
.getArray();
1062 for (i
= 0; i
< nCount
; i
++)
1064 const SvxMSDffHandle
* pData
= &pDefCustomShape
->pHandles
[i
];
1065 sal_Int32 nPropertiesNeeded
;
1066 beans::PropertyValues
& rPropValues
= pseqHandles
[ i
];
1067 nPropertiesNeeded
= GetNumberOfProperties( pData
);
1068 rPropValues
.realloc( nPropertiesNeeded
);
1069 lcl_ShapePropertiesFromDFF( pData
, rPropValues
);
1071 aPropVal
.Name
= sHandles
;
1072 aPropVal
.Value
<<= seqHandles
;
1073 aGeometryItem
.SetPropertyValue( aPropVal
);
1075 else if (pAny
&& sShapeType
.startsWith("ooxml-") && sShapeType
!= "ooxml-non-primitive")
1077 // ODF is not able to store the ooxml way of connecting handle to an adjustment
1078 // value by name, e.g. attribute RefX="adj". So the information is lost, when exporting
1079 // a pptx to odp, for example. This part reconstructs this information for the
1080 // ooxml preset shapes from their definition.
1081 uno::Sequence
<beans::PropertyValues
> seqHandles
;
1082 *pAny
>>= seqHandles
;
1083 auto seqHandlesRange
= asNonConstRange(seqHandles
);
1084 bool bChanged(false);
1085 for (sal_Int32 i
= 0; i
< seqHandles
.getLength(); i
++)
1087 comphelper::SequenceAsHashMap
aHandleProps(seqHandles
[i
]);
1088 OUString sFirstRefType
;
1089 sal_Int32 nFirstAdjRef
;
1090 OUString sSecondRefType
;
1091 sal_Int32 nSecondAdjRef
;
1092 PresetOOXHandleAdj::GetOOXHandleAdjRelation(sShapeType
, i
, sFirstRefType
, nFirstAdjRef
,
1093 sSecondRefType
, nSecondAdjRef
);
1094 if (sFirstRefType
!= "na" && 0 <= nFirstAdjRef
1095 && nFirstAdjRef
< seqAdjustmentValues
.getLength())
1097 bChanged
|= aHandleProps
.createItemIfMissing(sFirstRefType
, nFirstAdjRef
);
1099 if (sSecondRefType
!= "na" && 0 <= nSecondAdjRef
1100 && nSecondAdjRef
< seqAdjustmentValues
.getLength())
1102 bChanged
|= aHandleProps
.createItemIfMissing(sSecondRefType
, nSecondAdjRef
);
1104 aHandleProps
>> seqHandlesRange
[i
];
1108 aPropVal
.Name
= sHandles
;
1109 aPropVal
.Value
<<= seqHandles
;
1110 aGeometryItem
.SetPropertyValue(aPropVal
);
1114 SetMergedItem( aGeometryItem
);
1117 bool SdrObjCustomShape::IsDefaultGeometry( const DefaultType eDefaultType
) const
1119 bool bIsDefaultGeometry
= false;
1121 OUString sShapeType
;
1122 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
1124 const uno::Any
*pAny
= rGeometryItem
.GetPropertyValueByName( u
"Type"_ustr
);
1126 *pAny
>>= sShapeType
;
1128 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
1130 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eSpType
);
1131 static constexpr OUString
sPath( u
"Path"_ustr
);
1132 switch( eDefaultType
)
1134 case DefaultType::Viewbox
:
1136 const uno::Any
* pViewBox
= rGeometryItem
.GetPropertyValueByName( u
"ViewBox"_ustr
);
1137 awt::Rectangle aViewBox
;
1138 if (pViewBox
&& (*pViewBox
>>= aViewBox
) && pDefCustomShape
)
1140 if ( ( aViewBox
.Width
== pDefCustomShape
->nCoordWidth
)
1141 && ( aViewBox
.Height
== pDefCustomShape
->nCoordHeight
) )
1142 bIsDefaultGeometry
= true;
1147 case DefaultType::Path
:
1149 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"Coordinates"_ustr
);
1150 if (pAny
&& pDefCustomShape
&& !pDefCustomShape
->pVertices
.empty())
1152 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqCoordinates1
;
1153 if ( *pAny
>>= seqCoordinates1
)
1155 sal_Int32 i
, nCount
= pDefCustomShape
->pVertices
.size();
1156 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqCoordinates2( nCount
);
1157 auto pseqCoordinates2
= seqCoordinates2
.getArray();
1158 for ( i
= 0; i
< nCount
; i
++ )
1160 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2
[ i
].First
, pDefCustomShape
->pVertices
[ i
].nValA
);
1161 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqCoordinates2
[ i
].Second
, pDefCustomShape
->pVertices
[ i
].nValB
);
1163 if ( seqCoordinates1
== seqCoordinates2
)
1164 bIsDefaultGeometry
= true;
1167 else if (pDefCustomShape
&& pDefCustomShape
->pVertices
.empty())
1168 bIsDefaultGeometry
= true;
1172 case DefaultType::Gluepoints
:
1174 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"GluePoints"_ustr
);
1175 if (pAny
&& pDefCustomShape
&& !pDefCustomShape
->pGluePoints
.empty())
1177 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqGluePoints1
;
1178 if ( *pAny
>>= seqGluePoints1
)
1180 sal_Int32 i
, nCount
= pDefCustomShape
->pGluePoints
.size();
1181 uno::Sequence
<drawing::EnhancedCustomShapeParameterPair
> seqGluePoints2( nCount
);
1182 auto pseqGluePoints2
= seqGluePoints2
.getArray();
1183 for ( i
= 0; i
< nCount
; i
++ )
1185 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2
[ i
].First
, pDefCustomShape
->pGluePoints
[ i
].nValA
);
1186 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqGluePoints2
[ i
].Second
, pDefCustomShape
->pGluePoints
[ i
].nValB
);
1188 if ( seqGluePoints1
== seqGluePoints2
)
1189 bIsDefaultGeometry
= true;
1192 else if (pDefCustomShape
&& pDefCustomShape
->pGluePoints
.empty())
1193 bIsDefaultGeometry
= true;
1197 case DefaultType::Segments
:
1200 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"Segments"_ustr
);
1203 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> seqSegments1
;
1204 if ( *pAny
>>= seqSegments1
)
1206 if ( pDefCustomShape
&& pDefCustomShape
->nElements
&& pDefCustomShape
->pElements
)
1208 sal_Int32 i
, nCount
= pDefCustomShape
->nElements
;
1211 uno::Sequence
<drawing::EnhancedCustomShapeSegment
> seqSegments2( nCount
);
1212 auto pseqSegments2
= seqSegments2
.getArray();
1213 for ( i
= 0; i
< nCount
; i
++ )
1215 drawing::EnhancedCustomShapeSegment
& rSegInfo
= pseqSegments2
[ i
];
1216 sal_uInt16 nSDat
= pDefCustomShape
->pElements
[ i
];
1217 lcl_ShapeSegmentFromBinary( rSegInfo
, nSDat
);
1219 if ( seqSegments1
== seqSegments2
)
1220 bIsDefaultGeometry
= true;
1225 // check if it's the default segment description ( M L Z N )
1226 if ( seqSegments1
.getLength() == 4 )
1228 if ( ( seqSegments1
[ 0 ].Command
== drawing::EnhancedCustomShapeSegmentCommand::MOVETO
)
1229 && ( seqSegments1
[ 1 ].Command
== drawing::EnhancedCustomShapeSegmentCommand::LINETO
)
1230 && ( seqSegments1
[ 2 ].Command
== drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
)
1231 && ( seqSegments1
[ 3 ].Command
== drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH
) )
1232 bIsDefaultGeometry
= true;
1237 else if ( pDefCustomShape
&& ( ( pDefCustomShape
->nElements
== 0 ) || ( pDefCustomShape
->pElements
== nullptr ) ) )
1238 bIsDefaultGeometry
= true;
1242 case DefaultType::StretchX
:
1244 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"StretchX"_ustr
);
1245 if ( pAny
&& pDefCustomShape
)
1247 sal_Int32 nStretchX
= 0;
1248 if ( *pAny
>>= nStretchX
)
1250 if ( pDefCustomShape
->nXRef
== nStretchX
)
1251 bIsDefaultGeometry
= true;
1254 else if ( pDefCustomShape
&& ( pDefCustomShape
->nXRef
== DEFAULT_MINIMUM_SIGNED_COMPARE
) )
1255 bIsDefaultGeometry
= true;
1259 case DefaultType::StretchY
:
1261 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"StretchY"_ustr
);
1262 if ( pAny
&& pDefCustomShape
)
1264 sal_Int32 nStretchY
= 0;
1265 if ( *pAny
>>= nStretchY
)
1267 if ( pDefCustomShape
->nYRef
== nStretchY
)
1268 bIsDefaultGeometry
= true;
1271 else if ( pDefCustomShape
&& ( pDefCustomShape
->nYRef
== DEFAULT_MINIMUM_SIGNED_COMPARE
) )
1272 bIsDefaultGeometry
= true;
1276 case DefaultType::Equations
:
1278 pAny
= rGeometryItem
.GetPropertyValueByName( u
"Equations"_ustr
);
1279 if (pAny
&& pDefCustomShape
&& !pDefCustomShape
->pCalculation
.empty())
1281 uno::Sequence
<OUString
> seqEquations1
;
1282 if ( *pAny
>>= seqEquations1
)
1284 sal_Int32 i
, nCount
= pDefCustomShape
->pCalculation
.size();
1285 uno::Sequence
<OUString
> seqEquations2( nCount
);
1286 auto pseqEquations2
= seqEquations2
.getArray();
1288 for (i
= 0; i
< nCount
; i
++)
1290 const SvxMSDffCalculationData
* pData
= &pDefCustomShape
->pCalculation
[i
];
1291 pseqEquations2
[ i
] = EnhancedCustomShape2d::GetEquation( pData
->nFlags
, pData
->nVal
[ 0 ], pData
->nVal
[ 1 ], pData
->nVal
[ 2 ] );
1294 if ( seqEquations1
== seqEquations2
)
1295 bIsDefaultGeometry
= true;
1298 else if (pDefCustomShape
&& pDefCustomShape
->pCalculation
.empty())
1299 bIsDefaultGeometry
= true;
1303 case DefaultType::TextFrames
:
1305 pAny
= rGeometryItem
.GetPropertyValueByName( sPath
, u
"TextFrames"_ustr
);
1306 if (pAny
&& pDefCustomShape
&& !pDefCustomShape
->pTextRect
.empty())
1308 uno::Sequence
<drawing::EnhancedCustomShapeTextFrame
> seqTextFrames1
;
1309 if ( *pAny
>>= seqTextFrames1
)
1311 sal_Int32 i
, nCount
= pDefCustomShape
->pTextRect
.size();
1312 uno::Sequence
<drawing::EnhancedCustomShapeTextFrame
> seqTextFrames2( nCount
);
1313 auto pseqTextFrames2
= seqTextFrames2
.getArray();
1314 for (i
= 0; i
< nCount
; i
++)
1316 const SvxMSDffTextRectangles
* pRectangles
= &pDefCustomShape
->pTextRect
[i
];
1317 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2
[ i
].TopLeft
.First
, pRectangles
->nPairA
.nValA
);
1318 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2
[ i
].TopLeft
.Second
, pRectangles
->nPairA
.nValB
);
1319 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2
[ i
].BottomRight
.First
, pRectangles
->nPairB
.nValA
);
1320 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( pseqTextFrames2
[ i
].BottomRight
.Second
, pRectangles
->nPairB
.nValB
);
1322 if ( seqTextFrames1
== seqTextFrames2
)
1323 bIsDefaultGeometry
= true;
1326 else if (pDefCustomShape
&& pDefCustomShape
->pTextRect
.empty())
1327 bIsDefaultGeometry
= true;
1331 return bIsDefaultGeometry
;
1334 void SdrObjCustomShape::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
1336 rInfo
.bResizeFreeAllowed
=m_fObjectRotation
== 0.0;
1337 rInfo
.bResizePropAllowed
=true;
1338 rInfo
.bRotateFreeAllowed
=true;
1339 rInfo
.bRotate90Allowed
=true;
1340 rInfo
.bMirrorFreeAllowed
=true;
1341 rInfo
.bMirror45Allowed
=true;
1342 rInfo
.bMirror90Allowed
=true;
1343 rInfo
.bTransparenceAllowed
= false;
1344 rInfo
.bShearAllowed
=true;
1345 rInfo
.bEdgeRadiusAllowed
=false;
1346 rInfo
.bNoContortion
=true;
1349 if ( !mXRenderedCustomShape
.is() )
1352 const SdrObject
* pRenderedCustomShape
= SdrObject::getSdrObjectFromXShape( mXRenderedCustomShape
);
1353 if ( !pRenderedCustomShape
)
1357 // Iterate self over the contained objects, since there are combinations of
1358 // polygon and curve objects. In that case, aInfo.bCanConvToPath and
1359 // aInfo.bCanConvToPoly would be false. What is needed here is an or, not an and.
1360 SdrObjListIter
aIterator(*pRenderedCustomShape
);
1361 while(aIterator
.IsMore())
1363 SdrObject
* pCandidate
= aIterator
.Next();
1364 SdrObjTransformInfoRec aInfo
;
1365 pCandidate
->TakeObjInfo(aInfo
);
1367 // set path and poly conversion if one is possible since
1368 // this object will first be broken
1369 const bool bCanConvToPathOrPoly(aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
);
1370 if(rInfo
.bCanConvToPath
!= bCanConvToPathOrPoly
)
1372 rInfo
.bCanConvToPath
= bCanConvToPathOrPoly
;
1375 if(rInfo
.bCanConvToPoly
!= bCanConvToPathOrPoly
)
1377 rInfo
.bCanConvToPoly
= bCanConvToPathOrPoly
;
1380 if(rInfo
.bCanConvToContour
!= aInfo
.bCanConvToContour
)
1382 rInfo
.bCanConvToContour
= aInfo
.bCanConvToContour
;
1385 if(rInfo
.bShearAllowed
!= aInfo
.bShearAllowed
)
1387 rInfo
.bShearAllowed
= aInfo
.bShearAllowed
;
1392 SdrObjKind
SdrObjCustomShape::GetObjIdentifier() const
1394 return SdrObjKind::CustomShape
;
1397 // #115391# This implementation is based on the TextFrame size of the CustomShape and the
1398 // state of the ResizeShapeToFitText flag to correctly set TextMinFrameWidth/Height
1399 void SdrObjCustomShape::AdaptTextMinSize()
1401 if (getSdrModelFromSdrObject().IsCreatingDataObj() || getSdrModelFromSdrObject().IsPasteResize())
1404 // check if we need to change anything before creating an SfxItemSet, because that is expensive
1405 const bool bResizeShapeToFitText(GetObjectItem(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue());
1406 tools::Rectangle
aTextBound(getRectangle());
1407 bool bChanged(false);
1408 if(bResizeShapeToFitText
)
1410 else if(GetTextBounds(aTextBound
))
1415 SfxItemSetFixed
<SDRATTR_TEXT_MINFRAMEHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
1416 SDRATTR_TEXT_MINFRAMEWIDTH
, SDRATTR_TEXT_AUTOGROWWIDTH
> // contains SDRATTR_TEXT_MAXFRAMEWIDTH
1417 aSet(*GetObjectItemSet().GetPool());
1419 if(bResizeShapeToFitText
)
1421 // always reset MinWidthHeight to zero to only rely on text size and frame size
1422 // to allow resizing being completely dependent on text size only
1423 aSet
.Put(makeSdrTextMinFrameWidthItem(0));
1424 aSet
.Put(makeSdrTextMinFrameHeightItem(0));
1428 // recreate from CustomShape-specific TextBounds
1429 const tools::Long
nHDist(GetTextLeftDistance() + GetTextRightDistance());
1430 const tools::Long
nVDist(GetTextUpperDistance() + GetTextLowerDistance());
1431 const tools::Long
nTWdt(std::max(tools::Long(0), static_cast<tools::Long
>(aTextBound
.GetWidth() - 1 - nHDist
)));
1432 const tools::Long
nTHgt(std::max(tools::Long(0), static_cast<tools::Long
>(aTextBound
.GetHeight() - 1 - nVDist
)));
1434 aSet
.Put(makeSdrTextMinFrameWidthItem(nTWdt
));
1435 aSet
.Put(makeSdrTextMinFrameHeightItem(nTHgt
));
1438 SetObjectItemSet(aSet
);
1441 void SdrObjCustomShape::NbcSetSnapRect(const tools::Rectangle
& rRectangle
)
1443 tools::Rectangle
aRectangle(rRectangle
);
1444 ImpJustifyRect(aRectangle
);
1445 setRectangle(aRectangle
);
1446 InvalidateRenderGeometry();
1451 SetBoundAndSnapRectsDirty();
1455 void SdrObjCustomShape::SetSnapRect( const tools::Rectangle
& rRect
)
1457 tools::Rectangle aBoundRect0
;
1459 aBoundRect0
= GetLastBoundRect();
1460 NbcSetSnapRect( rRect
);
1461 BroadcastObjectChange();
1462 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
1465 void SdrObjCustomShape::NbcSetLogicRect(const tools::Rectangle
& rRectangle
, bool bAdaptTextMinSize
)
1467 tools::Rectangle
aRectangle(rRectangle
);
1468 ImpJustifyRect(aRectangle
);
1469 setRectangle(aRectangle
);
1470 InvalidateRenderGeometry();
1472 if (bAdaptTextMinSize
)
1475 SetBoundAndSnapRectsDirty();
1479 void SdrObjCustomShape::SetLogicRect( const tools::Rectangle
& rRect
)
1481 tools::Rectangle aBoundRect0
;
1483 aBoundRect0
= GetLastBoundRect();
1484 NbcSetLogicRect(rRect
);
1485 BroadcastObjectChange();
1486 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
1489 void SdrObjCustomShape::Move( const Size
& rSiz
)
1491 if ( rSiz
.Width() || rSiz
.Height() )
1493 tools::Rectangle aBoundRect0
;
1495 aBoundRect0
= GetLastBoundRect();
1498 BroadcastObjectChange();
1499 SendUserCall(SdrUserCallType::MoveOnly
,aBoundRect0
);
1502 void SdrObjCustomShape::NbcMove( const Size
& rSiz
)
1504 SdrTextObj::NbcMove( rSiz
);
1505 if ( mXRenderedCustomShape
.is() )
1507 SdrObject
* pRenderedCustomShape
= SdrObject::getSdrObjectFromXShape(mXRenderedCustomShape
);
1508 if ( pRenderedCustomShape
)
1510 // #i97149# the visualisation shape needs to be informed
1511 // about change, too
1512 pRenderedCustomShape
->ActionChanged();
1513 pRenderedCustomShape
->NbcMove( rSiz
);
1517 // #i37011# adapt geometry shadow
1518 if(mpLastShadowGeometry
)
1520 mpLastShadowGeometry
->NbcMove( rSiz
);
1524 void SdrObjCustomShape::NbcResize( const Point
& rRef
, const Fraction
& rxFact
, const Fraction
& ryFact
)
1526 // taking care of handles that should not been changed
1527 tools::Rectangle
aOld(getRectangle());
1528 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
1530 SdrTextObj::NbcResize( rRef
, rxFact
, ryFact
);
1532 if ( ( rxFact
.GetNumerator() != rxFact
.GetDenominator() )
1533 || ( ryFact
.GetNumerator()!= ryFact
.GetDenominator() ) )
1535 if ( ( ( rxFact
.GetNumerator() < 0 ) && ( rxFact
.GetDenominator() > 0 ) ) ||
1536 ( ( rxFact
.GetNumerator() > 0 ) && ( rxFact
.GetDenominator() < 0 ) ) )
1538 SetMirroredX( !IsMirroredX() );
1540 if ( ( ( ryFact
.GetNumerator() < 0 ) && ( ryFact
.GetDenominator() > 0 ) ) ||
1541 ( ( ryFact
.GetNumerator() > 0 ) && ( ryFact
.GetDenominator() < 0 ) ) )
1543 SetMirroredY( !IsMirroredY() );
1547 for (const auto& rInteraction
: aInteractionHandles
)
1551 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
1552 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
1553 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_X
)
1555 sal_Int32 nX
= ( rInteraction
.aPosition
.X
- aOld
.Left() ) + getRectangle().Left();
1556 rInteraction
.xInteraction
->setControllerPosition(awt::Point(nX
, rInteraction
.xInteraction
->getPosition().Y
));
1558 else if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
1560 sal_Int32 nX
= getRectangle().Right() - (aOld
.Right() - rInteraction
.aPosition
.X
);
1561 rInteraction
.xInteraction
->setControllerPosition(awt::Point(nX
, rInteraction
.xInteraction
->getPosition().Y
));
1563 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
)
1565 sal_Int32 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Top() ) + getRectangle().Top();
1566 rInteraction
.xInteraction
->setControllerPosition(awt::Point(rInteraction
.xInteraction
->getPosition().X
, nY
));
1569 catch ( const uno::RuntimeException
& )
1574 // updating fObjectRotation
1575 Degree100 nTextObjRotation
= maGeo
.m_nRotationAngle
;
1576 double fAngle
= toDegrees(nTextObjRotation
);
1580 m_fObjectRotation
= fAngle
- 180.0;
1582 m_fObjectRotation
= -fAngle
;
1587 m_fObjectRotation
= 180.0 - fAngle
;
1589 m_fObjectRotation
= fAngle
;
1591 while (m_fObjectRotation
< 0)
1592 m_fObjectRotation
+= 360.0;
1593 while (m_fObjectRotation
>= 360.0)
1594 m_fObjectRotation
-= 360.0;
1596 InvalidateRenderGeometry();
1599 void SdrObjCustomShape::NbcRotate( const Point
& rRef
, Degree100 nAngle
, double sn
, double cs
)
1601 bool bMirroredX
= IsMirroredX();
1602 bool bMirroredY
= IsMirroredY();
1604 m_fObjectRotation
= fmod( m_fObjectRotation
, 360.0 );
1605 if ( m_fObjectRotation
< 0 )
1606 m_fObjectRotation
= 360 + m_fObjectRotation
;
1608 // the rotation angle for ashapes is stored in fObjectRotation, this rotation
1609 // has to be applied to the text object (which is internally using maGeo.nAngle).
1610 SdrTextObj::NbcRotate( getRectangle().TopLeft(), -maGeo
.m_nRotationAngle
, // retrieving the unrotated text object
1611 -maGeo
.mfSinRotationAngle
,
1612 maGeo
.mfCosRotationAngle
);
1613 maGeo
.m_nRotationAngle
= 0_deg100
; // resetting aGeo data
1614 maGeo
.RecalcSinCos();
1616 Degree100
nW(static_cast<sal_Int32
>( m_fObjectRotation
* 100 )); // applying our object rotation
1618 nW
= 36000_deg100
- nW
;
1620 nW
= 18000_deg100
- nW
;
1621 nW
= nW
% 36000_deg100
;
1622 if ( nW
< 0_deg100
)
1623 nW
= 36000_deg100
+ nW
;
1624 SdrTextObj::NbcRotate( getRectangle().TopLeft(), nW
, // applying text rotation
1625 sin( toRadians(nW
) ),
1626 cos( toRadians(nW
) ) );
1634 double fAngle
= toDegrees(nAngle
); // updating to our new object rotation
1635 m_fObjectRotation
= fmod( nSwap
? m_fObjectRotation
- fAngle
: m_fObjectRotation
+ fAngle
, 360.0 );
1636 if ( m_fObjectRotation
< 0 )
1637 m_fObjectRotation
= 360 + m_fObjectRotation
;
1639 SdrTextObj::NbcRotate( rRef
, nAngle
, sn
, cs
); // applying text rotation
1640 InvalidateRenderGeometry();
1643 void SdrObjCustomShape::NbcMirror( const Point
& rRef1
, const Point
& rRef2
)
1645 // TTTT: Fix for old mirroring, can be removed again in aw080
1646 // storing horizontal and vertical flipping without modifying the rotate angle
1647 // decompose other flipping to rotation and MirrorX.
1648 tools::Long ndx
= rRef2
.X()-rRef1
.X();
1649 tools::Long ndy
= rRef2
.Y()-rRef1
.Y();
1651 if(!ndx
) // MirroredX
1653 SetMirroredX(!IsMirroredX());
1654 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1658 if(!ndy
) // MirroredY
1660 SetMirroredY(!IsMirroredY());
1661 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1663 else // neither horizontal nor vertical
1665 SetMirroredX(!IsMirroredX());
1668 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1670 // update fObjectRotation
1671 Degree100 nTextObjRotation
= maGeo
.m_nRotationAngle
;
1672 double fAngle
= toDegrees(nTextObjRotation
);
1674 bool bSingleFlip
= (IsMirroredX()!= IsMirroredY());
1676 m_fObjectRotation
= fmod( bSingleFlip
? -fAngle
: fAngle
, 360.0 );
1678 if ( m_fObjectRotation
< 0 )
1680 m_fObjectRotation
= 360.0 + m_fObjectRotation
;
1685 InvalidateRenderGeometry();
1688 void SdrObjCustomShape::Shear( const Point
& rRef
, Degree100 nAngle
, double tn
, bool bVShear
)
1690 SdrTextObj::Shear( rRef
, nAngle
, tn
, bVShear
);
1691 InvalidateRenderGeometry();
1693 void SdrObjCustomShape::NbcShear( const Point
& rRef
, Degree100 nAngle
, double tn
, bool bVShear
)
1695 // TTTT: Fix for old mirroring, can be removed again in aw080
1696 SdrTextObj::NbcShear(rRef
,nAngle
,tn
,bVShear
);
1698 // updating fObjectRotation
1699 Degree100 nTextObjRotation
= maGeo
.m_nRotationAngle
;
1700 double fAngle
= toDegrees(nTextObjRotation
);
1704 m_fObjectRotation
= fAngle
- 180.0;
1706 m_fObjectRotation
= -fAngle
;
1711 m_fObjectRotation
= 180.0 - fAngle
;
1713 m_fObjectRotation
= fAngle
;
1715 while (m_fObjectRotation
< 0)
1716 m_fObjectRotation
+= 360.0;
1717 while (m_fObjectRotation
>= 360.0)
1718 m_fObjectRotation
-= 360.0;
1720 InvalidateRenderGeometry();
1723 SdrGluePoint
SdrObjCustomShape::GetVertexGluePoint(sal_uInt16 nPosNum
) const
1725 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
1728 if(!LineIsOutsideGeometry())
1735 tools::Rectangle aRectangle
= getRectangle();
1738 case 0: aPt
= aRectangle
.TopCenter(); aPt
.AdjustY( -nWdt
); break;
1739 case 1: aPt
= aRectangle
.RightCenter(); aPt
.AdjustX(nWdt
); break;
1740 case 2: aPt
= aRectangle
.BottomCenter(); aPt
.AdjustY(nWdt
); break;
1741 case 3: aPt
= aRectangle
.LeftCenter(); aPt
.AdjustX( -nWdt
); break;
1743 if (maGeo
.m_nShearAngle
!= 0_deg100
)
1744 ShearPoint(aPt
, aRectangle
.TopLeft(), maGeo
.mfTanShearAngle
);
1745 if (maGeo
.m_nRotationAngle
!= 0_deg100
)
1746 RotatePoint(aPt
, aRectangle
.TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
1747 aPt
-=GetSnapRect().Center();
1748 SdrGluePoint
aGP(aPt
);
1749 aGP
.SetPercent(false);
1755 void SdrObjCustomShape::ImpCheckCustomGluePointsAreAdded()
1757 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
1762 const SdrGluePointList
* pSource
= pSdrObject
->GetGluePointList();
1764 if(!(pSource
&& pSource
->GetCount()))
1767 if(!SdrTextObj::GetGluePointList())
1769 SdrTextObj::ForceGluePointList();
1772 const SdrGluePointList
* pList
= SdrTextObj::GetGluePointList();
1777 SdrGluePointList aNewList
;
1780 for(a
= 0; a
< pSource
->GetCount(); a
++)
1782 SdrGluePoint
aCopy((*pSource
)[a
]);
1783 aCopy
.SetUserDefined(false);
1784 aNewList
.Insert(aCopy
);
1787 bool bMirroredX
= IsMirroredX();
1788 bool bMirroredY
= IsMirroredY();
1790 Degree100 nShearAngle
= maGeo
.m_nShearAngle
;
1791 double fTan
= maGeo
.mfTanShearAngle
;
1793 if (maGeo
.m_nRotationAngle
|| nShearAngle
|| bMirroredX
|| bMirroredY
)
1795 tools::Polygon
aPoly(getRectangle());
1798 sal_uInt16 nPointCount
=aPoly
.GetSize();
1799 for (sal_uInt16 i
=0; i
<nPointCount
; i
++)
1800 ShearPoint(aPoly
[i
], getRectangle().Center(), fTan
);
1802 if (maGeo
.m_nRotationAngle
)
1803 aPoly
.Rotate( getRectangle().Center(), to
<Degree10
>(maGeo
.m_nRotationAngle
) );
1805 tools::Rectangle
aBoundRect( aPoly
.GetBoundRect() );
1806 sal_Int32 nXDiff
= aBoundRect
.Left() - getRectangle().Left();
1807 sal_Int32 nYDiff
= aBoundRect
.Top() - getRectangle().Top();
1809 if (nShearAngle
&& bMirroredX
!= bMirroredY
)
1811 nShearAngle
= -nShearAngle
;
1815 Point
aRef( getRectangle().GetWidth() / 2, getRectangle().GetHeight() / 2 );
1816 for ( a
= 0; a
< aNewList
.GetCount(); a
++ )
1818 SdrGluePoint
& rPoint
= aNewList
[ a
];
1819 Point
aGlue( rPoint
.GetPos() );
1821 ShearPoint( aGlue
, aRef
, fTan
);
1823 RotatePoint(aGlue
, aRef
, sin(basegfx::deg2rad(m_fObjectRotation
)),
1824 cos(basegfx::deg2rad(m_fObjectRotation
)));
1826 aGlue
.setX( getRectangle().GetWidth() - aGlue
.X() );
1828 aGlue
.setY( getRectangle().GetHeight() - aGlue
.Y() );
1829 aGlue
.AdjustX( -nXDiff
);
1830 aGlue
.AdjustY( -nYDiff
);
1831 rPoint
.SetPos( aGlue
);
1835 for(a
= 0; a
< pList
->GetCount(); a
++)
1837 const SdrGluePoint
& rCandidate
= (*pList
)[a
];
1839 if(rCandidate
.IsUserDefined())
1841 aNewList
.Insert(rCandidate
);
1845 // copy new list to local. This is NOT very convenient behavior, the local
1846 // GluePointList should not be set, but we delivered by using GetGluePointList(),
1847 // maybe on demand. Since the local object is changed here, this is assumed to
1848 // be a result of GetGluePointList and thus the list is copied
1851 m_pPlusData
->SetGluePoints(aNewList
);
1856 const SdrGluePointList
* SdrObjCustomShape::GetGluePointList() const
1858 const_cast<SdrObjCustomShape
*>(this)->ImpCheckCustomGluePointsAreAdded();
1859 return SdrTextObj::GetGluePointList();
1863 SdrGluePointList
* SdrObjCustomShape::ForceGluePointList()
1865 if(SdrTextObj::ForceGluePointList())
1867 ImpCheckCustomGluePointsAreAdded();
1868 return SdrTextObj::ForceGluePointList();
1877 sal_uInt32
SdrObjCustomShape::GetHdlCount() const
1879 const sal_uInt32
nBasicHdlCount(SdrTextObj::GetHdlCount());
1880 return ( GetInteractionHandles().size() + nBasicHdlCount
);
1883 void SdrObjCustomShape::AddToHdlList(SdrHdlList
& rHdlList
) const
1885 SdrTextObj::AddToHdlList(rHdlList
);
1887 int nCustomShapeHdlNum
= 0;
1888 for (SdrCustomShapeInteraction
const & rInteraction
: GetInteractionHandles())
1890 if ( rInteraction
.xInteraction
.is() )
1894 awt::Point
aPosition( rInteraction
.xInteraction
->getPosition() );
1895 std::unique_ptr
<SdrHdl
> pH(new SdrHdl( Point( aPosition
.X
, aPosition
.Y
), SdrHdlKind::CustomShape1
));
1896 pH
->SetPointNum( nCustomShapeHdlNum
);
1897 pH
->SetObj( const_cast<SdrObjCustomShape
*>(this) );
1898 rHdlList
.AddHdl(std::move(pH
));
1900 catch ( const uno::RuntimeException
& )
1904 ++nCustomShapeHdlNum
;
1908 bool SdrObjCustomShape::hasSpecialDrag() const
1913 bool SdrObjCustomShape::beginSpecialDrag(SdrDragStat
& rDrag
) const
1915 const SdrHdl
* pHdl
= rDrag
.GetHdl();
1917 if(pHdl
&& SdrHdlKind::CustomShape1
== pHdl
->GetKind())
1919 rDrag
.SetEndDragChangesAttributes(true);
1924 const SdrHdl
* pHdl2
= rDrag
.GetHdl();
1925 const SdrHdlKind
eHdl((pHdl2
== nullptr) ? SdrHdlKind::Move
: pHdl2
->GetKind());
1929 case SdrHdlKind::UpperLeft
:
1930 case SdrHdlKind::Upper
:
1931 case SdrHdlKind::UpperRight
:
1932 case SdrHdlKind::Left
:
1933 case SdrHdlKind::Right
:
1934 case SdrHdlKind::LowerLeft
:
1935 case SdrHdlKind::Lower
:
1936 case SdrHdlKind::LowerRight
:
1937 case SdrHdlKind::Move
:
1951 void SdrObjCustomShape::DragResizeCustomShape( const tools::Rectangle
& rNewRect
)
1953 tools::Rectangle
aOld(getRectangle());
1954 bool bOldMirroredX( IsMirroredX() );
1955 bool bOldMirroredY( IsMirroredY() );
1957 tools::Rectangle
aNewRect( rNewRect
);
1958 aNewRect
.Normalize();
1960 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
1962 GeoStat
aGeoStat( GetGeoStat() );
1963 if ( aNewRect
.TopLeft() != getRectangle().TopLeft() &&
1964 ( maGeo
.m_nRotationAngle
|| maGeo
.m_nShearAngle
) )
1966 Point
aNewPos( aNewRect
.TopLeft() );
1967 if ( maGeo
.m_nShearAngle
) ShearPoint( aNewPos
, aOld
.TopLeft(), aGeoStat
.mfTanShearAngle
);
1968 if ( maGeo
.m_nRotationAngle
) RotatePoint(aNewPos
, aOld
.TopLeft(), aGeoStat
.mfSinRotationAngle
, aGeoStat
.mfCosRotationAngle
);
1969 aNewRect
.SetPos( aNewPos
);
1971 if (aNewRect
== getRectangle())
1974 SetLogicRect( aNewRect
);
1975 InvalidateRenderGeometry();
1977 if ( rNewRect
.Left() > rNewRect
.Right() )
1979 Point
aTop( ( GetSnapRect().Left() + GetSnapRect().Right() ) >> 1, GetSnapRect().Top() );
1980 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
1981 NbcMirror( aTop
, aBottom
);
1983 if ( rNewRect
.Top() > rNewRect
.Bottom() )
1985 Point
aLeft( GetSnapRect().Left(), ( GetSnapRect().Top() + GetSnapRect().Bottom() ) >> 1 );
1986 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
1987 NbcMirror( aLeft
, aRight
);
1990 for (const auto& rInteraction
: aInteractionHandles
)
1994 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
1995 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
1996 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_X
||
1997 rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
1999 if (rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
2000 bOldMirroredX
= !bOldMirroredX
;
2003 if ( bOldMirroredX
)
2005 nX
= ( rInteraction
.aPosition
.X
- aOld
.Right() );
2006 if ( rNewRect
.Left() > rNewRect
.Right() )
2007 nX
= getRectangle().Left() - nX
;
2009 nX
+= getRectangle().Right();
2013 nX
= ( rInteraction
.aPosition
.X
- aOld
.Left() );
2014 if ( rNewRect
.Left() > rNewRect
.Right() )
2015 nX
= getRectangle().Right() - nX
;
2017 nX
+= getRectangle().Left();
2019 rInteraction
.xInteraction
->setControllerPosition(awt::Point(nX
, rInteraction
.xInteraction
->getPosition().Y
));
2021 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
)
2024 if ( bOldMirroredY
)
2026 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Bottom() );
2027 if ( rNewRect
.Top() > rNewRect
.Bottom() )
2028 nY
= getRectangle().Top() - nY
;
2030 nY
+= getRectangle().Bottom();
2034 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Top() );
2035 if ( rNewRect
.Top() > rNewRect
.Bottom() )
2036 nY
= getRectangle().Bottom() - nY
;
2038 nY
+= getRectangle().Top();
2040 rInteraction
.xInteraction
->setControllerPosition(awt::Point(rInteraction
.xInteraction
->getPosition().X
, nY
));
2043 catch ( const uno::RuntimeException
& )
2049 void SdrObjCustomShape::DragMoveCustomShapeHdl( const Point
& rDestination
,
2050 const sal_uInt16 nCustomShapeHdlNum
, bool bMoveCalloutRectangle
)
2052 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2053 if ( nCustomShapeHdlNum
>= aInteractionHandles
.size() )
2056 SdrCustomShapeInteraction
aInteractionHandle( aInteractionHandles
[ nCustomShapeHdlNum
] );
2057 if ( !aInteractionHandle
.xInteraction
.is() )
2062 awt::Point
aPt( rDestination
.X(), rDestination
.Y() );
2063 if ( aInteractionHandle
.nMode
& CustomShapeHandleModes::MOVE_SHAPE
&& bMoveCalloutRectangle
)
2065 sal_Int32 nXDiff
= aPt
.X
- aInteractionHandle
.aPosition
.X
;
2066 sal_Int32 nYDiff
= aPt
.Y
- aInteractionHandle
.aPosition
.Y
;
2068 moveRectangle(nXDiff
, nYDiff
);
2069 moveOutRectangle(nXDiff
, nYDiff
);
2070 maSnapRect
.Move( nXDiff
, nYDiff
);
2071 SetBoundAndSnapRectsDirty(/*bNotMyself*/true);
2072 InvalidateRenderGeometry();
2074 for (const auto& rInteraction
: aInteractionHandles
)
2076 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2078 if ( rInteraction
.xInteraction
.is() )
2079 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2083 aInteractionHandle
.xInteraction
->setControllerPosition( aPt
);
2085 catch ( const uno::RuntimeException
& )
2090 bool SdrObjCustomShape::applySpecialDrag(SdrDragStat
& rDrag
)
2092 const SdrHdl
* pHdl
= rDrag
.GetHdl();
2093 const SdrHdlKind
eHdl((pHdl
== nullptr) ? SdrHdlKind::Move
: pHdl
->GetKind());
2097 case SdrHdlKind::CustomShape1
:
2099 rDrag
.SetEndDragChangesGeoAndAttributes(true);
2100 DragMoveCustomShapeHdl( rDrag
.GetNow(), static_cast<sal_uInt16
>(pHdl
->GetPointNum()), !rDrag
.GetDragMethod()->IsShiftPressed() );
2101 SetBoundAndSnapRectsDirty();
2102 InvalidateRenderGeometry();
2107 case SdrHdlKind::UpperLeft
:
2108 case SdrHdlKind::Upper
:
2109 case SdrHdlKind::UpperRight
:
2110 case SdrHdlKind::Left
:
2111 case SdrHdlKind::Right
:
2112 case SdrHdlKind::LowerLeft
:
2113 case SdrHdlKind::Lower
:
2114 case SdrHdlKind::LowerRight
:
2116 DragResizeCustomShape( ImpDragCalcRect(rDrag
) );
2119 case SdrHdlKind::Move
:
2121 Move(Size(rDrag
.GetDX(), rDrag
.GetDY()));
2131 void SdrObjCustomShape::DragCreateObject( SdrDragStat
& rStat
)
2133 tools::Rectangle aRect1
;
2134 rStat
.TakeCreateRect( aRect1
);
2136 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2138 constexpr sal_uInt32 nDefaultObjectSizeWidth
= 3000; // default width from SDOptions ?
2139 constexpr sal_uInt32 nDefaultObjectSizeHeight
= 3000;
2141 if ( ImpVerticalSwitch( *this ) )
2143 SetMirroredX( aRect1
.Left() > aRect1
.Right() );
2145 aRect1
= tools::Rectangle( rStat
.GetNow(), Size( nDefaultObjectSizeWidth
, nDefaultObjectSizeHeight
) );
2146 // subtracting the horizontal difference of the latest handle from shape position
2147 if ( !aInteractionHandles
.empty() )
2149 sal_Int32 nHandlePos
= aInteractionHandles
[ aInteractionHandles
.size() - 1 ].xInteraction
->getPosition().X
;
2150 aRect1
.Move(getRectangle().Left() - nHandlePos
, 0);
2153 ImpJustifyRect( aRect1
);
2154 rStat
.SetActionRect( aRect1
);
2155 setRectangle(aRect1
);
2156 SetBoundAndSnapRectsDirty();
2158 for (const auto& rInteraction
: aInteractionHandles
)
2162 if ( rInteraction
.nMode
& CustomShapeHandleModes::CREATE_FIXED
)
2163 rInteraction
.xInteraction
->setControllerPosition( awt::Point( rStat
.GetStart().X(), rStat
.GetStart().Y() ) );
2165 catch ( const uno::RuntimeException
& )
2170 SetBoundRectDirty();
2171 m_bSnapRectDirty
=true;
2174 bool SdrObjCustomShape::MovCreate(SdrDragStat
& rStat
)
2176 SdrView
* pView
= rStat
.GetView(); // #i37448#
2177 if( pView
&& pView
->IsSolidDragging() )
2179 InvalidateRenderGeometry();
2181 DragCreateObject( rStat
);
2182 SetBoundAndSnapRectsDirty();
2186 bool SdrObjCustomShape::EndCreate( SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
2188 DragCreateObject( rStat
);
2192 SetBoundAndSnapRectsDirty();
2193 return ( eCmd
== SdrCreateCmd::ForceEnd
|| rStat
.GetPointCount() >= 2 );
2196 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeCreatePoly(const SdrDragStat
& /*rDrag*/) const
2198 return GetLineGeometry( false );
2202 // in context with the SdrObjCustomShape the SdrTextAutoGrowHeightItem == true -> Resize Shape to fit text,
2203 // the SdrTextAutoGrowWidthItem == true -> Word wrap text in Shape
2204 bool SdrObjCustomShape::IsAutoGrowHeight() const
2206 const SfxItemSet
& rSet
= GetMergedItemSet();
2207 bool bIsAutoGrowHeight
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
2208 if ( bIsAutoGrowHeight
&& IsVerticalWriting() )
2209 bIsAutoGrowHeight
= !rSet
.Get(SDRATTR_TEXT_WORDWRAP
).GetValue();
2210 return bIsAutoGrowHeight
;
2212 bool SdrObjCustomShape::IsAutoGrowWidth() const
2214 const SfxItemSet
& rSet
= GetMergedItemSet();
2215 bool bIsAutoGrowWidth
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
2216 if ( bIsAutoGrowWidth
&& !IsVerticalWriting() )
2217 bIsAutoGrowWidth
= !rSet
.Get(SDRATTR_TEXT_WORDWRAP
).GetValue();
2218 return bIsAutoGrowWidth
;
2221 /* The following method is identical to the SdrTextObj::SetVerticalWriting method, the only difference
2222 is that the SdrAutoGrowWidthItem and SdrAutoGrowHeightItem are not exchanged if the vertical writing
2223 mode has been changed */
2225 void SdrObjCustomShape::SetVerticalWriting( bool bVertical
)
2227 ForceOutlinerParaObject();
2229 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
2231 DBG_ASSERT( pOutlinerParaObject
, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );
2233 if( !pOutlinerParaObject
||
2234 (pOutlinerParaObject
->IsEffectivelyVertical() == bVertical
) )
2237 // get item settings
2238 const SfxItemSet
& rSet
= GetObjectItemSet();
2240 // Also exchange horizontal and vertical adjust items
2241 SdrTextHorzAdjust eHorz
= rSet
.Get(SDRATTR_TEXT_HORZADJUST
).GetValue();
2242 SdrTextVertAdjust eVert
= rSet
.Get(SDRATTR_TEXT_VERTADJUST
).GetValue();
2244 // rescue object size, SetSnapRect below expects logic rect,
2246 tools::Rectangle aObjectRect
= GetLogicRect();
2248 // prepare ItemSet to set exchanged width and height items
2249 SfxItemSetFixed
<SDRATTR_TEXT_AUTOGROWHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
2250 // Expanded item ranges to also support horizontal and vertical adjust.
2251 SDRATTR_TEXT_VERTADJUST
, SDRATTR_TEXT_VERTADJUST
,
2252 SDRATTR_TEXT_AUTOGROWWIDTH
, SDRATTR_TEXT_HORZADJUST
> aNewSet(*rSet
.GetPool());
2256 // Exchange horizontal and vertical adjusts
2259 case SDRTEXTVERTADJUST_TOP
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT
)); break;
2260 case SDRTEXTVERTADJUST_CENTER
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER
)); break;
2261 case SDRTEXTVERTADJUST_BOTTOM
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT
)); break;
2262 case SDRTEXTVERTADJUST_BLOCK
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK
)); break;
2266 case SDRTEXTHORZADJUST_LEFT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM
)); break;
2267 case SDRTEXTHORZADJUST_CENTER
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER
)); break;
2268 case SDRTEXTHORZADJUST_RIGHT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP
)); break;
2269 case SDRTEXTHORZADJUST_BLOCK
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK
)); break;
2272 pOutlinerParaObject
= GetOutlinerParaObject();
2273 if ( pOutlinerParaObject
)
2274 pOutlinerParaObject
->SetVertical(bVertical
);
2275 SetObjectItemSet( aNewSet
);
2277 // restore object size
2278 SetSnapRect(aObjectRect
);
2281 void SdrObjCustomShape::SuggestTextFrameSize(Size aSuggestedTextFrameSize
)
2283 m_aSuggestedTextFrameSize
= aSuggestedTextFrameSize
;
2286 bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight(tools::Rectangle
& rR
, bool bHgt
, bool bWdt
) const
2288 // Either we have text or the application has native text and suggested its size to us.
2289 bool bHasText
= HasText() || !m_aSuggestedTextFrameSize
.IsEmpty();
2290 if ( bHasText
&& !rR
.IsEmpty() )
2292 bool bWdtGrow
=bWdt
&& IsAutoGrowWidth();
2293 bool bHgtGrow
=bHgt
&& IsAutoGrowHeight();
2294 if ( bWdtGrow
|| bHgtGrow
)
2296 tools::Rectangle
aR0(rR
);
2297 tools::Long nHgt
=0,nMinHgt
=0,nMaxHgt
=0;
2298 tools::Long nWdt
=0,nMinWdt
=0,nMaxWdt
=0;
2299 Size
aSiz(rR
.GetSize()); aSiz
.AdjustWidth( -1 ); aSiz
.AdjustHeight( -1 );
2300 Size
aMaxSiz(100000,100000);
2301 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2302 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
2303 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
2306 nMinWdt
=GetMinTextFrameWidth();
2307 nMaxWdt
=GetMaxTextFrameWidth();
2308 if (nMaxWdt
==0 || nMaxWdt
>aMaxSiz
.Width()) nMaxWdt
=aMaxSiz
.Width();
2309 if (nMinWdt
<=0) nMinWdt
=1;
2310 aSiz
.setWidth(nMaxWdt
);
2314 nMinHgt
=GetMinTextFrameHeight();
2315 nMaxHgt
=GetMaxTextFrameHeight();
2316 if (nMaxHgt
==0 || nMaxHgt
>aMaxSiz
.Height()) nMaxHgt
=aMaxSiz
.Height();
2317 if (nMinHgt
<=0) nMinHgt
=1;
2318 aSiz
.setHeight(nMaxHgt
);
2320 tools::Long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
2321 tools::Long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
2322 aSiz
.AdjustWidth( -nHDist
);
2323 aSiz
.AdjustHeight( -nVDist
);
2324 if ( aSiz
.Width() < 2 )
2325 aSiz
.setWidth( 2 ); // minimum size=2
2326 if ( aSiz
.Height() < 2 )
2327 aSiz
.setHeight( 2 ); // minimum size=2
2331 if(mpEditingOutliner
)
2333 mpEditingOutliner
->SetMaxAutoPaperSize( aSiz
);
2336 Size
aSiz2(mpEditingOutliner
->CalcTextSize());
2337 nWdt
=aSiz2
.Width()+1; // a little more tolerance
2338 if (bHgtGrow
) nHgt
=aSiz2
.Height()+1; // a little more tolerance
2341 nHgt
=mpEditingOutliner
->GetTextHeight()+1; // a little more tolerance
2346 Outliner
& rOutliner
=ImpGetDrawOutliner();
2347 rOutliner
.SetPaperSize(aSiz
);
2348 rOutliner
.SetUpdateLayout(true);
2349 // TODO: add the optimization with bPortionInfoChecked again.
2350 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
2351 if( pOutlinerParaObject
!= nullptr )
2353 rOutliner
.SetText(*pOutlinerParaObject
);
2354 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
2358 Size
aSiz2(rOutliner
.CalcTextSize());
2359 nWdt
=aSiz2
.Width()+1; // a little more tolerance
2361 nHgt
=aSiz2
.Height()+1; // a little more tolerance
2365 nHgt
= rOutliner
.GetTextHeight()+1; // a little more tolerance
2367 sal_Int16 nColumns
= GetMergedItem(SDRATTR_TEXTCOLUMNS_NUMBER
).GetValue();
2368 if (bHgtGrow
&& nColumns
> 1)
2370 // Both 'resize shape to fix text' and multiple columns are enabled. The
2371 // first means a dynamic height, the second expects a fixed height.
2372 // Resolve this conflict by going with the original height.
2373 nHgt
= rR
.getOpenHeight();
2381 nHgt
= m_aSuggestedTextFrameSize
.Height();
2382 nWdt
= m_aSuggestedTextFrameSize
.Width();
2384 if ( nWdt
< nMinWdt
)
2386 if ( nWdt
> nMaxWdt
)
2390 nWdt
= 1; // nHDist may also be negative
2391 if ( nHgt
< nMinHgt
)
2393 if ( nHgt
> nMaxHgt
)
2397 nHgt
= 1; // nVDist may also be negative
2398 tools::Long nWdtGrow
= nWdt
-(rR
.Right()-rR
.Left());
2399 tools::Long nHgtGrow
= nHgt
-(rR
.Bottom()-rR
.Top());
2400 if ( nWdtGrow
== 0 )
2402 if ( nHgtGrow
== 0 )
2404 if ( bWdtGrow
|| bHgtGrow
|| !m_aSuggestedTextFrameSize
.IsEmpty())
2406 if ( bWdtGrow
|| m_aSuggestedTextFrameSize
.Width() )
2408 SdrTextHorzAdjust eHAdj
=GetTextHorizontalAdjust();
2409 if (m_aSuggestedTextFrameSize
.Width())
2411 rR
.SetRight(rR
.Left() + m_aSuggestedTextFrameSize
.Width());
2413 else if ( eHAdj
== SDRTEXTHORZADJUST_LEFT
)
2414 rR
.AdjustRight(nWdtGrow
);
2415 else if ( eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
2416 rR
.AdjustLeft( -nWdtGrow
);
2419 tools::Long nWdtGrow2
=nWdtGrow
/2;
2420 rR
.AdjustLeft( -nWdtGrow2
);
2421 rR
.SetRight(rR
.Left()+nWdt
);
2424 if ( bHgtGrow
|| m_aSuggestedTextFrameSize
.Height() )
2426 SdrTextVertAdjust eVAdj
=GetTextVerticalAdjust();
2427 if (m_aSuggestedTextFrameSize
.Height())
2429 rR
.SetBottom(rR
.Top() + m_aSuggestedTextFrameSize
.Height());
2431 else if ( eVAdj
== SDRTEXTVERTADJUST_TOP
)
2432 rR
.AdjustBottom(nHgtGrow
);
2433 else if ( eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
2434 rR
.AdjustTop( -nHgtGrow
);
2437 tools::Long nHgtGrow2
=nHgtGrow
/2;
2438 rR
.AdjustTop( -nHgtGrow2
);
2439 rR
.SetBottom(rR
.Top()+nHgt
);
2442 if ( maGeo
.m_nRotationAngle
)
2444 Point
aD1(rR
.TopLeft());
2447 RotatePoint(aD2
,Point(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
2449 rR
.Move(aD2
.X(),aD2
.Y());
2458 tools::Rectangle
SdrObjCustomShape::ImpCalculateTextFrame( const bool bHgt
, const bool bWdt
)
2460 tools::Rectangle aReturnValue
;
2462 tools::Rectangle
aOldTextRect(getRectangle()); // <- initial text rectangle
2464 tools::Rectangle
aNewTextRect(getRectangle()); // <- new text rectangle returned from the custom shape renderer,
2465 GetTextBounds( aNewTextRect
); // it depends to the current logical shape size
2467 tools::Rectangle
aAdjustedTextRect( aNewTextRect
); // <- new text rectangle is being tested by AdjustTextFrameWidthAndHeight to ensure
2468 if ( AdjustTextFrameWidthAndHeight( aAdjustedTextRect
, bHgt
, bWdt
) ) // that the new text rectangle is matching the current text size from the outliner
2470 if (aAdjustedTextRect
!= aNewTextRect
&& aOldTextRect
!= aAdjustedTextRect
&&
2471 aNewTextRect
.GetWidth() && aNewTextRect
.GetHeight())
2473 aReturnValue
= getRectangle();
2474 double fXScale
= static_cast<double>(aOldTextRect
.GetWidth()) / static_cast<double>(aNewTextRect
.GetWidth());
2475 double fYScale
= static_cast<double>(aOldTextRect
.GetHeight()) / static_cast<double>(aNewTextRect
.GetHeight());
2476 double fRightDiff
= static_cast<double>( aAdjustedTextRect
.Right() - aNewTextRect
.Right() ) * fXScale
;
2477 double fLeftDiff
= static_cast<double>( aAdjustedTextRect
.Left() - aNewTextRect
.Left() ) * fXScale
;
2478 double fTopDiff
= static_cast<double>( aAdjustedTextRect
.Top() - aNewTextRect
.Top() ) * fYScale
;
2479 double fBottomDiff
= static_cast<double>( aAdjustedTextRect
.Bottom()- aNewTextRect
.Bottom()) * fYScale
;
2480 aReturnValue
.AdjustLeft(static_cast<sal_Int32
>(fLeftDiff
) );
2481 aReturnValue
.AdjustRight(static_cast<sal_Int32
>(fRightDiff
) );
2482 aReturnValue
.AdjustTop(static_cast<sal_Int32
>(fTopDiff
) );
2483 aReturnValue
.AdjustBottom(static_cast<sal_Int32
>(fBottomDiff
) );
2486 return aReturnValue
;
2489 bool SdrObjCustomShape::NbcAdjustTextFrameWidthAndHeight(bool bHgt
, bool bWdt
)
2491 tools::Rectangle aNewTextRect
= ImpCalculateTextFrame(bHgt
, bWdt
);
2492 const bool bRet
= !aNewTextRect
.IsEmpty() && aNewTextRect
!= getRectangle();
2493 if (bRet
&& !mbAdjustingTextFrameWidthAndHeight
)
2495 mbAdjustingTextFrameWidthAndHeight
= true;
2497 // taking care of handles that should not been changed
2498 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2500 setRectangle(aNewTextRect
);
2501 SetBoundAndSnapRectsDirty();
2504 for (const auto& rInteraction
: aInteractionHandles
)
2508 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2509 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2511 catch ( const uno::RuntimeException
& )
2515 InvalidateRenderGeometry();
2517 mbAdjustingTextFrameWidthAndHeight
= false;
2522 bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight()
2524 tools::Rectangle aNewTextRect
= ImpCalculateTextFrame( true/*bHgt*/, true/*bWdt*/ );
2525 bool bRet
= !aNewTextRect
.IsEmpty() && ( aNewTextRect
!= getRectangle());
2528 tools::Rectangle aBoundRect0
;
2530 aBoundRect0
= GetCurrentBoundRect();
2532 // taking care of handles that should not been changed
2533 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2535 setRectangle(aNewTextRect
);
2536 SetBoundAndSnapRectsDirty();
2538 for (const auto& rInteraction
: aInteractionHandles
)
2542 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2543 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2545 catch ( const uno::RuntimeException
& )
2550 InvalidateRenderGeometry();
2552 BroadcastObjectChange();
2553 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
2557 void SdrObjCustomShape::TakeTextEditArea(Size
* pPaperMin
, Size
* pPaperMax
, tools::Rectangle
* pViewInit
, tools::Rectangle
* pViewMin
) const
2559 tools::Rectangle aViewInit
;
2560 TakeTextAnchorRect( aViewInit
);
2561 if (maGeo
.m_nRotationAngle
)
2563 Point
aCenter(aViewInit
.Center());
2564 aCenter
-=aViewInit
.TopLeft();
2565 Point
aCenter0(aCenter
);
2566 RotatePoint(aCenter
, Point(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
2568 aViewInit
.Move(aCenter
.X(),aCenter
.Y());
2570 Size
aAnkSiz(aViewInit
.GetSize());
2571 aAnkSiz
.AdjustWidth( -1 ); aAnkSiz
.AdjustHeight( -1 ); // because GetSize() adds 1
2572 Size
aMaxSiz(1000000,1000000);
2574 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2575 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
2576 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
2578 SdrTextHorzAdjust
eHAdj(GetTextHorizontalAdjust());
2579 SdrTextVertAdjust
eVAdj(GetTextVerticalAdjust());
2581 tools::Long nMinWdt
= GetMinTextFrameWidth();
2582 tools::Long nMinHgt
= GetMinTextFrameHeight();
2583 tools::Long nMaxWdt
= GetMaxTextFrameWidth();
2584 tools::Long nMaxHgt
= GetMaxTextFrameHeight();
2585 if (nMinWdt
<1) nMinWdt
=1;
2586 if (nMinHgt
<1) nMinHgt
=1;
2587 if ( nMaxWdt
== 0 || nMaxWdt
> aMaxSiz
.Width() )
2588 nMaxWdt
= aMaxSiz
.Width();
2589 if ( nMaxHgt
== 0 || nMaxHgt
> aMaxSiz
.Height() )
2590 nMaxHgt
=aMaxSiz
.Height();
2592 if (GetMergedItem(SDRATTR_TEXT_WORDWRAP
).GetValue())
2594 if ( IsVerticalWriting() )
2596 nMaxHgt
= aAnkSiz
.Height();
2601 nMaxWdt
= aAnkSiz
.Width();
2605 Size
aPaperMax(nMaxWdt
, nMaxHgt
);
2606 Size
aPaperMin(nMinWdt
, nMinHgt
);
2610 *pViewMin
= aViewInit
;
2612 tools::Long nXFree
= aAnkSiz
.Width() - aPaperMin
.Width();
2613 if ( eHAdj
== SDRTEXTHORZADJUST_LEFT
)
2614 pViewMin
->AdjustRight( -nXFree
);
2615 else if ( eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
2616 pViewMin
->AdjustLeft(nXFree
);
2617 else { pViewMin
->AdjustLeft(nXFree
/ 2 ); pViewMin
->SetRight( pViewMin
->Left() + aPaperMin
.Width() ); }
2619 tools::Long nYFree
= aAnkSiz
.Height() - aPaperMin
.Height();
2620 if ( eVAdj
== SDRTEXTVERTADJUST_TOP
)
2621 pViewMin
->AdjustBottom( -nYFree
);
2622 else if ( eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
2623 pViewMin
->AdjustTop(nYFree
);
2624 else { pViewMin
->AdjustTop(nYFree
/ 2 ); pViewMin
->SetBottom( pViewMin
->Top() + aPaperMin
.Height() ); }
2627 if( IsVerticalWriting() )
2628 aPaperMin
.setWidth( 0 );
2630 aPaperMin
.setHeight( 0 );
2632 if( eHAdj
!= SDRTEXTHORZADJUST_BLOCK
)
2633 aPaperMin
.setWidth(0 );
2635 // For complete vertical adjust support, set paper min height to 0, here.
2636 if(SDRTEXTVERTADJUST_BLOCK
!= eVAdj
)
2637 aPaperMin
.setHeight( 0 );
2639 if (pPaperMin
!=nullptr) *pPaperMin
=aPaperMin
;
2640 if (pPaperMax
!=nullptr) *pPaperMax
=aPaperMax
;
2641 if (pViewInit
!=nullptr) *pViewInit
=aViewInit
;
2643 void SdrObjCustomShape::EndTextEdit( SdrOutliner
& rOutl
)
2645 SdrTextObj::EndTextEdit( rOutl
);
2646 InvalidateRenderGeometry();
2648 void SdrObjCustomShape::TakeTextAnchorRect( tools::Rectangle
& rAnchorRect
) const
2650 if ( GetTextBounds( rAnchorRect
) )
2652 Point
aRotateRef( maSnapRect
.Center() );
2653 const double fExtraTextRotation(GetExtraTextRotation());
2654 AdjustRectToTextDistance(rAnchorRect
, fExtraTextRotation
);
2656 if ( rAnchorRect
.GetWidth() < 2 )
2657 rAnchorRect
.SetRight( rAnchorRect
.Left() + 1 ); // minimal width is 2
2658 if ( rAnchorRect
.GetHeight() < 2 )
2659 rAnchorRect
.SetBottom( rAnchorRect
.Top() + 1 ); // minimal height is 2
2660 if (maGeo
.m_nRotationAngle
)
2662 Point
aP( rAnchorRect
.TopLeft() );
2663 RotatePoint(aP
, aRotateRef
, maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
2664 rAnchorRect
.SetPos( aP
);
2668 SdrTextObj::TakeTextAnchorRect( rAnchorRect
);
2670 void SdrObjCustomShape::TakeTextRect( SdrOutliner
& rOutliner
, tools::Rectangle
& rTextRect
, bool bNoEditText
,
2671 tools::Rectangle
* pAnchorRect
, bool /*bLineWidth*/) const
2673 tools::Rectangle aAnkRect
; // Rect in which we anchor
2674 TakeTextAnchorRect(aAnkRect
);
2675 SdrTextVertAdjust eVAdj
=GetTextVerticalAdjust();
2676 SdrTextHorzAdjust eHAdj
=GetTextHorizontalAdjust();
2677 EEControlBits nStat0
=rOutliner
.GetControlWord();
2680 rOutliner
.SetControlWord(nStat0
|EEControlBits::AUTOPAGESIZE
);
2681 rOutliner
.SetMinAutoPaperSize(aNullSize
);
2682 sal_Int32 nMaxAutoPaperWidth
= 1000000;
2683 sal_Int32 nMaxAutoPaperHeight
= 1000000;
2685 tools::Long nAnkWdt
=aAnkRect
.GetWidth();
2686 tools::Long nAnkHgt
=aAnkRect
.GetHeight();
2688 if (GetMergedItem(SDRATTR_TEXT_WORDWRAP
).GetValue())
2690 if ( IsVerticalWriting() )
2691 nMaxAutoPaperHeight
= nAnkHgt
;
2693 nMaxAutoPaperWidth
= nAnkWdt
;
2695 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !IsVerticalWriting())
2697 rOutliner
.SetMinAutoPaperSize(Size(nAnkWdt
, 0));
2700 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& IsVerticalWriting())
2702 rOutliner
.SetMinAutoPaperSize(Size(0, nAnkHgt
));
2704 rOutliner
.SetMaxAutoPaperSize( Size( nMaxAutoPaperWidth
, nMaxAutoPaperHeight
) );
2705 rOutliner
.SetPaperSize( aNullSize
);
2707 // put text into the Outliner - if necessary the use the text from the EditOutliner
2708 std::optional
<OutlinerParaObject
> pPara
;
2709 if (GetOutlinerParaObject())
2710 pPara
= *GetOutlinerParaObject();
2711 if (mpEditingOutliner
&& !bNoEditText
)
2712 pPara
=mpEditingOutliner
->CreateParaObject();
2716 bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner
);
2717 const SdrTextObj
* pTestObj
= rOutliner
.GetTextObj();
2719 if( !pTestObj
|| !bHitTest
|| pTestObj
!= this ||
2720 pTestObj
->GetOutlinerParaObject() != GetOutlinerParaObject() )
2723 rOutliner
.SetTextObj( this );
2725 rOutliner
.SetUpdateLayout(true);
2726 rOutliner
.SetText(*pPara
);
2731 rOutliner
.SetTextObj( nullptr );
2734 rOutliner
.SetUpdateLayout(true);
2735 rOutliner
.SetControlWord(nStat0
);
2737 SdrText
* pText
= getActiveText();
2739 pText
->CheckPortionInfo( rOutliner
);
2741 Point
aTextPos(aAnkRect
.TopLeft());
2742 Size
aTextSiz(rOutliner
.GetPaperSize()); // GetPaperSize() has a little added tolerance, no?
2744 // For draw objects containing text correct horizontal/vertical alignment if text is bigger
2745 // than the object itself. Without that correction, the text would always be
2746 // formatted to the left edge (or top edge when vertical) of the draw object.
2748 if( !IsTextFrame() )
2750 if(aAnkRect
.GetWidth() < aTextSiz
.Width() && !IsVerticalWriting())
2752 // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
2753 // else the alignment is wanted.
2754 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
)
2756 SvxAdjust eAdjust
= GetObjectItemSet().Get(EE_PARA_JUST
).GetAdjust();
2759 case SvxAdjust::Left
: eHAdj
= SDRTEXTHORZADJUST_LEFT
; break;
2760 case SvxAdjust::Right
: eHAdj
= SDRTEXTHORZADJUST_RIGHT
; break;
2761 case SvxAdjust::Center
: eHAdj
= SDRTEXTHORZADJUST_CENTER
; break;
2767 if(aAnkRect
.GetHeight() < aTextSiz
.Height() && IsVerticalWriting())
2769 // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
2770 // else the alignment is wanted.
2771 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
)
2773 eVAdj
= SDRTEXTVERTADJUST_CENTER
;
2778 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
|| eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
2780 tools::Long nFreeWdt
=aAnkRect
.GetWidth()-aTextSiz
.Width();
2781 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
)
2782 aTextPos
.AdjustX(nFreeWdt
/2 );
2783 if (eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
2784 aTextPos
.AdjustX(nFreeWdt
);
2786 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
|| eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
2788 tools::Long nFreeHgt
=aAnkRect
.GetHeight()-aTextSiz
.Height();
2789 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
)
2790 aTextPos
.AdjustY(nFreeHgt
/2 );
2791 if (eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
2792 aTextPos
.AdjustY(nFreeHgt
);
2794 if (maGeo
.m_nRotationAngle
!= 0_deg100
)
2795 RotatePoint(aTextPos
,aAnkRect
.TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
2798 *pAnchorRect
=aAnkRect
;
2800 // using rTextRect together with ContourFrame doesn't always work correctly
2801 rTextRect
=tools::Rectangle(aTextPos
,aTextSiz
);
2804 void SdrObjCustomShape::NbcSetOutlinerParaObject(std::optional
<OutlinerParaObject
> pTextObject
, bool bAdjustTextFrameWidthAndHeight
)
2806 SdrTextObj::NbcSetOutlinerParaObject( std::move(pTextObject
), bAdjustTextFrameWidthAndHeight
);
2807 SetBoundRectDirty();
2808 SetBoundAndSnapRectsDirty(true);
2809 InvalidateRenderGeometry();
2812 rtl::Reference
<SdrObject
> SdrObjCustomShape::CloneSdrObject(SdrModel
& rTargetModel
) const
2814 return new SdrObjCustomShape(rTargetModel
, *this);
2817 OUString
SdrObjCustomShape::TakeObjNameSingul() const
2819 OUString
sName(SvxResId(STR_ObjNameSingulCUSTOMSHAPE
));
2820 OUString
aNm(GetName());
2822 sName
+= " '" + aNm
+ "'";
2826 OUString
SdrObjCustomShape::TakeObjNamePlural() const
2828 return SvxResId(STR_ObjNamePluralCUSTOMSHAPE
);
2831 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeXorPoly() const
2833 return GetLineGeometry( false );
2836 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeContour() const
2838 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
2840 return pSdrObject
->TakeContour();
2841 return basegfx::B2DPolyPolygon();
2844 rtl::Reference
<SdrObject
> SdrObjCustomShape::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
2847 rtl::Reference
<SdrObject
> pRetval
;
2848 SdrObject
* pRenderedCustomShape
= nullptr;
2850 if ( !mXRenderedCustomShape
.is() )
2852 // force CustomShape
2853 GetSdrObjectFromCustomShape();
2856 if ( mXRenderedCustomShape
.is() )
2858 pRenderedCustomShape
= SdrObject::getSdrObjectFromXShape(mXRenderedCustomShape
);
2861 if ( pRenderedCustomShape
)
2863 // Clone to same SdrModel
2864 rtl::Reference
<SdrObject
> pCandidate(pRenderedCustomShape
->CloneSdrObject(pRenderedCustomShape
->getSdrModelFromSdrObject()));
2865 DBG_ASSERT(pCandidate
, "SdrObjCustomShape::DoConvertToPolyObj: Could not clone SdrObject (!)");
2866 pRetval
= pCandidate
->DoConvertToPolyObj(bBezier
, bAddText
);
2871 const bool bShadow(GetMergedItem(SDRATTR_SHADOW
).GetValue());
2874 pRetval
->SetMergedItem(makeSdrShadowItem(true));
2878 if(bAddText
&& HasText() && !IsTextPath())
2880 pRetval
= ImpConvertAddText(std::move(pRetval
), bBezier
);
2887 void SdrObjCustomShape::InternalSetStyleSheet( SfxStyleSheet
* pNewStyleSheet
, bool bDontRemoveHardAttr
, bool bBroadcast
, bool bAdjustTextFrameWidthAndHeight
)
2890 InvalidateRenderGeometry();
2891 SdrObject::InternalSetStyleSheet( pNewStyleSheet
, bDontRemoveHardAttr
, bBroadcast
, bAdjustTextFrameWidthAndHeight
);
2894 void SdrObjCustomShape::handlePageChange(SdrPage
* pOldPage
, SdrPage
* pNewPage
)
2897 SdrTextObj::handlePageChange(pOldPage
, pNewPage
);
2899 if(nullptr != pNewPage
)
2901 // invalidating rectangles by SetRectsDirty is not sufficient,
2902 // AdjustTextFrameWidthAndHeight() also has to be made, both
2903 // actions are done by NbcSetSnapRect
2904 tools::Rectangle
aRectangle(getRectangle()); //creating temporary rectangle #i61108#
2905 NbcSetSnapRect(aRectangle
);
2909 std::unique_ptr
<SdrObjGeoData
> SdrObjCustomShape::NewGeoData() const
2911 return std::make_unique
<SdrAShapeObjGeoData
>();
2914 void SdrObjCustomShape::SaveGeoData(SdrObjGeoData
& rGeo
) const
2916 SdrTextObj::SaveGeoData( rGeo
);
2917 SdrAShapeObjGeoData
& rAGeo
=static_cast<SdrAShapeObjGeoData
&>(rGeo
);
2918 rAGeo
.fObjectRotation
= m_fObjectRotation
;
2919 rAGeo
.bMirroredX
= IsMirroredX();
2920 rAGeo
.bMirroredY
= IsMirroredY();
2922 const uno::Any
* pAny
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
).GetPropertyValueByName( u
"AdjustmentValues"_ustr
);
2924 *pAny
>>= rAGeo
.aAdjustmentSeq
;
2927 void SdrObjCustomShape::RestoreGeoData(const SdrObjGeoData
& rGeo
)
2929 SdrTextObj::RestoreGeoData( rGeo
);
2930 const SdrAShapeObjGeoData
& rAGeo
=static_cast<const SdrAShapeObjGeoData
&>(rGeo
);
2931 m_fObjectRotation
= rAGeo
.fObjectRotation
;
2932 SetMirroredX( rAGeo
.bMirroredX
);
2933 SetMirroredY( rAGeo
.bMirroredY
);
2935 SdrCustomShapeGeometryItem rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
2936 beans::PropertyValue aPropVal
;
2937 aPropVal
.Name
= "AdjustmentValues";
2938 aPropVal
.Value
<<= rAGeo
.aAdjustmentSeq
;
2939 rGeometryItem
.SetPropertyValue( aPropVal
);
2940 SetMergedItem( rGeometryItem
);
2942 InvalidateRenderGeometry();
2945 void SdrObjCustomShape::AdjustToMaxRect(const tools::Rectangle
& rMaxRect
, bool bShrinkOnly
/* = false */)
2947 SAL_INFO_IF(bShrinkOnly
, "svx", "Case bShrinkOnly == true is not implemented yet.");
2949 if (rMaxRect
.IsEmpty() || rMaxRect
== GetSnapRect())
2952 // Get a matrix, that would produce the existing shape, when applied to a unit square
2953 basegfx::B2DPolyPolygon aPolyPolygon
; //not used, but formal needed
2954 basegfx::B2DHomMatrix aMatrix
;
2955 TRGetBaseGeometry(aMatrix
, aPolyPolygon
);
2956 // Using TRSetBaseGeometry(aMatrix, aPolyPolygon) would regenerate the current shape. But
2957 // applying aMatrix to a unit square will not generate the current shape. Scaling,
2958 // rotation and translation are correct, but shear angle has wrong sign. So break up
2959 // matrix and create a mathematically correct new one.
2960 basegfx::B2DTuple aScale
;
2961 basegfx::B2DTuple aTranslate
;
2962 double fRotate
, fShearX
;
2963 aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2964 basegfx::B2DHomMatrix aMathMatrix
;
2965 aMathMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2967 basegfx::fTools::equalZero(fShearX
) ? 0.0 : -fShearX
,
2968 basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
2971 // Calculate scaling factors from size of the transformed unit polygon as ersatz for the not
2972 // usable current snap rectangle.
2973 basegfx::B2DPolygon
aB2DPolygon(basegfx::utils::createUnitPolygon());
2974 aB2DPolygon
.transform(aMathMatrix
);
2975 basegfx::B2DRange
aB2DRange(aB2DPolygon
.getB2DRange());
2976 double fPolygonWidth
= aB2DRange
.getWidth();
2977 if (fPolygonWidth
== 0)
2979 double fPolygonHeight
= aB2DRange
.getHeight();
2980 if (fPolygonHeight
== 0)
2982 const double aFactorX
= static_cast<double>(rMaxRect
.GetWidth()) / fPolygonWidth
;
2983 const double aFactorY
= static_cast<double>(rMaxRect
.GetHeight()) / fPolygonHeight
;
2985 // Generate matrix, that would produce the desired rMaxRect when applied to unit square
2986 aMathMatrix
.scale(aFactorX
, aFactorY
);
2987 aB2DPolygon
= basegfx::utils::createUnitPolygon();
2988 aB2DPolygon
.transform(aMathMatrix
);
2989 aB2DRange
= aB2DPolygon
.getB2DRange();
2990 const double fPolygonLeft
= aB2DRange
.getMinX();
2991 const double fPolygonTop
= aB2DRange
.getMinY();
2992 aMathMatrix
.translate(rMaxRect
.Left() - fPolygonLeft
, rMaxRect
.Top() - fPolygonTop
);
2994 // Create a Matrix from aMathMatrix, which is usable with TRSetBaseGeometry
2995 aMathMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2996 aMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2998 basegfx::fTools::equalZero(fShearX
) ? 0.0 : -fShearX
,
2999 basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
3002 // Now use TRSetBaseGeometry to actually perform scale, shear, rotate and translate
3003 // on the shape. That considers gluepoints, interaction handles and text area, and includes
3004 // setting rectangles dirty and broadcast.
3005 TRSetBaseGeometry(aMatrix
, aPolyPolygon
);
3008 void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& /*rPolyPolygon*/)
3010 // The shape might have already flipping in its enhanced geometry. LibreOffice applies
3011 // such after all transformations. We remove it, but remember it to apply them later.
3012 bool bIsMirroredX
= IsMirroredX();
3013 bool bIsMirroredY
= IsMirroredY();
3014 if (bIsMirroredX
|| bIsMirroredY
)
3016 Point aCurrentCenter
= GetSnapRect().Center();
3017 if (bIsMirroredX
) // mirror on the y-axis
3019 Mirror(aCurrentCenter
, Point(aCurrentCenter
.X(), aCurrentCenter
.Y() + 1000));
3021 if (bIsMirroredY
) // mirror on the x-axis
3023 Mirror(aCurrentCenter
, Point(aCurrentCenter
.X() + 1000, aCurrentCenter
.Y()));
3028 basegfx::B2DTuple aScale
;
3029 basegfx::B2DTuple aTranslate
;
3030 double fRotate
, fShearX
;
3031 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
3033 // reset object shear and rotations
3034 m_fObjectRotation
= 0.0;
3035 maGeo
.m_nRotationAngle
= 0_deg100
;
3036 maGeo
.RecalcSinCos();
3037 maGeo
.m_nShearAngle
= 0_deg100
;
3040 // if anchor is used, make position relative to it
3041 if(getSdrModelFromSdrObject().IsWriter())
3043 if(GetAnchorPos().X() || GetAnchorPos().Y())
3045 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3050 Size
aSize(basegfx::fround
<tools::Long
>(fabs(aScale
.getX())),
3051 basegfx::fround
<tools::Long
>(fabs(aScale
.getY())));
3052 // fdo#47434 We need a valid rectangle here
3053 if( !aSize
.Height() ) aSize
.setHeight( 1 );
3054 if( !aSize
.Width() ) aSize
.setWidth( 1 );
3055 tools::Rectangle
aBaseRect(Point(), aSize
);
3056 SetLogicRect(aBaseRect
);
3058 // Apply flipping from Matrix, which is a transformation relative to origin
3059 if (aScale
.getX() < 0.0)
3060 Mirror(Point(0, 0), Point(0, 1000)); // mirror on the y-axis
3061 if (aScale
.getY() < 0.0)
3062 Mirror(Point(0, 0), Point(1000, 0)); // mirror on the x-axis
3065 if(!basegfx::fTools::equalZero(fShearX
))
3068 // #i123181# The fix for #121932# here was wrong, the trunk version does not correct the
3069 // mirrored shear values, neither at the object level, nor on the API or XML level. Taking
3070 // back the mirroring of the shear angle
3071 aGeoStat
.m_nShearAngle
= Degree100(basegfx::fround(basegfx::rad2deg
<100>(atan(fShearX
))));
3072 aGeoStat
.RecalcTan();
3073 Shear(Point(), aGeoStat
.m_nShearAngle
, aGeoStat
.mfTanShearAngle
, false);
3077 if(!basegfx::fTools::equalZero(fRotate
))
3082 // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
3083 // mirrored -> mirror value here
3084 aGeoStat
.m_nRotationAngle
= NormAngle36000(Degree100(basegfx::fround(-basegfx::rad2deg
<100>(fRotate
))));
3085 aGeoStat
.RecalcSinCos();
3086 Rotate(Point(), aGeoStat
.m_nRotationAngle
, aGeoStat
.mfSinRotationAngle
, aGeoStat
.mfCosRotationAngle
);
3090 if(!aTranslate
.equalZero())
3092 Move(Size(basegfx::fround
<tools::Long
>(aTranslate
.getX()),
3093 basegfx::fround
<tools::Long
>(aTranslate
.getY())));
3096 // Apply flipping from enhanced geometry at center of the shape.
3097 if (!(bIsMirroredX
|| bIsMirroredY
))
3100 // create mathematically matrix for the applied transformations
3101 // aScale was in most cases built from a rectangle including edge
3102 // and is therefore mathematically too large by 1
3103 if (aScale
.getX() > 2.0 && aScale
.getY() > 2.0)
3104 aScale
-= basegfx::B2DTuple(1.0, 1.0);
3105 basegfx::B2DHomMatrix aMathMat
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3106 aScale
, -fShearX
, basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
3108 // Use matrix to get current center
3109 basegfx::B2DPoint
aCenter(0.5,0.5);
3110 aCenter
= aMathMat
* aCenter
;
3111 double fCenterX
= aCenter
.getX();
3112 double fCenterY
= aCenter
.getY();
3113 if (bIsMirroredX
) // vertical axis
3114 Mirror(Point(basegfx::fround
<tools::Long
>(fCenterX
), basegfx::fround
<tools::Long
>(fCenterY
)),
3115 Point(basegfx::fround
<tools::Long
>(fCenterX
), basegfx::fround
<tools::Long
>(fCenterY
+ 1000.0)));
3116 if (bIsMirroredY
) // horizontal axis
3117 Mirror(Point(basegfx::fround
<tools::Long
>(fCenterX
), basegfx::fround
<tools::Long
>(fCenterY
)),
3118 Point(basegfx::fround
<tools::Long
>(fCenterX
+ 1000.0), basegfx::fround
<tools::Long
>(fCenterY
)));
3121 // taking fObjectRotation instead of aGeo.nAngle
3122 bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& /*rPolyPolygon*/) const
3124 // get turn and shear
3125 double fRotate
= basegfx::deg2rad(m_fObjectRotation
);
3126 double fShearX
= toRadians(maGeo
.m_nShearAngle
);
3128 // get aRectangle, this is the unrotated snaprect
3129 tools::Rectangle
aRectangle(getRectangle());
3131 bool bMirroredX
= IsMirroredX();
3132 bool bMirroredY
= IsMirroredY();
3133 if ( bMirroredX
|| bMirroredY
)
3134 { // we have to retrieve the unmirrored rect
3136 GeoStat
aNewGeo(maGeo
);
3141 tools::Polygon aPol
= Rect2Poly(getRectangle(), aNewGeo
);
3142 tools::Rectangle
aBoundRect( aPol
.GetBoundRect() );
3144 Point
aRef1( ( aBoundRect
.Left() + aBoundRect
.Right() ) >> 1, aBoundRect
.Top() );
3145 Point
aRef2( aRef1
.X(), aRef1
.Y() + 1000 );
3147 sal_uInt16 nPointCount
=aPol
.GetSize();
3148 for (i
=0; i
<nPointCount
; i
++)
3150 MirrorPoint(aPol
[i
],aRef1
,aRef2
);
3152 // mirror polygon and move it a bit
3153 tools::Polygon
aPol0(aPol
);
3159 aRectangle
= svx::polygonToRectangle(aPol
, aNewGeo
);
3164 tools::Polygon
aPol( Rect2Poly( aRectangle
, aNewGeo
) );
3165 tools::Rectangle
aBoundRect( aPol
.GetBoundRect() );
3167 Point
aRef1( aBoundRect
.Left(), ( aBoundRect
.Top() + aBoundRect
.Bottom() ) >> 1 );
3168 Point
aRef2( aRef1
.X() + 1000, aRef1
.Y() );
3170 sal_uInt16 nPointCount
=aPol
.GetSize();
3171 for (i
=0; i
<nPointCount
; i
++)
3173 MirrorPoint(aPol
[i
],aRef1
,aRef2
);
3175 // mirror polygon and move it a bit
3176 tools::Polygon
aPol0(aPol
);
3177 aPol
[0]=aPol0
[1]; // This was WRONG for vertical (!)
3178 aPol
[1]=aPol0
[0]; // #i121932# Despite my own comment above
3179 aPol
[2]=aPol0
[3]; // it was *not* wrong even when the reordering
3180 aPol
[3]=aPol0
[2]; // *seems* to be specific for X-Mirrorings. Oh
3181 aPol
[4]=aPol0
[1]; // will I be happy when this old stuff is |gone| with aw080 (!)
3182 aRectangle
= svx::polygonToRectangle(aPol
, aNewGeo
);
3186 // fill other values
3187 basegfx::B2DTuple
aScale(aRectangle
.GetWidth(), aRectangle
.GetHeight());
3188 basegfx::B2DTuple
aTranslate(aRectangle
.Left(), aRectangle
.Top());
3190 // position may be relative to anchorpos, convert
3191 if(getSdrModelFromSdrObject().IsWriter())
3193 if(GetAnchorPos().X() || GetAnchorPos().Y())
3195 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3200 rMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3202 basegfx::fTools::equalZero(fShearX
) ? 0.0 : tan(fShearX
),
3203 basegfx::fTools::equalZero(fRotate
) ? 0.0 : -fRotate
,
3209 std::unique_ptr
<sdr::contact::ViewContact
> SdrObjCustomShape::CreateObjectSpecificViewContact()
3211 return std::make_unique
<sdr::contact::ViewContactOfSdrObjCustomShape
>(*this);
3215 bool SdrObjCustomShape::doConstructOrthogonal(std::u16string_view rName
)
3217 bool bRetval(false);
3219 if(o3tl::equalsIgnoreAsciiCase(rName
, u
"quadrat"))
3223 else if(o3tl::equalsIgnoreAsciiCase(rName
, u
"round-quadrat"))
3227 else if(o3tl::equalsIgnoreAsciiCase(rName
, u
"circle"))
3231 else if(o3tl::equalsIgnoreAsciiCase(rName
, u
"circle-pie"))
3235 else if(o3tl::equalsIgnoreAsciiCase(rName
, u
"ring"))
3243 // #i37011# centralize throw-away of render geometry
3244 void SdrObjCustomShape::InvalidateRenderGeometry()
3246 mXRenderedCustomShape
= nullptr;
3247 mpLastShadowGeometry
= nullptr;
3250 void SdrObjCustomShape::setUnoShape(const uno::Reference
<drawing::XShape
>& rxUnoShape
)
3252 SdrTextObj::setUnoShape(rxUnoShape
);
3254 // The shape engine is created with _current_ shape. This means we
3255 // _must_ reset it when the shape changes.
3256 mxCustomShapeEngine
.clear();
3259 OUString
SdrObjCustomShape::GetCustomShapeName() const
3261 OUString sShapeName
;
3262 OUString
aEngine( GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue() );
3263 if ( aEngine
.isEmpty()
3264 || aEngine
== "com.sun.star.drawing.EnhancedCustomShapeEngine" )
3266 OUString sShapeType
;
3267 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
3268 const uno::Any
* pAny
= rGeometryItem
.GetPropertyValueByName( u
"Type"_ustr
);
3269 if ( pAny
&& ( *pAny
>>= sShapeType
) )
3270 sShapeName
= EnhancedCustomShapeTypeNames::GetAccName( sShapeType
);
3275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */