bump product version to 5.0.4.1
[LibreOffice.git] / svx / source / svdraw / svdorect.cxx
blob19e87c9134ecbded2cc07a3f79c4b351d2e7d95e
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 <math.h>
22 #include <stdlib.h>
23 #include <svx/xpool.hxx>
24 #include <svx/xpoly.hxx>
25 #include <svx/svdattr.hxx>
26 #include <svx/svdpool.hxx>
27 #include <svx/svdtrans.hxx>
28 #include <svx/svdetc.hxx>
29 #include <svx/svddrag.hxx>
30 #include <svx/svdmodel.hxx>
31 #include <svx/svdpage.hxx>
32 #include <svx/svdocapt.hxx>
33 #include <svx/svdpagv.hxx>
34 #include <svx/svdview.hxx>
35 #include <svx/svdundo.hxx>
36 #include <svx/svdopath.hxx>
37 #include "svdglob.hxx"
38 #include "svx/svdstr.hrc"
39 #include <svx/xflclit.hxx>
40 #include <svx/xlnclit.hxx>
41 #include <svx/xlnwtit.hxx>
42 #include <sdr/properties/rectangleproperties.hxx>
43 #include <svx/sdr/contact/viewcontactofsdrrectobj.hxx>
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
47 using namespace com::sun::star;
49 // BaseProperties section
51 sdr::properties::BaseProperties* SdrRectObj::CreateObjectSpecificProperties()
53 return new sdr::properties::RectangleProperties(*this);
57 // DrawContact section
59 sdr::contact::ViewContact* SdrRectObj::CreateObjectSpecificViewContact()
61 return new sdr::contact::ViewContactOfSdrRectObj(*this);
66 TYPEINIT1(SdrRectObj,SdrTextObj);
68 SdrRectObj::SdrRectObj()
69 : mpXPoly(0L)
71 bClosedObj=true;
74 SdrRectObj::SdrRectObj(const Rectangle& rRect)
75 : SdrTextObj(rRect),
76 mpXPoly(NULL)
78 bClosedObj=true;
81 SdrRectObj::SdrRectObj(SdrObjKind eNewTextKind)
82 : SdrTextObj(eNewTextKind),
83 mpXPoly(NULL)
85 DBG_ASSERT(eTextKind==OBJ_TEXT || eTextKind==OBJ_TEXTEXT ||
86 eTextKind==OBJ_OUTLINETEXT || eTextKind==OBJ_TITLETEXT,
87 "SdrRectObj::SdrRectObj(SdrObjKind) can only be applied to text frames.");
88 bClosedObj=true;
91 SdrRectObj::SdrRectObj(SdrObjKind eNewTextKind, const Rectangle& rRect)
92 : SdrTextObj(eNewTextKind,rRect),
93 mpXPoly(NULL)
95 DBG_ASSERT(eTextKind==OBJ_TEXT || eTextKind==OBJ_TEXTEXT ||
96 eTextKind==OBJ_OUTLINETEXT || eTextKind==OBJ_TITLETEXT,
97 "SdrRectObj::SdrRectObj(SdrObjKind,...) can only be applied to text frames.");
98 bClosedObj=true;
101 SdrRectObj::~SdrRectObj()
103 delete mpXPoly;
106 SdrRectObj& SdrRectObj::operator=(const SdrRectObj& rCopy)
108 if ( this == &rCopy )
109 return *this;
111 SdrTextObj::operator=( rCopy );
113 delete mpXPoly;
115 if ( rCopy.mpXPoly )
116 mpXPoly = new XPolygon( *rCopy.mpXPoly );
117 else
118 mpXPoly = NULL;
120 return *this;
123 void SdrRectObj::SetXPolyDirty()
125 delete mpXPoly;
126 mpXPoly = 0L;
129 XPolygon SdrRectObj::ImpCalcXPoly(const Rectangle& rRect1, long nRad1) const
131 XPolygon aXPoly(rRect1,nRad1,nRad1);
132 const sal_uInt16 nPointAnz(aXPoly.GetPointCount());
133 XPolygon aNeuPoly(nPointAnz+1);
134 sal_uInt16 nShift=nPointAnz-2;
135 if (nRad1!=0) nShift=nPointAnz-5;
136 sal_uInt16 j=nShift;
137 for (sal_uInt16 i=1; i<nPointAnz; i++) {
138 aNeuPoly[i]=aXPoly[j];
139 aNeuPoly.SetFlags(i,aXPoly.GetFlags(j));
140 j++;
141 if (j>=nPointAnz) j=1;
143 aNeuPoly[0]=rRect1.BottomCenter();
144 aNeuPoly[nPointAnz]=aNeuPoly[0];
145 aXPoly=aNeuPoly;
147 // these angles always relate to the top left corner of aRect
148 if (aGeo.nShearAngle!=0) ShearXPoly(aXPoly,maRect.TopLeft(),aGeo.nTan);
149 if (aGeo.nRotationAngle!=0) RotateXPoly(aXPoly,maRect.TopLeft(),aGeo.nSin,aGeo.nCos);
150 return aXPoly;
153 void SdrRectObj::RecalcXPoly()
155 delete mpXPoly;
156 mpXPoly = new XPolygon(ImpCalcXPoly(maRect,GetEckenradius()));
159 const XPolygon& SdrRectObj::GetXPoly() const
161 if(!mpXPoly)
163 const_cast<SdrRectObj*>(this)->RecalcXPoly();
166 return *mpXPoly;
169 void SdrRectObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
171 bool bNoTextFrame=!IsTextFrame();
172 rInfo.bResizeFreeAllowed=bNoTextFrame || aGeo.nRotationAngle%9000==0;
173 rInfo.bResizePropAllowed=true;
174 rInfo.bRotateFreeAllowed=true;
175 rInfo.bRotate90Allowed =true;
176 rInfo.bMirrorFreeAllowed=bNoTextFrame;
177 rInfo.bMirror45Allowed =bNoTextFrame;
178 rInfo.bMirror90Allowed =bNoTextFrame;
180 // allow transparency
181 rInfo.bTransparenceAllowed = true;
183 // gradient depends on fillstyle
184 drawing::FillStyle eFillStyle = static_cast<const XFillStyleItem&>(GetObjectItem(XATTR_FILLSTYLE)).GetValue();
185 rInfo.bGradientAllowed = (eFillStyle == drawing::FillStyle_GRADIENT);
187 rInfo.bShearAllowed =bNoTextFrame;
188 rInfo.bEdgeRadiusAllowed=true;
190 bool bCanConv=!HasText() || ImpCanConvTextToCurve();
191 if (bCanConv && !bNoTextFrame && !HasText()) {
192 bCanConv=HasFill() || HasLine();
194 rInfo.bCanConvToPath =bCanConv;
195 rInfo.bCanConvToPoly =bCanConv;
196 rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
199 sal_uInt16 SdrRectObj::GetObjIdentifier() const
201 if (IsTextFrame()) return sal_uInt16(eTextKind);
202 else return sal_uInt16(OBJ_RECT);
205 void SdrRectObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
207 rRect = maRect;
208 if (aGeo.nShearAngle!=0)
210 long nDst=Round((maRect.Bottom()-maRect.Top())*aGeo.nTan);
211 if (aGeo.nShearAngle>0)
213 Point aRef(rRect.TopLeft());
214 rRect.Left()-=nDst;
215 Point aTmpPt(rRect.TopLeft());
216 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
217 aTmpPt-=rRect.TopLeft();
218 rRect.Move(aTmpPt.X(),aTmpPt.Y());
220 else
222 rRect.Right()-=nDst;
227 OUString SdrRectObj::TakeObjNameSingul() const
229 if (IsTextFrame())
231 return SdrTextObj::TakeObjNameSingul();
234 OUStringBuffer sName;
236 sal_uInt16 nResId=STR_ObjNameSingulRECT;
237 if (aGeo.nShearAngle!=0) {
238 nResId+=4; // parallelogram or, maybe, rhombus
239 } else {
240 if (maRect.GetWidth() == maRect.GetHeight()) nResId+=2; // square
242 if (GetEckenradius()!=0) nResId+=8; // rounded down
243 sName.append(ImpGetResStr(nResId));
245 OUString aName(GetName());
246 if (!aName.isEmpty())
248 sName.append(' ');
249 sName.append('\'');
250 sName.append(aName);
251 sName.append('\'');
254 return sName.makeStringAndClear();
257 OUString SdrRectObj::TakeObjNamePlural() const
259 if (IsTextFrame())
261 return SdrTextObj::TakeObjNamePlural();
264 sal_uInt16 nResId=STR_ObjNamePluralRECT;
266 if (aGeo.nShearAngle!=0)
268 nResId+=4; // parallelogram or rhombus
270 else
272 if (maRect.GetWidth() == maRect.GetHeight())
273 nResId+=2; // square
276 if (GetEckenradius()!=0)
277 nResId+=8; // rounded down
279 return ImpGetResStr(nResId);
282 SdrRectObj* SdrRectObj::Clone() const
284 return CloneHelper< SdrRectObj >();
287 basegfx::B2DPolyPolygon SdrRectObj::TakeXorPoly() const
289 XPolyPolygon aXPP;
290 aXPP.Insert(ImpCalcXPoly(maRect,GetEckenradius()));
291 return aXPP.getB2DPolyPolygon();
294 void SdrRectObj::RecalcSnapRect()
296 long nEckRad=GetEckenradius();
297 if ((aGeo.nRotationAngle!=0 || aGeo.nShearAngle!=0) && nEckRad!=0) {
298 maSnapRect=GetXPoly().GetBoundRect();
299 } else {
300 SdrTextObj::RecalcSnapRect();
304 void SdrRectObj::NbcSetSnapRect(const Rectangle& rRect)
306 SdrTextObj::NbcSetSnapRect(rRect);
307 SetXPolyDirty();
310 void SdrRectObj::NbcSetLogicRect(const Rectangle& rRect)
312 SdrTextObj::NbcSetLogicRect(rRect);
313 SetXPolyDirty();
316 sal_uInt32 SdrRectObj::GetHdlCount() const
318 return IsTextFrame() ? 10 : 9;
321 SdrHdl* SdrRectObj::GetHdl(sal_uInt32 nHdlNum) const
323 SdrHdl* pH = NULL;
324 Point aPnt;
325 SdrHdlKind eKind = HDL_MOVE;
327 if(!IsTextFrame())
329 nHdlNum++;
332 switch(nHdlNum)
334 case 0:
336 OSL_ENSURE(!IsTextEditActive(), "Do not use a ImpTextframeHdl for hilighting text in active text edit, this will collide with EditEngine paints (!)");
337 // hack for calc grid sync to ensure the hatched area
338 // for a textbox is displayed at correct position
339 pH = new ImpTextframeHdl(maRect + GetGridOffset() );
340 pH->SetObj((SdrObject*)this);
341 pH->SetRotationAngle(aGeo.nRotationAngle);
342 break;
344 case 1:
346 long a = GetEckenradius();
347 long b = std::max(maRect.GetWidth(),maRect.GetHeight())/2; // rounded up, because GetWidth() adds 1
348 if (a>b) a=b;
349 if (a<0) a=0;
350 aPnt=maRect.TopLeft();
351 aPnt.X()+=a;
352 eKind = HDL_CIRC;
353 break;
355 case 2: aPnt=maRect.TopLeft(); eKind = HDL_UPLFT; break;
356 case 3: aPnt=maRect.TopCenter(); eKind = HDL_UPPER; break;
357 case 4: aPnt=maRect.TopRight(); eKind = HDL_UPRGT; break;
358 case 5: aPnt=maRect.LeftCenter(); eKind = HDL_LEFT ; break;
359 case 6: aPnt=maRect.RightCenter(); eKind = HDL_RIGHT; break;
360 case 7: aPnt=maRect.BottomLeft(); eKind = HDL_LWLFT; break;
361 case 8: aPnt=maRect.BottomCenter(); eKind = HDL_LOWER; break;
362 case 9: aPnt=maRect.BottomRight(); eKind = HDL_LWRGT; break;
365 if(!pH)
367 if(aGeo.nShearAngle)
369 ShearPoint(aPnt,maRect.TopLeft(),aGeo.nTan);
372 if(aGeo.nRotationAngle)
374 RotatePoint(aPnt,maRect.TopLeft(),aGeo.nSin,aGeo.nCos);
377 pH = new SdrHdl(aPnt,eKind);
378 pH->SetObj((SdrObject*)this);
379 pH->SetRotationAngle(aGeo.nRotationAngle);
382 return pH;
387 bool SdrRectObj::hasSpecialDrag() const
389 return true;
392 bool SdrRectObj::beginSpecialDrag(SdrDragStat& rDrag) const
394 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
396 if(bRad)
398 rDrag.SetEndDragChangesAttributes(true);
400 return true;
403 return SdrTextObj::beginSpecialDrag(rDrag);
406 bool SdrRectObj::applySpecialDrag(SdrDragStat& rDrag)
408 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
410 if (bRad)
412 Point aPt(rDrag.GetNow());
414 if(aGeo.nRotationAngle)
415 RotatePoint(aPt,maRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
417 sal_Int32 nRad(aPt.X() - maRect.Left());
419 if (nRad < 0)
420 nRad = 0;
422 if(nRad != GetEckenradius())
424 NbcSetEckenradius(nRad);
427 return true;
429 else
431 return SdrTextObj::applySpecialDrag(rDrag);
435 OUString SdrRectObj::getSpecialDragComment(const SdrDragStat& rDrag) const
437 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
439 if(bCreateComment)
441 return OUString();
443 else
445 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
447 if(bRad)
449 Point aPt(rDrag.GetNow());
451 // -sin for reversal
452 if(aGeo.nRotationAngle)
453 RotatePoint(aPt, maRect.TopLeft(), -aGeo.nSin, aGeo.nCos);
455 sal_Int32 nRad(aPt.X() - maRect.Left());
457 if(nRad < 0)
458 nRad = 0;
460 OUString aStr;
461 ImpTakeDescriptionStr(STR_DragRectEckRad, aStr);
462 OUStringBuffer aBuf(aStr);
463 aBuf.appendAscii(" (");
464 aBuf.append(GetMetrStr(nRad));
465 aBuf.append(')');
467 return aBuf.makeStringAndClear();
469 else
471 return SdrTextObj::getSpecialDragComment(rDrag);
478 basegfx::B2DPolyPolygon SdrRectObj::TakeCreatePoly(const SdrDragStat& rDrag) const
480 Rectangle aRect1;
481 rDrag.TakeCreateRect(aRect1);
482 aRect1.Justify();
484 basegfx::B2DPolyPolygon aRetval;
485 aRetval.append(ImpCalcXPoly(aRect1,GetEckenradius()).getB2DPolygon());
486 return aRetval;
489 Pointer SdrRectObj::GetCreatePointer() const
491 if (IsTextFrame()) return Pointer(PointerStyle::DrawText);
492 return Pointer(PointerStyle::DrawRect);
495 void SdrRectObj::NbcMove(const Size& rSiz)
497 SdrTextObj::NbcMove(rSiz);
498 SetXPolyDirty();
501 void SdrRectObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
503 SdrTextObj::NbcResize(rRef,xFact,yFact);
504 SetXPolyDirty();
507 void SdrRectObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
509 SdrTextObj::NbcRotate(rRef,nAngle,sn,cs);
510 SetXPolyDirty();
513 void SdrRectObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
515 SdrTextObj::NbcShear(rRef,nAngle,tn,bVShear);
516 SetXPolyDirty();
519 void SdrRectObj::NbcMirror(const Point& rRef1, const Point& rRef2)
521 SdrTextObj::NbcMirror(rRef1,rRef2);
522 SetXPolyDirty();
525 bool SdrRectObj::DoMacro(const SdrObjMacroHitRec& rRec)
527 return SdrTextObj::DoMacro(rRec);
530 OUString SdrRectObj::GetMacroPopupComment(const SdrObjMacroHitRec& rRec) const
532 return SdrTextObj::GetMacroPopupComment(rRec);
535 SdrGluePoint SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum) const
537 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
539 // #i25616#
540 if(!LineIsOutsideGeometry())
542 nWdt++;
543 nWdt /= 2;
546 Point aPt;
547 switch (nPosNum) {
548 case 0: aPt=maRect.TopCenter(); aPt.Y()-=nWdt; break;
549 case 1: aPt=maRect.RightCenter(); aPt.X()+=nWdt; break;
550 case 2: aPt=maRect.BottomCenter(); aPt.Y()+=nWdt; break;
551 case 3: aPt=maRect.LeftCenter(); aPt.X()-=nWdt; break;
553 if (aGeo.nShearAngle!=0) ShearPoint(aPt,maRect.TopLeft(),aGeo.nTan);
554 if (aGeo.nRotationAngle!=0) RotatePoint(aPt,maRect.TopLeft(),aGeo.nSin,aGeo.nCos);
555 aPt-=GetSnapRect().Center();
556 SdrGluePoint aGP(aPt);
557 aGP.SetPercent(false);
558 return aGP;
561 SdrGluePoint SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum) const
563 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
565 // #i25616#
566 if(!LineIsOutsideGeometry())
568 nWdt++;
569 nWdt /= 2;
572 Point aPt;
573 switch (nPosNum) {
574 case 0: aPt=maRect.TopLeft(); aPt.X()-=nWdt; aPt.Y()-=nWdt; break;
575 case 1: aPt=maRect.TopRight(); aPt.X()+=nWdt; aPt.Y()-=nWdt; break;
576 case 2: aPt=maRect.BottomRight(); aPt.X()+=nWdt; aPt.Y()+=nWdt; break;
577 case 3: aPt=maRect.BottomLeft(); aPt.X()-=nWdt; aPt.Y()+=nWdt; break;
579 if (aGeo.nShearAngle!=0) ShearPoint(aPt,maRect.TopLeft(),aGeo.nTan);
580 if (aGeo.nRotationAngle!=0) RotatePoint(aPt,maRect.TopLeft(),aGeo.nSin,aGeo.nCos);
581 aPt-=GetSnapRect().Center();
582 SdrGluePoint aGP(aPt);
583 aGP.SetPercent(false);
584 return aGP;
587 SdrObject* SdrRectObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
589 XPolygon aXP(ImpCalcXPoly(maRect,GetEckenradius()));
590 { // TODO: this is only for the moment, until we have the new TakeContour()
591 aXP.Remove(0,1);
592 aXP[aXP.GetPointCount()-1]=aXP[0];
595 basegfx::B2DPolyPolygon aPolyPolygon(aXP.getB2DPolygon());
596 aPolyPolygon.removeDoublePoints();
597 SdrObject* pRet = 0L;
599 // small correction: Do not create something when no fill and no line. To
600 // be sure to not damage something with non-text frames, do this only
601 // when used with bAddText==false from other converters
602 if((bAddText && !IsTextFrame()) || HasFill() || HasLine())
604 pRet = ImpConvertMakeObj(aPolyPolygon, true, bBezier);
607 if(bAddText)
609 pRet = ImpConvertAddText(pRet, bBezier);
612 return pRet;
615 void SdrRectObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
617 SdrTextObj::Notify(rBC,rHint);
618 SetXPolyDirty(); // because of the corner radius
621 void SdrRectObj::RestGeoData(const SdrObjGeoData& rGeo)
623 SdrTextObj::RestGeoData(rGeo);
624 SetXPolyDirty();
627 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */