Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <tools/debug.hxx>
21 :
22 : #include <svx/svdglue.hxx>
23 : #include <svx/svdobj.hxx>
24 : #include <svx/svdtrans.hxx>
25 :
26 145 : static const Size aGlueHalfSize(4,4);
27 :
28 204 : void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
29 : {
30 204 : if ( bReallyAbsolute != bOn )
31 : {
32 102 : if ( bOn )
33 : {
34 102 : aPos=GetAbsolutePos(rObj);
35 102 : bReallyAbsolute=bOn;
36 : }
37 : else
38 : {
39 0 : bReallyAbsolute=bOn;
40 0 : Point aPt(aPos);
41 0 : SetAbsolutePos(aPt,rObj);
42 : }
43 : }
44 204 : }
45 :
46 204 : Point SdrGluePoint::GetAbsolutePos(const SdrObject& rObj) const
47 : {
48 204 : if (bReallyAbsolute) return aPos;
49 204 : Rectangle aSnap(rObj.GetSnapRect());
50 204 : Rectangle aBound(rObj.GetSnapRect());
51 204 : Point aPt(aPos);
52 :
53 204 : Point aOfs(aSnap.Center());
54 204 : switch (GetHorzAlign()) {
55 204 : case SdrAlign::HORZ_LEFT : aOfs.X()=aSnap.Left(); break;
56 0 : case SdrAlign::HORZ_RIGHT : aOfs.X()=aSnap.Right(); break;
57 0 : default: break;
58 : }
59 204 : switch (GetVertAlign()) {
60 204 : case SdrAlign::VERT_TOP : aOfs.Y()=aSnap.Top(); break;
61 0 : case SdrAlign::VERT_BOTTOM: aOfs.Y()=aSnap.Bottom(); break;
62 0 : default: break;
63 : }
64 204 : if (!bNoPercent) {
65 0 : long nXMul=aSnap.Right()-aSnap.Left();
66 0 : long nYMul=aSnap.Bottom()-aSnap.Top();
67 0 : long nXDiv=10000;
68 0 : long nYDiv=10000;
69 0 : if (nXMul!=nXDiv) {
70 0 : aPt.X()*=nXMul;
71 0 : aPt.X()/=nXDiv;
72 : }
73 0 : if (nYMul!=nYDiv) {
74 0 : aPt.Y()*=nYMul;
75 0 : aPt.Y()/=nYDiv;
76 : }
77 : }
78 204 : aPt+=aOfs;
79 : // Now limit to the BoundRect of the object
80 204 : if (aPt.X()<aBound.Left ()) aPt.X()=aBound.Left ();
81 204 : if (aPt.X()>aBound.Right ()) aPt.X()=aBound.Right ();
82 204 : if (aPt.Y()<aBound.Top ()) aPt.Y()=aBound.Top ();
83 204 : if (aPt.Y()>aBound.Bottom()) aPt.Y()=aBound.Bottom();
84 204 : return aPt;
85 : }
86 :
87 102 : void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
88 : {
89 102 : if (bReallyAbsolute) {
90 0 : aPos=rNewPos;
91 102 : return;
92 : }
93 102 : Rectangle aSnap(rObj.GetSnapRect());
94 102 : Point aPt(rNewPos);
95 :
96 102 : Point aOfs(aSnap.Center());
97 102 : switch (GetHorzAlign()) {
98 81 : case SdrAlign::HORZ_LEFT : aOfs.X()=aSnap.Left(); break;
99 15 : case SdrAlign::HORZ_RIGHT : aOfs.X()=aSnap.Right(); break;
100 6 : default: break;
101 : }
102 102 : switch (GetVertAlign()) {
103 72 : case SdrAlign::VERT_TOP : aOfs.Y()=aSnap.Top(); break;
104 30 : case SdrAlign::VERT_BOTTOM: aOfs.Y()=aSnap.Bottom(); break;
105 0 : default: break;
106 : }
107 102 : aPt-=aOfs;
108 102 : if (!bNoPercent) {
109 0 : long nXMul=aSnap.Right()-aSnap.Left();
110 0 : long nYMul=aSnap.Bottom()-aSnap.Top();
111 0 : if (nXMul==0) nXMul=1;
112 0 : if (nYMul==0) nYMul=1;
113 0 : long nXDiv=10000;
114 0 : long nYDiv=10000;
115 0 : if (nXMul!=nXDiv) {
116 0 : aPt.X()*=nXDiv;
117 0 : aPt.X()/=nXMul;
118 : }
119 0 : if (nYMul!=nYDiv) {
120 0 : aPt.Y()*=nYDiv;
121 0 : aPt.Y()/=nYMul;
122 : }
123 : }
124 102 : aPos=aPt;
125 : }
126 :
127 102 : long SdrGluePoint::GetAlignAngle() const
128 : {
129 102 : if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
130 0 : return 0; // Invalid!
131 102 : else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER))
132 0 : return 0;
133 102 : else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP))
134 0 : return 4500;
135 102 : else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP))
136 0 : return 9000;
137 102 : else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP))
138 102 : return 13500;
139 0 : else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER))
140 0 : return 18000;
141 0 : else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM))
142 0 : return 22500;
143 0 : else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM))
144 0 : return 27000;
145 0 : else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM))
146 0 : return 31500;
147 0 : return 0;
148 : }
149 :
150 102 : void SdrGluePoint::SetAlignAngle(long nAngle)
151 : {
152 102 : nAngle=NormAngle360(nAngle);
153 102 : if (nAngle>=33750 || nAngle<2250) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER;
154 102 : else if (nAngle< 6750) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP ;
155 102 : else if (nAngle<11250) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP ;
156 96 : else if (nAngle<15750) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP ;
157 30 : else if (nAngle<20250) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER;
158 30 : else if (nAngle<24750) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM;
159 15 : else if (nAngle<29250) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM;
160 15 : else if (nAngle<33750) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM;
161 102 : }
162 :
163 0 : long SdrGluePoint::EscDirToAngle(SdrEscapeDirection nEsc)
164 : {
165 0 : switch (nEsc) {
166 0 : case SdrEscapeDirection::RIGHT : return 0;
167 0 : case SdrEscapeDirection::TOP : return 9000;
168 0 : case SdrEscapeDirection::LEFT : return 18000;
169 0 : case SdrEscapeDirection::BOTTOM: return 27000;
170 0 : default: break;
171 : } // switch
172 0 : return 0;
173 : }
174 :
175 0 : SdrEscapeDirection SdrGluePoint::EscAngleToDir(long nAngle)
176 : {
177 0 : nAngle=NormAngle360(nAngle);
178 0 : if (nAngle>=31500 || nAngle<4500)
179 0 : return SdrEscapeDirection::RIGHT;
180 0 : if (nAngle<13500)
181 0 : return SdrEscapeDirection::TOP;
182 0 : if (nAngle<22500)
183 0 : return SdrEscapeDirection::LEFT;
184 : /* (nAngle<31500)*/
185 0 : return SdrEscapeDirection::BOTTOM;
186 : }
187 :
188 87 : void SdrGluePoint::Rotate(const Point& rRef, long nAngle, double sn, double cs, const SdrObject* pObj)
189 : {
190 87 : Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
191 87 : RotatePoint(aPt,rRef,sn,cs);
192 : // rotate reference edge
193 87 : if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
194 : {
195 87 : SetAlignAngle(GetAlignAngle()+nAngle);
196 : }
197 : // rotate exit directions
198 87 : SdrEscapeDirection nEscDir0=nEscDir;
199 87 : SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
200 87 : if (nEscDir0&SdrEscapeDirection::LEFT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::LEFT )+nAngle);
201 87 : if (nEscDir0&SdrEscapeDirection::TOP ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::TOP )+nAngle);
202 87 : if (nEscDir0&SdrEscapeDirection::RIGHT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::RIGHT )+nAngle);
203 87 : if (nEscDir0&SdrEscapeDirection::BOTTOM) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::BOTTOM)+nAngle);
204 87 : nEscDir=nEscDir1;
205 87 : if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
206 87 : }
207 :
208 15 : void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, long nAngle, const SdrObject* pObj)
209 : {
210 15 : Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
211 15 : MirrorPoint(aPt,rRef1,rRef2);
212 : // mirror reference edge
213 15 : if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
214 : {
215 15 : long nAW=GetAlignAngle();
216 15 : nAW+=2*(nAngle-nAW);
217 15 : SetAlignAngle(nAW);
218 : }
219 : // mirror exit directions
220 15 : SdrEscapeDirection nEscDir0=nEscDir;
221 15 : SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
222 15 : if (nEscDir0&SdrEscapeDirection::LEFT) {
223 0 : long nEW=EscDirToAngle(SdrEscapeDirection::LEFT);
224 0 : nEW+=2*(nAngle-nEW);
225 0 : nEscDir1|=EscAngleToDir(nEW);
226 : }
227 15 : if (nEscDir0&SdrEscapeDirection::TOP) {
228 0 : long nEW=EscDirToAngle(SdrEscapeDirection::TOP);
229 0 : nEW+=2*(nAngle-nEW);
230 0 : nEscDir1|=EscAngleToDir(nEW);
231 : }
232 15 : if (nEscDir0&SdrEscapeDirection::RIGHT) {
233 0 : long nEW=EscDirToAngle(SdrEscapeDirection::RIGHT);
234 0 : nEW+=2*(nAngle-nEW);
235 0 : nEscDir1|=EscAngleToDir(nEW);
236 : }
237 15 : if (nEscDir0&SdrEscapeDirection::BOTTOM) {
238 0 : long nEW=EscDirToAngle(SdrEscapeDirection::BOTTOM);
239 0 : nEW+=2*(nAngle-nEW);
240 0 : nEscDir1|=EscAngleToDir(nEW);
241 : }
242 15 : nEscDir=nEscDir1;
243 15 : if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
244 15 : }
245 :
246 0 : void SdrGluePoint::Shear(const Point& rRef, long /*nAngle*/, double tn, bool bVShear, const SdrObject* pObj)
247 : {
248 0 : Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
249 0 : ShearPoint(aPt,rRef,tn,bVShear);
250 0 : if (pObj!=NULL) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
251 0 : }
252 :
253 0 : void SdrGluePoint::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
254 : {
255 0 : bool bMapMerk=rWin.IsMapModeEnabled();
256 0 : Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
257 0 : aPt=rWin.LogicToPixel(aPt);
258 0 : rWin.EnableMapMode(false);
259 :
260 0 : Size aSiz( aGlueHalfSize );
261 0 : Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),
262 0 : aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
263 :
264 : // do not erase background, that causes flicker (!)
265 0 : rWin.Invalidate(aRect, InvalidateFlags::NoErase);
266 :
267 0 : rWin.EnableMapMode(bMapMerk);
268 0 : }
269 :
270 0 : bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
271 : {
272 0 : Point aPt(pObj!=NULL ? GetAbsolutePos(*pObj) : GetPos());
273 0 : Size aSiz=rOut.PixelToLogic(aGlueHalfSize);
274 0 : Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
275 0 : return aRect.IsInside(rPnt);
276 : }
277 :
278 :
279 :
280 280 : void SdrGluePointList::Clear()
281 : {
282 280 : sal_uInt16 nCount=GetCount();
283 1920 : for (sal_uInt16 i=0; i<nCount; i++) {
284 1640 : delete GetObject(i);
285 : }
286 280 : aList.clear();
287 280 : }
288 :
289 123 : void SdrGluePointList::operator=(const SdrGluePointList& rSrcList)
290 : {
291 123 : if (GetCount()!=0) Clear();
292 123 : sal_uInt16 nCount=rSrcList.GetCount();
293 835 : for (sal_uInt16 i=0; i<nCount; i++) {
294 712 : Insert(rSrcList[i]);
295 : }
296 123 : }
297 :
298 : // The ID's of the glue points always increase monotonously!
299 : // If an ID is taken already, the new glue point gets a new ID. ID 0 is reserved.
300 1640 : sal_uInt16 SdrGluePointList::Insert(const SdrGluePoint& rGP)
301 : {
302 1640 : SdrGluePoint* pGP=new SdrGluePoint(rGP);
303 1640 : sal_uInt16 nId=pGP->GetId();
304 1640 : sal_uInt16 nCount=GetCount();
305 1640 : sal_uInt16 nInsPos=nCount;
306 1640 : sal_uInt16 nLastId=nCount!=0 ? GetObject(nCount-1)->GetId() : 0;
307 : DBG_ASSERT(nLastId>=nCount,"SdrGluePointList::Insert(): nLastId<nCount");
308 1640 : bool bHole = nLastId>nCount;
309 1640 : if (nId<=nLastId) {
310 216 : if (!bHole || nId==0) {
311 216 : nId=nLastId+1;
312 : } else {
313 0 : bool bBrk = false;
314 0 : for (sal_uInt16 nNum=0; nNum<nCount && !bBrk; nNum++) {
315 0 : const SdrGluePoint* pGP2=GetObject(nNum);
316 0 : sal_uInt16 nTmpId=pGP2->GetId();
317 0 : if (nTmpId==nId) {
318 0 : nId=nLastId+1; // already in use
319 0 : bBrk = true;
320 : }
321 0 : if (nTmpId>nId) {
322 0 : nInsPos=nNum; // insert here (sort)
323 0 : bBrk = true;
324 : }
325 : }
326 : }
327 216 : pGP->SetId(nId);
328 : }
329 1640 : aList.insert(aList.begin()+nInsPos, pGP);
330 1640 : return nInsPos;
331 : }
332 :
333 0 : void SdrGluePointList::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
334 : {
335 0 : sal_uInt16 nCount=GetCount();
336 0 : for (sal_uInt16 nNum=0; nNum<nCount; nNum++) {
337 0 : GetObject(nNum)->Invalidate(rWin,pObj);
338 : }
339 0 : }
340 :
341 4 : sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
342 : {
343 : // TODO: Implement a better search algorithm
344 : // List should be sorted at all times!
345 4 : sal_uInt16 nCount=GetCount();
346 4 : sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
347 16 : for (sal_uInt16 nNum=0; nNum<nCount && nRet==SDRGLUEPOINT_NOTFOUND; nNum++) {
348 12 : const SdrGluePoint* pGP=GetObject(nNum);
349 12 : if (pGP->GetId()==nId) nRet=nNum;
350 : }
351 4 : return nRet;
352 : }
353 :
354 0 : sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj, bool bBack, bool bNext, sal_uInt16 nId0) const
355 : {
356 0 : sal_uInt16 nCount=GetCount();
357 0 : sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
358 0 : sal_uInt16 nNum=bBack ? 0 : nCount;
359 0 : while ((bBack ? nNum<nCount : nNum>0) && nRet==SDRGLUEPOINT_NOTFOUND) {
360 0 : if (!bBack) nNum--;
361 0 : const SdrGluePoint* pGP=GetObject(nNum);
362 0 : if (bNext) {
363 0 : if (pGP->GetId()==nId0) bNext=false;
364 : } else {
365 0 : if (pGP->IsHit(rPnt,rOut,pObj)) nRet=nNum;
366 : }
367 0 : if (bBack) nNum++;
368 : }
369 0 : return nRet;
370 : }
371 :
372 36 : void SdrGluePointList::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
373 : {
374 36 : sal_uInt16 nCount=GetCount();
375 240 : for (sal_uInt16 nNum=0; nNum<nCount; nNum++) {
376 204 : GetObject(nNum)->SetReallyAbsolute(bOn,rObj);
377 : }
378 36 : }
379 :
380 15 : void SdrGluePointList::Rotate(const Point& rRef, long nAngle, double sn, double cs, const SdrObject* pObj)
381 : {
382 15 : sal_uInt16 nCount=GetCount();
383 102 : for (sal_uInt16 nNum=0; nNum<nCount; nNum++) {
384 87 : GetObject(nNum)->Rotate(rRef,nAngle,sn,cs,pObj);
385 : }
386 15 : }
387 :
388 3 : void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
389 : {
390 3 : Point aPt(rRef2); aPt-=rRef1;
391 3 : long nAngle=GetAngle(aPt);
392 3 : Mirror(rRef1,rRef2,nAngle,pObj);
393 3 : }
394 :
395 3 : void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, long nAngle, const SdrObject* pObj)
396 : {
397 3 : sal_uInt16 nCount=GetCount();
398 18 : for (sal_uInt16 nNum=0; nNum<nCount; nNum++) {
399 15 : GetObject(nNum)->Mirror(rRef1,rRef2,nAngle,pObj);
400 : }
401 3 : }
402 :
403 0 : void SdrGluePointList::Shear(const Point& rRef, long nAngle, double tn, bool bVShear, const SdrObject* pObj)
404 : {
405 0 : sal_uInt16 nCount=GetCount();
406 0 : for (sal_uInt16 nNum=0; nNum<nCount; nNum++) {
407 0 : GetObject(nNum)->Shear(rRef,nAngle,tn,bVShear,pObj);
408 : }
409 435 : }
410 :
411 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|