Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / svdraw / svdorect.cxx
blob45f9f01fed8123d03cb63a448a60f22806e58f8c
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 <svx/sdr/properties/rectangleproperties.hxx>
43 #include <svx/sdr/contact/viewcontactofsdrrectobj.hxx>
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
48 // BaseProperties section
50 sdr::properties::BaseProperties* SdrRectObj::CreateObjectSpecificProperties()
52 return new sdr::properties::RectangleProperties(*this);
56 // DrawContact section
58 sdr::contact::ViewContact* SdrRectObj::CreateObjectSpecificViewContact()
60 return new sdr::contact::ViewContactOfSdrRectObj(*this);
65 TYPEINIT1(SdrRectObj,SdrTextObj);
67 SdrRectObj::SdrRectObj()
68 : mpXPoly(0L)
70 bClosedObj=true;
73 SdrRectObj::SdrRectObj(const Rectangle& rRect)
74 : SdrTextObj(rRect),
75 mpXPoly(NULL)
77 bClosedObj=true;
80 SdrRectObj::SdrRectObj(SdrObjKind eNewTextKind)
81 : SdrTextObj(eNewTextKind),
82 mpXPoly(NULL)
84 DBG_ASSERT(eTextKind==OBJ_TEXT || eTextKind==OBJ_TEXTEXT ||
85 eTextKind==OBJ_OUTLINETEXT || eTextKind==OBJ_TITLETEXT,
86 "SdrRectObj::SdrRectObj(SdrObjKind) can only be applied to text frames.");
87 bClosedObj=true;
90 SdrRectObj::SdrRectObj(SdrObjKind eNewTextKind, const Rectangle& rRect)
91 : SdrTextObj(eNewTextKind,rRect),
92 mpXPoly(NULL)
94 DBG_ASSERT(eTextKind==OBJ_TEXT || eTextKind==OBJ_TEXTEXT ||
95 eTextKind==OBJ_OUTLINETEXT || eTextKind==OBJ_TITLETEXT,
96 "SdrRectObj::SdrRectObj(SdrObjKind,...) can only be applied to text frames.");
97 bClosedObj=true;
100 SdrRectObj::~SdrRectObj()
102 delete mpXPoly;
105 SdrRectObj& SdrRectObj::operator=(const SdrRectObj& rCopy)
107 if ( this == &rCopy )
108 return *this;
110 SdrTextObj::operator=( rCopy );
112 delete mpXPoly;
114 if ( rCopy.mpXPoly )
115 mpXPoly = new XPolygon( *rCopy.mpXPoly );
116 else
117 mpXPoly = NULL;
119 return *this;
122 void SdrRectObj::SetXPolyDirty()
124 delete mpXPoly;
125 mpXPoly = 0L;
128 XPolygon SdrRectObj::ImpCalcXPoly(const Rectangle& rRect1, long nRad1) const
130 XPolygon aXPoly(rRect1,nRad1,nRad1);
131 const sal_uInt16 nPointAnz(aXPoly.GetPointCount());
132 XPolygon aNeuPoly(nPointAnz+1);
133 sal_uInt16 nShift=nPointAnz-2;
134 if (nRad1!=0) nShift=nPointAnz-5;
135 sal_uInt16 j=nShift;
136 for (sal_uInt16 i=1; i<nPointAnz; i++) {
137 aNeuPoly[i]=aXPoly[j];
138 aNeuPoly.SetFlags(i,aXPoly.GetFlags(j));
139 j++;
140 if (j>=nPointAnz) j=1;
142 aNeuPoly[0]=rRect1.BottomCenter();
143 aNeuPoly[nPointAnz]=aNeuPoly[0];
144 aXPoly=aNeuPoly;
146 // these angles always relate to the top left corner of aRect
147 if (aGeo.nShearWink!=0) ShearXPoly(aXPoly,aRect.TopLeft(),aGeo.nTan);
148 if (aGeo.nDrehWink!=0) RotateXPoly(aXPoly,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
149 return aXPoly;
152 void SdrRectObj::RecalcXPoly()
154 delete mpXPoly;
155 mpXPoly = new XPolygon(ImpCalcXPoly(aRect,GetEckenradius()));
158 const XPolygon& SdrRectObj::GetXPoly() const
160 if(!mpXPoly)
162 ((SdrRectObj*)this)->RecalcXPoly();
165 return *mpXPoly;
168 void SdrRectObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
170 bool bNoTextFrame=!IsTextFrame();
171 rInfo.bResizeFreeAllowed=bNoTextFrame || aGeo.nDrehWink%9000==0;
172 rInfo.bResizePropAllowed=true;
173 rInfo.bRotateFreeAllowed=true;
174 rInfo.bRotate90Allowed =true;
175 rInfo.bMirrorFreeAllowed=bNoTextFrame;
176 rInfo.bMirror45Allowed =bNoTextFrame;
177 rInfo.bMirror90Allowed =bNoTextFrame;
179 // allow transparency
180 rInfo.bTransparenceAllowed = true;
182 // gradient depends on fillstyle
183 XFillStyle eFillStyle = ((XFillStyleItem&)(GetObjectItem(XATTR_FILLSTYLE))).GetValue();
184 rInfo.bGradientAllowed = (eFillStyle == XFILL_GRADIENT);
186 rInfo.bShearAllowed =bNoTextFrame;
187 rInfo.bEdgeRadiusAllowed=true;
189 bool bCanConv=!HasText() || ImpCanConvTextToCurve();
190 if (bCanConv && !bNoTextFrame && !HasText()) {
191 bCanConv=HasFill() || HasLine();
193 rInfo.bCanConvToPath =bCanConv;
194 rInfo.bCanConvToPoly =bCanConv;
195 rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
198 sal_uInt16 SdrRectObj::GetObjIdentifier() const
200 if (IsTextFrame()) return sal_uInt16(eTextKind);
201 else return sal_uInt16(OBJ_RECT);
204 void SdrRectObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
206 rRect=aRect;
207 if (aGeo.nShearWink!=0) {
208 long nDst=Round((aRect.Bottom()-aRect.Top())*aGeo.nTan);
209 if (aGeo.nShearWink>0) {
210 Point aRef(rRect.TopLeft());
211 rRect.Left()-=nDst;
212 Point aTmpPt(rRect.TopLeft());
213 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
214 aTmpPt-=rRect.TopLeft();
215 rRect.Move(aTmpPt.X(),aTmpPt.Y());
216 } else {
217 rRect.Right()-=nDst;
222 OUString SdrRectObj::TakeObjNameSingul() const
224 if (IsTextFrame())
226 return SdrTextObj::TakeObjNameSingul();
229 OUStringBuffer sName;
231 sal_uInt16 nResId=STR_ObjNameSingulRECT;
232 if (aGeo.nShearWink!=0) {
233 nResId+=4; // parallelogram or, maybe, rhombus
234 } else {
235 if (aRect.GetWidth()==aRect.GetHeight()) nResId+=2; // square
237 if (GetEckenradius()!=0) nResId+=8; // rounded down
238 sName.append(ImpGetResStr(nResId));
240 OUString aName(GetName());
241 if (!aName.isEmpty())
243 sName.append(' ');
244 sName.append('\'');
245 sName.append(aName);
246 sName.append('\'');
249 return sName.makeStringAndClear();
252 OUString SdrRectObj::TakeObjNamePlural() const
254 if (IsTextFrame())
256 return SdrTextObj::TakeObjNamePlural();
259 sal_uInt16 nResId=STR_ObjNamePluralRECT;
261 if (aGeo.nShearWink!=0)
263 nResId+=4; // parallelogram or rhombus
265 else
267 if (aRect.GetWidth()==aRect.GetHeight())
268 nResId+=2; // square
271 if (GetEckenradius()!=0)
272 nResId+=8; // rounded down
274 return ImpGetResStr(nResId);
277 SdrRectObj* SdrRectObj::Clone() const
279 return CloneHelper< SdrRectObj >();
282 basegfx::B2DPolyPolygon SdrRectObj::TakeXorPoly() const
284 XPolyPolygon aXPP;
285 aXPP.Insert(ImpCalcXPoly(aRect,GetEckenradius()));
286 return aXPP.getB2DPolyPolygon();
289 void SdrRectObj::RecalcSnapRect()
291 long nEckRad=GetEckenradius();
292 if ((aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) && nEckRad!=0) {
293 maSnapRect=GetXPoly().GetBoundRect();
294 } else {
295 SdrTextObj::RecalcSnapRect();
299 void SdrRectObj::NbcSetSnapRect(const Rectangle& rRect)
301 SdrTextObj::NbcSetSnapRect(rRect);
302 SetXPolyDirty();
305 void SdrRectObj::NbcSetLogicRect(const Rectangle& rRect)
307 SdrTextObj::NbcSetLogicRect(rRect);
308 SetXPolyDirty();
311 sal_uInt32 SdrRectObj::GetHdlCount() const
313 return IsTextFrame() ? 10 : 9;
316 SdrHdl* SdrRectObj::GetHdl(sal_uInt32 nHdlNum) const
318 SdrHdl* pH = NULL;
319 Point aPnt;
320 SdrHdlKind eKind = HDL_MOVE;
322 if(!IsTextFrame())
324 nHdlNum++;
327 switch(nHdlNum)
329 case 0:
331 OSL_ENSURE(!IsTextEditActive(), "Do not use a ImpTextframeHdl for hilighting text in active text edit, this will collide with EditEngine paints (!)");
332 // hack for calc grid sync to ensure the hatched area
333 // for a textbox is displayed at correct position
334 pH = new ImpTextframeHdl(aRect + GetGridOffset() );
335 pH->SetObj((SdrObject*)this);
336 pH->SetDrehWink(aGeo.nDrehWink);
337 break;
339 case 1:
341 long a = GetEckenradius();
342 long b = std::max(aRect.GetWidth(),aRect.GetHeight())/2; // rounded up, because GetWidth() adds 1
343 if (a>b) a=b;
344 if (a<0) a=0;
345 aPnt=aRect.TopLeft();
346 aPnt.X()+=a;
347 eKind = HDL_CIRC;
348 break;
350 case 2: aPnt=aRect.TopLeft(); eKind = HDL_UPLFT; break;
351 case 3: aPnt=aRect.TopCenter(); eKind = HDL_UPPER; break;
352 case 4: aPnt=aRect.TopRight(); eKind = HDL_UPRGT; break;
353 case 5: aPnt=aRect.LeftCenter(); eKind = HDL_LEFT ; break;
354 case 6: aPnt=aRect.RightCenter(); eKind = HDL_RIGHT; break;
355 case 7: aPnt=aRect.BottomLeft(); eKind = HDL_LWLFT; break;
356 case 8: aPnt=aRect.BottomCenter(); eKind = HDL_LOWER; break;
357 case 9: aPnt=aRect.BottomRight(); eKind = HDL_LWRGT; break;
360 if(!pH)
362 if(aGeo.nShearWink)
364 ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
367 if(aGeo.nDrehWink)
369 RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
372 pH = new SdrHdl(aPnt,eKind);
373 pH->SetObj((SdrObject*)this);
374 pH->SetDrehWink(aGeo.nDrehWink);
377 return pH;
382 bool SdrRectObj::hasSpecialDrag() const
384 return true;
387 bool SdrRectObj::beginSpecialDrag(SdrDragStat& rDrag) const
389 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
391 if(bRad)
393 rDrag.SetEndDragChangesAttributes(true);
395 return true;
398 return SdrTextObj::beginSpecialDrag(rDrag);
401 bool SdrRectObj::applySpecialDrag(SdrDragStat& rDrag)
403 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
405 if (bRad)
407 Point aPt(rDrag.GetNow());
409 if(aGeo.nDrehWink)
410 RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
412 sal_Int32 nRad(aPt.X() - aRect.Left());
414 if (nRad < 0)
415 nRad = 0;
417 if(nRad != GetEckenradius())
419 NbcSetEckenradius(nRad);
422 return true;
424 else
426 return SdrTextObj::applySpecialDrag(rDrag);
430 OUString SdrRectObj::getSpecialDragComment(const SdrDragStat& rDrag) const
432 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
434 if(bCreateComment)
436 return OUString();
438 else
440 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
442 if(bRad)
444 Point aPt(rDrag.GetNow());
446 // -sin for reversal
447 if(aGeo.nDrehWink)
448 RotatePoint(aPt, aRect.TopLeft(), -aGeo.nSin, aGeo.nCos);
450 sal_Int32 nRad(aPt.X() - aRect.Left());
452 if(nRad < 0)
453 nRad = 0;
455 OUString aStr;
456 ImpTakeDescriptionStr(STR_DragRectEckRad, aStr);
457 OUStringBuffer aBuf(aStr);
458 aBuf.appendAscii(" (");
459 aBuf.append(GetMetrStr(nRad));
460 aBuf.append(')');
462 return aBuf.makeStringAndClear();
464 else
466 return SdrTextObj::getSpecialDragComment(rDrag);
473 basegfx::B2DPolyPolygon SdrRectObj::TakeCreatePoly(const SdrDragStat& rDrag) const
475 Rectangle aRect1;
476 rDrag.TakeCreateRect(aRect1);
477 aRect1.Justify();
479 basegfx::B2DPolyPolygon aRetval;
480 aRetval.append(ImpCalcXPoly(aRect1,GetEckenradius()).getB2DPolygon());
481 return aRetval;
484 Pointer SdrRectObj::GetCreatePointer() const
486 if (IsTextFrame()) return Pointer(POINTER_DRAW_TEXT);
487 return Pointer(POINTER_DRAW_RECT);
490 void SdrRectObj::NbcMove(const Size& rSiz)
492 SdrTextObj::NbcMove(rSiz);
493 SetXPolyDirty();
496 void SdrRectObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
498 SdrTextObj::NbcResize(rRef,xFact,yFact);
499 SetXPolyDirty();
502 void SdrRectObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
504 SdrTextObj::NbcRotate(rRef,nWink,sn,cs);
505 SetXPolyDirty();
508 void SdrRectObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
510 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
511 SetXPolyDirty();
514 void SdrRectObj::NbcMirror(const Point& rRef1, const Point& rRef2)
516 SdrTextObj::NbcMirror(rRef1,rRef2);
517 SetXPolyDirty();
520 bool SdrRectObj::DoMacro(const SdrObjMacroHitRec& rRec)
522 return SdrTextObj::DoMacro(rRec);
525 OUString SdrRectObj::GetMacroPopupComment(const SdrObjMacroHitRec& rRec) const
527 return SdrTextObj::GetMacroPopupComment(rRec);
530 SdrGluePoint SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum) const
532 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
534 // #i25616#
535 if(!LineIsOutsideGeometry())
537 nWdt++;
538 nWdt /= 2;
541 Point aPt;
542 switch (nPosNum) {
543 case 0: aPt=aRect.TopCenter(); aPt.Y()-=nWdt; break;
544 case 1: aPt=aRect.RightCenter(); aPt.X()+=nWdt; break;
545 case 2: aPt=aRect.BottomCenter(); aPt.Y()+=nWdt; break;
546 case 3: aPt=aRect.LeftCenter(); aPt.X()-=nWdt; break;
548 if (aGeo.nShearWink!=0) ShearPoint(aPt,aRect.TopLeft(),aGeo.nTan);
549 if (aGeo.nDrehWink!=0) RotatePoint(aPt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
550 aPt-=GetSnapRect().Center();
551 SdrGluePoint aGP(aPt);
552 aGP.SetPercent(false);
553 return aGP;
556 SdrGluePoint SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum) const
558 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
560 // #i25616#
561 if(!LineIsOutsideGeometry())
563 nWdt++;
564 nWdt /= 2;
567 Point aPt;
568 switch (nPosNum) {
569 case 0: aPt=aRect.TopLeft(); aPt.X()-=nWdt; aPt.Y()-=nWdt; break;
570 case 1: aPt=aRect.TopRight(); aPt.X()+=nWdt; aPt.Y()-=nWdt; break;
571 case 2: aPt=aRect.BottomRight(); aPt.X()+=nWdt; aPt.Y()+=nWdt; break;
572 case 3: aPt=aRect.BottomLeft(); aPt.X()-=nWdt; aPt.Y()+=nWdt; break;
574 if (aGeo.nShearWink!=0) ShearPoint(aPt,aRect.TopLeft(),aGeo.nTan);
575 if (aGeo.nDrehWink!=0) RotatePoint(aPt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
576 aPt-=GetSnapRect().Center();
577 SdrGluePoint aGP(aPt);
578 aGP.SetPercent(false);
579 return aGP;
582 SdrObject* SdrRectObj::DoConvertToPolyObj(bool bBezier, bool bAddText) const
584 XPolygon aXP(ImpCalcXPoly(aRect,GetEckenradius()));
585 { // TODO: this is only for the moment, until we have the new TakeContour()
586 aXP.Remove(0,1);
587 aXP[aXP.GetPointCount()-1]=aXP[0];
590 basegfx::B2DPolyPolygon aPolyPolygon(aXP.getB2DPolygon());
591 aPolyPolygon.removeDoublePoints();
592 SdrObject* pRet = 0L;
594 // small correction: Do not create something when no fill and no line. To
595 // be sure to not damage something with non-text frames, do this only
596 // when used with bAddText==false from other converters
597 if((bAddText && !IsTextFrame()) || HasFill() || HasLine())
599 pRet = ImpConvertMakeObj(aPolyPolygon, true, bBezier);
602 if(bAddText)
604 pRet = ImpConvertAddText(pRet, bBezier);
607 return pRet;
610 void SdrRectObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
612 SdrTextObj::Notify(rBC,rHint);
613 SetXPolyDirty(); // because of the corner radius
616 void SdrRectObj::RestGeoData(const SdrObjGeoData& rGeo)
618 SdrTextObj::RestGeoData(rGeo);
619 SetXPolyDirty();
622 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */