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