LibreOffice Module svx (master)  1
svdglue.cxx
Go to the documentation of this file.
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 #include <vcl/window.hxx>
22 
23 #include <svx/svdglue.hxx>
24 #include <svx/svdobj.hxx>
25 #include <svx/svdtrans.hxx>
26 #include <comphelper/lok.hxx>
27 
28 const Size aGlueHalfSize(4,4);
29 
30 void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
31 {
32  if ( bReallyAbsolute == bOn )
33  return;
34 
35  if ( bOn )
36  {
37  aPos=GetAbsolutePos(rObj);
38  bReallyAbsolute=bOn;
39  }
40  else
41  {
42  bReallyAbsolute=bOn;
43  Point aPt(aPos);
44  SetAbsolutePos(aPt,rObj);
45  }
46 }
47 
49 {
50  if (bReallyAbsolute) return aPos;
51  tools::Rectangle aSnap(rObj.GetSnapRect());
52  tools::Rectangle aBound(rObj.GetSnapRect());
53  Point aPt(aPos);
54 
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;
60  }
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;
65  }
66  if (!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 );
74  }
75  if (nYMul!=nYDiv) {
76  aPt.setY( aPt.Y() * nYMul );
77  aPt.setY( aPt.Y() / nYDiv );
78  }
79  }
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;
87 }
88 
89 void SdrGluePoint::SetAbsolutePos(const Point& rNewPos, const SdrObject& rObj)
90 {
91  if (bReallyAbsolute) {
92  aPos=rNewPos;
93  return;
94  }
95  tools::Rectangle aSnap(rObj.GetSnapRect());
96  Point aPt(rNewPos);
97 
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;
103  }
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;
108  }
109  aPt-=aOfs;
110  if (!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 );
120  }
121  if (nYMul!=nYDiv) {
122  aPt.setY( aPt.Y() * nYDiv );
123  aPt.setY( aPt.Y() / nYMul );
124  }
125  }
126  aPos=aPt;
127 }
128 
130 {
132  return 0_deg100; // Invalid!
134  return 0_deg100;
136  return 4500_deg100;
138  return 9000_deg100;
140  return 13500_deg100;
142  return 18000_deg100;
144  return 22500_deg100;
146  return 27000_deg100;
148  return 31500_deg100;
149  return 0_deg100;
150 }
151 
153 {
154  nAngle=NormAngle36000(nAngle);
155  if (nAngle>=33750_deg100 || nAngle<2250_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_CENTER;
156  else if (nAngle< 6750_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_TOP ;
157  else if (nAngle<11250_deg100) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_TOP ;
158  else if (nAngle<15750_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_TOP ;
159  else if (nAngle<20250_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_CENTER;
160  else if (nAngle<24750_deg100) nAlign=SdrAlign::HORZ_LEFT |SdrAlign::VERT_BOTTOM;
161  else if (nAngle<29250_deg100) nAlign=SdrAlign::HORZ_CENTER|SdrAlign::VERT_BOTTOM;
162  else if (nAngle<33750_deg100) nAlign=SdrAlign::HORZ_RIGHT |SdrAlign::VERT_BOTTOM;
163 }
164 
166 {
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;
175 }
176 
178 {
179  nAngle=NormAngle36000(nAngle);
180  if (nAngle>=31500_deg100 || nAngle<4500_deg100)
182  if (nAngle<13500_deg100)
184  if (nAngle<22500_deg100)
186  /* (nAngle<31500)*/
188 }
189 
190 void SdrGluePoint::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
191 {
192  Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
193  RotatePoint(aPt,rRef,sn,cs);
194  // rotate reference edge
196  {
197  SetAlignAngle(GetAlignAngle()+nAngle);
198  }
199  // rotate exit directions
200  SdrEscapeDirection nEscDir0=nEscDir;
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  nEscDir=nEscDir1;
207  if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
208 }
209 
210 void SdrGluePoint::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
211 {
212  Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
213  MirrorPoint(aPt,rRef1,rRef2);
214  // mirror reference edge
216  {
217  Degree100 nAW=GetAlignAngle();
218  nAW+=2_deg100*(nAngle-nAW);
219  SetAlignAngle(nAW);
220  }
221  // mirror exit directions
222  SdrEscapeDirection nEscDir0=nEscDir;
224  if (nEscDir0&SdrEscapeDirection::LEFT) {
225  Degree100 nEW=EscDirToAngle(SdrEscapeDirection::LEFT);
226  nEW+=2_deg100*(nAngle-nEW);
227  nEscDir1|=EscAngleToDir(nEW);
228  }
229  if (nEscDir0&SdrEscapeDirection::TOP) {
230  Degree100 nEW=EscDirToAngle(SdrEscapeDirection::TOP);
231  nEW+=2_deg100*(nAngle-nEW);
232  nEscDir1|=EscAngleToDir(nEW);
233  }
234  if (nEscDir0&SdrEscapeDirection::RIGHT) {
235  Degree100 nEW=EscDirToAngle(SdrEscapeDirection::RIGHT);
236  nEW+=2_deg100*(nAngle-nEW);
237  nEscDir1|=EscAngleToDir(nEW);
238  }
239  if (nEscDir0&SdrEscapeDirection::BOTTOM) {
240  Degree100 nEW=EscDirToAngle(SdrEscapeDirection::BOTTOM);
241  nEW+=2_deg100*(nAngle-nEW);
242  nEscDir1|=EscAngleToDir(nEW);
243  }
244  nEscDir=nEscDir1;
245  if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
246 }
247 
248 void SdrGluePoint::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
249 {
250  Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
251  ShearPoint(aPt,rRef,tn,bVShear);
252  if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
253 }
254 
255 void SdrGluePoint::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
256 {
258  return;
259  bool bMapMode=rWin.IsMapModeEnabled();
260  Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
261  aPt=rWin.LogicToPixel(aPt);
262  rWin.EnableMapMode(false);
263 
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());
267 
268  // do not erase background, that causes flicker (!)
269  rWin.Invalidate(aRect, InvalidateFlags::NoErase);
270 
271  rWin.EnableMapMode(bMapMode);
272 }
273 
274 bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
275 {
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.IsInside(rPnt);
280 }
281 
282 
284 {
285  if (GetCount()!=0) aList.clear();
286  sal_uInt16 nCount=rSrcList.GetCount();
287  for (sal_uInt16 i=0; i<nCount; i++) {
288  Insert(rSrcList[i]);
289  }
290  return *this;
291 }
292 
293 // The ID's of the glue points always increase monotonously!
294 // If an ID is taken already, the new glue point gets a new ID. ID 0 is reserved.
296 {
297  SdrGluePoint* pGP=new SdrGluePoint(rGP);
298  sal_uInt16 nId=pGP->GetId();
299  sal_uInt16 nCount=GetCount();
300  sal_uInt16 nInsPos=nCount;
301  sal_uInt16 nLastId=nCount!=0 ? 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=aList[nNum];
311  sal_uInt16 nTmpId=pGP2->GetId();
312  if (nTmpId==nId) {
313  nId=nLastId+1; // already in use
314  bBrk = true;
315  }
316  if (nTmpId>nId) {
317  nInsPos=nNum; // insert here (sort)
318  bBrk = true;
319  }
320  }
321  }
322  pGP->SetId(nId);
323  }
324  aList.emplace(aList.begin()+nInsPos, pGP);
325  return nInsPos;
326 }
327 
328 void SdrGluePointList::Invalidate(vcl::Window& rWin, const SdrObject* pObj) const
329 {
331  return;
332  for (auto& xGP : aList)
333  xGP->Invalidate(rWin,pObj);
334 }
335 
336 sal_uInt16 SdrGluePointList::FindGluePoint(sal_uInt16 nId) const
337 {
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=aList[nNum];
344  if (pGP->GetId()==nId) nRet=nNum;
345  }
346  return nRet;
347 }
348 
349 sal_uInt16 SdrGluePointList::HitTest(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
350 {
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 = aList[nNum];
357  if (pGP->IsHit(rPnt,rOut,pObj))
358  nRet = nNum;
359  }
360  return nRet;
361 }
362 
364 {
365  for (auto& xGP : aList)
366  xGP->SetReallyAbsolute(bOn,rObj);
367 }
368 
369 void SdrGluePointList::Rotate(const Point& rRef, Degree100 nAngle, double sn, double cs, const SdrObject* pObj)
370 {
371  for (auto& xGP : aList)
372  xGP->Rotate(rRef,nAngle,sn,cs,pObj);
373 }
374 
375 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, const SdrObject* pObj)
376 {
377  Point aPt(rRef2); aPt-=rRef1;
378  Degree100 nAngle=GetAngle(aPt);
379  Mirror(rRef1,rRef2,nAngle,pObj);
380 }
381 
382 void SdrGluePointList::Mirror(const Point& rRef1, const Point& rRef2, Degree100 nAngle, const SdrObject* pObj)
383 {
384  for (auto& xGP : aList)
385  xGP->Mirror(rRef1,rRef2,nAngle,pObj);
386 }
387 
388 void SdrGluePointList::Shear(const Point& rRef, double tn, bool bVShear, const SdrObject* pObj)
389 {
390  for (auto& xGP : aList)
391  xGP->Shear(rRef,tn,bVShear,pObj);
392 }
393 
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void SetId(sal_uInt16 nNewId)
Definition: svdglue.hxx:88
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:123
const Size aGlueHalfSize(4, 4)
SdrAlign GetVertAlign() const
Definition: svdglue.hxx:102
SdrEscapeDirection
Definition: svdglue.hxx:36
long Long
bool IsMapModeEnabled() const
sal_Int16 nId
static SdrEscapeDirection EscAngleToDir(Degree100 nAngle)
Definition: svdglue.cxx:177
void Rotate(const Point &rRef, Degree100 nAngle, double sn, double cs, const SdrObject *pObj)
Definition: svdglue.cxx:190
void EnableMapMode(bool bEnable=true)
sal_uInt16 GetCount() const
Definition: svdglue.hxx:126
SdrGluePointList & operator=(const SdrGluePointList &rSrcList)
Definition: svdglue.cxx:283
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1640
constexpr tools::Long Width() const
sal_uInt16 GetId() const
Definition: svdglue.hxx:87
void Mirror(const Point &rRef1, const Point &rRef2, const SdrObject *pObj)
Definition: svdglue.cxx:375
sal_uInt16 HitTest(const Point &rPnt, const OutputDevice &rOut, const SdrObject *pObj) const
Definition: svdglue.cxx:349
int nCount
bool IsHit(const Point &rPnt, const OutputDevice &rOut, const SdrObject *pObj) const
Definition: svdglue.cxx:274
void Rotate(const Point &rRef, Degree100 nAngle, double sn, double cs, const SdrObject *pObj)
Definition: svdglue.cxx:369
Degree100 NormAngle36000(Degree100 deg100)
Normalize angle to -180.00..179.99.
Definition: svdtrans.cxx:409
SdrAlign GetHorzAlign() const
Definition: svdglue.hxx:100
SdrAlign nAlign
Definition: svdglue.hxx:76
#define DBG_ASSERT(sCon, aError)
std::vector< std::unique_ptr< SdrGluePoint > > aList
Definition: svdglue.hxx:120
int i
#define SDRGLUEPOINT_NOTFOUND
Definition: svdglue.hxx:117
Degree100 GetAngle(const Point &rPnt)
The Y axis points down! The function negates the Y axis, when calculating the angle, such that GetAngle(Point(0,-1))=90 deg.
Definition: svdtrans.cxx:387
Point aPos
Definition: svdglue.hxx:73
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
void Invalidate(vcl::Window &rWin, const SdrObject *pObj) const
Definition: svdglue.cxx:255
bool bNoPercent
Definition: svdglue.hxx:77
bool IsInside(const Point &rPOINT) const
void SetAbsolutePos(const Point &rNewPos, const SdrObject &rObj)
Definition: svdglue.cxx:89
Abstract DrawObject.
Definition: svdobj.hxx:258
void SetReallyAbsolute(bool bOn, const SdrObject &rObj)
Definition: svdglue.cxx:363
Point GetAbsolutePos(const SdrObject &rObj) const
Definition: svdglue.cxx:48
sal_uInt16 FindGluePoint(sal_uInt16 nId) const
Definition: svdglue.cxx:336
sal_uInt16 Insert(const SdrGluePoint &rGP)
Definition: svdglue.cxx:295
Point PixelToLogic(const Point &rDevicePt) const
Point LogicToPixel(const Point &rLogicPt) const
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:115
Degree100 GetAlignAngle() const
Definition: svdglue.cxx:129
constexpr tools::Long Height() const
SdrEscapeDirection nEscDir
Definition: svdglue.hxx:74
static Degree100 EscDirToAngle(SdrEscapeDirection nEsc)
Definition: svdglue.cxx:165
void Shear(const Point &rRef, double tn, bool bVShear, const SdrObject *pObj)
Definition: svdglue.cxx:248
const Point & GetPos() const
Definition: svdglue.hxx:83
void SetReallyAbsolute(bool bOn, const SdrObject &rObj)
Definition: svdglue.cxx:30
void Shear(const Point &rRef, double tn, bool bVShear, const SdrObject *pObj)
Definition: svdglue.cxx:388
void SetAlignAngle(Degree100 nAngle)
Definition: svdglue.cxx:152
void Mirror(const Point &rRef1, const Point &rRef2, Degree100 nAngle, const SdrObject *pObj)
Definition: svdglue.cxx:210
void SetPos(const Point &rNewPos)
Definition: svdglue.hxx:84
void Invalidate(vcl::Window &rWin, const SdrObject *pObj) const
Definition: svdglue.cxx:328
bool bReallyAbsolute
Definition: svdglue.hxx:78