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
29
30void SdrGluePoint::SetReallyAbsolute(bool bOn, const SdrObject& rObj)
31{
32 if ( bReallyAbsolute == bOn )
33 return;
34
35 if ( bOn )
36 {
37 aPos=GetAbsolutePos(rObj);
39 }
40 else
41 {
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
89void 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
190void 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 {
198 }
199 // rotate exit directions
206 nEscDir=nEscDir1;
207 if (pObj!=nullptr) SetAbsolutePos(aPt,*pObj); else SetPos(aPt);
208}
209
210void 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 {
218 nAW+=2_deg100*(nAngle-nAW);
219 SetAlignAngle(nAW);
220 }
221 // mirror exit directions
224 if (nEscDir0&SdrEscapeDirection::LEFT) {
226 nEW+=2_deg100*(nAngle-nEW);
227 nEscDir1|=EscAngleToDir(nEW);
228 }
229 if (nEscDir0&SdrEscapeDirection::TOP) {
231 nEW+=2_deg100*(nAngle-nEW);
232 nEscDir1|=EscAngleToDir(nEW);
233 }
234 if (nEscDir0&SdrEscapeDirection::RIGHT) {
236 nEW+=2_deg100*(nAngle-nEW);
237 nEscDir1|=EscAngleToDir(nEW);
238 }
239 if (nEscDir0&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
248void 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
255void 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
274bool SdrGluePoint::IsHit(const Point& rPnt, const OutputDevice& rOut, const SdrObject* pObj) const
275{
276 Point aPt(pObj!=nullptr ? GetAbsolutePos(*pObj) : GetPos());
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);
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 gluepoints always increase monotonously!
294// If an ID is taken already, the new gluepoint gets a new ID. ID 0 is reserved.
296{
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 ? 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 aGP.SetId(nId);
323 }
324 aList.emplace(aList.begin()+nInsPos, aGP);
325 return nInsPos;
326}
327
329{
331 return;
332 for (auto& xGP : aList)
333 xGP.Invalidate(rWin,pObj);
334}
335
336sal_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
349sal_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
369void 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
375void 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
382void 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
388void 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: */
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
std::vector< SdrGluePoint > aList
Definition: svdglue.hxx:185
sal_uInt16 Insert(const SdrGluePoint &rGP)
Definition: svdglue.cxx:295
void SetReallyAbsolute(bool bOn, const SdrObject &rObj)
Definition: svdglue.cxx:363
sal_uInt16 FindGluePoint(sal_uInt16 nId) const
Definition: svdglue.cxx:336
sal_uInt16 HitTest(const Point &rPnt, const OutputDevice &rOut, const SdrObject *pObj) const
Definition: svdglue.cxx:349
void Rotate(const Point &rRef, Degree100 nAngle, double sn, double cs, const SdrObject *pObj)
Definition: svdglue.cxx:369
void Mirror(const Point &rRef1, const Point &rRef2, const SdrObject *pObj)
Definition: svdglue.cxx:375
void Invalidate(vcl::Window &rWin, const SdrObject *pObj) const
Definition: svdglue.cxx:328
SdrGluePointList & operator=(const SdrGluePointList &rSrcList)
Definition: svdglue.cxx:283
void Shear(const Point &rRef, double tn, bool bVShear, const SdrObject *pObj)
Definition: svdglue.cxx:388
sal_uInt16 GetCount() const
Definition: svdglue.hxx:194
void Shear(const Point &rRef, double tn, bool bVShear, const SdrObject *pObj)
Definition: svdglue.cxx:248
SdrAlign nAlign
Definition: svdglue.hxx:74
Point aPos
Definition: svdglue.hxx:71
void Rotate(const Point &rRef, Degree100 nAngle, double sn, double cs, const SdrObject *pObj)
Definition: svdglue.cxx:190
bool IsHit(const Point &rPnt, const OutputDevice &rOut, const SdrObject *pObj) const
Definition: svdglue.cxx:274
Point GetAbsolutePos(const SdrObject &rObj) const
Definition: svdglue.cxx:48
Degree100 GetAlignAngle() const
Definition: svdglue.cxx:129
bool bNoPercent
Definition: svdglue.hxx:75
void Invalidate(vcl::Window &rWin, const SdrObject *pObj) const
Definition: svdglue.cxx:255
static Degree100 EscDirToAngle(SdrEscapeDirection nEsc)
Definition: svdglue.cxx:165
sal_uInt16 GetId() const
Definition: svdglue.hxx:112
void SetPos(const Point &rNewPos)
Definition: svdglue.hxx:100
void Mirror(const Point &rRef1, const Point &rRef2, Degree100 nAngle, const SdrObject *pObj)
Definition: svdglue.cxx:210
bool bReallyAbsolute
Definition: svdglue.hxx:76
void SetAlignAngle(Degree100 nAngle)
Definition: svdglue.cxx:152
void SetId(sal_uInt16 nNewId)
Definition: svdglue.hxx:116
SdrEscapeDirection nEscDir
Definition: svdglue.hxx:72
void SetReallyAbsolute(bool bOn, const SdrObject &rObj)
Definition: svdglue.cxx:30
SdrAlign GetVertAlign() const
Definition: svdglue.hxx:158
static SdrEscapeDirection EscAngleToDir(Degree100 nAngle)
Definition: svdglue.cxx:177
SdrAlign GetHorzAlign() const
Definition: svdglue.hxx:149
void SetAbsolutePos(const Point &rNewPos, const SdrObject &rObj)
Definition: svdglue.cxx:89
const Point & GetPos() const
Definition: svdglue.hxx:96
Abstract DrawObject.
Definition: svdobj.hxx:261
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1665
constexpr tools::Long Height() const
constexpr tools::Long Width() const
constexpr Point Center() const
bool Contains(const Point &rPOINT) const
constexpr tools::Long Top() const
constexpr tools::Long Right() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
Point LogicToPixel(const Point &rLogicPt) const
bool IsMapModeEnabled() const
virtual void Invalidate(InvalidateFlags nFlags=InvalidateFlags::NONE)
void EnableMapMode(bool bEnable=true)
int nCount
#define DBG_ASSERT(sCon, aError)
int i
long Long
sal_Int16 nId
const Size aGlueHalfSize(4, 4)
SdrEscapeDirection
Definition: svdglue.hxx:35
#define SDRGLUEPOINT_NOTFOUND
Definition: svdglue.hxx:181
Degree100 GetAngle(const Point &rPnt)
The Y axis points down! The function negates the Y axis, when calculating the angle,...
Definition: svdtrans.cxx:387
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
Degree100 NormAngle36000(Degree100 a)
Normalize angle to -180.00..179.99.
Definition: svdtrans.cxx:408
void ShearPoint(Point &rPnt, const Point &rRef, double tn, bool bVShear=false)
Definition: svdtrans.hxx:109
void RotatePoint(Point &rPnt, const Point &rRef, double sn, double cs)
Definition: svdtrans.hxx:101