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 .
21 #include <svx/svdsnpv.hxx>
24 #include <svx/svdobj.hxx>
25 #include <svx/svdpagv.hxx>
26 #include <svx/svdpage.hxx>
27 #include <svx/svditer.hxx>
28 #include <svx/sdr/overlay/overlayobjectlist.hxx>
29 #include <sdr/overlay/overlaycrosshair.hxx>
30 #include <sdr/overlay/overlayhelpline.hxx>
31 #include <svx/sdr/overlay/overlaymanager.hxx>
32 #include <svx/sdrpaintwindow.hxx>
33 #include <tools/debug.hxx>
34 #include <vcl/ptrstyle.hxx>
37 class ImplPageOriginOverlay
40 sdr::overlay::OverlayObjectList maObjects
;
42 // The current position in logical coordinates
43 basegfx::B2DPoint maPosition
;
46 ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
);
48 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
49 // That destructor calls clear() at the list which removes all objects from the
50 // OverlayManager and deletes them.
52 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
55 ImplPageOriginOverlay::ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
)
56 : maPosition(rStartPos
)
58 for(sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
60 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
61 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
63 if (xTargetOverlay
.is())
65 std::unique_ptr
<sdr::overlay::OverlayCrosshairStriped
> aNew(new sdr::overlay::OverlayCrosshairStriped(
67 xTargetOverlay
->add(*aNew
);
68 maObjects
.append(std::move(aNew
));
73 void ImplPageOriginOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
75 if(rNewPosition
== maPosition
)
78 // apply to OverlayObjects
79 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
81 sdr::overlay::OverlayCrosshairStriped
* pCandidate
=
82 static_cast< sdr::overlay::OverlayCrosshairStriped
* >(&maObjects
.getOverlayObject(a
));
86 pCandidate
->setBasePosition(rNewPosition
);
90 // remember new position
91 maPosition
= rNewPosition
;
95 class ImplHelpLineOverlay
98 sdr::overlay::OverlayObjectList maObjects
;
100 // The current position in logical coordinates
101 basegfx::B2DPoint maPosition
;
103 // HelpLine specific stuff
104 SdrPageView
* mpPageView
;
105 sal_uInt16 mnHelpLineNumber
;
106 SdrHelpLineKind meHelpLineKind
;
109 ImplHelpLineOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
110 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
);
112 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
113 // That destructor calls clear() at the list which removes all objects from the
114 // OverlayManager and deletes them.
116 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
118 // access to HelpLine specific stuff
119 SdrPageView
* GetPageView() const { return mpPageView
; }
120 sal_uInt16
GetHelpLineNumber() const { return mnHelpLineNumber
; }
121 SdrHelpLineKind
GetHelpLineKind() const { return meHelpLineKind
; }
124 ImplHelpLineOverlay::ImplHelpLineOverlay(
125 const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
126 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
)
127 : maPosition(rStartPos
),
128 mpPageView(pPageView
),
129 mnHelpLineNumber(nHelpLineNumber
),
130 meHelpLineKind(eKind
)
132 for(sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
134 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
135 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
137 if (xTargetOverlay
.is())
139 std::unique_ptr
<sdr::overlay::OverlayHelplineStriped
> aNew(new sdr::overlay::OverlayHelplineStriped(
140 maPosition
, meHelpLineKind
));
141 xTargetOverlay
->add(*aNew
);
142 maObjects
.append(std::move(aNew
));
147 void ImplHelpLineOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
149 if(rNewPosition
== maPosition
)
152 // apply to OverlayObjects
153 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
155 sdr::overlay::OverlayHelplineStriped
* pCandidate
=
156 static_cast< sdr::overlay::OverlayHelplineStriped
* >(&maObjects
.getOverlayObject(a
));
160 pCandidate
->setBasePosition(rNewPosition
);
164 // remember new position
165 maPosition
= rNewPosition
;
168 SdrSnapView::SdrSnapView(
171 : SdrPaintView(rSdrModel
, pOut
)
172 ,mpPageOriginOverlay(nullptr)
173 ,mpHelpLineOverlay(nullptr)
176 ,nEliminatePolyPointLimitAngle(0)
177 ,eCrookMode(SdrCrookMode::Rotate
)
185 ,bMoveSnapOnlyTopLeft(false)
188 ,bAngleSnapEnab(false)
189 ,bMoveOnlyDragging(false)
190 ,bSlantButShear(false)
191 ,bCrookNoContortion(false)
192 ,bEliminatePolyPoints(false)
196 SdrSnapView::~SdrSnapView()
203 bool SdrSnapView::IsAction() const
205 return IsSetPageOrg() || IsDragHelpLine() || SdrPaintView::IsAction();
208 void SdrSnapView::MovAction(const Point
& rPnt
)
210 SdrPaintView::MovAction(rPnt
);
211 if (IsSetPageOrg()) {
214 if (IsDragHelpLine()) {
215 MovDragHelpLine(rPnt
);
219 void SdrSnapView::EndAction()
221 if (IsSetPageOrg()) {
224 if (IsDragHelpLine()) {
227 SdrPaintView::EndAction();
230 void SdrSnapView::BckAction()
234 SdrPaintView::BckAction();
237 void SdrSnapView::BrkAction()
241 SdrPaintView::BrkAction();
244 void SdrSnapView::TakeActionRect(tools::Rectangle
& rRect
) const
246 if (IsSetPageOrg() || IsDragHelpLine()) {
247 rRect
=tools::Rectangle(maDragStat
.GetNow(),maDragStat
.GetNow());
249 SdrPaintView::TakeActionRect(rRect
);
254 Point
SdrSnapView::GetSnapPos(const Point
& rPnt
, const SdrPageView
* pPV
) const
261 #define NOT_SNAPPED 0x7FFFFFFF
262 SdrSnap
SdrSnapView::SnapPos(Point
& rPnt
, const SdrPageView
* pPV
) const
264 if (!bSnapEnab
) return SdrSnap::NOTSNAPPED
;
265 tools::Long x
=rPnt
.X();
266 tools::Long y
=rPnt
.Y();
268 pPV
=GetSdrPageView();
269 if (pPV
==nullptr) return SdrSnap::NOTSNAPPED
;
272 tools::Long dx
=NOT_SNAPPED
;
273 tools::Long dy
=NOT_SNAPPED
;
275 tools::Long mx
=aMagnSiz
.Width();
276 tools::Long my
=aMagnSiz
.Height();
277 if (mbHlplVisible
&& bHlplSnap
&& !IsDragHelpLine())
279 const SdrHelpLineList
& rHLL
=pPV
->GetHelpLines();
280 sal_uInt16 nCount
=rHLL
.GetCount();
281 for (sal_uInt16 i
=nCount
; i
>0;) {
283 const SdrHelpLine
& rHL
=rHLL
[i
];
284 const Point
& rPos
=rHL
.GetPos();
285 switch (rHL
.GetKind()) {
286 case SdrHelpLineKind::Vertical
: {
287 tools::Long a
=x
-rPos
.X();
288 if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
290 case SdrHelpLineKind::Horizontal
: {
291 tools::Long b
=y
-rPos
.Y();
292 if (std::abs(b
)<=my
) { dy1
=-b
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
294 case SdrHelpLineKind::Point
: {
295 tools::Long a
=x
-rPos
.X();
296 tools::Long b
=y
-rPos
.Y();
297 if (std::abs(a
)<=mx
&& std::abs(b
)<=my
) {
299 if (std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) { dx
=dx1
; dy
=dy1
; }
305 if (mbBordVisible
&& bBordSnap
) {
306 SdrPage
* pPage
=pPV
->GetPage();
307 tools::Long xs
=pPage
->GetWidth();
308 tools::Long ys
=pPage
->GetHeight();
309 tools::Long lft
=pPage
->GetLeftBorder();
310 tools::Long rgt
=pPage
->GetRightBorder();
311 tools::Long upp
=pPage
->GetUpperBorder();
312 tools::Long lwr
=pPage
->GetLowerBorder();
314 a
=x
- lft
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left margin
315 a
=x
-(xs
-rgt
); if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right margin
316 a
=x
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left edge of paper
317 a
=x
- xs
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right edge of paper
318 a
=y
- upp
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left margin
319 a
=y
-(ys
-lwr
); if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right margin
320 a
=y
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left edge of paper
321 a
=y
- ys
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right edge of paper
323 if (bOFrmSnap
|| bOPntSnap
) {
324 sal_uInt32 nMaxPointSnapCount
=200;
325 sal_uInt32 nMaxFrameSnapCount
=200;
327 // go back to SdrIterMode::DeepNoGroups runthrough for snap to object comparisons
328 SdrObjListIter
aIter(pPV
->GetPage(),SdrIterMode::DeepNoGroups
,true);
330 while (aIter
.IsMore() && (nMaxPointSnapCount
>0 || nMaxFrameSnapCount
>0)) {
331 SdrObject
* pO
=aIter
.Next();
332 tools::Rectangle
aRect(pO
->GetCurrentBoundRect());
333 aRect
.AdjustLeft( -mx
);
334 aRect
.AdjustRight(mx
);
335 aRect
.AdjustTop( -my
);
336 aRect
.AdjustBottom(my
);
337 if (aRect
.Contains(rPnt
)) {
338 if (bOPntSnap
&& nMaxPointSnapCount
>0)
340 sal_uInt32
nCount(pO
->GetSnapPointCount());
341 for (sal_uInt32
i(0); i
< nCount
&& nMaxPointSnapCount
> 0; i
++)
343 Point
aP(pO
->GetSnapPoint(i
));
346 if (std::abs(dx1
)<=mx
&& std::abs(dy1
)<=my
&& std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) {
350 nMaxPointSnapCount
--;
353 if (bOFrmSnap
&& nMaxFrameSnapCount
>0) {
354 tools::Rectangle
aLog(pO
->GetSnapRect());
355 tools::Rectangle
aR1(aLog
);
356 aR1
.AdjustLeft( -mx
);
357 aR1
.AdjustRight(mx
);
358 aR1
.AdjustTop( -my
);
359 aR1
.AdjustBottom(my
);
360 if (aR1
.Contains(rPnt
)) {
361 if (std::abs(x
-aLog
.Left ())<=mx
) { dx1
=-(x
-aLog
.Left ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
362 if (std::abs(x
-aLog
.Right ())<=mx
) { dx1
=-(x
-aLog
.Right ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
363 if (std::abs(y
-aLog
.Top ())<=my
) { dy1
=-(y
-aLog
.Top ()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
364 if (std::abs(y
-aLog
.Bottom())<=my
) { dy1
=-(y
-aLog
.Bottom()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
366 nMaxFrameSnapCount
--;
373 double fSnapWidth(aSnapWdtX
);
374 if(dx
== NOT_SNAPPED
&& fSnapWidth
!= 0.0)
376 double fx
= static_cast<double>(x
);
378 // round instead of trunc
379 if(fx
- static_cast<double>(pPV
->GetPageOrigin().X()) >= 0.0)
380 fx
+= fSnapWidth
/ 2.0;
382 fx
-= fSnapWidth
/ 2.0;
384 x
= static_cast<tools::Long
>((fx
- static_cast<double>(pPV
->GetPageOrigin().X())) / fSnapWidth
);
385 x
= static_cast<tools::Long
>(static_cast<double>(x
) * fSnapWidth
+ static_cast<double>(pPV
->GetPageOrigin().X()));
388 fSnapWidth
= double(aSnapWdtY
);
389 if(dy
== NOT_SNAPPED
&& fSnapWidth
)
391 double fy
= static_cast<double>(y
);
393 // round instead of trunc
394 if(fy
- static_cast<double>(pPV
->GetPageOrigin().Y()) >= 0.0)
395 fy
+= fSnapWidth
/ 2.0;
397 fy
-= fSnapWidth
/ 2.0;
399 y
= static_cast<tools::Long
>((fy
- static_cast<double>(pPV
->GetPageOrigin().Y())) / fSnapWidth
);
400 y
= static_cast<tools::Long
>(static_cast<double>(y
) * fSnapWidth
+ static_cast<double>(pPV
->GetPageOrigin().Y()));
404 SdrSnap bRet
=SdrSnap::NOTSNAPPED
;
405 if (dx
==NOT_SNAPPED
) dx
=0; else bRet
|=SdrSnap::XSNAPPED
;
406 if (dy
==NOT_SNAPPED
) dy
=0; else bRet
|=SdrSnap::YSNAPPED
;
412 void SdrSnapView::CheckSnap(const Point
& rPt
, tools::Long
& nBestXSnap
, tools::Long
& nBestYSnap
, bool& bXSnapped
, bool& bYSnapped
) const
415 SdrSnap nRet
=SnapPos(aPt
,nullptr);
417 if (nRet
& SdrSnap::XSNAPPED
) {
419 if (std::abs(aPt
.X())<std::abs(nBestXSnap
)) {
427 if (nRet
& SdrSnap::YSNAPPED
) {
429 if (std::abs(aPt
.Y())<std::abs(nBestYSnap
)) {
440 void SdrSnapView::BegSetPageOrg(const Point
& rPnt
)
444 DBG_ASSERT(nullptr == mpPageOriginOverlay
, "SdrSnapView::BegSetPageOrg: There exists an ImplPageOriginOverlay (!)");
445 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
446 mpPageOriginOverlay
= new ImplPageOriginOverlay(*this, aStartPos
);
447 maDragStat
.Reset(GetSnapPos(rPnt
,nullptr));
450 void SdrSnapView::MovSetPageOrg(const Point
& rPnt
)
454 maDragStat
.NextMove(GetSnapPos(rPnt
,nullptr));
455 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
456 basegfx::B2DPoint
aNewPos(maDragStat
.GetNow().X(), maDragStat
.GetNow().Y());
457 mpPageOriginOverlay
->SetPosition(aNewPos
);
461 void SdrSnapView::EndSetPageOrg()
466 SdrPageView
* pPV
= GetSdrPageView();
470 Point
aPnt(maDragStat
.GetNow());
471 pPV
->SetPageOrigin(aPnt
);
478 void SdrSnapView::BrkSetPageOrg()
482 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
483 delete mpPageOriginOverlay
;
484 mpPageOriginOverlay
= nullptr;
489 bool SdrSnapView::PickHelpLine(const Point
& rPnt
, short nTol
, const OutputDevice
& rOut
, sal_uInt16
& rnHelpLineNum
, SdrPageView
*& rpPV
) const
492 nTol
=ImpGetHitTolLogic(nTol
,&rOut
);
493 SdrPageView
* pPV
= GetSdrPageView();
498 sal_uInt16 nIndex
=pPV
->GetHelpLines().HitTest(aPnt
,sal_uInt16(nTol
),rOut
);
499 if (nIndex
!=SDRHELPLINE_NOTFOUND
) {
501 rnHelpLineNum
=nIndex
;
508 // start HelpLine drag for new HelpLine
509 bool SdrSnapView::BegDragHelpLine(sal_uInt16 nHelpLineNum
, SdrPageView
* pPV
)
515 if(pPV
&& nHelpLineNum
< pPV
->GetHelpLines().GetCount())
517 const SdrHelpLineList
& rHelpLines
= pPV
->GetHelpLines();
518 const SdrHelpLine
& rHelpLine
= rHelpLines
[nHelpLineNum
];
519 Point aHelpLinePos
= rHelpLine
.GetPos();
520 basegfx::B2DPoint
aStartPos(aHelpLinePos
.X(), aHelpLinePos
.Y());
522 DBG_ASSERT(nullptr == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
523 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, pPV
, nHelpLineNum
, rHelpLine
.GetKind());
525 maDragStat
.Reset(GetSnapPos(aHelpLinePos
, pPV
));
526 maDragStat
.SetMinMove(ImpGetMinMovLogic(-3, nullptr));
534 // start HelpLine drag with existing HelpLine
535 void SdrSnapView::BegDragHelpLine(const Point
& rPnt
, SdrHelpLineKind eNewKind
)
541 DBG_ASSERT(nullptr == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
542 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
543 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, nullptr, 0, eNewKind
);
544 maDragStat
.Reset(GetSnapPos(rPnt
, nullptr));
548 PointerStyle
SdrSnapView::GetDraggedHelpLinePointer() const
552 switch(mpHelpLineOverlay
->GetHelpLineKind())
554 case SdrHelpLineKind::Vertical
: return PointerStyle::ESize
;
555 case SdrHelpLineKind::Horizontal
: return PointerStyle::SSize
;
556 default : return PointerStyle::Move
;
560 return PointerStyle::Move
;
563 void SdrSnapView::MovDragHelpLine(const Point
& rPnt
)
565 if(IsDragHelpLine() && maDragStat
.CheckMinMoved(rPnt
))
567 Point
aPnt(GetSnapPos(rPnt
, nullptr));
569 if(aPnt
!= maDragStat
.GetNow())
571 maDragStat
.NextMove(aPnt
);
572 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::MovDragHelpLine: no ImplHelpLineOverlay (!)");
573 basegfx::B2DPoint
aNewPos(maDragStat
.GetNow().X(), maDragStat
.GetNow().Y());
574 mpHelpLineOverlay
->SetPosition(aNewPos
);
579 bool SdrSnapView::EndDragHelpLine()
585 if(maDragStat
.IsMinMoved())
587 SdrPageView
* pPageView
= mpHelpLineOverlay
->GetPageView();
591 // moved existing one
592 Point
aPnt(maDragStat
.GetNow());
593 const SdrHelpLineList
& rHelpLines
= pPageView
->GetHelpLines();
594 SdrHelpLine aChangedHelpLine
= rHelpLines
[mpHelpLineOverlay
->GetHelpLineNumber()];
595 aChangedHelpLine
.SetPos(aPnt
);
596 pPageView
->SetHelpLine(mpHelpLineOverlay
->GetHelpLineNumber(), aChangedHelpLine
);
603 pPageView
= GetSdrPageView();
607 Point
aPnt(maDragStat
.GetNow());
608 SdrHelpLine
aNewHelpLine(mpHelpLineOverlay
->GetHelpLineKind(), aPnt
);
609 pPageView
->InsertHelpLine(aNewHelpLine
);
623 void SdrSnapView::BrkDragHelpLine()
627 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::EndDragHelpLine: no ImplHelpLineOverlay (!)");
628 delete mpHelpLineOverlay
;
629 mpHelpLineOverlay
= nullptr;
633 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */