/*
 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.                                   *
*                                                                         *
***************************************************************************/
/***************************************************************************
				 canvasmode_editmeshpatch.cpp  -  description
							 -------------------
	begin                : Sun Sep 25 2011
	copyright            : (C) 2011 by Franz Schmid
	email                : Franz.Schmid@altmuehlnet.de
 ***************************************************************************/


#include "canvasmode_editmeshpatch.h"

#include <QApplication>
#include <QButtonGroup>
#include <QCheckBox>
#include <QCursor>
#include <QEvent>
#include <QMessageBox>
#include <QMouseEvent>
#include <QPainterPath>
#include <QPoint>
#include <QRect>
#include <QTimer>
#include <QWidgetAction>
#include <QDebug>

#include "appmodes.h"
#include "canvas.h"
#include "fpoint.h"
#include "fpointarray.h"
#include "hyphenator.h"
#include "pageitem_textframe.h"
#include "prefscontext.h"
#include "prefsfile.h"
#include "prefsmanager.h"
#include "sccolorengine.h"
#include "scribus.h"
#include "scribusXml.h"
#include "scribusdoc.h"
#include "scribusview.h"
#include "selection.h"
#include "ui/aligndistribute.h"
#include "ui/contextmenu.h"
#include "ui/pageselector.h"
#include "ui/propertiespalette.h"
#include "undomanager.h"
#include "units.h"
#include "util.h"
#include "util_math.h"


CanvasMode_EditMeshPatch::CanvasMode_EditMeshPatch(ScribusView* view) : CanvasMode(view), m_ScMW(view->m_ScMW)
{
	m_old_mesh = new MeshPoint();
}

CanvasMode_EditMeshPatch::~CanvasMode_EditMeshPatch()
{
	delete m_old_mesh;
	m_old_mesh = nullptr;
}

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

void CanvasMode_EditMeshPatch::drawControls(QPainter* p)
{
	p->save();
	if (m_canvas->m_viewMode.operItemMoving)
	{
		drawOutline(p);
	}
	else
	{
		drawSelection(p, false);
	}
	if (m_doc->appMode == modeEditMeshPatch)
	{
		drawControlsMeshPatch(p, m_doc->m_Selection->itemAt(0));
	}
	p->restore();
}

void CanvasMode_EditMeshPatch::drawControlsMeshPoint(QPainter* psx, const MeshPoint& mp, bool isSelected)
{
	QPen p8r = QPen(Qt::red, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	QPen p8m = QPen(Qt::magenta, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	QPen p14r = QPen(Qt::red, 18.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	QPen p14w = QPen(Qt::white, 18.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	if (m_view->editStrokeGradient == 8)
	{
		if (isSelected)
			psx->setPen(p14r);
		else
			psx->setPen(p14w);
		psx->drawPoint(QPointF(mp.gridPoint.x(), mp.gridPoint.y()));
		psx->setPen(QPen(mp.color, 14.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin));
		psx->drawPoint(QPointF(mp.gridPoint.x(), mp.gridPoint.y()));
		if (isSelected)
			psx->setPen(p8r);
		else
			psx->setPen(p8m);
		psx->drawPoint(QPointF(mp.controlColor.x(), mp.controlColor.y()));
	}
	else if (m_view->editStrokeGradient == 9)
	{
		if (isSelected)
			psx->setPen(p8r);
		else
			psx->setPen(p8m);
		psx->drawPoint(QPointF(mp.gridPoint.x(), mp.gridPoint.y()));
	}
}

void CanvasMode_EditMeshPatch::drawControlsMeshPatch(QPainter* psx, PageItem* currItem)
{
	QPen p1b = QPen(Qt::blue, 1.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin);
	QPen p1bd = QPen(Qt::blue, 1.0 / m_canvas->m_viewMode.scale, Qt::DotLine, Qt::FlatCap, Qt::MiterJoin);
//	QPen p8b = QPen(Qt::blue, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	QPen p8r = QPen(Qt::red, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	QPen p8m = QPen(Qt::magenta, 8.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
//	QPen p14r = QPen(Qt::red, 18.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
//	QPen p14w = QPen(Qt::white, 18.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::RoundCap, Qt::MiterJoin);
	psx->setTransform(currItem->getTransform(), true);
	psx->setPen(p1b);
	psx->setBrush(Qt::NoBrush);

	for (int col = 0; col < currItem->meshGradientPatches.count(); col++)
	{
		meshGradientPatch patch = currItem->meshGradientPatches[col];
		MeshPoint mp1 = patch.TL;
		MeshPoint mp2 = patch.TR;
		MeshPoint mp3 = patch.BR;
		MeshPoint mp4 = patch.BL;
		if (col != currItem->selectedMeshPointX)
		{
			QPainterPath Bez;
			Bez.moveTo(mp1.gridPoint.x(), mp1.gridPoint.y());
			Bez.cubicTo(mp1.controlRight.x(), mp1.controlRight.y(), mp2.controlLeft.x(), mp2.controlLeft.y(), mp2.gridPoint.x(), mp2.gridPoint.y());
			Bez.cubicTo(mp2.controlBottom.x(), mp2.controlBottom.y(), mp3.controlTop.x(), mp3.controlTop.y(), mp3.gridPoint.x(), mp3.gridPoint.y());
			Bez.cubicTo(mp3.controlLeft.x(), mp3.controlLeft.y(), mp4.controlRight.x(), mp4.controlRight.y(), mp4.gridPoint.x(), mp4.gridPoint.y());
			Bez.cubicTo(mp4.controlTop.x(), mp4.controlTop.y(), mp1.controlBottom.x(), mp1.controlBottom.y(), mp1.gridPoint.x(), mp1.gridPoint.y());
			psx->setPen(p1b);
			psx->drawPath(Bez);
		}
	}
	if (currItem->selectedMeshPointX >= 0)
	{
		meshGradientPatch patch = currItem->meshGradientPatches[currItem->selectedMeshPointX];
		MeshPoint mp1 = patch.TL;
		MeshPoint mp2 = patch.TR;
		MeshPoint mp3 = patch.BR;
		MeshPoint mp4 = patch.BL;
		QPainterPath Bez;
		Bez.moveTo(mp1.gridPoint.x(), mp1.gridPoint.y());
		Bez.cubicTo(mp1.controlRight.x(), mp1.controlRight.y(), mp2.controlLeft.x(), mp2.controlLeft.y(), mp2.gridPoint.x(), mp2.gridPoint.y());
		Bez.cubicTo(mp2.controlBottom.x(), mp2.controlBottom.y(), mp3.controlTop.x(), mp3.controlTop.y(), mp3.gridPoint.x(), mp3.gridPoint.y());
		Bez.cubicTo(mp3.controlLeft.x(), mp3.controlLeft.y(), mp4.controlRight.x(), mp4.controlRight.y(), mp4.gridPoint.x(), mp4.gridPoint.y());
		Bez.cubicTo(mp4.controlTop.x(), mp4.controlTop.y(), mp1.controlBottom.x(), mp1.controlBottom.y(), mp1.gridPoint.x(), mp1.gridPoint.y());
		psx->setPen(QPen(Qt::red, 1.0 / m_canvas->m_viewMode.scale, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin));
		psx->drawPath(Bez);
		drawControlsMeshPoint(psx, mp1, m_patchPoint == useTL);
		drawControlsMeshPoint(psx, mp2, m_patchPoint == useTR);
		drawControlsMeshPoint(psx, mp3, m_patchPoint == useBR);
		drawControlsMeshPoint(psx, mp4, m_patchPoint == useBL);
		if (m_view->editStrokeGradient == 10)
		{
			if (m_patchPoint == useTL)
			{
				psx->setPen(p1bd);
				psx->drawLine(QPointF(mp1.gridPoint.x(), mp1.gridPoint.y()), QPointF(mp1.controlBottom.x(), mp1.controlBottom.y()));
				psx->drawLine(QPointF(mp1.gridPoint.x(), mp1.gridPoint.y()), QPointF(mp1.controlRight.x(), mp1.controlRight.y()));
				if (m_gradientPoint == useControlB)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp1.controlBottom.x(), mp1.controlBottom.y()));
				if (m_gradientPoint == useControlR)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp1.controlRight.x(), mp1.controlRight.y()));
			}
			else if (m_patchPoint == useTR)
			{
				psx->setPen(p1bd);
				psx->drawLine(QPointF(mp2.gridPoint.x(), mp2.gridPoint.y()), QPointF(mp2.controlBottom.x(), mp2.controlBottom.y()));
				psx->drawLine(QPointF(mp2.gridPoint.x(), mp2.gridPoint.y()), QPointF(mp2.controlLeft.x(), mp2.controlLeft.y()));
				if (m_gradientPoint == useControlL)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp2.controlLeft.x(), mp2.controlLeft.y()));
				if (m_gradientPoint == useControlB)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp2.controlBottom.x(), mp2.controlBottom.y()));
			}
			else if (m_patchPoint == useBR)
			{
				psx->setPen(p1bd);
				psx->drawLine(QPointF(mp3.gridPoint.x(), mp3.gridPoint.y()), QPointF(mp3.controlTop.x(), mp3.controlTop.y()));
				psx->drawLine(QPointF(mp3.gridPoint.x(), mp3.gridPoint.y()), QPointF(mp3.controlLeft.x(), mp3.controlLeft.y()));
				if (m_gradientPoint == useControlL)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp3.controlLeft.x(), mp3.controlLeft.y()));
				if (m_gradientPoint == useControlT)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp3.controlTop.x(), mp3.controlTop.y()));
			}
			else if (m_patchPoint == useBL)
			{
				psx->setPen(p1bd);
				psx->drawLine(QPointF(mp4.gridPoint.x(), mp4.gridPoint.y()), QPointF(mp4.controlTop.x(), mp4.controlTop.y()));
				psx->drawLine(QPointF(mp4.gridPoint.x(), mp4.gridPoint.y()), QPointF(mp4.controlRight.x(), mp4.controlRight.y()));
				if (m_gradientPoint == useControlR)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp4.controlRight.x(), mp4.controlRight.y()));
				if (m_gradientPoint == useControlT)
					psx->setPen(p8r);
				else
					psx->setPen(p8m);
				psx->drawPoint(QPointF(mp4.controlTop.x(), mp4.controlTop.y()));
			}
		}
	}
	if (m_view->editStrokeGradient == 11)
	{
		if (m_clickPointPolygon.size() > 1)
		{
			psx->setPen(p1b);
			psx->drawPolyline(m_clickPointPolygon);
		}
		psx->setPen(p8r);
		for (int col = 0; col < m_clickPointPolygon.size(); col++)
		{
			psx->drawPoint(m_clickPointPolygon.value(col));
		}
		if (!m_clickPointPolygon.empty())
		{
			psx->setPen(p1bd);
			psx->drawLine(m_clickPointPolygon.value(m_clickPointPolygon.count() - 1), m_currentPoint);
			if (m_clickPointPolygon.size() == 3)
				psx->drawLine(m_clickPointPolygon.value(0), m_currentPoint);
		}
		psx->setPen(p8r);
		psx->drawPoint(m_currentPoint);
	}
}

void CanvasMode_EditMeshPatch::enterEvent(QEvent *e)
{
	if (!m_canvas->m_viewMode.m_MouseButtonPressed)
	{
		setModeCursor();
	}
}

void CanvasMode_EditMeshPatch::leaveEvent(QEvent *e)
{
}


void CanvasMode_EditMeshPatch::activate(bool fromGesture)
{
	CanvasMode::activate(fromGesture);

	m_canvas->m_viewMode.m_MouseButtonPressed = false;
	m_canvas->resetRenderMode();
	m_doc->DragP = false;
	m_doc->leaveDrag = false;
	m_canvas->m_viewMode.operItemMoving = false;
	m_canvas->m_viewMode.operItemResizing = false;
	m_view->MidButt = false;
	m_keyRepeat = false;
	m_currItem = m_doc->m_Selection->itemAt(0);
	m_Mxp = m_Myp = m_currItem->selectedMeshPointX = -1;
	m_click_count = 0;
	setModeCursor();
	if (fromGesture)
	{
		m_view->update();
	}
	m_currItem->snapToPatchGrid = false;
}

void CanvasMode_EditMeshPatch::deactivate(bool forGesture)
{
	m_view->setRedrawMarkerShown(false);
	m_patchPoint = noPointDefined;
	m_gradientPoint = noControlPointDefined;
	m_click_count = 0;
	m_currItem->selectedMeshPointX = -1;
	m_currItem->selectedMeshPointY = m_patchPoint;
	m_currItem->selectedMeshControlPoint = m_gradientPoint;
	m_ScMW->propertiesPalette->updateColorSpecialGradient();
	m_currItem->snapToPatchGrid = false;

	CanvasMode::deactivate(forGesture);
}

void CanvasMode_EditMeshPatch::keyPressEvent(QKeyEvent *e)
{
	if (m_currItem->selectedMeshPointX < 0)
		return;
	int kk = e->key();
	if (m_keyRepeat)
		return;
	m_keyRepeat = true;
	e->accept();

	if (e->key() == Qt::Key_Escape)
	{
		// Go back to normal mode.
		m_view->requestMode(modeNormal);
		return;
	}

	Qt::KeyboardModifiers buttonModifiers = e->modifiers();
	if ((!m_view->m_ScMW->zoomSpinBox->hasFocus()) && (!m_view->m_ScMW->pageSelector->hasFocus()))
	{
		if (m_doc->m_Selection->count() != 0)
		{
			double moveBy = 1.0;
			double moveX = 0.0;
			double moveY = 0.0;
			bool isMoving = false;
			bool doUpdate = false;
			if ((buttonModifiers & Qt::ShiftModifier) && !(buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
				moveBy=0.1;
			else if (!(buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
				moveBy=10.0;
			else if ((buttonModifiers & Qt::ShiftModifier) && (buttonModifiers & Qt::ControlModifier) && !(buttonModifiers & Qt::AltModifier))
				moveBy=0.01;
			moveBy /= m_doc->unitRatio();//Lets allow movement by the current doc ratio, not only points
			moveBy /= m_canvas->m_viewMode.scale;
			PageItem *currItem = m_doc->m_Selection->itemAt(0);
			switch (kk)
			{
				case Qt::Key_7:
					moveX = -moveBy;
					moveY = -moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_9:
					moveX = moveBy;
					moveY = -moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_3:
					moveX = moveBy;
					moveY = moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_1:
					moveX = -moveBy;
					moveY = moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_Left:
				case Qt::Key_4:
					moveX = -moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_Right:
				case Qt::Key_6:
					moveX = moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_Up:
				case Qt::Key_8:
					moveY = -moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_Down:
				case Qt::Key_2:
					moveY = moveBy;
					isMoving = true;
					doUpdate = true;
					break;
				case Qt::Key_5:
					if (m_view->editStrokeGradient == 8)
					{
						if (m_patchPoint == useTL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlColor = currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.gridPoint;
						if (m_patchPoint == useTR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlColor = currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.gridPoint;
						if (m_patchPoint == useBR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlColor = currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.gridPoint;
						if (m_patchPoint == useBL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlColor = currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.gridPoint;
						doUpdate = true;
					}
					else if (m_view->editStrokeGradient == 10)
					{
						if (m_patchPoint == useTL)
						{
							if (m_gradientPoint == useControlB)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlBottom = currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.gridPoint;
							else if (m_gradientPoint == useControlR)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlRight = currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.gridPoint;
						}
						else if (m_patchPoint == useTR)
						{
							if (m_gradientPoint == useControlB)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlBottom = currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.gridPoint;
							else if (m_gradientPoint == useControlL)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlLeft = currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.gridPoint;
						}
						else if (m_patchPoint == useBR)
						{
							if (m_gradientPoint == useControlT)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlTop = currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.gridPoint;
							else if (m_gradientPoint == useControlL)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlLeft = currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.gridPoint;
						}
						else if (m_patchPoint == useBL)
						{
							if (m_gradientPoint == useControlT)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlTop = currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.gridPoint;
							else if (m_gradientPoint == useControlR)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlRight = currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.gridPoint;
						}
						doUpdate = true;
					}
					break;
			}
			if (isMoving)
			{
				if (m_patchPoint != noPointDefined)
				{
					if (m_view->editStrokeGradient == 8)
					{
						if (m_patchPoint == useTL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlColor += FPoint(moveX, moveY);
						if (m_patchPoint == useTR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlColor += FPoint(moveX, moveY);
						if (m_patchPoint == useBR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlColor += FPoint(moveX, moveY);
						if (m_patchPoint == useBL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlColor += FPoint(moveX, moveY);
					}
					else if (m_view->editStrokeGradient == 9)
					{
						if (m_patchPoint == useTL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.moveRel(moveX, moveY);
						if (m_patchPoint == useTR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.moveRel(moveX, moveY);
						if (m_patchPoint == useBR)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.moveRel(moveX, moveY);
						if (m_patchPoint == useBL)
							currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.moveRel(moveX, moveY);
					}
					else if (m_view->editStrokeGradient == 10)
					{
						if (m_patchPoint == useTL)
						{
							if (m_gradientPoint == useControlB)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlBottom += FPoint(moveX, moveY);
							else if (m_gradientPoint == useControlR)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TL.controlRight += FPoint(moveX, moveY);
						}
						else if (m_patchPoint == useTR)
						{
							if (m_gradientPoint == useControlB)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlBottom += FPoint(moveX, moveY);
							else if (m_gradientPoint == useControlL)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].TR.controlLeft += FPoint(moveX, moveY);
						}
						else if (m_patchPoint == useBR)
						{
							if (m_gradientPoint == useControlT)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlTop += FPoint(moveX, moveY);
							else if (m_gradientPoint == useControlL)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BR.controlLeft += FPoint(moveX, moveY);
						}
						else if (m_patchPoint == useBL)
						{
							if (m_gradientPoint == useControlT)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlTop += FPoint(moveX, moveY);
							else if (m_gradientPoint == useControlR)
								currItem->meshGradientPatches[currItem->selectedMeshPointX].BL.controlRight += FPoint(moveX, moveY);
						}
					}
				}
			}
			if (doUpdate)
			{
				currItem->update();
				QTransform itemMatrix = currItem->getTransform();
				m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, currItem->width(), currItem->height())).adjusted(-currItem->width() / 2.0, -currItem->height() / 2.0, currItem->width(), currItem->height()));
			}
		}
	}
	m_keyRepeat = false;
}

void CanvasMode_EditMeshPatch::mouseDoubleClickEvent(QMouseEvent *m)
{
	m->accept();
	m_canvas->m_viewMode.m_MouseButtonPressed = false;
	m_canvas->resetRenderMode();
	if ((m_doc->m_Selection->isMultipleSelection()) || (m_doc->appMode != modeNormal))
	{
		if ((m_doc->m_Selection->isMultipleSelection()) && (m_doc->appMode == modeNormal))
		{
			if (GetItem(&m_currItem))
			{
				/* CB: old code, removing this as shift-alt select on an unselected table selects a cell now.
				//#6789 is closed by sorting this.
				if (currItem->isTableItem)
				{
					m_view->Deselect(false);
					m_doc->m_Selection->addItem(currItem);
					currItem->isSingleSel = true;
					//CB FIXME don't call this if the added item is item 0
					if (!m_doc->m_Selection->primarySelectionIs(currItem))
						currItem->emitAllToGUI();
					m_view->updateContents(currItem->getRedrawBounding(m_canvas->scale()));
				}*/
			}
			return;
		}
		if (!(GetItem(&m_currItem) && (m_doc->appMode == modeEdit) && m_currItem->isTextFrame()))
		{
			mousePressEvent(m);
			return;
		}
	}
}

void CanvasMode_EditMeshPatch::mouseMoveEvent(QMouseEvent *m)
{
	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());
	m->accept();
	FPoint npfN;
	double nx = mousePointDoc.x();
	double ny = mousePointDoc.y();
	if (!m_doc->ApplyGuides(&nx, &ny) && !m_doc->ApplyGuides(&nx, &ny,true))
		npfN = m_doc->ApplyGridF(FPoint(nx, ny));
	else
		npfN = FPoint(nx, ny);
	m_currItem = m_doc->m_Selection->itemAt(0);
	QTransform pp = m_currItem->getTransform();
	FPoint npf = npfN.transformPoint(pp, true);
	FPoint npx(m_Mxp - npfN.x(), m_Myp - npfN.y(), 0, 0, m_currItem->rotation(), 1, 1, true);
	if (m_view->editStrokeGradient == 11)
	{
		m_currentPoint = QPointF(npf.x(), npf.y());
		m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
		m_currItem->update();
		QRectF upRect;
		upRect = QRectF(QPointF(0, 0), QPointF(m_currItem->width(), m_currItem->height())).normalized();
		upRect.translate(m_currItem->xPos(), m_currItem->yPos());
		m_doc->regionsChanged()->update(upRect.adjusted(-10.0 - m_currItem->width() / 2.0, -10.0 - m_currItem->height() / 2.0, 10.0 + m_currItem->width() / 2.0, 10.0 + m_currItem->height() / 2.0));
	}
	if (m_canvas->m_viewMode.m_MouseButtonPressed && m_view->moveTimerElapsed())
	{
		if (m_currItem->selectedMeshPointX >= 0)
		{
			if (m_patchPoint != noPointDefined)
			{
				if (m_view->editStrokeGradient == 8)
				{
					FPoint cP;
					FPoint gP;
					if (m_patchPoint == useTL)
					{
						cP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.controlColor;
						gP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.gridPoint;
					}
					if (m_patchPoint == useTR)
					{
						cP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.controlColor;
						gP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.gridPoint;
					}
					if (m_patchPoint == useBR)
					{
						cP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.controlColor;
						gP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.gridPoint;
					}
					if (m_patchPoint == useBL)
					{
						cP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.controlColor;
						gP = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.gridPoint;
					}
					m_canvas->displayXYHUD(m->globalPos(), cP.x() - gP.x(), cP.y() - gP.y());
					if (m_patchPoint == useTL)
						m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.controlColor -= npx;
					if (m_patchPoint == useTR)
						m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.controlColor -= npx;
					if (m_patchPoint == useBR)
						m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.controlColor -= npx;
					if (m_patchPoint == useBL)
						m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.controlColor -= npx;
				}
				else if (m_view->editStrokeGradient == 9)
				{
					m_canvas->displayXYHUD(m->globalPos(), npf.x(), npf.y());
					if (m_view->editStrokeGradient == 9)
					{
						FPoint mp;
						FPoint mp_orig;
						double xx = 0.0;
						double yy = 0.0;
						if (m_patchPoint == useTL)
						{
							mp_orig = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.gridPoint;
							mp = mp_orig - npx;
							xx = mp.x();
							yy = mp.y();
							if (m_currItem->snapToPatchGrid)
								snapToOtherPatch(xx, yy);
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.moveAbs(xx, yy);
						}
						if (m_patchPoint == useTR)
						{
							mp_orig = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.gridPoint;
							mp = mp_orig - npx;
							xx = mp.x();
							yy = mp.y();
							if (m_currItem->snapToPatchGrid)
								snapToOtherPatch(xx, yy);
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.moveAbs(xx, yy);
						}
						if (m_patchPoint == useBR)
						{
							mp_orig = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.gridPoint;
							mp = mp_orig - npx;
							xx = mp.x();
							yy = mp.y();
							if (m_currItem->snapToPatchGrid)
								snapToOtherPatch(xx, yy);
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.moveAbs(xx, yy);
						}
						if (m_patchPoint == useBL)
						{
							mp_orig = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.gridPoint;
							mp = mp_orig - npx;
							xx = mp.x();
							yy = mp.y();
							if (m_currItem->snapToPatchGrid)
								snapToOtherPatch(xx, yy);
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.moveAbs(xx, yy);
						}
						if (m->modifiers() & Qt::ShiftModifier)
						{
							for (int col = 0; col < m_currItem->meshGradientPatches.count(); col++)
							{
								if (col != m_currItem->selectedMeshPointX)
								{
									if (m_currItem->meshGradientPatches[col].TL.gridPoint == mp_orig)
										m_currItem->meshGradientPatches[col].TL.moveAbs(xx, yy);
									if (m_currItem->meshGradientPatches[col].TR.gridPoint == mp_orig)
										m_currItem->meshGradientPatches[col].TR.moveAbs(xx, yy);
									if (m_currItem->meshGradientPatches[col].BR.gridPoint == mp_orig)
										m_currItem->meshGradientPatches[col].BR.moveAbs(xx, yy);
									if (m_currItem->meshGradientPatches[col].BL.gridPoint == mp_orig)
										m_currItem->meshGradientPatches[col].BL.moveAbs(xx, yy);
								}
							}
						}
					}
				}
				else if (m_view->editStrokeGradient == 10)
				{
					if (m_patchPoint == useTL)
					{
						if (m_gradientPoint == useControlB)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.controlBottom -= npx;
						else if (m_gradientPoint == useControlR)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL.controlRight -= npx;
					}
					else if (m_patchPoint == useTR)
					{
						if (m_gradientPoint == useControlB)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.controlBottom -= npx;
						else if (m_gradientPoint == useControlL)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR.controlLeft -= npx;
					}
					else if (m_patchPoint == useBR)
					{
						if (m_gradientPoint == useControlT)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.controlTop -= npx;
						else if (m_gradientPoint == useControlL)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR.controlLeft -= npx;
					}
					else if (m_patchPoint == useBL)
					{
						if (m_gradientPoint == useControlT)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.controlTop -= npx;
						else if (m_gradientPoint == useControlR)
							m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL.controlRight -= npx;
					}
				}
				m_currItem->update();
				QTransform itemMatrix = m_currItem->getTransform();
				m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, m_currItem->width(), m_currItem->height())).adjusted(-m_currItem->width() / 2.0, -m_currItem->height() / 2.0, m_currItem->width(), m_currItem->height()));
			}
		}
	}
	m_Mxp = npfN.x();
	m_Myp = npfN.y();
}

void CanvasMode_EditMeshPatch::mousePressEvent(QMouseEvent *m)
{
	const FPoint mousePointDoc = m_canvas->globalToCanvas(m->globalPos());

	m_canvas->PaintSizeRect(QRect());
	m_canvas->m_viewMode.m_MouseButtonPressed = true;
	m_canvas->m_viewMode.operItemMoving = false;
	m_view->HaveSelRect = false;
	m_doc->DragP = false;
	m_doc->leaveDrag = false;
	m->accept();
	m_view->registerMousePress(m->globalPos());
	m_Mxp = mousePointDoc.x(); //m->x();
	m_Myp = mousePointDoc.y(); //m->y();
	if (m->button() == Qt::MiddleButton)
	{
		m_view->MidButt = true;
		if (m->modifiers() & Qt::ControlModifier)
			m_view->DrawNew();
		return;
	}
	m_currItem = m_doc->m_Selection->itemAt(0);
	QTransform itemMatrix = m_currItem->getTransform();
	bool found = false;
	if (m_view->editStrokeGradient == 11)
	{
		m_gradientPoint = noControlPointDefined;
		m_patchPoint = noPointDefined;
		if (m_click_count == 0)
			m_clickPointPolygon.clear();
		m_currItem->selectedMeshPointX = -1;
		QTransform invItemMatrix = itemMatrix.inverted();
		QPointF clickPoint = invItemMatrix.map(QPointF(mousePointDoc.x(), mousePointDoc.y()));
		m_clickPointPolygon.append(clickPoint);
		m_click_count++;
		if (m_click_count > 3)
		{
			const ScColor& col = m_doc->PageColors["Black"];
			QColor qcol = ScColorEngine::getRGBColor(col, m_doc);
			MeshPoint mgP;
			meshGradientPatch patch;
			mgP.resetTo(FPoint(m_clickPointPolygon.value(0).x(), m_clickPointPolygon.value(0).y()));
			mgP.transparency = 1.0;
			mgP.shade = 100;
			mgP.colorName = "Black";
			mgP.color = qcol;
			patch.TL = mgP;
			mgP.resetTo(FPoint(m_clickPointPolygon.value(1).x(), m_clickPointPolygon.value(1).y()));
			patch.TR = mgP;
			mgP.resetTo(FPoint(m_clickPointPolygon.value(2).x(), m_clickPointPolygon.value(2).y()));
			patch.BR = mgP;
			mgP.resetTo(FPoint(m_clickPointPolygon.value(3).x(), m_clickPointPolygon.value(3).y()));
			patch.BL = mgP;
			m_currItem->meshGradientPatches.append(patch);
			m_currItem->selectedMeshPointX = m_currItem->meshGradientPatches.count() - 1;
			m_view->editStrokeGradient = 9;
			m_click_count = 0;
			m_clickPointPolygon.clear();
			m_ScMW->propertiesPalette->endPatchAdd();
		}
	}
	else
	{
		if (m_currItem->selectedMeshPointX >= 0)
		{
			if (m_view->editStrokeGradient == 8)
			{
				meshGradientPatch patch = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX];
				MeshPoint mp1 = patch.TL;
				MeshPoint mp2 = patch.TR;
				MeshPoint mp3 = patch.BR;
				MeshPoint mp4 = patch.BL;
				if ((m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp1.gridPoint.x(), mp1.gridPoint.y())))) || (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp1.controlColor.x(), mp1.controlColor.y())))))
				{
					m_patchPoint = useTL;
					*m_old_mesh = mp1;
				}
				else if ((m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp2.gridPoint.x(), mp2.gridPoint.y())))) || (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp2.controlColor.x(), mp2.controlColor.y())))))
				{
					*m_old_mesh = mp2;
					m_patchPoint = useTR;
				}
				else if ((m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp3.gridPoint.x(), mp3.gridPoint.y())))) || (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp3.controlColor.x(), mp3.controlColor.y())))))
				{
					*m_old_mesh = mp3;
					m_patchPoint = useBR;
				}
				else if ((m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp4.gridPoint.x(), mp4.gridPoint.y())))) || (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp4.controlColor.x(), mp4.controlColor.y())))))
				{
					*m_old_mesh = mp4;
					m_patchPoint = useBL;
				}
				else
					m_patchPoint = noPointDefined;
			}
			else if (m_view->editStrokeGradient == 9)
			{
				meshGradientPatch patch = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX];
				MeshPoint mp1 = patch.TL;
				MeshPoint mp2 = patch.TR;
				MeshPoint mp3 = patch.BR;
				MeshPoint mp4 = patch.BL;
				if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp1.gridPoint.x(), mp1.gridPoint.y()))))
				{
					*m_old_mesh = mp1;
					m_patchPoint = useTL;
				}
				else if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp2.gridPoint.x(), mp2.gridPoint.y()))))
				{
					*m_old_mesh = mp2;
					m_patchPoint = useTR;
				}
				else if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp3.gridPoint.x(), mp3.gridPoint.y()))))
				{
					*m_old_mesh = mp3;
					m_patchPoint = useBR;
				}
				else if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp4.gridPoint.x(), mp4.gridPoint.y()))))
				{
					*m_old_mesh = mp4;
					m_patchPoint = useBL;
				}
				else
					m_patchPoint = noPointDefined;
			}
			else if (m_view->editStrokeGradient == 10)
			{
				if (m_patchPoint != noPointDefined)
				{
					meshGradientPatch patch = m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX];
					MeshPoint mp1 = patch.TL;
					MeshPoint mp2 = patch.TR;
					MeshPoint mp3 = patch.BR;
					MeshPoint mp4 = patch.BL;
					if (m_patchPoint == useTL)
					{
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp1.controlBottom.x(), mp1.controlBottom.y()))))
							m_gradientPoint = useControlB;
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp1.controlRight.x(), mp1.controlRight.y()))))
							m_gradientPoint = useControlR;
					}
					else if (m_patchPoint == useTR)
					{
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp2.controlBottom.x(), mp2.controlBottom.y()))))
							m_gradientPoint = useControlB;
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp2.controlLeft.x(), mp2.controlLeft.y()))))
							m_gradientPoint = useControlL;
					}
					else if (m_patchPoint == useBR)
					{
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp3.controlTop.x(), mp3.controlTop.y()))))
							m_gradientPoint = useControlT;
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp3.controlLeft.x(), mp3.controlLeft.y()))))
							m_gradientPoint = useControlL;
					}
					else if (m_patchPoint == useBL)
					{
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp4.controlTop.x(), mp4.controlTop.y()))))
							m_gradientPoint = useControlT;
						if (m_canvas->hitsCanvasPoint(mousePointDoc, itemMatrix.map(QPointF(mp4.controlRight.x(), mp4.controlRight.y()))))
							m_gradientPoint = useControlR;
					}
					else
						m_gradientPoint = noControlPointDefined;
				}
			}
			if (m_patchPoint == noPointDefined)
			{
				for (int col = 0; col < m_currItem->meshGradientPatches.count(); col++)
				{
					meshGradientPatch patch = m_currItem->meshGradientPatches[col];
					MeshPoint mp1 = patch.TL;
					MeshPoint mp2 = patch.TR;
					MeshPoint mp3 = patch.BR;
					MeshPoint mp4 = patch.BL;
					QPainterPath Bez;
					Bez.moveTo(mp1.gridPoint.x(), mp1.gridPoint.y());
					Bez.cubicTo(mp1.controlRight.x(), mp1.controlRight.y(), mp2.controlLeft.x(), mp2.controlLeft.y(), mp2.gridPoint.x(), mp2.gridPoint.y());
					Bez.cubicTo(mp2.controlBottom.x(), mp2.controlBottom.y(), mp3.controlTop.x(), mp3.controlTop.y(), mp3.gridPoint.x(), mp3.gridPoint.y());
					Bez.cubicTo(mp3.controlLeft.x(), mp3.controlLeft.y(), mp4.controlRight.x(), mp4.controlRight.y(), mp4.gridPoint.x(), mp4.gridPoint.y());
					Bez.cubicTo(mp4.controlTop.x(), mp4.controlTop.y(), mp1.controlBottom.x(), mp1.controlBottom.y(), mp1.gridPoint.x(), mp1.gridPoint.y());
					QPainterPath pat = itemMatrix.map(Bez);
					if (pat.contains(QPointF(mousePointDoc.x(), mousePointDoc.y())))
					{
						m_currItem->selectedMeshPointX = col;
						found = true;
						break;
					}
				}
				m_gradientPoint = noControlPointDefined;
				if (!found)
					m_currItem->selectedMeshPointX = -1;
			}
		}
		else
		{
			for (int col = 0; col < m_currItem->meshGradientPatches.count(); col++)
			{
				meshGradientPatch patch = m_currItem->meshGradientPatches[col];
				MeshPoint mp1 = patch.TL;
				MeshPoint mp2 = patch.TR;
				MeshPoint mp3 = patch.BR;
				MeshPoint mp4 = patch.BL;
				QPainterPath Bez;
				Bez.moveTo(mp1.gridPoint.x(), mp1.gridPoint.y());
				Bez.cubicTo(mp1.controlRight.x(), mp1.controlRight.y(), mp2.controlLeft.x(), mp2.controlLeft.y(), mp2.gridPoint.x(), mp2.gridPoint.y());
				Bez.cubicTo(mp2.controlBottom.x(), mp2.controlBottom.y(), mp3.controlTop.x(), mp3.controlTop.y(), mp3.gridPoint.x(), mp3.gridPoint.y());
				Bez.cubicTo(mp3.controlLeft.x(), mp3.controlLeft.y(), mp4.controlRight.x(), mp4.controlRight.y(), mp4.gridPoint.x(), mp4.gridPoint.y());
				Bez.cubicTo(mp4.controlTop.x(), mp4.controlTop.y(), mp1.controlBottom.x(), mp1.controlBottom.y(), mp1.gridPoint.x(), mp1.gridPoint.y());
				QPainterPath pat = itemMatrix.map(Bez);
				if (pat.contains(QPointF(mousePointDoc.x(), mousePointDoc.y())))
				{
					m_currItem->selectedMeshPointX = col;
					found = true;
					break;
				}
			}
			m_patchPoint = noPointDefined;
			m_gradientPoint = noControlPointDefined;
			if (!found)
				m_currItem->selectedMeshPointX = -1;
		}
		m_currItem->selectedMeshPointY = m_patchPoint;
		m_currItem->selectedMeshControlPoint = m_gradientPoint;
	}
	m_canvas->m_viewMode.m_MouseButtonPressed = true;
	m_ScMW->propertiesPalette->updateColorSpecialGradient();
	m_view->setCursor(QCursor(Qt::CrossCursor));
	m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, m_currItem->width(), m_currItem->height())).adjusted(-m_currItem->width() / 2.0, -m_currItem->height() / 2.0, m_currItem->width(), m_currItem->height()));

}

void CanvasMode_EditMeshPatch::mouseReleaseEvent(QMouseEvent *m)
{
	m_canvas->m_viewMode.m_MouseButtonPressed = false;
	m_canvas->resetRenderMode();
	m->accept();
	if (m_view->editStrokeGradient != 11 && m_currItem->selectedMeshPointX >=0 && m_patchPoint != noPointDefined && UndoManager::undoEnabled())
	{
		auto *ss = new ScOldNewState<MeshPoint>(Um::GradPos);
		ss->set("MOVE_MESH_PATCH");
		ss->set("X", m_currItem->selectedMeshPointX);
		ss->set("Y", m_currItem->selectedMeshPointY);
		ss->set("ARRAY", false);
		switch (m_currItem->selectedMeshPointY){
			case 1:
				if ((*m_old_mesh) == m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL)
				{
					delete ss;
					ss = nullptr;
				}
				else
					ss->setStates(*m_old_mesh, m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TL);
				break;
			case 2:
				if ((*m_old_mesh) == m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR)
				{
					delete ss;
					ss = nullptr;
				}
				else
					ss->setStates(*m_old_mesh, m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].TR);
				break;
			case 3:
				if ((*m_old_mesh) == m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR)
				{
					delete ss;
					ss = nullptr;
				}
				else
					ss->setStates(*m_old_mesh, m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BR);
				break;
			case 4:
				if ((*m_old_mesh) == m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL)
				{
					delete ss;
					ss = nullptr;
				}
				else
					ss->setStates(*m_old_mesh,m_currItem->meshGradientPatches[m_currItem->selectedMeshPointX].BL);
				break;
		}
		if (ss)
			undoManager->action(m_currItem, ss);
	}
	m_currItem = m_doc->m_Selection->itemAt(0);
	m_currItem->update();
	QTransform itemMatrix = m_currItem->getTransform();
	m_doc->regionsChanged()->update(itemMatrix.mapRect(QRectF(0, 0, m_currItem->width(), m_currItem->height())).adjusted(-m_currItem->width() / 2.0, -m_currItem->height() / 2.0, m_currItem->width(), m_currItem->height()));
}

void CanvasMode_EditMeshPatch::snapToOtherPatch(double &x, double &y)
{
	int radius = m_doc->guidesPrefs().grabRadius;
	for (int col = 0; col < m_currItem->meshGradientPatches.count(); col++)
	{
		if (col != m_currItem->selectedMeshPointX)
		{
			meshGradientPatch patch = m_currItem->meshGradientPatches[col];
			QPointF mp1(patch.TL.gridPoint.x(), patch.TL.gridPoint.y());
			QPointF mp2(patch.TR.gridPoint.x(), patch.TR.gridPoint.y());
			QPointF mp3(patch.BR.gridPoint.x(), patch.BR.gridPoint.y());
			QPointF mp4(patch.BL.gridPoint.x(), patch.BL.gridPoint.y());
			if (qAbs(mp1.x() - x) < radius && qAbs(mp1.y() - y) < radius)
			{
				x = mp1.x();
				y = mp1.y();
				return;
			}
			if (qAbs(mp2.x() - x) < radius && qAbs(mp2.y() - y) < radius)
			{
				x = mp2.x();
				y = mp2.y();
				return;
			}
			if (qAbs(mp3.x() - x) < radius && qAbs(mp3.y() - y) < radius)
			{
				x = mp3.x();
				y = mp3.y();
				return;
			}
			if (qAbs(mp4.x() - x) < radius && qAbs(mp4.y() - y) < radius)
			{
				x = mp4.x();
				y = mp4.y();
				return;
			}
		}
	}
}
