Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / svdraw / svddrgmt.cxx
blob166b174c89bed90242adbbb5ffa4fe32990aee42
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 <comphelper/lok.hxx>
71 #include <map>
72 #include <vector>
75 SdrDragEntry::SdrDragEntry()
76 : mbAddToTransparent(false)
80 SdrDragEntry::~SdrDragEntry()
85 SdrDragEntryPolyPolygon::SdrDragEntryPolyPolygon(basegfx::B2DPolyPolygon aOriginalPolyPolygon)
86 : maOriginalPolyPolygon(std::move(aOriginalPolyPolygon))
90 SdrDragEntryPolyPolygon::~SdrDragEntryPolyPolygon()
94 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPolyPolygon::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
96 drawinglayer::primitive2d::Primitive2DContainer aRetval;
98 if(maOriginalPolyPolygon.count())
100 basegfx::B2DPolyPolygon aCopy(maOriginalPolyPolygon);
102 rDragMethod.applyCurrentTransformationToPolyPolygon(aCopy);
103 basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
104 basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
105 const double fStripeLength(SvtOptionsDrawinglayer::GetStripeLength());
107 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
109 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
110 aColB.invert();
113 aRetval.resize(2);
114 aRetval[0] = new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
115 aCopy,
116 aColA,
117 aColB,
118 fStripeLength);
120 const basegfx::BColor aHilightColor(SvtOptionsDrawinglayer::getHilightColor().getBColor());
121 const double fTransparence(SvtOptionsDrawinglayer::GetTransparentSelectionPercent() * 0.01);
123 aRetval[1] = new drawinglayer::primitive2d::PolyPolygonSelectionPrimitive2D(
124 std::move(aCopy),
125 aHilightColor,
126 fTransparence,
127 3.0,
128 false);
131 return aRetval;
135 SdrDragEntrySdrObject::SdrDragEntrySdrObject(
136 const SdrObject& rOriginal,
137 bool bModify)
138 : maOriginal(rOriginal),
139 mbModify(bModify)
141 // add SdrObject parts to transparent overlay stuff
142 setAddToTransparent(true);
145 SdrDragEntrySdrObject::~SdrDragEntrySdrObject()
149 void SdrDragEntrySdrObject::prepareCurrentState(SdrDragMethod& rDragMethod)
151 // for the moment, i need to re-create the clone in all cases. I need to figure
152 // out when clone and original have the same class, so that i can use operator=
153 // in those cases
155 mxClone.clear();
157 if(mbModify)
159 mxClone = maOriginal.getFullDragClone();
161 // apply original transformation, implemented at the DragMethods
162 rDragMethod.applyCurrentTransformationToSdrObject(*mxClone);
166 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntrySdrObject::createPrimitive2DSequenceInCurrentState(SdrDragMethod&)
168 const SdrObject* pSource = &maOriginal;
170 if(mbModify && mxClone)
172 // choose source for geometry data
173 pSource = mxClone.get();
176 // use the view-independent primitive representation (without
177 // evtl. GridOffset, that may be applied to the DragEntry individually)
178 drawinglayer::primitive2d::Primitive2DContainer xRetval;
179 pSource->GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
180 return xRetval;
184 SdrDragEntryPrimitive2DSequence::SdrDragEntryPrimitive2DSequence(
185 drawinglayer::primitive2d::Primitive2DContainer&& rSequence)
186 : maPrimitive2DSequence(std::move(rSequence))
188 // add parts to transparent overlay stuff if necessary
189 setAddToTransparent(true);
192 SdrDragEntryPrimitive2DSequence::~SdrDragEntryPrimitive2DSequence()
196 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPrimitive2DSequence::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
198 drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(
199 new drawinglayer::primitive2d::TransformPrimitive2D(
200 rDragMethod.getCurrentTransformation(),
201 drawinglayer::primitive2d::Primitive2DContainer(maPrimitive2DSequence)));
203 return drawinglayer::primitive2d::Primitive2DContainer { aTransformPrimitive2D };
207 SdrDragEntryPointGlueDrag::SdrDragEntryPointGlueDrag(std::vector< basegfx::B2DPoint >&& rPositions, bool bIsPointDrag)
208 : maPositions(std::move(rPositions)),
209 mbIsPointDrag(bIsPointDrag)
211 // add SdrObject parts to transparent overlay stuff
212 setAddToTransparent(true);
215 SdrDragEntryPointGlueDrag::~SdrDragEntryPointGlueDrag()
219 drawinglayer::primitive2d::Primitive2DContainer SdrDragEntryPointGlueDrag::createPrimitive2DSequenceInCurrentState(SdrDragMethod& rDragMethod)
221 drawinglayer::primitive2d::Primitive2DContainer aRetval;
223 if(!maPositions.empty())
225 basegfx::B2DPolygon aPolygon;
227 for(auto const & a: maPositions)
229 aPolygon.append(a);
232 basegfx::B2DPolyPolygon aPolyPolygon(aPolygon);
234 rDragMethod.applyCurrentTransformationToPolyPolygon(aPolyPolygon);
236 const basegfx::B2DPolygon aTransformed(aPolyPolygon.getB2DPolygon(0));
237 std::vector< basegfx::B2DPoint > aTransformedPositions;
239 aTransformedPositions.reserve(aTransformed.count());
241 for(sal_uInt32 a = 0; a < aTransformed.count(); a++)
243 aTransformedPositions.push_back(aTransformed.getB2DPoint(a));
246 if(mbIsPointDrag)
248 basegfx::BColor aColor(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
250 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
252 aColor = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
255 drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
256 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
257 drawinglayer::primitive2d::createDefaultCross_3x3(aColor)));
259 aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
261 else
263 drawinglayer::primitive2d::Primitive2DReference aMarkerArrayPrimitive2D(
264 new drawinglayer::primitive2d::MarkerArrayPrimitive2D(std::move(aTransformedPositions),
265 SdrHdl::createGluePointBitmap()));
266 aRetval = drawinglayer::primitive2d::Primitive2DContainer { aMarkerArrayPrimitive2D };
270 return aRetval;
274 void SdrDragMethod::resetSdrDragEntries()
276 // clear entries; creation is on demand
277 clearSdrDragEntries();
280 basegfx::B2DRange SdrDragMethod::getCurrentRange() const
282 return maOverlayObjectList.getBaseRange();
285 void SdrDragMethod::clearSdrDragEntries()
287 maSdrDragEntries.clear();
290 void SdrDragMethod::addSdrDragEntry(std::unique_ptr<SdrDragEntry> pNew)
292 assert(pNew);
293 maSdrDragEntries.push_back(std::move(pNew));
296 void SdrDragMethod::createSdrDragEntries()
298 if(!(getSdrDragView().GetSdrPageView() && getSdrDragView().GetSdrPageView()->HasMarkedObjPageView()))
299 return;
301 if(getSdrDragView().IsDraggingPoints())
303 createSdrDragEntries_PointDrag();
305 else if(getSdrDragView().IsDraggingGluePoints())
307 createSdrDragEntries_GlueDrag();
309 else
311 if(getSolidDraggingActive())
313 createSdrDragEntries_SolidDrag();
315 else
317 createSdrDragEntries_PolygonDrag();
322 void SdrDragMethod::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
324 // add full object drag; Clone() at the object has to work
325 // for this
326 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(rOriginal, true/*bModify*/)));
329 void SdrDragMethod::insertNewlyCreatedOverlayObjectForSdrDragMethod(
330 std::unique_ptr<sdr::overlay::OverlayObject> pOverlayObject,
331 const sdr::contact::ObjectContact& rObjectContact,
332 sdr::overlay::OverlayManager& rOverlayManager)
334 // check if we have an OverlayObject
335 if(!pOverlayObject)
337 return;
340 // add to OverlayManager
341 rOverlayManager.add(*pOverlayObject);
343 // Add GridOffset for non-linear ViewToDevice transformation (calc)
344 if(rObjectContact.supportsGridOffsets())
346 const basegfx::B2DRange& rNewRange(pOverlayObject->getBaseRange());
348 if(!rNewRange.isEmpty())
350 basegfx::B2DVector aOffset(0.0, 0.0);
351 rObjectContact.calculateGridOffsetForB2DRange(aOffset, rNewRange);
353 if(!aOffset.equalZero())
355 pOverlayObject->setOffset(aOffset);
360 // add to local OverlayObjectList - ownership change (!)
361 maOverlayObjectList.append(std::move(pOverlayObject));
364 void SdrDragMethod::createSdrDragEntries_SolidDrag()
366 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
367 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
369 if(!pPV)
370 return;
372 for(size_t a = 0; a < nMarkCount; ++a)
374 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
376 if(pM->GetPageView() == pPV)
378 const SdrObject* pObject = pM->GetMarkedSdrObj();
380 if(pObject)
382 if(pPV->PageWindowCount())
384 SdrObjListIter aIter(*pObject);
386 while(aIter.IsMore())
388 SdrObject* pCandidate = aIter.Next();
390 if(pCandidate)
392 const bool bSuppressFullDrag(!pCandidate->supportsFullDrag());
393 bool bAddWireframe(bSuppressFullDrag);
395 if(!bAddWireframe && !pCandidate->HasLineStyle())
397 // add wireframe for objects without outline
398 bAddWireframe = true;
401 if(!bSuppressFullDrag)
403 // add full object drag; Clone() at the object has to work
404 // for this
405 createSdrDragEntryForSdrObject(*pCandidate);
408 if(bAddWireframe)
410 // when dragging a 50% transparent copy of a filled or not filled object without
411 // outline, this is normally hard to see. Add extra wireframe in that case. This
412 // works nice e.g. with text frames etc.
413 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(pCandidate->TakeXorPoly())));
423 void SdrDragMethod::createSdrDragEntries_PolygonDrag()
425 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
426 bool bNoPolygons(getSdrDragView().IsNoDragXorPolys() || nMarkCount > SdrDragView::GetDragXorPolyLimit());
427 basegfx::B2DPolyPolygon aResult;
428 sal_uInt32 nPointCount(0);
430 for(size_t a = 0; !bNoPolygons && a < nMarkCount; ++a)
432 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(a);
434 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
436 const basegfx::B2DPolyPolygon aNewPolyPolygon(pM->GetMarkedSdrObj()->TakeXorPoly());
438 for(auto const& rPolygon : aNewPolyPolygon)
440 nPointCount += rPolygon.count();
443 if(nPointCount > SdrDragView::GetDragXorPointLimit())
445 bNoPolygons = true;
448 if(!bNoPolygons)
450 aResult.append(aNewPolyPolygon);
455 if(bNoPolygons)
457 const tools::Rectangle aR(getSdrDragView().GetSdrPageView()->MarkSnap());
458 const basegfx::B2DRange aNewRectangle = vcl::unotools::b2DRectangleFromRectangle(aR);
459 basegfx::B2DPolygon aNewPolygon(basegfx::utils::createPolygonFromRect(aNewRectangle));
461 aResult = basegfx::B2DPolyPolygon(basegfx::utils::expandToCurve(aNewPolygon));
464 if(aResult.count())
466 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aResult))));
470 void SdrDragMethod::createSdrDragEntries_PointDrag()
472 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
473 std::vector< basegfx::B2DPoint > aPositions;
475 for(size_t nm = 0; nm < nMarkCount; ++nm)
477 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
479 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
481 const SdrUShortCont& rPts = pM->GetMarkedPoints();
483 if (!rPts.empty())
485 const SdrObject* pObj = pM->GetMarkedSdrObj();
486 const SdrPathObj* pPath = dynamic_cast< const SdrPathObj* >(pObj);
488 if(pPath)
490 const basegfx::B2DPolyPolygon& aPathXPP = pPath->GetPathPoly();
492 if(aPathXPP.count())
494 for(const sal_uInt16 nObjPt : rPts)
496 sal_uInt32 nPolyNum, nPointNum;
498 if(sdr::PolyPolygonEditor::GetRelativePolyPoint(aPathXPP, nObjPt, nPolyNum, nPointNum))
500 aPositions.push_back(aPathXPP.getB2DPolygon(nPolyNum).getB2DPoint(nPointNum));
509 if(!aPositions.empty())
511 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), true)));
515 void SdrDragMethod::createSdrDragEntries_GlueDrag()
517 const size_t nMarkCount(getSdrDragView().GetMarkedObjectCount());
518 std::vector< basegfx::B2DPoint > aPositions;
520 for(size_t nm = 0; nm < nMarkCount; ++nm)
522 SdrMark* pM = getSdrDragView().GetSdrMarkByIndex(nm);
524 if(pM->GetPageView() == getSdrDragView().GetSdrPageView())
526 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
528 if (!rPts.empty())
530 const SdrObject* pObj = pM->GetMarkedSdrObj();
531 const SdrGluePointList* pGPL = pObj->GetGluePointList();
533 if (pGPL)
535 for(const sal_uInt16 nObjPt : rPts)
537 const sal_uInt16 nGlueNum(pGPL->FindGluePoint(nObjPt));
539 if(SDRGLUEPOINT_NOTFOUND != nGlueNum)
541 const Point aPoint((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
542 aPositions.emplace_back(aPoint.X(), aPoint.Y());
550 if(!aPositions.empty())
552 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPointGlueDrag(std::move(aPositions), false)));
556 OUString SdrDragMethod::ImpGetDescriptionStr(TranslateId pStrCacheID) const
558 ImpGetDescriptionOptions nOpt=ImpGetDescriptionOptions::NONE;
559 if (IsDraggingPoints()) {
560 nOpt=ImpGetDescriptionOptions::POINTS;
561 } else if (IsDraggingGluePoints()) {
562 nOpt=ImpGetDescriptionOptions::GLUEPOINTS;
564 return getSdrDragView().ImpGetDescriptionString(pStrCacheID, nOpt);
567 SdrObject* SdrDragMethod::GetDragObj() const
569 SdrObject* pObj=nullptr;
570 if (getSdrDragView().mpDragHdl!=nullptr) pObj=getSdrDragView().mpDragHdl->GetObj();
571 if (pObj==nullptr) pObj=getSdrDragView().mpMarkedObj;
572 return pObj;
575 SdrPageView* SdrDragMethod::GetDragPV() const
577 SdrPageView* pPV=nullptr;
578 if (getSdrDragView().mpDragHdl!=nullptr) pPV=getSdrDragView().mpDragHdl->GetPageView();
579 if (pPV==nullptr) pPV=getSdrDragView().mpMarkedPV;
580 return pPV;
583 void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
585 // the original applies the transformation using TRGetBaseGeometry/TRSetBaseGeometry.
586 // Later this should be the only needed one for linear transforms (not for SdrDragCrook and
587 // SdrDragDistort, those are NOT linear). Currently, this can not yet be used since the
588 // special handling of rotate/mirror due to the not-being-able to handle it in the old
589 // drawinglayer stuff. Text would currently not correctly be mirrored in the preview.
590 basegfx::B2DHomMatrix aObjectTransform;
591 basegfx::B2DPolyPolygon aObjectPolyPolygon;
592 bool bPolyUsed(rTarget.TRGetBaseGeometry(aObjectTransform, aObjectPolyPolygon));
594 // apply transform to object transform
595 aObjectTransform *= getCurrentTransformation();
597 if(bPolyUsed)
599 // do something special since the object size is in the polygon
600 // break up matrix to get the scale
601 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);
603 // get polygon's position and size
604 const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
606 // get the scaling factors (do not mirror, this is in the object transformation)
607 const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
608 const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
610 // prepare transform matrix for polygon
611 basegfx::B2DHomMatrix aPolyTransform(
612 basegfx::utils::createTranslateB2DHomMatrix(
613 -aPolyRange.getMinX(),
614 -aPolyRange.getMinY()));
615 aPolyTransform.scale(fScaleX, fScaleY);
617 // transform the polygon
618 aObjectPolyPolygon.transform(aPolyTransform);
621 rTarget.TRSetBaseGeometry(getCurrentTransformation() * aObjectTransform, aObjectPolyPolygon);
624 void SdrDragMethod::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
626 // original uses CurrentTransformation
627 rTarget.transform(getCurrentTransformation());
630 SdrDragMethod::SdrDragMethod(SdrDragView& rNewView)
631 : mrSdrDragView(rNewView),
632 mbMoveOnly(false),
633 mbSolidDraggingActive(getSdrDragView().IsSolidDragging()),
634 mbShiftPressed(false)
636 if(mbSolidDraggingActive && Application::GetSettings().GetStyleSettings().GetHighContrastMode())
638 // fallback to wireframe when high contrast is used
639 mbSolidDraggingActive = false;
643 SdrDragMethod::~SdrDragMethod()
645 clearSdrDragEntries();
648 void SdrDragMethod::Show()
650 getSdrDragView().ShowDragObj();
653 void SdrDragMethod::Hide()
655 getSdrDragView().HideDragObj();
658 basegfx::B2DHomMatrix SdrDragMethod::getCurrentTransformation() const
660 return basegfx::B2DHomMatrix();
663 void SdrDragMethod::CancelSdrDrag()
665 Hide();
668 typedef std::map< const SdrObject*, SdrObject* > SdrObjectAndCloneMap;
670 void SdrDragMethod::CreateOverlayGeometry(
671 sdr::overlay::OverlayManager& rOverlayManager,
672 const sdr::contact::ObjectContact& rObjectContact)
674 // We do client-side object manipulation with the Kit API
675 if (comphelper::LibreOfficeKit::isActive())
676 return;
678 // create SdrDragEntries on demand
679 if(maSdrDragEntries.empty())
681 createSdrDragEntries();
684 // if there are entries, derive OverlayObjects from the entries, including
685 // modification from current interactive state
686 if(!maSdrDragEntries.empty())
688 // #i54102# SdrDragEntrySdrObject creates clones of SdrObjects as base for creating the needed
689 // primitives, holding the original and the clone. If connectors (Edges) are involved,
690 // the cloned connectors need to be connected to the cloned SdrObjects (after cloning
691 // they are connected to the original SdrObjects). To do so, trigger the preparation
692 // steps for SdrDragEntrySdrObject, save an association of (orig, clone) in a helper
693 // and evtl. remember if it was an edge
694 SdrObjectAndCloneMap aOriginalAndClones;
695 std::vector< SdrEdgeObj* > aEdges;
697 // #i54102# execute prepareCurrentState for all SdrDragEntrySdrObject, register pair of original and
698 // clone, remember edges
699 for(auto const & a: maSdrDragEntries)
701 SdrDragEntrySdrObject* pSdrDragEntrySdrObject = dynamic_cast< SdrDragEntrySdrObject*>(a.get());
703 if(pSdrDragEntrySdrObject)
705 pSdrDragEntrySdrObject->prepareCurrentState(*this);
707 SdrEdgeObj* pSdrEdgeObj = dynamic_cast< SdrEdgeObj* >(pSdrDragEntrySdrObject->getClone());
709 if(pSdrEdgeObj)
711 aEdges.push_back(pSdrEdgeObj);
714 if(pSdrDragEntrySdrObject->getClone())
716 aOriginalAndClones[&pSdrDragEntrySdrObject->getOriginal()] = pSdrDragEntrySdrObject->getClone();
721 // #i54102# if there are edges, reconnect their ends to the corresponding clones (if found)
722 for(SdrEdgeObj* pSdrEdgeObj: aEdges)
724 SdrObject* pConnectedTo = pSdrEdgeObj->GetConnectedNode(true);
726 if(pConnectedTo)
728 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
730 if(aEntry != aOriginalAndClones.end())
732 pSdrEdgeObj->ConnectToNode(true, aEntry->second);
736 pConnectedTo = pSdrEdgeObj->GetConnectedNode(false);
738 if(pConnectedTo)
740 SdrObjectAndCloneMap::iterator aEntry = aOriginalAndClones.find(pConnectedTo);
742 if(aEntry != aOriginalAndClones.end())
744 pSdrEdgeObj->ConnectToNode(false, aEntry->second);
749 // collect primitives for visualisation
750 drawinglayer::primitive2d::Primitive2DContainer aResult;
751 drawinglayer::primitive2d::Primitive2DContainer aResultTransparent;
753 for(auto & pCandidate: maSdrDragEntries)
755 const drawinglayer::primitive2d::Primitive2DContainer aCandidateResult(pCandidate->createPrimitive2DSequenceInCurrentState(*this));
757 if(!aCandidateResult.empty())
759 if(pCandidate->getAddToTransparent())
761 aResultTransparent.append(aCandidateResult);
763 else
765 aResult.append(aCandidateResult);
770 if(DoAddConnectorOverlays())
772 const drawinglayer::primitive2d::Primitive2DContainer aConnectorOverlays(AddConnectorOverlays());
774 if(!aConnectorOverlays.empty())
776 // add connector overlays to transparent part
777 aResultTransparent.append(aConnectorOverlays);
781 if(!aResult.empty())
783 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
784 new sdr::overlay::OverlayPrimitive2DSequenceObject(
785 std::move(aResult)));
787 insertNewlyCreatedOverlayObjectForSdrDragMethod(
788 std::move(pNewOverlayObject),
789 rObjectContact,
790 rOverlayManager);
793 if(!aResultTransparent.empty())
795 drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(aResultTransparent), 0.5));
796 aResultTransparent = drawinglayer::primitive2d::Primitive2DContainer { aUnifiedTransparencePrimitive2D };
798 std::unique_ptr<sdr::overlay::OverlayObject> pNewOverlayObject(
799 new sdr::overlay::OverlayPrimitive2DSequenceObject(
800 std::move(aResultTransparent)));
802 insertNewlyCreatedOverlayObjectForSdrDragMethod(
803 std::move(pNewOverlayObject),
804 rObjectContact,
805 rOverlayManager);
809 // add DragStripes if necessary (help lines cross the page when dragging)
810 if(!getSdrDragView().IsDragStripes())
811 return;
813 tools::Rectangle aActionRectangle;
814 getSdrDragView().TakeActionRect(aActionRectangle);
816 const basegfx::B2DPoint aTopLeft(aActionRectangle.Left(), aActionRectangle.Top());
817 const basegfx::B2DPoint aBottomRight(aActionRectangle.Right(), aActionRectangle.Bottom());
818 std::unique_ptr<sdr::overlay::OverlayRollingRectangleStriped> pNew(
819 new sdr::overlay::OverlayRollingRectangleStriped(
820 aTopLeft,
821 aBottomRight,
822 true,
823 false));
825 insertNewlyCreatedOverlayObjectForSdrDragMethod(
826 std::move(pNew),
827 rObjectContact,
828 rOverlayManager);
831 void SdrDragMethod::destroyOverlayGeometry()
833 maOverlayObjectList.clear();
836 bool SdrDragMethod::DoAddConnectorOverlays()
838 // these conditions are translated from SdrDragView::ImpDrawEdgeXor
839 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
841 if(!rMarkedNodes.GetMarkCount())
843 return false;
846 if(getSdrDragView().IsDraggingPoints() || getSdrDragView().IsDraggingGluePoints())
848 return false;
851 if(!getMoveOnly() && !(
852 dynamic_cast<const SdrDragMove*>(this) != nullptr || dynamic_cast<const SdrDragResize*>(this) != nullptr ||
853 dynamic_cast<const SdrDragRotate*>(this) != nullptr || dynamic_cast<const SdrDragMirror*>(this) != nullptr ))
855 return false;
858 // one more migrated from SdrEdgeObj::NspToggleEdgeXor
859 if( dynamic_cast< const SdrDragObjOwn* >(this) != nullptr || dynamic_cast< const SdrDragMovHdl* >(this) != nullptr )
861 return false;
864 return true;
867 drawinglayer::primitive2d::Primitive2DContainer SdrDragMethod::AddConnectorOverlays()
869 drawinglayer::primitive2d::Primitive2DContainer aRetval;
870 const bool bDetail(getMoveOnly());
871 const SdrMarkList& rMarkedNodes = getSdrDragView().GetEdgesOfMarkedNodes();
873 for(size_t a = 0; a < rMarkedNodes.GetMarkCount(); ++a)
875 SdrMark* pEM = rMarkedNodes.GetMark(a);
877 if(pEM && pEM->GetMarkedSdrObj())
879 SdrEdgeObj* pEdge = dynamic_cast< SdrEdgeObj* >(pEM->GetMarkedSdrObj());
881 if(pEdge)
883 basegfx::B2DPolygon aEdgePolygon(pEdge->ImplAddConnectorOverlay(*this, pEM->IsCon1(), pEM->IsCon2(), bDetail));
885 if(aEdgePolygon.count())
887 // this polygon is a temporary calculated connector path, so it is not possible to fetch
888 // the needed primitives directly from the pEdge object which does not get changed. If full
889 // drag is on, use the SdrObjects ItemSet to create an adequate representation
890 bool bUseSolidDragging(getSolidDraggingActive());
892 if(bUseSolidDragging)
894 // switch off solid dragging if connector is not visible
895 if(!pEdge->HasLineStyle())
897 bUseSolidDragging = false;
901 if(bUseSolidDragging)
903 const SfxItemSet& rItemSet = pEdge->GetMergedItemSet();
904 const drawinglayer::attribute::SdrLineAttribute aLine(
905 drawinglayer::primitive2d::createNewSdrLineAttribute(rItemSet));
907 if(!aLine.isDefault())
909 const drawinglayer::attribute::SdrLineStartEndAttribute aLineStartEnd(
910 drawinglayer::primitive2d::createNewSdrLineStartEndAttribute(
911 rItemSet,
912 aLine.getWidth()));
914 aRetval.push_back(drawinglayer::primitive2d::createPolygonLinePrimitive(
915 aEdgePolygon,
916 aLine,
917 aLineStartEnd));
920 else
922 basegfx::BColor aColA(SvtOptionsDrawinglayer::GetStripeColorA().getBColor());
923 basegfx::BColor aColB(SvtOptionsDrawinglayer::GetStripeColorB().getBColor());
924 const double fStripeLength(SvtOptionsDrawinglayer::GetStripeLength());
926 if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
928 aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor().getBColor();
929 aColB.invert();
932 drawinglayer::primitive2d::Primitive2DReference aPolyPolygonMarkerPrimitive2D(
933 new drawinglayer::primitive2d::PolygonMarkerPrimitive2D(
934 std::move(aEdgePolygon), aColA, aColB, fStripeLength));
935 aRetval.push_back(aPolyPolygonMarkerPrimitive2D);
942 return aRetval;
946 SdrDragMovHdl::SdrDragMovHdl(SdrDragView& rNewView)
947 : SdrDragMethod(rNewView)
951 void SdrDragMovHdl::createSdrDragEntries()
953 // SdrDragMovHdl does not use the default drags,
954 // but creates nothing
957 OUString SdrDragMovHdl::GetSdrDragComment() const
959 OUString aStr=SvxResId(STR_DragMethMovHdl);
960 if (getSdrDragView().IsDragWithCopy()) aStr+=SvxResId(STR_EditWithCopy);
961 return aStr;
964 bool SdrDragMovHdl::BeginSdrDrag()
966 if( !GetDragHdl() )
967 return false;
969 DragStat().SetRef1(GetDragHdl()->GetPos());
970 DragStat().SetShown(!DragStat().IsShown());
971 SdrHdlKind eKind=GetDragHdl()->GetKind();
972 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
973 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
975 if (eKind==SdrHdlKind::MirrorAxis)
977 if (pH1==nullptr || pH2==nullptr)
979 OSL_FAIL("SdrDragMovHdl::BeginSdrDrag(): Moving the axis of reflection: reference handles not found.");
980 return false;
983 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
985 else
987 Point aPt(GetDragHdl()->GetPos());
988 DragStat().SetActionRect(tools::Rectangle(aPt,aPt));
991 return true;
994 void SdrDragMovHdl::MoveSdrDrag(const Point& rNoSnapPnt)
996 Point aPnt(rNoSnapPnt);
998 if ( !(GetDragHdl() && DragStat().CheckMinMoved(rNoSnapPnt)))
999 return;
1001 if (GetDragHdl()->GetKind()==SdrHdlKind::MirrorAxis)
1003 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
1004 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
1006 if (pH1==nullptr || pH2==nullptr)
1007 return;
1009 if (!DragStat().IsNoSnap())
1011 tools::Long nBestXSnap=0;
1012 tools::Long nBestYSnap=0;
1013 bool bXSnapped=false;
1014 bool bYSnapped=false;
1015 Point aDif(aPnt-DragStat().GetStart());
1016 getSdrDragView().CheckSnap(Ref1()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1017 getSdrDragView().CheckSnap(Ref2()+aDif,nBestXSnap,nBestYSnap,bXSnapped,bYSnapped);
1018 aPnt.AdjustX(nBestXSnap );
1019 aPnt.AdjustY(nBestYSnap );
1022 if (aPnt!=DragStat().GetNow())
1024 Hide();
1025 DragStat().NextMove(aPnt);
1026 Point aDif(DragStat().GetNow()-DragStat().GetStart());
1027 pH1->SetPos(Ref1()+aDif);
1028 pH2->SetPos(Ref2()+aDif);
1030 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1032 if(pHM)
1033 pHM->Touch();
1035 Show();
1036 DragStat().SetActionRect(tools::Rectangle(pH1->GetPos(),pH2->GetPos()));
1039 else
1041 if (!DragStat().IsNoSnap()) SnapPos(aPnt);
1042 Degree100 nSA(0);
1044 if (getSdrDragView().IsAngleSnapEnabled())
1045 nSA=getSdrDragView().GetSnapAngle();
1047 if (getSdrDragView().IsMirrorAllowed(true,true))
1048 { // limited
1049 if (!getSdrDragView().IsMirrorAllowed()) nSA=4500_deg100;
1050 if (!getSdrDragView().IsMirrorAllowed(true)) nSA=9000_deg100;
1053 if (getSdrDragView().IsOrtho() && nSA!=9000_deg100)
1054 nSA=4500_deg100;
1056 if (nSA)
1057 { // angle snapping
1058 SdrHdlKind eRef=SdrHdlKind::Ref1;
1060 if (GetDragHdl()->GetKind()==SdrHdlKind::Ref1)
1061 eRef=SdrHdlKind::Ref2;
1063 SdrHdl* pH=GetHdlList().GetHdl(eRef);
1065 if (pH!=nullptr)
1067 Point aRef(pH->GetPos());
1068 Degree100 nAngle=NormAngle36000(GetAngle(aPnt-aRef));
1069 Degree100 nNewAngle=nAngle;
1070 nNewAngle+=nSA/2_deg100;
1071 nNewAngle/=nSA;
1072 nNewAngle*=nSA;
1073 nNewAngle=NormAngle36000(nNewAngle);
1074 double a=toRadians(nNewAngle-nAngle);
1075 double nSin=sin(a);
1076 double nCos=cos(a);
1077 RotatePoint(aPnt,aRef,nSin,nCos);
1079 // eliminate rounding errors for certain values
1080 if (nSA==9000_deg100)
1082 if (nNewAngle==0_deg100 || nNewAngle==18000_deg100) aPnt.setY(aRef.Y() );
1083 if (nNewAngle==9000_deg100 || nNewAngle==27000_deg100) aPnt.setX(aRef.X() );
1086 if (nSA==4500_deg100)
1087 OrthoDistance8(aRef,aPnt,true);
1091 if (aPnt!=DragStat().GetNow())
1093 Hide();
1094 DragStat().NextMove(aPnt);
1095 GetDragHdl()->SetPos(DragStat().GetNow());
1096 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1098 if(pHM)
1099 pHM->Touch();
1101 Show();
1102 DragStat().SetActionRect(tools::Rectangle(aPnt,aPnt));
1107 bool SdrDragMovHdl::EndSdrDrag(bool /*bCopy*/)
1109 if( GetDragHdl() )
1111 switch (GetDragHdl()->GetKind())
1113 case SdrHdlKind::Ref1:
1114 Ref1()=DragStat().GetNow();
1115 break;
1117 case SdrHdlKind::Ref2:
1118 Ref2()=DragStat().GetNow();
1119 break;
1121 case SdrHdlKind::MirrorAxis:
1122 Ref1()+=DragStat().GetNow()-DragStat().GetStart();
1123 Ref2()+=DragStat().GetNow()-DragStat().GetStart();
1124 break;
1126 default: break;
1130 return true;
1133 void SdrDragMovHdl::CancelSdrDrag()
1135 Hide();
1137 SdrHdl* pHdl = GetDragHdl();
1138 if( pHdl )
1139 pHdl->SetPos(DragStat().GetRef1());
1141 SdrHdl* pHM = GetHdlList().GetHdl(SdrHdlKind::MirrorAxis);
1143 if(pHM)
1144 pHM->Touch();
1147 PointerStyle SdrDragMovHdl::GetSdrDragPointer() const
1149 const SdrHdl* pHdl = GetDragHdl();
1151 if (pHdl!=nullptr)
1153 return pHdl->GetPointer();
1156 return PointerStyle::RefHand;
1160 SdrDragObjOwn::SdrDragObjOwn(SdrDragView& rNewView)
1161 : SdrDragMethod(rNewView)
1163 const SdrObject* pObj = GetDragObj();
1165 if(pObj)
1167 // suppress full drag for some object types
1168 setSolidDraggingActive(pObj->supportsFullDrag());
1172 SdrDragObjOwn::~SdrDragObjOwn()
1176 void SdrDragObjOwn::createSdrDragEntries()
1178 if(!mxClone)
1179 return;
1181 basegfx::B2DPolyPolygon aDragPolyPolygon;
1182 bool bAddWireframe(true);
1184 if(getSolidDraggingActive())
1186 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
1188 if(pPV && pPV->PageWindowCount())
1190 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntrySdrObject(*mxClone, false)));
1192 // potentially no wireframe needed, full drag works
1193 bAddWireframe = false;
1197 if(!bAddWireframe)
1199 // check for extra conditions for wireframe, e.g. no border at
1200 // objects
1201 if(!mxClone->HasLineStyle())
1203 bAddWireframe = true;
1207 if(bAddWireframe)
1209 // use wireframe poly when full drag is off or did not work
1210 aDragPolyPolygon = mxClone->TakeXorPoly();
1213 // add evtl. extra DragPolyPolygon
1214 const basegfx::B2DPolyPolygon aSpecialDragPolyPolygon(mxClone->getSpecialDragPoly(DragStat()));
1216 if(aSpecialDragPolyPolygon.count())
1218 aDragPolyPolygon.append(aSpecialDragPolyPolygon);
1221 if(aDragPolyPolygon.count())
1223 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(std::move(aDragPolyPolygon))));
1227 OUString SdrDragObjOwn::GetSdrDragComment() const
1229 OUString aStr;
1230 // #i103058# get info string from the clone preferred, the original will
1231 // not be changed. For security, use original as fallback
1232 if(mxClone)
1234 aStr = mxClone->getSpecialDragComment(DragStat());
1236 else
1238 const SdrObject* pObj = GetDragObj();
1240 if(pObj)
1242 aStr = pObj->getSpecialDragComment(DragStat());
1245 return aStr;
1248 bool SdrDragObjOwn::BeginSdrDrag()
1250 if(!mxClone)
1252 const SdrObject* pObj = GetDragObj();
1254 if(pObj && !pObj->IsResizeProtect())
1256 if(pObj->beginSpecialDrag(DragStat()))
1258 // create initial clone to have a start visualization
1259 mxClone = pObj->getFullDragClone();
1260 mxClone->applySpecialDrag(DragStat());
1262 return true;
1267 return false;
1270 void SdrDragObjOwn::MoveSdrDrag(const Point& rNoSnapPnt)
1272 const SdrObject* pObj = GetDragObj();
1274 if (!pObj)
1275 // No object to drag. Bail out.
1276 return;
1278 Point aPnt(rNoSnapPnt);
1279 SdrPageView* pPV = GetDragPV();
1281 if (!pPV)
1282 // No page view available. Bail out.
1283 return;
1285 if(!DragStat().IsNoSnap())
1287 SnapPos(aPnt);
1289 if(getSdrDragView().IsOrtho())
1291 if (DragStat().IsOrtho8Possible())
1293 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1295 else if (DragStat().IsOrtho4Possible())
1297 OrthoDistance4(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1301 if (!DragStat().CheckMinMoved(rNoSnapPnt))
1302 // Not moved by the minimum threshold. Nothing to do.
1303 return;
1305 Hide();
1306 DragStat().NextMove(aPnt);
1308 // since SdrDragObjOwn currently supports no transformation of
1309 // existing SdrDragEntries but only their recreation, a recreation
1310 // after every move is needed in this mode. Delete existing
1311 // SdrDragEntries here to force their recreation in the following Show().
1312 clearSdrDragEntries();
1314 // delete current clone (after the last reference to it is deleted above)
1315 mxClone.clear();
1317 // create a new clone and modify to current drag state
1318 mxClone = pObj->getFullDragClone();
1319 mxClone->applySpecialDrag(DragStat());
1321 // AutoGrowWidth may change for SdrTextObj due to the automatism used
1322 // with bDisableAutoWidthOnDragging, so not only geometry changes but
1323 // also this (pretty indirect) property change is possible. If it gets
1324 // changed, it needs to be copied to the original since nothing will
1325 // happen when it only changes in the drag clone
1326 const bool bOldAutoGrowWidth(pObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1327 const bool bNewAutoGrowWidth(mxClone->GetMergedItem(SDRATTR_TEXT_AUTOGROWWIDTH).GetValue());
1329 if (bOldAutoGrowWidth != bNewAutoGrowWidth)
1331 GetDragObj()->SetMergedItem(makeSdrTextAutoGrowWidthItem(bNewAutoGrowWidth));
1334 Show();
1337 bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
1339 Hide();
1340 std::vector< std::unique_ptr<SdrUndoAction> > vConnectorUndoActions;
1341 bool bRet = false;
1342 SdrObject* pObj = GetDragObj();
1344 if(pObj)
1346 std::unique_ptr<SdrUndoAction> pUndo;
1347 std::unique_ptr<SdrUndoAction> pUndo2;
1348 const bool bUndo = getSdrDragView().IsUndoEnabled();
1350 if( bUndo )
1352 getSdrDragView().EndTextEditCurrentView();
1353 if(!getSdrDragView().IsInsObjPoint() && pObj->IsInserted() )
1355 if (DragStat().IsEndDragChangesAttributes())
1357 pUndo=getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj);
1359 if (DragStat().IsEndDragChangesGeoAndAttributes())
1361 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1362 pUndo2 = getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1365 else
1367 vConnectorUndoActions = getSdrDragView().CreateConnectorUndo( *pObj );
1368 pUndo= getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj);
1372 if( pUndo )
1374 getSdrDragView().BegUndo( pUndo->GetComment() );
1376 else
1378 getSdrDragView().BegUndo();
1382 // Maybe use operator = for setting changed object data (do not change selection in
1383 // view, this will destroy the interactor). This is possible since a clone is now
1384 // directly modified by the modifiers. Only SdrTableObj is adding own UNDOs
1385 // in its SdrTableObj::endSpecialDrag, so currently not possible. OTOH it uses
1386 // a CreateUndoGeoObject(), so maybe setting SetEndDragChangesAttributes is okay. I
1387 // will test this now
1388 tools::Rectangle aBoundRect0;
1390 if(pObj->GetUserCall())
1392 aBoundRect0 = pObj->GetLastBoundRect();
1395 bRet = pObj->applySpecialDrag(DragStat());
1396 if (DragStat().IsEndDragChangesLayout())
1398 auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo.get());
1399 if (pGeoUndo)
1400 pGeoUndo->SetSkipChangeLayout(true);
1403 if(bRet)
1405 pObj->SetChanged();
1406 pObj->BroadcastObjectChange();
1407 pObj->SendUserCall( SdrUserCallType::Resize, aBoundRect0 );
1410 if(bRet && bUndo )
1412 getSdrDragView().AddUndoActions( std::move(vConnectorUndoActions) );
1414 if ( pUndo )
1416 getSdrDragView().AddUndo(std::move(pUndo));
1419 if ( pUndo2 )
1421 getSdrDragView().AddUndo(std::move(pUndo2));
1425 if( bUndo )
1426 getSdrDragView().EndUndo();
1429 return bRet;
1432 PointerStyle SdrDragObjOwn::GetSdrDragPointer() const
1434 const SdrHdl* pHdl=GetDragHdl();
1436 if (pHdl)
1438 return pHdl->GetPointer();
1441 return PointerStyle::Move;
1445 void SdrDragMove::createSdrDragEntryForSdrObject(const SdrObject& rOriginal)
1447 // use the view-independent primitive representation (without
1448 // evtl. GridOffset, that may be applied to the DragEntry individually)
1449 drawinglayer::primitive2d::Primitive2DContainer xRetval;
1450 rOriginal.GetViewContact().getViewIndependentPrimitive2DContainer(xRetval);
1451 addSdrDragEntry(
1452 std::unique_ptr<SdrDragEntry>(
1453 new SdrDragEntryPrimitive2DSequence(
1454 std::move(xRetval))));
1458 void SdrDragMove::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
1460 rTarget.Move(Size(DragStat().GetDX(), DragStat().GetDY()));
1463 SdrDragMove::SdrDragMove(SdrDragView& rNewView)
1464 : SdrDragMethod(rNewView)
1465 , nBestXSnap(0)
1466 , nBestYSnap(0)
1467 , bXSnapped(false)
1468 , bYSnapped(false)
1470 setMoveOnly(true);
1473 OUString SdrDragMove::GetSdrDragComment() const
1475 OUString aStr = ImpGetDescriptionStr(STR_DragMethMove)
1476 + " (x="
1477 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
1478 + " y="
1479 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
1480 + ")";
1482 if(getSdrDragView().IsDragWithCopy())
1484 if(!getSdrDragView().IsInsObjPoint() && !getSdrDragView().IsInsGluePoint())
1486 aStr += SvxResId(STR_EditWithCopy);
1489 return aStr;
1492 bool SdrDragMove::BeginSdrDrag()
1494 DragStat().SetActionRect(GetMarkedRect());
1495 Show();
1497 return true;
1500 basegfx::B2DHomMatrix SdrDragMove::getCurrentTransformation() const
1502 return basegfx::utils::createTranslateB2DHomMatrix(DragStat().GetDX(), DragStat().GetDY());
1505 void SdrDragMove::ImpCheckSnap(const Point& rPt)
1507 Point aPt(rPt);
1508 SdrSnap nRet=SnapPos(aPt);
1509 aPt-=rPt;
1511 if (nRet & SdrSnap::XSNAPPED)
1513 if (bXSnapped)
1515 if (std::abs(aPt.X())<std::abs(nBestXSnap))
1517 nBestXSnap=aPt.X();
1520 else
1522 nBestXSnap=aPt.X();
1523 bXSnapped=true;
1527 if (!(nRet & SdrSnap::YSNAPPED))
1528 return;
1530 if (bYSnapped)
1532 if (std::abs(aPt.Y())<std::abs(nBestYSnap))
1534 nBestYSnap=aPt.Y();
1537 else
1539 nBestYSnap=aPt.Y();
1540 bYSnapped=true;
1544 void SdrDragMove::MoveSdrDrag(const Point& rNoSnapPnt_)
1546 nBestXSnap=0;
1547 nBestYSnap=0;
1548 bXSnapped=false;
1549 bYSnapped=false;
1550 Point aNoSnapPnt(rNoSnapPnt_);
1551 const tools::Rectangle& aSR=GetMarkedRect();
1552 tools::Long nMovedx=aNoSnapPnt.X()-DragStat().GetStart().X();
1553 tools::Long nMovedy=aNoSnapPnt.Y()-DragStat().GetStart().Y();
1554 Point aLO(aSR.TopLeft()); aLO.AdjustX(nMovedx ); aLO.AdjustY(nMovedy );
1555 Point aRU(aSR.BottomRight()); aRU.AdjustX(nMovedx ); aRU.AdjustY(nMovedy );
1556 Point aLU(aLO.X(),aRU.Y());
1557 Point aRO(aRU.X(),aLO.Y());
1558 ImpCheckSnap(aLO);
1560 if (!getSdrDragView().IsMoveSnapOnlyTopLeft())
1562 ImpCheckSnap(aRO);
1563 ImpCheckSnap(aLU);
1564 ImpCheckSnap(aRU);
1567 Point aPnt(aNoSnapPnt.X()+nBestXSnap,aNoSnapPnt.Y()+nBestYSnap);
1568 bool bOrtho=getSdrDragView().IsOrtho();
1570 if (bOrtho)
1571 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
1573 if (!DragStat().CheckMinMoved(aNoSnapPnt))
1574 return;
1576 Point aPt1(aPnt);
1577 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1578 bool bWorkArea=!aLR.IsEmpty();
1579 bool bDragLimit=IsDragLimit();
1581 if (bDragLimit || bWorkArea)
1583 tools::Rectangle aSR2(GetMarkedRect());
1584 Point aD(aPt1-DragStat().GetStart());
1586 if (bDragLimit)
1588 tools::Rectangle aR2(GetDragLimitRect());
1590 if (bWorkArea)
1591 aLR.Intersection(aR2);
1592 else
1593 aLR=aR2;
1596 if (aSR2.Left()>aLR.Left() || aSR2.Right()<aLR.Right())
1597 { // any space to move to?
1598 aSR2.Move(aD.X(),0);
1600 if (aSR2.Left()<aLR.Left())
1602 aPt1.AdjustX( -(aSR2.Left()-aLR.Left()) );
1604 else if (aSR2.Right()>aLR.Right())
1606 aPt1.AdjustX( -(aSR2.Right()-aLR.Right()) );
1609 else
1610 aPt1.setX(DragStat().GetStart().X() ); // no space to move to
1612 if (aSR2.Top()>aLR.Top() || aSR2.Bottom()<aLR.Bottom())
1613 { // any space to move to?
1614 aSR2.Move(0,aD.Y());
1616 if (aSR2.Top()<aLR.Top())
1618 aPt1.AdjustY( -(aSR2.Top()-aLR.Top()) );
1620 else if (aSR2.Bottom()>aLR.Bottom())
1622 aPt1.AdjustY( -(aSR2.Bottom()-aLR.Bottom()) );
1625 else
1626 aPt1.setY(DragStat().GetStart().Y() ); // no space to move to
1629 if (getSdrDragView().IsDraggingGluePoints())
1630 { // restrict gluepoints to the BoundRect of the Obj
1631 aPt1-=DragStat().GetStart();
1632 const SdrMarkList& rML=GetMarkedObjectList();
1633 const size_t nMarkCount=rML.GetMarkCount();
1635 for (size_t nMarkNum=0; nMarkNum<nMarkCount; ++nMarkNum)
1637 const SdrMark* pM=rML.GetMark(nMarkNum);
1638 const SdrUShortCont& rPts = pM->GetMarkedGluePoints();
1640 if (!rPts.empty())
1642 const SdrObject* pObj=pM->GetMarkedSdrObj();
1643 const SdrGluePointList* pGPL=pObj->GetGluePointList();
1644 tools::Rectangle aBound(pObj->GetCurrentBoundRect());
1646 for (sal_uInt16 nId : rPts)
1648 sal_uInt16 nGlueNum=pGPL->FindGluePoint(nId);
1650 if (nGlueNum!=SDRGLUEPOINT_NOTFOUND)
1652 Point aPt((*pGPL)[nGlueNum].GetAbsolutePos(*pObj));
1653 aPt+=aPt1; // move by this much
1654 if (aPt.X()<aBound.Left() ) aPt1.AdjustX( -(aPt.X()-aBound.Left()) ) ;
1655 if (aPt.X()>aBound.Right() ) aPt1.AdjustX( -(aPt.X()-aBound.Right()) ) ;
1656 if (aPt.Y()<aBound.Top() ) aPt1.AdjustY( -(aPt.Y()-aBound.Top()) ) ;
1657 if (aPt.Y()>aBound.Bottom()) aPt1.AdjustY( -(aPt.Y()-aBound.Bottom()) );
1663 aPt1+=DragStat().GetStart();
1666 if (bOrtho)
1667 OrthoDistance8(DragStat().GetStart(),aPt1,false);
1669 if (aPt1!=DragStat().GetNow())
1671 Hide();
1672 DragStat().NextMove(aPt1);
1673 tools::Rectangle aAction(GetMarkedRect());
1674 aAction.Move(DragStat().GetDX(),DragStat().GetDY());
1675 DragStat().SetActionRect(aAction);
1676 Show();
1680 bool SdrDragMove::EndSdrDrag(bool bCopy)
1682 Hide();
1684 if (getSdrDragView().IsInsObjPoint() || getSdrDragView().IsInsGluePoint())
1685 bCopy=false;
1687 if (IsDraggingPoints())
1689 getSdrDragView().MoveMarkedPoints(Size(DragStat().GetDX(),DragStat().GetDY()));
1691 else if (IsDraggingGluePoints())
1693 getSdrDragView().MoveMarkedGluePoints(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1695 else
1697 getSdrDragView().MoveMarkedObj(Size(DragStat().GetDX(),DragStat().GetDY()),bCopy);
1700 return true;
1703 PointerStyle SdrDragMove::GetSdrDragPointer() const
1705 if (IsDraggingPoints() || IsDraggingGluePoints())
1707 return PointerStyle::MovePoint;
1709 else
1711 return PointerStyle::Move;
1716 SdrDragResize::SdrDragResize(SdrDragView& rNewView)
1717 : SdrDragMethod(rNewView),
1718 aXFact(1,1),
1719 aYFact(1,1)
1723 OUString SdrDragResize::GetSdrDragComment() const
1725 OUString aStr = ImpGetDescriptionStr(STR_DragMethResize);
1726 Fraction aFact1(1,1);
1727 Point aStart(DragStat().GetStart());
1728 Point aRef(DragStat().GetRef1());
1729 sal_Int32 nXDiv(aStart.X() - aRef.X());
1731 if(!nXDiv)
1732 nXDiv = 1;
1734 sal_Int32 nYDiv(aStart.Y() - aRef.Y());
1736 if(!nYDiv)
1737 nYDiv = 1;
1739 bool bX(aXFact != aFact1 && std::abs(nXDiv) > 1);
1740 bool bY(aYFact != aFact1 && std::abs(nYDiv) > 1);
1742 if(bX || bY)
1744 aStr += " (";
1746 bool bEqual(aXFact == aYFact);
1747 if(bX)
1749 if(!bEqual)
1750 aStr += "x=";
1752 aStr += SdrModel::GetPercentString(aXFact);
1755 if(bY && !bEqual)
1757 if(bX)
1758 aStr += " ";
1760 aStr += "y=" + SdrModel::GetPercentString(aYFact);
1763 aStr += ")";
1766 if(getSdrDragView().IsDragWithCopy())
1767 aStr += SvxResId(STR_EditWithCopy);
1768 return aStr;
1771 bool SdrDragResize::BeginSdrDrag()
1773 SdrHdlKind eRefHdl=SdrHdlKind::Move;
1774 SdrHdl* pRefHdl=nullptr;
1776 switch (GetDragHdlKind())
1778 case SdrHdlKind::UpperLeft: eRefHdl=SdrHdlKind::LowerRight; break;
1779 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; DragStat().SetHorFixed(true); break;
1780 case SdrHdlKind::UpperRight: eRefHdl=SdrHdlKind::LowerLeft; break;
1781 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; DragStat().SetVerFixed(true); break;
1782 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; DragStat().SetVerFixed(true); break;
1783 case SdrHdlKind::LowerLeft: eRefHdl=SdrHdlKind::UpperRight; break;
1784 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; DragStat().SetHorFixed(true); break;
1785 case SdrHdlKind::LowerRight: eRefHdl=SdrHdlKind::UpperLeft; break;
1786 default: break;
1789 if (eRefHdl!=SdrHdlKind::Move)
1790 pRefHdl=GetHdlList().GetHdl(eRefHdl);
1792 if (pRefHdl!=nullptr && !getSdrDragView().IsResizeAtCenter())
1794 DragStat().SetRef1(pRefHdl->GetPos());
1796 else
1798 SdrHdl* pRef1=GetHdlList().GetHdl(SdrHdlKind::UpperLeft);
1799 SdrHdl* pRef2=GetHdlList().GetHdl(SdrHdlKind::LowerRight);
1801 if (pRef1!=nullptr && pRef2!=nullptr)
1803 DragStat().SetRef1(tools::Rectangle(pRef1->GetPos(),pRef2->GetPos()).Center());
1805 else
1807 DragStat().SetRef1(GetMarkedRect().Center());
1811 Show();
1813 return true;
1816 basegfx::B2DHomMatrix SdrDragResize::getCurrentTransformation() const
1818 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
1819 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
1820 aRetval.scale(double(aXFact), double(aYFact));
1821 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
1823 return aRetval;
1826 void SdrDragResize::MoveSdrDrag(const Point& rNoSnapPnt)
1828 Point aPnt(GetSnapPos(rNoSnapPnt));
1829 Point aStart(DragStat().GetStart());
1830 Point aRef(DragStat().GetRef1());
1831 Fraction aMaxFact(0x7FFFFFFF,1);
1832 tools::Rectangle aLR(getSdrDragView().GetWorkArea());
1833 bool bWorkArea=!aLR.IsEmpty();
1834 bool bDragLimit=IsDragLimit();
1836 if (bDragLimit || bWorkArea)
1838 tools::Rectangle aSR(GetMarkedRect());
1840 if (bDragLimit)
1842 tools::Rectangle aR2(GetDragLimitRect());
1844 if (bWorkArea)
1845 aLR.Intersection(aR2);
1846 else
1847 aLR=aR2;
1850 if (aPnt.X()<aLR.Left())
1851 aPnt.setX(aLR.Left() );
1852 else if (aPnt.X()>aLR.Right())
1853 aPnt.setX(aLR.Right() );
1855 if (aPnt.Y()<aLR.Top())
1856 aPnt.setY(aLR.Top() );
1857 else if (aPnt.Y()>aLR.Bottom())
1858 aPnt.setY(aLR.Bottom() );
1860 if (aRef.X()>aSR.Left())
1862 Fraction aMax(aRef.X()-aLR.Left(),aRef.X()-aSR.Left());
1864 if (aMax<aMaxFact)
1865 aMaxFact=aMax;
1868 if (aRef.X()<aSR.Right())
1870 Fraction aMax(aLR.Right()-aRef.X(),aSR.Right()-aRef.X());
1872 if (aMax<aMaxFact)
1873 aMaxFact=aMax;
1876 if (aRef.Y()>aSR.Top())
1878 Fraction aMax(aRef.Y()-aLR.Top(),aRef.Y()-aSR.Top());
1880 if (aMax<aMaxFact)
1881 aMaxFact=aMax;
1884 if (aRef.Y()<aSR.Bottom())
1886 Fraction aMax(aLR.Bottom()-aRef.Y(),aSR.Bottom()-aRef.Y());
1888 if (aMax<aMaxFact)
1889 aMaxFact=aMax;
1893 tools::Long nXDiv=aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
1894 tools::Long nYDiv=aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
1895 tools::Long nXMul=aPnt.X()-aRef.X();
1896 tools::Long nYMul=aPnt.Y()-aRef.Y();
1898 if (nXDiv<0)
1900 nXDiv=-nXDiv;
1901 nXMul=-nXMul;
1904 if (nYDiv<0)
1906 nYDiv=-nYDiv;
1907 nYMul=-nYMul;
1910 bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
1911 bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
1912 bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();
1914 if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
1916 if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
1917 bOrtho=false;
1919 if (bOrtho)
1921 if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
1923 nXMul=nYMul;
1924 nXDiv=nYDiv;
1926 else
1928 nYMul=nXMul;
1929 nYDiv=nXDiv;
1933 else
1935 if (bOrtho)
1937 if (DragStat().IsHorFixed())
1939 bXNeg=false;
1940 nXMul=nYMul;
1941 nXDiv=nYDiv;
1944 if (DragStat().IsVerFixed())
1946 bYNeg=false;
1947 nYMul=nXMul;
1948 nYDiv=nXDiv;
1951 else
1953 if (DragStat().IsHorFixed())
1955 bXNeg=false;
1956 nXMul=1;
1957 nXDiv=1;
1960 if (DragStat().IsVerFixed())
1962 bYNeg=false;
1963 nYMul=1;
1964 nYDiv=1;
1969 Fraction aNewXFact(nXMul,nXDiv);
1970 Fraction aNewYFact(nYMul,nYDiv);
1972 if (bOrtho)
1974 if (aNewXFact>aMaxFact)
1976 aNewXFact=aMaxFact;
1977 aNewYFact=aMaxFact;
1980 if (aNewYFact>aMaxFact)
1982 aNewXFact=aMaxFact;
1983 aNewYFact=aMaxFact;
1987 if (bXNeg)
1988 aNewXFact=Fraction(-aNewXFact.GetNumerator(),aNewXFact.GetDenominator());
1990 if (bYNeg)
1991 aNewYFact=Fraction(-aNewYFact.GetNumerator(),aNewYFact.GetDenominator());
1993 if (DragStat().CheckMinMoved(aPnt))
1995 if ((!DragStat().IsHorFixed() && aPnt.X()!=DragStat().GetNow().X()) ||
1996 (!DragStat().IsVerFixed() && aPnt.Y()!=DragStat().GetNow().Y()))
1998 Hide();
1999 DragStat().NextMove(aPnt);
2000 aXFact=aNewXFact;
2001 aYFact=aNewYFact;
2002 Show();
2007 void SdrDragResize::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2009 rTarget.Resize(DragStat().GetRef1(),aXFact,aYFact);
2012 bool SdrDragResize::EndSdrDrag(bool bCopy)
2014 Hide();
2016 if (IsDraggingPoints())
2018 getSdrDragView().ResizeMarkedPoints(DragStat().GetRef1(),aXFact,aYFact);
2020 else if (IsDraggingGluePoints())
2022 getSdrDragView().ResizeMarkedGluePoints(DragStat().GetRef1(),aXFact,aYFact,bCopy);
2024 else
2026 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aXFact,aYFact,bCopy);
2029 return true;
2032 PointerStyle SdrDragResize::GetSdrDragPointer() const
2034 const SdrHdl* pHdl=GetDragHdl();
2036 if (pHdl!=nullptr)
2038 return pHdl->GetPointer();
2041 return PointerStyle::Move;
2045 void SdrDragRotate::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2047 rTarget.Rotate(DragStat().GetRef1(), nAngle, nSin, nCos);
2050 SdrDragRotate::SdrDragRotate(SdrDragView& rNewView)
2051 : SdrDragMethod(rNewView),
2052 nSin(0.0),
2053 nCos(1.0),
2054 nAngle0(0),
2055 nAngle(0),
2056 bRight(false)
2060 OUString SdrDragRotate::GetSdrDragComment() const
2062 OUString aStr = ImpGetDescriptionStr(STR_DragMethRotate) +
2063 " (";
2064 Degree100 nTmpAngle(NormAngle36000(nAngle));
2066 if(bRight && nAngle)
2068 nTmpAngle -= 36000_deg100;
2071 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2073 if(getSdrDragView().IsDragWithCopy())
2074 aStr += SvxResId(STR_EditWithCopy);
2075 return aStr;
2078 bool SdrDragRotate::BeginSdrDrag()
2080 SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2082 if (nullptr != pH)
2084 Show();
2085 DragStat().SetRef1(pH->GetPos());
2086 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2087 return true;
2090 // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
2091 // the rotation point)
2092 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
2094 if(!aLocalMarkRect.IsEmpty())
2096 Show();
2097 DragStat().SetRef1(aLocalMarkRect.Center());
2098 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2099 return true;
2102 OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
2103 return false;
2106 basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation() const
2108 return basegfx::utils::createRotateAroundPoint(
2109 DragStat().GetRef1().X(), DragStat().GetRef1().Y(),
2110 -atan2(nSin, nCos));
2113 void SdrDragRotate::MoveSdrDrag(const Point& rPnt_)
2115 Point aPnt(rPnt_);
2116 if (!DragStat().CheckMinMoved(aPnt))
2117 return;
2119 Degree100 nNewAngle=NormAngle36000(GetAngle(aPnt-DragStat().GetRef1())-nAngle0);
2120 Degree100 nSA(0);
2122 if (getSdrDragView().IsAngleSnapEnabled())
2123 nSA=getSdrDragView().GetSnapAngle();
2125 if (!getSdrDragView().IsRotateAllowed())
2126 nSA=9000_deg100;
2128 if (nSA)
2129 { // angle snapping
2130 nNewAngle += nSA / 2_deg100;
2131 nNewAngle /= nSA;
2132 nNewAngle *= nSA;
2135 nNewAngle=NormAngle18000(nNewAngle);
2137 if (nAngle==nNewAngle)
2138 return;
2140 sal_uInt16 nSekt0=GetAngleSector(nAngle);
2141 sal_uInt16 nSekt1=GetAngleSector(nNewAngle);
2143 if (nSekt0==0 && nSekt1==3)
2144 bRight=true;
2146 if (nSekt0==3 && nSekt1==0)
2147 bRight=false;
2149 nAngle=nNewAngle;
2150 double a = toRadians(nAngle);
2151 double nSin1=sin(a); // calculate now, so as little time as possible
2152 double nCos1=cos(a); // passes between Hide() and Show()
2153 Hide();
2154 nSin=nSin1;
2155 nCos=nCos1;
2156 DragStat().NextMove(aPnt);
2157 Show();
2160 bool SdrDragRotate::EndSdrDrag(bool bCopy)
2162 Hide();
2164 if (nAngle!=0_deg100)
2166 if (IsDraggingPoints())
2168 getSdrDragView().RotateMarkedPoints(DragStat().GetRef1(),nAngle);
2170 else if (IsDraggingGluePoints())
2172 getSdrDragView().RotateMarkedGluePoints(DragStat().GetRef1(),nAngle,bCopy);
2174 else
2176 getSdrDragView().RotateMarkedObj(DragStat().GetRef1(),nAngle,bCopy);
2179 return true;
2182 PointerStyle SdrDragRotate::GetSdrDragPointer() const
2184 return PointerStyle::Rotate;
2188 SdrDragShear::SdrDragShear(SdrDragView& rNewView, bool bSlant1)
2189 : SdrDragMethod(rNewView),
2190 aFact(1,1),
2191 nAngle0(0),
2192 nAngle(0),
2193 nTan(0.0),
2194 bVertical(false),
2195 bResize(false),
2196 bUpSideDown(false),
2197 bSlant(bSlant1)
2201 OUString SdrDragShear::GetSdrDragComment() const
2203 OUString aStr = ImpGetDescriptionStr(STR_DragMethShear) +
2204 " (";
2206 Degree100 nTmpAngle(nAngle);
2208 if(bUpSideDown)
2209 nTmpAngle += 18000_deg100;
2211 nTmpAngle = NormAngle18000(nTmpAngle);
2213 aStr += SdrModel::GetAngleString(nTmpAngle) + ")";
2215 if(getSdrDragView().IsDragWithCopy())
2216 aStr += SvxResId(STR_EditWithCopy);
2217 return aStr;
2220 bool SdrDragShear::BeginSdrDrag()
2222 SdrHdlKind eRefHdl=SdrHdlKind::Move;
2223 SdrHdl* pRefHdl=nullptr;
2225 switch (GetDragHdlKind())
2227 case SdrHdlKind::Upper: eRefHdl=SdrHdlKind::Lower; break;
2228 case SdrHdlKind::Lower: eRefHdl=SdrHdlKind::Upper; break;
2229 case SdrHdlKind::Left : eRefHdl=SdrHdlKind::Right; bVertical=true; break;
2230 case SdrHdlKind::Right: eRefHdl=SdrHdlKind::Left ; bVertical=true; break;
2231 default: break;
2234 if (eRefHdl!=SdrHdlKind::Move)
2235 pRefHdl=GetHdlList().GetHdl(eRefHdl);
2237 if (pRefHdl!=nullptr)
2239 DragStat().SetRef1(pRefHdl->GetPos());
2240 nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
2242 else
2244 OSL_FAIL("SdrDragShear::BeginSdrDrag(): No reference point handle for shearing found.");
2245 return false;
2248 Show();
2249 return true;
2252 basegfx::B2DHomMatrix SdrDragShear::getCurrentTransformation() const
2254 basegfx::B2DHomMatrix aRetval(basegfx::utils::createTranslateB2DHomMatrix(
2255 -DragStat().GetRef1().X(), -DragStat().GetRef1().Y()));
2257 if (bResize)
2259 if (bVertical)
2261 aRetval.scale(double(aFact), 1.0);
2262 aRetval.shearY(-nTan);
2264 else
2266 aRetval.scale(1.0, double(aFact));
2267 aRetval.shearX(-nTan);
2271 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2273 return aRetval;
2276 void SdrDragShear::MoveSdrDrag(const Point& rPnt)
2278 if (!DragStat().CheckMinMoved(rPnt))
2279 return;
2281 bResize=!getSdrDragView().IsOrtho();
2282 Degree100 nSA(0);
2284 if (getSdrDragView().IsAngleSnapEnabled())
2285 nSA=getSdrDragView().GetSnapAngle();
2287 Point aP0(DragStat().GetStart());
2288 Point aPnt(rPnt);
2289 Fraction aNewFract(1,1);
2291 // if angle snapping not activated, snap to raster (except when using slant)
2292 if (nSA==0_deg100 && !bSlant)
2293 aPnt=GetSnapPos(aPnt);
2295 if (!bSlant && !bResize)
2296 { // shear, but no resize
2297 if (bVertical)
2298 aPnt.setX(aP0.X() );
2299 else
2300 aPnt.setY(aP0.Y() );
2303 Point aRef(DragStat().GetRef1());
2304 Point aDif(aPnt-aRef);
2306 Degree100 nNewAngle(0);
2308 if (bSlant)
2310 nNewAngle=NormAngle18000(-(GetAngle(aDif)-nAngle0));
2312 if (bVertical)
2313 nNewAngle=NormAngle18000(-nNewAngle);
2315 else
2317 if (bVertical)
2318 nNewAngle=NormAngle18000(GetAngle(aDif));
2319 else
2320 nNewAngle=NormAngle18000(-(GetAngle(aDif)-9000_deg100));
2322 if (nNewAngle<Degree100(-9000) || nNewAngle>9000_deg100)
2323 nNewAngle=NormAngle18000(nNewAngle+18000_deg100);
2325 if (bResize)
2327 Point aPt2(aPnt);
2329 if (nSA!=0_deg100)
2330 aPt2=GetSnapPos(aPnt); // snap this one in any case
2332 if (bVertical)
2334 aNewFract=Fraction(aPt2.X()-aRef.X(),aP0.X()-aRef.X());
2336 else
2338 aNewFract=Fraction(aPt2.Y()-aRef.Y(),aP0.Y()-aRef.Y());
2343 bool bNeg=nNewAngle<0_deg100;
2345 if (bNeg)
2346 nNewAngle=-nNewAngle;
2348 if (nSA)
2349 { // angle snapping
2350 nNewAngle += nSA / 2_deg100;
2351 nNewAngle /= nSA;
2352 nNewAngle *= nSA;
2355 nNewAngle=NormAngle36000(nNewAngle);
2356 bUpSideDown=nNewAngle>9000_deg100 && nNewAngle<27000_deg100;
2358 if (bSlant)
2359 { // calculate resize for slant
2360 // when angle snapping is activated, disable 89 degree limit
2361 Degree100 nTmpAngle=nNewAngle;
2362 if (bUpSideDown) nNewAngle -= 18000_deg100;
2363 if (bNeg) nTmpAngle=-nTmpAngle;
2364 bResize=true;
2365 aNewFract = cos(toRadians(nTmpAngle));
2366 aFact.ReduceInaccurate(10); // three decimals should be enough
2369 if (nNewAngle > 8900_deg100)
2370 nNewAngle = 8900_deg100;
2372 if (bNeg)
2373 nNewAngle=-nNewAngle;
2375 if (nAngle!=nNewAngle || aFact!=aNewFract)
2377 nAngle=nNewAngle;
2378 aFact=aNewFract;
2379 double a = toRadians(nAngle);
2380 double nTan1=tan(a); // calculate now, so as little time as possible passes between Hide() and Show()
2381 Hide();
2382 nTan=nTan1;
2383 DragStat().NextMove(rPnt);
2384 Show();
2388 void SdrDragShear::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2390 if (bResize)
2392 if (bVertical)
2394 rTarget.Resize(DragStat().GetRef1(),aFact,Fraction(1,1));
2396 else
2398 rTarget.Resize(DragStat().GetRef1(),Fraction(1,1),aFact);
2402 if (nAngle)
2404 rTarget.Shear(DragStat().GetRef1(), nAngle, nTan, bVertical);
2408 bool SdrDragShear::EndSdrDrag(bool bCopy)
2410 Hide();
2412 if (bResize && aFact==Fraction(1,1))
2413 bResize=false;
2415 if (nAngle || bResize)
2417 if (nAngle && bResize)
2419 OUString aStr = ImpGetDescriptionStr(STR_EditShear);
2421 if (bCopy)
2422 aStr += SvxResId(STR_EditWithCopy);
2424 getSdrDragView().BegUndo(aStr);
2427 if (bResize)
2429 if (bVertical)
2431 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),aFact,Fraction(1,1),bCopy);
2433 else
2435 getSdrDragView().ResizeMarkedObj(DragStat().GetRef1(),Fraction(1,1),aFact,bCopy);
2438 bCopy=false;
2441 if (nAngle)
2443 getSdrDragView().ShearMarkedObj(DragStat().GetRef1(),nAngle,bVertical,bCopy);
2446 if (nAngle && bResize)
2447 getSdrDragView().EndUndo();
2449 return true;
2452 return false;
2455 PointerStyle SdrDragShear::GetSdrDragPointer() const
2457 if (bVertical)
2458 return PointerStyle::VShear;
2459 else
2460 return PointerStyle::HShear;
2464 void SdrDragMirror::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
2466 if(bMirrored)
2468 rTarget.Mirror(DragStat().GetRef1(), DragStat().GetRef2());
2472 SdrDragMirror::SdrDragMirror(SdrDragView& rNewView)
2473 : SdrDragMethod(rNewView),
2474 nAngle(0),
2475 bMirrored(false),
2476 bSide0(false)
2480 bool SdrDragMirror::ImpCheckSide(const Point& rPnt) const
2482 Degree100 nAngle1=GetAngle(rPnt-DragStat().GetRef1());
2483 nAngle1-=nAngle;
2484 nAngle1=NormAngle36000(nAngle1);
2486 return nAngle1<18000_deg100;
2489 OUString SdrDragMirror::GetSdrDragComment() const
2491 OUString aStr;
2492 if (aDif.X()==0)
2493 aStr = ImpGetDescriptionStr(STR_DragMethMirrorHori);
2494 else if (aDif.Y()==0)
2495 aStr = ImpGetDescriptionStr(STR_DragMethMirrorVert);
2496 else if (std::abs(aDif.X()) == std::abs(aDif.Y()))
2497 aStr = ImpGetDescriptionStr(STR_DragMethMirrorDiag);
2498 else
2499 aStr = ImpGetDescriptionStr(STR_DragMethMirrorFree);
2501 if (getSdrDragView().IsDragWithCopy())
2502 aStr+=SvxResId(STR_EditWithCopy);
2503 return aStr;
2506 bool SdrDragMirror::BeginSdrDrag()
2508 SdrHdl* pH1=GetHdlList().GetHdl(SdrHdlKind::Ref1);
2509 SdrHdl* pH2=GetHdlList().GetHdl(SdrHdlKind::Ref2);
2511 if (pH1!=nullptr && pH2!=nullptr)
2513 DragStat().SetRef1(pH1->GetPos());
2514 DragStat().SetRef2(pH2->GetPos());
2515 Ref1()=pH1->GetPos();
2516 Ref2()=pH2->GetPos();
2517 aDif=pH2->GetPos()-pH1->GetPos();
2518 bool b90=(aDif.X()==0) || aDif.Y()==0;
2519 bool b45=b90 || (std::abs(aDif.X()) == std::abs(aDif.Y()));
2520 nAngle=NormAngle36000(GetAngle(aDif));
2522 if (!getSdrDragView().IsMirrorAllowed() && !b45)
2523 return false; // free choice of axis angle not allowed
2525 if (!getSdrDragView().IsMirrorAllowed() && !b90)
2526 return false; // 45 degrees not allowed either
2528 bSide0=ImpCheckSide(DragStat().GetStart());
2529 Show();
2530 return true;
2532 else
2534 OSL_FAIL("SdrDragMirror::BeginSdrDrag(): Axis of reflection not found.");
2535 return false;
2539 basegfx::B2DHomMatrix SdrDragMirror::getCurrentTransformation() const
2541 basegfx::B2DHomMatrix aRetval;
2543 if (bMirrored)
2545 const double fDeltaX(DragStat().GetRef2().X() - DragStat().GetRef1().X());
2546 const double fDeltaY(DragStat().GetRef2().Y() - DragStat().GetRef1().Y());
2547 const double fRotation(atan2(fDeltaY, fDeltaX));
2549 aRetval = basegfx::utils::createTranslateB2DHomMatrix(-DragStat().GetRef1().X(), -DragStat().GetRef1().Y());
2550 aRetval.rotate(-fRotation);
2551 aRetval.scale(1.0, -1.0);
2552 aRetval.rotate(fRotation);
2553 aRetval.translate(DragStat().GetRef1().X(), DragStat().GetRef1().Y());
2556 return aRetval;
2559 void SdrDragMirror::MoveSdrDrag(const Point& rPnt)
2561 if (!DragStat().CheckMinMoved(rPnt))
2562 return;
2564 bool bNewSide=ImpCheckSide(rPnt);
2565 bool bNewMirrored=bSide0!=bNewSide;
2567 if (bMirrored!=bNewMirrored)
2569 Hide();
2570 bMirrored=bNewMirrored;
2571 DragStat().NextMove(rPnt);
2572 Show();
2576 bool SdrDragMirror::EndSdrDrag(bool bCopy)
2578 Hide();
2580 if (bMirrored)
2582 getSdrDragView().MirrorMarkedObj(DragStat().GetRef1(),DragStat().GetRef2(),bCopy);
2585 return true;
2588 PointerStyle SdrDragMirror::GetSdrDragPointer() const
2590 return PointerStyle::Mirror;
2594 SdrDragGradient::SdrDragGradient(SdrDragView& rNewView, bool bGrad)
2595 : SdrDragMethod(rNewView),
2596 pIAOHandle(nullptr),
2597 bIsGradient(bGrad)
2601 OUString SdrDragGradient::GetSdrDragComment() const
2603 if(IsGradient())
2604 return ImpGetDescriptionStr(STR_DragMethGradient);
2605 else
2606 return ImpGetDescriptionStr(STR_DragMethTransparence);
2609 bool SdrDragGradient::BeginSdrDrag()
2611 bool bRetval(false);
2613 pIAOHandle = static_cast<SdrHdlGradient*>(GetHdlList().GetHdl(IsGradient() ? SdrHdlKind::Gradient : SdrHdlKind::Transparence));
2615 if(pIAOHandle)
2617 // save old values
2618 DragStat().SetRef1( pIAOHandle->GetPos() );
2619 DragStat().SetRef2( pIAOHandle->Get2ndPos() );
2621 // what was hit?
2622 bool bHit(false);
2623 SdrHdlColor* pColHdl = pIAOHandle->GetColorHdl1();
2625 // init handling flags
2626 pIAOHandle->SetMoveSingleHandle(false);
2627 pIAOHandle->SetMoveFirstHandle(false);
2629 // test first color handle
2630 if(pColHdl)
2632 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2634 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2636 bHit = true;
2637 pIAOHandle->SetMoveSingleHandle(true);
2638 pIAOHandle->SetMoveFirstHandle(true);
2642 // test second color handle
2643 pColHdl = pIAOHandle->GetColorHdl2();
2645 if(!bHit && pColHdl)
2647 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2649 if(pColHdl->getOverlayObjectList().isHitLogic(aPosition))
2651 bHit = true;
2652 pIAOHandle->SetMoveSingleHandle(true);
2656 // test gradient handle itself
2657 if(!bHit)
2659 basegfx::B2DPoint aPosition(DragStat().GetStart().X(), DragStat().GetStart().Y());
2661 if(pIAOHandle->getOverlayObjectList().isHitLogic(aPosition))
2663 bHit = true;
2667 // everything up and running :o}
2668 bRetval = bHit;
2670 else
2672 OSL_FAIL("SdrDragGradient::BeginSdrDrag(): IAOGradient not found.");
2675 return bRetval;
2678 void SdrDragGradient::MoveSdrDrag(const Point& rPnt)
2680 if(!(pIAOHandle && DragStat().CheckMinMoved(rPnt)))
2681 return;
2683 DragStat().NextMove(rPnt);
2685 // Do the Move here!!! DragStat().GetStart()
2686 Point aMoveDiff = rPnt - DragStat().GetStart();
2688 if(pIAOHandle->IsMoveSingleHandle())
2690 if(pIAOHandle->IsMoveFirstHandle())
2692 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2693 if(pIAOHandle->GetColorHdl1())
2694 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2696 else
2698 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2699 if(pIAOHandle->GetColorHdl2())
2700 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2703 else
2705 pIAOHandle->SetPos(DragStat().GetRef1() + aMoveDiff);
2706 pIAOHandle->Set2ndPos(DragStat().GetRef2() + aMoveDiff);
2708 if(pIAOHandle->GetColorHdl1())
2709 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1() + aMoveDiff);
2711 if(pIAOHandle->GetColorHdl2())
2712 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2() + aMoveDiff);
2715 // new state
2716 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), false, false);
2719 bool SdrDragGradient::EndSdrDrag(bool /*bCopy*/)
2721 Ref1() = pIAOHandle->GetPos();
2722 Ref2() = pIAOHandle->Get2ndPos();
2724 // new state
2725 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, true);
2727 return true;
2730 void SdrDragGradient::CancelSdrDrag()
2732 // restore old values
2733 pIAOHandle->SetPos(DragStat().GetRef1());
2734 pIAOHandle->Set2ndPos(DragStat().GetRef2());
2736 if(pIAOHandle->GetColorHdl1())
2737 pIAOHandle->GetColorHdl1()->SetPos(DragStat().GetRef1());
2739 if(pIAOHandle->GetColorHdl2())
2740 pIAOHandle->GetColorHdl2()->SetPos(DragStat().GetRef2());
2742 // new state
2743 pIAOHandle->FromIAOToItem(getSdrDragView().GetMarkedObjectList().GetMark(0)->GetMarkedSdrObj(), true, false);
2746 PointerStyle SdrDragGradient::GetSdrDragPointer() const
2748 return PointerStyle::RefHand;
2752 SdrDragCrook::SdrDragCrook(SdrDragView& rNewView)
2753 : SdrDragMethod(rNewView),
2754 aFact(1,1),
2755 bContortionAllowed(false),
2756 bNoContortionAllowed(false),
2757 bContortion(false),
2758 bResizeAllowed(false),
2759 bResize(false),
2760 bRotateAllowed(false),
2761 bRotate(false),
2762 bVertical(false),
2763 bValid(false),
2764 bLft(false),
2765 bRgt(false),
2766 bUpr(false),
2767 bLwr(false),
2768 bAtCenter(false),
2769 nAngle(0),
2770 nMarkSize(0),
2771 eMode(SdrCrookMode::Rotate)
2775 OUString SdrDragCrook::GetSdrDragComment() const
2777 OUString aStr = ImpGetDescriptionStr(!bContortion ? STR_DragMethCrook : STR_DragMethCrookContortion);
2779 if(bValid)
2781 aStr += " (";
2783 sal_Int32 nVal(nAngle);
2785 if(bAtCenter)
2786 nVal *= 2;
2788 nVal = std::abs(nVal);
2789 aStr += SdrModel::GetAngleString(Degree100(nVal)) + ")";
2792 if(getSdrDragView().IsDragWithCopy())
2793 aStr += SvxResId(STR_EditWithCopy);
2794 return aStr;
2797 // These defines parametrize the created raster
2798 // for interactions
2799 #define DRAG_CROOK_RASTER_MINIMUM (4)
2800 #define DRAG_CROOK_RASTER_MAXIMUM (15)
2801 #define DRAG_CROOK_RASTER_DISTANCE (30)
2803 static basegfx::B2DPolyPolygon impCreateDragRaster(SdrPageView const & rPageView, const tools::Rectangle& rMarkRect)
2805 basegfx::B2DPolyPolygon aRetval;
2807 if(rPageView.PageWindowCount())
2809 OutputDevice& rOut = rPageView.GetPageWindow(0)->GetPaintWindow().GetOutputDevice();
2810 tools::Rectangle aPixelSize = rOut.LogicToPixel(rMarkRect);
2811 sal_uInt32 nHorDiv(aPixelSize.GetWidth() / DRAG_CROOK_RASTER_DISTANCE);
2812 sal_uInt32 nVerDiv(aPixelSize.GetHeight() / DRAG_CROOK_RASTER_DISTANCE);
2814 if(nHorDiv > DRAG_CROOK_RASTER_MAXIMUM)
2815 nHorDiv = DRAG_CROOK_RASTER_MAXIMUM;
2816 if(nHorDiv < DRAG_CROOK_RASTER_MINIMUM)
2817 nHorDiv = DRAG_CROOK_RASTER_MINIMUM;
2819 if(nVerDiv > DRAG_CROOK_RASTER_MAXIMUM)
2820 nVerDiv = DRAG_CROOK_RASTER_MAXIMUM;
2821 if(nVerDiv < DRAG_CROOK_RASTER_MINIMUM)
2822 nVerDiv = DRAG_CROOK_RASTER_MINIMUM;
2824 const double fXLen(rMarkRect.GetWidth() / static_cast<double>(nHorDiv));
2825 const double fYLen(rMarkRect.GetHeight() / static_cast<double>(nVerDiv));
2826 double fYPos(rMarkRect.Top());
2827 sal_uInt32 a, b;
2829 for(a = 0; a <= nVerDiv; a++)
2831 // horizontal lines
2832 for(b = 0; b < nHorDiv; b++)
2834 basegfx::B2DPolygon aHorLineSegment;
2836 const double fNewX(rMarkRect.Left() + (b * fXLen));
2837 aHorLineSegment.append(basegfx::B2DPoint(fNewX, fYPos));
2838 aHorLineSegment.appendBezierSegment(
2839 basegfx::B2DPoint(fNewX + (fXLen * (1.0 / 3.0)), fYPos),
2840 basegfx::B2DPoint(fNewX + (fXLen * (2.0 / 3.0)), fYPos),
2841 basegfx::B2DPoint(fNewX + fXLen, fYPos));
2842 aRetval.append(aHorLineSegment);
2845 // increments
2846 fYPos += fYLen;
2849 double fXPos(rMarkRect.Left());
2851 for(a = 0; a <= nHorDiv; a++)
2853 // vertical lines
2854 for(b = 0; b < nVerDiv; b++)
2856 basegfx::B2DPolygon aVerLineSegment;
2858 const double fNewY(rMarkRect.Top() + (b * fYLen));
2859 aVerLineSegment.append(basegfx::B2DPoint(fXPos, fNewY));
2860 aVerLineSegment.appendBezierSegment(
2861 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (1.0 / 3.0))),
2862 basegfx::B2DPoint(fXPos, fNewY + (fYLen * (2.0 / 3.0))),
2863 basegfx::B2DPoint(fXPos, fNewY + fYLen));
2864 aRetval.append(aVerLineSegment);
2867 // increments
2868 fXPos += fXLen;
2872 return aRetval;
2875 void SdrDragCrook::createSdrDragEntries()
2877 // Add extended frame raster first, so it will be behind objects
2878 if(getSdrDragView().GetSdrPageView())
2880 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
2882 if(aDragRaster.count())
2884 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
2888 // call parent
2889 SdrDragMethod::createSdrDragEntries();
2892 bool SdrDragCrook::BeginSdrDrag()
2894 bContortionAllowed=getSdrDragView().IsCrookAllowed();
2895 bNoContortionAllowed=getSdrDragView().IsCrookAllowed(true);
2896 bResizeAllowed=getSdrDragView().IsResizeAllowed();
2897 bRotateAllowed=getSdrDragView().IsRotateAllowed();
2899 if (bContortionAllowed || bNoContortionAllowed)
2901 bVertical=(GetDragHdlKind()==SdrHdlKind::Lower || GetDragHdlKind()==SdrHdlKind::Upper);
2902 aMarkRect=GetMarkedRect();
2903 aMarkCenter=aMarkRect.Center();
2904 nMarkSize=bVertical ? (aMarkRect.GetHeight()-1) : (aMarkRect.GetWidth()-1);
2905 aCenter=aMarkCenter;
2906 aStart=DragStat().GetStart();
2907 Show();
2908 return true;
2910 else
2912 return false;
2916 void SdrDragCrook::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
2918 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
2920 if(!pPV)
2921 return;
2923 XPolyPolygon aTempPolyPoly(rTarget);
2925 if (pPV->HasMarkedObjPageView())
2927 sal_uInt16 nPolyCount=aTempPolyPoly.Count();
2929 if (!bContortion && !getSdrDragView().IsNoDragXorPolys())
2931 sal_uInt16 n1st=0,nLast=0;
2932 Point aC(aCenter);
2934 while (n1st<nPolyCount)
2936 nLast=n1st;
2937 while (nLast<nPolyCount && aTempPolyPoly[nLast].GetPointCount()!=0) nLast++;
2938 tools::Rectangle aBound(aTempPolyPoly[n1st].GetBoundRect());
2939 sal_uInt16 i;
2941 for (i=n1st+1; i<nLast; i++)
2943 aBound.Union(aTempPolyPoly[n1st].GetBoundRect());
2946 Point aCtr0(aBound.Center());
2947 Point aCtr1(aCtr0);
2949 if (bResize)
2951 Fraction aFact1(1,1);
2953 if (bVertical)
2955 ResizePoint(aCtr1,aC,aFact1,aFact);
2957 else
2959 ResizePoint(aCtr1,aC,aFact,aFact1);
2963 bool bRotOk=false;
2964 double nSin=0,nCos=0;
2966 if (aRad.X()!=0 && aRad.Y()!=0)
2968 bRotOk=bRotate;
2970 switch (eMode)
2972 case SdrCrookMode::Rotate : CrookRotateXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2973 case SdrCrookMode::Slant : CrookSlantXPoint (aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical); break;
2974 case SdrCrookMode::Stretch: CrookStretchXPoint(aCtr1,nullptr,nullptr,aC,aRad,nSin,nCos,bVertical,aMarkRect); break;
2975 } // switch
2978 aCtr1-=aCtr0;
2980 for (i=n1st; i<nLast; i++)
2982 if (bRotOk)
2984 RotateXPoly(aTempPolyPoly[i],aCtr0,nSin,nCos);
2987 aTempPolyPoly[i].Move(aCtr1.X(),aCtr1.Y());
2990 n1st=nLast+1;
2993 else
2995 sal_uInt16 i,j;
2997 for (j=0; j<nPolyCount; j++)
2999 XPolygon& aPol=aTempPolyPoly[j];
3000 sal_uInt16 nPointCount=aPol.GetPointCount();
3001 i=0;
3003 while (i<nPointCount)
3005 Point* pPnt=&aPol[i];
3006 Point* pC1=nullptr;
3007 Point* pC2=nullptr;
3009 if (i+1<nPointCount && aPol.IsControl(i))
3010 { // control point on the left
3011 pC1=pPnt;
3012 i++;
3013 pPnt=&aPol[i];
3016 i++;
3018 if (i<nPointCount && aPol.IsControl(i))
3019 { // control point on the right
3020 pC2=&aPol[i];
3021 i++;
3024 MovCrookPoint(*pPnt,pC1,pC2);
3030 rTarget = aTempPolyPoly.getB2DPolyPolygon();
3033 void SdrDragCrook::MovCrookPoint(Point& rPnt, Point* pC1, Point* pC2)
3035 bool bVert=bVertical;
3036 bool bC1=pC1!=nullptr;
3037 bool bC2=pC2!=nullptr;
3038 Point aC(aCenter);
3040 if (bResize)
3042 Fraction aFact1(1,1);
3044 if (bVert)
3046 ResizePoint(rPnt,aC,aFact1,aFact);
3048 if (bC1)
3049 ResizePoint(*pC1,aC,aFact1,aFact);
3051 if (bC2)
3052 ResizePoint(*pC2,aC,aFact1,aFact);
3054 else
3056 ResizePoint(rPnt,aC,aFact,aFact1);
3058 if (bC1)
3059 ResizePoint(*pC1,aC,aFact,aFact1);
3061 if (bC2)
3062 ResizePoint(*pC2,aC,aFact,aFact1);
3066 if (aRad.X()!=0 && aRad.Y()!=0)
3068 double nSin,nCos;
3070 switch (eMode)
3072 case SdrCrookMode::Rotate : CrookRotateXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3073 case SdrCrookMode::Slant : CrookSlantXPoint (rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert); break;
3074 case SdrCrookMode::Stretch: CrookStretchXPoint(rPnt,pC1,pC2,aC,aRad,nSin,nCos,bVert,aMarkRect); break;
3075 } // switch
3079 void SdrDragCrook::MoveSdrDrag(const Point& rPnt)
3081 if (!DragStat().CheckMinMoved(rPnt))
3082 return;
3084 bool bNewMoveOnly=getSdrDragView().IsMoveOnlyDragging();
3085 bAtCenter=false;
3086 SdrCrookMode eNewMode=getSdrDragView().GetCrookMode();
3087 bool bNewContortion=!bNewMoveOnly && ((bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed);
3088 bResize=!getSdrDragView().IsOrtho() && bResizeAllowed && !bNewMoveOnly;
3089 bool bNewRotate=bRotateAllowed && !bNewContortion && !bNewMoveOnly && eNewMode==SdrCrookMode::Rotate;
3091 Point aPnt(GetSnapPos(rPnt));
3093 Point aNewCenter(aMarkCenter.X(),aStart.Y());
3095 if (bVertical)
3097 aNewCenter.setX(aStart.X() );
3098 aNewCenter.setY(aMarkCenter.Y() );
3101 if (!getSdrDragView().IsCrookAtCenter())
3103 switch (GetDragHdlKind())
3105 case SdrHdlKind::UpperLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3106 case SdrHdlKind::Upper: aNewCenter.setY(aMarkRect.Bottom() ); bUpr=true; break;
3107 case SdrHdlKind::UpperRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3108 case SdrHdlKind::Left : aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3109 case SdrHdlKind::Right: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3110 case SdrHdlKind::LowerLeft: aNewCenter.setX(aMarkRect.Right() ); bLft=true; break;
3111 case SdrHdlKind::Lower: aNewCenter.setY(aMarkRect.Top() ); bLwr=true; break;
3112 case SdrHdlKind::LowerRight: aNewCenter.setX(aMarkRect.Left() ); bRgt=true; break;
3113 default: bAtCenter=true;
3116 else
3117 bAtCenter=true;
3119 Fraction aNewFract(1,1);
3120 tools::Long dx1=aPnt.X()-aNewCenter.X();
3121 tools::Long dy1=aPnt.Y()-aNewCenter.Y();
3122 bValid=bVertical ? dx1!=0 : dy1!=0;
3124 if (bValid)
3126 if (bVertical)
3127 bValid = std::abs(dx1)*100>std::abs(dy1);
3128 else
3129 bValid = std::abs(dy1)*100>std::abs(dx1);
3132 tools::Long nNewRad=0;
3133 nAngle=0_deg100;
3135 if (bValid)
3137 double a=0; // slope of the radius
3138 Degree100 nPntAngle(0);
3140 if (bVertical)
3142 a=static_cast<double>(dy1)/static_cast<double>(dx1); // slope of the radius
3143 nNewRad=(static_cast<tools::Long>(dy1*a)+dx1) /2;
3144 aNewCenter.AdjustX(nNewRad );
3145 nPntAngle=GetAngle(aPnt-aNewCenter);
3147 else
3149 a=static_cast<double>(dx1)/static_cast<double>(dy1); // slope of the radius
3150 nNewRad=(static_cast<tools::Long>(dx1*a)+dy1) /2;
3151 aNewCenter.AdjustY(nNewRad );
3152 nPntAngle=GetAngle(aPnt-aNewCenter)-9000_deg100;
3155 if (!bAtCenter)
3157 if (nNewRad<0)
3159 if (bRgt) nPntAngle += 18000_deg100;
3160 if (bLft) nPntAngle = 18000_deg100 - nPntAngle;
3161 if (bLwr) nPntAngle =- nPntAngle;
3163 else
3165 if (bRgt) nPntAngle = -nPntAngle;
3166 if (bUpr) nPntAngle = 18000_deg100 - nPntAngle;
3167 if (bLwr) nPntAngle += 18000_deg100;
3170 nPntAngle=NormAngle36000(nPntAngle);
3172 else
3174 if (nNewRad<0) nPntAngle += 18000_deg100;
3175 if (bVertical) nPntAngle = 18000_deg100 - nPntAngle;
3176 nPntAngle = NormAngle18000(nPntAngle);
3177 nPntAngle = abs(nPntAngle);
3180 double nCircumference = 2 * std::abs(nNewRad) * M_PI;
3182 if (bResize)
3184 tools::Long nMul=static_cast<tools::Long>(nCircumference * NormAngle36000(nPntAngle).get() / 36000.0);
3186 if (bAtCenter)
3187 nMul*=2;
3189 aNewFract=Fraction(nMul,nMarkSize);
3190 nAngle=nPntAngle;
3192 else
3194 nAngle = Degree100(static_cast<tools::Long>((nMarkSize*360/nCircumference)*100)/2);
3196 if (nAngle==0_deg100)
3197 bValid=false;
3201 if (nAngle==0_deg100 || nNewRad==0)
3202 bValid=false;
3204 if (!bValid)
3205 nNewRad=0;
3207 if (!bValid && bResize)
3209 tools::Long nMul=bVertical ? dy1 : dx1;
3211 if (bLft || bUpr)
3212 nMul=-nMul;
3214 tools::Long nDiv=nMarkSize;
3216 if (bAtCenter)
3218 nMul*=2;
3219 nMul = std::abs(nMul);
3222 aNewFract=Fraction(nMul,nDiv);
3225 if (aNewCenter==aCenter && bNewContortion==bContortion && aNewFract==aFact &&
3226 bNewMoveOnly == getMoveOnly() && bNewRotate==bRotate && eNewMode==eMode)
3227 return;
3229 Hide();
3230 setMoveOnly(bNewMoveOnly);
3231 bRotate=bNewRotate;
3232 eMode=eNewMode;
3233 bContortion=bNewContortion;
3234 aCenter=aNewCenter;
3235 aFact=aNewFract;
3236 aRad=Point(nNewRad,nNewRad);
3237 bResize=aFact!=Fraction(1,1) && aFact.GetDenominator()!=0 && aFact.IsValid();
3238 DragStat().NextMove(aPnt);
3239 Show();
3242 void SdrDragCrook::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3244 const bool bDoResize(aFact!=Fraction(1,1));
3245 const bool bDoCrook(aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0);
3247 if (!(bDoCrook || bDoResize))
3248 return;
3250 if (bDoResize)
3252 Fraction aFact1(1,1);
3254 if (bContortion)
3256 if (bVertical)
3258 rTarget.Resize(aCenter,aFact1,aFact);
3260 else
3262 rTarget.Resize(aCenter,aFact,aFact1);
3265 else
3267 Point aCtr0(rTarget.GetSnapRect().Center());
3268 Point aCtr1(aCtr0);
3270 if (bVertical)
3272 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3274 else
3276 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3279 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3281 rTarget.Move(aSiz);
3285 if (bDoCrook)
3287 const tools::Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
3288 const bool bLocalRotate(!bContortion && eMode == SdrCrookMode::Rotate && getSdrDragView().IsRotateAllowed());
3290 SdrEditView::ImpCrookObj(&rTarget,aCenter,aRad,eMode,bVertical,!bContortion,bLocalRotate,aLocalMarkRect);
3294 void SdrDragCrook::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3296 // use helper derived from old stuff
3297 MovAllPoints(rTarget);
3300 bool SdrDragCrook::EndSdrDrag(bool bCopy)
3302 Hide();
3304 if (bResize && aFact==Fraction(1,1))
3305 bResize=false;
3307 const bool bUndo = getSdrDragView().IsUndoEnabled();
3309 bool bDoCrook=aCenter!=aMarkCenter && aRad.X()!=0 && aRad.Y()!=0;
3311 if (bDoCrook || bResize)
3313 if (bResize && bUndo)
3315 OUString aStr = ImpGetDescriptionStr(!bContortion?STR_EditCrook:STR_EditCrookContortion);
3317 if (bCopy)
3318 aStr += SvxResId(STR_EditWithCopy);
3320 getSdrDragView().BegUndo(aStr);
3323 if (bResize)
3325 Fraction aFact1(1,1);
3327 if (bContortion)
3329 if (bVertical)
3330 getSdrDragView().ResizeMarkedObj(aCenter,aFact1,aFact,bCopy);
3331 else
3332 getSdrDragView().ResizeMarkedObj(aCenter,aFact,aFact1,bCopy);
3334 else
3336 if (bCopy)
3337 getSdrDragView().CopyMarkedObj();
3339 const size_t nMarkCount=getSdrDragView().GetMarkedObjectList().GetMarkCount();
3341 for (size_t nm=0; nm<nMarkCount; ++nm)
3343 SdrMark* pM=getSdrDragView().GetMarkedObjectList().GetMark(nm);
3344 SdrObject* pO=pM->GetMarkedSdrObj();
3345 Point aCtr0(pO->GetSnapRect().Center());
3346 Point aCtr1(aCtr0);
3348 if (bVertical)
3349 ResizePoint(aCtr1,aCenter,aFact1,aFact);
3350 else
3351 ResizePoint(aCtr1,aCenter,aFact,aFact1);
3353 Size aSiz(aCtr1.X()-aCtr0.X(),aCtr1.Y()-aCtr0.Y());
3354 if( bUndo )
3355 AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoMoveObject(*pO,aSiz));
3356 pO->Move(aSiz);
3360 bCopy=false;
3363 if (bDoCrook)
3365 getSdrDragView().CrookMarkedObj(aCenter,aRad,eMode,bVertical,!bContortion,bCopy);
3368 if (bResize && bUndo)
3369 getSdrDragView().EndUndo();
3371 return true;
3374 return false;
3377 PointerStyle SdrDragCrook::GetSdrDragPointer() const
3379 return PointerStyle::Crook;
3383 SdrDragDistort::SdrDragDistort(SdrDragView& rNewView)
3384 : SdrDragMethod(rNewView),
3385 nPolyPt(0),
3386 bContortionAllowed(false),
3387 bNoContortionAllowed(false),
3388 bContortion(false)
3392 OUString SdrDragDistort::GetSdrDragComment() const
3394 OUString aStr = ImpGetDescriptionStr(STR_DragMethDistort)
3395 + " (x="
3396 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
3397 + " y="
3398 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
3399 + ")";
3401 if(getSdrDragView().IsDragWithCopy())
3402 aStr += SvxResId(STR_EditWithCopy);
3403 return aStr;
3406 void SdrDragDistort::createSdrDragEntries()
3408 // Add extended frame raster first, so it will be behind objects
3409 if(getSdrDragView().GetSdrPageView())
3411 const basegfx::B2DPolyPolygon aDragRaster(impCreateDragRaster(*getSdrDragView().GetSdrPageView(), GetMarkedRect()));
3413 if(aDragRaster.count())
3415 addSdrDragEntry(std::unique_ptr<SdrDragEntry>(new SdrDragEntryPolyPolygon(aDragRaster)));
3419 // call parent
3420 SdrDragMethod::createSdrDragEntries();
3423 bool SdrDragDistort::BeginSdrDrag()
3425 bContortionAllowed=getSdrDragView().IsDistortAllowed();
3426 bNoContortionAllowed=getSdrDragView().IsDistortAllowed(true);
3428 if (bContortionAllowed || bNoContortionAllowed)
3430 SdrHdlKind eKind=GetDragHdlKind();
3431 nPolyPt=0xFFFF;
3433 if (eKind==SdrHdlKind::UpperLeft) nPolyPt=0;
3434 if (eKind==SdrHdlKind::UpperRight) nPolyPt=1;
3435 if (eKind==SdrHdlKind::LowerRight) nPolyPt=2;
3436 if (eKind==SdrHdlKind::LowerLeft) nPolyPt=3;
3437 if (nPolyPt>3) return false;
3439 aMarkRect=GetMarkedRect();
3440 aDistortedRect=XPolygon(aMarkRect);
3441 Show();
3442 return true;
3444 else
3446 return false;
3450 void SdrDragDistort::MovAllPoints(basegfx::B2DPolyPolygon& rTarget)
3452 if (!bContortion)
3453 return;
3455 SdrPageView* pPV = getSdrDragView().GetSdrPageView();
3457 if(pPV && pPV->HasMarkedObjPageView())
3459 basegfx::B2DPolyPolygon aDragPolygon(rTarget);
3460 const basegfx::B2DRange aOriginalRange = vcl::unotools::b2DRectangleFromRectangle(aMarkRect);
3461 const basegfx::B2DPoint aTopLeft(aDistortedRect[0].X(), aDistortedRect[0].Y());
3462 const basegfx::B2DPoint aTopRight(aDistortedRect[1].X(), aDistortedRect[1].Y());
3463 const basegfx::B2DPoint aBottomLeft(aDistortedRect[3].X(), aDistortedRect[3].Y());
3464 const basegfx::B2DPoint aBottomRight(aDistortedRect[2].X(), aDistortedRect[2].Y());
3466 aDragPolygon = basegfx::utils::distort(aDragPolygon, aOriginalRange, aTopLeft, aTopRight, aBottomLeft, aBottomRight);
3467 rTarget = aDragPolygon;
3471 void SdrDragDistort::MoveSdrDrag(const Point& rPnt)
3473 if (!DragStat().CheckMinMoved(rPnt))
3474 return;
3476 Point aPnt(GetSnapPos(rPnt));
3478 if (getSdrDragView().IsOrtho())
3479 OrthoDistance8(DragStat().GetStart(),aPnt,getSdrDragView().IsBigOrtho());
3481 bool bNewContortion=(bContortionAllowed && !getSdrDragView().IsCrookNoContortion()) || !bNoContortionAllowed;
3483 if (bNewContortion!=bContortion || aDistortedRect[nPolyPt]!=aPnt)
3485 Hide();
3486 aDistortedRect[nPolyPt]=aPnt;
3487 bContortion=bNewContortion;
3488 DragStat().NextMove(aPnt);
3489 Show();
3493 bool SdrDragDistort::EndSdrDrag(bool bCopy)
3495 Hide();
3496 bool bDoDistort=DragStat().GetDX()!=0 || DragStat().GetDY()!=0;
3498 if (bDoDistort)
3500 getSdrDragView().DistortMarkedObj(aMarkRect,aDistortedRect,!bContortion,bCopy);
3501 return true;
3504 return false;
3507 PointerStyle SdrDragDistort::GetSdrDragPointer() const
3509 return PointerStyle::RefHand;
3512 void SdrDragDistort::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
3514 const bool bDoDistort(DragStat().GetDX()!=0 || DragStat().GetDY()!=0);
3516 if (bDoDistort)
3518 SdrEditView::ImpDistortObj(&rTarget, aMarkRect, aDistortedRect, !bContortion);
3522 void SdrDragDistort::applyCurrentTransformationToPolyPolygon(basegfx::B2DPolyPolygon& rTarget)
3524 // use helper derived from old stuff
3525 MovAllPoints(rTarget);
3529 SdrDragCrop::SdrDragCrop(SdrDragView& rNewView)
3530 : SdrDragObjOwn(rNewView)
3532 // switch off solid dragging for crop; it just makes no sense since showing
3533 // a 50% transparent object above the original will not be visible
3534 setSolidDraggingActive(false);
3537 OUString SdrDragCrop::GetSdrDragComment() const
3539 OUString aStr = ImpGetDescriptionStr(STR_DragMethCrop)
3540 + " (x="
3541 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDX())
3542 + " y="
3543 + getSdrDragView().GetModel().GetMetricString(DragStat().GetDY())
3544 + ")";
3546 if(getSdrDragView().IsDragWithCopy())
3547 aStr += SvxResId(STR_EditWithCopy);
3548 return aStr;
3551 bool SdrDragCrop::BeginSdrDrag()
3553 // call parent
3554 bool bRetval(SdrDragObjOwn::BeginSdrDrag());
3556 if(!GetDragHdl())
3558 // we need the DragHdl, break if not there
3559 bRetval = false;
3562 return bRetval;
3565 bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
3567 Hide();
3569 if(0 == DragStat().GetDX() && 0 == DragStat().GetDY())
3571 // no change, done
3572 return false;
3575 const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
3577 if(1 != rMarkList.GetMarkCount())
3579 // Crop only with single Object selected
3580 return false;
3583 // prepare for SdrGrafObj or others. This code has to work with usual
3584 // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from
3585 // Writer. It would be better to handle this in Writer directly, but
3586 // there are currently no easy mechanisms to plug an alternative interaction
3587 // from there
3588 SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
3589 rtl::Reference<SdrObject> pFullDragClone;
3590 bool bExternal(false);
3591 SdrObject* pExternalSdrObject(nullptr);
3593 // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now
3594 // locally, no two-in-one methods any more
3595 if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) == nullptr)
3597 // If Writer, get the already offered for interaction SdrGrafObj
3598 // and set up for using that replacement object that contains the
3599 // real transformation. That SdrObject is owned and has to be deleted,
3600 // so use a std::unique_ptr with special handling for the protected
3601 // SDrObject destructor
3602 pFullDragClone = pSdrObject->getFullDragClone();
3604 if(dynamic_cast< SdrGrafObj* >(pFullDragClone.get()))
3606 bExternal = true;
3607 pExternalSdrObject = pSdrObject;
3608 pSdrObject = pFullDragClone.get();
3612 // get and check for SdrGrafObj now
3613 SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject );
3615 if(!pObj)
3617 return false;
3620 // no undo for external needed, done there
3621 const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled());
3623 if(bUndo)
3625 OUString aUndoStr = ImpGetDescriptionStr(STR_DragMethCrop);
3627 getSdrDragView().BegUndo( aUndoStr );
3628 getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
3629 // also need attr undo, the SdrGrafCropItem will be changed
3630 getSdrDragView().AddUndo(getSdrDragView().GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
3633 // get the original objects transformation
3634 basegfx::B2DHomMatrix aOriginalMatrix;
3635 basegfx::B2DPolyPolygon aPolyPolygon;
3636 bool bShearCorrected(false);
3637 pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
3639 { // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
3640 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix);
3642 if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX()))
3644 bShearCorrected = true;
3645 aOriginalMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3646 aTmpDecomp.getScale(),
3647 -aTmpDecomp.getShearX(),
3648 aTmpDecomp.getRotate(),
3649 aTmpDecomp.getTranslate());
3653 // generate start point of original drag vector in unit coordinates (the
3654 // vis-a-vis of the drag point)
3655 basegfx::B2DPoint aLocalStart(0.0, 0.0);
3656 bool bOnAxis(false);
3658 switch(GetDragHdlKind())
3660 case SdrHdlKind::UpperLeft: aLocalStart.setX(1.0); aLocalStart.setY(1.0); break;
3661 case SdrHdlKind::Upper: aLocalStart.setX(0.5); aLocalStart.setY(1.0); bOnAxis = true; break;
3662 case SdrHdlKind::UpperRight: aLocalStart.setX(0.0); aLocalStart.setY(1.0); break;
3663 case SdrHdlKind::Left : aLocalStart.setX(1.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3664 case SdrHdlKind::Right: aLocalStart.setX(0.0); aLocalStart.setY(0.5); bOnAxis = true; break;
3665 case SdrHdlKind::LowerLeft: aLocalStart.setX(1.0); aLocalStart.setY(0.0); break;
3666 case SdrHdlKind::Lower: aLocalStart.setX(0.5); aLocalStart.setY(0.0); bOnAxis = true; break;
3667 case SdrHdlKind::LowerRight: aLocalStart.setX(0.0); aLocalStart.setY(0.0); break;
3668 default: break;
3671 // create the current drag position in unit coordinates. To get there,
3672 // transform back the DragPoint to UnitCoordinates
3673 basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
3674 aInverse.invert();
3675 basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y()));
3677 // if one of the edge handles is used, limit to X or Y drag only
3678 if(bOnAxis)
3680 if(basegfx::fTools::equal(aLocalStart.getX(), 0.5))
3682 aLocalCurrent.setX(aLocalStart.getX());
3684 else
3686 aLocalCurrent.setY(aLocalStart.getY());
3690 // create internal change in unit coordinates
3691 basegfx::B2DHomMatrix aDiscreteChangeMatrix;
3693 if(!basegfx::fTools::equal(aLocalCurrent.getX(), aLocalStart.getX()))
3695 if(aLocalStart.getX() < 0.5)
3697 aDiscreteChangeMatrix.scale(aLocalCurrent.getX(), 1.0);
3699 else
3701 aDiscreteChangeMatrix.scale(1.0 - aLocalCurrent.getX(), 1.0);
3702 aDiscreteChangeMatrix.translate(aLocalCurrent.getX(), 0.0);
3706 if(!basegfx::fTools::equal(aLocalCurrent.getY(), aLocalStart.getY()))
3708 if(aLocalStart.getY() < 0.5)
3710 aDiscreteChangeMatrix.scale(1.0, aLocalCurrent.getY());
3712 else
3714 aDiscreteChangeMatrix.scale(1.0, 1.0 - aLocalCurrent.getY());
3715 aDiscreteChangeMatrix.translate(0.0, aLocalCurrent.getY());
3719 // We now have the whole executed Crop in UnitCoordinates in
3720 // aDiscreteChangeMatrix, go to concrete sizes now.
3721 // Create the unrotated original rectangle and the unrotated modified
3722 // rectangle as Ranges
3723 const basegfx::utils::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix);
3725 // prepare unsheared/unrotated versions of the old and new transformation
3726 const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
3727 basegfx::utils::createScaleTranslateB2DHomMatrix(
3728 basegfx::absolute(aOriginalMatrixDecomp.getScale()),
3729 aOriginalMatrixDecomp.getTranslate()));
3731 // create the ranges for these
3732 basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3733 basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
3734 aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate);
3735 aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix);
3737 if(bExternal)
3739 // With aLocalStart point (opposed to dragged point), X scale and Y scale,
3740 // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
3741 // crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
3742 // the called instance knows best how to use it
3743 const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
3744 const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
3746 pExternalSdrObject->Crop(
3747 aLocalStart,
3748 fScaleX,
3749 fScaleY);
3751 else
3753 // prepare matrix to apply to object; evtl. back-correct shear
3754 basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
3756 if(bShearCorrected)
3758 // back-correct shear
3759 const basegfx::utils::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix);
3761 aNewObjectMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
3762 aTmpDecomp.getScale(),
3763 -aTmpDecomp.getShearX(),
3764 aTmpDecomp.getRotate(),
3765 aTmpDecomp.getTranslate());
3768 // apply change to object by applying the unit coordinate change followed
3769 // by the original change
3770 pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
3772 // extract the old Rectangle structures
3773 tools::Rectangle aOldRect(
3774 basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()),
3775 basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()),
3776 basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()),
3777 basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY()));
3778 tools::Rectangle aNewRect(
3779 basegfx::fround(aRangeNewNoShearNoRotate.getMinX()),
3780 basegfx::fround(aRangeNewNoShearNoRotate.getMinY()),
3781 basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()),
3782 basegfx::fround(aRangeNewNoShearNoRotate.getMaxY()));
3784 // continue with the old original stuff
3785 if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
3787 throw o3tl::divide_by_zero();
3790 if((pObj->GetGraphicType() == GraphicType::NONE) || (pObj->GetGraphicType() == GraphicType::Default))
3792 return false;
3795 const GraphicObject& rGraphicObject(pObj->GetGraphicObject());
3796 // tdf#117145 Usually Writer will go the bExternal path (see above), but more correct for
3797 // the future is to use the MapMode from the SdrModel/SfxItemPool if the Writer's current
3798 // special handling should be unified to this path in the future. Usually it *should* be
3799 // MapUnit::Map100thMM, but better do not mix up Units.
3800 // Checked now what SwVirtFlyDrawObj::NbcCrop is doing - it calculates everything forced
3801 // to MapUnit::Map100thMM, but extracts/packs Twips to the used SdrGrafCropItem in Writer.
3802 const MapMode aMapModePool(pObj->getSdrModelFromSdrObject().GetItemPool().GetMetric(0));
3803 Size aGraphicSize(rGraphicObject.GetPrefSize());
3805 if(MapUnit::MapPixel == rGraphicObject.GetPrefMapMode().GetMapUnit())
3807 aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapModePool);
3809 else
3811 aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapModePool);
3814 if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height())
3816 return false;
3819 const SdrGrafCropItem& rOldCrop = pObj->GetMergedItem(SDRATTR_GRAFCROP);
3820 double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / static_cast<double>(aOldRect.GetWidth());
3821 double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / static_cast<double>(aOldRect.GetHeight());
3823 sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
3824 sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
3825 sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
3826 sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
3828 if(pObj->IsMirrored())
3830 // mirrored X or Y, for old stuff, exchange X
3831 // check for aw080
3832 sal_Int32 nTmp(nDiffLeft);
3833 nDiffLeft = -nDiffRight;
3834 nDiffRight = -nTmp;
3837 sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
3838 sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
3839 sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
3840 sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
3842 SfxItemPool& rPool = getSdrDragView().GetModel().GetItemPool();
3843 SfxItemSetFixed<SDRATTR_GRAFCROP, SDRATTR_GRAFCROP> aSet( rPool );
3844 aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
3845 getSdrDragView().SetAttributes( aSet, false );
3848 if(bUndo)
3850 getSdrDragView().EndUndo();
3853 return true;
3856 PointerStyle SdrDragCrop::GetSdrDragPointer() const
3858 return PointerStyle::Crop;
3861 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */