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 <svx/svdoashp.hxx>
21 #include <svx/unoapi.hxx>
22 #include <com/sun/star/loader/CannotActivateFactoryException.hpp>
23 #include <com/sun/star/drawing/XShape.hpp>
24 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
25 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
26 #include <com/sun/star/beans/PropertyValue.hpp>
27 #include <com/sun/star/awt/Rectangle.hpp>
28 #include <com/sun/star/uno/XComponentContext.hpp>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/sequenceashashmap.hxx>
31 #include <com/sun/star/uno/Sequence.h>
32 #include <tools/helpers.hxx>
33 #include <svx/svddrag.hxx>
34 #include <svx/svddrgmt.hxx>
35 #include <svx/svdmodel.hxx>
36 #include <svx/svdpage.hxx>
37 #include <svx/svditer.hxx>
38 #include <svx/svdobj.hxx>
39 #include <svx/svdtrans.hxx>
40 #include <svx/dialmgr.hxx>
41 #include <svx/strings.hrc>
42 #include <editeng/eeitem.hxx>
43 #include <editeng/editstat.hxx>
44 #include <editeng/adjustitem.hxx>
45 #include <svx/svdoutl.hxx>
46 #include <editeng/outlobj.hxx>
47 #include <svx/sdtfchim.hxx>
48 #include <svx/EnhancedCustomShapeGeometry.hxx>
49 #include <svx/EnhancedCustomShapeTypeNames.hxx>
50 #include <svx/EnhancedCustomShape2d.hxx>
51 #include <com/sun/star/beans/PropertyValues.hpp>
52 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
53 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
54 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
55 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
56 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
57 #include <editeng/writingmodeitem.hxx>
58 #include <svx/xlineit0.hxx>
59 #include <svx/xlnclit.hxx>
60 #include <sdr/properties/customshapeproperties.hxx>
61 #include <sdr/contact/viewcontactofsdrobjcustomshape.hxx>
62 #include <svx/xlntrit.hxx>
63 #include <svx/xfillit0.hxx>
64 #include <svx/xfltrit.hxx>
65 #include <svx/xflclit.hxx>
66 #include <svx/xflgrit.hxx>
67 #include <svx/xflhtit.hxx>
68 #include <svx/xbtmpit.hxx>
69 #include <vcl/virdev.hxx>
70 #include <svx/svdview.hxx>
71 #include <svx/sdmetitm.hxx>
72 #include <svx/sdprcitm.hxx>
73 #include <svx/sdshitm.hxx>
74 #include <svx/sdsxyitm.hxx>
75 #include <svx/sdtmfitm.hxx>
76 #include <svx/sdasitm.hxx>
77 #include <basegfx/polygon/b2dpolypolygontools.hxx>
78 #include <basegfx/matrix/b2dhommatrix.hxx>
79 #include <basegfx/matrix/b2dhommatrixtools.hxx>
80 #include <basegfx/polygon/b2dpolygon.hxx>
81 #include <basegfx/polygon/b2dpolygontools.hxx>
82 #include <basegfx/range/b2drange.hxx>
83 #include <svdobjplusdata.hxx>
84 #include <rtl/ustrbuf.hxx>
85 #include <sal/log.hxx>
86 #include "presetooxhandleadjustmentrelations.hxx"
88 using namespace ::com::sun::star
;
89 using namespace ::com::sun::star::uno
;
90 using namespace ::com::sun::star::lang
;
91 using namespace ::com::sun::star::beans
;
92 using namespace ::com::sun::star::drawing
;
94 static void lcl_ShapeSegmentFromBinary( EnhancedCustomShapeSegment
& rSegInfo
, sal_uInt16 nSDat
)
99 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::LINETO
;
100 rSegInfo
.Count
= nSDat
& 0xff;
101 if ( !rSegInfo
.Count
)
105 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::CURVETO
;
106 rSegInfo
.Count
= nSDat
& 0xff;
107 if ( !rSegInfo
.Count
)
111 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::MOVETO
;
112 rSegInfo
.Count
= nSDat
& 0xff;
113 if ( !rSegInfo
.Count
)
117 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
;
121 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ENDSUBPATH
;
125 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO
;
126 rSegInfo
.Count
= ( nSDat
& 0xff ) / 3;
129 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE
;
130 rSegInfo
.Count
= ( nSDat
& 0xff ) / 3;
133 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ARCTO
;
134 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
137 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ARC
;
138 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
141 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO
;
142 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
145 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::CLOCKWISEARC
;
146 rSegInfo
.Count
= ( nSDat
& 0xff ) >> 2;
149 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX
;
150 rSegInfo
.Count
= nSDat
& 0xff;
153 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY
;
154 rSegInfo
.Count
= nSDat
& 0xff;
157 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::NOFILL
;
161 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::NOSTROKE
;
166 rSegInfo
.Command
= EnhancedCustomShapeSegmentCommand::UNKNOWN
;
167 rSegInfo
.Count
= nSDat
;
172 static MSO_SPT
ImpGetCustomShapeType( const SdrObjCustomShape
& rCustoShape
)
174 MSO_SPT eRetValue
= mso_sptNil
;
176 OUString
aEngine( rCustoShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue() );
177 if ( aEngine
.isEmpty() || aEngine
== "com.sun.star.drawing.EnhancedCustomShapeEngine" )
180 const SdrCustomShapeGeometryItem
& rGeometryItem( rCustoShape
.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
181 const Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "Type" );
182 if ( pAny
&& ( *pAny
>>= sShapeType
) )
183 eRetValue
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
188 static bool ImpVerticalSwitch( const SdrObjCustomShape
& rCustoShape
)
191 MSO_SPT
eShapeType( ImpGetCustomShapeType( rCustoShape
) );
194 case mso_sptAccentBorderCallout90
: // 2 ortho
195 case mso_sptBorderCallout1
: // 2 diag
196 case mso_sptBorderCallout2
: // 3
206 // #i37011# create a clone with all attributes changed to shadow attributes
207 // and translation executed, too.
208 static SdrObject
* ImpCreateShadowObjectClone(const SdrObject
& rOriginal
, const SfxItemSet
& rOriginalSet
)
210 SdrObject
* pRetval
= nullptr;
211 const bool bShadow(rOriginalSet
.Get(SDRATTR_SHADOW
).GetValue());
215 // create a shadow representing object
216 const sal_Int32
nXDist(rOriginalSet
.Get(SDRATTR_SHADOWXDIST
).GetValue());
217 const sal_Int32
nYDist(rOriginalSet
.Get(SDRATTR_SHADOWYDIST
).GetValue());
218 const ::Color
aShadowColor(rOriginalSet
.Get(SDRATTR_SHADOWCOLOR
).GetColorValue());
219 const sal_uInt16
nShadowTransparence(rOriginalSet
.Get(SDRATTR_SHADOWTRANSPARENCE
).GetValue());
220 pRetval
= rOriginal
.CloneSdrObject(rOriginal
.getSdrModelFromSdrObject());
221 DBG_ASSERT(pRetval
, "ImpCreateShadowObjectClone: Could not clone object (!)");
223 // look for used stuff
224 SdrObjListIter
aIterator(rOriginal
);
225 bool bLineUsed(false);
226 bool bAllFillUsed(false);
227 bool bSolidFillUsed(false);
228 bool bGradientFillUsed(false);
229 bool bHatchFillUsed(false);
230 bool bBitmapFillUsed(false);
232 while(aIterator
.IsMore())
234 SdrObject
* pObj
= aIterator
.Next();
235 drawing::FillStyle eFillStyle
= pObj
->GetMergedItem(XATTR_FILLSTYLE
).GetValue();
239 drawing::LineStyle eLineStyle
= pObj
->GetMergedItem(XATTR_LINESTYLE
).GetValue();
241 if(drawing::LineStyle_NONE
!= eLineStyle
)
249 if(!bSolidFillUsed
&& drawing::FillStyle_SOLID
== eFillStyle
)
251 bSolidFillUsed
= true;
252 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
254 if(!bGradientFillUsed
&& drawing::FillStyle_GRADIENT
== eFillStyle
)
256 bGradientFillUsed
= true;
257 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
259 if(!bHatchFillUsed
&& drawing::FillStyle_HATCH
== eFillStyle
)
261 bHatchFillUsed
= true;
262 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
264 if(!bBitmapFillUsed
&& drawing::FillStyle_BITMAP
== eFillStyle
)
266 bBitmapFillUsed
= true;
267 bAllFillUsed
= (bSolidFillUsed
&& bGradientFillUsed
&& bHatchFillUsed
&& bBitmapFillUsed
);
272 // translate to shadow coordinates
273 pRetval
->NbcMove(Size(nXDist
, nYDist
));
275 // set items as needed
276 SfxItemSet
aTempSet(rOriginalSet
);
278 // if a SvxWritingModeItem (Top->Bottom) is set the text object
279 // is creating a paraobject, but paraobjects can not be created without model. So
280 // we are preventing the crash by setting the writing mode always left to right,
281 // this is not bad since our shadow geometry does not contain text.
282 aTempSet
.Put( SvxWritingModeItem( css::text::WritingMode_LR_TB
, SDRATTR_TEXTDIRECTION
) );
285 aTempSet
.Put(makeSdrShadowItem(false));
286 aTempSet
.Put(makeSdrShadowXDistItem(0));
287 aTempSet
.Put(makeSdrShadowYDistItem(0));
289 // line color and transparency like shadow
292 aTempSet
.Put(XLineColorItem(OUString(), aShadowColor
));
293 aTempSet
.Put(XLineTransparenceItem(nShadowTransparence
));
296 // fill color and transparency like shadow
299 aTempSet
.Put(XFillColorItem(OUString(), aShadowColor
));
300 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
303 // gradient and transparency like shadow
304 if(bGradientFillUsed
)
306 XGradient
aGradient(rOriginalSet
.Get(XATTR_FILLGRADIENT
).GetGradientValue());
307 sal_uInt8
nStartLuminance(aGradient
.GetStartColor().GetLuminance());
308 sal_uInt8
nEndLuminance(aGradient
.GetEndColor().GetLuminance());
310 if(aGradient
.GetStartIntens() != 100)
312 nStartLuminance
= static_cast<sal_uInt8
>(nStartLuminance
* (static_cast<double>(aGradient
.GetStartIntens()) / 100.0));
315 if(aGradient
.GetEndIntens() != 100)
317 nEndLuminance
= static_cast<sal_uInt8
>(nEndLuminance
* (static_cast<double>(aGradient
.GetEndIntens()) / 100.0));
321 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetRed()) / 256),
322 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetGreen()) / 256),
323 static_cast<sal_uInt8
>((nStartLuminance
* aShadowColor
.GetBlue()) / 256));
326 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetRed()) / 256),
327 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetGreen()) / 256),
328 static_cast<sal_uInt8
>((nEndLuminance
* aShadowColor
.GetBlue()) / 256));
330 aGradient
.SetStartColor(aStartColor
);
331 aGradient
.SetEndColor(aEndColor
);
332 aTempSet
.Put(XFillGradientItem(aGradient
));
333 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
336 // hatch and transparency like shadow
339 XHatch
aHatch(rOriginalSet
.Get(XATTR_FILLHATCH
).GetHatchValue());
340 aHatch
.SetColor(aShadowColor
);
341 aTempSet
.Put(XFillHatchItem(aHatch
));
342 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
345 // bitmap and transparency like shadow
348 GraphicObject
aGraphicObject(rOriginalSet
.Get(XATTR_FILLBITMAP
).GetGraphicObject());
349 const BitmapEx
aBitmapEx(aGraphicObject
.GetGraphic().GetBitmapEx());
351 if(!aBitmapEx
.IsEmpty())
353 ScopedVclPtr
<VirtualDevice
> pVirDev(VclPtr
<VirtualDevice
>::Create());
354 pVirDev
->SetOutputSizePixel(aBitmapEx
.GetSizePixel());
355 pVirDev
->DrawShadowBitmapEx(aBitmapEx
, aShadowColor
);
356 aGraphicObject
.SetGraphic(Graphic(pVirDev
->GetBitmapEx(Point(0,0), aBitmapEx
.GetSizePixel())));
359 aTempSet
.Put(XFillBitmapItem(aGraphicObject
));
360 aTempSet
.Put(XFillTransparenceItem(nShadowTransparence
));
363 // set attributes and paint shadow object
364 pRetval
->SetMergedItemSet( aTempSet
);
370 Reference
< XCustomShapeEngine
> const & SdrObjCustomShape::GetCustomShapeEngine() const
372 if (mxCustomShapeEngine
.is())
373 return mxCustomShapeEngine
;
375 OUString
aEngine(GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue());
376 if ( aEngine
.isEmpty() )
377 aEngine
= "com.sun.star.drawing.EnhancedCustomShapeEngine";
379 Reference
< XComponentContext
> xContext( ::comphelper::getProcessComponentContext() );
381 Reference
< XShape
> aXShape
= GetXShapeForSdrObject(const_cast<SdrObjCustomShape
*>(this));
384 Sequence
< Any
> aArgument( 1 );
385 Sequence
< PropertyValue
> aPropValues( 1 );
386 aPropValues
[ 0 ].Name
= "CustomShape";
387 aPropValues
[ 0 ].Value
<<= aXShape
;
388 aArgument
[ 0 ] <<= aPropValues
;
391 Reference
<XInterface
> xInterface(xContext
->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine
, aArgument
, xContext
));
393 mxCustomShapeEngine
.set( xInterface
, UNO_QUERY
);
395 catch (const css::loader::CannotActivateFactoryException
&)
400 return mxCustomShapeEngine
;
403 const SdrObject
* SdrObjCustomShape::GetSdrObjectFromCustomShape() const
405 if ( !mXRenderedCustomShape
.is() )
407 Reference
< XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
408 if ( xCustomShapeEngine
.is() )
409 const_cast<SdrObjCustomShape
*>(this)->mXRenderedCustomShape
= xCustomShapeEngine
->render();
411 SdrObject
* pRenderedCustomShape
= mXRenderedCustomShape
.is()
412 ? GetSdrObjectFromXShape( mXRenderedCustomShape
)
414 return pRenderedCustomShape
;
417 // #i37011# Shadow geometry creation
418 const SdrObject
* SdrObjCustomShape::GetSdrObjectShadowFromCustomShape() const
420 if(!mpLastShadowGeometry
)
422 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
425 const SfxItemSet
& rOriginalSet
= GetObjectItemSet();
426 const bool bShadow(rOriginalSet
.Get( SDRATTR_SHADOW
).GetValue());
430 // create a clone with all attributes changed to shadow attributes
431 // and translation executed, too.
432 const_cast<SdrObjCustomShape
*>(this)->mpLastShadowGeometry
=
433 ImpCreateShadowObjectClone(*pSdrObject
, rOriginalSet
);
438 return mpLastShadowGeometry
;
441 bool SdrObjCustomShape::IsTextPath() const
443 const OUString
sTextPath( "TextPath" );
444 bool bTextPathOn
= false;
445 const SdrCustomShapeGeometryItem
& rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
446 const Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sTextPath
, sTextPath
);
448 *pAny
>>= bTextPathOn
;
452 bool SdrObjCustomShape::UseNoFillStyle() const
456 const OUString
sType( "Type" );
457 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
458 const Any
* pAny
= rGeometryItem
.GetPropertyValueByName( sType
);
460 *pAny
>>= sShapeType
;
461 bRet
= !IsCustomShapeFilledByDefault( EnhancedCustomShapeTypeNames::Get( sType
) );
466 bool SdrObjCustomShape::IsMirroredX() const
468 bool bMirroredX
= false;
469 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
470 css::uno::Any
* pAny
= aGeometryItem
.GetPropertyValueByName( "MirroredX" );
472 *pAny
>>= bMirroredX
;
475 bool SdrObjCustomShape::IsMirroredY() const
477 bool bMirroredY
= false;
478 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
479 css::uno::Any
* pAny
= aGeometryItem
.GetPropertyValueByName( "MirroredY" );
481 *pAny
>>= bMirroredY
;
484 void SdrObjCustomShape::SetMirroredX( const bool bMirrorX
)
486 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
487 PropertyValue aPropVal
;
488 aPropVal
.Name
= "MirroredX";
489 aPropVal
.Value
<<= bMirrorX
;
490 aGeometryItem
.SetPropertyValue( aPropVal
);
491 SetMergedItem( aGeometryItem
);
493 void SdrObjCustomShape::SetMirroredY( const bool bMirrorY
)
495 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
496 PropertyValue aPropVal
;
497 aPropVal
.Name
= "MirroredY";
498 aPropVal
.Value
<<= bMirrorY
;
499 aGeometryItem
.SetPropertyValue( aPropVal
);
500 SetMergedItem( aGeometryItem
);
503 double SdrObjCustomShape::GetExtraTextRotation( const bool bPreRotation
) const
505 const css::uno::Any
* pAny
;
506 const SdrCustomShapeGeometryItem
& rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
507 pAny
= rGeometryItem
.GetPropertyValueByName( bPreRotation
? OUString( "TextPreRotateAngle" ) : OUString( "TextRotateAngle" ) );
508 double fExtraTextRotateAngle
= 0.0;
510 *pAny
>>= fExtraTextRotateAngle
;
511 return fExtraTextRotateAngle
;
514 bool SdrObjCustomShape::GetTextBounds( tools::Rectangle
& rTextBound
) const
518 Reference
< XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
519 if ( xCustomShapeEngine
.is() )
521 awt::Rectangle
aR( xCustomShapeEngine
->getTextBounds() );
522 if ( aR
.Width
> 1 && aR
.Height
> 1 )
524 rTextBound
= tools::Rectangle( Point( aR
.X
, aR
.Y
), Size( aR
.Width
, aR
.Height
) );
530 basegfx::B2DPolyPolygon
SdrObjCustomShape::GetLineGeometry( const bool bBezierAllowed
) const
532 basegfx::B2DPolyPolygon aRetval
;
533 Reference
< XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
534 if ( xCustomShapeEngine
.is() )
536 css::drawing::PolyPolygonBezierCoords aBezierCoords
= xCustomShapeEngine
->getLineGeometry();
539 aRetval
= basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon( aBezierCoords
);
540 if ( !bBezierAllowed
&& aRetval
.areControlPointsUsed())
542 aRetval
= basegfx::utils::adaptiveSubdivideByAngle(aRetval
);
545 catch ( const css::lang::IllegalArgumentException
& )
552 std::vector
< SdrCustomShapeInteraction
> SdrObjCustomShape::GetInteractionHandles() const
554 std::vector
< SdrCustomShapeInteraction
> aRet
;
557 Reference
< XCustomShapeEngine
> xCustomShapeEngine( GetCustomShapeEngine() );
558 if ( xCustomShapeEngine
.is() )
561 Sequence
< Reference
< XCustomShapeHandle
> > xInteractionHandles( xCustomShapeEngine
->getInteraction() );
562 for ( i
= 0; i
< xInteractionHandles
.getLength(); i
++ )
564 if ( xInteractionHandles
[ i
].is() )
566 SdrCustomShapeInteraction aSdrCustomShapeInteraction
;
567 aSdrCustomShapeInteraction
.xInteraction
= xInteractionHandles
[ i
];
568 aSdrCustomShapeInteraction
.aPosition
= xInteractionHandles
[ i
]->getPosition();
570 CustomShapeHandleModes nMode
= CustomShapeHandleModes::NONE
;
571 switch( ImpGetCustomShapeType( *this ) )
573 case mso_sptAccentBorderCallout90
: // 2 ortho
576 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
578 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
| CustomShapeHandleModes::ORTHO4
;
582 case mso_sptChevron
:
583 case mso_sptHomePlate
:
584 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
;
587 case mso_sptWedgeRectCallout
:
588 case mso_sptWedgeRRectCallout
:
589 case mso_sptCloudCallout
:
590 case mso_sptWedgeEllipseCallout
:
593 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
;
597 case mso_sptBorderCallout1
: // 2 diag
600 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
602 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
;
605 case mso_sptBorderCallout2
: // 3
608 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
610 nMode
|= CustomShapeHandleModes::RESIZE_ABSOLUTE_X
| CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
| CustomShapeHandleModes::MOVE_SHAPE
;
613 case mso_sptCallout90
:
614 case mso_sptAccentCallout90
:
615 case mso_sptBorderCallout90
:
616 case mso_sptCallout1
:
617 case mso_sptCallout2
:
618 case mso_sptCallout3
:
619 case mso_sptAccentCallout1
:
620 case mso_sptAccentCallout2
:
621 case mso_sptAccentCallout3
:
622 case mso_sptBorderCallout3
:
623 case mso_sptAccentBorderCallout1
:
624 case mso_sptAccentBorderCallout2
:
625 case mso_sptAccentBorderCallout3
:
628 nMode
|= CustomShapeHandleModes::RESIZE_FIXED
| CustomShapeHandleModes::CREATE_FIXED
;
633 aSdrCustomShapeInteraction
.nMode
= nMode
;
634 aRet
.push_back( aSdrCustomShapeInteraction
);
639 catch( const uno::RuntimeException
& )
646 // BaseProperties section
647 #define DEFAULT_MINIMUM_SIGNED_COMPARE (sal_Int32(0x80000000))
648 #define DEFAULT_MAXIMUM_SIGNED_COMPARE (sal_Int32(0x7fffffff))
650 static sal_Int32
GetNumberOfProperties ( const SvxMSDffHandle
* pData
)
652 sal_Int32 nPropertiesNeeded
=1; // position is always needed
653 SvxMSDffHandleFlags nFlags
= pData
->nFlags
;
655 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_X
)
657 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_Y
)
659 if ( nFlags
& SvxMSDffHandleFlags::SWITCHED
)
661 if ( nFlags
& SvxMSDffHandleFlags::POLAR
)
664 if ( nFlags
& SvxMSDffHandleFlags::RADIUS_RANGE
)
666 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
668 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
672 else if ( nFlags
& SvxMSDffHandleFlags::RANGE
)
674 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
676 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
678 if ( pData
->nRangeYMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
680 if ( pData
->nRangeYMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
684 return nPropertiesNeeded
;
687 static void lcl_ShapePropertiesFromDFF( const SvxMSDffHandle
* pData
, css::beans::PropertyValues
& rPropValues
)
689 SvxMSDffHandleFlags nFlags
= pData
->nFlags
;
694 css::drawing::EnhancedCustomShapeParameterPair aPosition
;
695 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition
.First
, pData
->nPositionX
, true, true );
696 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition
.Second
, pData
->nPositionY
, true, false );
697 rPropValues
[ n
].Name
= "Position";
698 rPropValues
[ n
++ ].Value
<<= aPosition
;
700 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_X
)
702 rPropValues
[ n
].Name
= "MirroredX";
703 rPropValues
[ n
++ ].Value
<<= true;
705 if ( nFlags
& SvxMSDffHandleFlags::MIRRORED_Y
)
707 rPropValues
[ n
].Name
= "MirroredY";
708 rPropValues
[ n
++ ].Value
<<= true;
710 if ( nFlags
& SvxMSDffHandleFlags::SWITCHED
)
712 rPropValues
[ n
].Name
= "Switched";
713 rPropValues
[ n
++ ].Value
<<= true;
715 if ( nFlags
& SvxMSDffHandleFlags::POLAR
)
717 css::drawing::EnhancedCustomShapeParameterPair aCenter
;
718 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter
.First
, pData
->nCenterX
,
719 bool( nFlags
& SvxMSDffHandleFlags::CENTER_X_IS_SPECIAL
), true );
720 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter
.Second
, pData
->nCenterY
,
721 bool( nFlags
& SvxMSDffHandleFlags::CENTER_Y_IS_SPECIAL
), false );
722 rPropValues
[ n
].Name
= "Polar";
723 rPropValues
[ n
++ ].Value
<<= aCenter
;
724 if ( nFlags
& SvxMSDffHandleFlags::RADIUS_RANGE
)
726 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
728 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum
;
729 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum
, pData
->nRangeXMin
,
730 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL
), true );
731 rPropValues
[ n
].Name
= "RadiusRangeMinimum";
732 rPropValues
[ n
++ ].Value
<<= aRadiusRangeMinimum
;
734 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
736 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum
;
737 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum
, pData
->nRangeXMax
,
738 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL
), false );
739 rPropValues
[ n
].Name
= "RadiusRangeMaximum";
740 rPropValues
[ n
++ ].Value
<<= aRadiusRangeMaximum
;
744 else if ( nFlags
& SvxMSDffHandleFlags::RANGE
)
746 if ( pData
->nRangeXMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
748 css::drawing::EnhancedCustomShapeParameter aRangeXMinimum
;
749 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum
, pData
->nRangeXMin
,
750 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MIN_IS_SPECIAL
), true );
751 rPropValues
[ n
].Name
= "RangeXMinimum";
752 rPropValues
[ n
++ ].Value
<<= aRangeXMinimum
;
754 if ( pData
->nRangeXMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
756 css::drawing::EnhancedCustomShapeParameter aRangeXMaximum
;
757 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum
, pData
->nRangeXMax
,
758 bool( nFlags
& SvxMSDffHandleFlags::RANGE_X_MAX_IS_SPECIAL
), false );
759 rPropValues
[ n
].Name
= "RangeXMaximum";
760 rPropValues
[ n
++ ].Value
<<= aRangeXMaximum
;
762 if ( pData
->nRangeYMin
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
764 css::drawing::EnhancedCustomShapeParameter aRangeYMinimum
;
765 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum
, pData
->nRangeYMin
,
766 bool( nFlags
& SvxMSDffHandleFlags::RANGE_Y_MIN_IS_SPECIAL
), true );
767 rPropValues
[ n
].Name
= "RangeYMinimum";
768 rPropValues
[ n
++ ].Value
<<= aRangeYMinimum
;
770 if ( pData
->nRangeYMax
!= DEFAULT_MAXIMUM_SIGNED_COMPARE
)
772 css::drawing::EnhancedCustomShapeParameter aRangeYMaximum
;
773 EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum
, pData
->nRangeYMax
,
774 bool( nFlags
& SvxMSDffHandleFlags::RANGE_Y_MAX_IS_SPECIAL
), false );
775 rPropValues
[ n
].Name
= "RangeYMaximum";
776 rPropValues
[ n
++ ].Value
<<= aRangeYMaximum
;
781 std::unique_ptr
<sdr::properties::BaseProperties
> SdrObjCustomShape::CreateObjectSpecificProperties()
783 return std::make_unique
<sdr::properties::CustomShapeProperties
>(*this);
786 SdrObjCustomShape::SdrObjCustomShape(SdrModel
& rSdrModel
)
787 : SdrTextObj(rSdrModel
)
788 , fObjectRotation(0.0)
789 , mbAdjustingTextFrameWidthAndHeight(false)
790 , mpLastShadowGeometry(nullptr)
792 bClosedObj
= true; // custom shapes may be filled
796 SdrObjCustomShape::~SdrObjCustomShape()
798 // delete buffered display geometry
799 InvalidateRenderGeometry();
802 void SdrObjCustomShape::MergeDefaultAttributes( const OUString
* pType
)
804 PropertyValue aPropVal
;
806 const OUString
sType( "Type" );
807 SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
808 if ( pType
&& !pType
->isEmpty() )
810 sal_Int32 nType
= pType
->toInt32();
812 sShapeType
= EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT
>( nType
) );
816 aPropVal
.Name
= sType
;
817 aPropVal
.Value
<<= sShapeType
;
818 aGeometryItem
.SetPropertyValue( aPropVal
);
822 Any
*pAny
= aGeometryItem
.GetPropertyValueByName( sType
);
824 *pAny
>>= sShapeType
;
826 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
828 const sal_Int32
* pDefData
= nullptr;
829 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eSpType
);
830 if ( pDefCustomShape
)
831 pDefData
= pDefCustomShape
->pDefData
;
833 css::uno::Sequence
< css::drawing::EnhancedCustomShapeAdjustmentValue
> seqAdjustmentValues
;
838 const OUString
sAdjustmentValues( "AdjustmentValues" );
839 const Any
* pAny
= aGeometryItem
.GetPropertyValueByName( sAdjustmentValues
);
841 *pAny
>>= seqAdjustmentValues
;
842 if ( pDefCustomShape
&& pDefData
) // now check if we have to default some adjustment values
844 // first check if there are adjustment values are to be appended
845 sal_Int32 i
, nAdjustmentValues
= seqAdjustmentValues
.getLength();
846 sal_Int32 nAdjustmentDefaults
= *pDefData
++;
847 if ( nAdjustmentDefaults
> nAdjustmentValues
)
849 seqAdjustmentValues
.realloc( nAdjustmentDefaults
);
850 for ( i
= nAdjustmentValues
; i
< nAdjustmentDefaults
; i
++ )
852 seqAdjustmentValues
[ i
].Value
<<= pDefData
[ i
];
853 seqAdjustmentValues
[ i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
856 // check if there are defaulted adjustment values that should be filled the hard coded defaults (pDefValue)
857 sal_Int32 nCount
= std::min(nAdjustmentValues
, nAdjustmentDefaults
);
858 for ( i
= 0; i
< nCount
; i
++ )
860 if ( seqAdjustmentValues
[ i
].State
!= css::beans::PropertyState_DIRECT_VALUE
)
862 seqAdjustmentValues
[ i
].Value
<<= pDefData
[ i
];
863 seqAdjustmentValues
[ i
].State
= css::beans::PropertyState_DIRECT_VALUE
;
867 aPropVal
.Name
= sAdjustmentValues
;
868 aPropVal
.Value
<<= seqAdjustmentValues
;
869 aGeometryItem
.SetPropertyValue( aPropVal
);
874 const OUString
sViewBox( "ViewBox" );
875 const Any
* pViewBox
= aGeometryItem
.GetPropertyValueByName( sViewBox
);
876 css::awt::Rectangle aViewBox
;
877 if ( !pViewBox
|| !(*pViewBox
>>= aViewBox
) )
879 if ( pDefCustomShape
)
883 aViewBox
.Width
= pDefCustomShape
->nCoordWidth
;
884 aViewBox
.Height
= pDefCustomShape
->nCoordHeight
;
885 aPropVal
.Name
= sViewBox
;
886 aPropVal
.Value
<<= aViewBox
;
887 aGeometryItem
.SetPropertyValue( aPropVal
);
891 const OUString
sPath( "Path" );
896 const OUString
sCoordinates( "Coordinates" );
897 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sCoordinates
);
898 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nVertices
&& pDefCustomShape
->pVertices
)
900 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> seqCoordinates
;
902 sal_Int32 i
, nCount
= pDefCustomShape
->nVertices
;
903 seqCoordinates
.realloc( nCount
);
904 for ( i
= 0; i
< nCount
; i
++ )
906 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates
[ i
].First
, pDefCustomShape
->pVertices
[ i
].nValA
);
907 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates
[ i
].Second
, pDefCustomShape
->pVertices
[ i
].nValB
);
909 aPropVal
.Name
= sCoordinates
;
910 aPropVal
.Value
<<= seqCoordinates
;
911 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
915 const OUString
sGluePoints( "GluePoints" );
916 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sGluePoints
);
917 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nGluePoints
&& pDefCustomShape
->pGluePoints
)
919 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> seqGluePoints
;
920 sal_Int32 i
, nCount
= pDefCustomShape
->nGluePoints
;
921 seqGluePoints
.realloc( nCount
);
922 for ( i
= 0; i
< nCount
; i
++ )
924 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints
[ i
].First
, pDefCustomShape
->pGluePoints
[ i
].nValA
);
925 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints
[ i
].Second
, pDefCustomShape
->pGluePoints
[ i
].nValB
);
927 aPropVal
.Name
= sGluePoints
;
928 aPropVal
.Value
<<= seqGluePoints
;
929 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
933 const OUString
sSegments( "Segments" );
934 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sSegments
);
935 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nElements
&& pDefCustomShape
->pElements
)
937 css::uno::Sequence
< css::drawing::EnhancedCustomShapeSegment
> seqSegments
;
939 sal_Int32 i
, nCount
= pDefCustomShape
->nElements
;
940 seqSegments
.realloc( nCount
);
941 for ( i
= 0; i
< nCount
; i
++ )
943 EnhancedCustomShapeSegment
& rSegInfo
= seqSegments
[ i
];
944 sal_uInt16 nSDat
= pDefCustomShape
->pElements
[ i
];
945 lcl_ShapeSegmentFromBinary( rSegInfo
, nSDat
);
947 aPropVal
.Name
= sSegments
;
948 aPropVal
.Value
<<= seqSegments
;
949 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
953 const OUString
sStretchX( "StretchX" );
954 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sStretchX
);
955 if ( !pAny
&& pDefCustomShape
)
957 sal_Int32 nXRef
= pDefCustomShape
->nXRef
;
958 if ( nXRef
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
960 aPropVal
.Name
= sStretchX
;
961 aPropVal
.Value
<<= nXRef
;
962 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
967 const OUString
sStretchY( "StretchY" );
968 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sStretchY
);
969 if ( !pAny
&& pDefCustomShape
)
971 sal_Int32 nYRef
= pDefCustomShape
->nYRef
;
972 if ( nYRef
!= DEFAULT_MINIMUM_SIGNED_COMPARE
)
974 aPropVal
.Name
= sStretchY
;
975 aPropVal
.Value
<<= nYRef
;
976 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
981 const OUString
sTextFrames( "TextFrames" );
982 pAny
= aGeometryItem
.GetPropertyValueByName( sPath
, sTextFrames
);
983 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nTextRect
&& pDefCustomShape
->pTextRect
)
985 css::uno::Sequence
< css::drawing::EnhancedCustomShapeTextFrame
> seqTextFrames
;
987 sal_Int32 i
, nCount
= pDefCustomShape
->nTextRect
;
988 seqTextFrames
.realloc( nCount
);
989 const SvxMSDffTextRectangles
* pRectangles
= pDefCustomShape
->pTextRect
;
990 for ( i
= 0; i
< nCount
; i
++, pRectangles
++ )
992 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames
[ i
].TopLeft
.First
, pRectangles
->nPairA
.nValA
);
993 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames
[ i
].TopLeft
.Second
, pRectangles
->nPairA
.nValB
);
994 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames
[ i
].BottomRight
.First
, pRectangles
->nPairB
.nValA
);
995 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames
[ i
].BottomRight
.Second
, pRectangles
->nPairB
.nValB
);
997 aPropVal
.Name
= sTextFrames
;
998 aPropVal
.Value
<<= seqTextFrames
;
999 aGeometryItem
.SetPropertyValue( sPath
, aPropVal
);
1003 const OUString
sEquations( "Equations" );
1004 pAny
= aGeometryItem
.GetPropertyValueByName( sEquations
);
1005 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nCalculation
&& pDefCustomShape
->pCalculation
)
1007 css::uno::Sequence
< OUString
> seqEquations
;
1009 sal_Int32 i
, nCount
= pDefCustomShape
->nCalculation
;
1010 seqEquations
.realloc( nCount
);
1011 const SvxMSDffCalculationData
* pData
= pDefCustomShape
->pCalculation
;
1012 for ( i
= 0; i
< nCount
; i
++, pData
++ )
1013 seqEquations
[ i
] = EnhancedCustomShape2d::GetEquation( pData
->nFlags
, pData
->nVal
[ 0 ], pData
->nVal
[ 1 ], pData
->nVal
[ 2 ] );
1014 aPropVal
.Name
= sEquations
;
1015 aPropVal
.Value
<<= seqEquations
;
1016 aGeometryItem
.SetPropertyValue( aPropVal
);
1020 const OUString
sHandles( "Handles" );
1021 pAny
= aGeometryItem
.GetPropertyValueByName( sHandles
);
1022 if ( !pAny
&& pDefCustomShape
&& pDefCustomShape
->nHandles
&& pDefCustomShape
->pHandles
)
1024 css::uno::Sequence
< css::beans::PropertyValues
> seqHandles
;
1026 sal_Int32 i
, nCount
= pDefCustomShape
->nHandles
;
1027 const SvxMSDffHandle
* pData
= pDefCustomShape
->pHandles
;
1028 seqHandles
.realloc( nCount
);
1029 for ( i
= 0; i
< nCount
; i
++, pData
++ )
1031 sal_Int32 nPropertiesNeeded
;
1032 css::beans::PropertyValues
& rPropValues
= seqHandles
[ i
];
1033 nPropertiesNeeded
= GetNumberOfProperties( pData
);
1034 rPropValues
.realloc( nPropertiesNeeded
);
1035 lcl_ShapePropertiesFromDFF( pData
, rPropValues
);
1037 aPropVal
.Name
= sHandles
;
1038 aPropVal
.Value
<<= seqHandles
;
1039 aGeometryItem
.SetPropertyValue( aPropVal
);
1041 else if (pAny
&& sShapeType
.startsWith("ooxml-") && sShapeType
!= "ooxml-non-primitive")
1043 // ODF is not able to store the ooxml way of connecting handle to an adjustment
1044 // value by name, e.g. attribute RefX="adj". So the information is lost, when exporting
1045 // a pptx to odp, for example. This part reconstructs this information for the
1046 // ooxml preset shapes from their definition.
1047 css::uno::Sequence
<css::beans::PropertyValues
> seqHandles
;
1048 *pAny
>>= seqHandles
;
1049 bool bChanged(false);
1050 for (sal_Int32 i
= 0; i
< seqHandles
.getLength(); i
++)
1052 comphelper::SequenceAsHashMap
aHandleProps(seqHandles
[i
]);
1053 OUString sFirstRefType
;
1054 sal_Int32 nFirstAdjRef
;
1055 OUString sSecondRefType
;
1056 sal_Int32 nSecondAdjRef
;
1057 PresetOOXHandleAdj::GetOOXHandleAdjRelation(sShapeType
, i
, sFirstRefType
, nFirstAdjRef
,
1058 sSecondRefType
, nSecondAdjRef
);
1059 if (sFirstRefType
!= "na" && 0 <= nFirstAdjRef
1060 && nFirstAdjRef
< seqAdjustmentValues
.getLength())
1062 bChanged
|= aHandleProps
.createItemIfMissing(sFirstRefType
, nFirstAdjRef
);
1064 if (sSecondRefType
!= "na" && 0 <= nSecondAdjRef
1065 && nSecondAdjRef
< seqAdjustmentValues
.getLength())
1067 bChanged
|= aHandleProps
.createItemIfMissing(sSecondRefType
, nSecondAdjRef
);
1069 aHandleProps
>> seqHandles
[i
];
1073 aPropVal
.Name
= sHandles
;
1074 aPropVal
.Value
<<= seqHandles
;
1075 aGeometryItem
.SetPropertyValue(aPropVal
);
1079 SetMergedItem( aGeometryItem
);
1082 bool SdrObjCustomShape::IsDefaultGeometry( const DefaultType eDefaultType
) const
1084 bool bIsDefaultGeometry
= false;
1086 OUString sShapeType
;
1087 const SdrCustomShapeGeometryItem
aGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
1089 const Any
*pAny
= aGeometryItem
.GetPropertyValueByName( "Type" );
1091 *pAny
>>= sShapeType
;
1093 MSO_SPT eSpType
= EnhancedCustomShapeTypeNames::Get( sShapeType
);
1095 const mso_CustomShape
* pDefCustomShape
= GetCustomShapeContent( eSpType
);
1096 const OUString
sPath( "Path" );
1097 switch( eDefaultType
)
1099 case DefaultType::Viewbox
:
1101 const Any
* pViewBox
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( "ViewBox" );
1102 css::awt::Rectangle aViewBox
;
1103 if (pViewBox
&& (*pViewBox
>>= aViewBox
) && pDefCustomShape
)
1105 if ( ( aViewBox
.Width
== pDefCustomShape
->nCoordWidth
)
1106 && ( aViewBox
.Height
== pDefCustomShape
->nCoordHeight
) )
1107 bIsDefaultGeometry
= true;
1112 case DefaultType::Path
:
1114 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "Coordinates" );
1115 if ( pAny
&& pDefCustomShape
&& pDefCustomShape
->nVertices
&& pDefCustomShape
->pVertices
)
1117 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> seqCoordinates1
, seqCoordinates2
;
1118 if ( *pAny
>>= seqCoordinates1
)
1120 sal_Int32 i
, nCount
= pDefCustomShape
->nVertices
;
1121 seqCoordinates2
.realloc( nCount
);
1122 for ( i
= 0; i
< nCount
; i
++ )
1124 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2
[ i
].First
, pDefCustomShape
->pVertices
[ i
].nValA
);
1125 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2
[ i
].Second
, pDefCustomShape
->pVertices
[ i
].nValB
);
1127 if ( seqCoordinates1
== seqCoordinates2
)
1128 bIsDefaultGeometry
= true;
1131 else if ( pDefCustomShape
&& ( ( pDefCustomShape
->nVertices
== 0 ) || ( pDefCustomShape
->pVertices
== nullptr ) ) )
1132 bIsDefaultGeometry
= true;
1136 case DefaultType::Gluepoints
:
1138 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "GluePoints" );
1139 if ( pAny
&& pDefCustomShape
&& pDefCustomShape
->nGluePoints
&& pDefCustomShape
->pGluePoints
)
1141 css::uno::Sequence
< css::drawing::EnhancedCustomShapeParameterPair
> seqGluePoints1
, seqGluePoints2
;
1142 if ( *pAny
>>= seqGluePoints1
)
1144 sal_Int32 i
, nCount
= pDefCustomShape
->nGluePoints
;
1145 seqGluePoints2
.realloc( nCount
);
1146 for ( i
= 0; i
< nCount
; i
++ )
1148 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints2
[ i
].First
, pDefCustomShape
->pGluePoints
[ i
].nValA
);
1149 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints2
[ i
].Second
, pDefCustomShape
->pGluePoints
[ i
].nValB
);
1151 if ( seqGluePoints1
== seqGluePoints2
)
1152 bIsDefaultGeometry
= true;
1155 else if ( pDefCustomShape
&& ( pDefCustomShape
->nGluePoints
== 0 ) )
1156 bIsDefaultGeometry
= true;
1160 case DefaultType::Segments
:
1163 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "Segments" );
1166 css::uno::Sequence
< css::drawing::EnhancedCustomShapeSegment
> seqSegments1
, seqSegments2
;
1167 if ( *pAny
>>= seqSegments1
)
1169 if ( pDefCustomShape
&& pDefCustomShape
->nElements
&& pDefCustomShape
->pElements
)
1171 sal_Int32 i
, nCount
= pDefCustomShape
->nElements
;
1174 seqSegments2
.realloc( nCount
);
1175 for ( i
= 0; i
< nCount
; i
++ )
1177 EnhancedCustomShapeSegment
& rSegInfo
= seqSegments2
[ i
];
1178 sal_uInt16 nSDat
= pDefCustomShape
->pElements
[ i
];
1179 lcl_ShapeSegmentFromBinary( rSegInfo
, nSDat
);
1181 if ( seqSegments1
== seqSegments2
)
1182 bIsDefaultGeometry
= true;
1187 // check if it's the default segment description ( M L Z N )
1188 if ( seqSegments1
.getLength() == 4 )
1190 if ( ( seqSegments1
[ 0 ].Command
== EnhancedCustomShapeSegmentCommand::MOVETO
)
1191 && ( seqSegments1
[ 1 ].Command
== EnhancedCustomShapeSegmentCommand::LINETO
)
1192 && ( seqSegments1
[ 2 ].Command
== EnhancedCustomShapeSegmentCommand::CLOSESUBPATH
)
1193 && ( seqSegments1
[ 3 ].Command
== EnhancedCustomShapeSegmentCommand::ENDSUBPATH
) )
1194 bIsDefaultGeometry
= true;
1199 else if ( pDefCustomShape
&& ( ( pDefCustomShape
->nElements
== 0 ) || ( pDefCustomShape
->pElements
== nullptr ) ) )
1200 bIsDefaultGeometry
= true;
1204 case DefaultType::StretchX
:
1206 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "StretchX" );
1207 if ( pAny
&& pDefCustomShape
)
1209 sal_Int32 nStretchX
= 0;
1210 if ( *pAny
>>= nStretchX
)
1212 if ( pDefCustomShape
->nXRef
== nStretchX
)
1213 bIsDefaultGeometry
= true;
1216 else if ( pDefCustomShape
&& ( pDefCustomShape
->nXRef
== DEFAULT_MINIMUM_SIGNED_COMPARE
) )
1217 bIsDefaultGeometry
= true;
1221 case DefaultType::StretchY
:
1223 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "StretchY" );
1224 if ( pAny
&& pDefCustomShape
)
1226 sal_Int32 nStretchY
= 0;
1227 if ( *pAny
>>= nStretchY
)
1229 if ( pDefCustomShape
->nYRef
== nStretchY
)
1230 bIsDefaultGeometry
= true;
1233 else if ( pDefCustomShape
&& ( pDefCustomShape
->nYRef
== DEFAULT_MINIMUM_SIGNED_COMPARE
) )
1234 bIsDefaultGeometry
= true;
1238 case DefaultType::Equations
:
1240 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( "Equations" );
1241 if ( pAny
&& pDefCustomShape
&& pDefCustomShape
->nCalculation
&& pDefCustomShape
->pCalculation
)
1243 css::uno::Sequence
< OUString
> seqEquations1
, seqEquations2
;
1244 if ( *pAny
>>= seqEquations1
)
1246 sal_Int32 i
, nCount
= pDefCustomShape
->nCalculation
;
1247 seqEquations2
.realloc( nCount
);
1249 const SvxMSDffCalculationData
* pData
= pDefCustomShape
->pCalculation
;
1250 for ( i
= 0; i
< nCount
; i
++, pData
++ )
1251 seqEquations2
[ i
] = EnhancedCustomShape2d::GetEquation( pData
->nFlags
, pData
->nVal
[ 0 ], pData
->nVal
[ 1 ], pData
->nVal
[ 2 ] );
1253 if ( seqEquations1
== seqEquations2
)
1254 bIsDefaultGeometry
= true;
1257 else if ( pDefCustomShape
&& ( ( pDefCustomShape
->nCalculation
== 0 ) || ( pDefCustomShape
->pCalculation
== nullptr ) ) )
1258 bIsDefaultGeometry
= true;
1262 case DefaultType::TextFrames
:
1264 pAny
= const_cast<SdrCustomShapeGeometryItem
&>(aGeometryItem
).GetPropertyValueByName( sPath
, "TextFrames" );
1265 if ( pAny
&& pDefCustomShape
&& pDefCustomShape
->nTextRect
&& pDefCustomShape
->pTextRect
)
1267 css::uno::Sequence
< css::drawing::EnhancedCustomShapeTextFrame
> seqTextFrames1
, seqTextFrames2
;
1268 if ( *pAny
>>= seqTextFrames1
)
1270 sal_Int32 i
, nCount
= pDefCustomShape
->nTextRect
;
1271 seqTextFrames2
.realloc( nCount
);
1272 const SvxMSDffTextRectangles
* pRectangles
= pDefCustomShape
->pTextRect
;
1273 for ( i
= 0; i
< nCount
; i
++, pRectangles
++ )
1275 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2
[ i
].TopLeft
.First
, pRectangles
->nPairA
.nValA
);
1276 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2
[ i
].TopLeft
.Second
, pRectangles
->nPairA
.nValB
);
1277 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2
[ i
].BottomRight
.First
, pRectangles
->nPairB
.nValA
);
1278 EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2
[ i
].BottomRight
.Second
, pRectangles
->nPairB
.nValB
);
1280 if ( seqTextFrames1
== seqTextFrames2
)
1281 bIsDefaultGeometry
= true;
1284 else if ( pDefCustomShape
&& ( ( pDefCustomShape
->nTextRect
== 0 ) || ( pDefCustomShape
->pTextRect
== nullptr ) ) )
1285 bIsDefaultGeometry
= true;
1289 return bIsDefaultGeometry
;
1292 void SdrObjCustomShape::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
1294 rInfo
.bResizeFreeAllowed
=fObjectRotation
== 0.0;
1295 rInfo
.bResizePropAllowed
=true;
1296 rInfo
.bRotateFreeAllowed
=true;
1297 rInfo
.bRotate90Allowed
=true;
1298 rInfo
.bMirrorFreeAllowed
=true;
1299 rInfo
.bMirror45Allowed
=true;
1300 rInfo
.bMirror90Allowed
=true;
1301 rInfo
.bTransparenceAllowed
= false;
1302 rInfo
.bShearAllowed
=true;
1303 rInfo
.bEdgeRadiusAllowed
=false;
1304 rInfo
.bNoContortion
=true;
1307 if ( !mXRenderedCustomShape
.is() )
1310 const SdrObject
* pRenderedCustomShape
= GetSdrObjectFromXShape( mXRenderedCustomShape
);
1311 if ( !pRenderedCustomShape
)
1315 // Iterate self over the contained objects, since there are combinations of
1316 // polygon and curve objects. In that case, aInfo.bCanConvToPath and
1317 // aInfo.bCanConvToPoly would be false. What is needed here is an or, not an and.
1318 SdrObjListIter
aIterator(*pRenderedCustomShape
);
1319 while(aIterator
.IsMore())
1321 SdrObject
* pCandidate
= aIterator
.Next();
1322 SdrObjTransformInfoRec aInfo
;
1323 pCandidate
->TakeObjInfo(aInfo
);
1325 // set path and poly conversion if one is possible since
1326 // this object will first be broken
1327 const bool bCanConvToPathOrPoly(aInfo
.bCanConvToPath
|| aInfo
.bCanConvToPoly
);
1328 if(rInfo
.bCanConvToPath
!= bCanConvToPathOrPoly
)
1330 rInfo
.bCanConvToPath
= bCanConvToPathOrPoly
;
1333 if(rInfo
.bCanConvToPoly
!= bCanConvToPathOrPoly
)
1335 rInfo
.bCanConvToPoly
= bCanConvToPathOrPoly
;
1338 if(rInfo
.bCanConvToContour
!= aInfo
.bCanConvToContour
)
1340 rInfo
.bCanConvToContour
= aInfo
.bCanConvToContour
;
1343 if(rInfo
.bShearAllowed
!= aInfo
.bShearAllowed
)
1345 rInfo
.bShearAllowed
= aInfo
.bShearAllowed
;
1350 SdrObjKind
SdrObjCustomShape::GetObjIdentifier() const
1352 return OBJ_CUSTOMSHAPE
;
1355 // #115391# This implementation is based on the TextFrame size of the CustomShape and the
1356 // state of the ResizeShapeToFitText flag to correctly set TextMinFrameWidth/Height
1357 void SdrObjCustomShape::AdaptTextMinSize()
1359 if (getSdrModelFromSdrObject().IsCreatingDataObj() || getSdrModelFromSdrObject().IsPasteResize())
1362 const bool bResizeShapeToFitText(GetObjectItem(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue());
1364 *GetObjectItemSet().GetPool(),
1365 svl::Items
<SDRATTR_TEXT_MINFRAMEHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
1366 SDRATTR_TEXT_MINFRAMEWIDTH
, SDRATTR_TEXT_AUTOGROWWIDTH
>{}); // contains SDRATTR_TEXT_MAXFRAMEWIDTH
1367 bool bChanged(false);
1369 if(bResizeShapeToFitText
)
1371 // always reset MinWidthHeight to zero to only rely on text size and frame size
1372 // to allow resizing being completely dependent on text size only
1373 aSet
.Put(makeSdrTextMinFrameWidthItem(0));
1374 aSet
.Put(makeSdrTextMinFrameHeightItem(0));
1379 // recreate from CustomShape-specific TextBounds
1380 tools::Rectangle
aTextBound(maRect
);
1382 if(GetTextBounds(aTextBound
))
1384 const tools::Long
nHDist(GetTextLeftDistance() + GetTextRightDistance());
1385 const tools::Long
nVDist(GetTextUpperDistance() + GetTextLowerDistance());
1386 const tools::Long
nTWdt(std::max(tools::Long(0), static_cast<tools::Long
>(aTextBound
.GetWidth() - 1 - nHDist
)));
1387 const tools::Long
nTHgt(std::max(tools::Long(0), static_cast<tools::Long
>(aTextBound
.GetHeight() - 1 - nVDist
)));
1389 aSet
.Put(makeSdrTextMinFrameWidthItem(nTWdt
));
1390 aSet
.Put(makeSdrTextMinFrameHeightItem(nTHgt
));
1396 SetObjectItemSet(aSet
);
1399 void SdrObjCustomShape::NbcSetSnapRect( const tools::Rectangle
& rRect
)
1402 ImpJustifyRect(maRect
);
1403 InvalidateRenderGeometry();
1412 void SdrObjCustomShape::SetSnapRect( const tools::Rectangle
& rRect
)
1414 tools::Rectangle aBoundRect0
;
1416 aBoundRect0
= GetLastBoundRect();
1417 NbcSetSnapRect( rRect
);
1418 BroadcastObjectChange();
1419 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
1422 void SdrObjCustomShape::NbcSetLogicRect( const tools::Rectangle
& rRect
)
1425 ImpJustifyRect(maRect
);
1426 InvalidateRenderGeometry();
1434 void SdrObjCustomShape::SetLogicRect( const tools::Rectangle
& rRect
)
1436 tools::Rectangle aBoundRect0
;
1438 aBoundRect0
= GetLastBoundRect();
1439 NbcSetLogicRect(rRect
);
1440 BroadcastObjectChange();
1441 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
1444 void SdrObjCustomShape::Move( const Size
& rSiz
)
1446 if ( rSiz
.Width() || rSiz
.Height() )
1448 tools::Rectangle aBoundRect0
;
1450 aBoundRect0
= GetLastBoundRect();
1453 BroadcastObjectChange();
1454 SendUserCall(SdrUserCallType::MoveOnly
,aBoundRect0
);
1457 void SdrObjCustomShape::NbcMove( const Size
& rSiz
)
1459 SdrTextObj::NbcMove( rSiz
);
1460 if ( mXRenderedCustomShape
.is() )
1462 SdrObject
* pRenderedCustomShape
= GetSdrObjectFromXShape( mXRenderedCustomShape
);
1463 if ( pRenderedCustomShape
)
1465 // #i97149# the visualisation shape needs to be informed
1466 // about change, too
1467 pRenderedCustomShape
->ActionChanged();
1468 pRenderedCustomShape
->NbcMove( rSiz
);
1472 // #i37011# adapt geometry shadow
1473 if(mpLastShadowGeometry
)
1475 mpLastShadowGeometry
->NbcMove( rSiz
);
1479 void SdrObjCustomShape::NbcResize( const Point
& rRef
, const Fraction
& rxFact
, const Fraction
& ryFact
)
1481 // taking care of handles that should not been changed
1482 tools::Rectangle
aOld( maRect
);
1483 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
1485 SdrTextObj::NbcResize( rRef
, rxFact
, ryFact
);
1487 if ( ( rxFact
.GetNumerator() != rxFact
.GetDenominator() )
1488 || ( ryFact
.GetNumerator()!= ryFact
.GetDenominator() ) )
1490 if ( ( ( rxFact
.GetNumerator() < 0 ) && ( rxFact
.GetDenominator() > 0 ) ) ||
1491 ( ( rxFact
.GetNumerator() > 0 ) && ( rxFact
.GetDenominator() < 0 ) ) )
1493 SetMirroredX( !IsMirroredX() );
1495 if ( ( ( ryFact
.GetNumerator() < 0 ) && ( ryFact
.GetDenominator() > 0 ) ) ||
1496 ( ( ryFact
.GetNumerator() > 0 ) && ( ryFact
.GetDenominator() < 0 ) ) )
1498 SetMirroredY( !IsMirroredY() );
1502 for (const auto& rInteraction
: aInteractionHandles
)
1506 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
1507 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
1508 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_X
)
1510 sal_Int32 nX
= ( rInteraction
.aPosition
.X
- aOld
.Left() ) + maRect
.Left();
1511 rInteraction
.xInteraction
->setControllerPosition( css::awt::Point( nX
, rInteraction
.xInteraction
->getPosition().Y
) );
1513 else if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
1515 sal_Int32 nX
= maRect
.Right() - (aOld
.Right() - rInteraction
.aPosition
.X
);
1516 rInteraction
.xInteraction
->setControllerPosition( css::awt::Point( nX
, rInteraction
.xInteraction
->getPosition().Y
) );
1518 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
)
1520 sal_Int32 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Top() ) + maRect
.Top();
1521 rInteraction
.xInteraction
->setControllerPosition( css::awt::Point( rInteraction
.xInteraction
->getPosition().X
, nY
) );
1524 catch ( const uno::RuntimeException
& )
1529 // updating fObjectRotation
1530 tools::Long nTextObjRotation
= aGeo
.nRotationAngle
;
1531 double fAngle
= nTextObjRotation
;
1536 fObjectRotation
= fAngle
- 180.0;
1538 fObjectRotation
= -fAngle
;
1543 fObjectRotation
= 180.0 - fAngle
;
1545 fObjectRotation
= fAngle
;
1547 while (fObjectRotation
< 0)
1548 fObjectRotation
+= 360.0;
1549 while (fObjectRotation
>= 360.0)
1550 fObjectRotation
-= 360.0;
1552 InvalidateRenderGeometry();
1555 void SdrObjCustomShape::NbcRotate( const Point
& rRef
, tools::Long nAngle
, double sn
, double cs
)
1557 bool bMirroredX
= IsMirroredX();
1558 bool bMirroredY
= IsMirroredY();
1560 fObjectRotation
= fmod( fObjectRotation
, 360.0 );
1561 if ( fObjectRotation
< 0 )
1562 fObjectRotation
= 360 + fObjectRotation
;
1564 // the rotation angle for ashapes is stored in fObjectRotation, this rotation
1565 // has to be applied to the text object (which is internally using aGeo.nAngle).
1566 SdrTextObj::NbcRotate( maRect
.TopLeft(), -aGeo
.nRotationAngle
, // retrieving the unrotated text object
1567 sin( (-aGeo
.nRotationAngle
) * F_PI18000
),
1568 cos( (-aGeo
.nRotationAngle
) * F_PI18000
) );
1569 aGeo
.nRotationAngle
= 0; // resetting aGeo data
1570 aGeo
.RecalcSinCos();
1572 tools::Long nW
= static_cast<tools::Long
>( fObjectRotation
* 100 ); // applying our object rotation
1580 SdrTextObj::NbcRotate( maRect
.TopLeft(), nW
, // applying text rotation
1581 sin( nW
* F_PI18000
),
1582 cos( nW
* F_PI18000
) );
1590 double fAngle
= nAngle
; // updating to our new object rotation
1592 fObjectRotation
= fmod( nSwap
? fObjectRotation
- fAngle
: fObjectRotation
+ fAngle
, 360.0 );
1593 if ( fObjectRotation
< 0 )
1594 fObjectRotation
= 360 + fObjectRotation
;
1596 SdrTextObj::NbcRotate( rRef
, nAngle
, sn
, cs
); // applying text rotation
1597 InvalidateRenderGeometry();
1600 void SdrObjCustomShape::NbcMirror( const Point
& rRef1
, const Point
& rRef2
)
1602 // TTTT: Fix for old mirroring, can be removed again in aw080
1603 // storing horizontal and vertical flipping without modifying the rotate angle
1604 // decompose other flipping to rotation and MirrorX.
1605 tools::Long ndx
= rRef2
.X()-rRef1
.X();
1606 tools::Long ndy
= rRef2
.Y()-rRef1
.Y();
1608 if(!ndx
) // MirroredX
1610 SetMirroredX(!IsMirroredX());
1611 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1615 if(!ndy
) // MirroredY
1617 SetMirroredY(!IsMirroredY());
1618 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1620 else // neither horizontal nor vertical
1622 SetMirroredX(!IsMirroredX());
1625 SdrTextObj::NbcMirror( rRef1
, rRef2
);
1627 // update fObjectRotation
1628 tools::Long nTextObjRotation
= aGeo
.nRotationAngle
;
1629 double fAngle
= nTextObjRotation
;
1633 bool bSingleFlip
= (IsMirroredX()!= IsMirroredY());
1635 fObjectRotation
= fmod( bSingleFlip
? -fAngle
: fAngle
, 360.0 );
1637 if ( fObjectRotation
< 0 )
1639 fObjectRotation
= 360.0 + fObjectRotation
;
1644 InvalidateRenderGeometry();
1647 void SdrObjCustomShape::Shear( const Point
& rRef
, tools::Long nAngle
, double tn
, bool bVShear
)
1649 SdrTextObj::Shear( rRef
, nAngle
, tn
, bVShear
);
1650 InvalidateRenderGeometry();
1652 void SdrObjCustomShape::NbcShear( const Point
& rRef
, tools::Long nAngle
, double tn
, bool bVShear
)
1654 // TTTT: Fix for old mirroring, can be removed again in aw080
1655 SdrTextObj::NbcShear(rRef
,nAngle
,tn
,bVShear
);
1657 // updating fObjectRotation
1658 tools::Long nTextObjRotation
= aGeo
.nRotationAngle
;
1659 double fAngle
= nTextObjRotation
;
1664 fObjectRotation
= fAngle
- 180.0;
1666 fObjectRotation
= -fAngle
;
1671 fObjectRotation
= 180.0 - fAngle
;
1673 fObjectRotation
= fAngle
;
1675 while (fObjectRotation
< 0)
1676 fObjectRotation
+= 360.0;
1677 while (fObjectRotation
>= 360.0)
1678 fObjectRotation
-= 360.0;
1680 InvalidateRenderGeometry();
1683 SdrGluePoint
SdrObjCustomShape::GetVertexGluePoint(sal_uInt16 nPosNum
) const
1685 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
1688 if(!LineIsOutsideGeometry())
1696 case 0: aPt
=maRect
.TopCenter(); aPt
.AdjustY( -nWdt
); break;
1697 case 1: aPt
=maRect
.RightCenter(); aPt
.AdjustX(nWdt
); break;
1698 case 2: aPt
=maRect
.BottomCenter(); aPt
.AdjustY(nWdt
); break;
1699 case 3: aPt
=maRect
.LeftCenter(); aPt
.AdjustX( -nWdt
); break;
1701 if (aGeo
.nShearAngle
!=0) ShearPoint(aPt
,maRect
.TopLeft(),aGeo
.nTan
);
1702 if (aGeo
.nRotationAngle
!=0) RotatePoint(aPt
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
1703 aPt
-=GetSnapRect().Center();
1704 SdrGluePoint
aGP(aPt
);
1705 aGP
.SetPercent(false);
1711 void SdrObjCustomShape::ImpCheckCustomGluePointsAreAdded()
1713 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
1718 const SdrGluePointList
* pSource
= pSdrObject
->GetGluePointList();
1720 if(!(pSource
&& pSource
->GetCount()))
1723 if(!SdrTextObj::GetGluePointList())
1725 SdrTextObj::ForceGluePointList();
1728 const SdrGluePointList
* pList
= SdrTextObj::GetGluePointList();
1733 SdrGluePointList aNewList
;
1736 for(a
= 0; a
< pSource
->GetCount(); a
++)
1738 SdrGluePoint
aCopy((*pSource
)[a
]);
1739 aCopy
.SetUserDefined(false);
1740 aNewList
.Insert(aCopy
);
1743 bool bMirroredX
= IsMirroredX();
1744 bool bMirroredY
= IsMirroredY();
1746 tools::Long nShearAngle
= aGeo
.nShearAngle
;
1747 double fTan
= aGeo
.nTan
;
1749 if ( aGeo
.nRotationAngle
|| nShearAngle
|| bMirroredX
|| bMirroredY
)
1751 tools::Polygon
aPoly( maRect
);
1754 sal_uInt16 nPointCount
=aPoly
.GetSize();
1755 for (sal_uInt16 i
=0; i
<nPointCount
; i
++)
1756 ShearPoint(aPoly
[i
],maRect
.Center(), fTan
);
1758 if ( aGeo
.nRotationAngle
)
1759 aPoly
.Rotate( maRect
.Center(), Degree10(aGeo
.nRotationAngle
/ 10) );
1761 tools::Rectangle
aBoundRect( aPoly
.GetBoundRect() );
1762 sal_Int32 nXDiff
= aBoundRect
.Left() - maRect
.Left();
1763 sal_Int32 nYDiff
= aBoundRect
.Top() - maRect
.Top();
1765 if (nShearAngle
&& bMirroredX
!= bMirroredY
)
1767 nShearAngle
= -nShearAngle
;
1771 Point
aRef( maRect
.GetWidth() / 2, maRect
.GetHeight() / 2 );
1772 for ( a
= 0; a
< aNewList
.GetCount(); a
++ )
1774 SdrGluePoint
& rPoint
= aNewList
[ a
];
1775 Point
aGlue( rPoint
.GetPos() );
1777 ShearPoint( aGlue
, aRef
, fTan
);
1779 RotatePoint(aGlue
, aRef
, sin(basegfx::deg2rad(fObjectRotation
)),
1780 cos(basegfx::deg2rad(fObjectRotation
)));
1782 aGlue
.setX( maRect
.GetWidth() - aGlue
.X() );
1784 aGlue
.setY( maRect
.GetHeight() - aGlue
.Y() );
1785 aGlue
.AdjustX( -nXDiff
);
1786 aGlue
.AdjustY( -nYDiff
);
1787 rPoint
.SetPos( aGlue
);
1791 for(a
= 0; a
< pList
->GetCount(); a
++)
1793 const SdrGluePoint
& rCandidate
= (*pList
)[a
];
1795 if(rCandidate
.IsUserDefined())
1797 aNewList
.Insert(rCandidate
);
1801 // copy new list to local. This is NOT very convenient behavior, the local
1802 // GluePointList should not be set, but we delivered by using GetGluePointList(),
1803 // maybe on demand. Since the local object is changed here, this is assumed to
1804 // be a result of GetGluePointList and thus the list is copied
1807 pPlusData
->SetGluePoints(aNewList
);
1812 const SdrGluePointList
* SdrObjCustomShape::GetGluePointList() const
1814 const_cast<SdrObjCustomShape
*>(this)->ImpCheckCustomGluePointsAreAdded();
1815 return SdrTextObj::GetGluePointList();
1819 SdrGluePointList
* SdrObjCustomShape::ForceGluePointList()
1821 if(SdrTextObj::ForceGluePointList())
1823 ImpCheckCustomGluePointsAreAdded();
1824 return SdrTextObj::ForceGluePointList();
1833 sal_uInt32
SdrObjCustomShape::GetHdlCount() const
1835 const sal_uInt32
nBasicHdlCount(SdrTextObj::GetHdlCount());
1836 return ( GetInteractionHandles().size() + nBasicHdlCount
);
1839 void SdrObjCustomShape::AddToHdlList(SdrHdlList
& rHdlList
) const
1841 SdrTextObj::AddToHdlList(rHdlList
);
1843 int nCustomShapeHdlNum
= 0;
1844 for (SdrCustomShapeInteraction
const & rInteraction
: GetInteractionHandles())
1846 if ( rInteraction
.xInteraction
.is() )
1850 css::awt::Point
aPosition( rInteraction
.xInteraction
->getPosition() );
1851 std::unique_ptr
<SdrHdl
> pH(new SdrHdl( Point( aPosition
.X
, aPosition
.Y
), SdrHdlKind::CustomShape1
));
1852 pH
->SetPointNum( nCustomShapeHdlNum
);
1853 pH
->SetObj( const_cast<SdrObjCustomShape
*>(this) );
1854 rHdlList
.AddHdl(std::move(pH
));
1856 catch ( const uno::RuntimeException
& )
1860 ++nCustomShapeHdlNum
;
1864 bool SdrObjCustomShape::hasSpecialDrag() const
1869 bool SdrObjCustomShape::beginSpecialDrag(SdrDragStat
& rDrag
) const
1871 const SdrHdl
* pHdl
= rDrag
.GetHdl();
1873 if(pHdl
&& SdrHdlKind::CustomShape1
== pHdl
->GetKind())
1875 rDrag
.SetEndDragChangesAttributes(true);
1880 const SdrHdl
* pHdl2
= rDrag
.GetHdl();
1881 const SdrHdlKind
eHdl((pHdl2
== nullptr) ? SdrHdlKind::Move
: pHdl2
->GetKind());
1885 case SdrHdlKind::UpperLeft
:
1886 case SdrHdlKind::Upper
:
1887 case SdrHdlKind::UpperRight
:
1888 case SdrHdlKind::Left
:
1889 case SdrHdlKind::Right
:
1890 case SdrHdlKind::LowerLeft
:
1891 case SdrHdlKind::Lower
:
1892 case SdrHdlKind::LowerRight
:
1893 case SdrHdlKind::Move
:
1907 void SdrObjCustomShape::DragResizeCustomShape( const tools::Rectangle
& rNewRect
)
1909 tools::Rectangle
aOld( maRect
);
1910 bool bOldMirroredX( IsMirroredX() );
1911 bool bOldMirroredY( IsMirroredY() );
1913 tools::Rectangle
aNewRect( rNewRect
);
1916 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
1918 GeoStat
aGeoStat( GetGeoStat() );
1919 if ( aNewRect
.TopLeft()!= maRect
.TopLeft() &&
1920 ( aGeo
.nRotationAngle
|| aGeo
.nShearAngle
) )
1922 Point
aNewPos( aNewRect
.TopLeft() );
1923 if ( aGeo
.nShearAngle
) ShearPoint( aNewPos
, aOld
.TopLeft(), aGeoStat
.nTan
);
1924 if ( aGeo
.nRotationAngle
) RotatePoint(aNewPos
, aOld
.TopLeft(), aGeoStat
.nSin
, aGeoStat
.nCos
);
1925 aNewRect
.SetPos( aNewPos
);
1927 if ( aNewRect
== maRect
)
1930 SetLogicRect( aNewRect
);
1931 InvalidateRenderGeometry();
1933 if ( rNewRect
.Left() > rNewRect
.Right() )
1935 Point
aTop( ( GetSnapRect().Left() + GetSnapRect().Right() ) >> 1, GetSnapRect().Top() );
1936 Point
aBottom( aTop
.X(), aTop
.Y() + 1000 );
1937 NbcMirror( aTop
, aBottom
);
1939 if ( rNewRect
.Top() > rNewRect
.Bottom() )
1941 Point
aLeft( GetSnapRect().Left(), ( GetSnapRect().Top() + GetSnapRect().Bottom() ) >> 1 );
1942 Point
aRight( aLeft
.X() + 1000, aLeft
.Y() );
1943 NbcMirror( aLeft
, aRight
);
1946 for (const auto& rInteraction
: aInteractionHandles
)
1950 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
1951 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
1952 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_X
||
1953 rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
1955 if (rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_NEGX
)
1956 bOldMirroredX
= !bOldMirroredX
;
1959 if ( bOldMirroredX
)
1961 nX
= ( rInteraction
.aPosition
.X
- aOld
.Right() );
1962 if ( rNewRect
.Left() > rNewRect
.Right() )
1963 nX
= maRect
.Left() - nX
;
1965 nX
+= maRect
.Right();
1969 nX
= ( rInteraction
.aPosition
.X
- aOld
.Left() );
1970 if ( rNewRect
.Left() > rNewRect
.Right() )
1971 nX
= maRect
.Right() - nX
;
1973 nX
+= maRect
.Left();
1975 rInteraction
.xInteraction
->setControllerPosition( css::awt::Point( nX
, rInteraction
.xInteraction
->getPosition().Y
) );
1977 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_ABSOLUTE_Y
)
1980 if ( bOldMirroredY
)
1982 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Bottom() );
1983 if ( rNewRect
.Top() > rNewRect
.Bottom() )
1984 nY
= maRect
.Top() - nY
;
1986 nY
+= maRect
.Bottom();
1990 nY
= ( rInteraction
.aPosition
.Y
- aOld
.Top() );
1991 if ( rNewRect
.Top() > rNewRect
.Bottom() )
1992 nY
= maRect
.Bottom() - nY
;
1996 rInteraction
.xInteraction
->setControllerPosition( css::awt::Point( rInteraction
.xInteraction
->getPosition().X
, nY
) );
1999 catch ( const uno::RuntimeException
& )
2005 void SdrObjCustomShape::DragMoveCustomShapeHdl( const Point
& rDestination
,
2006 const sal_uInt16 nCustomShapeHdlNum
, bool bMoveCalloutRectangle
)
2008 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2009 if ( nCustomShapeHdlNum
>= aInteractionHandles
.size() )
2012 SdrCustomShapeInteraction
aInteractionHandle( aInteractionHandles
[ nCustomShapeHdlNum
] );
2013 if ( !aInteractionHandle
.xInteraction
.is() )
2018 css::awt::Point
aPt( rDestination
.X(), rDestination
.Y() );
2019 if ( aInteractionHandle
.nMode
& CustomShapeHandleModes::MOVE_SHAPE
&& bMoveCalloutRectangle
)
2021 sal_Int32 nXDiff
= aPt
.X
- aInteractionHandle
.aPosition
.X
;
2022 sal_Int32 nYDiff
= aPt
.Y
- aInteractionHandle
.aPosition
.Y
;
2024 maRect
.Move( nXDiff
, nYDiff
);
2025 aOutRect
.Move( nXDiff
, nYDiff
);
2026 maSnapRect
.Move( nXDiff
, nYDiff
);
2027 SetRectsDirty(true);
2028 InvalidateRenderGeometry();
2030 for (const auto& rInteraction
: aInteractionHandles
)
2032 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2034 if ( rInteraction
.xInteraction
.is() )
2035 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2039 aInteractionHandle
.xInteraction
->setControllerPosition( aPt
);
2041 catch ( const uno::RuntimeException
& )
2046 bool SdrObjCustomShape::applySpecialDrag(SdrDragStat
& rDrag
)
2048 const SdrHdl
* pHdl
= rDrag
.GetHdl();
2049 const SdrHdlKind
eHdl((pHdl
== nullptr) ? SdrHdlKind::Move
: pHdl
->GetKind());
2053 case SdrHdlKind::CustomShape1
:
2055 rDrag
.SetEndDragChangesGeoAndAttributes(true);
2056 DragMoveCustomShapeHdl( rDrag
.GetNow(), static_cast<sal_uInt16
>(pHdl
->GetPointNum()), !rDrag
.GetDragMethod()->IsShiftPressed() );
2058 InvalidateRenderGeometry();
2063 case SdrHdlKind::UpperLeft
:
2064 case SdrHdlKind::Upper
:
2065 case SdrHdlKind::UpperRight
:
2066 case SdrHdlKind::Left
:
2067 case SdrHdlKind::Right
:
2068 case SdrHdlKind::LowerLeft
:
2069 case SdrHdlKind::Lower
:
2070 case SdrHdlKind::LowerRight
:
2072 DragResizeCustomShape( ImpDragCalcRect(rDrag
) );
2075 case SdrHdlKind::Move
:
2077 Move(Size(rDrag
.GetDX(), rDrag
.GetDY()));
2087 void SdrObjCustomShape::DragCreateObject( SdrDragStat
& rStat
)
2089 tools::Rectangle aRect1
;
2090 rStat
.TakeCreateRect( aRect1
);
2092 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2094 constexpr sal_uInt32 nDefaultObjectSizeWidth
= 3000; // default width from SDOptions ?
2095 constexpr sal_uInt32 nDefaultObjectSizeHeight
= 3000;
2097 if ( ImpVerticalSwitch( *this ) )
2099 SetMirroredX( aRect1
.Left() > aRect1
.Right() );
2101 aRect1
= tools::Rectangle( rStat
.GetNow(), Size( nDefaultObjectSizeWidth
, nDefaultObjectSizeHeight
) );
2102 // subtracting the horizontal difference of the latest handle from shape position
2103 if ( !aInteractionHandles
.empty() )
2105 sal_Int32 nHandlePos
= aInteractionHandles
[ aInteractionHandles
.size() - 1 ].xInteraction
->getPosition().X
;
2106 aRect1
.Move( maRect
.Left() - nHandlePos
, 0 );
2109 ImpJustifyRect( aRect1
);
2110 rStat
.SetActionRect( aRect1
);
2114 for (const auto& rInteraction
: aInteractionHandles
)
2118 if ( rInteraction
.nMode
& CustomShapeHandleModes::CREATE_FIXED
)
2119 rInteraction
.xInteraction
->setControllerPosition( awt::Point( rStat
.GetStart().X(), rStat
.GetStart().Y() ) );
2121 catch ( const uno::RuntimeException
& )
2126 SetBoundRectDirty();
2127 bSnapRectDirty
=true;
2130 bool SdrObjCustomShape::MovCreate(SdrDragStat
& rStat
)
2132 SdrView
* pView
= rStat
.GetView(); // #i37448#
2133 if( pView
&& pView
->IsSolidDragging() )
2135 InvalidateRenderGeometry();
2137 DragCreateObject( rStat
);
2142 bool SdrObjCustomShape::EndCreate( SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
2144 DragCreateObject( rStat
);
2149 return ( eCmd
== SdrCreateCmd::ForceEnd
|| rStat
.GetPointCount() >= 2 );
2152 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeCreatePoly(const SdrDragStat
& /*rDrag*/) const
2154 return GetLineGeometry( false );
2158 // in context with the SdrObjCustomShape the SdrTextAutoGrowHeightItem == true -> Resize Shape to fit text,
2159 // the SdrTextAutoGrowWidthItem == true -> Word wrap text in Shape
2160 bool SdrObjCustomShape::IsAutoGrowHeight() const
2162 const SfxItemSet
& rSet
= GetMergedItemSet();
2163 bool bIsAutoGrowHeight
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
2164 if ( bIsAutoGrowHeight
&& IsVerticalWriting() )
2165 bIsAutoGrowHeight
= !rSet
.Get(SDRATTR_TEXT_WORDWRAP
).GetValue();
2166 return bIsAutoGrowHeight
;
2168 bool SdrObjCustomShape::IsAutoGrowWidth() const
2170 const SfxItemSet
& rSet
= GetMergedItemSet();
2171 bool bIsAutoGrowWidth
= rSet
.Get(SDRATTR_TEXT_AUTOGROWHEIGHT
).GetValue();
2172 if ( bIsAutoGrowWidth
&& !IsVerticalWriting() )
2173 bIsAutoGrowWidth
= !rSet
.Get(SDRATTR_TEXT_WORDWRAP
).GetValue();
2174 return bIsAutoGrowWidth
;
2177 /* The following method is identical to the SdrTextObj::SetVerticalWriting method, the only difference
2178 is that the SdrAutoGrowWidthItem and SdrAutoGrowHeightItem are not exchanged if the vertical writing
2179 mode has been changed */
2181 void SdrObjCustomShape::SetVerticalWriting( bool bVertical
)
2183 ForceOutlinerParaObject();
2185 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
2187 DBG_ASSERT( pOutlinerParaObject
, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );
2189 if( !pOutlinerParaObject
||
2190 (pOutlinerParaObject
->IsVertical() == bVertical
) )
2193 // get item settings
2194 const SfxItemSet
& rSet
= GetObjectItemSet();
2196 // Also exchange horizontal and vertical adjust items
2197 SdrTextHorzAdjust eHorz
= rSet
.Get(SDRATTR_TEXT_HORZADJUST
).GetValue();
2198 SdrTextVertAdjust eVert
= rSet
.Get(SDRATTR_TEXT_VERTADJUST
).GetValue();
2200 // rescue object size, SetSnapRect below expects logic rect,
2202 tools::Rectangle aObjectRect
= GetLogicRect();
2204 // prepare ItemSet to set exchanged width and height items
2205 SfxItemSet
aNewSet(*rSet
.GetPool(),
2206 svl::Items
<SDRATTR_TEXT_AUTOGROWHEIGHT
, SDRATTR_TEXT_AUTOGROWHEIGHT
,
2207 // Expanded item ranges to also support horizontal and vertical adjust.
2208 SDRATTR_TEXT_VERTADJUST
, SDRATTR_TEXT_VERTADJUST
,
2209 SDRATTR_TEXT_AUTOGROWWIDTH
, SDRATTR_TEXT_HORZADJUST
>{});
2213 // Exchange horizontal and vertical adjusts
2216 case SDRTEXTVERTADJUST_TOP
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT
)); break;
2217 case SDRTEXTVERTADJUST_CENTER
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER
)); break;
2218 case SDRTEXTVERTADJUST_BOTTOM
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT
)); break;
2219 case SDRTEXTVERTADJUST_BLOCK
: aNewSet
.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK
)); break;
2223 case SDRTEXTHORZADJUST_LEFT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM
)); break;
2224 case SDRTEXTHORZADJUST_CENTER
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER
)); break;
2225 case SDRTEXTHORZADJUST_RIGHT
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP
)); break;
2226 case SDRTEXTHORZADJUST_BLOCK
: aNewSet
.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK
)); break;
2229 pOutlinerParaObject
= GetOutlinerParaObject();
2230 if ( pOutlinerParaObject
)
2231 pOutlinerParaObject
->SetVertical(bVertical
);
2232 SetObjectItemSet( aNewSet
);
2234 // restore object size
2235 SetSnapRect(aObjectRect
);
2238 void SdrObjCustomShape::SuggestTextFrameSize(Size aSuggestedTextFrameSize
)
2240 m_aSuggestedTextFrameSize
= aSuggestedTextFrameSize
;
2243 bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight(tools::Rectangle
& rR
, bool bHgt
, bool bWdt
) const
2245 // Either we have text or the application has native text and suggested its size to us.
2246 bool bHasText
= HasText() || !m_aSuggestedTextFrameSize
.IsEmpty();
2247 if ( bHasText
&& !rR
.IsEmpty() )
2249 bool bWdtGrow
=bWdt
&& IsAutoGrowWidth();
2250 bool bHgtGrow
=bHgt
&& IsAutoGrowHeight();
2251 if ( bWdtGrow
|| bHgtGrow
)
2253 tools::Rectangle
aR0(rR
);
2254 tools::Long nHgt
=0,nMinHgt
=0,nMaxHgt
=0;
2255 tools::Long nWdt
=0,nMinWdt
=0,nMaxWdt
=0;
2256 Size
aSiz(rR
.GetSize()); aSiz
.AdjustWidth( -1 ); aSiz
.AdjustHeight( -1 );
2257 Size
aMaxSiz(100000,100000);
2258 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2259 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
2260 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
2263 nMinWdt
=GetMinTextFrameWidth();
2264 nMaxWdt
=GetMaxTextFrameWidth();
2265 if (nMaxWdt
==0 || nMaxWdt
>aMaxSiz
.Width()) nMaxWdt
=aMaxSiz
.Width();
2266 if (nMinWdt
<=0) nMinWdt
=1;
2267 aSiz
.setWidth(nMaxWdt
);
2271 nMinHgt
=GetMinTextFrameHeight();
2272 nMaxHgt
=GetMaxTextFrameHeight();
2273 if (nMaxHgt
==0 || nMaxHgt
>aMaxSiz
.Height()) nMaxHgt
=aMaxSiz
.Height();
2274 if (nMinHgt
<=0) nMinHgt
=1;
2275 aSiz
.setHeight(nMaxHgt
);
2277 tools::Long nHDist
=GetTextLeftDistance()+GetTextRightDistance();
2278 tools::Long nVDist
=GetTextUpperDistance()+GetTextLowerDistance();
2279 aSiz
.AdjustWidth( -nHDist
);
2280 aSiz
.AdjustHeight( -nVDist
);
2281 if ( aSiz
.Width() < 2 )
2282 aSiz
.setWidth( 2 ); // minimum size=2
2283 if ( aSiz
.Height() < 2 )
2284 aSiz
.setHeight( 2 ); // minimum size=2
2290 pEdtOutl
->SetMaxAutoPaperSize( aSiz
);
2293 Size
aSiz2(pEdtOutl
->CalcTextSize());
2294 nWdt
=aSiz2
.Width()+1; // a little more tolerance
2295 if (bHgtGrow
) nHgt
=aSiz2
.Height()+1; // a little more tolerance
2298 nHgt
=pEdtOutl
->GetTextHeight()+1; // a little more tolerance
2303 Outliner
& rOutliner
=ImpGetDrawOutliner();
2304 rOutliner
.SetPaperSize(aSiz
);
2305 rOutliner
.SetUpdateMode(true);
2306 // TODO: add the optimization with bPortionInfoChecked again.
2307 OutlinerParaObject
* pOutlinerParaObject
= GetOutlinerParaObject();
2308 if( pOutlinerParaObject
!= nullptr )
2310 rOutliner
.SetText(*pOutlinerParaObject
);
2311 rOutliner
.SetFixedCellHeight(GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT
).GetValue());
2315 Size
aSiz2(rOutliner
.CalcTextSize());
2316 nWdt
=aSiz2
.Width()+1; // a little more tolerance
2318 nHgt
=aSiz2
.Height()+1; // a little more tolerance
2321 nHgt
= rOutliner
.GetTextHeight()+1; // a little more tolerance
2327 nHgt
= m_aSuggestedTextFrameSize
.Height();
2328 nWdt
= m_aSuggestedTextFrameSize
.Width();
2330 if ( nWdt
< nMinWdt
)
2332 if ( nWdt
> nMaxWdt
)
2336 nWdt
= 1; // nHDist may also be negative
2337 if ( nHgt
< nMinHgt
)
2339 if ( nHgt
> nMaxHgt
)
2343 nHgt
= 1; // nVDist may also be negative
2344 tools::Long nWdtGrow
= nWdt
-(rR
.Right()-rR
.Left());
2345 tools::Long nHgtGrow
= nHgt
-(rR
.Bottom()-rR
.Top());
2346 if ( nWdtGrow
== 0 )
2348 if ( nHgtGrow
== 0 )
2350 if ( bWdtGrow
|| bHgtGrow
|| !m_aSuggestedTextFrameSize
.IsEmpty())
2352 if ( bWdtGrow
|| m_aSuggestedTextFrameSize
.Width() )
2354 SdrTextHorzAdjust eHAdj
=GetTextHorizontalAdjust();
2355 if (m_aSuggestedTextFrameSize
.Width())
2357 rR
.SetRight(rR
.Left() + m_aSuggestedTextFrameSize
.Width());
2359 else if ( eHAdj
== SDRTEXTHORZADJUST_LEFT
)
2360 rR
.AdjustRight(nWdtGrow
);
2361 else if ( eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
2362 rR
.AdjustLeft( -nWdtGrow
);
2365 tools::Long nWdtGrow2
=nWdtGrow
/2;
2366 rR
.AdjustLeft( -nWdtGrow2
);
2367 rR
.SetRight(rR
.Left()+nWdt
);
2370 if ( bHgtGrow
|| m_aSuggestedTextFrameSize
.Height() )
2372 SdrTextVertAdjust eVAdj
=GetTextVerticalAdjust();
2373 if (m_aSuggestedTextFrameSize
.Height())
2375 rR
.SetBottom(rR
.Top() + m_aSuggestedTextFrameSize
.Height());
2377 else if ( eVAdj
== SDRTEXTVERTADJUST_TOP
)
2378 rR
.AdjustBottom(nHgtGrow
);
2379 else if ( eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
2380 rR
.AdjustTop( -nHgtGrow
);
2383 tools::Long nHgtGrow2
=nHgtGrow
/2;
2384 rR
.AdjustTop( -nHgtGrow2
);
2385 rR
.SetBottom(rR
.Top()+nHgt
);
2388 if ( aGeo
.nRotationAngle
)
2390 Point
aD1(rR
.TopLeft());
2393 RotatePoint(aD2
,Point(),aGeo
.nSin
,aGeo
.nCos
);
2395 rR
.Move(aD2
.X(),aD2
.Y());
2404 tools::Rectangle
SdrObjCustomShape::ImpCalculateTextFrame( const bool bHgt
, const bool bWdt
)
2406 tools::Rectangle aReturnValue
;
2408 tools::Rectangle
aOldTextRect( maRect
); // <- initial text rectangle
2410 tools::Rectangle
aNewTextRect( maRect
); // <- new text rectangle returned from the custom shape renderer,
2411 GetTextBounds( aNewTextRect
); // it depends to the current logical shape size
2413 tools::Rectangle
aAdjustedTextRect( aNewTextRect
); // <- new text rectangle is being tested by AdjustTextFrameWidthAndHeight to ensure
2414 if ( AdjustTextFrameWidthAndHeight( aAdjustedTextRect
, bHgt
, bWdt
) ) // that the new text rectangle is matching the current text size from the outliner
2416 if (aAdjustedTextRect
!= aNewTextRect
&& aOldTextRect
!= aAdjustedTextRect
&&
2417 aNewTextRect
.GetWidth() && aNewTextRect
.GetHeight())
2419 aReturnValue
= maRect
;
2420 double fXScale
= static_cast<double>(aOldTextRect
.GetWidth()) / static_cast<double>(aNewTextRect
.GetWidth());
2421 double fYScale
= static_cast<double>(aOldTextRect
.GetHeight()) / static_cast<double>(aNewTextRect
.GetHeight());
2422 double fRightDiff
= static_cast<double>( aAdjustedTextRect
.Right() - aNewTextRect
.Right() ) * fXScale
;
2423 double fLeftDiff
= static_cast<double>( aAdjustedTextRect
.Left() - aNewTextRect
.Left() ) * fXScale
;
2424 double fTopDiff
= static_cast<double>( aAdjustedTextRect
.Top() - aNewTextRect
.Top() ) * fYScale
;
2425 double fBottomDiff
= static_cast<double>( aAdjustedTextRect
.Bottom()- aNewTextRect
.Bottom()) * fYScale
;
2426 aReturnValue
.AdjustLeft(static_cast<sal_Int32
>(fLeftDiff
) );
2427 aReturnValue
.AdjustRight(static_cast<sal_Int32
>(fRightDiff
) );
2428 aReturnValue
.AdjustTop(static_cast<sal_Int32
>(fTopDiff
) );
2429 aReturnValue
.AdjustBottom(static_cast<sal_Int32
>(fBottomDiff
) );
2432 return aReturnValue
;
2435 bool SdrObjCustomShape::NbcAdjustTextFrameWidthAndHeight(bool bHgt
, bool bWdt
)
2437 tools::Rectangle aNewTextRect
= ImpCalculateTextFrame(bHgt
, bWdt
);
2438 const bool bRet
= !aNewTextRect
.IsEmpty() && aNewTextRect
!= maRect
;
2439 if (bRet
&& !mbAdjustingTextFrameWidthAndHeight
)
2441 mbAdjustingTextFrameWidthAndHeight
= true;
2443 // taking care of handles that should not been changed
2444 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2446 maRect
= aNewTextRect
;
2450 for (const auto& rInteraction
: aInteractionHandles
)
2454 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2455 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2457 catch ( const uno::RuntimeException
& )
2461 InvalidateRenderGeometry();
2463 mbAdjustingTextFrameWidthAndHeight
= false;
2468 bool SdrObjCustomShape::AdjustTextFrameWidthAndHeight()
2470 tools::Rectangle aNewTextRect
= ImpCalculateTextFrame( true/*bHgt*/, true/*bWdt*/ );
2471 bool bRet
= !aNewTextRect
.IsEmpty() && ( aNewTextRect
!= maRect
);
2474 tools::Rectangle aBoundRect0
;
2476 aBoundRect0
= GetCurrentBoundRect();
2478 // taking care of handles that should not been changed
2479 std::vector
< SdrCustomShapeInteraction
> aInteractionHandles( GetInteractionHandles() );
2481 maRect
= aNewTextRect
;
2484 for (const auto& rInteraction
: aInteractionHandles
)
2488 if ( rInteraction
.nMode
& CustomShapeHandleModes::RESIZE_FIXED
)
2489 rInteraction
.xInteraction
->setControllerPosition( rInteraction
.aPosition
);
2491 catch ( const uno::RuntimeException
& )
2496 InvalidateRenderGeometry();
2498 BroadcastObjectChange();
2499 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
2503 void SdrObjCustomShape::TakeTextEditArea(Size
* pPaperMin
, Size
* pPaperMax
, tools::Rectangle
* pViewInit
, tools::Rectangle
* pViewMin
) const
2505 Size aPaperMin
,aPaperMax
;
2506 tools::Rectangle aViewInit
;
2507 TakeTextAnchorRect( aViewInit
);
2508 if ( aGeo
.nRotationAngle
)
2510 Point
aCenter(aViewInit
.Center());
2511 aCenter
-=aViewInit
.TopLeft();
2512 Point
aCenter0(aCenter
);
2513 RotatePoint(aCenter
,Point(),aGeo
.nSin
,aGeo
.nCos
);
2515 aViewInit
.Move(aCenter
.X(),aCenter
.Y());
2517 Size
aAnkSiz(aViewInit
.GetSize());
2518 aAnkSiz
.AdjustWidth( -1 ); aAnkSiz
.AdjustHeight( -1 ); // because GetSize() adds 1
2519 Size
aMaxSiz(1000000,1000000);
2521 Size
aTmpSiz(getSdrModelFromSdrObject().GetMaxObjSize());
2522 if (aTmpSiz
.Width()!=0) aMaxSiz
.setWidth(aTmpSiz
.Width() );
2523 if (aTmpSiz
.Height()!=0) aMaxSiz
.setHeight(aTmpSiz
.Height() );
2525 SdrTextHorzAdjust
eHAdj(GetTextHorizontalAdjust());
2526 SdrTextVertAdjust
eVAdj(GetTextVerticalAdjust());
2528 tools::Long nMinWdt
= GetMinTextFrameWidth();
2529 tools::Long nMinHgt
= GetMinTextFrameHeight();
2530 tools::Long nMaxWdt
= GetMaxTextFrameWidth();
2531 tools::Long nMaxHgt
= GetMaxTextFrameHeight();
2532 if (nMinWdt
<1) nMinWdt
=1;
2533 if (nMinHgt
<1) nMinHgt
=1;
2534 if ( nMaxWdt
== 0 || nMaxWdt
> aMaxSiz
.Width() )
2535 nMaxWdt
= aMaxSiz
.Width();
2536 if ( nMaxHgt
== 0 || nMaxHgt
> aMaxSiz
.Height() )
2537 nMaxHgt
=aMaxSiz
.Height();
2539 if (GetMergedItem(SDRATTR_TEXT_WORDWRAP
).GetValue())
2541 if ( IsVerticalWriting() )
2543 nMaxHgt
= aAnkSiz
.Height();
2548 nMaxWdt
= aAnkSiz
.Width();
2552 aPaperMax
.setWidth(nMaxWdt
);
2553 aPaperMax
.setHeight(nMaxHgt
);
2555 aPaperMin
.setWidth(nMinWdt
);
2556 aPaperMin
.setHeight(nMinHgt
);
2560 *pViewMin
= aViewInit
;
2562 tools::Long nXFree
= aAnkSiz
.Width() - aPaperMin
.Width();
2563 if ( eHAdj
== SDRTEXTHORZADJUST_LEFT
)
2564 pViewMin
->AdjustRight( -nXFree
);
2565 else if ( eHAdj
== SDRTEXTHORZADJUST_RIGHT
)
2566 pViewMin
->AdjustLeft(nXFree
);
2567 else { pViewMin
->AdjustLeft(nXFree
/ 2 ); pViewMin
->SetRight( pViewMin
->Left() + aPaperMin
.Width() ); }
2569 tools::Long nYFree
= aAnkSiz
.Height() - aPaperMin
.Height();
2570 if ( eVAdj
== SDRTEXTVERTADJUST_TOP
)
2571 pViewMin
->AdjustBottom( -nYFree
);
2572 else if ( eVAdj
== SDRTEXTVERTADJUST_BOTTOM
)
2573 pViewMin
->AdjustTop(nYFree
);
2574 else { pViewMin
->AdjustTop(nYFree
/ 2 ); pViewMin
->SetBottom( pViewMin
->Top() + aPaperMin
.Height() ); }
2577 if( IsVerticalWriting() )
2578 aPaperMin
.setWidth( 0 );
2580 aPaperMin
.setHeight( 0 );
2582 if( eHAdj
!= SDRTEXTHORZADJUST_BLOCK
)
2583 aPaperMin
.setWidth(0 );
2585 // For complete vertical adjust support, set paper min height to 0, here.
2586 if(SDRTEXTVERTADJUST_BLOCK
!= eVAdj
)
2587 aPaperMin
.setHeight( 0 );
2589 if (pPaperMin
!=nullptr) *pPaperMin
=aPaperMin
;
2590 if (pPaperMax
!=nullptr) *pPaperMax
=aPaperMax
;
2591 if (pViewInit
!=nullptr) *pViewInit
=aViewInit
;
2593 void SdrObjCustomShape::EndTextEdit( SdrOutliner
& rOutl
)
2595 SdrTextObj::EndTextEdit( rOutl
);
2596 InvalidateRenderGeometry();
2598 void SdrObjCustomShape::TakeTextAnchorRect( tools::Rectangle
& rAnchorRect
) const
2600 if ( GetTextBounds( rAnchorRect
) )
2602 Point
aRotateRef( maSnapRect
.Center() );
2603 rAnchorRect
.AdjustLeft(GetTextLeftDistance() );
2604 rAnchorRect
.AdjustTop(GetTextUpperDistance() );
2605 rAnchorRect
.AdjustRight( -(GetTextRightDistance()) );
2606 rAnchorRect
.AdjustBottom( -(GetTextLowerDistance()) );
2607 ImpJustifyRect( rAnchorRect
);
2609 if ( rAnchorRect
.GetWidth() < 2 )
2610 rAnchorRect
.SetRight( rAnchorRect
.Left() + 1 ); // minimal width is 2
2611 if ( rAnchorRect
.GetHeight() < 2 )
2612 rAnchorRect
.SetBottom( rAnchorRect
.Top() + 1 ); // minimal height is 2
2613 if ( aGeo
.nRotationAngle
)
2615 Point
aP( rAnchorRect
.TopLeft() );
2616 RotatePoint( aP
, aRotateRef
, aGeo
.nSin
, aGeo
. nCos
);
2617 rAnchorRect
.SetPos( aP
);
2621 SdrTextObj::TakeTextAnchorRect( rAnchorRect
);
2623 void SdrObjCustomShape::TakeTextRect( SdrOutliner
& rOutliner
, tools::Rectangle
& rTextRect
, bool bNoEditText
,
2624 tools::Rectangle
* pAnchorRect
, bool /*bLineWidth*/) const
2626 tools::Rectangle aAnkRect
; // Rect in which we anchor
2627 TakeTextAnchorRect(aAnkRect
);
2628 SdrTextVertAdjust eVAdj
=GetTextVerticalAdjust();
2629 SdrTextHorzAdjust eHAdj
=GetTextHorizontalAdjust();
2630 EEControlBits nStat0
=rOutliner
.GetControlWord();
2633 rOutliner
.SetControlWord(nStat0
|EEControlBits::AUTOPAGESIZE
);
2634 rOutliner
.SetMinAutoPaperSize(aNullSize
);
2635 sal_Int32 nMaxAutoPaperWidth
= 1000000;
2636 sal_Int32 nMaxAutoPaperHeight
= 1000000;
2638 tools::Long nAnkWdt
=aAnkRect
.GetWidth();
2639 tools::Long nAnkHgt
=aAnkRect
.GetHeight();
2641 if (GetMergedItem(SDRATTR_TEXT_WORDWRAP
).GetValue())
2643 if ( IsVerticalWriting() )
2644 nMaxAutoPaperHeight
= nAnkHgt
;
2646 nMaxAutoPaperWidth
= nAnkWdt
;
2648 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
&& !IsVerticalWriting())
2650 rOutliner
.SetMinAutoPaperSize(Size(nAnkWdt
, 0));
2653 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
&& IsVerticalWriting())
2655 rOutliner
.SetMinAutoPaperSize(Size(0, nAnkHgt
));
2657 rOutliner
.SetMaxAutoPaperSize( Size( nMaxAutoPaperWidth
, nMaxAutoPaperHeight
) );
2658 rOutliner
.SetPaperSize( aNullSize
);
2660 // put text into the Outliner - if necessary the use the text from the EditOutliner
2661 OutlinerParaObject
* pPara
= GetOutlinerParaObject();
2662 if (pEdtOutl
&& !bNoEditText
)
2663 pPara
=pEdtOutl
->CreateParaObject().release();
2667 bool bHitTest(&getSdrModelFromSdrObject().GetHitTestOutliner() == &rOutliner
);
2668 const SdrTextObj
* pTestObj
= rOutliner
.GetTextObj();
2670 if( !pTestObj
|| !bHitTest
|| pTestObj
!= this ||
2671 pTestObj
->GetOutlinerParaObject() != GetOutlinerParaObject() )
2674 rOutliner
.SetTextObj( this );
2676 rOutliner
.SetUpdateMode(true);
2677 rOutliner
.SetText(*pPara
);
2682 rOutliner
.SetTextObj( nullptr );
2684 if (pEdtOutl
&& !bNoEditText
&& pPara
)
2687 rOutliner
.SetUpdateMode(true);
2688 rOutliner
.SetControlWord(nStat0
);
2690 SdrText
* pText
= getActiveText();
2692 pText
->CheckPortionInfo( rOutliner
);
2694 Point
aTextPos(aAnkRect
.TopLeft());
2695 Size
aTextSiz(rOutliner
.GetPaperSize()); // GetPaperSize() has a little added tolerance, no?
2697 // For draw objects containing text correct horizontal/vertical alignment if text is bigger
2698 // than the object itself. Without that correction, the text would always be
2699 // formatted to the left edge (or top edge when vertical) of the draw object.
2701 if( !IsTextFrame() )
2703 if(aAnkRect
.GetWidth() < aTextSiz
.Width() && !IsVerticalWriting())
2705 // Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
2706 // else the alignment is wanted.
2707 if(SDRTEXTHORZADJUST_BLOCK
== eHAdj
)
2709 SvxAdjust eAdjust
= GetObjectItemSet().Get(EE_PARA_JUST
).GetAdjust();
2712 case SvxAdjust::Left
: eHAdj
= SDRTEXTHORZADJUST_LEFT
; break;
2713 case SvxAdjust::Right
: eHAdj
= SDRTEXTHORZADJUST_RIGHT
; break;
2714 case SvxAdjust::Center
: eHAdj
= SDRTEXTHORZADJUST_CENTER
; break;
2720 if(aAnkRect
.GetHeight() < aTextSiz
.Height() && IsVerticalWriting())
2722 // Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
2723 // else the alignment is wanted.
2724 if(SDRTEXTVERTADJUST_BLOCK
== eVAdj
)
2726 eVAdj
= SDRTEXTVERTADJUST_CENTER
;
2731 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
|| eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
2733 tools::Long nFreeWdt
=aAnkRect
.GetWidth()-aTextSiz
.Width();
2734 if (eHAdj
==SDRTEXTHORZADJUST_CENTER
)
2735 aTextPos
.AdjustX(nFreeWdt
/2 );
2736 if (eHAdj
==SDRTEXTHORZADJUST_RIGHT
)
2737 aTextPos
.AdjustX(nFreeWdt
);
2739 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
|| eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
2741 tools::Long nFreeHgt
=aAnkRect
.GetHeight()-aTextSiz
.Height();
2742 if (eVAdj
==SDRTEXTVERTADJUST_CENTER
)
2743 aTextPos
.AdjustY(nFreeHgt
/2 );
2744 if (eVAdj
==SDRTEXTVERTADJUST_BOTTOM
)
2745 aTextPos
.AdjustY(nFreeHgt
);
2747 if (aGeo
.nRotationAngle
!=0)
2748 RotatePoint(aTextPos
,aAnkRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
2751 *pAnchorRect
=aAnkRect
;
2753 // using rTextRect together with ContourFrame doesn't always work correctly
2754 rTextRect
=tools::Rectangle(aTextPos
,aTextSiz
);
2757 void SdrObjCustomShape::NbcSetOutlinerParaObject(std::unique_ptr
<OutlinerParaObject
> pTextObject
)
2759 SdrTextObj::NbcSetOutlinerParaObject( std::move(pTextObject
) );
2760 SetBoundRectDirty();
2761 SetRectsDirty(true);
2762 InvalidateRenderGeometry();
2765 SdrObjCustomShape
* SdrObjCustomShape::CloneSdrObject(SdrModel
& rTargetModel
) const
2767 return CloneHelper
< SdrObjCustomShape
>(rTargetModel
);
2770 SdrObjCustomShape
& SdrObjCustomShape::operator=(const SdrObjCustomShape
& rObj
)
2774 SdrTextObj::operator=( rObj
);
2775 fObjectRotation
= rObj
.fObjectRotation
;
2776 mbAdjustingTextFrameWidthAndHeight
= rObj
.mbAdjustingTextFrameWidthAndHeight
;
2777 assert(!mbAdjustingTextFrameWidthAndHeight
);
2778 InvalidateRenderGeometry();
2783 OUString
SdrObjCustomShape::TakeObjNameSingul() const
2785 OUStringBuffer
sName(SvxResId(STR_ObjNameSingulCUSTOMSHAPE
));
2786 OUString
aNm(GetName());
2794 return sName
.makeStringAndClear();
2797 OUString
SdrObjCustomShape::TakeObjNamePlural() const
2799 return SvxResId(STR_ObjNamePluralCUSTOMSHAPE
);
2802 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeXorPoly() const
2804 return GetLineGeometry( false );
2807 basegfx::B2DPolyPolygon
SdrObjCustomShape::TakeContour() const
2809 const SdrObject
* pSdrObject
= GetSdrObjectFromCustomShape();
2811 return pSdrObject
->TakeContour();
2812 return basegfx::B2DPolyPolygon();
2815 SdrObjectUniquePtr
SdrObjCustomShape::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
2818 SdrObjectUniquePtr pRetval
;
2819 SdrObject
* pRenderedCustomShape
= nullptr;
2821 if ( !mXRenderedCustomShape
.is() )
2823 // force CustomShape
2824 GetSdrObjectFromCustomShape();
2827 if ( mXRenderedCustomShape
.is() )
2829 pRenderedCustomShape
= GetSdrObjectFromXShape( mXRenderedCustomShape
);
2832 if ( pRenderedCustomShape
)
2834 // Clone to same SdrModel
2835 SdrObject
* pCandidate(pRenderedCustomShape
->CloneSdrObject(pRenderedCustomShape
->getSdrModelFromSdrObject()));
2836 DBG_ASSERT(pCandidate
, "SdrObjCustomShape::DoConvertToPolyObj: Could not clone SdrObject (!)");
2837 pRetval
= pCandidate
->DoConvertToPolyObj(bBezier
, bAddText
);
2838 SdrObject::Free( pCandidate
);
2842 const bool bShadow(GetMergedItem(SDRATTR_SHADOW
).GetValue());
2845 pRetval
->SetMergedItem(makeSdrShadowItem(true));
2849 if(bAddText
&& HasText() && !IsTextPath())
2851 pRetval
= ImpConvertAddText(std::move(pRetval
), bBezier
);
2858 void SdrObjCustomShape::NbcSetStyleSheet( SfxStyleSheet
* pNewStyleSheet
, bool bDontRemoveHardAttr
)
2861 InvalidateRenderGeometry();
2862 SdrObject::NbcSetStyleSheet( pNewStyleSheet
, bDontRemoveHardAttr
);
2865 void SdrObjCustomShape::handlePageChange(SdrPage
* pOldPage
, SdrPage
* pNewPage
)
2868 SdrTextObj::handlePageChange(pOldPage
, pNewPage
);
2870 if(nullptr != pNewPage
)
2872 // invalidating rectangles by SetRectsDirty is not sufficient,
2873 // AdjustTextFrameWidthAndHeight() also has to be made, both
2874 // actions are done by NbcSetSnapRect
2875 tools::Rectangle
aTmp( maRect
); //creating temporary rectangle #i61108#
2876 NbcSetSnapRect( aTmp
);
2880 SdrObjGeoData
* SdrObjCustomShape::NewGeoData() const
2882 return new SdrAShapeObjGeoData
;
2885 void SdrObjCustomShape::SaveGeoData(SdrObjGeoData
& rGeo
) const
2887 SdrTextObj::SaveGeoData( rGeo
);
2888 SdrAShapeObjGeoData
& rAGeo
=static_cast<SdrAShapeObjGeoData
&>(rGeo
);
2889 rAGeo
.fObjectRotation
= fObjectRotation
;
2890 rAGeo
.bMirroredX
= IsMirroredX();
2891 rAGeo
.bMirroredY
= IsMirroredY();
2893 const Any
* pAny
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
).GetPropertyValueByName( "AdjustmentValues" );
2895 *pAny
>>= rAGeo
.aAdjustmentSeq
;
2898 void SdrObjCustomShape::RestGeoData(const SdrObjGeoData
& rGeo
)
2900 SdrTextObj::RestGeoData( rGeo
);
2901 const SdrAShapeObjGeoData
& rAGeo
=static_cast<const SdrAShapeObjGeoData
&>(rGeo
);
2902 fObjectRotation
= rAGeo
.fObjectRotation
;
2903 SetMirroredX( rAGeo
.bMirroredX
);
2904 SetMirroredY( rAGeo
.bMirroredY
);
2906 SdrCustomShapeGeometryItem rGeometryItem
= GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
);
2907 PropertyValue aPropVal
;
2908 aPropVal
.Name
= "AdjustmentValues";
2909 aPropVal
.Value
<<= rAGeo
.aAdjustmentSeq
;
2910 rGeometryItem
.SetPropertyValue( aPropVal
);
2911 SetMergedItem( rGeometryItem
);
2913 InvalidateRenderGeometry();
2916 void SdrObjCustomShape::AdjustToMaxRect(const tools::Rectangle
& rMaxRect
, bool bShrinkOnly
/* = false */)
2918 SAL_INFO_IF(bShrinkOnly
, "svx", "Case bShrinkOnly == true is not implemented yet.");
2920 if (rMaxRect
.IsEmpty() || rMaxRect
== GetSnapRect())
2923 // Get a matrix, that would produce the existing shape, when applied to a unit square
2924 basegfx::B2DPolyPolygon aPolyPolygon
; //not used, but formal needed
2925 basegfx::B2DHomMatrix aMatrix
;
2926 TRGetBaseGeometry(aMatrix
, aPolyPolygon
);
2927 // Using TRSetBaseGeometry(aMatrix, aPolyPolygon) would regenerate the current shape. But
2928 // applying aMatrix to a unit square will not generate the current shape. Scaling,
2929 // rotation and translation are correct, but shear angle has wrong sign. So break up
2930 // matrix and create a mathematically correct new one.
2931 basegfx::B2DTuple aScale
;
2932 basegfx::B2DTuple aTranslate
;
2933 double fRotate
, fShearX
;
2934 aMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2935 basegfx::B2DHomMatrix aMathMatrix
;
2936 aMathMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2938 basegfx::fTools::equalZero(fShearX
) ? 0.0 : -fShearX
,
2939 basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
2942 // Calculate scaling factors from size of the transformed unit polygon as ersatz for the not
2943 // usable current snap rectangle.
2944 basegfx::B2DPolygon
aB2DPolygon(basegfx::utils::createUnitPolygon());
2945 aB2DPolygon
.transform(aMathMatrix
);
2946 basegfx::B2DRange
aB2DRange(aB2DPolygon
.getB2DRange());
2947 double fPolygonWidth
= aB2DRange
.getWidth();
2948 if (fPolygonWidth
== 0)
2950 double fPolygonHeight
= aB2DRange
.getHeight();
2951 if (fPolygonHeight
== 0)
2953 const double aFactorX
= static_cast<double>(rMaxRect
.GetWidth()) / fPolygonWidth
;
2954 const double aFactorY
= static_cast<double>(rMaxRect
.GetHeight()) / fPolygonHeight
;
2956 // Generate matrix, that would produce the desired rMaxRect when applied to unit square
2957 aMathMatrix
.scale(aFactorX
, aFactorY
);
2958 aB2DPolygon
= basegfx::utils::createUnitPolygon();
2959 aB2DPolygon
.transform(aMathMatrix
);
2960 aB2DRange
= aB2DPolygon
.getB2DRange();
2961 const double fPolygonLeft
= aB2DRange
.getMinX();
2962 const double fPolygonTop
= aB2DRange
.getMinY();
2963 aMathMatrix
.translate(rMaxRect
.getX() - fPolygonLeft
, rMaxRect
.getY() - fPolygonTop
);
2965 // Create a Matrix from aMathMatrix, which is usable with TRSetBaseGeometry
2966 aMathMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
2967 aMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
2969 basegfx::fTools::equalZero(fShearX
) ? 0.0 : -fShearX
,
2970 basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
2973 // Now use TRSetBaseGeometry to actually perform scale, shear, rotate and translate
2974 // on the shape. That considers gluepoints, interaction handles and text area, and includes
2975 // setting rectangles dirty and broadcast.
2976 TRSetBaseGeometry(aMatrix
, aPolyPolygon
);
2979 void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& /*rPolyPolygon*/)
2981 // The shape might have already flipping in its enhanced geometry. LibreOffice applies
2982 // such after all transformations. We remove it, but remember it to apply them later.
2983 bool bIsMirroredX
= IsMirroredX();
2984 bool bIsMirroredY
= IsMirroredY();
2985 if (bIsMirroredX
|| bIsMirroredY
)
2987 Point aCurrentCenter
= GetSnapRect().Center();
2988 if (bIsMirroredX
) // mirror on the y-axis
2990 Mirror(aCurrentCenter
, Point(aCurrentCenter
.X(), aCurrentCenter
.Y() + 1000));
2992 if (bIsMirroredY
) // mirror on the x-axis
2994 Mirror(aCurrentCenter
, Point(aCurrentCenter
.X() + 1000, aCurrentCenter
.Y()));
2999 basegfx::B2DTuple aScale
;
3000 basegfx::B2DTuple aTranslate
;
3001 double fRotate
, fShearX
;
3002 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
3004 // reset object shear and rotations
3005 fObjectRotation
= 0.0;
3006 aGeo
.nRotationAngle
= 0;
3007 aGeo
.RecalcSinCos();
3008 aGeo
.nShearAngle
= 0;
3011 // if anchor is used, make position relative to it
3012 if(getSdrModelFromSdrObject().IsWriter())
3014 if(GetAnchorPos().X() || GetAnchorPos().Y())
3016 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3021 Size
aSize(FRound(fabs(aScale
.getX())), FRound(fabs(aScale
.getY())));
3022 // fdo#47434 We need a valid rectangle here
3023 if( !aSize
.Height() ) aSize
.setHeight( 1 );
3024 if( !aSize
.Width() ) aSize
.setWidth( 1 );
3025 tools::Rectangle
aBaseRect(Point(), aSize
);
3026 SetLogicRect(aBaseRect
);
3028 // Apply flipping from Matrix, which is a transformation relative to origin
3029 if (basegfx::fTools::less(aScale
.getX(), 0.0))
3030 Mirror(Point(0, 0), Point(0, 1000)); // mirror on the y-axis
3031 if (basegfx::fTools::less(aScale
.getY(), 0.0))
3032 Mirror(Point(0, 0), Point(1000, 0)); // mirror on the x-axis
3035 if(!basegfx::fTools::equalZero(fShearX
))
3038 // #i123181# The fix for #121932# here was wrong, the trunk version does not correct the
3039 // mirrored shear values, neither at the object level, nor on the API or XML level. Taking
3040 // back the mirroring of the shear angle
3041 aGeoStat
.nShearAngle
= FRound(basegfx::rad2deg(atan(fShearX
)) * 100.0);
3042 aGeoStat
.RecalcTan();
3043 Shear(Point(), aGeoStat
.nShearAngle
, aGeoStat
.nTan
, false);
3047 if(!basegfx::fTools::equalZero(fRotate
))
3052 // fRotate is mathematically correct, but aGeoStat.nRotationAngle is
3053 // mirrored -> mirror value here
3054 aGeoStat
.nRotationAngle
= NormAngle36000(FRound(-fRotate
/ F_PI18000
));
3055 aGeoStat
.RecalcSinCos();
3056 Rotate(Point(), aGeoStat
.nRotationAngle
, aGeoStat
.nSin
, aGeoStat
.nCos
);
3060 if(!aTranslate
.equalZero())
3062 Move(Size(FRound(aTranslate
.getX()), FRound(aTranslate
.getY())));
3065 // Apply flipping from enhanced geometry at center of the shape.
3066 if (!(bIsMirroredX
|| bIsMirroredY
))
3069 // create mathematically matrix for the applied transformations
3070 // aScale was in most cases built from a rectangle including edge
3071 // and is therefore mathematically too large by 1
3072 if (aScale
.getX() > 2.0 && aScale
.getY() > 2.0)
3073 aScale
-= basegfx::B2DTuple(1.0, 1.0);
3074 basegfx::B2DHomMatrix aMathMat
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3075 aScale
, -fShearX
, basegfx::fTools::equalZero(fRotate
) ? 0.0 : fRotate
,
3077 // Use matrix to get current center
3078 basegfx::B2DPoint
aCenter(0.5,0.5);
3079 aCenter
= aMathMat
* aCenter
;
3080 double fCenterX
= aCenter
.getX();
3081 double fCenterY
= aCenter
.getY();
3082 if (bIsMirroredX
) // vertical axis
3083 Mirror(Point(FRound(fCenterX
),FRound(fCenterY
)),
3084 Point(FRound(fCenterX
), FRound(fCenterY
+ 1000.0)));
3085 if (bIsMirroredY
) // horizontal axis
3086 Mirror(Point(FRound(fCenterX
),FRound(fCenterY
)),
3087 Point(FRound(fCenterX
+ 1000.0), FRound(fCenterY
)));
3090 // taking fObjectRotation instead of aGeo.nAngle
3091 bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& /*rPolyPolygon*/) const
3093 // get turn and shear
3094 double fRotate
= basegfx::deg2rad(fObjectRotation
);
3095 double fShearX
= basegfx::deg2rad(aGeo
.nShearAngle
/ 100.0);
3097 // get aRect, this is the unrotated snaprect
3098 tools::Rectangle
aRectangle(maRect
);
3100 bool bMirroredX
= IsMirroredX();
3101 bool bMirroredY
= IsMirroredY();
3102 if ( bMirroredX
|| bMirroredY
)
3103 { // we have to retrieve the unmirrored rect
3105 GeoStat
aNewGeo( aGeo
);
3110 tools::Polygon aPol
= Rect2Poly(maRect
, aNewGeo
);
3111 tools::Rectangle
aBoundRect( aPol
.GetBoundRect() );
3113 Point
aRef1( ( aBoundRect
.Left() + aBoundRect
.Right() ) >> 1, aBoundRect
.Top() );
3114 Point
aRef2( aRef1
.X(), aRef1
.Y() + 1000 );
3116 sal_uInt16 nPointCount
=aPol
.GetSize();
3117 for (i
=0; i
<nPointCount
; i
++)
3119 MirrorPoint(aPol
[i
],aRef1
,aRef2
);
3121 // mirror polygon and move it a bit
3122 tools::Polygon
aPol0(aPol
);
3128 Poly2Rect(aPol
,aRectangle
,aNewGeo
);
3133 tools::Polygon
aPol( Rect2Poly( aRectangle
, aNewGeo
) );
3134 tools::Rectangle
aBoundRect( aPol
.GetBoundRect() );
3136 Point
aRef1( aBoundRect
.Left(), ( aBoundRect
.Top() + aBoundRect
.Bottom() ) >> 1 );
3137 Point
aRef2( aRef1
.X() + 1000, aRef1
.Y() );
3139 sal_uInt16 nPointCount
=aPol
.GetSize();
3140 for (i
=0; i
<nPointCount
; i
++)
3142 MirrorPoint(aPol
[i
],aRef1
,aRef2
);
3144 // mirror polygon and move it a bit
3145 tools::Polygon
aPol0(aPol
);
3146 aPol
[0]=aPol0
[1]; // This was WRONG for vertical (!)
3147 aPol
[1]=aPol0
[0]; // #i121932# Despite my own comment above
3148 aPol
[2]=aPol0
[3]; // it was *not* wrong even when the reordering
3149 aPol
[3]=aPol0
[2]; // *seems* to be specific for X-Mirrorings. Oh
3150 aPol
[4]=aPol0
[1]; // will I be happy when this old stuff is |gone| with aw080 (!)
3151 Poly2Rect(aPol
,aRectangle
,aNewGeo
);
3155 // fill other values
3156 basegfx::B2DTuple
aScale(aRectangle
.GetWidth(), aRectangle
.GetHeight());
3157 basegfx::B2DTuple
aTranslate(aRectangle
.Left(), aRectangle
.Top());
3159 // position may be relative to anchorpos, convert
3160 if(getSdrModelFromSdrObject().IsWriter())
3162 if(GetAnchorPos().X() || GetAnchorPos().Y())
3164 aTranslate
-= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
3169 rMatrix
= basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3171 basegfx::fTools::equalZero(fShearX
) ? 0.0 : tan(fShearX
),
3172 basegfx::fTools::equalZero(fRotate
) ? 0.0 : -fRotate
,
3178 std::unique_ptr
<sdr::contact::ViewContact
> SdrObjCustomShape::CreateObjectSpecificViewContact()
3180 return std::make_unique
<sdr::contact::ViewContactOfSdrObjCustomShape
>(*this);
3184 bool SdrObjCustomShape::doConstructOrthogonal(const OUString
& rName
)
3186 bool bRetval(false);
3188 if(rName
.equalsIgnoreAsciiCase("quadrat"))
3192 else if(rName
.equalsIgnoreAsciiCase("round-quadrat"))
3196 else if(rName
.equalsIgnoreAsciiCase("circle"))
3200 else if(rName
.equalsIgnoreAsciiCase("circle-pie"))
3204 else if(rName
.equalsIgnoreAsciiCase("ring"))
3212 // #i37011# centralize throw-away of render geometry
3213 void SdrObjCustomShape::InvalidateRenderGeometry()
3215 mXRenderedCustomShape
= nullptr;
3216 SdrObject::Free( mpLastShadowGeometry
);
3217 mpLastShadowGeometry
= nullptr;
3220 void SdrObjCustomShape::impl_setUnoShape(const uno::Reference
<uno::XInterface
>& rxUnoShape
)
3222 SdrTextObj::impl_setUnoShape(rxUnoShape
);
3224 // The shape engine is created with _current_ shape. This means we
3225 // _must_ reset it when the shape changes.
3226 mxCustomShapeEngine
.set(nullptr);
3229 OUString
SdrObjCustomShape::GetCustomShapeName() const
3231 OUString sShapeName
;
3232 OUString
aEngine( GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE
).GetValue() );
3233 if ( aEngine
.isEmpty()
3234 || aEngine
== "com.sun.star.drawing.EnhancedCustomShapeEngine" )
3236 OUString sShapeType
;
3237 const SdrCustomShapeGeometryItem
& rGeometryItem( GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY
) );
3238 const Any
* pAny
= rGeometryItem
.GetPropertyValueByName( "Type" );
3239 if ( pAny
&& ( *pAny
>>= sShapeType
) )
3240 sShapeName
= EnhancedCustomShapeTypeNames::GetAccName( sShapeType
);
3245 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */