bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / svdraw / svdorect.cxx
blobd17a0ed3b43e1c366c866492a1136abedebdefdc
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> // for Import of SdrFileVersion 2
33 #include <svx/svdpagv.hxx> // for
34 #include <svx/svdview.hxx> // the
35 #include <svx/svdundo.hxx> // macro example
36 #include <svx/svdopath.hxx>
37 #include "svx/svdglob.hxx" // Stringcache
38 #include "svx/svdstr.hrc" // the object's name
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>
47 //////////////////////////////////////////////////////////////////////////////
48 // BaseProperties section
50 sdr::properties::BaseProperties* SdrRectObj::CreateObjectSpecificProperties()
52 return new sdr::properties::RectangleProperties(*this);
55 //////////////////////////////////////////////////////////////////////////////
56 // DrawContact section
58 sdr::contact::ViewContact* SdrRectObj::CreateObjectSpecificViewContact()
60 return new sdr::contact::ViewContactOfSdrRectObj(*this);
63 //////////////////////////////////////////////////////////////////////////////
65 TYPEINIT1(SdrRectObj,SdrTextObj);
67 SdrRectObj::SdrRectObj()
68 : mpXPoly(0L)
70 bClosedObj=sal_True;
73 SdrRectObj::SdrRectObj(const Rectangle& rRect)
74 : SdrTextObj(rRect),
75 mpXPoly(NULL)
77 bClosedObj=sal_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=sal_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=sal_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=sal_True;
173 rInfo.bRotateFreeAllowed=sal_True;
174 rInfo.bRotate90Allowed =sal_True;
175 rInfo.bMirrorFreeAllowed=bNoTextFrame;
176 rInfo.bMirror45Allowed =bNoTextFrame;
177 rInfo.bMirror90Allowed =bNoTextFrame;
179 // allow transparency
180 rInfo.bTransparenceAllowed = sal_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=sal_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 void SdrRectObj::TakeObjNameSingul(XubString& rName) const
224 if (IsTextFrame())
226 SdrTextObj::TakeObjNameSingul(rName);
228 else
230 sal_uInt16 nResId=STR_ObjNameSingulRECT;
231 if (aGeo.nShearWink!=0) {
232 nResId+=4; // parallelogram or, maybe, rhombus
233 } else {
234 if (aRect.GetWidth()==aRect.GetHeight()) nResId+=2; // square
236 if (GetEckenradius()!=0) nResId+=8; // rounded down
237 rName=ImpGetResStr(nResId);
239 String aName( GetName() );
240 if(aName.Len())
242 rName += sal_Unicode(' ');
243 rName += sal_Unicode('\'');
244 rName += aName;
245 rName += sal_Unicode('\'');
250 void SdrRectObj::TakeObjNamePlural(XubString& rName) const
252 if (IsTextFrame()) SdrTextObj::TakeObjNamePlural(rName);
253 else {
254 sal_uInt16 nResId=STR_ObjNamePluralRECT;
255 if (aGeo.nShearWink!=0) {
256 nResId+=4; // parallelogram or rhombus
257 } else {
258 if (aRect.GetWidth()==aRect.GetHeight()) nResId+=2; // square
260 if (GetEckenradius()!=0) nResId+=8; // rounded down
261 rName=ImpGetResStr(nResId);
265 SdrRectObj* SdrRectObj::Clone() const
267 return CloneHelper< SdrRectObj >();
270 basegfx::B2DPolyPolygon SdrRectObj::TakeXorPoly() const
272 XPolyPolygon aXPP;
273 aXPP.Insert(ImpCalcXPoly(aRect,GetEckenradius()));
274 return aXPP.getB2DPolyPolygon();
277 void SdrRectObj::RecalcSnapRect()
279 long nEckRad=GetEckenradius();
280 if ((aGeo.nDrehWink!=0 || aGeo.nShearWink!=0) && nEckRad!=0) {
281 maSnapRect=GetXPoly().GetBoundRect();
282 } else {
283 SdrTextObj::RecalcSnapRect();
287 void SdrRectObj::NbcSetSnapRect(const Rectangle& rRect)
289 SdrTextObj::NbcSetSnapRect(rRect);
290 SetXPolyDirty();
293 void SdrRectObj::NbcSetLogicRect(const Rectangle& rRect)
295 SdrTextObj::NbcSetLogicRect(rRect);
296 SetXPolyDirty();
299 sal_uInt32 SdrRectObj::GetHdlCount() const
301 return IsTextFrame() ? 10 : 9;
304 SdrHdl* SdrRectObj::GetHdl(sal_uInt32 nHdlNum) const
306 SdrHdl* pH = NULL;
307 Point aPnt;
308 SdrHdlKind eKind = HDL_MOVE;
310 if(!IsTextFrame())
312 nHdlNum++;
315 switch(nHdlNum)
317 case 0:
319 OSL_ENSURE(!IsTextEditActive(), "Do not use a ImpTextframeHdl for hilighting text in active text edit, this will collide with EditEngine paints (!)");
320 // hack for calc grid sync to ensure the hatched area
321 // for a textbox is displayed at correct position
322 pH = new ImpTextframeHdl(aRect + GetGridOffset() );
323 pH->SetObj((SdrObject*)this);
324 pH->SetDrehWink(aGeo.nDrehWink);
325 break;
327 case 1:
329 long a = GetEckenradius();
330 long b = std::max(aRect.GetWidth(),aRect.GetHeight())/2; // rounded up, because GetWidth() adds 1
331 if (a>b) a=b;
332 if (a<0) a=0;
333 aPnt=aRect.TopLeft();
334 aPnt.X()+=a;
335 eKind = HDL_CIRC;
336 break;
338 case 2: aPnt=aRect.TopLeft(); eKind = HDL_UPLFT; break;
339 case 3: aPnt=aRect.TopCenter(); eKind = HDL_UPPER; break;
340 case 4: aPnt=aRect.TopRight(); eKind = HDL_UPRGT; break;
341 case 5: aPnt=aRect.LeftCenter(); eKind = HDL_LEFT ; break;
342 case 6: aPnt=aRect.RightCenter(); eKind = HDL_RIGHT; break;
343 case 7: aPnt=aRect.BottomLeft(); eKind = HDL_LWLFT; break;
344 case 8: aPnt=aRect.BottomCenter(); eKind = HDL_LOWER; break;
345 case 9: aPnt=aRect.BottomRight(); eKind = HDL_LWRGT; break;
348 if(!pH)
350 if(aGeo.nShearWink)
352 ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
355 if(aGeo.nDrehWink)
357 RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
360 pH = new SdrHdl(aPnt,eKind);
361 pH->SetObj((SdrObject*)this);
362 pH->SetDrehWink(aGeo.nDrehWink);
365 return pH;
368 ////////////////////////////////////////////////////////////////////////////////////////////////////
370 bool SdrRectObj::hasSpecialDrag() const
372 return true;
375 bool SdrRectObj::beginSpecialDrag(SdrDragStat& rDrag) const
377 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
379 if(bRad)
381 rDrag.SetEndDragChangesAttributes(true);
383 return true;
386 return SdrTextObj::beginSpecialDrag(rDrag);
389 bool SdrRectObj::applySpecialDrag(SdrDragStat& rDrag)
391 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
393 if (bRad)
395 Point aPt(rDrag.GetNow());
397 if(aGeo.nDrehWink)
398 RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
400 sal_Int32 nRad(aPt.X() - aRect.Left());
402 if (nRad < 0)
403 nRad = 0;
405 if(nRad != GetEckenradius())
407 NbcSetEckenradius(nRad);
410 return true;
412 else
414 return SdrTextObj::applySpecialDrag(rDrag);
418 String SdrRectObj::getSpecialDragComment(const SdrDragStat& rDrag) const
420 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
422 if(bCreateComment)
424 return String();
426 else
428 const bool bRad(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
430 if(bRad)
432 Point aPt(rDrag.GetNow());
434 // -sin for reversal
435 if(aGeo.nDrehWink)
436 RotatePoint(aPt, aRect.TopLeft(), -aGeo.nSin, aGeo.nCos);
438 sal_Int32 nRad(aPt.X() - aRect.Left());
440 if(nRad < 0)
441 nRad = 0;
443 OUString aStr;
444 ImpTakeDescriptionStr(STR_DragRectEckRad, aStr);
445 OUStringBuffer aBuf(aStr);
446 aBuf.appendAscii(" (");
447 aBuf.append(GetMetrStr(nRad));
448 aBuf.append(sal_Unicode(')'));
450 return aBuf.makeStringAndClear();
452 else
454 return SdrTextObj::getSpecialDragComment(rDrag);
459 ////////////////////////////////////////////////////////////////////////////////////////////////////
461 basegfx::B2DPolyPolygon SdrRectObj::TakeCreatePoly(const SdrDragStat& rDrag) const
463 Rectangle aRect1;
464 rDrag.TakeCreateRect(aRect1);
465 aRect1.Justify();
467 basegfx::B2DPolyPolygon aRetval;
468 aRetval.append(ImpCalcXPoly(aRect1,GetEckenradius()).getB2DPolygon());
469 return aRetval;
472 Pointer SdrRectObj::GetCreatePointer() const
474 if (IsTextFrame()) return Pointer(POINTER_DRAW_TEXT);
475 return Pointer(POINTER_DRAW_RECT);
478 void SdrRectObj::NbcMove(const Size& rSiz)
480 SdrTextObj::NbcMove(rSiz);
481 SetXPolyDirty();
484 void SdrRectObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
486 SdrTextObj::NbcResize(rRef,xFact,yFact);
487 SetXPolyDirty();
490 void SdrRectObj::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
492 SdrTextObj::NbcRotate(rRef,nWink,sn,cs);
493 SetXPolyDirty();
496 void SdrRectObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
498 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
499 SetXPolyDirty();
502 void SdrRectObj::NbcMirror(const Point& rRef1, const Point& rRef2)
504 SdrTextObj::NbcMirror(rRef1,rRef2);
505 SetXPolyDirty();
508 bool SdrRectObj::DoMacro(const SdrObjMacroHitRec& rRec)
510 return SdrTextObj::DoMacro(rRec);
513 OUString SdrRectObj::GetMacroPopupComment(const SdrObjMacroHitRec& rRec) const
515 return SdrTextObj::GetMacroPopupComment(rRec);
518 SdrGluePoint SdrRectObj::GetVertexGluePoint(sal_uInt16 nPosNum) const
520 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
522 // #i25616#
523 if(!LineIsOutsideGeometry())
525 nWdt++;
526 nWdt /= 2;
529 Point aPt;
530 switch (nPosNum) {
531 case 0: aPt=aRect.TopCenter(); aPt.Y()-=nWdt; break;
532 case 1: aPt=aRect.RightCenter(); aPt.X()+=nWdt; break;
533 case 2: aPt=aRect.BottomCenter(); aPt.Y()+=nWdt; break;
534 case 3: aPt=aRect.LeftCenter(); aPt.X()-=nWdt; break;
536 if (aGeo.nShearWink!=0) ShearPoint(aPt,aRect.TopLeft(),aGeo.nTan);
537 if (aGeo.nDrehWink!=0) RotatePoint(aPt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
538 aPt-=GetSnapRect().Center();
539 SdrGluePoint aGP(aPt);
540 aGP.SetPercent(sal_False);
541 return aGP;
544 SdrGluePoint SdrRectObj::GetCornerGluePoint(sal_uInt16 nPosNum) const
546 sal_Int32 nWdt = ImpGetLineWdt(); // #i25616#
548 // #i25616#
549 if(!LineIsOutsideGeometry())
551 nWdt++;
552 nWdt /= 2;
555 Point aPt;
556 switch (nPosNum) {
557 case 0: aPt=aRect.TopLeft(); aPt.X()-=nWdt; aPt.Y()-=nWdt; break;
558 case 1: aPt=aRect.TopRight(); aPt.X()+=nWdt; aPt.Y()-=nWdt; break;
559 case 2: aPt=aRect.BottomRight(); aPt.X()+=nWdt; aPt.Y()+=nWdt; break;
560 case 3: aPt=aRect.BottomLeft(); aPt.X()-=nWdt; aPt.Y()+=nWdt; break;
562 if (aGeo.nShearWink!=0) ShearPoint(aPt,aRect.TopLeft(),aGeo.nTan);
563 if (aGeo.nDrehWink!=0) RotatePoint(aPt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
564 aPt-=GetSnapRect().Center();
565 SdrGluePoint aGP(aPt);
566 aGP.SetPercent(sal_False);
567 return aGP;
570 SdrObject* SdrRectObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
572 XPolygon aXP(ImpCalcXPoly(aRect,GetEckenradius()));
573 { // TODO: this is only for the moment, until we have the new TakeContour()
574 aXP.Remove(0,1);
575 aXP[aXP.GetPointCount()-1]=aXP[0];
578 basegfx::B2DPolyPolygon aPolyPolygon(aXP.getB2DPolygon());
579 aPolyPolygon.removeDoublePoints();
580 SdrObject* pRet = 0L;
582 // small correction: Do not create something when no fill and no line. To
583 // be sure to not damage something with non-text frames, do this only
584 // when used with bAddText==false from other converters
585 if((bAddText && !IsTextFrame()) || HasFill() || HasLine())
587 pRet = ImpConvertMakeObj(aPolyPolygon, sal_True, bBezier);
590 if(bAddText)
592 pRet = ImpConvertAddText(pRet, bBezier);
595 return pRet;
598 void SdrRectObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
600 SdrTextObj::Notify(rBC,rHint);
601 SetXPolyDirty(); // because of the corner radius
604 void SdrRectObj::RestGeoData(const SdrObjGeoData& rGeo)
606 SdrTextObj::RestGeoData(rGeo);
607 SetXPolyDirty();
610 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */