tdf#144694 In direct SQL dialog, activate options 'Run SQL command
[LibreOffice.git] / svx / source / svdraw / svdglue.cxx
blobc27fc2e2bde9733abbc7baa451db7a714f9b825a
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>
26 #include <comphelper/lok.hxx>
28 const Size aGlueHalfSize(4,4);
30 void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
32 if ( m_bReallyAbsolute == bOn )
33 return;
35 if ( bOn )
37 m_aPos=GetAbsolutePos(rObj);
38 m_bReallyAbsolute=bOn;
40 else
42 m_bReallyAbsolute=bOn;
43 Point aPt(m_aPos);
44 SetAbsolutePos(aPt,rObj);
48 Point SdrGluePoint::GetAbsolutePos(const SdrObject& rObj) const
50 if (m_bReallyAbsolute) return m_aPos;
51 tools::Rectangle aSnap(rObj.GetSnapRect());
52 tools::Rectangle aBound(rObj.GetSnapRect());
53 Point aPt(m_aPos);
55 Point aOfs(aSnap.Center());
56 switch (GetHorzAlign()) {
57 case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
58 case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
59 default: break;
61 switch (GetVertAlign()) {
62 case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
63 case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
64 default: break;
66 if (!m_bNoPercent) {
67 tools::Long nXMul=aSnap.Right()-aSnap.Left();
68 tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
69 tools::Long nXDiv=10000;
70 tools::Long nYDiv=10000;
71 if (nXMul!=nXDiv) {
72 aPt.setX( aPt.X() * nXMul );
73 aPt.setX( aPt.X() / nXDiv );
75 if (nYMul!=nYDiv) {
76 aPt.setY( aPt.Y() * nYMul );
77 aPt.setY( aPt.Y() / nYDiv );
80 aPt+=aOfs;
81 // Now limit to the BoundRect of the object
82 if (aPt.X()<aBound.Left ()) aPt.setX(aBound.Left () );
83 if (aPt.X()>aBound.Right ()) aPt.setX(aBound.Right () );
84 if (aPt.Y()<aBound.Top ()) aPt.setY(aBound.Top () );
85 if (aPt.Y()>aBound.Bottom()) aPt.setY(aBound.Bottom() );
86 return aPt;
89 void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
91 if (m_bReallyAbsolute) {
92 m_aPos=rNewPos;
93 return;
95 tools::Rectangle aSnap(rObj.GetSnapRect());
96 Point aPt(rNewPos);
98 Point aOfs(aSnap.Center());
99 switch (GetHorzAlign()) {
100 case SdrAlign::HORZ_LEFT : aOfs.setX(aSnap.Left() ); break;
101 case SdrAlign::HORZ_RIGHT : aOfs.setX(aSnap.Right() ); break;
102 default: break;
104 switch (GetVertAlign()) {
105 case SdrAlign::VERT_TOP : aOfs.setY(aSnap.Top() ); break;
106 case SdrAlign::VERT_BOTTOM: aOfs.setY(aSnap.Bottom() ); break;
107 default: break;
109 aPt-=aOfs;
110 if (!m_bNoPercent) {
111 tools::Long nXMul=aSnap.Right()-aSnap.Left();
112 tools::Long nYMul=aSnap.Bottom()-aSnap.Top();
113 if (nXMul==0) nXMul=1;
114 if (nYMul==0) nYMul=1;
115 tools::Long nXDiv=10000;
116 tools::Long nYDiv=10000;
117 if (nXMul!=nXDiv) {
118 aPt.setX( aPt.X() * nXDiv );
119 aPt.setX( aPt.X() / nXMul );
121 if (nYMul!=nYDiv) {
122 aPt.setY( aPt.Y() * nYDiv );
123 aPt.setY( aPt.Y() / nYMul );
126 m_aPos=aPt;
129 Degree100 SdrGluePoint::GetAlignAngle() const
131 if (m_nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
132 return 0_deg100; // Invalid!
133 else if (m_nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER))
134 return 0_deg100;
135 else if (m_nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP))
136 return 4500_deg100;
137 else if (m_nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP))
138 return 9000_deg100;
139 else if (m_nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP))
140 return 13500_deg100;
141 else if (m_nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER))
142 return 18000_deg100;
143 else if (m_nAlign == (SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM))
144 return 22500_deg100;
145 else if (m_nAlign == (SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM))
146 return 27000_deg100;
147 else if (m_nAlign == (SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM))
148 return 31500_deg100;
149 return 0_deg100;
152 void SdrGluePoint::SetAlignAngle(Degree100 nAngle)
154 nAngle=NormAngle36000(nAngle);
155 if (nAngle>=33750_deg100 || nAngle<2250_deg100) m_nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER;
156 else if (nAngle< 6750_deg100) m_nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP ;
157 else if (nAngle<11250_deg100) m_nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP ;
158 else if (nAngle<15750_deg100) m_nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP ;
159 else if (nAngle<20250_deg100) m_nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER;
160 else if (nAngle<24750_deg100) m_nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM;
161 else if (nAngle<29250_deg100) m_nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM;
162 else if (nAngle<33750_deg100) m_nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM;
165 Degree100 SdrGluePoint::EscDirToAngle(SdrEscapeDirection nEsc)
167 switch (nEsc) {
168 case SdrEscapeDirection::RIGHT : return 0_deg100;
169 case SdrEscapeDirection::TOP : return 9000_deg100;
170 case SdrEscapeDirection::LEFT : return 18000_deg100;
171 case SdrEscapeDirection::BOTTOM: return 27000_deg100;
172 default: break;
173 } // switch
174 return 0_deg100;
177 SdrEscapeDirection SdrGluePoint::EscAngleToDir(Degree100 nAngle)
179 nAngle=NormAngle36000(nAngle);
180 if (nAngle>=31500_deg100 || nAngle<4500_deg100)
181 return SdrEscapeDirection::RIGHT;
182 if (nAngle<13500_deg100)
183 return SdrEscapeDirection::TOP;
184 if (nAngle<22500_deg100)
185 return SdrEscapeDirection::LEFT;
186 /* (nAngle<31500)*/
187 return SdrEscapeDirection::BOTTOM;
190 void SdrGluePoint::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
192 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
193 RotatePoint(aPt,rRef,sn,cs);
194 // rotate reference edge
195 if(m_nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
197 SetAlignAngle(GetAlignAngle()+nAngle);
199 // rotate exit directions
200 SdrEscapeDirection nEscDir0=m_nEscDir;
201 SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
202 if (nEscDir0&SdrEscapeDirection::LEFT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::LEFT )+nAngle);
203 if (nEscDir0&SdrEscapeDirection::TOP ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::TOP )+nAngle);
204 if (nEscDir0&SdrEscapeDirection::RIGHT ) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::RIGHT )+nAngle);
205 if (nEscDir0&SdrEscapeDirection::BOTTOM) nEscDir1 |= EscAngleToDir(EscDirToAngle(SdrEscapeDirection::BOTTOM)+nAngle);
206 m_nEscDir=nEscDir1;
207 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
210 void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
212 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
213 MirrorPoint(aPt,rRef1,rRef2);
214 // mirror reference edge
215 if(m_nAlign != (SdrAlign::HORZ_CENTER|SdrAlign::VERT_CENTER))
217 Degree100 nAW=GetAlignAngle();
218 nAW+=2_deg100*(nAngle-nAW);
219 SetAlignAngle(nAW);
221 // mirror exit directions
222 SdrEscapeDirection nEscDir0=m_nEscDir;
223 SdrEscapeDirection nEscDir1=SdrEscapeDirection::SMART;
224 if (nEscDir0&SdrEscapeDirection::LEFT) {
225 Degree100 nEW=EscDirToAngle(SdrEscapeDirection::LEFT);
226 nEW+=2_deg100*(nAngle-nEW);
227 nEscDir1|=EscAngleToDir(nEW);
229 if (nEscDir0&SdrEscapeDirection::TOP) {
230 Degree100 nEW=EscDirToAngle(SdrEscapeDirection::TOP);
231 nEW+=2_deg100*(nAngle-nEW);
232 nEscDir1|=EscAngleToDir(nEW);
234 if (nEscDir0&SdrEscapeDirection::RIGHT) {
235 Degree100 nEW=EscDirToAngle(SdrEscapeDirection::RIGHT);
236 nEW+=2_deg100*(nAngle-nEW);
237 nEscDir1|=EscAngleToDir(nEW);
239 if (nEscDir0&SdrEscapeDirection::BOTTOM) {
240 Degree100 nEW=EscDirToAngle(SdrEscapeDirection::BOTTOM);
241 nEW+=2_deg100*(nAngle-nEW);
242 nEscDir1|=EscAngleToDir(nEW);
244 m_nEscDir=nEscDir1;
245 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
248 void SdrGluePoint::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
250 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
251 ShearPoint(aPt,rRef,tn,bVShear);
252 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
255 void SdrGluePoint::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
257 if (comphelper::LibreOfficeKit::isActive())
258 return;
259 bool bMapMode=rWin.IsMapModeEnabled();
260 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
261 aPt=rWin.LogicToPixel(aPt);
262 rWin.EnableMapMode(false);
264 Size aSiz( aGlueHalfSize );
265 tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),
266 aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
268 // do not erase background, that causes flicker (!)
269 rWin.Invalidate(aRect, InvalidateFlags::NoErase);
271 rWin.EnableMapMode(bMapMode);
274 bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
276 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
277 Size aSiz=rOut.PixelToLogic(aGlueHalfSize);
278 tools::Rectangle aRect(aPt.X()-aSiz.Width(),aPt.Y()-aSiz.Height(),aPt.X()+aSiz.Width(),aPt.Y()+aSiz.Height());
279 return aRect.Contains(rPnt);
283 SdrGluePointList& SdrGluePointList::operator=(const SdrGluePointList& rSrcList)
285 if (GetCount()!=0) m_aList.clear();
286 sal_uInt16 nCount=rSrcList.GetCount();
287 for (sal_uInt16 i=0; i<nCount; i++) {
288 Insert(rSrcList[i]);
290 return *this;
293 // The ID's of the gluepoints always increase monotonously!
294 // If an ID is taken already, the new gluepoint gets a new ID. ID 0 is reserved.
295 sal_uInt16 SdrGluePointList::Insert(const SdrGluePoint& rGP)
297 SdrGluePoint aGP(rGP);
298 sal_uInt16 nId=aGP.GetId();
299 sal_uInt16 nCount=GetCount();
300 sal_uInt16 nInsPos=nCount;
301 sal_uInt16 nLastId=nCount!=0 ? m_aList[nCount-1].GetId() : 0;
302 DBG_ASSERT(nLastId>=nCount,"SdrGluePointList::Insert(): nLastId<nCount");
303 bool bHole = nLastId>nCount;
304 if (nId<=nLastId) {
305 if (!bHole || nId==0) {
306 nId=nLastId+1;
307 } else {
308 bool bBrk = false;
309 for (sal_uInt16 nNum=0; nNum<nCount && !bBrk; nNum++) {
310 const auto& pGP2=m_aList[nNum];
311 sal_uInt16 nTmpId=pGP2.GetId();
312 if (nTmpId==nId) {
313 nId=nLastId+1; // already in use
314 bBrk = true;
316 if (nTmpId>nId) {
317 nInsPos=nNum; // insert here (sort)
318 bBrk = true;
322 aGP.SetId(nId);
324 m_aList.emplace(m_aList.begin()+nInsPos, aGP);
325 return nInsPos;
328 void SdrGluePointList::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
330 if (comphelper::LibreOfficeKit::isActive())
331 return;
332 for (auto& xGP : m_aList)
333 xGP.Invalidate(rWin,pObj);
336 sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
338 // TODO: Implement a better search algorithm
339 // List should be sorted at all times!
340 sal_uInt16 nCount=GetCount();
341 sal_uInt16 nRet=SDRGLUEPOINT_NOTFOUND;
342 for (sal_uInt16 nNum=0; nNum<nCount && nRet==SDRGLUEPOINT_NOTFOUND; nNum++) {
343 const auto& pGP=m_aList[nNum];
344 if (pGP.GetId()==nId) nRet=nNum;
346 return nRet;
349 sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
351 sal_uInt16 nCount = GetCount();
352 sal_uInt16 nRet = SDRGLUEPOINT_NOTFOUND;
353 sal_uInt16 nNum = nCount;
354 while ((nNum>0) && nRet==SDRGLUEPOINT_NOTFOUND) {
355 nNum--;
356 const auto& pGP = m_aList[nNum];
357 if (pGP.IsHit(rPnt,rOut,pObj))
358 nRet = nNum;
360 return nRet;
363 void SdrGluePointList::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
365 for (auto& xGP : m_aList)
366 xGP.SetReallyAbsolute(bOn,rObj);
369 void SdrGluePointList::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
371 for (auto& xGP : m_aList)
372 xGP.Rotate(rRef,nAngle,sn,cs,pObj);
375 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
377 Point aPt(rRef2); aPt-=rRef1;
378 Degree100 nAngle=GetAngle(aPt);
379 Mirror(rRef1,rRef2,nAngle,pObj);
382 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
384 for (auto& xGP : m_aList)
385 xGP.Mirror(rRef1,rRef2,nAngle,pObj);
388 void SdrGluePointList::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
390 for (auto& xGP : m_aList)
391 xGP.Shear(rRef,tn,bVShear,pObj);
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */