Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / svdraw / svdglue.cxx
blob0d3db7f8d57d6dd2ec7551596e595ef5487d76d7
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>
21 #include <vcl/window.hxx>
23 #include <svx/svdglue.hxx>
24 #include <svx/svdobj.hxx>
25 #include <svx/svdtrans.hxx>
27 const Size aGlueHalfSize(4,4);
29 void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
31 if ( bReallyAbsolute == bOn )
32 return;
34 if ( bOn )
36 aPos=GetAbsolutePos(rObj);
37 bReallyAbsolute=bOn;
39 else
41 bReallyAbsolute=bOn;
42 Point aPt(aPos);
43 SetAbsolutePos(aPt,rObj);
47 Point SdrGluePoint::GetAbsolutePos(const SdrObject& rObj) const
49 if (bReallyAbsolute) return aPos;
50 tools::Rectangle aSnap(rObj.GetSnapRect());
51 tools::Rectangle aBound(rObj.GetSnapRect());
52 Point aPt(aPos);
54 Point aOfs(aSnap.Center());
55 switch (GetHorzAlign()) {
56 case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
57 case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
58 default: break;
60 switch (GetVertAlign()) {
61 case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
62 case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
63 default: break;
65 if (!bNoPercent) {
66 tools::Long nXMul=aSnap.Right()-aSnap.Left();
67 tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
68 tools::Long nXDiv=10000;
69 tools::Long nYDiv=10000;
70 if (nXMul!=nXDiv) {
71 aPt.setX( aPt.X() * nXMul );
72 aPt.setX( aPt.X() / nXDiv );
74 if (nYMul!=nYDiv) {
75 aPt.setY( aPt.Y() * nYMul );
76 aPt.setY( aPt.Y() / nYDiv );
79 aPt+=aOfs;
80 // Now limit to the BoundRect of the object
81 if (aPt.X()<aBound.Left ()) aPt.setX(aBound.Left () );
82 if (aPt.X()>aBound.Right ()) aPt.setX(aBound.Right () );
83 if (aPt.Y()<aBound.Top ()) aPt.setY(aBound.Top () );
84 if (aPt.Y()>aBound.Bottom()) aPt.setY(aBound.Bottom() );
85 return aPt;
88 void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
90 if (bReallyAbsolute) {
91 aPos=rNewPos;
92 return;
94 tools::Rectangle aSnap(rObj.GetSnapRect());
95 Point aPt(rNewPos);
97 Point aOfs(aSnap.Center());
98 switch (GetHorzAlign()) {
99 case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
100 case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
101 default: break;
103 switch (GetVertAlign()) {
104 case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
105 case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
106 default: break;
108 aPt-=aOfs;
109 if (!bNoPercent) {
110 tools::Long nXMul=aSnap.Right()-aSnap.Left();
111 tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
112 if (nXMul==0) nXMul=1;
113 if (nYMul==0) nYMul=1;
114 tools::Long nXDiv=10000;
115 tools::Long nYDiv=10000;
116 if (nXMul!=nXDiv) {
117 aPt.setX( aPt.X() * nXDiv );
118 aPt.setX( aPt.X() / nXMul );
120 if (nYMul!=nYDiv) {
121 aPt.setY( aPt.Y() * nYDiv );
122 aPt.setY( aPt.Y() / nYMul );
125 aPos=aPt;
128 tools::Long SdrGluePoint::GetAlignAngle() const
130 if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
131 return 0; // Invalid!
132 else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER))
133 return 0;
134 else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP))
135 return 4500;
136 else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP))
137 return 9000;
138 else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP))
139 return 13500;
140 else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER))
141 return 18000;
142 else if (nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM))
143 return 22500;
144 else if (nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM))
145 return 27000;
146 else if (nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM))
147 return 31500;
148 return 0;
151 void SdrGluePoint::SetAlignAngle(tools::Long nAngle)
153 nAngle=NormAngle36000(nAngle);
154 if (nAngle>=33750 || nAngle<2250) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER;
155 else if (nAngle< 6750) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP ;
156 else if (nAngle<11250) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP ;
157 else if (nAngle<15750) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP ;
158 else if (nAngle<20250) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER;
159 else if (nAngle<24750) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM;
160 else if (nAngle<29250) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM;
161 else if (nAngle<33750) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM;
164 tools::Long SdrGluePoint::EscDirToAngle(SdrEscapeDirection nEsc)
166 switch (nEsc) {
167 case SdrEscapeDirection::RIGHT : return 0;
168 case SdrEscapeDirection::TOP : return 9000;
169 case SdrEscapeDirection::LEFT : return 18000;
170 case SdrEscapeDirection::BOTTOM: return 27000;
171 default: break;
172 } // switch
173 return 0;
176 SdrEscapeDirection SdrGluePoint::EscAngleToDir(tools::Long nAngle)
178 nAngle=NormAngle36000(nAngle);
179 if (nAngle>=31500 || nAngle<4500)
180 return SdrEscapeDirection::RIGHT;
181 if (nAngle<13500)
182 return SdrEscapeDirection::TOP;
183 if (nAngle<22500)
184 return SdrEscapeDirection::LEFT;
185 /* (nAngle<31500)*/
186 return SdrEscapeDirection::BOTTOM;
189 void SdrGluePoint::Rotate(const Point& rRef, tools::Long nAngle, double sn, double cs, const SdrObject* pObj)
191 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
192 RotatePoint(aPt,rRef,sn,cs);
193 // rotate reference edge
194 if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
196 SetAlignAngle(GetAlignAngle()+nAngle);
198 // rotate exit directions
199 SdrEscapeDirection nEscDir0=nEscDir;
200 SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
201 if (nEscDir0&SdrEscapeDirection::LEFT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::LEFT )+nAngle);
202 if (nEscDir0&SdrEscapeDirection::TOP ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::TOP )+nAngle);
203 if (nEscDir0&SdrEscapeDirection::RIGHT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::RIGHT )+nAngle);
204 if (nEscDir0&SdrEscapeDirection::BOTTOM) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::BOTTOM)+nAngle);
205 nEscDir=nEscDir1;
206 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
209 void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, tools::Long nAngle, const SdrObject* pObj)
211 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
212 MirrorPoint(aPt,rRef1,rRef2);
213 // mirror reference edge
214 if(nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
216 tools::Long nAW=GetAlignAngle();
217 nAW+=2*(nAngle-nAW);
218 SetAlignAngle(nAW);
220 // mirror exit directions
221 SdrEscapeDirection nEscDir0=nEscDir;
222 SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
223 if (nEscDir0&SdrEscapeDirection::LEFT) {
224 tools::Long nEW=EscDirToAngle(SdrEscapeDirection::LEFT);
225 nEW+=2*(nAngle-nEW);
226 nEscDir1|=EscAngleToDir(nEW);
228 if (nEscDir0&SdrEscapeDirection::TOP) {
229 tools::Long nEW=EscDirToAngle(SdrEscapeDirection::TOP);
230 nEW+=2*(nAngle-nEW);
231 nEscDir1|=EscAngleToDir(nEW);
233 if (nEscDir0&SdrEscapeDirection::RIGHT) {
234 tools::Long nEW=EscDirToAngle(SdrEscapeDirection::RIGHT);
235 nEW+=2*(nAngle-nEW);
236 nEscDir1|=EscAngleToDir(nEW);
238 if (nEscDir0&SdrEscapeDirection::BOTTOM) {
239 tools::Long nEW=EscDirToAngle(SdrEscapeDirection::BOTTOM);
240 nEW+=2*(nAngle-nEW);
241 nEscDir1|=EscAngleToDir(nEW);
243 nEscDir=nEscDir1;
244 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
247 void SdrGluePoint::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
249 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
250 ShearPoint(aPt,rRef,tn,bVShear);
251 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
254 void SdrGluePoint::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
256 bool bMapMode=rWin.IsMapModeEnabled();
257 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
258 aPt=rWin.LogicToPixel(aPt);
259 rWin.EnableMapMode(false);
261 Size aSiz( aGlueHalfSize );
262 tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),
263 aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
265 // do not erase background, that causes flicker (!)
266 rWin.Invalidate(aRect, InvalidateFlags::NoErase);
268 rWin.EnableMapMode(bMapMode);
271 bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
273 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
274 Size aSiz=rOut.PixelToLogic(aGlueHalfSize);
275 tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
276 return aRect.IsInside(rPnt);
280 SdrGluePointList& SdrGluePointList::operator=(const SdrGluePointList& rSrcList)
282 if (GetCount()!=0) aList.clear();
283 sal_uInt16 nCount=rSrcList.GetCount();
284 for (sal_uInt16 i=0; i<nCount; i++) {
285 Insert(rSrcList[i]);
287 return *this;
290 // The ID's of the glue points always increase monotonously!
291 // If an ID is taken already, the new glue point gets a new ID. ID 0 is reserved.
292 sal_uInt16 SdrGluePointList::Insert(const SdrGluePoint& rGP)
294 SdrGluePoint* pGP=new SdrGluePoint(rGP);
295 sal_uInt16 nId=pGP->GetId();
296 sal_uInt16 nCount=GetCount();
297 sal_uInt16 nInsPos=nCount;
298 sal_uInt16 nLastId=nCount!=0 ? aList[nCount-1]->GetId() : 0;
299 DBG_ASSERT(nLastId>=nCount,"SdrGluePointList::Insert(): nLastId<nCount");
300 bool bHole = nLastId>nCount;
301 if (nId<=nLastId) {
302 if (!bHole || nId==0) {
303 nId=nLastId+1;
304 } else {
305 bool bBrk = false;
306 for (sal_uInt16 nNum=0; nNum<nCount && !bBrk; nNum++) {
307 const auto& pGP2=aList[nNum];
308 sal_uInt16 nTmpId=pGP2->GetId();
309 if (nTmpId==nId) {
310 nId=nLastId+1; // already in use
311 bBrk = true;
313 if (nTmpId>nId) {
314 nInsPos=nNum; // insert here (sort)
315 bBrk = true;
319 pGP->SetId(nId);
321 aList.emplace(aList.begin()+nInsPos, pGP);
322 return nInsPos;
325 void SdrGluePointList::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
327 for (auto& xGP : aList)
328 xGP->Invalidate(rWin,pObj);
331 sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
333 // TODO: Implement a better search algorithm
334 // List should be sorted at all times!
335 sal_uInt16 nCount=GetCount();
336 sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
337 for (sal_uInt16 nNum=0; nNum<nCount && nRet==SDRGLUEPOINT_NOTFOUND; nNum++) {
338 const auto& pGP=aList[nNum];
339 if (pGP->GetId()==nId) nRet=nNum;
341 return nRet;
344 sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
346 sal_uInt16 nCount = GetCount();
347 sal_uInt16 nRet = SDRGLUEPOINT_NOTFOUND;
348 sal_uInt16 nNum = nCount;
349 while ((nNum>0) && nRet==SDRGLUEPOINT_NOTFOUND) {
350 nNum--;
351 const auto& pGP = aList[nNum];
352 if (pGP->IsHit(rPnt,rOut,pObj))
353 nRet = nNum;
355 return nRet;
358 void SdrGluePointList::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
360 for (auto& xGP : aList)
361 xGP->SetReallyAbsolute(bOn,rObj);
364 void SdrGluePointList::Rotate(const Point& rRef, tools::Long nAngle, double sn, double cs, const SdrObject* pObj)
366 for (auto& xGP : aList)
367 xGP->Rotate(rRef,nAngle,sn,cs,pObj);
370 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
372 Point aPt(rRef2); aPt-=rRef1;
373 tools::Long nAngle=GetAngle(aPt);
374 Mirror(rRef1,rRef2,nAngle,pObj);
377 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, tools::Long nAngle, const SdrObject* pObj)
379 for (auto& xGP : aList)
380 xGP->Mirror(rRef1,rRef2,nAngle,pObj);
383 void SdrGluePointList::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
385 for (auto& xGP : aList)
386 xGP->Shear(rRef,tn,bVShear,pObj);
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */