nss: upgrade to release 3.73
[LibreOffice.git] / svx / source / svdraw / svdocapt.cxx
blob1773901490e3c0b15ffb562933a65afd9fec0eee
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include <cassert>
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>
31 #include <rtl/ustrbuf.hxx>
33 #include <svx/dialmgr.hxx>
34 #include <svx/strings.hrc>
36 #include <sdr/contact/viewcontactofsdrcaptionobj.hxx>
37 #include <sdr/properties/captionproperties.hxx>
38 #include <svx/sdrhittesthelper.hxx>
39 #include <svx/sdooitm.hxx>
40 #include <svx/svddrag.hxx>
41 #include <svx/svdhdl.hxx>
42 #include <svx/svdmodel.hxx>
43 #include <svx/svdocapt.hxx>
44 #include <svx/svdopath.hxx>
45 #include <svx/svdogrp.hxx>
46 #include <svx/svdpage.hxx>
47 #include <svx/svdtrans.hxx>
48 #include <svx/svdview.hxx>
49 #include <svx/sxcecitm.hxx>
50 #include <svx/sxcgitm.hxx>
51 #include <svx/sxcllitm.hxx>
52 #include <svx/sxctitm.hxx>
53 #include <vcl/canvastools.hxx>
54 #include <vcl/ptrstyle.hxx>
56 namespace {
58 enum EscDir {LKS,RTS,OBN,UNT};
62 class ImpCaptParams
64 public:
65 SdrCaptionType eType;
66 tools::Long nGap;
67 tools::Long nEscRel;
68 tools::Long nEscAbs;
69 tools::Long nLineLen;
70 SdrCaptionEscDir eEscDir;
71 bool bFitLineLen;
72 bool bEscRel;
73 bool bFixedAngle;
75 public:
76 ImpCaptParams()
77 : eType(SdrCaptionType::Type3),
78 nGap(0), nEscRel(5000), nEscAbs(0),
79 nLineLen(0), eEscDir(SdrCaptionEscDir::Horizontal),
80 bFitLineLen(true), bEscRel(true), bFixedAngle(false)
83 void CalcEscPos(const Point& rTail, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const;
86 void ImpCaptParams::CalcEscPos(const Point& rTailPt, const tools::Rectangle& rRect, Point& rPt, EscDir& rDir) const
88 Point aTl(rTailPt); // copy locally for performance reasons
89 tools::Long nX,nY;
90 if (bEscRel) {
91 nX=rRect.Right()-rRect.Left();
92 nX=BigMulDiv(nX,nEscRel,10000);
93 nY=rRect.Bottom()-rRect.Top();
94 nY=BigMulDiv(nY,nEscRel,10000);
95 } else {
96 nX=nEscAbs;
97 nY=nEscAbs;
99 nX+=rRect.Left();
100 nY+=rRect.Top();
101 Point aBestPt;
102 EscDir eBestDir=LKS;
103 bool bTryH=eEscDir==SdrCaptionEscDir::BestFit;
104 if (!bTryH) {
105 if (eType!=SdrCaptionType::Type1) {
106 bTryH=eEscDir==SdrCaptionEscDir::Horizontal;
107 } else {
108 bTryH=eEscDir==SdrCaptionEscDir::Vertical;
111 bool bTryV=eEscDir==SdrCaptionEscDir::BestFit;
112 if (!bTryV) {
113 if (eType!=SdrCaptionType::Type1) {
114 bTryV=eEscDir==SdrCaptionEscDir::Vertical;
115 } else {
116 bTryV=eEscDir==SdrCaptionEscDir::Horizontal;
120 if (bTryH) {
121 Point aLft(rRect.Left()-nGap,nY);
122 Point aRgt(rRect.Right()+nGap,nY);
123 bool bLft=(aTl.X()-aLft.X()<aRgt.X()-aTl.X());
124 if (bLft) {
125 eBestDir=LKS;
126 aBestPt=aLft;
127 } else {
128 eBestDir=RTS;
129 aBestPt=aRgt;
132 if (bTryV) {
133 Point aTop(nX,rRect.Top()-nGap);
134 Point aBtm(nX,rRect.Bottom()+nGap);
135 bool bTop=(aTl.Y()-aTop.Y()<aBtm.Y()-aTl.Y());
136 Point aBest2;
137 EscDir eBest2;
138 if (bTop) {
139 eBest2=OBN;
140 aBest2=aTop;
141 } else {
142 eBest2=UNT;
143 aBest2=aBtm;
145 bool bTakeIt=eEscDir!=SdrCaptionEscDir::BestFit;
146 if (!bTakeIt) {
147 BigInt aHorX(aBestPt.X()-aTl.X()); aHorX*=aHorX;
148 BigInt aHorY(aBestPt.Y()-aTl.Y()); aHorY*=aHorY;
149 BigInt aVerX(aBest2.X()-aTl.X()); aVerX*=aVerX;
150 BigInt aVerY(aBest2.Y()-aTl.Y()); aVerY*=aVerY;
151 if (eType!=SdrCaptionType::Type1) {
152 bTakeIt=aVerX+aVerY<aHorX+aHorY;
153 } else {
154 bTakeIt=aVerX+aVerY>=aHorX+aHorY;
157 if (bTakeIt) {
158 aBestPt=aBest2;
159 eBestDir=eBest2;
162 rPt=aBestPt;
163 rDir=eBestDir;
167 // BaseProperties section
169 std::unique_ptr<sdr::properties::BaseProperties> SdrCaptionObj::CreateObjectSpecificProperties()
171 return std::make_unique<sdr::properties::CaptionProperties>(*this);
175 // DrawContact section
177 std::unique_ptr<sdr::contact::ViewContact> SdrCaptionObj::CreateObjectSpecificViewContact()
179 return std::make_unique<sdr::contact::ViewContactOfSdrCaptionObj>(*this);
183 SdrCaptionObj::SdrCaptionObj(SdrModel& rSdrModel)
184 : SdrRectObj(rSdrModel, OBJ_TEXT),
185 aTailPoly(3), // default size: 3 points = 2 lines
186 mbSpecialTextBoxShadow(false),
187 mbFixedTail(false),
188 mbSuppressGetBitmap(false),
189 maFixedTailPos()
193 SdrCaptionObj::SdrCaptionObj(
194 SdrModel& rSdrModel,
195 const tools::Rectangle& rRect,
196 const Point& rTail)
197 : SdrRectObj(rSdrModel, OBJ_TEXT,rRect),
198 aTailPoly(3), // default size: 3 points = 2 lines
199 mbSpecialTextBoxShadow(false),
200 mbFixedTail(false),
201 mbSuppressGetBitmap(false),
202 maFixedTailPos()
204 aTailPoly[0]=maFixedTailPos=rTail;
207 SdrCaptionObj::~SdrCaptionObj()
211 void SdrCaptionObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
213 rInfo.bRotateFreeAllowed=false;
214 rInfo.bRotate90Allowed =false;
215 rInfo.bMirrorFreeAllowed=false;
216 rInfo.bMirror45Allowed =false;
217 rInfo.bMirror90Allowed =false;
218 rInfo.bTransparenceAllowed = false;
219 rInfo.bShearAllowed =false;
220 rInfo.bEdgeRadiusAllowed=false;
221 rInfo.bCanConvToPath =true;
222 rInfo.bCanConvToPoly =true;
223 rInfo.bCanConvToPathLineToArea=false;
224 rInfo.bCanConvToPolyLineToArea=false;
225 rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
228 SdrObjKind SdrCaptionObj::GetObjIdentifier() const
230 return OBJ_CAPTION;
233 SdrCaptionObj* SdrCaptionObj::CloneSdrObject(SdrModel& rTargetModel) const
235 return CloneHelper< SdrCaptionObj >(rTargetModel);
238 SdrCaptionObj& SdrCaptionObj::operator=(const SdrCaptionObj& rObj)
240 if( this == &rObj )
241 return *this;
242 SdrRectObj::operator=(rObj);
244 aTailPoly = rObj.aTailPoly;
245 mbSpecialTextBoxShadow = rObj.mbSpecialTextBoxShadow;
246 mbFixedTail = rObj.mbFixedTail;
247 maFixedTailPos = rObj.maFixedTailPos;
249 return *this;
252 OUString SdrCaptionObj::TakeObjNameSingul() const
254 OUStringBuffer sName(SvxResId(STR_ObjNameSingulCAPTION));
256 OUString aName(GetName());
257 if (!aName.isEmpty())
259 sName.append(' ');
260 sName.append('\'');
261 sName.append(aName);
262 sName.append('\'');
265 return sName.makeStringAndClear();
268 OUString SdrCaptionObj::TakeObjNamePlural() const
270 return SvxResId(STR_ObjNamePluralCAPTION);
273 basegfx::B2DPolyPolygon SdrCaptionObj::TakeXorPoly() const
275 basegfx::B2DPolyPolygon aPolyPoly(SdrRectObj::TakeXorPoly());
276 aPolyPoly.append(aTailPoly.getB2DPolygon());
278 return aPolyPoly;
281 sal_uInt32 SdrCaptionObj::GetHdlCount() const
283 sal_uInt32 nCount1(SdrRectObj::GetHdlCount());
284 // Currently only dragging the tail's end is implemented.
285 return nCount1 + 1;
288 void SdrCaptionObj::AddToHdlList(SdrHdlList& rHdlList) const
290 SdrRectObj::AddToHdlList(rHdlList);
291 // Currently only dragging the tail's end is implemented.
292 std::unique_ptr<SdrHdl> pHdl(new SdrHdl(aTailPoly.GetPoint(0), SdrHdlKind::Poly));
293 pHdl->SetPolyNum(1);
294 pHdl->SetPointNum(0);
295 rHdlList.AddHdl(std::move(pHdl));
298 bool SdrCaptionObj::hasSpecialDrag() const
300 return true;
303 bool SdrCaptionObj::beginSpecialDrag(SdrDragStat& rDrag) const
305 const SdrHdl* pHdl = rDrag.GetHdl();
306 rDrag.SetEndDragChangesAttributes(true);
307 rDrag.SetEndDragChangesGeoAndAttributes(true);
309 if(pHdl && 0 == pHdl->GetPolyNum())
311 return SdrRectObj::beginSpecialDrag(rDrag);
313 else
315 rDrag.SetOrtho8Possible();
317 if(!pHdl)
319 if (bMovProt)
320 return false;
322 rDrag.SetNoSnap();
323 rDrag.SetActionRect(maRect);
325 Point aHit(rDrag.GetStart());
327 if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, 0, *rDrag.GetPageView(), nullptr, false))
329 return true;
332 else
334 if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
335 return true;
339 return false;
342 bool SdrCaptionObj::applySpecialDrag(SdrDragStat& rDrag)
344 const SdrHdl* pHdl = rDrag.GetHdl();
346 if(pHdl && 0 == pHdl->GetPolyNum())
348 const bool bRet(SdrRectObj::applySpecialDrag(rDrag));
349 ImpRecalcTail();
350 ActionChanged();
352 return bRet;
354 else
356 Point aDelt(rDrag.GetNow()-rDrag.GetStart());
358 if(!pHdl)
360 maRect.Move(aDelt.X(),aDelt.Y());
362 else
364 aTailPoly[0] += aDelt;
367 ImpRecalcTail();
368 ActionChanged();
370 return true;
374 OUString SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
376 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
378 if(bCreateComment)
380 return OUString();
382 else
384 const SdrHdl* pHdl = rDrag.GetHdl();
386 if(pHdl && 0 == pHdl->GetPolyNum())
388 return SdrRectObj::getSpecialDragComment(rDrag);
390 else
392 if(!pHdl)
394 return ImpGetDescriptionStr(STR_DragCaptFram);
396 else
398 return ImpGetDescriptionStr(STR_DragCaptTail);
405 void SdrCaptionObj::ImpGetCaptParams(ImpCaptParams& rPara) const
407 const SfxItemSet& rSet = GetObjectItemSet();
408 rPara.eType =rSet.Get(SDRATTR_CAPTIONTYPE ).GetValue();
409 rPara.bFixedAngle=rSet.Get(SDRATTR_CAPTIONFIXEDANGLE).GetValue();
410 rPara.nGap =static_cast<const SdrCaptionGapItem&> (rSet.Get(SDRATTR_CAPTIONGAP )).GetValue();
411 rPara.eEscDir =rSet.Get(SDRATTR_CAPTIONESCDIR ).GetValue();
412 rPara.bEscRel =rSet.Get(SDRATTR_CAPTIONESCISREL ).GetValue();
413 rPara.nEscRel =rSet.Get(SDRATTR_CAPTIONESCREL ).GetValue();
414 rPara.nEscAbs =rSet.Get(SDRATTR_CAPTIONESCABS ).GetValue();
415 rPara.nLineLen =rSet.Get(SDRATTR_CAPTIONLINELEN ).GetValue();
416 rPara.bFitLineLen=rSet.Get(SDRATTR_CAPTIONFITLINELEN).GetValue();
419 void SdrCaptionObj::ImpRecalcTail()
421 ImpCaptParams aPara;
422 ImpGetCaptParams(aPara);
423 ImpCalcTail(aPara, aTailPoly, maRect);
424 SetRectsDirty();
425 SetXPolyDirty();
428 // #i35971#
429 // SdrCaptionObj::ImpCalcTail1 does move the object(!). What a hack.
430 // I really wonder why this had not triggered problems before. I am
431 // sure there are some places where SetTailPos() is called at least
432 // twice or SetSnapRect after it again just to work around this.
433 // Changed this method to not do that.
434 // Also found why this has been done: For interactive dragging of the
435 // tail end pos for SdrCaptionType::Type1. This sure was the simplest method
436 // to achieve this, at the cost of making a whole group of const methods
437 // of this object implicitly change the object's position.
438 void SdrCaptionObj::ImpCalcTail1(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
440 tools::Polygon aPol(2);
441 Point aTl(rPoly[0]);
443 aPol[0] = aTl;
444 aPol[1] = aTl;
446 EscDir eEscDir;
447 Point aEscPos;
449 rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
450 aPol[1] = aEscPos;
452 if(eEscDir==LKS || eEscDir==RTS)
454 aPol[0].setX( aEscPos.X() );
456 else
458 aPol[0].setY( aEscPos.Y() );
461 rPoly = aPol;
464 void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
465 { // Gap/EscDir/EscPos/Angle
466 tools::Polygon aPol(2);
467 Point aTl(rPoly[0]);
468 aPol[0]=aTl;
470 EscDir eEscDir;
471 Point aEscPos;
472 rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
473 aPol[1]=aEscPos;
475 if (!rPara.bFixedAngle) {
476 // TODO: Implementation missing.
478 rPoly=aPol;
481 void SdrCaptionObj::ImpCalcTail3(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
482 { // Gap/EscDir/EscPos/Angle/LineLen
483 tools::Polygon aPol(3);
484 Point aTl(rPoly[0]);
485 aPol[0]=aTl;
487 EscDir eEscDir;
488 Point aEscPos;
489 rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
490 aPol[1]=aEscPos;
491 aPol[2]=aEscPos;
493 if (eEscDir==LKS || eEscDir==RTS) {
494 if (rPara.bFitLineLen) {
495 aPol[1].setX((aTl.X()+aEscPos.X())/2 );
496 } else {
497 if (eEscDir==LKS) aPol[1].AdjustX( -(rPara.nLineLen) );
498 else aPol[1].AdjustX(rPara.nLineLen );
500 } else {
501 if (rPara.bFitLineLen) {
502 aPol[1].setY((aTl.Y()+aEscPos.Y())/2 );
503 } else {
504 if (eEscDir==OBN) aPol[1].AdjustY( -(rPara.nLineLen) );
505 else aPol[1].AdjustY(rPara.nLineLen );
508 if (!rPara.bFixedAngle) {
509 // TODO: Implementation missing.
511 rPoly=aPol;
514 void SdrCaptionObj::ImpCalcTail(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
516 switch (rPara.eType) {
517 case SdrCaptionType::Type1: ImpCalcTail1(rPara,rPoly,rRect); break;
518 case SdrCaptionType::Type2: ImpCalcTail2(rPara,rPoly,rRect); break;
519 case SdrCaptionType::Type3: ImpCalcTail3(rPara,rPoly,rRect); break;
520 case SdrCaptionType::Type4: ImpCalcTail3(rPara,rPoly,rRect); break;
524 bool SdrCaptionObj::BegCreate(SdrDragStat& rStat)
526 if (maRect.IsEmpty()) return false; // Create currently only works with the given Rect
528 ImpCaptParams aPara;
529 ImpGetCaptParams(aPara);
530 maRect.SetPos(rStat.GetNow());
531 aTailPoly[0]=rStat.GetStart();
532 ImpCalcTail(aPara,aTailPoly,maRect);
533 rStat.SetActionRect(maRect);
534 return true;
537 bool SdrCaptionObj::MovCreate(SdrDragStat& rStat)
539 ImpCaptParams aPara;
540 ImpGetCaptParams(aPara);
541 maRect.SetPos(rStat.GetNow());
542 ImpCalcTail(aPara,aTailPoly,maRect);
543 rStat.SetActionRect(maRect);
544 SetBoundRectDirty();
545 bSnapRectDirty=true;
546 return true;
549 bool SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
551 ImpCaptParams aPara;
552 ImpGetCaptParams(aPara);
553 maRect.SetPos(rStat.GetNow());
554 ImpCalcTail(aPara,aTailPoly,maRect);
555 SetRectsDirty();
556 return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2);
559 bool SdrCaptionObj::BckCreate(SdrDragStat& /*rStat*/)
561 return false;
564 void SdrCaptionObj::BrkCreate(SdrDragStat& /*rStat*/)
568 basegfx::B2DPolyPolygon SdrCaptionObj::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
570 basegfx::B2DPolyPolygon aRetval;
571 const basegfx::B2DRange aRange =vcl::unotools::b2DRectangleFromRectangle(maRect);
572 aRetval.append(basegfx::utils::createPolygonFromRect(aRange));
573 aRetval.append(aTailPoly.getB2DPolygon());
574 return aRetval;
577 PointerStyle SdrCaptionObj::GetCreatePointer() const
579 return PointerStyle::DrawCaption;
582 void SdrCaptionObj::NbcMove(const Size& rSiz)
584 SdrRectObj::NbcMove(rSiz);
585 MovePoly(aTailPoly,rSiz);
586 if(mbFixedTail)
587 SetTailPos(GetFixedTailPos());
590 void SdrCaptionObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
592 SdrRectObj::NbcResize(rRef,xFact,yFact);
593 ResizePoly(aTailPoly,rRef,xFact,yFact);
594 ImpRecalcTail();
595 if(mbFixedTail)
596 SetTailPos(GetFixedTailPos());
599 void SdrCaptionObj::NbcSetRelativePos(const Point& rPnt)
601 Point aRelPos0(aTailPoly.GetPoint(0)-aAnchor);
602 Size aSiz(rPnt.X()-aRelPos0.X(),rPnt.Y()-aRelPos0.Y());
603 NbcMove(aSiz); // This also calls SetRectsDirty()
606 Point SdrCaptionObj::GetRelativePos() const
608 return aTailPoly.GetPoint(0)-aAnchor;
611 const tools::Rectangle& SdrCaptionObj::GetLogicRect() const
613 return maRect;
616 void SdrCaptionObj::NbcSetLogicRect(const tools::Rectangle& rRect)
618 SdrRectObj::NbcSetLogicRect(rRect);
619 ImpRecalcTail();
622 const Point& SdrCaptionObj::GetTailPos() const
624 return aTailPoly[0];
627 void SdrCaptionObj::SetTailPos(const Point& rPos)
629 if (aTailPoly.GetSize()==0 || aTailPoly[0]!=rPos) {
630 tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
631 NbcSetTailPos(rPos);
632 SetChanged();
633 BroadcastObjectChange();
634 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
638 void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
640 aTailPoly[0]=rPos;
641 ImpRecalcTail();
644 sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
646 // TODO: Implementation missing.
647 return 0;
650 Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
652 // TODO: Implementation missing.
653 return Point(0,0);
656 void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
658 SdrRectObj::Notify(rBC,rHint);
659 ImpRecalcTail();
662 SdrObjGeoData* SdrCaptionObj::NewGeoData() const
664 return new SdrCaptObjGeoData;
667 void SdrCaptionObj::SaveGeoData(SdrObjGeoData& rGeo) const
669 SdrRectObj::SaveGeoData(rGeo);
670 SdrCaptObjGeoData& rCGeo=static_cast<SdrCaptObjGeoData&>(rGeo);
671 rCGeo.aTailPoly=aTailPoly;
674 void SdrCaptionObj::RestGeoData(const SdrObjGeoData& rGeo)
676 SdrRectObj::RestGeoData(rGeo);
677 const SdrCaptObjGeoData& rCGeo=static_cast<const SdrCaptObjGeoData&>(rGeo);
678 aTailPoly=rCGeo.aTailPoly;
681 SdrObjectUniquePtr SdrCaptionObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
683 SdrObjectUniquePtr pRect = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
684 SdrObjectUniquePtr pTail = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aTailPoly.getB2DPolygon()), false, bBezier);
685 SdrObjectUniquePtr pRet;
686 if (pTail && !pRect)
687 pRet = std::move(pTail);
688 else if (pRect && !pTail)
689 pRet = std::move(pRect);
690 else if (pTail && pRect)
692 if (pTail->GetSubList())
694 pTail->GetSubList()->NbcInsertObject(pRect.release());
695 pRet = std::move(pTail);
697 else if (pRect->GetSubList())
699 pRect->GetSubList()->NbcInsertObject(pTail.release(),0);
700 pRet = std::move(pRect);
702 else
704 SdrObjGroup* pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
705 pGrp->GetSubList()->NbcInsertObject(pRect.release());
706 pGrp->GetSubList()->NbcInsertObject(pTail.release(),0);
707 pRet.reset(pGrp);
710 return pRet;
713 namespace {
715 void handleNegativeScale(basegfx::B2DTuple & scale, double * rotate) {
716 assert(rotate != nullptr);
718 // #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
719 // in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
720 if(basegfx::fTools::less(scale.getX(), 0.0) && basegfx::fTools::less(scale.getY(), 0.0))
722 scale.setX(fabs(scale.getX()));
723 scale.setY(fabs(scale.getY()));
724 *rotate = fmod(*rotate + F_PI, F_2PI);
730 // #i32599#
731 // Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
732 void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
734 // break up matrix
735 basegfx::B2DTuple aScale;
736 basegfx::B2DTuple aTranslate;
737 double fRotate, fShearX;
738 rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
740 handleNegativeScale(aScale, &fRotate);
742 // if anchor is used, make position relative to it
743 if(getSdrModelFromSdrObject().IsWriter())
745 if(GetAnchorPos().X() || GetAnchorPos().Y())
747 aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
751 // build BaseRect
752 Point aPoint(FRound(aTranslate.getX()), FRound(aTranslate.getY()));
753 tools::Rectangle aBaseRect(aPoint, Size(FRound(aScale.getX()), FRound(aScale.getY())));
755 // set BaseRect, but rescue TailPos over this call
756 const Point aTailPoint = GetTailPos();
757 SetSnapRect(aBaseRect);
758 SetTailPos(aTailPoint);
759 ImpRecalcTail();
762 // geometry access
763 basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
765 return aTailPoly.getB2DPolygon();
768 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */