Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svdocapt.cxx
blob98c86664c28aa51120da1a3c1813ed1b316a7fae
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>
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>
55 namespace {
57 enum EscDir {LKS,RTS,OBN,UNT};
61 class ImpCaptParams
63 public:
64 SdrCaptionType eType;
65 tools::Long nGap;
66 tools::Long nEscRel;
67 tools::Long nEscAbs;
68 tools::Long nLineLen;
69 SdrCaptionEscDir eEscDir;
70 bool bFitLineLen;
71 bool bEscRel;
72 bool bFixedAngle;
74 public:
75 ImpCaptParams()
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
88 tools::Long nX,nY;
89 if (bEscRel) {
90 nX=rRect.Right()-rRect.Left();
91 nX=BigMulDiv(nX,nEscRel,10000);
92 nY=rRect.Bottom()-rRect.Top();
93 nY=BigMulDiv(nY,nEscRel,10000);
94 } else {
95 nX=nEscAbs;
96 nY=nEscAbs;
98 nX+=rRect.Left();
99 nY+=rRect.Top();
100 Point aBestPt;
101 EscDir eBestDir=LKS;
102 bool bTryH=eEscDir==SdrCaptionEscDir::BestFit;
103 if (!bTryH) {
104 if (eType!=SdrCaptionType::Type1) {
105 bTryH=eEscDir==SdrCaptionEscDir::Horizontal;
106 } else {
107 bTryH=eEscDir==SdrCaptionEscDir::Vertical;
110 bool bTryV=eEscDir==SdrCaptionEscDir::BestFit;
111 if (!bTryV) {
112 if (eType!=SdrCaptionType::Type1) {
113 bTryV=eEscDir==SdrCaptionEscDir::Vertical;
114 } else {
115 bTryV=eEscDir==SdrCaptionEscDir::Horizontal;
119 if (bTryH) {
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());
123 if (bLft) {
124 eBestDir=LKS;
125 aBestPt=aLft;
126 } else {
127 eBestDir=RTS;
128 aBestPt=aRgt;
131 if (bTryV) {
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());
135 Point aBest2;
136 EscDir eBest2;
137 if (bTop) {
138 eBest2=OBN;
139 aBest2=aTop;
140 } else {
141 eBest2=UNT;
142 aBest2=aBtm;
144 bool bTakeIt=eEscDir!=SdrCaptionEscDir::BestFit;
145 if (!bTakeIt) {
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;
152 } else {
153 bTakeIt=aVerX+aVerY>=aHorX+aHorY;
156 if (bTakeIt) {
157 aBestPt=aBest2;
158 eBestDir=eBest2;
161 rPt=aBestPt;
162 rDir=eBestDir;
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),
186 mbFixedTail(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(
202 SdrModel& rSdrModel,
203 const tools::Rectangle& rRect,
204 const Point& rTail)
205 : SdrRectObj(rSdrModel, SdrObjKind::Text,rRect),
206 aTailPoly(3), // default size: 3 points = 2 lines
207 mbSpecialTextBoxShadow(false),
208 mbFixedTail(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 + "'";
253 return sName;
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());
266 return aPolyPoly;
269 sal_uInt32 SdrCaptionObj::GetHdlCount() const
271 sal_uInt32 nCount1(SdrRectObj::GetHdlCount());
272 // Currently only dragging the tail's end is implemented.
273 return nCount1 + 1;
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));
281 pHdl->SetPolyNum(1);
282 pHdl->SetPointNum(0);
283 rHdlList.AddHdl(std::move(pHdl));
286 bool SdrCaptionObj::hasSpecialDrag() const
288 return true;
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);
301 else
303 rDrag.SetOrtho8Possible();
305 if(!pHdl)
307 if (m_bMovProt)
308 return false;
310 rDrag.SetNoSnap();
311 rDrag.SetActionRect(getRectangle());
313 Point aHit(rDrag.GetStart());
315 if(rDrag.GetPageView() && SdrObjectPrimitiveHit(*this, aHit, {0, 0}, *rDrag.GetPageView(), nullptr, false))
317 return true;
320 else
322 if((1 == pHdl->GetPolyNum()) && (0 == pHdl->GetPointNum()))
323 return true;
327 return false;
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));
337 ImpRecalcTail();
338 ActionChanged();
340 return bRet;
342 else
344 Point aDelta(rDrag.GetNow()-rDrag.GetStart());
346 if(!pHdl)
348 moveRectangle(aDelta.X(), aDelta.Y());
350 else
352 aTailPoly[0] += aDelta;
355 ImpRecalcTail();
356 ActionChanged();
358 return true;
362 OUString SdrCaptionObj::getSpecialDragComment(const SdrDragStat& rDrag) const
364 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
366 if(bCreateComment)
368 return OUString();
370 else
372 const SdrHdl* pHdl = rDrag.GetHdl();
374 if(pHdl && 0 == pHdl->GetPolyNum())
376 return SdrRectObj::getSpecialDragComment(rDrag);
378 else
380 if(!pHdl)
382 return ImpGetDescriptionStr(STR_DragCaptFram);
384 else
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()
409 ImpCaptParams aPara;
410 ImpGetCaptParams(aPara);
411 ImpCalcTail(aPara, aTailPoly, getRectangle());
412 SetBoundAndSnapRectsDirty();
413 SetXPolyDirty();
416 // #i35971#
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);
429 Point aTl(rPoly[0]);
431 aPol[0] = aTl;
432 aPol[1] = aTl;
434 EscDir eEscDir;
435 Point aEscPos;
437 rPara.CalcEscPos(aTl, rRect, aEscPos, eEscDir);
438 aPol[1] = aEscPos;
440 if(eEscDir==LKS || eEscDir==RTS)
442 aPol[0].setX( aEscPos.X() );
444 else
446 aPol[0].setY( aEscPos.Y() );
449 rPoly = aPol;
452 void SdrCaptionObj::ImpCalcTail2(const ImpCaptParams& rPara, tools::Polygon& rPoly, tools::Rectangle const & rRect)
453 { // Gap/EscDir/EscPos/Angle
454 tools::Polygon aPol(2);
455 Point aTl(rPoly[0]);
456 aPol[0]=aTl;
458 EscDir eEscDir;
459 Point aEscPos;
460 rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
461 aPol[1]=aEscPos;
463 if (!rPara.bFixedAngle) {
464 // TODO: Implementation missing.
466 rPoly=aPol;
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);
472 Point aTl(rPoly[0]);
473 aPol[0]=aTl;
475 EscDir eEscDir;
476 Point aEscPos;
477 rPara.CalcEscPos(aTl,rRect,aEscPos,eEscDir);
478 aPol[1]=aEscPos;
479 aPol[2]=aEscPos;
481 if (eEscDir==LKS || eEscDir==RTS) {
482 if (rPara.bFitLineLen) {
483 aPol[1].setX((aTl.X()+aEscPos.X())/2 );
484 } else {
485 if (eEscDir==LKS) aPol[1].AdjustX( -(rPara.nLineLen) );
486 else aPol[1].AdjustX(rPara.nLineLen );
488 } else {
489 if (rPara.bFitLineLen) {
490 aPol[1].setY((aTl.Y()+aEscPos.Y())/2 );
491 } else {
492 if (eEscDir==OBN) aPol[1].AdjustY( -(rPara.nLineLen) );
493 else aPol[1].AdjustY(rPara.nLineLen );
496 if (!rPara.bFixedAngle) {
497 // TODO: Implementation missing.
499 rPoly=aPol;
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
517 ImpCaptParams aPara;
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());
523 return true;
526 bool SdrCaptionObj::MovCreate(SdrDragStat& rStat)
528 ImpCaptParams aPara;
529 ImpGetCaptParams(aPara);
530 moveRectanglePosition(rStat.GetNow().X(), rStat.GetNow().Y());
531 ImpCalcTail(aPara,aTailPoly, getRectangle());
532 rStat.SetActionRect(getRectangle());
533 SetBoundRectDirty();
534 m_bSnapRectDirty=true;
535 return true;
538 bool SdrCaptionObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
540 ImpCaptParams aPara;
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*/)
550 return false;
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());
563 return aRetval;
566 PointerStyle SdrCaptionObj::GetCreatePointer() const
568 return PointerStyle::DrawCaption;
571 void SdrCaptionObj::NbcMove(const Size& rSiz)
573 SdrRectObj::NbcMove(rSiz);
574 MovePoly(aTailPoly,rSiz);
575 if(mbFixedTail)
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);
583 ImpRecalcTail();
584 if(mbFixedTail)
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);
608 ImpRecalcTail();
611 const Point& SdrCaptionObj::GetTailPos() const
613 return aTailPoly[0];
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();
620 NbcSetTailPos(rPos);
621 SetChanged();
622 BroadcastObjectChange();
623 SendUserCall(SdrUserCallType::Resize,aBoundRect0);
627 void SdrCaptionObj::NbcSetTailPos(const Point& rPos)
629 aTailPoly[0]=rPos;
630 ImpRecalcTail();
633 sal_uInt32 SdrCaptionObj::GetSnapPointCount() const
635 // TODO: Implementation missing.
636 return 0;
639 Point SdrCaptionObj::GetSnapPoint(sal_uInt32 /*i*/) const
641 // TODO: Implementation missing.
642 return Point(0,0);
645 void SdrCaptionObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
647 SdrRectObj::Notify(rBC,rHint);
648 ImpRecalcTail();
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;
675 if (pTail && !pRect)
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);
691 else
693 rtl::Reference<SdrObjGroup> pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
694 pGrp->GetSubList()->NbcInsertObject(pRect.get());
695 pGrp->GetSubList()->NbcInsertObject(pTail.get(),0);
696 pRet = pGrp;
699 return pRet;
702 namespace {
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);
719 // #i32599#
720 // Add own implementation for TRSetBaseGeometry to handle TailPos over changes.
721 void SdrCaptionObj::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
723 // break up matrix
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());
740 // build BaseRect
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);
748 ImpRecalcTail();
751 // geometry access
752 basegfx::B2DPolygon SdrCaptionObj::getTailPolygon() const
754 return aTailPoly.getB2DPolygon();
757 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */