/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/))); } void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod( std::unique_ptr 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(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(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_cast< const 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(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(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 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 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 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(this) != nullptr || dynamic_cast(this) != nullptr || dynamic_cast(this) != nullptr || dynamic_cast(this) != nullptr )) { return false; } // one more migrated from SdrEdgeObj::NspToggleEdgeXor if( dynamic_cast< const SdrDragObjOwn* >(this) != nullptr || dynamic_cast< const 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; default: break; } } 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(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(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 > vConnectorUndoActions; bool bRet = false; SdrObject* pObj = GetDragObj(); if(pObj) { std::unique_ptr pUndo; std::unique_ptr 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(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( new SdrDragEntryPrimitive2DSequence( std::move(xRetval)))); } void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY())); } SdrDragMove::SdrDragMove(SdrDragView& rNewView) : SdrDragMethod(rNewView) , nBestXSnap(0) , nBestYSnap(0) , bXSnapped(false) , 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 (bXSnapped) { if (std::abs(aPt.X())aLR.Left() || 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()) { 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; nMarkNumGetMarkedGluePoints(); 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.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ; 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), aXFact(1,1), 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(aXFact != aFact1 && std::abs(nXDiv) > 1); bool bY(aYFact != aFact1 && std::abs(nYDiv) > 1); if(bX || bY) { aStr += " ("; bool bEqual(aXFact == aYFact); if(bX) { if(!bEqual) aStr += "x="; aStr += SdrModel::GetPercentString(aXFact); } if(bY && !bEqual) { if(bX) aStr += " "; aStr += "y=" + SdrModel::GetPercentString(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; default: break; } 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(aXFact), double(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.Right()) aPnt.setX(aLR.Right() ); 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 (aMaxaSR.Top()) { Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top()); if (aMaxFraction(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); aXFact=aNewXFact; 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(),aXFact,aYFact); } bool SdrDragResize::EndSdrDrag(bool bCopy) { Hide(); if (IsDraggingPoints()) { getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),aXFact,aYFact); } else if (IsDraggingGluePoints()) { getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),aXFact,aYFact,bCopy); } else { getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aXFact,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) bRight=true; if (nSekt0==3 && nSekt1==0) bRight=false; nAngle=nNewAngle; double a = toRadians(nAngle); double nSin1=sin(a); // calculate now, so as little time as possible double nCos1=cos(a); // passes between Hide() and Show() Hide(); nSin=nSin1; nCos=nCos1; DragStat().NextMove(aPnt); Show(); } bool SdrDragRotate::EndSdrDrag(bool bCopy) { Hide(); if (nAngle!=0_deg100) { if (IsDraggingPoints()) { getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nAngle); } else if (IsDraggingGluePoints()) { getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nAngle,bCopy); } else { getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nAngle,bCopy); } } return true; } PointerStyle SdrDragRotate::GetSdrDragPointer() const { return PointerStyle::Rotate; } SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1) : SdrDragMethod(rNewView), aFact(1,1), nAngle0(0), nAngle(0), nTan(0.0), bVertical(false), bResize(false), bUpSideDown(false), bSlant(bSlant1) { } OUString SdrDragShear::GetSdrDragComment() const { OUString aStr = ImpGetDescriptionStr(STR_DragMethShear) + " ("; Degree100 nTmpAngle(nAngle); if(bUpSideDown) nTmpAngle += 18000_deg100; nTmpAngle = NormAngle18000(nTmpAngle); aStr += SdrModel::GetAngleString(nTmpAngle) + ")"; if(getSdrDragView().IsDragWithCopy()) aStr += SvxResId(STR_EditWithCopy); return aStr; } bool SdrDragShear::BeginSdrDrag() { SdrHdlKind eRefHdl=SdrHdlKind::Move; SdrHdl* pRefHdl=nullptr; switch (GetDragHdlKind()) { case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; break; case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; break; case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; bVertical=true; break; case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; bVertical=true; break; default: break; } if (eRefHdl!=SdrHdlKind::Move) pRefHdl=GetHdlList().GetHdl(eRefHdl); if (pRefHdl!=nullptr) { DragStat().SetRef1(pRefHdl->GetPos()); nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1()); } else { OSL_FAIL("SdrDragShear::BeginSdrDrag(): No reference point handle for shearing found."); return false; } Show(); return true; } basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation() const { basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix( -DragStat().GetRef1().X(), -DragStat().GetRef1().Y())); if (bResize) { if (bVertical) { aRetval.scale(double(aFact), 1.0); aRetval.shearY(-nTan); } else { aRetval.scale(1.0, double(aFact)); aRetval.shearX(-nTan); } } aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y()); return aRetval; } void SdrDragShear::MoveSdrDrag(const Point& rPnt) { if (!DragStat().CheckMinMoved(rPnt)) return; bResize=!getSdrDragView().IsOrtho(); Degree100 nSA(0); if (getSdrDragView().IsAngleSnapEnabled()) nSA=getSdrDragView().GetSnapAngle(); Point aP0(DragStat().GetStart()); Point aPnt(rPnt); Fraction aNewFract(1,1); // if angle snapping not activated, snap to raster (except when using slant) if (nSA==0_deg100 && !bSlant) aPnt=GetSnapPos(aPnt); if (!bSlant && !bResize) { // shear, but no resize if (bVertical) aPnt.setX(aP0.X() ); else aPnt.setY(aP0.Y() ); } Point aRef(DragStat().GetRef1()); Point aDif(aPnt-aRef); Degree100 nNewAngle(0); if (bSlant) { nNewAngle=NormAngle18000(-(GetAngle(aDif)-nAngle0)); if (bVertical) nNewAngle=NormAngle18000(-nNewAngle); } else { if (bVertical) nNewAngle=NormAngle18000(GetAngle(aDif)); else nNewAngle=NormAngle18000(-(GetAngle(aDif)-9000_deg100)); if (nNewAngle9000_deg100) nNewAngle=NormAngle18000(nNewAngle+18000_deg100); if (bResize) { Point aPt2(aPnt); if (nSA!=0_deg100) aPt2=GetSnapPos(aPnt); // snap this one in any case if (bVertical) { aNewFract=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X()); } else { aNewFract=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y()); } } } bool bNeg=nNewAngle<0_deg100; if (bNeg) nNewAngle=-nNewAngle; if (nSA) { // angle snapping nNewAngle += nSA / 2_deg100; nNewAngle /= nSA; nNewAngle *= nSA; } nNewAngle=NormAngle36000(nNewAngle); bUpSideDown=nNewAngle>9000_deg100 && nNewAngle<27000_deg100; if (bSlant) { // calculate resize for slant // when angle snapping is activated, disable 89 degree limit Degree100 nTmpAngle=nNewAngle; if (bUpSideDown) nNewAngle -= 18000_deg100; if (bNeg) nTmpAngle=-nTmpAngle; bResize=true; aNewFract = cos(toRadians(nTmpAngle)); aFact.ReduceInaccurate(10); // three decimals should be enough } if (nNewAngle > 8900_deg100) nNewAngle = 8900_deg100; if (bNeg) nNewAngle=-nNewAngle; if (nAngle!=nNewAngle || aFact!=aNewFract) { nAngle=nNewAngle; aFact=aNewFract; double a = toRadians(nAngle); double nTan1=tan(a); // calculate now, so as little time as possible passes between Hide() and Show() Hide(); nTan=nTan1; DragStat().NextMove(rPnt); Show(); } } void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { if (bResize) { if (bVertical) { rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1)); } else { rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact); } } if (nAngle) { rTarget.Shear(DragStat().GetRef1(), nAngle, nTan, bVertical); } } bool SdrDragShear::EndSdrDrag(bool bCopy) { Hide(); if (bResize && aFact==Fraction(1,1)) bResize=false; if (nAngle || bResize) { if (nAngle && bResize) { OUString aStr = ImpGetDescriptionStr(STR_EditShear); if (bCopy) aStr += SvxResId(STR_EditWithCopy); getSdrDragView().BegUndo(aStr); } if (bResize) { if (bVertical) { getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy); } else { getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy); } bCopy=false; } if (nAngle) { getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nAngle,bVertical,bCopy); } if (nAngle && bResize) getSdrDragView().EndUndo(); return true; } return false; } PointerStyle SdrDragShear::GetSdrDragPointer() const { if (bVertical) return PointerStyle::VShear; else return PointerStyle::HShear; } void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { if(bMirrored) { rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2()); } } SdrDragMirror::SdrDragMirror(SdrDragView& rNewView) : SdrDragMethod(rNewView), nAngle(0), bMirrored(false), bSide0(false) { } bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const { Degree100 nAngle1=GetAngle(rPnt-DragStat().GetRef1()); nAngle1-=nAngle; nAngle1=NormAngle36000(nAngle1); return nAngle1<18000_deg100; } OUString SdrDragMirror::GetSdrDragComment() const { OUString aStr; if (aDif.X()==0) aStr = ImpGetDescriptionStr(STR_DragMethMirrorHori); else if (aDif.Y()==0) aStr = ImpGetDescriptionStr(STR_DragMethMirrorVert); else if (std::abs(aDif.X()) == std::abs(aDif.Y())) aStr = ImpGetDescriptionStr(STR_DragMethMirrorDiag); else aStr = ImpGetDescriptionStr(STR_DragMethMirrorFree); if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy); return aStr; } bool SdrDragMirror::BeginSdrDrag() { SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1); SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2); if (pH1!=nullptr && pH2!=nullptr) { DragStat().SetRef1(pH1->GetPos()); DragStat().SetRef2(pH2->GetPos()); Ref1()=pH1->GetPos(); Ref2()=pH2->GetPos(); aDif=pH2->GetPos()-pH1->GetPos(); bool b90=(aDif.X()==0) || aDif.Y()==0; bool b45=b90 || (std::abs(aDif.X()) == std::abs(aDif.Y())); nAngle=NormAngle36000(GetAngle(aDif)); if (!getSdrDragView().IsMirrorAllowed() && !b45) return false; // free choice of axis angle not allowed if (!getSdrDragView().IsMirrorAllowed() && !b90) return false; // 45 degrees not allowed either bSide0=ImpCheckSide(DragStat().GetStart()); Show(); return true; } else { OSL_FAIL("SdrDragMirror::BeginSdrDrag(): Axis of reflection not found."); return false; } } basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation() const { basegfx::B2DHomMatrix aRetval; if (bMirrored) { const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X()); const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y()); const double fRotation(atan2(fDeltaY, fDeltaX)); aRetval = basegfx::utils::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y()); aRetval.rotate(-fRotation); aRetval.scale(1.0, -1.0); aRetval.rotate(fRotation); aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y()); } return aRetval; } void SdrDragMirror::MoveSdrDrag(const Point& rPnt) { if (!DragStat().CheckMinMoved(rPnt)) return; bool bNewSide=ImpCheckSide(rPnt); bool bNewMirrored=bSide0!=bNewSide; if (bMirrored!=bNewMirrored) { Hide(); bMirrored=bNewMirrored; DragStat().NextMove(rPnt); Show(); } } bool SdrDragMirror::EndSdrDrag(bool bCopy) { Hide(); if (bMirrored) { getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy); } return true; } PointerStyle SdrDragMirror::GetSdrDragPointer() const { return PointerStyle::Mirror; } SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad) : SdrDragMethod(rNewView), pIAOHandle(nullptr), bIsGradient(bGrad) { } OUString SdrDragGradient::GetSdrDragComment() const { if(IsGradient()) return ImpGetDescriptionStr(STR_DragMethGradient); else return ImpGetDescriptionStr(STR_DragMethTransparence); } bool SdrDragGradient::BeginSdrDrag() { bool bRetval(false); pIAOHandle = static_cast(GetHdlList().GetHdl(IsGradient() ? SdrHdlKind::Gradient : SdrHdlKind::Transparence)); if(pIAOHandle) { // save old values DragStat().SetRef1( pIAOHandle->GetPos() ); DragStat().SetRef2( pIAOHandle->Get2ndPos() ); // what was hit? bool bHit(false); SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1(); // init handling flags pIAOHandle->SetMoveSingleHandle(false); pIAOHandle->SetMoveFirstHandle(false); // test first color handle if(pColHdl) { basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y()); if(pColHdl->getOverlayObjectList().isHitLogic(aPosition)) { bHit = true; pIAOHandle->SetMoveSingleHandle(true); pIAOHandle->SetMoveFirstHandle(true); } } // test second color handle pColHdl = pIAOHandle->GetColorHdl2(); if(!bHit && pColHdl) { basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y()); if(pColHdl->getOverlayObjectList().isHitLogic(aPosition)) { bHit = true; pIAOHandle->SetMoveSingleHandle(true); } } // test gradient handle itself if(!bHit) { basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y()); if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition)) { bHit = true; } } // everything up and running :o} bRetval = bHit; } else { OSL_FAIL("SdrDragGradient::BeginSdrDrag(): IAOGradient not found."); } return bRetval; } void SdrDragGradient::MoveSdrDrag(const Point& rPnt) { if(!(pIAOHandle && DragStat().CheckMinMoved(rPnt))) return; DragStat().NextMove(rPnt); // Do the Move here!!! DragStat().GetStart() Point aMoveDiff = rPnt - DragStat().GetStart(); if(pIAOHandle->IsMoveSingleHandle()) { if(pIAOHandle->IsMoveFirstHandle()) { pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff); if(pIAOHandle->GetColorHdl1()) pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff); } else { pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff); if(pIAOHandle->GetColorHdl2()) pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff); } } else { pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff); pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff); if(pIAOHandle->GetColorHdl1()) pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff); if(pIAOHandle->GetColorHdl2()) pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff); } // new state const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), false, false); } bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/) { Ref1() = pIAOHandle->GetPos(); Ref2() = pIAOHandle->Get2ndPos(); // new state const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), true, true); return true; } void SdrDragGradient::CancelSdrDrag() { // restore old values pIAOHandle->SetPos(DragStat().GetRef1()); pIAOHandle->Set2ndPos(DragStat().GetRef2()); if(pIAOHandle->GetColorHdl1()) pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1()); if(pIAOHandle->GetColorHdl2()) pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2()); // new state const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), true, false); } PointerStyle SdrDragGradient::GetSdrDragPointer() const { return PointerStyle::RefHand; } SdrDragCrook::SdrDragCrook(SdrDragView& rNewView) : SdrDragMethod(rNewView), aFact(1,1), bContortionAllowed(false), bNoContortionAllowed(false), bContortion(false), bResizeAllowed(false), bResize(false), bRotateAllowed(false), bRotate(false), bVertical(false), bValid(false), bLft(false), bRgt(false), bUpr(false), bLwr(false), bAtCenter(false), nAngle(0), nMarkSize(0), eMode(SdrCrookMode::Rotate) { } OUString SdrDragCrook::GetSdrDragComment() const { OUString aStr = ImpGetDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion); if(bValid) { aStr += " ("; sal_Int32 nVal(nAngle); if(bAtCenter) nVal *= 2; nVal = std::abs(nVal); aStr += SdrModel::GetAngleString(Degree100(nVal)) + ")"; } if(getSdrDragView().IsDragWithCopy()) aStr += SvxResId(STR_EditWithCopy); return aStr; } // These defines parametrize the created raster // for interactions #define DRAG_CROOK_RASTER_MINIMUM (4) #define DRAG_CROOK_RASTER_MAXIMUM (15) #define DRAG_CROOK_RASTER_DISTANCE (30) static basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView const & rPageView, const tools::Rectangle& rMarkRect) { basegfx::B2DPolyPolygon aRetval; if(rPageView.PageWindowCount()) { OutputDevice& rOut = rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice(); tools::Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect); sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE); sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE); if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM) nHorDiv = DRAG_CROOK_RASTER_MAXIMUM; if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM) nHorDiv = DRAG_CROOK_RASTER_MINIMUM; if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM) nVerDiv = DRAG_CROOK_RASTER_MAXIMUM; if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM) nVerDiv = DRAG_CROOK_RASTER_MINIMUM; const double fXLen(rMarkRect.GetWidth() / static_cast(nHorDiv)); const double fYLen(rMarkRect.GetHeight() / static_cast(nVerDiv)); double fYPos(rMarkRect.Top()); sal_uInt32 a, b; for(a = 0; a <= nVerDiv; a++) { // horizontal lines for(b = 0; b < nHorDiv; b++) { basegfx::B2DPolygon aHorLineSegment; const double fNewX(rMarkRect.Left() + (b * fXLen)); aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos)); aHorLineSegment.appendBezierSegment( basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos), basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos), basegfx::B2DPoint(fNewX + fXLen, fYPos)); aRetval.append(aHorLineSegment); } // increments fYPos += fYLen; } double fXPos(rMarkRect.Left()); for(a = 0; a <= nHorDiv; a++) { // vertical lines for(b = 0; b < nVerDiv; b++) { basegfx::B2DPolygon aVerLineSegment; const double fNewY(rMarkRect.Top() + (b * fYLen)); aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY)); aVerLineSegment.appendBezierSegment( basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))), basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))), basegfx::B2DPoint(fXPos, fNewY + fYLen)); aRetval.append(aVerLineSegment); } // increments fXPos += fXLen; } } return aRetval; } void SdrDragCrook::createSdrDragEntries() { // Add extended frame raster first, so it will be behind objects if(getSdrDragView().GetSdrPageView()) { const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect())); if(aDragRaster.count()) { addSdrDragEntry(std::unique_ptr(new SdrDragEntryPolyPolygon(aDragRaster))); } } // call parent SdrDragMethod::createSdrDragEntries(); } bool SdrDragCrook::BeginSdrDrag() { bContortionAllowed=getSdrDragView().IsCrookAllowed(); bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true); bResizeAllowed=getSdrDragView().IsResizeAllowed(); bRotateAllowed=getSdrDragView().IsRotateAllowed(); if (bContortionAllowed || bNoContortionAllowed) { bVertical=(GetDragHdlKind()==SdrHdlKind::Lower || GetDragHdlKind()==SdrHdlKind::Upper); aMarkRect=GetMarkedRect(); aMarkCenter=aMarkRect.Center(); nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1); aCenter=aMarkCenter; aStart=DragStat().GetStart(); Show(); return true; } else { return false; } } void SdrDragCrook::MovAllPoints(basegfx::B2DPolyPolygon& rTarget) { SdrPageView* pPV = getSdrDragView().GetSdrPageView(); if(!pPV) return; XPolyPolygon aTempPolyPoly(rTarget); if (pPV->HasMarkedObjPageView()) { sal_uInt16 nPolyCount=aTempPolyPoly.Count(); if (!bContortion && !getSdrDragView().IsNoDragXorPolys()) { sal_uInt16 n1st=0,nLast=0; Point aC(aCenter); while (n1ststd::abs(dy1); else bValid = std::abs(dy1)*100>std::abs(dx1); } tools::Long nNewRad=0; nAngle=0_deg100; if (bValid) { double a=0; // slope of the radius Degree100 nPntAngle(0); if (bVertical) { a=static_cast(dy1)/static_cast(dx1); // slope of the radius nNewRad=(static_cast(dy1*a)+dx1) /2; aNewCenter.AdjustX(nNewRad ); nPntAngle=GetAngle(aPnt-aNewCenter); } else { a=static_cast(dx1)/static_cast(dy1); // slope of the radius nNewRad=(static_cast(dx1*a)+dy1) /2; aNewCenter.AdjustY(nNewRad ); nPntAngle=GetAngle(aPnt-aNewCenter)-9000_deg100; } if (!bAtCenter) { if (nNewRad<0) { if (bRgt) nPntAngle += 18000_deg100; if (bLft) nPntAngle = 18000_deg100 - nPntAngle; if (bLwr) nPntAngle =- nPntAngle; } else { if (bRgt) nPntAngle = -nPntAngle; if (bUpr) nPntAngle = 18000_deg100 - nPntAngle; if (bLwr) nPntAngle += 18000_deg100; } nPntAngle=NormAngle36000(nPntAngle); } else { if (nNewRad<0) nPntAngle += 18000_deg100; if (bVertical) nPntAngle = 18000_deg100 - nPntAngle; nPntAngle = NormAngle18000(nPntAngle); nPntAngle = abs(nPntAngle); } double nCircumference = 2 * std::abs(nNewRad) * M_PI; if (bResize) { tools::Long nMul=static_cast(nCircumference * NormAngle36000(nPntAngle).get() / 36000.0); if (bAtCenter) nMul*=2; aNewFract=Fraction(nMul,nMarkSize); nAngle=nPntAngle; } else { nAngle = Degree100(static_cast((nMarkSize*360/nCircumference)*100)/2); if (nAngle==0_deg100) bValid=false; } } if (nAngle==0_deg100 || nNewRad==0) bValid=false; if (!bValid) nNewRad=0; if (!bValid && bResize) { tools::Long nMul=bVertical ? dy1 : dx1; if (bLft || bUpr) nMul=-nMul; tools::Long nDiv=nMarkSize; if (bAtCenter) { nMul*=2; nMul = std::abs(nMul); } aNewFract=Fraction(nMul,nDiv); } if (aNewCenter==aCenter && bNewContortion==bContortion && aNewFract==aFact && bNewMoveOnly == getMoveOnly() && bNewRotate==bRotate && eNewMode==eMode) return; Hide(); setMoveOnly(bNewMoveOnly); bRotate=bNewRotate; eMode=eNewMode; bContortion=bNewContortion; aCenter=aNewCenter; aFact=aNewFract; aRad=Point(nNewRad,nNewRad); bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid(); DragStat().NextMove(aPnt); Show(); } void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { const bool bDoResize(aFact!=Fraction(1,1)); const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0); if (!(bDoCrook || bDoResize)) return; if (bDoResize) { Fraction aFact1(1,1); if (bContortion) { if (bVertical) { rTarget.Resize(aCenter,aFact1,aFact); } else { rTarget.Resize(aCenter,aFact,aFact1); } } else { Point aCtr0(rTarget.GetSnapRect().Center()); Point aCtr1(aCtr0); if (bVertical) { ResizePoint(aCtr1,aCenter,aFact1,aFact); } else { ResizePoint(aCtr1,aCenter,aFact,aFact1); } Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y()); rTarget.Move(aSiz); } } if (bDoCrook) { const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect()); const bool bLocalRotate(!bContortion && eMode == SdrCrookMode::Rotate && getSdrDragView().IsRotateAllowed()); SdrEditView::ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect); } } void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget) { // use helper derived from old stuff MovAllPoints(rTarget); } bool SdrDragCrook::EndSdrDrag(bool bCopy) { Hide(); if (bResize && aFact==Fraction(1,1)) bResize=false; const bool bUndo = getSdrDragView().IsUndoEnabled(); bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0; if (bDoCrook || bResize) { if (bResize && bUndo) { OUString aStr = ImpGetDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion); if (bCopy) aStr += SvxResId(STR_EditWithCopy); getSdrDragView().BegUndo(aStr); } if (bResize) { Fraction aFact1(1,1); if (bContortion) { if (bVertical) getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy); else getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy); } else { if (bCopy) getSdrDragView().CopyMarkedObj(); const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); const size_t nMarkCount=rMarkList.GetMarkCount(); for (size_t nm=0; nmGetMarkedSdrObj(); Point aCtr0(pO->GetSnapRect().Center()); Point aCtr1(aCtr0); if (bVertical) ResizePoint(aCtr1,aCenter,aFact1,aFact); else ResizePoint(aCtr1,aCenter,aFact,aFact1); Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y()); if( bUndo ) AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz)); pO->Move(aSiz); } } bCopy=false; } if (bDoCrook) { getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy); } if (bResize && bUndo) getSdrDragView().EndUndo(); return true; } return false; } PointerStyle SdrDragCrook::GetSdrDragPointer() const { return PointerStyle::Crook; } SdrDragDistort::SdrDragDistort(SdrDragView& rNewView) : SdrDragMethod(rNewView), nPolyPt(0), bContortionAllowed(false), bNoContortionAllowed(false), bContortion(false) { } OUString SdrDragDistort::GetSdrDragComment() const { OUString aStr = ImpGetDescriptionStr(STR_DragMethDistort) + " (x=" + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX()) + " y=" + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY()) + ")"; if(getSdrDragView().IsDragWithCopy()) aStr += SvxResId(STR_EditWithCopy); return aStr; } void SdrDragDistort::createSdrDragEntries() { // Add extended frame raster first, so it will be behind objects if(getSdrDragView().GetSdrPageView()) { const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect())); if(aDragRaster.count()) { addSdrDragEntry(std::unique_ptr(new SdrDragEntryPolyPolygon(aDragRaster))); } } // call parent SdrDragMethod::createSdrDragEntries(); } bool SdrDragDistort::BeginSdrDrag() { bContortionAllowed=getSdrDragView().IsDistortAllowed(); bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true); if (bContortionAllowed || bNoContortionAllowed) { SdrHdlKind eKind=GetDragHdlKind(); nPolyPt=0xFFFF; if (eKind==SdrHdlKind::UpperLeft) nPolyPt=0; if (eKind==SdrHdlKind::UpperRight) nPolyPt=1; if (eKind==SdrHdlKind::LowerRight) nPolyPt=2; if (eKind==SdrHdlKind::LowerLeft) nPolyPt=3; if (nPolyPt>3) return false; aMarkRect=GetMarkedRect(); aDistortedRect=XPolygon(aMarkRect); Show(); return true; } else { return false; } } void SdrDragDistort::MovAllPoints(basegfx::B2DPolyPolygon& rTarget) { if (!bContortion) return; SdrPageView* pPV = getSdrDragView().GetSdrPageView(); if(pPV && pPV->HasMarkedObjPageView()) { basegfx::B2DPolyPolygon aDragPolygon(rTarget); const basegfx::B2DRange aOriginalRange = vcl::unotools::b2DRectangleFromRectangle(aMarkRect); const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y()); const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y()); const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y()); const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y()); rTarget = basegfx::utils::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight); } } void SdrDragDistort::MoveSdrDrag(const Point& rPnt) { if (!DragStat().CheckMinMoved(rPnt)) return; Point aPnt(GetSnapPos(rPnt)); if (getSdrDragView().IsOrtho()) OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho()); bool bNewContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed; if (bNewContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt) { Hide(); aDistortedRect[nPolyPt]=aPnt; bContortion=bNewContortion; DragStat().NextMove(aPnt); Show(); } } bool SdrDragDistort::EndSdrDrag(bool bCopy) { Hide(); bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0; if (bDoDistort) { getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy); return true; } return false; } PointerStyle SdrDragDistort::GetSdrDragPointer() const { return PointerStyle::RefHand; } void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget) { const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0); if (bDoDistort) { SdrEditView::ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion); } } void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget) { // use helper derived from old stuff MovAllPoints(rTarget); } SdrDragCrop::SdrDragCrop(SdrDragView& rNewView) : SdrDragObjOwn(rNewView) { // switch off solid dragging for crop; it just makes no sense since showing // a 50% transparent object above the original will not be visible setSolidDraggingActive(false); } OUString SdrDragCrop::GetSdrDragComment() const { OUString aStr = ImpGetDescriptionStr(STR_DragMethCrop) + " (x=" + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX()) + " y=" + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY()) + ")"; if(getSdrDragView().IsDragWithCopy()) aStr += SvxResId(STR_EditWithCopy); return aStr; } bool SdrDragCrop::BeginSdrDrag() { // call parent bool bRetval(SdrDragObjOwn::BeginSdrDrag()); if(!GetDragHdl()) { // we need the DragHdl, break if not there bRetval = false; } return bRetval; } bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/) { Hide(); if(0 == DragStat().GetDX() && 0 == DragStat().GetDY()) { // no change, done return false; } const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList(); if(1 != rMarkList.GetMarkCount()) { // Crop only with single Object selected return false; } // prepare for SdrGrafObj or others. This code has to work with usual // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from // Writer. It would be better to handle this in Writer directly, but // there are currently no easy mechanisms to plug an alternative interaction // from there SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj(); rtl::Reference pFullDragClone; bool bExternal(false); SdrObject* pExternalSdrObject(nullptr); // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now // locally, no two-in-one methods any more if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr) { // If Writer, get the already offered for interaction SdrGrafObj // and set up for using that replacement object that contains the // real transformation. That SdrObject is owned and has to be deleted, // so use a std::unique_ptr with special handling for the protected // SDrObject destructor pFullDragClone = pSdrObject->getFullDragClone(); if(dynamic_cast< SdrGrafObj* >(pFullDragClone.get())) { bExternal = true; pExternalSdrObject = pSdrObject; pSdrObject = pFullDragClone.get(); } } // get and check for SdrGrafObj now SdrGrafObj* pObj = dynamic_cast( pSdrObject ); if(!pObj) { return false; } // no undo for external needed, done there const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled()); if(bUndo) { OUString aUndoStr = ImpGetDescriptionStr(STR_DragMethCrop); getSdrDragView().BegUndo( aUndoStr ); getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj)); // also need attr undo, the SdrGrafCropItem will be changed getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj)); } // get the original objects transformation basegfx::B2DHomMatrix aOriginalMatrix; basegfx::B2DPolyPolygon aPolyPolygon; bool bShearCorrected(false); pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon); { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix); if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX())) { bShearCorrected = true; aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( aTmpDecomp.getScale(), -aTmpDecomp.getShearX(), aTmpDecomp.getRotate(), aTmpDecomp.getTranslate()); } } // generate start point of original drag vector in unit coordinates (the // vis-a-vis of the drag point) basegfx::B2DPoint aLocalStart(0.0, 0.0); bool bOnAxis(false); switch(GetDragHdlKind()) { case SdrHdlKind::UpperLeft: aLocalStart.setX(1.0); aLocalStart.setY(1.0); break; case SdrHdlKind::Upper: aLocalStart.setX(0.5); aLocalStart.setY(1.0); bOnAxis = true; break; case SdrHdlKind::UpperRight: aLocalStart.setX(0.0); aLocalStart.setY(1.0); break; case SdrHdlKind::Left : aLocalStart.setX(1.0); aLocalStart.setY(0.5); bOnAxis = true; break; case SdrHdlKind::Right: aLocalStart.setX(0.0); aLocalStart.setY(0.5); bOnAxis = true; break; case SdrHdlKind::LowerLeft: aLocalStart.setX(1.0); aLocalStart.setY(0.0); break; case SdrHdlKind::Lower: aLocalStart.setX(0.5); aLocalStart.setY(0.0); bOnAxis = true; break; case SdrHdlKind::LowerRight: aLocalStart.setX(0.0); aLocalStart.setY(0.0); break; default: break; } // create the current drag position in unit coordinates. To get there, // transform back the DragPoint to UnitCoordinates basegfx::B2DHomMatrix aInverse(aOriginalMatrix); aInverse.invert(); basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y())); // if one of the edge handles is used, limit to X or Y drag only if(bOnAxis) { if(basegfx::fTools::equal(aLocalStart.getX(), 0.5)) { aLocalCurrent.setX(aLocalStart.getX()); } else { aLocalCurrent.setY(aLocalStart.getY()); } } // create internal change in unit coordinates basegfx::B2DHomMatrix aDiscreteChangeMatrix; if(!basegfx::fTools::equal(aLocalCurrent.getX(), aLocalStart.getX())) { if(aLocalStart.getX() < 0.5) { aDiscreteChangeMatrix.scale(aLocalCurrent.getX(), 1.0); } else { aDiscreteChangeMatrix.scale(1.0 - aLocalCurrent.getX(), 1.0); aDiscreteChangeMatrix.translate(aLocalCurrent.getX(), 0.0); } } if(!basegfx::fTools::equal(aLocalCurrent.getY(), aLocalStart.getY())) { if(aLocalStart.getY() < 0.5) { aDiscreteChangeMatrix.scale(1.0, aLocalCurrent.getY()); } else { aDiscreteChangeMatrix.scale(1.0, 1.0 - aLocalCurrent.getY()); aDiscreteChangeMatrix.translate(0.0, aLocalCurrent.getY()); } } // We now have the whole executed Crop in UnitCoordinates in // aDiscreteChangeMatrix, go to concrete sizes now. // Create the unrotated original rectangle and the unrotated modified // rectangle as Ranges const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix); // prepare unsheared/unrotated versions of the old and new transformation const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate( basegfx::utils::createScaleTranslateB2DHomMatrix( basegfx::absolute(aOriginalMatrixDecomp.getScale()), aOriginalMatrixDecomp.getTranslate())); // create the ranges for these basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0); basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0); aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate); aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix); if(bExternal) { // With aLocalStart point (opposed to dragged point), X scale and Y scale, // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj // crop. Use aLocalStart unchanged, so being relative to the Crop-Action, // the called instance knows best how to use it const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth()); const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight()); pExternalSdrObject->Crop( aLocalStart, fScaleX, fScaleY); } else { // prepare matrix to apply to object; evtl. back-correct shear basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix); if(bShearCorrected) { // back-correct shear const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix); aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( aTmpDecomp.getScale(), -aTmpDecomp.getShearX(), aTmpDecomp.getRotate(), aTmpDecomp.getTranslate()); } // apply change to object by applying the unit coordinate change followed // by the original change pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon); // extract the old Rectangle structures tools::Rectangle aOldRect( basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()), basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()), basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()), basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY())); tools::Rectangle aNewRect( basegfx::fround(aRangeNewNoShearNoRotate.getMinX()), basegfx::fround(aRangeNewNoShearNoRotate.getMinY()), basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()), basegfx::fround(aRangeNewNoShearNoRotate.getMaxY())); // continue with the old original stuff if (!aOldRect.GetWidth() || !aOldRect.GetHeight()) { throw o3tl::divide_by_zero(); } if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default)) { return false; } const GraphicObject& rGraphicObject(pObj->GetGraphicObject()); // tdf#117145 Usually Writer will go the bExternal path (see above), but more correct for // the future is to use the MapMode from the SdrModel/SfxItemPool if the Writer's current // special handling should be unified to this path in the future. Usually it *should* be // MapUnit::Map100thMM, but better do not mix up Units. // Checked now what SwVirtFlyDrawObj::NbcCrop is doing - it calculates everything forced // to MapUnit::Map100thMM, but extracts/packs Twips to the used SdrGrafCropItem in Writer. const MapMode aMapModePool(pObj->getSdrModelFromSdrObject().GetItemPool().GetMetric(0)); Size aGraphicSize(rGraphicObject.GetPrefSize()); if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit()) { aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapModePool); } else { aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapModePool); } if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height()) { return false; } const SdrGrafCropItem& rOldCrop = pObj->GetMergedItem(SDRATTR_GRAFCROP); double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / static_cast(aOldRect.GetWidth()); double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / static_cast(aOldRect.GetHeight()); sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left(); sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top(); sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right(); sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom(); if(pObj->IsMirrored()) { // mirrored X or Y, for old stuff, exchange X // check for aw080 sal_Int32 nTmp(nDiffLeft); nDiffLeft = -nDiffRight; nDiffRight = -nTmp; } sal_Int32 nLeftCrop = static_cast( rOldCrop.GetLeft() + nDiffLeft * fScaleX ); sal_Int32 nTopCrop = static_cast( rOldCrop.GetTop() + nDiffTop * fScaleY ); sal_Int32 nRightCrop = static_cast( rOldCrop.GetRight() - nDiffRight * fScaleX ); sal_Int32 nBottomCrop = static_cast( rOldCrop.GetBottom() - nDiffBottom * fScaleY ); SfxItemPool& rPool = getSdrDragView().GetModel().GetItemPool(); SfxItemSetFixed aSet( rPool ); aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) ); getSdrDragView().SetAttributes( aSet, false ); } if(bUndo) { getSdrDragView().EndUndo(); } return true; } PointerStyle SdrDragCrop::GetSdrDragPointer() const { return PointerStyle::Crop; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */