LibreOffice Module svx (master) 1
svdoedge.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 <svx/dialmgr.hxx>
21#include <svx/strings.hrc>
22#include <osl/diagnose.h>
23
26#include <svl/hint.hxx>
27
31#include <svx/svddrag.hxx>
32#include <svx/svddrgmt.hxx>
33#include <svx/svdhdl.hxx>
34#include <svx/svdmodel.hxx>
35#include <svx/svdoedge.hxx>
36#include <svx/svdopath.hxx>
37#include <svx/svdpage.hxx>
38#include <svx/svdpagv.hxx>
39#include <svx/svdtrans.hxx>
40#include <svx/svdview.hxx>
41#include <svx/sxekitm.hxx>
42#include <svx/sxelditm.hxx>
43#include <svx/sxenditm.hxx>
44#include <svx/xpoly.hxx>
45#include <vcl/ptrstyle.hxx>
46#include <comphelper/lok.hxx>
47
49{
50 pObj=nullptr;
51 nConId=0;
52 bBestConn=true;
53 bBestVertex=true;
54 bAutoVertex=false;
55 bAutoCorner=false;
56}
57
59{
60 bool bRet = false;
61 if (pObj!=nullptr) { // one object has to be docked already!
62 if (bAutoVertex) {
64 bRet = true;
65 } else if (bAutoCorner) {
67 bRet = true;
68 } else {
70 if (pGPL!=nullptr) {
71 sal_uInt16 nNum=pGPL->FindGluePoint(nConId);
72 if (nNum!=SDRGLUEPOINT_NOTFOUND) {
73 rGP=(*pGPL)[nNum];
74 bRet = true;
75 }
76 }
77 }
78 }
79 if (bRet) {
80 Point aPt(rGP.GetAbsolutePos(*pObj));
81 aPt+=aObjOfs;
82 rGP.SetPos(aPt);
83 }
84 return bRet;
85}
86
88{
89 switch (eLineCode) {
95 } // switch
96 return aMiddleLine;
97}
98
99sal_uInt16 SdrEdgeInfoRec::ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const
100{
101 switch (eLineCode) {
102 case SdrEdgeLineCode::Obj1Line2 : return 1;
103 case SdrEdgeLineCode::Obj1Line3 : return 2;
104 case SdrEdgeLineCode::Obj2Line2 : return rXP.GetPointCount()-3;
105 case SdrEdgeLineCode::Obj2Line3 : return rXP.GetPointCount()-4;
107 } // switch
108 return 0;
109}
110
112{
113 sal_uInt16 nIdx=ImpGetPolyIdx(eLineCode,rXP);
114 bool bHorz=nAngle1==0 || nAngle1==18000;
115 if (eLineCode==SdrEdgeLineCode::Obj2Line2 || eLineCode==SdrEdgeLineCode::Obj2Line3) {
116 nIdx=rXP.GetPointCount()-nIdx;
117 bHorz=nAngle2==0 || nAngle2==18000;
118 }
119 if ((nIdx & 1)==1) bHorz=!bHorz;
120 return bHorz;
121}
122
124{
125 Point& rPt=ImpGetLineOffsetPoint(eLineCode);
126 if (ImpIsHorzLine(eLineCode,rXP)) rPt.setY(nVal );
127 else rPt.setX(nVal );
128}
129
131{
132 const Point& rPt = const_cast<SdrEdgeInfoRec*>(this)->ImpGetLineOffsetPoint(eLineCode);
133 if (ImpIsHorzLine(eLineCode,rXP))
134 return rPt.Y();
135 else
136 return rPt.X();
137}
138
139
140// BaseProperties section
141
142std::unique_ptr<sdr::properties::BaseProperties> SdrEdgeObj::CreateObjectSpecificProperties()
143{
144 return std::make_unique<sdr::properties::ConnectorProperties>(*this);
145}
146
147
148// DrawContact section
149
150std::unique_ptr<sdr::contact::ViewContact> SdrEdgeObj::CreateObjectSpecificViewContact()
151{
152 return std::make_unique<sdr::contact::ViewContactOfSdrEdgeObj>(*this);
153}
154
155
157: SdrTextObj(rSdrModel),
158 nNotifyingCount(0),
159 bEdgeTrackDirty(false),
160 bEdgeTrackUserDefined(false),
161 // Default is to allow default connects
162 mbSuppressDefaultConnect(false),
163 mbBoundRectCalculationRunning(false),
164 mbSuppressed(false)
165{
166 m_bClosedObj=false;
167 m_bIsEdge=true;
169}
170
171SdrEdgeObj::SdrEdgeObj(SdrModel& rSdrModel, SdrEdgeObj const & rSource)
172: SdrTextObj(rSdrModel, rSource),
173 nNotifyingCount(0),
174 bEdgeTrackDirty(false),
175 bEdgeTrackUserDefined(false),
176 // Default is to allow default connects
177 mbSuppressDefaultConnect(false),
178 mbBoundRectCalculationRunning(false),
179 mbSuppressed(false)
180{
181 m_bClosedObj = false;
182 m_bIsEdge = true;
183 pEdgeTrack = rSource.pEdgeTrack;
185 aCon1 =rSource.aCon1;
186 aCon2 =rSource.aCon2;
187 aCon1.pObj=nullptr;
188 aCon2.pObj=nullptr;
189 aEdgeInfo=rSource.aEdgeInfo;
190}
191
193{
196}
197
199{
200 // call parent
201 SdrTextObj::handlePageChange(pOldPage, pNewPage);
202
203 if(nullptr != GetConnection(true).GetObject() || nullptr != GetConnection(false).GetObject())
204 {
205 // check broadcasters; when we are not inserted we do not need broadcasters
206 // TTTT not yet added, but keep hint to do this here
207 // mpCon1->ownerPageChange();
208 // mpCon2->ownerPageChange();
209 }
210}
211
213{
215 SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
216 sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
217 sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
218 sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
219
220 if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
221 {
222 sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
223 sal_uInt16 n = 0;
224
225 if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
226 {
228 n++;
229 }
230
231 if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
232 {
234 n++;
235 }
236
237 if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
238 {
240 n++;
241 }
242
243 if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
244 {
246 n++;
247 }
248
249 if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
250 {
252 n++;
253 }
254 }
255 else if(eKind == SdrEdgeKind::ThreeLines)
256 {
257 bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
258 bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
259
260 if(bHor1)
261 {
262 aEdgeInfo.aObj1Line2.setX( nVal1 );
263 }
264 else
265 {
266 aEdgeInfo.aObj1Line2.setY( nVal1 );
267 }
268
269 if(bHor2)
270 {
271 aEdgeInfo.aObj2Line2.setX( nVal2 );
272 }
273 else
274 {
275 aEdgeInfo.aObj2Line2.setY( nVal2 );
276 }
277 }
278
280}
281
283{
285 SdrEdgeKind eKind = rSet.Get(SDRATTR_EDGEKIND).GetValue();
286 sal_Int32 nValCnt = rSet.Get(SDRATTR_EDGELINEDELTACOUNT).GetValue();
287 sal_Int32 nVal1 = rSet.Get(SDRATTR_EDGELINE1DELTA).GetValue();
288 sal_Int32 nVal2 = rSet.Get(SDRATTR_EDGELINE2DELTA).GetValue();
289 sal_Int32 nVal3 = rSet.Get(SDRATTR_EDGELINE3DELTA).GetValue();
290 sal_Int32 nVals[3] = { nVal1, nVal2, nVal3 };
291 sal_uInt16 n = 0;
292
293 if(eKind == SdrEdgeKind::OrthoLines || eKind == SdrEdgeKind::Bezier)
294 {
295 if(aEdgeInfo.nObj1Lines >= 2 && n < 3)
296 {
298 n++;
299 }
300
301 if(aEdgeInfo.nObj1Lines >= 3 && n < 3)
302 {
304 n++;
305 }
306
307 if(aEdgeInfo.nMiddleLine != 0xFFFF && n < 3)
308 {
310 n++;
311 }
312
313 if(aEdgeInfo.nObj2Lines >= 3 && n < 3)
314 {
316 n++;
317 }
318
319 if(aEdgeInfo.nObj2Lines >= 2 && n < 3)
320 {
322 n++;
323 }
324 }
325 else if(eKind == SdrEdgeKind::ThreeLines)
326 {
327 bool bHor1 = aEdgeInfo.nAngle1 == 0 || aEdgeInfo.nAngle1 == 18000;
328 bool bHor2 = aEdgeInfo.nAngle2 == 0 || aEdgeInfo.nAngle2 == 18000;
329
330 n = 2;
331 nVals[0] = bHor1 ? aEdgeInfo.aObj1Line2.X() : aEdgeInfo.aObj1Line2.Y();
332 nVals[1] = bHor2 ? aEdgeInfo.aObj2Line2.X() : aEdgeInfo.aObj2Line2.Y();
333 }
334
335 if(!(n != nValCnt || nVals[0] != nVal1 || nVals[1] != nVal2 || nVals[2] != nVal3))
336 return;
337
338 // Here no more notifying is necessary, just local changes are OK.
339 if(n != nValCnt)
340 {
342 }
343
344 if(nVals[0] != nVal1)
345 {
347 }
348
349 if(nVals[1] != nVal2)
350 {
352 }
353
354 if(nVals[2] != nVal3)
355 {
357 }
358
359 if(n < 3)
360 {
362 }
363
364 if(n < 2)
365 {
367 }
368
369 if(n < 1)
370 {
372 }
373}
374
376{
377 // #i54102# allow rotation, mirror and shear
378 rInfo.bRotateFreeAllowed = true;
379 rInfo.bRotate90Allowed = true;
380 rInfo.bMirrorFreeAllowed = true;
381 rInfo.bMirror45Allowed = true;
382 rInfo.bMirror90Allowed = true;
383 rInfo.bTransparenceAllowed = false;
384 rInfo.bShearAllowed = true;
385 rInfo.bEdgeRadiusAllowed = false;
386 bool bCanConv=!HasText() || ImpCanConvTextToCurve();
387 rInfo.bCanConvToPath=bCanConv;
388 rInfo.bCanConvToPoly=bCanConv;
390}
391
393{
394 return SdrObjKind::Edge;
395}
396
398{
400 {
401 const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
402 }
403
405}
406
408{
410 {
411 const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
412 }
413
415}
416
418{
419 maSnapRect=pEdgeTrack->GetBoundRect();
420}
421
423{
424 rRect=GetSnapRect();
425}
426
428{
429 Point aPt;
430 sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
431 if (nPointCount>0)
432 {
433 Point aOfs = GetSnapRect().Center();
434 if (nNum==2 && GetConnectedNode(true)==nullptr) aPt=(*pEdgeTrack)[0];
435 else if (nNum==3 && GetConnectedNode(false)==nullptr) aPt=(*pEdgeTrack)[nPointCount-1];
436 else {
437 if ((nPointCount & 1) ==1) {
438 aPt=(*pEdgeTrack)[nPointCount/2];
439 } else {
440 Point aPt1((*pEdgeTrack)[nPointCount/2-1]);
441 Point aPt2((*pEdgeTrack)[nPointCount/2]);
442 aPt1+=aPt2;
443 aPt1.setX( aPt1.X() / 2 );
444 aPt1.setY( aPt1.Y() / 2 );
445 aPt=aPt1;
446 }
447 }
448 aPt-=aOfs;
449 }
450 SdrGluePoint aGP(aPt);
451 aGP.SetPercent(false);
452 return aGP;
453}
454
456{
457 return GetVertexGluePoint(nNum);
458}
459
461{
462 return nullptr; // no user defined gluepoints for connectors
463}
464
466{
467 return nullptr; // no user defined gluepoints for connectors
468}
469
470void SdrEdgeObj::ConnectToNode(bool bTail1, SdrObject* pObj)
471{
472 SdrObjConnection& rCon=GetConnection(bTail1);
473 DisconnectFromNode(bTail1);
474 if (pObj!=nullptr) {
475 pObj->AddListener(*this);
476 rCon.pObj=pObj;
477
478 // #i120437# If connection is set, reset bEdgeTrackUserDefined
479 bEdgeTrackUserDefined = false;
480
482 }
483}
484
486{
487 SdrObjConnection& rCon=GetConnection(bTail1);
488 if (rCon.pObj!=nullptr) {
489 rCon.pObj->RemoveListener(*this);
490 rCon.pObj=nullptr;
491 }
492}
493
495{
496 SdrObject* pObj(GetConnection(bTail1).pObj);
497
498 if(nullptr != pObj
499 && (pObj->getSdrPageFromSdrObject() != getSdrPageFromSdrObject() || !pObj->IsInserted()))
500 {
501 pObj = nullptr;
502 }
503
504 return pObj;
505}
506
507bool SdrEdgeObj::CheckNodeConnection(bool bTail1) const
508{
509 bool bRet = false;
510 const SdrObjConnection& rCon=GetConnection(bTail1);
511 sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
512
513 if(nullptr != rCon.pObj && rCon.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject() && 0 != nPointCount)
514 {
515 const SdrGluePointList* pGPL=rCon.pObj->GetGluePointList();
516 sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
517 sal_uInt16 nGesAnz=nGluePointCnt+8;
518 Point aTail(bTail1 ? (*pEdgeTrack)[0] : (*pEdgeTrack)[sal_uInt16(nPointCount-1)]);
519 for (sal_uInt16 i=0; i<nGesAnz && !bRet; i++) {
520 if (i<nGluePointCnt) { // UserDefined
521 bRet=aTail==(*pGPL)[i].GetAbsolutePos(*rCon.pObj);
522 } else if (i<nGluePointCnt+4) { // Vertex
523 SdrGluePoint aPt(rCon.pObj->GetVertexGluePoint(i-nGluePointCnt));
524 bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
525 } else { // Corner
526 SdrGluePoint aPt(rCon.pObj->GetCornerGluePoint(i-nGluePointCnt-4));
527 bRet=aTail==aPt.GetAbsolutePos(*rCon.pObj);
528 }
529 }
530 }
531 return bRet;
532}
533
534void SdrEdgeObj::ImpSetTailPoint(bool bTail1, const Point& rPt)
535{
536 sal_uInt16 nPointCount=pEdgeTrack->GetPointCount();
537 if (nPointCount==0) {
538 (*pEdgeTrack)[0]=rPt;
539 (*pEdgeTrack)[1]=rPt;
540 } else if (nPointCount==1) {
541 if (!bTail1) (*pEdgeTrack)[1]=rPt;
542 else { (*pEdgeTrack)[1]=(*pEdgeTrack)[0]; (*pEdgeTrack)[0]=rPt; }
543 } else {
544 if (!bTail1) (*pEdgeTrack)[sal_uInt16(nPointCount-1)]=rPt;
545 else (*pEdgeTrack)[0]=rPt;
546 }
549}
550
552{
553 if ( !bEdgeTrackUserDefined || !getSdrModelFromSdrObject().isLocked() )
554 bEdgeTrackDirty = true;
555}
556
558{
559 if (bEdgeTrackDirty && getSdrModelFromSdrObject().isLocked())
560 {
562 }
563}
564
566{
567 // #i120437# if bEdgeTrackUserDefined, do not recalculate
569 {
570 return;
571 }
572
573 // #i120437# also not when model locked during import, but remember
574 if(getSdrModelFromSdrObject().isLocked())
575 {
576 mbSuppressed = true;
577 return;
578 }
579
580 // #i110649#
582 {
583 // This object is involved into another ImpRecalcEdgeTrack() call
584 // from another SdrEdgeObj. Do not calculate again to avoid loop.
585 // Also, do not change bEdgeTrackDirty so that it gets recalculated
586 // later at the first non-looping call.
587 }
588 else
589 {
590 // To not run in a depth loop, use a coloring algorithm on
591 // SdrEdgeObj BoundRect calculations
593
594 if(mbSuppressed)
595 {
596 // #i123048# If layouting was ever suppressed, it needs to be done once
597 // and the attr need to be set at EdgeInfo, else these attr *will be lost*
598 // in the following call to ImpSetEdgeInfoToAttr() since they were never
599 // set before (!)
602 mbSuppressed = false;
603 }
604
605 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
608 ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
609 bEdgeTrackDirty=false;
610
611 // Only redraw here, no object change
613
615
617 }
618}
619
621{
622 if (pObj==nullptr) return SdrEscapeDirection::ALL;
623 tools::Rectangle aR(pObj->GetSnapRect());
624 tools::Long dxl=rPt.X()-aR.Left();
625 tools::Long dyo=rPt.Y()-aR.Top();
626 tools::Long dxr=aR.Right()-rPt.X();
627 tools::Long dyu=aR.Bottom()-rPt.Y();
628 bool bxMitt=std::abs(dxl-dxr)<2;
629 bool byMitt=std::abs(dyo-dyu)<2;
630 tools::Long dx=std::min(dxl,dxr);
631 tools::Long dy=std::min(dyo,dyu);
632 bool bDiag=std::abs(dx-dy)<2;
633 if (bxMitt && byMitt) return SdrEscapeDirection::ALL; // in the center
634 if (bDiag) { // diagonally
636 if (byMitt) nRet|=SdrEscapeDirection::VERT;
637 if (bxMitt) nRet|=SdrEscapeDirection::HORZ;
638 if (dxl<dxr) { // left
641 } else { // right
644 }
645 return nRet;
646 }
647 if (dx<dy) { // horizontal
648 if (bxMitt) return SdrEscapeDirection::HORZ;
649 if (dxl<dxr) return SdrEscapeDirection::LEFT;
650 else return SdrEscapeDirection::RIGHT;
651 } else { // vertical
652 if (byMitt) return SdrEscapeDirection::VERT;
653 if (dyo<dyu) return SdrEscapeDirection::TOP;
654 else return SdrEscapeDirection::BOTTOM;
655 }
656}
657
658XPolygon SdrEdgeObj::ImpCalcObjToCenter(const Point& rStPt, tools::Long nEscAngle, const tools::Rectangle& rRect, const Point& rMeeting)
659{
660 XPolygon aXP;
661 aXP.Insert(XPOLY_APPEND,rStPt,PolyFlags::Normal);
662 bool bRts=nEscAngle==0;
663 bool bObn=nEscAngle==9000;
664 bool bLks=nEscAngle==18000;
665 bool bUnt=nEscAngle==27000;
666
667 Point aP1(rStPt); // mandatory difference first,...
668 if (bLks) aP1.setX(rRect.Left() );
669 if (bRts) aP1.setX(rRect.Right() );
670 if (bObn) aP1.setY(rRect.Top() );
671 if (bUnt) aP1.setY(rRect.Bottom() );
672
673 Point aP2(aP1); // ...now increase to Meeting height, if necessary
674 if (bLks && rMeeting.X()<=aP2.X()) aP2.setX(rMeeting.X() );
675 if (bRts && rMeeting.X()>=aP2.X()) aP2.setX(rMeeting.X() );
676 if (bObn && rMeeting.Y()<=aP2.Y()) aP2.setY(rMeeting.Y() );
677 if (bUnt && rMeeting.Y()>=aP2.Y()) aP2.setY(rMeeting.Y() );
678 aXP.Insert(XPOLY_APPEND,aP2,PolyFlags::Normal);
679
680 Point aP3(aP2);
681 if ((bLks && rMeeting.X()>aP2.X()) || (bRts && rMeeting.X()<aP2.X())) { // around
682 if (rMeeting.Y()<aP2.Y()) {
683 aP3.setY(rRect.Top() );
684 if (rMeeting.Y()<aP3.Y()) aP3.setY(rMeeting.Y() );
685 } else {
686 aP3.setY(rRect.Bottom() );
687 if (rMeeting.Y()>aP3.Y()) aP3.setY(rMeeting.Y() );
688 }
689 aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
690 if (aP3.Y()!=rMeeting.Y()) {
691 aP3.setX(rMeeting.X() );
692 aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
693 }
694 }
695 if ((bObn && rMeeting.Y()>aP2.Y()) || (bUnt && rMeeting.Y()<aP2.Y())) { // around
696 if (rMeeting.X()<aP2.X()) {
697 aP3.setX(rRect.Left() );
698 if (rMeeting.X()<aP3.X()) aP3.setX(rMeeting.X() );
699 } else {
700 aP3.setX(rRect.Right() );
701 if (rMeeting.X()>aP3.X()) aP3.setX(rMeeting.X() );
702 }
703 aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
704 if (aP3.X()!=rMeeting.X()) {
705 aP3.setY(rMeeting.Y() );
706 aXP.Insert(XPOLY_APPEND,aP3,PolyFlags::Normal);
707 }
708 }
709#ifdef DBG_UTIL
710 if (aXP.GetPointCount()>4) {
711 OSL_FAIL("SdrEdgeObj::ImpCalcObjToCenter(): Polygon has more than 4 points!");
712 }
713#endif
714 return aXP;
715}
716
718{
719 Point aPt1,aPt2;
720 SdrGluePoint aGP1,aGP2;
722 tools::Rectangle aBoundRect1;
723 tools::Rectangle aBoundRect2;
724 tools::Rectangle aBewareRect1;
725 tools::Rectangle aBewareRect2;
726 // first, get the old corner points
727 if (rTrack0.GetPointCount()!=0) {
728 aPt1=rTrack0[0];
729 sal_uInt16 nSiz=rTrack0.GetPointCount();
730 nSiz--;
731 aPt2=rTrack0[nSiz];
732 }
733 else
734 {
735 auto aRectangle = getOutRectangle();
736 if (!aRectangle.IsEmpty()) {
737 aPt1 = aRectangle.TopLeft();
738 aPt2 = aRectangle.BottomRight();
739 }
740 }
741
742 // #i54102# To allow interactive preview, do also if not inserted
743 const bool bCon1(nullptr != rCon1.pObj && rCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
744 const bool bCon2(nullptr != rCon2.pObj && rCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
746
747 if (bCon1)
748 {
749 if (rCon1.pObj==static_cast<SdrObject const *>(this))
750 {
751 // check, just in case
752 aBoundRect1 = getOutRectangle();
753 }
754 else
755 {
756 aBoundRect1 = rCon1.pObj->GetCurrentBoundRect();
757 }
758
759 aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
760 aBewareRect1=aBoundRect1;
761 sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE1HORZDIST).GetValue();
762 sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE1VERTDIST).GetValue();
763 aBewareRect1.AdjustLeft( -nH );
764 aBewareRect1.AdjustRight(nH );
765 aBewareRect1.AdjustTop( -nV );
766 aBewareRect1.AdjustBottom(nV );
767 }
768 else
769 {
770 aBoundRect1=tools::Rectangle(aPt1,aPt1);
771 aBoundRect1.Move(rCon1.aObjOfs.X(),rCon1.aObjOfs.Y());
772 aBewareRect1=aBoundRect1;
773 }
774
775 if (bCon2)
776 {
777 if (rCon2.pObj==static_cast<SdrObject const *>(this))
778 { // check, just in case
779 aBoundRect2 = getOutRectangle();
780 }
781 else
782 {
783 aBoundRect2 = rCon2.pObj->GetCurrentBoundRect();
784 }
785
786 aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
787 aBewareRect2=aBoundRect2;
788 sal_Int32 nH = rSet.Get(SDRATTR_EDGENODE2HORZDIST).GetValue();
789 sal_Int32 nV = rSet.Get(SDRATTR_EDGENODE2VERTDIST).GetValue();
790 aBewareRect2.AdjustLeft( -nH );
791 aBewareRect2.AdjustRight(nH );
792 aBewareRect2.AdjustTop( -nV );
793 aBewareRect2.AdjustBottom(nV );
794 }
795 else
796 {
797 aBoundRect2=tools::Rectangle(aPt2,aPt2);
798 aBoundRect2.Move(rCon2.aObjOfs.X(),rCon2.aObjOfs.Y());
799 aBewareRect2=aBoundRect2;
800 }
801
802 XPolygon aBestXP;
803 sal_uIntPtr nBestQual=0xFFFFFFFF;
804 SdrEdgeInfoRec aBestInfo;
805 bool bAuto1=bCon1 && rCon1.bBestVertex;
806 bool bAuto2=bCon2 && rCon2.bBestVertex;
807 if (bAuto1) rCon1.bAutoVertex=true;
808 if (bAuto2) rCon2.bAutoVertex=true;
809 sal_uInt16 nBestAuto1=0;
810 sal_uInt16 nBestAuto2=0;
811 sal_uInt16 nCount1=bAuto1 ? 4 : 1;
812 sal_uInt16 nCount2=bAuto2 ? 4 : 1;
813
814 for (sal_uInt16 nNum1=0; nNum1<nCount1; nNum1++)
815 {
816 if (bAuto1) rCon1.nConId=nNum1;
817 if (bCon1 && rCon1.TakeGluePoint(aGP1))
818 {
819 aPt1=aGP1.GetPos();
820 nEsc1=aGP1.GetEscDir();
821 if (nEsc1==SdrEscapeDirection::SMART) nEsc1=ImpCalcEscAngle(rCon1.pObj,aPt1-rCon1.aObjOfs);
822 }
823 for (sal_uInt16 nNum2=0; nNum2<nCount2; nNum2++)
824 {
825 if (bAuto2) rCon2.nConId=nNum2;
826 if (bCon2 && rCon2.TakeGluePoint(aGP2))
827 {
828 aPt2=aGP2.GetPos();
829 nEsc2=aGP2.GetEscDir();
830 if (nEsc2==SdrEscapeDirection::SMART) nEsc2=ImpCalcEscAngle(rCon2.pObj,aPt2-rCon2.aObjOfs);
831 }
832 for (tools::Long nA1=0; nA1<36000; nA1+=9000)
833 {
835 for (tools::Long nA2=0; nA2<36000; nA2+=9000)
836 {
838 if ((nEsc1&nE1) && (nEsc2&nE2))
839 {
840 sal_uIntPtr nQual=0;
841 SdrEdgeInfoRec aInfo;
842 if (pInfo!=nullptr) aInfo=*pInfo;
843 XPolygon aXP(ImpCalcEdgeTrack(aPt1,nA1,aBoundRect1,aBewareRect1,aPt2,nA2,aBoundRect2,aBewareRect2,&nQual,&aInfo));
844 if (nQual<nBestQual)
845 {
846 aBestXP=std::move(aXP);
847 nBestQual=nQual;
848 aBestInfo=aInfo;
849 nBestAuto1=nNum1;
850 nBestAuto2=nNum2;
851 }
852 }
853 }
854 }
855 }
856 }
857 if (bAuto1) rCon1.nConId=nBestAuto1;
858 if (bAuto2) rCon2.nConId=nBestAuto2;
859 if (pInfo!=nullptr) *pInfo=aBestInfo;
860 return aBestXP;
861}
862
863XPolygon SdrEdgeObj::ImpCalcEdgeTrack(const Point& rPt1, tools::Long nAngle1, const tools::Rectangle& rBoundRect1, const tools::Rectangle& rBewareRect1,
864 const Point& rPt2, tools::Long nAngle2, const tools::Rectangle& rBoundRect2, const tools::Rectangle& rBewareRect2,
865 sal_uIntPtr* pnQuality, SdrEdgeInfoRec* pInfo) const
866{
868 bool bRts1=nAngle1==0;
869 bool bObn1=nAngle1==9000;
870 bool bLks1=nAngle1==18000;
871 bool bUnt1=nAngle1==27000;
872 bool bHor1=bLks1 || bRts1;
873 bool bVer1=bObn1 || bUnt1;
874 bool bRts2=nAngle2==0;
875 bool bObn2=nAngle2==9000;
876 bool bLks2=nAngle2==18000;
877 bool bUnt2=nAngle2==27000;
878 bool bHor2=bLks2 || bRts2;
879 bool bVer2=bObn2 || bUnt2;
880 bool bInfo=pInfo!=nullptr;
881 if (bInfo) {
882 pInfo->nAngle1=nAngle1;
883 pInfo->nAngle2=nAngle2;
884 pInfo->nObj1Lines=1;
885 pInfo->nObj2Lines=1;
886 pInfo->nMiddleLine=0xFFFF;
887 }
888 Point aPt1(rPt1);
889 Point aPt2(rPt2);
890 tools::Rectangle aBoundRect1 (rBoundRect1 );
891 tools::Rectangle aBoundRect2 (rBoundRect2 );
892 tools::Rectangle aBewareRect1(rBewareRect1);
893 tools::Rectangle aBewareRect2(rBewareRect2);
894 Point aMeeting((aPt1.X()+aPt2.X()+1)/2,(aPt1.Y()+aPt2.Y()+1)/2);
895 if (eKind==SdrEdgeKind::OneLine) {
896 XPolygon aXP(2);
897 aXP[0]=rPt1;
898 aXP[1]=rPt2;
899 if (pnQuality!=nullptr) {
900 *pnQuality=std::abs(rPt1.X()-rPt2.X())+std::abs(rPt1.Y()-rPt2.Y());
901 }
902 return aXP;
903 } else if (eKind==SdrEdgeKind::ThreeLines) {
904 XPolygon aXP(4);
905 aXP[0]=rPt1;
906 aXP[1]=rPt1;
907 aXP[2]=rPt2;
908 aXP[3]=rPt2;
909 if (bRts1) aXP[1].setX(aBewareRect1.Right() ); //+=500;
910 if (bObn1) aXP[1].setY(aBewareRect1.Top() ); //-=500;
911 if (bLks1) aXP[1].setX(aBewareRect1.Left() ); //-=500;
912 if (bUnt1) aXP[1].setY(aBewareRect1.Bottom() ); //+=500;
913 if (bRts2) aXP[2].setX(aBewareRect2.Right() ); //+=500;
914 if (bObn2) aXP[2].setY(aBewareRect2.Top() ); //-=500;
915 if (bLks2) aXP[2].setX(aBewareRect2.Left() ); //-=500;
916 if (bUnt2) aXP[2].setY(aBewareRect2.Bottom() ); //+=500;
917 if (pnQuality!=nullptr) {
918 tools::Long nQ=std::abs(aXP[1].X()-aXP[0].X())+std::abs(aXP[1].Y()-aXP[0].Y());
919 nQ+=std::abs(aXP[2].X()-aXP[1].X())+std::abs(aXP[2].Y()-aXP[1].Y());
920 nQ+=std::abs(aXP[3].X()-aXP[2].X())+std::abs(aXP[3].Y()-aXP[2].Y());
921 *pnQuality=nQ;
922 }
923 if (bInfo) {
924 pInfo->nObj1Lines=2;
925 pInfo->nObj2Lines=2;
926 if (bHor1) {
927 aXP[1].AdjustX(pInfo->aObj1Line2.X() );
928 } else {
929 aXP[1].AdjustY(pInfo->aObj1Line2.Y() );
930 }
931 if (bHor2) {
932 aXP[2].AdjustX(pInfo->aObj2Line2.X() );
933 } else {
934 aXP[2].AdjustY(pInfo->aObj2Line2.Y() );
935 }
936 }
937 return aXP;
938 }
939 sal_uInt16 nIntersections=0;
940 {
941 Point aC1(aBewareRect1.Center());
942 Point aC2(aBewareRect2.Center());
943 if (aBewareRect1.Left()<=aBewareRect2.Right() && aBewareRect1.Right()>=aBewareRect2.Left()) {
944 // overlapping on the x axis
945 tools::Long n1=std::max(aBewareRect1.Left(),aBewareRect2.Left());
946 tools::Long n2=std::min(aBewareRect1.Right(),aBewareRect2.Right());
947 aMeeting.setX((n1+n2+1)/2 );
948 } else {
949 // otherwise the center point of the empty space
950 if (aC1.X()<aC2.X()) {
951 aMeeting.setX((aBewareRect1.Right()+aBewareRect2.Left()+1)/2 );
952 } else {
953 aMeeting.setX((aBewareRect1.Left()+aBewareRect2.Right()+1)/2 );
954 }
955 }
956 if (aBewareRect1.Top()<=aBewareRect2.Bottom() && aBewareRect1.Bottom()>=aBewareRect2.Top()) {
957 // overlapping on the x axis
958 tools::Long n1=std::max(aBewareRect1.Top(),aBewareRect2.Top());
959 tools::Long n2=std::min(aBewareRect1.Bottom(),aBewareRect2.Bottom());
960 aMeeting.setY((n1+n2+1)/2 );
961 } else {
962 // otherwise the center point of the empty space
963 if (aC1.Y()<aC2.Y()) {
964 aMeeting.setY((aBewareRect1.Bottom()+aBewareRect2.Top()+1)/2 );
965 } else {
966 aMeeting.setY((aBewareRect1.Top()+aBewareRect2.Bottom()+1)/2 );
967 }
968 }
969 // Here, there are three cases:
970 // 1. both go into the same direction
971 // 2. both go into opposite directions
972 // 3. one is vertical, the other is horizontal
973 tools::Long nXMin=std::min(aBewareRect1.Left(),aBewareRect2.Left());
974 tools::Long nXMax=std::max(aBewareRect1.Right(),aBewareRect2.Right());
975 tools::Long nYMin=std::min(aBewareRect1.Top(),aBewareRect2.Top());
976 tools::Long nYMax=std::max(aBewareRect1.Bottom(),aBewareRect2.Bottom());
977 bool bBewareOverlap=aBewareRect1.Right()>aBewareRect2.Left() && aBewareRect1.Left()<aBewareRect2.Right() &&
978 aBewareRect1.Bottom()>aBewareRect2.Top() && aBewareRect1.Top()<aBewareRect2.Bottom();
979 unsigned nMainCase=3;
980 if (nAngle1==nAngle2) nMainCase=1;
981 else if ((bHor1 && bHor2) || (bVer1 && bVer2)) nMainCase=2;
982 if (nMainCase==1) { // case 1 (both go in one direction) is possible
983 if (bVer1) aMeeting.setX((aPt1.X()+aPt2.X()+1)/2 ); // Here, this is better than
984 if (bHor1) aMeeting.setY((aPt1.Y()+aPt2.Y()+1)/2 ); // using center point of empty space
985 // bX1Ok means that the vertical exiting Obj1 doesn't conflict with Obj2, ...
986 bool bX1Ok=aPt1.X()<=aBewareRect2.Left() || aPt1.X()>=aBewareRect2.Right();
987 bool bX2Ok=aPt2.X()<=aBewareRect1.Left() || aPt2.X()>=aBewareRect1.Right();
988 bool bY1Ok=aPt1.Y()<=aBewareRect2.Top() || aPt1.Y()>=aBewareRect2.Bottom();
989 bool bY2Ok=aPt2.Y()<=aBewareRect1.Top() || aPt2.Y()>=aBewareRect1.Bottom();
990 if (bLks1 && (bY1Ok || aBewareRect1.Left()<aBewareRect2.Right()) && (bY2Ok || aBewareRect2.Left()<aBewareRect1.Right())) {
991 aMeeting.setX(nXMin );
992 }
993 if (bRts1 && (bY1Ok || aBewareRect1.Right()>aBewareRect2.Left()) && (bY2Ok || aBewareRect2.Right()>aBewareRect1.Left())) {
994 aMeeting.setX(nXMax );
995 }
996 if (bObn1 && (bX1Ok || aBewareRect1.Top()<aBewareRect2.Bottom()) && (bX2Ok || aBewareRect2.Top()<aBewareRect1.Bottom())) {
997 aMeeting.setY(nYMin );
998 }
999 if (bUnt1 && (bX1Ok || aBewareRect1.Bottom()>aBewareRect2.Top()) && (bX2Ok || aBewareRect2.Bottom()>aBewareRect1.Top())) {
1000 aMeeting.setY(nYMax );
1001 }
1002 } else if (nMainCase==2) {
1003 // case 2:
1004 if (bHor1) { // both horizontal
1005 /* 9 sub-cases:
1006 (legend: line exits to the left (-|), right (|-))
1007
1008 2.1: Facing; overlap only on y axis
1009 * * *
1010 |--| *
1011 * * *
1012
1013 2.2, 2.3: Facing, offset vertically; no overlap on either
1014 axis
1015 |- * * * * *
1016 * -| * * -| *
1017 * * * , * * *
1018
1019 2.4, 2.5: One below the other; overlap only on y axis
1020 * |- * * * *
1021 * -| * * -| *
1022 * * * , * |- *
1023
1024 2.6, 2.7: Not facing, offset vertically; no overlap on either
1025 axis
1026 * * |- * * *
1027 * -| * * -| *
1028 * * * , * * |-
1029
1030 2.8: Not facing; overlap only on y axis
1031 * * *
1032 * -| |-
1033 * * *
1034
1035 2.9: The objects's BewareRects overlap on x and y axis
1036
1037 These cases, with some modifications are also valid for
1038 horizontal line exits.
1039 Cases 2.1 through 2.7 are covered well enough with the
1040 default meetings. Only for cases 2.8 and 2.9 do we determine
1041 special meeting points here.
1042 */
1043
1044 // normalization; be aR1 the one exiting to the right,
1045 // be aR2 the one exiting to the left
1046 tools::Rectangle aBewR1(bRts1 ? aBewareRect1 : aBewareRect2);
1047 tools::Rectangle aBewR2(bRts1 ? aBewareRect2 : aBewareRect1);
1048 tools::Rectangle aBndR1(bRts1 ? aBoundRect1 : aBoundRect2);
1049 tools::Rectangle aBndR2(bRts1 ? aBoundRect2 : aBoundRect1);
1050 if (aBewR1.Bottom()>aBewR2.Top() && aBewR1.Top()<aBewR2.Bottom()) {
1051 // overlap on y axis; cases 2.1, 2.8, 2.9
1052 if (aBewR1.Right()>aBewR2.Left()) {
1053 /* Cases 2.8, 2.9:
1054 Case 2.8: always going around on the outside
1055 (bDirect=false).
1056
1057 Case 2.9 could also be a direct connection (in the
1058 case that the BewareRects overlap only slightly and
1059 the BoundRects don't overlap at all and if the
1060 line exits would otherwise violate the respective
1061 other object's BewareRect).
1062 */
1063 bool bCase29Direct = false;
1064 bool bCase29=aBewR1.Right()>aBewR2.Left();
1065 if (aBndR1.Right()<=aBndR2.Left()) { // case 2.9 without BoundRect overlap
1066 if ((aPt1.Y()>aBewareRect2.Top() && aPt1.Y()<aBewareRect2.Bottom()) ||
1067 (aPt2.Y()>aBewareRect1.Top() && aPt2.Y()<aBewareRect1.Bottom())) {
1068 bCase29Direct = true;
1069 }
1070 }
1071 if (!bCase29Direct) {
1072 bool bObenLang=std::abs(nYMin-aMeeting.Y())<=std::abs(nYMax-aMeeting.Y());
1073 if (bObenLang) {
1074 aMeeting.setY(nYMin );
1075 } else {
1076 aMeeting.setY(nYMax );
1077 }
1078 if (bCase29) {
1079 // now make sure that the surrounded object
1080 // isn't traversed
1081 if ((aBewR1.Center().Y()<aBewR2.Center().Y()) != bObenLang) {
1082 aMeeting.setX(aBewR2.Right() );
1083 } else {
1084 aMeeting.setX(aBewR1.Left() );
1085 }
1086 }
1087 } else {
1088 // We need a direct connection (3-line Z connection),
1089 // because we have to violate the BewareRects.
1090 // Use rule of three to scale down the BewareRects.
1091 tools::Long nWant1=aBewR1.Right()-aBndR1.Right(); // distance at Obj1
1092 tools::Long nWant2=aBndR2.Left()-aBewR2.Left(); // distance at Obj2
1093 tools::Long nSpace=aBndR2.Left()-aBndR1.Right(); // available space
1094 tools::Long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
1095 tools::Long nGet2=nSpace-nGet1;
1096 if (bRts1) { // revert normalization
1097 aBewareRect1.AdjustRight(nGet1-nWant1 );
1098 aBewareRect2.AdjustLeft( -(nGet2-nWant2) );
1099 } else {
1100 aBewareRect2.AdjustRight(nGet1-nWant1 );
1101 aBewareRect1.AdjustLeft( -(nGet2-nWant2) );
1102 }
1103 nIntersections++; // lower quality
1104 }
1105 }
1106 }
1107 } else if (bVer1) { // both horizontal
1108 tools::Rectangle aBewR1(bUnt1 ? aBewareRect1 : aBewareRect2);
1109 tools::Rectangle aBewR2(bUnt1 ? aBewareRect2 : aBewareRect1);
1110 tools::Rectangle aBndR1(bUnt1 ? aBoundRect1 : aBoundRect2);
1111 tools::Rectangle aBndR2(bUnt1 ? aBoundRect2 : aBoundRect1);
1112 if (aBewR1.Right()>aBewR2.Left() && aBewR1.Left()<aBewR2.Right()) {
1113 // overlap on y axis; cases 2.1, 2.8, 2.9
1114 if (aBewR1.Bottom()>aBewR2.Top()) {
1115 /* Cases 2.8, 2.9
1116 Case 2.8 always going around on the outside (bDirect=false).
1117
1118 Case 2.9 could also be a direct connection (in the
1119 case that the BewareRects overlap only slightly and
1120 the BoundRects don't overlap at all and if the
1121 line exits would otherwise violate the respective
1122 other object's BewareRect).
1123 */
1124 bool bCase29Direct = false;
1125 bool bCase29=aBewR1.Bottom()>aBewR2.Top();
1126 if (aBndR1.Bottom()<=aBndR2.Top()) { // case 2.9 without BoundRect overlap
1127 if ((aPt1.X()>aBewareRect2.Left() && aPt1.X()<aBewareRect2.Right()) ||
1128 (aPt2.X()>aBewareRect1.Left() && aPt2.X()<aBewareRect1.Right())) {
1129 bCase29Direct = true;
1130 }
1131 }
1132 if (!bCase29Direct) {
1133 bool bLinksLang=std::abs(nXMin-aMeeting.X())<=std::abs(nXMax-aMeeting.X());
1134 if (bLinksLang) {
1135 aMeeting.setX(nXMin );
1136 } else {
1137 aMeeting.setX(nXMax );
1138 }
1139 if (bCase29) {
1140 // now make sure that the surrounded object
1141 // isn't traversed
1142 if ((aBewR1.Center().X()<aBewR2.Center().X()) != bLinksLang) {
1143 aMeeting.setY(aBewR2.Bottom() );
1144 } else {
1145 aMeeting.setY(aBewR1.Top() );
1146 }
1147 }
1148 } else {
1149 // We need a direct connection (3-line Z connection),
1150 // because we have to violate the BewareRects.
1151 // Use rule of three to scale down the BewareRects.
1152 tools::Long nWant1=aBewR1.Bottom()-aBndR1.Bottom(); // difference at Obj1
1153 tools::Long nWant2=aBndR2.Top()-aBewR2.Top(); // difference at Obj2
1154 tools::Long nSpace=aBndR2.Top()-aBndR1.Bottom(); // available space
1155 tools::Long nGet1=BigMulDiv(nWant1,nSpace,nWant1+nWant2);
1156 tools::Long nGet2=nSpace-nGet1;
1157 if (bUnt1) { // revert normalization
1158 aBewareRect1.AdjustBottom(nGet1-nWant1 );
1159 aBewareRect2.AdjustTop( -(nGet2-nWant2) );
1160 } else {
1161 aBewareRect2.AdjustBottom(nGet1-nWant1 );
1162 aBewareRect1.AdjustTop( -(nGet2-nWant2) );
1163 }
1164 nIntersections++; // lower quality
1165 }
1166 }
1167 }
1168 }
1169 } else if (nMainCase==3) { // case 3: one horizontal, the other vertical
1170 /* legend:
1171 The line exits to the:
1172 -| left
1173
1174 |- right
1175
1176 _|_ top
1177
1178 T bottom
1179
1180 * . * . * -- no overlap, at most might touch
1181 . . . . . -- overlap
1182 * . |- . * -- same height
1183 . . . . . -- overlap
1184 * . * . * -- no overlap, at most might touch
1185
1186 Overall, there are 96 possible constellations, some of these can't even
1187 be unambiguously assigned to a certain case/method of handling.
1188
1189
1190 3.1: All those constellations that are covered reasonably well
1191 by the default MeetingPoint (20+12).
1192
1193 T T T . _|_ _|_ . T T T these 12 * . * T * * . * . * * T * . * * . * . *
1194 . . . . _|_ _|_ . . . . constellations . . . . . . . . . T . . . . . T . . . .
1195 * . |- . * * . -| . * are covered * . |- . _|_ * . |- . T _|_ . -| . * T . -| . *
1196 . . . . T T . . . . only in . . . . _|_ . . . . . _|_ . . . . . . . . .
1197 _|__|__|_ . T T . _|__|__|_ part: * . * _|_ * * . * . * * _|_ * . * * . * . *
1198
1199 The last 16 of these cases can be excluded, if the objects face each other openly.
1200
1201
1202 3.2: The objects face each other openly, thus a connection using only two lines is possible (4+20);
1203 This case is priority #1.
1204 * . * . T T . * . * these 20 * . * T * * T * . * * . * . * * . * . *
1205 . . . . . . . . . . constellations . . . T T T T . . . . . . . . . . . . .
1206 * . |- . * * . -| . * are covered * . |-_|__|_ _|__|_-| . * * . |- T T T T -| . *
1207 . . . . . . . . . . only in . . . _|__|_ _|__|_ . . . . . . . . . . . . .
1208 * . * . _|_ _|_ . * . * part: * . * _|_ * * _|_ * . * * . * . * * . * . *
1209
1210 3.3: The line exits point away from the other object or miss its back (52+4).
1211 _|__|__|__|_ * * _|__|__|__|_ * . . . * * . * . * these 4 * . * . * * . * . *
1212 _|__|__|__|_ . . _|__|__|__|_ T T T . . . . T T T constellations . . . T . . T . . .
1213 _|__|_ |- . * * . -| _|__|_ T T |- . * * . -| T T are covered * . |- . * * . -| . *
1214 _|__|__|_ . . . . _|__|__|_ T T T T . . T T T T only in . . . _|_ . . _|_ . . .
1215 * . * . * * . * . * T T T T * * T T T T part: * . * . * * . * . *
1216 */
1217
1218 // case 3.2
1219 tools::Rectangle aTmpR1(aBewareRect1);
1220 tools::Rectangle aTmpR2(aBewareRect2);
1221 if (bBewareOverlap) {
1222 // overlapping BewareRects: use BoundRects for checking for case 3.2
1223 aTmpR1=aBoundRect1;
1224 aTmpR2=aBoundRect2;
1225 }
1226 if ((((bRts1 && aTmpR1.Right ()<=aPt2.X()) || (bLks1 && aTmpR1.Left()>=aPt2.X())) &&
1227 ((bUnt2 && aTmpR2.Bottom()<=aPt1.Y()) || (bObn2 && aTmpR2.Top ()>=aPt1.Y()))) ||
1228 (((bRts2 && aTmpR2.Right ()<=aPt1.X()) || (bLks2 && aTmpR2.Left()>=aPt1.X())) &&
1229 ((bUnt1 && aTmpR1.Bottom()<=aPt2.Y()) || (bObn1 && aTmpR1.Top ()>=aPt2.Y())))) {
1230 // case 3.2 applies: connector with only 2 lines
1231 if (bHor1) {
1232 aMeeting.setX(aPt2.X() );
1233 aMeeting.setY(aPt1.Y() );
1234 } else {
1235 aMeeting.setX(aPt1.X() );
1236 aMeeting.setY(aPt2.Y() );
1237 }
1238 // in the case of overlapping BewareRects:
1239 aBewareRect1=aTmpR1;
1240 aBewareRect2=aTmpR2;
1241 } else if ((((bRts1 && aBewareRect1.Right ()>aBewareRect2.Left ()) ||
1242 (bLks1 && aBewareRect1.Left ()<aBewareRect2.Right ())) &&
1243 ((bUnt2 && aBewareRect2.Bottom()>aBewareRect1.Top ()) ||
1244 (bObn2 && aBewareRect2.Top ()<aBewareRect1.Bottom()))) ||
1245 (((bRts2 && aBewareRect2.Right ()>aBewareRect1.Left ()) ||
1246 (bLks2 && aBewareRect2.Left ()<aBewareRect1.Right ())) &&
1247 ((bUnt1 && aBewareRect1.Bottom()>aBewareRect2.Top ()) ||
1248 (bObn1 && aBewareRect1.Top ()<aBewareRect2.Bottom())))) {
1249 // case 3.3
1250 if (bRts1 || bRts2) { aMeeting.setX(nXMax ); }
1251 if (bLks1 || bLks2) { aMeeting.setX(nXMin ); }
1252 if (bUnt1 || bUnt2) { aMeeting.setY(nYMax ); }
1253 if (bObn1 || bObn2) { aMeeting.setY(nYMin ); }
1254 }
1255 }
1256 }
1257
1258 XPolygon aXP1(ImpCalcObjToCenter(aPt1,nAngle1,aBewareRect1,aMeeting));
1259 XPolygon aXP2(ImpCalcObjToCenter(aPt2,nAngle2,aBewareRect2,aMeeting));
1260 sal_uInt16 nXP1Cnt=aXP1.GetPointCount();
1261 sal_uInt16 nXP2Cnt=aXP2.GetPointCount();
1262 if (bInfo) {
1263 pInfo->nObj1Lines=nXP1Cnt; if (nXP1Cnt>1) pInfo->nObj1Lines--;
1264 pInfo->nObj2Lines=nXP2Cnt; if (nXP2Cnt>1) pInfo->nObj2Lines--;
1265 }
1266 Point aEP1(aXP1[nXP1Cnt-1]);
1267 Point aEP2(aXP2[nXP2Cnt-1]);
1268 bool bInsMeetingPoint=aEP1.X()!=aEP2.X() && aEP1.Y()!=aEP2.Y();
1269 bool bHorzE1=aEP1.Y()==aXP1[nXP1Cnt-2].Y(); // is last line of XP1 horizontal?
1270 bool bHorzE2=aEP2.Y()==aXP2[nXP2Cnt-2].Y(); // is last line of XP2 horizontal?
1271 if (aEP1==aEP2 && ((bHorzE1 && bHorzE2 && aEP1.Y()==aEP2.Y()) || (!bHorzE1 && !bHorzE2 && aEP1.X()==aEP2.X()))) {
1272 // special casing 'I' connectors
1273 nXP1Cnt--; aXP1.Remove(nXP1Cnt,1);
1274 nXP2Cnt--; aXP2.Remove(nXP2Cnt,1);
1275 }
1276 if (bInsMeetingPoint) {
1277 aXP1.Insert(XPOLY_APPEND,aMeeting,PolyFlags::Normal);
1278 if (bInfo) {
1279 // Inserting a MeetingPoint adds 2 new lines,
1280 // either might become the center line.
1281 if (pInfo->nObj1Lines==pInfo->nObj2Lines) {
1282 pInfo->nObj1Lines++;
1283 pInfo->nObj2Lines++;
1284 } else {
1285 if (pInfo->nObj1Lines>pInfo->nObj2Lines) {
1286 pInfo->nObj2Lines++;
1287 pInfo->nMiddleLine=nXP1Cnt-1;
1288 } else {
1289 pInfo->nObj1Lines++;
1290 pInfo->nMiddleLine=nXP1Cnt;
1291 }
1292 }
1293 }
1294 } else if (bInfo && aEP1!=aEP2 && nXP1Cnt+nXP2Cnt>=4) {
1295 // By connecting both ends, another line is added, this becomes the center line.
1296 pInfo->nMiddleLine=nXP1Cnt-1;
1297 }
1298 sal_uInt16 nNum=aXP2.GetPointCount();
1299 if (aXP1[nXP1Cnt-1]==aXP2[nXP2Cnt-1] && nXP1Cnt>1 && nXP2Cnt>1) nNum--;
1300 while (nNum>0) {
1301 nNum--;
1302 aXP1.Insert(XPOLY_APPEND,aXP2[nNum],PolyFlags::Normal);
1303 }
1304 sal_uInt16 nPointCount=aXP1.GetPointCount();
1305 char cForm;
1306 if (bInfo || pnQuality!=nullptr) {
1307 if (nPointCount==2) cForm='I';
1308 else if (nPointCount==3) cForm='L';
1309 else if (nPointCount==4) { // Z or U
1310 if (nAngle1==nAngle2) cForm='U';
1311 else cForm='Z';
1312 } else if (nPointCount==6) { // S or C or ...
1313 if (nAngle1!=nAngle2) {
1314 // For type S, line 2 has the same direction as line 4.
1315 // For type C, the opposite is true.
1316 Point aP1(aXP1[1]);
1317 Point aP2(aXP1[2]);
1318 Point aP3(aXP1[3]);
1319 Point aP4(aXP1[4]);
1320 if (aP1.Y()==aP2.Y()) { // else both lines are horizontal
1321 if ((aP1.X()<aP2.X())==(aP3.X()<aP4.X())) cForm='S';
1322 else cForm='C';
1323 } else { // else both lines are vertical
1324 if ((aP1.Y()<aP2.Y())==(aP3.Y()<aP4.Y())) cForm='S';
1325 else cForm='C';
1326 }
1327 } else cForm='4'; // else is case 3 with 5 lines
1328 } else cForm='?';
1329 // more shapes:
1330 if (bInfo) {
1331 if (cForm=='I' || cForm=='L' || cForm=='Z' || cForm=='U') {
1332 pInfo->nObj1Lines=1;
1333 pInfo->nObj2Lines=1;
1334 if (cForm=='Z' || cForm=='U') {
1335 pInfo->nMiddleLine=1;
1336 } else {
1337 pInfo->nMiddleLine=0xFFFF;
1338 }
1339 } else if (cForm=='S' || cForm=='C') {
1340 pInfo->nObj1Lines=2;
1341 pInfo->nObj2Lines=2;
1342 pInfo->nMiddleLine=2;
1343 }
1344 }
1345 }
1346 else
1347 {
1348 cForm = 0;
1349 }
1350 if (pnQuality!=nullptr) {
1351 sal_uIntPtr nQual=0;
1352 sal_uIntPtr nQual0=nQual; // prevent overruns
1353 bool bOverflow = false;
1354 Point aPt0(aXP1[0]);
1355 for (sal_uInt16 nPntNum=1; nPntNum<nPointCount; nPntNum++) {
1356 Point aPt1b(aXP1[nPntNum]);
1357 nQual+=std::abs(aPt1b.X()-aPt0.X())+std::abs(aPt1b.Y()-aPt0.Y());
1358 if (nQual<nQual0) bOverflow = true;
1359 nQual0=nQual;
1360 aPt0=aPt1b;
1361 }
1362
1363 sal_uInt16 nTmp=nPointCount;
1364 if (cForm=='Z') {
1365 nTmp=2; // Z shape with good quality (nTmp=2 instead of 4)
1366 sal_uIntPtr n1=std::abs(aXP1[1].X()-aXP1[0].X())+std::abs(aXP1[1].Y()-aXP1[0].Y());
1367 sal_uIntPtr n2=std::abs(aXP1[2].X()-aXP1[1].X())+std::abs(aXP1[2].Y()-aXP1[1].Y());
1368 sal_uIntPtr n3=std::abs(aXP1[3].X()-aXP1[2].X())+std::abs(aXP1[3].Y()-aXP1[2].Y());
1369 // try to make lines lengths similar
1370 sal_uIntPtr nBesser=0;
1371 n1+=n3;
1372 n3=n2/4;
1373 if (n1>=n2) nBesser=6;
1374 else if (n1>=3*n3) nBesser=4;
1375 else if (n1>=2*n3) nBesser=2;
1376 if (aXP1[0].Y()!=aXP1[1].Y()) nBesser++; // vertical starting line gets a plus (for H/V-Prio)
1377 if (nQual>nBesser) nQual-=nBesser; else nQual=0;
1378 }
1379 if (nTmp>=3) {
1380 nQual0=nQual;
1381 nQual+=static_cast<sal_uIntPtr>(nTmp)*0x01000000;
1382 if (nQual<nQual0 || nTmp>15) bOverflow = true;
1383 }
1384 if (nPointCount>=2) { // check exit angle again
1385 Point aP1(aXP1[1]); aP1-=aXP1[0];
1386 Point aP2(aXP1[nPointCount-2]); aP2-=aXP1[nPointCount-1];
1387 tools::Long nAng1=0; if (aP1.X()<0) nAng1=18000; if (aP1.Y()>0) nAng1=27000;
1388 if (aP1.Y()<0) nAng1=9000;
1389 if (aP1.X()!=0 && aP1.Y()!=0) nAng1=1; // slant?!
1390 tools::Long nAng2=0; if (aP2.X()<0) nAng2=18000; if (aP2.Y()>0) nAng2=27000;
1391 if (aP2.Y()<0) nAng2=9000;
1392 if (aP2.X()!=0 && aP2.Y()!=0) nAng2=1; // slant?!
1393 if (nAng1!=nAngle1) nIntersections++;
1394 if (nAng2!=nAngle2) nIntersections++;
1395 }
1396
1397 // For the quality check, use the original Rects and at the same time
1398 // check whether one them was scaled down for the calculation of the
1399 // Edges (e. g. case 2.9)
1400 aBewareRect1=rBewareRect1;
1401 aBewareRect2=rBewareRect2;
1402
1403 for (sal_uInt16 i=0; i<nPointCount; i++) {
1404 Point aPt1b(aXP1[i]);
1405 bool b1=aPt1b.X()>aBewareRect1.Left() && aPt1b.X()<aBewareRect1.Right() &&
1406 aPt1b.Y()>aBewareRect1.Top() && aPt1b.Y()<aBewareRect1.Bottom();
1407 bool b2=aPt1b.X()>aBewareRect2.Left() && aPt1b.X()<aBewareRect2.Right() &&
1408 aPt1b.Y()>aBewareRect2.Top() && aPt1b.Y()<aBewareRect2.Bottom();
1409 sal_uInt16 nInt0=nIntersections;
1410 if (i==0 || i==nPointCount-1) {
1411 if (b1 && b2) nIntersections++;
1412 } else {
1413 if (b1) nIntersections++;
1414 if (b2) nIntersections++;
1415 }
1416 // check for overlaps
1417 if (i>0 && nInt0==nIntersections) {
1418 if (aPt0.Y()==aPt1b.Y()) { // horizontal line
1419 if (aPt0.Y()>aBewareRect1.Top() && aPt0.Y()<aBewareRect1.Bottom() &&
1420 ((aPt0.X()<=aBewareRect1.Left() && aPt1b.X()>=aBewareRect1.Right()) ||
1421 (aPt1b.X()<=aBewareRect1.Left() && aPt0.X()>=aBewareRect1.Right()))) nIntersections++;
1422 if (aPt0.Y()>aBewareRect2.Top() && aPt0.Y()<aBewareRect2.Bottom() &&
1423 ((aPt0.X()<=aBewareRect2.Left() && aPt1b.X()>=aBewareRect2.Right()) ||
1424 (aPt1b.X()<=aBewareRect2.Left() && aPt0.X()>=aBewareRect2.Right()))) nIntersections++;
1425 } else { // vertical line
1426 if (aPt0.X()>aBewareRect1.Left() && aPt0.X()<aBewareRect1.Right() &&
1427 ((aPt0.Y()<=aBewareRect1.Top() && aPt1b.Y()>=aBewareRect1.Bottom()) ||
1428 (aPt1b.Y()<=aBewareRect1.Top() && aPt0.Y()>=aBewareRect1.Bottom()))) nIntersections++;
1429 if (aPt0.X()>aBewareRect2.Left() && aPt0.X()<aBewareRect2.Right() &&
1430 ((aPt0.Y()<=aBewareRect2.Top() && aPt1b.Y()>=aBewareRect2.Bottom()) ||
1431 (aPt1b.Y()<=aBewareRect2.Top() && aPt0.Y()>=aBewareRect2.Bottom()))) nIntersections++;
1432 }
1433 }
1434 aPt0=aPt1b;
1435 }
1436 if (nPointCount<=1) nIntersections++;
1437 nQual0=nQual;
1438 nQual+=static_cast<sal_uIntPtr>(nIntersections)*0x10000000;
1439 if (nQual<nQual0 || nIntersections>15) bOverflow = true;
1440
1441 if (bOverflow || nQual==0xFFFFFFFF) nQual=0xFFFFFFFE;
1442 *pnQuality=nQual;
1443 }
1444 if (bInfo) { // now apply line offsets to aXP1
1445 if (pInfo->nMiddleLine!=0xFFFF) {
1446 sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::MiddleLine,aXP1);
1447 if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::MiddleLine,aXP1)) {
1448 aXP1[nIdx].AdjustY(pInfo->aMiddleLine.Y() );
1449 aXP1[nIdx+1].AdjustY(pInfo->aMiddleLine.Y() );
1450 } else {
1451 aXP1[nIdx].AdjustX(pInfo->aMiddleLine.X() );
1452 aXP1[nIdx+1].AdjustX(pInfo->aMiddleLine.X() );
1453 }
1454 }
1455 if (pInfo->nObj1Lines>=2) {
1456 sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line2,aXP1);
1457 if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line2,aXP1)) {
1458 aXP1[nIdx].AdjustY(pInfo->aObj1Line2.Y() );
1459 aXP1[nIdx+1].AdjustY(pInfo->aObj1Line2.Y() );
1460 } else {
1461 aXP1[nIdx].AdjustX(pInfo->aObj1Line2.X() );
1462 aXP1[nIdx+1].AdjustX(pInfo->aObj1Line2.X() );
1463 }
1464 }
1465 if (pInfo->nObj1Lines>=3) {
1466 sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj1Line3,aXP1);
1467 if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj1Line3,aXP1)) {
1468 aXP1[nIdx].AdjustY(pInfo->aObj1Line3.Y() );
1469 aXP1[nIdx+1].AdjustY(pInfo->aObj1Line3.Y() );
1470 } else {
1471 aXP1[nIdx].AdjustX(pInfo->aObj1Line3.X() );
1472 aXP1[nIdx+1].AdjustX(pInfo->aObj1Line3.X() );
1473 }
1474 }
1475 if (pInfo->nObj2Lines>=2) {
1476 sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line2,aXP1);
1477 if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line2,aXP1)) {
1478 aXP1[nIdx].AdjustY(pInfo->aObj2Line2.Y() );
1479 aXP1[nIdx+1].AdjustY(pInfo->aObj2Line2.Y() );
1480 } else {
1481 aXP1[nIdx].AdjustX(pInfo->aObj2Line2.X() );
1482 aXP1[nIdx+1].AdjustX(pInfo->aObj2Line2.X() );
1483 }
1484 }
1485 if (pInfo->nObj2Lines>=3) {
1486 sal_uInt16 nIdx=pInfo->ImpGetPolyIdx(SdrEdgeLineCode::Obj2Line3,aXP1);
1487 if (pInfo->ImpIsHorzLine(SdrEdgeLineCode::Obj2Line3,aXP1)) {
1488 aXP1[nIdx].AdjustY(pInfo->aObj2Line3.Y() );
1489 aXP1[nIdx+1].AdjustY(pInfo->aObj2Line3.Y() );
1490 } else {
1491 aXP1[nIdx].AdjustX(pInfo->aObj2Line3.X() );
1492 aXP1[nIdx+1].AdjustX(pInfo->aObj2Line3.X() );
1493 }
1494 }
1495 }
1496 // make the connector a bezier curve, if appropriate
1497 if (eKind==SdrEdgeKind::Bezier && nPointCount>2) {
1498 Point* pPt1=&aXP1[0];
1499 Point* pPt2=&aXP1[1];
1500 Point* pPt3=&aXP1[nPointCount-2];
1501 Point* pPt4=&aXP1[nPointCount-1];
1502 tools::Long dx1=pPt2->X()-pPt1->X();
1503 tools::Long dy1=pPt2->Y()-pPt1->Y();
1504 tools::Long dx2=pPt3->X()-pPt4->X();
1505 tools::Long dy2=pPt3->Y()-pPt4->Y();
1506 if (cForm=='L') { // nPointCount==3
1507 aXP1.SetFlags(1,PolyFlags::Control);
1508 Point aPt3(*pPt2);
1509 aXP1.Insert(2,aPt3,PolyFlags::Control);
1510 nPointCount=aXP1.GetPointCount();
1511 pPt2=&aXP1[1];
1512 pPt3=&aXP1[nPointCount-2];
1513 pPt2->AdjustX( -(dx1/3) );
1514 pPt2->AdjustY( -(dy1/3) );
1515 pPt3->AdjustX( -(dx2/3) );
1516 pPt3->AdjustY( -(dy2/3) );
1517 } else if (nPointCount>=4 && nPointCount<=6) { // Z or U or ...
1518 // To all others, the end points of the original lines become control
1519 // points for now. Thus, we need to do some more work for nPointCount>4!
1520 aXP1.SetFlags(1,PolyFlags::Control);
1521 aXP1.SetFlags(nPointCount-2,PolyFlags::Control);
1522 // distance x1.5
1523 pPt2->AdjustX(dx1/2 );
1524 pPt2->AdjustY(dy1/2 );
1525 pPt3->AdjustX(dx2/2 );
1526 pPt3->AdjustY(dy2/2 );
1527 if (nPointCount==5) {
1528 // add a control point before and after center
1529 Point aCenter(aXP1[2]);
1530 tools::Long dx1b=aCenter.X()-aXP1[1].X();
1531 tools::Long dy1b=aCenter.Y()-aXP1[1].Y();
1532 tools::Long dx2b=aCenter.X()-aXP1[3].X();
1533 tools::Long dy2b=aCenter.Y()-aXP1[3].Y();
1534 aXP1.Insert(2,aCenter,PolyFlags::Control);
1535 aXP1.SetFlags(3,PolyFlags::Symmetric);
1536 aXP1.Insert(4,aCenter,PolyFlags::Control);
1537 aXP1[2].AdjustX( -(dx1b/2) );
1538 aXP1[2].AdjustY( -(dy1b/2) );
1539 aXP1[3].AdjustX( -((dx1b+dx2b)/4) );
1540 aXP1[3].AdjustY( -((dy1b+dy2b)/4) );
1541 aXP1[4].AdjustX( -(dx2b/2) );
1542 aXP1[4].AdjustY( -(dy2b/2) );
1543 }
1544 if (nPointCount==6) {
1545 Point aPt1b(aXP1[2]);
1546 Point aPt2b(aXP1[3]);
1547 aXP1.Insert(2,aPt1b,PolyFlags::Control);
1548 aXP1.Insert(5,aPt2b,PolyFlags::Control);
1549 tools::Long dx=aPt1b.X()-aPt2b.X();
1550 tools::Long dy=aPt1b.Y()-aPt2b.Y();
1551 aXP1[3].AdjustX( -(dx/2) );
1552 aXP1[3].AdjustY( -(dy/2) );
1553 aXP1.SetFlags(3,PolyFlags::Symmetric);
1554 aXP1.Remove(4,1); // because it's identical with aXP1[3]
1555 }
1556 }
1557 }
1558 return aXP1;
1559}
1560
1561/*
1562There could be a maximum of 64 different developments with 5 lines, a
1563maximum of 32 developments with 4 lines, a maximum of 16 developments with
15643 lines, a maximum of 8 developments with 2 lines.
1565This gives us a total of 124 possibilities.
1566Normalized for the 1st exit angle to the right, there remain 31 possibilities.
1567Now, normalizing away the vertical mirroring, we get to a total of 16
1568characteristic developments with 1 through 5 lines:
1569
15701 line (type "I") --
1571
15722 lines (type "L") __|
1573
15743 lines (type "U") __ (type "Z") _
1575 __| _|
1576 _ _
15774 lines #1 _| #2 | | #3 |_ #4 | |
1578 _| _| _| _|
1579 Of these, #1 is implausible, #2 is a rotated version of #3. This leaves
1580 #2 (from now on referred to as 4.1) and #4 (from now on referred to as 4.2).
1581 _ _
15825 lines #1 _| #2 _| #3 ___ #4 _
1583 _| _| _| _| _| |_
1584 _ _ _
1585 #5 |_ #6 |_ #7 _| | #8 ____
1586 _| _| _| |_ _|
1587 Of these, 5.1, 5.2, 5.4 and 5.5 are implausible, 5.7 is a reversed version
1588 of 5.3. This leaves 5.3 (type "4"), 5.6 (type "S") and 5.8 (type "C").
1589
1590We now have discerned the 9 basic types to cover all 400 possible constellations
1591of object positions and exit angles. 4 of the 9 types have got a center
1592line (CL). The number of object margins per object varies between 0 and 3:
1593
1594 CL O1 O2 Note
1595"I": n 0 0
1596"L": n 0 0
1597"U": n 0-1 0-1
1598"Z": y 0 0
15994.2: y 0 1 = U+1, respectively 1+U
16004.4: n 0-2 0-2 = Z+1
1601"4": y 0 2 = Z+2
1602"S": y 1 1 = 1+Z+1
1603"C": n 0-3 0-3 = 1+U+1
1604*/
1605
1607{
1608 const SfxHintId nId = rHint.GetId();
1609 bool bDataChg=nId==SfxHintId::DataChanged;
1610 bool bDying=nId==SfxHintId::Dying;
1611 bool bObj1=aCon1.pObj!=nullptr && aCon1.pObj->GetBroadcaster()==&rBC;
1612 bool bObj2=aCon2.pObj!=nullptr && aCon2.pObj->GetBroadcaster()==&rBC;
1613 if (bDying && (bObj1 || bObj2)) {
1614 // catch Dying, so AttrObj doesn't start broadcasting
1615 // about an alleged change of template
1616 if (bObj1) aCon1.pObj=nullptr;
1617 if (bObj2) aCon2.pObj=nullptr;
1618 return;
1619 }
1620 if ( bObj1 || bObj2 )
1621 {
1622 bEdgeTrackUserDefined = false;
1623 }
1624 SdrTextObj::Notify(rBC,rHint);
1625 if (nNotifyingCount!=0)return;
1626
1627// a locking flag
1629 const SdrHint* pSdrHint = ( rHint.GetId() == SfxHintId::ThisIsAnSdrHint ? static_cast<const SdrHint*>(&rHint) : nullptr );
1630
1631 if (bDataChg) { // StyleSheet changed
1632 ImpSetAttrToEdgeInfo(); // when changing templates, copy values from Pool to aEdgeInfo
1633 }
1634 if (bDataChg ||
1637 (pSdrHint && pSdrHint->GetKind()==SdrHintKind::ObjectRemoved))
1638 {
1639 // broadcasting only, if on the same page
1640 tools::Rectangle aBoundRect0; if (m_pUserCall!=nullptr) aBoundRect0=GetCurrentBoundRect();
1642
1643 // only redraw here, object hasn't actually changed
1644 ActionChanged();
1645
1647 }
1649}
1650
1655{
1656 if( nullptr != aCon1.pObj )
1657 {
1658 SfxHint aHint( SfxHintId::DataChanged );
1659 Notify( *const_cast<SfxBroadcaster*>(aCon1.pObj->GetBroadcaster()), aHint );
1660 }
1661
1662 if( nullptr != aCon2.pObj )
1663 {
1664 SfxHint aHint( SfxHintId::DataChanged );
1665 Notify( *const_cast<SfxBroadcaster*>(aCon2.pObj->GetBroadcaster()), aHint );
1666 }
1667}
1668
1670{
1671 return new SdrEdgeObj(rTargetModel, *this);
1672}
1673
1675{
1676 OUString sName(SvxResId(STR_ObjNameSingulEDGE));
1677
1678 OUString aName(GetName());
1679 if (!aName.isEmpty())
1680 sName += " '" + aName + "'";
1681 return sName;
1682}
1683
1685{
1686 return SvxResId(STR_ObjNamePluralEDGE);
1687}
1688
1690{
1691 basegfx::B2DPolyPolygon aPolyPolygon;
1692
1693 if (bEdgeTrackDirty)
1694 {
1695 const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
1696 }
1697
1698 if(pEdgeTrack)
1699 {
1700 aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
1701 }
1702
1703 return aPolyPolygon;
1704}
1705
1707{
1708 if ( !rPoly.count() )
1709 {
1710 bEdgeTrackDirty = true;
1711 bEdgeTrackUserDefined = false;
1712 }
1713 else
1714 {
1715 *pEdgeTrack = XPolygon( rPoly.getB2DPolygon( 0 ) );
1716 bEdgeTrackDirty = false;
1717 bEdgeTrackUserDefined = true;
1718
1719 // #i110629# also set aRect and maSnapeRect depending on pEdgeTrack
1720 const tools::Rectangle aPolygonBounds(pEdgeTrack->GetBoundRect());
1721 maRect = aPolygonBounds;
1722 maSnapRect = aPolygonBounds;
1723 }
1724}
1725
1727{
1728 basegfx::B2DPolyPolygon aPolyPolygon;
1729
1730 if (bEdgeTrackDirty)
1731 const_cast<SdrEdgeObj*>(this)->ImpRecalcEdgeTrack();
1732
1733 aPolyPolygon.append( pEdgeTrack->getB2DPolygon() );
1734
1735 return aPolyPolygon;
1736}
1737
1738sal_uInt32 SdrEdgeObj::GetHdlCount() const
1739{
1740 SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1741 sal_uInt32 nHdlCnt(0);
1742 sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
1743
1744 if(nPointCount)
1745 {
1746 nHdlCnt = 2;
1747 if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
1748 {
1749 sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
1750 sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
1751 sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
1752 nHdlCnt += nO1 + nO2 + nM;
1753 }
1754 else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
1755 {
1756 if(GetConnectedNode(true))
1757 nHdlCnt++;
1758
1759 if(GetConnectedNode(false))
1760 nHdlCnt++;
1761 }
1762 }
1763
1764 return nHdlCnt;
1765}
1766
1768{
1769 sal_uInt32 nPointCount(pEdgeTrack->GetPointCount());
1770 if (nPointCount==0)
1771 return;
1772
1773 {
1774 std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[0],SdrHdlKind::Poly));
1775 if (aCon1.pObj!=nullptr && aCon1.bBestVertex) pHdl->Set1PixMore();
1776 pHdl->SetPointNum(0);
1777 rHdlList.AddHdl(std::move(pHdl));
1778 }
1779 {
1780 std::unique_ptr<SdrHdl> pHdl(new ImpEdgeHdl((*pEdgeTrack)[sal_uInt16(nPointCount-1)],SdrHdlKind::Poly));
1781 if (aCon2.pObj!=nullptr && aCon2.bBestVertex) pHdl->Set1PixMore();
1782 pHdl->SetPointNum(1);
1783 rHdlList.AddHdl(std::move(pHdl));
1784 }
1785 {
1786 SdrEdgeKind eKind=GetObjectItem(SDRATTR_EDGEKIND).GetValue();
1787 if ((eKind==SdrEdgeKind::OrthoLines || eKind==SdrEdgeKind::Bezier) && nPointCount >= 4)
1788 {
1789 sal_uInt32 nO1(aEdgeInfo.nObj1Lines > 0 ? aEdgeInfo.nObj1Lines - 1 : 0);
1790 sal_uInt32 nO2(aEdgeInfo.nObj2Lines > 0 ? aEdgeInfo.nObj2Lines - 1 : 0);
1791 sal_uInt32 nM(aEdgeInfo.nMiddleLine != 0xFFFF ? 1 : 0);
1792 for(sal_uInt32 i = 0; i < (nO1 + nO2 + nM); ++i)
1793 {
1794 sal_Int32 nPt(0);
1795 sal_uInt32 nNum = i;
1796 std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(Point(),SdrHdlKind::Poly));
1797 if (nNum<nO1) {
1798 nPt=nNum+1;
1799 if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
1800 if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line3);
1801 } else {
1802 nNum=nNum-nO1;
1803 if (nNum<nO2) {
1804 nPt=nPointCount-3-nNum;
1805 if (nNum==0) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
1806 if (nNum==1) pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line3);
1807 } else {
1808 nNum=nNum-nO2;
1809 if (nNum<nM) {
1811 pHdl->SetLineCode(SdrEdgeLineCode::MiddleLine);
1812 }
1813 }
1814 }
1815 if (nPt>0) {
1816 Point aPos((*pEdgeTrack)[static_cast<sal_uInt16>(nPt)]);
1817 aPos+=(*pEdgeTrack)[static_cast<sal_uInt16>(nPt)+1];
1818 aPos.setX( aPos.X() / 2 );
1819 aPos.setY( aPos.Y() / 2 );
1820 pHdl->SetPos(aPos);
1821 pHdl->SetPointNum(i + 2);
1822 rHdlList.AddHdl(std::move(pHdl));
1823 }
1824 }
1825 }
1826 else if (eKind==SdrEdgeKind::ThreeLines && nPointCount == 4)
1827 {
1828 if(GetConnectedNode(true))
1829 {
1830 Point aPos((*pEdgeTrack)[1]);
1831 std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
1832 pHdl->SetLineCode(SdrEdgeLineCode::Obj1Line2);
1833 pHdl->SetPointNum(2);
1834 rHdlList.AddHdl(std::move(pHdl));
1835 }
1836 if(GetConnectedNode(false))
1837 {
1838 Point aPos((*pEdgeTrack)[2]);
1839 std::unique_ptr<ImpEdgeHdl> pHdl(new ImpEdgeHdl(aPos,SdrHdlKind::Poly));
1840 pHdl->SetLineCode(SdrEdgeLineCode::Obj2Line2);
1841 pHdl->SetPointNum(3);
1842 rHdlList.AddHdl(std::move(pHdl));
1843 }
1844 }
1845 }
1846}
1847
1849{
1850 return true;
1851}
1852
1854{
1855 // use Clone operator
1857
1858 // copy connections for clone, SdrEdgeObj::operator= does not do this
1859 pRetval->ConnectToNode(true, GetConnectedNode(true));
1860 pRetval->ConnectToNode(false, GetConnectedNode(false));
1861
1862 return pRetval;
1863}
1864
1866{
1867 if(!rDrag.GetHdl())
1868 return false;
1869
1870 rDrag.SetEndDragChangesAttributes(true);
1871
1872 if(rDrag.GetHdl()->GetPointNum() < 2)
1873 {
1874 rDrag.SetNoSnap();
1875 }
1876
1877 return true;
1878}
1879
1881{
1882 SdrEdgeObj* pOriginalEdge = dynamic_cast< SdrEdgeObj* >(rDragStat.GetHdl()->GetObj());
1883 const bool bOriginalEdgeModified(pOriginalEdge == this);
1884
1885 if(!bOriginalEdgeModified && pOriginalEdge)
1886 {
1887 // copy connections when clone is modified. This is needed because
1888 // as preparation to this modification the data from the original object
1889 // was copied to the clone using the operator=. As can be seen there,
1890 // that operator does not copy the connections (for good reason)
1891 ConnectToNode(true, pOriginalEdge->GetConnection(true).GetObject());
1892 ConnectToNode(false, pOriginalEdge->GetConnection(false).GetObject());
1893 }
1894
1895 if(rDragStat.GetHdl()->GetPointNum() < 2)
1896 {
1897 // start or end point connector drag
1898 const bool bDragA(0 == rDragStat.GetHdl()->GetPointNum());
1899 const Point aPointNow(rDragStat.GetNow());
1900
1901 rDragStat.SetEndDragChangesGeoAndAttributes(true);
1902
1903 if(rDragStat.GetPageView())
1904 {
1905 SdrObjConnection* pDraggedOne(bDragA ? &aCon1 : &aCon2);
1906
1907 // clear connection
1908 DisconnectFromNode(bDragA);
1909
1910 // look for new connection
1911 ImpFindConnector(aPointNow, *rDragStat.GetPageView(), *pDraggedOne, pOriginalEdge, nullptr, &rDragStat);
1912
1913 if(pDraggedOne->pObj)
1914 {
1915 // if found, officially connect to it; ImpFindConnector only
1916 // sets pObj hard
1917 SdrObject* pNewConnection = pDraggedOne->pObj;
1918 pDraggedOne->pObj = nullptr;
1919 ConnectToNode(bDragA, pNewConnection);
1920 }
1921
1922 if(rDragStat.GetView() && !bOriginalEdgeModified)
1923 {
1924 // show IA helper, but only do this during IA, so not when the original
1925 // Edge gets modified in the last call
1926 rDragStat.GetView()->SetConnectMarker(*pDraggedOne);
1927 }
1928 }
1929
1930 if(pEdgeTrack)
1931 {
1932 // change pEdgeTrack to modified position
1933 if(bDragA)
1934 {
1935 (*pEdgeTrack)[0] = aPointNow;
1936 }
1937 else
1938 {
1939 (*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount()-1)] = aPointNow;
1940 }
1941 }
1942
1943 // reset edge info's offsets, this is an end point drag
1949 }
1950 else
1951 {
1952 // control point connector drag
1953 const ImpEdgeHdl* pEdgeHdl = static_cast<const ImpEdgeHdl*>(rDragStat.GetHdl());
1954 const SdrEdgeLineCode eLineCode = pEdgeHdl->GetLineCode();
1955 const Point aDist(rDragStat.GetNow() - rDragStat.GetStart());
1956 sal_Int32 nDist(pEdgeHdl->IsHorzDrag() ? aDist.X() : aDist.Y());
1957
1958 nDist += aEdgeInfo.ImpGetLineOffset(eLineCode, *pEdgeTrack);
1959 aEdgeInfo.ImpSetLineOffset(eLineCode, *pEdgeTrack, nDist);
1960 }
1961
1962 // force recalculation of EdgeTrack
1964 bEdgeTrackDirty=false;
1965
1966 // save EdgeInfos and mark object as user modified
1968 bEdgeTrackUserDefined = false;
1969
1971
1972 if(bOriginalEdgeModified && rDragStat.GetView())
1973 {
1974 // hide connect marker helper again when original gets changed.
1975 // This happens at the end of the interaction
1976 rDragStat.GetView()->HideConnectMarker();
1977 }
1978
1979 return true;
1980}
1981
1983{
1984 const bool bCreateComment(rDrag.GetView() && this == rDrag.GetView()->GetCreateObj());
1985
1986 if(bCreateComment)
1987 {
1988 return OUString();
1989 }
1990 else
1991 {
1992 return ImpGetDescriptionStr(STR_DragEdgeTail);
1993 }
1994}
1995
1996
1997basegfx::B2DPolygon SdrEdgeObj::ImplAddConnectorOverlay(const SdrDragMethod& rDragMethod, bool bTail1, bool bTail2, bool bDetail) const
1998{
1999 basegfx::B2DPolygon aResult;
2000
2001 if(bDetail)
2002 {
2003 SdrObjConnection aMyCon1(aCon1);
2004 SdrObjConnection aMyCon2(aCon2);
2005
2006 if (bTail1)
2007 {
2008 const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon1.aObjOfs.X(), aMyCon1.aObjOfs.Y()));
2009 aMyCon1.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
2010 aMyCon1.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
2011 }
2012
2013 if (bTail2)
2014 {
2015 const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aMyCon2.aObjOfs.X(), aMyCon2.aObjOfs.Y()));
2016 aMyCon2.aObjOfs.setX( basegfx::fround(aTemp.getX()) );
2017 aMyCon2.aObjOfs.setY( basegfx::fround(aTemp.getY()) );
2018 }
2019
2021 XPolygon aXP(ImpCalcEdgeTrack(*pEdgeTrack, aMyCon1, aMyCon2, &aInfo));
2022
2023 if(aXP.GetPointCount())
2024 {
2025 aResult = aXP.getB2DPolygon();
2026 }
2027 }
2028 else
2029 {
2030 Point aPt1((*pEdgeTrack)[0]);
2031 Point aPt2((*pEdgeTrack)[sal_uInt16(pEdgeTrack->GetPointCount() - 1)]);
2032
2034 aPt1 = aCon1.pObj->GetSnapRect().Center();
2035
2037 aPt2 = aCon2.pObj->GetSnapRect().Center();
2038
2039 if (bTail1)
2040 {
2041 const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
2042 aPt1.setX( basegfx::fround(aTemp.getX()) );
2043 aPt1.setY( basegfx::fround(aTemp.getY()) );
2044 }
2045
2046 if (bTail2)
2047 {
2048 const basegfx::B2DPoint aTemp(rDragMethod.getCurrentTransformation() * basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
2049 aPt2.setX( basegfx::fround(aTemp.getX()) );
2050 aPt2.setY( basegfx::fround(aTemp.getY()) );
2051 }
2052
2053 aResult.append(basegfx::B2DPoint(aPt1.X(), aPt1.Y()));
2054 aResult.append(basegfx::B2DPoint(aPt2.X(), aPt2.Y()));
2055 }
2056
2057 return aResult;
2058}
2059
2061{
2062 rDragStat.SetNoSnap();
2063 pEdgeTrack->SetPointCount(2);
2064 (*pEdgeTrack)[0]=rDragStat.GetStart();
2065 (*pEdgeTrack)[1]=rDragStat.GetNow();
2066 if (rDragStat.GetPageView()!=nullptr) {
2067 ImpFindConnector(rDragStat.GetStart(),*rDragStat.GetPageView(),aCon1,this);
2068 ConnectToNode(true,aCon1.pObj);
2069 }
2071 return true;
2072}
2073
2075{
2076 sal_uInt16 nMax=pEdgeTrack->GetPointCount();
2077 (*pEdgeTrack)[nMax-1]=rDragStat.GetNow();
2078 if (rDragStat.GetPageView()!=nullptr) {
2079 ImpFindConnector(rDragStat.GetNow(),*rDragStat.GetPageView(),aCon2,this);
2080 rDragStat.GetView()->SetConnectMarker(aCon2);
2081 }
2083 m_bSnapRectDirty=true;
2084 ConnectToNode(false,aCon2.pObj);
2086 bEdgeTrackDirty=false;
2087 return true;
2088}
2089
2091{
2092 bool bOk=(eCmd==SdrCreateCmd::ForceEnd || rDragStat.GetPointCount()>=2);
2093 if (bOk) {
2094 ConnectToNode(true,aCon1.pObj);
2095 ConnectToNode(false,aCon2.pObj);
2096 if (rDragStat.GetView()!=nullptr) {
2097 rDragStat.GetView()->HideConnectMarker();
2098 }
2099 ImpSetEdgeInfoToAttr(); // copy values from aEdgeInfo into the pool
2100 }
2102 return bOk;
2103}
2104
2106{
2107 if (rDragStat.GetView()!=nullptr) {
2108 rDragStat.GetView()->HideConnectMarker();
2109 }
2110 return false;
2111}
2112
2114{
2115 if (rDragStat.GetView()!=nullptr) {
2116 rDragStat.GetView()->HideConnectMarker();
2117 }
2118}
2119
2121{
2123 aRetval.append(pEdgeTrack->getB2DPolygon());
2124 return aRetval;
2125}
2126
2128{
2129 return PointerStyle::DrawConnect;
2130}
2131
2132bool SdrEdgeObj::ImpFindConnector(const Point& rPt, const SdrPageView& rPV, SdrObjConnection& rCon, const SdrEdgeObj* pThis, OutputDevice* pOut, SdrDragStat* pDragStat)
2133{
2134 rCon.ResetVars();
2135 if (pOut==nullptr) pOut=rPV.GetView().GetFirstOutputDevice();
2136 if (pOut==nullptr) return false;
2137 SdrObjList* pOL=rPV.GetObjList();
2138 const SdrLayerIDSet& rVisLayer=rPV.GetVisibleLayers();
2139 // sensitive area of connectors is twice as large as the one of the handles
2140 sal_uInt16 nMarkHdSiz=rPV.GetView().GetMarkHdlSizePixel();
2141 Size aHalfConSiz(nMarkHdSiz,nMarkHdSiz);
2142 if (comphelper::LibreOfficeKit::isActive() && pOut->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
2143 aHalfConSiz=pOut->PixelToLogic(aHalfConSiz, MapMode(MapUnit::Map100thMM));
2144 else
2145 aHalfConSiz=pOut->PixelToLogic(aHalfConSiz);
2146 tools::Rectangle aMouseRect(rPt,rPt);
2147 aMouseRect.AdjustLeft( -(aHalfConSiz.Width()) );
2148 aMouseRect.AdjustTop( -(aHalfConSiz.Height()) );
2149 aMouseRect.AdjustRight(aHalfConSiz.Width() );
2150 aMouseRect.AdjustBottom(aHalfConSiz.Height() );
2151 sal_uInt16 nBoundHitTol=static_cast<sal_uInt16>(aHalfConSiz.Width())/2; if (nBoundHitTol==0) nBoundHitTol=1;
2152 size_t no=pOL->GetObjCount();
2153 bool bFnd = false;
2154 SdrObjConnection aTestCon;
2155 bool bTiledRendering = comphelper::LibreOfficeKit::isActive();
2156 bool bHasRequestedOrdNum = false;
2157 sal_Int32 requestedOrdNum = -1;
2158
2159 if (bTiledRendering && pDragStat)
2160 {
2161 auto& glueOptions = pDragStat->GetGlueOptions();
2162 if (glueOptions.objectOrdNum != -1)
2163 {
2164 requestedOrdNum = glueOptions.objectOrdNum;
2165 bHasRequestedOrdNum = true;
2166 }
2167 }
2168
2169 while (no>0 && !bFnd) {
2170 // issue: group objects on different layers return LayerID=0!
2171 no--;
2172 SdrObject* pObj=pOL->GetObj(no);
2173 if (bHasRequestedOrdNum)
2174 {
2175 if (pObj->GetOrdNumDirect() != static_cast<sal_uInt32>(requestedOrdNum))
2176 continue;
2177 }
2178 if (rVisLayer.IsSet(pObj->GetLayer()) && pObj->IsVisible() && // only visible objects
2179 (pThis==nullptr || pObj!=static_cast<SdrObject const *>(pThis))) // don't connect it to itself
2180 {
2181 tools::Rectangle aObjBound(pObj->GetCurrentBoundRect());
2182 if (aObjBound.Overlaps(aMouseRect)) {
2183 aTestCon.ResetVars();
2184 bool bEdge=dynamic_cast<const SdrEdgeObj *>(pObj) != nullptr; // no BestCon for Edge
2185 // User-defined connectors have absolute priority.
2186 // After those come Vertex, Corner and center (Best), all prioritized equally.
2187 // Finally, a HitTest for the object.
2188 const SdrGluePointList* pGPL=pObj->GetGluePointList();
2189 sal_uInt16 nGluePointCnt=pGPL==nullptr ? 0 : pGPL->GetCount();
2190 sal_uInt16 nGesAnz=nGluePointCnt+9;
2191 bool bUserFnd = false;
2192 sal_uIntPtr nBestDist=0xFFFFFFFF;
2193 for (sal_uInt16 i=0; i<nGesAnz; i++)
2194 {
2195 bool bUser=i<nGluePointCnt;
2196 bool bVertex=i>=nGluePointCnt+0 && i<nGluePointCnt+4;
2197 bool bCorner=i>=nGluePointCnt+4 && i<nGluePointCnt+8;
2198 bool bCenter=i==nGluePointCnt+8;
2199 bool bOk = false;
2200 Point aConPos;
2201 sal_uInt16 nConNum=i;
2202 if (bUser) {
2203 const SdrGluePoint& rGP=(*pGPL)[nConNum];
2204 aConPos=rGP.GetAbsolutePos(*pObj);
2205 nConNum=rGP.GetId();
2206 bOk = true;
2207 } else if (bVertex && !bUserFnd) {
2208 nConNum=nConNum-nGluePointCnt;
2209 SdrGluePoint aPt(pObj->GetVertexGluePoint(nConNum));
2210 aConPos=aPt.GetAbsolutePos(*pObj);
2211 bOk = true;
2212 } else if (bCorner && !bUserFnd) {
2213 nConNum-=nGluePointCnt+4;
2214 i+=3;
2215 }
2216 else if (bCenter && !bUserFnd && !bEdge)
2217 {
2218 // Suppress default connect at object center
2219 if(!pThis || !pThis->GetSuppressDefaultConnect())
2220 {
2221 // not the edges!
2222 nConNum=0;
2223 aConPos=aObjBound.Center();
2224 bOk = true;
2225 }
2226 }
2227 if (bOk && aMouseRect.Contains(aConPos)) {
2228 if (bUser) bUserFnd = true;
2229 bFnd = true;
2230 sal_uIntPtr nDist=static_cast<sal_uIntPtr>(std::abs(aConPos.X()-rPt.X()))+static_cast<sal_uIntPtr>(std::abs(aConPos.Y()-rPt.Y()));
2231 if (nDist<nBestDist) {
2232 nBestDist=nDist;
2233 aTestCon.pObj=pObj;
2234 aTestCon.nConId=nConNum;
2235 aTestCon.bAutoCorner=bCorner;
2236 aTestCon.bAutoVertex=bVertex;
2237 aTestCon.bBestConn=false; // bCenter;
2238 aTestCon.bBestVertex=bCenter;
2239 }
2240 }
2241 }
2242 // if no connector is hit, try HitTest again, for BestConnector (=bCenter)
2243 if(!bFnd &&
2244 !bEdge &&
2245 SdrObjectPrimitiveHit(*pObj, rPt, nBoundHitTol, rPV, &rVisLayer, false))
2246 {
2247 // Suppress default connect at object inside bound
2248 if(!pThis || !pThis->GetSuppressDefaultConnect())
2249 {
2250 bFnd = true;
2251 aTestCon.pObj=pObj;
2252 aTestCon.bBestConn=true;
2253 }
2254 }
2255 if (bFnd) {
2256 aMouseRect.AdjustLeft( -nBoundHitTol );
2257 aMouseRect.AdjustTop( -nBoundHitTol );
2258 aMouseRect.AdjustRight(nBoundHitTol );
2259 aMouseRect.AdjustBottom(nBoundHitTol );
2260 }
2261
2262 }
2263 }
2264 }
2265 rCon=aTestCon;
2266 return bFnd;
2267}
2268
2270{
2271 const tools::Rectangle aOld(GetSnapRect());
2272
2273 if(aOld == rRect)
2274 return;
2275
2276 if (maRect.IsEmpty() && 0 == pEdgeTrack->GetPointCount())
2277 {
2278 // #i110629# When initializing, do not scale on empty Rectangle; this
2279 // will mirror the underlying text object (!)
2280 maRect = rRect;
2281 maSnapRect = rRect;
2282 }
2283 else
2284 {
2285 tools::Long nMulX = rRect.Right() - rRect.Left();
2286 tools::Long nDivX = aOld.Right() - aOld.Left();
2287 tools::Long nMulY = rRect.Bottom() - rRect.Top();
2288 tools::Long nDivY = aOld.Bottom() - aOld.Top();
2289 if ( nDivX == 0 ) { nMulX = 1; nDivX = 1; }
2290 if ( nDivY == 0 ) { nMulY = 1; nDivY = 1; }
2291 Fraction aX(nMulX, nDivX);
2292 Fraction aY(nMulY, nDivY);
2293 NbcResize(aOld.TopLeft(), aX, aY);
2294 NbcMove(Size(rRect.Left() - aOld.Left(), rRect.Top() - aOld.Top()));
2295 }
2296}
2297
2298void SdrEdgeObj::NbcMove(const Size& rSiz)
2299{
2300 SdrTextObj::NbcMove(rSiz);
2301 MoveXPoly(*pEdgeTrack,rSiz);
2302}
2303
2304void SdrEdgeObj::NbcResize(const Point& rRefPnt, const Fraction& aXFact, const Fraction& aYFact)
2305{
2306 SdrTextObj::NbcResize(rRefPnt,aXFact,aXFact);
2307 ResizeXPoly(*pEdgeTrack,rRefPnt,aXFact,aYFact);
2308
2309 // if resize is not from paste, forget user distances
2310 if (!getSdrModelFromSdrObject().IsPasteResize())
2311 {
2317 }
2318}
2319
2320// #i54102# added rotation support
2321void SdrEdgeObj::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs)
2322{
2324 {
2325 // #i120437# special handling when track is imported, apply
2326 // transformation directly to imported track.
2327 SdrTextObj::NbcRotate(rRef, nAngle, sn, cs);
2328 RotateXPoly(*pEdgeTrack, rRef, sn, cs);
2329 }
2330 else
2331 {
2332 // handle start and end point if not connected
2333 const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2334 const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2335
2336 if(!bCon1 && pEdgeTrack)
2337 {
2338 RotatePoint((*pEdgeTrack)[0],rRef,sn,cs);
2340 }
2341
2342 if(!bCon2 && pEdgeTrack)
2343 {
2344 sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2345 RotatePoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,sn,cs);
2347 }
2348 }
2349}
2350
2351// #i54102# added mirror support
2352void SdrEdgeObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2353{
2355 {
2356 // #i120437# special handling when track is imported, apply
2357 // transformation directly to imported track.
2358 SdrTextObj::NbcMirror(rRef1, rRef2);
2359 MirrorXPoly(*pEdgeTrack, rRef1, rRef2);
2360 }
2361 else
2362 {
2363 // handle start and end point if not connected
2364 const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2365 const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2366
2367 if(!bCon1 && pEdgeTrack)
2368 {
2369 MirrorPoint((*pEdgeTrack)[0],rRef1,rRef2);
2371 }
2372
2373 if(!bCon2 && pEdgeTrack)
2374 {
2375 sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2376 MirrorPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef1,rRef2);
2378 }
2379 }
2380}
2381
2382// #i54102# added shear support
2383void SdrEdgeObj::NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear)
2384{
2386 {
2387 // #i120437# special handling when track is imported, apply
2388 // transformation directly to imported track.
2389 SdrTextObj::NbcShear(rRef, nAngle, tn, bVShear);
2390 ShearXPoly(*pEdgeTrack, rRef, tn, bVShear);
2391 }
2392 else
2393 {
2394 // handle start and end point if not connected
2395 const bool bCon1(nullptr != aCon1.pObj && aCon1.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2396 const bool bCon2(nullptr != aCon2.pObj && aCon2.pObj->getSdrPageFromSdrObject() == getSdrPageFromSdrObject());
2397
2398 if(!bCon1 && pEdgeTrack)
2399 {
2400 ShearPoint((*pEdgeTrack)[0],rRef,tn,bVShear);
2402 }
2403
2404 if(!bCon2 && pEdgeTrack)
2405 {
2406 sal_uInt16 nPointCount = pEdgeTrack->GetPointCount();
2407 ShearPoint((*pEdgeTrack)[sal_uInt16(nPointCount-1)],rRef,tn,bVShear);
2409 }
2410 }
2411}
2412
2414{
2415 basegfx::B2DPolyPolygon aPolyPolygon;
2416 aPolyPolygon.append(pEdgeTrack->getB2DPolygon());
2417 rtl::Reference<SdrObject> pRet = ImpConvertMakeObj(aPolyPolygon, false, bBezier);
2418
2419 if(bAddText)
2420 {
2421 pRet = ImpConvertAddText(std::move(pRet), bBezier);
2422 }
2423
2424 return pRet;
2425}
2426
2428{
2429 return 2;
2430}
2431
2433{
2434 const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
2435 sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2436 if (i==0) return (*pEdgeTrack)[0];
2437 else return (*pEdgeTrack)[nCount-1];
2438}
2439
2441{
2442 return false;
2443}
2444
2446{
2447 return 0;
2448}
2449
2450Point SdrEdgeObj::GetPoint(sal_uInt32 i) const
2451{
2452 const_cast<SdrEdgeObj*>(this)->ImpUndirtyEdgeTrack();
2453 sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2454 if (0 == i)
2455 return (*pEdgeTrack)[0];
2456 else
2457 return (*pEdgeTrack)[nCount-1];
2458}
2459
2460void SdrEdgeObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2461{
2462 // TODO: Need an implementation to connect differently.
2464 sal_uInt16 nCount=pEdgeTrack->GetPointCount();
2465 if (0 == i)
2466 (*pEdgeTrack)[0]=rPnt;
2467 if (1 == i)
2468 (*pEdgeTrack)[nCount-1]=rPnt;
2471}
2472
2474 : pEdgeTrack(std::in_place)
2475 , bEdgeTrackDirty(false)
2476 , bEdgeTrackUserDefined(false)
2477{
2478}
2479
2481{
2482}
2483
2484std::unique_ptr<SdrObjGeoData> SdrEdgeObj::NewGeoData() const
2485{
2486 return std::make_unique<SdrEdgeObjGeoData>();
2487}
2488
2490{
2492 SdrEdgeObjGeoData& rEGeo=static_cast<SdrEdgeObjGeoData&>(rGeo);
2493 rEGeo.aCon1 =aCon1;
2494 rEGeo.aCon2 =aCon2;
2495 *rEGeo.pEdgeTrack =*pEdgeTrack;
2498 rEGeo.aEdgeInfo =aEdgeInfo;
2499}
2500
2502{
2504 const SdrEdgeObjGeoData& rEGeo=static_cast<const SdrEdgeObjGeoData&>(rGeo);
2505 if (aCon1.pObj!=rEGeo.aCon1.pObj) {
2506 if (aCon1.pObj!=nullptr) aCon1.pObj->RemoveListener(*this);
2507 aCon1=rEGeo.aCon1;
2508 if (aCon1.pObj!=nullptr) aCon1.pObj->AddListener(*this);
2509 }
2510 else
2511 aCon1=rEGeo.aCon1;
2512
2513 if (aCon2.pObj!=rEGeo.aCon2.pObj) {
2514 if (aCon2.pObj!=nullptr) aCon2.pObj->RemoveListener(*this);
2515 aCon2=rEGeo.aCon2;
2516 if (aCon2.pObj!=nullptr) aCon2.pObj->AddListener(*this);
2517 }
2518 else
2519 aCon2=rEGeo.aCon2;
2520
2521 *pEdgeTrack =*rEGeo.pEdgeTrack;
2524 aEdgeInfo =rEGeo.aEdgeInfo;
2525}
2526
2528{
2529 if( pEdgeTrack && pEdgeTrack->GetPointCount()!=0)
2530 {
2531 const XPolygon& rTrack0 = *pEdgeTrack;
2532 if(bTail)
2533 {
2534 return rTrack0[0];
2535 }
2536 else
2537 {
2538 const sal_uInt16 nSiz = rTrack0.GetPointCount() - 1;
2539 return rTrack0[nSiz];
2540 }
2541 }
2542 else
2543 {
2544 if(bTail)
2545 return getOutRectangle().TopLeft();
2546 else
2547 return getOutRectangle().BottomRight();
2548 }
2549
2550}
2551
2552void SdrEdgeObj::SetTailPoint( bool bTail, const Point& rPt )
2553{
2554 ImpSetTailPoint( bTail, rPt );
2555 SetChanged();
2556}
2557
2563void SdrEdgeObj::setGluePointIndex( bool bTail, sal_Int32 nIndex /* = -1 */ )
2564{
2565 SdrObjConnection& rConn1 = GetConnection( bTail );
2566
2567 rConn1.SetAutoVertex( nIndex >= 0 && nIndex <= 3 );
2568 rConn1.SetBestConnection( nIndex < 0 );
2569 rConn1.SetBestVertex( nIndex < 0 );
2570
2571 if( nIndex > 3 )
2572 {
2573 nIndex -= 3; // the start api index is 0, whereas the implementation in svx starts from 1
2574
2575 // for user defined gluepoints we have
2576 // to get the id for this index first
2577 const SdrGluePointList* pList = rConn1.GetObject() ? rConn1.GetObject()->GetGluePointList() : nullptr;
2578 if( pList == nullptr || SDRGLUEPOINT_NOTFOUND == pList->FindGluePoint(static_cast<sal_uInt16>(nIndex)) )
2579 return;
2580 }
2581 else if( nIndex < 0 )
2582 {
2583 nIndex = 0;
2584 }
2585
2586 rConn1.SetConnectorId( static_cast<sal_uInt16>(nIndex) );
2587
2588 SetChanged();
2591}
2592
2595sal_Int32 SdrEdgeObj::getGluePointIndex( bool bTail )
2596{
2597 SdrObjConnection& rConn1 = GetConnection( bTail );
2598 sal_Int32 nId = -1;
2599 if( !rConn1.IsBestConnection() )
2600 {
2601 nId = rConn1.GetConnectorId();
2602 if( !rConn1.IsAutoVertex() )
2603 nId += 3; // the start api index is 0, whereas the implementation in svx starts from 1
2604 }
2605 return nId;
2606}
2607
2608// Implementation was missing; edge track needs to be invalidated additionally.
2609void SdrEdgeObj::NbcSetAnchorPos(const Point& rPnt)
2610{
2611 // call parent functionality
2613
2614 // Additionally, invalidate edge track
2616}
2617
2619{
2620 // use base method from SdrObject, it's not rotatable and
2621 // a call to GetSnapRect() is used. That's what we need for Connector.
2622 return SdrObject::TRGetBaseGeometry(rMatrix, rPolyPolygon);
2623}
2624
2626{
2627 // where appropriate take care for existing connections. For now, just use the
2628 // implementation from SdrObject.
2629 SdrObject::TRSetBaseGeometry(rMatrix, rPolyPolygon);
2630}
2631
2632// for geometry access
2634{
2635 if(bEdgeTrackDirty)
2636 {
2637 const_cast< SdrEdgeObj* >(this)->ImpRecalcEdgeTrack();
2638 }
2639
2640 if(pEdgeTrack)
2641 {
2642 return pEdgeTrack->getB2DPolygon();
2643 }
2644 else
2645 {
2646 return ::basegfx::B2DPolygon();
2647 }
2648}
2649
2650/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool IsHorzDrag() const
Definition: svdhdl.cxx:1695
SdrEdgeLineCode GetLineCode() const
Definition: svdhdl.hxx:397
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoattr.cxx:49
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Detects when a stylesheet is changed.
Definition: svdoattr.cxx:61
tools::Rectangle maSnapRect
Definition: svdoattr.hxx:41
void HideConnectMarker()
Definition: svdcrtv.cxx:291
SdrObject * GetCreateObj() const
Definition: svdcrtv.hxx:120
void SetConnectMarker(const SdrObjConnection &rCon)
Definition: svdcrtv.cxx:268
virtual basegfx::B2DHomMatrix getCurrentTransformation() const
Definition: svddrgmt.cxx:658
auto & GetGlueOptions()
Definition: svddrag.hxx:172
sal_Int32 GetPointCount() const
Definition: svddrag.hxx:101
const Point & GetStart() const
Definition: svddrag.hxx:102
SdrView * GetView() const
Definition: svddrag.hxx:96
void SetEndDragChangesGeoAndAttributes(bool bOn)
Definition: svddrag.hxx:145
const SdrHdl * GetHdl() const
Definition: svddrag.hxx:111
const Point & GetNow() const
Definition: svddrag.hxx:105
void SetNoSnap(bool bOn=true)
Definition: svddrag.hxx:131
SdrPageView * GetPageView() const
Definition: svddrag.hxx:98
void SetEndDragChangesAttributes(bool bOn)
Definition: svddrag.hxx:143
Utility class SdrEdgeInfoRec.
Definition: svdoedge.hxx:76
Point aObj1Line2
Definition: svdoedge.hxx:81
Point aObj2Line3
Definition: svdoedge.hxx:84
void ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon &rXP, tools::Long nVal)
Definition: svdoedge.cxx:123
bool ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:111
sal_uInt16 nObj1Lines
Definition: svdoedge.hxx:90
Point aObj2Line2
Definition: svdoedge.hxx:83
Point & ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode)
Definition: svdoedge.cxx:87
sal_uInt16 nObj2Lines
Definition: svdoedge.hxx:91
Point aObj1Line3
Definition: svdoedge.hxx:82
sal_uInt16 nMiddleLine
Definition: svdoedge.hxx:92
Point aMiddleLine
Definition: svdoedge.hxx:85
tools::Long nAngle1
Definition: svdoedge.hxx:88
tools::Long nAngle2
Definition: svdoedge.hxx:89
sal_uInt16 ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:99
tools::Long ImpGetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon &rXP) const
Definition: svdoedge.cxx:130
Utility class SdrEdgeObjGeoData.
Definition: svdoedge.hxx:113
bool bEdgeTrackUserDefined
Definition: svdoedge.hxx:119
SdrObjConnection aCon1
Definition: svdoedge.hxx:115
virtual ~SdrEdgeObjGeoData() override
Definition: svdoedge.cxx:2480
SdrObjConnection aCon2
Definition: svdoedge.hxx:116
SdrEdgeInfoRec aEdgeInfo
Definition: svdoedge.hxx:120
std::optional< XPolygon > pEdgeTrack
Definition: svdoedge.hxx:117
Utility class SdrEdgeObj.
Definition: svdoedge.hxx:130
virtual SdrGluePointList * ForceGluePointList() override
Definition: svdoedge.cxx:465
static XPolygon ImpCalcObjToCenter(const Point &rStPt, tools::Long nEscAngle, const tools::Rectangle &rRect, const Point &rCenter)
Definition: svdoedge.cxx:658
virtual bool EndCreate(SdrDragStat &rStat, SdrCreateCmd eCmd) override
Definition: svdoedge.cxx:2090
void ConnectToNode(bool bTail1, SdrObject *pObj) override
Definition: svdoedge.cxx:470
SdrObjConnection aCon2
Definition: svdoedge.hxx:142
virtual void NbcResize(const Point &rRefPnt, const Fraction &aXFact, const Fraction &aYFact) override
Definition: svdoedge.cxx:2304
void ImpRecalcEdgeTrack()
Definition: svdoedge.cxx:565
virtual bool IsPolyObj() const override
Definition: svdoedge.cxx:2440
virtual sal_uInt32 GetPointCount() const override
Definition: svdoedge.cxx:2445
virtual void TakeObjInfo(SdrObjTransformInfoRec &rInfo) const override
Definition: svdoedge.cxx:375
virtual const tools::Rectangle & GetSnapRect() const override
Definition: svdoedge.cxx:407
virtual ~SdrEdgeObj() override
Definition: svdoedge.cxx:192
virtual void BrkCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2113
static SdrEscapeDirection ImpCalcEscAngle(SdrObject const *pObj, const Point &aPt2)
Definition: svdoedge.cxx:620
virtual SdrObjKind GetObjIdentifier() const override
Definition: svdoedge.cxx:392
virtual bool BckCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2105
virtual void RecalcSnapRect() override
Snap is not done on the BoundRect but if possible on logic coordinates (i.e.
Definition: svdoedge.cxx:417
virtual rtl::Reference< SdrObject > CloneSdrObject(SdrModel &rTargetModel) const override
Definition: svdoedge.cxx:1669
bool bEdgeTrackDirty
Definition: svdoedge.hxx:148
virtual basegfx::B2DPolyPolygon TakeXorPoly() const override
The Xor-Polygon is required by the View to drag the object.
Definition: svdoedge.cxx:1689
void DisconnectFromNode(bool bTail1) override
Definition: svdoedge.cxx:485
virtual bool MovCreate(SdrDragStat &rStat) override
Definition: svdoedge.cxx:2074
virtual rtl::Reference< SdrObject > getFullDragClone() const override
Definition: svdoedge.cxx:1853
virtual std::unique_ptr< SdrObjGeoData > NewGeoData() const override
A derived class must override these 3 methods if it has own geometric data that must be saved for Und...
Definition: svdoedge.cxx:2484
virtual std::unique_ptr< sdr::properties::BaseProperties > CreateObjectSpecificProperties() override
Definition: svdoedge.cxx:142
virtual void NbcSetAnchorPos(const Point &rPnt) override
Definition: svdoedge.cxx:2609
void ImpUndirtyEdgeTrack()
Definition: svdoedge.cxx:557
friend class ImpEdgeHdl
Definition: svdoedge.hxx:136
virtual void RestoreGeoData(const SdrObjGeoData &rGeo) override
Definition: svdoedge.cxx:2501
virtual void NbcMirror(const Point &rRef1, const Point &rRef2) override
Definition: svdoedge.cxx:2352
SdrObjConnection aCon1
Definition: svdoedge.hxx:141
sal_Int32 getGluePointIndex(bool bTail)
this method is used by the api to return a gluepoint id for a connection.
Definition: svdoedge.cxx:2595
virtual void NbcMove(const Size &aSize) override
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdoedge.cxx:2298
::basegfx::B2DPolygon getEdgeTrack() const
Definition: svdoedge.cxx:2633
void ImpDirtyEdgeTrack()
Definition: svdoedge.cxx:551
virtual std::unique_ptr< sdr::contact::ViewContact > CreateObjectSpecificViewContact() override
Definition: svdoedge.cxx:150
virtual void NbcRotate(const Point &rRef, Degree100 nAngle, double sn, double cs) override
Definition: svdoedge.cxx:2321
virtual OUString TakeObjNamePlural() const override
Definition: svdoedge.cxx:1684
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix &rMatrix, const basegfx::B2DPolyPolygon &rPolyPolygon) override
Definition: svdoedge.cxx:2625
XPolygon ImpCalcEdgeTrack(const XPolygon &rTrack0, SdrObjConnection &rCon1, SdrObjConnection &rCon2, SdrEdgeInfoRec *pInfo) const
Definition: svdoedge.cxx:717
virtual void NbcSetPoint(const Point &rPnt, sal_uInt32 i) override
Definition: svdoedge.cxx:2460
void SetEdgeTrackPath(const basegfx::B2DPolyPolygon &rPoly)
Definition: svdoedge.cxx:1706
virtual const SdrGluePointList * GetGluePointList() const override
Definition: svdoedge.cxx:460
virtual OUString getSpecialDragComment(const SdrDragStat &rDrag) const override
Definition: svdoedge.cxx:1982
SdrEdgeInfoRec aEdgeInfo
Definition: svdoedge.hxx:146
virtual PointerStyle GetCreatePointer() const override
get the cursor/pointer that signals creating this object
Definition: svdoedge.cxx:2127
virtual Point GetSnapPoint(sal_uInt32 i) const override
Definition: svdoedge.cxx:2432
static bool ImpFindConnector(const Point &rPt, const SdrPageView &rPV, SdrObjConnection &rCon, const SdrEdgeObj *pThis, OutputDevice *pOut=nullptr, SdrDragStat *pDragStat=nullptr)
Definition: svdoedge.cxx:2132
virtual void Notify(SfxBroadcaster &rBC, const SfxHint &rHint) override
Detects when a stylesheet is changed.
Definition: svdoedge.cxx:1606
basegfx::B2DPolygon ImplAddConnectorOverlay(const SdrDragMethod &rDragMethod, bool bTail1, bool bTail2, bool bDetail) const
Definition: svdoedge.cxx:1997
virtual basegfx::B2DPolyPolygon TakeCreatePoly(const SdrDragStat &rDrag) const override
Polygon dragged by the user when creating the object.
Definition: svdoedge.cxx:2120
virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const override
Definition: svdoedge.cxx:455
bool mbSuppressed
Definition: svdoedge.hxx:164
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix &rMatrix, basegfx::B2DPolyPolygon &rPolyPolygon) const override
Definition: svdoedge.cxx:2618
SdrObjConnection & GetConnection(bool bTail1)
Definition: svdoedge.hxx:199
virtual bool beginSpecialDrag(SdrDragStat &rDrag) const override
Definition: svdoedge.cxx:1865
void SetTailPoint(bool bTail, const Point &rPt)
Definition: svdoedge.cxx:2552
virtual Point GetPoint(sal_uInt32 i) const override
Definition: svdoedge.cxx:2450
virtual bool applySpecialDrag(SdrDragStat &rDrag) override
Definition: svdoedge.cxx:1880
virtual void handlePageChange(SdrPage *pOldPage, SdrPage *pNewPage) override
Definition: svdoedge.cxx:198
void setGluePointIndex(bool bTail, sal_Int32 nId=-1)
this method is used by the api to set a gluepoint for a connection nId == -1 : The best default point...
Definition: svdoedge.cxx:2563
bool bEdgeTrackUserDefined
Definition: svdoedge.hxx:149
virtual bool BegCreate(SdrDragStat &rStat) override
Every object must be able to create itself interactively.
Definition: svdoedge.cxx:2060
virtual void NbcShear(const Point &rRef, Degree100 nAngle, double tn, bool bVShear) override
Definition: svdoedge.cxx:2383
virtual void NbcSetSnapRect(const tools::Rectangle &rRect) override
Definition: svdoedge.cxx:2269
bool mbBoundRectCalculationRunning
Definition: svdoedge.hxx:160
virtual void SaveGeoData(SdrObjGeoData &rGeo) const override
Definition: svdoedge.cxx:2489
virtual const tools::Rectangle & GetCurrentBoundRect() const override
Definition: svdoedge.cxx:397
SdrObject * GetConnectedNode(bool bTail1) const override
Definition: svdoedge.cxx:494
virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const override
Definition: svdoedge.cxx:427
virtual OUString TakeObjNameSingul() const override
Definition: svdoedge.cxx:1674
void SetEdgeTrackDirty()
Definition: svdoedge.hxx:212
bool CheckNodeConnection(bool bTail1) const
Definition: svdoedge.cxx:507
sal_uInt16 nNotifyingCount
Definition: svdoedge.hxx:145
virtual sal_uInt32 GetHdlCount() const override
Via GetHdlCount the number of Handles can be retrieved.
Definition: svdoedge.cxx:1738
basegfx::B2DPolyPolygon GetEdgeTrackPath() const
Definition: svdoedge.cxx:1726
bool GetSuppressDefaultConnect() const
Definition: svdoedge.hxx:169
void Reformat()
updates edges that are connected to the edges of this object as if the connected objects send a repai...
Definition: svdoedge.cxx:1654
virtual sal_uInt32 GetSnapPointCount() const override
snap to special points of an Object (polygon points, center of circle)
Definition: svdoedge.cxx:2427
void ImpSetTailPoint(bool bTail1, const Point &rPt)
Definition: svdoedge.cxx:534
void ImpSetAttrToEdgeInfo()
Definition: svdoedge.cxx:212
virtual bool hasSpecialDrag() const override
The standard transformations (Move,Resize,Rotate,Mirror,Shear) are taken over by the View (TakeXorPol...
Definition: svdoedge.cxx:1848
Point GetTailPoint(bool bTail) const
Definition: svdoedge.cxx:2527
std::optional< XPolygon > pEdgeTrack
Definition: svdoedge.hxx:144
void ImpSetEdgeInfoToAttr()
Definition: svdoedge.cxx:282
virtual void AddToHdlList(SdrHdlList &rHdlList) const override
Definition: svdoedge.cxx:1767
SdrEdgeObj(SdrModel &rSdrModel)
Definition: svdoedge.cxx:156
virtual void TakeUnrotatedSnapRect(tools::Rectangle &rRect) const override
Definition: svdoedge.cxx:422
virtual rtl::Reference< SdrObject > DoConvertToPolyObj(bool bBezier, bool bAddText) const override
Definition: svdoedge.cxx:2413
sal_uInt16 FindGluePoint(sal_uInt16 nId) const
Definition: svdglue.cxx:336
sal_uInt16 GetCount() const
Definition: svdglue.hxx:194
void SetPercent(bool bOn)
Definition: svdglue.hxx:124
Point GetAbsolutePos(const SdrObject &rObj) const
Definition: svdglue.cxx:48
sal_uInt16 GetId() const
Definition: svdglue.hxx:112
void SetPos(const Point &rNewPos)
Definition: svdglue.hxx:100
SdrEscapeDirection GetEscDir() const
Definition: svdglue.hxx:104
const Point & GetPos() const
Definition: svdglue.hxx:96
void AddHdl(std::unique_ptr< SdrHdl > pHdl)
Definition: svdhdl.cxx:2291
SdrObject * GetObj() const
Definition: svdhdl.hxx:203
sal_uInt32 GetPointNum() const
Definition: svdhdl.hxx:222
SdrHintKind GetKind() const
Definition: svdmodel.hxx:132
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:69
sal_uInt16 GetMarkHdlSizePixel() const
Definition: svdmrkv.cxx:2211
Utility class SdrObjConnection.
Definition: svdoedge.hxx:40
bool TakeGluePoint(SdrGluePoint &rGP) const
Definition: svdoedge.cxx:58
sal_uInt16 GetConnectorId() const
Definition: svdoedge.hxx:67
void SetBestConnection(bool rB)
Definition: svdoedge.hxx:60
void ResetVars()
Definition: svdoedge.cxx:48
void SetBestVertex(bool rB)
Definition: svdoedge.hxx:61
void SetAutoVertex(bool rB)
Definition: svdoedge.hxx:62
bool IsAutoVertex() const
Definition: svdoedge.hxx:66
sal_uInt16 nConId
Definition: svdoedge.hxx:47
bool IsBestConnection() const
Definition: svdoedge.hxx:65
SdrObject * GetObject() const
Definition: svdoedge.hxx:68
SdrObject * pObj
Definition: svdoedge.hxx:46
void SetConnectorId(sal_uInt16 nId)
Definition: svdoedge.hxx:63
All geometrical data of an arbitrary object for use in undo/redo.
Definition: svdobj.hxx:175
SdrObject * GetObj(size_t nNum) const
Definition: svdpage.cxx:822
size_t GetObjCount() const
Definition: svdpage.cxx:816
Provides information about various ZObject properties.
Definition: svdobj.hxx:197
Abstract DrawObject.
Definition: svdobj.hxx:261
sal_uInt32 GetOrdNumDirect() const
Definition: svdobj.hxx:850
virtual void NbcSetAnchorPos(const Point &rPnt)
Definition: svdobj.cxx:1638
void ActionChanged() const
Definition: svdobj.cxx:273
const tools::Rectangle & getOutRectangle() const
Definition: svdobj.cxx:3178
virtual sdr::properties::BaseProperties & GetProperties() const
Definition: svdobj.cxx:220
const SfxBroadcaster * GetBroadcaster() const
Definition: svdobj.cxx:695
bool LineGeometryUsageIsNecessary() const
Definition: svdobj.cxx:1035
void RemoveListener(SfxListener &rListener)
Definition: svdobj.cxx:685
const SfxPoolItem & GetObjectItem(const sal_uInt16 nWhich) const
Definition: svdobj.cxx:2007
bool m_bSnapRectDirty
Definition: svdobj.hxx:908
static rtl::Reference< T > Clone(T const &rObj, SdrModel &rTargetModel)
Definition: svdobj.hxx:449
virtual const tools::Rectangle & GetCurrentBoundRect() const
Definition: svdobj.cxx:926
SdrModel & getSdrModelFromSdrObject() const
Definition: svdobj.cxx:289
virtual const tools::Rectangle & GetSnapRect() const
Definition: svdobj.cxx:1665
SdrObjUserCall * m_pUserCall
Definition: svdobj.hxx:903
virtual const OUString & GetName() const
Definition: svdobj.cxx:769
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix &rMatrix, const basegfx::B2DPolyPolygon &rPolyPolygon)
Definition: svdobj.cxx:3013
void SendUserCall(SdrUserCallType eUserCall, const tools::Rectangle &rBoundRect) const
Definition: svdobj.cxx:2766
virtual void SetChanged()
Definition: svdobj.cxx:1002
bool m_bIsEdge
Definition: svdobj.hxx:922
void AddListener(SfxListener &rListener)
Definition: svdobj.cxx:674
SdrPage * getSdrPageFromSdrObject() const
Definition: svdobj.cxx:279
virtual const SdrGluePointList * GetGluePointList() const
Definition: svdobj.cxx:2315
bool IsVisible() const
Definition: svdobj.hxx:762
OUString ImpGetDescriptionStr(TranslateId pStrCacheID) const
Definition: svdobj.cxx:1067
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:645
bool m_bClosedObj
Definition: svdobj.hxx:921
virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const
Definition: svdobj.cxx:2299
virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const
Definition: svdobj.cxx:2278
virtual void SetBoundRectDirty()
Definition: svdobj.cxx:329
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix &rMatrix, basegfx::B2DPolyPolygon &rPolyPolygon) const
Definition: svdobj.cxx:2986
virtual void SetBoundAndSnapRectsDirty(bool bNotMyself=false, bool bRecursive=true)
Definition: svdobj.cxx:509
const SfxItemSet & GetObjectItemSet() const
Definition: svdobj.cxx:1972
const SdrLayerIDSet & GetVisibleLayers() const
Definition: svdpagv.hxx:210
SdrObjList * GetObjList() const
Return current List.
Definition: svdpagv.hxx:169
SdrView & GetView()
Definition: svdpagv.hxx:130
A SdrPage contains exactly one SdrObjList and a description of the physical page dimensions (size / m...
Definition: svdpage.hxx:377
bool IsInserted() const
Definition: svdpage.hxx:464
OutputDevice * GetFirstOutputDevice() const
Definition: svdpntv.cxx:91
virtual void SaveGeoData(SdrObjGeoData &rGeo) const override
Definition: svdotext.cxx:1431
virtual void NbcMirror(const Point &rRef1, const Point &rRef2) override
Definition: svdotxtr.cxx:232
virtual void RestoreGeoData(const SdrObjGeoData &rGeo) override
Definition: svdotext.cxx:1439
virtual void NbcShear(const Point &rRef, Degree100 nAngle, double tn, bool bVShear) override
Definition: svdotxtr.cxx:210
virtual void NbcMove(const Size &rSiz) override
The methods Move, Resize, Rotate, Mirror, Shear, SetSnapRect and SetLogicRect call the corresponding ...
Definition: svdotxtr.cxx:94
tools::Rectangle maRect
Definition: svdotext.hxx:168
rtl::Reference< SdrPathObj > ImpConvertMakeObj(const basegfx::B2DPolyPolygon &rPolyPolygon, bool bClosed, bool bBezier) const
Definition: svdotxtr.cxx:418
bool ImpCanConvTextToCurve() const
Definition: svdotxtr.cxx:413
virtual bool HasText() const override
Definition: svdotxat.cxx:418
virtual void handlePageChange(SdrPage *pOldPage, SdrPage *pNewPage) override
Definition: svdotext.cxx:474
rtl::Reference< SdrObject > ImpConvertAddText(rtl::Reference< SdrObject > pObj, bool bBezier) const
Definition: svdotxtr.cxx:452
virtual void NbcResize(const Point &rRef, const Fraction &xFact, const Fraction &yFact) override
Definition: svdotxtr.cxx:102
virtual void NbcRotate(const Point &rRef, Degree100 nAngle, double sn, double cs) override
Definition: svdotxtr.cxx:186
SfxHintId GetId() const
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
void Remove(sal_uInt16 nPos, sal_uInt16 nCount)
Definition: _xpoly.cxx:376
sal_uInt16 GetPointCount() const
Definition: _xpoly.cxx:346
void Insert(sal_uInt16 nPos, const Point &rPt, PolyFlags eFlags)
Definition: _xpoly.cxx:352
void SetFlags(sal_uInt16 nPos, PolyFlags eFlags)
set the flags for the point at the given position
Definition: _xpoly.cxx:459
basegfx::B2DPolygon getB2DPolygon() const
Definition: _xpoly.cxx:811
B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const
void append(const B2DPolygon &rPolygon, sal_uInt32 nCount=1)
sal_uInt32 count() const
void append(const basegfx::B2DPoint &rPoint, sal_uInt32 nCount)
TYPE getX() const
TYPE getY() const
virtual void ClearObjectItemDirect(const sal_uInt16 nWhich)=0
virtual void SetObjectItemDirect(const SfxPoolItem &rItem)=0
constexpr Point Center() const
bool Contains(const Point &rPOINT) const
bool Overlaps(const tools::Rectangle &rRect) const
constexpr tools::Long Top() const
constexpr Point TopLeft() const
void Move(tools::Long nHorzMoveDelta, tools::Long nVertMoveDelta)
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr Point BottomRight() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
int nCount
OUString SvxResId(TranslateId aId)
Definition: dialmgr.cxx:24
virtual css::uno::Reference< css::embed::XEmbeddedObject > GetObject() override
OUString sName
SfxHintId
sal_Int32 nIndex
OUString aName
sal_Int64 n
int n2
int n1
B2IRange fround(const B2DRange &rRange)
int i
long Long
sal_Int16 nId
#define Y
PointerStyle
SdrObject * SdrObjectPrimitiveHit(const SdrObject &rObject, const Point &rPnt, sal_uInt16 nTol, const SdrPageView &rSdrPageView, const SdrLayerIDSet *pVisiLayer, bool bTextOnly, drawinglayer::primitive2d::Primitive2DContainer *pHitContainer)
static SfxItemSet & rSet
constexpr TypedWhichId< SdrEdgeNode1HorzDistItem > SDRATTR_EDGENODE1HORZDIST(SDRATTR_EDGE_FIRST+1)
constexpr TypedWhichId< SdrEdgeLineDeltaCountItem > SDRATTR_EDGELINEDELTACOUNT(SDRATTR_EDGE_FIRST+7)
constexpr TypedWhichId< SdrEdgeKindItem > SDRATTR_EDGEKIND(SDRATTR_EDGE_FIRST+0)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE2DELTA(SDRATTR_EDGE_FIRST+9)
constexpr TypedWhichId< SdrEdgeNode1VertDistItem > SDRATTR_EDGENODE1VERTDIST(SDRATTR_EDGE_FIRST+2)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE3DELTA(SDRATTR_EDGE_FIRST+10)
constexpr TypedWhichId< SdrEdgeNode2HorzDistItem > SDRATTR_EDGENODE2HORZDIST(SDRATTR_EDGE_FIRST+3)
constexpr TypedWhichId< SdrMetricItem > SDRATTR_EDGELINE1DELTA(SDRATTR_EDGE_FIRST+8)
constexpr TypedWhichId< SdrEdgeNode2VertDistItem > SDRATTR_EDGENODE2VERTDIST(SDRATTR_EDGE_FIRST+4)
SdrEscapeDirection
Definition: svdglue.hxx:35
#define SDRGLUEPOINT_NOTFOUND
Definition: svdglue.hxx:181
SdrObjKind
Definition: svdobjkind.hxx:25
@ Edge
OLE object.
SdrEdgeLineCode
Definition: svdoedge.hxx:72
void ResizeXPoly(XPolygon &rPoly, const Point &rRef, const Fraction &xFact, const Fraction &yFact)
Definition: svdtrans.cxx:73
void ShearXPoly(XPolygon &rPoly, const Point &rRef, double tn, bool bVShear)
Definition: svdtrans.cxx:155
void RotateXPoly(XPolygon &rPoly, const Point &rRef, double sn, double cs)
Definition: svdtrans.cxx:89
void MirrorPoint(Point &rPnt, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:105
tools::Long BigMulDiv(tools::Long nVal, tools::Long nMul, tools::Long nDiv)
Definition: svdtrans.cxx:552
void MoveXPoly(XPolygon &rPoly, const Size &S)
Definition: svdtrans.cxx:33
void MirrorXPoly(XPolygon &rPoly, const Point &rRef1, const Point &rRef2)
Definition: svdtrans.cxx:139
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
SdrCreateCmd
Definition: svdtypes.hxx:27
SdrEdgeKind
Definition: sxekitm.hxx:27
SdrMetricItem makeSdrEdgeLine2DeltaItem(tools::Long nVal)
Definition: sxelditm.hxx:43
SdrMetricItem makeSdrEdgeLine1DeltaItem(tools::Long nVal)
Definition: sxelditm.hxx:38
SdrMetricItem makeSdrEdgeLine3DeltaItem(tools::Long nVal)
Definition: sxelditm.hxx:48
oslFileHandle & pOut
#define XPOLY_APPEND
Definition: xpoly.hxx:38