From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- svx/source/svdraw/svddrgv.cxx | 920 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 920 insertions(+) create mode 100644 svx/source/svdraw/svddrgv.cxx (limited to 'svx/source/svdraw/svddrgv.cxx') diff --git a/svx/source/svdraw/svddrgv.cxx b/svx/source/svdraw/svddrgv.cxx new file mode 100644 index 0000000000..8b9567c20b --- /dev/null +++ b/svx/source/svdraw/svddrgv.cxx @@ -0,0 +1,920 @@ +/* -*- 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 . + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "svddrgm1.hxx" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace sdr; + +SdrDragView::SdrDragView(SdrModel& rSdrModel, OutputDevice* pOut) + : SdrExchangeView(rSdrModel, pOut) + , mpDragHdl(nullptr) + , mpInsPointUndo(nullptr) + , meDragHdl(SdrHdlKind::Move) + , mnDragThresholdPixels(6) + , mbFramDrag(false) + , mbMarkedHitMovesAlways(false) + , mbDragLimit(false) + , mbDragHdl(false) + , mbDragStripes(false) + , mbSolidDragging(utl::ConfigManager::IsFuzzing() || SvtOptionsDrawinglayer::IsSolidDragCreate()) + , mbResizeAtCenter(false) + , mbCrookAtCenter(false) + , mbDragWithCopy(false) + , mbInsGluePoint(false) + , mbInsObjPointMode(false) + , mbInsGluePointMode(false) + , mbNoDragXorPolys(false) +{ + meDragMode = SdrDragMode::Move; +} + +SdrDragView::~SdrDragView() +{ +} + +bool SdrDragView::IsAction() const +{ + return (mpCurrentSdrDragMethod || SdrExchangeView::IsAction()); +} + +void SdrDragView::MovAction(const Point& rPnt) +{ + SdrExchangeView::MovAction(rPnt); + if (mpCurrentSdrDragMethod) + { + MovDragObj(rPnt); + } +} + +void SdrDragView::EndAction() +{ + if (mpCurrentSdrDragMethod) + { + EndDragObj(); + } + SdrExchangeView::EndAction(); +} + +void SdrDragView::BckAction() +{ + SdrExchangeView::BckAction(); + BrkDragObj(); +} + +void SdrDragView::BrkAction() +{ + SdrExchangeView::BrkAction(); + BrkDragObj(); +} + +void SdrDragView::TakeActionRect(tools::Rectangle& rRect) const +{ + if (mpCurrentSdrDragMethod) + { + rRect=maDragStat.GetActionRect(); + if (rRect.IsEmpty()) + { + SdrPageView* pPV = GetSdrPageView(); + + if(pPV&& pPV->HasMarkedObjPageView()) + { + // #i95646# is this used..? + const basegfx::B2DRange aBoundRange(mpCurrentSdrDragMethod->getCurrentRange()); + if (aBoundRange.isEmpty()) + { + rRect.SetEmpty(); + } + else + { + rRect = tools::Rectangle( + basegfx::fround(aBoundRange.getMinX()), basegfx::fround(aBoundRange.getMinY()), + basegfx::fround(aBoundRange.getMaxX()), basegfx::fround(aBoundRange.getMaxY())); + } + } + } + if (rRect.IsEmpty()) + { + rRect=tools::Rectangle(maDragStat.GetNow(),maDragStat.GetNow()); + } + } + else + { + SdrExchangeView::TakeActionRect(rRect); + } +} + +bool SdrDragView::TakeDragObjAnchorPos(Point& rPos, bool bTR ) const +{ + tools::Rectangle aR; + TakeActionRect(aR); + rPos = bTR ? aR.TopRight() : aR.TopLeft(); + if (GetMarkedObjectCount()==1 && IsDragObj() && // only on single selection + !IsDraggingPoints() && !IsDraggingGluePoints() && // not when moving points + dynamic_cast( mpCurrentSdrDragMethod.get() ) == nullptr) // not when moving handles + { + SdrObject* pObj=GetMarkedObjectByIndex(0); + if (auto pCaptionObj = dynamic_cast(pObj)) + { + Point aPt(pCaptionObj->GetTailPos()); + bool bTail=meDragHdl==SdrHdlKind::Poly; // drag tail + bool bOwn=dynamic_cast( mpCurrentSdrDragMethod.get() ) != nullptr; // specific to object + if (!bTail) + { // for bTail, TakeActionRect already does the right thing + if (bOwn) + { // bOwn may be MoveTextFrame, ResizeTextFrame, but may not (any more) be DragTail + rPos=aPt; + } + else + { + // drag the whole Object (Move, Resize, ...) + const basegfx::B2DPoint aTransformed(mpCurrentSdrDragMethod->getCurrentTransformation() * basegfx::B2DPoint(aPt.X(), aPt.Y())); + rPos.setX( basegfx::fround(aTransformed.getX()) ); + rPos.setY( basegfx::fround(aTransformed.getY()) ); + } + } + } + return true; + } + return false; +} + + +bool SdrDragView::TakeDragLimit(SdrDragMode /*eMode*/, tools::Rectangle& /*rRect*/) const +{ + return false; +} + +bool SdrDragView::BegDragObj(const Point& rPnt, OutputDevice* pOut, SdrHdl* pHdl, short nMinMov, SdrDragMethod* _pForcedMeth) +{ + BrkAction(); + + // so we don't leak the object on early return + std::unique_ptr pForcedMeth(_pForcedMeth); + + bool bRet=false; + { + SetDragWithCopy(false); + //TODO: aAni.Reset(); + mpCurrentSdrDragMethod=nullptr; + SdrDragMode eTmpMode=meDragMode; + if (eTmpMode==SdrDragMode::Move && pHdl!=nullptr && pHdl->GetKind()!=SdrHdlKind::Move) { + eTmpMode=SdrDragMode::Resize; + } + mbDragLimit=TakeDragLimit(eTmpMode,maDragLimit); + mbFramDrag=ImpIsFrameHandles(); + if (!mbFramDrag && + (mpMarkedObj==nullptr || !mpMarkedObj->hasSpecialDrag()) && + (pHdl==nullptr || pHdl->GetObj()==nullptr)) { + mbFramDrag=true; + } + + Point aPnt(rPnt); + basegfx::B2DVector aGridOffset(0.0, 0.0); + + // Coordinate maybe affected by GridOffset, so we may need to + // adapt to Model-coordinates here + if((comphelper::LibreOfficeKit::isActive() && mpMarkedObj + && getPossibleGridOffsetForSdrObject(aGridOffset, GetMarkedObjectByIndex(0), GetSdrPageView())) + || (getPossibleGridOffsetForPosition( + aGridOffset, + basegfx::B2DPoint(aPnt.X(), aPnt.Y()), + GetSdrPageView()))) + { + aPnt.AdjustX(basegfx::fround(-aGridOffset.getX())); + aPnt.AdjustY(basegfx::fround(-aGridOffset.getY())); + } + + if(pHdl == nullptr + || pHdl->GetKind() == SdrHdlKind::Move + || pHdl->GetKind() == SdrHdlKind::MirrorAxis + || pHdl->GetKind() == SdrHdlKind::Transparence + || pHdl->GetKind() == SdrHdlKind::Gradient) + { + maDragStat.Reset(aPnt); + } + else + { + maDragStat.Reset(pHdl->GetPos()); + } + + maDragStat.SetView(static_cast(this)); + maDragStat.SetPageView(mpMarkedPV); // <<-- DragPV has to go here!!! + maDragStat.SetMinMove(ImpGetMinMovLogic(nMinMov,pOut)); + maDragStat.SetHdl(pHdl); + maDragStat.NextPoint(); + mpDragWin=pOut; + mpDragHdl=pHdl; + meDragHdl= pHdl==nullptr ? SdrHdlKind::Move : pHdl->GetKind(); + mbDragHdl=meDragHdl==SdrHdlKind::Ref1 || meDragHdl==SdrHdlKind::Ref2 || meDragHdl==SdrHdlKind::MirrorAxis; + + // Expand test for SdrHdlKind::Anchor_TR + bool bNotDraggable = (SdrHdlKind::Anchor == meDragHdl || SdrHdlKind::Anchor_TR == meDragHdl); + + if(pHdl && (pHdl->GetKind() == SdrHdlKind::SmartTag) && pForcedMeth ) + { + // just use the forced method for smart tags + } + else if(mbDragHdl) + { + mpCurrentSdrDragMethod.reset(new SdrDragMovHdl(*this)); + } + else if(!bNotDraggable) + { + switch (meDragMode) + { + case SdrDragMode::Rotate: case SdrDragMode::Shear: + { + switch (meDragHdl) + { + case SdrHdlKind::Left: case SdrHdlKind::Right: + case SdrHdlKind::Upper: case SdrHdlKind::Lower: + { + // are 3D objects selected? + bool b3DObjSelected = false; + for(size_t a=0; !b3DObjSelected && a(mpMarkedObj)->IsTextFrame() ) + bSingleTextObjMark = true; + } + if ( bSingleTextObjMark ) + mpCurrentSdrDragMethod.reset( new SdrDragObjOwn(*this) ); + else + mpCurrentSdrDragMethod.reset( new SdrDragResize(*this) ); + } + } + else + { + if(SdrHdlKind::Move == meDragHdl) + { + const bool bCustomShapeSelected(1 == GetMarkedObjectCount() && dynamic_cast(GetMarkedObjectByIndex(0)) != nullptr); + + if(bCustomShapeSelected) + { + mpCurrentSdrDragMethod.reset( new SdrDragMove( *this ) ); + } + } + else if(SdrHdlKind::Poly == meDragHdl) + { + const bool bConnectorSelected(1 == GetMarkedObjectCount() && dynamic_cast(GetMarkedObjectByIndex(0)) != nullptr); + + if(bConnectorSelected) + { + // #i97784# + // fallback to old behaviour for connectors (see + // text in task description for more details) + } + else if(!IsMoveAllowed() || !IsResizeAllowed()) + { + // #i77187# + // do not allow move of polygon points if object is move or size protected + return false; + } + } + + if(!mpCurrentSdrDragMethod) + { + // fallback to DragSpecial if no interaction defined + mpCurrentSdrDragMethod.reset( new SdrDragObjOwn(*this) ); + } + } + } + } + } + } + if (pForcedMeth) + { + mpCurrentSdrDragMethod = std::move(pForcedMeth); + } + maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get()); + if (mpCurrentSdrDragMethod) + { + bRet = mpCurrentSdrDragMethod->BeginSdrDrag(); + if (!bRet) + { + if (pHdl==nullptr && dynamic_cast< const SdrDragObjOwn* >(mpCurrentSdrDragMethod.get()) != nullptr) + { + // Obj may not Move SpecialDrag, so try with MoveFrameDrag + mpCurrentSdrDragMethod.reset(); + + if (!IsMoveAllowed()) + return false; + + mbFramDrag=true; + mpCurrentSdrDragMethod.reset( new SdrDragMove(*this) ); + maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get()); + bRet = mpCurrentSdrDragMethod->BeginSdrDrag(); + } + } + if (!bRet) + { + mpCurrentSdrDragMethod.reset(); + maDragStat.SetDragMethod(mpCurrentSdrDragMethod.get()); + } + } + } + + return bRet; +} + +void SdrDragView::MovDragObj(const Point& rPnt) +{ + if (!mpCurrentSdrDragMethod) + return; + + Point aPnt(rPnt); + basegfx::B2DVector aGridOffset(0.0, 0.0); + + // Coordinate maybe affected by GridOffset, so we may need to + // adapt to Model-coordinates here + if((comphelper::LibreOfficeKit::isActive() && mpMarkedObj + && getPossibleGridOffsetForSdrObject(aGridOffset, GetMarkedObjectByIndex(0), GetSdrPageView())) + || (getPossibleGridOffsetForPosition( + aGridOffset, + basegfx::B2DPoint(aPnt.X(), aPnt.Y()), + GetSdrPageView()))) + { + aPnt.AdjustX(basegfx::fround(-aGridOffset.getX())); + aPnt.AdjustY(basegfx::fround(-aGridOffset.getY())); + } + + ImpLimitToWorkArea(aPnt); + mpCurrentSdrDragMethod->MoveSdrDrag(aPnt); // this call already makes a Hide()/Show combination +} + +bool SdrDragView::EndDragObj(bool bCopy) +{ + bool bRet(false); + + // #i73341# If inserting GluePoint, do not insist on last points being different + if(mpCurrentSdrDragMethod && maDragStat.IsMinMoved() && (IsInsertGluePoint() || maDragStat.GetNow() != maDragStat.GetPrev())) + { + sal_Int32 nSavedHdlCount=0; + + if (bEliminatePolyPoints) + { + nSavedHdlCount=GetMarkablePointCount(); + } + + const bool bUndo = IsUndoEnabled(); + if (IsInsertGluePoint() && bUndo) + { + BegUndo(maInsPointUndoStr); + AddUndo(std::unique_ptr(mpInsPointUndo)); + } + + bRet = mpCurrentSdrDragMethod->EndSdrDrag(bCopy); + + if( IsInsertGluePoint() && bUndo) + EndUndo(); + + mpCurrentSdrDragMethod.reset(); + + if (bEliminatePolyPoints) + { + if (nSavedHdlCount!=GetMarkablePointCount()) + { + UnmarkAllPoints(); + } + } + + if (mbInsPolyPoint) + { + SetMarkHandles(nullptr); + mbInsPolyPoint=false; + if( bUndo ) + { + BegUndo(maInsPointUndoStr); + AddUndo(std::unique_ptr(mpInsPointUndo)); + EndUndo(); + } + } + + meDragHdl=SdrHdlKind::Move; + mpDragHdl=nullptr; + + if (!mbSomeObjChgdFlag) + { + // Obj did not broadcast (e. g. Writer FlyFrames) + if(!mbDragHdl) + { + AdjustMarkHdl(); + } + } + } + else + { + BrkDragObj(); + } + + mbInsPolyPoint=false; + SetInsertGluePoint(false); + + return bRet; +} + +void SdrDragView::BrkDragObj() +{ + if (!mpCurrentSdrDragMethod) + return; + + mpCurrentSdrDragMethod->CancelSdrDrag(); + + mpCurrentSdrDragMethod.reset(); + + if (mbInsPolyPoint) + { + mpInsPointUndo->Undo(); // delete inserted point again + delete mpInsPointUndo; + mpInsPointUndo=nullptr; + SetMarkHandles(nullptr); + mbInsPolyPoint=false; + } + + if (IsInsertGluePoint()) + { + mpInsPointUndo->Undo(); // delete inserted gluepoint again + delete mpInsPointUndo; + mpInsPointUndo=nullptr; + SetInsertGluePoint(false); + } + + meDragHdl=SdrHdlKind::Move; + mpDragHdl=nullptr; +} + +bool SdrDragView::IsInsObjPointPossible() const +{ + return mpMarkedObj!=nullptr && mpMarkedObj->IsPolyObj(); +} + +bool SdrDragView::ImpBegInsObjPoint(bool bIdxZwang, const Point& rPnt, bool bNewObj, OutputDevice* pOut) +{ + bool bRet(false); + + if(auto pMarkedPath = dynamic_cast( mpMarkedObj)) + { + BrkAction(); + mpInsPointUndo = dynamic_cast(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*mpMarkedObj).release()); + DBG_ASSERT( mpInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" ); + + OUString aStr(SvxResId(STR_DragInsertPoint)); + + maInsPointUndoStr = aStr.replaceFirst("%1", mpMarkedObj->TakeObjNameSingul() ); + + Point aPt(rPnt); + + if(bNewObj) + aPt = GetSnapPos(aPt,mpMarkedPV); + + bool bClosed0 = pMarkedPath->IsClosedObj(); + + const sal_uInt32 nInsPointNum { bIdxZwang + ? pMarkedPath->NbcInsPoint(aPt, bNewObj) + : pMarkedPath->NbcInsPointOld(aPt, bNewObj) + }; + + if(bClosed0 != pMarkedPath->IsClosedObj()) + { + // Obj was closed implicitly + // object changed + pMarkedPath->SetChanged(); + pMarkedPath->BroadcastObjectChange(); + } + + if (nInsPointNum != SAL_MAX_UINT32) + { + mbInsPolyPoint = true; + UnmarkAllPoints(); + AdjustMarkHdl(); + + bRet = BegDragObj(rPnt, pOut, maHdlList.GetHdl(nInsPointNum), 0); + + if (bRet) + { + maDragStat.SetMinMoved(); + MovDragObj(rPnt); + } + } + else + { + delete mpInsPointUndo; + mpInsPointUndo = nullptr; + } + } + + return bRet; +} + +bool SdrDragView::EndInsObjPoint(SdrCreateCmd eCmd) +{ + if(IsInsObjPoint()) + { + Point aPnt(maDragStat.GetNow()); + bool bOk=EndDragObj(); + if (bOk && eCmd!=SdrCreateCmd::ForceEnd) + { + // Ret=True means: Action is over. + bOk = ! ImpBegInsObjPoint(true, aPnt, eCmd == SdrCreateCmd::NextObject, mpDragWin); + } + + return bOk; + } else return false; +} + +bool SdrDragView::IsInsGluePointPossible() const +{ + bool bRet=false; + if (IsInsGluePointMode() && AreObjectsMarked()) + { + if (GetMarkedObjectCount()==1) + { + // return sal_False, if only 1 object which is a connector. + const SdrObject* pObj=GetMarkedObjectByIndex(0); + if (dynamic_cast(pObj) == nullptr) + { + bRet=true; + } + } + else + { + bRet=true; + } + } + return bRet; +} + +bool SdrDragView::BegInsGluePoint(const Point& rPnt) +{ + bool bRet=false; + SdrObject* pObj; + SdrPageView* pPV; + if (PickMarkedObj(rPnt,pObj,pPV,SdrSearchOptions::PASS2BOUND)) + { + BrkAction(); + UnmarkAllGluePoints(); + mpInsPointUndo = dynamic_cast(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj).release()); + DBG_ASSERT( mpInsPointUndo, "svx::SdrDragView::BegInsObjPoint(), could not create correct undo object!" ); + OUString aStr(SvxResId(STR_DragInsertGluePoint)); + + maInsPointUndoStr = aStr.replaceFirst("%1", pObj->TakeObjNameSingul() ); + + SdrGluePointList* pGPL=pObj->ForceGluePointList(); + if (pGPL!=nullptr) + { + sal_uInt16 nGlueIdx=pGPL->Insert(SdrGluePoint()); + SdrGluePoint& rGP=(*pGPL)[nGlueIdx]; + sal_uInt16 nGlueId=rGP.GetId(); + rGP.SetAbsolutePos(rPnt,*pObj); + + SdrHdl* pHdl=nullptr; + if (MarkGluePoint(pObj,nGlueId,false)) + { + pHdl=GetGluePointHdl(pObj,nGlueId); + } + if (pHdl!=nullptr && pHdl->GetKind()==SdrHdlKind::Glue && pHdl->GetObj()==pObj && pHdl->GetObjHdlNum()==nGlueId) + { + SetInsertGluePoint(true); + bRet=BegDragObj(rPnt,nullptr,pHdl,0); + if (bRet) + { + maDragStat.SetMinMoved(); + MovDragObj(rPnt); + } + else + { + SetInsertGluePoint(false); + delete mpInsPointUndo; + mpInsPointUndo=nullptr; + } + } + else + { + OSL_FAIL("BegInsGluePoint(): GluePoint handle not found."); + } + } + else + { + // no gluepoints possible for this object (e. g. Edge) + SetInsertGluePoint(false); + delete mpInsPointUndo; + mpInsPointUndo=nullptr; + } + } + + return bRet; +} + +void SdrDragView::ShowDragObj() +{ + if(!mpCurrentSdrDragMethod || maDragStat.IsShown()) + return; + + // Changed for the GridOffset stuff: No longer iterate over + // SdrPaintWindow(s), but now over SdrPageWindow(s), so doing the + // same as the SdrHdl visualizations (see ::CreateB2dIAObject) do. + // This is needed to get access to an ObjectContact which is needed + // to evtl. process that GridOffset in CreateOverlayGeometry + SdrPageView* pPageView(GetSdrPageView()); + + if(nullptr != pPageView) + { + for(sal_uInt32 a(0); a < pPageView->PageWindowCount(); a++) + { + const SdrPageWindow& rPageWindow(*pPageView->GetPageWindow(a)); + const SdrPaintWindow& rPaintWindow(rPageWindow.GetPaintWindow()); + + if(rPaintWindow.OutputToWindow()) + { + const rtl::Reference& xOverlayManager( + rPaintWindow.GetOverlayManager()); + + if(xOverlayManager.is()) + { + mpCurrentSdrDragMethod->CreateOverlayGeometry( + *xOverlayManager, + rPageWindow.GetObjectContact()); + + // #i101679# Force changed overlay to be shown + xOverlayManager->flush(); + } + } + } + } + + maDragStat.SetShown(true); +} + +void SdrDragView::HideDragObj() +{ + if(mpCurrentSdrDragMethod && maDragStat.IsShown()) + { + mpCurrentSdrDragMethod->destroyOverlayGeometry(); + maDragStat.SetShown(false); + } +} + + +void SdrDragView::SetNoDragXorPolys(bool bOn) +{ + if (IsNoDragXorPolys()==bOn) + return; + + const bool bDragging(mpCurrentSdrDragMethod); + const bool bShown(bDragging && maDragStat.IsShown()); + + if(bShown) + { + HideDragObj(); + } + + mbNoDragXorPolys = bOn; + + if(bDragging) + { + // force recreation of drag content + mpCurrentSdrDragMethod->resetSdrDragEntries(); + } + + if(bShown) + { + ShowDragObj(); + } +} + +void SdrDragView::SetDragStripes(bool bOn) +{ + if (mpCurrentSdrDragMethod && maDragStat.IsShown()) + { + HideDragObj(); + mbDragStripes=bOn; + ShowDragObj(); + } + else + { + mbDragStripes=bOn; + } +} + +bool SdrDragView::IsOrthoDesired() const +{ + if( dynamic_cast< const SdrDragObjOwn* >( mpCurrentSdrDragMethod.get() ) + || dynamic_cast< const SdrDragResize* >(mpCurrentSdrDragMethod.get() )) + { + return m_bOrthoDesiredOnMarked; + } + + return false; +} + +void SdrDragView::SetMarkHandles(SfxViewShell* pOtherShell) +{ + if( mpDragHdl ) + mpDragHdl = nullptr; + + SdrExchangeView::SetMarkHandles(pOtherShell); +} + +void SdrDragView::SetSolidDragging(bool bOn) +{ + if(mbSolidDragging != bOn) + { + mbSolidDragging = bOn; + } +} + +bool SdrDragView::IsSolidDragging() const +{ + // allow each user to disable by having a local setting, but using AND for + // checking allowance + return mbSolidDragging && SvtOptionsDrawinglayer::IsSolidDragCreate(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3