1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
29 #include <svl/style.hxx>
30 #include <svx/xlnwtit.hxx>
31 #include <svx/xlnedwit.hxx>
32 #include <svx/xlnstwit.hxx>
33 #include <svx/xlnstit.hxx>
34 #include <svx/xlnedit.hxx>
35 #include <svx/svdocirc.hxx>
37 #include <svx/xpool.hxx>
38 #include <svx/svdattr.hxx>
39 #include <svx/svdpool.hxx>
40 #include <svx/svdattrx.hxx>
41 #include <svx/svdtrans.hxx>
42 #include <svx/svdetc.hxx>
43 #include <svx/svddrag.hxx>
44 #include <svx/svdmodel.hxx>
45 #include <svx/svdpage.hxx>
46 #include <svx/svdopath.hxx> // for the object conversion
47 #include <svx/svdview.hxx> // for dragging (Ortho)
48 #include "svx/svdglob.hxx" // StringCache
49 #include "svx/svdstr.hrc" // the object's name
50 #include <editeng/eeitem.hxx>
51 #include <svx/sdr/properties/circleproperties.hxx>
52 #include <svx/sdr/contact/viewcontactofsdrcircobj.hxx>
53 #include <basegfx/point/b2dpoint.hxx>
54 #include <basegfx/polygon/b2dpolygon.hxx>
55 #include <basegfx/polygon/b2dpolygontools.hxx>
56 #include <basegfx/matrix/b2dhommatrix.hxx>
57 #include <basegfx/matrix/b2dhommatrixtools.hxx>
59 //////////////////////////////////////////////////////////////////////////////
61 Point
GetWinkPnt(const Rectangle
& rR
, long nWink
)
63 Point
aCenter(rR
.Center());
64 long nWdt
=rR
.Right()-rR
.Left();
65 long nHgt
=rR
.Bottom()-rR
.Top();
66 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
69 Point
aRetval(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
70 if (nWdt
==0) aRetval
.X()=0;
71 if (nHgt
==0) aRetval
.Y()=0;
75 // stop possible overruns for very large objects
76 if (Abs(nHgt
)>32767 || Abs(aRetval
.Y())>32767) {
77 aRetval
.Y()=BigMulDiv(aRetval
.Y(),nHgt
,nWdt
);
79 aRetval
.Y()=aRetval
.Y()*nHgt
/nWdt
;
84 // stop possible overruns for very large objects
85 if (Abs(nWdt
)>32767 || Abs(aRetval
.X())>32767) {
86 aRetval
.X()=BigMulDiv(aRetval
.X(),nWdt
,nHgt
);
88 aRetval
.X()=aRetval
.X()*nWdt
/nHgt
;
97 //////////////////////////////////////////////////////////////////////////////
98 // BaseProperties section
100 sdr::properties::BaseProperties
* SdrCircObj::CreateObjectSpecificProperties()
102 return new sdr::properties::CircleProperties(*this);
105 //////////////////////////////////////////////////////////////////////////////
106 // DrawContact section
108 sdr::contact::ViewContact
* SdrCircObj::CreateObjectSpecificViewContact()
110 return new sdr::contact::ViewContactOfSdrCircObj(*this);
113 //////////////////////////////////////////////////////////////////////////////
115 TYPEINIT1(SdrCircObj
,SdrRectObj
);
117 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
)
121 meCircleKind
=eNewKind
;
122 bClosedObj
=eNewKind
!=OBJ_CARC
;
125 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
):
130 meCircleKind
=eNewKind
;
131 bClosedObj
=eNewKind
!=OBJ_CARC
;
134 SdrCircObj::SdrCircObj(SdrObjKind eNewKind
, const Rectangle
& rRect
, long nNewStartWink
, long nNewEndWink
):
137 long nWinkDif
=nNewEndWink
-nNewStartWink
;
138 nStartWink
=NormAngle360(nNewStartWink
);
139 nEndWink
=NormAngle360(nNewEndWink
);
140 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
141 meCircleKind
=eNewKind
;
142 bClosedObj
=eNewKind
!=OBJ_CARC
;
145 SdrCircObj::~SdrCircObj()
149 void SdrCircObj::TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const
151 bool bCanConv
=!HasText() || ImpCanConvTextToCurve();
152 rInfo
.bEdgeRadiusAllowed
= sal_False
;
153 rInfo
.bCanConvToPath
=bCanConv
;
154 rInfo
.bCanConvToPoly
=bCanConv
;
155 rInfo
.bCanConvToContour
= !IsFontwork() && (rInfo
.bCanConvToPoly
|| LineGeometryUsageIsNecessary());
158 sal_uInt16
SdrCircObj::GetObjIdentifier() const
160 return sal_uInt16(meCircleKind
);
163 bool SdrCircObj::PaintNeedsXPolyCirc() const
165 // XPoly is necessary for all rotated ellipse objects, circle and
167 // If not WIN, then (for now) also for circle/ellipse segments and circle/
168 // ellipse arcs (for precision)
169 bool bNeed
=aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
==OBJ_CCUT
;
170 // If not WIN, then for everything except full circle (for now!)
171 if (meCircleKind
!=OBJ_CIRC
) bNeed
= true;
173 const SfxItemSet
& rSet
= GetObjectItemSet();
176 // XPoly is necessary for everything that isn't LineSolid or LineNone
177 XLineStyle eLine
= ((XLineStyleItem
&)(rSet
.Get(XATTR_LINESTYLE
))).GetValue();
178 bNeed
= eLine
!= XLINE_NONE
&& eLine
!= XLINE_SOLID
;
180 // XPoly is necessary for thick lines
181 if(!bNeed
&& eLine
!= XLINE_NONE
)
182 bNeed
= ((XLineWidthItem
&)(rSet
.Get(XATTR_LINEWIDTH
))).GetValue() != 0;
184 // XPoly is necessary for circle arcs with line ends
185 if(!bNeed
&& meCircleKind
== OBJ_CARC
)
187 // start of the line is here if StartPolygon, StartWidth!=0
188 bNeed
=((XLineStartItem
&)(rSet
.Get(XATTR_LINESTART
))).GetLineStartValue().count() != 0L &&
189 ((XLineStartWidthItem
&)(rSet
.Get(XATTR_LINESTARTWIDTH
))).GetValue() != 0;
193 // end of the line is here if EndPolygon, EndWidth!=0
194 bNeed
= ((XLineEndItem
&)(rSet
.Get(XATTR_LINEEND
))).GetLineEndValue().count() != 0L &&
195 ((XLineEndWidthItem
&)(rSet
.Get(XATTR_LINEENDWIDTH
))).GetValue() != 0;
200 // XPoly is necessary if Fill !=None and !=Solid
201 if(!bNeed
&& meCircleKind
!= OBJ_CARC
)
203 XFillStyle eFill
=((XFillStyleItem
&)(rSet
.Get(XATTR_FILLSTYLE
))).GetValue();
204 bNeed
= eFill
!= XFILL_NONE
&& eFill
!= XFILL_SOLID
;
207 if(!bNeed
&& meCircleKind
!= OBJ_CIRC
&& nStartWink
== nEndWink
)
208 bNeed
= true; // otherwise we're drawing a full circle
213 basegfx::B2DPolygon
SdrCircObj::ImpCalcXPolyCirc(const SdrObjKind eCicrleKind
, const Rectangle
& rRect1
, long nStart
, long nEnd
) const
215 const basegfx::B2DRange
aRange(rRect1
.Left(), rRect1
.Top(), rRect1
.Right(), rRect1
.Bottom());
216 basegfx::B2DPolygon aCircPolygon
;
218 if(OBJ_CIRC
== eCicrleKind
)
220 // create full circle. Do not use createPolygonFromEllipse; it's necessary
221 // to get the start point to the bottom of the circle to keep compatible to
222 // old geometry creation
223 aCircPolygon
= basegfx::tools::createPolygonFromUnitCircle(1);
225 // needs own scaling and translation from unit circle to target size (same as
226 // would be in createPolygonFromEllipse)
227 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
228 const basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createScaleTranslateB2DHomMatrix(
229 aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
230 aCenter
.getX(), aCenter
.getY()));
231 aCircPolygon
.transform(aMatrix
);
235 // mirror start, end for geometry creation since model coordinate system is mirrored in Y
236 // #i111715# increase numerical correctness by first dividing and not using F_PI1800
237 const double fStart((((36000 - nEnd
) % 36000) / 18000.0) * F_PI
);
238 const double fEnd((((36000 - nStart
) % 36000) / 18000.0) * F_PI
);
240 // create circle segment. This is not closed by default
241 aCircPolygon
= basegfx::tools::createPolygonFromEllipseSegment(
242 aRange
.getCenter(), aRange
.getWidth() / 2.0, aRange
.getHeight() / 2.0,
245 // check closing states
246 const bool bCloseSegment(OBJ_CARC
!= eCicrleKind
);
247 const bool bCloseUsingCenter(OBJ_SECT
== eCicrleKind
);
251 if(bCloseUsingCenter
)
253 // add center point at start (for historical reasons)
254 basegfx::B2DPolygon aSector
;
255 aSector
.append(aRange
.getCenter());
256 aSector
.append(aCircPolygon
);
257 aCircPolygon
= aSector
;
261 aCircPolygon
.setClosed(true);
266 if(aGeo
.nShearWink
|| aGeo
.nDrehWink
)
268 // translate top left to (0,0)
269 const basegfx::B2DPoint
aTopLeft(aRange
.getMinimum());
270 basegfx::B2DHomMatrix
aMatrix(basegfx::tools::createTranslateB2DHomMatrix(
271 -aTopLeft
.getX(), -aTopLeft
.getY()));
273 // shear, rotate and back to top left (if needed)
274 aMatrix
= basegfx::tools::createShearXRotateTranslateB2DHomMatrix(
275 aGeo
.nShearWink
? tan((36000 - aGeo
.nShearWink
) * F_PI18000
) : 0.0,
276 aGeo
.nDrehWink
? (36000 - aGeo
.nDrehWink
) * F_PI18000
: 0.0,
279 // apply transformation
280 aCircPolygon
.transform(aMatrix
);
286 void SdrCircObj::RecalcXPoly()
288 const basegfx::B2DPolygon
aPolyCirc(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
289 mpXPoly
= new XPolygon(aPolyCirc
);
292 void SdrCircObj::TakeObjNameSingul(XubString
& rName
) const
294 sal_uInt16 nID
=STR_ObjNameSingulCIRC
;
295 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
296 switch (meCircleKind
) {
297 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRC
; break;
298 case OBJ_SECT
: nID
=STR_ObjNameSingulSECT
; break;
299 case OBJ_CARC
: nID
=STR_ObjNameSingulCARC
; break;
300 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUT
; break;
304 switch (meCircleKind
) {
305 case OBJ_CIRC
: nID
=STR_ObjNameSingulCIRCE
; break;
306 case OBJ_SECT
: nID
=STR_ObjNameSingulSECTE
; break;
307 case OBJ_CARC
: nID
=STR_ObjNameSingulCARCE
; break;
308 case OBJ_CCUT
: nID
=STR_ObjNameSingulCCUTE
; break;
312 rName
=ImpGetResStr(nID
);
314 String
aName( GetName() );
317 rName
+= sal_Unicode(' ');
318 rName
+= sal_Unicode('\'');
320 rName
+= sal_Unicode('\'');
324 void SdrCircObj::TakeObjNamePlural(XubString
& rName
) const
326 sal_uInt16 nID
=STR_ObjNamePluralCIRC
;
327 if (aRect
.GetWidth()==aRect
.GetHeight() && aGeo
.nShearWink
==0) {
328 switch (meCircleKind
) {
329 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRC
; break;
330 case OBJ_SECT
: nID
=STR_ObjNamePluralSECT
; break;
331 case OBJ_CARC
: nID
=STR_ObjNamePluralCARC
; break;
332 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUT
; break;
336 switch (meCircleKind
) {
337 case OBJ_CIRC
: nID
=STR_ObjNamePluralCIRCE
; break;
338 case OBJ_SECT
: nID
=STR_ObjNamePluralSECTE
; break;
339 case OBJ_CARC
: nID
=STR_ObjNamePluralCARCE
; break;
340 case OBJ_CCUT
: nID
=STR_ObjNamePluralCCUTE
; break;
344 rName
=ImpGetResStr(nID
);
347 SdrCircObj
* SdrCircObj::Clone() const
349 return CloneHelper
< SdrCircObj
>();
352 basegfx::B2DPolyPolygon
SdrCircObj::TakeXorPoly() const
354 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
355 return basegfx::B2DPolyPolygon(aCircPolygon
);
358 struct ImpCircUser
: public SdrDragStatUserData
371 bool bRight
; // not yet implemented
383 void SetCreateParams(SdrDragStat
& rStat
);
386 sal_uInt32
SdrCircObj::GetHdlCount() const
388 if(OBJ_CIRC
!= meCircleKind
)
398 SdrHdl
* SdrCircObj::GetHdl(sal_uInt32 nHdlNum
) const
400 if (meCircleKind
==OBJ_CIRC
)
407 SdrHdlKind
eLocalKind(HDL_MOVE
);
413 aPnt
= GetWinkPnt(aRect
,nStartWink
);
414 eLocalKind
= HDL_CIRC
;
418 aPnt
= GetWinkPnt(aRect
,nEndWink
);
419 eLocalKind
= HDL_CIRC
;
423 aPnt
= aRect
.TopLeft();
424 eLocalKind
= HDL_UPLFT
;
427 aPnt
= aRect
.TopCenter();
428 eLocalKind
= HDL_UPPER
;
431 aPnt
= aRect
.TopRight();
432 eLocalKind
= HDL_UPRGT
;
435 aPnt
= aRect
.LeftCenter();
436 eLocalKind
= HDL_LEFT
;
439 aPnt
= aRect
.RightCenter();
440 eLocalKind
= HDL_RIGHT
;
443 aPnt
= aRect
.BottomLeft();
444 eLocalKind
= HDL_LWLFT
;
447 aPnt
= aRect
.BottomCenter();
448 eLocalKind
= HDL_LOWER
;
451 aPnt
= aRect
.BottomRight();
452 eLocalKind
= HDL_LWRGT
;
458 ShearPoint(aPnt
,aRect
.TopLeft(),aGeo
.nTan
);
463 RotatePoint(aPnt
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
466 if (eLocalKind
!= HDL_MOVE
)
468 pH
= new SdrHdl(aPnt
,eLocalKind
);
469 pH
->SetPointNum(nPNum
);
470 pH
->SetObj((SdrObject
*)this);
471 pH
->SetDrehWink(aGeo
.nDrehWink
);
477 ////////////////////////////////////////////////////////////////////////////////////////////////////
479 bool SdrCircObj::hasSpecialDrag() const
484 bool SdrCircObj::beginSpecialDrag(SdrDragStat
& rDrag
) const
486 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
490 if(1 == rDrag
.GetHdl()->GetPointNum() || 2 == rDrag
.GetHdl()->GetPointNum())
492 rDrag
.SetNoSnap(true);
498 return SdrTextObj::beginSpecialDrag(rDrag
);
501 bool SdrCircObj::applySpecialDrag(SdrDragStat
& rDrag
)
503 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
507 Point
aPt(rDrag
.GetNow());
509 if (aGeo
.nDrehWink
!=0)
510 RotatePoint(aPt
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
);
512 if (aGeo
.nShearWink
!=0)
513 ShearPoint(aPt
,aRect
.TopLeft(),-aGeo
.nTan
);
517 long nWdt
=aRect
.Right()-aRect
.Left();
518 long nHgt
=aRect
.Bottom()-aRect
.Top();
522 aPt
.Y()=BigMulDiv(aPt
.Y(),nWdt
,nHgt
);
526 aPt
.X()=BigMulDiv(aPt
.X(),nHgt
,nWdt
);
529 long nWink
=NormAngle360(GetAngle(aPt
));
531 if (rDrag
.GetView() && rDrag
.GetView()->IsAngleSnapEnabled())
533 long nSA
=rDrag
.GetView()->GetSnapAngle();
540 nWink
=NormAngle360(nWink
);
544 if(1 == rDrag
.GetHdl()->GetPointNum())
548 else if(2 == rDrag
.GetHdl()->GetPointNum())
555 ImpSetCircInfoToAttr();
562 return SdrTextObj::applySpecialDrag(rDrag
);
566 String
SdrCircObj::getSpecialDragComment(const SdrDragStat
& rDrag
) const
568 const bool bCreateComment(rDrag
.GetView() && this == rDrag
.GetView()->GetCreateObj());
573 ImpTakeDescriptionStr(STR_ViewCreateObj
, aStr
);
574 rtl::OUStringBuffer
aBuf(aStr
);
575 const sal_uInt32
nPntAnz(rDrag
.GetPointAnz());
577 if(OBJ_CIRC
!= meCircleKind
&& nPntAnz
> 2)
579 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
582 aBuf
.appendAscii(" (");
593 aBuf
.append(GetWinkStr(nWink
,false));
594 aBuf
.append(sal_Unicode(')'));
597 return aBuf
.makeStringAndClear();
601 const bool bWink(rDrag
.GetHdl() && HDL_CIRC
== rDrag
.GetHdl()->GetKind());
605 const sal_Int32
nWink(1 == rDrag
.GetHdl()->GetPointNum() ? nStartWink
: nEndWink
);
608 ImpTakeDescriptionStr(STR_DragCircAngle
, aStr
);
609 rtl::OUStringBuffer
aBuf(aStr
);
610 aBuf
.appendAscii(" (");
611 aBuf
.append(GetWinkStr(nWink
,false));
612 aBuf
.append(sal_Unicode(')'));
614 return aBuf
.makeStringAndClear();
618 return SdrTextObj::getSpecialDragComment(rDrag
);
623 ////////////////////////////////////////////////////////////////////////////////////////////////////
625 void ImpCircUser::SetCreateParams(SdrDragStat
& rStat
)
627 rStat
.TakeCreateRect(aR
);
630 nWdt
=aR
.Right()-aR
.Left();
631 nHgt
=aR
.Bottom()-aR
.Top();
632 nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
635 if (rStat
.GetPointAnz()>2) {
636 Point
aP(rStat
.GetPoint(2)-aCenter
);
637 if (nWdt
==0) aP
.X()=0;
638 if (nHgt
==0) aP
.Y()=0;
640 if (nHgt
!=0) aP
.Y()=aP
.Y()*nWdt
/nHgt
;
642 if (nWdt
!=0) aP
.X()=aP
.X()*nHgt
/nWdt
;
644 nStart
=NormAngle360(GetAngle(aP
));
645 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
646 long nSA
=rStat
.GetView()->GetSnapAngle();
647 if (nSA
!=0) { // angle snapping
651 nStart
=NormAngle360(nStart
);
654 aP1
= GetWinkPnt(aR
,nStart
);
658 if (rStat
.GetPointAnz()>3) {
659 Point
aP(rStat
.GetPoint(3)-aCenter
);
661 aP
.Y()=BigMulDiv(aP
.Y(),nWdt
,nHgt
);
663 aP
.X()=BigMulDiv(aP
.X(),nHgt
,nWdt
);
665 nEnd
=NormAngle360(GetAngle(aP
));
666 if (rStat
.GetView()!=NULL
&& rStat
.GetView()->IsAngleSnapEnabled()) {
667 long nSA
=rStat
.GetView()->GetSnapAngle();
668 if (nSA
!=0) { // angle snapping
672 nEnd
=NormAngle360(nEnd
);
675 aP2
= GetWinkPnt(aR
,nEnd
);
679 void SdrCircObj::ImpSetCreateParams(SdrDragStat
& rStat
) const
681 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
686 pU
->SetCreateParams(rStat
);
689 bool SdrCircObj::BegCreate(SdrDragStat
& rStat
)
691 rStat
.SetOrtho4Possible();
692 Rectangle
aRect1(rStat
.GetStart(), rStat
.GetNow());
694 rStat
.SetActionRect(aRect1
);
696 ImpSetCreateParams(rStat
);
700 bool SdrCircObj::MovCreate(SdrDragStat
& rStat
)
702 ImpSetCreateParams(rStat
);
703 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
704 rStat
.SetActionRect(pU
->aR
);
705 aRect
=pU
->aR
; // for ObjName
706 ImpJustifyRect(aRect
);
707 nStartWink
=pU
->nStart
;
710 bSnapRectDirty
=sal_True
;
713 // #i103058# push current angle settings to ItemSet to
714 // allow FullDrag visualisation
715 if(rStat
.GetPointAnz() >= 4)
717 ImpSetCircInfoToAttr();
723 bool SdrCircObj::EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
)
725 ImpSetCreateParams(rStat
);
726 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
728 if (eCmd
==SDRCREATE_FORCEEND
&& rStat
.GetPointAnz()<4) meCircleKind
=OBJ_CIRC
;
729 if (meCircleKind
==OBJ_CIRC
) {
730 bRet
=rStat
.GetPointAnz()>=2;
733 ImpJustifyRect(aRect
);
736 rStat
.SetNoSnap(rStat
.GetPointAnz()>=2);
737 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<2);
738 bRet
=rStat
.GetPointAnz()>=4;
741 ImpJustifyRect(aRect
);
742 nStartWink
=pU
->nStart
;
746 bClosedObj
=meCircleKind
!=OBJ_CARC
;
749 ImpSetCircInfoToAttr();
757 void SdrCircObj::BrkCreate(SdrDragStat
& rStat
)
759 ImpCircUser
* pU
=(ImpCircUser
*)rStat
.GetUser();
764 bool SdrCircObj::BckCreate(SdrDragStat
& rStat
)
766 rStat
.SetNoSnap(rStat
.GetPointAnz()>=3);
767 rStat
.SetOrtho4Possible(rStat
.GetPointAnz()<3);
768 return meCircleKind
!=OBJ_CIRC
;
771 basegfx::B2DPolyPolygon
SdrCircObj::TakeCreatePoly(const SdrDragStat
& rDrag
) const
773 ImpCircUser
* pU
= (ImpCircUser
*)rDrag
.GetUser();
775 if(rDrag
.GetPointAnz() < 4L)
777 // force to OBJ_CIRC to get full visualisation
778 basegfx::B2DPolyPolygon
aRetval(ImpCalcXPolyCirc(OBJ_CIRC
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
780 if(3L == rDrag
.GetPointAnz())
782 // add edge to first point on ellipse
783 basegfx::B2DPolygon aNew
;
785 aNew
.append(basegfx::B2DPoint(pU
->aCenter
.X(), pU
->aCenter
.Y()));
786 aNew
.append(basegfx::B2DPoint(pU
->aP1
.X(), pU
->aP1
.Y()));
787 aRetval
.append(aNew
);
794 return basegfx::B2DPolyPolygon(ImpCalcXPolyCirc(meCircleKind
, pU
->aR
, pU
->nStart
, pU
->nEnd
));
798 Pointer
SdrCircObj::GetCreatePointer() const
800 switch (meCircleKind
) {
801 case OBJ_CIRC
: return Pointer(POINTER_DRAW_ELLIPSE
);
802 case OBJ_SECT
: return Pointer(POINTER_DRAW_PIE
);
803 case OBJ_CARC
: return Pointer(POINTER_DRAW_ARC
);
804 case OBJ_CCUT
: return Pointer(POINTER_DRAW_CIRCLECUT
);
807 return Pointer(POINTER_CROSS
);
810 void SdrCircObj::NbcMove(const Size
& aSiz
)
812 MoveRect(aRect
,aSiz
);
813 MoveRect(aOutRect
,aSiz
);
814 MoveRect(maSnapRect
,aSiz
);
816 SetRectsDirty(sal_True
);
819 void SdrCircObj::NbcResize(const Point
& rRef
, const Fraction
& xFact
, const Fraction
& yFact
)
821 long nWink0
=aGeo
.nDrehWink
;
822 bool bNoShearRota
=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
823 SdrTextObj::NbcResize(rRef
,xFact
,yFact
);
824 bNoShearRota
|=(aGeo
.nDrehWink
==0 && aGeo
.nShearWink
==0);
825 if (meCircleKind
!=OBJ_CIRC
) {
826 bool bXMirr
=(xFact
.GetNumerator()<0) != (xFact
.GetDenominator()<0);
827 bool bYMirr
=(yFact
.GetNumerator()<0) != (yFact
.GetDenominator()<0);
828 if (bXMirr
|| bYMirr
) {
829 // At bXMirr!=bYMirr we should actually swap both line ends.
830 // That, however, is pretty bad (because of forced "hard" formatting).
831 // Alternatively, we could implement a bMirrored flag (maybe even
832 // a more general one, e. g. for mirrored text, ...).
836 // the RectObj already mirrors at VMirror because of a 180deg rotation
837 if (! (bXMirr
&& bYMirr
)) {
842 } else { // mirror contorted ellipses
843 if (bXMirr
!=bYMirr
) {
860 long nWinkDif
=nE0
-nS0
;
861 nStartWink
=NormAngle360(nS0
);
862 nEndWink
=NormAngle360(nE0
);
863 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
867 ImpSetCircInfoToAttr();
870 void SdrCircObj::NbcShear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
)
872 SdrTextObj::NbcShear(rRef
,nWink
,tn
,bVShear
);
874 ImpSetCircInfoToAttr();
877 void SdrCircObj::NbcMirror(const Point
& rRef1
, const Point
& rRef2
)
879 bool bFreeMirr
=meCircleKind
!=OBJ_CIRC
;
882 if (bFreeMirr
) { // some preparations for using an arbitrary axis of reflection
883 Point
aCenter(aRect
.Center());
884 long nWdt
=aRect
.GetWidth()-1;
885 long nHgt
=aRect
.GetHeight()-1;
886 long nMaxRad
=((nWdt
>nHgt
? nWdt
: nHgt
)+1) /2;
890 aTmpPt1
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
891 if (nWdt
==0) aTmpPt1
.X()=0;
892 if (nHgt
==0) aTmpPt1
.Y()=0;
896 aTmpPt2
=Point(Round(cos(a
)*nMaxRad
),-Round(sin(a
)*nMaxRad
));
897 if (nWdt
==0) aTmpPt2
.X()=0;
898 if (nHgt
==0) aTmpPt2
.Y()=0;
900 if (aGeo
.nDrehWink
!=0) {
901 RotatePoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
902 RotatePoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nSin
,aGeo
.nCos
);
904 if (aGeo
.nShearWink
!=0) {
905 ShearPoint(aTmpPt1
,aRect
.TopLeft(),aGeo
.nTan
);
906 ShearPoint(aTmpPt2
,aRect
.TopLeft(),aGeo
.nTan
);
909 SdrTextObj::NbcMirror(rRef1
,rRef2
);
910 if (meCircleKind
!=OBJ_CIRC
) { // adapt starting and finishing angle
911 MirrorPoint(aTmpPt1
,rRef1
,rRef2
);
912 MirrorPoint(aTmpPt2
,rRef1
,rRef2
);
914 if (aGeo
.nDrehWink
!=0) {
915 RotatePoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
916 RotatePoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nSin
,aGeo
.nCos
); // -sin for reversion
919 if (aGeo
.nShearWink
!=0) {
920 ShearPoint(aTmpPt1
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
921 ShearPoint(aTmpPt2
,aRect
.TopLeft(),-aGeo
.nTan
); // -tan for reversion
923 Point
aCenter(aRect
.Center());
926 // because it's mirrored, the angles are swapped, too
927 nStartWink
=GetAngle(aTmpPt2
);
928 nEndWink
=GetAngle(aTmpPt1
);
929 long nWinkDif
=nEndWink
-nStartWink
;
930 nStartWink
=NormAngle360(nStartWink
);
931 nEndWink
=NormAngle360(nEndWink
);
932 if (nWinkDif
==36000) nEndWink
+=nWinkDif
; // full circle
935 ImpSetCircInfoToAttr();
938 SdrObjGeoData
* SdrCircObj::NewGeoData() const
940 return new SdrCircObjGeoData
;
943 void SdrCircObj::SaveGeoData(SdrObjGeoData
& rGeo
) const
945 SdrRectObj::SaveGeoData(rGeo
);
946 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
947 rCGeo
.nStartWink
=nStartWink
;
948 rCGeo
.nEndWink
=nEndWink
;
951 void SdrCircObj::RestGeoData(const SdrObjGeoData
& rGeo
)
953 SdrRectObj::RestGeoData(rGeo
);
954 SdrCircObjGeoData
& rCGeo
=(SdrCircObjGeoData
&)rGeo
;
955 nStartWink
=rCGeo
.nStartWink
;
956 nEndWink
=rCGeo
.nEndWink
;
958 ImpSetCircInfoToAttr();
961 void Union(Rectangle
& rR
, const Point
& rP
)
963 if (rP
.X()<rR
.Left ()) rR
.Left ()=rP
.X();
964 if (rP
.X()>rR
.Right ()) rR
.Right ()=rP
.X();
965 if (rP
.Y()<rR
.Top ()) rR
.Top ()=rP
.Y();
966 if (rP
.Y()>rR
.Bottom()) rR
.Bottom()=rP
.Y();
969 void SdrCircObj::TakeUnrotatedSnapRect(Rectangle
& rRect
) const
972 if (meCircleKind
!=OBJ_CIRC
) {
973 const Point
aPntStart(GetWinkPnt(aRect
,nStartWink
));
974 const Point
aPntEnd(GetWinkPnt(aRect
,nEndWink
));
977 rRect
.Left ()=aRect
.Right();
978 rRect
.Right ()=aRect
.Left();
979 rRect
.Top ()=aRect
.Bottom();
980 rRect
.Bottom()=aRect
.Top();
981 Union(rRect
,aPntStart
);
982 Union(rRect
,aPntEnd
);
983 if ((a
<=18000 && e
>=18000) || (a
>e
&& (a
<=18000 || e
>=18000))) {
984 Union(rRect
,aRect
.LeftCenter());
986 if ((a
<=27000 && e
>=27000) || (a
>e
&& (a
<=27000 || e
>=27000))) {
987 Union(rRect
,aRect
.BottomCenter());
990 Union(rRect
,aRect
.RightCenter());
992 if ((a
<=9000 && e
>=9000) || (a
>e
&& (a
<=9000 || e
>=9000))) {
993 Union(rRect
,aRect
.TopCenter());
995 if (meCircleKind
==OBJ_SECT
) {
996 Union(rRect
,aRect
.Center());
998 if (aGeo
.nDrehWink
!=0) {
999 Point
aDst(rRect
.TopLeft());
1000 aDst
-=aRect
.TopLeft();
1002 RotatePoint(aDst
,Point(),aGeo
.nSin
,aGeo
.nCos
);
1004 rRect
.Move(aDst
.X(),aDst
.Y());
1007 if (aGeo
.nShearWink
!=0) {
1008 long nDst
=Round((rRect
.Bottom()-rRect
.Top())*aGeo
.nTan
);
1009 if (aGeo
.nShearWink
>0) {
1010 Point
aRef(rRect
.TopLeft());
1012 Point
aTmpPt(rRect
.TopLeft());
1013 RotatePoint(aTmpPt
,aRef
,aGeo
.nSin
,aGeo
.nCos
);
1014 aTmpPt
-=rRect
.TopLeft();
1015 rRect
.Move(aTmpPt
.X(),aTmpPt
.Y());
1017 rRect
.Right()-=nDst
;
1022 void SdrCircObj::RecalcSnapRect()
1024 if (PaintNeedsXPolyCirc()) {
1025 maSnapRect
=GetXPoly().GetBoundRect();
1027 TakeUnrotatedSnapRect(maSnapRect
);
1031 void SdrCircObj::NbcSetSnapRect(const Rectangle
& rRect
)
1033 if (aGeo
.nDrehWink
!=0 || aGeo
.nShearWink
!=0 || meCircleKind
!=OBJ_CIRC
) {
1034 Rectangle
aSR0(GetSnapRect());
1035 long nWdt0
=aSR0
.Right()-aSR0
.Left();
1036 long nHgt0
=aSR0
.Bottom()-aSR0
.Top();
1037 long nWdt1
=rRect
.Right()-rRect
.Left();
1038 long nHgt1
=rRect
.Bottom()-rRect
.Top();
1039 NbcResize(maSnapRect
.TopLeft(),Fraction(nWdt1
,nWdt0
),Fraction(nHgt1
,nHgt0
));
1040 NbcMove(Size(rRect
.Left()-aSR0
.Left(),rRect
.Top()-aSR0
.Top()));
1043 ImpJustifyRect(aRect
);
1047 ImpSetCircInfoToAttr();
1050 sal_uInt32
SdrCircObj::GetSnapPointCount() const
1052 if (meCircleKind
==OBJ_CIRC
) {
1059 Point
SdrCircObj::GetSnapPoint(sal_uInt32 i
) const
1062 case 1 : return GetWinkPnt(aRect
,nStartWink
);
1063 case 2 : return GetWinkPnt(aRect
,nEndWink
);
1064 default: return aRect
.Center();
1068 void SdrCircObj::Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
)
1071 SdrRectObj::Notify(rBC
,rHint
);
1072 ImpSetAttrToCircInfo();
1075 ////////////////////////////////////////////////////////////////////////////////////////////////////
1077 void SdrCircObj::ImpSetAttrToCircInfo()
1079 const SfxItemSet
& rSet
= GetObjectItemSet();
1080 SdrCircKind eNewKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1081 SdrObjKind eNewKind
= meCircleKind
;
1083 if(eNewKindA
== SDRCIRC_FULL
)
1084 eNewKind
= OBJ_CIRC
;
1085 else if(eNewKindA
== SDRCIRC_SECT
)
1086 eNewKind
= OBJ_SECT
;
1087 else if(eNewKindA
== SDRCIRC_ARC
)
1088 eNewKind
= OBJ_CARC
;
1089 else if(eNewKindA
== SDRCIRC_CUT
)
1090 eNewKind
= OBJ_CCUT
;
1092 sal_Int32 nNewStart
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1093 sal_Int32 nNewEnd
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1095 sal_Bool bKindChg
= meCircleKind
!= eNewKind
;
1096 sal_Bool bWinkChg
= nNewStart
!= nStartWink
|| nNewEnd
!= nEndWink
;
1098 if(bKindChg
|| bWinkChg
)
1100 meCircleKind
= eNewKind
;
1101 nStartWink
= nNewStart
;
1104 if(bKindChg
|| (meCircleKind
!= OBJ_CIRC
&& bWinkChg
))
1112 void SdrCircObj::ImpSetCircInfoToAttr()
1114 SdrCircKind eNewKindA
= SDRCIRC_FULL
;
1115 const SfxItemSet
& rSet
= GetObjectItemSet();
1117 if(meCircleKind
== OBJ_SECT
)
1118 eNewKindA
= SDRCIRC_SECT
;
1119 else if(meCircleKind
== OBJ_CARC
)
1120 eNewKindA
= SDRCIRC_ARC
;
1121 else if(meCircleKind
== OBJ_CCUT
)
1122 eNewKindA
= SDRCIRC_CUT
;
1124 SdrCircKind eOldKindA
= ((SdrCircKindItem
&)rSet
.Get(SDRATTR_CIRCKIND
)).GetValue();
1125 sal_Int32 nOldStartWink
= ((SdrCircStartAngleItem
&)rSet
.Get(SDRATTR_CIRCSTARTANGLE
)).GetValue();
1126 sal_Int32 nOldEndWink
= ((SdrCircEndAngleItem
&)rSet
.Get(SDRATTR_CIRCENDANGLE
)).GetValue();
1128 if(eNewKindA
!= eOldKindA
|| nStartWink
!= nOldStartWink
|| nEndWink
!= nOldEndWink
)
1130 // since SetItem() implicitly calls ImpSetAttrToCircInfo()
1131 // setting the item directly is necessary here.
1132 if(eNewKindA
!= eOldKindA
)
1134 GetProperties().SetObjectItemDirect(SdrCircKindItem(eNewKindA
));
1137 if(nStartWink
!= nOldStartWink
)
1139 GetProperties().SetObjectItemDirect(SdrCircStartAngleItem(nStartWink
));
1142 if(nEndWink
!= nOldEndWink
)
1144 GetProperties().SetObjectItemDirect(SdrCircEndAngleItem(nEndWink
));
1148 ImpSetAttrToCircInfo();
1152 SdrObject
* SdrCircObj::DoConvertToPolyObj(sal_Bool bBezier
) const
1154 const sal_Bool
bFill(OBJ_CARC
== meCircleKind
? sal_False
: sal_True
);
1155 const basegfx::B2DPolygon
aCircPolygon(ImpCalcXPolyCirc(meCircleKind
, aRect
, nStartWink
, nEndWink
));
1156 SdrObject
* pRet
= ImpConvertMakeObj(basegfx::B2DPolyPolygon(aCircPolygon
), bFill
, bBezier
);
1157 pRet
= ImpConvertAddText(pRet
, bBezier
);
1162 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */