/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
struct ImpSdrPathDragData : public SdrDragStatUserData
{
XPolygon aXP; // section of the original polygon bool bValid; // FALSE = too few points bool bClosed; // closed object?
sal_uInt16 nPoly; // number of the polygon in the PolyPolygon
sal_uInt16 nPnt; // number of point in the above polygon
sal_uInt16 nPointCount; // number of points of the polygon bool bBegPnt; // dragged point is first point of a Polyline bool bEndPnt; // dragged point is finishing point of a Polyline
sal_uInt16 nPrevPnt; // index of previous point
sal_uInt16 nNextPnt; // index of next point bool bPrevIsBegPnt; // previous point is first point of a Polyline bool bNextIsEndPnt; // next point is first point of a Polyline
sal_uInt16 nPrevPrevPnt; // index of point before previous point
sal_uInt16 nNextNextPnt; // index of point after next point bool bControl; // point is a control point bool bIsNextControl; // point is a control point after a support point bool bPrevIsControl; // if nPnt is a support point: a control point comes before bool bNextIsControl; // if nPnt is a support point: a control point comes after
sal_uInt16 nPrevPrevPnt0;
sal_uInt16 nPrevPnt0;
sal_uInt16 nPnt0;
sal_uInt16 nNextPnt0;
sal_uInt16 nNextNextPnt0; bool bEliminate; // delete point? (is set by MovDrag)
maMove = maOrig;
bValid = true;
} else
{
sal_uInt16 nPntMax = 0; // maximum index
bValid=false;
bClosed=rPO.IsClosed(); // closed object?
nPoly=static_cast<sal_uInt16>(rHdl.GetPolyNum()); // number of the polygon in the PolyPolygon
nPnt=static_cast<sal_uInt16>(rHdl.GetPointNum()); // number of points in the above polygon const XPolygon aTmpXP(rPO.GetPathPoly().getB2DPolygon(nPoly));
nPointCount=aTmpXP.GetPointCount(); // number of point of the polygon if (nPointCount==0 || (bClosed && nPointCount==1)) return; // minimum of 1 points for Lines, minimum of 2 points for Polygon
nPntMax=nPointCount-1; // maximum index
bBegPnt=!bClosed && nPnt==0; // dragged point is first point of a Polyline
bEndPnt=!bClosed && nPnt==nPntMax; // dragged point is finishing point of a Polyline if (bClosed && nPointCount<=3) { // if polygon is only a line
bBegPnt=(nPointCount<3) || nPnt==0;
bEndPnt=(nPointCount<3) || nPnt==nPntMax-1;
}
nPrevPnt=nPnt; // index of previous point
nNextPnt=nPnt; // index of next point if (!bBegPnt) nPrevPnt=GetPrevPnt(nPnt,nPntMax,bClosed); if (!bEndPnt) nNextPnt=GetNextPnt(nPnt,nPntMax,bClosed);
bPrevIsBegPnt=bBegPnt || (!bClosed && nPrevPnt==0);
bNextIsEndPnt=bEndPnt || (!bClosed && nNextPnt==nPntMax);
nPrevPrevPnt=nPnt; // index of point before previous point
nNextNextPnt=nPnt; // index of point after next point if (!bPrevIsBegPnt) nPrevPrevPnt=GetPrevPnt(nPrevPnt,nPntMax,bClosed); if (!bNextIsEndPnt) nNextNextPnt=GetNextPnt(nNextPnt,nPntMax,bClosed);
bControl=rHdl.IsPlusHdl(); // point is a control point
bIsNextControl=false; // point is a control point after a support point
bPrevIsControl=false; // if nPnt is a support point: a control point comes before
bNextIsControl=false; // if nPnt is a support point: a control point comes after if (bControl) {
bIsNextControl=!aTmpXP.IsControl(nPrevPnt);
} else {
bPrevIsControl=!bBegPnt && !bPrevIsBegPnt && aTmpXP.GetFlags(nPrevPnt)==PolyFlags::Control;
bNextIsControl=!bEndPnt && !bNextIsEndPnt && aTmpXP.GetFlags(nNextPnt)==PolyFlags::Control;
}
nPrevPrevPnt0=nPrevPrevPnt;
nPrevPnt0 =nPrevPnt;
nPnt0 =nPnt;
nNextPnt0 =nNextPnt;
nNextNextPnt0=nNextNextPnt;
nPrevPrevPnt=0;
nPrevPnt=1;
nPnt=2;
nNextPnt=3;
nNextNextPnt=4;
bEliminate=false;
ResetPoly(rPO);
bValid=true;
}
}
struct ImpPathCreateUser : public SdrDragStatUserData
{
Point aBezControl0;
Point aBezStart;
Point aBezCtrl1;
Point aBezCtrl2;
Point aBezEnd;
Point aCircStart;
Point aCircEnd;
Point aCircCenter;
Point aLineStart;
Point aLineEnd;
Point aRectP1;
Point aRectP2;
Point aRectP3;
tools::Long nCircRadius;
Degree100 nCircStAngle;
Degree100 nCircRelAngle; bool bBezier; bool bBezHasCtrl0; bool bCircle; bool bAngleSnap; bool bLine; bool bLine90; bool bRect; bool bMixedCreate;
sal_uInt16 nBezierStartPoint;
SdrObjKind eStartKind;
SdrObjKind eCurrentKind;
// move point itself
rMove[nPointIndex] = rOrig[nPointIndex] + aDelta;
// when point is first and poly closed, move close point, too. if(nPointCount > 0 && !nPointIndex && bClosed)
{
rMove[nPointCount - 1] = rOrig[nPointCount - 1] + aDelta;
// when moving the last point it may be necessary to move the // control point in front of this one, too. if(nPointCount > 1 && rOrig.IsControl(nPointCount - 2))
rMove[nPointCount - 2] = rOrig[nPointCount - 2] + aDelta;
}
// is a control point before this? if(nPointIndex > 0 && rOrig.IsControl(nPointIndex - 1))
{ // Yes, move it, too
rMove[nPointIndex - 1] = rOrig[nPointIndex - 1] + aDelta;
}
// is a control point after this? if(nPointIndex + 1 < nPointCount && rOrig.IsControl(nPointIndex + 1))
{ // Yes, move it, too
rMove[nPointIndex + 1] = rOrig[nPointIndex + 1] + aDelta;
}
}
}
} else
{
mpSdrPathDragData->ResetPoly(mrSdrPathObject);
// copy certain data locally to use less code and have faster access times bool bClosed =mpSdrPathDragData->bClosed ; // closed object?
sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // number of point in the above polygon bool bBegPnt =mpSdrPathDragData->bBegPnt ; // dragged point is first point of a Polyline bool bEndPnt =mpSdrPathDragData->bEndPnt ; // dragged point is last point of a Polyline
sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // index of previous point
sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // index of next point bool bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline bool bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // index of the point before the previous point
sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // index if the point after the next point bool bControl =mpSdrPathDragData->bControl ; // point is a control point bool bIsNextControl =mpSdrPathDragData->bIsNextControl; // point is a control point after a support point bool bPrevIsControl =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before bool bNextIsControl =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
// Ortho for lines/polygons: keep angle if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsOrtho()) { bool bBigOrtho=rDrag.GetView()->IsBigOrtho();
Point aPos(rDrag.GetNow()); // current position
Point aPnt(mpSdrPathDragData->aXP[nPnt]); // the dragged point
sal_uInt16 nPnt1=0xFFFF,nPnt2=0xFFFF; // its neighboring points
Point aNewPos1,aNewPos2; // new alternative for aPos bool bPnt1 = false, bPnt2 = false; // are these valid alternatives? if (!bClosed && mpSdrPathDragData->nPointCount>=2) { // minimum of 2 points for lines if (!bBegPnt) nPnt1=nPrevPnt; if (!bEndPnt) nPnt2=nNextPnt;
} if (bClosed && mpSdrPathDragData->nPointCount>=3) { // minimum of 3 points for polygon
nPnt1=nPrevPnt;
nPnt2=nNextPnt;
} if (nPnt1!=0xFFFF && !bPrevIsControl) {
Point aPnt1=mpSdrPathDragData->aXP[nPnt1];
tools::Long ndx0=aPnt.X()-aPnt1.X();
tools::Long ndy0=aPnt.Y()-aPnt1.Y(); bool bHLin=ndy0==0; bool bVLin=ndx0==0; if (!bHLin || !bVLin) {
tools::Long ndx=aPos.X()-aPnt1.X();
tools::Long ndy=aPos.Y()-aPnt1.Y();
bPnt1=true; double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0); double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0); bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho); bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho); if (bHor) ndy=tools::Long(ndy0*nXFact); if (bVer) ndx=tools::Long(ndx0*nYFact);
aNewPos1=aPnt1;
aNewPos1.AdjustX(ndx );
aNewPos1.AdjustY(ndy );
}
} if (nPnt2!=0xFFFF && !bNextIsControl) {
Point aPnt2=mpSdrPathDragData->aXP[nPnt2];
tools::Long ndx0=aPnt.X()-aPnt2.X();
tools::Long ndy0=aPnt.Y()-aPnt2.Y(); bool bHLin=ndy0==0; bool bVLin=ndx0==0; if (!bHLin || !bVLin) {
tools::Long ndx=aPos.X()-aPnt2.X();
tools::Long ndy=aPos.Y()-aPnt2.Y();
bPnt2=true; double nXFact=0; if (!bVLin) nXFact=static_cast<double>(ndx)/static_cast<double>(ndx0); double nYFact=0; if (!bHLin) nYFact=static_cast<double>(ndy)/static_cast<double>(ndy0); bool bHor=bHLin || (!bVLin && (nXFact>nYFact) ==bBigOrtho); bool bVer=bVLin || (!bHLin && (nXFact<=nYFact)==bBigOrtho); if (bHor) ndy=tools::Long(ndy0*nXFact); if (bVer) ndx=tools::Long(ndx0*nYFact);
aNewPos2=aPnt2;
aNewPos2.AdjustX(ndx );
aNewPos2.AdjustY(ndy );
}
} if (bPnt1 && bPnt2) { // both alternatives exist (and compete)
BigInt nX1(aNewPos1.X()-aPos.X()); nX1*=nX1;
BigInt nY1(aNewPos1.Y()-aPos.Y()); nY1*=nY1;
BigInt nX2(aNewPos2.X()-aPos.X()); nX2*=nX2;
BigInt nY2(aNewPos2.Y()-aPos.Y()); nY2*=nY2;
nX1+=nY1; // correction distance to square
nX2+=nY2; // correction distance to square // let the alternative that allows fewer correction win if (nX1<nX2) bPnt2=false; else bPnt1=false;
} if (bPnt1) rDrag.SetNow(aNewPos1); if (bPnt2) rDrag.SetNow(aNewPos2);
}
rDrag.SetActionRect(tools::Rectangle(rDrag.GetNow(),rDrag.GetNow()));
// specially for IBM: Eliminate points if both adjoining lines form near 180 degrees angle anyway if (!bControl && rDrag.GetView()!=nullptr && rDrag.GetView()->IsEliminatePolyPoints() &&
!bBegPnt && !bEndPnt && !bPrevIsControl && !bNextIsControl)
{
Point aPt(mpSdrPathDragData->aXP[nNextPnt]);
aPt-=rDrag.GetNow();
Degree100 nAngle1=GetAngle(aPt);
aPt=rDrag.GetNow();
aPt-=mpSdrPathDragData->aXP[nPrevPnt];
Degree100 nAngle2=GetAngle(aPt);
Degree100 nDiff=nAngle1-nAngle2;
nDiff=abs(nDiff);
mpSdrPathDragData->bEliminate=nDiff<=rDrag.GetView()->GetEliminatePolyPointLimitAngle(); if (mpSdrPathDragData->bEliminate) { // adapt position, Smooth is true for the ends
aPt=mpSdrPathDragData->aXP[nNextPnt];
aPt+=mpSdrPathDragData->aXP[nPrevPnt];
aPt/=2;
rDrag.SetNow(aPt);
}
}
// we dragged by this distance
Point aDiff(rDrag.GetNow()); aDiff-=mpSdrPathDragData->aXP[nPnt];
/* There are 8 possible cases: X 1. A control point neither on the left nor on the right. o--X--o 2. There are control points on the left and the right, we are dragging a support point. o--X 3. There is a control point on the left, we are dragging a support point. X--o 4. There is a control point on the right, we are dragging a support point. x--O--o 5. There are control points on the left and the right, we are dragging the left one. x--O 6. There is a control point on the left, we are dragging it. o--O--x 7. There are control points on the left and the right, we are dragging the right one. O--x 8. There is a control point on the right, we are dragging it. Note: modifying a line (not a curve!) might create a curve on the other end of the line if Smooth is set there (with control points aligned to line).
*/
mpSdrPathDragData->aXP[nPnt]+=aDiff;
// now check symmetric plus handles if (bControl) { // cases 5,6,7,8
sal_uInt16 nSt; // the associated support point
sal_uInt16 nFix; // the opposing control point if (bIsNextControl) { // if the next one is a control point, the on before has to be a support point
nSt=nPrevPnt;
nFix=nPrevPrevPnt;
} else {
nSt=nNextPnt;
nFix=nNextNextPnt;
} if (mpSdrPathDragData->aXP.IsSmooth(nSt)) {
mpSdrPathDragData->aXP.CalcSmoothJoin(nSt,nPnt,nFix);
}
}
if (!bControl) { // Cases 1,2,3,4. In case 1, nothing happens; in cases 3 and 4, there is more following below. // move both control points if (bPrevIsControl) mpSdrPathDragData->aXP[nPrevPnt]+=aDiff; if (bNextIsControl) mpSdrPathDragData->aXP[nNextPnt]+=aDiff; // align control point to line, if appropriate if (mpSdrPathDragData->aXP.IsSmooth(nPnt)) { if (bPrevIsControl && !bNextIsControl && !bEndPnt) { // case 3
mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nNextPnt,nPrevPnt);
} if (bNextIsControl && !bPrevIsControl && !bBegPnt) { // case 4
mpSdrPathDragData->aXP.CalcSmoothJoin(nPnt,nPrevPnt,nNextPnt);
}
} // Now check the other ends of the line (nPnt+-1). If there is a // curve (IsControl(nPnt+-2)) with SmoothJoin (nPnt+-1), the // associated control point (nPnt+-2) has to be adapted. if (!bBegPnt && !bPrevIsControl && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsSmooth(nPrevPnt)) { if (mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
mpSdrPathDragData->aXP.CalcSmoothJoin(nPrevPnt,nPnt,nPrevPrevPnt);
}
} if (!bEndPnt && !bNextIsControl && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsSmooth(nNextPnt)) { if (mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
mpSdrPathDragData->aXP.CalcSmoothJoin(nNextPnt,nPnt,nNextNextPnt);
}
}
}
}
returntrue;
}
bool ImpPathForDragAndCreate::endPathDrag(SdrDragStat const & rDrag)
{
Point aLinePt1;
Point aLinePt2; bool bLineGlueMirror(SdrObjKind::Line == meObjectKind); if (bLineGlueMirror) {
XPolygon& rXP=aPathPolygon[0];
aLinePt1=rXP[0];
aLinePt2=rXP[1];
}
if(!mpSdrPathDragData || !mpSdrPathDragData->bValid)
{
OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid."); returnfalse;
}
// reference the polygon
XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(pHdl->GetPolyNum())];
// the 5 points that might have changed if (!mpSdrPathDragData->bPrevIsBegPnt) rXP[mpSdrPathDragData->nPrevPrevPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPrevPnt]; if (!mpSdrPathDragData->bNextIsEndPnt) rXP[mpSdrPathDragData->nNextNextPnt0]=mpSdrPathDragData->aXP[mpSdrPathDragData->nNextNextPnt]; if (!mpSdrPathDragData->bBegPnt) rXP[mpSdrPathDragData->nPrevPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPrevPnt]; if (!mpSdrPathDragData->bEndPnt) rXP[mpSdrPathDragData->nNextPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nNextPnt];
rXP[mpSdrPathDragData->nPnt0] =mpSdrPathDragData->aXP[mpSdrPathDragData->nPnt];
// for closed objects: last point has to be equal to first point if (mpSdrPathDragData->bClosed) rXP[rXP.GetPointCount()-1]=rXP[0];
if (mpSdrPathDragData->bEliminate)
{
basegfx::B2DPolyPolygon aTempPolyPolygon(aPathPolygon.getB2DPolyPolygon());
sal_uInt32 nPoly,nPnt;
// adapt angle for text beneath a simple line if (bLineGlueMirror)
{
Point aLinePt1_(aPathPolygon[0][0]);
Point aLinePt2_(aPathPolygon[0][1]); bool bXMirr=(aLinePt1_.X()>aLinePt2_.X())!=(aLinePt1.X()>aLinePt2.X()); bool bYMirr=(aLinePt1_.Y()>aLinePt2_.Y())!=(aLinePt1.Y()>aLinePt2.Y()); if (bXMirr || bYMirr) {
Point aRef1(mrSdrPathObject.GetSnapRect().Center()); if (bXMirr) {
Point aRef2(aRef1);
aRef2.AdjustY( 1 );
mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
} if (bYMirr) {
Point aRef2(aRef1);
aRef2.AdjustX( 1 );
mrSdrPathObject.NbcMirrorGluePoints(aRef1,aRef2);
}
}
}
}
aStr += ")";
} elseif(!pHdl)
{ // #i103058# fallback when no model and/or Handle, both needed // for else-path
aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_DragPathObj);
} else
{ // #i103058# standard for modification; model and handle needed
ImpSdrPathDragData* pDragData = mpSdrPathDragData.get();
if(!pDragData)
{ // getSpecialDragComment is also used from create, so fallback to GetUser() // when mpSdrPathDragData is not set
pDragData = static_cast<ImpSdrPathDragData*>(rDrag.GetUser());
}
if(!pDragData)
{
OSL_FAIL("ImpPathForDragAndCreate::MovDrag(): ImpSdrPathDragData is invalid."); return OUString();
}
if(!pDragData->IsMultiPointDrag() && pDragData->bEliminate)
{ // point of ...
aStr = mrSdrPathObject.ImpGetDescriptionStr(STR_ViewMarkedPoint);
// UNICODE: delete point of ...
aStr2 = aStr2.replaceFirst("%1", aStr);
return aStr2;
}
// dx=0.00 dy=0.00 -- both sides bezier // dx=0.00 dy=0.00 l=0.00 0.00\302\260 -- one bezier/lever on one side, a start, or an ending // dx=0.00 dy=0.00 l=0.00 0.00\302\260 / l=0.00 0.00\302\260 -- in between
Point aBeg(rDrag.GetStart());
Point aNow(rDrag.GetNow());
if(mpSdrPathDragData->IsMultiPointDrag())
{
aRetval.Insert(mpSdrPathDragData->maMove);
} else
{ const XPolygon& rXP=aPathPolygon[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPolyNum())]; if (rXP.GetPointCount()<=2) {
XPolygon aXPoly(rXP);
aXPoly[static_cast<sal_uInt16>(rDrag.GetHdl()->GetPointNum())]=rDrag.GetNow();
aRetval.Insert(std::move(aXPoly)); return aRetval.getB2DPolyPolygon();
} // copy certain data locally to use less code and have faster access times bool bClosed =mpSdrPathDragData->bClosed ; // closed object?
sal_uInt16 nPointCount = mpSdrPathDragData->nPointCount; // number of points
sal_uInt16 nPnt =mpSdrPathDragData->nPnt ; // number of points in the polygon bool bBegPnt =mpSdrPathDragData->bBegPnt ; // dragged point is the first point of a Polyline bool bEndPnt =mpSdrPathDragData->bEndPnt ; // dragged point is the last point of a Polyline
sal_uInt16 nPrevPnt =mpSdrPathDragData->nPrevPnt ; // index of the previous point
sal_uInt16 nNextPnt =mpSdrPathDragData->nNextPnt ; // index of the next point bool bPrevIsBegPnt =mpSdrPathDragData->bPrevIsBegPnt ; // previous point is first point of a Polyline bool bNextIsEndPnt =mpSdrPathDragData->bNextIsEndPnt ; // next point is last point of a Polyline
sal_uInt16 nPrevPrevPnt =mpSdrPathDragData->nPrevPrevPnt ; // index of the point before the previous point
sal_uInt16 nNextNextPnt =mpSdrPathDragData->nNextNextPnt ; // index of the point after the last point bool bControl =mpSdrPathDragData->bControl ; // point is a control point bool bIsNextControl =mpSdrPathDragData->bIsNextControl; //point is a control point after a support point bool bPrevIsControl =mpSdrPathDragData->bPrevIsControl; // if nPnt is a support point: there's a control point before bool bNextIsControl =mpSdrPathDragData->bNextIsControl; // if nPnt is a support point: there's a control point after
XPolygon aXPoly(mpSdrPathDragData->aXP);
XPolygon aLine1(2);
XPolygon aLine2(2);
XPolygon aLine3(2);
XPolygon aLine4(2); if (bControl) {
aLine1[1]=mpSdrPathDragData->aXP[nPnt]; if (bIsNextControl) { // is this a control point after the support point?
aLine1[0]=mpSdrPathDragData->aXP[nPrevPnt];
aLine2[0]=mpSdrPathDragData->aXP[nNextNextPnt];
aLine2[1]=mpSdrPathDragData->aXP[nNextPnt]; if (mpSdrPathDragData->aXP.IsSmooth(nPrevPnt) && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal); // leverage lines for the opposing curve segment
aLine3[0]=mpSdrPathDragData->aXP[nPrevPnt];
aLine3[1]=mpSdrPathDragData->aXP[nPrevPrevPnt];
aLine4[0]=rXP[mpSdrPathDragData->nPrevPrevPnt0-2];
aLine4[1]=rXP[mpSdrPathDragData->nPrevPrevPnt0-1];
} else {
aXPoly.Remove(0,1);
}
} else { // else this is a control point before a support point
aLine1[0]=mpSdrPathDragData->aXP[nNextPnt];
aLine2[0]=mpSdrPathDragData->aXP[nPrevPrevPnt];
aLine2[1]=mpSdrPathDragData->aXP[nPrevPnt]; if (mpSdrPathDragData->aXP.IsSmooth(nNextPnt) && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal); // leverage lines for the opposing curve segment
aLine3[0]=mpSdrPathDragData->aXP[nNextPnt];
aLine3[1]=mpSdrPathDragData->aXP[nNextNextPnt];
aLine4[0]=rXP[mpSdrPathDragData->nNextNextPnt0+2];
aLine4[1]=rXP[mpSdrPathDragData->nNextNextPnt0+1];
} else {
aXPoly.Remove(aXPoly.GetPointCount()-1,1);
}
}
} else { // else is not a control point if (mpSdrPathDragData->bEliminate) {
aXPoly.Remove(2,1);
} if (bPrevIsControl) aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Normal); elseif (!bBegPnt && !bPrevIsBegPnt && mpSdrPathDragData->aXP.IsControl(nPrevPrevPnt)) {
aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-1],PolyFlags::Control);
aXPoly.Insert(0,rXP[mpSdrPathDragData->nPrevPrevPnt0-2],PolyFlags::Normal);
} else {
aXPoly.Remove(0,1); if (bBegPnt) aXPoly.Remove(0,1);
} if (bNextIsControl) aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Normal); elseif (!bEndPnt && !bNextIsEndPnt && mpSdrPathDragData->aXP.IsControl(nNextNextPnt)) {
aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+1],PolyFlags::Control);
aXPoly.Insert(XPOLY_APPEND,rXP[mpSdrPathDragData->nNextNextPnt0+2],PolyFlags::Normal);
} else {
aXPoly.Remove(aXPoly.GetPointCount()-1,1); if (bEndPnt) aXPoly.Remove(aXPoly.GetPointCount()-1,1);
} if (bClosed) { // "pear problem": 2 lines, 1 curve, everything smoothed, a point between both lines is dragged if (aXPoly.GetPointCount()>nPointCount && aXPoly.IsControl(1)) {
sal_uInt16 a=aXPoly.GetPointCount();
aXPoly[a-2]=aXPoly[2]; aXPoly.SetFlags(a-2,aXPoly.GetFlags(2));
aXPoly[a-1]=aXPoly[3]; aXPoly.SetFlags(a-1,aXPoly.GetFlags(3));
aXPoly.Remove(0,3);
}
}
}
aRetval.Insert(std::move(aXPoly)); if (aLine1.GetPointCount()>1) aRetval.Insert(std::move(aLine1)); if (aLine2.GetPointCount()>1) aRetval.Insert(std::move(aLine2)); if (aLine3.GetPointCount()>1) aRetval.Insert(std::move(aLine3)); if (aLine4.GetPointCount()>1) aRetval.Insert(std::move(aLine4));
}
bool ImpPathForDragAndCreate::MovCreate(SdrDragStat& rStat)
{
ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser());
SdrView* pView=rStat.GetView();
XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1]; if (pView!=nullptr && pView->IsCreateMode()) { // switch to different CreateTool, if appropriate
SdrObjKind nIdent;
SdrInventor nInvent;
pView->TakeCurrentObj(nIdent,nInvent); if (nInvent==SdrInventor::Default && pU->eCurrentKind != nIdent) {
SdrObjKind eNewKind = nIdent; switch (eNewKind) { case SdrObjKind::CircleArc: case SdrObjKind::CircleOrEllipse: case SdrObjKind::CircleCut: case SdrObjKind::CircleSection:
eNewKind=SdrObjKind::CircleArc;
[[fallthrough]]; case SdrObjKind::Rectangle: case SdrObjKind::Line: case SdrObjKind::PolyLine: case SdrObjKind::Polygon: case SdrObjKind::PathLine: case SdrObjKind::PathFill: case SdrObjKind::FreehandLine: case SdrObjKind::FreehandFill:
{
pU->eCurrentKind=eNewKind;
pU->bMixedCreate=true;
pU->nBezierStartPoint=rXPoly.GetPointCount(); if (pU->nBezierStartPoint>0) pU->nBezierStartPoint--;
} break; default: break;
} // switch
}
}
sal_uInt16 nCurrentPoint=rXPoly.GetPointCount(); if (aPathPolygon.Count()>1 && rStat.IsMouseDown() && nCurrentPoint<2) {
rXPoly[0]=rStat.GetPos0();
rXPoly[1]=rStat.GetNow();
nCurrentPoint=2;
} if (nCurrentPoint==0) {
rXPoly[0]=rStat.GetPos0();
} else nCurrentPoint--; bool bFreeHand=IsFreeHand(pU->eCurrentKind);
rStat.SetNoSnap(bFreeHand);
rStat.SetOrtho8Possible(pU->eCurrentKind!=SdrObjKind::CircleArc && pU->eCurrentKind!=SdrObjKind::Rectangle && (!pU->bMixedCreate || pU->eCurrentKind!=SdrObjKind::Line));
rXPoly[nCurrentPoint]=rStat.GetNow(); if (!pU->bMixedCreate && pU->eStartKind==SdrObjKind::Line && rXPoly.GetPointCount()>=1) {
Point aPt(rStat.GetStart()); if (pView!=nullptr && pView->IsCreate1stPointAsCenter()) {
aPt+=aPt;
aPt-=rStat.GetNow();
}
rXPoly[0]=aPt;
}
OutputDevice* pOut=pView==nullptr ? nullptr : pView->GetFirstOutputDevice(); if (bFreeHand) { if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint; if (rStat.IsMouseDown() && nCurrentPoint>0) { // don't allow two consecutive points to occupy too similar positions
tools::Long nMinDist=1; if (pView!=nullptr) nMinDist=pView->GetFreeHandMinDistPix(); if (pOut!=nullptr) nMinDist=pOut->PixelToLogic(Size(nMinDist,0)).Width(); if (nMinDist<1) nMinDist=1;
Point aPt0(rXPoly[nCurrentPoint-1]);
Point aPt1(rStat.GetNow());
tools::Long dx=aPt0.X()-aPt1.X(); if (dx<0) dx=-dx;
tools::Long dy=aPt0.Y()-aPt1.Y(); if (dy<0) dy=-dy; if (dx<nMinDist && dy<nMinDist) returnfalse;
// TODO: the following is copied from EndCreate (with a few smaller modifications) // and should be combined into a method with the code there.
if (nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
rXPoly.PointsToBezier(nCurrentPoint-3);
rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);
if (!pU->bMixedCreate && IsFreeHand(pU->eStartKind)) { if (rStat.GetPointCount()>=2) eCmd=SdrCreateCmd::ForceEnd;
bRet=eCmd==SdrCreateCmd::ForceEnd; if (bRet) {
mbCreating=false;
rStat.SetUser(nullptr);
} return bRet;
} if (eCmd==SdrCreateCmd::NextPoint || eCmd==SdrCreateCmd::NextObject) { // don't allow two consecutive points to occupy the same position if (nCurrentPoint==0 || rStat.GetNow()!=rXPoly[nCurrentPoint-1]) { if (bIncomp) { if (pU->nBezierStartPoint>nCurrentPoint) pU->nBezierStartPoint=nCurrentPoint; if (IsBezier(pU->eCurrentKind) && nCurrentPoint-pU->nBezierStartPoint>=3 && ((nCurrentPoint-pU->nBezierStartPoint)%3)==0) {
rXPoly.PointsToBezier(nCurrentPoint-3);
rXPoly.SetFlags(nCurrentPoint-1,PolyFlags::Control);
rXPoly.SetFlags(nCurrentPoint-2,PolyFlags::Control);
if (nCurrentPoint>=6 && rXPoly.IsControl(nCurrentPoint-4)) {
rXPoly.CalcTangent(nCurrentPoint-3,nCurrentPoint-4,nCurrentPoint-2);
rXPoly.SetFlags(nCurrentPoint-3,PolyFlags::Smooth);
}
}
} else { if (nCurrentPoint==1 && IsBezier(pU->eCurrentKind) && !pU->bBezHasCtrl0) {
pU->aBezControl0=rStat.GetNow();
pU->bBezHasCtrl0=true;
nCurrentPoint--;
} if (pU->IsFormFlag()) {
sal_uInt16 nPointCount0=rXPoly.GetPointCount();
rXPoly.Remove(nCurrentPoint-1,2); // remove last two points and replace by form
rXPoly.Insert(XPOLY_APPEND,pU->GetFormPoly());
sal_uInt16 nPointCount1=rXPoly.GetPointCount(); for (sal_uInt16 i=nPointCount0+1; i<nPointCount1-1; i++) { // to make BckAction work if (!rXPoly.IsControl(i)) rStat.NextPoint();
}
nCurrentPoint=rXPoly.GetPointCount()-1;
}
}
nCurrentPoint++;
rXPoly[nCurrentPoint]=rStat.GetNow();
} if (eCmd==SdrCreateCmd::NextObject) { if (rXPoly.GetPointCount()>=2) {
pU->bBezHasCtrl0=false; // only a singular polygon may be opened, so close this
rXPoly[nCurrentPoint]=rXPoly[0];
XPolygon aXP;
aXP[0]=rStat.GetNow();
aPathPolygon.Insert(std::move(aXP));
}
}
}
sal_uInt16 nPolyCount=aPathPolygon.Count(); if (nPolyCount!=0) { // delete last point, if necessary if (eCmd==SdrCreateCmd::ForceEnd) {
XPolygon& rXP=aPathPolygon[nPolyCount-1];
sal_uInt16 nPointCount=rXP.GetPointCount(); if (nPointCount>=2) { if (!rXP.IsControl(nPointCount-2)) { if (rXP[nPointCount-1]==rXP[nPointCount-2]) {
rXP.Remove(nPointCount-1,1);
}
} else { if (rXP[nPointCount-3]==rXP[nPointCount-2]) {
rXP.Remove(nPointCount-3,3);
}
}
}
} for (sal_uInt16 nPolyNum=nPolyCount; nPolyNum>0;) {
nPolyNum--;
XPolygon& rXP=aPathPolygon[nPolyNum];
sal_uInt16 nPointCount=rXP.GetPointCount(); // delete polygons with too few points if (nPolyNum<nPolyCount-1 || eCmd==SdrCreateCmd::ForceEnd) { if (nPointCount<2) aPathPolygon.Remove(nPolyNum);
}
}
}
pU->ResetFormFlags();
bRet=eCmd==SdrCreateCmd::ForceEnd; if (bRet) {
mbCreating=false;
rStat.SetUser(nullptr);
} return bRet;
}
bool ImpPathForDragAndCreate::BckCreate(SdrDragStat const & rStat)
{
ImpPathCreateUser* pU=static_cast<ImpPathCreateUser*>(rStat.GetUser()); if (aPathPolygon.Count()>0) {
XPolygon& rXPoly=aPathPolygon[aPathPolygon.Count()-1];
sal_uInt16 nCurrentPoint=rXPoly.GetPointCount(); if (nCurrentPoint>0) {
nCurrentPoint--; // make the last part of a bezier curve a line
rXPoly.Remove(nCurrentPoint,1); if (nCurrentPoint>=3 && rXPoly.IsControl(nCurrentPoint-1)) { // there should never be a bezier segment at the end, so this is just in case...
rXPoly.Remove(nCurrentPoint-1,1); if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
}
}
nCurrentPoint=rXPoly.GetPointCount(); if (nCurrentPoint>=4) { // no bezier segment at the end
nCurrentPoint--; if (rXPoly.IsControl(nCurrentPoint-1)) {
rXPoly.Remove(nCurrentPoint-1,1); if (rXPoly.IsControl(nCurrentPoint-2)) rXPoly.Remove(nCurrentPoint-2,1);
}
} if (rXPoly.GetPointCount()<2) {
aPathPolygon.Remove(aPathPolygon.Count()-1);
} if (aPathPolygon.Count()>0) {
XPolygon& rLocalXPoly=aPathPolygon[aPathPolygon.Count()-1];
sal_uInt16 nLocalCurrentPoint=rLocalXPoly.GetPointCount(); if (nLocalCurrentPoint>0) {
nLocalCurrentPoint--;
rLocalXPoly[nLocalCurrentPoint]=rStat.GetNow();
}
}
}
pU->ResetFormFlags(); return aPathPolygon.Count()!=0;
}
if(pU->IsFormFlag() && aNewPolygon.count() > 1)
{ // remove last segment and replace with current // do not forget to rescue the previous control point which will be lost when
--> --------------------
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.