summaryrefslogtreecommitdiffstats
path: root/include/svx/svdsnpv.hxx
blob: 1fd8fce3ba9784891b67e78faacf4d589ddd2ca7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */

#pragma once

#include <svx/svdpntv.hxx>
#include <svx/svdhlpln.hxx>
#include <svx/svxdllapi.h>
#include <tools/degree.hxx>
#include <o3tl/typed_flags_set.hxx>

/**
 * Definition:
 *  - snap something means e.g. the mouse pointer or some marked objects in drag can be snapped
 *  - snap on something means you can e.g. snap on the grid or on auxiliary lines
 *
 *
 * Basically, we only catch visible elements (borders, helper lines, connectors),
 * with the exception of the grid. Likewise, we can only catch visible elements (i.e. connectors).
 * We only catch on the grid, if nothing else is close by (magnetic behaviour).
 *
 * The cursor which is used during creation of objects, while dragging polygon points
 * etc. (i.e. the mouse cursor) is always caught on all enabled catch alternatives (max 6).
 *
 * This is different, when moving selected objects. Instead of one mouse cursor, there are
 * four alternatives, which can be caught at the selected objects:
 *   1. the logically enclosing frame of every single object
 *   2. the logically enclosing frame of all selected objects
 *   3. highlighted points of all selected objects (polygon points, ...)
 *   4. the connectors of the selected objects
 *
 * As the first and second case exclude each other (the second is a refinement of the first one)
 * three alternatives remain, which are independent from each other. For 6 possible values for the
 * caught ones, we would end up with max. 18 different possible combinations!
 *
 * Therefore, we introduce the following simplifications:
 *   1. Connectors only catch on connectors
 *
 * Only max. 2*5+1 = 11 combinations remain for MoveDrag:
 *   1-3.  enclosing frame on grid/border/helper lines
 *   4.    enclosing frame on highlighted object points
 *   5.    enclosing frame on enclosing frame
 *   6-8.  highlighted points on grid/border/helper lines
 *   7.    highlighted points on highlighted object points
 *   8-10. highlighted points on enclosing frame
 *   11.   connectors on connectors
 *
 * We test for all of these possible 11 combinations in the MouseMove event in the DragMove
 * and those with the least need of correction are carried out.
 *
 * In the Resize() etc. methods we only catch the logically enclosing frame of the highlighted objects.
 */

/** Return value for SnapPos() method */
enum class SdrSnap
{
    NOTSNAPPED = 0x00,
    XSNAPPED   = 0x01,
    YSNAPPED   = 0x02
};
namespace o3tl
{
    template<> struct typed_flags<SdrSnap> : is_typed_flags<SdrSnap, 3> {};
}

// TODO SdrCrookMode::Stretch is not implemented yet!
enum class SdrCrookMode {
    Rotate,
    Slant,
    Stretch
};


// #114409#-1 Migrate PageOrigin
class ImplPageOriginOverlay;

class SVXCORE_DLLPUBLIC SdrSnapView : public SdrPaintView
{
protected:
    // #114409#-1 Migrate PageOrigin
    class ImplPageOriginOverlay*            mpPageOriginOverlay;

    // #114409#-2 Migrate HelpLine
    class ImplHelpLineOverlay*              mpHelpLineOverlay;

    Size                        aMagnSiz;
    Fraction                    aSnapWdtX;
    Fraction                    aSnapWdtY;

    sal_uInt16                  nMagnSizPix;
    Degree100                   nSnapAngle;
    Degree100                   nEliminatePolyPointLimitAngle;

    SdrCrookMode                eCrookMode;

    bool                        bSnapEnab : 1;
    bool                        bGridSnap : 1;
    bool                        bBordSnap : 1;
    bool                        bHlplSnap : 1;
    bool                        bOFrmSnap : 1;
    bool                        bOPntSnap : 1;
    bool                        bOConSnap : 1;
    bool                        bMoveSnapOnlyTopLeft : 1;    //  Special for dialogeditor
    bool                        bOrtho : 1;
    bool                        bBigOrtho : 1;
    bool                        bAngleSnapEnab : 1;
    bool                        bMoveOnlyDragging : 1;       // only move objects while Resize/Rotate/...
    bool                        bSlantButShear : 1;          // use slant instead of shear
    bool                        bCrookNoContortion : 1;      // no contorsion while Crook
    bool                        bEliminatePolyPoints : 1;

protected:
    // #i71538# make constructors of SdrView sub-components protected to avoid incomplete incarnations which may get casted to SdrView
    SdrSnapView(
        SdrModel& rSdrModel,
        OutputDevice* pOut);

    virtual ~SdrSnapView() override;

public:
    virtual bool IsAction() const override;
    virtual void MovAction(const Point& rPnt) override;
    virtual void EndAction() override;
    virtual void BckAction() override;
    virtual void BrkAction() override; // break actions for derived classes e.g. interrupt dragging.
    virtual void TakeActionRect(tools::Rectangle& rRect) const override;

    void SetSnapGridWidth(const Fraction& rX, const Fraction& rY) { aSnapWdtX=rX; aSnapWdtY=rY; }
    const Fraction& GetSnapGridWidthX() const { return aSnapWdtX; }
    const Fraction& GetSnapGridWidthY() const { return aSnapWdtY; }

    void SetSnapMagnetic(const Size& rSiz) { if (rSiz!=aMagnSiz) { aMagnSiz=rSiz; } }
    void SetSnapMagneticPixel(sal_uInt16 nPix) { nMagnSizPix=nPix; }
    sal_uInt16 GetSnapMagneticPixel() const { return nMagnSizPix; }

    // RecalcLogicSnapMagnetic has to be called for every change of OutputDevices and every change of the MapMode!
    void RecalcLogicSnapMagnetic(const OutputDevice& rOut) { SetSnapMagnetic(rOut.PixelToLogic(Size(nMagnSizPix,nMagnSizPix))); }
    void SetActualWin(const OutputDevice* pWin) { SdrPaintView::SetActualWin(pWin); if (pWin!=nullptr) RecalcLogicSnapMagnetic(*pWin); }

    // Coordinates referred to the view!
    // Returnvalues are SdrSnap::NOTSNAPPED,SdrSnap::XSNAPPED,
    // SdrSnap::YSNAPPED or SdrSnap::XYSNAPPED
    SdrSnap SnapPos(Point& rPnt, const SdrPageView* pPV) const;
    Point GetSnapPos(const Point& rPnt, const SdrPageView* pPV) const;
    void CheckSnap(const Point& rPt, tools::Long& nBestXSnap, tools::Long& nBestYSnap, bool& bXSnapped, bool& bYSnapped) const;

    // All attitudes to snap are persistent.
    bool IsSnapEnabled() const { return bSnapEnab; }
    bool IsGridSnap() const { return bGridSnap; } // Snap to grid
    bool IsBordSnap() const { return bBordSnap; } // Snap to border
    bool IsHlplSnap() const { return bHlplSnap; } // Snap to auxiliary line
    bool IsOFrmSnap() const { return bOFrmSnap; } // Snap to LogFram from surrounding drawing objects
    bool IsOPntSnap() const { return bOPntSnap; } // Snap to distinct points from surrounding drawing objects
    bool IsOConSnap() const { return bOConSnap; } // Snap to connectors of the drawing objects
    void SetSnapEnabled(bool bOn) { bSnapEnab=bOn; }
    void SetGridSnap(bool bOn) { bGridSnap=bOn; }
    void SetBordSnap(bool bOn) { bBordSnap=bOn; }
    void SetHlplSnap(bool bOn) { bHlplSnap=bOn; }
    void SetOFrmSnap(bool bOn) { bOFrmSnap=bOn; }
    void SetOPntSnap(bool bOn) { bOPntSnap=bOn; }
    void SetOConSnap(bool bOn) { bOConSnap=bOn; }

    // Usually every 4 corners of Object-SnapRects are snapped for Move-Dragging.
    // The following attitudes e.g. if you only want to snap the left corner on the top (e.g. DialogEditor)
    // persistent, Default=FALSE.
    void SetMoveSnapOnlyTopLeft(bool bOn) { bMoveSnapOnlyTopLeft=bOn; }
    bool IsMoveSnapOnlyTopLeft() const { return bMoveSnapOnlyTopLeft; }

    // #114409#-1 Migrate PageOrigin
    void BegSetPageOrg(const Point& rPnt);
    void MovSetPageOrg(const Point& rPnt);
    void EndSetPageOrg();
    void BrkSetPageOrg();
    bool IsSetPageOrg() const { return (nullptr != mpPageOriginOverlay); }

    // HitTest. If sal_True, in rnHelpLineNum is the number of the auxiliary line and in rpPv
    // the appended PageView.
    bool PickHelpLine(const Point& rPnt, short nTol, const OutputDevice& rOut, sal_uInt16& rnHelpLineNum, SdrPageView*& rpPV) const;

    // Move of an available auxiliary line. Use nHelpLineNum and pPV from PickHelpLine.
    bool BegDragHelpLine(sal_uInt16 nHelpLineNum, SdrPageView* pPV);
    // interactive insertion of a new auxiliary line
    void BegDragHelpLine(const Point& rPnt, SdrHelpLineKind eNewKind);
    PointerStyle GetDraggedHelpLinePointer() const;

    // change the type of auxiliary line while dragging
    // void SetDraggedHelpLineKind(SdrHelpLineKind eNewKind);
    void MovDragHelpLine(const Point& rPnt);
    bool EndDragHelpLine();
    void BrkDragHelpLine();
    bool IsDragHelpLine() const { return (nullptr != mpHelpLineOverlay); }

    // SnapAngle is for angles in circle, RotateDragging, ...
    // The snapping of an angle is beared down, if it is switched off
    // with SetAngleSnapEnabled(sal_False)
    // The snapping angles is independent of snapping coordinates
    // and so independent of the attitude IsSnapEnabled()
    // Only values should be specified for them is applied:
    //     36000 modulo nAngle = 0
    // Implemented for:
    // - Rotate (Dragging)
    // - Shear (Dragging)
    // - circular arc/-sector/-section angle (Create and Dragging)
    // persistent.
    void SetAngleSnapEnabled(bool bOn) { bAngleSnapEnab=bOn; }
    bool IsAngleSnapEnabled() const { return bAngleSnapEnab; }
    void SetSnapAngle(Degree100 nAngle) { nSnapAngle=nAngle; }
    Degree100 GetSnapAngle() const { return nSnapAngle; }

    // different effects from Ortho (depending on the context):
    // - Create
    //   - only lines in 45deg grid
    //   - instead of rectangles squares are created
    //   - instead of ellipse circles are created
    // - Dragging
    //   - general Dragging
    //     - Move only horizontal, vertical or 45deg
    //     - Resize proportional
    //     - Mirror: nothing
    //     - Shear without Resize
    //     - Crook without Resize
    //   - move handles
    //     - mirror axis only 45deg grid
    //   - object-specific Dragging
    //     - rectangle corner radius: nothing
    //     - circle object angle: nothing
    //     - line keeps while Dragging the angle and is only stretched/ contracted
    // Default value for Ortho is off. persistent.
    void SetOrtho(bool bOn) { bOrtho=bOn; } // incomplete
    bool IsOrtho() const { return bOrtho; }

    // BigOrtho is only relevant if Ortho is switched on.
    // Example: rectangle is created and ortho is switched on (--> square)
    //   and the Mouse was dragged from zero to the coordinates
    //   (80,30). Now there are 2 alternatives to determine the edge length
    //   of the square: 30 and 80.
    //   The standard Ortho-Function took 30 (every time the smaller length)
    //   If BigOrtho is switched on, you get a square with edge length of 80.
    // The same also applies to Resize.
    // Default value for BigOrtho is on. persistent.
    void SetBigOrtho(bool bOn) { bBigOrtho=bOn; }
    bool IsBigOrtho() const { return bBigOrtho; }

    // If MoveOnlyDragging=sal_True only the center of the marked objects is
    // transformed when Resize/Rotate/Shear/Mirror/Crook is executed.
    // Size, form and rotation angle of the objects are conserved only their positions
    // are changed. persistent. Default=FALSE. (ni)
    void SetMoveOnlyDragging(bool bOn) { bMoveOnlyDragging=bOn; }
    bool IsMoveOnlyDragging() const { return bMoveOnlyDragging; }

    // Use Slant instead of Shear. persistent. Default=FALSE.
    void SetSlantButShear(bool bOn) { bSlantButShear=bOn; }
    bool IsSlantButShear() const { return bSlantButShear; }

    // Don't contort objecte while Crook. persistent. Default=FALSE. (ni)
    void SetCrookNoContortion(bool bOn) { bCrookNoContortion=bOn; }
    bool IsCrookNoContortion() const { return bCrookNoContortion; }

    // Crook-Mode. persistent. Default=SdrCrookMode::Rotate. (ni)
    void SetCrookMode(SdrCrookMode eMode) { eCrookMode=eMode; }
    SdrCrookMode GetCrookMode() const { return eCrookMode; }

    // Special for IBM: While Dragging of a traverse station, it is deleted
    // if its adjacent lines are almost a solid line.
    void SetEliminatePolyPoints(bool bOn) { bEliminatePolyPoints=bOn; }
    bool IsEliminatePolyPoints() const { return bEliminatePolyPoints; }
    void SetEliminatePolyPointLimitAngle(Degree100 nAngle) { nEliminatePolyPointLimitAngle=nAngle; }
    Degree100 GetEliminatePolyPointLimitAngle() const { return nEliminatePolyPointLimitAngle; }
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */