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/svdetc.hxx>
25 #include <svx/svdobj.hxx>
26 #include <svx/svdpagv.hxx>
27 #include <svx/svdpage.hxx>
28 #include "svx/svditer.hxx"
29 #include <svx/sdr/overlay/overlayobjectlist.hxx>
30 #include <sdr/overlay/overlaycrosshair.hxx>
31 #include <sdr/overlay/overlayhelpline.hxx>
32 #include <svx/sdr/overlay/overlaymanager.hxx>
33 #include <basegfx/matrix/b2dhommatrix.hxx>
34 #include <svx/sdrpaintwindow.hxx>
37 class ImplPageOriginOverlay
40 ::sdr::overlay::OverlayObjectList maObjects
;
42 // The current position in logical coodinates
43 basegfx::B2DPoint maPosition
;
46 ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
);
47 ~ImplPageOriginOverlay();
49 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
52 ImplPageOriginOverlay::ImplPageOriginOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
)
53 : maPosition(rStartPos
)
55 for(sal_uInt32
a(0L); a
< rView
.PaintWindowCount(); a
++)
57 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
58 rtl::Reference
< ::sdr::overlay::OverlayManager
> xTargetOverlay
= pCandidate
->GetOverlayManager();
60 if (xTargetOverlay
.is())
62 ::sdr::overlay::OverlayCrosshairStriped
* aNew
= new ::sdr::overlay::OverlayCrosshairStriped(
64 xTargetOverlay
->add(*aNew
);
65 maObjects
.append(*aNew
);
70 ImplPageOriginOverlay::~ImplPageOriginOverlay()
72 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
73 // That destructor calls clear() at the list which removes all objects from the
74 // OverlayManager and deletes them.
77 void ImplPageOriginOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
79 if(rNewPosition
!= maPosition
)
81 // apply to OverlayObjects
82 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
84 sdr::overlay::OverlayCrosshairStriped
* pCandidate
=
85 static_cast< sdr::overlay::OverlayCrosshairStriped
* >(&maObjects
.getOverlayObject(a
));
89 pCandidate
->setBasePosition(rNewPosition
);
93 // remember new position
94 maPosition
= rNewPosition
;
99 class ImplHelpLineOverlay
101 // The OverlayObjects
102 ::sdr::overlay::OverlayObjectList maObjects
;
104 // The current position in logical coodinates
105 basegfx::B2DPoint maPosition
;
107 // HelpLine specific stuff
108 SdrPageView
* mpPageView
;
109 sal_uInt16 mnHelpLineNumber
;
110 SdrHelpLineKind meHelpLineKind
;
113 ImplHelpLineOverlay(const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
114 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
);
115 ~ImplHelpLineOverlay();
117 void SetPosition(const basegfx::B2DPoint
& rNewPosition
);
119 // access to HelpLine specific stuff
120 SdrPageView
* GetPageView() const { return mpPageView
; }
121 sal_uInt16
GetHelpLineNumber() const { return mnHelpLineNumber
; }
122 SdrHelpLineKind
GetHelpLineKind() const { return meHelpLineKind
; }
125 ImplHelpLineOverlay::ImplHelpLineOverlay(
126 const SdrPaintView
& rView
, const basegfx::B2DPoint
& rStartPos
,
127 SdrPageView
* pPageView
, sal_uInt16 nHelpLineNumber
, SdrHelpLineKind eKind
)
128 : maPosition(rStartPos
),
129 mpPageView(pPageView
),
130 mnHelpLineNumber(nHelpLineNumber
),
131 meHelpLineKind(eKind
)
133 for(sal_uInt32
a(0L); a
< rView
.PaintWindowCount(); a
++)
135 SdrPaintWindow
* pCandidate
= rView
.GetPaintWindow(a
);
136 rtl::Reference
< ::sdr::overlay::OverlayManager
> xTargetOverlay
= pCandidate
->GetOverlayManager();
138 if (xTargetOverlay
.is())
140 ::sdr::overlay::OverlayHelplineStriped
* aNew
= new ::sdr::overlay::OverlayHelplineStriped(
141 maPosition
, meHelpLineKind
);
142 xTargetOverlay
->add(*aNew
);
143 maObjects
.append(*aNew
);
148 ImplHelpLineOverlay::~ImplHelpLineOverlay()
150 // The OverlayObjects are cleared using the destructor of OverlayObjectList.
151 // That destructor calls clear() at the list which removes all objects from the
152 // OverlayManager and deletes them.
155 void ImplHelpLineOverlay::SetPosition(const basegfx::B2DPoint
& rNewPosition
)
157 if(rNewPosition
!= maPosition
)
159 // apply to OverlayObjects
160 for(sal_uInt32
a(0); a
< maObjects
.count(); a
++)
162 sdr::overlay::OverlayHelplineStriped
* pCandidate
=
163 static_cast< sdr::overlay::OverlayHelplineStriped
* >(&maObjects
.getOverlayObject(a
));
167 pCandidate
->setBasePosition(rNewPosition
);
171 // remember new position
172 maPosition
= rNewPosition
;
177 void SdrSnapView::ClearVars()
192 bMoveSnapOnlyTopLeft
=false;
196 bAngleSnapEnab
=false;
197 bMoveOnlyDragging
=false;
198 bSlantButShear
=false;
199 bCrookNoContortion
=false;
200 eCrookMode
=SDRCROOK_ROTATE
;
202 bEliminatePolyPoints
=false;
203 nEliminatePolyPointLimitAngle
=0;
209 SdrSnapView::SdrSnapView(SdrModel
* pModel1
, OutputDevice
* pOut
):
210 SdrPaintView(pModel1
,pOut
),
211 mpPageOriginOverlay(0L),
212 mpHelpLineOverlay(0L)
217 SdrSnapView::~SdrSnapView()
225 bool SdrSnapView::IsAction() const
227 return IsSetPageOrg() || IsDragHelpLine() || SdrPaintView::IsAction();
230 void SdrSnapView::MovAction(const Point
& rPnt
)
232 SdrPaintView::MovAction(rPnt
);
233 if (IsSetPageOrg()) {
236 if (IsDragHelpLine()) {
237 MovDragHelpLine(rPnt
);
241 void SdrSnapView::EndAction()
243 if (IsSetPageOrg()) {
246 if (IsDragHelpLine()) {
249 SdrPaintView::EndAction();
252 void SdrSnapView::BckAction()
256 SdrPaintView::BckAction();
259 void SdrSnapView::BrkAction()
263 SdrPaintView::BrkAction();
266 void SdrSnapView::TakeActionRect(Rectangle
& rRect
) const
268 if (IsSetPageOrg() || IsDragHelpLine()) {
269 rRect
=Rectangle(aDragStat
.GetNow(),aDragStat
.GetNow());
271 SdrPaintView::TakeActionRect(rRect
);
277 Point
SdrSnapView::GetSnapPos(const Point
& rPnt
, const SdrPageView
* pPV
) const
284 #define NOT_SNAPPED 0x7FFFFFFF
285 sal_uInt16
SdrSnapView::SnapPos(Point
& rPnt
, const SdrPageView
* pPV
) const
287 if (!bSnapEnab
) return SDRSNAP_NOTSNAPPED
;
291 pPV
=GetSdrPageView();
292 if (pPV
==NULL
) return SDRSNAP_NOTSNAPPED
;
298 long mx
=aMagnSiz
.Width();
299 long my
=aMagnSiz
.Height();
300 if (bHlplVisible
&& bHlplSnap
&& !IsDragHelpLine())
302 const SdrHelpLineList
& rHLL
=pPV
->GetHelpLines();
303 sal_uInt16 nAnz
=rHLL
.GetCount();
304 for (sal_uInt16 i
=nAnz
; i
>0;) {
306 const SdrHelpLine
& rHL
=rHLL
[i
];
307 const Point
& rPos
=rHL
.GetPos();
308 switch (rHL
.GetKind()) {
309 case SDRHELPLINE_VERTICAL
: {
311 if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
313 case SDRHELPLINE_HORIZONTAL
: {
315 if (std::abs(b
)<=my
) { dy1
=-b
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
317 case SDRHELPLINE_POINT
: {
320 if (std::abs(a
)<=mx
&& std::abs(b
)<=my
) {
322 if (std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) { dx
=dx1
; dy
=dy1
; }
328 if (bBordVisible
&& bBordSnap
) {
329 SdrPage
* pPage
=pPV
->GetPage();
330 long xs
=pPage
->GetWdt();
331 long ys
=pPage
->GetHgt();
332 long lft
=pPage
->GetLftBorder();
333 long rgt
=pPage
->GetRgtBorder();
334 long upp
=pPage
->GetUppBorder();
335 long lwr
=pPage
->GetLwrBorder();
337 a
=x
- lft
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left margin
338 a
=x
-(xs
-rgt
); if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right margin
339 a
=x
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // left edge of paper
340 a
=x
- xs
; if (std::abs(a
)<=mx
) { dx1
=-a
; if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; } // right edge of paper
341 a
=y
- upp
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left margin
342 a
=y
-(ys
-lwr
); if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right margin
343 a
=y
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // left edge of paper
344 a
=y
- ys
; if (std::abs(a
)<=my
) { dy1
=-a
; if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; } // right edge of paper
346 if (bOFrmSnap
|| bOPntSnap
) {
347 sal_uIntPtr nMaxPointSnapCount
=200;
348 sal_uIntPtr nMaxFrameSnapCount
=200;
350 // go back to IM_DEEPNOGROUPS runthrough for snap to object comparisons
351 SdrObjListIter
aIter(*pPV
->GetPage(),IM_DEEPNOGROUPS
,true);
353 while (aIter
.IsMore() && (nMaxPointSnapCount
>0 || nMaxFrameSnapCount
>0)) {
354 SdrObject
* pO
=aIter
.Next();
355 Rectangle
aRect(pO
->GetCurrentBoundRect());
360 if (aRect
.IsInside(rPnt
)) {
361 if (bOPntSnap
&& nMaxPointSnapCount
>0)
363 sal_uInt32
nAnz(pO
->GetSnapPointCount());
364 for (sal_uInt32
i(0L); i
< nAnz
&& nMaxPointSnapCount
> 0L; i
++)
366 Point
aP(pO
->GetSnapPoint(i
));
369 if (std::abs(dx1
)<=mx
&& std::abs(dy1
)<=my
&& std::abs(dx1
)<std::abs(dx
) && std::abs(dy1
)<std::abs(dy
)) {
373 nMaxPointSnapCount
--;
376 if (bOFrmSnap
&& nMaxFrameSnapCount
>0) {
377 Rectangle
aLog(pO
->GetSnapRect());
383 if (aR1
.IsInside(rPnt
)) {
384 if (std::abs(x
-aLog
.Left ())<=mx
) { dx1
=-(x
-aLog
.Left ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
385 if (std::abs(x
-aLog
.Right ())<=mx
) { dx1
=-(x
-aLog
.Right ()); if (std::abs(dx1
)<std::abs(dx
)) dx
=dx1
; }
386 if (std::abs(y
-aLog
.Top ())<=my
) { dy1
=-(y
-aLog
.Top ()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
387 if (std::abs(y
-aLog
.Bottom())<=my
) { dy1
=-(y
-aLog
.Bottom()); if (std::abs(dy1
)<std::abs(dy
)) dy
=dy1
; }
389 nMaxFrameSnapCount
--;
396 double fSnapWidth
= aSnapWdtX
;
397 if(dx
== NOT_SNAPPED
&& fSnapWidth
!= 0.0)
399 double fx
= (double)x
;
401 // round instead of trunc
402 if(fx
- (double)pPV
->GetPageOrigin().X() >= 0.0)
403 fx
+= fSnapWidth
/ 2.0;
405 fx
-= fSnapWidth
/ 2.0;
407 x
= (long)((fx
- (double)pPV
->GetPageOrigin().X()) / fSnapWidth
);
408 x
= (long)((double)x
* fSnapWidth
+ (double)pPV
->GetPageOrigin().X());
411 fSnapWidth
= aSnapWdtY
;
412 if(dy
== NOT_SNAPPED
&& fSnapWidth
)
414 double fy
= (double)y
;
416 // round instead of trunc
417 if(fy
- (double)pPV
->GetPageOrigin().Y() >= 0.0)
418 fy
+= fSnapWidth
/ 2.0;
420 fy
-= fSnapWidth
/ 2.0;
422 y
= (long)((fy
- (double)pPV
->GetPageOrigin().Y()) / fSnapWidth
);
423 y
= (long)((double)y
* fSnapWidth
+ (double)pPV
->GetPageOrigin().Y());
427 sal_uInt16 bRet
=SDRSNAP_NOTSNAPPED
;
428 if (dx
==NOT_SNAPPED
) dx
=0; else bRet
|=SDRSNAP_XSNAPPED
;
429 if (dy
==NOT_SNAPPED
) dy
=0; else bRet
|=SDRSNAP_YSNAPPED
;
435 void SdrSnapView::CheckSnap(const Point
& rPt
, const SdrPageView
* pPV
, long& nBestXSnap
, long& nBestYSnap
, bool& bXSnapped
, bool& bYSnapped
) const
438 sal_uInt16 nRet
=SnapPos(aPt
,pPV
);
440 if ((nRet
& SDRSNAP_XSNAPPED
) !=0) {
442 if (std::abs(aPt
.X())<std::abs(nBestXSnap
)) {
450 if ((nRet
& SDRSNAP_YSNAPPED
) !=0) {
452 if (std::abs(aPt
.Y())<std::abs(nBestYSnap
)) {
464 bool SdrSnapView::BegSetPageOrg(const Point
& rPnt
)
468 DBG_ASSERT(0L == mpPageOriginOverlay
, "SdrSnapView::BegSetPageOrg: There exists a ImplPageOriginOverlay (!)");
469 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
470 mpPageOriginOverlay
= new ImplPageOriginOverlay(*this, aStartPos
);
471 aDragStat
.Reset(GetSnapPos(rPnt
,NULL
));
476 void SdrSnapView::MovSetPageOrg(const Point
& rPnt
)
480 aDragStat
.NextMove(GetSnapPos(rPnt
,NULL
));
481 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
482 basegfx::B2DPoint
aNewPos(aDragStat
.GetNow().X(), aDragStat
.GetNow().Y());
483 mpPageOriginOverlay
->SetPosition(aNewPos
);
487 bool SdrSnapView::EndSetPageOrg()
493 SdrPageView
* pPV
= GetSdrPageView();
497 Point
aPnt(aDragStat
.GetNow());
498 pPV
->SetPageOrigin(aPnt
);
509 void SdrSnapView::BrkSetPageOrg()
513 DBG_ASSERT(mpPageOriginOverlay
, "SdrSnapView::MovSetPageOrg: no ImplPageOriginOverlay (!)");
514 delete mpPageOriginOverlay
;
515 mpPageOriginOverlay
= 0L;
521 bool SdrSnapView::PickHelpLine(const Point
& rPnt
, short nTol
, const OutputDevice
& rOut
, sal_uInt16
& rnHelpLineNum
, SdrPageView
*& rpPV
) const
524 nTol
=ImpGetHitTolLogic(nTol
,&rOut
);
525 SdrPageView
* pPV
= GetSdrPageView();
530 sal_uInt16 nIndex
=pPV
->GetHelpLines().HitTest(aPnt
,sal_uInt16(nTol
),rOut
);
531 if (nIndex
!=SDRHELPLINE_NOTFOUND
) {
533 rnHelpLineNum
=nIndex
;
540 // start HelpLine drag for new HelpLine
541 bool SdrSnapView::BegDragHelpLine(sal_uInt16 nHelpLineNum
, SdrPageView
* pPV
)
549 if(pPV
&& nHelpLineNum
< pPV
->GetHelpLines().GetCount())
551 const SdrHelpLineList
& rHelpLines
= pPV
->GetHelpLines();
552 const SdrHelpLine
& rHelpLine
= rHelpLines
[nHelpLineNum
];
553 Point aHelpLinePos
= rHelpLine
.GetPos();
554 basegfx::B2DPoint
aStartPos(aHelpLinePos
.X(), aHelpLinePos
.Y());
556 DBG_ASSERT(0L == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists a ImplHelpLineOverlay (!)");
557 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, pPV
, nHelpLineNum
, rHelpLine
.GetKind());
559 aDragStat
.Reset(GetSnapPos(aHelpLinePos
, pPV
));
560 aDragStat
.SetMinMove(ImpGetMinMovLogic(-3, 0L));
569 // start HelpLine drag with existing HelpLine
570 bool SdrSnapView::BegDragHelpLine(const Point
& rPnt
, SdrHelpLineKind eNewKind
)
578 DBG_ASSERT(0L == mpHelpLineOverlay
, "SdrSnapView::BegDragHelpLine: There exists a ImplHelpLineOverlay (!)");
579 basegfx::B2DPoint
aStartPos(rPnt
.X(), rPnt
.Y());
580 mpHelpLineOverlay
= new ImplHelpLineOverlay(*this, aStartPos
, 0L, 0, eNewKind
);
581 aDragStat
.Reset(GetSnapPos(rPnt
, 0L));
588 Pointer
SdrSnapView::GetDraggedHelpLinePointer() const
592 switch(mpHelpLineOverlay
->GetHelpLineKind())
594 case SDRHELPLINE_VERTICAL
: return Pointer(POINTER_ESIZE
);
595 case SDRHELPLINE_HORIZONTAL
: return Pointer(POINTER_SSIZE
);
596 default : return Pointer(POINTER_MOVE
);
600 return Pointer(POINTER_MOVE
);
603 void SdrSnapView::MovDragHelpLine(const Point
& rPnt
)
605 if(IsDragHelpLine() && aDragStat
.CheckMinMoved(rPnt
))
607 Point
aPnt(GetSnapPos(rPnt
, 0L));
609 if(aPnt
!= aDragStat
.GetNow())
611 aDragStat
.NextMove(aPnt
);
612 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::MovDragHelpLine: no ImplHelpLineOverlay (!)");
613 basegfx::B2DPoint
aNewPos(aDragStat
.GetNow().X(), aDragStat
.GetNow().Y());
614 mpHelpLineOverlay
->SetPosition(aNewPos
);
619 bool SdrSnapView::EndDragHelpLine()
625 if(aDragStat
.IsMinMoved())
627 SdrPageView
* pPageView
= mpHelpLineOverlay
->GetPageView();
631 // moved existing one
632 Point
aPnt(aDragStat
.GetNow());
633 const SdrHelpLineList
& rHelpLines
= pPageView
->GetHelpLines();
634 SdrHelpLine aChangedHelpLine
= rHelpLines
[mpHelpLineOverlay
->GetHelpLineNumber()];
635 aChangedHelpLine
.SetPos(aPnt
);
636 pPageView
->SetHelpLine(mpHelpLineOverlay
->GetHelpLineNumber(), aChangedHelpLine
);
643 pPageView
= GetSdrPageView();
647 Point
aPnt(aDragStat
.GetNow());
648 SdrHelpLine
aNewHelpLine(mpHelpLineOverlay
->GetHelpLineKind(), aPnt
);
649 pPageView
->InsertHelpLine(aNewHelpLine
);
663 void SdrSnapView::BrkDragHelpLine()
667 DBG_ASSERT(mpHelpLineOverlay
, "SdrSnapView::EndDragHelpLine: no ImplHelpLineOverlay (!)");
668 delete mpHelpLineOverlay
;
669 mpHelpLineOverlay
= 0L;
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */