Adjust includes
[LibreOffice.git] / svx / source / svdraw / svdpoev.cxx
blobf6b9bd6d784548118be3d0ad0a7bdd12a422f011
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 .
21 #include <svx/svdpoev.hxx>
22 #include <math.h>
23 #include <svx/svdpagv.hxx>
24 #include <svx/svdpage.hxx>
25 #include <svx/svdopath.hxx>
26 #include <svx/svdundo.hxx>
27 #include <svx/strings.hrc>
28 #include <svdglob.hxx>
29 #include <svx/svdtrans.hxx>
30 #include <basegfx/polygon/b2dpolygon.hxx>
31 #include <basegfx/polygon/b2dpolygontools.hxx>
32 #include <tools/helpers.hxx>
34 #include <svx/polypolygoneditor.hxx>
36 using namespace sdr;
39 void SdrPolyEditView::ImpResetPolyPossibilityFlags()
41 eMarkedPointsSmooth=SdrPathSmoothKind::DontCare;
42 eMarkedSegmentsKind=SdrPathSegmentKind::DontCare;
43 bSetMarkedPointsSmoothPossible=false;
44 bSetMarkedSegmentsKindPossible=false;
47 SdrPolyEditView::SdrPolyEditView(SdrModel* pModel1, OutputDevice* pOut):
48 SdrEditView(pModel1,pOut)
50 ImpResetPolyPossibilityFlags();
53 SdrPolyEditView::~SdrPolyEditView()
57 void SdrPolyEditView::ImpCheckPolyPossibilities()
59 ImpResetPolyPossibilityFlags();
60 const size_t nMarkCount(GetMarkedObjectCount());
62 if(nMarkCount && !ImpIsFrameHandles())
64 bool b1stSmooth(true);
65 bool b1stSegm(true);
66 bool bCurve(false);
67 bool bSmoothFuz(false);
68 bool bSegmFuz(false);
69 basegfx::B2VectorContinuity eSmooth = basegfx::B2VectorContinuity::NONE;
71 for(size_t nMarkNum = 0; nMarkNum < nMarkCount; ++nMarkNum)
73 SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
74 CheckPolyPossibilitiesHelper( pM, b1stSmooth, b1stSegm, bCurve, bSmoothFuz, bSegmFuz, eSmooth );
79 void SdrPolyEditView::CheckPolyPossibilitiesHelper( SdrMark* pM, bool& b1stSmooth, bool& b1stSegm, bool& bCurve, bool& bSmoothFuz, bool& bSegmFuz, basegfx::B2VectorContinuity& eSmooth )
81 SdrObject* pObj = pM->GetMarkedSdrObj();
82 SdrPathObj* pPath = dynamic_cast<SdrPathObj*>( pObj );
84 if (!pPath)
85 return;
87 SdrUShortCont& rPts = pM->GetMarkedPoints();
88 if (rPts.empty())
89 return;
91 const bool bClosed(pPath->IsClosed());
92 bSetMarkedPointsSmoothPossible = true;
94 if (bClosed)
96 bSetMarkedSegmentsKindPossible = true;
99 for (SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); ++it)
101 sal_uInt32 nNum(*it);
102 sal_uInt32 nPolyNum, nPntNum;
104 if(PolyPolygonEditor::GetRelativePolyPoint(pPath->GetPathPoly(), nNum, nPolyNum, nPntNum))
106 const basegfx::B2DPolygon aLocalPolygon(pPath->GetPathPoly().getB2DPolygon(nPolyNum));
107 bool bCanSegment(bClosed || nPntNum < aLocalPolygon.count() - 1);
109 if(!bSetMarkedSegmentsKindPossible && bCanSegment)
111 bSetMarkedSegmentsKindPossible = true;
114 if(!bSmoothFuz)
116 if (b1stSmooth)
118 b1stSmooth = false;
119 eSmooth = basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum);
121 else
123 bSmoothFuz = (eSmooth != basegfx::utils::getContinuityInPoint(aLocalPolygon, nPntNum));
127 if(!bSegmFuz)
129 if(bCanSegment)
131 bool bCrv(aLocalPolygon.isNextControlPointUsed(nPntNum));
133 if(b1stSegm)
135 b1stSegm = false;
136 bCurve = bCrv;
138 else
140 bSegmFuz = (bCrv != bCurve);
147 if(!b1stSmooth && !bSmoothFuz)
149 if(basegfx::B2VectorContinuity::NONE == eSmooth)
151 eMarkedPointsSmooth = SdrPathSmoothKind::Angular;
154 if(basegfx::B2VectorContinuity::C1 == eSmooth)
156 eMarkedPointsSmooth = SdrPathSmoothKind::Asymmetric;
159 if(basegfx::B2VectorContinuity::C2 == eSmooth)
161 eMarkedPointsSmooth = SdrPathSmoothKind::Symmetric;
165 if(!b1stSegm && !bSegmFuz)
167 eMarkedSegmentsKind = bCurve ? SdrPathSegmentKind::Curve : SdrPathSegmentKind::Line;
171 void SdrPolyEditView::SetMarkedPointsSmooth(SdrPathSmoothKind eKind)
173 basegfx::B2VectorContinuity eFlags;
175 if(SdrPathSmoothKind::Angular == eKind)
177 eFlags = basegfx::B2VectorContinuity::NONE;
179 else if(SdrPathSmoothKind::Asymmetric == eKind)
181 eFlags = basegfx::B2VectorContinuity::C1;
183 else if(SdrPathSmoothKind::Symmetric == eKind)
185 eFlags = basegfx::B2VectorContinuity::C2;
187 else
189 return;
192 if(HasMarkedPoints())
194 SortMarkedObjects();
196 const bool bUndo = IsUndoEnabled();
197 if( bUndo )
198 BegUndo(ImpGetResStr(STR_EditSetPointsSmooth), GetDescriptionOfMarkedPoints());
199 const size_t nMarkCount(GetMarkedObjectCount());
201 for(size_t nMarkNum(nMarkCount); nMarkNum > 0;)
203 --nMarkNum;
204 SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
205 SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
206 if (!pPath)
207 continue;
209 SdrUShortCont& rPts = pM->GetMarkedPoints();
210 PolyPolygonEditor aEditor(pPath->GetPathPoly());
211 if (aEditor.SetPointsSmooth(eFlags, rPts))
213 if( bUndo )
214 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
215 pPath->SetPathPoly(aEditor.GetPolyPolygon());
219 if( bUndo )
220 EndUndo();
224 void SdrPolyEditView::SetMarkedSegmentsKind(SdrPathSegmentKind eKind)
226 if(HasMarkedPoints())
228 SortMarkedObjects();
230 const bool bUndo = IsUndoEnabled();
231 if( bUndo )
232 BegUndo(ImpGetResStr(STR_EditSetSegmentsKind), GetDescriptionOfMarkedPoints());
233 const size_t nMarkCount(GetMarkedObjectCount());
235 for(size_t nMarkNum=nMarkCount; nMarkNum > 0;)
237 --nMarkNum;
238 SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
239 SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
240 if (!pPath)
241 continue;
242 SdrUShortCont& rPts = pM->GetMarkedPoints();
243 PolyPolygonEditor aEditor( pPath->GetPathPoly());
244 if (aEditor.SetSegmentsKind(eKind, rPts))
246 if( bUndo )
247 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath));
248 pPath->SetPathPoly(aEditor.GetPolyPolygon());
252 if( bUndo )
253 EndUndo();
257 bool SdrPolyEditView::IsSetMarkedPointsSmoothPossible() const
259 ForcePossibilities();
260 return bSetMarkedPointsSmoothPossible;
263 SdrPathSmoothKind SdrPolyEditView::GetMarkedPointsSmooth() const
265 ForcePossibilities();
266 return eMarkedPointsSmooth;
269 bool SdrPolyEditView::IsSetMarkedSegmentsKindPossible() const
271 ForcePossibilities();
272 return bSetMarkedSegmentsKindPossible;
275 SdrPathSegmentKind SdrPolyEditView::GetMarkedSegmentsKind() const
277 ForcePossibilities();
278 return eMarkedSegmentsKind;
281 bool SdrPolyEditView::IsDeleteMarkedPointsPossible() const
283 return HasMarkedPoints();
286 void SdrPolyEditView::DeleteMarkedPoints()
288 if (HasMarkedPoints())
290 BrkAction();
291 SortMarkedObjects();
292 const size_t nMarkCount=GetMarkedObjectCount();
294 const bool bUndo = IsUndoEnabled();
295 if( bUndo )
297 // Description
298 BegUndo(ImpGetResStr(STR_EditDelete),GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Delete);
301 for (size_t nMarkNum=nMarkCount; nMarkNum>0;)
303 --nMarkNum;
304 SdrMark* pM=GetSdrMarkByIndex(nMarkNum);
305 SdrPathObj* pPath = dynamic_cast< SdrPathObj* >( pM->GetMarkedSdrObj() );
306 if (!pPath)
307 continue;
309 SdrUShortCont& rPts = pM->GetMarkedPoints();
310 PolyPolygonEditor aEditor( pPath->GetPathPoly());
311 if (aEditor.DeletePoints(rPts))
313 if( aEditor.GetPolyPolygon().count() )
315 if( bUndo )
316 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath ));
317 pPath->SetPathPoly( aEditor.GetPolyPolygon() );
319 else
321 if( bUndo )
322 AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pPath ) );
323 pM->GetPageView()->GetObjList()->RemoveObject(pPath->GetOrdNum());
324 if( !bUndo )
326 SdrObject* pObj = pPath;
327 SdrObject::Free(pObj);
333 if( bUndo )
334 EndUndo();
335 UnmarkAllPoints();
336 MarkListHasChanged();
340 void SdrPolyEditView::RipUpAtMarkedPoints()
342 if(HasMarkedPoints())
344 SortMarkedObjects();
345 const size_t nMarkCount(GetMarkedObjectCount());
347 const bool bUndo = IsUndoEnabled();
348 if( bUndo )
349 BegUndo(ImpGetResStr(STR_EditRipUp), GetDescriptionOfMarkedPoints());
351 for(size_t nMarkNum = nMarkCount; nMarkNum > 0;)
353 --nMarkNum;
354 SdrMark* pM = GetSdrMarkByIndex(nMarkNum);
355 SdrPathObj* pObj = dynamic_cast<SdrPathObj*>( pM->GetMarkedSdrObj() );
356 if (!pObj)
357 continue;
359 SdrUShortCont& rPts = pM->GetMarkedPoints();
361 if( bUndo )
362 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
363 bool bKorregFlag(false);
364 sal_uInt32 nMax(pObj->GetHdlCount());
366 for(SdrUShortCont::const_reverse_iterator it = rPts.rbegin(); it != rPts.rend(); ++it)
368 sal_uInt32 nNewPt0Idx(0);
369 SdrObject* pNewObj = pObj->RipPoint(*it, nNewPt0Idx);
371 if(pNewObj)
373 pM->GetPageView()->GetObjList()->InsertObject(pNewObj, pObj->GetOrdNum() + 1);
374 if( bUndo )
375 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewObj));
376 MarkObj(pNewObj, pM->GetPageView(), false, true);
379 if(nNewPt0Idx)
381 // correction necessary?
382 DBG_ASSERT(!bKorregFlag,"Multiple index corrections at SdrPolyEditView::RipUp().");
383 if(!bKorregFlag)
385 bKorregFlag = true;
387 SdrUShortCont aReplaceSet;
388 for(SdrUShortCont::const_iterator it2 = rPts.begin(); it2 != rPts.end(); ++it2)
390 sal_uInt32 nPntNum(*it2);
391 nPntNum += nNewPt0Idx;
393 if(nPntNum >= nMax)
395 nPntNum -= nMax;
398 aReplaceSet.insert( (sal_uInt16)nPntNum );
400 rPts.swap(aReplaceSet);
402 it = rPts.rbegin();
408 UnmarkAllPoints();
409 if( bUndo )
410 EndUndo();
411 MarkListHasChanged();
415 bool SdrPolyEditView::IsRipUpAtMarkedPointsPossible() const
417 bool bRetval(false);
418 const size_t nMarkCount(GetMarkedObjectCount());
420 for(size_t a = 0; a < nMarkCount; ++a)
422 const SdrMark* pMark = GetSdrMarkByIndex(a);
423 const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
425 if (!pMarkedPathObject)
426 continue;
428 const SdrUShortCont& rSelectedPoints = pMark->GetMarkedPoints();
429 if (rSelectedPoints.empty())
430 continue;
432 const basegfx::B2DPolyPolygon& rPathPolyPolygon = pMarkedPathObject->GetPathPoly();
434 if(1 == rPathPolyPolygon.count())
436 // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
437 // are different and methods need to be changed thoroughly with interaction rework
438 const tools::Polygon aPathPolygon(rPathPolyPolygon.getB2DPolygon(0));
439 const sal_uInt16 nPointCount(aPathPolygon.GetSize());
441 if(nPointCount >= 3)
443 bRetval = pMarkedPathObject->IsClosedObj(); // #i76617#
445 for(SdrUShortCont::const_iterator it = rSelectedPoints.begin();
446 !bRetval && it != rSelectedPoints.end(); ++it)
448 const sal_uInt16 nMarkedPointNum(*it);
450 bRetval = (nMarkedPointNum > 0 && nMarkedPointNum < nPointCount - 1);
456 return bRetval;
459 bool SdrPolyEditView::IsOpenCloseMarkedObjectsPossible() const
461 bool bRetval(false);
462 const size_t nMarkCount(GetMarkedObjectCount());
464 for(size_t a = 0; a < nMarkCount; ++a)
466 const SdrMark* pMark = GetSdrMarkByIndex(a);
467 const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
469 if(pMarkedPathObject)
471 // #i76617# Do not yet use basegfx::B2DPolygon since curve definitions
472 // are different and methods need to be changed thoroughly with interaction rework
473 const tools::PolyPolygon aPathPolyPolygon(pMarkedPathObject->GetPathPoly());
474 const sal_uInt16 nPolygonCount(aPathPolyPolygon.Count());
476 for(sal_uInt16 b(0); !bRetval && b < nPolygonCount; b++)
478 const tools::Polygon& rPathPolygon = aPathPolyPolygon[b];
479 const sal_uInt16 nPointCount(rPathPolygon.GetSize());
481 bRetval = (nPointCount >= 3);
486 return bRetval;
489 SdrObjClosedKind SdrPolyEditView::GetMarkedObjectsClosedState() const
491 bool bOpen(false);
492 bool bClosed(false);
493 const size_t nMarkCount(GetMarkedObjectCount());
495 for(size_t a = 0; !(bOpen && bClosed) && a < nMarkCount; ++a)
497 const SdrMark* pMark = GetSdrMarkByIndex(a);
498 const SdrPathObj* pMarkedPathObject = dynamic_cast< const SdrPathObj* >(pMark->GetMarkedSdrObj());
500 if(pMarkedPathObject)
502 if(pMarkedPathObject->IsClosedObj())
504 bClosed = true;
506 else
508 bOpen = true;
513 if(bOpen && bClosed)
515 return SdrObjClosedKind::DontCare;
517 else if(bOpen)
519 return SdrObjClosedKind::Open;
521 else
523 return SdrObjClosedKind::Closed;
527 void SdrPolyEditView::ImpTransformMarkedPoints(PPolyTrFunc pTrFunc, const void* p1, const void* p2, const void* p3, const void* p4)
529 const bool bUndo = IsUndoEnabled();
531 const size_t nMarkCount=GetMarkedObjectCount();
532 for (size_t nm=0; nm<nMarkCount; ++nm)
534 SdrMark* pM=GetSdrMarkByIndex(nm);
535 SdrObject* pObj=pM->GetMarkedSdrObj();
536 SdrPathObj* pPath=dynamic_cast<SdrPathObj*>( pObj );
537 if (!pPath)
538 continue;
540 const SdrUShortCont& rPts = pM->GetMarkedPoints();
541 if (rPts.empty())
542 continue;
544 if( bUndo )
545 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pObj));
547 basegfx::B2DPolyPolygon aXPP(pPath->GetPathPoly());
549 for (SdrUShortCont::const_iterator it = rPts.begin(); it != rPts.end(); ++it)
551 sal_uInt32 nPt = *it;
552 sal_uInt32 nPolyNum, nPointNum;
554 if(PolyPolygonEditor::GetRelativePolyPoint(aXPP, nPt, nPolyNum, nPointNum))
556 //#i83671# used nLocalPointNum (which was the polygon point count)
557 // instead of the point index (nPointNum). This of course leaded
558 // to a wrong point access to the B2DPolygon.
559 basegfx::B2DPolygon aNewXP(aXPP.getB2DPolygon(nPolyNum));
560 Point aPos, aC1, aC2;
561 bool bC1(false);
562 bool bC2(false);
564 const basegfx::B2DPoint aB2DPos(aNewXP.getB2DPoint(nPointNum));
565 aPos = Point(FRound(aB2DPos.getX()), FRound(aB2DPos.getY()));
567 if(aNewXP.isPrevControlPointUsed(nPointNum))
569 const basegfx::B2DPoint aB2DC1(aNewXP.getPrevControlPoint(nPointNum));
570 aC1 = Point(FRound(aB2DC1.getX()), FRound(aB2DC1.getY()));
571 bC1 = true;
574 if(aNewXP.isNextControlPointUsed(nPointNum))
576 const basegfx::B2DPoint aB2DC2(aNewXP.getNextControlPoint(nPointNum));
577 aC2 = Point(FRound(aB2DC2.getX()), FRound(aB2DC2.getY()));
578 bC2 = true;
581 (*pTrFunc)(aPos,&aC1,&aC2,p1,p2,p3,p4);
582 aNewXP.setB2DPoint(nPointNum, basegfx::B2DPoint(aPos.X(), aPos.Y()));
584 if (bC1)
586 aNewXP.setPrevControlPoint(nPointNum, basegfx::B2DPoint(aC1.X(), aC1.Y()));
589 if (bC2)
591 aNewXP.setNextControlPoint(nPointNum, basegfx::B2DPoint(aC2.X(), aC2.Y()));
594 aXPP.setB2DPolygon(nPolyNum, aNewXP);
598 pPath->SetPathPoly(aXPP);
603 static void ImpMove(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* /*p3*/, const void* /*p4*/)
605 MovePoint(rPt,*static_cast<const Size*>(p1));
606 if (pC1!=nullptr) MovePoint(*pC1,*static_cast<const Size*>(p1));
607 if (pC2!=nullptr) MovePoint(*pC2,*static_cast<const Size*>(p1));
610 void SdrPolyEditView::MoveMarkedPoints(const Size& rSiz)
612 ForceUndirtyMrkPnt();
613 OUString aStr(ImpGetResStr(STR_EditMove));
614 BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Move);
615 ImpTransformMarkedPoints(ImpMove,&rSiz);
616 EndUndo();
617 AdjustMarkHdl();
620 static void ImpResize(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* p2, const void* p3, const void* /*p4*/)
622 ResizePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
623 if (pC1!=nullptr) ResizePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
624 if (pC2!=nullptr) ResizePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const Fraction*>(p2),*static_cast<const Fraction*>(p3));
627 void SdrPolyEditView::ResizeMarkedPoints(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
629 ForceUndirtyMrkPnt();
630 OUString aStr(ImpGetResStr(STR_EditResize));
631 BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Resize);
632 ImpTransformMarkedPoints(ImpResize,&rRef,&xFact,&yFact);
633 EndUndo();
634 AdjustMarkHdl();
637 static void ImpRotate(Point& rPt, Point* pC1, Point* pC2, const void* p1, const void* /*p2*/, const void* p3, const void* p4)
639 RotatePoint(rPt,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
640 if (pC1!=nullptr) RotatePoint(*pC1,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
641 if (pC2!=nullptr) RotatePoint(*pC2,*static_cast<const Point*>(p1),*static_cast<const double*>(p3),*static_cast<const double*>(p4));
644 void SdrPolyEditView::RotateMarkedPoints(const Point& rRef, long nAngle)
646 ForceUndirtyMrkPnt();
647 OUString aStr(ImpGetResStr(STR_EditResize));
648 BegUndo(aStr,GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Rotate);
649 double nSin=sin(nAngle*nPi180);
650 double nCos=cos(nAngle*nPi180);
651 ImpTransformMarkedPoints(ImpRotate,&rRef,&nAngle,&nSin,&nCos);
652 EndUndo();
653 AdjustMarkHdl();
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */