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/svddrgv.hxx>
22 #include "svx/xattr.hxx"
23 #include <svx/xpoly.hxx>
24 #include <svx/svdetc.hxx>
25 #include <svx/svdtrans.hxx>
26 #include <svx/svdundo.hxx>
27 #include <svx/svdocapt.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/svdopath.hxx>
30 #include <svx/svdoedge.hxx>
31 #include "svx/svdstr.hrc"
32 #include "svdglob.hxx"
33 #include "svddrgm1.hxx"
34 #include <svx/obj3d.hxx>
35 #include <svx/svdoashp.hxx>
36 #include <svx/sdrpaintwindow.hxx>
37 #include <basegfx/polygon/b2dpolypolygontools.hxx>
38 #include <basegfx/polygon/b2dpolygontools.hxx>
39 #include <svx/polypolygoneditor.hxx>
40 #include <basegfx/matrix/b2dhommatrix.hxx>
41 #include <svx/sdr/overlay/overlaymanager.hxx>
51 void SdrDragView::ImpClearVars()
54 eDragMode
=SDRDRAG_MOVE
;
56 bMarkedHitMovesAlways
=false;
61 mpCurrentSdrDragMethod
=NULL
;
67 bInsObjPointMode
=false;
68 bInsGluePointMode
=false;
69 nDragXorPolyLimit
=100;
70 nDragXorPointLimit
=500;
71 bNoDragXorPolys
=false;
74 bRubberEdgeDragging
=true;
75 bDetailedEdgeDragging
=true;
76 nDetailedEdgeDraggingLimit
=10;
77 bResizeAtCenter
=false;
79 bMouseHideWhileDraggingPoints
=false;
82 mbSolidDragging
= getOptionsDrawinglayer().IsSolidDragCreate();
85 SdrDragView::SdrDragView(SdrModel
* pModel1
, OutputDevice
* pOut
)
86 : SdrExchangeView(pModel1
,pOut
)
91 SdrDragView::~SdrDragView()
95 bool SdrDragView::IsAction() const
97 return (mpCurrentSdrDragMethod
|| SdrExchangeView::IsAction());
100 void SdrDragView::MovAction(const Point
& rPnt
)
102 SdrExchangeView::MovAction(rPnt
);
103 if (mpCurrentSdrDragMethod
)
109 void SdrDragView::EndAction()
111 if (mpCurrentSdrDragMethod
)
115 SdrExchangeView::EndAction();
118 void SdrDragView::BckAction()
120 SdrExchangeView::BckAction();
124 void SdrDragView::BrkAction()
126 SdrExchangeView::BrkAction();
130 void SdrDragView::TakeActionRect(Rectangle
& rRect
) const
132 if (mpCurrentSdrDragMethod
)
134 rRect
=aDragStat
.GetActionRect();
137 SdrPageView
* pPV
= GetSdrPageView();
139 if(pPV
&& pPV
->HasMarkedObjPageView())
141 // #i95646# is this used..?
142 const basegfx::B2DRange
aBoundRange(mpCurrentSdrDragMethod
->getCurrentRange());
144 basegfx::fround(aBoundRange
.getMinX()), basegfx::fround(aBoundRange
.getMinY()),
145 basegfx::fround(aBoundRange
.getMaxX()), basegfx::fround(aBoundRange
.getMaxY()));
150 rRect
=Rectangle(aDragStat
.GetNow(),aDragStat
.GetNow());
155 SdrExchangeView::TakeActionRect(rRect
);
159 bool SdrDragView::TakeDragObjAnchorPos(Point
& rPos
, bool bTR
) const
163 rPos
= bTR
? aR
.TopRight() : aR
.TopLeft();
164 if (GetMarkedObjectCount()==1 && IsDragObj() && // only on single selection
165 !IsDraggingPoints() && !IsDraggingGluePoints() && // not when moving points
166 !mpCurrentSdrDragMethod
->ISA(SdrDragMovHdl
)) // not when moving handles
168 SdrObject
* pObj
=GetMarkedObjectByIndex(0);
169 if (pObj
->ISA(SdrCaptionObj
))
171 Point
aPt(((SdrCaptionObj
*)pObj
)->GetTailPos());
172 bool bTail
=eDragHdl
==HDL_POLY
; // drag tail
173 bool bOwn
=mpCurrentSdrDragMethod
->ISA(SdrDragObjOwn
); // specific to object
175 { // for bTail, TakeActionRect already does the right thing
177 { // bOwn may be MoveTextFrame, ResizeTextFrame, but may not (any more) be DragTail
182 // drag the whole Object (Move, Resize, ...)
183 const basegfx::B2DPoint
aTransformed(mpCurrentSdrDragMethod
->getCurrentTransformation() * basegfx::B2DPoint(aPt
.X(), aPt
.Y()));
184 rPos
.X() = basegfx::fround(aTransformed
.getX());
185 rPos
.Y() = basegfx::fround(aTransformed
.getY());
196 bool SdrDragView::TakeDragLimit(SdrDragMode
/*eMode*/, Rectangle
& /*rRect*/) const
201 bool SdrDragView::BegDragObj(const Point
& rPnt
, OutputDevice
* pOut
, SdrHdl
* pHdl
, short nMinMov
, SdrDragMethod
* pForcedMeth
)
207 SetDragWithCopy(false);
208 //TODO: aAni.Reset();
209 mpCurrentSdrDragMethod
=NULL
;
212 SdrDragMode eTmpMode
=eDragMode
;
213 if (eTmpMode
==SDRDRAG_MOVE
&& pHdl
!=NULL
&& pHdl
->GetKind()!=HDL_MOVE
) {
214 eTmpMode
=SDRDRAG_RESIZE
;
216 bDragLimit
=TakeDragLimit(eTmpMode
,aDragLimit
);
217 bFramDrag
=ImpIsFrameHandles();
219 (pMarkedObj
==NULL
|| !pMarkedObj
->hasSpecialDrag()) &&
220 (pHdl
==NULL
|| pHdl
->GetObj()==NULL
)) {
226 || pHdl
->GetKind() == HDL_MOVE
227 || pHdl
->GetKind() == HDL_MIRX
228 || pHdl
->GetKind() == HDL_TRNS
229 || pHdl
->GetKind() == HDL_GRAD
)
231 aDragStat
.Reset(aPnt
);
235 aDragStat
.Reset(pHdl
->GetPos());
238 aDragStat
.SetView((SdrView
*)this);
239 aDragStat
.SetPageView(pMarkedPV
); // <<-- DragPV has to go here!!!
240 aDragStat
.SetMinMove(ImpGetMinMovLogic(nMinMov
,pOut
));
241 aDragStat
.SetHdl(pHdl
);
242 aDragStat
.NextPoint();
245 eDragHdl
= pHdl
==NULL
? HDL_MOVE
: pHdl
->GetKind();
246 bDragHdl
=eDragHdl
==HDL_REF1
|| eDragHdl
==HDL_REF2
|| eDragHdl
==HDL_MIRX
;
248 // Expand test for HDL_ANCHOR_TR
249 bool bNotDraggable
= (HDL_ANCHOR
== eDragHdl
|| HDL_ANCHOR_TR
== eDragHdl
);
251 if(pHdl
&& (pHdl
->GetKind() == HDL_SMARTTAG
) && pForcedMeth
)
253 // just use the forced method for smart tags
257 mpCurrentSdrDragMethod
= new SdrDragMovHdl(*this);
259 else if(!bNotDraggable
)
263 case SDRDRAG_ROTATE
: case SDRDRAG_SHEAR
: case SDRDRAG_DISTORT
:
267 case HDL_LEFT
: case HDL_RIGHT
:
268 case HDL_UPPER
: case HDL_LOWER
:
270 // are 3D objects selected?
271 bool b3DObjSelected
= false;
272 for(sal_uInt32 a
=0;!b3DObjSelected
&& a
<GetMarkedObjectCount();a
++)
274 SdrObject
* pObj
= GetMarkedObjectByIndex(a
);
275 if(pObj
&& pObj
->ISA(E3dObject
))
276 b3DObjSelected
= true;
278 // If yes, allow shear even when !IsShearAllowed,
279 // because 3D objects are limited rotations
280 if (!b3DObjSelected
&& !IsShearAllowed())
282 mpCurrentSdrDragMethod
= new SdrDragShear(*this,eDragMode
==SDRDRAG_ROTATE
);
284 case HDL_UPLFT
: case HDL_UPRGT
:
285 case HDL_LWLFT
: case HDL_LWRGT
:
287 if (eDragMode
==SDRDRAG_SHEAR
|| eDragMode
==SDRDRAG_DISTORT
)
289 if (!IsDistortAllowed(true) && !IsDistortAllowed(false)) return false;
290 mpCurrentSdrDragMethod
= new SdrDragDistort(*this);
294 if (!IsRotateAllowed(true)) return false;
295 mpCurrentSdrDragMethod
= new SdrDragRotate(*this);
300 if (IsMarkedHitMovesAlways() && eDragHdl
==HDL_MOVE
)
301 { // HDL_MOVE is true, even if Obj is hit directly
302 if (!IsMoveAllowed()) return false;
303 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
307 if (!IsRotateAllowed(true)) return false;
308 mpCurrentSdrDragMethod
= new SdrDragRotate(*this);
315 if (eDragHdl
==HDL_MOVE
&& IsMarkedHitMovesAlways())
317 if (!IsMoveAllowed()) return false;
318 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
322 if (!IsMirrorAllowed(true,true)) return false;
323 mpCurrentSdrDragMethod
= new SdrDragMirror(*this);
329 if (eDragHdl
==HDL_MOVE
&& IsMarkedHitMovesAlways())
331 if (!IsMoveAllowed())
333 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
337 if (!IsCrookAllowed(true) && !IsCrookAllowed(false))
339 mpCurrentSdrDragMethod
= new SdrDragCrop(*this);
344 case SDRDRAG_TRANSPARENCE
:
346 if(eDragHdl
== HDL_MOVE
&& IsMarkedHitMovesAlways())
350 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
354 if(!IsTransparenceAllowed())
357 mpCurrentSdrDragMethod
= new SdrDragGradient(*this, false);
361 case SDRDRAG_GRADIENT
:
363 if(eDragHdl
== HDL_MOVE
&& IsMarkedHitMovesAlways())
367 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
371 if(!IsGradientAllowed())
374 mpCurrentSdrDragMethod
= new SdrDragGradient(*this);
381 if (eDragHdl
==HDL_MOVE
&& IsMarkedHitMovesAlways())
383 if (!IsMoveAllowed()) return false;
384 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
388 if (!IsCrookAllowed(true) && !IsCrookAllowed(false)) return false;
389 mpCurrentSdrDragMethod
= new SdrDragCrook(*this);
396 if((eDragHdl
== HDL_MOVE
) && !IsMoveAllowed())
400 else if(eDragHdl
== HDL_GLUE
)
402 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
408 if(eDragHdl
== HDL_MOVE
)
410 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
414 if(!IsResizeAllowed(true))
419 bool bSingleTextObjMark
= false; // SJ: #i100490#
420 if ( GetMarkedObjectCount() == 1 )
422 pMarkedObj
=GetMarkedObjectByIndex(0);
424 pMarkedObj
->ISA( SdrTextObj
) &&
425 static_cast<SdrTextObj
*>(pMarkedObj
)->IsTextFrame() )
426 bSingleTextObjMark
= true;
428 if ( bSingleTextObjMark
)
429 mpCurrentSdrDragMethod
= new SdrDragObjOwn(*this);
431 mpCurrentSdrDragMethod
= new SdrDragResize(*this);
436 if(HDL_MOVE
== eDragHdl
)
438 const bool bCustomShapeSelected(1 == GetMarkedObjectCount() && GetMarkedObjectByIndex(0)->ISA(SdrObjCustomShape
));
440 if(bCustomShapeSelected
)
442 mpCurrentSdrDragMethod
= new SdrDragMove( *this );
445 else if(HDL_POLY
== eDragHdl
)
447 const bool bConnectorSelected(1 == GetMarkedObjectCount() && GetMarkedObjectByIndex(0)->ISA(SdrEdgeObj
));
449 if(bConnectorSelected
)
452 // fallback to old behaviour for connectors (see
453 // text in task description for more details)
455 else if(!IsMoveAllowed() || !IsResizeAllowed())
458 // do not allow move of polygon points if object is move or size protected
463 if(!mpCurrentSdrDragMethod
)
465 // fallback to DragSpecial if no interaction defined
467 mpCurrentSdrDragMethod
= new SdrDragObjOwn(*this);
474 if (pForcedMeth
!=NULL
)
476 delete mpCurrentSdrDragMethod
;
477 mpCurrentSdrDragMethod
= pForcedMeth
;
479 aDragStat
.SetDragMethod(mpCurrentSdrDragMethod
);
480 if (mpCurrentSdrDragMethod
)
482 bRet
= mpCurrentSdrDragMethod
->BeginSdrDrag();
485 if (pHdl
==NULL
&& IS_TYPE(SdrDragObjOwn
,mpCurrentSdrDragMethod
))
487 // Obj may not Move SpecialDrag, so try with MoveFrameDrag
488 delete mpCurrentSdrDragMethod
;
489 mpCurrentSdrDragMethod
= 0;
492 if (!IsMoveAllowed())
496 mpCurrentSdrDragMethod
= new SdrDragMove(*this);
497 aDragStat
.SetDragMethod(mpCurrentSdrDragMethod
);
498 bRet
= mpCurrentSdrDragMethod
->BeginSdrDrag();
503 delete mpCurrentSdrDragMethod
;
504 mpCurrentSdrDragMethod
= 0;
505 aDragStat
.SetDragMethod(mpCurrentSdrDragMethod
);
513 void SdrDragView::MovDragObj(const Point
& rPnt
)
515 if (mpCurrentSdrDragMethod
)
518 ImpLimitToWorkArea(aPnt
);
519 mpCurrentSdrDragMethod
->MoveSdrDrag(aPnt
); // this call already makes a Hide()/Show combination
523 bool SdrDragView::EndDragObj(bool bCopy
)
527 // #i73341# If inserting GluePoint, do not insist on last points being different
528 if(mpCurrentSdrDragMethod
&& aDragStat
.IsMinMoved() && (IsInsertGluePoint() || aDragStat
.GetNow() != aDragStat
.GetPrev()))
530 sal_uIntPtr nHdlAnzMerk
=0;
532 if (bEliminatePolyPoints
)
534 nHdlAnzMerk
=GetMarkablePointCount();
537 const bool bUndo
= IsUndoEnabled();
538 if (IsInsertGluePoint() && bUndo
)
540 BegUndo(aInsPointUndoStr
);
541 AddUndo(pInsPointUndo
);
544 bRet
= mpCurrentSdrDragMethod
->EndSdrDrag(bCopy
);
546 if( IsInsertGluePoint() && bUndo
)
549 delete mpCurrentSdrDragMethod
;
550 mpCurrentSdrDragMethod
= 0;
552 if (bEliminatePolyPoints
)
554 if (nHdlAnzMerk
!=GetMarkablePointCount())
566 BegUndo(aInsPointUndoStr
);
567 AddUndo(pInsPointUndo
);
575 if (!bSomeObjChgdFlag
)
577 // Obj did not broadcast (e. g. Writer FlyFrames)
590 SetInsertGluePoint(false);
595 void SdrDragView::BrkDragObj()
597 if (mpCurrentSdrDragMethod
)
599 mpCurrentSdrDragMethod
->CancelSdrDrag();
601 delete mpCurrentSdrDragMethod
;
602 mpCurrentSdrDragMethod
= 0;
606 pInsPointUndo
->Undo(); // delete inserted point again
607 delete pInsPointUndo
;
613 if (IsInsertGluePoint())
615 pInsPointUndo
->Undo(); // delete inserted glue point again
616 delete pInsPointUndo
;
618 SetInsertGluePoint(false);
626 bool SdrDragView::IsInsObjPointPossible() const
628 return pMarkedObj
!=NULL
&& pMarkedObj
->IsPolyObj();
631 bool SdrDragView::ImpBegInsObjPoint(bool bIdxZwang
, sal_uInt32 nIdx
, const Point
& rPnt
, bool bNewObj
, OutputDevice
* pOut
)
635 if(pMarkedObj
&& pMarkedObj
->ISA(SdrPathObj
))
637 SdrPathObj
* pMarkedPath
= (SdrPathObj
*)pMarkedObj
;
639 pInsPointUndo
= dynamic_cast< SdrUndoGeoObj
* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pMarkedObj
) );
640 DBG_ASSERT( pInsPointUndo
, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );
642 OUString
aStr(ImpGetResStr(STR_DragInsertPoint
));
644 aInsPointUndoStr
= aStr
.replaceFirst("%1", pMarkedObj
->TakeObjNameSingul() );
649 aPt
= GetSnapPos(aPt
,pMarkedPV
);
651 bool bClosed0
= pMarkedPath
->IsClosedObj();
655 mnInsPointNum
= pMarkedPath
->NbcInsPoint(nIdx
, aPt
, bNewObj
, true);
659 mnInsPointNum
= pMarkedPath
->NbcInsPointOld(aPt
, bNewObj
, true);
662 if(bClosed0
!= pMarkedPath
->IsClosedObj())
664 // Obj was closed implicitly
666 pMarkedPath
->SetChanged();
667 pMarkedPath
->BroadcastObjectChange();
670 if(0xffffffff != mnInsPointNum
)
672 bInsPolyPoint
= true;
676 bRet
= BegDragObj(rPnt
, pOut
, aHdl
.GetHdl(mnInsPointNum
), 0);
680 aDragStat
.SetMinMoved();
686 delete pInsPointUndo
;
687 pInsPointUndo
= NULL
;
694 bool SdrDragView::EndInsObjPoint(SdrCreateCmd eCmd
)
698 sal_uInt32
nNextPnt(mnInsPointNum
);
699 Point
aPnt(aDragStat
.GetNow());
700 bool bOk
=EndDragObj(false);
701 if (bOk
&& eCmd
!=SDRCREATE_FORCEEND
)
703 // Ret=True means: Action is over.
704 bOk
=!(ImpBegInsObjPoint(true, nNextPnt
, aPnt
, eCmd
== SDRCREATE_NEXTOBJECT
, pDragWin
));
711 bool SdrDragView::IsInsGluePointPossible() const
714 if (IsInsGluePointMode() && AreObjectsMarked())
716 if (GetMarkedObjectCount()==1)
718 // return sal_False, if only 1 object which is a connector.
719 const SdrObject
* pObj
=GetMarkedObjectByIndex(0);
720 if (!HAS_BASE(SdrEdgeObj
,pObj
))
733 bool SdrDragView::BegInsGluePoint(const Point
& rPnt
)
738 sal_uIntPtr nMarkNum
;
739 if (PickMarkedObj(rPnt
,pObj
,pPV
,&nMarkNum
,SDRSEARCH_PASS2BOUND
))
742 UnmarkAllGluePoints();
743 pInsPointUndo
= dynamic_cast< SdrUndoGeoObj
* >( GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj
) );
744 DBG_ASSERT( pInsPointUndo
, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" );
745 OUString
aStr(ImpGetResStr(STR_DragInsertGluePoint
));
747 aInsPointUndoStr
= aStr
.replaceFirst("%1", pObj
->TakeObjNameSingul() );
749 SdrGluePointList
* pGPL
=pObj
->ForceGluePointList();
752 sal_uInt16 nGlueIdx
=pGPL
->Insert(SdrGluePoint());
753 SdrGluePoint
& rGP
=(*pGPL
)[nGlueIdx
];
754 sal_uInt16 nGlueId
=rGP
.GetId();
755 rGP
.SetAbsolutePos(rPnt
,*pObj
);
758 if (MarkGluePoint(pObj
,nGlueId
,pPV
))
760 pHdl
=GetGluePointHdl(pObj
,nGlueId
);
762 if (pHdl
!=NULL
&& pHdl
->GetKind()==HDL_GLUE
&& pHdl
->GetObj()==pObj
&& pHdl
->GetObjHdlNum()==nGlueId
)
764 SetInsertGluePoint(true);
765 bRet
=BegDragObj(rPnt
,NULL
,pHdl
,0);
768 aDragStat
.SetMinMoved();
773 SetInsertGluePoint(false);
774 delete pInsPointUndo
;
780 OSL_FAIL("BegInsGluePoint(): GluePoint handle not found.");
785 // no glue points possible for this object (e. g. Edge)
786 SetInsertGluePoint(false);
787 delete pInsPointUndo
;
795 void SdrDragView::ShowDragObj()
797 if(mpCurrentSdrDragMethod
&& !aDragStat
.IsShown())
799 for(sal_uInt32
a(0); a
< PaintWindowCount(); a
++)
801 SdrPaintWindow
* pCandidate
= GetPaintWindow(a
);
802 rtl::Reference
<sdr::overlay::OverlayManager
> xOverlayManager
= pCandidate
->GetOverlayManager();
804 if (xOverlayManager
.is())
806 mpCurrentSdrDragMethod
->CreateOverlayGeometry(*xOverlayManager
);
808 // #i101679# Force changed overlay to be shown
809 xOverlayManager
->flush();
813 aDragStat
.SetShown(true);
817 void SdrDragView::HideDragObj()
819 if(mpCurrentSdrDragMethod
&& aDragStat
.IsShown())
821 mpCurrentSdrDragMethod
->destroyOverlayGeometry();
822 aDragStat
.SetShown(false);
828 void SdrDragView::SetNoDragXorPolys(bool bOn
)
830 if (IsNoDragXorPolys()!=bOn
)
832 const bool bDragging(mpCurrentSdrDragMethod
);
833 const bool bShown(bDragging
&& aDragStat
.IsShown());
840 bNoDragXorPolys
= bOn
;
844 // force recreation of drag content
845 mpCurrentSdrDragMethod
->resetSdrDragEntries();
855 void SdrDragView::SetDragStripes(bool bOn
)
857 if (mpCurrentSdrDragMethod
&& aDragStat
.IsShown())
869 bool SdrDragView::IsOrthoDesired() const
871 if(mpCurrentSdrDragMethod
&& (IS_TYPE(SdrDragObjOwn
, mpCurrentSdrDragMethod
) || IS_TYPE(SdrDragResize
, mpCurrentSdrDragMethod
)))
873 return bOrthoDesiredOnMarked
;
879 void SdrDragView::SetMarkHandles()
884 SdrExchangeView::SetMarkHandles();
887 void SdrDragView::SetSolidDragging(bool bOn
)
889 if((bool)mbSolidDragging
!= bOn
)
891 mbSolidDragging
= bOn
;
895 bool SdrDragView::IsSolidDragging() const
897 // allow each user to disable by having a local setting, but using AND for
898 // checking allowance
899 return mbSolidDragging
&& getOptionsDrawinglayer().IsSolidDragCreate();
902 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */