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 <sal/config.h>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/polygon/b2dpolygon.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/range/b2drange.hxx>
28 #include <basegfx/tuple/b2dtuple.hxx>
29 #include <tools/bigint.hxx>
30 #include <tools/helpers.hxx>
32 #include <svx/dialmgr.hxx>
33 #include <svx/strings.hrc>
35 #include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
36 #include <sdr/properties/captionproperties.hxx>
37 #include <svx/sdrhittesthelper.hxx>
38 #include <svx/sdooitm.hxx>
39 #include <svx/svddrag.hxx>
40 #include <svx/svdhdl.hxx>
41 #include <svx/svdmodel.hxx>
42 #include <svx/svdocapt.hxx>
43 #include <svx/svdopath.hxx>
44 #include <svx/svdogrp.hxx>
45 #include <svx/svdpage.hxx>
46 #include <svx/svdtrans.hxx>
47 #include <svx/svdview.hxx>
48 #include <svx/sxcecitm.hxx>
49 #include <svx/sxcgitm.hxx>
50 #include <svx/sxcllitm.hxx>
51 #include <svx/sxctitm.hxx>
52 #include <vcl/canvastools.hxx>
53 #include <vcl/ptrstyle.hxx>
57 enum EscDir
{LKS
,RTS
,OBN
,UNT
};
69 SdrCaptionEscDir eEscDir
;
76 : eType(SdrCaptionType::Type3
),
77 nGap(0), nEscRel(5000), nEscAbs(0),
78 nLineLen(0), eEscDir(SdrCaptionEscDir::Horizontal
),
79 bFitLineLen(true), bEscRel(true), bFixedAngle(false)
82 void CalcEscPos(const Point
& rTail
, const tools::Rectangle
& rRect
, Point
& rPt
, EscDir
& rDir
) const;
85 void ImpCaptParams::CalcEscPos(const Point
& rTailPt
, const tools::Rectangle
& rRect
, Point
& rPt
, EscDir
& rDir
) const
87 Point
aTl(rTailPt
); // copy locally for performance reasons
90 nX
=rRect
.Right()-rRect
.Left();
91 nX
=BigMulDiv(nX
,nEscRel
,10000);
92 nY
=rRect
.Bottom()-rRect
.Top();
93 nY
=BigMulDiv(nY
,nEscRel
,10000);
102 bool bTryH
=eEscDir
==SdrCaptionEscDir::BestFit
;
104 if (eType
!=SdrCaptionType::Type1
) {
105 bTryH
=eEscDir
==SdrCaptionEscDir::Horizontal
;
107 bTryH
=eEscDir
==SdrCaptionEscDir::Vertical
;
110 bool bTryV
=eEscDir
==SdrCaptionEscDir::BestFit
;
112 if (eType
!=SdrCaptionType::Type1
) {
113 bTryV
=eEscDir
==SdrCaptionEscDir::Vertical
;
115 bTryV
=eEscDir
==SdrCaptionEscDir::Horizontal
;
120 Point
aLft(rRect
.Left()-nGap
,nY
);
121 Point
aRgt(rRect
.Right()+nGap
,nY
);
122 bool bLft
=(aTl
.X()-aLft
.X()<aRgt
.X()-aTl
.X());
132 Point
aTop(nX
,rRect
.Top()-nGap
);
133 Point
aBtm(nX
,rRect
.Bottom()+nGap
);
134 bool bTop
=(aTl
.Y()-aTop
.Y()<aBtm
.Y()-aTl
.Y());
144 bool bTakeIt
=eEscDir
!=SdrCaptionEscDir::BestFit
;
146 BigInt
aHorX(aBestPt
.X()-aTl
.X()); aHorX
*=aHorX
;
147 BigInt
aHorY(aBestPt
.Y()-aTl
.Y()); aHorY
*=aHorY
;
148 BigInt
aVerX(aBest2
.X()-aTl
.X()); aVerX
*=aVerX
;
149 BigInt
aVerY(aBest2
.Y()-aTl
.Y()); aVerY
*=aVerY
;
150 if (eType
!=SdrCaptionType::Type1
) {
151 bTakeIt
=aVerX
+aVerY
<aHorX
+aHorY
;
153 bTakeIt
=aVerX
+aVerY
>=aHorX
+aHorY
;
166 // BaseProperties section
168 std::unique_ptr
<sdr::properties::BaseProperties
> SdrCaptionObj::CreateObjectSpecificProperties()
170 return std::make_unique
<sdr::properties::CaptionProperties
>(*this);
174 // DrawContact section
176 std::unique_ptr
<sdr::contact::ViewContact
> SdrCaptionObj::CreateObjectSpecificViewContact()
178 return std::make_unique
<sdr::contact::ViewContactOfSdrCaptionObj
>(*this);
182 SdrCaptionObj::SdrCaptionObj(SdrModel
& rSdrModel
)
183 : SdrRectObj(rSdrModel
, SdrObjKind::Text
),
184 aTailPoly(3), // default size: 3 points = 2 lines
185 mbSpecialTextBoxShadow(false),
187 mbSuppressGetBitmap(false)
191 SdrCaptionObj::SdrCaptionObj(SdrModel
& rSdrModel
, SdrCaptionObj
const & rSource
)
192 : SdrRectObj(rSdrModel
, rSource
),
193 mbSuppressGetBitmap(false)
195 aTailPoly
= rSource
.aTailPoly
;
196 mbSpecialTextBoxShadow
= rSource
.mbSpecialTextBoxShadow
;
197 mbFixedTail
= rSource
.mbFixedTail
;
198 maFixedTailPos
= rSource
.maFixedTailPos
;
201 SdrCaptionObj::SdrCaptionObj(
203 const tools::Rectangle
& rRect
,
205 : SdrRectObj(rSdrModel
, SdrObjKind::Text
,rRect
),
206 aTailPoly(3), // default size: 3 points = 2 lines
207 mbSpecialTextBoxShadow(false),
209 mbSuppressGetBitmap(false)
211 aTailPoly
[0]=maFixedTailPos
=rTail
;
214 SdrCaptionObj::~SdrCaptionObj()
218 void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
220 rInfo
.bRotateFreeAllowed
=false;
221 rInfo
.bRotate90Allowed
=false;
222 rInfo
.bMirrorFreeAllowed
=false;
223 rInfo
.bMirror45Allowed
=false;
224 rInfo
.bMirror90Allowed
=false;
225 rInfo
.bTransparenceAllowed
= false;
226 rInfo
.bShearAllowed
=false;
227 rInfo
.bEdgeRadiusAllowed
=false;
228 rInfo
.bCanConvToPath
=true;
229 rInfo
.bCanConvToPoly
=true;
230 rInfo
.bCanConvToPathLineToArea
=false;
231 rInfo
.bCanConvToPolyLineToArea
=false;
232 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
235 SdrObjKind
SdrCaptionObj::GetObjIdentifier() const
237 return SdrObjKind::Caption
;
240 rtl::Reference
<SdrObject
> SdrCaptionObj::CloneSdrObject(SdrModel
& rTargetModel
) const
242 return new SdrCaptionObj(rTargetModel
, *this);
245 OUString
SdrCaptionObj::TakeObjNameSingul() const
247 OUString
sName(SvxResId(STR_ObjNameSingulCAPTION
));
249 OUString
aName(GetName());
250 if (!aName
.isEmpty())
251 sName
+= " '" + aName
+ "'";
256 OUString
SdrCaptionObj::TakeObjNamePlural() const
258 return SvxResId(STR_ObjNamePluralCAPTION
);
261 basegfx::B2DPolyPolygon
SdrCaptionObj::TakeXorPoly() const
263 basegfx::B2DPolyPolygon
aPolyPoly(SdrRectObj::TakeXorPoly());
264 aPolyPoly
.append(aTailPoly
.getB2DPolygon());
269 sal_uInt32
SdrCaptionObj::GetHdlCount() const
271 sal_uInt32
nCount1(SdrRectObj::GetHdlCount());
272 // Currently only dragging the tail's end is implemented.
276 void SdrCaptionObj::AddToHdlList(SdrHdlList
& rHdlList
) const
278 SdrRectObj::AddToHdlList(rHdlList
);
279 // Currently only dragging the tail's end is implemented.
280 std::unique_ptr
<SdrHdl
> pHdl(new SdrHdl(aTailPoly
.GetPoint(0), SdrHdlKind::Poly
));
282 pHdl
->SetPointNum(0);
283 rHdlList
.AddHdl(std::move(pHdl
));
286 bool SdrCaptionObj::hasSpecialDrag() const
291 bool SdrCaptionObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
293 const SdrHdl
* pHdl
= rDrag
.GetHdl();
294 rDrag
.SetEndDragChangesAttributes(true);
295 rDrag
.SetEndDragChangesGeoAndAttributes(true);
297 if(pHdl
&& 0 == pHdl
->GetPolyNum())
299 return SdrRectObj::beginSpecialDrag(rDrag
);
303 rDrag
.SetOrtho8Possible();
311 rDrag
.SetActionRect(getRectangle());
313 Point
aHit(rDrag
.GetStart());
315 if(rDrag
.GetPageView() && SdrObjectPrimitiveHit(*this, aHit
, {0, 0}, *rDrag
.GetPageView(), nullptr, false))
322 if((1 == pHdl
->GetPolyNum()) && (0 == pHdl
->GetPointNum()))
330 bool SdrCaptionObj::applySpecialDrag(SdrDragStat
& rDrag
)
332 const SdrHdl
* pHdl
= rDrag
.GetHdl();
334 if(pHdl
&& 0 == pHdl
->GetPolyNum())
336 const bool bRet(SdrRectObj::applySpecialDrag(rDrag
));
344 Point
aDelta(rDrag
.GetNow()-rDrag
.GetStart());
348 moveRectangle(aDelta
.X(), aDelta
.Y());
352 aTailPoly
[0] += aDelta
;
362 OUString
SdrCaptionObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
364 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
372 const SdrHdl
* pHdl
= rDrag
.GetHdl();
374 if(pHdl
&& 0 == pHdl
->GetPolyNum())
376 return SdrRectObj::getSpecialDragComment(rDrag
);
382 return ImpGetDescriptionStr(STR_DragCaptFram
);
386 return ImpGetDescriptionStr(STR_DragCaptTail
);
393 void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams
& rPara
) const
395 const SfxItemSet
& rSet
= GetObjectItemSet();
396 rPara
.eType
=rSet
.Get(SDRATTR_CAPTIONTYPE
).GetValue();
397 rPara
.bFixedAngle
=rSet
.Get(SDRATTR_CAPTIONFIXEDANGLE
).GetValue();
398 rPara
.nGap
=static_cast<const SdrCaptionGapItem
&> (rSet
.Get(SDRATTR_CAPTIONGAP
)).GetValue();
399 rPara
.eEscDir
=rSet
.Get(SDRATTR_CAPTIONESCDIR
).GetValue();
400 rPara
.bEscRel
=rSet
.Get(SDRATTR_CAPTIONESCISREL
).GetValue();
401 rPara
.nEscRel
=rSet
.Get(SDRATTR_CAPTIONESCREL
).GetValue();
402 rPara
.nEscAbs
=rSet
.Get(SDRATTR_CAPTIONESCABS
).GetValue();
403 rPara
.nLineLen
=rSet
.Get(SDRATTR_CAPTIONLINELEN
).GetValue();
404 rPara
.bFitLineLen
=rSet
.Get(SDRATTR_CAPTIONFITLINELEN
).GetValue();
407 void SdrCaptionObj::ImpRecalcTail()
410 ImpGetCaptParams(aPara
);
411 ImpCalcTail(aPara
, aTailPoly
, getRectangle());
412 SetBoundAndSnapRectsDirty();
417 // SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
418 // I really wonder why this had not triggered problems before. I am
419 // sure there are some places where SetTailPos() is called at least
420 // twice or SetSnapRect after it again just to work around this.
421 // Changed this method to not do that.
422 // Also found why this has been done: For interactive dragging of the
423 // tail end pos for SdrCaptionType::Type1. This sure was the simplest method
424 // to achieve this, at the cost of making a whole group of const methods
425 // of this object implicitly change the object's position.
426 void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams
& rPara
, tools::Polygon
& rPoly
, tools::Rectangle
const & rRect
)
428 tools::Polygon
aPol(2);
437 rPara
.CalcEscPos(aTl
, rRect
, aEscPos
, eEscDir
);
440 if(eEscDir
==LKS
|| eEscDir
==RTS
)
442 aPol
[0].setX( aEscPos
.X() );
446 aPol
[0].setY( aEscPos
.Y() );
452 void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams
& rPara
, tools::Polygon
& rPoly
, tools::Rectangle
const & rRect
)
453 { // Gap/EscDir/EscPos/Angle
454 tools::Polygon
aPol(2);
460 rPara
.CalcEscPos(aTl
,rRect
,aEscPos
,eEscDir
);
463 if (!rPara
.bFixedAngle
) {
464 // TODO: Implementation missing.
469 void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams
& rPara
, tools::Polygon
& rPoly
, tools::Rectangle
const & rRect
)
470 { // Gap/EscDir/EscPos/Angle/LineLen
471 tools::Polygon
aPol(3);
477 rPara
.CalcEscPos(aTl
,rRect
,aEscPos
,eEscDir
);
481 if (eEscDir
==LKS
|| eEscDir
==RTS
) {
482 if (rPara
.bFitLineLen
) {
483 aPol
[1].setX((aTl
.X()+aEscPos
.X())/2 );
485 if (eEscDir
==LKS
) aPol
[1].AdjustX( -(rPara
.nLineLen
) );
486 else aPol
[1].AdjustX(rPara
.nLineLen
);
489 if (rPara
.bFitLineLen
) {
490 aPol
[1].setY((aTl
.Y()+aEscPos
.Y())/2 );
492 if (eEscDir
==OBN
) aPol
[1].AdjustY( -(rPara
.nLineLen
) );
493 else aPol
[1].AdjustY(rPara
.nLineLen
);
496 if (!rPara
.bFixedAngle
) {
497 // TODO: Implementation missing.
502 void SdrCaptionObj::ImpCalcTail(const ImpCaptParams
& rPara
, tools::Polygon
& rPoly
, tools::Rectangle
const & rRect
)
504 switch (rPara
.eType
) {
505 case SdrCaptionType::Type1
: ImpCalcTail1(rPara
,rPoly
,rRect
); break;
506 case SdrCaptionType::Type2
: ImpCalcTail2(rPara
,rPoly
,rRect
); break;
507 case SdrCaptionType::Type3
: ImpCalcTail3(rPara
,rPoly
,rRect
); break;
508 case SdrCaptionType::Type4
: ImpCalcTail3(rPara
,rPoly
,rRect
); break;
512 bool SdrCaptionObj::BegCreate(SdrDragStat
& rStat
)
514 if (getRectangle().IsEmpty())
515 return false; // Create currently only works with the given Rect
518 ImpGetCaptParams(aPara
);
519 moveRectanglePosition(rStat
.GetNow().X(), rStat
.GetNow().Y());
520 aTailPoly
[0]=rStat
.GetStart();
521 ImpCalcTail(aPara
,aTailPoly
, getRectangle());
522 rStat
.SetActionRect(getRectangle());
526 bool SdrCaptionObj::MovCreate(SdrDragStat
& rStat
)
529 ImpGetCaptParams(aPara
);
530 moveRectanglePosition(rStat
.GetNow().X(), rStat
.GetNow().Y());
531 ImpCalcTail(aPara
,aTailPoly
, getRectangle());
532 rStat
.SetActionRect(getRectangle());
534 m_bSnapRectDirty
=true;
538 bool SdrCaptionObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
541 ImpGetCaptParams(aPara
);
542 moveRectanglePosition(rStat
.GetNow().X(), rStat
.GetNow().Y());
543 ImpCalcTail(aPara
,aTailPoly
, getRectangle());
544 SetBoundAndSnapRectsDirty();
545 return (eCmd
==SdrCreateCmd::ForceEnd
|| rStat
.GetPointCount()>=2);
548 bool SdrCaptionObj::BckCreate(SdrDragStat
& /*rStat*/)
553 void SdrCaptionObj::BrkCreate(SdrDragStat
& /*rStat*/)
557 basegfx::B2DPolyPolygon
SdrCaptionObj::TakeCreatePoly(const SdrDragStat
& /*rDrag*/) const
559 basegfx::B2DPolyPolygon aRetval
;
560 const basegfx::B2DRange aRange
=vcl::unotools::b2DRectangleFromRectangle(getRectangle());
561 aRetval
.append(basegfx::utils::createPolygonFromRect(aRange
));
562 aRetval
.append(aTailPoly
.getB2DPolygon());
566 PointerStyle
SdrCaptionObj::GetCreatePointer() const
568 return PointerStyle::DrawCaption
;
571 void SdrCaptionObj::NbcMove(const Size
& rSiz
)
573 SdrRectObj::NbcMove(rSiz
);
574 MovePoly(aTailPoly
,rSiz
);
576 SetTailPos(GetFixedTailPos());
579 void SdrCaptionObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
581 SdrRectObj::NbcResize(rRef
,xFact
,yFact
);
582 ResizePoly(aTailPoly
,rRef
,xFact
,yFact
);
585 SetTailPos(GetFixedTailPos());
588 void SdrCaptionObj::NbcSetRelativePos(const Point
& rPnt
)
590 Point
aRelPos0(aTailPoly
.GetPoint(0)-m_aAnchor
);
591 Size
aSiz(rPnt
.X()-aRelPos0
.X(),rPnt
.Y()-aRelPos0
.Y());
592 NbcMove(aSiz
); // This also calls SetRectsDirty()
595 Point
SdrCaptionObj::GetRelativePos() const
597 return aTailPoly
.GetPoint(0)-m_aAnchor
;
600 const tools::Rectangle
& SdrCaptionObj::GetLogicRect() const
602 return getRectangle();
605 void SdrCaptionObj::NbcSetLogicRect(const tools::Rectangle
& rRect
)
607 SdrRectObj::NbcSetLogicRect(rRect
);
611 const Point
& SdrCaptionObj::GetTailPos() const
616 void SdrCaptionObj::SetTailPos(const Point
& rPos
)
618 if (aTailPoly
.GetSize()==0 || aTailPoly
[0]!=rPos
) {
619 tools::Rectangle aBoundRect0
; if (m_pUserCall
!=nullptr) aBoundRect0
=GetLastBoundRect();
622 BroadcastObjectChange();
623 SendUserCall(SdrUserCallType::Resize
,aBoundRect0
);
627 void SdrCaptionObj::NbcSetTailPos(const Point
& rPos
)
633 sal_uInt32
SdrCaptionObj::GetSnapPointCount() const
635 // TODO: Implementation missing.
639 Point
SdrCaptionObj::GetSnapPoint(sal_uInt32
/*i*/) const
641 // TODO: Implementation missing.
645 void SdrCaptionObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
647 SdrRectObj::Notify(rBC
,rHint
);
651 std::unique_ptr
<SdrObjGeoData
> SdrCaptionObj::NewGeoData() const
653 return std::make_unique
<SdrCaptObjGeoData
>();
656 void SdrCaptionObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
658 SdrRectObj::SaveGeoData(rGeo
);
659 SdrCaptObjGeoData
& rCGeo
=static_cast<SdrCaptObjGeoData
&>(rGeo
);
660 rCGeo
.aTailPoly
=aTailPoly
;
663 void SdrCaptionObj::RestoreGeoData(const SdrObjGeoData
& rGeo
)
665 SdrRectObj::RestoreGeoData(rGeo
);
666 const SdrCaptObjGeoData
& rCGeo
=static_cast<const SdrCaptObjGeoData
&>(rGeo
);
667 aTailPoly
=rCGeo
.aTailPoly
;
670 rtl::Reference
<SdrObject
> SdrCaptionObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
672 rtl::Reference
<SdrObject
> pRect
= SdrRectObj::DoConvertToPolyObj(bBezier
, bAddText
);
673 rtl::Reference
<SdrObject
> pTail
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aTailPoly
.getB2DPolygon()), false, bBezier
);
674 rtl::Reference
<SdrObject
> pRet
;
676 pRet
= std::move(pTail
);
677 else if (pRect
&& !pTail
)
678 pRet
= std::move(pRect
);
679 else if (pTail
&& pRect
)
681 if (pTail
->GetSubList())
683 pTail
->GetSubList()->NbcInsertObject(pRect
.get());
684 pRet
= std::move(pTail
);
686 else if (pRect
->GetSubList())
688 pRect
->GetSubList()->NbcInsertObject(pTail
.get(),0);
689 pRet
= std::move(pRect
);
693 rtl::Reference
<SdrObjGroup
> pGrp
= new SdrObjGroup(getSdrModelFromSdrObject());
694 pGrp
->GetSubList()->NbcInsertObject(pRect
.get());
695 pGrp
->GetSubList()->NbcInsertObject(pTail
.get(),0);
704 void handleNegativeScale(basegfx::B2DTuple
& scale
, double * rotate
) {
705 assert(rotate
!= nullptr);
707 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
708 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
709 if(basegfx::fTools::less(scale
.getX(), 0.0) && basegfx::fTools::less(scale
.getY(), 0.0))
711 scale
.setX(fabs(scale
.getX()));
712 scale
.setY(fabs(scale
.getY()));
713 *rotate
= fmod(*rotate
+ M_PI
, 2 * M_PI
);
720 // Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
721 void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& /*rPolyPolygon*/)
724 basegfx::B2DTuple aScale
;
725 basegfx::B2DTuple aTranslate
;
726 double fRotate
, fShearX
;
727 rMatrix
.decompose(aScale
, aTranslate
, fRotate
, fShearX
);
729 handleNegativeScale(aScale
, &fRotate
);
731 // if anchor is used, make position relative to it
732 if(getSdrModelFromSdrObject().IsWriter())
734 if(GetAnchorPos().X() || GetAnchorPos().Y())
736 aTranslate
+= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
741 Point
aPoint(FRound(aTranslate
.getX()), FRound(aTranslate
.getY()));
742 tools::Rectangle
aBaseRect(aPoint
, Size(FRound(aScale
.getX()), FRound(aScale
.getY())));
744 // set BaseRect, but rescue TailPos over this call
745 const Point aTailPoint
= GetTailPos();
746 SetSnapRect(aBaseRect
);
747 SetTailPos(aTailPoint
);
752 basegfx::B2DPolygon
SdrCaptionObj::getTailPolygon() const
754 return aTailPoly
.getB2DPolygon();
757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */