Subversion Repositories Scribus

Rev

Rev 19081 | Rev 19454 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 For general Scribus (>=1.3.2) copyright and licensing information please refer
 to the COPYING file provided with the program. Following this notice may exist
 a copyright and/or license notice that predates the release of Scribus 1.3.2
 for which a new license (GPL+exception) is in place.
 */

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
***************************************************************************/


#include "canvasmode_nodeedit.h"

#include <QMenu>
#include <QMouseEvent>

#include "canvas.h"
#include "canvasgesture_rectselect.h"
#include "fpoint.h"
#include "pageitem.h"
#include "pageselector.h"
#include "scraction.h"
#include "scrapbookpalette.h"
#include "scribus.h"
#include "scribusdoc.h"
#include "scribusview.h"
#include "scribusXml.h"
#include "selection.h"
#include "undomanager.h"
#include "util_icon.h"
#include "util_math.h"


CanvasMode_NodeEdit::CanvasMode_NodeEdit(ScribusView* view) : CanvasMode(view), m_rectangleSelect(NULL)
{
        Mxp = -1;  // last mouse position
        Myp = -1;
        Dxp = -1;  // last mouse press position for rectangle select
        Dyp = -1;
        GxM = -1;  // guide position
        GyM = -1;
        MoveGX = MoveGY = false;
        m_ScMW = m_view->m_ScMW;
}

void CanvasMode_NodeEdit::drawControls(QPainter* p)
{
        double x, y;
        if (m_doc->m_Selection->count() == 0)
                return;
        PageItem* currItem = m_doc->m_Selection->itemAt(0);
        FPointArray cli;
       
        p->save();
        p->scale(m_canvas->scale(), m_canvas->scale());
        p->translate(-m_doc->minCanvasCoordinate.x(), -m_doc->minCanvasCoordinate.y());
        p->translate(currItem->xPos(), currItem->yPos());
        p->rotate(currItem->rotation());                       
        p->setPen(QPen(Qt::blue, 1 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
        p->setBrush(Qt::NoBrush);

        if ((m_doc->nodeEdit.isContourLine) && (currItem->ContourLine.size() != 0))
                cli = currItem->ContourLine;
        else
                cli = currItem->PoLine;
        // draw curve
        const double scale = m_canvas->m_viewMode.scale;
        const double onePerScale = 1 / scale;
        if (cli.size() > 3)
        {
                for (uint poi=0; poi<cli.size()-3; poi += 4)
                {
                        if (cli.point(poi).x() > 900000)
                                continue;
                        p->setPen(QPen(Qt::blue, onePerScale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
                        FPoint a1 = cli.point(poi);
                        FPoint a2 = cli.point(poi+1);
                        FPoint a3 = cli.point(poi+3);
                        FPoint a4 =     cli.point(poi+2);
                        QPainterPath Bez;
                        Bez.moveTo(a1.x(), a1.y());
                        Bez.cubicTo(a2.x(), a2.y(), a3.x(), a3.y(), a4.x(), a4.y());
                        p->drawPath(Bez);
                        p->setPen(QPen(Qt::blue, onePerScale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin));
                        p->drawLine(QPointF(a1.x(), a1.y()), QPointF(a2.x(), a2.y()));
                        p->drawLine(QPointF(a3.x(), a3.y()), QPointF(a4.x(), a4.y()));
                }
        }
        // draw points
        for (uint a=0; a<cli.size()-1; a += 2)
        {
                if (cli.point(a).x() > 900000)
                        continue;
                if (m_doc->nodeEdit.EdPoints)
                {
                        if (m_doc->nodeEdit.ClRe == static_cast<int>(a+1))
                                p->setPen(QPen(Qt::red, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        else
                                p->setPen(QPen(Qt::magenta, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        cli.point(a+1, &x, &y);
                        p->drawPoint(QPointF(x, y));
                        if (m_doc->nodeEdit.ClRe == static_cast<int>(a))
                                p->setPen(QPen(Qt::red, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        else
                                p->setPen(QPen(Qt::blue, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        cli.point(a, &x, &y);
                        p->drawPoint(QPointF(x, y));
                }
                else
                {
                        if (m_doc->nodeEdit.ClRe == static_cast<int>(a))
                                p->setPen(QPen(Qt::red, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        else
                                p->setPen(QPen(Qt::blue, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        cli.point(a, &x, &y);
                        p->drawPoint(QPointF(x, y));
                        if (m_doc->nodeEdit.ClRe == static_cast<int>(a+1))
                                p->setPen(QPen(Qt::red, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        else
                                p->setPen(QPen(Qt::magenta, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                        cli.point(a+1, &x, &y);
                        p->drawPoint(QPointF(x, y));
                }
        }
       
        if (m_doc->nodeEdit.ClRe != -1)
        {
                p->setPen(QPen(Qt::red, 8 / scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
                cli.point(m_doc->nodeEdit.ClRe, &x, &y);
                p->drawPoint(QPointF(x, y));
                QList<int>::Iterator itm;
                for (itm = m_doc->nodeEdit.SelNode.begin(); itm != m_doc->nodeEdit.SelNode.end(); ++itm)
                {
                        cli.point((*itm), &x, &y);
                        p->drawPoint(QPointF(x, y));
                }
        }
       
        bool havePoint = (m_doc->nodeEdit.ClRe != -1);
        emit m_view->HavePoint(havePoint, m_doc->nodeEdit.MoveSym);

        if (m_doc->nodeEdit.ClRe != -1) // May change when calling HavePoint()
        {
                cli.point(m_doc->nodeEdit.ClRe, &x, &y);
                emit m_view->ClipPo(x, y);
        }

        p->restore();
}


void CanvasMode_NodeEdit::activate(bool fromGesture)
{
        if (fromGesture && m_rectangleSelect)
        {
                m_canvas->m_viewMode.m_MouseButtonPressed = false;
                // handle rectangle select
                PageItem* currItem = m_doc->m_Selection->itemAt(0);
                m_doc->nodeEdit.SelNode.clear();
                QRectF Sele = m_rectangleSelect->result(); //QRect(Dxp, Dyp, SeRx-Dxp, SeRy-Dyp).normalized();
                FPointArray Clip;
                bool firstPoint = false;
//      m_canvas->setScale(1.0);
                if (m_doc->nodeEdit.isContourLine)
                        Clip = currItem->ContourLine;
                else
                        Clip = currItem->PoLine;
                for (uint a = 0; a < Clip.size(); ++a)
                {
                        if (Clip.point(a).x() > 900000)
                                continue;
                        FPoint np = Clip.point(a);
                        FPoint npf2 = np.transformPoint(currItem->xPos(), currItem->yPos(), currItem->rotation(), 1.0, 1.0, false);
                        if ((Sele.contains(npf2.x(), npf2.y())) && ((a == 0) || (((a-2) % 4) == 0)))
                        {
                                if (a == 0)
                                        firstPoint = true;
                                if ((firstPoint) && (a == Clip.size() - 2) && (!currItem->asPolyLine()))
                                        continue;
                                m_doc->nodeEdit.ClRe = a;
                                m_doc->nodeEdit.SelNode.append(a);
                                m_doc->nodeEdit.update(Clip.pointQF(a));
                        }
                }
                currItem->update();
                m_doc->nodeEdit.finishTransaction(currItem);
                delete m_rectangleSelect;
                m_rectangleSelect = NULL;
        }
        else
        {
                Mxp = -1;  // last mouse position
                Myp = -1;
                Dxp = -1;  // last mouse press position for rectangle select
                Dyp = -1;
                GxM = -1;  // guide position
                GyM = -1;
                MoveGX = MoveGY = false;
        }              
}


void CanvasMode_NodeEdit::deactivate(bool forGesture)
{
        if (!forGesture && m_rectangleSelect)
        {
                m_rectangleSelect->clear();
                delete m_rectangleSelect;
                m_rectangleSelect = NULL;
        }
}


inline bool CanvasMode_NodeEdit::GetItem(PageItem** pi)
{
        *pi = m_doc->m_Selection->itemAt(0);
        return (*pi) != NULL;
}



void CanvasMode_NodeEdit::enterEvent(QEvent *)
{

}


void CanvasMode_NodeEdit::leaveEvent(QEvent *e)
{

}



void CanvasMode_NodeEdit::mouseDoubleClickEvent(QMouseEvent *m)
{
        m->accept();
        m_canvas->m_viewMode.m_MouseButtonPressed = false;
        m_canvas->resetRenderMode();
        m_view->requestMode(submodeEndNodeEdit);
}


void CanvasMode_NodeEdit::mouseMoveEvent(QMouseEvent *m)
{
        PageItem *currItem;
        QPoint np, np2, mop;
        FPoint npf, npf2;
        double sc = m_canvas->scale();
        m->accept();
        npf = m_canvas->globalToCanvas(m->globalPos());
        if (GetItem(&currItem))
        {
                if (m_doc->DragP)
                        return;
                //Operations run here:
                //Item resize, esp after creating a new one
                if (m_view->moveTimerElapsed() && m_canvas->m_viewMode.m_MouseButtonPressed
                        && (m->buttons() & Qt::LeftButton) &&  (!currItem->locked()))
                {
                        handleNodeEditDrag(m, currItem);
                }
                else if (!m_canvas->m_viewMode.m_MouseButtonPressed)
                {
                        if (!currItem->locked())
                        {
                                QMatrix p;
                                QRect mpo;
                                handleNodeEditMove(m, mpo, currItem, p);
                        }
                }

        }
        else // shouldnt be in nodeedit mode now, should it??
        {
                npf = m_canvas->globalToCanvas(m->globalPos());
                if ((m_canvas->m_viewMode.m_MouseButtonPressed) && (m->buttons() & Qt::LeftButton) && (GyM == -1) && (GxM == -1))
                {
                        if (!m_rectangleSelect)
                        {
                                m_rectangleSelect = new RectSelect(this);
                        }
                        m_rectangleSelect->prepare(m->globalPos());
                        m_view->startGesture(m_rectangleSelect);
                        return;
                }
                if ((m_doc->guidesSettings.guidesShown) && (!m_doc->GuideLock)
                        && (m_doc->OnPage(npf.x(), npf.y()) != -1))
                {
                        Guides::iterator it;
                        Guides tmpGuides = m_doc->currentPage()->guides.horizontals(GuideManagerCore::Standard);
                        for (it = tmpGuides.begin(); it != tmpGuides.end(); ++it)
                        {
                                if ( (*it) + m_doc->currentPage()->yOffset() < npf.y() + m_doc->guidesSettings.grabRad * sc &&
                                         (*it) + m_doc->currentPage()->yOffset() > npf.y() - m_doc->guidesSettings.grabRad * sc )
                                {
                                        if ((m_canvas->m_viewMode.m_MouseButtonPressed) && (GyM != -1))
                                                MoveGY = true;
                                        if (npf.x() < m_doc->currentPage()->xOffset() ||
                                                npf.x() >= m_doc->currentPage()->xOffset() + m_doc->currentPage()->width() - 1)
                                                m_view->setCursor(QCursor(Qt::ArrowCursor));
                                        else
                                                m_view->setCursor(QCursor(Qt::SplitVCursor));
                                        return;
                                }
                        }
                        tmpGuides = m_doc->currentPage()->guides.verticals(GuideManagerCore::Standard);
                        for (it = tmpGuides.begin(); it!= tmpGuides.end(); ++it)
                        {
                                if ( (*it) + m_doc->currentPage()->xOffset() < npf.x() + m_doc->guidesSettings.grabRad * sc &&
                                         (*it) + m_doc->currentPage()->xOffset() > npf.x() - m_doc->guidesSettings.grabRad * sc)
                                {
                                        if ((m_canvas->m_viewMode.m_MouseButtonPressed) && (GxM != -1))
                                                MoveGX = true;
                                        if (npf.y() < m_doc->currentPage()->yOffset() ||
                                                npf.y() >= m_doc->currentPage()->yOffset() + m_doc->currentPage()->height() - 1)
                                                m_view->setCursor(QCursor(Qt::ArrowCursor));
                                        else
                                                m_view->setCursor(QCursor(Qt::SplitHCursor));
                                        return;
                                }
                        }
                        m_view->setCursor(QCursor(Qt::ArrowCursor));
                }
        }
}

void CanvasMode_NodeEdit::mousePressEvent(QMouseEvent *m)
{
        m_canvas->m_viewMode.m_MouseButtonPressed = true;
        m_canvas->m_viewMode.operItemMoving = false;
        m_doc->DragP = false;
        m_doc->leaveDrag = false;
        MoveGX = MoveGY = false;
        m->accept();
        m_view->registerMousePress(m->globalPos());
        QRect mpo;
        Mxp = m->x();
        Myp = m->y();
       
        if (m_doc->m_Selection->count() != 0)
        {
                handleNodeEditPress(m, mpo);
        }                      
        if ((m_doc->m_Selection->count() != 0) && (m->button() == Qt::RightButton))
        {
                m_canvas->m_viewMode.m_MouseButtonPressed = true;
                Dxp = Mxp;
                Dyp = Myp;
        }
}



void CanvasMode_NodeEdit::mouseReleaseEvent(QMouseEvent *m)
{
        PageItem *currItem;
        m_canvas->m_viewMode.m_MouseButtonPressed = false;
        m_canvas->resetRenderMode();
        m->accept();
        if (m_view->moveTimerElapsed())
        {
                if (m_doc->nodeEdit.SegP1 != -1 && m_doc->nodeEdit.SegP2 != -1)
                {
                        m_doc->nodeEdit.deselect();
                        m_doc->nodeEdit.SegP1 = -1;
                        m_doc->nodeEdit.SegP2 = -1;
                }
                currItem = m_doc->m_Selection->itemAt(0);
                m_canvas->m_viewMode.operItemMoving = false;
                double xposOrig = currItem->xPos();
                double yposOrig = currItem->yPos();

                ItemState<QPair<FPointArray, FPointArray> > *state = NULL;
                state = m_doc->nodeEdit.finishTransaction1(currItem);
                xposOrig = currItem->xPos();
                yposOrig = currItem->yPos();
                if (m_doc->nodeEdit.hasNodeSelected() && (m_doc->nodeEdit.SelNode.count() == 1))
                {
                        //FIXME:av
                        FPoint newP = m_canvas->globalToCanvas(m->globalPos());
                        currItem->OldB2 = currItem->width();
                        currItem->OldH2 = currItem->height();
                        FPointArray Clip;
                        if (m_doc->nodeEdit.isContourLine)
                                Clip = currItem->ContourLine;
                        else
                                Clip = currItem->PoLine;
                        FPoint npf;
                        double nx = newP.x();
                        double ny = newP.y();
                        if (!m_doc->ApplyGuides(&nx, &ny))
                                npf = m_doc->ApplyGridF(FPoint(nx, ny));
                        else
                                npf = FPoint(nx, ny);
                        npf = FPoint(npf.x(), npf.y(), currItem->xPos(), currItem->yPos(), currItem->rotation(), 1, 1, true);
                        m_doc->nodeEdit.moveClipPoint(currItem, npf);
                }

                m_doc->AdjustItemSize(currItem);
                if (!m_doc->nodeEdit.isContourLine)
                        currItem->ContourLine.translate(xposOrig - currItem->xPos(), yposOrig - currItem->yPos());
                m_doc->regionsChanged()->update(QRectF());
                if (state)
                {
                        m_doc->nodeEdit.finishTransaction2(currItem, state);
                }
                return;
        }

        m_canvas->setRenderModeUseBuffer(false);
        m_doc->DragP = false;
        m_doc->leaveDrag = false;
        m_canvas->m_viewMode.operItemMoving = false;
        m_canvas->m_viewMode.operItemResizing = false;
        m_view->MidButt = false;
        if (m_view->groupTransactionStarted())
        {
                for (int i = 0; i < m_doc->m_Selection->count(); ++i)
                        m_doc->m_Selection->itemAt(i)->checkChanges(true);
                m_view->endGroupTransaction();
        }
        //Commit drag created items to undo manager.
        if (m_doc->m_Selection->itemAt(0)!=NULL)
        {
                m_doc->itemAddCommit(m_doc->m_Selection->itemAt(0)->ItemNr);
        }
        //Make sure the Zoom spinbox and page selector dont have focus if we click on the canvas
        m_view->zoomSpinBox->clearFocus();
        m_view->pageSelector->clearFocus();
        if (m_doc->m_Selection->itemAt(0) != 0) // is there the old clip stored for the undo action
        {
                currItem = m_doc->m_Selection->itemAt(0);
                m_doc->nodeEdit.finishTransaction(currItem);
        }
}



void CanvasMode_NodeEdit::handleNodeEditPress(QMouseEvent* m, QRect)
{
        FPoint npf2;
       
        PageItem* currItem = m_doc->m_Selection->itemAt(0);
        FPointArray Clip = m_doc->nodeEdit.beginTransaction(currItem);
        bool edited = false;
        bool pfound = false;
        npf2 = m_canvas->globalToCanvas(m->globalPos()).transformPoint(currItem->xPos(), currItem->yPos(), currItem->rotation(), 1.0, 1.0, true);
        QMatrix pm2 = currItem->getTransform();
        for (int a=0; a < signed(Clip.size()); ++a)
        {
                if (((m_doc->nodeEdit.EdPoints) && (a % 2 != 0)) || ((!m_doc->nodeEdit.EdPoints) && (a % 2 == 0)))
                        continue;
                QPointF npf = pm2.map(Clip.pointQF(a));
                if (m_canvas->hitsCanvasPoint(m->globalPos(), npf))
                {
                        m_doc->nodeEdit.ClRe = a;
                        if ((m_doc->nodeEdit.EdPoints) && (m_doc->nodeEdit.SelNode.contains(a) == 0))
                        {
                                if (m->modifiers() == Qt::ShiftModifier)
                                        m_doc->nodeEdit.SelNode.append(a);
                                else
                                {
                                        m_doc->nodeEdit.SelNode.clear();
                                        m_doc->nodeEdit.SelNode.append(a);
                                }
                        }
                        m_doc->nodeEdit.update(Clip.pointQF(a));
                        pfound = true;
                        edited = true;
                        break;
                }
        }
        if ((!pfound) || (!m_doc->nodeEdit.EdPoints))
                m_doc->nodeEdit.SelNode.clear();

        if ((m_doc->nodeEdit.submode == NodeEditContext::MOVE_POINT) && (m_doc->nodeEdit.ClRe2 != -1) && !m_doc->nodeEdit.hasNodeSelected())
        {
                m_doc->nodeEdit.SegP1 = m_doc->nodeEdit.ClRe2;
                m_doc->nodeEdit.SegP2 = m_doc->nodeEdit.ClRe2+2;
                m_doc->nodeEdit.ClRe = m_doc->nodeEdit.ClRe2;
        }
        FPointArray cli;
        uint EndInd = Clip.size();
        uint StartInd = 0;
        for (uint n = m_doc->nodeEdit.ClRe; n < Clip.size(); ++n)
        {
                if (Clip.point(n).x() > 900000)
                {
                        EndInd = n;
                        break;
                }
        }
        if (m_doc->nodeEdit.ClRe > 0)
        {
                for (uint n2 = m_doc->nodeEdit.ClRe; n2 > 0; n2--)
                {
                        if (n2 == 0)
                                break;
                        if (Clip.point(n2).x() > 900000)
                        {
                                StartInd = n2 + 1;
                                break;
                        }
                }
        }
        if (m_doc->nodeEdit.submode == NodeEditContext::SPLIT_PATH)
        {
                if (!m_doc->nodeEdit.EdPoints)
                        return;
                if ((!m_doc->nodeEdit.hasNodeSelected()) && (m_doc->nodeEdit.ClRe2 != -1)) // We don't have a Point, try to add one onto the current curve segment
                {
                        bool foundP = false;
                        uint seg = 0;
                        double absDist = 9999999999.9;
                        FPoint point = FPoint(0, 0);
                        FPoint normal = FPoint(0, 0);
                        FPoint tangent = FPoint(0, 0);
                        FPoint nearPoint = FPoint(0, 0);
                        double nearT = 0.0;
                        QRect mpo2(0, 0, m_doc->guidesSettings.grabRad*3, m_doc->guidesSettings.grabRad*3);
                        mpo2.moveCenter(QPoint(qRound(npf2.x()), qRound(npf2.y())));
                        for (uint poi=0; poi<Clip.size()-3; poi += 4)
                        {
                                FPoint a1 = Clip.point(poi);
                                FPoint a2 = Clip.point(poi+1);
                                FPoint a3 = Clip.point(poi+3);
                                FPoint a4 = Clip.point(poi+2);
                                QPainterPath Bez;
                                Bez.moveTo(a1.x(), a1.y());
                                Bez.cubicTo(a2.x(), a2.y(), a3.x(), a3.y(), a4.x(), a4.y());
                                QPolygon cli2 = Bez.toFillPolygon().toPolygon();
                                for (int clp = 0; clp < cli2.size()-1; ++clp)
                                {
                                        if (m_view->PointOnLine(cli2.point(clp), cli2.point(clp+1), mpo2))
                                        {
                                                seg = poi;
                                                double sp = 0.0;
                                                double spadd = 1.0 / (Clip.lenPathSeg(seg) * m_canvas->scale());
                                                while (sp < 1.0)
                                                {
                                                        Clip.pointTangentNormalAt(seg, sp, &point, &tangent, &normal );
                                                        double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y() ,2)));
                                                        if (d1 < absDist)
                                                        {
                                                                foundP = true;
                                                                nearPoint = point;
                                                                nearT = sp;
                                                                absDist = d1;
                                                        }
                                                        sp += spadd;
                                                }
                                        }
                                }
                        }
                        cli.putPoints(0, m_doc->nodeEdit.ClRe2+2, Clip);
                        if (foundP)
                        {
                                npf2 = nearPoint;
                                FPoint base = cli.point(cli.size()-2);
                                FPoint c1 = cli.point(cli.size()-1);
                                FPoint base2 =  Clip.point(m_doc->nodeEdit.ClRe2+2);
                                FPoint c2 = Clip.point(m_doc->nodeEdit.ClRe2+3);
                                if ((base == c1) && (base2 == c2))
                                {
                                        cli.resize(cli.size()+4);
                                        cli.putPoints(cli.size()-4, 4, npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y());
                                        cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe2 + 2), Clip, m_doc->nodeEdit.ClRe2+2);
                                }
                                else
                                {
                                        FPoint cn1 = (1.0 - nearT) * base + nearT * c1;
                                        FPoint cn2 = (1.0 - nearT) * cn1 + nearT * ((1.0 - nearT) * c1 + nearT * c2);
                                        FPoint cn3 = (1.0 - nearT) * ((1.0 - nearT) * c1 + nearT * c2) + nearT * ((1.0 - nearT) * c2 + nearT * base2);
                                        FPoint cn4 = (1.0 - nearT) * c2 + nearT * base2;
                                        cli.setPoint(cli.size()-1, cn1);
                                        cli.resize(cli.size()+4);
                                        uint basind = cli.size()+1;
                                        cli.putPoints(cli.size()-4, 4, npf2.x(), npf2.y(), cn2.x(), cn2.y(), npf2.x(), npf2.y(), cn3.x(), cn3.y());
                                        cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe2 + 2), Clip, m_doc->nodeEdit.ClRe2+2);
                                        cli.setPoint(basind, cn4);
                                }
                                Clip = cli.copy();
                                cli.resize(0);
                                m_doc->nodeEdit.ClRe = m_doc->nodeEdit.ClRe2+2;
                                m_doc->nodeEdit.ClRe2 = -1;
                                EndInd = Clip.size();
                                StartInd = 0;
                                for (uint n = m_doc->nodeEdit.ClRe; n < Clip.size(); ++n)
                                {
                                        if (Clip.point(n).x() > 900000)
                                        {
                                                EndInd = n;
                                                break;
                                        }
                                }
                                if (m_doc->nodeEdit.ClRe > 0)
                                {
                                        for (uint n2 = m_doc->nodeEdit.ClRe; n2 > 0; n2--)
                                        {
                                                if (n2 == 0)
                                                        break;
                                                if (Clip.point(n2).x() > 900000)
                                                {
                                                        StartInd = n2 + 1;
                                                        break;
                                                }
                                        }
                                }
                        }
                        else
                                m_doc->nodeEdit.deselect();
                }
                if (m_doc->nodeEdit.hasNodeSelected())
                {
                        if (currItem->asPolygon())
                        {
                                if ((m_doc->nodeEdit.ClRe != 0) && (m_doc->nodeEdit.ClRe != static_cast<int>(EndInd-2)))
                                {
                                        if (currItem->Segments.count() == 0)
                                        {
                                                cli.putPoints(0, EndInd-(m_doc->nodeEdit.ClRe+2), Clip, m_doc->nodeEdit.ClRe+2);
                                                cli.putPoints(cli.size(), m_doc->nodeEdit.ClRe+2, Clip);
                                        }
                                        else
                                        {
                                                cli.putPoints(0, EndInd-StartInd, Clip, StartInd);
                                                int z = m_doc->itemAdd(PageItem::Polygon, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->fillColor(), currItem->lineColor(), true);
                                                PageItem* bb = m_doc->Items->at(z);
                                                if (m_doc->nodeEdit.isContourLine)
                                                        bb->ContourLine.resize(0);
                                                else
                                                        bb->PoLine.resize(0);
                                                if (StartInd != 0)
                                                {
                                                        if (m_doc->nodeEdit.isContourLine)
                                                        {
                                                                bb->ContourLine.putPoints(0, StartInd - 4, Clip);
                                                                bb->ContourLine.putPoints(bb->ContourLine.size(), Clip.size()-EndInd, Clip, EndInd);
                                                        }
                                                        else
                                                        {
                                                                bb->PoLine.putPoints(0, StartInd - 4, Clip);
                                                                bb->PoLine.putPoints(bb->PoLine.size(), Clip.size()-EndInd, Clip, EndInd);
                                                        }
                                                }
                                                else
                                                {
                                                        if (m_doc->nodeEdit.isContourLine)
                                                                bb->ContourLine.putPoints(0, Clip.size()-EndInd-4, Clip, EndInd+4);
                                                        else
                                                                bb->PoLine.putPoints(0, Clip.size()-EndInd-4, Clip, EndInd+4);
                                                }
                                                bb->setRotation(currItem->rotation());
                                                m_doc->AdjustItemSize(bb);
                                                bb->ClipEdited = true;
                                                PageItem *bx = m_doc->Items->takeAt(bb->ItemNr);
                                                m_doc->Items->insert(bb->ItemNr-1, bx);
                                        }
                                        currItem->PoLine = cli.copy();
                                }
                                m_doc->nodeEdit.deselect();
                                currItem->ClipEdited = true;
                                edited = true;
                                m_doc->nodeEdit.submode = NodeEditContext::MOVE_POINT;
                                PageItem* newItem=m_doc->convertItemTo(currItem, PageItem::PolyLine);
                                currItem=newItem;
                                m_doc->m_Selection->clear();
                                m_doc->m_Selection->addItem(currItem);
                                emit m_view->PolyOpen();
                        }
                        else
                        {
                                if ((currItem->asPolyLine()) || (currItem->asPathText()))
                                {
                                        if ((m_doc->nodeEdit.ClRe > 1) && (m_doc->nodeEdit.ClRe < static_cast<int>(Clip.size()-2)))
                                        {
                                                int z = m_doc->itemAdd(PageItem::PolyLine, PageItem::Unspecified, currItem->xPos(), currItem->yPos(), currItem->width(), currItem->height(), currItem->lineWidth(), currItem->fillColor(), currItem->lineColor(), true);
                                                PageItem* bb = m_doc->Items->at(z);
                                                if (m_doc->nodeEdit.isContourLine)
                                                        bb->ContourLine.putPoints(0, Clip.size()-(m_doc->nodeEdit.ClRe+2), Clip, m_doc->nodeEdit.ClRe+2);
                                                else
                                                        bb->PoLine.putPoints(0, Clip.size()-(m_doc->nodeEdit.ClRe+2), Clip, m_doc->nodeEdit.ClRe+2);
                                                bb->setRotation(currItem->rotation());
                                                m_doc->AdjustItemSize(bb);
                                                bb->ClipEdited = true;
                                                bb->setFrameType(currItem->frameType());
                                                cli.resize(0);
                                                cli.putPoints(0, m_doc->nodeEdit.ClRe+2, Clip);
                                                currItem->PoLine = cli.copy();
                                                m_doc->m_Selection->clear();
                                                m_doc->m_Selection->addItem(currItem);
                                        }
                                        m_doc->nodeEdit.deselect();
                                        currItem->ClipEdited = true;
                                        edited = true;
                                        m_doc->nodeEdit.submode = NodeEditContext::MOVE_POINT;
                                        currItem->setPolyClip(qRound(qMax(currItem->lineWidth() / 2.0, 1.0)));
                                        emit m_view->PolyOpen();
                                }
                        }
                }
        }
        if ((m_doc->nodeEdit.submode == NodeEditContext::DEL_POINT) && m_doc->nodeEdit.hasNodeSelected())
        {
                if (!m_doc->nodeEdit.EdPoints)
                        return;
                if ((currItem->asPolygon()) || (currItem->asTextFrame()) || (currItem->asImageFrame()))
                {
                        if ((currItem->Segments.count() == 0) && (Clip.size() <= 12))  // min. 3 points
                                return;
                }
                else
                {
                        if (Clip.size() <= 4)
                                return;
                }
                if ((currItem->Segments.count() != 0) && ((EndInd - StartInd) <= 12))
                {
                        if (StartInd != 0)
                                cli.putPoints(0, StartInd-4, Clip);
                        cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd);
                }
                else
                {
                        if (m_doc->nodeEdit.ClRe == static_cast<int>(StartInd))
                        {
                                if ((currItem->asPolygon()) || (currItem->asTextFrame()) || (currItem->asImageFrame()))
                                {
                                        FPoint kp(Clip.point(EndInd-3));
                                        cli.putPoints(0, StartInd, Clip);
                                        cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd);
                                        cli.setPoint(StartInd, cli.point(cli.size()-2));
                                        cli.setPoint(StartInd + 1, kp);
                                        cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd);
                                }
                                else
                                {
                                        cli.putPoints(0, StartInd, Clip);
                                        cli.putPoints(cli.size(), EndInd - StartInd - 4, Clip, StartInd+4);
                                        cli.putPoints(cli.size(), Clip.size() - EndInd, Clip, EndInd);
                                }
                        }
                        else
                        {
                                if (m_doc->nodeEdit.ClRe != 0)
                                        cli.putPoints(0, m_doc->nodeEdit.ClRe, Clip);
                                cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe + 4), Clip, m_doc->nodeEdit.ClRe+4);
                        }
                }
                if (m_doc->nodeEdit.isContourLine)
                        currItem->ContourLine = cli.copy();
                else
                        currItem->PoLine = cli.copy();
                m_doc->nodeEdit.deselect();
                currItem->ClipEdited = true;
                edited = true;
        }
        if ((m_doc->nodeEdit.submode == NodeEditContext::ADD_POINT) && (m_doc->nodeEdit.ClRe2 != -1))
        {
                bool foundP = false;
                uint seg = 0;
                double absDist = 9999999999.9;
                FPoint point = FPoint(0, 0);
                FPoint normal = FPoint(0, 0);
                FPoint tangent = FPoint(0, 0);
                FPoint nearPoint = FPoint(0, 0);
                double nearT = 0.0;
                QRect mpo2(0, 0, m_doc->guidesSettings.grabRad*3, m_doc->guidesSettings.grabRad*3);
                mpo2.moveCenter(QPoint(qRound(npf2.x()), qRound(npf2.y())));
                for (uint poi=0; poi<Clip.size()-3; poi += 4)
                {
                        FPoint a1 = Clip.point(poi);
                        FPoint a2 = Clip.point(poi+1);
                        FPoint a3 = Clip.point(poi+3);
                        FPoint a4 = Clip.point(poi+2);
                        QPainterPath Bez;
                        Bez.moveTo(a1.x(), a1.y());
                        Bez.cubicTo(a2.x(), a2.y(), a3.x(), a3.y(), a4.x(), a4.y());
                        QPolygon cli2 = Bez.toFillPolygon().toPolygon();
                        for (int clp = 0; clp < cli2.size()-1; ++clp)
                        {
                                if (m_view->PointOnLine(cli2.point(clp), cli2.point(clp+1), mpo2))
                                {
                                        seg = poi;
                                        double sp = 0.0;
                                        double spadd = 1.0 / (Clip.lenPathSeg(seg) * m_canvas->scale());
                                        while (sp < 1.0)
                                        {
                                                Clip.pointTangentNormalAt(seg, sp, &point, &tangent, &normal );
                                                double d1 = fabs(sqrt(pow(point.x() - npf2.x(), 2) + pow(point.y() - npf2.y() ,2)));
                                                if (d1 < absDist)
                                                {
                                                        foundP = true;
                                                        nearPoint = point;
                                                        nearT = sp;
                                                        absDist = d1;
                                                }
                                                sp += spadd;
                                        }
                                }
                        }
                }
                cli.putPoints(0, m_doc->nodeEdit.ClRe2+2, Clip);
                if (foundP)
                {
                        npf2 = nearPoint;
                        FPoint base = cli.point(cli.size()-2);
                        FPoint c1 = cli.point(cli.size()-1);
                        FPoint base2 =  Clip.point(m_doc->nodeEdit.ClRe2+2);
                        FPoint c2 = Clip.point(m_doc->nodeEdit.ClRe2+3);
                        if ((base == c1) && (base2 == c2))
                        {
                                cli.resize(cli.size()+4);
                                cli.putPoints(cli.size()-4, 4, npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y());
                                                cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe2 + 2), Clip, m_doc->nodeEdit.ClRe2+2);
                        }
                        else
                        {
                                FPoint cn1 = (1.0 - nearT) * base + nearT * c1;
                                FPoint cn2 = (1.0 - nearT) * cn1 + nearT * ((1.0 - nearT) * c1 + nearT * c2);
                                FPoint cn3 = (1.0 - nearT) * ((1.0 - nearT) * c1 + nearT * c2) + nearT * ((1.0 - nearT) * c2 + nearT * base2);
                                FPoint cn4 = (1.0 - nearT) * c2 + nearT * base2;
                                cli.setPoint(cli.size()-1, cn1);
                                cli.resize(cli.size()+4);
                                uint basind = cli.size()+1;
                                cli.putPoints(cli.size()-4, 4, npf2.x(), npf2.y(), cn2.x(), cn2.y(), npf2.x(), npf2.y(), cn3.x(), cn3.y());
                                cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe2 + 2), Clip, m_doc->nodeEdit.ClRe2+2);
                                cli.setPoint(basind, cn4);
                        }
                }
                else
                {
                        cli.resize(cli.size()+4);
                        cli.putPoints(cli.size()-4, 4, npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y(), npf2.x(), npf2.y());
                        cli.putPoints(cli.size(), Clip.size()-(m_doc->nodeEdit.ClRe2 + 2), Clip, m_doc->nodeEdit.ClRe2+2);
                }
                if (m_doc->nodeEdit.isContourLine)
                        currItem->ContourLine = cli.copy();
                else
                        currItem->PoLine = cli.copy();
                m_doc->nodeEdit.ClRe2 = -1;
                currItem->ClipEdited = true;
                edited = true;
        }
        if (edited)
        {
                currItem->FrameType = 3;
                m_doc->AdjustItemSize(currItem);
                currItem->update();
                emit m_view->PolyStatus(currItem->itemType(), currItem->PoLine.size());
        }
        if ((m_doc->nodeEdit.SelNode.count() != 0) || ((m_doc->nodeEdit.SegP1 != -1) && (m_doc->nodeEdit.SegP2 != -1)) || (m_doc->nodeEdit.hasNodeSelected() && (!m_doc->nodeEdit.EdPoints)))
        {
                Mxp = m->x();
                Myp = m->y();
                m_canvas->setRenderModeFillBuffer();
        }
        else
        {
                Mxp = m->x();
                Myp = m->y();
                Dxp = qRound(m->x()/m_canvas->scale());
                Dyp = qRound(m->y()/m_canvas->scale());
                if (!m_rectangleSelect)
                        m_rectangleSelect = new RectSelect(this);
                m_rectangleSelect->prepare(m->globalPos());
                m_view->startGesture(m_rectangleSelect);
        }
       
}



bool CanvasMode_NodeEdit::handleNodeEditMove(QMouseEvent* m, QRect, PageItem* currItem, QMatrix)
{
        QMatrix itemPos = currItem->getTransform();
        FPointArray Clip;
        m_doc->nodeEdit.ClRe2 = -1;
        m_doc->nodeEdit.SegP1 = -1;
        m_doc->nodeEdit.SegP2 = -1;
        if (m_doc->nodeEdit.isContourLine)
                Clip = currItem->ContourLine;
        else
                Clip = currItem->PoLine;
        if ((m_doc->nodeEdit.submode == NodeEditContext::DEL_POINT) ||
                (m_doc->nodeEdit.submode == NodeEditContext::MOVE_POINT) ||
                (m_doc->nodeEdit.submode == NodeEditContext::SPLIT_PATH))
        {
                for (int a=0; a < signed(Clip.size()); ++a)
                {
                        if (((m_doc->nodeEdit.EdPoints) && (a % 2 != 0)) || ((!m_doc->nodeEdit.EdPoints) && (a % 2 == 0)))
                                continue;
                        QPointF point = Clip.pointQF(a);
                        if (m_canvas->hitsCanvasPoint(m->globalPos(), itemPos.map(point)))
                        {
                                if (m_doc->nodeEdit.submode == NodeEditContext::MOVE_POINT)
                                        m_view->setCursor(QCursor(Qt::SizeAllCursor));
                                if (m_doc->nodeEdit.submode == NodeEditContext::DEL_POINT)
                                        m_view->setCursor(QCursor(loadIcon("DelPoint.png"), 1, 1));
                                if (m_doc->nodeEdit.submode == NodeEditContext::SPLIT_PATH)
                                        m_view->setCursor(QCursor(loadIcon("Split.png"), 1, 1));
                                return true;
                        }
                }
        }
        if ((m_doc->nodeEdit.submode == NodeEditContext::ADD_POINT) ||
                (m_doc->nodeEdit.submode == NodeEditContext::MOVE_POINT) ||
                (m_doc->nodeEdit.submode == NodeEditContext::SPLIT_PATH && m_doc->nodeEdit.EdPoints))
        {
                for (uint poi=0; poi<Clip.size()-3; poi += 4)
                {
                        // create bezier curve in canvas coords
                        QPointF a1 = itemPos.map(Clip.pointQF(poi));
                        QPointF a2 = itemPos.map(Clip.pointQF(poi+1));
                        QPointF a3 = itemPos.map(Clip.pointQF(poi+3));
                        QPointF a4 = itemPos.map(Clip.pointQF(poi+2));
                        QPainterPath Bez;
                        Bez.moveTo(a1);
                        Bez.cubicTo(a2, a3, a4);
                        double len = Bez.length();
                        if (len > 0.0)
                        {
                                double delta = 2.0 / len;
                                for (double d = 0.0; d <= 1.0; d += delta)
                                {
                                        QPointF pl = Bez.pointAtPercent(d);
                                        if (m_canvas->hitsCanvasPoint(m->globalPos(), FPoint(pl.x(), pl.y())))
                                        {
                                                if (m_doc->nodeEdit.submode == NodeEditContext::MOVE_POINT)
                                                        m_view->setCursor(QCursor(loadIcon("HandC.xpm")));
                                                else if (m_doc->nodeEdit.submode == NodeEditContext::ADD_POINT)
                                                        m_view->setCursor(QCursor(loadIcon("AddPoint.png"), 1, 1));
                                                else if (m_doc->nodeEdit.submode == NodeEditContext::SPLIT_PATH)
                                                        m_view->setCursor(QCursor(loadIcon("Split.png"), 1, 1));
                                                else
                                                        m_view->setCursor(QCursor(Qt::ArrowCursor));
                                                m_doc->nodeEdit.ClRe2 = poi;
                                                return true;
                                        }
                                }
                        }
                }
        }
        m_view->setCursor(QCursor(Qt::ArrowCursor));
        return false;
}

void CanvasMode_NodeEdit::handleNodeEditDrag(QMouseEvent* m, PageItem* currItem)
{
        FPoint npf;
        if ((m_canvas->m_viewMode.m_MouseButtonPressed) && !m_doc->nodeEdit.hasNodeSelected() && (m_doc->nodeEdit.SegP1 == -1) && (m_doc->nodeEdit.SegP2 == -1))
        {
                if (!m_rectangleSelect)
                {
                        m_rectangleSelect = new RectSelect(this);
                }
                m_rectangleSelect->prepare(m->globalPos());
                m_view->startGesture(m_rectangleSelect);
                return;
        }
        int newX = m->x();
        int newY = m->y();
        FPoint np(newX-Mxp, newY-Myp, 0, 0, currItem->rotation(), 1, 1, true);
        np = np * (1.0 / m_canvas->scale());
        m_canvas->m_viewMode.operItemMoving = true;
        currItem = m_doc->m_Selection->itemAt(0);
        if ((m_doc->nodeEdit.SegP1 != -1) && (m_doc->nodeEdit.SegP2 != -1))
        {
                if (m_doc->nodeEdit.isContourLine)
                        npf = currItem->ContourLine.point(m_doc->nodeEdit.SegP2) + np;
                else
                        npf = currItem->PoLine.point(m_doc->nodeEdit.SegP2) + np;
                m_doc->nodeEdit.ClRe = m_doc->nodeEdit.SegP2;
                m_doc->nodeEdit.moveClipPoint(currItem, npf);
                if (m_doc->nodeEdit.isContourLine)
                        npf = currItem->ContourLine.point(m_doc->nodeEdit.SegP1) + np;
                else
                        npf = currItem->PoLine.point(m_doc->nodeEdit.SegP1) + np;
                m_doc->nodeEdit.ClRe = m_doc->nodeEdit.SegP1;
                m_doc->nodeEdit.moveClipPoint(currItem, npf);
                Mxp = newX;
                Myp = newY;
        }
        else
        {
                if ((m_doc->nodeEdit.SelNode.count() != 0) && (m_doc->nodeEdit.EdPoints))
                {
                        int storedClRe = m_doc->nodeEdit.ClRe;
                        if (m_doc->nodeEdit.SelNode.count() == 1)
                        {
                                npf = m_canvas->globalToCanvas(m->globalPos());
                                double nx = npf.x();
                                double ny = npf.y();
                                if (!m_doc->ApplyGuides(&nx, &ny))
                                        npf = m_doc->ApplyGridF(FPoint(nx, ny));
                                else
                                        npf = FPoint(nx, ny);
                                npf = FPoint(npf.x(), npf.y(), currItem->xPos(), currItem->yPos(), currItem->rotation(), 1, 1, true);
                                m_doc->nodeEdit.moveClipPoint(currItem, npf);
                                m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
                        }
                        else
                        {
                                for (int itm = 0; itm < m_doc->nodeEdit.SelNode.count(); ++itm)
                                {
                                        m_doc->nodeEdit.ClRe = m_doc->nodeEdit.SelNode.at(itm);
                                        if (m_doc->nodeEdit.isContourLine)
                                                npf = currItem->ContourLine.point(m_doc->nodeEdit.ClRe) + np;
                                        else
                                                npf = currItem->PoLine.point(m_doc->nodeEdit.ClRe) + np;
                                        m_doc->nodeEdit.moveClipPoint(currItem, npf);
                                }
                        }
                        m_doc->nodeEdit.ClRe = storedClRe;
                }
                else
                {
                        npf = m_canvas->globalToCanvas(m->globalPos());
                        double nx = npf.x();
                        double ny = npf.y();
                        if (!m_doc->ApplyGuides(&nx, &ny))
                                npf = m_doc->ApplyGridF(FPoint(nx, ny));
                        else
                                npf = FPoint(nx, ny);
                        npf = FPoint(npf.x(), npf.y(), currItem->xPos(), currItem->yPos(), currItem->rotation(), 1, 1, true);
                        m_doc->nodeEdit.moveClipPoint(currItem, npf);
                        m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
                }
                Mxp = newX;
                Myp = newY;
        }
        m_canvas->m_viewMode.operItemMoving = false;
        m_doc->regionsChanged()->update(QRectF());
}