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 <rtl/ustrbuf.hxx>
32 #include <tools/debug.hxx>
33 #include <vcl/ptrstyle.hxx>
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(
61 const tools::Rectangle
& rRect
)
62 : SdrTextObj(rSdrModel
, rRect
)
67 SdrRectObj::SdrRectObj(
69 SdrObjKind eNewTextKind
)
70 : SdrTextObj(rSdrModel
, eNewTextKind
)
72 DBG_ASSERT(eTextKind
==OBJ_TEXT
||
73 eTextKind
==OBJ_OUTLINETEXT
|| eTextKind
==OBJ_TITLETEXT
,
74 "SdrRectObj::SdrRectObj(SdrObjKind) can only be applied to text frames.");
78 SdrRectObj::SdrRectObj(
80 SdrObjKind eNewTextKind
,
81 const tools::Rectangle
& rRect
)
82 : SdrTextObj(rSdrModel
, eNewTextKind
, rRect
)
84 DBG_ASSERT(eTextKind
==OBJ_TEXT
||
85 eTextKind
==OBJ_OUTLINETEXT
|| eTextKind
==OBJ_TITLETEXT
,
86 "SdrRectObj::SdrRectObj(SdrObjKind,...) can only be applied to text frames.");
90 SdrRectObj::~SdrRectObj()
94 void SdrRectObj::SetXPolyDirty()
99 XPolygon
SdrRectObj::ImpCalcXPoly(const tools::Rectangle
& rRect1
, tools::Long nRad1
) const
101 XPolygon
aXPoly(rRect1
,nRad1
,nRad1
);
102 const sal_uInt16
nPointCnt(aXPoly
.GetPointCount());
103 XPolygon
aNewPoly(nPointCnt
+1);
104 sal_uInt16 nShift
=nPointCnt
-2;
105 if (nRad1
!=0) nShift
=nPointCnt
-5;
107 for (sal_uInt16 i
=1; i
<nPointCnt
; i
++) {
108 aNewPoly
[i
]=aXPoly
[j
];
109 aNewPoly
.SetFlags(i
,aXPoly
.GetFlags(j
));
111 if (j
>=nPointCnt
) j
=1;
113 aNewPoly
[0]=rRect1
.BottomCenter();
114 aNewPoly
[nPointCnt
]=aNewPoly
[0];
117 // these angles always relate to the top left corner of aRect
118 if (aGeo
.nShearAngle
!=0) ShearXPoly(aXPoly
,maRect
.TopLeft(),aGeo
.nTan
);
119 if (aGeo
.nRotationAngle
!=0) RotateXPoly(aXPoly
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
123 void SdrRectObj::RecalcXPoly()
125 mpXPoly
.reset( new XPolygon(ImpCalcXPoly(maRect
,GetEckenradius())) );
128 const XPolygon
& SdrRectObj::GetXPoly() const
132 const_cast<SdrRectObj
*>(this)->RecalcXPoly();
138 void SdrRectObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
140 bool bNoTextFrame
=!IsTextFrame();
141 rInfo
.bResizeFreeAllowed
=bNoTextFrame
|| aGeo
.nRotationAngle
%9000==0;
142 rInfo
.bResizePropAllowed
=true;
143 rInfo
.bRotateFreeAllowed
=true;
144 rInfo
.bRotate90Allowed
=true;
145 rInfo
.bMirrorFreeAllowed
=bNoTextFrame
;
146 rInfo
.bMirror45Allowed
=bNoTextFrame
;
147 rInfo
.bMirror90Allowed
=bNoTextFrame
;
149 // allow transparency
150 rInfo
.bTransparenceAllowed
= true;
152 rInfo
.bShearAllowed
=bNoTextFrame
;
153 rInfo
.bEdgeRadiusAllowed
=true;
155 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
156 if (bCanConv
&& !bNoTextFrame
&& !HasText()) {
157 bCanConv
=HasFill() || HasLine();
159 rInfo
.bCanConvToPath
=bCanConv
;
160 rInfo
.bCanConvToPoly
=bCanConv
;
161 rInfo
.bCanConvToContour
= (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
164 SdrObjKind
SdrRectObj::GetObjIdentifier() const
166 if (IsTextFrame()) return eTextKind
;
167 else return OBJ_RECT
;
170 void SdrRectObj::TakeUnrotatedSnapRect(tools::Rectangle
& rRect
) const
173 if (aGeo
.nShearAngle
==0)
176 tools::Long nDst
=FRound((maRect
.Bottom()-maRect
.Top())*aGeo
.nTan
);
177 if (aGeo
.nShearAngle
>0)
179 Point
aRef(rRect
.TopLeft());
180 rRect
.AdjustLeft( -nDst
);
181 Point
aTmpPt(rRect
.TopLeft());
182 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
183 aTmpPt
-=rRect
.TopLeft();
184 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
188 rRect
.AdjustRight( -nDst
);
192 OUString
SdrRectObj::TakeObjNameSingul() const
196 return SdrTextObj::TakeObjNameSingul();
199 OUStringBuffer sName
;
201 bool bRounded
= GetEckenradius() != 0; // rounded down
202 const char* pResId
= bRounded
? STR_ObjNameSingulRECTRND
: STR_ObjNameSingulRECT
;
203 if (aGeo
.nShearAngle
!=0)
205 pResId
= bRounded
? STR_ObjNameSingulPARALRND
: STR_ObjNameSingulPARAL
; // parallelogram or, maybe, rhombus
207 else if (maRect
.GetWidth() == maRect
.GetHeight())
209 pResId
= bRounded
? STR_ObjNameSingulQUADRND
: STR_ObjNameSingulQUAD
; // square
211 sName
.append(SvxResId(pResId
));
213 OUString
aName(GetName());
214 if (!aName
.isEmpty())
222 return sName
.makeStringAndClear();
225 OUString
SdrRectObj::TakeObjNamePlural() const
229 return SdrTextObj::TakeObjNamePlural();
232 bool bRounded
= GetEckenradius() != 0; // rounded down
233 const char* pResId
= bRounded
? STR_ObjNamePluralRECTRND
: STR_ObjNamePluralRECT
;
234 if (aGeo
.nShearAngle
!=0)
236 pResId
= bRounded
? STR_ObjNamePluralPARALRND
: STR_ObjNamePluralPARAL
; // parallelogram or rhombus
238 else if (maRect
.GetWidth() == maRect
.GetHeight())
240 pResId
= bRounded
? STR_ObjNamePluralQUADRND
: STR_ObjNamePluralQUAD
; // square
243 return SvxResId(pResId
);
246 SdrRectObj
* SdrRectObj::CloneSdrObject(SdrModel
& rTargetModel
) const
248 return CloneHelper
< SdrRectObj
>(rTargetModel
);
251 SdrRectObj
& SdrRectObj::operator=(const SdrRectObj
& rCopy
)
253 if ( this == &rCopy
)
256 SdrTextObj::operator=( rCopy
);
259 mpXPoly
.reset( new XPolygon( *rCopy
.mpXPoly
) );
266 basegfx::B2DPolyPolygon
SdrRectObj::TakeXorPoly() const
269 aXPP
.Insert(ImpCalcXPoly(maRect
,GetEckenradius()));
270 return aXPP
.getB2DPolyPolygon();
273 void SdrRectObj::RecalcSnapRect()
275 tools::Long nEckRad
=GetEckenradius();
276 if ((aGeo
.nRotationAngle
!=0 || aGeo
.nShearAngle
!=0) && nEckRad
!=0) {
277 maSnapRect
=GetXPoly().GetBoundRect();
279 SdrTextObj::RecalcSnapRect();
283 void SdrRectObj::NbcSetSnapRect(const tools::Rectangle
& rRect
)
285 SdrTextObj::NbcSetSnapRect(rRect
);
289 void SdrRectObj::NbcSetLogicRect(const tools::Rectangle
& rRect
)
291 SdrTextObj::NbcSetLogicRect(rRect
);
295 sal_uInt32
SdrRectObj::GetHdlCount() const
297 return IsTextFrame() ? 10 : 9;
300 void SdrRectObj::AddToHdlList(SdrHdlList
& rHdlList
) const
302 // A text box has an additional (pseudo-)handle for the blinking frame.
305 OSL_ENSURE(!IsTextEditActive(), "Do not use an ImpTextframeHdl for highlighting text in active text edit, this will collide with EditEngine paints (!)");
306 std::unique_ptr
<SdrHdl
> pH(new ImpTextframeHdl(maRect
));
307 pH
->SetObj(const_cast<SdrRectObj
*>(this));
308 pH
->SetRotationAngle(aGeo
.nRotationAngle
);
309 rHdlList
.AddHdl(std::move(pH
));
312 for(sal_Int32 nHdlNum
= 1; nHdlNum
<= 9; ++nHdlNum
)
315 SdrHdlKind eKind
= SdrHdlKind::Move
;
319 case 1: // Handle for changing the corner radius
321 tools::Long a
= GetEckenradius();
322 tools::Long b
= std::max(maRect
.GetWidth(),maRect
.GetHeight())/2; // rounded up, because GetWidth() adds 1
325 aPnt
=maRect
.TopLeft();
327 eKind
= SdrHdlKind::Circle
;
330 case 2: aPnt
=maRect
.TopLeft(); eKind
= SdrHdlKind::UpperLeft
; break;
331 case 3: aPnt
=maRect
.TopCenter(); eKind
= SdrHdlKind::Upper
; break;
332 case 4: aPnt
=maRect
.TopRight(); eKind
= SdrHdlKind::UpperRight
; break;
333 case 5: aPnt
=maRect
.LeftCenter(); eKind
= SdrHdlKind::Left
; break;
334 case 6: aPnt
=maRect
.RightCenter(); eKind
= SdrHdlKind::Right
; break;
335 case 7: aPnt
=maRect
.BottomLeft(); eKind
= SdrHdlKind::LowerLeft
; break;
336 case 8: aPnt
=maRect
.BottomCenter(); eKind
= SdrHdlKind::Lower
; break;
337 case 9: aPnt
=maRect
.BottomRight(); eKind
= SdrHdlKind::LowerRight
; break;
342 ShearPoint(aPnt
,maRect
.TopLeft(),aGeo
.nTan
);
344 if(aGeo
.nRotationAngle
)
346 RotatePoint(aPnt
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
349 std::unique_ptr
<SdrHdl
> pH(new SdrHdl(aPnt
,eKind
));
350 pH
->SetObj(const_cast<SdrRectObj
*>(this));
351 pH
->SetRotationAngle(aGeo
.nRotationAngle
);
352 rHdlList
.AddHdl(std::move(pH
));
356 bool SdrRectObj::hasSpecialDrag() const
361 bool SdrRectObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
363 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
367 rDrag
.SetEndDragChangesAttributes(true);
372 return SdrTextObj::beginSpecialDrag(rDrag
);
375 bool SdrRectObj::applySpecialDrag(SdrDragStat
& rDrag
)
377 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
381 Point
aPt(rDrag
.GetNow());
383 if(aGeo
.nRotationAngle
)
384 RotatePoint(aPt
,maRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
386 sal_Int32
nRad(aPt
.X() - maRect
.Left());
391 if(nRad
!= GetEckenradius())
393 NbcSetEckenradius(nRad
);
400 return SdrTextObj::applySpecialDrag(rDrag
);
404 OUString
SdrRectObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
406 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
414 const bool bRad(rDrag
.GetHdl() && SdrHdlKind::Circle
== rDrag
.GetHdl()->GetKind());
418 Point
aPt(rDrag
.GetNow());
421 if(aGeo
.nRotationAngle
)
422 RotatePoint(aPt
, maRect
.TopLeft(), -aGeo
.nSin
, aGeo
.nCos
);
424 sal_Int32
nRad(aPt
.X() - maRect
.Left());
429 OUStringBuffer
aBuf(ImpGetDescriptionStr(STR_DragRectEckRad
));
431 aBuf
.append(GetMetrStr(nRad
));
434 return aBuf
.makeStringAndClear();
438 return SdrTextObj::getSpecialDragComment(rDrag
);
444 basegfx::B2DPolyPolygon
SdrRectObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
446 tools::Rectangle aRect1
;
447 rDrag
.TakeCreateRect(aRect1
);
450 basegfx::B2DPolyPolygon aRetval
;
451 aRetval
.append(ImpCalcXPoly(aRect1
,GetEckenradius()).getB2DPolygon());
455 PointerStyle
SdrRectObj::GetCreatePointer() const
457 if (IsTextFrame()) return PointerStyle::DrawText
;
458 return PointerStyle::DrawRect
;
461 void SdrRectObj::NbcMove(const Size
& rSiz
)
463 SdrTextObj::NbcMove(rSiz
);
467 void SdrRectObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
469 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
473 void SdrRectObj::NbcRotate(const Point
& rRef
, tools::Long nAngle
, double sn
, double cs
)
475 SdrTextObj::NbcRotate(rRef
,nAngle
,sn
,cs
);
479 void SdrRectObj::NbcShear(const Point
& rRef
, tools::Long nAngle
, double tn
, bool bVShear
)
481 SdrTextObj::NbcShear(rRef
,nAngle
,tn
,bVShear
);
485 void SdrRectObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
487 SdrTextObj::NbcMirror(rRef1
,rRef2
);
491 SdrGluePoint
SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum
) const
493 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
496 if(!LineIsOutsideGeometry())
504 case 0: aPt
=maRect
.TopCenter(); aPt
.AdjustY( -nWdt
); break;
505 case 1: aPt
=maRect
.RightCenter(); aPt
.AdjustX(nWdt
); break;
506 case 2: aPt
=maRect
.BottomCenter(); aPt
.AdjustY(nWdt
); break;
507 case 3: aPt
=maRect
.LeftCenter(); aPt
.AdjustX( -nWdt
); break;
509 if (aGeo
.nShearAngle
!=0) ShearPoint(aPt
,maRect
.TopLeft(),aGeo
.nTan
);
510 if (aGeo
.nRotationAngle
!=0) RotatePoint(aPt
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
511 aPt
-=GetSnapRect().Center();
512 SdrGluePoint
aGP(aPt
);
513 aGP
.SetPercent(false);
517 SdrGluePoint
SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum
) const
519 sal_Int32 nWdt
= ImpGetLineWdt(); // #i25616#
522 if(!LineIsOutsideGeometry())
530 case 0: aPt
=maRect
.TopLeft(); aPt
.AdjustX( -nWdt
); aPt
.AdjustY( -nWdt
); break;
531 case 1: aPt
=maRect
.TopRight(); aPt
.AdjustX(nWdt
); aPt
.AdjustY( -nWdt
); break;
532 case 2: aPt
=maRect
.BottomRight(); aPt
.AdjustX(nWdt
); aPt
.AdjustY(nWdt
); break;
533 case 3: aPt
=maRect
.BottomLeft(); aPt
.AdjustX( -nWdt
); aPt
.AdjustY(nWdt
); break;
535 if (aGeo
.nShearAngle
!=0) ShearPoint(aPt
,maRect
.TopLeft(),aGeo
.nTan
);
536 if (aGeo
.nRotationAngle
!=0) RotatePoint(aPt
,maRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
537 aPt
-=GetSnapRect().Center();
538 SdrGluePoint
aGP(aPt
);
539 aGP
.SetPercent(false);
543 SdrObjectUniquePtr
SdrRectObj::DoConvertToPolyObj(bool bBezier
, bool bAddText
) const
545 XPolygon
aXP(ImpCalcXPoly(maRect
,GetEckenradius()));
546 { // TODO: this is only for the moment, until we have the new TakeContour()
548 aXP
[aXP
.GetPointCount()-1]=aXP
[0];
551 basegfx::B2DPolyPolygon
aPolyPolygon(aXP
.getB2DPolygon());
552 aPolyPolygon
.removeDoublePoints();
553 SdrObjectUniquePtr pRet
;
555 // small correction: Do not create something when no fill and no line. To
556 // be sure to not damage something with non-text frames, do this only
557 // when used with bAddText==false from other converters
558 if((bAddText
&& !IsTextFrame()) || HasFill() || HasLine())
560 pRet
= ImpConvertMakeObj(aPolyPolygon
, true, bBezier
);
565 pRet
= ImpConvertAddText(std::move(pRet
), bBezier
);
571 void SdrRectObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
573 SdrTextObj::Notify(rBC
,rHint
);
574 SetXPolyDirty(); // because of the corner radius
577 void SdrRectObj::RestGeoData(const SdrObjGeoData
& rGeo
)
579 SdrTextObj::RestGeoData(rGeo
);
583 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */