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_SVDSNPV_HXX
21 #define INCLUDED_SVX_SVDSNPV_HXX
22 
23 #include <svx/svdpntv.hxx>
24 #include <svx/svdhlpln.hxx>
25 #include <svx/svxdllapi.h>
26 #include <o3tl/typed_flags_set.hxx>
27 
28 /**
29  * Definition:
30  *  - snap something means e.g. the mouse pointer or some marked objects in drag can be snapped
31  *  - snap on something means you can e.g. snap on the grid or on auxiliary lines
32  *
33  *
34  * Basically, we only catch visible elements (borders, helper lines, connectors),
35  * with the exception of the grid. Likewise, we can only catch visible elements (i.e. connectors).
36  * We only catch on the grid, if nothing else is close by (magnetic behaviour).
37  *
38  * The cursor which is used during creation of objects, while dragging polygon points
39  * etc. (i.e. the mouse cursor) is always caught on all enabled catch alternatives (max 6).
40  *
41  * This is different, when moving selected objects. Instead of one mouse cursor, there are
42  * four alternatives, which can be caught at the selected objects:
43  *   1. the logically enclosing frame of every single object
44  *   2. the logically enclosing frame of all selected objects
45  *   3. highlighted points of all selected objects (polygon points, ...)
46  *   4. the connectors of the selected objects
47  *
48  * As the first and second case exclude each other (the second is a refinement of the first one)
49  * three alternatives remain, which are independent from each other. For 6 possible values for the
50  * caught ones, we would end up with max. 18 different possible combinations!
51  *
52  * Therefore, we introduce the following simplifications:
53  *   1. Connectors only catch on connectors
54  *
55  * Only max. 2*5+1 = 11 combinations remain for MoveDrag:
56  *   1-3.  enclosing frame on grid/border/helper lines
57  *   4.    enclosing frame on highlighted object points
58  *   5.    enclosing frame on enclosing frame
59  *   6-8.  highlighted points on grid/border/helper lines
60  *   7.    highlighted points on highlighted object points
61  *   8-10. highlighted points on enclosing frame
62  *   11.   connectors on connectors
63  *
64  * We test for all of these possible 11 combinations in the MouseMove event in the DragMove
65  * and those with the least need of correction are carried out.
66  *
67  * In the Resize() etc. methods we only catch the logically enclosing frame of the highlighted objects.
68  */
69 
70 /** Return value for SnapPos() method */
71 enum class SdrSnap
72 {
73     NOTSNAPPED = 0x00,
74     XSNAPPED   = 0x01,
75     YSNAPPED   = 0x02
76 };
77 namespace o3tl
78 {
79     template<> struct typed_flags<SdrSnap> : is_typed_flags<SdrSnap, 3> {};
80 }
81 
82 // TODO SdrCrookMode::Stretch is not implemented yet!
83 enum class SdrCrookMode {
84     Rotate,
85     Slant,
86     Stretch
87 };
88 
89 
90 // #114409#-1 Migrate PageOrigin
91 class ImplPageOriginOverlay;
92 
93 class SVX_DLLPUBLIC SdrSnapView : public SdrPaintView
94 {
95 protected:
96     // #114409#-1 Migrate PageOrigin
97     class ImplPageOriginOverlay*            mpPageOriginOverlay;
98 
99     // #114409#-2 Migrate HelpLine
100     class ImplHelpLineOverlay*              mpHelpLineOverlay;
101 
102     Size                        aMagnSiz;
103     Fraction                    aSnapWdtX;
104     Fraction                    aSnapWdtY;
105 
106     sal_uInt16                  nMagnSizPix;
107     long                        nSnapAngle;
108     long                        nEliminatePolyPointLimitAngle;
109 
110     SdrCrookMode                eCrookMode;
111 
112     bool                        bSnapEnab : 1;
113     bool                        bGridSnap : 1;
114     bool                        bBordSnap : 1;
115     bool                        bHlplSnap : 1;
116     bool                        bOFrmSnap : 1;
117     bool                        bOPntSnap : 1;
118     bool                        bOConSnap : 1;
119     bool                        bMoveSnapOnlyTopLeft : 1;    //  Special for dialogeditor
120     bool                        bOrtho : 1;
121     bool                        bBigOrtho : 1;
122     bool                        bAngleSnapEnab : 1;
123     bool                        bMoveOnlyDragging : 1;       // only move objects while Resize/Rotate/...
124     bool                        bSlantButShear : 1;          // use slant instead of shear
125     bool                        bCrookNoContortion : 1;      // no contorsion while Crook
126     bool                        bEliminatePolyPoints : 1;
127 
128 protected:
129     // #i71538# make constructors of SdrView sub-components protected to avoid incomplete incarnations which may get casted to SdrView
130     SdrSnapView(
131         SdrModel& rSdrModel,
132         OutputDevice* pOut);
133 
134     virtual ~SdrSnapView() override;
135 
136 public:
137     virtual bool IsAction() const override;
138     virtual void MovAction(const Point& rPnt) override;
139     virtual void EndAction() override;
140     virtual void BckAction() override;
141     virtual void BrkAction() override; // break actions for derived classes e.g. interrupt dragging.
142     virtual void TakeActionRect(tools::Rectangle& rRect) const override;
143 
SetSnapGridWidth(const Fraction & rX,const Fraction & rY)144     void SetSnapGridWidth(const Fraction& rX, const Fraction& rY) { aSnapWdtX=rX; aSnapWdtY=rY; }
GetSnapGridWidthX() const145     const Fraction& GetSnapGridWidthX() const { return aSnapWdtX; }
GetSnapGridWidthY() const146     const Fraction& GetSnapGridWidthY() const { return aSnapWdtY; }
147 
SetSnapMagnetic(const Size & rSiz)148     void SetSnapMagnetic(const Size& rSiz) { if (rSiz!=aMagnSiz) { aMagnSiz=rSiz; } }
SetSnapMagneticPixel(sal_uInt16 nPix)149     void SetSnapMagneticPixel(sal_uInt16 nPix) { nMagnSizPix=nPix; }
GetSnapMagneticPixel() const150     sal_uInt16 GetSnapMagneticPixel() const { return nMagnSizPix; }
151 
152     // RecalcLogicSnapMagnetic has to be called for every change of OutputDevices and every change of the MapMode!
RecalcLogicSnapMagnetic(const OutputDevice & rOut)153     void RecalcLogicSnapMagnetic(const OutputDevice& rOut) { SetSnapMagnetic(rOut.PixelToLogic(Size(nMagnSizPix,nMagnSizPix))); }
SetActualWin(const OutputDevice * pWin)154     void SetActualWin(const OutputDevice* pWin) { SdrPaintView::SetActualWin(pWin); if (pWin!=nullptr) RecalcLogicSnapMagnetic(*pWin); }
155 
156     // Coordinates referred to the view!
157     // Returnvalues are SdrSnap::NOTSNAPPED,SdrSnap::XSNAPPED,
158     // SdrSnap::YSNAPPED or SdrSnap::XYSNAPPED
159     SdrSnap SnapPos(Point& rPnt, const SdrPageView* pPV) const;
160     Point GetSnapPos(const Point& rPnt, const SdrPageView* pPV) const;
161     void CheckSnap(const Point& rPt, long& nBestXSnap, long& nBestYSnap, bool& bXSnapped, bool& bYSnapped) const;
162 
163     // All attitudes to snap are persistent.
IsSnapEnabled() const164     bool IsSnapEnabled() const { return bSnapEnab; }
IsGridSnap() const165     bool IsGridSnap() const { return bGridSnap; } // Snap to grid
IsBordSnap() const166     bool IsBordSnap() const { return bBordSnap; } // Snap to border
IsHlplSnap() const167     bool IsHlplSnap() const { return bHlplSnap; } // Snap to auxiliary line
IsOFrmSnap() const168     bool IsOFrmSnap() const { return bOFrmSnap; } // Snap to LogFram from surrounding drawing objects
IsOPntSnap() const169     bool IsOPntSnap() const { return bOPntSnap; } // Snap to distinct points from surrounding drawing objects
IsOConSnap() const170     bool IsOConSnap() const { return bOConSnap; } // Snap to connectors of the drawing objects
SetSnapEnabled(bool bOn)171     void SetSnapEnabled(bool bOn) { bSnapEnab=bOn; }
SetGridSnap(bool bOn)172     void SetGridSnap(bool bOn) { bGridSnap=bOn; }
SetBordSnap(bool bOn)173     void SetBordSnap(bool bOn) { bBordSnap=bOn; }
SetHlplSnap(bool bOn)174     void SetHlplSnap(bool bOn) { bHlplSnap=bOn; }
SetOFrmSnap(bool bOn)175     void SetOFrmSnap(bool bOn) { bOFrmSnap=bOn; }
SetOPntSnap(bool bOn)176     void SetOPntSnap(bool bOn) { bOPntSnap=bOn; }
SetOConSnap(bool bOn)177     void SetOConSnap(bool bOn) { bOConSnap=bOn; }
178 
179     // Usually every 4 corners of Object-SnapRects are snapped for Move-Dragging.
180     // The following attitudes e.g. if you only want to snap the left corner on the top (e.g. DialogEditor)
181     // persistent, Default=FALSE.
SetMoveSnapOnlyTopLeft(bool bOn)182     void SetMoveSnapOnlyTopLeft(bool bOn) { bMoveSnapOnlyTopLeft=bOn; }
IsMoveSnapOnlyTopLeft() const183     bool IsMoveSnapOnlyTopLeft() const { return bMoveSnapOnlyTopLeft; }
184 
185     // #114409#-1 Migrate PageOrigin
186     void BegSetPageOrg(const Point& rPnt);
187     void MovSetPageOrg(const Point& rPnt);
188     void EndSetPageOrg();
189     void BrkSetPageOrg();
IsSetPageOrg() const190     bool IsSetPageOrg() const { return (nullptr != mpPageOriginOverlay); }
191 
192     // HitTest. If sal_True, in rnHelpLineNum is the number of the auxiliary line and in rpPv
193     // the appended PageView.
194     bool PickHelpLine(const Point& rPnt, short nTol, const OutputDevice& rOut, sal_uInt16& rnHelpLineNum, SdrPageView*& rpPV) const;
195 
196     // Move of an available auxiliary line. Use nHelpLineNum and pPV from PickHelpLine.
197     bool BegDragHelpLine(sal_uInt16 nHelpLineNum, SdrPageView* pPV);
198     // interactive insertion of a new auxiliary line
199     void BegDragHelpLine(const Point& rPnt, SdrHelpLineKind eNewKind);
200     PointerStyle GetDraggedHelpLinePointer() const;
201 
202     // change the type of auxiliary line while dragging
203     // void SetDraggedHelpLineKind(SdrHelpLineKind eNewKind);
204     void MovDragHelpLine(const Point& rPnt);
205     bool EndDragHelpLine();
206     void BrkDragHelpLine();
IsDragHelpLine() const207     bool IsDragHelpLine() const { return (nullptr != mpHelpLineOverlay); }
208 
209     // SnapAngle is for angles in circle, RotateDragging, ...
210     // The snapping of an angle is beared down, if it is switched off
211     // with SetAngleSnapEnabled(sal_False)
212     // The snapping angles is independent of snapping coordinates
213     // and so independent of the attitude IsSnapEnabled()
214     // Only values should be specified for them is applied:
215     //     36000 modulo nAngle = 0
216     // Implemented for:
217     // - Rotate (Dragging)
218     // - Shear (Dragging)
219     // - circular arc/-sector/-section angle (Create and Dragging)
220     // persistent.
SetAngleSnapEnabled(bool bOn)221     void SetAngleSnapEnabled(bool bOn) { bAngleSnapEnab=bOn; }
IsAngleSnapEnabled() const222     bool IsAngleSnapEnabled() const { return bAngleSnapEnab; }
SetSnapAngle(long nAngle)223     void SetSnapAngle(long nAngle) { nSnapAngle=nAngle; }
GetSnapAngle() const224     long GetSnapAngle() const { return nSnapAngle; }
225 
226     // different effects from Ortho (depending on the context):
227     // - Create
228     //   - only lines in 45deg grid
229     //   - instead of rectangles squares are created
230     //   - instead of ellipse circles are created
231     // - Dragging
232     //   - general Dragging
233     //     - Move only horizontal, vertical or 45deg
234     //     - Resize proportional
235     //     - Mirror: nothing
236     //     - Shear without Resize
237     //     - Crook without Resize
238     //   - move handles
239     //     - mirror axis only 45deg grid
240     //   - object-specific Dragging
241     //     - rectangle corner radius: nothing
242     //     - circle object angle: nothing
243     //     - line keeps while Dragging the angle and is only stretched/ contracted
244     // Default value for Ortho is off. persistent.
SetOrtho(bool bOn)245     void SetOrtho(bool bOn) { bOrtho=bOn; } // incomplete
IsOrtho() const246     bool IsOrtho() const { return bOrtho; }
247 
248     // BigOrtho is only relevant if Ortho is switched on.
249     // Example: rectangle is created and ortho is switched on (--> square)
250     //   and the Mouse was dragged from zero to the coordinates
251     //   (80,30). Now there are 2 alternatives to determine the edge length
252     //   of the square: 30 and 80.
253     //   The standard Ortho-Function took 30 (every time the smaller length)
254     //   If BigOrtho is switched on, you get a square with edge length of 80.
255     // The same also applies to Resize.
256     // Default value for BigOrtho is on. persistent.
SetBigOrtho(bool bOn)257     void SetBigOrtho(bool bOn) { bBigOrtho=bOn; }
IsBigOrtho() const258     bool IsBigOrtho() const { return bBigOrtho; }
259 
260     // If MoveOnlyDragging=sal_True only the center of the marked objects is
261     // transformed when Resize/Rotate/Shear/Mirror/Crook is executed.
262     // Size, form and rotation angle of the objects are conserved only their positions
263     // are changed. persistent. Default=FALSE. (ni)
SetMoveOnlyDragging(bool bOn)264     void SetMoveOnlyDragging(bool bOn) { bMoveOnlyDragging=bOn; }
IsMoveOnlyDragging() const265     bool IsMoveOnlyDragging() const { return bMoveOnlyDragging; }
266 
267     // Use Slant instead of Shear. persistent. Default=FALSE.
SetSlantButShear(bool bOn)268     void SetSlantButShear(bool bOn) { bSlantButShear=bOn; }
IsSlantButShear() const269     bool IsSlantButShear() const { return bSlantButShear; }
270 
271     // Don't contort objecte while Crook. persistent. Default=FALSE. (ni)
SetCrookNoContortion(bool bOn)272     void SetCrookNoContortion(bool bOn) { bCrookNoContortion=bOn; }
IsCrookNoContortion() const273     bool IsCrookNoContortion() const { return bCrookNoContortion; }
274 
275     // Crook-Mode. persistent. Default=SdrCrookMode::Rotate. (ni)
SetCrookMode(SdrCrookMode eMode)276     void SetCrookMode(SdrCrookMode eMode) { eCrookMode=eMode; }
GetCrookMode() const277     SdrCrookMode GetCrookMode() const { return eCrookMode; }
278 
279     // Special for IBM: While Dragging of a traverse station, it is deleted
280     // if its adjacent lines are almost a solid line.
SetEliminatePolyPoints(bool bOn)281     void SetEliminatePolyPoints(bool bOn) { bEliminatePolyPoints=bOn; }
IsEliminatePolyPoints() const282     bool IsEliminatePolyPoints() const { return bEliminatePolyPoints; }
SetEliminatePolyPointLimitAngle(long nAngle)283     void SetEliminatePolyPointLimitAngle(long nAngle) { nEliminatePolyPointLimitAngle=nAngle; }
GetEliminatePolyPointLimitAngle() const284     long GetEliminatePolyPointLimitAngle() const { return nEliminatePolyPointLimitAngle; }
285 };
286 
287 #endif // INCLUDED_SVX_SVDSNPV_HXX
288 
289 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
290