Version 7.1.7.1, tag libreoffice-7.1.7.1
[LibreOffice.git] / svx / source / svdraw / svddrgmt.cxx
blob6f6ac53a11fa7ffb1414805c06fa00eed5020e6d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "svddrgm1.hxx"
21 #include <math.h>
23 #include <o3tl/numeric.hxx>
24 #include <vcl/canvastools.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/settings.hxx>
27 #include <vcl/ptrstyle.hxx>
28 #include <svx/xpoly.hxx>
29 #include <svx/svdtrans.hxx>
30 #include <svx/svdundo.hxx>
31 #include <svx/svdmark.hxx>
32 #include <svx/svdpagv.hxx>
33 #include <svx/svddrgv.hxx>
34 #include <svx/svdograf.hxx>
35 #include <svx/strings.hrc>
36 #include <svx/dialmgr.hxx>
37 #include <svx/sdgcpitm.hxx>
38 #include <svx/sdooitm.hxx>
39 #include <svx/sdtagitm.hxx>
40 #include <basegfx/polygon/b2dpolygon.hxx>
41 #include <basegfx/polygon/b2dpolygontools.hxx>
42 #include <svx/sdr/overlay/overlaymanager.hxx>
43 #include <sdr/overlay/overlayrollingrectangle.hxx>
44 #include <svx/sdrpagewindow.hxx>
45 #include <svx/sdrpaintwindow.hxx>
46 #include <basegfx/matrix/b2dhommatrix.hxx>
47 #include <basegfx/polygon/b2dpolypolygontools.hxx>
48 #include <svx/sdr/contact/viewcontact.hxx>
49 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
50 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
51 #include <svx/sdr/contact/objectcontact.hxx>
52 #include <svx/svditer.hxx>
53 #include <svx/svdopath.hxx>
54 #include <svx/polypolygoneditor.hxx>
55 #include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
56 #include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
57 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
58 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
59 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
60 #include <sdr/primitive2d/sdrattributecreator.hxx>
61 #include <sdr/primitive2d/sdrdecompositiontools.hxx>
62 #include <sdr/primitive2d/sdrprimitivetools.hxx>
63 #include <basegfx/matrix/b2dhommatrixtools.hxx>
64 #include <drawinglayer/attribute/sdrlineattribute.hxx>
65 #include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
66 #include <svl/itempool.hxx>
67 #include <comphelper/lok.hxx>
68 #include <map>
69 #include <vector>
72 SdrDragEntry::SdrDragEntry()
73 : mbAddToTransparent(false)
77 SdrDragEntry::~SdrDragEntry()
82 SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(const basegfx::B2DPolyPolygon& rOriginalPolyPolygon)
83 : SdrDragEntry(),
84 maOriginalPolyPolygon(rOriginalPolyPolygon)
88 SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
92 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
94 drawinglayer::primitive2d::Primitive2DContainer aRetval;
96 if(maOriginalPolyPolygon.count())
98 basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);
99 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
101 rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
102 basegfx::BColor aColA(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
103 basegfx::BColor aColB(aSvtOptionsDrawinglayer.GetStripeColorB().getBColor());
104 const double fStripeLength(aSvtOptionsDrawinglayer.GetStripeLength());
106 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
108 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
109 aColB.invert();
112 aRetval.resize(2);
113 aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
114 aCopy,
115 aColA,
116 aColB,
117 fStripeLength);
119 const basegfx::BColor aHilightColor(aSvtOptionsDrawinglayer.getHilightColor().getBColor());
120 const double fTransparence(aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01);
122 aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
123 aCopy,
124 aHilightColor,
125 fTransparence,
126 3.0,
127 false);
130 return aRetval;
134 SdrDragEntrySdrObject::SdrDragEntrySdrObject(
135 const SdrObject& rOriginal,
136 bool bModify)
137 : SdrDragEntry(),
138 maOriginal(rOriginal),
139 mbModify(bModify)
141 // add SdrObject parts to transparent overlay stuff
142 setAddToTransparent(true);
145 SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
149 void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
151 // for the moment, i need to re-create the clone in all cases. I need to figure
152 // out when clone and original have the same class, so that i can use operator=
153 // in those cases
155 mxClone.reset();
157 if(mbModify)
159 mxClone = maOriginal.getFullDragClone();
161 // apply original transformation, implemented at the DragMethods
162 rDragMethod.applyCurrentTransformationToSdrObject(*mxClone);
166 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod&)
168 const SdrObject* pSource = &maOriginal;
170 if(mbModify && mxClone)
172 // choose source for geometry data
173 pSource = mxClone.get();
176 // use the view-independent primitive representation (without
177 // evtl. GridOffset, that may be applied to the DragEntry individually)
178 return pSource->GetViewContact().getViewIndependentPrimitive2DContainer();
182 SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
183 const drawinglayer::primitive2d::Primitive2DContainer& rSequence)
184 : SdrDragEntry(),
185 maPrimitive2DSequence(rSequence)
187 // add parts to transparent overlay stuff if necessary
188 setAddToTransparent(true);
191 SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
195 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
197 drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(
198 new drawinglayer::primitive2d::TransformPrimitive2D(
199 rDragMethod.getCurrentTransformation(),
200 maPrimitive2DSequence));
202 return drawinglayer::primitive2d::Primitive2DContainer { aTransformPrimitive2D };
206 SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(const std::vector< basegfx::B2DPoint >& rPositions, bool bIsPointDrag)
207 : maPositions(rPositions),
208 mbIsPointDrag(bIsPointDrag)
210 // add SdrObject parts to transparent overlay stuff
211 setAddToTransparent(true);
214 SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
218 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
220 drawinglayer::primitive2d::Primitive2DContainer aRetval;
222 if(!maPositions.empty())
224 basegfx::B2DPolygon aPolygon;
226 for(auto const & a: maPositions)
228 aPolygon.append(a);
231 basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);
233 rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);
235 const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
236 std::vector< basegfx::B2DPoint > aTransformedPositions;
238 aTransformedPositions.reserve(aTransformed.count());
240 for(sal_uInt32 a = 0; a < aTransformed.count(); a++)
242 aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
245 if(mbIsPointDrag)
247 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
248 basegfx::BColor aColor(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
250 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
252 aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
255 drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
256 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(aTransformedPositions,
257 drawinglayer::primitive2d::createDefaultCross_3x3(aColor)));
259 aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
261 else
263 drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
264 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(aTransformedPositions,
265 SdrHdl::createGluePointBitmap()));
266 aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
270 return aRetval;
274 void SdrDragMethod::resetSdrDragEntries()
276 // clear entries; creation is on demand
277 clearSdrDragEntries();
280 basegfx::B2DRange SdrDragMethod::getCurrentRange() const
282 return maOverlayObjectList.getBaseRange();
285 void SdrDragMethod::clearSdrDragEntries()
287 maSdrDragEntries.clear();
290 void SdrDragMethod::addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew)
292 assert(pNew);
293 maSdrDragEntries.push_back(std::move(pNew));
296 void SdrDragMethod::createSdrDragEntries()
298 if(!(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView()))
299 return;
301 if(getSdrDragView().IsDraggingPoints())
303 createSdrDragEntries_PointDrag();
305 else if(getSdrDragView().IsDraggingGluePoints())
307 createSdrDragEntries_GlueDrag();
309 else
311 if(getSolidDraggingActive())
313 createSdrDragEntries_SolidDrag();
315 else
317 createSdrDragEntries_PolygonDrag();
322 void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
324 // add full object drag; Clone() at the object has to work
325 // for this
326 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
329 void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
330 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
331 const sdr::contact::ObjectContact& rObjectContact,
332 sdr::overlay::OverlayManager& rOverlayManager)
334 // check if we have an OverlayObject
335 if(!pOverlayObject)
337 return;
340 // add to OverlayManager
341 rOverlayManager.add(*pOverlayObject);
343 // Add GridOffset for non-linear ViewToDevice transformation (calc)
344 if(rObjectContact.supportsGridOffsets())
346 const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());
348 if(!rNewRange.isEmpty())
350 basegfx::B2DVector aOffset(0.0, 0.0);
351 rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);
353 if(!aOffset.equalZero())
355 pOverlayObject->setOffset(aOffset);
360 // add to local OverlayObjectList - ownership change (!)
361 maOverlayObjectList.append(std::move(pOverlayObject));
364 void SdrDragMethod::createSdrDragEntries_SolidDrag()
366 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
367 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
369 if(!pPV)
370 return;
372 for(size_t a = 0; a < nMarkCount; ++a)
374 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
376 if(pM->GetPageView() == pPV)
378 const SdrObject* pObject = pM->GetMarkedSdrObj();
380 if(pObject)
382 if(pPV->PageWindowCount())
384 SdrObjListIter aIter(*pObject);
386 while(aIter.IsMore())
388 SdrObject* pCandidate = aIter.Next();
390 if(pCandidate)
392 const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
393 bool bAddWireframe(bSuppressFullDrag);
395 if(!bAddWireframe && !pCandidate->HasLineStyle())
397 // add wireframe for objects without outline
398 bAddWireframe = true;
401 if(!bSuppressFullDrag)
403 // add full object drag; Clone() at the object has to work
404 // for this
405 createSdrDragEntryForSdrObject(*pCandidate);
408 if(bAddWireframe)
410 // when dragging a 50% transparent copy of a filled or not filled object without
411 // outline, this is normally hard to see. Add extra wireframe in that case. This
412 // works nice e.g. with text frames etc.
413 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly())));
423 void SdrDragMethod::createSdrDragEntries_PolygonDrag()
425 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
426 bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkCount > SdrDragView::GetDragXorPolyLimit());
427 basegfx::B2DPolyPolygon aResult;
428 sal_uInt32 nPointCount(0);
430 for(size_t a = 0; !bNoPolygons && a < nMarkCount; ++a)
432 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
434 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
436 const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());
438 for(auto const& rPolygon : aNewPolyPolygon)
440 nPointCount += rPolygon.count();
443 if(nPointCount > SdrDragView::GetDragXorPointLimit())
445 bNoPolygons = true;
448 if(!bNoPolygons)
450 aResult.append(aNewPolyPolygon);
455 if(bNoPolygons)
457 const tools::Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
458 const basegfx::B2DRange aNewRectangle = vcl::unotools::b2DRectangleFromRectangle(aR);
459 basegfx::B2DPolygon aNewPolygon(basegfx::utils::createPolygonFromRect(aNewRectangle));
461 aResult = basegfx::B2DPolyPolygon(basegfx::utils::expandToCurve(aNewPolygon));
464 if(aResult.count())
466 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aResult)));
470 void SdrDragMethod::createSdrDragEntries_PointDrag()
472 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
473 std::vector< basegfx::B2DPoint > aPositions;
475 for(size_t nm = 0; nm < nMarkCount; ++nm)
477 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
479 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
481 const SdrUShortCont& rPts = pM->GetMarkedPoints();
483 if (!rPts.empty())
485 const SdrObject* pObj = pM->GetMarkedSdrObj();
486 const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
488 if(pPath)
490 const basegfx::B2DPolyPolygon& aPathXPP = pPath->GetPathPoly();
492 if(aPathXPP.count())
494 for(const sal_uInt16 nObjPt : rPts)
496 sal_uInt32 nPolyNum, nPointNum;
498 if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum))
500 aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
509 if(!aPositions.empty())
511 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(aPositions, true)));
515 void SdrDragMethod::createSdrDragEntries_GlueDrag()
517 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
518 std::vector< basegfx::B2DPoint > aPositions;
520 for(size_t nm = 0; nm < nMarkCount; ++nm)
522 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
524 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
526 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
528 if (!rPts.empty())
530 const SdrObject* pObj = pM->GetMarkedSdrObj();
531 const SdrGluePointList* pGPL = pObj->GetGluePointList();
533 if (pGPL)
535 for(const sal_uInt16 nObjPt : rPts)
537 const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));
539 if(SDRGLUEPOINT_NOTFOUND != nGlueNum)
541 const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
542 aPositions.emplace_back(aPoint.X(), aPoint.Y());
550 if(!aPositions.empty())
552 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(aPositions, false)));
556 OUString SdrDragMethod::ImpGetDescriptionStr(const char* pStrCacheID) const
558 ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE;
559 if (IsDraggingPoints()) {
560 nOpt=ImpGetDescriptionOptions::POINTS;
561 } else if (IsDraggingGluePoints()) {
562 nOpt=ImpGetDescriptionOptions::GLUEPOINTS;
564 return getSdrDragView().ImpGetDescriptionString(pStrCacheID, nOpt);
567 SdrObject* SdrDragMethod::GetDragObj() const
569 SdrObject* pObj=nullptr;
570 if (getSdrDragView().mpDragHdl!=nullptr) pObj=getSdrDragView().mpDragHdl->GetObj();
571 if (pObj==nullptr) pObj=getSdrDragView().mpMarkedObj;
572 return pObj;
575 SdrPageView* SdrDragMethod::GetDragPV() const
577 SdrPageView* pPV=nullptr;
578 if (getSdrDragView().mpDragHdl!=nullptr) pPV=getSdrDragView().mpDragHdl->GetPageView();
579 if (pPV==nullptr) pPV=getSdrDragView().mpMarkedPV;
580 return pPV;
583 void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
585 // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
586 // Later this should be the only needed one for linear transforms (not for SdrDragCrook and
587 // SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the
588 // special handling of rotate/mirror due to the not-being-able to handle it in the old
589 // drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
590 basegfx::B2DHomMatrix aObjectTransform;
591 basegfx::B2DPolyPolygon aObjectPolyPolygon;
592 bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));
594 // apply transform to object transform
595 aObjectTransform *= getCurrentTransformation();
597 if(bPolyUsed)
599 // do something special since the object size is in the polygon
600 // break up matrix to get the scale
601 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);
603 // get polygon's position and size
604 const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
606 // get the scaling factors (do not mirror, this is in the object transformation)
607 const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
608 const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
610 // prepare transform matrix for polygon
611 basegfx::B2DHomMatrix aPolyTransform(
612 basegfx::utils::createTranslateB2DHomMatrix(
613 -aPolyRange.getMinX(),
614 -aPolyRange.getMinY()));
615 aPolyTransform.scale(fScaleX, fScaleY);
617 // transform the polygon
618 aObjectPolyPolygon.transform(aPolyTransform);
621 rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
624 void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
626 // original uses CurrentTransformation
627 rTarget.transform(getCurrentTransformation());
630 SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
631 : maSdrDragEntries(),
632 maOverlayObjectList(),
633 mrSdrDragView(rNewView),
634 mbMoveOnly(false),
635 mbSolidDraggingActive(getSdrDragView().IsSolidDragging()),
636 mbShiftPressed(false)
638 if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
640 // fallback to wireframe when high contrast is used
641 mbSolidDraggingActive = false;
645 SdrDragMethod::~SdrDragMethod()
647 clearSdrDragEntries();
650 void SdrDragMethod::Show()
652 getSdrDragView().ShowDragObj();
655 void SdrDragMethod::Hide()
657 getSdrDragView().HideDragObj();
660 basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation()
662 return basegfx::B2DHomMatrix();
665 void SdrDragMethod::CancelSdrDrag()
667 Hide();
670 typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;
672 void SdrDragMethod::CreateOverlayGeometry(
673 sdr::overlay::OverlayManager& rOverlayManager,
674 const sdr::contact::ObjectContact& rObjectContact)
676 // We do client-side object manipulation with the Kit API
677 if (comphelper::LibreOfficeKit::isActive())
678 return;
680 // create SdrDragEntries on demand
681 if(maSdrDragEntries.empty())
683 createSdrDragEntries();
686 // if there are entries, derive OverlayObjects from the entries, including
687 // modification from current interactive state
688 if(!maSdrDragEntries.empty())
690 // #i54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
691 // primitives, holding the original and the clone. If connectors (Edges) are involved,
692 // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
693 // they are connected to the original SdrObjects). To do so, trigger the preparation
694 // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
695 // and evtl. remember if it was an edge
696 SdrObjectAndCloneMap aOriginalAndClones;
697 std::vector< SdrEdgeObj* > aEdges;
699 // #i54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
700 // clone, remember edges
701 for(auto const & a: maSdrDragEntries)
703 SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(a.get());
705 if(pSdrDragEntrySdrObject)
707 pSdrDragEntrySdrObject->prepareCurrentState(*this);
709 SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());
711 if(pSdrEdgeObj)
713 aEdges.push_back(pSdrEdgeObj);
716 if(pSdrDragEntrySdrObject->getClone())
718 aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
723 // #i54102# if there are edges, reconnect their ends to the corresponding clones (if found)
724 for(SdrEdgeObj* pSdrEdgeObj: aEdges)
726 SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);
728 if(pConnectedTo)
730 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
732 if(aEntry != aOriginalAndClones.end())
734 pSdrEdgeObj->ConnectToNode(true, aEntry->second);
738 pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);
740 if(pConnectedTo)
742 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
744 if(aEntry != aOriginalAndClones.end())
746 pSdrEdgeObj->ConnectToNode(false, aEntry->second);
751 // collect primitives for visualisation
752 drawinglayer::primitive2d::Primitive2DContainer aResult;
753 drawinglayer::primitive2d::Primitive2DContainer aResultTransparent;
755 for(auto & pCandidate: maSdrDragEntries)
757 const drawinglayer::primitive2d::Primitive2DContainer aCandidateResult(pCandidate->createPrimitive2DSequenceInCurrentState(*this));
759 if(!aCandidateResult.empty())
761 if(pCandidate->getAddToTransparent())
763 aResultTransparent.append(aCandidateResult);
765 else
767 aResult.append(aCandidateResult);
772 if(DoAddConnectorOverlays())
774 const drawinglayer::primitive2d::Primitive2DContainer aConnectorOverlays(AddConnectorOverlays());
776 if(!aConnectorOverlays.empty())
778 // add connector overlays to transparent part
779 aResultTransparent.append(aConnectorOverlays);
783 if(!aResult.empty())
785 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
786 new sdr::overlay::OverlayPrimitive2DSequenceObject(
787 aResult));
789 insertNewlyCreatedOverlayObjectForSdrDragMethod(
790 std::move(pNewOverlayObject),
791 rObjectContact,
792 rOverlayManager);
795 if(!aResultTransparent.empty())
797 drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aResultTransparent, 0.5));
798 aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };
800 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
801 new sdr::overlay::OverlayPrimitive2DSequenceObject(
802 aResultTransparent));
804 insertNewlyCreatedOverlayObjectForSdrDragMethod(
805 std::move(pNewOverlayObject),
806 rObjectContact,
807 rOverlayManager);
811 // add DragStripes if necessary (help lines cross the page when dragging)
812 if(!getSdrDragView().IsDragStripes())
813 return;
815 tools::Rectangle aActionRectangle;
816 getSdrDragView().TakeActionRect(aActionRectangle);
818 const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
819 const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
820 std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
821 new sdr::overlay::OverlayRollingRectangleStriped(
822 aTopLeft,
823 aBottomRight,
824 true,
825 false));
827 insertNewlyCreatedOverlayObjectForSdrDragMethod(
828 std::move(pNew),
829 rObjectContact,
830 rOverlayManager);
833 void SdrDragMethod::destroyOverlayGeometry()
835 maOverlayObjectList.clear();
838 bool SdrDragMethod::DoAddConnectorOverlays()
840 // these conditions are translated from SdrDragView::ImpDrawEdgeXor
841 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
843 if(!rMarkedNodes.GetMarkCount())
845 return false;
848 if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
850 return false;
853 if(!getMoveOnly() && !(
854 dynamic_cast<const SdrDragMove*>(this) != nullptr || dynamic_cast<const SdrDragResize*>(this) != nullptr ||
855 dynamic_cast<const SdrDragRotate*>(this) != nullptr || dynamic_cast<const SdrDragMirror*>(this) != nullptr ))
857 return false;
860 // one more migrated from SdrEdgeObj::NspToggleEdgeXor
861 if( dynamic_cast< const SdrDragObjOwn* >(this) != nullptr || dynamic_cast< const SdrDragMovHdl* >(this) != nullptr )
863 return false;
866 return true;
869 drawinglayer::primitive2d::Primitive2DContainer SdrDragMethod::AddConnectorOverlays()
871 drawinglayer::primitive2d::Primitive2DContainer aRetval;
872 const bool bDetail(getMoveOnly());
873 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
875 for(size_t a = 0; a < rMarkedNodes.GetMarkCount(); ++a)
877 SdrMark* pEM = rMarkedNodes.GetMark(a);
879 if(pEM && pEM->GetMarkedSdrObj())
881 SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());
883 if(pEdge)
885 const basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));
887 if(aEdgePolygon.count())
889 // this polygon is a temporary calculated connector path, so it is not possible to fetch
890 // the needed primitives directly from the pEdge object which does not get changed. If full
891 // drag is on, use the SdrObjects ItemSet to create an adequate representation
892 bool bUseSolidDragging(getSolidDraggingActive());
894 if(bUseSolidDragging)
896 // switch off solid dragging if connector is not visible
897 if(!pEdge->HasLineStyle())
899 bUseSolidDragging = false;
903 if(bUseSolidDragging)
905 const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
906 const drawinglayer::attribute::SdrLineAttribute aLine(
907 drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));
909 if(!aLine.isDefault())
911 const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
912 drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
913 rItemSet,
914 aLine.getWidth()));
916 aRetval.push_back(drawinglayer::primitive2d::createPolygonLinePrimitive(
917 aEdgePolygon,
918 aLine,
919 aLineStartEnd));
922 else
924 const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
925 basegfx::BColor aColA(aSvtOptionsDrawinglayer.GetStripeColorA().getBColor());
926 basegfx::BColor aColB(aSvtOptionsDrawinglayer.GetStripeColorB().getBColor());
927 const double fStripeLength(aSvtOptionsDrawinglayer.GetStripeLength());
929 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
931 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
932 aColB.invert();
935 drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
936 new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
937 aEdgePolygon, aColA, aColB, fStripeLength));
938 aRetval.push_back(aPolyPolygonMarkerPrimitive2D);
945 return aRetval;
949 SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
950 : SdrDragMethod(rNewView)
954 void SdrDragMovHdl::createSdrDragEntries()
956 // SdrDragMovHdl does not use the default drags,
957 // but creates nothing
960 OUString SdrDragMovHdl::GetSdrDragComment() const
962 OUString aStr=SvxResId(STR_DragMethMovHdl);
963 if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy);
964 return aStr;
967 bool SdrDragMovHdl::BeginSdrDrag()
969 if( !GetDragHdl() )
970 return false;
972 DragStat().SetRef1(GetDragHdl()->GetPos());
973 DragStat().SetShown(!DragStat().IsShown());
974 SdrHdlKind eKind=GetDragHdl()->GetKind();
975 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
976 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
978 if (eKind==SdrHdlKind::MirrorAxis)
980 if (pH1==nullptr || pH2==nullptr)
982 OSL_FAIL("SdrDragMovHdl::BeginSdrDrag(): Moving the axis of reflection: reference handles not found.");
983 return false;
986 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
988 else
990 Point aPt(GetDragHdl()->GetPos());
991 DragStat().SetActionRect(tools::Rectangle(aPt,aPt));
994 return true;
997 void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
999 Point aPnt(rNoSnapPnt);
1001 if ( !(GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)))
1002 return;
1004 if (GetDragHdl()->GetKind()==SdrHdlKind::MirrorAxis)
1006 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
1007 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
1009 if (pH1==nullptr || pH2==nullptr)
1010 return;
1012 if (!DragStat().IsNoSnap())
1014 tools::Long nBestXSnap=0;
1015 tools::Long nBestYSnap=0;
1016 bool bXSnapped=false;
1017 bool bYSnapped=false;
1018 Point aDif(aPnt-DragStat().GetStart());
1019 getSdrDragView().CheckSnap(Ref1()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1020 getSdrDragView().CheckSnap(Ref2()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1021 aPnt.AdjustX(nBestXSnap );
1022 aPnt.AdjustY(nBestYSnap );
1025 if (aPnt!=DragStat().GetNow())
1027 Hide();
1028 DragStat().NextMove(aPnt);
1029 Point aDif(DragStat().GetNow()-DragStat().GetStart());
1030 pH1->SetPos(Ref1()+aDif);
1031 pH2->SetPos(Ref2()+aDif);
1033 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1035 if(pHM)
1036 pHM->Touch();
1038 Show();
1039 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
1042 else
1044 if (!DragStat().IsNoSnap()) SnapPos(aPnt);
1045 tools::Long nSA=0;
1047 if (getSdrDragView().IsAngleSnapEnabled())
1048 nSA=getSdrDragView().GetSnapAngle();
1050 if (getSdrDragView().IsMirrorAllowed(true,true))
1051 { // limited
1052 if (!getSdrDragView().IsMirrorAllowed()) nSA=4500;
1053 if (!getSdrDragView().IsMirrorAllowed(true)) nSA=9000;
1056 if (getSdrDragView().IsOrtho() && nSA!=9000)
1057 nSA=4500;
1059 if (nSA!=0)
1060 { // angle snapping
1061 SdrHdlKind eRef=SdrHdlKind::Ref1;
1063 if (GetDragHdl()->GetKind()==SdrHdlKind::Ref1)
1064 eRef=SdrHdlKind::Ref2;
1066 SdrHdl* pH=GetHdlList().GetHdl(eRef);
1068 if (pH!=nullptr)
1070 Point aRef(pH->GetPos());
1071 tools::Long nAngle=NormAngle36000(GetAngle(aPnt-aRef));
1072 tools::Long nNewAngle=nAngle;
1073 nNewAngle+=nSA/2;
1074 nNewAngle/=nSA;
1075 nNewAngle*=nSA;
1076 nNewAngle=NormAngle36000(nNewAngle);
1077 double a=(nNewAngle-nAngle)*F_PI18000;
1078 double nSin=sin(a);
1079 double nCos=cos(a);
1080 RotatePoint(aPnt,aRef,nSin,nCos);
1082 // eliminate rounding errors for certain values
1083 if (nSA==9000)
1085 if (nNewAngle==0 || nNewAngle==18000) aPnt.setY(aRef.Y() );
1086 if (nNewAngle==9000 || nNewAngle==27000) aPnt.setX(aRef.X() );
1089 if (nSA==4500)
1090 OrthoDistance8(aRef,aPnt,true);
1094 if (aPnt!=DragStat().GetNow())
1096 Hide();
1097 DragStat().NextMove(aPnt);
1098 GetDragHdl()->SetPos(DragStat().GetNow());
1099 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1101 if(pHM)
1102 pHM->Touch();
1104 Show();
1105 DragStat().SetActionRect(tools::Rectangle(aPnt,aPnt));
1110 bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
1112 if( GetDragHdl() )
1114 switch (GetDragHdl()->GetKind())
1116 case SdrHdlKind::Ref1:
1117 Ref1()=DragStat().GetNow();
1118 break;
1120 case SdrHdlKind::Ref2:
1121 Ref2()=DragStat().GetNow();
1122 break;
1124 case SdrHdlKind::MirrorAxis:
1125 Ref1()+=DragStat().GetNow()-DragStat().GetStart();
1126 Ref2()+=DragStat().GetNow()-DragStat().GetStart();
1127 break;
1129 default: break;
1133 return true;
1136 void SdrDragMovHdl::CancelSdrDrag()
1138 Hide();
1140 SdrHdl* pHdl = GetDragHdl();
1141 if( pHdl )
1142 pHdl->SetPos(DragStat().GetRef1());
1144 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1146 if(pHM)
1147 pHM->Touch();
1150 PointerStyle SdrDragMovHdl::GetSdrDragPointer() const
1152 const SdrHdl* pHdl = GetDragHdl();
1154 if (pHdl!=nullptr)
1156 return pHdl->GetPointer();
1159 return PointerStyle::RefHand;
1163 SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
1164 : SdrDragMethod(rNewView)
1166 const SdrObject* pObj = GetDragObj();
1168 if(pObj)
1170 // suppress full drag for some object types
1171 setSolidDraggingActive(pObj->supportsFullDrag());
1175 SdrDragObjOwn::~SdrDragObjOwn()
1179 void SdrDragObjOwn::createSdrDragEntries()
1181 if(!mxClone)
1182 return;
1184 basegfx::B2DPolyPolygon aDragPolyPolygon;
1185 bool bAddWireframe(true);
1187 if(getSolidDraggingActive())
1189 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
1191 if(pPV && pPV->PageWindowCount())
1193 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mxClone, false)));
1195 // potentially no wireframe needed, full drag works
1196 bAddWireframe = false;
1200 if(!bAddWireframe)
1202 // check for extra conditions for wireframe, e.g. no border at
1203 // objects
1204 if(!mxClone->HasLineStyle())
1206 bAddWireframe = true;
1210 if(bAddWireframe)
1212 // use wireframe poly when full drag is off or did not work
1213 aDragPolyPolygon = mxClone->TakeXorPoly();
1216 // add evtl. extra DragPolyPolygon
1217 const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mxClone->getSpecialDragPoly(DragStat()));
1219 if(aSpecialDragPolyPolygon.count())
1221 aDragPolyPolygon.append(aSpecialDragPolyPolygon);
1224 if(aDragPolyPolygon.count())
1226 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragPolyPolygon)));
1230 OUString SdrDragObjOwn::GetSdrDragComment() const
1232 OUString aStr;
1233 // #i103058# get info string from the clone preferred, the original will
1234 // not be changed. For security, use original as fallback
1235 if(mxClone)
1237 aStr = mxClone->getSpecialDragComment(DragStat());
1239 else
1241 const SdrObject* pObj = GetDragObj();
1243 if(pObj)
1245 aStr = pObj->getSpecialDragComment(DragStat());
1248 return aStr;
1251 bool SdrDragObjOwn::BeginSdrDrag()
1253 if(!mxClone)
1255 const SdrObject* pObj = GetDragObj();
1257 if(pObj && !pObj->IsResizeProtect())
1259 if(pObj->beginSpecialDrag(DragStat()))
1261 // create initial clone to have a start visualization
1262 mxClone = pObj->getFullDragClone();
1263 mxClone->applySpecialDrag(DragStat());
1265 return true;
1270 return false;
1273 void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
1275 const SdrObject* pObj = GetDragObj();
1277 if (!pObj)
1278 // No object to drag. Bail out.
1279 return;
1281 Point aPnt(rNoSnapPnt);
1282 SdrPageView* pPV = GetDragPV();
1284 if (!pPV)
1285 // No page view available. Bail out.
1286 return;
1288 if(!DragStat().IsNoSnap())
1290 SnapPos(aPnt);
1292 if(getSdrDragView().IsOrtho())
1294 if (DragStat().IsOrtho8Possible())
1296 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1298 else if (DragStat().IsOrtho4Possible())
1300 OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1304 if (!DragStat().CheckMinMoved(rNoSnapPnt))
1305 // Not moved by the minimum threshold. Nothing to do.
1306 return;
1308 Hide();
1309 DragStat().NextMove(aPnt);
1311 // since SdrDragObjOwn currently supports no transformation of
1312 // existing SdrDragEntries but only their recreation, a recreation
1313 // after every move is needed in this mode. Delete existing
1314 // SdrDragEntries here to force their recreation in the following Show().
1315 clearSdrDragEntries();
1317 // delete current clone (after the last reference to it is deleted above)
1318 mxClone.reset();
1320 // create a new clone and modify to current drag state
1321 mxClone = pObj->getFullDragClone();
1322 mxClone->applySpecialDrag(DragStat());
1324 // AutoGrowWidth may change for SdrTextObj due to the automatism used
1325 // with bDisableAutoWidthOnDragging, so not only geometry changes but
1326 // also this (pretty indirect) property change is possible. If it gets
1327 // changed, it needs to be copied to the original since nothing will
1328 // happen when it only changes in the drag clone
1329 const bool bOldAutoGrowWidth(pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1330 const bool bNewAutoGrowWidth(mxClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1332 if (bOldAutoGrowWidth != bNewAutoGrowWidth)
1334 GetDragObj()->SetMergedItem(makeSdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
1337 Show();
1340 bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
1342 Hide();
1343 std::vector< std::unique_ptr<SdrUndoAction> > vConnectorUndoActions;
1344 bool bRet = false;
1345 SdrObject* pObj = GetDragObj();
1347 if(pObj)
1349 std::unique_ptr<SdrUndoAction> pUndo;
1350 std::unique_ptr<SdrUndoAction> pUndo2;
1351 const bool bUndo = getSdrDragView().IsUndoEnabled();
1353 if( bUndo )
1355 getSdrDragView().EndTextEditAllViews();
1356 if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() )
1358 if (DragStat().IsEndDragChangesAttributes())
1360 pUndo=getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj);
1362 if (DragStat().IsEndDragChangesGeoAndAttributes())
1364 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1365 pUndo2 = getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1368 else
1370 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1371 pUndo= getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1375 if( pUndo )
1377 getSdrDragView().BegUndo( pUndo->GetComment() );
1379 else
1381 getSdrDragView().BegUndo();
1385 // Maybe use operator = for setting changed object data (do not change selection in
1386 // view, this will destroy the interactor). This is possible since a clone is now
1387 // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
1388 // in its SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
1389 // a CreateUndoGeoObject(), so maybe setting SetEndDragChangesAttributes is okay. I
1390 // will test this now
1391 tools::Rectangle aBoundRect0;
1393 if(pObj->GetUserCall())
1395 aBoundRect0 = pObj->GetLastBoundRect();
1398 bRet = pObj->applySpecialDrag(DragStat());
1399 if (DragStat().IsEndDragChangesLayout())
1401 auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo.get());
1402 if (pGeoUndo)
1403 pGeoUndo->SetSkipChangeLayout(true);
1406 if(bRet)
1408 pObj->SetChanged();
1409 pObj->BroadcastObjectChange();
1410 pObj->SendUserCall( SdrUserCallType::Resize, aBoundRect0 );
1413 if(bRet && bUndo )
1415 getSdrDragView().AddUndoActions( std::move(vConnectorUndoActions) );
1417 if ( pUndo )
1419 getSdrDragView().AddUndo(std::move(pUndo));
1422 if ( pUndo2 )
1424 getSdrDragView().AddUndo(std::move(pUndo2));
1428 if( bUndo )
1429 getSdrDragView().EndUndo();
1432 return bRet;
1435 PointerStyle SdrDragObjOwn::GetSdrDragPointer() const
1437 const SdrHdl* pHdl=GetDragHdl();
1439 if (pHdl)
1441 return pHdl->GetPointer();
1444 return PointerStyle::Move;
1448 void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
1450 // use the view-independent primitive representation (without
1451 // evtl. GridOffset, that may be applied to the DragEntry individually)
1452 addSdrDragEntry(
1453 std::unique_ptr<SdrDragEntry>(
1454 new SdrDragEntryPrimitive2DSequence(
1455 rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer())));
1459 void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
1461 rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
1464 SdrDragMove::SdrDragMove(SdrDragView& rNewView)
1465 : SdrDragMethod(rNewView)
1466 , nBestXSnap(0)
1467 , nBestYSnap(0)
1468 , bXSnapped(false)
1469 , bYSnapped(false)
1471 setMoveOnly(true);
1474 OUString SdrDragMove::GetSdrDragComment() const
1476 OUString aStr = ImpGetDescriptionStr(STR_DragMethMove)
1477 + " (x="
1478 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
1479 + " y="
1480 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
1481 + ")";
1483 if(getSdrDragView().IsDragWithCopy())
1485 if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint())
1487 aStr += SvxResId(STR_EditWithCopy);
1490 return aStr;
1493 bool SdrDragMove::BeginSdrDrag()
1495 DragStat().SetActionRect(GetMarkedRect());
1496 Show();
1498 return true;
1501 basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation()
1503 return basegfx::utils::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
1506 void SdrDragMove::ImpCheckSnap(const Point& rPt)
1508 Point aPt(rPt);
1509 SdrSnap nRet=SnapPos(aPt);
1510 aPt-=rPt;
1512 if (nRet & SdrSnap::XSNAPPED)
1514 if (bXSnapped)
1516 if (std::abs(aPt.X())<std::abs(nBestXSnap))
1518 nBestXSnap=aPt.X();
1521 else
1523 nBestXSnap=aPt.X();
1524 bXSnapped=true;
1528 if (!(nRet & SdrSnap::YSNAPPED))
1529 return;
1531 if (bYSnapped)
1533 if (std::abs(aPt.Y())<std::abs(nBestYSnap))
1535 nBestYSnap=aPt.Y();
1538 else
1540 nBestYSnap=aPt.Y();
1541 bYSnapped=true;
1545 void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
1547 nBestXSnap=0;
1548 nBestYSnap=0;
1549 bXSnapped=false;
1550 bYSnapped=false;
1551 Point aNoSnapPnt(rNoSnapPnt_);
1552 const tools::Rectangle& aSR=GetMarkedRect();
1553 tools::Long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
1554 tools::Long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
1555 Point aLO(aSR.TopLeft()); aLO.AdjustX(nMovedx ); aLO.AdjustY(nMovedy );
1556 Point aRU(aSR.BottomRight()); aRU.AdjustX(nMovedx ); aRU.AdjustY(nMovedy );
1557 Point aLU(aLO.X(),aRU.Y());
1558 Point aRO(aRU.X(),aLO.Y());
1559 ImpCheckSnap(aLO);
1561 if (!getSdrDragView().IsMoveSnapOnlyTopLeft())
1563 ImpCheckSnap(aRO);
1564 ImpCheckSnap(aLU);
1565 ImpCheckSnap(aRU);
1568 Point aPnt(aNoSnapPnt.X()+nBestXSnap,aNoSnapPnt.Y()+nBestYSnap);
1569 bool bOrtho=getSdrDragView().IsOrtho();
1571 if (bOrtho)
1572 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1574 if (!DragStat().CheckMinMoved(aNoSnapPnt))
1575 return;
1577 Point aPt1(aPnt);
1578 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1579 bool bWorkArea=!aLR.IsEmpty();
1580 bool bDragLimit=IsDragLimit();
1582 if (bDragLimit || bWorkArea)
1584 tools::Rectangle aSR2(GetMarkedRect());
1585 Point aD(aPt1-DragStat().GetStart());
1587 if (bDragLimit)
1589 tools::Rectangle aR2(GetDragLimitRect());
1591 if (bWorkArea)
1592 aLR.Intersection(aR2);
1593 else
1594 aLR=aR2;
1597 if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right())
1598 { // any space to move to?
1599 aSR2.Move(aD.X(),0);
1601 if (aSR2.Left()<aLR.Left())
1603 aPt1.AdjustX( -(aSR2.Left()-aLR.Left()) );
1605 else if (aSR2.Right()>aLR.Right())
1607 aPt1.AdjustX( -(aSR2.Right()-aLR.Right()) );
1610 else
1611 aPt1.setX(DragStat().GetStart().X() ); // no space to move to
1613 if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom())
1614 { // any space to move to?
1615 aSR2.Move(0,aD.Y());
1617 if (aSR2.Top()<aLR.Top())
1619 aPt1.AdjustY( -(aSR2.Top()-aLR.Top()) );
1621 else if (aSR2.Bottom()>aLR.Bottom())
1623 aPt1.AdjustY( -(aSR2.Bottom()-aLR.Bottom()) );
1626 else
1627 aPt1.setY(DragStat().GetStart().Y() ); // no space to move to
1630 if (getSdrDragView().IsDraggingGluePoints())
1631 { // restrict glue points to the BoundRect of the Obj
1632 aPt1-=DragStat().GetStart();
1633 const SdrMarkList& rML=GetMarkedObjectList();
1634 const size_t nMarkCount=rML.GetMarkCount();
1636 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1638 const SdrMark* pM=rML.GetMark(nMarkNum);
1639 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
1641 if (!rPts.empty())
1643 const SdrObject* pObj=pM->GetMarkedSdrObj();
1644 const SdrGluePointList* pGPL=pObj->GetGluePointList();
1645 tools::Rectangle aBound(pObj->GetCurrentBoundRect());
1647 for (sal_uInt16 nId : rPts)
1649 sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);
1651 if (nGlueNum!=SDRGLUEPOINT_NOTFOUND)
1653 Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
1654 aPt+=aPt1; // move by this much
1655 if (aPt.X()<aBound.Left() ) aPt1.AdjustX( -(aPt.X()-aBound.Left()) ) ;
1656 if (aPt.X()>aBound.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ;
1657 if (aPt.Y()<aBound.Top() ) aPt1.AdjustY( -(aPt.Y()-aBound.Top()) ) ;
1658 if (aPt.Y()>aBound.Bottom()) aPt1.AdjustY( -(aPt.Y()-aBound.Bottom()) );
1664 aPt1+=DragStat().GetStart();
1667 if (bOrtho)
1668 OrthoDistance8(DragStat().GetStart(),aPt1,false);
1670 if (aPt1!=DragStat().GetNow())
1672 Hide();
1673 DragStat().NextMove(aPt1);
1674 tools::Rectangle aAction(GetMarkedRect());
1675 aAction.Move(DragStat().GetDX(),DragStat().GetDY());
1676 DragStat().SetActionRect(aAction);
1677 Show();
1681 bool SdrDragMove::EndSdrDrag(bool bCopy)
1683 Hide();
1685 if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint())
1686 bCopy=false;
1688 if (IsDraggingPoints())
1690 getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()));
1692 else if (IsDraggingGluePoints())
1694 getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1696 else
1698 getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1701 return true;
1704 PointerStyle SdrDragMove::GetSdrDragPointer() const
1706 if (IsDraggingPoints() || IsDraggingGluePoints())
1708 return PointerStyle::MovePoint;
1710 else
1712 return PointerStyle::Move;
1717 SdrDragResize::SdrDragResize(SdrDragView& rNewView)
1718 : SdrDragMethod(rNewView),
1719 aXFact(1,1),
1720 aYFact(1,1)
1724 OUString SdrDragResize::GetSdrDragComment() const
1726 OUString aStr = ImpGetDescriptionStr(STR_DragMethResize);
1727 Fraction aFact1(1,1);
1728 Point aStart(DragStat().GetStart());
1729 Point aRef(DragStat().GetRef1());
1730 sal_Int32 nXDiv(aStart.X() - aRef.X());
1732 if(!nXDiv)
1733 nXDiv = 1;
1735 sal_Int32 nYDiv(aStart.Y() - aRef.Y());
1737 if(!nYDiv)
1738 nYDiv = 1;
1740 bool bX(aXFact != aFact1 && std::abs(nXDiv) > 1);
1741 bool bY(aYFact != aFact1 && std::abs(nYDiv) > 1);
1743 if(bX || bY)
1745 aStr += " (";
1747 bool bEqual(aXFact == aYFact);
1748 if(bX)
1750 if(!bEqual)
1751 aStr += "x=";
1753 aStr += SdrModel::GetPercentString(aXFact);
1756 if(bY && !bEqual)
1758 if(bX)
1759 aStr += " ";
1761 aStr += "y=" + SdrModel::GetPercentString(aYFact);
1764 aStr += ")";
1767 if(getSdrDragView().IsDragWithCopy())
1768 aStr += SvxResId(STR_EditWithCopy);
1769 return aStr;
1772 bool SdrDragResize::BeginSdrDrag()
1774 SdrHdlKind eRefHdl=SdrHdlKind::Move;
1775 SdrHdl* pRefHdl=nullptr;
1777 switch (GetDragHdlKind())
1779 case SdrHdlKind::UpperLeft: eRefHdl=SdrHdlKind::LowerRight; break;
1780 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; DragStat().SetHorFixed(true); break;
1781 case SdrHdlKind::UpperRight: eRefHdl=SdrHdlKind::LowerLeft; break;
1782 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; DragStat().SetVerFixed(true); break;
1783 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; DragStat().SetVerFixed(true); break;
1784 case SdrHdlKind::LowerLeft: eRefHdl=SdrHdlKind::UpperRight; break;
1785 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; DragStat().SetHorFixed(true); break;
1786 case SdrHdlKind::LowerRight: eRefHdl=SdrHdlKind::UpperLeft; break;
1787 default: break;
1790 if (eRefHdl!=SdrHdlKind::Move)
1791 pRefHdl=GetHdlList().GetHdl(eRefHdl);
1793 if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
1795 DragStat().SetRef1(pRefHdl->GetPos());
1797 else
1799 SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft);
1800 SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight);
1802 if (pRef1!=nullptr && pRef2!=nullptr)
1804 DragStat().SetRef1(tools::Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center());
1806 else
1808 DragStat().SetRef1(GetMarkedRect().Center());
1812 Show();
1814 return true;
1817 basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation()
1819 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
1820 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
1821 aRetval.scale(double(aXFact), double(aYFact));
1822 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
1824 return aRetval;
1827 void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
1829 Point aPnt(GetSnapPos(rNoSnapPnt));
1830 Point aStart(DragStat().GetStart());
1831 Point aRef(DragStat().GetRef1());
1832 Fraction aMaxFact(0x7FFFFFFF,1);
1833 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1834 bool bWorkArea=!aLR.IsEmpty();
1835 bool bDragLimit=IsDragLimit();
1837 if (bDragLimit || bWorkArea)
1839 tools::Rectangle aSR(GetMarkedRect());
1841 if (bDragLimit)
1843 tools::Rectangle aR2(GetDragLimitRect());
1845 if (bWorkArea)
1846 aLR.Intersection(aR2);
1847 else
1848 aLR=aR2;
1851 if (aPnt.X()<aLR.Left())
1852 aPnt.setX(aLR.Left() );
1853 else if (aPnt.X()>aLR.Right())
1854 aPnt.setX(aLR.Right() );
1856 if (aPnt.Y()<aLR.Top())
1857 aPnt.setY(aLR.Top() );
1858 else if (aPnt.Y()>aLR.Bottom())
1859 aPnt.setY(aLR.Bottom() );
1861 if (aRef.X()>aSR.Left())
1863 Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());
1865 if (aMax<aMaxFact)
1866 aMaxFact=aMax;
1869 if (aRef.X()<aSR.Right())
1871 Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());
1873 if (aMax<aMaxFact)
1874 aMaxFact=aMax;
1877 if (aRef.Y()>aSR.Top())
1879 Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());
1881 if (aMax<aMaxFact)
1882 aMaxFact=aMax;
1885 if (aRef.Y()<aSR.Bottom())
1887 Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());
1889 if (aMax<aMaxFact)
1890 aMaxFact=aMax;
1894 tools::Long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
1895 tools::Long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
1896 tools::Long nXMul=aPnt.X()-aRef.X();
1897 tools::Long nYMul=aPnt.Y()-aRef.Y();
1899 if (nXDiv<0)
1901 nXDiv=-nXDiv;
1902 nXMul=-nXMul;
1905 if (nYDiv<0)
1907 nYDiv=-nYDiv;
1908 nYMul=-nYMul;
1911 bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
1912 bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
1913 bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();
1915 if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
1917 if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
1918 bOrtho=false;
1920 if (bOrtho)
1922 if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
1924 nXMul=nYMul;
1925 nXDiv=nYDiv;
1927 else
1929 nYMul=nXMul;
1930 nYDiv=nXDiv;
1934 else
1936 if (bOrtho)
1938 if (DragStat().IsHorFixed())
1940 bXNeg=false;
1941 nXMul=nYMul;
1942 nXDiv=nYDiv;
1945 if (DragStat().IsVerFixed())
1947 bYNeg=false;
1948 nYMul=nXMul;
1949 nYDiv=nXDiv;
1952 else
1954 if (DragStat().IsHorFixed())
1956 bXNeg=false;
1957 nXMul=1;
1958 nXDiv=1;
1961 if (DragStat().IsVerFixed())
1963 bYNeg=false;
1964 nYMul=1;
1965 nYDiv=1;
1970 Fraction aNewXFact(nXMul,nXDiv);
1971 Fraction aNewYFact(nYMul,nYDiv);
1973 if (bOrtho)
1975 if (aNewXFact>aMaxFact)
1977 aNewXFact=aMaxFact;
1978 aNewYFact=aMaxFact;
1981 if (aNewYFact>aMaxFact)
1983 aNewXFact=aMaxFact;
1984 aNewYFact=aMaxFact;
1988 if (bXNeg)
1989 aNewXFact=Fraction(-aNewXFact.GetNumerator(),aNewXFact.GetDenominator());
1991 if (bYNeg)
1992 aNewYFact=Fraction(-aNewYFact.GetNumerator(),aNewYFact.GetDenominator());
1994 if (DragStat().CheckMinMoved(aPnt))
1996 if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
1997 (!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y()))
1999 Hide();
2000 DragStat().NextMove(aPnt);
2001 aXFact=aNewXFact;
2002 aYFact=aNewYFact;
2003 Show();
2008 void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2010 rTarget.Resize(DragStat().GetRef1(),aXFact,aYFact);
2013 bool SdrDragResize::EndSdrDrag(bool bCopy)
2015 Hide();
2017 if (IsDraggingPoints())
2019 getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),aXFact,aYFact);
2021 else if (IsDraggingGluePoints())
2023 getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),aXFact,aYFact,bCopy);
2025 else
2027 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aXFact,aYFact,bCopy);
2030 return true;
2033 PointerStyle SdrDragResize::GetSdrDragPointer() const
2035 const SdrHdl* pHdl=GetDragHdl();
2037 if (pHdl!=nullptr)
2039 return pHdl->GetPointer();
2042 return PointerStyle::Move;
2046 void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2048 rTarget.Rotate(DragStat().GetRef1(), nAngle, sin(nAngle * F_PI18000), cos(nAngle * F_PI18000));
2051 SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
2052 : SdrDragMethod(rNewView),
2053 nSin(0.0),
2054 nCos(1.0),
2055 nAngle0(0),
2056 nAngle(0),
2057 bRight(false)
2061 OUString SdrDragRotate::GetSdrDragComment() const
2063 OUString aStr = ImpGetDescriptionStr(STR_DragMethRotate) +
2064 " (";
2065 sal_Int32 nTmpAngle(NormAngle36000(nAngle));
2067 if(bRight && nAngle)
2069 nTmpAngle -= 36000;
2072 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2074 if(getSdrDragView().IsDragWithCopy())
2075 aStr += SvxResId(STR_EditWithCopy);
2076 return aStr;
2079 bool SdrDragRotate::BeginSdrDrag()
2081 SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2083 if (nullptr != pH)
2085 Show();
2086 DragStat().SetRef1(pH->GetPos());
2087 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2088 return true;
2091 // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
2092 // the rotation point)
2093 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
2095 if(!aLocalMarkRect.IsEmpty())
2097 Show();
2098 DragStat().SetRef1(aLocalMarkRect.Center());
2099 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2100 return true;
2103 OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
2104 return false;
2107 basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation()
2109 return basegfx::utils::createRotateAroundPoint(
2110 DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
2111 -atan2(nSin, nCos));
2114 void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
2116 Point aPnt(rPnt_);
2117 if (!DragStat().CheckMinMoved(aPnt))
2118 return;
2120 tools::Long nNewAngle=NormAngle36000(GetAngle(aPnt-DragStat().GetRef1())-nAngle0);
2121 tools::Long nSA=0;
2123 if (getSdrDragView().IsAngleSnapEnabled())
2124 nSA=getSdrDragView().GetSnapAngle();
2126 if (!getSdrDragView().IsRotateAllowed())
2127 nSA=9000;
2129 if (nSA!=0)
2130 { // angle snapping
2131 nNewAngle+=nSA/2;
2132 nNewAngle/=nSA;
2133 nNewAngle*=nSA;
2136 nNewAngle=NormAngle18000(nNewAngle);
2138 if (nAngle==nNewAngle)
2139 return;
2141 sal_uInt16 nSekt0=GetAngleSector(nAngle);
2142 sal_uInt16 nSekt1=GetAngleSector(nNewAngle);
2144 if (nSekt0==0 && nSekt1==3)
2145 bRight=true;
2147 if (nSekt0==3 && nSekt1==0)
2148 bRight=false;
2150 nAngle=nNewAngle;
2151 double a = nAngle * F_PI18000;
2152 double nSin1=sin(a); // calculate now, so as little time as possible
2153 double nCos1=cos(a); // passes between Hide() and Show()
2154 Hide();
2155 nSin=nSin1;
2156 nCos=nCos1;
2157 DragStat().NextMove(aPnt);
2158 Show();
2161 bool SdrDragRotate::EndSdrDrag(bool bCopy)
2163 Hide();
2165 if (nAngle!=0)
2167 if (IsDraggingPoints())
2169 getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nAngle);
2171 else if (IsDraggingGluePoints())
2173 getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nAngle,bCopy);
2175 else
2177 getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nAngle,bCopy);
2180 return true;
2183 PointerStyle SdrDragRotate::GetSdrDragPointer() const
2185 return PointerStyle::Rotate;
2189 SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1)
2190 : SdrDragMethod(rNewView),
2191 aFact(1,1),
2192 nAngle0(0),
2193 nAngle(0),
2194 nTan(0.0),
2195 bVertical(false),
2196 bResize(false),
2197 bUpSideDown(false),
2198 bSlant(bSlant1)
2202 OUString SdrDragShear::GetSdrDragComment() const
2204 OUString aStr = ImpGetDescriptionStr(STR_DragMethShear) +
2205 " (";
2207 sal_Int32 nTmpAngle(nAngle);
2209 if(bUpSideDown)
2210 nTmpAngle += 18000;
2212 nTmpAngle = NormAngle18000(nTmpAngle);
2214 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2216 if(getSdrDragView().IsDragWithCopy())
2217 aStr += SvxResId(STR_EditWithCopy);
2218 return aStr;
2221 bool SdrDragShear::BeginSdrDrag()
2223 SdrHdlKind eRefHdl=SdrHdlKind::Move;
2224 SdrHdl* pRefHdl=nullptr;
2226 switch (GetDragHdlKind())
2228 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; break;
2229 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; break;
2230 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; bVertical=true; break;
2231 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; bVertical=true; break;
2232 default: break;
2235 if (eRefHdl!=SdrHdlKind::Move)
2236 pRefHdl=GetHdlList().GetHdl(eRefHdl);
2238 if (pRefHdl!=nullptr)
2240 DragStat().SetRef1(pRefHdl->GetPos());
2241 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2243 else
2245 OSL_FAIL("SdrDragShear::BeginSdrDrag(): No reference point handle for shearing found.");
2246 return false;
2249 Show();
2250 return true;
2253 basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation()
2255 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
2256 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
2258 if (bResize)
2260 if (bVertical)
2262 aRetval.scale(double(aFact), 1.0);
2263 aRetval.shearY(-nTan);
2265 else
2267 aRetval.scale(1.0, double(aFact));
2268 aRetval.shearX(-nTan);
2272 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2274 return aRetval;
2277 void SdrDragShear::MoveSdrDrag(const Point& rPnt)
2279 if (!DragStat().CheckMinMoved(rPnt))
2280 return;
2282 bResize=!getSdrDragView().IsOrtho();
2283 tools::Long nSA=0;
2285 if (getSdrDragView().IsAngleSnapEnabled())
2286 nSA=getSdrDragView().GetSnapAngle();
2288 Point aP0(DragStat().GetStart());
2289 Point aPnt(rPnt);
2290 Fraction aNewFract(1,1);
2292 // if angle snapping not activated, snap to raster (except when using slant)
2293 if (nSA==0 && !bSlant)
2294 aPnt=GetSnapPos(aPnt);
2296 if (!bSlant && !bResize)
2297 { // shear, but no resize
2298 if (bVertical)
2299 aPnt.setX(aP0.X() );
2300 else
2301 aPnt.setY(aP0.Y() );
2304 Point aRef(DragStat().GetRef1());
2305 Point aDif(aPnt-aRef);
2307 tools::Long nNewAngle=0;
2309 if (bSlant)
2311 nNewAngle=NormAngle18000(-(GetAngle(aDif)-nAngle0));
2313 if (bVertical)
2314 nNewAngle=NormAngle18000(-nNewAngle);
2316 else
2318 if (bVertical)
2319 nNewAngle=NormAngle18000(GetAngle(aDif));
2320 else
2321 nNewAngle=NormAngle18000(-(GetAngle(aDif)-9000));
2323 if (nNewAngle<-9000 || nNewAngle>9000)
2324 nNewAngle=NormAngle18000(nNewAngle+18000);
2326 if (bResize)
2328 Point aPt2(aPnt);
2330 if (nSA!=0)
2331 aPt2=GetSnapPos(aPnt); // snap this one in any case
2333 if (bVertical)
2335 aNewFract=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X());
2337 else
2339 aNewFract=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y());
2344 bool bNeg=nNewAngle<0;
2346 if (bNeg)
2347 nNewAngle=-nNewAngle;
2349 if (nSA!=0)
2350 { // angle snapping
2351 nNewAngle+=nSA/2;
2352 nNewAngle/=nSA;
2353 nNewAngle*=nSA;
2356 nNewAngle=NormAngle36000(nNewAngle);
2357 bUpSideDown=nNewAngle>9000 && nNewAngle<27000;
2359 if (bSlant)
2360 { // calculate resize for slant
2361 // when angle snapping is activated, disable 89 degree limit
2362 tools::Long nTmpAngle=nNewAngle;
2363 if (bUpSideDown) nNewAngle-=18000;
2364 if (bNeg) nTmpAngle=-nTmpAngle;
2365 bResize=true;
2366 aNewFract = cos(nTmpAngle * F_PI18000);
2367 aFact.ReduceInaccurate(10); // three decimals should be enough
2370 if (nNewAngle>8900)
2371 nNewAngle=8900;
2373 if (bNeg)
2374 nNewAngle=-nNewAngle;
2376 if (nAngle!=nNewAngle || aFact!=aNewFract)
2378 nAngle=nNewAngle;
2379 aFact=aNewFract;
2380 double a = nAngle * F_PI18000;
2381 double nTan1=tan(a); // calculate now, so as little time as possible passes between Hide() and Show()
2382 Hide();
2383 nTan=nTan1;
2384 DragStat().NextMove(rPnt);
2385 Show();
2389 void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2391 if (bResize)
2393 if (bVertical)
2395 rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1));
2397 else
2399 rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact);
2403 if (nAngle!=0)
2405 rTarget.Shear(DragStat().GetRef1(), nAngle, tan(nAngle * F_PI18000), bVertical);
2409 bool SdrDragShear::EndSdrDrag(bool bCopy)
2411 Hide();
2413 if (bResize && aFact==Fraction(1,1))
2414 bResize=false;
2416 if (nAngle!=0 || bResize)
2418 if (nAngle!=0 && bResize)
2420 OUString aStr = ImpGetDescriptionStr(STR_EditShear);
2422 if (bCopy)
2423 aStr += SvxResId(STR_EditWithCopy);
2425 getSdrDragView().BegUndo(aStr);
2428 if (bResize)
2430 if (bVertical)
2432 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy);
2434 else
2436 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy);
2439 bCopy=false;
2442 if (nAngle!=0)
2444 getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nAngle,bVertical,bCopy);
2447 if (nAngle!=0 && bResize)
2448 getSdrDragView().EndUndo();
2450 return true;
2453 return false;
2456 PointerStyle SdrDragShear::GetSdrDragPointer() const
2458 if (bVertical)
2459 return PointerStyle::VShear;
2460 else
2461 return PointerStyle::HShear;
2465 void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2467 if(bMirrored)
2469 rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2());
2473 SdrDragMirror::SdrDragMirror(SdrDragView& rNewView)
2474 : SdrDragMethod(rNewView),
2475 nAngle(0),
2476 bMirrored(false),
2477 bSide0(false)
2481 bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const
2483 tools::Long nAngle1=GetAngle(rPnt-DragStat().GetRef1());
2484 nAngle1-=nAngle;
2485 nAngle1=NormAngle36000(nAngle1);
2487 return nAngle1<18000;
2490 OUString SdrDragMirror::GetSdrDragComment() const
2492 OUString aStr;
2493 if (aDif.X()==0)
2494 aStr = ImpGetDescriptionStr(STR_DragMethMirrorHori);
2495 else if (aDif.Y()==0)
2496 aStr = ImpGetDescriptionStr(STR_DragMethMirrorVert);
2497 else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
2498 aStr = ImpGetDescriptionStr(STR_DragMethMirrorDiag);
2499 else
2500 aStr = ImpGetDescriptionStr(STR_DragMethMirrorFree);
2502 if (getSdrDragView().IsDragWithCopy())
2503 aStr+=SvxResId(STR_EditWithCopy);
2504 return aStr;
2507 bool SdrDragMirror::BeginSdrDrag()
2509 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2510 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
2512 if (pH1!=nullptr && pH2!=nullptr)
2514 DragStat().SetRef1(pH1->GetPos());
2515 DragStat().SetRef2(pH2->GetPos());
2516 Ref1()=pH1->GetPos();
2517 Ref2()=pH2->GetPos();
2518 aDif=pH2->GetPos()-pH1->GetPos();
2519 bool b90=(aDif.X()==0) || aDif.Y()==0;
2520 bool b45=b90 || (std::abs(aDif.X()) == std::abs(aDif.Y()));
2521 nAngle=NormAngle36000(GetAngle(aDif));
2523 if (!getSdrDragView().IsMirrorAllowed() && !b45)
2524 return false; // free choice of axis angle not allowed
2526 if (!getSdrDragView().IsMirrorAllowed() && !b90)
2527 return false; // 45 degrees not allowed either
2529 bSide0=ImpCheckSide(DragStat().GetStart());
2530 Show();
2531 return true;
2533 else
2535 OSL_FAIL("SdrDragMirror::BeginSdrDrag(): Axis of reflection not found.");
2536 return false;
2540 basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation()
2542 basegfx::B2DHomMatrix aRetval;
2544 if (bMirrored)
2546 const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X());
2547 const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y());
2548 const double fRotation(atan2(fDeltaY, fDeltaX));
2550 aRetval = basegfx::utils::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y());
2551 aRetval.rotate(-fRotation);
2552 aRetval.scale(1.0, -1.0);
2553 aRetval.rotate(fRotation);
2554 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2557 return aRetval;
2560 void SdrDragMirror::MoveSdrDrag(const Point& rPnt)
2562 if (!DragStat().CheckMinMoved(rPnt))
2563 return;
2565 bool bNewSide=ImpCheckSide(rPnt);
2566 bool bNewMirrored=bSide0!=bNewSide;
2568 if (bMirrored!=bNewMirrored)
2570 Hide();
2571 bMirrored=bNewMirrored;
2572 DragStat().NextMove(rPnt);
2573 Show();
2577 bool SdrDragMirror::EndSdrDrag(bool bCopy)
2579 Hide();
2581 if (bMirrored)
2583 getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy);
2586 return true;
2589 PointerStyle SdrDragMirror::GetSdrDragPointer() const
2591 return PointerStyle::Mirror;
2595 SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad)
2596 : SdrDragMethod(rNewView),
2597 pIAOHandle(nullptr),
2598 bIsGradient(bGrad)
2602 OUString SdrDragGradient::GetSdrDragComment() const
2604 if(IsGradient())
2605 return ImpGetDescriptionStr(STR_DragMethGradient);
2606 else
2607 return ImpGetDescriptionStr(STR_DragMethTransparence);
2610 bool SdrDragGradient::BeginSdrDrag()
2612 bool bRetval(false);
2614 pIAOHandle = static_cast<SdrHdlGradient*>(GetHdlList().GetHdl(IsGradient() ? SdrHdlKind::Gradient : SdrHdlKind::Transparence));
2616 if(pIAOHandle)
2618 // save old values
2619 DragStat().SetRef1( pIAOHandle->GetPos() );
2620 DragStat().SetRef2( pIAOHandle->Get2ndPos() );
2622 // what was hit?
2623 bool bHit(false);
2624 SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1();
2626 // init handling flags
2627 pIAOHandle->SetMoveSingleHandle(false);
2628 pIAOHandle->SetMoveFirstHandle(false);
2630 // test first color handle
2631 if(pColHdl)
2633 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2635 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2637 bHit = true;
2638 pIAOHandle->SetMoveSingleHandle(true);
2639 pIAOHandle->SetMoveFirstHandle(true);
2643 // test second color handle
2644 pColHdl = pIAOHandle->GetColorHdl2();
2646 if(!bHit && pColHdl)
2648 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2650 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2652 bHit = true;
2653 pIAOHandle->SetMoveSingleHandle(true);
2657 // test gradient handle itself
2658 if(!bHit)
2660 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2662 if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition))
2664 bHit = true;
2668 // everything up and running :o}
2669 bRetval = bHit;
2671 else
2673 OSL_FAIL("SdrDragGradient::BeginSdrDrag(): IAOGradient not found.");
2676 return bRetval;
2679 void SdrDragGradient::MoveSdrDrag(const Point& rPnt)
2681 if(!(pIAOHandle && DragStat().CheckMinMoved(rPnt)))
2682 return;
2684 DragStat().NextMove(rPnt);
2686 // Do the Move here!!! DragStat().GetStart()
2687 Point aMoveDiff = rPnt - DragStat().GetStart();
2689 if(pIAOHandle->IsMoveSingleHandle())
2691 if(pIAOHandle->IsMoveFirstHandle())
2693 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2694 if(pIAOHandle->GetColorHdl1())
2695 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2697 else
2699 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2700 if(pIAOHandle->GetColorHdl2())
2701 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2704 else
2706 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2707 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2709 if(pIAOHandle->GetColorHdl1())
2710 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2712 if(pIAOHandle->GetColorHdl2())
2713 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2716 // new state
2717 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), false, false);
2720 bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/)
2722 Ref1() = pIAOHandle->GetPos();
2723 Ref2() = pIAOHandle->Get2ndPos();
2725 // new state
2726 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, true);
2728 return true;
2731 void SdrDragGradient::CancelSdrDrag()
2733 // restore old values
2734 pIAOHandle->SetPos(DragStat().GetRef1());
2735 pIAOHandle->Set2ndPos(DragStat().GetRef2());
2737 if(pIAOHandle->GetColorHdl1())
2738 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1());
2740 if(pIAOHandle->GetColorHdl2())
2741 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2());
2743 // new state
2744 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, false);
2747 PointerStyle SdrDragGradient::GetSdrDragPointer() const
2749 return PointerStyle::RefHand;
2753 SdrDragCrook::SdrDragCrook(SdrDragView& rNewView)
2754 : SdrDragMethod(rNewView),
2755 aFact(1,1),
2756 bContortionAllowed(false),
2757 bNoContortionAllowed(false),
2758 bContortion(false),
2759 bResizeAllowed(false),
2760 bResize(false),
2761 bRotateAllowed(false),
2762 bRotate(false),
2763 bVertical(false),
2764 bValid(false),
2765 bLft(false),
2766 bRgt(false),
2767 bUpr(false),
2768 bLwr(false),
2769 bAtCenter(false),
2770 nAngle(0),
2771 nMarkSize(0),
2772 eMode(SdrCrookMode::Rotate)
2776 OUString SdrDragCrook::GetSdrDragComment() const
2778 OUString aStr = ImpGetDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion);
2780 if(bValid)
2782 aStr += " (";
2784 sal_Int32 nVal(nAngle);
2786 if(bAtCenter)
2787 nVal *= 2;
2789 nVal = std::abs(nVal);
2790 aStr += SdrModel::GetAngleString(nVal) + ")";
2793 if(getSdrDragView().IsDragWithCopy())
2794 aStr += SvxResId(STR_EditWithCopy);
2795 return aStr;
2798 // These defines parametrize the created raster
2799 // for interactions
2800 #define DRAG_CROOK_RASTER_MINIMUM (4)
2801 #define DRAG_CROOK_RASTER_MAXIMUM (15)
2802 #define DRAG_CROOK_RASTER_DISTANCE (30)
2804 static basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView const & rPageView, const tools::Rectangle& rMarkRect)
2806 basegfx::B2DPolyPolygon aRetval;
2808 if(rPageView.PageWindowCount())
2810 OutputDevice& rOut = rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice();
2811 tools::Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect);
2812 sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE);
2813 sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE);
2815 if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM)
2816 nHorDiv = DRAG_CROOK_RASTER_MAXIMUM;
2817 if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM)
2818 nHorDiv = DRAG_CROOK_RASTER_MINIMUM;
2820 if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM)
2821 nVerDiv = DRAG_CROOK_RASTER_MAXIMUM;
2822 if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM)
2823 nVerDiv = DRAG_CROOK_RASTER_MINIMUM;
2825 const double fXLen(rMarkRect.GetWidth() / static_cast<double>(nHorDiv));
2826 const double fYLen(rMarkRect.GetHeight() / static_cast<double>(nVerDiv));
2827 double fYPos(rMarkRect.Top());
2828 sal_uInt32 a, b;
2830 for(a = 0; a <= nVerDiv; a++)
2832 // horizontal lines
2833 for(b = 0; b < nHorDiv; b++)
2835 basegfx::B2DPolygon aHorLineSegment;
2837 const double fNewX(rMarkRect.Left() + (b * fXLen));
2838 aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos));
2839 aHorLineSegment.appendBezierSegment(
2840 basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos),
2841 basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos),
2842 basegfx::B2DPoint(fNewX + fXLen, fYPos));
2843 aRetval.append(aHorLineSegment);
2846 // increments
2847 fYPos += fYLen;
2850 double fXPos(rMarkRect.Left());
2852 for(a = 0; a <= nHorDiv; a++)
2854 // vertical lines
2855 for(b = 0; b < nVerDiv; b++)
2857 basegfx::B2DPolygon aVerLineSegment;
2859 const double fNewY(rMarkRect.Top() + (b * fYLen));
2860 aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY));
2861 aVerLineSegment.appendBezierSegment(
2862 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))),
2863 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))),
2864 basegfx::B2DPoint(fXPos, fNewY + fYLen));
2865 aRetval.append(aVerLineSegment);
2868 // increments
2869 fXPos += fXLen;
2873 return aRetval;
2876 void SdrDragCrook::createSdrDragEntries()
2878 // Add extended frame raster first, so it will be behind objects
2879 if(getSdrDragView().GetSdrPageView())
2881 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
2883 if(aDragRaster.count())
2885 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
2889 // call parent
2890 SdrDragMethod::createSdrDragEntries();
2893 bool SdrDragCrook::BeginSdrDrag()
2895 bContortionAllowed=getSdrDragView().IsCrookAllowed();
2896 bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true);
2897 bResizeAllowed=getSdrDragView().IsResizeAllowed();
2898 bRotateAllowed=getSdrDragView().IsRotateAllowed();
2900 if (bContortionAllowed || bNoContortionAllowed)
2902 bVertical=(GetDragHdlKind()==SdrHdlKind::Lower || GetDragHdlKind()==SdrHdlKind::Upper);
2903 aMarkRect=GetMarkedRect();
2904 aMarkCenter=aMarkRect.Center();
2905 nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1);
2906 aCenter=aMarkCenter;
2907 aStart=DragStat().GetStart();
2908 Show();
2909 return true;
2911 else
2913 return false;
2917 void SdrDragCrook::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
2919 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
2921 if(!pPV)
2922 return;
2924 XPolyPolygon aTempPolyPoly(rTarget);
2926 if (pPV->HasMarkedObjPageView())
2928 sal_uInt16 nPolyCount=aTempPolyPoly.Count();
2930 if (!bContortion && !getSdrDragView().IsNoDragXorPolys())
2932 sal_uInt16 n1st=0,nLast=0;
2933 Point aC(aCenter);
2935 while (n1st<nPolyCount)
2937 nLast=n1st;
2938 while (nLast<nPolyCount && aTempPolyPoly[nLast].GetPointCount()!=0) nLast++;
2939 tools::Rectangle aBound(aTempPolyPoly[n1st].GetBoundRect());
2940 sal_uInt16 i;
2942 for (i=n1st+1; i<nLast; i++)
2944 aBound.Union(aTempPolyPoly[n1st].GetBoundRect());
2947 Point aCtr0(aBound.Center());
2948 Point aCtr1(aCtr0);
2950 if (bResize)
2952 Fraction aFact1(1,1);
2954 if (bVertical)
2956 ResizePoint(aCtr1,aC,aFact1,aFact);
2958 else
2960 ResizePoint(aCtr1,aC,aFact,aFact1);
2964 bool bRotOk=false;
2965 double nSin=0,nCos=0;
2967 if (aRad.X()!=0 && aRad.Y()!=0)
2969 bRotOk=bRotate;
2971 switch (eMode)
2973 case SdrCrookMode::Rotate : CrookRotateXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2974 case SdrCrookMode::Slant : CrookSlantXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2975 case SdrCrookMode::Stretch: CrookStretchXPoint(aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical,aMarkRect); break;
2976 } // switch
2979 aCtr1-=aCtr0;
2981 for (i=n1st; i<nLast; i++)
2983 if (bRotOk)
2985 RotateXPoly(aTempPolyPoly[i],aCtr0,nSin,nCos);
2988 aTempPolyPoly[i].Move(aCtr1.X(),aCtr1.Y());
2991 n1st=nLast+1;
2994 else
2996 sal_uInt16 i,j;
2998 for (j=0; j<nPolyCount; j++)
3000 XPolygon& aPol=aTempPolyPoly[j];
3001 sal_uInt16 nPointCount=aPol.GetPointCount();
3002 i=0;
3004 while (i<nPointCount)
3006 Point* pPnt=&aPol[i];
3007 Point* pC1=nullptr;
3008 Point* pC2=nullptr;
3010 if (i+1<nPointCount && aPol.IsControl(i))
3011 { // control point on the left
3012 pC1=pPnt;
3013 i++;
3014 pPnt=&aPol[i];
3017 i++;
3019 if (i<nPointCount && aPol.IsControl(i))
3020 { // control point on the right
3021 pC2=&aPol[i];
3022 i++;
3025 MovCrookPoint(*pPnt,pC1,pC2);
3031 rTarget = aTempPolyPoly.getB2DPolyPolygon();
3034 void SdrDragCrook::MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2)
3036 bool bVert=bVertical;
3037 bool bC1=pC1!=nullptr;
3038 bool bC2=pC2!=nullptr;
3039 Point aC(aCenter);
3041 if (bResize)
3043 Fraction aFact1(1,1);
3045 if (bVert)
3047 ResizePoint(rPnt,aC,aFact1,aFact);
3049 if (bC1)
3050 ResizePoint(*pC1,aC,aFact1,aFact);
3052 if (bC2)
3053 ResizePoint(*pC2,aC,aFact1,aFact);
3055 else
3057 ResizePoint(rPnt,aC,aFact,aFact1);
3059 if (bC1)
3060 ResizePoint(*pC1,aC,aFact,aFact1);
3062 if (bC2)
3063 ResizePoint(*pC2,aC,aFact,aFact1);
3067 if (aRad.X()!=0 && aRad.Y()!=0)
3069 double nSin,nCos;
3071 switch (eMode)
3073 case SdrCrookMode::Rotate : CrookRotateXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3074 case SdrCrookMode::Slant : CrookSlantXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3075 case SdrCrookMode::Stretch: CrookStretchXPoint(rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert,aMarkRect); break;
3076 } // switch
3080 void SdrDragCrook::MoveSdrDrag(const Point& rPnt)
3082 if (!DragStat().CheckMinMoved(rPnt))
3083 return;
3085 bool bNewMoveOnly=getSdrDragView().IsMoveOnlyDragging();
3086 bAtCenter=false;
3087 SdrCrookMode eNewMode=getSdrDragView().GetCrookMode();
3088 bool bNewContortion=!bNewMoveOnly && ((bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed);
3089 bResize=!getSdrDragView().IsOrtho() && bResizeAllowed && !bNewMoveOnly;
3090 bool bNewRotate=bRotateAllowed && !bNewContortion && !bNewMoveOnly && eNewMode==SdrCrookMode::Rotate;
3092 Point aPnt(GetSnapPos(rPnt));
3094 Point aNewCenter(aMarkCenter.X(),aStart.Y());
3096 if (bVertical)
3098 aNewCenter.setX(aStart.X() );
3099 aNewCenter.setY(aMarkCenter.Y() );
3102 if (!getSdrDragView().IsCrookAtCenter())
3104 switch (GetDragHdlKind())
3106 case SdrHdlKind::UpperLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3107 case SdrHdlKind::Upper: aNewCenter.setY(aMarkRect.Bottom() ); bUpr=true; break;
3108 case SdrHdlKind::UpperRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3109 case SdrHdlKind::Left : aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3110 case SdrHdlKind::Right: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3111 case SdrHdlKind::LowerLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3112 case SdrHdlKind::Lower: aNewCenter.setY(aMarkRect.Top() ); bLwr=true; break;
3113 case SdrHdlKind::LowerRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3114 default: bAtCenter=true;
3117 else
3118 bAtCenter=true;
3120 Fraction aNewFract(1,1);
3121 tools::Long dx1=aPnt.X()-aNewCenter.X();
3122 tools::Long dy1=aPnt.Y()-aNewCenter.Y();
3123 bValid=bVertical ? dx1!=0 : dy1!=0;
3125 if (bValid)
3127 if (bVertical)
3128 bValid = std::abs(dx1)*100>std::abs(dy1);
3129 else
3130 bValid = std::abs(dy1)*100>std::abs(dx1);
3133 tools::Long nNewRad=0;
3134 nAngle=0;
3136 if (bValid)
3138 double a=0; // slope of the radius
3139 tools::Long nPntWink=0;
3141 if (bVertical)
3143 a=static_cast<double>(dy1)/static_cast<double>(dx1); // slope of the radius
3144 nNewRad=(static_cast<tools::Long>(dy1*a)+dx1) /2;
3145 aNewCenter.AdjustX(nNewRad );
3146 nPntWink=GetAngle(aPnt-aNewCenter);
3148 else
3150 a=static_cast<double>(dx1)/static_cast<double>(dy1); // slope of the radius
3151 nNewRad=(static_cast<tools::Long>(dx1*a)+dy1) /2;
3152 aNewCenter.AdjustY(nNewRad );
3153 nPntWink=GetAngle(aPnt-aNewCenter)-9000;
3156 if (!bAtCenter)
3158 if (nNewRad<0)
3160 if (bRgt) nPntWink+=18000;
3161 if (bLft) nPntWink=18000-nPntWink;
3162 if (bLwr) nPntWink=-nPntWink;
3164 else
3166 if (bRgt) nPntWink=-nPntWink;
3167 if (bUpr) nPntWink=18000-nPntWink;
3168 if (bLwr) nPntWink+=18000;
3171 nPntWink=NormAngle36000(nPntWink);
3173 else
3175 if (nNewRad<0) nPntWink+=18000;
3176 if (bVertical) nPntWink=18000-nPntWink;
3177 nPntWink=NormAngle18000(nPntWink);
3178 nPntWink = std::abs(nPntWink);
3181 double nUmfang = 2 * std::abs(nNewRad) * M_PI;
3183 if (bResize)
3185 tools::Long nMul=static_cast<tools::Long>(nUmfang*NormAngle36000(nPntWink)/36000);
3187 if (bAtCenter)
3188 nMul*=2;
3190 aNewFract=Fraction(nMul,nMarkSize);
3191 nAngle=nPntWink;
3193 else
3195 nAngle=static_cast<tools::Long>((nMarkSize*360/nUmfang)*100)/2;
3197 if (nAngle==0)
3198 bValid=false;
3202 if (nAngle==0 || nNewRad==0)
3203 bValid=false;
3205 if (!bValid)
3206 nNewRad=0;
3208 if (!bValid && bResize)
3210 tools::Long nMul=bVertical ? dy1 : dx1;
3212 if (bLft || bUpr)
3213 nMul=-nMul;
3215 tools::Long nDiv=nMarkSize;
3217 if (bAtCenter)
3219 nMul*=2;
3220 nMul = std::abs(nMul);
3223 aNewFract=Fraction(nMul,nDiv);
3226 if (aNewCenter==aCenter && bNewContortion==bContortion && aNewFract==aFact &&
3227 bNewMoveOnly == getMoveOnly() && bNewRotate==bRotate && eNewMode==eMode)
3228 return;
3230 Hide();
3231 setMoveOnly(bNewMoveOnly);
3232 bRotate=bNewRotate;
3233 eMode=eNewMode;
3234 bContortion=bNewContortion;
3235 aCenter=aNewCenter;
3236 aFact=aNewFract;
3237 aRad=Point(nNewRad,nNewRad);
3238 bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid();
3239 DragStat().NextMove(aPnt);
3240 Show();
3243 void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3245 const bool bDoResize(aFact!=Fraction(1,1));
3246 const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0);
3248 if (!(bDoCrook || bDoResize))
3249 return;
3251 if (bDoResize)
3253 Fraction aFact1(1,1);
3255 if (bContortion)
3257 if (bVertical)
3259 rTarget.Resize(aCenter,aFact1,aFact);
3261 else
3263 rTarget.Resize(aCenter,aFact,aFact1);
3266 else
3268 Point aCtr0(rTarget.GetSnapRect().Center());
3269 Point aCtr1(aCtr0);
3271 if (bVertical)
3273 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3275 else
3277 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3280 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3282 rTarget.Move(aSiz);
3286 if (bDoCrook)
3288 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
3289 const bool bLocalRotate(!bContortion && eMode == SdrCrookMode::Rotate && getSdrDragView().IsRotateAllowed());
3291 SdrEditView::ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect);
3295 void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3297 // use helper derived from old stuff
3298 MovAllPoints(rTarget);
3301 bool SdrDragCrook::EndSdrDrag(bool bCopy)
3303 Hide();
3305 if (bResize && aFact==Fraction(1,1))
3306 bResize=false;
3308 const bool bUndo = getSdrDragView().IsUndoEnabled();
3310 bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0;
3312 if (bDoCrook || bResize)
3314 if (bResize && bUndo)
3316 OUString aStr = ImpGetDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion);
3318 if (bCopy)
3319 aStr += SvxResId(STR_EditWithCopy);
3321 getSdrDragView().BegUndo(aStr);
3324 if (bResize)
3326 Fraction aFact1(1,1);
3328 if (bContortion)
3330 if (bVertical)
3331 getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy);
3332 else
3333 getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy);
3335 else
3337 if (bCopy)
3338 getSdrDragView().CopyMarkedObj();
3340 const size_t nMarkCount=getSdrDragView().GetMarkedObjectList().GetMarkCount();
3342 for (size_t nm=0; nm<nMarkCount; ++nm)
3344 SdrMark* pM=getSdrDragView().GetMarkedObjectList().GetMark(nm);
3345 SdrObject* pO=pM->GetMarkedSdrObj();
3346 Point aCtr0(pO->GetSnapRect().Center());
3347 Point aCtr1(aCtr0);
3349 if (bVertical)
3350 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3351 else
3352 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3354 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3355 if( bUndo )
3356 AddUndo(getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz));
3357 pO->Move(aSiz);
3361 bCopy=false;
3364 if (bDoCrook)
3366 getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy);
3369 if (bResize && bUndo)
3370 getSdrDragView().EndUndo();
3372 return true;
3375 return false;
3378 PointerStyle SdrDragCrook::GetSdrDragPointer() const
3380 return PointerStyle::Crook;
3384 SdrDragDistort::SdrDragDistort(SdrDragView& rNewView)
3385 : SdrDragMethod(rNewView),
3386 nPolyPt(0),
3387 bContortionAllowed(false),
3388 bNoContortionAllowed(false),
3389 bContortion(false)
3393 OUString SdrDragDistort::GetSdrDragComment() const
3395 OUString aStr = ImpGetDescriptionStr(STR_DragMethDistort)
3396 + " (x="
3397 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
3398 + " y="
3399 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
3400 + ")";
3402 if(getSdrDragView().IsDragWithCopy())
3403 aStr += SvxResId(STR_EditWithCopy);
3404 return aStr;
3407 void SdrDragDistort::createSdrDragEntries()
3409 // Add extended frame raster first, so it will be behind objects
3410 if(getSdrDragView().GetSdrPageView())
3412 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
3414 if(aDragRaster.count())
3416 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
3420 // call parent
3421 SdrDragMethod::createSdrDragEntries();
3424 bool SdrDragDistort::BeginSdrDrag()
3426 bContortionAllowed=getSdrDragView().IsDistortAllowed();
3427 bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true);
3429 if (bContortionAllowed || bNoContortionAllowed)
3431 SdrHdlKind eKind=GetDragHdlKind();
3432 nPolyPt=0xFFFF;
3434 if (eKind==SdrHdlKind::UpperLeft) nPolyPt=0;
3435 if (eKind==SdrHdlKind::UpperRight) nPolyPt=1;
3436 if (eKind==SdrHdlKind::LowerRight) nPolyPt=2;
3437 if (eKind==SdrHdlKind::LowerLeft) nPolyPt=3;
3438 if (nPolyPt>3) return false;
3440 aMarkRect=GetMarkedRect();
3441 aDistortedRect=XPolygon(aMarkRect);
3442 Show();
3443 return true;
3445 else
3447 return false;
3451 void SdrDragDistort::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
3453 if (!bContortion)
3454 return;
3456 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
3458 if(pPV && pPV->HasMarkedObjPageView())
3460 basegfx::B2DPolyPolygon aDragPolygon(rTarget);
3461 const basegfx::B2DRange aOriginalRange = vcl::unotools::b2DRectangleFromRectangle(aMarkRect);
3462 const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y());
3463 const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y());
3464 const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y());
3465 const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y());
3467 aDragPolygon = basegfx::utils::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight);
3468 rTarget = aDragPolygon;
3472 void SdrDragDistort::MoveSdrDrag(const Point& rPnt)
3474 if (!DragStat().CheckMinMoved(rPnt))
3475 return;
3477 Point aPnt(GetSnapPos(rPnt));
3479 if (getSdrDragView().IsOrtho())
3480 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
3482 bool bNewContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed;
3484 if (bNewContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt)
3486 Hide();
3487 aDistortedRect[nPolyPt]=aPnt;
3488 bContortion=bNewContortion;
3489 DragStat().NextMove(aPnt);
3490 Show();
3494 bool SdrDragDistort::EndSdrDrag(bool bCopy)
3496 Hide();
3497 bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0;
3499 if (bDoDistort)
3501 getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy);
3502 return true;
3505 return false;
3508 PointerStyle SdrDragDistort::GetSdrDragPointer() const
3510 return PointerStyle::RefHand;
3513 void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3515 const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0);
3517 if (bDoDistort)
3519 SdrEditView::ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion);
3523 void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3525 // use helper derived from old stuff
3526 MovAllPoints(rTarget);
3530 SdrDragCrop::SdrDragCrop(SdrDragView& rNewView)
3531 : SdrDragObjOwn(rNewView)
3533 // switch off solid dragging for crop; it just makes no sense since showing
3534 // a 50% transparent object above the original will not be visible
3535 setSolidDraggingActive(false);
3538 OUString SdrDragCrop::GetSdrDragComment() const
3540 OUString aStr = ImpGetDescriptionStr(STR_DragMethCrop)
3541 + " (x="
3542 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDX())
3543 + " y="
3544 + getSdrDragView().GetModel()->GetMetricString(DragStat().GetDY())
3545 + ")";
3547 if(getSdrDragView().IsDragWithCopy())
3548 aStr += SvxResId(STR_EditWithCopy);
3549 return aStr;
3552 bool SdrDragCrop::BeginSdrDrag()
3554 // call parent
3555 bool bRetval(SdrDragObjOwn::BeginSdrDrag());
3557 if(!GetDragHdl())
3559 // we need the DragHdl, break if not there
3560 bRetval = false;
3563 return bRetval;
3566 bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
3568 Hide();
3570 if(0 == DragStat().GetDX() && 0 == DragStat().GetDY())
3572 // no change, done
3573 return false;
3576 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
3578 if(1 != rMarkList.GetMarkCount())
3580 // Crop only with single Object selected
3581 return false;
3584 // prepare for SdrGrafObj or others. This code has to work with usual
3585 // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from
3586 // Writer. It would be better to handle this in Writer directly, but
3587 // there are currently no easy mechanisms to plug an alternative interaction
3588 // from there
3589 SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
3590 SdrObjectUniquePtr pFullDragClone;
3591 bool bExternal(false);
3592 SdrObject* pExternalSdrObject(nullptr);
3594 // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now
3595 // locally, no two-in-one methods any more
3596 if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr)
3598 // If Writer, get the already offered for interaction SdrGrafObj
3599 // and set up for using that replacement object that contains the
3600 // real transformation. That SdrObject is owned and has to be deleted,
3601 // so use a std::unique_ptr with special handling for the protected
3602 // SDrObject destructor
3603 pFullDragClone = pSdrObject->getFullDragClone();
3605 if(dynamic_cast< SdrGrafObj* >(pFullDragClone.get()))
3607 bExternal = true;
3608 pExternalSdrObject = pSdrObject;
3609 pSdrObject = pFullDragClone.get();
3613 // get and check for SdrGrafObj now
3614 SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject );
3616 if(!pObj)
3618 return false;
3621 // no undo for external needed, done there
3622 const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled());
3624 if(bUndo)
3626 OUString aUndoStr = ImpGetDescriptionStr(STR_DragMethCrop);
3628 getSdrDragView().BegUndo( aUndoStr );
3629 getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
3630 // also need attr undo, the SdrGrafCropItem will be changed
3631 getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
3634 // get the original objects transformation
3635 basegfx::B2DHomMatrix aOriginalMatrix;
3636 basegfx::B2DPolyPolygon aPolyPolygon;
3637 bool bShearCorrected(false);
3638 pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
3640 { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
3641 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix);
3643 if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX()))
3645 bShearCorrected = true;
3646 aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3647 aTmpDecomp.getScale(),
3648 -aTmpDecomp.getShearX(),
3649 aTmpDecomp.getRotate(),
3650 aTmpDecomp.getTranslate());
3654 // generate start point of original drag vector in unit coordinates (the
3655 // vis-a-vis of the drag point)
3656 basegfx::B2DPoint aLocalStart(0.0, 0.0);
3657 bool bOnAxis(false);
3659 switch(GetDragHdlKind())
3661 case SdrHdlKind::UpperLeft: aLocalStart.setX(1.0); aLocalStart.setY(1.0); break;
3662 case SdrHdlKind::Upper: aLocalStart.setX(0.5); aLocalStart.setY(1.0); bOnAxis = true; break;
3663 case SdrHdlKind::UpperRight: aLocalStart.setX(0.0); aLocalStart.setY(1.0); break;
3664 case SdrHdlKind::Left : aLocalStart.setX(1.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3665 case SdrHdlKind::Right: aLocalStart.setX(0.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3666 case SdrHdlKind::LowerLeft: aLocalStart.setX(1.0); aLocalStart.setY(0.0); break;
3667 case SdrHdlKind::Lower: aLocalStart.setX(0.5); aLocalStart.setY(0.0); bOnAxis = true; break;
3668 case SdrHdlKind::LowerRight: aLocalStart.setX(0.0); aLocalStart.setY(0.0); break;
3669 default: break;
3672 // create the current drag position in unit coordinates. To get there,
3673 // transform back the DragPoint to UnitCoordinates
3674 basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
3675 aInverse.invert();
3676 basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y()));
3678 // if one of the edge handles is used, limit to X or Y drag only
3679 if(bOnAxis)
3681 if(basegfx::fTools::equal(aLocalStart.getX(), 0.5))
3683 aLocalCurrent.setX(aLocalStart.getX());
3685 else
3687 aLocalCurrent.setY(aLocalStart.getY());
3691 // create internal change in unit coordinates
3692 basegfx::B2DHomMatrix aDiscreteChangeMatrix;
3694 if(!basegfx::fTools::equal(aLocalCurrent.getX(), aLocalStart.getX()))
3696 if(aLocalStart.getX() < 0.5)
3698 aDiscreteChangeMatrix.scale(aLocalCurrent.getX(), 1.0);
3700 else
3702 aDiscreteChangeMatrix.scale(1.0 - aLocalCurrent.getX(), 1.0);
3703 aDiscreteChangeMatrix.translate(aLocalCurrent.getX(), 0.0);
3707 if(!basegfx::fTools::equal(aLocalCurrent.getY(), aLocalStart.getY()))
3709 if(aLocalStart.getY() < 0.5)
3711 aDiscreteChangeMatrix.scale(1.0, aLocalCurrent.getY());
3713 else
3715 aDiscreteChangeMatrix.scale(1.0, 1.0 - aLocalCurrent.getY());
3716 aDiscreteChangeMatrix.translate(0.0, aLocalCurrent.getY());
3720 // We now have the whole executed Crop in UnitCoordinates in
3721 // aDiscreteChangeMatrix, go to concrete sizes now.
3722 // Create the unrotated original rectangle and the unrotated modified
3723 // rectangle as Ranges
3724 const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix);
3726 // prepare unsheared/unrotated versions of the old and new transformation
3727 const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
3728 basegfx::utils::createScaleTranslateB2DHomMatrix(
3729 basegfx::absolute(aOriginalMatrixDecomp.getScale()),
3730 aOriginalMatrixDecomp.getTranslate()));
3732 // create the ranges for these
3733 basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3734 basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3735 aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate);
3736 aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix);
3738 if(bExternal)
3740 // With aLocalStart point (opposed to dragged point), X scale and Y scale,
3741 // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
3742 // crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
3743 // the called instance knows best how to use it
3744 const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
3745 const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
3747 pExternalSdrObject->Crop(
3748 aLocalStart,
3749 fScaleX,
3750 fScaleY);
3752 else
3754 // prepare matrix to apply to object; evtl. back-correct shear
3755 basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
3757 if(bShearCorrected)
3759 // back-correct shear
3760 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix);
3762 aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3763 aTmpDecomp.getScale(),
3764 -aTmpDecomp.getShearX(),
3765 aTmpDecomp.getRotate(),
3766 aTmpDecomp.getTranslate());
3769 // apply change to object by applying the unit coordinate change followed
3770 // by the original change
3771 pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
3773 // extract the old Rectangle structures
3774 tools::Rectangle aOldRect(
3775 basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()),
3776 basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()),
3777 basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()),
3778 basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY()));
3779 tools::Rectangle aNewRect(
3780 basegfx::fround(aRangeNewNoShearNoRotate.getMinX()),
3781 basegfx::fround(aRangeNewNoShearNoRotate.getMinY()),
3782 basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()),
3783 basegfx::fround(aRangeNewNoShearNoRotate.getMaxY()));
3785 // continue with the old original stuff
3786 if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
3788 throw o3tl::divide_by_zero();
3791 if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default))
3793 return false;
3796 const GraphicObject& rGraphicObject(pObj->GetGraphicObject());
3797 // tdf#117145 Usually Writer will go the bExternal path (see above), but more correct for
3798 // the future is to use the MapMode from the SdrModel/SfxItemPool if the Writer's current
3799 // special handling should be unified to this path in the future. Usually it *should* be
3800 // MapUnit::Map100thMM, but better do not mix up Units.
3801 // Checked now what SwVirtFlyDrawObj::NbcCrop is doing - it calculates everything forced
3802 // to MapUnit::Map100thMM, but extracts/packs Twips to the used SdrGrafCropItem in Writer.
3803 const MapMode aMapModePool(pObj->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
3804 Size aGraphicSize(rGraphicObject.GetPrefSize());
3806 if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit())
3808 aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapModePool);
3810 else
3812 aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapModePool);
3815 if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height())
3817 return false;
3820 const SdrGrafCropItem& rOldCrop = pObj->GetMergedItem(SDRATTR_GRAFCROP);
3821 double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / static_cast<double>(aOldRect.GetWidth());
3822 double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / static_cast<double>(aOldRect.GetHeight());
3824 sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
3825 sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
3826 sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
3827 sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
3829 if(pObj->IsMirrored())
3831 // mirrored X or Y, for old stuff, exchange X
3832 // check for aw080
3833 sal_Int32 nTmp(nDiffLeft);
3834 nDiffLeft = -nDiffRight;
3835 nDiffRight = -nTmp;
3838 sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
3839 sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
3840 sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
3841 sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
3843 SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool();
3844 SfxItemSet aSet( rPool, svl::Items<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP>{} );
3845 aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
3846 getSdrDragView().SetAttributes( aSet, false );
3849 if(bUndo)
3851 getSdrDragView().EndUndo();
3854 return true;
3857 PointerStyle SdrDragCrop::GetSdrDragPointer() const
3859 return PointerStyle::Crop;
3862 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */