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>
23 #include <svx/svdobj.hxx>
24 #include <svx/svdpagv.hxx>
25 #include <svx/svdpage.hxx>
26 #include <svx/svditer.hxx>
27 #include <svx/sdr/overlay/overlayobjectlist.hxx>
28 #include <sdr/overlay/overlaycrosshair.hxx>
29 #include <sdr/overlay/overlayhelpline.hxx>
30 #include <svx/sdr/overlay/overlaymanager.hxx>
31 #include <svx/sdrpaintwindow.hxx>
32 #include <tools/debug.hxx>
33 #include <vcl/ptrstyle.hxx>
36 class ImplPageOriginOverlay
39 sdr::overlay::OverlayObjectList maObjects
;
41 // The current position in logical coordinates
42 basegfx::B2DPoint maPosition
;
45 ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
);
47 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
48 // That destructor calls clear() at the list which removes all objects from the
49 // OverlayManager and deletes them.
51 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
54 ImplPageOriginOverlay::ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
)
55 : maPosition(rStartPos
)
57 for(sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
59 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
60 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
62 if (xTargetOverlay
.is())
64 std::unique_ptr
<sdr::overlay::OverlayCrosshairStriped
> aNew(new sdr::overlay::OverlayCrosshairStriped(
66 xTargetOverlay
->add(*aNew
);
67 maObjects
.append(std::move(aNew
));
72 void ImplPageOriginOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
74 if(rNewPosition
== maPosition
)
77 // apply to OverlayObjects
78 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
80 sdr::overlay::OverlayCrosshairStriped
* pCandidate
=
81 static_cast< sdr::overlay::OverlayCrosshairStriped
* >(&maObjects
.getOverlayObject(a
));
85 pCandidate
->setBasePosition(rNewPosition
);
89 // remember new position
90 maPosition
= rNewPosition
;
94 class ImplHelpLineOverlay
97 sdr::overlay::OverlayObjectList maObjects
;
99 // The current position in logical coordinates
100 basegfx::B2DPoint maPosition
;
102 // HelpLine specific stuff
103 SdrPageView
* mpPageView
;
104 sal_uInt16 mnHelpLineNumber
;
105 SdrHelpLineKind meHelpLineKind
;
108 ImplHelpLineOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
109 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
);
111 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
112 // That destructor calls clear() at the list which removes all objects from the
113 // OverlayManager and deletes them.
115 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
117 // access to HelpLine specific stuff
118 SdrPageView
* GetPageView() const { return mpPageView
; }
119 sal_uInt16
GetHelpLineNumber() const { return mnHelpLineNumber
; }
120 SdrHelpLineKind
GetHelpLineKind() const { return meHelpLineKind
; }
123 ImplHelpLineOverlay::ImplHelpLineOverlay(
124 const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
125 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
)
126 : maPosition(rStartPos
),
127 mpPageView(pPageView
),
128 mnHelpLineNumber(nHelpLineNumber
),
129 meHelpLineKind(eKind
)
131 for(sal_uInt32
a(0); a
< rView
.PaintWindowCount(); a
++)
133 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
134 const rtl::Reference
< sdr::overlay::OverlayManager
>& xTargetOverlay
= pCandidate
->GetOverlayManager();
136 if (xTargetOverlay
.is())
138 std::unique_ptr
<sdr::overlay::OverlayHelplineStriped
> aNew(new sdr::overlay::OverlayHelplineStriped(
139 maPosition
, meHelpLineKind
));
140 xTargetOverlay
->add(*aNew
);
141 maObjects
.append(std::move(aNew
));
146 void ImplHelpLineOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
148 if(rNewPosition
== maPosition
)
151 // apply to OverlayObjects
152 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
154 sdr::overlay::OverlayHelplineStriped
* pCandidate
=
155 static_cast< sdr::overlay::OverlayHelplineStriped
* >(&maObjects
.getOverlayObject(a
));
159 pCandidate
->setBasePosition(rNewPosition
);
163 // remember new position
164 maPosition
= rNewPosition
;
167 SdrSnapView::SdrSnapView(
170 : SdrPaintView(rSdrModel
, pOut
)
171 ,mpPageOriginOverlay(nullptr)
172 ,mpHelpLineOverlay(nullptr)
175 ,mnEliminatePolyPointLimitAngle(0)
176 ,meCrookMode(SdrCrookMode::Rotate
)
184 ,mbMoveSnapOnlyTopLeft(false)
187 ,mbAngleSnapEnab(false)
188 ,mbMoveOnlyDragging(false)
189 ,mbSlantButShear(false)
190 ,mbCrookNoContortion(false)
191 ,mbEliminatePolyPoints(false)
195 SdrSnapView::~SdrSnapView()
202 bool SdrSnapView::IsAction() const
204 return IsSetPageOrg() || IsDragHelpLine() || SdrPaintView::IsAction();
207 void SdrSnapView::MovAction(const Point
& rPnt
)
209 SdrPaintView::MovAction(rPnt
);
210 if (IsSetPageOrg()) {
213 if (IsDragHelpLine()) {
214 MovDragHelpLine(rPnt
);
218 void SdrSnapView::EndAction()
220 if (IsSetPageOrg()) {
223 if (IsDragHelpLine()) {
226 SdrPaintView::EndAction();
229 void SdrSnapView::BckAction()
233 SdrPaintView::BckAction();
236 void SdrSnapView::BrkAction()
240 SdrPaintView::BrkAction();
243 void SdrSnapView::TakeActionRect(tools::Rectangle
& rRect
) const
245 if (IsSetPageOrg() || IsDragHelpLine()) {
246 rRect
=tools::Rectangle(maDragStat
.GetNow(),maDragStat
.GetNow());
248 SdrPaintView::TakeActionRect(rRect
);
253 Point
SdrSnapView::GetSnapPos(const Point
& rPnt
, const SdrPageView
* pPV
) const
260 #define NOT_SNAPPED 0x7FFFFFFF
261 SdrSnap
SdrSnapView::SnapPos(Point
& rPnt
, const SdrPageView
* pPV
) const
263 if (!mbSnapEnab
) return SdrSnap::NOTSNAPPED
;
264 tools::Long x
=rPnt
.X();
265 tools::Long y
=rPnt
.Y();
267 pPV
=GetSdrPageView();
268 if (pPV
==nullptr) return SdrSnap::NOTSNAPPED
;
271 tools::Long dx
=NOT_SNAPPED
;
272 tools::Long dy
=NOT_SNAPPED
;
274 tools::Long mx
=maMagnSiz
.Width();
275 tools::Long my
=maMagnSiz
.Height();
276 if (mbHlplVisible
&& mbHlplSnap
&& !IsDragHelpLine())
278 const SdrHelpLineList
& rHLL
=pPV
->GetHelpLines();
279 sal_uInt16 nCount
=rHLL
.GetCount();
280 for (sal_uInt16 i
=nCount
; i
>0;) {
282 const SdrHelpLine
& rHL
=rHLL
[i
];
283 const Point
& rPos
=rHL
.GetPos();
284 switch (rHL
.GetKind()) {
285 case SdrHelpLineKind::Vertical
: {
286 tools::Long a
=x
-rPos
.X();
287 if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
289 case SdrHelpLineKind::Horizontal
: {
290 tools::Long b
=y
-rPos
.Y();
291 if (std::abs(b
)<=my
) { dy1
=-b
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
293 case SdrHelpLineKind::Point
: {
294 tools::Long a
=x
-rPos
.X();
295 tools::Long b
=y
-rPos
.Y();
296 if (std::abs(a
)<=mx
&& std::abs(b
)<=my
) {
298 if (std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) { dx
=dx1
; dy
=dy1
; }
304 if (mbBordVisible
&& mbBordSnap
) {
305 SdrPage
* pPage
=pPV
->GetPage();
306 tools::Long xs
=pPage
->GetWidth();
307 tools::Long ys
=pPage
->GetHeight();
308 tools::Long lft
=pPage
->GetLeftBorder();
309 tools::Long rgt
=pPage
->GetRightBorder();
310 tools::Long upp
=pPage
->GetUpperBorder();
311 tools::Long lwr
=pPage
->GetLowerBorder();
313 a
=x
- lft
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left margin
314 a
=x
-(xs
-rgt
); if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right margin
315 a
=x
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left edge of paper
316 a
=x
- xs
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right edge of paper
317 a
=y
- upp
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left margin
318 a
=y
-(ys
-lwr
); if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right margin
319 a
=y
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left edge of paper
320 a
=y
- ys
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right edge of paper
322 if (mbOFrmSnap
|| mbOPntSnap
) {
323 sal_uInt32 nMaxPointSnapCount
=200;
324 sal_uInt32 nMaxFrameSnapCount
=200;
326 // go back to SdrIterMode::DeepNoGroups runthrough for snap to object comparisons
327 SdrObjListIter
aIter(pPV
->GetPage(),SdrIterMode::DeepNoGroups
,true);
329 while (aIter
.IsMore() && (nMaxPointSnapCount
>0 || nMaxFrameSnapCount
>0)) {
330 SdrObject
* pO
=aIter
.Next();
331 tools::Rectangle
aRect(pO
->GetCurrentBoundRect());
332 aRect
.AdjustLeft( -mx
);
333 aRect
.AdjustRight(mx
);
334 aRect
.AdjustTop( -my
);
335 aRect
.AdjustBottom(my
);
336 if (aRect
.Contains(rPnt
)) {
337 if (mbOPntSnap
&& nMaxPointSnapCount
>0)
339 sal_uInt32
nCount(pO
->GetSnapPointCount());
340 for (sal_uInt32
i(0); i
< nCount
&& nMaxPointSnapCount
> 0; i
++)
342 Point
aP(pO
->GetSnapPoint(i
));
345 if (std::abs(dx1
)<=mx
&& std::abs(dy1
)<=my
&& std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) {
349 nMaxPointSnapCount
--;
352 if (mbOFrmSnap
&& nMaxFrameSnapCount
>0) {
353 tools::Rectangle
aLog(pO
->GetSnapRect());
354 tools::Rectangle
aR1(aLog
);
355 aR1
.AdjustLeft( -mx
);
356 aR1
.AdjustRight(mx
);
357 aR1
.AdjustTop( -my
);
358 aR1
.AdjustBottom(my
);
359 if (aR1
.Contains(rPnt
)) {
360 if (std::abs(x
-aLog
.Left ())<=mx
) { dx1
=-(x
-aLog
.Left ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
361 if (std::abs(x
-aLog
.Right ())<=mx
) { dx1
=-(x
-aLog
.Right ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
362 if (std::abs(y
-aLog
.Top ())<=my
) { dy1
=-(y
-aLog
.Top ()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
363 if (std::abs(y
-aLog
.Bottom())<=my
) { dy1
=-(y
-aLog
.Bottom()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
365 nMaxFrameSnapCount
--;
372 double fSnapWidth(maSnapWdtX
);
373 if(dx
== NOT_SNAPPED
&& fSnapWidth
!= 0.0)
375 double fx
= static_cast<double>(x
);
377 // round instead of trunc
378 if(fx
- static_cast<double>(pPV
->GetPageOrigin().X()) >= 0.0)
379 fx
+= fSnapWidth
/ 2.0;
381 fx
-= fSnapWidth
/ 2.0;
383 x
= static_cast<tools::Long
>((fx
- static_cast<double>(pPV
->GetPageOrigin().X())) / fSnapWidth
);
384 x
= static_cast<tools::Long
>(static_cast<double>(x
) * fSnapWidth
+ static_cast<double>(pPV
->GetPageOrigin().X()));
387 fSnapWidth
= double(maSnapWdtY
);
388 if(dy
== NOT_SNAPPED
&& fSnapWidth
)
390 double fy
= static_cast<double>(y
);
392 // round instead of trunc
393 if(fy
- static_cast<double>(pPV
->GetPageOrigin().Y()) >= 0.0)
394 fy
+= fSnapWidth
/ 2.0;
396 fy
-= fSnapWidth
/ 2.0;
398 y
= static_cast<tools::Long
>((fy
- static_cast<double>(pPV
->GetPageOrigin().Y())) / fSnapWidth
);
399 y
= static_cast<tools::Long
>(static_cast<double>(y
) * fSnapWidth
+ static_cast<double>(pPV
->GetPageOrigin().Y()));
403 SdrSnap bRet
=SdrSnap::NOTSNAPPED
;
404 if (dx
==NOT_SNAPPED
) dx
=0; else bRet
|=SdrSnap::XSNAPPED
;
405 if (dy
==NOT_SNAPPED
) dy
=0; else bRet
|=SdrSnap::YSNAPPED
;
411 void SdrSnapView::CheckSnap(const Point
& rPt
, tools::Long
& nBestXSnap
, tools::Long
& nBestYSnap
, bool& bXSnapped
, bool& bYSnapped
) const
414 SdrSnap nRet
=SnapPos(aPt
,nullptr);
416 if (nRet
& SdrSnap::XSNAPPED
) {
418 if (std::abs(aPt
.X())<std::abs(nBestXSnap
)) {
426 if (nRet
& SdrSnap::YSNAPPED
) {
428 if (std::abs(aPt
.Y())<std::abs(nBestYSnap
)) {
439 void SdrSnapView::BegSetPageOrg(const Point
& rPnt
)
443 DBG_ASSERT(nullptr == mpPageOriginOverlay
, "SdrSnapView::BegSetPageOrg: There exists an ImplPageOriginOverlay (!)");
444 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
445 mpPageOriginOverlay
= new ImplPageOriginOverlay(*this, aStartPos
);
446 maDragStat
.Reset(GetSnapPos(rPnt
,nullptr));
449 void SdrSnapView::MovSetPageOrg(const Point
& rPnt
)
453 maDragStat
.NextMove(GetSnapPos(rPnt
,nullptr));
454 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
455 basegfx::B2DPoint
aNewPos(maDragStat
.GetNow().X(), maDragStat
.GetNow().Y());
456 mpPageOriginOverlay
->SetPosition(aNewPos
);
460 void SdrSnapView::EndSetPageOrg()
465 SdrPageView
* pPV
= GetSdrPageView();
469 Point
aPnt(maDragStat
.GetNow());
470 pPV
->SetPageOrigin(aPnt
);
477 void SdrSnapView::BrkSetPageOrg()
481 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
482 delete mpPageOriginOverlay
;
483 mpPageOriginOverlay
= nullptr;
488 bool SdrSnapView::PickHelpLine(const Point
& rPnt
, short nTol
, const OutputDevice
& rOut
, sal_uInt16
& rnHelpLineNum
, SdrPageView
*& rpPV
) const
491 nTol
=ImpGetHitTolLogic(nTol
,&rOut
);
492 SdrPageView
* pPV
= GetSdrPageView();
497 sal_uInt16 nIndex
=pPV
->GetHelpLines().HitTest(aPnt
,sal_uInt16(nTol
),rOut
);
498 if (nIndex
!=SDRHELPLINE_NOTFOUND
) {
500 rnHelpLineNum
=nIndex
;
507 // start HelpLine drag for new HelpLine
508 bool SdrSnapView::BegDragHelpLine(sal_uInt16 nHelpLineNum
, SdrPageView
* pPV
)
514 if(pPV
&& nHelpLineNum
< pPV
->GetHelpLines().GetCount())
516 const SdrHelpLineList
& rHelpLines
= pPV
->GetHelpLines();
517 const SdrHelpLine
& rHelpLine
= rHelpLines
[nHelpLineNum
];
518 Point aHelpLinePos
= rHelpLine
.GetPos();
519 basegfx::B2DPoint
aStartPos(aHelpLinePos
.X(), aHelpLinePos
.Y());
521 DBG_ASSERT(nullptr == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
522 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, pPV
, nHelpLineNum
, rHelpLine
.GetKind());
524 maDragStat
.Reset(GetSnapPos(aHelpLinePos
, pPV
));
525 maDragStat
.SetMinMove(ImpGetMinMovLogic(-3, nullptr));
533 // start HelpLine drag with existing HelpLine
534 void SdrSnapView::BegDragHelpLine(const Point
& rPnt
, SdrHelpLineKind eNewKind
)
540 DBG_ASSERT(nullptr == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists an ImplHelpLineOverlay (!)");
541 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
542 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, nullptr, 0, eNewKind
);
543 maDragStat
.Reset(GetSnapPos(rPnt
, nullptr));
547 PointerStyle
SdrSnapView::GetDraggedHelpLinePointer() const
551 switch(mpHelpLineOverlay
->GetHelpLineKind())
553 case SdrHelpLineKind::Vertical
: return PointerStyle::ESize
;
554 case SdrHelpLineKind::Horizontal
: return PointerStyle::SSize
;
555 default : return PointerStyle::Move
;
559 return PointerStyle::Move
;
562 void SdrSnapView::MovDragHelpLine(const Point
& rPnt
)
564 if(IsDragHelpLine() && maDragStat
.CheckMinMoved(rPnt
))
566 Point
aPnt(GetSnapPos(rPnt
, nullptr));
568 if(aPnt
!= maDragStat
.GetNow())
570 maDragStat
.NextMove(aPnt
);
571 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::MovDragHelpLine: no ImplHelpLineOverlay (!)");
572 basegfx::B2DPoint
aNewPos(maDragStat
.GetNow().X(), maDragStat
.GetNow().Y());
573 mpHelpLineOverlay
->SetPosition(aNewPos
);
578 bool SdrSnapView::EndDragHelpLine()
584 if(maDragStat
.IsMinMoved())
586 SdrPageView
* pPageView
= mpHelpLineOverlay
->GetPageView();
590 // moved existing one
591 Point
aPnt(maDragStat
.GetNow());
592 const SdrHelpLineList
& rHelpLines
= pPageView
->GetHelpLines();
593 SdrHelpLine aChangedHelpLine
= rHelpLines
[mpHelpLineOverlay
->GetHelpLineNumber()];
594 aChangedHelpLine
.SetPos(aPnt
);
595 pPageView
->SetHelpLine(mpHelpLineOverlay
->GetHelpLineNumber(), aChangedHelpLine
);
602 pPageView
= GetSdrPageView();
606 Point
aPnt(maDragStat
.GetNow());
607 SdrHelpLine
aNewHelpLine(mpHelpLineOverlay
->GetHelpLineKind(), aPnt
);
608 pPageView
->InsertHelpLine(aNewHelpLine
);
622 void SdrSnapView::BrkDragHelpLine()
626 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::EndDragHelpLine: no ImplHelpLineOverlay (!)");
627 delete mpHelpLineOverlay
;
628 mpHelpLineOverlay
= nullptr;
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */