bump product version to 4.1.6.2
[LibreOffice.git] / svx / source / svdraw / svdocirc.cxx
blob9390388327b83512ce0c42c134e19d28e6af218b
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 <svl/style.hxx>
21 #include <svx/xlnwtit.hxx>
22 #include <svx/xlnedwit.hxx>
23 #include <svx/xlnstwit.hxx>
24 #include <svx/xlnstit.hxx>
25 #include <svx/xlnedit.hxx>
26 #include <svx/svdocirc.hxx>
27 #include <math.h>
28 #include <svx/xpool.hxx>
29 #include <svx/svdattr.hxx>
30 #include <svx/svdpool.hxx>
31 #include <svx/svdattrx.hxx>
32 #include <svx/svdtrans.hxx>
33 #include <svx/svdetc.hxx>
34 #include <svx/svddrag.hxx>
35 #include <svx/svdmodel.hxx>
36 #include <svx/svdpage.hxx>
37 #include <svx/svdopath.hxx> // for the object conversion
38 #include <svx/svdview.hxx> // for dragging (Ortho)
39 #include "svx/svdglob.hxx" // StringCache
40 #include "svx/svdstr.hrc" // the object's name
41 #include <editeng/eeitem.hxx>
42 #include <svx/sdr/properties/circleproperties.hxx>
43 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
44 #include <basegfx/point/b2dpoint.hxx>
45 #include <basegfx/polygon/b2dpolygon.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
47 #include <basegfx/matrix/b2dhommatrix.hxx>
48 #include <basegfx/matrix/b2dhommatrixtools.hxx>
50 //////////////////////////////////////////////////////////////////////////////
52 Point GetWinkPnt(const Rectangle& rR, long nWink)
54 Point aCenter(rR.Center());
55 long nWdt=rR.Right()-rR.Left();
56 long nHgt=rR.Bottom()-rR.Top();
57 long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
58 double a;
59 a=nWink*nPi180;
60 Point aRetval(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
61 if (nWdt==0) aRetval.X()=0;
62 if (nHgt==0) aRetval.Y()=0;
63 if (nWdt!=nHgt) {
64 if (nWdt>nHgt) {
65 if (nWdt!=0) {
66 // stop possible overruns for very large objects
67 if (std::abs(nHgt)>32767 || std::abs(aRetval.Y())>32767) {
68 aRetval.Y()=BigMulDiv(aRetval.Y(),nHgt,nWdt);
69 } else {
70 aRetval.Y()=aRetval.Y()*nHgt/nWdt;
73 } else {
74 if (nHgt!=0) {
75 // stop possible overruns for very large objects
76 if (std::abs(nWdt)>32767 || std::abs(aRetval.X())>32767) {
77 aRetval.X()=BigMulDiv(aRetval.X(),nWdt,nHgt);
78 } else {
79 aRetval.X()=aRetval.X()*nWdt/nHgt;
84 aRetval+=aCenter;
85 return aRetval;
88 //////////////////////////////////////////////////////////////////////////////
89 // BaseProperties section
91 sdr::properties::BaseProperties* SdrCircObj::CreateObjectSpecificProperties()
93 return new sdr::properties::CircleProperties(*this);
96 //////////////////////////////////////////////////////////////////////////////
97 // DrawContact section
99 sdr::contact::ViewContact* SdrCircObj::CreateObjectSpecificViewContact()
101 return new sdr::contact::ViewContactOfSdrCircObj(*this);
104 //////////////////////////////////////////////////////////////////////////////
106 TYPEINIT1(SdrCircObj,SdrRectObj);
108 SdrCircObj::SdrCircObj(SdrObjKind eNewKind)
110 nStartWink=0;
111 nEndWink=36000;
112 meCircleKind=eNewKind;
113 bClosedObj=eNewKind!=OBJ_CARC;
116 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect):
117 SdrRectObj(rRect)
119 nStartWink=0;
120 nEndWink=36000;
121 meCircleKind=eNewKind;
122 bClosedObj=eNewKind!=OBJ_CARC;
125 SdrCircObj::SdrCircObj(SdrObjKind eNewKind, const Rectangle& rRect, long nNewStartWink, long nNewEndWink):
126 SdrRectObj(rRect)
128 long nWinkDif=nNewEndWink-nNewStartWink;
129 nStartWink=NormAngle360(nNewStartWink);
130 nEndWink=NormAngle360(nNewEndWink);
131 if (nWinkDif==36000) nEndWink+=nWinkDif; // full circle
132 meCircleKind=eNewKind;
133 bClosedObj=eNewKind!=OBJ_CARC;
136 SdrCircObj::~SdrCircObj()
140 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
142 bool bCanConv=!HasText() || ImpCanConvTextToCurve();
143 rInfo.bEdgeRadiusAllowed = sal_False;
144 rInfo.bCanConvToPath=bCanConv;
145 rInfo.bCanConvToPoly=bCanConv;
146 rInfo.bCanConvToContour = !IsFontwork() && (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
149 sal_uInt16 SdrCircObj::GetObjIdentifier() const
151 return sal_uInt16(meCircleKind);
154 bool SdrCircObj::PaintNeedsXPolyCirc() const
156 // XPoly is necessary for all rotated ellipse objects, circle and
157 // ellipse segments.
158 // If not WIN, then (for now) also for circle/ellipse segments and circle/
159 // ellipse arcs (for precision)
160 bool bNeed=aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind==OBJ_CCUT;
161 // If not WIN, then for everything except full circle (for now!)
162 if (meCircleKind!=OBJ_CIRC) bNeed = true;
164 const SfxItemSet& rSet = GetObjectItemSet();
165 if(!bNeed)
167 // XPoly is necessary for everything that isn't LineSolid or LineNone
168 XLineStyle eLine = ((XLineStyleItem&)(rSet.Get(XATTR_LINESTYLE))).GetValue();
169 bNeed = eLine != XLINE_NONE && eLine != XLINE_SOLID;
171 // XPoly is necessary for thick lines
172 if(!bNeed && eLine != XLINE_NONE)
173 bNeed = ((XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue() != 0;
175 // XPoly is necessary for circle arcs with line ends
176 if(!bNeed && meCircleKind == OBJ_CARC)
178 // start of the line is here if StartPolygon, StartWidth!=0
179 bNeed=((XLineStartItem&)(rSet.Get(XATTR_LINESTART))).GetLineStartValue().count() != 0L &&
180 ((XLineStartWidthItem&)(rSet.Get(XATTR_LINESTARTWIDTH))).GetValue() != 0;
182 if(!bNeed)
184 // end of the line is here if EndPolygon, EndWidth!=0
185 bNeed = ((XLineEndItem&)(rSet.Get(XATTR_LINEEND))).GetLineEndValue().count() != 0L &&
186 ((XLineEndWidthItem&)(rSet.Get(XATTR_LINEENDWIDTH))).GetValue() != 0;
191 // XPoly is necessary if Fill !=None and !=Solid
192 if(!bNeed && meCircleKind != OBJ_CARC)
194 XFillStyle eFill=((XFillStyleItem&)(rSet.Get(XATTR_FILLSTYLE))).GetValue();
195 bNeed = eFill != XFILL_NONE && eFill != XFILL_SOLID;
198 if(!bNeed && meCircleKind != OBJ_CIRC && nStartWink == nEndWink)
199 bNeed = true; // otherwise we're drawing a full circle
201 return bNeed;
204 basegfx::B2DPolygon SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind, const Rectangle& rRect1, long nStart, long nEnd) const
206 const basegfx::B2DRange aRange(rRect1.Left(), rRect1.Top(), rRect1.Right(), rRect1.Bottom());
207 basegfx::B2DPolygon aCircPolygon;
209 if(OBJ_CIRC == eCicrleKind)
211 // create full circle. Do not use createPolygonFromEllipse; it's necessary
212 // to get the start point to the bottom of the circle to keep compatible to
213 // old geometry creation
214 aCircPolygon = basegfx::tools::createPolygonFromUnitCircle(1);
216 // needs own scaling and translation from unit circle to target size (same as
217 // would be in createPolygonFromEllipse)
218 const basegfx::B2DPoint aCenter(aRange.getCenter());
219 const basegfx::B2DHomMatrix aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
220 aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
221 aCenter.getX(), aCenter.getY()));
222 aCircPolygon.transform(aMatrix);
224 else
226 // mirror start, end for geometry creation since model coordinate system is mirrored in Y
227 // #i111715# increase numerical correctness by first dividing and not using F_PI1800
228 const double fStart((((36000 - nEnd) % 36000) / 18000.0) * F_PI);
229 const double fEnd((((36000 - nStart) % 36000) / 18000.0) * F_PI);
231 // create circle segment. This is not closed by default
232 aCircPolygon = basegfx::tools::createPolygonFromEllipseSegment(
233 aRange.getCenter(), aRange.getWidth() / 2.0, aRange.getHeight() / 2.0,
234 fStart, fEnd);
236 // check closing states
237 const bool bCloseSegment(OBJ_CARC != eCicrleKind);
238 const bool bCloseUsingCenter(OBJ_SECT == eCicrleKind);
240 if(bCloseSegment)
242 if(bCloseUsingCenter)
244 // add center point at start (for historical reasons)
245 basegfx::B2DPolygon aSector;
246 aSector.append(aRange.getCenter());
247 aSector.append(aCircPolygon);
248 aCircPolygon = aSector;
251 // close
252 aCircPolygon.setClosed(true);
256 // #i76950#
257 if(aGeo.nShearWink || aGeo.nDrehWink)
259 // translate top left to (0,0)
260 const basegfx::B2DPoint aTopLeft(aRange.getMinimum());
261 basegfx::B2DHomMatrix aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
262 -aTopLeft.getX(), -aTopLeft.getY()));
264 // shear, rotate and back to top left (if needed)
265 aMatrix = basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
266 aGeo.nShearWink ? tan((36000 - aGeo.nShearWink) * F_PI18000) : 0.0,
267 aGeo.nDrehWink ? (36000 - aGeo.nDrehWink) * F_PI18000 : 0.0,
268 aTopLeft) * aMatrix;
270 // apply transformation
271 aCircPolygon.transform(aMatrix);
274 return aCircPolygon;
277 void SdrCircObj::RecalcXPoly()
279 const basegfx::B2DPolygon aPolyCirc(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
280 mpXPoly = new XPolygon(aPolyCirc);
283 void SdrCircObj::TakeObjNameSingul(XubString& rName) const
285 sal_uInt16 nID=STR_ObjNameSingulCIRC;
286 if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
287 switch (meCircleKind) {
288 case OBJ_CIRC: nID=STR_ObjNameSingulCIRC; break;
289 case OBJ_SECT: nID=STR_ObjNameSingulSECT; break;
290 case OBJ_CARC: nID=STR_ObjNameSingulCARC; break;
291 case OBJ_CCUT: nID=STR_ObjNameSingulCCUT; break;
292 default: break;
294 } else {
295 switch (meCircleKind) {
296 case OBJ_CIRC: nID=STR_ObjNameSingulCIRCE; break;
297 case OBJ_SECT: nID=STR_ObjNameSingulSECTE; break;
298 case OBJ_CARC: nID=STR_ObjNameSingulCARCE; break;
299 case OBJ_CCUT: nID=STR_ObjNameSingulCCUTE; break;
300 default: break;
303 rName=ImpGetResStr(nID);
305 String aName( GetName() );
306 if(aName.Len())
308 rName += sal_Unicode(' ');
309 rName += sal_Unicode('\'');
310 rName += aName;
311 rName += sal_Unicode('\'');
315 void SdrCircObj::TakeObjNamePlural(XubString& rName) const
317 sal_uInt16 nID=STR_ObjNamePluralCIRC;
318 if (aRect.GetWidth()==aRect.GetHeight() && aGeo.nShearWink==0) {
319 switch (meCircleKind) {
320 case OBJ_CIRC: nID=STR_ObjNamePluralCIRC; break;
321 case OBJ_SECT: nID=STR_ObjNamePluralSECT; break;
322 case OBJ_CARC: nID=STR_ObjNamePluralCARC; break;
323 case OBJ_CCUT: nID=STR_ObjNamePluralCCUT; break;
324 default: break;
326 } else {
327 switch (meCircleKind) {
328 case OBJ_CIRC: nID=STR_ObjNamePluralCIRCE; break;
329 case OBJ_SECT: nID=STR_ObjNamePluralSECTE; break;
330 case OBJ_CARC: nID=STR_ObjNamePluralCARCE; break;
331 case OBJ_CCUT: nID=STR_ObjNamePluralCCUTE; break;
332 default: break;
335 rName=ImpGetResStr(nID);
338 SdrCircObj* SdrCircObj::Clone() const
340 return CloneHelper< SdrCircObj >();
343 basegfx::B2DPolyPolygon SdrCircObj::TakeXorPoly() const
345 const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
346 return basegfx::B2DPolyPolygon(aCircPolygon);
349 struct ImpCircUser : public SdrDragStatUserData
351 Rectangle aR;
352 Point aCenter;
353 Point aRadius;
354 Point aP1;
355 Point aP2;
356 long nMaxRad;
357 long nHgt;
358 long nWdt;
359 long nStart;
360 long nEnd;
361 long nWink;
362 bool bRight; // not yet implemented
364 public:
365 ImpCircUser()
366 : nMaxRad(0),
367 nHgt(0),
368 nWdt(0),
369 nStart(0),
370 nEnd(0),
371 nWink(0),
372 bRight(sal_False)
374 void SetCreateParams(SdrDragStat& rStat);
377 sal_uInt32 SdrCircObj::GetHdlCount() const
379 if(OBJ_CIRC != meCircleKind)
381 return 10L;
383 else
385 return 8L;
389 SdrHdl* SdrCircObj::GetHdl(sal_uInt32 nHdlNum) const
391 if (meCircleKind==OBJ_CIRC)
393 nHdlNum += 2L;
396 SdrHdl* pH = NULL;
397 Point aPnt;
398 SdrHdlKind eLocalKind(HDL_MOVE);
399 sal_uInt32 nPNum(0);
401 switch (nHdlNum)
403 case 0:
404 aPnt = GetWinkPnt(aRect,nStartWink);
405 eLocalKind = HDL_CIRC;
406 nPNum = 1;
407 break;
408 case 1:
409 aPnt = GetWinkPnt(aRect,nEndWink);
410 eLocalKind = HDL_CIRC;
411 nPNum = 2L;
412 break;
413 case 2:
414 aPnt = aRect.TopLeft();
415 eLocalKind = HDL_UPLFT;
416 break;
417 case 3:
418 aPnt = aRect.TopCenter();
419 eLocalKind = HDL_UPPER;
420 break;
421 case 4:
422 aPnt = aRect.TopRight();
423 eLocalKind = HDL_UPRGT;
424 break;
425 case 5:
426 aPnt = aRect.LeftCenter();
427 eLocalKind = HDL_LEFT;
428 break;
429 case 6:
430 aPnt = aRect.RightCenter();
431 eLocalKind = HDL_RIGHT;
432 break;
433 case 7:
434 aPnt = aRect.BottomLeft();
435 eLocalKind = HDL_LWLFT;
436 break;
437 case 8:
438 aPnt = aRect.BottomCenter();
439 eLocalKind = HDL_LOWER;
440 break;
441 case 9:
442 aPnt = aRect.BottomRight();
443 eLocalKind = HDL_LWRGT;
444 break;
447 if (aGeo.nShearWink)
449 ShearPoint(aPnt,aRect.TopLeft(),aGeo.nTan);
452 if (aGeo.nDrehWink)
454 RotatePoint(aPnt,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
457 if (eLocalKind != HDL_MOVE)
459 pH = new SdrHdl(aPnt,eLocalKind);
460 pH->SetPointNum(nPNum);
461 pH->SetObj((SdrObject*)this);
462 pH->SetDrehWink(aGeo.nDrehWink);
465 return pH;
468 ////////////////////////////////////////////////////////////////////////////////////////////////////
470 bool SdrCircObj::hasSpecialDrag() const
472 return true;
475 bool SdrCircObj::beginSpecialDrag(SdrDragStat& rDrag) const
477 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
479 if(bWink)
481 if(1 == rDrag.GetHdl()->GetPointNum() || 2 == rDrag.GetHdl()->GetPointNum())
483 rDrag.SetNoSnap(true);
486 return true;
489 return SdrTextObj::beginSpecialDrag(rDrag);
492 bool SdrCircObj::applySpecialDrag(SdrDragStat& rDrag)
494 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
496 if(bWink)
498 Point aPt(rDrag.GetNow());
500 if (aGeo.nDrehWink!=0)
501 RotatePoint(aPt,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos);
503 if (aGeo.nShearWink!=0)
504 ShearPoint(aPt,aRect.TopLeft(),-aGeo.nTan);
506 aPt-=aRect.Center();
508 long nWdt=aRect.Right()-aRect.Left();
509 long nHgt=aRect.Bottom()-aRect.Top();
511 if(nWdt>=nHgt)
513 aPt.Y()=BigMulDiv(aPt.Y(),nWdt,nHgt);
515 else
517 aPt.X()=BigMulDiv(aPt.X(),nHgt,nWdt);
520 long nWink=NormAngle360(GetAngle(aPt));
522 if (rDrag.GetView() && rDrag.GetView()->IsAngleSnapEnabled())
524 long nSA=rDrag.GetView()->GetSnapAngle();
526 if (nSA!=0)
528 nWink+=nSA/2;
529 nWink/=nSA;
530 nWink*=nSA;
531 nWink=NormAngle360(nWink);
535 if(1 == rDrag.GetHdl()->GetPointNum())
537 nStartWink = nWink;
539 else if(2 == rDrag.GetHdl()->GetPointNum())
541 nEndWink = nWink;
544 SetRectsDirty();
545 SetXPolyDirty();
546 ImpSetCircInfoToAttr();
547 SetChanged();
549 return true;
551 else
553 return SdrTextObj::applySpecialDrag(rDrag);
557 String SdrCircObj::getSpecialDragComment(const SdrDragStat& rDrag) const
559 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
561 if(bCreateComment)
563 OUString aStr;
564 ImpTakeDescriptionStr(STR_ViewCreateObj, aStr);
565 OUStringBuffer aBuf(aStr);
566 const sal_uInt32 nPntAnz(rDrag.GetPointAnz());
568 if(OBJ_CIRC != meCircleKind && nPntAnz > 2)
570 ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
571 sal_Int32 nWink;
573 aBuf.appendAscii(" (");
575 if(3 == nPntAnz)
577 nWink = pU->nStart;
579 else
581 nWink = pU->nEnd;
584 aBuf.append(GetWinkStr(nWink,false));
585 aBuf.append(sal_Unicode(')'));
588 return aBuf.makeStringAndClear();
590 else
592 const bool bWink(rDrag.GetHdl() && HDL_CIRC == rDrag.GetHdl()->GetKind());
594 if(bWink)
596 const sal_Int32 nWink(1 == rDrag.GetHdl()->GetPointNum() ? nStartWink : nEndWink);
598 OUString aStr;
599 ImpTakeDescriptionStr(STR_DragCircAngle, aStr);
600 OUStringBuffer aBuf(aStr);
601 aBuf.appendAscii(" (");
602 aBuf.append(GetWinkStr(nWink,false));
603 aBuf.append(sal_Unicode(')'));
605 return aBuf.makeStringAndClear();
607 else
609 return SdrTextObj::getSpecialDragComment(rDrag);
614 ////////////////////////////////////////////////////////////////////////////////////////////////////
616 void ImpCircUser::SetCreateParams(SdrDragStat& rStat)
618 rStat.TakeCreateRect(aR);
619 aR.Justify();
620 aCenter=aR.Center();
621 nWdt=aR.Right()-aR.Left();
622 nHgt=aR.Bottom()-aR.Top();
623 nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
624 nStart=0;
625 nEnd=36000;
626 if (rStat.GetPointAnz()>2) {
627 Point aP(rStat.GetPoint(2)-aCenter);
628 if (nWdt==0) aP.X()=0;
629 if (nHgt==0) aP.Y()=0;
630 if (nWdt>=nHgt) {
631 if (nHgt!=0) aP.Y()=aP.Y()*nWdt/nHgt;
632 } else {
633 if (nWdt!=0) aP.X()=aP.X()*nHgt/nWdt;
635 nStart=NormAngle360(GetAngle(aP));
636 if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
637 long nSA=rStat.GetView()->GetSnapAngle();
638 if (nSA!=0) { // angle snapping
639 nStart+=nSA/2;
640 nStart/=nSA;
641 nStart*=nSA;
642 nStart=NormAngle360(nStart);
645 aP1 = GetWinkPnt(aR,nStart);
646 nEnd=nStart;
647 aP2=aP1;
648 } else aP1=aCenter;
649 if (rStat.GetPointAnz()>3) {
650 Point aP(rStat.GetPoint(3)-aCenter);
651 if (nWdt>=nHgt) {
652 aP.Y()=BigMulDiv(aP.Y(),nWdt,nHgt);
653 } else {
654 aP.X()=BigMulDiv(aP.X(),nHgt,nWdt);
656 nEnd=NormAngle360(GetAngle(aP));
657 if (rStat.GetView()!=NULL && rStat.GetView()->IsAngleSnapEnabled()) {
658 long nSA=rStat.GetView()->GetSnapAngle();
659 if (nSA!=0) { // angle snapping
660 nEnd+=nSA/2;
661 nEnd/=nSA;
662 nEnd*=nSA;
663 nEnd=NormAngle360(nEnd);
666 aP2 = GetWinkPnt(aR,nEnd);
667 } else aP2=aCenter;
670 void SdrCircObj::ImpSetCreateParams(SdrDragStat& rStat) const
672 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
673 if (pU==NULL) {
674 pU=new ImpCircUser;
675 rStat.SetUser(pU);
677 pU->SetCreateParams(rStat);
680 bool SdrCircObj::BegCreate(SdrDragStat& rStat)
682 rStat.SetOrtho4Possible();
683 Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
684 aRect1.Justify();
685 rStat.SetActionRect(aRect1);
686 aRect = aRect1;
687 ImpSetCreateParams(rStat);
688 return sal_True;
691 bool SdrCircObj::MovCreate(SdrDragStat& rStat)
693 ImpSetCreateParams(rStat);
694 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
695 rStat.SetActionRect(pU->aR);
696 aRect=pU->aR; // for ObjName
697 ImpJustifyRect(aRect);
698 nStartWink=pU->nStart;
699 nEndWink=pU->nEnd;
700 SetBoundRectDirty();
701 bSnapRectDirty=sal_True;
702 SetXPolyDirty();
704 // #i103058# push current angle settings to ItemSet to
705 // allow FullDrag visualisation
706 if(rStat.GetPointAnz() >= 4)
708 ImpSetCircInfoToAttr();
711 return sal_True;
714 bool SdrCircObj::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
716 ImpSetCreateParams(rStat);
717 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
718 bool bRet = false;
719 if (eCmd==SDRCREATE_FORCEEND && rStat.GetPointAnz()<4) meCircleKind=OBJ_CIRC;
720 if (meCircleKind==OBJ_CIRC) {
721 bRet=rStat.GetPointAnz()>=2;
722 if (bRet) {
723 aRect=pU->aR;
724 ImpJustifyRect(aRect);
726 } else {
727 rStat.SetNoSnap(rStat.GetPointAnz()>=2);
728 rStat.SetOrtho4Possible(rStat.GetPointAnz()<2);
729 bRet=rStat.GetPointAnz()>=4;
730 if (bRet) {
731 aRect=pU->aR;
732 ImpJustifyRect(aRect);
733 nStartWink=pU->nStart;
734 nEndWink=pU->nEnd;
737 bClosedObj=meCircleKind!=OBJ_CARC;
738 SetRectsDirty();
739 SetXPolyDirty();
740 ImpSetCircInfoToAttr();
741 if (bRet) {
742 delete pU;
743 rStat.SetUser(NULL);
745 return bRet;
748 void SdrCircObj::BrkCreate(SdrDragStat& rStat)
750 ImpCircUser* pU=(ImpCircUser*)rStat.GetUser();
751 delete pU;
752 rStat.SetUser(NULL);
755 bool SdrCircObj::BckCreate(SdrDragStat& rStat)
757 rStat.SetNoSnap(rStat.GetPointAnz()>=3);
758 rStat.SetOrtho4Possible(rStat.GetPointAnz()<3);
759 return meCircleKind!=OBJ_CIRC;
762 basegfx::B2DPolyPolygon SdrCircObj::TakeCreatePoly(const SdrDragStat& rDrag) const
764 ImpCircUser* pU = (ImpCircUser*)rDrag.GetUser();
766 if(rDrag.GetPointAnz() < 4L)
768 // force to OBJ_CIRC to get full visualisation
769 basegfx::B2DPolyPolygon aRetval(ImpCalcXPolyCirc(OBJ_CIRC, pU->aR, pU->nStart, pU->nEnd));
771 if(3L == rDrag.GetPointAnz())
773 // add edge to first point on ellipse
774 basegfx::B2DPolygon aNew;
776 aNew.append(basegfx::B2DPoint(pU->aCenter.X(), pU->aCenter.Y()));
777 aNew.append(basegfx::B2DPoint(pU->aP1.X(), pU->aP1.Y()));
778 aRetval.append(aNew);
781 return aRetval;
783 else
785 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind, pU->aR, pU->nStart, pU->nEnd));
789 Pointer SdrCircObj::GetCreatePointer() const
791 switch (meCircleKind) {
792 case OBJ_CIRC: return Pointer(POINTER_DRAW_ELLIPSE);
793 case OBJ_SECT: return Pointer(POINTER_DRAW_PIE);
794 case OBJ_CARC: return Pointer(POINTER_DRAW_ARC);
795 case OBJ_CCUT: return Pointer(POINTER_DRAW_CIRCLECUT);
796 default: break;
797 } // switch
798 return Pointer(POINTER_CROSS);
801 void SdrCircObj::NbcMove(const Size& aSiz)
803 MoveRect(aRect,aSiz);
804 MoveRect(aOutRect,aSiz);
805 MoveRect(maSnapRect,aSiz);
806 SetXPolyDirty();
807 SetRectsDirty(sal_True);
810 void SdrCircObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
812 long nWink0=aGeo.nDrehWink;
813 bool bNoShearRota=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
814 SdrTextObj::NbcResize(rRef,xFact,yFact);
815 bNoShearRota|=(aGeo.nDrehWink==0 && aGeo.nShearWink==0);
816 if (meCircleKind!=OBJ_CIRC) {
817 bool bXMirr=(xFact.GetNumerator()<0) != (xFact.GetDenominator()<0);
818 bool bYMirr=(yFact.GetNumerator()<0) != (yFact.GetDenominator()<0);
819 if (bXMirr || bYMirr) {
820 // At bXMirr!=bYMirr we should actually swap both line ends.
821 // That, however, is pretty bad (because of forced "hard" formatting).
822 // Alternatively, we could implement a bMirrored flag (maybe even
823 // a more general one, e. g. for mirrored text, ...).
824 long nS0=nStartWink;
825 long nE0=nEndWink;
826 if (bNoShearRota) {
827 // the RectObj already mirrors at VMirror because of a 180deg rotation
828 if (! (bXMirr && bYMirr)) {
829 long nTmp=nS0;
830 nS0=18000-nE0;
831 nE0=18000-nTmp;
833 } else { // mirror contorted ellipses
834 if (bXMirr!=bYMirr) {
835 nS0+=nWink0;
836 nE0+=nWink0;
837 if (bXMirr) {
838 long nTmp=nS0;
839 nS0=18000-nE0;
840 nE0=18000-nTmp;
842 if (bYMirr) {
843 long nTmp=nS0;
844 nS0=-nE0;
845 nE0=-nTmp;
847 nS0-=aGeo.nDrehWink;
848 nE0-=aGeo.nDrehWink;
851 long nWinkDif=nE0-nS0;
852 nStartWink=NormAngle360(nS0);
853 nEndWink =NormAngle360(nE0);
854 if (nWinkDif==36000) nEndWink+=nWinkDif; // full circle
857 SetXPolyDirty();
858 ImpSetCircInfoToAttr();
861 void SdrCircObj::NbcShear(const Point& rRef, long nWink, double tn, bool bVShear)
863 SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
864 SetXPolyDirty();
865 ImpSetCircInfoToAttr();
868 void SdrCircObj::NbcMirror(const Point& rRef1, const Point& rRef2)
870 bool bFreeMirr=meCircleKind!=OBJ_CIRC;
871 Point aTmpPt1;
872 Point aTmpPt2;
873 if (bFreeMirr) { // some preparations for using an arbitrary axis of reflection
874 Point aCenter(aRect.Center());
875 long nWdt=aRect.GetWidth()-1;
876 long nHgt=aRect.GetHeight()-1;
877 long nMaxRad=((nWdt>nHgt ? nWdt : nHgt)+1) /2;
878 double a;
879 // starting point
880 a=nStartWink*nPi180;
881 aTmpPt1=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
882 if (nWdt==0) aTmpPt1.X()=0;
883 if (nHgt==0) aTmpPt1.Y()=0;
884 aTmpPt1+=aCenter;
885 // finishing point
886 a=nEndWink*nPi180;
887 aTmpPt2=Point(Round(cos(a)*nMaxRad),-Round(sin(a)*nMaxRad));
888 if (nWdt==0) aTmpPt2.X()=0;
889 if (nHgt==0) aTmpPt2.Y()=0;
890 aTmpPt2+=aCenter;
891 if (aGeo.nDrehWink!=0) {
892 RotatePoint(aTmpPt1,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
893 RotatePoint(aTmpPt2,aRect.TopLeft(),aGeo.nSin,aGeo.nCos);
895 if (aGeo.nShearWink!=0) {
896 ShearPoint(aTmpPt1,aRect.TopLeft(),aGeo.nTan);
897 ShearPoint(aTmpPt2,aRect.TopLeft(),aGeo.nTan);
900 SdrTextObj::NbcMirror(rRef1,rRef2);
901 if (meCircleKind!=OBJ_CIRC) { // adapt starting and finishing angle
902 MirrorPoint(aTmpPt1,rRef1,rRef2);
903 MirrorPoint(aTmpPt2,rRef1,rRef2);
904 // unrotate:
905 if (aGeo.nDrehWink!=0) {
906 RotatePoint(aTmpPt1,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin for reversion
907 RotatePoint(aTmpPt2,aRect.TopLeft(),-aGeo.nSin,aGeo.nCos); // -sin for reversion
909 // unshear:
910 if (aGeo.nShearWink!=0) {
911 ShearPoint(aTmpPt1,aRect.TopLeft(),-aGeo.nTan); // -tan for reversion
912 ShearPoint(aTmpPt2,aRect.TopLeft(),-aGeo.nTan); // -tan for reversion
914 Point aCenter(aRect.Center());
915 aTmpPt1-=aCenter;
916 aTmpPt2-=aCenter;
917 // because it's mirrored, the angles are swapped, too
918 nStartWink=GetAngle(aTmpPt2);
919 nEndWink =GetAngle(aTmpPt1);
920 long nWinkDif=nEndWink-nStartWink;
921 nStartWink=NormAngle360(nStartWink);
922 nEndWink =NormAngle360(nEndWink);
923 if (nWinkDif==36000) nEndWink+=nWinkDif; // full circle
925 SetXPolyDirty();
926 ImpSetCircInfoToAttr();
929 SdrObjGeoData* SdrCircObj::NewGeoData() const
931 return new SdrCircObjGeoData;
934 void SdrCircObj::SaveGeoData(SdrObjGeoData& rGeo) const
936 SdrRectObj::SaveGeoData(rGeo);
937 SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
938 rCGeo.nStartWink=nStartWink;
939 rCGeo.nEndWink =nEndWink;
942 void SdrCircObj::RestGeoData(const SdrObjGeoData& rGeo)
944 SdrRectObj::RestGeoData(rGeo);
945 SdrCircObjGeoData& rCGeo=(SdrCircObjGeoData&)rGeo;
946 nStartWink=rCGeo.nStartWink;
947 nEndWink =rCGeo.nEndWink;
948 SetXPolyDirty();
949 ImpSetCircInfoToAttr();
952 void Union(Rectangle& rR, const Point& rP)
954 if (rP.X()<rR.Left ()) rR.Left ()=rP.X();
955 if (rP.X()>rR.Right ()) rR.Right ()=rP.X();
956 if (rP.Y()<rR.Top ()) rR.Top ()=rP.Y();
957 if (rP.Y()>rR.Bottom()) rR.Bottom()=rP.Y();
960 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle& rRect) const
962 rRect=aRect;
963 if (meCircleKind!=OBJ_CIRC) {
964 const Point aPntStart(GetWinkPnt(aRect,nStartWink));
965 const Point aPntEnd(GetWinkPnt(aRect,nEndWink));
966 long a=nStartWink;
967 long e=nEndWink;
968 rRect.Left ()=aRect.Right();
969 rRect.Right ()=aRect.Left();
970 rRect.Top ()=aRect.Bottom();
971 rRect.Bottom()=aRect.Top();
972 Union(rRect,aPntStart);
973 Union(rRect,aPntEnd);
974 if ((a<=18000 && e>=18000) || (a>e && (a<=18000 || e>=18000))) {
975 Union(rRect,aRect.LeftCenter());
977 if ((a<=27000 && e>=27000) || (a>e && (a<=27000 || e>=27000))) {
978 Union(rRect,aRect.BottomCenter());
980 if (a>e) {
981 Union(rRect,aRect.RightCenter());
983 if ((a<=9000 && e>=9000) || (a>e && (a<=9000 || e>=9000))) {
984 Union(rRect,aRect.TopCenter());
986 if (meCircleKind==OBJ_SECT) {
987 Union(rRect,aRect.Center());
989 if (aGeo.nDrehWink!=0) {
990 Point aDst(rRect.TopLeft());
991 aDst-=aRect.TopLeft();
992 Point aDst0(aDst);
993 RotatePoint(aDst,Point(),aGeo.nSin,aGeo.nCos);
994 aDst-=aDst0;
995 rRect.Move(aDst.X(),aDst.Y());
998 if (aGeo.nShearWink!=0) {
999 long nDst=Round((rRect.Bottom()-rRect.Top())*aGeo.nTan);
1000 if (aGeo.nShearWink>0) {
1001 Point aRef(rRect.TopLeft());
1002 rRect.Left()-=nDst;
1003 Point aTmpPt(rRect.TopLeft());
1004 RotatePoint(aTmpPt,aRef,aGeo.nSin,aGeo.nCos);
1005 aTmpPt-=rRect.TopLeft();
1006 rRect.Move(aTmpPt.X(),aTmpPt.Y());
1007 } else {
1008 rRect.Right()-=nDst;
1013 void SdrCircObj::RecalcSnapRect()
1015 if (PaintNeedsXPolyCirc()) {
1016 maSnapRect=GetXPoly().GetBoundRect();
1017 } else {
1018 TakeUnrotatedSnapRect(maSnapRect);
1022 void SdrCircObj::NbcSetSnapRect(const Rectangle& rRect)
1024 if (aGeo.nDrehWink!=0 || aGeo.nShearWink!=0 || meCircleKind!=OBJ_CIRC) {
1025 Rectangle aSR0(GetSnapRect());
1026 long nWdt0=aSR0.Right()-aSR0.Left();
1027 long nHgt0=aSR0.Bottom()-aSR0.Top();
1028 long nWdt1=rRect.Right()-rRect.Left();
1029 long nHgt1=rRect.Bottom()-rRect.Top();
1030 NbcResize(maSnapRect.TopLeft(),Fraction(nWdt1,nWdt0),Fraction(nHgt1,nHgt0));
1031 NbcMove(Size(rRect.Left()-aSR0.Left(),rRect.Top()-aSR0.Top()));
1032 } else {
1033 aRect=rRect;
1034 ImpJustifyRect(aRect);
1036 SetRectsDirty();
1037 SetXPolyDirty();
1038 ImpSetCircInfoToAttr();
1041 sal_uInt32 SdrCircObj::GetSnapPointCount() const
1043 if (meCircleKind==OBJ_CIRC) {
1044 return 1L;
1045 } else {
1046 return 3L;
1050 Point SdrCircObj::GetSnapPoint(sal_uInt32 i) const
1052 switch (i) {
1053 case 1 : return GetWinkPnt(aRect,nStartWink);
1054 case 2 : return GetWinkPnt(aRect,nEndWink);
1055 default: return aRect.Center();
1059 void SdrCircObj::Notify(SfxBroadcaster& rBC, const SfxHint& rHint)
1061 SetXPolyDirty();
1062 SdrRectObj::Notify(rBC,rHint);
1063 ImpSetAttrToCircInfo();
1066 ////////////////////////////////////////////////////////////////////////////////////////////////////
1068 void SdrCircObj::ImpSetAttrToCircInfo()
1070 const SfxItemSet& rSet = GetObjectItemSet();
1071 SdrCircKind eNewKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
1072 SdrObjKind eNewKind = meCircleKind;
1074 if(eNewKindA == SDRCIRC_FULL)
1075 eNewKind = OBJ_CIRC;
1076 else if(eNewKindA == SDRCIRC_SECT)
1077 eNewKind = OBJ_SECT;
1078 else if(eNewKindA == SDRCIRC_ARC)
1079 eNewKind = OBJ_CARC;
1080 else if(eNewKindA == SDRCIRC_CUT)
1081 eNewKind = OBJ_CCUT;
1083 sal_Int32 nNewStart = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
1084 sal_Int32 nNewEnd = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
1086 bool bKindChg = meCircleKind != eNewKind;
1087 bool bWinkChg = nNewStart != nStartWink || nNewEnd != nEndWink;
1089 if(bKindChg || bWinkChg)
1091 meCircleKind = eNewKind;
1092 nStartWink = nNewStart;
1093 nEndWink = nNewEnd;
1095 if(bKindChg || (meCircleKind != OBJ_CIRC && bWinkChg))
1097 SetXPolyDirty();
1098 SetRectsDirty();
1103 void SdrCircObj::ImpSetCircInfoToAttr()
1105 SdrCircKind eNewKindA = SDRCIRC_FULL;
1106 const SfxItemSet& rSet = GetObjectItemSet();
1108 if(meCircleKind == OBJ_SECT)
1109 eNewKindA = SDRCIRC_SECT;
1110 else if(meCircleKind == OBJ_CARC)
1111 eNewKindA = SDRCIRC_ARC;
1112 else if(meCircleKind == OBJ_CCUT)
1113 eNewKindA = SDRCIRC_CUT;
1115 SdrCircKind eOldKindA = ((SdrCircKindItem&)rSet.Get(SDRATTR_CIRCKIND)).GetValue();
1116 sal_Int32 nOldStartWink = ((SdrCircStartAngleItem&)rSet.Get(SDRATTR_CIRCSTARTANGLE)).GetValue();
1117 sal_Int32 nOldEndWink = ((SdrCircEndAngleItem&)rSet.Get(SDRATTR_CIRCENDANGLE)).GetValue();
1119 if(eNewKindA != eOldKindA || nStartWink != nOldStartWink || nEndWink != nOldEndWink)
1121 // since SetItem() implicitly calls ImpSetAttrToCircInfo()
1122 // setting the item directly is necessary here.
1123 if(eNewKindA != eOldKindA)
1125 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA));
1128 if(nStartWink != nOldStartWink)
1130 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink));
1133 if(nEndWink != nOldEndWink)
1135 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink));
1138 SetXPolyDirty();
1139 ImpSetAttrToCircInfo();
1143 SdrObject* SdrCircObj::DoConvertToPolyObj(sal_Bool bBezier, bool bAddText) const
1145 const sal_Bool bFill(OBJ_CARC == meCircleKind ? sal_False : sal_True);
1146 const basegfx::B2DPolygon aCircPolygon(ImpCalcXPolyCirc(meCircleKind, aRect, nStartWink, nEndWink));
1147 SdrObject* pRet = ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon), bFill, bBezier);
1149 if(bAddText)
1151 pRet = ImpConvertAddText(pRet, bBezier);
1154 return pRet;
1157 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */