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 #ifndef INCLUDED_SVX_SVDOEDGE_HXX
21 #define INCLUDED_SVX_SVDOEDGE_HXX
22 
23 #include <memory>
24 #include <svx/svdotext.hxx>
25 #include <svx/svdglue.hxx>
26 #include <svx/svxdllapi.h>
27 
28 
29 class SdrDragMethod;
30 class SdrPageView;
31 
32 namespace sdr::properties {
33     class ConnectorProperties;
34 }
35 
36 
37 /// Utility class SdrObjConnection
38 class SdrObjConnection final
39 {
40     friend class                SdrEdgeObj;
41     friend class                ImpEdgeHdl;
42     friend class                SdrCreateView;
43 
44     Point                       aObjOfs;       // set during dragging of a node
45     SdrObject*                  pObj;          // referenced object
46     sal_uInt16                  nConId;        // connector number
47 
48     bool                        bBestConn : 1;   // true -> the best-matching connector is searched for
49     bool                        bBestVertex : 1; // true -> the best-matching vertex to connect is searched for
50     bool                        bAutoVertex : 1; // autoConnector at apex nCon
51     bool                        bAutoCorner : 1; // autoConnector at corner nCon
52 
53 public:
SdrObjConnection()54     SdrObjConnection() { ResetVars(); }
55 
56     void ResetVars();
57     bool TakeGluePoint(SdrGluePoint& rGP) const;
58 
SetBestConnection(bool rB)59     void SetBestConnection( bool rB ) { bBestConn = rB; };
SetBestVertex(bool rB)60     void SetBestVertex( bool rB ) { bBestVertex = rB; };
SetAutoVertex(bool rB)61     void SetAutoVertex( bool rB ) { bAutoVertex = rB; };
SetConnectorId(sal_uInt16 nId)62     void SetConnectorId( sal_uInt16 nId ) { nConId = nId; };
63 
IsBestConnection() const64     bool IsBestConnection() const { return bBestConn; };
IsAutoVertex() const65     bool IsAutoVertex() const { return bAutoVertex; };
GetConnectorId() const66     sal_uInt16 GetConnectorId() const { return nConId; };
GetObject() const67     SdrObject* GetObject() const { return pObj; }
68 };
69 
70 
71 enum class SdrEdgeLineCode { Obj1Line2, Obj1Line3, Obj2Line2, Obj2Line3, MiddleLine };
72 
73 /// Utility class SdrEdgeInfoRec
74 class SdrEdgeInfoRec
75 {
76 public:
77     // The 5 distances are set on dragging or via SetAttr and are
78     // evaluated by ImpCalcEdgeTrack. Only 0-3 longs are transported
79     // via Get/SetAttr/Get/SetStyleSh though.
80     Point                       aObj1Line2;
81     Point                       aObj1Line3;
82     Point                       aObj2Line2;
83     Point                       aObj2Line3;
84     Point                       aMiddleLine;
85 
86     // Following values are set by ImpCalcEdgeTrack
87     tools::Long                        nAngle1;           // exit angle at Obj1
88     tools::Long                        nAngle2;           // exit angle at Obj2
89     sal_uInt16                  nObj1Lines;        // 1..3
90     sal_uInt16                  nObj2Lines;        // 1..3
91     sal_uInt16                  nMiddleLine;       // 0xFFFF=none, otherwise point number of the beginning of the line
92 
93 public:
SdrEdgeInfoRec()94     SdrEdgeInfoRec()
95     :   nAngle1(0),
96         nAngle2(0),
97         nObj1Lines(0),
98         nObj2Lines(0),
99         nMiddleLine(0xFFFF)
100     {}
101 
102     Point& ImpGetLineOffsetPoint(SdrEdgeLineCode eLineCode);
103     sal_uInt16 ImpGetPolyIdx(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
104     bool ImpIsHorzLine(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
105     void ImpSetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP, tools::Long nVal);
106     tools::Long ImpGetLineOffset(SdrEdgeLineCode eLineCode, const XPolygon& rXP) const;
107 };
108 
109 
110 /// Utility class SdrEdgeObjGeoData
111 class SdrEdgeObjGeoData final : public SdrTextObjGeoData
112 {
113 public:
114     SdrObjConnection            aCon1;  // connection status of the beginning of the line
115     SdrObjConnection            aCon2;  // connection status of the end of the line
116     std::unique_ptr<XPolygon>   pEdgeTrack;
117     bool                        bEdgeTrackDirty; // true -> connector track needs to be recalculated
118     bool                        bEdgeTrackUserDefined;
119     SdrEdgeInfoRec              aEdgeInfo;
120 
121 public:
122     SdrEdgeObjGeoData();
123     virtual ~SdrEdgeObjGeoData() override;
124 };
125 
126 
127 /// Utility class SdrEdgeObj
128 class SVXCORE_DLLPUBLIC SdrEdgeObj : public SdrTextObj
129 {
130 private:
131     // to allow sdr::properties::ConnectorProperties access to ImpSetAttrToEdgeInfo()
132     friend class sdr::properties::ConnectorProperties;
133 
134     friend class                SdrCreateView;
135     friend class                ImpEdgeHdl;
136 
137 protected:
138     virtual std::unique_ptr<sdr::contact::ViewContact> CreateObjectSpecificViewContact() override;
139     virtual std::unique_ptr<sdr::properties::BaseProperties> CreateObjectSpecificProperties() override;
140 
141     SdrObjConnection            aCon1;  // Connection status of the beginning of the line
142     SdrObjConnection            aCon2;  // Connection status of the end of the line
143 
144     std::unique_ptr<XPolygon>   pEdgeTrack;
145     sal_uInt16                  nNotifyingCount; // Locking
146     SdrEdgeInfoRec              aEdgeInfo;
147 
148     bool                        bEdgeTrackDirty : 1; // true -> Connection track needs to be recalculated
149     bool                        bEdgeTrackUserDefined : 1;
150 
151     // Bool to allow suppression of default connects at object
152     // inside test (HitTest) and object center test (see ImpFindConnector())
153     bool                        mbSuppressDefaultConnect : 1;
154 
155     // Flag value for avoiding infinite loops when calculating
156     // BoundRects from ring-connected connectors. A coloring algorithm
157     // is used here. When the GetCurrentBoundRect() calculation of a
158     // SdrEdgeObj is running, the flag is set, else it is always
159     // false.
160     bool                        mbBoundRectCalculationRunning : 1;
161 
162     // #i123048# need to remember if layouting was suppressed before to get
163     // to a correct state for first real layouting
164     bool                        mbSuppressed : 1;
165 
166 public:
167     // Interface to default connect suppression
SetSuppressDefaultConnect(bool bNew)168     void SetSuppressDefaultConnect(bool bNew) { mbSuppressDefaultConnect = bNew; }
GetSuppressDefaultConnect() const169     bool GetSuppressDefaultConnect() const { return mbSuppressDefaultConnect; }
170 
171 protected:
172     virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
173 
174     static XPolygon ImpCalcObjToCenter(const Point& rStPt, tools::Long nEscAngle, const tools::Rectangle& rRect, const Point& rCenter);
175     void ImpRecalcEdgeTrack();   // recalculation of the connection track
176     XPolygon ImpCalcEdgeTrack(const XPolygon& rTrack0, SdrObjConnection& rCon1, SdrObjConnection& rCon2, SdrEdgeInfoRec* pInfo) const;
177     XPolygon ImpCalcEdgeTrack(const Point& rPt1, tools::Long nAngle1, const tools::Rectangle& rBoundRect1, const tools::Rectangle& rBewareRect1,
178         const Point& rPt2, tools::Long nAngle2, const tools::Rectangle& rBoundRect2, const tools::Rectangle& rBewareRect2,
179         sal_uIntPtr* pnQuality, SdrEdgeInfoRec* pInfo) const;
180     static bool ImpFindConnector(const Point& rPt, const SdrPageView& rPV, SdrObjConnection& rCon, const SdrEdgeObj* pThis, OutputDevice* pOut=nullptr, SdrDragStat* pDragStat = nullptr);
181     static SdrEscapeDirection ImpCalcEscAngle(SdrObject const * pObj, const Point& aPt2);
182     void ImpSetTailPoint(bool bTail1, const Point& rPt);
183     void ImpUndirtyEdgeTrack();  // potential recalculation of the connection track
184     void ImpDirtyEdgeTrack();    // invalidate connector path, so it will be recalculated next time
185     void ImpSetAttrToEdgeInfo(); // copying values from the pool to aEdgeInfo
186     void ImpSetEdgeInfoToAttr(); // copying values from the aEdgeInfo to the pool
187 
188     // protected destructor
189     virtual ~SdrEdgeObj() override;
190 
191 public:
192     SdrEdgeObj(SdrModel& rSdrModel);
193     // Copy constructor
194     SdrEdgeObj(SdrModel& rSdrModel, SdrEdgeObj const & rSource);
195 
196     // react on model/page change
197     virtual void handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) override;
198 
GetConnection(bool bTail1)199     SdrObjConnection& GetConnection(bool bTail1) { return *(bTail1 ? &aCon1 : &aCon2); }
200     virtual void TakeObjInfo(SdrObjTransformInfoRec& rInfo) const override;
201     virtual SdrObjKind GetObjIdentifier() const override;
202     virtual const tools::Rectangle& GetCurrentBoundRect() const override;
203     virtual const tools::Rectangle& GetSnapRect() const override;
204     virtual SdrGluePoint GetVertexGluePoint(sal_uInt16 nNum) const override;
205     virtual SdrGluePoint GetCornerGluePoint(sal_uInt16 nNum) const override;
206     virtual const SdrGluePointList* GetGluePointList() const override;
207     virtual SdrGluePointList* ForceGluePointList() override;
208 
209     // * for all of the below: bTail1=true: beginning of the line,
210     //   otherwise end of the line
211     // * pObj=NULL: disconnect connector
SetEdgeTrackDirty()212     void SetEdgeTrackDirty() { bEdgeTrackDirty=true; }
213     void ConnectToNode(bool bTail1, SdrObject* pObj) override;
214     void DisconnectFromNode(bool bTail1) override;
215     SdrObject* GetConnectedNode(bool bTail1) const override;
GetConnection(bool bTail1) const216     const SdrObjConnection& GetConnection(bool bTail1) const { return *(bTail1 ? &aCon1 : &aCon2); }
217     bool CheckNodeConnection(bool bTail1) const;
218 
219     virtual void RecalcSnapRect() override;
220     virtual void TakeUnrotatedSnapRect(tools::Rectangle& rRect) const override;
221     virtual SdrEdgeObj* CloneSdrObject(SdrModel& rTargetModel) const override;
222     virtual OUString TakeObjNameSingul() const override;
223     virtual OUString TakeObjNamePlural() const override;
224 
225     void    SetEdgeTrackPath( const basegfx::B2DPolyPolygon& rPoly );
226     basegfx::B2DPolyPolygon GetEdgeTrackPath() const;
227 
228     virtual basegfx::B2DPolyPolygon TakeXorPoly() const override;
229     virtual sal_uInt32 GetHdlCount() const override;
230     virtual void AddToHdlList(SdrHdlList& rHdlList) const override;
231 
232     // special drag methods
233     virtual bool hasSpecialDrag() const override;
234     virtual bool beginSpecialDrag(SdrDragStat& rDrag) const override;
235     virtual bool applySpecialDrag(SdrDragStat& rDrag) override;
236     virtual OUString getSpecialDragComment(const SdrDragStat& rDrag) const override;
237 
238     // FullDrag support
239     virtual SdrObjectUniquePtr getFullDragClone() const override;
240 
241     virtual void NbcSetSnapRect(const tools::Rectangle& rRect) override;
242     virtual void NbcMove(const Size& aSize) override;
243     virtual void NbcResize(const Point& rRefPnt, const Fraction& aXFact, const Fraction& aYFact) override;
244 
245     // #i54102# added rotate, mirror and shear support
246     virtual void NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) override;
247     virtual void NbcMirror(const Point& rRef1, const Point& rRef2) override;
248     virtual void NbcShear(const Point& rRef, Degree100 nAngle, double tn, bool bVShear) override;
249 
250     // #102344# Added missing implementation
251     virtual void NbcSetAnchorPos(const Point& rPnt) override;
252 
253     virtual bool BegCreate(SdrDragStat& rStat) override;
254     virtual bool MovCreate(SdrDragStat& rStat) override;
255     virtual bool EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) override;
256     virtual bool BckCreate(SdrDragStat& rStat) override;
257     virtual void BrkCreate(SdrDragStat& rStat) override;
258     virtual basegfx::B2DPolyPolygon TakeCreatePoly(const SdrDragStat& rDrag) const override;
259     virtual PointerStyle GetCreatePointer() const override;
260     virtual SdrObjectUniquePtr DoConvertToPolyObj(bool bBezier, bool bAddText) const override;
261 
262     virtual sal_uInt32 GetSnapPointCount() const override;
263     virtual Point GetSnapPoint(sal_uInt32 i) const override;
264     virtual bool IsPolyObj() const override;
265     virtual sal_uInt32 GetPointCount() const override;
266     virtual Point GetPoint(sal_uInt32 i) const override;
267     virtual void NbcSetPoint(const Point& rPnt, sal_uInt32 i) override;
268 
269     virtual std::unique_ptr<SdrObjGeoData> NewGeoData() const override;
270     virtual void SaveGeoData(SdrObjGeoData& rGeo) const override;
271     virtual void RestoreGeoData(const SdrObjGeoData& rGeo) override;
272 
273     /** updates edges that are connected to the edges of this object
274         as if the connected objects send a repaint broadcast
275         #103122#
276     */
277     void Reformat();
278 
279     // helper methods for the StarOffice api
280     Point GetTailPoint( bool bTail ) const;
281     void SetTailPoint( bool bTail, const Point& rPt );
282     void setGluePointIndex( bool bTail, sal_Int32 nId = -1 );
283     sal_Int32 getGluePointIndex( bool bTail );
284 
285     virtual bool TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon) const override;
286     virtual void TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& rPolyPolygon) override;
287 
288     // for geometry access
289     ::basegfx::B2DPolygon getEdgeTrack() const;
290 
291     // helper method for SdrDragMethod::AddConnectorOverlays. Adds an overlay polygon for
292     // this connector to rResult.
293     basegfx::B2DPolygon ImplAddConnectorOverlay(SdrDragMethod& rDragMethod, bool bTail1, bool bTail2, bool bDetail) const;
294 };
295 
296  // The following item parameters of the SdrItemPool are used to
297  // determine the actual connector line routing:
298  //
299  //  sal_uInt16 EdgeFlowAngle       default 9000 (= 90.00 deg), min 0, max 9000
300  //      Clearance angle.
301  //      The angle at which the connecting line may run.
302  //
303  //  sal_uInt16 EdgeEscAngle        default 9000 (= 90.00 Deg), min 0, max 9000
304  //      Object exit angle.
305  //      The angle at which the connection line may exit from the object.
306  //
307  //  bool EdgeEscAsRay              default false
308  //      true -> the connecting line emerges from the object radially.
309  //      Thus, angle specification by the line ObjCenter / connector.
310  //
311  //  bool EdgeEscUseObjAngle        default false
312  //      Object rotation angle is considered
313  //      true -> when determining the connector exit angle, angle for
314  //      object rotation is taken as an offset.
315  //
316  //  sal_uIntPtr EdgeFlowDefDist    default 0, min 0, max ?
317  //      This is the default minimum distance on calculation of the
318  //      connection Line to the docked objects is in logical units.
319  //      This distance is overridden within the object, as soon as the
320  //      user drags on the lines. When docking onto a new object,
321  //      however, this default is used again.
322  //
323  //
324  // General Information About Connectors:
325  //
326  // There are nodes and edge objects. Two nodes can be joined by an
327  // edge. If a connector is connected to a node only at one end, the
328  // other end is fixed to an absolute position in the document. It is
329  // of course also possible for a connector to be "free" at both ends,
330  // i.e. not connected to a node object on each side.
331  //
332  // A connector object can also theoretically be a node object at the
333  // same time. In the first version, however, this will not yet be
334  // realized.
335  //
336  // A connection between node and connector edge can be established by:
337  // - Interactive creation of a new edge object at the SdrView where
338  //   the beginning or end point of the edge is placed on a connector
339  //   (glueing point) of an already existing node object.
340  // - Interactive dragging of the beginning or end point of an
341  //   existing connector edge object on the SdrView to a connector
342  //   (glueing point) of an already existing node object.
343  // - Undo/Redo
344  //   Moving node objects does not make any connections. Also not the
345  //   direct shifting of edge endpoints on the SdrModel... Connections
346  //   can also be established, if the connectors are not configured to
347  //   be visible in the view.
348  //
349  // An existing connection between node and edge is retained for:
350  // - Dragging (Move/Resize/Rotate/...) of the node object
351  // - Moving a connector position in the node object
352  // - Simultaneous dragging (Move/Resize/Rotate/...) of the node and the
353  //   edge
354  //
355  // A connection between node and edge can be removed by:
356  // - Deleting one of the objects
357  // - Dragging the edge object without simultaneously dragging the node
358  // - Deleting the connector at the node object
359  // - Undo/Redo/Repeat
360  // When dragging, the request to remove the connection must be
361  // requested from outside of the model (for example, from the
362  // SdrView). SdrEdgeObj::Move() itself does not remove the
363  // connection.
364  //
365  // Each node object can have connectors, so-called glue points. These
366  // are the geometric points at which the connecting edge object ends
367  // when the connection is established. By default, each object has no
368  // connectors.  Nevertheless, one can dock an edge in certain view
369  // settings since then, e.g., connectors can be automatically
370  // generated at the 4 vertices of the node object when needed. Each
371  // object provides 2x4 so-called default connector positions, 4 at
372  // the vertices and 4 at the corner positions. In the normal case,
373  // these are located at the 8 handle positions; exceptions here are
374  // ellipses, parallelograms, ... .  In addition, user-specific
375  // connectors can be set for each node object.
376  //
377  // Then there is also the possibility to dock an edge on an object
378  // with the attribute "bUseBestConnector". The best-matching
379  // connector position for the routing of the connection line is then
380  // used from the offering of connectors of the object or/and of the
381  // vertices. The user assigns this attribute by docking the node in
382  // its center (see, e.g., Visio).
383  // 09-06-1996: bUseBestConnector uses vertex glue points only.
384  //
385  // And here is some terminology:
386  //   Connector : The connector object (edge object)
387  //   Node      : Any object to which a connector can be glued to, e.g., a rectangle,
388  //               etc.
389  //   Glue point: The point at which the connector is glued to the node object.
390  //               There are:
391  //                 Vertex glue points: Each node object presents these glue
392  //                     points inherently. Perhaps there is already the option
393  //                     "automatically glue to object vertex" in Draw (default is
394  //                     on).
395  //                 Corner glue points: These glue points, too, are already
396  //                     auto-enabled on objects. Similar to the ones above,
397  //                     there may already be an option for them in Draw (default is
398  //                     off).
399  //                 In contrast to Visio, vertex glue points and corner glue
400  //                     points are not displayed in the UI; they are simply there (if
401  //                     the option is activated).
402  //                 Custom glue points: Any number of them are present on each
403  //                     node object. They can be made visible using the option
404  //                     (always visible when editing). At the moment, however, they
405  //                     are not yet fully implemented.
406  //                 Automatic glue point selection: If the connector is docked
407  //                     to the node object so that the black frame encompasses the
408  //                     entire object, then the connector tries to find the most
409  //                     convenient of the 4 vertex glue points (and only of those).
410 
411 #endif // INCLUDED_SVX_SVDOEDGE_HXX
412 
413 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
414