Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/svx/source/svdraw/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 114 kB image not shown  

Quelle  svddrgmt.cxx   Sprache: C

 
/* -*- 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 "svddrgm1.hxx"
#include <math.h>

#include <o3tl/numeric.hxx>
#include <osl/diagnose.h>
#include <utility>
#include <vcl/canvastools.hxx>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/ptrstyle.hxx>
#include <svx/xpoly.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdundo.hxx>
#include <svx/svdmark.hxx>
#include <svx/svdpagv.hxx>
#include <svx/svddrgv.hxx>
#include <svx/svdograf.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
#include <svx/sdgcpitm.hxx>
#include <svx/sdooitm.hxx>
#include <svx/sdtagitm.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
#include <sdr/overlay/overlayrollingrectangle.hxx>
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <svx/svditer.hxx>
#include <svx/svdopath.hxx>
#include <svx/polypolygoneditor.hxx>
#include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
#include <sdr/primitive2d/sdrattributecreator.hxx>
#include <sdr/primitive2d/sdrdecompositiontools.hxx>
#include <sdr/primitive2d/sdrprimitivetools.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <drawinglayer/attribute/sdrlineattribute.hxx>
#include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
#include <svl/itempool.hxx>
#include <svtools/optionsdrawinglayer.hxx>
#include <officecfg/Office/Common.hxx>
#include <comphelper/lok.hxx>
#include <map>
#include <vector>


SdrDragEntry::SdrDragEntry()
:   mbAddToTransparent(false)
{
}

SdrDragEntry::~SdrDragEntry()
{
}


SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(basegfx::B2DPolyPolygon aOriginalPolyPolygon)
:   maOriginalPolyPolygon(std::move(aOriginalPolyPolygon))
{
}

SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
{
}

drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool IsDragSizeValid)
{
    drawinglayer::primitive2d::Primitive2DContainer aRetval;

    if(maOriginalPolyPolygon.count())
    {
        basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);

        rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
        basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
        basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
        const double fStripeLength(officecfg::Office::Common::Drawinglayer::StripeLength::get());

        if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
        {
            aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
            aColB.invert();
        }

        aRetval.resize(2);
        aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
            aCopy,
            aColA,
            aColB,
            fStripeLength);

        basegfx::BColor aHilightColor;
        if (IsDragSizeValid)
            aHilightColor = SvtOptionsDrawinglayer::getHilightColor().getBColor();
        else
            aHilightColor = basegfx::BColor(1.0, 0, 0);

        const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
        aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
            std::move(aCopy),
            aHilightColor,
            fTransparence,
            3.0,
            false);
    }

    return aRetval;
}


SdrDragEntrySdrObject::SdrDragEntrySdrObject(
    const SdrObject& rOriginal,
    bool bModify)
:   maOriginal(rOriginal),
    mbModify(bModify)
{
    // add SdrObject parts to transparent overlay stuff
    setAddToTransparent(true);
}

SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
{
}

void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
{
    // for the moment, i need to re-create the clone in all cases. I need to figure
    // out when clone and original have the same class, so that i can use operator=
    // in those cases

    mxClone.clear();

    if(mbModify)
    {
        mxClone = maOriginal.getFullDragClone();

        // apply original transformation, implemented at the DragMethods
        rDragMethod.applyCurrentTransformationToSdrObject(*mxClone);
    }
}

drawinglayer::primitive2d::Primitive2DContainer SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod&, bool /* IsDragSizeValid */)
{
    const SdrObject* pSource = &maOriginal;

    if(mbModify && mxClone)
    {
        // choose source for geometry data
        pSource = mxClone.get();
    }

    // use the view-independent primitive representation (without
    // evtl. GridOffset, that may be applied to the DragEntry individually)
    drawinglayer::primitive2d::Primitive2DContainer xRetval;
    pSource->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
    return xRetval;
}


SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
    drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
:   maPrimitive2DSequence(std::move(rSequence))
{
    // add parts to transparent overlay stuff if necessary
    setAddToTransparent(true);
}

SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
{
}

drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool /* IsDragSizeValid */)
{
    return drawinglayer::primitive2d::Primitive2DContainer {
            new drawinglayer::primitive2d::TransformPrimitive2D(
                rDragMethod.getCurrentTransformation(),
                drawinglayer::primitive2d::Primitive2DContainer(maPrimitive2DSequence))
    };
}

SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(std::vector< basegfx::B2DPoint >&& rPositions, bool bIsPointDrag)
:   maPositions(std::move(rPositions)),
    mbIsPointDrag(bIsPointDrag)
{
    // add SdrObject parts to transparent overlay stuff
    setAddToTransparent(true);
}

SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
{
}

drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool /* IsDragSizeValid */)
{
    drawinglayer::primitive2d::Primitive2DContainer aRetval;

    if(!maPositions.empty())
    {
        basegfx::B2DPolygon aPolygon;

        for(auto const & a: maPositions)
        {
            aPolygon.append(a);
        }

        basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);

        rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);

        const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
        std::vector< basegfx::B2DPoint > aTransformedPositions;

        aTransformedPositions.reserve(aTransformed.count());

        for(sal_uInt32 a = 0; a < aTransformed.count(); a++)
        {
            aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
        }

        if(mbIsPointDrag)
        {
            basegfx::BColor aColor(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());

            if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
            {
                aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
            }

            aRetval = drawinglayer::primitive2d::Primitive2DContainer {
                    new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
                        drawinglayer::primitive2d::createDefaultCross_3x3(aColor))
            };
        }
        else
        {
            aRetval = drawinglayer::primitive2d::Primitive2DContainer {
                    new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
                                                                          SdrHdl::createGluePointBitmap())
             };
        }
    }

    return aRetval;
}


void SdrDragMethod::resetSdrDragEntries()
{
    // clear entries; creation is on demand
    clearSdrDragEntries();
}

basegfx::B2DRange SdrDragMethod::getCurrentRange() const
{
    return maOverlayObjectList.getBaseRange();
}

void SdrDragMethod::clearSdrDragEntries()
{
    maSdrDragEntries.clear();
}

void SdrDragMethod::addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew)
{
    assert(pNew);
    maSdrDragEntries.push_back(std::move(pNew));
}

void SdrDragMethod::createSdrDragEntries()
{
    if(!(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView()))
        return;

    if(getSdrDragView().IsDraggingPoints())
    {
        createSdrDragEntries_PointDrag();
    }
    else if(getSdrDragView().IsDraggingGluePoints())
    {
        createSdrDragEntries_GlueDrag();
    }
    else
    {
        if(getSolidDraggingActive())
        {
            createSdrDragEntries_SolidDrag();
        }
        else
        {
            createSdrDragEntries_PolygonDrag();
        }
    }
}

void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
{
    // add full object drag; Clone() at the object has to work
    // for this
    addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
}

void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
    std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
    const sdr::contact::ObjectContact& rObjectContact,
    sdr::overlay::OverlayManager& rOverlayManager)
{
    // check if we have an OverlayObject
    if(!pOverlayObject)
    {
        return;
    }

    // add to OverlayManager
    rOverlayManager.add(*pOverlayObject);

    // Add GridOffset for non-linear ViewToDevice transformation (calc)
    if(rObjectContact.supportsGridOffsets())
    {
        const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());

        if(!rNewRange.isEmpty())
        {
            basegfx::B2DVector aOffset(0.0, 0.0);
            rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);

            if(!aOffset.equalZero())
            {
                pOverlayObject->setOffset(aOffset);
            }
        }
    }

    // add to local OverlayObjectList - ownership change (!)
    maOverlayObjectList.append(std::move(pOverlayObject));
}

void SdrDragMethod::createSdrDragEntries_SolidDrag()
{
    const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
    const size_t nMarkCount(rMarkList.GetMarkCount());
    SdrPageView* pPV = getSdrDragView().GetSdrPageView();

    if(!pPV)
        return;

    for(size_t a = 0; a < nMarkCount; ++a)
    {
        SdrMark* pM = rMarkList.GetMark(a);

        if(pM->GetPageView() == pPV)
        {
            const SdrObject* pObject = pM->GetMarkedSdrObj();

            if(pObject)
            {
                if(pPV->PageWindowCount())
                {
                    SdrObjListIter aIter(*pObject);

                    while(aIter.IsMore())
                    {
                        SdrObject* pCandidate = aIter.Next();

                        if(pCandidate)
                        {
                            const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
                            bool bAddWireframe(bSuppressFullDrag);

                            if(!bAddWireframe && !pCandidate->HasLineStyle())
                            {
                                // add wireframe for objects without outline
                                bAddWireframe = true;
                            }

                            if(!bSuppressFullDrag)
                            {
                                // add full object drag; Clone() at the object has to work
                                // for this
                                createSdrDragEntryForSdrObject(*pCandidate);
                            }

                            if(bAddWireframe)
                            {
                                // when dragging a 50% transparent copy of a filled or not filled object without
                                // outline, this is normally hard to see. Add extra wireframe in that case. This
                                // works nice e.g. with text frames etc.
                                addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly())));
                            }
                        }
                    }
                }
            }
        }
    }
}

void SdrDragMethod::createSdrDragEntries_PolygonDrag()
{
    const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
    const size_t nMarkCount(rMarkList.GetMarkCount());
    bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkCount > SdrDragView::GetDragXorPolyLimit());
    basegfx::B2DPolyPolygon aResult;
    sal_uInt32 nPointCount(0);

    for(size_t a = 0; !bNoPolygons && a < nMarkCount; ++a)
    {
        SdrMark* pM = rMarkList.GetMark(a);

        if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
        {
            const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());

            for(auto const& rPolygon : aNewPolyPolygon)
            {
                nPointCount += rPolygon.count();
            }

            if(nPointCount > SdrDragView::GetDragXorPointLimit())
            {
                bNoPolygons = true;
            }

            if(!bNoPolygons)
            {
                aResult.append(aNewPolyPolygon);
            }
        }
    }

    if(bNoPolygons)
    {
        const tools::Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
        const basegfx::B2DRange aNewRectangle = vcl::unotools::b2DRectangleFromRectangle(aR);
        basegfx::B2DPolygon aNewPolygon(basegfx::utils::createPolygonFromRect(aNewRectangle));

        aResult = basegfx::B2DPolyPolygon(basegfx::utils::expandToCurve(aNewPolygon));
    }

    if(aResult.count())
    {
        addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aResult))));
    }
}

void SdrDragMethod::createSdrDragEntries_PointDrag()
{
    const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
    const size_t nMarkCount(rMarkList.GetMarkCount());
    std::vector< basegfx::B2DPoint > aPositions;

    for(size_t nm = 0; nm < nMarkCount; ++nm)
    {
        SdrMark* pM = rMarkList.GetMark(nm);

        if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
        {
            const SdrUShortCont& rPts = pM->GetMarkedPoints();

            if (!rPts.empty())
            {
                const SdrObject* pObj = pM->GetMarkedSdrObj();
                const SdrPathObj* pPath = dynamic_castconst SdrPathObj* >(pObj);

                if(pPath)
                {
                    const basegfx::B2DPolyPolygon& aPathXPP = pPath->GetPathPoly();

                    if(aPathXPP.count())
                    {
                        for(const sal_uInt16 nObjPt : rPts)
                        {
                            sal_uInt32 nPolyNum, nPointNum;

                            if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum))
                            {
                                aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
                            }
                        }
                    }
                }
            }
        }
    }

    if(!aPositions.empty())
    {
        addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), true)));
    }
}

void SdrDragMethod::createSdrDragEntries_GlueDrag()
{
    const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
    const size_t nMarkCount(rMarkList.GetMarkCount());
    std::vector< basegfx::B2DPoint > aPositions;

    for(size_t nm = 0; nm < nMarkCount; ++nm)
    {
        SdrMark* pM = rMarkList.GetMark(nm);

        if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
        {
            const SdrUShortCont& rPts = pM->GetMarkedGluePoints();

            if (!rPts.empty())
            {
                const SdrObject* pObj = pM->GetMarkedSdrObj();
                const SdrGluePointList* pGPL = pObj->GetGluePointList();

                if (pGPL)
                {
                    for(const sal_uInt16 nObjPt : rPts)
                    {
                        const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));

                        if(SDRGLUEPOINT_NOTFOUND != nGlueNum)
                        {
                            const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
                            aPositions.emplace_back(aPoint.X(), aPoint.Y());
                        }
                    }
                }
            }
        }
    }

    if(!aPositions.empty())
    {
        addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), false)));
    }
}

OUString SdrDragMethod::ImpGetDescriptionStr(TranslateId pStrCacheID) const
{
    ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE;
    if (IsDraggingPoints()) {
        nOpt=ImpGetDescriptionOptions::POINTS;
    } else if (IsDraggingGluePoints()) {
        nOpt=ImpGetDescriptionOptions::GLUEPOINTS;
    }
    return getSdrDragView().ImpGetDescriptionString(pStrCacheID, nOpt);
}

SdrObject* SdrDragMethod::GetDragObj() const
{
    SdrObject* pObj=nullptr;
    if (getSdrDragView().mpDragHdl!=nullptr) pObj=getSdrDragView().mpDragHdl->GetObj();
    if (pObj==nullptr) pObj=getSdrDragView().mpMarkedObj;
    return pObj;
}

SdrPageView* SdrDragMethod::GetDragPV() const
{
    SdrPageView* pPV=nullptr;
    if (getSdrDragView().mpDragHdl!=nullptr) pPV=getSdrDragView().mpDragHdl->GetPageView();
    if (pPV==nullptr) pPV=getSdrDragView().mpMarkedPV;
    return pPV;
}

void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
    // Later this should be the only needed one for linear transforms (not for SdrDragCrook and
    // SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the
    // special handling of rotate/mirror due to the not-being-able to handle it in the old
    // drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
    basegfx::B2DHomMatrix aObjectTransform;
    basegfx::B2DPolyPolygon aObjectPolyPolygon;
    bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));

    // apply transform to object transform
    aObjectTransform *= getCurrentTransformation();

    if(bPolyUsed)
    {
        // do something special since the object size is in the polygon
        // break up matrix to get the scale
        const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);

        // get polygon's position and size
        const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());

        // get the scaling factors (do not mirror, this is in the object transformation)
        const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
        const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));

        // prepare transform matrix for polygon
        basegfx::B2DHomMatrix aPolyTransform(
            basegfx::utils::createTranslateB2DHomMatrix(
                -aPolyRange.getMinX(),
                -aPolyRange.getMinY()));
        aPolyTransform.scale(fScaleX, fScaleY);

        // transform the polygon
        aObjectPolyPolygon.transform(aPolyTransform);
    }

    rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
}

void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
{
    // original uses CurrentTransformation
    rTarget.transform(getCurrentTransformation());
}

SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
:   mrSdrDragView(rNewView),
    mbMoveOnly(false),
    mbSolidDraggingActive(getSdrDragView().IsSolidDragging()),
    mbShiftPressed(false)
{
    if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
    {
        // fallback to wireframe when high contrast is used
        mbSolidDraggingActive = false;
    }
}

SdrDragMethod::~SdrDragMethod()
{
    clearSdrDragEntries();
}

void SdrDragMethod::Show(bool IsValidSize)
{
    getSdrDragView().ShowDragObj(IsValidSize);
}

void SdrDragMethod::Hide()
{
    getSdrDragView().HideDragObj();
}

basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation() const
{
    return basegfx::B2DHomMatrix();
}

void SdrDragMethod::CancelSdrDrag()
{
    Hide();
}

typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;

void SdrDragMethod::CreateOverlayGeometry(
    sdr::overlay::OverlayManager& rOverlayManager,
    const sdr::contact::ObjectContact& rObjectContact, bool bIsGeometrySizeValid)
{
    // We do client-side object manipulation with the Kit API
    if (comphelper::LibreOfficeKit::isActive())
        return;

    // create SdrDragEntries on demand
    if(maSdrDragEntries.empty())
    {
        createSdrDragEntries();
    }

    // if there are entries, derive OverlayObjects from the entries, including
    // modification from current interactive state
    if(!maSdrDragEntries.empty())
    {
        // #i54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
        // primitives, holding the original and the clone. If connectors (Edges) are involved,
        // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
        // they are connected to the original SdrObjects). To do so, trigger the preparation
        // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
        // and evtl. remember if it was an edge
        SdrObjectAndCloneMap aOriginalAndClones;
        std::vector< SdrEdgeObj* > aEdges;

        // #i54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
        // clone, remember edges
        for(auto const & a: maSdrDragEntries)
        {
            SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(a.get());

            if(pSdrDragEntrySdrObject)
            {
                pSdrDragEntrySdrObject->prepareCurrentState(*this);

                SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());

                if(pSdrEdgeObj)
                {
                    aEdges.push_back(pSdrEdgeObj);
                }

                if(pSdrDragEntrySdrObject->getClone())
                {
                    aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
                }
            }
        }

        // #i54102# if there are edges, reconnect their ends to the corresponding clones (if found)
        for(SdrEdgeObj* pSdrEdgeObj: aEdges)
        {
            SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);

            if(pConnectedTo)
            {
                SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);

                if(aEntry != aOriginalAndClones.end())
                {
                    pSdrEdgeObj->ConnectToNode(true, aEntry->second);
                }
            }

            pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);

            if(pConnectedTo)
            {
                SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);

                if(aEntry != aOriginalAndClones.end())
                {
                    pSdrEdgeObj->ConnectToNode(false, aEntry->second);
                }
            }
        }

        // collect primitives for visualisation
        drawinglayer::primitive2d::Primitive2DContainer aResult;
        drawinglayer::primitive2d::Primitive2DContainer aResultTransparent;

        for(auto & pCandidate: maSdrDragEntries)
        {
            const drawinglayer::primitive2d::Primitive2DContainer aCandidateResult(
                    pCandidate->createPrimitive2DSequenceInCurrentState(*this, bIsGeometrySizeValid));

            if(!aCandidateResult.empty())
            {
                if(pCandidate->getAddToTransparent())
                {
                    aResultTransparent.append(aCandidateResult);
                }
                else
                {
                    aResult.append(aCandidateResult);
                }
            }
        }

        if(DoAddConnectorOverlays())
        {
            drawinglayer::primitive2d::Primitive2DContainer aConnectorOverlays(AddConnectorOverlays());

            if(!aConnectorOverlays.empty())
            {
                // add connector overlays to transparent part
                aResultTransparent.append(std::move(aConnectorOverlays));
            }
        }

        if(!aResult.empty())
        {
            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
                new sdr::overlay::OverlayPrimitive2DSequenceObject(
                    std::move(aResult)));

            insertNewlyCreatedOverlayObjectForSdrDragMethod(
                std::move(pNewOverlayObject),
                rObjectContact,
                rOverlayManager);
        }

        if(!aResultTransparent.empty())
        {
            aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer {
                new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aResultTransparent), 0.5)
            };

            std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
                new sdr::overlay::OverlayPrimitive2DSequenceObject(
                    std::move(aResultTransparent)));

            insertNewlyCreatedOverlayObjectForSdrDragMethod(
                std::move(pNewOverlayObject),
                rObjectContact,
                rOverlayManager);
        }
    }

    // add DragStripes if necessary (help lines cross the page when dragging)
    if(!getSdrDragView().IsDragStripes())
        return;

    tools::Rectangle aActionRectangle;
    getSdrDragView().TakeActionRect(aActionRectangle);

    const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
    const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
    std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
        new sdr::overlay::OverlayRollingRectangleStriped(
            aTopLeft,
            aBottomRight,
            true,
            false));

    insertNewlyCreatedOverlayObjectForSdrDragMethod(
        std::move(pNew),
        rObjectContact,
        rOverlayManager);
}

void SdrDragMethod::destroyOverlayGeometry()
{
    maOverlayObjectList.clear();
}

bool SdrDragMethod::DoAddConnectorOverlays()
{
    // these conditions are translated from SdrDragView::ImpDrawEdgeXor
    const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();

    if(!rMarkedNodes.GetMarkCount())
    {
        return false;
    }

    if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
    {
        return false;
    }

    if(!getMoveOnly() && !(
        dynamic_cast<const SdrDragMove*>(this) != nullptr || dynamic_cast<const SdrDragResize*>(this) != nullptr ||
        dynamic_cast<const SdrDragRotate*>(this) != nullptr || dynamic_cast<const SdrDragMirror*>(this) != nullptr ))
    {
        return false;
    }

    // one more migrated from SdrEdgeObj::NspToggleEdgeXor
    ifdynamic_castconst SdrDragObjOwn* >(this) != nullptr || dynamic_castconst SdrDragMovHdl* >(this) != nullptr )
    {
        return false;
    }

    return true;
}

drawinglayer::primitive2d::Primitive2DContainer SdrDragMethod::AddConnectorOverlays()
{
    drawinglayer::primitive2d::Primitive2DContainer aRetval;
    const bool bDetail(getMoveOnly());
    const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();

    for(size_t a = 0; a < rMarkedNodes.GetMarkCount(); ++a)
    {
        SdrMark* pEM = rMarkedNodes.GetMark(a);

        if(pEM && pEM->GetMarkedSdrObj())
        {
            SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());

            if(pEdge)
            {
                basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));

                if(aEdgePolygon.count())
                {
                    // this polygon is a temporary calculated connector path, so it is not possible to fetch
                    // the needed primitives directly from the pEdge object which does not get changed. If full
                    // drag is on, use the SdrObjects ItemSet to create an adequate representation
                    bool bUseSolidDragging(getSolidDraggingActive());

                    if(bUseSolidDragging)
                    {
                        // switch off solid dragging if connector is not visible
                        if(!pEdge->HasLineStyle())
                        {
                            bUseSolidDragging = false;
                        }
                    }

                    if(bUseSolidDragging)
                    {
                        const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
                        const drawinglayer::attribute::SdrLineAttribute aLine(
                            drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));

                        if(!aLine.isDefault())
                        {
                            const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
                                drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
                                    rItemSet,
                                    aLine.getWidth()));

                            aRetval.push_back(drawinglayer::primitive2d::createPolygonLinePrimitive(
                                    aEdgePolygon,
                                    aLine,
                                    aLineStartEnd));
                        }
                    }
                    else
                    {
                        basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
                        basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
                        const double fStripeLength(officecfg::Office::Common::Drawinglayer::StripeLength::get());

                        if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
                        {
                            aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
                            aColB.invert();
                        }

                        drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
                            new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
                                std::move(aEdgePolygon), aColA, aColB, fStripeLength));
                        aRetval.push_back(aPolyPolygonMarkerPrimitive2D);
                    }
                }
            }
        }
    }

    return aRetval;
}


SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
:   SdrDragMethod(rNewView)
{
}

void SdrDragMovHdl::createSdrDragEntries()
{
    // SdrDragMovHdl does not use the default drags,
    // but creates nothing
}

OUString SdrDragMovHdl::GetSdrDragComment() const
{
    OUString aStr=SvxResId(STR_DragMethMovHdl);
    if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy);
    return aStr;
}

bool SdrDragMovHdl::BeginSdrDrag()
{
    if( !GetDragHdl() )
        return false;

    DragStat().SetRef1(GetDragHdl()->GetPos());
    DragStat().SetShown(!DragStat().IsShown());
    SdrHdlKind eKind=GetDragHdl()->GetKind();
    SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
    SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);

    if (eKind==SdrHdlKind::MirrorAxis)
    {
        if (pH1==nullptr || pH2==nullptr)
        {
            OSL_FAIL("SdrDragMovHdl::BeginSdrDrag(): Moving the axis of reflection: reference handles not found.");
            return false;
        }

        DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
    }
    else
    {
        Point aPt(GetDragHdl()->GetPos());
        DragStat().SetActionRect(tools::Rectangle(aPt,aPt));
    }

    return true;
}

void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
{
    Point aPnt(rNoSnapPnt);

    if ( !(GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)))
        return;

    if (GetDragHdl()->GetKind()==SdrHdlKind::MirrorAxis)
    {
        SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
        SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);

        if (pH1==nullptr || pH2==nullptr)
            return;

        if (!DragStat().IsNoSnap())
        {
            tools::Long nBestXSnap=0;
            tools::Long nBestYSnap=0;
            bool bXSnapped=false;
            bool bYSnapped=false;
            Point aDif(aPnt-DragStat().GetStart());
            getSdrDragView().CheckSnap(Ref1()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
            getSdrDragView().CheckSnap(Ref2()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
            aPnt.AdjustX(nBestXSnap );
            aPnt.AdjustY(nBestYSnap );
        }

        if (aPnt!=DragStat().GetNow())
        {
            Hide();
            DragStat().NextMove(aPnt);
            Point aDif(DragStat().GetNow()-DragStat().GetStart());
            pH1->SetPos(Ref1()+aDif);
            pH2->SetPos(Ref2()+aDif);

            SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);

            if(pHM)
                pHM->Touch();

            Show();
            DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
        }
    }
    else
    {
        if (!DragStat().IsNoSnap()) SnapPos(aPnt);
        Degree100 nSA(0);

        if (getSdrDragView().IsAngleSnapEnabled())
            nSA=getSdrDragView().GetSnapAngle();

        if (getSdrDragView().IsMirrorAllowed(true,true))
        { // limited
            if (!getSdrDragView().IsMirrorAllowed()) nSA=4500_deg100;
            if (!getSdrDragView().IsMirrorAllowed(true)) nSA=9000_deg100;
        }

        if (getSdrDragView().IsOrtho() && nSA!=9000_deg100)
            nSA=4500_deg100;

        if (nSA)
        { // angle snapping
            SdrHdlKind eRef=SdrHdlKind::Ref1;

            if (GetDragHdl()->GetKind()==SdrHdlKind::Ref1)
                eRef=SdrHdlKind::Ref2;

            SdrHdl* pH=GetHdlList().GetHdl(eRef);

            if (pH!=nullptr)
            {
                Point aRef(pH->GetPos());
                Degree100 nAngle=NormAngle36000(GetAngle(aPnt-aRef));
                Degree100 nNewAngle=nAngle;
                nNewAngle+=nSA/2_deg100;
                nNewAngle/=nSA;
                nNewAngle*=nSA;
                nNewAngle=NormAngle36000(nNewAngle);
                double a=toRadians(nNewAngle-nAngle);
                double nSin=sin(a);
                double nCos=cos(a);
                RotatePoint(aPnt,aRef,nSin,nCos);

                // eliminate rounding errors for certain values
                if (nSA==9000_deg100)
                {
                    if (nNewAngle==0_deg100    || nNewAngle==18000_deg100) aPnt.setY(aRef.Y() );
                    if (nNewAngle==9000_deg100 || nNewAngle==27000_deg100) aPnt.setX(aRef.X() );
                }

                if (nSA==4500_deg100)
                    OrthoDistance8(aRef,aPnt,true);
            }
        }

        if (aPnt!=DragStat().GetNow())
        {
            Hide();
            DragStat().NextMove(aPnt);
            GetDragHdl()->SetPos(DragStat().GetNow());
            SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);

            if(pHM)
                pHM->Touch();

            Show();
            DragStat().SetActionRect(tools::Rectangle(aPnt,aPnt));
        }
    }
}

bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
{
    if( GetDragHdl() )
    {
        switch (GetDragHdl()->GetKind())
        {
            case SdrHdlKind::Ref1:
                Ref1()=DragStat().GetNow();
                break;

            case SdrHdlKind::Ref2:
                Ref2()=DragStat().GetNow();
                break;

            case SdrHdlKind::MirrorAxis:
                Ref1()+=DragStat().GetNow()-DragStat().GetStart();
                Ref2()+=DragStat().GetNow()-DragStat().GetStart();
                break;

            defaultbreak;
        }
    }

    return true;
}

void SdrDragMovHdl::CancelSdrDrag()
{
    Hide();

    SdrHdl* pHdl = GetDragHdl();
    if( pHdl )
        pHdl->SetPos(DragStat().GetRef1());

    SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);

    if(pHM)
        pHM->Touch();
}

PointerStyle SdrDragMovHdl::GetSdrDragPointer() const
{
    const SdrHdl* pHdl = GetDragHdl();

    if (pHdl!=nullptr)
    {
        return pHdl->GetPointer();
    }

    return PointerStyle::RefHand;
}


SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
:   SdrDragMethod(rNewView)
{
    const SdrObject* pObj = GetDragObj();

    if(pObj)
    {
        // suppress full drag for some object types
        setSolidDraggingActive(pObj->supportsFullDrag());
    }
}

SdrDragObjOwn::~SdrDragObjOwn()
{
}

void SdrDragObjOwn::createSdrDragEntries()
{
    if(!mxClone)
        return;

    basegfx::B2DPolyPolygon aDragPolyPolygon;
    bool bAddWireframe(true);

    if(getSolidDraggingActive())
    {
        SdrPageView* pPV = getSdrDragView().GetSdrPageView();

        if(pPV && pPV->PageWindowCount())
        {
            addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mxClone, false)));

            // potentially no wireframe needed, full drag works
            bAddWireframe = false;
        }
    }

    if(!bAddWireframe)
    {
        // check for extra conditions for wireframe, e.g. no border at
        // objects
        if(!mxClone->HasLineStyle())
        {
            bAddWireframe = true;
        }
    }

    if(bAddWireframe)
    {
        // use wireframe poly when full drag is off or did not work
        aDragPolyPolygon = mxClone->TakeXorPoly();
    }

    // add evtl. extra DragPolyPolygon
    const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mxClone->getSpecialDragPoly(DragStat()));

    if(aSpecialDragPolyPolygon.count())
    {
        aDragPolyPolygon.append(aSpecialDragPolyPolygon);
    }

    if(aDragPolyPolygon.count())
    {
        addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aDragPolyPolygon))));
    }
}

OUString SdrDragObjOwn::GetSdrDragComment() const
{
    OUString aStr;
    // #i103058# get info string from the clone preferred, the original will
    // not be changed. For security, use original as fallback
    if(mxClone)
    {
        aStr = mxClone->getSpecialDragComment(DragStat());
    }
    else
    {
        const SdrObject* pObj = GetDragObj();

        if(pObj)
        {
            aStr = pObj->getSpecialDragComment(DragStat());
        }
    }
    return aStr;
}

bool SdrDragObjOwn::BeginSdrDrag()
{
    if(!mxClone)
    {
        const SdrObject* pObj = GetDragObj();

        if(pObj && !pObj->IsResizeProtect())
        {
            if(pObj->beginSpecialDrag(DragStat()))
            {
                // create initial clone to have a start visualization
                mxClone = pObj->getFullDragClone();
                mxClone->applySpecialDrag(DragStat());

                return true;
            }
        }
    }

    return false;
}

void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
{
    const SdrObject* pObj = GetDragObj();

    if (!pObj)
        // No object to drag.  Bail out.
        return;

    Point aPnt(rNoSnapPnt);
    SdrPageView* pPV = GetDragPV();

    if (!pPV)
        // No page view available.  Bail out.
        return;

    if(!DragStat().IsNoSnap())
    {
        SnapPos(aPnt);
    }
    if(getSdrDragView().IsOrtho())
    {
        if (DragStat().IsOrtho8Possible())
        {
            OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
        }
        else if (DragStat().IsOrtho4Possible())
        {
            OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
        }
    }

    if (!DragStat().CheckMinMoved(rNoSnapPnt))
        // Not moved by the minimum threshold. Nothing to do.
        return;

    Hide();
    DragStat().NextMove(aPnt);

    // since SdrDragObjOwn currently supports no transformation of
    // existing SdrDragEntries but only their recreation, a recreation
    // after every move is needed in this mode. Delete existing
    // SdrDragEntries here  to force their recreation in the following Show().
    clearSdrDragEntries();

    // delete current clone (after the last reference to it is deleted above)
    mxClone.clear();

    // create a new clone and modify to current drag state
    mxClone = pObj->getFullDragClone();
    mxClone->applySpecialDrag(DragStat());

    // AutoGrowWidth may change for SdrTextObj due to the automatism used
    // with bDisableAutoWidthOnDragging, so not only geometry changes but
    // also this (pretty indirect) property change is possible. If it gets
    // changed, it needs to be copied to the original since nothing will
    // happen when it only changes in the drag clone
    const bool bOldAutoGrowWidth(pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
    const bool bNewAutoGrowWidth(mxClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());

    if (bOldAutoGrowWidth != bNewAutoGrowWidth)
    {
        GetDragObj()->SetMergedItem(makeSdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
    }

    Show();
}

bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
{
    Hide();
    std::vector< std::unique_ptr<SdrUndoAction> > vConnectorUndoActions;
    bool bRet = false;
    SdrObject* pObj = GetDragObj();

    if(pObj)
    {
        std::unique_ptr<SdrUndoAction> pUndo;
        std::unique_ptr<SdrUndoAction> pUndo2;
        const bool bUndo = getSdrDragView().IsUndoEnabled();

        if( bUndo )
        {
            getSdrDragView().EndTextEditCurrentView();
            if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() )
            {
                if (DragStat().IsEndDragChangesAttributes())
                {
                    pUndo=getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj);

                    if (DragStat().IsEndDragChangesGeoAndAttributes())
                    {
                        vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
                        pUndo2 = getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
                    }
                }
                else
                {
                    vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
                    pUndo= getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
                }
            }

            if( pUndo )
            {
                getSdrDragView().BegUndo( pUndo->GetComment() );
            }
            else
            {
                getSdrDragView().BegUndo();
            }
        }

        // Maybe use operator = for setting changed object data (do not change selection in
        // view, this will destroy the interactor). This is possible since a clone is now
        // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
        // in its SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
        // a CreateUndoGeoObject(), so maybe setting SetEndDragChangesAttributes is okay. I
        // will test this now
        tools::Rectangle aBoundRect0;

        if(pObj->GetUserCall())
        {
            aBoundRect0 = pObj->GetLastBoundRect();
        }

        bRet = pObj->applySpecialDrag(DragStat());
        if (DragStat().IsEndDragChangesLayout())
        {
            auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo.get());
            if (pGeoUndo)
                pGeoUndo->SetSkipChangeLayout(true);
        }

        if(bRet)
        {
            pObj->SetChanged();
            pObj->BroadcastObjectChange();
            pObj->SendUserCall( SdrUserCallType::Resize, aBoundRect0 );
        }

        if(bRet && bUndo )
        {
            getSdrDragView().AddUndoActions( std::move(vConnectorUndoActions) );

            if ( pUndo )
            {
                getSdrDragView().AddUndo(std::move(pUndo));
            }

            if ( pUndo2 )
            {
                getSdrDragView().AddUndo(std::move(pUndo2));
            }
        }

        if( bUndo )
            getSdrDragView().EndUndo();
    }

    return bRet;
}

PointerStyle SdrDragObjOwn::GetSdrDragPointer() const
{
    const SdrHdl* pHdl=GetDragHdl();

    if (pHdl)
    {
        return pHdl->GetPointer();
    }

    return PointerStyle::Move;
}


void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
{
    // use the view-independent primitive representation (without
    // evtl. GridOffset, that may be applied to the DragEntry individually)
    drawinglayer::primitive2d::Primitive2DContainer xRetval;
    rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
    addSdrDragEntry(
        std::unique_ptr<SdrDragEntry>(
            new SdrDragEntryPrimitive2DSequence(
                std::move(xRetval))));

}

void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
}

SdrDragMove::SdrDragMove(SdrDragView& rNewView)
    : SdrDragMethod(rNewView)
    , m_nBestXSnap(0)
    , m_nBestYSnap(0)
    , m_bXSnapped(false)
    , m_bYSnapped(false)
{
    setMoveOnly(true);
}

OUString SdrDragMove::GetSdrDragComment() const
{
    OUString aStr = ImpGetDescriptionStr(STR_DragMethMove)
            + " (x="
            + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
            + " y="
            + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
            + ")";

    if(getSdrDragView().IsDragWithCopy())
    {
        if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint())
        {
            aStr += SvxResId(STR_EditWithCopy);
        }
    }
    return aStr;
}

bool SdrDragMove::BeginSdrDrag()
{
    DragStat().SetActionRect(GetMarkedRect());
    Show();

    return true;
}

basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation() const
{
    return basegfx::utils::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
}

void SdrDragMove::ImpCheckSnap(const Point& rPt)
{
    Point aPt(rPt);
    SdrSnap nRet=SnapPos(aPt);
    aPt-=rPt;

    if (nRet & SdrSnap::XSNAPPED)
    {
        if (m_bXSnapped)
        {
            if (std::abs(aPt.X())<std::abs(m_nBestXSnap))
            {
                m_nBestXSnap=aPt.X();
            }
        }
        else
        {
            m_nBestXSnap=aPt.X();
            m_bXSnapped=true;
        }
    }

    if (!(nRet & SdrSnap::YSNAPPED))
        return;

    if (m_bYSnapped)
    {
        if (std::abs(aPt.Y())<std::abs(m_nBestYSnap))
        {
            m_nBestYSnap=aPt.Y();
        }
    }
    else
    {
        m_nBestYSnap=aPt.Y();
        m_bYSnapped=true;
    }
}

void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
{
    m_nBestXSnap=0;
    m_nBestYSnap=0;
    m_bXSnapped=false;
    m_bYSnapped=false;
    Point aNoSnapPnt(rNoSnapPnt_);
    const tools::Rectangle& aSR=GetMarkedRect();
    tools::Long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
    tools::Long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
    Point aLO(aSR.TopLeft());      aLO.AdjustX(nMovedx ); aLO.AdjustY(nMovedy );
    Point aRU(aSR.BottomRight());  aRU.AdjustX(nMovedx ); aRU.AdjustY(nMovedy );
    Point aLU(aLO.X(),aRU.Y());
    Point aRO(aRU.X(),aLO.Y());
    ImpCheckSnap(aLO);

    if (!getSdrDragView().IsMoveSnapOnlyTopLeft())
    {
        ImpCheckSnap(aRO);
        ImpCheckSnap(aLU);
        ImpCheckSnap(aRU);
    }

    Point aPnt(aNoSnapPnt.X()+m_nBestXSnap,aNoSnapPnt.Y()+m_nBestYSnap);
    bool bOrtho=getSdrDragView().IsOrtho();

    if (bOrtho)
        OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());

    if (!DragStat().CheckMinMoved(aNoSnapPnt))
        return;

    Point aPt1(aPnt);
    tools::Rectangle aLR(getSdrDragView().GetWorkArea());
    bool bWorkArea=!aLR.IsEmpty();
    bool bDragLimit=IsDragLimit();

    if (bDragLimit || bWorkArea)
    {
        tools::Rectangle aSR2(GetMarkedRect());
        Point aD(aPt1-DragStat().GetStart());

        if (bDragLimit)
        {
            tools::Rectangle aR2(GetDragLimitRect());

            if (bWorkArea)
                aLR.Intersection(aR2);
            else
                aLR=aR2;
        }

        if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right())
        { // any space to move to?
            aSR2.Move(aD.X(),0);

            if (aSR2.Left()<aLR.Left())
            {
                aPt1.AdjustX( -(aSR2.Left()-aLR.Left()) );
            }
            else if (aSR2.Right()>aLR.Right())
            {
                aPt1.AdjustX( -(aSR2.Right()-aLR.Right()) );
            }
        }
        else
            aPt1.setX(DragStat().GetStart().X() ); // no space to move to

        if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom())
        { // any space to move to?
            aSR2.Move(0,aD.Y());

            if (aSR2.Top()<aLR.Top())
            {
                aPt1.AdjustY( -(aSR2.Top()-aLR.Top()) );
            }
            else if (aSR2.Bottom()>aLR.Bottom())
            {
                aPt1.AdjustY( -(aSR2.Bottom()-aLR.Bottom()) );
            }
        }
        else
            aPt1.setY(DragStat().GetStart().Y() ); // no space to move to
    }

    if (getSdrDragView().IsDraggingGluePoints())
    { // restrict gluepoints to the BoundRect of the Obj
        aPt1-=DragStat().GetStart();
        const SdrMarkList& rMarkList = GetMarkedObjectList();
        const size_t nMarkCount = rMarkList.GetMarkCount();

        for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
        {
            const SdrMark* pM = rMarkList.GetMark(nMarkNum);
            const SdrUShortCont& rPts = pM->GetMarkedGluePoints();

            if (!rPts.empty())
            {
                const SdrObject* pObj=pM->GetMarkedSdrObj();
                const SdrGluePointList* pGPL=pObj->GetGluePointList();
                tools::Rectangle aBound(pObj->GetCurrentBoundRect());

                for (sal_uInt16 nId : rPts)
                {
                    sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);

                    if (nGlueNum!=SDRGLUEPOINT_NOTFOUND)
                    {
                        Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
                        aPt+=aPt1; // move by this much
                        if (aPt.X()<aBound.Left()  ) aPt1.AdjustX( -(aPt.X()-aBound.Left()) )  ;
                        if (aPt.X()>aBound.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ;
                        if (aPt.Y()<aBound.Top()   ) aPt1.AdjustY( -(aPt.Y()-aBound.Top()) )   ;
                        if (aPt.Y()>aBound.Bottom()) aPt1.AdjustY( -(aPt.Y()-aBound.Bottom()) );
                    }
                }
            }
        }

        aPt1+=DragStat().GetStart();
    }

    if (bOrtho)
        OrthoDistance8(DragStat().GetStart(),aPt1,false);

    if (aPt1!=DragStat().GetNow())
    {
        Hide();
        DragStat().NextMove(aPt1);
        tools::Rectangle aAction(GetMarkedRect());
        aAction.Move(DragStat().GetDX(),DragStat().GetDY());
        DragStat().SetActionRect(aAction);
        Show();
    }
}

bool SdrDragMove::EndSdrDrag(bool bCopy)
{
    Hide();

    if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint())
        bCopy=false;

    if (IsDraggingPoints())
    {
        getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()));
    }
    else if (IsDraggingGluePoints())
    {
        getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
    }
    else
    {
        getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
    }

    return true;
}

PointerStyle SdrDragMove::GetSdrDragPointer() const
{
    if (IsDraggingPoints() || IsDraggingGluePoints())
    {
        return PointerStyle::MovePoint;
    }
    else
    {
        return PointerStyle::Move;
    }
}


SdrDragResize::SdrDragResize(SdrDragView& rNewView)
:   SdrDragMethod(rNewView),
    m_aXFact(1,1),
    m_aYFact(1,1)
{
}

OUString SdrDragResize::GetSdrDragComment() const
{
    OUString aStr = ImpGetDescriptionStr(STR_DragMethResize);
    Fraction aFact1(1,1);
    Point aStart(DragStat().GetStart());
    Point aRef(DragStat().GetRef1());
    sal_Int32 nXDiv(aStart.X() - aRef.X());

    if(!nXDiv)
        nXDiv = 1;

    sal_Int32 nYDiv(aStart.Y() - aRef.Y());

    if(!nYDiv)
        nYDiv = 1;

    bool bX(m_aXFact != aFact1 && std::abs(nXDiv) > 1);
    bool bY(m_aYFact != aFact1 && std::abs(nYDiv) > 1);

    if(bX || bY)
    {
        aStr += " (";

        bool bEqual(m_aXFact == m_aYFact);
        if(bX)
        {
            if(!bEqual)
                aStr += "x=";

            aStr += SdrModel::GetPercentString(m_aXFact);
        }

        if(bY && !bEqual)
        {
            if(bX)
                aStr += " ";

            aStr += "y=" + SdrModel::GetPercentString(m_aYFact);
        }

        aStr += ")";
    }

    if(getSdrDragView().IsDragWithCopy())
        aStr += SvxResId(STR_EditWithCopy);
    return aStr;
}

bool SdrDragResize::BeginSdrDrag()
{
    SdrHdlKind eRefHdl=SdrHdlKind::Move;
    SdrHdl* pRefHdl=nullptr;

    switch (GetDragHdlKind())
    {
        case SdrHdlKind::UpperLeft: eRefHdl=SdrHdlKind::LowerRight; break;
        case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; DragStat().SetHorFixed(true); break;
        case SdrHdlKind::UpperRight: eRefHdl=SdrHdlKind::LowerLeft; break;
        case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; DragStat().SetVerFixed(true); break;
        case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; DragStat().SetVerFixed(true); break;
        case SdrHdlKind::LowerLeft: eRefHdl=SdrHdlKind::UpperRight; break;
        case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; DragStat().SetHorFixed(true); break;
        case SdrHdlKind::LowerRight: eRefHdl=SdrHdlKind::UpperLeft; break;
        defaultbreak;
    }

    if (eRefHdl!=SdrHdlKind::Move)
        pRefHdl=GetHdlList().GetHdl(eRefHdl);

    if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
    {
        DragStat().SetRef1(pRefHdl->GetPos());
    }
    else
    {
        SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft);
        SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight);

        if (pRef1!=nullptr && pRef2!=nullptr)
        {
            DragStat().SetRef1(tools::Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center());
        }
        else
        {
            DragStat().SetRef1(GetMarkedRect().Center());
        }
    }

    Show();

    return true;
}

basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation() const
{
    basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
        -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
    aRetval.scale(double(m_aXFact), double(m_aYFact));
    aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());

    return aRetval;
}

void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
{
    Point aPnt(GetSnapPos(rNoSnapPnt));
    Point aStart(DragStat().GetStart());
    Point aRef(DragStat().GetRef1());
    Fraction aMaxFact(0x7FFFFFFF,1);
    tools::Rectangle aLR(getSdrDragView().GetWorkArea());
    bool bWorkArea=!aLR.IsEmpty();
    bool bDragLimit=IsDragLimit();

    if (bDragLimit || bWorkArea)
    {
        tools::Rectangle aSR(GetMarkedRect());

        if (bDragLimit)
        {
            tools::Rectangle aR2(GetDragLimitRect());

            if (bWorkArea)
                aLR.Intersection(aR2);
            else
                aLR=aR2;
        }

        if (aPnt.X()<aLR.Left())
            aPnt.setX(aLR.Left() );
        else if (aPnt.X()>aLR.Right())
            aPnt.setX(aLR.Right() );

        if (aPnt.Y()<aLR.Top())
            aPnt.setY(aLR.Top() );
        else if (aPnt.Y()>aLR.Bottom())
            aPnt.setY(aLR.Bottom() );

        if (aRef.X()>aSR.Left())
        {
            Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());

            if (aMax<aMaxFact)
                aMaxFact=aMax;
        }

        if (aRef.X()<aSR.Right())
        {
            Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());

            if (aMax<aMaxFact)
                aMaxFact=aMax;
        }

        if (aRef.Y()>aSR.Top())
        {
            Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());

            if (aMax<aMaxFact)
                aMaxFact=aMax;
        }

        if (aRef.Y()<aSR.Bottom())
        {
            Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());

            if (aMax<aMaxFact)
                aMaxFact=aMax;
        }
    }

    tools::Long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
    tools::Long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
    tools::Long nXMul=aPnt.X()-aRef.X();
    tools::Long nYMul=aPnt.Y()-aRef.Y();

    if (nXDiv<0)
    {
        nXDiv=-nXDiv;
        nXMul=-nXMul;
    }

    if (nYDiv<0)
    {
        nYDiv=-nYDiv;
        nYMul=-nYMul;
    }

    bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
    bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
    bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();

    if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
    {
        if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
            bOrtho=false;

        if (bOrtho)
        {
            if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
            {
                nXMul=nYMul;
                nXDiv=nYDiv;
            }
            else
            {
                nYMul=nXMul;
                nYDiv=nXDiv;
            }
        }
    }
    else
    {
        if (bOrtho)
        {
            if (DragStat().IsHorFixed())
            {
                bXNeg=false;
                nXMul=nYMul;
                nXDiv=nYDiv;
            }

            if (DragStat().IsVerFixed())
            {
                bYNeg=false;
                nYMul=nXMul;
                nYDiv=nXDiv;
            }
        }
        else
        {
            if (DragStat().IsHorFixed())
            {
                bXNeg=false;
                nXMul=1;
                nXDiv=1;
            }

            if (DragStat().IsVerFixed())
            {
                bYNeg=false;
                nYMul=1;
                nYDiv=1;
            }
        }
    }

    Fraction aNewXFact(nXMul,nXDiv);
    Fraction aNewYFact(nYMul,nYDiv);

    if (bOrtho)
    {
        if (aNewXFact>aMaxFact)
        {
            aNewXFact=aMaxFact;
            aNewYFact=aMaxFact;
        }

        if (aNewYFact>aMaxFact)
        {
            aNewXFact=aMaxFact;
            aNewYFact=aMaxFact;
        }
    }

    if (bXNeg)
        aNewXFact=Fraction(-aNewXFact.GetNumerator(),aNewXFact.GetDenominator());

    if (bYNeg)
        aNewYFact=Fraction(-aNewYFact.GetNumerator(),aNewYFact.GetDenominator());

    if (DragStat().CheckMinMoved(aPnt))
    {
        if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
            (!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y()))
        {
            Hide();
            DragStat().NextMove(aPnt);
            m_aXFact=aNewXFact;
            m_aYFact=aNewYFact;

            aNewXFact = double(aNewXFact) > 0 ? aNewXFact : Fraction(1, 1);
            aNewYFact = double(aNewYFact) > 0 ? aNewYFact : Fraction(1, 1);
            Size aTargetSize(
                    GetMarkedRect().GetSize().scale(aNewXFact.GetNumerator(), aNewXFact.GetDenominator(),
                                                    aNewYFact.GetNumerator(), aNewYFact.GetDenominator()));
            Show(getSdrDragView().IsMarkedObjSizeValid(aTargetSize));
        }
    }
}

void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    rTarget.Resize(DragStat().GetRef1(),m_aXFact,m_aYFact);
}

bool SdrDragResize::EndSdrDrag(bool bCopy)
{
    Hide();

    if (IsDraggingPoints())
    {
        getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),m_aXFact,m_aYFact);
    }
    else if (IsDraggingGluePoints())
    {
        getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),m_aXFact,m_aYFact,bCopy);
    }
    else
    {
        getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),m_aXFact,m_aYFact,bCopy);
    }

    return true;
}

PointerStyle SdrDragResize::GetSdrDragPointer() const
{
    const SdrHdl* pHdl=GetDragHdl();

    if (pHdl!=nullptr)
    {
        return pHdl->GetPointer();
    }

    return PointerStyle::Move;
}


void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
{
    rTarget.Rotate(DragStat().GetRef1(), nAngle, nSin, nCos);
}

SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
:   SdrDragMethod(rNewView),
    nSin(0.0),
    nCos(1.0),
    nAngle0(0),
    nAngle(0),
    bRight(false)
{
}

OUString SdrDragRotate::GetSdrDragComment() const
{
    OUString aStr = ImpGetDescriptionStr(STR_DragMethRotate) +
        " (";
    Degree100 nTmpAngle(NormAngle36000(nAngle));

    if(bRight && nAngle)
    {
        nTmpAngle -= 36000_deg100;
    }

    aStr += SdrModel::GetAngleString(nTmpAngle) + ")";

    if(getSdrDragView().IsDragWithCopy())
        aStr += SvxResId(STR_EditWithCopy);
    return aStr;
}

bool SdrDragRotate::BeginSdrDrag()
{
    SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1);

    if (nullptr != pH)
    {
        Show();
        DragStat().SetRef1(pH->GetPos());
        nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
        return true;
    }

    // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
    // the rotation point)
    const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());

    if(!aLocalMarkRect.IsEmpty())
    {
        Show();
        DragStat().SetRef1(aLocalMarkRect.Center());
        nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
        return true;
    }

    OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
    return false;
}

basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation() const
{
    return basegfx::utils::createRotateAroundPoint(
        DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
        -atan2(nSin, nCos));
}

void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
{
    Point aPnt(rPnt_);
    if (!DragStat().CheckMinMoved(aPnt))
        return;

    Degree100 nNewAngle=NormAngle36000(GetAngle(aPnt-DragStat().GetRef1())-nAngle0);
    Degree100 nSA(0);

    if (getSdrDragView().IsAngleSnapEnabled())
        nSA=getSdrDragView().GetSnapAngle();

    if (!getSdrDragView().IsRotateAllowed())
        nSA=9000_deg100;

    if (nSA)
    { // angle snapping
        nNewAngle += nSA / 2_deg100;
        nNewAngle /= nSA;
        nNewAngle *= nSA;
    }

    nNewAngle=NormAngle18000(nNewAngle);

    if (nAngle==nNewAngle)
        return;

    sal_uInt16 nSekt0=GetAngleSector(nAngle);
    sal_uInt16 nSekt1=GetAngleSector(nNewAngle);

    if (nSekt0==0 && nSekt1==3)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=96 G=94

¤ Dauer der Verarbeitung: 0.26 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.