1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
24 #include <svx/svdotext.hxx>
25 #include <svx/svdglue.hxx>
26 #include <svx/svxdllapi.h>
27 #include <svx/xpoly.hxx>
33 namespace sdr::properties
{
34 class ConnectorProperties
;
38 /// Utility class SdrObjConnection
39 class SdrObjConnection final
41 friend class SdrEdgeObj
;
42 friend class ImpEdgeHdl
;
43 friend class SdrCreateView
;
45 Point m_aObjOfs
; // set during dragging of a node
46 SdrObject
* m_pSdrObj
; // referenced object
47 sal_uInt16 m_nConId
; // connector number
49 bool m_bBestConn
: 1; // true -> the best-matching connector is searched for
50 bool m_bBestVertex
: 1; // true -> the best-matching vertex to connect is searched for
51 bool m_bAutoVertex
: 1; // autoConnector at apex nCon
52 bool m_bAutoCorner
: 1; // autoConnector at corner nCon
55 SdrObjConnection() { ResetVars(); }
58 bool TakeGluePoint(SdrGluePoint
& rGP
) const;
60 void SetBestConnection( bool rB
) { m_bBestConn
= rB
; };
61 void SetBestVertex( bool rB
) { m_bBestVertex
= rB
; };
62 void SetAutoVertex( bool rB
) { m_bAutoVertex
= rB
; };
63 void SetConnectorId( sal_uInt16 nId
) { m_nConId
= nId
; };
65 bool IsBestConnection() const { return m_bBestConn
; };
66 bool IsAutoVertex() const { return m_bAutoVertex
; };
67 sal_uInt16
GetConnectorId() const { return m_nConId
; };
68 SdrObject
* GetSdrObject() const { return m_pSdrObj
; }
72 enum class SdrEdgeLineCode
{ Obj1Line2
, Obj1Line3
, Obj2Line2
, Obj2Line3
, MiddleLine
};
74 /// Utility class SdrEdgeInfoRec
78 // The 5 distances are set on dragging or via SetAttr and are
79 // evaluated by ImpCalcEdgeTrack. Only 0-3 longs are transported
80 // via Get/SetAttr/Get/SetStyleSh though.
87 // Following values are set by ImpCalcEdgeTrack
88 tools::Long m_nAngle1
; // exit angle at Obj1
89 tools::Long m_nAngle2
; // exit angle at Obj2
90 sal_uInt16 m_nObj1Lines
; // 1..3
91 sal_uInt16 m_nObj2Lines
; // 1..3
92 sal_uInt16 m_nMiddleLine
; // 0xFFFF=none, otherwise point number of the beginning of the line
94 // The value determines how curved connectors are routed. With value 'true' it is routed
95 // compatible to OOXML, with value 'false' LO routing is used.
96 // The value is set/get via property SDRATTR_EDGEOOXMLCURVE.
97 bool m_bUseOOXMLCurve
;
105 m_nMiddleLine(0xFFFF),
106 m_bUseOOXMLCurve(false)
109 Point
& ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode
);
110 sal_uInt16
ImpGetPolyIdx(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const;
111 bool ImpIsHorzLine(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const;
112 void ImpSetLineOffset(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
, tools::Long nVal
);
113 tools::Long
ImpGetLineOffset(SdrEdgeLineCode eLineCode
, const XPolygon
& rXP
) const;
117 /// Utility class SdrEdgeObjGeoData
118 class SdrEdgeObjGeoData final
: public SdrTextObjGeoData
121 SdrObjConnection m_aCon1
; // connection status of the beginning of the line
122 SdrObjConnection m_aCon2
; // connection status of the end of the line
123 std::optional
<XPolygon
> m_pEdgeTrack
;
124 bool m_bEdgeTrackDirty
; // true -> connector track needs to be recalculated
125 bool m_bEdgeTrackUserDefined
;
126 SdrEdgeInfoRec m_aEdgeInfo
;
130 virtual ~SdrEdgeObjGeoData() override
;
134 /// Utility class SdrEdgeObj
135 class SVXCORE_DLLPUBLIC SdrEdgeObj final
: public SdrTextObj
138 // to allow sdr::properties::ConnectorProperties access to ImpSetAttrToEdgeInfo()
139 friend class sdr::properties::ConnectorProperties
;
141 friend class SdrCreateView
;
142 friend class ImpEdgeHdl
;
144 SAL_DLLPRIVATE
virtual std::unique_ptr
<sdr::contact::ViewContact
> CreateObjectSpecificViewContact() override
;
145 SAL_DLLPRIVATE
virtual std::unique_ptr
<sdr::properties::BaseProperties
> CreateObjectSpecificProperties() override
;
147 SdrObjConnection m_aCon1
; // Connection status of the beginning of the line
148 SdrObjConnection m_aCon2
; // Connection status of the end of the line
150 std::optional
<XPolygon
> m_pEdgeTrack
;
151 sal_uInt16 m_nNotifyingCount
; // Locking
152 SdrEdgeInfoRec m_aEdgeInfo
;
154 bool m_bEdgeTrackDirty
: 1; // true -> Connection track needs to be recalculated
155 bool m_bEdgeTrackUserDefined
: 1;
157 // Bool to allow suppression of default connects at object
158 // inside test (HitTest) and object center test (see ImpFindConnector())
159 bool mbSuppressDefaultConnect
: 1;
161 // Flag value for avoiding infinite loops when calculating
162 // BoundRects from ring-connected connectors. A coloring algorithm
163 // is used here. When the GetCurrentBoundRect() calculation of a
164 // SdrEdgeObj is running, the flag is set, else it is always
166 bool mbBoundRectCalculationRunning
: 1;
168 // #i123048# need to remember if layouting was suppressed before to get
169 // to a correct state for first real layouting
170 bool mbSuppressed
: 1;
173 // Interface to default connect suppression
174 void SetSuppressDefaultConnect(bool bNew
) { mbSuppressDefaultConnect
= bNew
; }
175 bool GetSuppressDefaultConnect() const { return mbSuppressDefaultConnect
; }
178 SAL_DLLPRIVATE
virtual void Notify(SfxBroadcaster
& rBC
, const SfxHint
& rHint
) override
;
180 SAL_DLLPRIVATE
static XPolygon
ImpCalcObjToCenter(const Point
& rStPt
, tools::Long nEscAngle
, const tools::Rectangle
& rRect
, const Point
& rCenter
);
181 SAL_DLLPRIVATE
void ImpRecalcEdgeTrack(); // recalculation of the connection track
182 SAL_DLLPRIVATE XPolygon
ImpCalcEdgeTrack(const XPolygon
& rTrack0
, SdrObjConnection
& rCon1
, SdrObjConnection
& rCon2
, SdrEdgeInfoRec
* pInfo
) const;
183 SAL_DLLPRIVATE XPolygon
ImpCalcEdgeTrack(const Point
& rPt1
, tools::Long nAngle1
, const tools::Rectangle
& rBoundRect1
, const tools::Rectangle
& rBewareRect1
,
184 const Point
& rPt2
, tools::Long nAngle2
, const tools::Rectangle
& rBoundRect2
, const tools::Rectangle
& rBewareRect2
,
185 sal_uIntPtr
* pnQuality
, SdrEdgeInfoRec
* pInfo
) const;
186 SAL_DLLPRIVATE
static bool ImpFindConnector(const Point
& rPt
, const SdrPageView
& rPV
, SdrObjConnection
& rCon
, const SdrEdgeObj
* pThis
, OutputDevice
* pOut
=nullptr, SdrDragStat
* pDragStat
= nullptr);
187 SAL_DLLPRIVATE
static SdrEscapeDirection
ImpCalcEscAngle(SdrObject
const * pObj
, const Point
& aPt2
);
188 SAL_DLLPRIVATE
void ImpSetTailPoint(bool bTail1
, const Point
& rPt
);
189 SAL_DLLPRIVATE
void ImpUndirtyEdgeTrack(); // potential recalculation of the connection track
190 SAL_DLLPRIVATE
void ImpDirtyEdgeTrack(); // invalidate connector path, so it will be recalculated next time
191 SAL_DLLPRIVATE
void ImpSetAttrToEdgeInfo(); // copying values from the pool to aEdgeInfo
192 SAL_DLLPRIVATE
void ImpSetEdgeInfoToAttr(); // copying values from the aEdgeInfo to the pool
194 // protected destructor
195 SAL_DLLPRIVATE
virtual ~SdrEdgeObj() override
;
198 SdrEdgeObj(SdrModel
& rSdrModel
);
200 SAL_DLLPRIVATE
SdrEdgeObj(SdrModel
& rSdrModel
, SdrEdgeObj
const & rSource
);
202 // react on model/page change
203 SAL_DLLPRIVATE
virtual void handlePageChange(SdrPage
* pOldPage
, SdrPage
* pNewPage
) override
;
205 SdrObjConnection
& GetConnection(bool bTail1
) { return *(bTail1
? &m_aCon1
: &m_aCon2
); }
206 SAL_DLLPRIVATE
virtual void TakeObjInfo(SdrObjTransformInfoRec
& rInfo
) const override
;
207 SAL_DLLPRIVATE
virtual SdrObjKind
GetObjIdentifier() const override
;
208 SAL_DLLPRIVATE
virtual const tools::Rectangle
& GetCurrentBoundRect() const override
;
209 SAL_DLLPRIVATE
virtual const tools::Rectangle
& GetSnapRect() const override
;
210 SAL_DLLPRIVATE
virtual SdrGluePoint
GetVertexGluePoint(sal_uInt16 nNum
) const override
;
211 SAL_DLLPRIVATE
virtual SdrGluePoint
GetCornerGluePoint(sal_uInt16 nNum
) const override
;
212 SAL_DLLPRIVATE
virtual const SdrGluePointList
* GetGluePointList() const override
;
213 SAL_DLLPRIVATE
virtual SdrGluePointList
* ForceGluePointList() override
;
215 // * for all of the below: bTail1=true: beginning of the line,
216 // otherwise end of the line
217 // * pObj=NULL: disconnect connector
218 void SetEdgeTrackDirty() { m_bEdgeTrackDirty
=true; }
219 void ConnectToNode(bool bTail1
, SdrObject
* pObj
) override
;
220 SAL_DLLPRIVATE
void DisconnectFromNode(bool bTail1
) override
;
221 SdrObject
* GetConnectedNode(bool bTail1
) const override
;
222 const SdrObjConnection
& GetConnection(bool bTail1
) const { return *(bTail1
? &m_aCon1
: &m_aCon2
); }
223 SAL_DLLPRIVATE
bool CheckNodeConnection(bool bTail1
) const;
225 SAL_DLLPRIVATE
virtual void RecalcSnapRect() override
;
226 SAL_DLLPRIVATE
virtual void TakeUnrotatedSnapRect(tools::Rectangle
& rRect
) const override
;
227 virtual rtl::Reference
<SdrObject
> CloneSdrObject(SdrModel
& rTargetModel
) const override
;
228 SAL_DLLPRIVATE
virtual OUString
TakeObjNameSingul() const override
;
229 SAL_DLLPRIVATE
virtual OUString
TakeObjNamePlural() const override
;
231 void SetEdgeTrackPath( const basegfx::B2DPolyPolygon
& rPoly
);
232 basegfx::B2DPolyPolygon
GetEdgeTrackPath() const;
234 SAL_DLLPRIVATE
virtual basegfx::B2DPolyPolygon
TakeXorPoly() const override
;
235 SAL_DLLPRIVATE
virtual sal_uInt32
GetHdlCount() const override
;
236 SAL_DLLPRIVATE
virtual void AddToHdlList(SdrHdlList
& rHdlList
) const override
;
238 // special drag methods
239 SAL_DLLPRIVATE
virtual bool hasSpecialDrag() const override
;
240 SAL_DLLPRIVATE
virtual bool beginSpecialDrag(SdrDragStat
& rDrag
) const override
;
241 SAL_DLLPRIVATE
virtual bool applySpecialDrag(SdrDragStat
& rDrag
) override
;
242 SAL_DLLPRIVATE
virtual OUString
getSpecialDragComment(const SdrDragStat
& rDrag
) const override
;
245 SAL_DLLPRIVATE
virtual rtl::Reference
<SdrObject
> getFullDragClone() const override
;
247 SAL_DLLPRIVATE
virtual void NbcSetSnapRect(const tools::Rectangle
& rRect
) override
;
248 SAL_DLLPRIVATE
virtual void NbcMove(const Size
& aSize
) override
;
249 SAL_DLLPRIVATE
virtual void NbcResize(const Point
& rRefPnt
, const Fraction
& aXFact
, const Fraction
& aYFact
) override
;
251 // #i54102# added rotate, mirror and shear support
252 SAL_DLLPRIVATE
virtual void NbcRotate(const Point
& rRef
, Degree100 nAngle
, double sn
, double cs
) override
;
253 SAL_DLLPRIVATE
virtual void NbcMirror(const Point
& rRef1
, const Point
& rRef2
) override
;
254 SAL_DLLPRIVATE
virtual void NbcShear(const Point
& rRef
, Degree100 nAngle
, double tn
, bool bVShear
) override
;
256 // #102344# Added missing implementation
257 SAL_DLLPRIVATE
virtual void NbcSetAnchorPos(const Point
& rPnt
) override
;
259 SAL_DLLPRIVATE
virtual bool BegCreate(SdrDragStat
& rStat
) override
;
260 SAL_DLLPRIVATE
virtual bool MovCreate(SdrDragStat
& rStat
) override
;
261 SAL_DLLPRIVATE
virtual bool EndCreate(SdrDragStat
& rStat
, SdrCreateCmd eCmd
) override
;
262 SAL_DLLPRIVATE
virtual bool BckCreate(SdrDragStat
& rStat
) override
;
263 SAL_DLLPRIVATE
virtual void BrkCreate(SdrDragStat
& rStat
) override
;
264 SAL_DLLPRIVATE
virtual basegfx::B2DPolyPolygon
TakeCreatePoly(const SdrDragStat
& rDrag
) const override
;
265 SAL_DLLPRIVATE
virtual PointerStyle
GetCreatePointer() const override
;
266 SAL_DLLPRIVATE
virtual rtl::Reference
<SdrObject
> DoConvertToPolyObj(bool bBezier
, bool bAddText
) const override
;
268 SAL_DLLPRIVATE
virtual sal_uInt32
GetSnapPointCount() const override
;
269 SAL_DLLPRIVATE
virtual Point
GetSnapPoint(sal_uInt32 i
) const override
;
270 SAL_DLLPRIVATE
virtual bool IsPolyObj() const override
;
271 SAL_DLLPRIVATE
virtual sal_uInt32
GetPointCount() const override
;
272 SAL_DLLPRIVATE
virtual Point
GetPoint(sal_uInt32 i
) const override
;
273 SAL_DLLPRIVATE
virtual void NbcSetPoint(const Point
& rPnt
, sal_uInt32 i
) override
;
275 SAL_DLLPRIVATE
virtual std::unique_ptr
<SdrObjGeoData
> NewGeoData() const override
;
276 SAL_DLLPRIVATE
virtual void SaveGeoData(SdrObjGeoData
& rGeo
) const override
;
277 SAL_DLLPRIVATE
virtual void RestoreGeoData(const SdrObjGeoData
& rGeo
) override
;
279 /** updates edges that are connected to the edges of this object
280 as if the connected objects send a repaint broadcast
283 SAL_DLLPRIVATE
void Reformat();
285 // helper methods for the StarOffice api
286 SAL_DLLPRIVATE Point
GetTailPoint( bool bTail
) const;
287 void SetTailPoint( bool bTail
, const Point
& rPt
);
288 SAL_DLLPRIVATE
void setGluePointIndex( bool bTail
, sal_Int32 nId
= -1 );
289 SAL_DLLPRIVATE sal_Int32
getGluePointIndex( bool bTail
);
291 SAL_DLLPRIVATE
virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix
& rMatrix
, basegfx::B2DPolyPolygon
& rPolyPolygon
) const override
;
292 SAL_DLLPRIVATE
virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix
& rMatrix
, const basegfx::B2DPolyPolygon
& rPolyPolygon
) override
;
294 // for geometry access
295 SAL_DLLPRIVATE ::basegfx::B2DPolygon
getEdgeTrack() const;
297 // helper method for SdrDragMethod::AddConnectorOverlays. Adds an overlay polygon for
298 // this connector to rResult.
299 SAL_DLLPRIVATE
basegfx::B2DPolygon
ImplAddConnectorOverlay(const SdrDragMethod
& rDragMethod
, bool bTail1
, bool bTail2
, bool bDetail
) const;
302 // The following item parameters of the SdrItemPool are used to
303 // determine the actual connector line routing:
305 // sal_uInt16 EdgeFlowAngle default 9000 (= 90.00 deg), min 0, max 9000
307 // The angle at which the connecting line may run.
309 // sal_uInt16 EdgeEscAngle default 9000 (= 90.00 Deg), min 0, max 9000
310 // Object exit angle.
311 // The angle at which the connection line may exit from the object.
313 // bool EdgeEscAsRay default false
314 // true -> the connecting line emerges from the object radially.
315 // Thus, angle specification by the line ObjCenter / connector.
317 // bool EdgeEscUseObjAngle default false
318 // Object rotation angle is considered
319 // true -> when determining the connector exit angle, angle for
320 // object rotation is taken as an offset.
322 // sal_uIntPtr EdgeFlowDefDist default 0, min 0, max ?
323 // This is the default minimum distance on calculation of the
324 // connection Line to the docked objects is in logical units.
325 // This distance is overridden within the object, as soon as the
326 // user drags on the lines. When docking onto a new object,
327 // however, this default is used again.
330 // General Information About Connectors:
332 // There are nodes and edge objects. Two nodes can be joined by an
333 // edge. If a connector is connected to a node only at one end, the
334 // other end is fixed to an absolute position in the document. It is
335 // of course also possible for a connector to be "free" at both ends,
336 // i.e. not connected to a node object on each side.
338 // A connector object can also theoretically be a node object at the
339 // same time. In the first version, however, this will not yet be
342 // A connection between node and connector edge can be established by:
343 // - Interactive creation of a new edge object at the SdrView where
344 // the beginning or end point of the edge is placed on a connector
345 // (glueing point) of an already existing node object.
346 // - Interactive dragging of the beginning or end point of an
347 // existing connector edge object on the SdrView to a connector
348 // (glueing point) of an already existing node object.
350 // Moving node objects does not make any connections. Also not the
351 // direct shifting of edge endpoints on the SdrModel... Connections
352 // can also be established, if the connectors are not configured to
353 // be visible in the view.
355 // An existing connection between node and edge is retained for:
356 // - Dragging (Move/Resize/Rotate/...) of the node object
357 // - Moving a connector position in the node object
358 // - Simultaneous dragging (Move/Resize/Rotate/...) of the node and the
361 // A connection between node and edge can be removed by:
362 // - Deleting one of the objects
363 // - Dragging the edge object without simultaneously dragging the node
364 // - Deleting the connector at the node object
365 // - Undo/Redo/Repeat
366 // When dragging, the request to remove the connection must be
367 // requested from outside of the model (for example, from the
368 // SdrView). SdrEdgeObj::Move() itself does not remove the
371 // Each node object can have connectors, so-called gluepoints. These
372 // are the geometric points at which the connecting edge object ends
373 // when the connection is established. By default, each object has no
374 // connectors. Nevertheless, one can dock an edge in certain view
375 // settings since then, e.g., connectors can be automatically
376 // generated at the 4 vertices of the node object when needed. Each
377 // object provides 2x4 so-called default connector positions, 4 at
378 // the vertices and 4 at the corner positions. In the normal case,
379 // these are located at the 8 handle positions; exceptions here are
380 // ellipses, parallelograms, ... . In addition, user-specific
381 // connectors can be set for each node object.
383 // Then there is also the possibility to dock an edge on an object
384 // with the attribute "bUseBestConnector". The best-matching
385 // connector position for the routing of the connection line is then
386 // used from the offering of connectors of the object or/and of the
387 // vertices. The user assigns this attribute by docking the node in
388 // its center (see, e.g., Visio).
389 // 09-06-1996: bUseBestConnector uses vertex gluepoints only.
391 // And here is some terminology:
392 // Connector : The connector object (edge object)
393 // Node : Any object to which a connector can be glued to, e.g., a rectangle,
395 // Gluepoint: The point at which the connector is glued to the node object.
397 // Vertex gluepoints: Each node object presents these glue
398 // points inherently. Perhaps there is already the option
399 // "automatically glue to object vertex" in Draw (default is
401 // Corner gluepoints: These gluepoints, too, are already
402 // auto-enabled on objects. Similar to the ones above,
403 // there may already be an option for them in Draw (default is
405 // In contrast to Visio, vertex gluepoints and corner glue
406 // points are not displayed in the UI; they are simply there (if
407 // the option is activated).
408 // Custom gluepoints: Any number of them are present on each
409 // node object. They can be made visible using the option
410 // (always visible when editing). At the moment, however, they
411 // are not yet fully implemented.
412 // Automatic gluepoint selection: If the connector is docked
413 // to the node object so that the black frame encompasses the
414 // entire object, then the connector tries to find the most
415 // convenient of the 4 vertex gluepoints (and only of those).
417 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */