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 <tools/debug.hxx>
31 #include <svx/svdglue.hxx>
32 #include <svx/svdobj.hxx>
33 #include <svx/svdtrans.hxx>
35 static const Size
aGlueHalfSize(4,4);
37 void SdrGluePoint::SetReallyAbsolute(bool bOn
, const SdrObject
& rObj
)
39 if ( bReallyAbsolute
!= bOn
)
43 aPos
=GetAbsolutePos(rObj
);
50 SetAbsolutePos(aPt
,rObj
);
55 Point
SdrGluePoint::GetAbsolutePos(const SdrObject
& rObj
) const
57 if (bReallyAbsolute
) return aPos
;
58 Rectangle
aSnap(rObj
.GetSnapRect());
59 Rectangle
aBound(rObj
.GetSnapRect());
62 Point
aOfs(aSnap
.Center());
63 switch (GetHorzAlign()) {
64 case SDRHORZALIGN_LEFT
: aOfs
.X()=aSnap
.Left(); break;
65 case SDRHORZALIGN_RIGHT
: aOfs
.X()=aSnap
.Right(); break;
67 switch (GetVertAlign()) {
68 case SDRVERTALIGN_TOP
: aOfs
.Y()=aSnap
.Top(); break;
69 case SDRVERTALIGN_BOTTOM
: aOfs
.Y()=aSnap
.Bottom(); break;
72 long nXMul
=aSnap
.Right()-aSnap
.Left();
73 long nYMul
=aSnap
.Bottom()-aSnap
.Top();
86 // Now limit to the BoundRect of the object
87 if (aPt
.X()<aBound
.Left ()) aPt
.X()=aBound
.Left ();
88 if (aPt
.X()>aBound
.Right ()) aPt
.X()=aBound
.Right ();
89 if (aPt
.Y()<aBound
.Top ()) aPt
.Y()=aBound
.Top ();
90 if (aPt
.Y()>aBound
.Bottom()) aPt
.Y()=aBound
.Bottom();
94 void SdrGluePoint::SetAbsolutePos(const Point
& rNewPos
, const SdrObject
& rObj
)
96 if (bReallyAbsolute
) {
100 Rectangle
aSnap(rObj
.GetSnapRect());
103 Point
aOfs(aSnap
.Center());
104 switch (GetHorzAlign()) {
105 case SDRHORZALIGN_LEFT
: aOfs
.X()=aSnap
.Left(); break;
106 case SDRHORZALIGN_RIGHT
: aOfs
.X()=aSnap
.Right(); break;
108 switch (GetVertAlign()) {
109 case SDRVERTALIGN_TOP
: aOfs
.Y()=aSnap
.Top(); break;
110 case SDRVERTALIGN_BOTTOM
: aOfs
.Y()=aSnap
.Bottom(); break;
114 long nXMul
=aSnap
.Right()-aSnap
.Left();
115 long nYMul
=aSnap
.Bottom()-aSnap
.Top();
116 if (nXMul
==0) nXMul
=1;
117 if (nYMul
==0) nYMul
=1;
132 long SdrGluePoint::GetAlignAngle() const
135 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
: return 0; // Invalid!
136 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_CENTER
: return 0;
137 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_TOP
: return 4500;
138 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_TOP
: return 9000;
139 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_TOP
: return 13500;
140 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_CENTER
: return 18000;
141 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_BOTTOM
: return 22500;
142 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_BOTTOM
: return 27000;
143 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_BOTTOM
: return 31500;
148 void SdrGluePoint::SetAlignAngle(long nWink
)
150 nWink
=NormAngle360(nWink
);
151 if (nWink
>=33750 || nWink
<2250) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_CENTER
;
152 else if (nWink
< 6750) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_TOP
;
153 else if (nWink
<11250) nAlign
=SDRHORZALIGN_CENTER
|SDRVERTALIGN_TOP
;
154 else if (nWink
<15750) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_TOP
;
155 else if (nWink
<20250) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_CENTER
;
156 else if (nWink
<24750) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_BOTTOM
;
157 else if (nWink
<29250) nAlign
=SDRHORZALIGN_CENTER
|SDRVERTALIGN_BOTTOM
;
158 else if (nWink
<33750) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_BOTTOM
;
161 long SdrGluePoint::EscDirToAngle(sal_uInt16 nEsc
) const
164 case SDRESC_RIGHT
: return 0;
165 case SDRESC_TOP
: return 9000;
166 case SDRESC_LEFT
: return 18000;
167 case SDRESC_BOTTOM
: return 27000;
172 sal_uInt16
SdrGluePoint::EscAngleToDir(long nWink
) const
174 nWink
=NormAngle360(nWink
);
175 if (nWink
>=31500 || nWink
<4500) return SDRESC_RIGHT
;
176 if (nWink
<13500) return SDRESC_TOP
;
177 if (nWink
<22500) return SDRESC_LEFT
;
178 if (nWink
<31500) return SDRESC_BOTTOM
;
182 void SdrGluePoint::Rotate(const Point
& rRef
, long nWink
, double sn
, double cs
, const SdrObject
* pObj
)
184 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
185 RotatePoint(aPt
,rRef
,sn
,cs
);
186 // rotate reference edge
187 if(nAlign
!= (SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
))
189 SetAlignAngle(GetAlignAngle()+nWink
);
191 // rotate exit directions
192 sal_uInt16 nEscDir0
=nEscDir
;
193 sal_uInt16 nEscDir1
=0;
194 if ((nEscDir0
&SDRESC_LEFT
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_LEFT
)+nWink
);
195 if ((nEscDir0
&SDRESC_TOP
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_TOP
)+nWink
);
196 if ((nEscDir0
&SDRESC_RIGHT
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_RIGHT
)+nWink
);
197 if ((nEscDir0
&SDRESC_BOTTOM
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_BOTTOM
)+nWink
);
199 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
202 void SdrGluePoint::Mirror(const Point
& rRef1
, const Point
& rRef2
, long nWink
, const SdrObject
* pObj
)
204 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
205 MirrorPoint(aPt
,rRef1
,rRef2
);
206 // mirror reference edge
207 if(nAlign
!= (SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
))
209 long nAW
=GetAlignAngle();
213 // mirror exit directions
214 sal_uInt16 nEscDir0
=nEscDir
;
215 sal_uInt16 nEscDir1
=0;
216 if ((nEscDir0
&SDRESC_LEFT
)!=0) {
217 long nEW
=EscDirToAngle(SDRESC_LEFT
);
219 nEscDir1
|=EscAngleToDir(nEW
);
221 if ((nEscDir0
&SDRESC_TOP
)!=0) {
222 long nEW
=EscDirToAngle(SDRESC_TOP
);
224 nEscDir1
|=EscAngleToDir(nEW
);
226 if ((nEscDir0
&SDRESC_RIGHT
)!=0) {
227 long nEW
=EscDirToAngle(SDRESC_RIGHT
);
229 nEscDir1
|=EscAngleToDir(nEW
);
231 if ((nEscDir0
&SDRESC_BOTTOM
)!=0) {
232 long nEW
=EscDirToAngle(SDRESC_BOTTOM
);
234 nEscDir1
|=EscAngleToDir(nEW
);
237 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
240 void SdrGluePoint::Shear(const Point
& rRef
, long /*nWink*/, double tn
, bool bVShear
, const SdrObject
* pObj
)
242 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
243 ShearPoint(aPt
,rRef
,tn
,bVShear
);
244 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
247 void SdrGluePoint::Invalidate(Window
& rWin
, const SdrObject
* pObj
) const
249 bool bMapMerk
=rWin
.IsMapModeEnabled();
250 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
251 aPt
=rWin
.LogicToPixel(aPt
);
252 rWin
.EnableMapMode(sal_False
);
254 Size
aSiz( aGlueHalfSize
);
255 Rectangle
aRect(aPt
.X()-aSiz
.Width(),aPt
.Y()-aSiz
.Height(),
256 aPt
.X()+aSiz
.Width(),aPt
.Y()+aSiz
.Height());
258 // do not erase background, that causes flicker (!)
259 rWin
.Invalidate(aRect
, INVALIDATE_NOERASE
);
261 rWin
.EnableMapMode(bMapMerk
);
264 bool SdrGluePoint::IsHit(const Point
& rPnt
, const OutputDevice
& rOut
, const SdrObject
* pObj
) const
266 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
267 Size aSiz
=rOut
.PixelToLogic(aGlueHalfSize
);
268 Rectangle
aRect(aPt
.X()-aSiz
.Width(),aPt
.Y()-aSiz
.Height(),aPt
.X()+aSiz
.Width(),aPt
.Y()+aSiz
.Height());
269 return aRect
.IsInside(rPnt
);
272 ////////////////////////////////////////////////////////////////////////////////////////////////////
274 void SdrGluePointList::Clear()
276 sal_uInt16 nAnz
=GetCount();
277 for (sal_uInt16 i
=0; i
<nAnz
; i
++) {
283 void SdrGluePointList::operator=(const SdrGluePointList
& rSrcList
)
285 if (GetCount()!=0) Clear();
286 sal_uInt16 nAnz
=rSrcList
.GetCount();
287 for (sal_uInt16 i
=0; i
<nAnz
; i
++) {
292 // The ID's of the glue points always increase monotonously!
293 // If an ID is taken already, the new glue point gets a new ID. ID 0 is reserved.
294 sal_uInt16
SdrGluePointList::Insert(const SdrGluePoint
& rGP
)
296 SdrGluePoint
* pGP
=new SdrGluePoint(rGP
);
297 sal_uInt16 nId
=pGP
->GetId();
298 sal_uInt16 nAnz
=GetCount();
299 sal_uInt16 nInsPos
=nAnz
;
300 sal_uInt16 nLastId
=nAnz
!=0 ? GetObject(nAnz
-1)->GetId() : 0;
301 DBG_ASSERT(nLastId
>=nAnz
,"SdrGluePointList::Insert(): nLastId<nAnz");
302 bool bHole
= nLastId
>nAnz
;
304 if (!bHole
|| nId
==0) {
308 for (sal_uInt16 nNum
=0; nNum
<nAnz
&& !bBrk
; nNum
++) {
309 const SdrGluePoint
* pGP2
=GetObject(nNum
);
310 sal_uInt16 nTmpId
=pGP2
->GetId();
312 nId
=nLastId
+1; // already in use
316 nInsPos
=nNum
; // insert here (sort)
323 aList
.Insert(pGP
,nInsPos
);
327 void SdrGluePointList::Invalidate(Window
& rWin
, const SdrObject
* pObj
) const
329 sal_uInt16 nAnz
=GetCount();
330 for (sal_uInt16 nNum
=0; nNum
<nAnz
; nNum
++) {
331 GetObject(nNum
)->Invalidate(rWin
,pObj
);
335 sal_uInt16
SdrGluePointList::FindGluePoint(sal_uInt16 nId
) const
337 // TODO: Implement a better search algorithm
338 // List should be sorted at all times!
339 sal_uInt16 nAnz
=GetCount();
340 sal_uInt16 nRet
=SDRGLUEPOINT_NOTFOUND
;
341 for (sal_uInt16 nNum
=0; nNum
<nAnz
&& nRet
==SDRGLUEPOINT_NOTFOUND
; nNum
++) {
342 const SdrGluePoint
* pGP
=GetObject(nNum
);
343 if (pGP
->GetId()==nId
) nRet
=nNum
;
348 sal_uInt16
SdrGluePointList::HitTest(const Point
& rPnt
, const OutputDevice
& rOut
, const SdrObject
* pObj
, bool bBack
, bool bNext
, sal_uInt16 nId0
) const
350 sal_uInt16 nAnz
=GetCount();
351 sal_uInt16 nRet
=SDRGLUEPOINT_NOTFOUND
;
352 sal_uInt16 nNum
=bBack
? 0 : nAnz
;
353 while ((bBack
? nNum
<nAnz
: nNum
>0) && nRet
==SDRGLUEPOINT_NOTFOUND
) {
355 const SdrGluePoint
* pGP
=GetObject(nNum
);
357 if (pGP
->GetId()==nId0
) bNext
=sal_False
;
359 if (pGP
->IsHit(rPnt
,rOut
,pObj
)) nRet
=nNum
;
366 void SdrGluePointList::SetReallyAbsolute(bool bOn
, const SdrObject
& rObj
)
368 sal_uInt16 nAnz
=GetCount();
369 for (sal_uInt16 nNum
=0; nNum
<nAnz
; nNum
++) {
370 GetObject(nNum
)->SetReallyAbsolute(bOn
,rObj
);
374 void SdrGluePointList::Rotate(const Point
& rRef
, long nWink
, double sn
, double cs
, const SdrObject
* pObj
)
376 sal_uInt16 nAnz
=GetCount();
377 for (sal_uInt16 nNum
=0; nNum
<nAnz
; nNum
++) {
378 GetObject(nNum
)->Rotate(rRef
,nWink
,sn
,cs
,pObj
);
382 void SdrGluePointList::Mirror(const Point
& rRef1
, const Point
& rRef2
, const SdrObject
* pObj
)
384 Point
aPt(rRef2
); aPt
-=rRef1
;
385 long nWink
=GetAngle(aPt
);
386 Mirror(rRef1
,rRef2
,nWink
,pObj
);
389 void SdrGluePointList::Mirror(const Point
& rRef1
, const Point
& rRef2
, long nWink
, const SdrObject
* pObj
)
391 sal_uInt16 nAnz
=GetCount();
392 for (sal_uInt16 nNum
=0; nNum
<nAnz
; nNum
++) {
393 GetObject(nNum
)->Mirror(rRef1
,rRef2
,nWink
,pObj
);
397 void SdrGluePointList::Shear(const Point
& rRef
, long nWink
, double tn
, bool bVShear
, const SdrObject
* pObj
)
399 sal_uInt16 nAnz
=GetCount();
400 for (sal_uInt16 nNum
=0; nNum
<nAnz
; nNum
++) {
401 GetObject(nNum
)->Shear(rRef
,nWink
,tn
,bVShear
,pObj
);
407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */