Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / svx / source / svdraw / svdglue.cxx
blob41b37ae0e885f02640eaf6c10bf0e25ced90e4b4
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 <tools/debug.hxx>
22 #include <svx/svdglue.hxx>
23 #include <svx/svdobj.hxx>
24 #include <svx/svdtrans.hxx>
26 static const Size aGlueHalfSize(4,4);
28 void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
30 if ( bReallyAbsolute != bOn )
32 if ( bOn )
34 aPos=GetAbsolutePos(rObj);
35 bReallyAbsolute=bOn;
37 else
39 bReallyAbsolute=bOn;
40 Point aPt(aPos);
41 SetAbsolutePos(aPt,rObj);
46 Point SdrGluePoint::GetAbsolutePos(const SdrObject& rObj) const
48 if (bReallyAbsolute) return aPos;
49 Rectangle aSnap(rObj.GetSnapRect());
50 Rectangle aBound(rObj.GetSnapRect());
51 Point aPt(aPos);
53 Point aOfs(aSnap.Center());
54 switch (GetHorzAlign()) {
55 case SDRHORZALIGN_LEFT : aOfs.X()=aSnap.Left(); break;
56 case SDRHORZALIGN_RIGHT : aOfs.X()=aSnap.Right(); break;
58 switch (GetVertAlign()) {
59 case SDRVERTALIGN_TOP : aOfs.Y()=aSnap.Top(); break;
60 case SDRVERTALIGN_BOTTOM: aOfs.Y()=aSnap.Bottom(); break;
62 if (!bNoPercent) {
63 long nXMul=aSnap.Right()-aSnap.Left();
64 long nYMul=aSnap.Bottom()-aSnap.Top();
65 long nXDiv=10000;
66 long nYDiv=10000;
67 if (nXMul!=nXDiv) {
68 aPt.X()*=nXMul;
69 aPt.X()/=nXDiv;
71 if (nYMul!=nYDiv) {
72 aPt.Y()*=nYMul;
73 aPt.Y()/=nYDiv;
76 aPt+=aOfs;
77 // Now limit to the BoundRect of the object
78 if (aPt.X()<aBound.Left ()) aPt.X()=aBound.Left ();
79 if (aPt.X()>aBound.Right ()) aPt.X()=aBound.Right ();
80 if (aPt.Y()<aBound.Top ()) aPt.Y()=aBound.Top ();
81 if (aPt.Y()>aBound.Bottom()) aPt.Y()=aBound.Bottom();
82 return aPt;
85 void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
87 if (bReallyAbsolute) {
88 aPos=rNewPos;
89 return;
91 Rectangle aSnap(rObj.GetSnapRect());
92 Point aPt(rNewPos);
94 Point aOfs(aSnap.Center());
95 switch (GetHorzAlign()) {
96 case SDRHORZALIGN_LEFT : aOfs.X()=aSnap.Left(); break;
97 case SDRHORZALIGN_RIGHT : aOfs.X()=aSnap.Right(); break;
99 switch (GetVertAlign()) {
100 case SDRVERTALIGN_TOP : aOfs.Y()=aSnap.Top(); break;
101 case SDRVERTALIGN_BOTTOM: aOfs.Y()=aSnap.Bottom(); break;
103 aPt-=aOfs;
104 if (!bNoPercent) {
105 long nXMul=aSnap.Right()-aSnap.Left();
106 long nYMul=aSnap.Bottom()-aSnap.Top();
107 if (nXMul==0) nXMul=1;
108 if (nYMul==0) nYMul=1;
109 long nXDiv=10000;
110 long nYDiv=10000;
111 if (nXMul!=nXDiv) {
112 aPt.X()*=nXDiv;
113 aPt.X()/=nXMul;
115 if (nYMul!=nYDiv) {
116 aPt.Y()*=nYDiv;
117 aPt.Y()/=nYMul;
120 aPos=aPt;
123 long SdrGluePoint::GetAlignAngle() const
125 switch (nAlign) {
126 case SDRHORZALIGN_CENTER|SDRVERTALIGN_CENTER: return 0; // Invalid!
127 case SDRHORZALIGN_RIGHT |SDRVERTALIGN_CENTER: return 0;
128 case SDRHORZALIGN_RIGHT |SDRVERTALIGN_TOP : return 4500;
129 case SDRHORZALIGN_CENTER|SDRVERTALIGN_TOP : return 9000;
130 case SDRHORZALIGN_LEFT |SDRVERTALIGN_TOP : return 13500;
131 case SDRHORZALIGN_LEFT |SDRVERTALIGN_CENTER: return 18000;
132 case SDRHORZALIGN_LEFT |SDRVERTALIGN_BOTTOM: return 22500;
133 case SDRHORZALIGN_CENTER|SDRVERTALIGN_BOTTOM: return 27000;
134 case SDRHORZALIGN_RIGHT |SDRVERTALIGN_BOTTOM: return 31500;
135 } // switch
136 return 0;
139 void SdrGluePoint::SetAlignAngle(long nWink)
141 nWink=NormAngle360(nWink);
142 if (nWink>=33750 || nWink<2250) nAlign=SDRHORZALIGN_RIGHT |SDRVERTALIGN_CENTER;
143 else if (nWink< 6750) nAlign=SDRHORZALIGN_RIGHT |SDRVERTALIGN_TOP ;
144 else if (nWink<11250) nAlign=SDRHORZALIGN_CENTER|SDRVERTALIGN_TOP ;
145 else if (nWink<15750) nAlign=SDRHORZALIGN_LEFT |SDRVERTALIGN_TOP ;
146 else if (nWink<20250) nAlign=SDRHORZALIGN_LEFT |SDRVERTALIGN_CENTER;
147 else if (nWink<24750) nAlign=SDRHORZALIGN_LEFT |SDRVERTALIGN_BOTTOM;
148 else if (nWink<29250) nAlign=SDRHORZALIGN_CENTER|SDRVERTALIGN_BOTTOM;
149 else if (nWink<33750) nAlign=SDRHORZALIGN_RIGHT |SDRVERTALIGN_BOTTOM;
152 long SdrGluePoint::EscDirToAngle(sal_uInt16 nEsc) const
154 switch (nEsc) {
155 case SDRESC_RIGHT : return 0;
156 case SDRESC_TOP : return 9000;
157 case SDRESC_LEFT : return 18000;
158 case SDRESC_BOTTOM: return 27000;
159 } // switch
160 return 0;
163 sal_uInt16 SdrGluePoint::EscAngleToDir(long nWink) const
165 nWink=NormAngle360(nWink);
166 if (nWink>=31500 || nWink<4500) return SDRESC_RIGHT;
167 if (nWink<13500) return SDRESC_TOP;
168 if (nWink<22500) return SDRESC_LEFT;
169 if (nWink<31500) return SDRESC_BOTTOM;
170 return 0;
173 void SdrGluePoint::Rotate(const Point& rRef, long nWink, double sn, double cs, const SdrObject* pObj)
175 Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
176 RotatePoint(aPt,rRef,sn,cs);
177 // rotate reference edge
178 if(nAlign != (SDRHORZALIGN_CENTER|SDRVERTALIGN_CENTER))
180 SetAlignAngle(GetAlignAngle()+nWink);
182 // rotate exit directions
183 sal_uInt16 nEscDir0=nEscDir;
184 sal_uInt16 nEscDir1=0;
185 if ((nEscDir0&SDRESC_LEFT )!=0) nEscDir1|=EscAngleToDir(EscDirToAngle(SDRESC_LEFT )+nWink);
186 if ((nEscDir0&SDRESC_TOP )!=0) nEscDir1|=EscAngleToDir(EscDirToAngle(SDRESC_TOP )+nWink);
187 if ((nEscDir0&SDRESC_RIGHT )!=0) nEscDir1|=EscAngleToDir(EscDirToAngle(SDRESC_RIGHT )+nWink);
188 if ((nEscDir0&SDRESC_BOTTOM)!=0) nEscDir1|=EscAngleToDir(EscDirToAngle(SDRESC_BOTTOM)+nWink);
189 nEscDir=nEscDir1;
190 if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
193 void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, long nWink, const SdrObject* pObj)
195 Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
196 MirrorPoint(aPt,rRef1,rRef2);
197 // mirror reference edge
198 if(nAlign != (SDRHORZALIGN_CENTER|SDRVERTALIGN_CENTER))
200 long nAW=GetAlignAngle();
201 nAW+=2*(nWink-nAW);
202 SetAlignAngle(nAW);
204 // mirror exit directions
205 sal_uInt16 nEscDir0=nEscDir;
206 sal_uInt16 nEscDir1=0;
207 if ((nEscDir0&SDRESC_LEFT)!=0) {
208 long nEW=EscDirToAngle(SDRESC_LEFT);
209 nEW+=2*(nWink-nEW);
210 nEscDir1|=EscAngleToDir(nEW);
212 if ((nEscDir0&SDRESC_TOP)!=0) {
213 long nEW=EscDirToAngle(SDRESC_TOP);
214 nEW+=2*(nWink-nEW);
215 nEscDir1|=EscAngleToDir(nEW);
217 if ((nEscDir0&SDRESC_RIGHT)!=0) {
218 long nEW=EscDirToAngle(SDRESC_RIGHT);
219 nEW+=2*(nWink-nEW);
220 nEscDir1|=EscAngleToDir(nEW);
222 if ((nEscDir0&SDRESC_BOTTOM)!=0) {
223 long nEW=EscDirToAngle(SDRESC_BOTTOM);
224 nEW+=2*(nWink-nEW);
225 nEscDir1|=EscAngleToDir(nEW);
227 nEscDir=nEscDir1;
228 if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
231 void SdrGluePoint::Shear(const Point& rRef, long /*nWink*/, double tn, bool bVShear, const SdrObject* pObj)
233 Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
234 ShearPoint(aPt,rRef,tn,bVShear);
235 if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
238 void SdrGluePoint::Invalidate(Window& rWin, const SdrObject* pObj) const
240 bool bMapMerk=rWin.IsMapModeEnabled();
241 Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
242 aPt=rWin.LogicToPixel(aPt);
243 rWin.EnableMapMode(false);
245 Size aSiz( aGlueHalfSize );
246 Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),
247 aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
249 // do not erase background, that causes flicker (!)
250 rWin.Invalidate(aRect, INVALIDATE_NOERASE);
252 rWin.EnableMapMode(bMapMerk);
255 bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
257 Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
258 Size aSiz=rOut.PixelToLogic(aGlueHalfSize);
259 Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
260 return aRect.IsInside(rPnt);
265 void SdrGluePointList::Clear()
267 sal_uInt16 nAnz=GetCount();
268 for (sal_uInt16 i=0; i<nAnz; i++) {
269 delete GetObject(i);
271 aList.clear();
274 void SdrGluePointList::operator=(const SdrGluePointList& rSrcList)
276 if (GetCount()!=0) Clear();
277 sal_uInt16 nAnz=rSrcList.GetCount();
278 for (sal_uInt16 i=0; i<nAnz; i++) {
279 Insert(rSrcList[i]);
283 // The ID's of the glue points always increase monotonously!
284 // If an ID is taken already, the new glue point gets a new ID. ID 0 is reserved.
285 sal_uInt16 SdrGluePointList::Insert(const SdrGluePoint& rGP)
287 SdrGluePoint* pGP=new SdrGluePoint(rGP);
288 sal_uInt16 nId=pGP->GetId();
289 sal_uInt16 nAnz=GetCount();
290 sal_uInt16 nInsPos=nAnz;
291 sal_uInt16 nLastId=nAnz!=0 ? GetObject(nAnz-1)->GetId() : 0;
292 DBG_ASSERT(nLastId>=nAnz,"SdrGluePointList::Insert(): nLastId<nAnz");
293 bool bHole = nLastId>nAnz;
294 if (nId<=nLastId) {
295 if (!bHole || nId==0) {
296 nId=nLastId+1;
297 } else {
298 bool bBrk = false;
299 for (sal_uInt16 nNum=0; nNum<nAnz && !bBrk; nNum++) {
300 const SdrGluePoint* pGP2=GetObject(nNum);
301 sal_uInt16 nTmpId=pGP2->GetId();
302 if (nTmpId==nId) {
303 nId=nLastId+1; // already in use
304 bBrk = true;
306 if (nTmpId>nId) {
307 nInsPos=nNum; // insert here (sort)
308 bBrk = true;
312 pGP->SetId(nId);
314 aList.insert(aList.begin()+nInsPos, pGP);
315 return nInsPos;
318 void SdrGluePointList::Invalidate(Window& rWin, const SdrObject* pObj) const
320 sal_uInt16 nAnz=GetCount();
321 for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
322 GetObject(nNum)->Invalidate(rWin,pObj);
326 sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
328 // TODO: Implement a better search algorithm
329 // List should be sorted at all times!
330 sal_uInt16 nAnz=GetCount();
331 sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
332 for (sal_uInt16 nNum=0; nNum<nAnz && nRet==SDRGLUEPOINT_NOTFOUND; nNum++) {
333 const SdrGluePoint* pGP=GetObject(nNum);
334 if (pGP->GetId()==nId) nRet=nNum;
336 return nRet;
339 sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj, bool bBack, bool bNext, sal_uInt16 nId0) const
341 sal_uInt16 nAnz=GetCount();
342 sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
343 sal_uInt16 nNum=bBack ? 0 : nAnz;
344 while ((bBack ? nNum<nAnz : nNum>0) && nRet==SDRGLUEPOINT_NOTFOUND) {
345 if (!bBack) nNum--;
346 const SdrGluePoint* pGP=GetObject(nNum);
347 if (bNext) {
348 if (pGP->GetId()==nId0) bNext=false;
349 } else {
350 if (pGP->IsHit(rPnt,rOut,pObj)) nRet=nNum;
352 if (bBack) nNum++;
354 return nRet;
357 void SdrGluePointList::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
359 sal_uInt16 nAnz=GetCount();
360 for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
361 GetObject(nNum)->SetReallyAbsolute(bOn,rObj);
365 void SdrGluePointList::Rotate(const Point& rRef, long nWink, double sn, double cs, const SdrObject* pObj)
367 sal_uInt16 nAnz=GetCount();
368 for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
369 GetObject(nNum)->Rotate(rRef,nWink,sn,cs,pObj);
373 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
375 Point aPt(rRef2); aPt-=rRef1;
376 long nWink=GetAngle(aPt);
377 Mirror(rRef1,rRef2,nWink,pObj);
380 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, long nWink, const SdrObject* pObj)
382 sal_uInt16 nAnz=GetCount();
383 for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
384 GetObject(nNum)->Mirror(rRef1,rRef2,nWink,pObj);
388 void SdrGluePointList::Shear(const Point& rRef, long nWink, double tn, bool bVShear, const SdrObject* pObj)
390 sal_uInt16 nAnz=GetCount();
391 for (sal_uInt16 nNum=0; nNum<nAnz; nNum++) {
392 GetObject(nNum)->Shear(rRef,nWink,tn,bVShear,pObj);
396 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */