nss: upgrade to release 3.73
[LibreOffice.git] / svx / source / svdraw / svdorect.cxx
blobc3a2a66c8483973460e5901f2cd145ddd8d11b18
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 <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)
56 bClosedObj=true;
59 SdrRectObj::SdrRectObj(
60 SdrModel& rSdrModel,
61 const tools::Rectangle& rRect)
62 : SdrTextObj(rSdrModel, rRect)
64 bClosedObj=true;
67 SdrRectObj::SdrRectObj(
68 SdrModel& rSdrModel,
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.");
75 bClosedObj=true;
78 SdrRectObj::SdrRectObj(
79 SdrModel& rSdrModel,
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.");
87 bClosedObj=true;
90 SdrRectObj::~SdrRectObj()
94 void SdrRectObj::SetXPolyDirty()
96 mpXPoly.reset();
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;
106 sal_uInt16 j=nShift;
107 for (sal_uInt16 i=1; i<nPointCnt; i++) {
108 aNewPoly[i]=aXPoly[j];
109 aNewPoly.SetFlags(i,aXPoly.GetFlags(j));
110 j++;
111 if (j>=nPointCnt) j=1;
113 aNewPoly[0]=rRect1.BottomCenter();
114 aNewPoly[nPointCnt]=aNewPoly[0];
115 aXPoly=aNewPoly;
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);
120 return aXPoly;
123 void SdrRectObj::RecalcXPoly()
125 mpXPoly.reset( new XPolygon(ImpCalcXPoly(maRect,GetEckenradius())) );
128 const XPolygon& SdrRectObj::GetXPoly() const
130 if(!mpXPoly)
132 const_cast<SdrRectObj*>(this)->RecalcXPoly();
135 return *mpXPoly;
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
172 rRect = maRect;
173 if (aGeo.nShearAngle==0)
174 return;
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());
186 else
188 rRect.AdjustRight( -nDst );
192 OUString SdrRectObj::TakeObjNameSingul() const
194 if (IsTextFrame())
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())
216 sName.append(' ');
217 sName.append('\'');
218 sName.append(aName);
219 sName.append('\'');
222 return sName.makeStringAndClear();
225 OUString SdrRectObj::TakeObjNamePlural() const
227 if (IsTextFrame())
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 )
254 return *this;
256 SdrTextObj::operator=( rCopy );
258 if ( rCopy.mpXPoly )
259 mpXPoly.reset( new XPolygon( *rCopy.mpXPoly ) );
260 else
261 mpXPoly.reset();
263 return *this;
266 basegfx::B2DPolyPolygon SdrRectObj::TakeXorPoly() const
268 XPolyPolygon aXPP;
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();
278 } else {
279 SdrTextObj::RecalcSnapRect();
283 void SdrRectObj::NbcSetSnapRect(const tools::Rectangle& rRect)
285 SdrTextObj::NbcSetSnapRect(rRect);
286 SetXPolyDirty();
289 void SdrRectObj::NbcSetLogicRect(const tools::Rectangle& rRect)
291 SdrTextObj::NbcSetLogicRect(rRect);
292 SetXPolyDirty();
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.
303 if(IsTextFrame())
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)
314 Point aPnt;
315 SdrHdlKind eKind = SdrHdlKind::Move;
317 switch(nHdlNum)
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
323 if (a>b) a=b;
324 if (a<0) a=0;
325 aPnt=maRect.TopLeft();
326 aPnt.AdjustX(a );
327 eKind = SdrHdlKind::Circle;
328 break;
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;
340 if(aGeo.nShearAngle)
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
358 return true;
361 bool SdrRectObj::beginSpecialDrag(SdrDragStat& rDrag) const
363 const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
365 if(bRad)
367 rDrag.SetEndDragChangesAttributes(true);
369 return true;
372 return SdrTextObj::beginSpecialDrag(rDrag);
375 bool SdrRectObj::applySpecialDrag(SdrDragStat& rDrag)
377 const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
379 if (bRad)
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());
388 if (nRad < 0)
389 nRad = 0;
391 if(nRad != GetEckenradius())
393 NbcSetEckenradius(nRad);
396 return true;
398 else
400 return SdrTextObj::applySpecialDrag(rDrag);
404 OUString SdrRectObj::getSpecialDragComment(const SdrDragStat& rDrag) const
406 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
408 if(bCreateComment)
410 return OUString();
412 else
414 const bool bRad(rDrag.GetHdl() && SdrHdlKind::Circle == rDrag.GetHdl()->GetKind());
416 if(bRad)
418 Point aPt(rDrag.GetNow());
420 // -sin for reversal
421 if(aGeo.nRotationAngle)
422 RotatePoint(aPt, maRect.TopLeft(), -aGeo.nSin, aGeo.nCos);
424 sal_Int32 nRad(aPt.X() - maRect.Left());
426 if(nRad < 0)
427 nRad = 0;
429 OUStringBuffer aBuf(ImpGetDescriptionStr(STR_DragRectEckRad));
430 aBuf.append(" (");
431 aBuf.append(GetMetrStr(nRad));
432 aBuf.append(')');
434 return aBuf.makeStringAndClear();
436 else
438 return SdrTextObj::getSpecialDragComment(rDrag);
444 basegfx::B2DPolyPolygon SdrRectObj::TakeCreatePoly(const SdrDragStat& rDrag) const
446 tools::Rectangle aRect1;
447 rDrag.TakeCreateRect(aRect1);
448 aRect1.Justify();
450 basegfx::B2DPolyPolygon aRetval;
451 aRetval.append(ImpCalcXPoly(aRect1,GetEckenradius()).getB2DPolygon());
452 return aRetval;
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);
464 SetXPolyDirty();
467 void SdrRectObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
469 SdrTextObj::NbcResize(rRef,xFact,yFact);
470 SetXPolyDirty();
473 void SdrRectObj::NbcRotate(const Point& rRef, tools::Long nAngle, double sn, double cs)
475 SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
476 SetXPolyDirty();
479 void SdrRectObj::NbcShear(const Point& rRef, tools::Long nAngle, double tn, bool bVShear)
481 SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
482 SetXPolyDirty();
485 void SdrRectObj::NbcMirror(const Point& rRef1, const Point& rRef2)
487 SdrTextObj::NbcMirror(rRef1,rRef2);
488 SetXPolyDirty();
491 SdrGluePoint SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum) const
493 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
495 // #i25616#
496 if(!LineIsOutsideGeometry())
498 nWdt++;
499 nWdt /= 2;
502 Point aPt;
503 switch (nPosNum) {
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);
514 return aGP;
517 SdrGluePoint SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum) const
519 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
521 // #i25616#
522 if(!LineIsOutsideGeometry())
524 nWdt++;
525 nWdt /= 2;
528 Point aPt;
529 switch (nPosNum) {
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);
540 return aGP;
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()
547 aXP.Remove(0,1);
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);
563 if(bAddText)
565 pRet = ImpConvertAddText(std::move(pRet), bBezier);
568 return pRet;
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);
580 SetXPolyDirty();
583 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */