1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
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);
67 bool bSmoothFuz(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
);
87 SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
91 const bool bClosed(pPath
->IsClosed());
92 bSetMarkedPointsSmoothPossible
= true;
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;
119 eSmooth
= basegfx::utils::getContinuityInPoint(aLocalPolygon
, nPntNum
);
123 bSmoothFuz
= (eSmooth
!= basegfx::utils::getContinuityInPoint(aLocalPolygon
, nPntNum
));
131 bool bCrv(aLocalPolygon
.isNextControlPointUsed(nPntNum
));
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
;
192 if(HasMarkedPoints())
196 const bool bUndo
= IsUndoEnabled();
198 BegUndo(ImpGetResStr(STR_EditSetPointsSmooth
), GetDescriptionOfMarkedPoints());
199 const size_t nMarkCount(GetMarkedObjectCount());
201 for(size_t nMarkNum(nMarkCount
); nMarkNum
> 0;)
204 SdrMark
* pM
= GetSdrMarkByIndex(nMarkNum
);
205 SdrPathObj
* pPath
= dynamic_cast< SdrPathObj
* >( pM
->GetMarkedSdrObj() );
209 SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
210 PolyPolygonEditor
aEditor(pPath
->GetPathPoly());
211 if (aEditor
.SetPointsSmooth(eFlags
, rPts
))
214 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath
));
215 pPath
->SetPathPoly(aEditor
.GetPolyPolygon());
224 void SdrPolyEditView::SetMarkedSegmentsKind(SdrPathSegmentKind eKind
)
226 if(HasMarkedPoints())
230 const bool bUndo
= IsUndoEnabled();
232 BegUndo(ImpGetResStr(STR_EditSetSegmentsKind
), GetDescriptionOfMarkedPoints());
233 const size_t nMarkCount(GetMarkedObjectCount());
235 for(size_t nMarkNum
=nMarkCount
; nMarkNum
> 0;)
238 SdrMark
* pM
= GetSdrMarkByIndex(nMarkNum
);
239 SdrPathObj
* pPath
= dynamic_cast< SdrPathObj
* >( pM
->GetMarkedSdrObj() );
242 SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
243 PolyPolygonEditor
aEditor( pPath
->GetPathPoly());
244 if (aEditor
.SetSegmentsKind(eKind
, rPts
))
247 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath
));
248 pPath
->SetPathPoly(aEditor
.GetPolyPolygon());
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())
292 const size_t nMarkCount
=GetMarkedObjectCount();
294 const bool bUndo
= IsUndoEnabled();
298 BegUndo(ImpGetResStr(STR_EditDelete
),GetDescriptionOfMarkedPoints(),SdrRepeatFunc::Delete
);
301 for (size_t nMarkNum
=nMarkCount
; nMarkNum
>0;)
304 SdrMark
* pM
=GetSdrMarkByIndex(nMarkNum
);
305 SdrPathObj
* pPath
= dynamic_cast< SdrPathObj
* >( pM
->GetMarkedSdrObj() );
309 SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
310 PolyPolygonEditor
aEditor( pPath
->GetPathPoly());
311 if (aEditor
.DeletePoints(rPts
))
313 if( aEditor
.GetPolyPolygon().count() )
316 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pPath
));
317 pPath
->SetPathPoly( aEditor
.GetPolyPolygon() );
322 AddUndo( GetModel()->GetSdrUndoFactory().CreateUndoDeleteObject(*pPath
) );
323 pM
->GetPageView()->GetObjList()->RemoveObject(pPath
->GetOrdNum());
326 SdrObject
* pObj
= pPath
;
327 SdrObject::Free(pObj
);
336 MarkListHasChanged();
340 void SdrPolyEditView::RipUpAtMarkedPoints()
342 if(HasMarkedPoints())
345 const size_t nMarkCount(GetMarkedObjectCount());
347 const bool bUndo
= IsUndoEnabled();
349 BegUndo(ImpGetResStr(STR_EditRipUp
), GetDescriptionOfMarkedPoints());
351 for(size_t nMarkNum
= nMarkCount
; nMarkNum
> 0;)
354 SdrMark
* pM
= GetSdrMarkByIndex(nMarkNum
);
355 SdrPathObj
* pObj
= dynamic_cast<SdrPathObj
*>( pM
->GetMarkedSdrObj() );
359 SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
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
);
373 pM
->GetPageView()->GetObjList()->InsertObject(pNewObj
, pObj
->GetOrdNum() + 1);
375 AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewObj
));
376 MarkObj(pNewObj
, pM
->GetPageView(), false, true);
381 // correction necessary?
382 DBG_ASSERT(!bKorregFlag
,"Multiple index corrections at SdrPolyEditView::RipUp().");
387 SdrUShortCont aReplaceSet
;
388 for(SdrUShortCont::const_iterator it2
= rPts
.begin(); it2
!= rPts
.end(); ++it2
)
390 sal_uInt32
nPntNum(*it2
);
391 nPntNum
+= nNewPt0Idx
;
398 aReplaceSet
.insert( (sal_uInt16
)nPntNum
);
400 rPts
.swap(aReplaceSet
);
411 MarkListHasChanged();
415 bool SdrPolyEditView::IsRipUpAtMarkedPointsPossible() const
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
)
428 const SdrUShortCont
& rSelectedPoints
= pMark
->GetMarkedPoints();
429 if (rSelectedPoints
.empty())
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());
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);
459 bool SdrPolyEditView::IsOpenCloseMarkedObjectsPossible() const
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);
489 SdrObjClosedKind
SdrPolyEditView::GetMarkedObjectsClosedState() const
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())
515 return SdrObjClosedKind::DontCare
;
519 return SdrObjClosedKind::Open
;
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
);
540 const SdrUShortCont
& rPts
= pM
->GetMarkedPoints();
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
;
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()));
574 if(aNewXP
.isNextControlPointUsed(nPointNum
))
576 const basegfx::B2DPoint
aB2DC2(aNewXP
.getNextControlPoint(nPointNum
));
577 aC2
= Point(FRound(aB2DC2
.getX()), FRound(aB2DC2
.getY()));
581 (*pTrFunc
)(aPos
,&aC1
,&aC2
,p1
,p2
,p3
,p4
);
582 aNewXP
.setB2DPoint(nPointNum
, basegfx::B2DPoint(aPos
.X(), aPos
.Y()));
586 aNewXP
.setPrevControlPoint(nPointNum
, basegfx::B2DPoint(aC1
.X(), aC1
.Y()));
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
);
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
);
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
);
656 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */