sc: factor out common code
[LibreOffice.git] / svx / source / svdraw / svddrgmt.cxx
blob80b3b0bf6b3ba8f90808432f3baa306ec15946ac
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 <osl/diagnose.h>
25 #include <utility>
26 #include <vcl/canvastools.hxx>
27 #include <vcl/svapp.hxx>
28 #include <vcl/settings.hxx>
29 #include <vcl/ptrstyle.hxx>
30 #include <svx/xpoly.hxx>
31 #include <svx/svdtrans.hxx>
32 #include <svx/svdundo.hxx>
33 #include <svx/svdmark.hxx>
34 #include <svx/svdpagv.hxx>
35 #include <svx/svddrgv.hxx>
36 #include <svx/svdograf.hxx>
37 #include <svx/strings.hrc>
38 #include <svx/dialmgr.hxx>
39 #include <svx/sdgcpitm.hxx>
40 #include <svx/sdooitm.hxx>
41 #include <svx/sdtagitm.hxx>
42 #include <basegfx/polygon/b2dpolygon.hxx>
43 #include <basegfx/polygon/b2dpolygontools.hxx>
44 #include <svx/sdr/overlay/overlaymanager.hxx>
45 #include <sdr/overlay/overlayrollingrectangle.hxx>
46 #include <svx/sdrpagewindow.hxx>
47 #include <svx/sdrpaintwindow.hxx>
48 #include <basegfx/matrix/b2dhommatrix.hxx>
49 #include <basegfx/polygon/b2dpolypolygontools.hxx>
50 #include <svx/sdr/contact/viewcontact.hxx>
51 #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
52 #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
53 #include <svx/sdr/contact/objectcontact.hxx>
54 #include <svx/svditer.hxx>
55 #include <svx/svdopath.hxx>
56 #include <svx/polypolygoneditor.hxx>
57 #include <drawinglayer/primitive2d/PolygonMarkerPrimitive2D.hxx>
58 #include <drawinglayer/primitive2d/PolyPolygonSelectionPrimitive2D.hxx>
59 #include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
60 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
61 #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
62 #include <sdr/primitive2d/sdrattributecreator.hxx>
63 #include <sdr/primitive2d/sdrdecompositiontools.hxx>
64 #include <sdr/primitive2d/sdrprimitivetools.hxx>
65 #include <basegfx/matrix/b2dhommatrixtools.hxx>
66 #include <drawinglayer/attribute/sdrlineattribute.hxx>
67 #include <drawinglayer/attribute/sdrlinestartendattribute.hxx>
68 #include <svl/itempool.hxx>
69 #include <svtools/optionsdrawinglayer.hxx>
70 #include <officecfg/Office/Common.hxx>
71 #include <comphelper/lok.hxx>
72 #include <map>
73 #include <vector>
76 SdrDragEntry::SdrDragEntry()
77 : mbAddToTransparent(false)
81 SdrDragEntry::~SdrDragEntry()
86 SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(basegfx::B2DPolyPolygon aOriginalPolyPolygon)
87 : maOriginalPolyPolygon(std::move(aOriginalPolyPolygon))
91 SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
95 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool IsDragSizeValid)
97 drawinglayer::primitive2d::Primitive2DContainer aRetval;
99 if(maOriginalPolyPolygon.count())
101 basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);
103 rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
104 basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
105 basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
106 const double fStripeLength(officecfg::Office::Common::Drawinglayer::StripeLength::get());
108 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
110 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
111 aColB.invert();
114 aRetval.resize(2);
115 aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
116 aCopy,
117 aColA,
118 aColB,
119 fStripeLength);
121 basegfx::BColor aHilightColor;
122 if (IsDragSizeValid)
123 aHilightColor = SvtOptionsDrawinglayer::getHilightColor().getBColor();
124 else
125 aHilightColor = basegfx::BColor(1.0, 0, 0);
127 const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
128 aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
129 std::move(aCopy),
130 aHilightColor,
131 fTransparence,
132 3.0,
133 false);
136 return aRetval;
140 SdrDragEntrySdrObject::SdrDragEntrySdrObject(
141 const SdrObject& rOriginal,
142 bool bModify)
143 : maOriginal(rOriginal),
144 mbModify(bModify)
146 // add SdrObject parts to transparent overlay stuff
147 setAddToTransparent(true);
150 SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
154 void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
156 // for the moment, i need to re-create the clone in all cases. I need to figure
157 // out when clone and original have the same class, so that i can use operator=
158 // in those cases
160 mxClone.clear();
162 if(mbModify)
164 mxClone = maOriginal.getFullDragClone();
166 // apply original transformation, implemented at the DragMethods
167 rDragMethod.applyCurrentTransformationToSdrObject(*mxClone);
171 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod&, bool /* IsDragSizeValid */)
173 const SdrObject* pSource = &maOriginal;
175 if(mbModify && mxClone)
177 // choose source for geometry data
178 pSource = mxClone.get();
181 // use the view-independent primitive representation (without
182 // evtl. GridOffset, that may be applied to the DragEntry individually)
183 drawinglayer::primitive2d::Primitive2DContainer xRetval;
184 pSource->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
185 return xRetval;
189 SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
190 drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
191 : maPrimitive2DSequence(std::move(rSequence))
193 // add parts to transparent overlay stuff if necessary
194 setAddToTransparent(true);
197 SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
201 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool /* IsDragSizeValid */)
203 return drawinglayer::primitive2d::Primitive2DContainer {
204 new drawinglayer::primitive2d::TransformPrimitive2D(
205 rDragMethod.getCurrentTransformation(),
206 drawinglayer::primitive2d::Primitive2DContainer(maPrimitive2DSequence))
210 SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(std::vector< basegfx::B2DPoint >&& rPositions, bool bIsPointDrag)
211 : maPositions(std::move(rPositions)),
212 mbIsPointDrag(bIsPointDrag)
214 // add SdrObject parts to transparent overlay stuff
215 setAddToTransparent(true);
218 SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
222 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod, bool /* IsDragSizeValid */)
224 drawinglayer::primitive2d::Primitive2DContainer aRetval;
226 if(!maPositions.empty())
228 basegfx::B2DPolygon aPolygon;
230 for(auto const & a: maPositions)
232 aPolygon.append(a);
235 basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);
237 rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);
239 const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
240 std::vector< basegfx::B2DPoint > aTransformedPositions;
242 aTransformedPositions.reserve(aTransformed.count());
244 for(sal_uInt32 a = 0; a < aTransformed.count(); a++)
246 aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
249 if(mbIsPointDrag)
251 basegfx::BColor aColor(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
253 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
255 aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
258 aRetval = drawinglayer::primitive2d::Primitive2DContainer {
259 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
260 drawinglayer::primitive2d::createDefaultCross_3x3(aColor))
263 else
265 aRetval = drawinglayer::primitive2d::Primitive2DContainer {
266 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
267 SdrHdl::createGluePointBitmap())
272 return aRetval;
276 void SdrDragMethod::resetSdrDragEntries()
278 // clear entries; creation is on demand
279 clearSdrDragEntries();
282 basegfx::B2DRange SdrDragMethod::getCurrentRange() const
284 return maOverlayObjectList.getBaseRange();
287 void SdrDragMethod::clearSdrDragEntries()
289 maSdrDragEntries.clear();
292 void SdrDragMethod::addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew)
294 assert(pNew);
295 maSdrDragEntries.push_back(std::move(pNew));
298 void SdrDragMethod::createSdrDragEntries()
300 if(!(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView()))
301 return;
303 if(getSdrDragView().IsDraggingPoints())
305 createSdrDragEntries_PointDrag();
307 else if(getSdrDragView().IsDraggingGluePoints())
309 createSdrDragEntries_GlueDrag();
311 else
313 if(getSolidDraggingActive())
315 createSdrDragEntries_SolidDrag();
317 else
319 createSdrDragEntries_PolygonDrag();
324 void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
326 // add full object drag; Clone() at the object has to work
327 // for this
328 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
331 void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
332 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
333 const sdr::contact::ObjectContact& rObjectContact,
334 sdr::overlay::OverlayManager& rOverlayManager)
336 // check if we have an OverlayObject
337 if(!pOverlayObject)
339 return;
342 // add to OverlayManager
343 rOverlayManager.add(*pOverlayObject);
345 // Add GridOffset for non-linear ViewToDevice transformation (calc)
346 if(rObjectContact.supportsGridOffsets())
348 const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());
350 if(!rNewRange.isEmpty())
352 basegfx::B2DVector aOffset(0.0, 0.0);
353 rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);
355 if(!aOffset.equalZero())
357 pOverlayObject->setOffset(aOffset);
362 // add to local OverlayObjectList - ownership change (!)
363 maOverlayObjectList.append(std::move(pOverlayObject));
366 void SdrDragMethod::createSdrDragEntries_SolidDrag()
368 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
369 const size_t nMarkCount(rMarkList.GetMarkCount());
370 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
372 if(!pPV)
373 return;
375 for(size_t a = 0; a < nMarkCount; ++a)
377 SdrMark* pM = rMarkList.GetMark(a);
379 if(pM->GetPageView() == pPV)
381 const SdrObject* pObject = pM->GetMarkedSdrObj();
383 if(pObject)
385 if(pPV->PageWindowCount())
387 SdrObjListIter aIter(*pObject);
389 while(aIter.IsMore())
391 SdrObject* pCandidate = aIter.Next();
393 if(pCandidate)
395 const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
396 bool bAddWireframe(bSuppressFullDrag);
398 if(!bAddWireframe && !pCandidate->HasLineStyle())
400 // add wireframe for objects without outline
401 bAddWireframe = true;
404 if(!bSuppressFullDrag)
406 // add full object drag; Clone() at the object has to work
407 // for this
408 createSdrDragEntryForSdrObject(*pCandidate);
411 if(bAddWireframe)
413 // when dragging a 50% transparent copy of a filled or not filled object without
414 // outline, this is normally hard to see. Add extra wireframe in that case. This
415 // works nice e.g. with text frames etc.
416 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly())));
426 void SdrDragMethod::createSdrDragEntries_PolygonDrag()
428 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
429 const size_t nMarkCount(rMarkList.GetMarkCount());
430 bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkCount > SdrDragView::GetDragXorPolyLimit());
431 basegfx::B2DPolyPolygon aResult;
432 sal_uInt32 nPointCount(0);
434 for(size_t a = 0; !bNoPolygons && a < nMarkCount; ++a)
436 SdrMark* pM = rMarkList.GetMark(a);
438 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
440 const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());
442 for(auto const& rPolygon : aNewPolyPolygon)
444 nPointCount += rPolygon.count();
447 if(nPointCount > SdrDragView::GetDragXorPointLimit())
449 bNoPolygons = true;
452 if(!bNoPolygons)
454 aResult.append(aNewPolyPolygon);
459 if(bNoPolygons)
461 const tools::Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
462 const basegfx::B2DRange aNewRectangle = vcl::unotools::b2DRectangleFromRectangle(aR);
463 basegfx::B2DPolygon aNewPolygon(basegfx::utils::createPolygonFromRect(aNewRectangle));
465 aResult = basegfx::B2DPolyPolygon(basegfx::utils::expandToCurve(aNewPolygon));
468 if(aResult.count())
470 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aResult))));
474 void SdrDragMethod::createSdrDragEntries_PointDrag()
476 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
477 const size_t nMarkCount(rMarkList.GetMarkCount());
478 std::vector< basegfx::B2DPoint > aPositions;
480 for(size_t nm = 0; nm < nMarkCount; ++nm)
482 SdrMark* pM = rMarkList.GetMark(nm);
484 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
486 const SdrUShortCont& rPts = pM->GetMarkedPoints();
488 if (!rPts.empty())
490 const SdrObject* pObj = pM->GetMarkedSdrObj();
491 const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
493 if(pPath)
495 const basegfx::B2DPolyPolygon& aPathXPP = pPath->GetPathPoly();
497 if(aPathXPP.count())
499 for(const sal_uInt16 nObjPt : rPts)
501 sal_uInt32 nPolyNum, nPointNum;
503 if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum))
505 aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
514 if(!aPositions.empty())
516 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), true)));
520 void SdrDragMethod::createSdrDragEntries_GlueDrag()
522 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
523 const size_t nMarkCount(rMarkList.GetMarkCount());
524 std::vector< basegfx::B2DPoint > aPositions;
526 for(size_t nm = 0; nm < nMarkCount; ++nm)
528 SdrMark* pM = rMarkList.GetMark(nm);
530 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
532 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
534 if (!rPts.empty())
536 const SdrObject* pObj = pM->GetMarkedSdrObj();
537 const SdrGluePointList* pGPL = pObj->GetGluePointList();
539 if (pGPL)
541 for(const sal_uInt16 nObjPt : rPts)
543 const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));
545 if(SDRGLUEPOINT_NOTFOUND != nGlueNum)
547 const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
548 aPositions.emplace_back(aPoint.X(), aPoint.Y());
556 if(!aPositions.empty())
558 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), false)));
562 OUString SdrDragMethod::ImpGetDescriptionStr(TranslateId pStrCacheID) const
564 ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE;
565 if (IsDraggingPoints()) {
566 nOpt=ImpGetDescriptionOptions::POINTS;
567 } else if (IsDraggingGluePoints()) {
568 nOpt=ImpGetDescriptionOptions::GLUEPOINTS;
570 return getSdrDragView().ImpGetDescriptionString(pStrCacheID, nOpt);
573 SdrObject* SdrDragMethod::GetDragObj() const
575 SdrObject* pObj=nullptr;
576 if (getSdrDragView().mpDragHdl!=nullptr) pObj=getSdrDragView().mpDragHdl->GetObj();
577 if (pObj==nullptr) pObj=getSdrDragView().mpMarkedObj;
578 return pObj;
581 SdrPageView* SdrDragMethod::GetDragPV() const
583 SdrPageView* pPV=nullptr;
584 if (getSdrDragView().mpDragHdl!=nullptr) pPV=getSdrDragView().mpDragHdl->GetPageView();
585 if (pPV==nullptr) pPV=getSdrDragView().mpMarkedPV;
586 return pPV;
589 void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
591 // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
592 // Later this should be the only needed one for linear transforms (not for SdrDragCrook and
593 // SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the
594 // special handling of rotate/mirror due to the not-being-able to handle it in the old
595 // drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
596 basegfx::B2DHomMatrix aObjectTransform;
597 basegfx::B2DPolyPolygon aObjectPolyPolygon;
598 bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));
600 // apply transform to object transform
601 aObjectTransform *= getCurrentTransformation();
603 if(bPolyUsed)
605 // do something special since the object size is in the polygon
606 // break up matrix to get the scale
607 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);
609 // get polygon's position and size
610 const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
612 // get the scaling factors (do not mirror, this is in the object transformation)
613 const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
614 const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
616 // prepare transform matrix for polygon
617 basegfx::B2DHomMatrix aPolyTransform(
618 basegfx::utils::createTranslateB2DHomMatrix(
619 -aPolyRange.getMinX(),
620 -aPolyRange.getMinY()));
621 aPolyTransform.scale(fScaleX, fScaleY);
623 // transform the polygon
624 aObjectPolyPolygon.transform(aPolyTransform);
627 rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
630 void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
632 // original uses CurrentTransformation
633 rTarget.transform(getCurrentTransformation());
636 SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
637 : mrSdrDragView(rNewView),
638 mbMoveOnly(false),
639 mbSolidDraggingActive(getSdrDragView().IsSolidDragging()),
640 mbShiftPressed(false)
642 if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
644 // fallback to wireframe when high contrast is used
645 mbSolidDraggingActive = false;
649 SdrDragMethod::~SdrDragMethod()
651 clearSdrDragEntries();
654 void SdrDragMethod::Show(bool IsValidSize)
656 getSdrDragView().ShowDragObj(IsValidSize);
659 void SdrDragMethod::Hide()
661 getSdrDragView().HideDragObj();
664 basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation() const
666 return basegfx::B2DHomMatrix();
669 void SdrDragMethod::CancelSdrDrag()
671 Hide();
674 typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;
676 void SdrDragMethod::CreateOverlayGeometry(
677 sdr::overlay::OverlayManager& rOverlayManager,
678 const sdr::contact::ObjectContact& rObjectContact, bool bIsGeometrySizeValid)
680 // We do client-side object manipulation with the Kit API
681 if (comphelper::LibreOfficeKit::isActive())
682 return;
684 // create SdrDragEntries on demand
685 if(maSdrDragEntries.empty())
687 createSdrDragEntries();
690 // if there are entries, derive OverlayObjects from the entries, including
691 // modification from current interactive state
692 if(!maSdrDragEntries.empty())
694 // #i54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
695 // primitives, holding the original and the clone. If connectors (Edges) are involved,
696 // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
697 // they are connected to the original SdrObjects). To do so, trigger the preparation
698 // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
699 // and evtl. remember if it was an edge
700 SdrObjectAndCloneMap aOriginalAndClones;
701 std::vector< SdrEdgeObj* > aEdges;
703 // #i54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
704 // clone, remember edges
705 for(auto const & a: maSdrDragEntries)
707 SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(a.get());
709 if(pSdrDragEntrySdrObject)
711 pSdrDragEntrySdrObject->prepareCurrentState(*this);
713 SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());
715 if(pSdrEdgeObj)
717 aEdges.push_back(pSdrEdgeObj);
720 if(pSdrDragEntrySdrObject->getClone())
722 aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
727 // #i54102# if there are edges, reconnect their ends to the corresponding clones (if found)
728 for(SdrEdgeObj* pSdrEdgeObj: aEdges)
730 SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);
732 if(pConnectedTo)
734 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
736 if(aEntry != aOriginalAndClones.end())
738 pSdrEdgeObj->ConnectToNode(true, aEntry->second);
742 pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);
744 if(pConnectedTo)
746 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
748 if(aEntry != aOriginalAndClones.end())
750 pSdrEdgeObj->ConnectToNode(false, aEntry->second);
755 // collect primitives for visualisation
756 drawinglayer::primitive2d::Primitive2DContainer aResult;
757 drawinglayer::primitive2d::Primitive2DContainer aResultTransparent;
759 for(auto & pCandidate: maSdrDragEntries)
761 const drawinglayer::primitive2d::Primitive2DContainer aCandidateResult(
762 pCandidate->createPrimitive2DSequenceInCurrentState(*this, bIsGeometrySizeValid));
764 if(!aCandidateResult.empty())
766 if(pCandidate->getAddToTransparent())
768 aResultTransparent.append(aCandidateResult);
770 else
772 aResult.append(aCandidateResult);
777 if(DoAddConnectorOverlays())
779 drawinglayer::primitive2d::Primitive2DContainer aConnectorOverlays(AddConnectorOverlays());
781 if(!aConnectorOverlays.empty())
783 // add connector overlays to transparent part
784 aResultTransparent.append(std::move(aConnectorOverlays));
788 if(!aResult.empty())
790 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
791 new sdr::overlay::OverlayPrimitive2DSequenceObject(
792 std::move(aResult)));
794 insertNewlyCreatedOverlayObjectForSdrDragMethod(
795 std::move(pNewOverlayObject),
796 rObjectContact,
797 rOverlayManager);
800 if(!aResultTransparent.empty())
802 aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer {
803 new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aResultTransparent), 0.5)
806 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
807 new sdr::overlay::OverlayPrimitive2DSequenceObject(
808 std::move(aResultTransparent)));
810 insertNewlyCreatedOverlayObjectForSdrDragMethod(
811 std::move(pNewOverlayObject),
812 rObjectContact,
813 rOverlayManager);
817 // add DragStripes if necessary (help lines cross the page when dragging)
818 if(!getSdrDragView().IsDragStripes())
819 return;
821 tools::Rectangle aActionRectangle;
822 getSdrDragView().TakeActionRect(aActionRectangle);
824 const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
825 const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
826 std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
827 new sdr::overlay::OverlayRollingRectangleStriped(
828 aTopLeft,
829 aBottomRight,
830 true,
831 false));
833 insertNewlyCreatedOverlayObjectForSdrDragMethod(
834 std::move(pNew),
835 rObjectContact,
836 rOverlayManager);
839 void SdrDragMethod::destroyOverlayGeometry()
841 maOverlayObjectList.clear();
844 bool SdrDragMethod::DoAddConnectorOverlays()
846 // these conditions are translated from SdrDragView::ImpDrawEdgeXor
847 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
849 if(!rMarkedNodes.GetMarkCount())
851 return false;
854 if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
856 return false;
859 if(!getMoveOnly() && !(
860 dynamic_cast<const SdrDragMove*>(this) != nullptr || dynamic_cast<const SdrDragResize*>(this) != nullptr ||
861 dynamic_cast<const SdrDragRotate*>(this) != nullptr || dynamic_cast<const SdrDragMirror*>(this) != nullptr ))
863 return false;
866 // one more migrated from SdrEdgeObj::NspToggleEdgeXor
867 if( dynamic_cast< const SdrDragObjOwn* >(this) != nullptr || dynamic_cast< const SdrDragMovHdl* >(this) != nullptr )
869 return false;
872 return true;
875 drawinglayer::primitive2d::Primitive2DContainer SdrDragMethod::AddConnectorOverlays()
877 drawinglayer::primitive2d::Primitive2DContainer aRetval;
878 const bool bDetail(getMoveOnly());
879 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
881 for(size_t a = 0; a < rMarkedNodes.GetMarkCount(); ++a)
883 SdrMark* pEM = rMarkedNodes.GetMark(a);
885 if(pEM && pEM->GetMarkedSdrObj())
887 SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());
889 if(pEdge)
891 basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));
893 if(aEdgePolygon.count())
895 // this polygon is a temporary calculated connector path, so it is not possible to fetch
896 // the needed primitives directly from the pEdge object which does not get changed. If full
897 // drag is on, use the SdrObjects ItemSet to create an adequate representation
898 bool bUseSolidDragging(getSolidDraggingActive());
900 if(bUseSolidDragging)
902 // switch off solid dragging if connector is not visible
903 if(!pEdge->HasLineStyle())
905 bUseSolidDragging = false;
909 if(bUseSolidDragging)
911 const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
912 const drawinglayer::attribute::SdrLineAttribute aLine(
913 drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));
915 if(!aLine.isDefault())
917 const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
918 drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
919 rItemSet,
920 aLine.getWidth()));
922 aRetval.push_back(drawinglayer::primitive2d::createPolygonLinePrimitive(
923 aEdgePolygon,
924 aLine,
925 aLineStartEnd));
928 else
930 basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
931 basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
932 const double fStripeLength(officecfg::Office::Common::Drawinglayer::StripeLength::get());
934 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
936 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
937 aColB.invert();
940 drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
941 new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
942 std::move(aEdgePolygon), aColA, aColB, fStripeLength));
943 aRetval.push_back(aPolyPolygonMarkerPrimitive2D);
950 return aRetval;
954 SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
955 : SdrDragMethod(rNewView)
959 void SdrDragMovHdl::createSdrDragEntries()
961 // SdrDragMovHdl does not use the default drags,
962 // but creates nothing
965 OUString SdrDragMovHdl::GetSdrDragComment() const
967 OUString aStr=SvxResId(STR_DragMethMovHdl);
968 if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy);
969 return aStr;
972 bool SdrDragMovHdl::BeginSdrDrag()
974 if( !GetDragHdl() )
975 return false;
977 DragStat().SetRef1(GetDragHdl()->GetPos());
978 DragStat().SetShown(!DragStat().IsShown());
979 SdrHdlKind eKind=GetDragHdl()->GetKind();
980 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
981 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
983 if (eKind==SdrHdlKind::MirrorAxis)
985 if (pH1==nullptr || pH2==nullptr)
987 OSL_FAIL("SdrDragMovHdl::BeginSdrDrag(): Moving the axis of reflection: reference handles not found.");
988 return false;
991 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
993 else
995 Point aPt(GetDragHdl()->GetPos());
996 DragStat().SetActionRect(tools::Rectangle(aPt,aPt));
999 return true;
1002 void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
1004 Point aPnt(rNoSnapPnt);
1006 if ( !(GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)))
1007 return;
1009 if (GetDragHdl()->GetKind()==SdrHdlKind::MirrorAxis)
1011 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
1012 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
1014 if (pH1==nullptr || pH2==nullptr)
1015 return;
1017 if (!DragStat().IsNoSnap())
1019 tools::Long nBestXSnap=0;
1020 tools::Long nBestYSnap=0;
1021 bool bXSnapped=false;
1022 bool bYSnapped=false;
1023 Point aDif(aPnt-DragStat().GetStart());
1024 getSdrDragView().CheckSnap(Ref1()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1025 getSdrDragView().CheckSnap(Ref2()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1026 aPnt.AdjustX(nBestXSnap );
1027 aPnt.AdjustY(nBestYSnap );
1030 if (aPnt!=DragStat().GetNow())
1032 Hide();
1033 DragStat().NextMove(aPnt);
1034 Point aDif(DragStat().GetNow()-DragStat().GetStart());
1035 pH1->SetPos(Ref1()+aDif);
1036 pH2->SetPos(Ref2()+aDif);
1038 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1040 if(pHM)
1041 pHM->Touch();
1043 Show();
1044 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
1047 else
1049 if (!DragStat().IsNoSnap()) SnapPos(aPnt);
1050 Degree100 nSA(0);
1052 if (getSdrDragView().IsAngleSnapEnabled())
1053 nSA=getSdrDragView().GetSnapAngle();
1055 if (getSdrDragView().IsMirrorAllowed(true,true))
1056 { // limited
1057 if (!getSdrDragView().IsMirrorAllowed()) nSA=4500_deg100;
1058 if (!getSdrDragView().IsMirrorAllowed(true)) nSA=9000_deg100;
1061 if (getSdrDragView().IsOrtho() && nSA!=9000_deg100)
1062 nSA=4500_deg100;
1064 if (nSA)
1065 { // angle snapping
1066 SdrHdlKind eRef=SdrHdlKind::Ref1;
1068 if (GetDragHdl()->GetKind()==SdrHdlKind::Ref1)
1069 eRef=SdrHdlKind::Ref2;
1071 SdrHdl* pH=GetHdlList().GetHdl(eRef);
1073 if (pH!=nullptr)
1075 Point aRef(pH->GetPos());
1076 Degree100 nAngle=NormAngle36000(GetAngle(aPnt-aRef));
1077 Degree100 nNewAngle=nAngle;
1078 nNewAngle+=nSA/2_deg100;
1079 nNewAngle/=nSA;
1080 nNewAngle*=nSA;
1081 nNewAngle=NormAngle36000(nNewAngle);
1082 double a=toRadians(nNewAngle-nAngle);
1083 double nSin=sin(a);
1084 double nCos=cos(a);
1085 RotatePoint(aPnt,aRef,nSin,nCos);
1087 // eliminate rounding errors for certain values
1088 if (nSA==9000_deg100)
1090 if (nNewAngle==0_deg100 || nNewAngle==18000_deg100) aPnt.setY(aRef.Y() );
1091 if (nNewAngle==9000_deg100 || nNewAngle==27000_deg100) aPnt.setX(aRef.X() );
1094 if (nSA==4500_deg100)
1095 OrthoDistance8(aRef,aPnt,true);
1099 if (aPnt!=DragStat().GetNow())
1101 Hide();
1102 DragStat().NextMove(aPnt);
1103 GetDragHdl()->SetPos(DragStat().GetNow());
1104 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1106 if(pHM)
1107 pHM->Touch();
1109 Show();
1110 DragStat().SetActionRect(tools::Rectangle(aPnt,aPnt));
1115 bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
1117 if( GetDragHdl() )
1119 switch (GetDragHdl()->GetKind())
1121 case SdrHdlKind::Ref1:
1122 Ref1()=DragStat().GetNow();
1123 break;
1125 case SdrHdlKind::Ref2:
1126 Ref2()=DragStat().GetNow();
1127 break;
1129 case SdrHdlKind::MirrorAxis:
1130 Ref1()+=DragStat().GetNow()-DragStat().GetStart();
1131 Ref2()+=DragStat().GetNow()-DragStat().GetStart();
1132 break;
1134 default: break;
1138 return true;
1141 void SdrDragMovHdl::CancelSdrDrag()
1143 Hide();
1145 SdrHdl* pHdl = GetDragHdl();
1146 if( pHdl )
1147 pHdl->SetPos(DragStat().GetRef1());
1149 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1151 if(pHM)
1152 pHM->Touch();
1155 PointerStyle SdrDragMovHdl::GetSdrDragPointer() const
1157 const SdrHdl* pHdl = GetDragHdl();
1159 if (pHdl!=nullptr)
1161 return pHdl->GetPointer();
1164 return PointerStyle::RefHand;
1168 SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
1169 : SdrDragMethod(rNewView)
1171 const SdrObject* pObj = GetDragObj();
1173 if(pObj)
1175 // suppress full drag for some object types
1176 setSolidDraggingActive(pObj->supportsFullDrag());
1180 SdrDragObjOwn::~SdrDragObjOwn()
1184 void SdrDragObjOwn::createSdrDragEntries()
1186 if(!mxClone)
1187 return;
1189 basegfx::B2DPolyPolygon aDragPolyPolygon;
1190 bool bAddWireframe(true);
1192 if(getSolidDraggingActive())
1194 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
1196 if(pPV && pPV->PageWindowCount())
1198 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mxClone, false)));
1200 // potentially no wireframe needed, full drag works
1201 bAddWireframe = false;
1205 if(!bAddWireframe)
1207 // check for extra conditions for wireframe, e.g. no border at
1208 // objects
1209 if(!mxClone->HasLineStyle())
1211 bAddWireframe = true;
1215 if(bAddWireframe)
1217 // use wireframe poly when full drag is off or did not work
1218 aDragPolyPolygon = mxClone->TakeXorPoly();
1221 // add evtl. extra DragPolyPolygon
1222 const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mxClone->getSpecialDragPoly(DragStat()));
1224 if(aSpecialDragPolyPolygon.count())
1226 aDragPolyPolygon.append(aSpecialDragPolyPolygon);
1229 if(aDragPolyPolygon.count())
1231 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aDragPolyPolygon))));
1235 OUString SdrDragObjOwn::GetSdrDragComment() const
1237 OUString aStr;
1238 // #i103058# get info string from the clone preferred, the original will
1239 // not be changed. For security, use original as fallback
1240 if(mxClone)
1242 aStr = mxClone->getSpecialDragComment(DragStat());
1244 else
1246 const SdrObject* pObj = GetDragObj();
1248 if(pObj)
1250 aStr = pObj->getSpecialDragComment(DragStat());
1253 return aStr;
1256 bool SdrDragObjOwn::BeginSdrDrag()
1258 if(!mxClone)
1260 const SdrObject* pObj = GetDragObj();
1262 if(pObj && !pObj->IsResizeProtect())
1264 if(pObj->beginSpecialDrag(DragStat()))
1266 // create initial clone to have a start visualization
1267 mxClone = pObj->getFullDragClone();
1268 mxClone->applySpecialDrag(DragStat());
1270 return true;
1275 return false;
1278 void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
1280 const SdrObject* pObj = GetDragObj();
1282 if (!pObj)
1283 // No object to drag. Bail out.
1284 return;
1286 Point aPnt(rNoSnapPnt);
1287 SdrPageView* pPV = GetDragPV();
1289 if (!pPV)
1290 // No page view available. Bail out.
1291 return;
1293 if(!DragStat().IsNoSnap())
1295 SnapPos(aPnt);
1297 if(getSdrDragView().IsOrtho())
1299 if (DragStat().IsOrtho8Possible())
1301 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1303 else if (DragStat().IsOrtho4Possible())
1305 OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1309 if (!DragStat().CheckMinMoved(rNoSnapPnt))
1310 // Not moved by the minimum threshold. Nothing to do.
1311 return;
1313 Hide();
1314 DragStat().NextMove(aPnt);
1316 // since SdrDragObjOwn currently supports no transformation of
1317 // existing SdrDragEntries but only their recreation, a recreation
1318 // after every move is needed in this mode. Delete existing
1319 // SdrDragEntries here to force their recreation in the following Show().
1320 clearSdrDragEntries();
1322 // delete current clone (after the last reference to it is deleted above)
1323 mxClone.clear();
1325 // create a new clone and modify to current drag state
1326 mxClone = pObj->getFullDragClone();
1327 mxClone->applySpecialDrag(DragStat());
1329 // AutoGrowWidth may change for SdrTextObj due to the automatism used
1330 // with bDisableAutoWidthOnDragging, so not only geometry changes but
1331 // also this (pretty indirect) property change is possible. If it gets
1332 // changed, it needs to be copied to the original since nothing will
1333 // happen when it only changes in the drag clone
1334 const bool bOldAutoGrowWidth(pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1335 const bool bNewAutoGrowWidth(mxClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1337 if (bOldAutoGrowWidth != bNewAutoGrowWidth)
1339 GetDragObj()->SetMergedItem(makeSdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
1342 Show();
1345 bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
1347 Hide();
1348 std::vector< std::unique_ptr<SdrUndoAction> > vConnectorUndoActions;
1349 bool bRet = false;
1350 SdrObject* pObj = GetDragObj();
1352 if(pObj)
1354 std::unique_ptr<SdrUndoAction> pUndo;
1355 std::unique_ptr<SdrUndoAction> pUndo2;
1356 const bool bUndo = getSdrDragView().IsUndoEnabled();
1358 if( bUndo )
1360 getSdrDragView().EndTextEditCurrentView();
1361 if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() )
1363 if (DragStat().IsEndDragChangesAttributes())
1365 pUndo=getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj);
1367 if (DragStat().IsEndDragChangesGeoAndAttributes())
1369 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1370 pUndo2 = getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1373 else
1375 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1376 pUndo= getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1380 if( pUndo )
1382 getSdrDragView().BegUndo( pUndo->GetComment() );
1384 else
1386 getSdrDragView().BegUndo();
1390 // Maybe use operator = for setting changed object data (do not change selection in
1391 // view, this will destroy the interactor). This is possible since a clone is now
1392 // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
1393 // in its SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
1394 // a CreateUndoGeoObject(), so maybe setting SetEndDragChangesAttributes is okay. I
1395 // will test this now
1396 tools::Rectangle aBoundRect0;
1398 if(pObj->GetUserCall())
1400 aBoundRect0 = pObj->GetLastBoundRect();
1403 bRet = pObj->applySpecialDrag(DragStat());
1404 if (DragStat().IsEndDragChangesLayout())
1406 auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo.get());
1407 if (pGeoUndo)
1408 pGeoUndo->SetSkipChangeLayout(true);
1411 if(bRet)
1413 pObj->SetChanged();
1414 pObj->BroadcastObjectChange();
1415 pObj->SendUserCall( SdrUserCallType::Resize, aBoundRect0 );
1418 if(bRet && bUndo )
1420 getSdrDragView().AddUndoActions( std::move(vConnectorUndoActions) );
1422 if ( pUndo )
1424 getSdrDragView().AddUndo(std::move(pUndo));
1427 if ( pUndo2 )
1429 getSdrDragView().AddUndo(std::move(pUndo2));
1433 if( bUndo )
1434 getSdrDragView().EndUndo();
1437 return bRet;
1440 PointerStyle SdrDragObjOwn::GetSdrDragPointer() const
1442 const SdrHdl* pHdl=GetDragHdl();
1444 if (pHdl)
1446 return pHdl->GetPointer();
1449 return PointerStyle::Move;
1453 void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
1455 // use the view-independent primitive representation (without
1456 // evtl. GridOffset, that may be applied to the DragEntry individually)
1457 drawinglayer::primitive2d::Primitive2DContainer xRetval;
1458 rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
1459 addSdrDragEntry(
1460 std::unique_ptr<SdrDragEntry>(
1461 new SdrDragEntryPrimitive2DSequence(
1462 std::move(xRetval))));
1466 void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
1468 rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
1471 SdrDragMove::SdrDragMove(SdrDragView& rNewView)
1472 : SdrDragMethod(rNewView)
1473 , m_nBestXSnap(0)
1474 , m_nBestYSnap(0)
1475 , m_bXSnapped(false)
1476 , m_bYSnapped(false)
1478 setMoveOnly(true);
1481 OUString SdrDragMove::GetSdrDragComment() const
1483 OUString aStr = ImpGetDescriptionStr(STR_DragMethMove)
1484 + " (x="
1485 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
1486 + " y="
1487 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
1488 + ")";
1490 if(getSdrDragView().IsDragWithCopy())
1492 if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint())
1494 aStr += SvxResId(STR_EditWithCopy);
1497 return aStr;
1500 bool SdrDragMove::BeginSdrDrag()
1502 DragStat().SetActionRect(GetMarkedRect());
1503 Show();
1505 return true;
1508 basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation() const
1510 return basegfx::utils::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
1513 void SdrDragMove::ImpCheckSnap(const Point& rPt)
1515 Point aPt(rPt);
1516 SdrSnap nRet=SnapPos(aPt);
1517 aPt-=rPt;
1519 if (nRet & SdrSnap::XSNAPPED)
1521 if (m_bXSnapped)
1523 if (std::abs(aPt.X())<std::abs(m_nBestXSnap))
1525 m_nBestXSnap=aPt.X();
1528 else
1530 m_nBestXSnap=aPt.X();
1531 m_bXSnapped=true;
1535 if (!(nRet & SdrSnap::YSNAPPED))
1536 return;
1538 if (m_bYSnapped)
1540 if (std::abs(aPt.Y())<std::abs(m_nBestYSnap))
1542 m_nBestYSnap=aPt.Y();
1545 else
1547 m_nBestYSnap=aPt.Y();
1548 m_bYSnapped=true;
1552 void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
1554 m_nBestXSnap=0;
1555 m_nBestYSnap=0;
1556 m_bXSnapped=false;
1557 m_bYSnapped=false;
1558 Point aNoSnapPnt(rNoSnapPnt_);
1559 const tools::Rectangle& aSR=GetMarkedRect();
1560 tools::Long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
1561 tools::Long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
1562 Point aLO(aSR.TopLeft()); aLO.AdjustX(nMovedx ); aLO.AdjustY(nMovedy );
1563 Point aRU(aSR.BottomRight()); aRU.AdjustX(nMovedx ); aRU.AdjustY(nMovedy );
1564 Point aLU(aLO.X(),aRU.Y());
1565 Point aRO(aRU.X(),aLO.Y());
1566 ImpCheckSnap(aLO);
1568 if (!getSdrDragView().IsMoveSnapOnlyTopLeft())
1570 ImpCheckSnap(aRO);
1571 ImpCheckSnap(aLU);
1572 ImpCheckSnap(aRU);
1575 Point aPnt(aNoSnapPnt.X()+m_nBestXSnap,aNoSnapPnt.Y()+m_nBestYSnap);
1576 bool bOrtho=getSdrDragView().IsOrtho();
1578 if (bOrtho)
1579 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1581 if (!DragStat().CheckMinMoved(aNoSnapPnt))
1582 return;
1584 Point aPt1(aPnt);
1585 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1586 bool bWorkArea=!aLR.IsEmpty();
1587 bool bDragLimit=IsDragLimit();
1589 if (bDragLimit || bWorkArea)
1591 tools::Rectangle aSR2(GetMarkedRect());
1592 Point aD(aPt1-DragStat().GetStart());
1594 if (bDragLimit)
1596 tools::Rectangle aR2(GetDragLimitRect());
1598 if (bWorkArea)
1599 aLR.Intersection(aR2);
1600 else
1601 aLR=aR2;
1604 if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right())
1605 { // any space to move to?
1606 aSR2.Move(aD.X(),0);
1608 if (aSR2.Left()<aLR.Left())
1610 aPt1.AdjustX( -(aSR2.Left()-aLR.Left()) );
1612 else if (aSR2.Right()>aLR.Right())
1614 aPt1.AdjustX( -(aSR2.Right()-aLR.Right()) );
1617 else
1618 aPt1.setX(DragStat().GetStart().X() ); // no space to move to
1620 if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom())
1621 { // any space to move to?
1622 aSR2.Move(0,aD.Y());
1624 if (aSR2.Top()<aLR.Top())
1626 aPt1.AdjustY( -(aSR2.Top()-aLR.Top()) );
1628 else if (aSR2.Bottom()>aLR.Bottom())
1630 aPt1.AdjustY( -(aSR2.Bottom()-aLR.Bottom()) );
1633 else
1634 aPt1.setY(DragStat().GetStart().Y() ); // no space to move to
1637 if (getSdrDragView().IsDraggingGluePoints())
1638 { // restrict gluepoints to the BoundRect of the Obj
1639 aPt1-=DragStat().GetStart();
1640 const SdrMarkList& rMarkList = GetMarkedObjectList();
1641 const size_t nMarkCount = rMarkList.GetMarkCount();
1643 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1645 const SdrMark* pM = rMarkList.GetMark(nMarkNum);
1646 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
1648 if (!rPts.empty())
1650 const SdrObject* pObj=pM->GetMarkedSdrObj();
1651 const SdrGluePointList* pGPL=pObj->GetGluePointList();
1652 tools::Rectangle aBound(pObj->GetCurrentBoundRect());
1654 for (sal_uInt16 nId : rPts)
1656 sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);
1658 if (nGlueNum!=SDRGLUEPOINT_NOTFOUND)
1660 Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
1661 aPt+=aPt1; // move by this much
1662 if (aPt.X()<aBound.Left() ) aPt1.AdjustX( -(aPt.X()-aBound.Left()) ) ;
1663 if (aPt.X()>aBound.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ;
1664 if (aPt.Y()<aBound.Top() ) aPt1.AdjustY( -(aPt.Y()-aBound.Top()) ) ;
1665 if (aPt.Y()>aBound.Bottom()) aPt1.AdjustY( -(aPt.Y()-aBound.Bottom()) );
1671 aPt1+=DragStat().GetStart();
1674 if (bOrtho)
1675 OrthoDistance8(DragStat().GetStart(),aPt1,false);
1677 if (aPt1!=DragStat().GetNow())
1679 Hide();
1680 DragStat().NextMove(aPt1);
1681 tools::Rectangle aAction(GetMarkedRect());
1682 aAction.Move(DragStat().GetDX(),DragStat().GetDY());
1683 DragStat().SetActionRect(aAction);
1684 Show();
1688 bool SdrDragMove::EndSdrDrag(bool bCopy)
1690 Hide();
1692 if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint())
1693 bCopy=false;
1695 if (IsDraggingPoints())
1697 getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()));
1699 else if (IsDraggingGluePoints())
1701 getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1703 else
1705 getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1708 return true;
1711 PointerStyle SdrDragMove::GetSdrDragPointer() const
1713 if (IsDraggingPoints() || IsDraggingGluePoints())
1715 return PointerStyle::MovePoint;
1717 else
1719 return PointerStyle::Move;
1724 SdrDragResize::SdrDragResize(SdrDragView& rNewView)
1725 : SdrDragMethod(rNewView),
1726 m_aXFact(1,1),
1727 m_aYFact(1,1)
1731 OUString SdrDragResize::GetSdrDragComment() const
1733 OUString aStr = ImpGetDescriptionStr(STR_DragMethResize);
1734 Fraction aFact1(1,1);
1735 Point aStart(DragStat().GetStart());
1736 Point aRef(DragStat().GetRef1());
1737 sal_Int32 nXDiv(aStart.X() - aRef.X());
1739 if(!nXDiv)
1740 nXDiv = 1;
1742 sal_Int32 nYDiv(aStart.Y() - aRef.Y());
1744 if(!nYDiv)
1745 nYDiv = 1;
1747 bool bX(m_aXFact != aFact1 && std::abs(nXDiv) > 1);
1748 bool bY(m_aYFact != aFact1 && std::abs(nYDiv) > 1);
1750 if(bX || bY)
1752 aStr += " (";
1754 bool bEqual(m_aXFact == m_aYFact);
1755 if(bX)
1757 if(!bEqual)
1758 aStr += "x=";
1760 aStr += SdrModel::GetPercentString(m_aXFact);
1763 if(bY && !bEqual)
1765 if(bX)
1766 aStr += " ";
1768 aStr += "y=" + SdrModel::GetPercentString(m_aYFact);
1771 aStr += ")";
1774 if(getSdrDragView().IsDragWithCopy())
1775 aStr += SvxResId(STR_EditWithCopy);
1776 return aStr;
1779 bool SdrDragResize::BeginSdrDrag()
1781 SdrHdlKind eRefHdl=SdrHdlKind::Move;
1782 SdrHdl* pRefHdl=nullptr;
1784 switch (GetDragHdlKind())
1786 case SdrHdlKind::UpperLeft: eRefHdl=SdrHdlKind::LowerRight; break;
1787 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; DragStat().SetHorFixed(true); break;
1788 case SdrHdlKind::UpperRight: eRefHdl=SdrHdlKind::LowerLeft; break;
1789 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; DragStat().SetVerFixed(true); break;
1790 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; DragStat().SetVerFixed(true); break;
1791 case SdrHdlKind::LowerLeft: eRefHdl=SdrHdlKind::UpperRight; break;
1792 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; DragStat().SetHorFixed(true); break;
1793 case SdrHdlKind::LowerRight: eRefHdl=SdrHdlKind::UpperLeft; break;
1794 default: break;
1797 if (eRefHdl!=SdrHdlKind::Move)
1798 pRefHdl=GetHdlList().GetHdl(eRefHdl);
1800 if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
1802 DragStat().SetRef1(pRefHdl->GetPos());
1804 else
1806 SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft);
1807 SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight);
1809 if (pRef1!=nullptr && pRef2!=nullptr)
1811 DragStat().SetRef1(tools::Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center());
1813 else
1815 DragStat().SetRef1(GetMarkedRect().Center());
1819 Show();
1821 return true;
1824 basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation() const
1826 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
1827 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
1828 aRetval.scale(double(m_aXFact), double(m_aYFact));
1829 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
1831 return aRetval;
1834 void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
1836 Point aPnt(GetSnapPos(rNoSnapPnt));
1837 Point aStart(DragStat().GetStart());
1838 Point aRef(DragStat().GetRef1());
1839 Fraction aMaxFact(0x7FFFFFFF,1);
1840 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1841 bool bWorkArea=!aLR.IsEmpty();
1842 bool bDragLimit=IsDragLimit();
1844 if (bDragLimit || bWorkArea)
1846 tools::Rectangle aSR(GetMarkedRect());
1848 if (bDragLimit)
1850 tools::Rectangle aR2(GetDragLimitRect());
1852 if (bWorkArea)
1853 aLR.Intersection(aR2);
1854 else
1855 aLR=aR2;
1858 if (aPnt.X()<aLR.Left())
1859 aPnt.setX(aLR.Left() );
1860 else if (aPnt.X()>aLR.Right())
1861 aPnt.setX(aLR.Right() );
1863 if (aPnt.Y()<aLR.Top())
1864 aPnt.setY(aLR.Top() );
1865 else if (aPnt.Y()>aLR.Bottom())
1866 aPnt.setY(aLR.Bottom() );
1868 if (aRef.X()>aSR.Left())
1870 Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());
1872 if (aMax<aMaxFact)
1873 aMaxFact=aMax;
1876 if (aRef.X()<aSR.Right())
1878 Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());
1880 if (aMax<aMaxFact)
1881 aMaxFact=aMax;
1884 if (aRef.Y()>aSR.Top())
1886 Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());
1888 if (aMax<aMaxFact)
1889 aMaxFact=aMax;
1892 if (aRef.Y()<aSR.Bottom())
1894 Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());
1896 if (aMax<aMaxFact)
1897 aMaxFact=aMax;
1901 tools::Long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
1902 tools::Long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
1903 tools::Long nXMul=aPnt.X()-aRef.X();
1904 tools::Long nYMul=aPnt.Y()-aRef.Y();
1906 if (nXDiv<0)
1908 nXDiv=-nXDiv;
1909 nXMul=-nXMul;
1912 if (nYDiv<0)
1914 nYDiv=-nYDiv;
1915 nYMul=-nYMul;
1918 bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
1919 bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
1920 bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();
1922 if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
1924 if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
1925 bOrtho=false;
1927 if (bOrtho)
1929 if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
1931 nXMul=nYMul;
1932 nXDiv=nYDiv;
1934 else
1936 nYMul=nXMul;
1937 nYDiv=nXDiv;
1941 else
1943 if (bOrtho)
1945 if (DragStat().IsHorFixed())
1947 bXNeg=false;
1948 nXMul=nYMul;
1949 nXDiv=nYDiv;
1952 if (DragStat().IsVerFixed())
1954 bYNeg=false;
1955 nYMul=nXMul;
1956 nYDiv=nXDiv;
1959 else
1961 if (DragStat().IsHorFixed())
1963 bXNeg=false;
1964 nXMul=1;
1965 nXDiv=1;
1968 if (DragStat().IsVerFixed())
1970 bYNeg=false;
1971 nYMul=1;
1972 nYDiv=1;
1977 Fraction aNewXFact(nXMul,nXDiv);
1978 Fraction aNewYFact(nYMul,nYDiv);
1980 if (bOrtho)
1982 if (aNewXFact>aMaxFact)
1984 aNewXFact=aMaxFact;
1985 aNewYFact=aMaxFact;
1988 if (aNewYFact>aMaxFact)
1990 aNewXFact=aMaxFact;
1991 aNewYFact=aMaxFact;
1995 if (bXNeg)
1996 aNewXFact=Fraction(-aNewXFact.GetNumerator(),aNewXFact.GetDenominator());
1998 if (bYNeg)
1999 aNewYFact=Fraction(-aNewYFact.GetNumerator(),aNewYFact.GetDenominator());
2001 if (DragStat().CheckMinMoved(aPnt))
2003 if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
2004 (!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y()))
2006 Hide();
2007 DragStat().NextMove(aPnt);
2008 m_aXFact=aNewXFact;
2009 m_aYFact=aNewYFact;
2011 aNewXFact = double(aNewXFact) > 0 ? aNewXFact : Fraction(1, 1);
2012 aNewYFact = double(aNewYFact) > 0 ? aNewYFact : Fraction(1, 1);
2013 Size aTargetSize(
2014 GetMarkedRect().GetSize().scale(aNewXFact.GetNumerator(), aNewXFact.GetDenominator(),
2015 aNewYFact.GetNumerator(), aNewYFact.GetDenominator()));
2016 Show(getSdrDragView().IsMarkedObjSizeValid(aTargetSize));
2021 void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2023 rTarget.Resize(DragStat().GetRef1(),m_aXFact,m_aYFact);
2026 bool SdrDragResize::EndSdrDrag(bool bCopy)
2028 Hide();
2030 if (IsDraggingPoints())
2032 getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),m_aXFact,m_aYFact);
2034 else if (IsDraggingGluePoints())
2036 getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),m_aXFact,m_aYFact,bCopy);
2038 else
2040 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),m_aXFact,m_aYFact,bCopy);
2043 return true;
2046 PointerStyle SdrDragResize::GetSdrDragPointer() const
2048 const SdrHdl* pHdl=GetDragHdl();
2050 if (pHdl!=nullptr)
2052 return pHdl->GetPointer();
2055 return PointerStyle::Move;
2059 void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2061 rTarget.Rotate(DragStat().GetRef1(), nAngle, nSin, nCos);
2064 SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
2065 : SdrDragMethod(rNewView),
2066 nSin(0.0),
2067 nCos(1.0),
2068 nAngle0(0),
2069 nAngle(0),
2070 bRight(false)
2074 OUString SdrDragRotate::GetSdrDragComment() const
2076 OUString aStr = ImpGetDescriptionStr(STR_DragMethRotate) +
2077 " (";
2078 Degree100 nTmpAngle(NormAngle36000(nAngle));
2080 if(bRight && nAngle)
2082 nTmpAngle -= 36000_deg100;
2085 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2087 if(getSdrDragView().IsDragWithCopy())
2088 aStr += SvxResId(STR_EditWithCopy);
2089 return aStr;
2092 bool SdrDragRotate::BeginSdrDrag()
2094 SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2096 if (nullptr != pH)
2098 Show();
2099 DragStat().SetRef1(pH->GetPos());
2100 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2101 return true;
2104 // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
2105 // the rotation point)
2106 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
2108 if(!aLocalMarkRect.IsEmpty())
2110 Show();
2111 DragStat().SetRef1(aLocalMarkRect.Center());
2112 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2113 return true;
2116 OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
2117 return false;
2120 basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation() const
2122 return basegfx::utils::createRotateAroundPoint(
2123 DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
2124 -atan2(nSin, nCos));
2127 void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
2129 Point aPnt(rPnt_);
2130 if (!DragStat().CheckMinMoved(aPnt))
2131 return;
2133 Degree100 nNewAngle=NormAngle36000(GetAngle(aPnt-DragStat().GetRef1())-nAngle0);
2134 Degree100 nSA(0);
2136 if (getSdrDragView().IsAngleSnapEnabled())
2137 nSA=getSdrDragView().GetSnapAngle();
2139 if (!getSdrDragView().IsRotateAllowed())
2140 nSA=9000_deg100;
2142 if (nSA)
2143 { // angle snapping
2144 nNewAngle += nSA / 2_deg100;
2145 nNewAngle /= nSA;
2146 nNewAngle *= nSA;
2149 nNewAngle=NormAngle18000(nNewAngle);
2151 if (nAngle==nNewAngle)
2152 return;
2154 sal_uInt16 nSekt0=GetAngleSector(nAngle);
2155 sal_uInt16 nSekt1=GetAngleSector(nNewAngle);
2157 if (nSekt0==0 && nSekt1==3)
2158 bRight=true;
2160 if (nSekt0==3 && nSekt1==0)
2161 bRight=false;
2163 nAngle=nNewAngle;
2164 double a = toRadians(nAngle);
2165 double nSin1=sin(a); // calculate now, so as little time as possible
2166 double nCos1=cos(a); // passes between Hide() and Show()
2167 Hide();
2168 nSin=nSin1;
2169 nCos=nCos1;
2170 DragStat().NextMove(aPnt);
2171 Show();
2174 bool SdrDragRotate::EndSdrDrag(bool bCopy)
2176 Hide();
2178 if (nAngle!=0_deg100)
2180 if (IsDraggingPoints())
2182 getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nAngle);
2184 else if (IsDraggingGluePoints())
2186 getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nAngle,bCopy);
2188 else
2190 getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nAngle,bCopy);
2193 return true;
2196 PointerStyle SdrDragRotate::GetSdrDragPointer() const
2198 return PointerStyle::Rotate;
2202 SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1)
2203 : SdrDragMethod(rNewView),
2204 aFact(1,1),
2205 nAngle0(0),
2206 nAngle(0),
2207 nTan(0.0),
2208 bVertical(false),
2209 bResize(false),
2210 bUpSideDown(false),
2211 bSlant(bSlant1)
2215 OUString SdrDragShear::GetSdrDragComment() const
2217 OUString aStr = ImpGetDescriptionStr(STR_DragMethShear) +
2218 " (";
2220 Degree100 nTmpAngle(nAngle);
2222 if(bUpSideDown)
2223 nTmpAngle += 18000_deg100;
2225 nTmpAngle = NormAngle18000(nTmpAngle);
2227 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2229 if(getSdrDragView().IsDragWithCopy())
2230 aStr += SvxResId(STR_EditWithCopy);
2231 return aStr;
2234 bool SdrDragShear::BeginSdrDrag()
2236 SdrHdlKind eRefHdl=SdrHdlKind::Move;
2237 SdrHdl* pRefHdl=nullptr;
2239 switch (GetDragHdlKind())
2241 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; break;
2242 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; break;
2243 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; bVertical=true; break;
2244 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; bVertical=true; break;
2245 default: break;
2248 if (eRefHdl!=SdrHdlKind::Move)
2249 pRefHdl=GetHdlList().GetHdl(eRefHdl);
2251 if (pRefHdl!=nullptr)
2253 DragStat().SetRef1(pRefHdl->GetPos());
2254 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2256 else
2258 OSL_FAIL("SdrDragShear::BeginSdrDrag(): No reference point handle for shearing found.");
2259 return false;
2262 Show();
2263 return true;
2266 basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation() const
2268 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
2269 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
2271 if (bResize)
2273 if (bVertical)
2275 aRetval.scale(double(aFact), 1.0);
2276 aRetval.shearY(-nTan);
2278 else
2280 aRetval.scale(1.0, double(aFact));
2281 aRetval.shearX(-nTan);
2285 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2287 return aRetval;
2290 void SdrDragShear::MoveSdrDrag(const Point& rPnt)
2292 if (!DragStat().CheckMinMoved(rPnt))
2293 return;
2295 bResize=!getSdrDragView().IsOrtho();
2296 Degree100 nSA(0);
2298 if (getSdrDragView().IsAngleSnapEnabled())
2299 nSA=getSdrDragView().GetSnapAngle();
2301 Point aP0(DragStat().GetStart());
2302 Point aPnt(rPnt);
2303 Fraction aNewFract(1,1);
2305 // if angle snapping not activated, snap to raster (except when using slant)
2306 if (nSA==0_deg100 && !bSlant)
2307 aPnt=GetSnapPos(aPnt);
2309 if (!bSlant && !bResize)
2310 { // shear, but no resize
2311 if (bVertical)
2312 aPnt.setX(aP0.X() );
2313 else
2314 aPnt.setY(aP0.Y() );
2317 Point aRef(DragStat().GetRef1());
2318 Point aDif(aPnt-aRef);
2320 Degree100 nNewAngle(0);
2322 if (bSlant)
2324 nNewAngle=NormAngle18000(-(GetAngle(aDif)-nAngle0));
2326 if (bVertical)
2327 nNewAngle=NormAngle18000(-nNewAngle);
2329 else
2331 if (bVertical)
2332 nNewAngle=NormAngle18000(GetAngle(aDif));
2333 else
2334 nNewAngle=NormAngle18000(-(GetAngle(aDif)-9000_deg100));
2336 if (nNewAngle<Degree100(-9000) || nNewAngle>9000_deg100)
2337 nNewAngle=NormAngle18000(nNewAngle+18000_deg100);
2339 if (bResize)
2341 Point aPt2(aPnt);
2343 if (nSA!=0_deg100)
2344 aPt2=GetSnapPos(aPnt); // snap this one in any case
2346 if (bVertical)
2348 aNewFract=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X());
2350 else
2352 aNewFract=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y());
2357 bool bNeg=nNewAngle<0_deg100;
2359 if (bNeg)
2360 nNewAngle=-nNewAngle;
2362 if (nSA)
2363 { // angle snapping
2364 nNewAngle += nSA / 2_deg100;
2365 nNewAngle /= nSA;
2366 nNewAngle *= nSA;
2369 nNewAngle=NormAngle36000(nNewAngle);
2370 bUpSideDown=nNewAngle>9000_deg100 && nNewAngle<27000_deg100;
2372 if (bSlant)
2373 { // calculate resize for slant
2374 // when angle snapping is activated, disable 89 degree limit
2375 Degree100 nTmpAngle=nNewAngle;
2376 if (bUpSideDown) nNewAngle -= 18000_deg100;
2377 if (bNeg) nTmpAngle=-nTmpAngle;
2378 bResize=true;
2379 aNewFract = cos(toRadians(nTmpAngle));
2380 aFact.ReduceInaccurate(10); // three decimals should be enough
2383 if (nNewAngle > 8900_deg100)
2384 nNewAngle = 8900_deg100;
2386 if (bNeg)
2387 nNewAngle=-nNewAngle;
2389 if (nAngle!=nNewAngle || aFact!=aNewFract)
2391 nAngle=nNewAngle;
2392 aFact=aNewFract;
2393 double a = toRadians(nAngle);
2394 double nTan1=tan(a); // calculate now, so as little time as possible passes between Hide() and Show()
2395 Hide();
2396 nTan=nTan1;
2397 DragStat().NextMove(rPnt);
2398 Show();
2402 void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2404 if (bResize)
2406 if (bVertical)
2408 rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1));
2410 else
2412 rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact);
2416 if (nAngle)
2418 rTarget.Shear(DragStat().GetRef1(), nAngle, nTan, bVertical);
2422 bool SdrDragShear::EndSdrDrag(bool bCopy)
2424 Hide();
2426 if (bResize && aFact==Fraction(1,1))
2427 bResize=false;
2429 if (nAngle || bResize)
2431 if (nAngle && bResize)
2433 OUString aStr = ImpGetDescriptionStr(STR_EditShear);
2435 if (bCopy)
2436 aStr += SvxResId(STR_EditWithCopy);
2438 getSdrDragView().BegUndo(aStr);
2441 if (bResize)
2443 if (bVertical)
2445 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy);
2447 else
2449 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy);
2452 bCopy=false;
2455 if (nAngle)
2457 getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nAngle,bVertical,bCopy);
2460 if (nAngle && bResize)
2461 getSdrDragView().EndUndo();
2463 return true;
2466 return false;
2469 PointerStyle SdrDragShear::GetSdrDragPointer() const
2471 if (bVertical)
2472 return PointerStyle::VShear;
2473 else
2474 return PointerStyle::HShear;
2478 void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2480 if(bMirrored)
2482 rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2());
2486 SdrDragMirror::SdrDragMirror(SdrDragView& rNewView)
2487 : SdrDragMethod(rNewView),
2488 nAngle(0),
2489 bMirrored(false),
2490 bSide0(false)
2494 bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const
2496 Degree100 nAngle1=GetAngle(rPnt-DragStat().GetRef1());
2497 nAngle1-=nAngle;
2498 nAngle1=NormAngle36000(nAngle1);
2500 return nAngle1<18000_deg100;
2503 OUString SdrDragMirror::GetSdrDragComment() const
2505 OUString aStr;
2506 if (aDif.X()==0)
2507 aStr = ImpGetDescriptionStr(STR_DragMethMirrorHori);
2508 else if (aDif.Y()==0)
2509 aStr = ImpGetDescriptionStr(STR_DragMethMirrorVert);
2510 else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
2511 aStr = ImpGetDescriptionStr(STR_DragMethMirrorDiag);
2512 else
2513 aStr = ImpGetDescriptionStr(STR_DragMethMirrorFree);
2515 if (getSdrDragView().IsDragWithCopy())
2516 aStr+=SvxResId(STR_EditWithCopy);
2517 return aStr;
2520 bool SdrDragMirror::BeginSdrDrag()
2522 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2523 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
2525 if (pH1!=nullptr && pH2!=nullptr)
2527 DragStat().SetRef1(pH1->GetPos());
2528 DragStat().SetRef2(pH2->GetPos());
2529 Ref1()=pH1->GetPos();
2530 Ref2()=pH2->GetPos();
2531 aDif=pH2->GetPos()-pH1->GetPos();
2532 bool b90=(aDif.X()==0) || aDif.Y()==0;
2533 bool b45=b90 || (std::abs(aDif.X()) == std::abs(aDif.Y()));
2534 nAngle=NormAngle36000(GetAngle(aDif));
2536 if (!getSdrDragView().IsMirrorAllowed() && !b45)
2537 return false; // free choice of axis angle not allowed
2539 if (!getSdrDragView().IsMirrorAllowed() && !b90)
2540 return false; // 45 degrees not allowed either
2542 bSide0=ImpCheckSide(DragStat().GetStart());
2543 Show();
2544 return true;
2546 else
2548 OSL_FAIL("SdrDragMirror::BeginSdrDrag(): Axis of reflection not found.");
2549 return false;
2553 basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation() const
2555 basegfx::B2DHomMatrix aRetval;
2557 if (bMirrored)
2559 const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X());
2560 const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y());
2561 const double fRotation(atan2(fDeltaY, fDeltaX));
2563 aRetval = basegfx::utils::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y());
2564 aRetval.rotate(-fRotation);
2565 aRetval.scale(1.0, -1.0);
2566 aRetval.rotate(fRotation);
2567 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2570 return aRetval;
2573 void SdrDragMirror::MoveSdrDrag(const Point& rPnt)
2575 if (!DragStat().CheckMinMoved(rPnt))
2576 return;
2578 bool bNewSide=ImpCheckSide(rPnt);
2579 bool bNewMirrored=bSide0!=bNewSide;
2581 if (bMirrored!=bNewMirrored)
2583 Hide();
2584 bMirrored=bNewMirrored;
2585 DragStat().NextMove(rPnt);
2586 Show();
2590 bool SdrDragMirror::EndSdrDrag(bool bCopy)
2592 Hide();
2594 if (bMirrored)
2596 getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy);
2599 return true;
2602 PointerStyle SdrDragMirror::GetSdrDragPointer() const
2604 return PointerStyle::Mirror;
2608 SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad)
2609 : SdrDragMethod(rNewView),
2610 pIAOHandle(nullptr),
2611 bIsGradient(bGrad)
2615 OUString SdrDragGradient::GetSdrDragComment() const
2617 if(IsGradient())
2618 return ImpGetDescriptionStr(STR_DragMethGradient);
2619 else
2620 return ImpGetDescriptionStr(STR_DragMethTransparence);
2623 bool SdrDragGradient::BeginSdrDrag()
2625 bool bRetval(false);
2627 pIAOHandle = static_cast<SdrHdlGradient*>(GetHdlList().GetHdl(IsGradient() ? SdrHdlKind::Gradient : SdrHdlKind::Transparence));
2629 if(pIAOHandle)
2631 // save old values
2632 DragStat().SetRef1( pIAOHandle->GetPos() );
2633 DragStat().SetRef2( pIAOHandle->Get2ndPos() );
2635 // what was hit?
2636 bool bHit(false);
2637 SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1();
2639 // init handling flags
2640 pIAOHandle->SetMoveSingleHandle(false);
2641 pIAOHandle->SetMoveFirstHandle(false);
2643 // test first color handle
2644 if(pColHdl)
2646 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2648 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2650 bHit = true;
2651 pIAOHandle->SetMoveSingleHandle(true);
2652 pIAOHandle->SetMoveFirstHandle(true);
2656 // test second color handle
2657 pColHdl = pIAOHandle->GetColorHdl2();
2659 if(!bHit && pColHdl)
2661 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2663 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2665 bHit = true;
2666 pIAOHandle->SetMoveSingleHandle(true);
2670 // test gradient handle itself
2671 if(!bHit)
2673 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2675 if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition))
2677 bHit = true;
2681 // everything up and running :o}
2682 bRetval = bHit;
2684 else
2686 OSL_FAIL("SdrDragGradient::BeginSdrDrag(): IAOGradient not found.");
2689 return bRetval;
2692 void SdrDragGradient::MoveSdrDrag(const Point& rPnt)
2694 if(!(pIAOHandle && DragStat().CheckMinMoved(rPnt)))
2695 return;
2697 DragStat().NextMove(rPnt);
2699 // Do the Move here!!! DragStat().GetStart()
2700 Point aMoveDiff = rPnt - DragStat().GetStart();
2702 if(pIAOHandle->IsMoveSingleHandle())
2704 if(pIAOHandle->IsMoveFirstHandle())
2706 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2707 if(pIAOHandle->GetColorHdl1())
2708 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2710 else
2712 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2713 if(pIAOHandle->GetColorHdl2())
2714 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2717 else
2719 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2720 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2722 if(pIAOHandle->GetColorHdl1())
2723 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2725 if(pIAOHandle->GetColorHdl2())
2726 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2729 // new state
2730 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
2731 pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), false, false);
2734 bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/)
2736 Ref1() = pIAOHandle->GetPos();
2737 Ref2() = pIAOHandle->Get2ndPos();
2739 // new state
2740 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
2741 pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), true, true);
2743 return true;
2746 void SdrDragGradient::CancelSdrDrag()
2748 // restore old values
2749 pIAOHandle->SetPos(DragStat().GetRef1());
2750 pIAOHandle->Set2ndPos(DragStat().GetRef2());
2752 if(pIAOHandle->GetColorHdl1())
2753 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1());
2755 if(pIAOHandle->GetColorHdl2())
2756 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2());
2758 // new state
2759 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
2760 pIAOHandle->FromIAOToItem(rMarkList.GetMark(0)->GetMarkedSdrObj(), true, false);
2763 PointerStyle SdrDragGradient::GetSdrDragPointer() const
2765 return PointerStyle::RefHand;
2769 SdrDragCrook::SdrDragCrook(SdrDragView& rNewView)
2770 : SdrDragMethod(rNewView),
2771 aFact(1,1),
2772 bContortionAllowed(false),
2773 bNoContortionAllowed(false),
2774 bContortion(false),
2775 bResizeAllowed(false),
2776 bResize(false),
2777 bRotateAllowed(false),
2778 bRotate(false),
2779 bVertical(false),
2780 bValid(false),
2781 bLft(false),
2782 bRgt(false),
2783 bUpr(false),
2784 bLwr(false),
2785 bAtCenter(false),
2786 nAngle(0),
2787 nMarkSize(0),
2788 eMode(SdrCrookMode::Rotate)
2792 OUString SdrDragCrook::GetSdrDragComment() const
2794 OUString aStr = ImpGetDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion);
2796 if(bValid)
2798 aStr += " (";
2800 sal_Int32 nVal(nAngle);
2802 if(bAtCenter)
2803 nVal *= 2;
2805 nVal = std::abs(nVal);
2806 aStr += SdrModel::GetAngleString(Degree100(nVal)) + ")";
2809 if(getSdrDragView().IsDragWithCopy())
2810 aStr += SvxResId(STR_EditWithCopy);
2811 return aStr;
2814 // These defines parametrize the created raster
2815 // for interactions
2816 #define DRAG_CROOK_RASTER_MINIMUM (4)
2817 #define DRAG_CROOK_RASTER_MAXIMUM (15)
2818 #define DRAG_CROOK_RASTER_DISTANCE (30)
2820 static basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView const & rPageView, const tools::Rectangle& rMarkRect)
2822 basegfx::B2DPolyPolygon aRetval;
2824 if(rPageView.PageWindowCount())
2826 OutputDevice& rOut = rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice();
2827 tools::Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect);
2828 sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE);
2829 sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE);
2831 if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM)
2832 nHorDiv = DRAG_CROOK_RASTER_MAXIMUM;
2833 if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM)
2834 nHorDiv = DRAG_CROOK_RASTER_MINIMUM;
2836 if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM)
2837 nVerDiv = DRAG_CROOK_RASTER_MAXIMUM;
2838 if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM)
2839 nVerDiv = DRAG_CROOK_RASTER_MINIMUM;
2841 const double fXLen(rMarkRect.GetWidth() / static_cast<double>(nHorDiv));
2842 const double fYLen(rMarkRect.GetHeight() / static_cast<double>(nVerDiv));
2843 double fYPos(rMarkRect.Top());
2844 sal_uInt32 a, b;
2846 for(a = 0; a <= nVerDiv; a++)
2848 // horizontal lines
2849 for(b = 0; b < nHorDiv; b++)
2851 basegfx::B2DPolygon aHorLineSegment;
2853 const double fNewX(rMarkRect.Left() + (b * fXLen));
2854 aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos));
2855 aHorLineSegment.appendBezierSegment(
2856 basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos),
2857 basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos),
2858 basegfx::B2DPoint(fNewX + fXLen, fYPos));
2859 aRetval.append(aHorLineSegment);
2862 // increments
2863 fYPos += fYLen;
2866 double fXPos(rMarkRect.Left());
2868 for(a = 0; a <= nHorDiv; a++)
2870 // vertical lines
2871 for(b = 0; b < nVerDiv; b++)
2873 basegfx::B2DPolygon aVerLineSegment;
2875 const double fNewY(rMarkRect.Top() + (b * fYLen));
2876 aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY));
2877 aVerLineSegment.appendBezierSegment(
2878 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))),
2879 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))),
2880 basegfx::B2DPoint(fXPos, fNewY + fYLen));
2881 aRetval.append(aVerLineSegment);
2884 // increments
2885 fXPos += fXLen;
2889 return aRetval;
2892 void SdrDragCrook::createSdrDragEntries()
2894 // Add extended frame raster first, so it will be behind objects
2895 if(getSdrDragView().GetSdrPageView())
2897 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
2899 if(aDragRaster.count())
2901 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
2905 // call parent
2906 SdrDragMethod::createSdrDragEntries();
2909 bool SdrDragCrook::BeginSdrDrag()
2911 bContortionAllowed=getSdrDragView().IsCrookAllowed();
2912 bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true);
2913 bResizeAllowed=getSdrDragView().IsResizeAllowed();
2914 bRotateAllowed=getSdrDragView().IsRotateAllowed();
2916 if (bContortionAllowed || bNoContortionAllowed)
2918 bVertical=(GetDragHdlKind()==SdrHdlKind::Lower || GetDragHdlKind()==SdrHdlKind::Upper);
2919 aMarkRect=GetMarkedRect();
2920 aMarkCenter=aMarkRect.Center();
2921 nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1);
2922 aCenter=aMarkCenter;
2923 aStart=DragStat().GetStart();
2924 Show();
2925 return true;
2927 else
2929 return false;
2933 void SdrDragCrook::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
2935 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
2937 if(!pPV)
2938 return;
2940 XPolyPolygon aTempPolyPoly(rTarget);
2942 if (pPV->HasMarkedObjPageView())
2944 sal_uInt16 nPolyCount=aTempPolyPoly.Count();
2946 if (!bContortion && !getSdrDragView().IsNoDragXorPolys())
2948 sal_uInt16 n1st=0,nLast=0;
2949 Point aC(aCenter);
2951 while (n1st<nPolyCount)
2953 nLast=n1st;
2954 while (nLast<nPolyCount && aTempPolyPoly[nLast].GetPointCount()!=0) nLast++;
2955 tools::Rectangle aBound(aTempPolyPoly[n1st].GetBoundRect());
2956 sal_uInt16 i;
2958 for (i=n1st+1; i<nLast; i++)
2960 aBound.Union(aTempPolyPoly[n1st].GetBoundRect());
2963 Point aCtr0(aBound.Center());
2964 Point aCtr1(aCtr0);
2966 if (bResize)
2968 Fraction aFact1(1,1);
2970 if (bVertical)
2972 ResizePoint(aCtr1,aC,aFact1,aFact);
2974 else
2976 ResizePoint(aCtr1,aC,aFact,aFact1);
2980 bool bRotOk=false;
2981 double nSin=0,nCos=0;
2983 if (aRad.X()!=0 && aRad.Y()!=0)
2985 bRotOk=bRotate;
2987 switch (eMode)
2989 case SdrCrookMode::Rotate : CrookRotateXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2990 case SdrCrookMode::Slant : CrookSlantXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2991 case SdrCrookMode::Stretch: CrookStretchXPoint(aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical,aMarkRect); break;
2992 } // switch
2995 aCtr1-=aCtr0;
2997 for (i=n1st; i<nLast; i++)
2999 if (bRotOk)
3001 RotateXPoly(aTempPolyPoly[i],aCtr0,nSin,nCos);
3004 aTempPolyPoly[i].Move(aCtr1.X(),aCtr1.Y());
3007 n1st=nLast+1;
3010 else
3012 sal_uInt16 i,j;
3014 for (j=0; j<nPolyCount; j++)
3016 XPolygon& aPol=aTempPolyPoly[j];
3017 sal_uInt16 nPointCount=aPol.GetPointCount();
3018 i=0;
3020 while (i<nPointCount)
3022 Point* pPnt=&aPol[i];
3023 Point* pC1=nullptr;
3024 Point* pC2=nullptr;
3026 if (i+1<nPointCount && aPol.IsControl(i))
3027 { // control point on the left
3028 pC1=pPnt;
3029 i++;
3030 pPnt=&aPol[i];
3033 i++;
3035 if (i<nPointCount && aPol.IsControl(i))
3036 { // control point on the right
3037 pC2=&aPol[i];
3038 i++;
3041 MovCrookPoint(*pPnt,pC1,pC2);
3047 rTarget = aTempPolyPoly.getB2DPolyPolygon();
3050 void SdrDragCrook::MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2)
3052 bool bVert=bVertical;
3053 bool bC1=pC1!=nullptr;
3054 bool bC2=pC2!=nullptr;
3055 Point aC(aCenter);
3057 if (bResize)
3059 Fraction aFact1(1,1);
3061 if (bVert)
3063 ResizePoint(rPnt,aC,aFact1,aFact);
3065 if (bC1)
3066 ResizePoint(*pC1,aC,aFact1,aFact);
3068 if (bC2)
3069 ResizePoint(*pC2,aC,aFact1,aFact);
3071 else
3073 ResizePoint(rPnt,aC,aFact,aFact1);
3075 if (bC1)
3076 ResizePoint(*pC1,aC,aFact,aFact1);
3078 if (bC2)
3079 ResizePoint(*pC2,aC,aFact,aFact1);
3083 if (aRad.X()!=0 && aRad.Y()!=0)
3085 double nSin,nCos;
3087 switch (eMode)
3089 case SdrCrookMode::Rotate : CrookRotateXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3090 case SdrCrookMode::Slant : CrookSlantXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3091 case SdrCrookMode::Stretch: CrookStretchXPoint(rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert,aMarkRect); break;
3092 } // switch
3096 void SdrDragCrook::MoveSdrDrag(const Point& rPnt)
3098 if (!DragStat().CheckMinMoved(rPnt))
3099 return;
3101 bool bNewMoveOnly=getSdrDragView().IsMoveOnlyDragging();
3102 bAtCenter=false;
3103 SdrCrookMode eNewMode=getSdrDragView().GetCrookMode();
3104 bool bNewContortion=!bNewMoveOnly && ((bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed);
3105 bResize=!getSdrDragView().IsOrtho() && bResizeAllowed && !bNewMoveOnly;
3106 bool bNewRotate=bRotateAllowed && !bNewContortion && !bNewMoveOnly && eNewMode==SdrCrookMode::Rotate;
3108 Point aPnt(GetSnapPos(rPnt));
3110 Point aNewCenter(aMarkCenter.X(),aStart.Y());
3112 if (bVertical)
3114 aNewCenter.setX(aStart.X() );
3115 aNewCenter.setY(aMarkCenter.Y() );
3118 if (!getSdrDragView().IsCrookAtCenter())
3120 switch (GetDragHdlKind())
3122 case SdrHdlKind::UpperLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3123 case SdrHdlKind::Upper: aNewCenter.setY(aMarkRect.Bottom() ); bUpr=true; break;
3124 case SdrHdlKind::UpperRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3125 case SdrHdlKind::Left : aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3126 case SdrHdlKind::Right: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3127 case SdrHdlKind::LowerLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3128 case SdrHdlKind::Lower: aNewCenter.setY(aMarkRect.Top() ); bLwr=true; break;
3129 case SdrHdlKind::LowerRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3130 default: bAtCenter=true;
3133 else
3134 bAtCenter=true;
3136 Fraction aNewFract(1,1);
3137 tools::Long dx1=aPnt.X()-aNewCenter.X();
3138 tools::Long dy1=aPnt.Y()-aNewCenter.Y();
3139 bValid=bVertical ? dx1!=0 : dy1!=0;
3141 if (bValid)
3143 if (bVertical)
3144 bValid = std::abs(dx1)*100>std::abs(dy1);
3145 else
3146 bValid = std::abs(dy1)*100>std::abs(dx1);
3149 tools::Long nNewRad=0;
3150 nAngle=0_deg100;
3152 if (bValid)
3154 double a=0; // slope of the radius
3155 Degree100 nPntAngle(0);
3157 if (bVertical)
3159 a=static_cast<double>(dy1)/static_cast<double>(dx1); // slope of the radius
3160 nNewRad=(static_cast<tools::Long>(dy1*a)+dx1) /2;
3161 aNewCenter.AdjustX(nNewRad );
3162 nPntAngle=GetAngle(aPnt-aNewCenter);
3164 else
3166 a=static_cast<double>(dx1)/static_cast<double>(dy1); // slope of the radius
3167 nNewRad=(static_cast<tools::Long>(dx1*a)+dy1) /2;
3168 aNewCenter.AdjustY(nNewRad );
3169 nPntAngle=GetAngle(aPnt-aNewCenter)-9000_deg100;
3172 if (!bAtCenter)
3174 if (nNewRad<0)
3176 if (bRgt) nPntAngle += 18000_deg100;
3177 if (bLft) nPntAngle = 18000_deg100 - nPntAngle;
3178 if (bLwr) nPntAngle =- nPntAngle;
3180 else
3182 if (bRgt) nPntAngle = -nPntAngle;
3183 if (bUpr) nPntAngle = 18000_deg100 - nPntAngle;
3184 if (bLwr) nPntAngle += 18000_deg100;
3187 nPntAngle=NormAngle36000(nPntAngle);
3189 else
3191 if (nNewRad<0) nPntAngle += 18000_deg100;
3192 if (bVertical) nPntAngle = 18000_deg100 - nPntAngle;
3193 nPntAngle = NormAngle18000(nPntAngle);
3194 nPntAngle = abs(nPntAngle);
3197 double nCircumference = 2 * std::abs(nNewRad) * M_PI;
3199 if (bResize)
3201 tools::Long nMul=static_cast<tools::Long>(nCircumference * NormAngle36000(nPntAngle).get() / 36000.0);
3203 if (bAtCenter)
3204 nMul*=2;
3206 aNewFract=Fraction(nMul,nMarkSize);
3207 nAngle=nPntAngle;
3209 else
3211 nAngle = Degree100(static_cast<tools::Long>((nMarkSize*360/nCircumference)*100)/2);
3213 if (nAngle==0_deg100)
3214 bValid=false;
3218 if (nAngle==0_deg100 || nNewRad==0)
3219 bValid=false;
3221 if (!bValid)
3222 nNewRad=0;
3224 if (!bValid && bResize)
3226 tools::Long nMul=bVertical ? dy1 : dx1;
3228 if (bLft || bUpr)
3229 nMul=-nMul;
3231 tools::Long nDiv=nMarkSize;
3233 if (bAtCenter)
3235 nMul*=2;
3236 nMul = std::abs(nMul);
3239 aNewFract=Fraction(nMul,nDiv);
3242 if (aNewCenter==aCenter && bNewContortion==bContortion && aNewFract==aFact &&
3243 bNewMoveOnly == getMoveOnly() && bNewRotate==bRotate && eNewMode==eMode)
3244 return;
3246 Hide();
3247 setMoveOnly(bNewMoveOnly);
3248 bRotate=bNewRotate;
3249 eMode=eNewMode;
3250 bContortion=bNewContortion;
3251 aCenter=aNewCenter;
3252 aFact=aNewFract;
3253 aRad=Point(nNewRad,nNewRad);
3254 bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid();
3255 DragStat().NextMove(aPnt);
3256 Show();
3259 void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3261 const bool bDoResize(aFact!=Fraction(1,1));
3262 const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0);
3264 if (!(bDoCrook || bDoResize))
3265 return;
3267 if (bDoResize)
3269 Fraction aFact1(1,1);
3271 if (bContortion)
3273 if (bVertical)
3275 rTarget.Resize(aCenter,aFact1,aFact);
3277 else
3279 rTarget.Resize(aCenter,aFact,aFact1);
3282 else
3284 Point aCtr0(rTarget.GetSnapRect().Center());
3285 Point aCtr1(aCtr0);
3287 if (bVertical)
3289 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3291 else
3293 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3296 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3298 rTarget.Move(aSiz);
3302 if (bDoCrook)
3304 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
3305 const bool bLocalRotate(!bContortion && eMode == SdrCrookMode::Rotate && getSdrDragView().IsRotateAllowed());
3307 SdrEditView::ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect);
3311 void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3313 // use helper derived from old stuff
3314 MovAllPoints(rTarget);
3317 bool SdrDragCrook::EndSdrDrag(bool bCopy)
3319 Hide();
3321 if (bResize && aFact==Fraction(1,1))
3322 bResize=false;
3324 const bool bUndo = getSdrDragView().IsUndoEnabled();
3326 bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0;
3328 if (bDoCrook || bResize)
3330 if (bResize && bUndo)
3332 OUString aStr = ImpGetDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion);
3334 if (bCopy)
3335 aStr += SvxResId(STR_EditWithCopy);
3337 getSdrDragView().BegUndo(aStr);
3340 if (bResize)
3342 Fraction aFact1(1,1);
3344 if (bContortion)
3346 if (bVertical)
3347 getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy);
3348 else
3349 getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy);
3351 else
3353 if (bCopy)
3354 getSdrDragView().CopyMarkedObj();
3356 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
3357 const size_t nMarkCount=rMarkList.GetMarkCount();
3359 for (size_t nm=0; nm<nMarkCount; ++nm)
3361 SdrMark* pM=rMarkList.GetMark(nm);
3362 SdrObject* pO=pM->GetMarkedSdrObj();
3363 Point aCtr0(pO->GetSnapRect().Center());
3364 Point aCtr1(aCtr0);
3366 if (bVertical)
3367 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3368 else
3369 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3371 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3372 if( bUndo )
3373 AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz));
3374 pO->Move(aSiz);
3378 bCopy=false;
3381 if (bDoCrook)
3383 getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy);
3386 if (bResize && bUndo)
3387 getSdrDragView().EndUndo();
3389 return true;
3392 return false;
3395 PointerStyle SdrDragCrook::GetSdrDragPointer() const
3397 return PointerStyle::Crook;
3401 SdrDragDistort::SdrDragDistort(SdrDragView& rNewView)
3402 : SdrDragMethod(rNewView),
3403 nPolyPt(0),
3404 bContortionAllowed(false),
3405 bNoContortionAllowed(false),
3406 bContortion(false)
3410 OUString SdrDragDistort::GetSdrDragComment() const
3412 OUString aStr = ImpGetDescriptionStr(STR_DragMethDistort)
3413 + " (x="
3414 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
3415 + " y="
3416 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
3417 + ")";
3419 if(getSdrDragView().IsDragWithCopy())
3420 aStr += SvxResId(STR_EditWithCopy);
3421 return aStr;
3424 void SdrDragDistort::createSdrDragEntries()
3426 // Add extended frame raster first, so it will be behind objects
3427 if(getSdrDragView().GetSdrPageView())
3429 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
3431 if(aDragRaster.count())
3433 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
3437 // call parent
3438 SdrDragMethod::createSdrDragEntries();
3441 bool SdrDragDistort::BeginSdrDrag()
3443 bContortionAllowed=getSdrDragView().IsDistortAllowed();
3444 bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true);
3446 if (bContortionAllowed || bNoContortionAllowed)
3448 SdrHdlKind eKind=GetDragHdlKind();
3449 nPolyPt=0xFFFF;
3451 if (eKind==SdrHdlKind::UpperLeft) nPolyPt=0;
3452 if (eKind==SdrHdlKind::UpperRight) nPolyPt=1;
3453 if (eKind==SdrHdlKind::LowerRight) nPolyPt=2;
3454 if (eKind==SdrHdlKind::LowerLeft) nPolyPt=3;
3455 if (nPolyPt>3) return false;
3457 aMarkRect=GetMarkedRect();
3458 aDistortedRect=XPolygon(aMarkRect);
3459 Show();
3460 return true;
3462 else
3464 return false;
3468 void SdrDragDistort::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
3470 if (!bContortion)
3471 return;
3473 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
3475 if(pPV && pPV->HasMarkedObjPageView())
3477 basegfx::B2DPolyPolygon aDragPolygon(rTarget);
3478 const basegfx::B2DRange aOriginalRange = vcl::unotools::b2DRectangleFromRectangle(aMarkRect);
3479 const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y());
3480 const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y());
3481 const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y());
3482 const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y());
3484 rTarget = basegfx::utils::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight);
3488 void SdrDragDistort::MoveSdrDrag(const Point& rPnt)
3490 if (!DragStat().CheckMinMoved(rPnt))
3491 return;
3493 Point aPnt(GetSnapPos(rPnt));
3495 if (getSdrDragView().IsOrtho())
3496 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
3498 bool bNewContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed;
3500 if (bNewContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt)
3502 Hide();
3503 aDistortedRect[nPolyPt]=aPnt;
3504 bContortion=bNewContortion;
3505 DragStat().NextMove(aPnt);
3506 Show();
3510 bool SdrDragDistort::EndSdrDrag(bool bCopy)
3512 Hide();
3513 bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0;
3515 if (bDoDistort)
3517 getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy);
3518 return true;
3521 return false;
3524 PointerStyle SdrDragDistort::GetSdrDragPointer() const
3526 return PointerStyle::RefHand;
3529 void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3531 const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0);
3533 if (bDoDistort)
3535 SdrEditView::ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion);
3539 void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3541 // use helper derived from old stuff
3542 MovAllPoints(rTarget);
3546 SdrDragCrop::SdrDragCrop(SdrDragView& rNewView)
3547 : SdrDragObjOwn(rNewView)
3549 // switch off solid dragging for crop; it just makes no sense since showing
3550 // a 50% transparent object above the original will not be visible
3551 setSolidDraggingActive(false);
3554 OUString SdrDragCrop::GetSdrDragComment() const
3556 OUString aStr = ImpGetDescriptionStr(STR_DragMethCrop)
3557 + " (x="
3558 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
3559 + " y="
3560 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
3561 + ")";
3563 if(getSdrDragView().IsDragWithCopy())
3564 aStr += SvxResId(STR_EditWithCopy);
3565 return aStr;
3568 bool SdrDragCrop::BeginSdrDrag()
3570 // call parent
3571 bool bRetval(SdrDragObjOwn::BeginSdrDrag());
3573 if(!GetDragHdl())
3575 // we need the DragHdl, break if not there
3576 bRetval = false;
3579 return bRetval;
3582 bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
3584 Hide();
3586 if(0 == DragStat().GetDX() && 0 == DragStat().GetDY())
3588 // no change, done
3589 return false;
3592 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
3594 if(1 != rMarkList.GetMarkCount())
3596 // Crop only with single Object selected
3597 return false;
3600 // prepare for SdrGrafObj or others. This code has to work with usual
3601 // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from
3602 // Writer. It would be better to handle this in Writer directly, but
3603 // there are currently no easy mechanisms to plug an alternative interaction
3604 // from there
3605 SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
3606 rtl::Reference<SdrObject> pFullDragClone;
3607 bool bExternal(false);
3608 SdrObject* pExternalSdrObject(nullptr);
3610 // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now
3611 // locally, no two-in-one methods any more
3612 if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr)
3614 // If Writer, get the already offered for interaction SdrGrafObj
3615 // and set up for using that replacement object that contains the
3616 // real transformation. That SdrObject is owned and has to be deleted,
3617 // so use a std::unique_ptr with special handling for the protected
3618 // SDrObject destructor
3619 pFullDragClone = pSdrObject->getFullDragClone();
3621 if(dynamic_cast< SdrGrafObj* >(pFullDragClone.get()))
3623 bExternal = true;
3624 pExternalSdrObject = pSdrObject;
3625 pSdrObject = pFullDragClone.get();
3629 // get and check for SdrGrafObj now
3630 SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject );
3632 if(!pObj)
3634 return false;
3637 // no undo for external needed, done there
3638 const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled());
3640 if(bUndo)
3642 OUString aUndoStr = ImpGetDescriptionStr(STR_DragMethCrop);
3644 getSdrDragView().BegUndo( aUndoStr );
3645 getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
3646 // also need attr undo, the SdrGrafCropItem will be changed
3647 getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
3650 // get the original objects transformation
3651 basegfx::B2DHomMatrix aOriginalMatrix;
3652 basegfx::B2DPolyPolygon aPolyPolygon;
3653 bool bShearCorrected(false);
3654 pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
3656 { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
3657 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix);
3659 if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX()))
3661 bShearCorrected = true;
3662 aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3663 aTmpDecomp.getScale(),
3664 -aTmpDecomp.getShearX(),
3665 aTmpDecomp.getRotate(),
3666 aTmpDecomp.getTranslate());
3670 // generate start point of original drag vector in unit coordinates (the
3671 // vis-a-vis of the drag point)
3672 basegfx::B2DPoint aLocalStart(0.0, 0.0);
3673 bool bOnAxis(false);
3675 switch(GetDragHdlKind())
3677 case SdrHdlKind::UpperLeft: aLocalStart.setX(1.0); aLocalStart.setY(1.0); break;
3678 case SdrHdlKind::Upper: aLocalStart.setX(0.5); aLocalStart.setY(1.0); bOnAxis = true; break;
3679 case SdrHdlKind::UpperRight: aLocalStart.setX(0.0); aLocalStart.setY(1.0); break;
3680 case SdrHdlKind::Left : aLocalStart.setX(1.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3681 case SdrHdlKind::Right: aLocalStart.setX(0.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3682 case SdrHdlKind::LowerLeft: aLocalStart.setX(1.0); aLocalStart.setY(0.0); break;
3683 case SdrHdlKind::Lower: aLocalStart.setX(0.5); aLocalStart.setY(0.0); bOnAxis = true; break;
3684 case SdrHdlKind::LowerRight: aLocalStart.setX(0.0); aLocalStart.setY(0.0); break;
3685 default: break;
3688 // create the current drag position in unit coordinates. To get there,
3689 // transform back the DragPoint to UnitCoordinates
3690 basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
3691 aInverse.invert();
3692 basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y()));
3694 // if one of the edge handles is used, limit to X or Y drag only
3695 if(bOnAxis)
3697 if(basegfx::fTools::equal(aLocalStart.getX(), 0.5))
3699 aLocalCurrent.setX(aLocalStart.getX());
3701 else
3703 aLocalCurrent.setY(aLocalStart.getY());
3707 // create internal change in unit coordinates
3708 basegfx::B2DHomMatrix aDiscreteChangeMatrix;
3710 if(!basegfx::fTools::equal(aLocalCurrent.getX(), aLocalStart.getX()))
3712 if(aLocalStart.getX() < 0.5)
3714 aDiscreteChangeMatrix.scale(aLocalCurrent.getX(), 1.0);
3716 else
3718 aDiscreteChangeMatrix.scale(1.0 - aLocalCurrent.getX(), 1.0);
3719 aDiscreteChangeMatrix.translate(aLocalCurrent.getX(), 0.0);
3723 if(!basegfx::fTools::equal(aLocalCurrent.getY(), aLocalStart.getY()))
3725 if(aLocalStart.getY() < 0.5)
3727 aDiscreteChangeMatrix.scale(1.0, aLocalCurrent.getY());
3729 else
3731 aDiscreteChangeMatrix.scale(1.0, 1.0 - aLocalCurrent.getY());
3732 aDiscreteChangeMatrix.translate(0.0, aLocalCurrent.getY());
3736 // We now have the whole executed Crop in UnitCoordinates in
3737 // aDiscreteChangeMatrix, go to concrete sizes now.
3738 // Create the unrotated original rectangle and the unrotated modified
3739 // rectangle as Ranges
3740 const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix);
3742 // prepare unsheared/unrotated versions of the old and new transformation
3743 const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
3744 basegfx::utils::createScaleTranslateB2DHomMatrix(
3745 basegfx::absolute(aOriginalMatrixDecomp.getScale()),
3746 aOriginalMatrixDecomp.getTranslate()));
3748 // create the ranges for these
3749 basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3750 basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3751 aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate);
3752 aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix);
3754 if(bExternal)
3756 // With aLocalStart point (opposed to dragged point), X scale and Y scale,
3757 // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
3758 // crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
3759 // the called instance knows best how to use it
3760 const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
3761 const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
3763 pExternalSdrObject->Crop(
3764 aLocalStart,
3765 fScaleX,
3766 fScaleY);
3768 else
3770 // prepare matrix to apply to object; evtl. back-correct shear
3771 basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
3773 if(bShearCorrected)
3775 // back-correct shear
3776 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix);
3778 aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3779 aTmpDecomp.getScale(),
3780 -aTmpDecomp.getShearX(),
3781 aTmpDecomp.getRotate(),
3782 aTmpDecomp.getTranslate());
3785 // apply change to object by applying the unit coordinate change followed
3786 // by the original change
3787 pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
3789 // extract the old Rectangle structures
3790 tools::Rectangle aOldRect(
3791 basegfx::fround<tools::Long>(aRangeOriginalNoShearNoRotate.getMinX()),
3792 basegfx::fround<tools::Long>(aRangeOriginalNoShearNoRotate.getMinY()),
3793 basegfx::fround<tools::Long>(aRangeOriginalNoShearNoRotate.getMaxX()),
3794 basegfx::fround<tools::Long>(aRangeOriginalNoShearNoRotate.getMaxY()));
3795 tools::Rectangle aNewRect(
3796 basegfx::fround<tools::Long>(aRangeNewNoShearNoRotate.getMinX()),
3797 basegfx::fround<tools::Long>(aRangeNewNoShearNoRotate.getMinY()),
3798 basegfx::fround<tools::Long>(aRangeNewNoShearNoRotate.getMaxX()),
3799 basegfx::fround<tools::Long>(aRangeNewNoShearNoRotate.getMaxY()));
3801 // continue with the old original stuff
3802 if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
3804 throw o3tl::divide_by_zero();
3807 if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default))
3809 return false;
3812 const GraphicObject& rGraphicObject(pObj->GetGraphicObject());
3813 // tdf#117145 Usually Writer will go the bExternal path (see above), but more correct for
3814 // the future is to use the MapMode from the SdrModel/SfxItemPool if the Writer's current
3815 // special handling should be unified to this path in the future. Usually it *should* be
3816 // MapUnit::Map100thMM, but better do not mix up Units.
3817 // Checked now what SwVirtFlyDrawObj::NbcCrop is doing - it calculates everything forced
3818 // to MapUnit::Map100thMM, but extracts/packs Twips to the used SdrGrafCropItem in Writer.
3819 const MapMode aMapModePool(pObj->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
3820 Size aGraphicSize(rGraphicObject.GetPrefSize());
3822 if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit())
3824 aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapModePool);
3826 else
3828 aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapModePool);
3831 if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height())
3833 return false;
3836 const SdrGrafCropItem& rOldCrop = pObj->GetMergedItem(SDRATTR_GRAFCROP);
3837 double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / static_cast<double>(aOldRect.GetWidth());
3838 double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / static_cast<double>(aOldRect.GetHeight());
3840 sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
3841 sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
3842 sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
3843 sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
3845 if(pObj->IsMirrored())
3847 // mirrored X or Y, for old stuff, exchange X
3848 // check for aw080
3849 sal_Int32 nTmp(nDiffLeft);
3850 nDiffLeft = -nDiffRight;
3851 nDiffRight = -nTmp;
3854 sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
3855 sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
3856 sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
3857 sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
3859 SfxItemPool& rPool = getSdrDragView().GetModel().GetItemPool();
3860 SfxItemSetFixed<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP> aSet( rPool );
3861 aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
3862 getSdrDragView().SetAttributes( aSet, false );
3865 if(bUndo)
3867 getSdrDragView().EndUndo();
3870 return true;
3873 PointerStyle SdrDragCrop::GetSdrDragPointer() const
3875 return PointerStyle::Crop;
3878 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */