1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: svdglue.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <tools/debug.hxx>
35 #include <svx/svdglue.hxx>
36 #include <svx/svdobj.hxx>
37 #include <svx/svdtrans.hxx>
39 ////////////////////////////////////////////////////////////////////////////////////////////////////
41 void SdrGluePoint::SetReallyAbsolute(FASTBOOL bOn
, const SdrObject
& rObj
)
43 if ( bReallyAbsolute
!= bOn
)
47 aPos
=GetAbsolutePos(rObj
);
54 SetAbsolutePos(aPt
,rObj
);
59 Point
SdrGluePoint::GetAbsolutePos(const SdrObject
& rObj
) const
61 if (bReallyAbsolute
) return aPos
;
62 Rectangle
aSnap(rObj
.GetSnapRect());
63 Rectangle
aBound(rObj
.GetSnapRect());
66 Point
aOfs(aSnap
.Center());
67 switch (GetHorzAlign()) {
68 case SDRHORZALIGN_LEFT
: aOfs
.X()=aSnap
.Left(); break;
69 case SDRHORZALIGN_RIGHT
: aOfs
.X()=aSnap
.Right(); break;
71 switch (GetVertAlign()) {
72 case SDRVERTALIGN_TOP
: aOfs
.Y()=aSnap
.Top(); break;
73 case SDRVERTALIGN_BOTTOM
: aOfs
.Y()=aSnap
.Bottom(); break;
76 long nXMul
=aSnap
.Right()-aSnap
.Left();
77 long nYMul
=aSnap
.Bottom()-aSnap
.Top();
90 // Und nun auf's BoundRect des Objekts begrenzen
91 if (aPt
.X()<aBound
.Left ()) aPt
.X()=aBound
.Left ();
92 if (aPt
.X()>aBound
.Right ()) aPt
.X()=aBound
.Right ();
93 if (aPt
.Y()<aBound
.Top ()) aPt
.Y()=aBound
.Top ();
94 if (aPt
.Y()>aBound
.Bottom()) aPt
.Y()=aBound
.Bottom();
98 void SdrGluePoint::SetAbsolutePos(const Point
& rNewPos
, const SdrObject
& rObj
)
100 if (bReallyAbsolute
) {
104 Rectangle
aSnap(rObj
.GetSnapRect());
107 Point
aOfs(aSnap
.Center());
108 switch (GetHorzAlign()) {
109 case SDRHORZALIGN_LEFT
: aOfs
.X()=aSnap
.Left(); break;
110 case SDRHORZALIGN_RIGHT
: aOfs
.X()=aSnap
.Right(); break;
112 switch (GetVertAlign()) {
113 case SDRVERTALIGN_TOP
: aOfs
.Y()=aSnap
.Top(); break;
114 case SDRVERTALIGN_BOTTOM
: aOfs
.Y()=aSnap
.Bottom(); break;
118 long nXMul
=aSnap
.Right()-aSnap
.Left();
119 long nYMul
=aSnap
.Bottom()-aSnap
.Top();
120 if (nXMul
==0) nXMul
=1;
121 if (nYMul
==0) nYMul
=1;
136 long SdrGluePoint::GetAlignAngle() const
139 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
: return 0; // Invalid!
140 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_CENTER
: return 0;
141 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_TOP
: return 4500;
142 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_TOP
: return 9000;
143 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_TOP
: return 13500;
144 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_CENTER
: return 18000;
145 case SDRHORZALIGN_LEFT
|SDRVERTALIGN_BOTTOM
: return 22500;
146 case SDRHORZALIGN_CENTER
|SDRVERTALIGN_BOTTOM
: return 27000;
147 case SDRHORZALIGN_RIGHT
|SDRVERTALIGN_BOTTOM
: return 31500;
152 void SdrGluePoint::SetAlignAngle(long nWink
)
154 nWink
=NormAngle360(nWink
);
155 if (nWink
>=33750 || nWink
<2250) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_CENTER
;
156 else if (nWink
< 6750) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_TOP
;
157 else if (nWink
<11250) nAlign
=SDRHORZALIGN_CENTER
|SDRVERTALIGN_TOP
;
158 else if (nWink
<15750) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_TOP
;
159 else if (nWink
<20250) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_CENTER
;
160 else if (nWink
<24750) nAlign
=SDRHORZALIGN_LEFT
|SDRVERTALIGN_BOTTOM
;
161 else if (nWink
<29250) nAlign
=SDRHORZALIGN_CENTER
|SDRVERTALIGN_BOTTOM
;
162 else if (nWink
<33750) nAlign
=SDRHORZALIGN_RIGHT
|SDRVERTALIGN_BOTTOM
;
165 long SdrGluePoint::EscDirToAngle(USHORT nEsc
) const
168 case SDRESC_RIGHT
: return 0;
169 case SDRESC_TOP
: return 9000;
170 case SDRESC_LEFT
: return 18000;
171 case SDRESC_BOTTOM
: return 27000;
176 USHORT
SdrGluePoint::EscAngleToDir(long nWink
) const
178 nWink
=NormAngle360(nWink
);
179 if (nWink
>=31500 || nWink
<4500) return SDRESC_RIGHT
;
180 if (nWink
<13500) return SDRESC_TOP
;
181 if (nWink
<22500) return SDRESC_LEFT
;
182 if (nWink
<31500) return SDRESC_BOTTOM
;
186 void SdrGluePoint::Rotate(const Point
& rRef
, long nWink
, double sn
, double cs
, const SdrObject
* pObj
)
188 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
189 RotatePoint(aPt
,rRef
,sn
,cs
);
190 // Bezugskante drehen
191 if(nAlign
!= (SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
))
193 SetAlignAngle(GetAlignAngle()+nWink
);
195 // Austrittsrichtungen drehen
196 USHORT nEscDir0
=nEscDir
;
198 if ((nEscDir0
&SDRESC_LEFT
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_LEFT
)+nWink
);
199 if ((nEscDir0
&SDRESC_TOP
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_TOP
)+nWink
);
200 if ((nEscDir0
&SDRESC_RIGHT
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_RIGHT
)+nWink
);
201 if ((nEscDir0
&SDRESC_BOTTOM
)!=0) nEscDir1
|=EscAngleToDir(EscDirToAngle(SDRESC_BOTTOM
)+nWink
);
203 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
206 void SdrGluePoint::Mirror(const Point
& rRef1
, const Point
& rRef2
, const SdrObject
* pObj
)
208 Point
aPt(rRef2
); aPt
-=rRef1
;
209 long nWink
=GetAngle(aPt
);
210 Mirror(rRef1
,rRef2
,nWink
,pObj
);
213 void SdrGluePoint::Mirror(const Point
& rRef1
, const Point
& rRef2
, long nWink
, const SdrObject
* pObj
)
215 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
216 MirrorPoint(aPt
,rRef1
,rRef2
);
217 // Bezugskante spiegeln
218 if(nAlign
!= (SDRHORZALIGN_CENTER
|SDRVERTALIGN_CENTER
))
220 long nAW
=GetAlignAngle();
224 // Austrittsrichtungen spiegeln
225 USHORT nEscDir0
=nEscDir
;
227 if ((nEscDir0
&SDRESC_LEFT
)!=0) {
228 long nEW
=EscDirToAngle(SDRESC_LEFT
);
230 nEscDir1
|=EscAngleToDir(nEW
);
232 if ((nEscDir0
&SDRESC_TOP
)!=0) {
233 long nEW
=EscDirToAngle(SDRESC_TOP
);
235 nEscDir1
|=EscAngleToDir(nEW
);
237 if ((nEscDir0
&SDRESC_RIGHT
)!=0) {
238 long nEW
=EscDirToAngle(SDRESC_RIGHT
);
240 nEscDir1
|=EscAngleToDir(nEW
);
242 if ((nEscDir0
&SDRESC_BOTTOM
)!=0) {
243 long nEW
=EscDirToAngle(SDRESC_BOTTOM
);
245 nEscDir1
|=EscAngleToDir(nEW
);
248 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
251 void SdrGluePoint::Shear(const Point
& rRef
, long /*nWink*/, double tn
, FASTBOOL bVShear
, const SdrObject
* pObj
)
253 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
254 ShearPoint(aPt
,rRef
,tn
,bVShear
);
255 if (pObj
!=NULL
) SetAbsolutePos(aPt
,*pObj
); else SetPos(aPt
);
258 void SdrGluePoint::Draw(OutputDevice
& rOut
, const SdrObject
* pObj
) const
260 Color
aBackPenColor(COL_WHITE
);
261 Color
aForePenColor(COL_LIGHTBLUE
);
263 bool bMapMerk
=rOut
.IsMapModeEnabled();
264 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
265 aPt
=rOut
.LogicToPixel(aPt
);
266 rOut
.EnableMapMode(FALSE
);
267 long x
=aPt
.X(),y
=aPt
.Y(); // Groesse erstmal fest auf 7 Pixel
269 rOut
.SetLineColor( aBackPenColor
);
270 rOut
.DrawLine(Point(x
-2,y
-3),Point(x
+3,y
+2));
271 rOut
.DrawLine(Point(x
-3,y
-2),Point(x
+2,y
+3));
272 rOut
.DrawLine(Point(x
-3,y
+2),Point(x
+2,y
-3));
273 rOut
.DrawLine(Point(x
-2,y
+3),Point(x
+3,y
-2));
277 switch (GetHorzAlign())
279 case SDRHORZALIGN_LEFT
: rOut
.DrawLine(Point(x
-3,y
-1),Point(x
-3,y
+1)); break;
280 case SDRHORZALIGN_RIGHT
: rOut
.DrawLine(Point(x
+3,y
-1),Point(x
+3,y
+1)); break;
283 switch (GetVertAlign())
285 case SDRVERTALIGN_TOP
: rOut
.DrawLine(Point(x
-1,y
-3),Point(x
+1,y
-3)); break;
286 case SDRVERTALIGN_BOTTOM
: rOut
.DrawLine(Point(x
-1,y
+3),Point(x
+1,y
+3)); break;
290 rOut
.SetLineColor( aForePenColor
);
291 rOut
.DrawLine(Point(x
-2,y
-2),Point(x
+2,y
+2));
292 rOut
.DrawLine(Point(x
-2,y
+2),Point(x
+2,y
-2));
293 rOut
.EnableMapMode(bMapMerk
);
296 void SdrGluePoint::Invalidate(Window
& rWin
, const SdrObject
* pObj
) const
298 bool bMapMerk
=rWin
.IsMapModeEnabled();
299 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
300 aPt
=rWin
.LogicToPixel(aPt
);
301 rWin
.EnableMapMode(FALSE
);
302 long x
=aPt
.X(),y
=aPt
.Y(); // Groesse erstmal fest auf 7 Pixel
305 // do not erase background, that causes flicker (!)
306 rWin
.Invalidate(Rectangle(Point(x
-3,y
-3),Point(x
+3,y
+3)), INVALIDATE_NOERASE
);
308 rWin
.EnableMapMode(bMapMerk
);
311 FASTBOOL
SdrGluePoint::IsHit(const Point
& rPnt
, const OutputDevice
& rOut
, const SdrObject
* pObj
) const
313 Point
aPt(pObj
!=NULL
? GetAbsolutePos(*pObj
) : GetPos());
314 Size aSiz
=rOut
.PixelToLogic(Size(3,3));
315 Rectangle
aRect(aPt
.X()-aSiz
.Width(),aPt
.Y()-aSiz
.Height(),aPt
.X()+aSiz
.Width(),aPt
.Y()+aSiz
.Height());
316 return aRect
.IsInside(rPnt
);
319 ////////////////////////////////////////////////////////////////////////////////////////////////////
321 void SdrGluePointList::Clear()
323 USHORT nAnz
=GetCount();
324 for (USHORT i
=0; i
<nAnz
; i
++) {
330 void SdrGluePointList::operator=(const SdrGluePointList
& rSrcList
)
332 if (GetCount()!=0) Clear();
333 USHORT nAnz
=rSrcList
.GetCount();
334 for (USHORT i
=0; i
<nAnz
; i
++) {
339 // Die Id's der Klebepunkte in der Liste sind stets streng monoton steigend!
340 // Ggf. wird dem neuen Klebepunkt eine neue Id zugewiesen (wenn diese bereits
341 // vergeben ist). Die Id 0 ist reserviert.
342 USHORT
SdrGluePointList::Insert(const SdrGluePoint
& rGP
)
344 SdrGluePoint
* pGP
=new SdrGluePoint(rGP
);
345 USHORT nId
=pGP
->GetId();
346 USHORT nAnz
=GetCount();
348 USHORT nLastId
=nAnz
!=0 ? GetObject(nAnz
-1)->GetId() : 0;
349 DBG_ASSERT(nLastId
>=nAnz
,"SdrGluePointList::Insert(): nLastId<nAnz");
350 FASTBOOL bHole
=nLastId
>nAnz
;
352 if (!bHole
|| nId
==0) {
356 for (USHORT nNum
=0; nNum
<nAnz
&& !bBrk
; nNum
++) {
357 const SdrGluePoint
* pGP2
=GetObject(nNum
);
358 USHORT nTmpId
=pGP2
->GetId();
360 nId
=nLastId
+1; // bereits vorhanden
364 nInsPos
=nNum
; // Hier einfuegen (einsortieren)
371 aList
.Insert(pGP
,nInsPos
);
375 void SdrGluePointList::Invalidate(Window
& rWin
, const SdrObject
* pObj
) const
377 USHORT nAnz
=GetCount();
378 for (USHORT nNum
=0; nNum
<nAnz
; nNum
++) {
379 GetObject(nNum
)->Invalidate(rWin
,pObj
);
383 USHORT
SdrGluePointList::FindGluePoint(USHORT nId
) const
385 // Hier noch einen optimaleren Suchalgorithmus implementieren.
386 // Die Liste sollte stets sortiert sein!!!!
387 USHORT nAnz
=GetCount();
388 USHORT nRet
=SDRGLUEPOINT_NOTFOUND
;
389 for (USHORT nNum
=0; nNum
<nAnz
&& nRet
==SDRGLUEPOINT_NOTFOUND
; nNum
++) {
390 const SdrGluePoint
* pGP
=GetObject(nNum
);
391 if (pGP
->GetId()==nId
) nRet
=nNum
;
396 USHORT
SdrGluePointList::HitTest(const Point
& rPnt
, const OutputDevice
& rOut
, const SdrObject
* pObj
, FASTBOOL bBack
, FASTBOOL bNext
, USHORT nId0
) const
398 USHORT nAnz
=GetCount();
399 USHORT nRet
=SDRGLUEPOINT_NOTFOUND
;
400 USHORT nNum
=bBack
? 0 : nAnz
;
401 while ((bBack
? nNum
<nAnz
: nNum
>0) && nRet
==SDRGLUEPOINT_NOTFOUND
) {
403 const SdrGluePoint
* pGP
=GetObject(nNum
);
405 if (pGP
->GetId()==nId0
) bNext
=FALSE
;
407 if (pGP
->IsHit(rPnt
,rOut
,pObj
)) nRet
=nNum
;
414 void SdrGluePointList::SetReallyAbsolute(FASTBOOL bOn
, const SdrObject
& rObj
)
416 USHORT nAnz
=GetCount();
417 for (USHORT nNum
=0; nNum
<nAnz
; nNum
++) {
418 GetObject(nNum
)->SetReallyAbsolute(bOn
,rObj
);
422 void SdrGluePointList::Rotate(const Point
& rRef
, long nWink
, double sn
, double cs
, const SdrObject
* pObj
)
424 USHORT nAnz
=GetCount();
425 for (USHORT nNum
=0; nNum
<nAnz
; nNum
++) {
426 GetObject(nNum
)->Rotate(rRef
,nWink
,sn
,cs
,pObj
);
430 void SdrGluePointList::Mirror(const Point
& rRef1
, const Point
& rRef2
, const SdrObject
* pObj
)
432 Point
aPt(rRef2
); aPt
-=rRef1
;
433 long nWink
=GetAngle(aPt
);
434 Mirror(rRef1
,rRef2
,nWink
,pObj
);
437 void SdrGluePointList::Mirror(const Point
& rRef1
, const Point
& rRef2
, long nWink
, const SdrObject
* pObj
)
439 USHORT nAnz
=GetCount();
440 for (USHORT nNum
=0; nNum
<nAnz
; nNum
++) {
441 GetObject(nNum
)->Mirror(rRef1
,rRef2
,nWink
,pObj
);
445 void SdrGluePointList::Shear(const Point
& rRef
, long nWink
, double tn
, FASTBOOL bVShear
, const SdrObject
* pObj
)
447 USHORT nAnz
=GetCount();
448 for (USHORT nNum
=0; nNum
<nAnz
; nNum
++) {
449 GetObject(nNum
)->Shear(rRef
,nWink
,tn
,bVShear
,pObj
);