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/svdorect.hxx>
21 #include <svx/xpoly.hxx>
22 #include <svx/svdtrans.hxx>
23 #include <svx/svddrag.hxx>
24 #include <svx/svdmodel.hxx>
25 #include <svx/svdview.hxx>
26 #include <svx/svdopath.hxx>
27 #include <svx/dialmgr.hxx>
28 #include <svx/strings.hrc>
29 #include <sdr/properties/rectangleproperties.hxx>
30 #include <sdr/contact/viewcontactofsdrrectobj.hxx>
31 #include <tools/debug.hxx>
32 #include <vcl/ptrstyle.hxx>
33 #include <osl/diagnose.h>
35 using namespace com::sun::star
;
37 // BaseProperties section
39 std::unique_ptr
<sdr::properties::BaseProperties
> SdrRectObj::CreateObjectSpecificProperties()
41 return std::make_unique
<sdr::properties::RectangleProperties
>(*this);
45 // DrawContact section
47 std::unique_ptr
<sdr::contact::ViewContact
> SdrRectObj::CreateObjectSpecificViewContact()
49 return std::make_unique
<sdr::contact::ViewContactOfSdrRectObj
>(*this);
53 SdrRectObj::SdrRectObj(SdrModel
& rSdrModel
)
54 : SdrTextObj(rSdrModel
)
59 SdrRectObj::SdrRectObj(SdrModel
& rSdrModel
, SdrRectObj
const & rSource
)
60 : SdrTextObj(rSdrModel
, rSource
)
63 mpXPoly
= rSource
.mpXPoly
;
66 SdrRectObj::SdrRectObj(
68 const tools::Rectangle
& rRect
)
69 : SdrTextObj(rSdrModel
, rRect
)
74 SdrRectObj::SdrRectObj(
76 SdrObjKind eNewTextKind
)
77 : SdrTextObj(rSdrModel
, eNewTextKind
)
79 DBG_ASSERT(meTextKind
== SdrObjKind::Text
||
80 meTextKind
== SdrObjKind::OutlineText
|| meTextKind
== SdrObjKind::TitleText
,
81 "SdrRectObj::SdrRectObj(SdrObjKind) can only be applied to text frames.");
85 SdrRectObj::SdrRectObj(
87 SdrObjKind eNewTextKind
,
88 const tools::Rectangle
& rRect
)
89 : SdrTextObj(rSdrModel
, eNewTextKind
, rRect
)
91 DBG_ASSERT(meTextKind
== SdrObjKind::Text
||
92 meTextKind
== SdrObjKind::OutlineText
|| meTextKind
== SdrObjKind::TitleText
,
93 "SdrRectObj::SdrRectObj(SdrObjKind,...) can only be applied to text frames.");
97 SdrRectObj::~SdrRectObj()
101 void SdrRectObj::SetXPolyDirty()
106 XPolygon
SdrRectObj::ImpCalcXPoly(const tools::Rectangle
& rRect1
, tools::Long nRad1
) const
108 XPolygon
aXPoly(rRect1
,nRad1
,nRad1
);
109 const sal_uInt16
nPointCnt(aXPoly
.GetPointCount());
110 XPolygon
aNewPoly(nPointCnt
+1);
111 sal_uInt16 nShift
=nPointCnt
-2;
112 if (nRad1
!=0) nShift
=nPointCnt
-5;
114 for (sal_uInt16 i
=1; i
<nPointCnt
; i
++) {
115 aNewPoly
[i
]=aXPoly
[j
];
116 aNewPoly
.SetFlags(i
,aXPoly
.GetFlags(j
));
118 if (j
>=nPointCnt
) j
=1;
120 aNewPoly
[0]=rRect1
.BottomCenter();
121 aNewPoly
[nPointCnt
]=aNewPoly
[0];
122 aXPoly
=std::move(aNewPoly
);
124 // these angles always relate to the top left corner of aRect
125 if (maGeo
.m_nShearAngle
) ShearXPoly(aXPoly
, getRectangle().TopLeft(), maGeo
.mfTanShearAngle
);
126 if (maGeo
.m_nRotationAngle
) RotateXPoly(aXPoly
, getRectangle().TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
130 void SdrRectObj::RecalcXPoly()
132 mpXPoly
= ImpCalcXPoly(getRectangle(), GetEckenradius());
135 const XPolygon
& SdrRectObj::GetXPoly() const
139 const_cast<SdrRectObj
*>(this)->RecalcXPoly();
145 void SdrRectObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
147 bool bNoTextFrame
=!IsTextFrame();
148 rInfo
.bResizeFreeAllowed
=bNoTextFrame
|| ((maGeo
.m_nRotationAngle
.get() % 9000) == 0);
149 rInfo
.bResizePropAllowed
=true;
150 rInfo
.bRotateFreeAllowed
=true;
151 rInfo
.bRotate90Allowed
=true;
152 rInfo
.bMirrorFreeAllowed
=bNoTextFrame
;
153 rInfo
.bMirror45Allowed
=bNoTextFrame
;
154 rInfo
.bMirror90Allowed
=bNoTextFrame
;
156 // allow transparency
157 rInfo
.bTransparenceAllowed
= true;
159 rInfo
.bShearAllowed
=bNoTextFrame
;
160 rInfo
.bEdgeRadiusAllowed
=true;
162 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
163 if (bCanConv
&& !bNoTextFrame
&& !HasText()) {
164 bCanConv
=HasFill() || HasLine();
166 rInfo
.bCanConvToPath
=bCanConv
;
167 rInfo
.bCanConvToPoly
=bCanConv
;
168 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
171 SdrObjKind
SdrRectObj::GetObjIdentifier() const
175 else return SdrObjKind::Rectangle
;
178 void SdrRectObj::TakeUnrotatedSnapRect(tools::Rectangle
& rRect
) const
180 rRect
= getRectangle();
181 if (maGeo
.m_nShearAngle
==0_deg100
)
184 tools::Long nDst
=basegfx::fround
<tools::Long
>((getRectangle().Bottom()-getRectangle().Top()) * maGeo
.mfTanShearAngle
);
185 if (maGeo
.m_nShearAngle
>0_deg100
)
187 Point
aRef(rRect
.TopLeft());
188 rRect
.AdjustLeft( -nDst
);
189 Point
aTmpPt(rRect
.TopLeft());
190 RotatePoint(aTmpPt
,aRef
,maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
191 aTmpPt
-=rRect
.TopLeft();
192 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
196 rRect
.AdjustRight( -nDst
);
200 OUString
SdrRectObj::TakeObjNameSingul() const
204 return SdrTextObj::TakeObjNameSingul();
207 bool bRounded
= GetEckenradius() != 0; // rounded down
208 TranslateId pResId
= bRounded
? STR_ObjNameSingulRECTRND
: STR_ObjNameSingulRECT
;
209 if (maGeo
.m_nShearAngle
)
211 pResId
= bRounded
? STR_ObjNameSingulPARALRND
: STR_ObjNameSingulPARAL
; // parallelogram or, maybe, rhombus
213 else if (getRectangle().GetWidth() == getRectangle().GetHeight())
215 pResId
= bRounded
? STR_ObjNameSingulQUADRND
: STR_ObjNameSingulQUAD
; // square
217 OUString
sName(SvxResId(pResId
));
219 OUString
aName(GetName());
220 if (!aName
.isEmpty())
221 sName
+= " '" + aName
+ "'";
226 OUString
SdrRectObj::TakeObjNamePlural() const
230 return SdrTextObj::TakeObjNamePlural();
233 bool bRounded
= GetEckenradius() != 0; // rounded down
234 TranslateId pResId
= bRounded
? STR_ObjNamePluralRECTRND
: STR_ObjNamePluralRECT
;
235 if (maGeo
.m_nShearAngle
)
237 pResId
= bRounded
? STR_ObjNamePluralPARALRND
: STR_ObjNamePluralPARAL
; // parallelogram or rhombus
239 else if (getRectangle().GetWidth() == getRectangle().GetHeight())
241 pResId
= bRounded
? STR_ObjNamePluralQUADRND
: STR_ObjNamePluralQUAD
; // square
244 return SvxResId(pResId
);
247 rtl::Reference
<SdrObject
> SdrRectObj::CloneSdrObject(SdrModel
& rTargetModel
) const
249 return new SdrRectObj(rTargetModel
, *this);
252 basegfx::B2DPolyPolygon
SdrRectObj::TakeXorPoly() const
255 aXPP
.Insert(ImpCalcXPoly(getRectangle(), GetEckenradius()));
256 return aXPP
.getB2DPolyPolygon();
259 void SdrRectObj::RecalcSnapRect()
261 tools::Long nEckRad
=GetEckenradius();
262 if ((maGeo
.m_nRotationAngle
|| maGeo
.m_nShearAngle
) && nEckRad
!=0) {
263 maSnapRect
=GetXPoly().GetBoundRect();
265 SdrTextObj::RecalcSnapRect();
269 void SdrRectObj::NbcSetSnapRect(const tools::Rectangle
& rRect
)
271 SdrTextObj::NbcSetSnapRect(rRect
);
275 void SdrRectObj::NbcSetLogicRect(const tools::Rectangle
& rRect
, bool bAdaptTextMinSize
)
277 SdrTextObj::NbcSetLogicRect(rRect
, bAdaptTextMinSize
);
281 sal_uInt32
SdrRectObj::GetHdlCount() const
283 return IsTextFrame() ? 10 : 9;
286 void SdrRectObj::AddToHdlList(SdrHdlList
& rHdlList
) const
288 // A text box has an additional (pseudo-)handle for the blinking frame.
291 OSL_ENSURE(!IsTextEditActive(), "Do not use an ImpTextframeHdl for highlighting text in active text edit, this will collide with EditEngine paints (!)");
292 std::unique_ptr
<SdrHdl
> pH(new ImpTextframeHdl(getRectangle()));
293 pH
->SetObj(const_cast<SdrRectObj
*>(this));
294 pH
->SetRotationAngle(maGeo
.m_nRotationAngle
);
295 rHdlList
.AddHdl(std::move(pH
));
298 for(sal_Int32 nHdlNum
= 1; nHdlNum
<= 9; ++nHdlNum
)
301 SdrHdlKind eKind
= SdrHdlKind::Move
;
302 auto const& rRectangle
= getRectangle();
305 case 1: // Handle for changing the corner radius
307 tools::Long a
= GetEckenradius();
308 tools::Long b
= std::max(rRectangle
.GetWidth(), rRectangle
.GetHeight())/2; // rounded up, because GetWidth() adds 1
311 aPnt
= rRectangle
.TopLeft();
313 eKind
= SdrHdlKind::Circle
;
316 case 2: aPnt
= rRectangle
.TopLeft(); eKind
= SdrHdlKind::UpperLeft
; break;
317 case 3: aPnt
= rRectangle
.TopCenter(); eKind
= SdrHdlKind::Upper
; break;
318 case 4: aPnt
= rRectangle
.TopRight(); eKind
= SdrHdlKind::UpperRight
; break;
319 case 5: aPnt
= rRectangle
.LeftCenter(); eKind
= SdrHdlKind::Left
; break;
320 case 6: aPnt
= rRectangle
.RightCenter(); eKind
= SdrHdlKind::Right
; break;
321 case 7: aPnt
= rRectangle
.BottomLeft(); eKind
= SdrHdlKind::LowerLeft
; break;
322 case 8: aPnt
= rRectangle
.BottomCenter(); eKind
= SdrHdlKind::Lower
; break;
323 case 9: aPnt
= rRectangle
.BottomRight(); eKind
= SdrHdlKind::LowerRight
; break;
326 if (maGeo
.m_nShearAngle
)
328 ShearPoint(aPnt
,rRectangle
.TopLeft(),maGeo
.mfTanShearAngle
);
330 if (maGeo
.m_nRotationAngle
)
332 RotatePoint(aPnt
,rRectangle
.TopLeft(),maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
335 std::unique_ptr
<SdrHdl
> pH(new SdrHdl(aPnt
,eKind
));
336 pH
->SetObj(const_cast<SdrRectObj
*>(this));
337 pH
->SetRotationAngle(maGeo
.m_nRotationAngle
);
338 rHdlList
.AddHdl(std::move(pH
));
342 bool SdrRectObj::hasSpecialDrag() const
347 bool SdrRectObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
349 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
353 rDrag
.SetEndDragChangesAttributes(true);
358 return SdrTextObj::beginSpecialDrag(rDrag
);
361 bool SdrRectObj::applySpecialDrag(SdrDragStat
& rDrag
)
363 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
367 Point
aPt(rDrag
.GetNow());
369 if (maGeo
.m_nRotationAngle
)
370 RotatePoint(aPt
, getRectangle().TopLeft(), -maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
372 sal_Int32
nRad(aPt
.X() - getRectangle().Left());
377 if(nRad
!= GetEckenradius())
379 NbcSetEckenradius(nRad
);
386 return SdrTextObj::applySpecialDrag(rDrag
);
390 OUString
SdrRectObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
392 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
400 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
404 Point
aPt(rDrag
.GetNow());
407 if (maGeo
.m_nRotationAngle
)
408 RotatePoint(aPt
, getRectangle().TopLeft(), -maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
410 sal_Int32
nRad(aPt
.X() - getRectangle().Left());
415 return ImpGetDescriptionStr(STR_DragRectEckRad
) +
422 return SdrTextObj::getSpecialDragComment(rDrag
);
428 basegfx::B2DPolyPolygon
SdrRectObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
430 tools::Rectangle aRect1
;
431 rDrag
.TakeCreateRect(aRect1
);
434 basegfx::B2DPolyPolygon aRetval
;
435 aRetval
.append(ImpCalcXPoly(aRect1
,GetEckenradius()).getB2DPolygon());
439 PointerStyle
SdrRectObj::GetCreatePointer() const
441 if (IsTextFrame()) return PointerStyle::DrawText
;
442 return PointerStyle::DrawRect
;
445 void SdrRectObj::NbcMove(const Size
& rSiz
)
447 SdrTextObj::NbcMove(rSiz
);
451 void SdrRectObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
453 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
457 void SdrRectObj::NbcRotate(const Point
& rRef
, Degree100 nAngle
, double sn
, double cs
)
459 SdrTextObj::NbcRotate(rRef
,nAngle
,sn
,cs
);
463 void SdrRectObj::NbcShear(const Point
& rRef
, Degree100 nAngle
, double tn
, bool bVShear
)
465 SdrTextObj::NbcShear(rRef
,nAngle
,tn
,bVShear
);
469 void SdrRectObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
471 SdrTextObj::NbcMirror(rRef1
,rRef2
);
475 SdrGluePoint
SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum
) const
477 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
480 if(!LineIsOutsideGeometry())
487 auto const& rRectangle
= getRectangle();
489 case 0: aPt
= rRectangle
.TopCenter(); aPt
.AdjustY( -nWdt
); break;
490 case 1: aPt
= rRectangle
.RightCenter(); aPt
.AdjustX(nWdt
); break;
491 case 2: aPt
= rRectangle
.BottomCenter(); aPt
.AdjustY(nWdt
); break;
492 case 3: aPt
= rRectangle
.LeftCenter(); aPt
.AdjustX( -nWdt
); break;
494 if (maGeo
.m_nShearAngle
)
495 ShearPoint(aPt
, rRectangle
.TopLeft(), maGeo
.mfTanShearAngle
);
496 if (maGeo
.m_nRotationAngle
)
497 RotatePoint(aPt
, rRectangle
.TopLeft(), maGeo
.mfSinRotationAngle
, maGeo
.mfCosRotationAngle
);
498 aPt
-=GetSnapRect().Center();
499 SdrGluePoint
aGP(aPt
);
500 aGP
.SetPercent(false);
504 SdrGluePoint
SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum
) const
506 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
509 if(!LineIsOutsideGeometry())
516 auto const& rRectangle
= getRectangle();
518 case 0: aPt
= rRectangle
.TopLeft(); aPt
.AdjustX( -nWdt
); aPt
.AdjustY( -nWdt
); break;
519 case 1: aPt
= rRectangle
.TopRight(); aPt
.AdjustX(nWdt
); aPt
.AdjustY( -nWdt
); break;
520 case 2: aPt
= rRectangle
.BottomRight(); aPt
.AdjustX(nWdt
); aPt
.AdjustY(nWdt
); break;
521 case 3: aPt
= rRectangle
.BottomLeft(); aPt
.AdjustX( -nWdt
); aPt
.AdjustY(nWdt
); break;
523 if (maGeo
.m_nShearAngle
)
524 ShearPoint(aPt
, rRectangle
.TopLeft(),maGeo
.mfTanShearAngle
);
525 if (maGeo
.m_nRotationAngle
)
526 RotatePoint(aPt
, rRectangle
.TopLeft(),maGeo
.mfSinRotationAngle
,maGeo
.mfCosRotationAngle
);
527 aPt
-=GetSnapRect().Center();
528 SdrGluePoint
aGP(aPt
);
529 aGP
.SetPercent(false);
533 rtl::Reference
<SdrObject
> SdrRectObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
535 XPolygon
aXP(ImpCalcXPoly(getRectangle(), GetEckenradius()));
536 { // TODO: this is only for the moment, until we have the new TakeContour()
538 aXP
[aXP
.GetPointCount()-1]=aXP
[0];
541 basegfx::B2DPolyPolygon
aPolyPolygon(aXP
.getB2DPolygon());
542 aPolyPolygon
.removeDoublePoints();
543 rtl::Reference
<SdrObject
> pRet
;
545 // small correction: Do not create something when no fill and no line. To
546 // be sure to not damage something with non-text frames, do this only
547 // when used with bAddText==false from other converters
548 if((bAddText
&& !IsTextFrame()) || HasFill() || HasLine())
550 pRet
= ImpConvertMakeObj(aPolyPolygon
, true, bBezier
);
555 pRet
= ImpConvertAddText(std::move(pRet
), bBezier
);
561 void SdrRectObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
563 SdrTextObj::Notify(rBC
,rHint
);
564 SetXPolyDirty(); // because of the corner radius
567 void SdrRectObj::RestoreGeoData(const SdrObjGeoData
& rGeo
)
569 SdrTextObj::RestoreGeoData(rGeo
);
573 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */