Image
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************

ScriptName = "MR_CurveTool"

-- **************************************************
-- General information about this script
-- **************************************************

MR_CurveTool = {}

function MR_CurveTool:Name()
	return self:Localize('UILabel')
end

function MR_CurveTool:Version()
	return '4.1.3'
end

function MR_CurveTool:UILabel()
	return self:Localize('UILabel')
end

function MR_CurveTool:Creator()
	return 'Eugene Babich, Alexandra Evseeva, Dauid'
end

function MR_CurveTool:Description()
	return self:Localize('Description')
end

-- **************************************************
-- Is Relevant / Is Enabled
-- **************************************************

function MR_CurveTool:IsRelevant(moho)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return false
	end
	
	local v1, v2, v3 = MR_Utilities:GetMohoVersion(moho)
	self.mohoVersion = v1
	self.isMoho13_5_3 = true
	if not v3 then
		v3 = 0
	end
	if v1 < 13 then
		self.isMoho13_5_3 = false
	elseif v1 == 13 then
		if v2 < 5 then
			self.isMoho13_5_3 = false
		elseif v3 < 3 then	
			self.isMoho13_5_3 = false
		end
	end

	self.selectedPointID = -1
	self.startCurvePointID = -1
	self.drawingStatus = false
	self.drawWeldPoint = false
	self.startPoint = 1000000
	self.step = 0
	return true
end

function MR_CurveTool:IsEnabled(moho)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return false
	end
	
	local v1, v2, v3 = MR_Utilities:GetMohoVersion(moho)
	self.mohoVersion = v1
	self.isMoho13_5_2 = true
	if not v3 then
		v3 = 0
	end
	if v1 < 13 then
		self.isMoho13_5_2 = false
	elseif v2 < 5 then
		self.isMoho13_5_2 = false
	elseif v3 < 3 then	
		self.isMoho13_5_2 = false
	end
	
	if self.isMoho13_5_2 then
		if (mesh:ContinuousTriangulation()) then
			return false
		end
	end	
	
	self.selectedPoints = moho:CountSelectedPoints()
	
	if moho:CurrentTool() ~= 'MR_CurveTool' then
		self.selectedPointID = -1
		self.startCurvePointID = -1
		self.drawingStatus = false
		self.drawWeldPoint = false
		self.startPoint = 1000000
		self.step = 0
	end
	return true
end

-- **************************************************
-- Recurring Values
-- **************************************************

MR_CurveTool.drawInZeroFrame = true
MR_CurveTool.drawInNonZeroFrame = true
MR_CurveTool.alwaysDrawOnFBF = true
MR_CurveTool.showAllHandles = false
MR_CurveTool.enableSkewTransformation = true
MR_CurveTool.enableDistortTransformation = true
MR_CurveTool.clickToSelect = true
MR_CurveTool.drawBehind = false
MR_CurveTool.usePeakForCorners = false

MR_CurveTool.curvatureSC = 0.33
MR_CurveTool.points = 1
MR_CurveTool.step = 0

MR_CurveTool.singleCurveMode = false
MR_CurveTool.drawingStatus = false
MR_CurveTool.showHandles = true
MR_CurveTool.fixedHandles = true
MR_CurveTool.useBezierHandles = true
MR_CurveTool.threshold = 0.05
MR_CurveTool.autoWeld = true
MR_CurveTool.autoWeldRadius = 144
MR_CurveTool.sharpCorners = false
MR_CurveTool.autoFill = true
MR_CurveTool.autoStroke = true
MR_CurveTool.selectedPointID = -1
MR_CurveTool.curvePointID = -1
MR_CurveTool.lastSelectedPointID = -1
MR_CurveTool.curvature = 0.33
MR_CurveTool.lastClickVec = LM.Vector2:new_local()
MR_CurveTool.closest = 100000
MR_CurveTool.closestID = -1
MR_CurveTool.endWeldVec = LM.Vector2:new_local()
MR_CurveTool.endWeldVec:Set(-10000000, -10000000)
MR_CurveTool.endWeldToPoint = true
MR_CurveTool.drawWeldPoint = false
MR_CurveTool.startPoint = -1
MR_CurveTool.startPointClick = false
MR_CurveTool.isBackspace = false
MR_CurveTool.needCreateNewPoint = false
MR_CurveTool.isMousePressed = false
MR_CurveTool.lastPointID = -1
MR_CurveTool.isBezierChanged = false
MR_CurveTool.applyPeakedCorner = false
MR_CurveTool.isLastPointBezierMode = false
MR_CurveTool.isStartPoint = false
MR_CurveTool.continueEndPoint = false
MR_CurveTool.handlePt = LM.Vector2:new_local()
MR_CurveTool.handlePt2 = LM.Vector2:new_local()
MR_CurveTool.midPt = LM.Vector2:new_local()
MR_CurveTool.startCurvePointID = -1
MR_CurveTool.targetPointID = -1
MR_CurveTool.statusMode = 0 -- 1 close curve
MR_CurveTool.peakedCornerDef = 0.0001
MR_CurveTool.peakedCorner = 0.0001
MR_CurveTool.needCreateShape = false
MR_CurveTool.curveForCreateShape = nil
MR_CurveTool.curveIDForMove = 0
MR_CurveTool.fillColorR = 255
MR_CurveTool.fillColorG = 255
MR_CurveTool.fillColorB = 255
MR_CurveTool.fillColorA = 255
MR_CurveTool.strokeColorR = 0
MR_CurveTool.strokeColorG = 0
MR_CurveTool.strokeColorB = 0
MR_CurveTool.strokeColorA = 255
MR_CurveTool.strokeWidth = 1
MR_CurveTool.isMouseDragging = false
MR_CurveTool.selRect = LM.Rect:new_local()
MR_CurveTool.movePoints = true
MR_CurveTool.dragPoint = false
MR_CurveTool.prewVec = LM.Vector2:new_local()
MR_CurveTool.prewVec:Set(-10000, -10000)
MR_CurveTool.isFirstClick = false
MR_CurveTool.isCurveEnded = false
MR_CurveTool.selectedPoints = 0
MR_CurveTool.lastVec = LM.Vector2:new_local()
MR_CurveTool.pivotOffset = LM.Vector2:new_local()
MR_CurveTool.centerVec = LM.Vector2:new_local()
MR_CurveTool.markerR = 8
MR_CurveTool.dragging = false
MR_CurveTool.createdMidPoint = false
MR_CurveTool.pointPoseChanged = false
MR_CurveTool.isFBF = false
MR_CurveTool.clickOffset = LM.Vector2:new_local()
MR_CurveTool.clickPos = LM.Vector2:new_local()
MR_CurveTool.mohoVersion = 0
MR_CurveTool.reset = false

-- **************************************************
-- Prefs
-- **************************************************

function MR_CurveTool:LoadPrefs(prefs)
	self.drawInZeroFrame = prefs:GetBool("MR_CurveTool.drawInZeroFrame", true)
	self.drawInNonZeroFrame = prefs:GetBool("MR_CurveTool.drawInNonZeroFrame", true)
	self.alwaysDrawOnFBF = prefs:GetBool("MR_CurveTool.alwaysDrawOnFBF", true)
	self.showAllHandles = prefs:GetBool("MR_CurveTool.showAllHandles", false)
	self.enableSkewTransformation = prefs:GetBool("MR_CurveTool.enableSkewTransformation", true)
	self.enableDistortTransformation = prefs:GetBool("MR_CurveTool.enableDistortTransformation", true)
	self.clickToSelect = prefs:GetBool("MR_CurveTool.clickToSelect", true)
	self.drawBehind = prefs:GetBool("MR_CurveTool.drawBehind", false)
	self.usePeakForCorners = prefs:GetBool("MR_CurveTool.usePeakForCorners", false)
	
	self.curvatureSC = prefs:GetFloat("MR_CurveTool.curvatureSC", 0.33)
	self.points = prefs:GetInt("MR_CurveTool.points", 1)
	
	self.singleCurveMode = prefs:GetBool("MR_CurveTool.singleCurveMode", false)
	self.curvature = prefs:GetFloat("MR_CurveTool.curvature", 0.33)
	self.showHandles = prefs:GetBool("MR_CurveTool.showHandles", true)
	self.fixedHandles = prefs:GetBool("MR_CurveTool.fixedHandles", true)
	self.useBezierHandles = prefs:GetBool("MR_CurveTool.useBezierHandles", true)
	self.threshold = prefs:GetFloat("MR_CurveTool.threshold", 0.05)
	self.autoWeld = prefs:GetBool("MR_CurveTool.autoWeld", true)
	self.sharpCorners = prefs:GetBool("MR_CurveTool.sharpCorners", false)
	self.autoFill = prefs:GetBool("MR_CurveTool.autoFill", true)
	self.autoStroke = prefs:GetBool("MR_CurveTool.autoStroke", true)
	self.fillColorR = prefs:GetInt("MR_CurveTool.fillColorR", 255)
	self.fillColorG = prefs:GetInt("MR_CurveTool.fillColorG", 255)
	self.fillColorB = prefs:GetInt("MR_CurveTool.fillColorB", 255)
	self.fillColorA = prefs:GetInt("MR_CurveTool.fillColorA", 255)
	self.strokeColorR = prefs:GetInt("MR_CurveTool.strokeColorR", 0)
	self.strokeColorG = prefs:GetInt("MR_CurveTool.strokeColorG", 0)
	self.strokeColorB = prefs:GetInt("MR_CurveTool.strokeColorB", 0)
	self.strokeColorA = prefs:GetInt("MR_CurveTool.strokeColorA", 255)
	self.strokeWidth = prefs:GetFloat("MR_CurveTool.strokeWidth", 1)
end

function MR_CurveTool:SavePrefs(prefs)
	prefs:SetBool("MR_CurveTool.drawInZeroFrame", self.drawInZeroFrame)
	prefs:SetBool("MR_CurveTool.drawInNonZeroFrame", self.drawInNonZeroFrame)
	prefs:SetBool("MR_CurveTool.alwaysDrawOnFBF", self.alwaysDrawOnFBF)
	prefs:SetBool("MR_CurveTool.showAllHandles", self.showAllHandles)
	prefs:SetBool("MR_CurveTool.enableSkewTransformation", self.enableSkewTransformation)
	prefs:SetBool("MR_CurveTool.enableDistortTransformation", self.enableDistortTransformation)
	prefs:SetBool("MR_CurveTool.clickToSelect", self.clickToSelect)
	prefs:SetBool("MR_CurveTool.drawBehind", self.drawBehind)
	prefs:SetBool("MR_CurveTool.usePeakForCorners", self.usePeakForCorners)
	
	prefs:SetFloat("MR_CurveTool.curvatureSC", self.curvatureSC)
	prefs:SetInt("MR_CurveTool.points", self.points)
	
	prefs:SetBool("MR_CurveTool.singleCurveMode", self.singleCurveMode)
	prefs:SetFloat("MR_CurveTool.curvature", self.curvature)
	prefs:SetBool("MR_CurveTool.showHandles", self.showHandles)
	prefs:SetBool("MR_CurveTool.fixedHandles", self.fixedHandles)
	prefs:SetBool("MR_CurveTool.useBezierHandles", self.useBezierHandles)
	prefs:SetFloat("MR_CurveTool.threshold", self.threshold)
	prefs:SetBool("MR_CurveTool.autoWeld", self.autoWeld)
	prefs:SetBool("MR_CurveTool.sharpCorners", self.sharpCorners)
	prefs:SetBool("MR_CurveTool.autoFill", self.autoFill)
	prefs:SetBool("MR_CurveTool.autoStroke", self.autoStroke)
	prefs:SetInt("MR_CurveTool.fillColorR", self.fillColorR)
	prefs:SetInt("MR_CurveTool.fillColorG", self.fillColorG)
	prefs:SetInt("MR_CurveTool.fillColorB", self.fillColorB)
	prefs:SetInt("MR_CurveTool.fillColorA", self.fillColorA)
	prefs:SetInt("MR_CurveTool.strokeColorR", self.strokeColorR)
	prefs:SetInt("MR_CurveTool.strokeColorG", self.strokeColorG)
	prefs:SetInt("MR_CurveTool.strokeColorB", self.strokeColorB)
	prefs:SetInt("MR_CurveTool.strokeColorA", self.strokeColorA)
	prefs:SetFloat("MR_CurveTool.strokeWidth", self.strokeWidth)
end

function MR_CurveTool:ResetPrefs()
	self.drawInZeroFrame = true
	self.drawInNonZeroFrame = true
	self.alwaysDrawOnFBF = true
	self.showAllHandles = false
	self.enableSkewTransformation = true
	self.enableDistortTransformation = true
	self.clickToSelect = true
	self.drawBehind = false
	self.usePeakForCorners = false
	
	self.curvatureSC = 0.33
	self.points = 1
	
	self.singleCurveMode = false
	self.curvature = 0.33
	self.showHandles = true
	self.fixedHandles = true
	self.useBezierHandles = true
	self.threshold = 0.05
	self.autoWeld = true
	self.sharpCorners = false
	self.autoFill = true
	self.autoStroke = true
	self.fillColorR = 255
	self.fillColorG = 255
	self.fillColorB = 255
	self.fillColorA = 255
	self.strokeColorR = 0
	self.strokeColorG = 0
	self.strokeColorB = 0
	self.strokeColorA = 255
	self.strokeWidth = 1
	self.reset = true
end

-- **************************************************
-- Keyboard/Mouse Control
-- **************************************************

function MR_CurveTool:NonDragMouseMove()
	return true
end

function MR_CurveTool:OnMouseDown(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	if self.isBezierChanged and self.isMousePressed then
		self:CloseCurve(moho)
		self.isMousePressed = false
		self.isBezierChanged = false
		return
	end
	
	if self.usePeakForCorners then
		self.peakedCorner = 0
	else
		self.peakedCorner = self.peakedCornerDef
	end
	
	local doubleClick = mouseEvent.doubleClick
	self.isFBF = false
	if moho.layer:LayerType() == MOHO.LT_SWITCH then
		if moho:LayerAsSwitch(moho.layer):IsFBFLayer() then
			self.isFBF = true
		end	
	end

	local closestID = -1
	local closest = 1e6

	local selectedPoint
	self.doNotAddNewPoint = false
	local clickVec = LM.Vector2:new_local()
	clickVec:Set(mouseEvent.drawingVec)
	local testVec1 = LM.Vector2:new_local()
	testVec1:Set(mouseEvent.drawingVec)
	closestID = mesh:ClosestPoint(testVec1)
	
	if closestID >= 0 then
		local testVec2 = LM.Vector2:new_local()
		testVec2:Set(mesh:Point(closestID).fPos)
		closest = self:GetColosestVec(moho, mouseEvent.view, testVec1,testVec2)
	end

	self.selectedPoints = moho:CountSelectedPoints()
	self.isMouseDragging = false
	if ((mouseEvent.shiftKey and mouseEvent.altKey) or (mouseEvent.ctrlKey and mouseEvent.altKey) or (mouseEvent.shiftKey and mouseEvent.ctrlKey) and not self.drawingStatus) 
	or (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey) or 
	(not self.drawInZeroFrame and moho.frame == 0 and self.selectedPoints == 0) then
		self.isMouseDragging = true
		if not ((mouseEvent.shiftKey and mouseEvent.ctrlKey) or (not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey) or ((self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey))) then
			mesh:SelectNone()
		end

		self.selRect.left = mouseEvent.startPt.x
		self.selRect.top = mouseEvent.startPt.y
		self.selRect.right = mouseEvent.pt.x
		self.selRect.bottom = mouseEvent.pt.y
		mouseEvent.view:Graphics():SelectionRect(self.selRect)
		mouseEvent.view:DrawMe()
		return
	else
		local isDrawingEnabled = true
		if not self.drawInZeroFrame and moho.frame == 0 or not self.drawInNonZeroFrame and moho.frame ~= 0 then
			isDrawingEnabled = false
		end
		
		if self.isFBF and self.alwaysDrawOnFBF then
			isDrawingEnabled = true
		end
	
		if not isDrawingEnabled then
			self.handleSide = 0
			if self.selectedPoints == 1 then
				self:TestForClosestHandle(moho, mouseEvent)
			end
			if not (not self.drawingStatus and closestID >= 0 and closest < self.autoWeldRadius * 1.5) and self.selectedPoints <= 1 and self.handleSide == 0 then
				self.isMouseDragging = true
				self.selRect.left = mouseEvent.startPt.x
				self.selRect.top = mouseEvent.startPt.y
				self.selRect.right = mouseEvent.pt.x
				self.selRect.bottom = mouseEvent.pt.y
				mouseEvent.view:Graphics():SelectionRect(self.selRect)
				mouseEvent.view:DrawMe()
				return
			end	
		end
	end
	
	if moho.layerFrame > 0 then
		self:ClearPointKeys(moho, self.selectedPointID)
		self:ClearPointKeys(moho, self.lastSelectedPointID)
	end	
	if not (self.step == 1 or self.step == 2) then
		moho.document:PrepUndo(moho.drawingLayer)
		moho.document:SetDirty()
	end
	
	mesh:PrepMovePoints()
	local totalPoints = mesh:CountPoints()
	if self.fixedHandles then
		mesh:PrepFixedHandles(moho.layerFrame)
		self:FixHandles(moho, mesh)
	end

	if self.drawingStatus and self.selectedPoints == 1 then
		if self.selectedPointID >= 0 and self.selectedPointID < totalPoints then
			local point = mesh:Point(self.selectedPointID)
			point.fSelected = true
		end
	end

	self.curveID = -1
	self.curveIDForMove = -1
	self.selectedCurvePointID = -1
	self.curvePointID = -1
	self.needCreateNewPoint = false
	self.lastPointID = -1
	self.isBezierChanged = false
	self.applyPeakedCorner = false
	self.isStartPoint = false
	self.continueEndPoint = false
	self.startCurvePointID = -1
	self.targetPointID = -1
	self.statusMode = 0
	self.needCreateShape = false
	self.dragPoint = false
	self.curveForCreateShape = nil
	self.isFirstClick = false
	self.isCurveEnded = false
	self.createdMidPoint = false
	self.prewVec:Set(mouseEvent.drawingVec)
	self.handleSide = 0
	self.clickOffset:Set(0, 0)
	self.pointPoseChanged = false
	self.transformation = false
	self.outside = false
	
	local clickToSelect = self.clickToSelect
	
	if not self.drawInNonZeroFrame and moho.frame ~= 0 and not self.isFBF then
		clickToSelect = true
	end

	if (clickToSelect and not doubleClick and not self.drawingStatus and closestID >= 0 and closest < self.autoWeldRadius * 1.5 and self.selectedPoints == 0 ) then
		if closestID >= 0 then
			mesh:Point(closestID).fSelected = true
			self.selectedPoints = 1
			self.drawingStatus = false
			self.drawWeldPoint = false
			self.selectedPointID = -1
			self.startPoint = -1
			self.curveID = -1
			self.curveIDForMove = -1
			self.selectedCurvePointID = -1
			self.curvePointID = -1
			self.needCreateNewPoint = false
			self.lastPointID = -1
			self.isBezierChanged = false
			self.applyPeakedCorner = false
			self.isStartPoint = false
			self.continueEndPoint = false
			self.startCurvePointID = -1
			self.targetPointID = -1
			self.statusMode = 0
			self.needCreateShape = false
			self.dragPoint = false
			self.curveForCreateShape = nil
			self.isFirstClick = false
			self.isCurveEnded = false
			self.createdMidPoint = false
			self.prewVec:Set(mouseEvent.drawingVec)
			self.handleSide = 0
			self.clickOffset:Set(0, 0)
			self.pointPoseChanged = false
		end
	end
	
	if (clickToSelect and not doubleClick and not self.drawingStatus) or not clickToSelect then
		if self.selectedPoints == 1 and not self.drawingStatus then
			self:TestForClosestHandle(moho, mouseEvent)
			self:DrawMe(moho, mouseEvent.view)
			if self.handleSide ~= 0 then
				self.dragPoint = true
				self.drawingStatus = true
				self.savedVal = 0
				self.selectedPointID = self.selID

				local pt = mesh:Point(self.selectedPointID)
				local handlePt = self.startHandle + (mouseEvent.vec - mouseEvent.startVec)
				if (moho.gridOn) then
					moho:SnapToGrid(handlePt)
				end
				local curve = mesh:Curve(self.handleCurveID)
				local oldWeight = curve:GetWeight(self.handlePointID, moho.layerFrame, (self.handleSide == -1))
				local newVector = handlePt - self.startFPos
				local weightMultiply = newVector:Mag()/self.startVectorMag
				local newWeight = newVector:Mag()/self.weightMultiplier - self.weightDelta
				self.weightStartDelta = newWeight - oldWeight
				self.flipDirection = self:CheckFlipDirection(moho, pt)
				moho.drawingLayer:UpdateCurFrame()
				return
			else
				if closest < self.autoWeldRadius * 1.5 then
					local point
					local pointID
					for i=0, mesh:CountPoints()-1 do
						point = mesh:Point(i)
						if point.fSelected then
							pointID = i
							break
						end	
					end
					if closestID == pointID then
						mesh:PrepFixedHandles(moho.layerFrame)
						self.selectedPointID = pointID
						point.fTempPos:Set(point.fPos)
						self.clickOffset:Set(point.fPos - mouseEvent.drawingVec)
						self.dragPoint = true
						self.doNotAddNewPoint = true
						self.drawingStatus = true
						self.drawWeldPoint = false
						mesh:PrepMovePoints()
						if self.fixedHandles then
							mesh:PrepFixedHandles(moho.layerFrame)
							self:FixHandles(moho, mesh)
							self:MakeFlipDirectionList(moho)
						end
						moho.drawingLayer:UpdateCurFrame()
						self:PopulateSelList(moho, mesh)
						mouseEvent.view:DrawMe()
						return
					else
						mesh:SelectNone()
						return
					end
				else	
					mesh:SelectNone()
					return
				end	
			end
		elseif self.selectedPoints > 1 then
			self.dragging = true
			self.endWeldVec:Set(-10000000, -10000000)
			self.centerVec = mesh:SelectedCenter()
			self.centerVec = self.centerVec + self.pivotOffset
			self.startPivotOffset = LM.Vector2:new_local()
			self.startPivotOffset:Set(self.pivotOffset)
			self.mode, self.outside = self:TestMousePoint(moho, mouseEvent)
			self.selectedMin = LM.Vector2:new_local()
			self.selectedMax = LM.Vector2:new_local()
			mesh:SelectedBounds(self.selectedMin, self.selectedMax)
			moho.document:SetDirty()
			self.numSel = self.selectedPoints
			
			if doubleClick and self.mode ~= 11 then -- pivot point
				mesh:SelectNone()
				self.dragging = false
				return
			end
			
			if (self.mode == 0) then -- translate
			elseif (self.mode == 1) then -- rotate
				self.startAngle = 0
				self.lastVec:Set(mouseEvent.drawingVec)
			elseif (self.mode == 11) then -- pivot point
				if mouseEvent.doubleClick then
					self.centerVec:Set(mesh:SelectedCenter())
					self.pivotOffset:Set(0, 0)
				end
			elseif (self.mode >= 24 and self.mode <= 27) then -- distord
				self.handle = 'none'
				self.bottomLeft = LM.Vector2:new_local()
				self.topLeft = LM.Vector2:new_local()
				self.bottomRight = LM.Vector2:new_local()
				self.topRight = LM.Vector2:new_local()

				self.horizonPercent = {}
				self.vertPercent = {}
				self.ptlist = {}

				self.minVec = LM.Vector2:new_local()	
				self.maxVec = LM.Vector2:new_local()

				mesh:SelectedBounds(self.minVec, self.maxVec)
				self.clickPos:Set(mouseEvent.drawingStartVec)
				
				self.bottomLeft.x = self.minVec.x
				self.bottomLeft.y = self.minVec.y
					
				self.topLeft.x = self.minVec.x
				self.topLeft.y = self.maxVec.y
					
				self.bottomRight.x = self.maxVec.x
				self.bottomRight.y = self.minVec.y
					
				self.topRight.x = self.maxVec.x
				self.topRight.y = self.maxVec.y
				
				for i = 0, mesh:CountPoints() - 1 do
					local pt = mesh:Point(i)
					if pt.fSelected then
						self.ptlist[i + 1] = pt
						local maxXdistance = self.topRight.x - self.topLeft.x
						local Xdistance = pt.fPos.x - self.topLeft.x
						self.horizonPercent[i + 1] = Xdistance/maxXdistance
						
						local maxYdistance = self.bottomLeft.y - self.topLeft.y
						local Ydistance = pt.fPos.y - self.topLeft.y
						self.vertPercent[i + 1] = Ydistance/maxYdistance
					end
				end
				
				local maxXdistance = self.topRight.x - self.topLeft.x
				local Xdistance = self.centerVec.x - self.topLeft.x
				self.horizonPercentCenter = Xdistance / maxXdistance
				
				local maxYdistance = self.bottomLeft.y - self.topLeft.y
				local Ydistance = self.centerVec.y - self.topLeft.y
				self.vertPercentCenter = Ydistance / maxYdistance
			elseif (self.mode >= 20 and self.mode <= 23) then -- skew
				self.selList = {}
				for i = 0, mesh:CountPoints() - 1 do
					local point = mesh:Point(i)
					if point.fSelected then
						self.selList[i + 1] = point
					end
				end
				self.minVec = LM.Vector2:new_local()	
				self.maxVec = LM.Vector2:new_local()
				mesh:SelectedBounds(self.minVec, self.maxVec)
			elseif (self.mode >= 2 and self.mode <= 9) then -- scale
				self.lastScaleX = 1.0
				self.lastScaleY = 1.0
				self.minVec = LM.Vector2:new_local()	
				self.maxVec = LM.Vector2:new_local()
				mesh:SelectedBounds(self.minVec, self.maxVec)
			end

			if self.fixedHandles then
				self:MakeFlipDirectionList(moho)
				mesh:PrepFixedHandles(moho.layerFrame)
			end
			mesh:PrepMovePoints()
			
			self:PopulateSelList(moho, mesh)
			self:AddPointKeyframe(moho, moho.layerFrame, moho.drawingLayer)
			mouseEvent.view:DrawMe()
			return
		end	
	end	
	
	if doubleClick and self.selectedPoints > 1 then
		self.mode = self:TestMousePoint(moho, mouseEvent)
		if (self.mode == 11) then -- pivot point
			if mouseEvent.doubleClick then
				self.centerVec:Set(mesh:SelectedCenter())
				self.pivotOffset:Set(0, 0)
				return
			end
		else
			mesh:SelectNone()
			self.dragging = false
			return
		end	
	end

	if not self.drawInZeroFrame and moho.frame == 0 and not (self.isFBF and self.alwaysDrawOnFBF) then
		return
	end
	
	if not self.drawInNonZeroFrame and moho.frame ~= 0 and not (self.isFBF and self.alwaysDrawOnFBF) then
		return
	end

	if moho.drawingLayer:CurrentAction() ~= "" then
		return
	end
	
	if self.singleCurveMode then
		if self.step == 0 then
			self.isWelded = false
			self.step = 1
			self.drawingStatus = true
			self.isMousePressed = true
		elseif self.step == 1 then
			self.step = 2
		end
		self.selectedPoints = 0
		mesh:PrepFixedHandles(moho.layerFrame)
		mesh:SelectNone()
		if self.step == 1 then
			self.isNewCurve = false 
			local closestID = -1
			local closest = 1e6
			
			local clickVec = LM.Vector2:new_local()
			clickVec:Set(mouseEvent.drawingVec)
			local testVec1 = LM.Vector2:new_local()
			testVec1:Set(mouseEvent.drawingVec)
			closestID = mesh:ClosestPoint(testVec1)
			self.firstPointID = -1
			self.secondPointID = -1
			if closestID >= 0 then
				local testVec2 = LM.Vector2:new_local()
				testVec2:Set(mesh:Point(closestID).fPos)
				closest = self:GetColosestVec(moho, mouseEvent.view, testVec1,testVec2)
			end
			if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then
				if closest < self.autoWeldRadius and closestID >= 0 then
					self.firstPointID = closestID
				else	
					local newPoint = self:AddPointOnCurve(moho, mouseEvent)
					if newPoint then
						self.clickOffset:Set(newPoint.fPos - mouseEvent.drawingVec)
						mesh:SelectNone()
						self.selectedPointID = mesh:PointID(newPoint)
						newPoint.fSelected = true
						newPoint.fTempPos:Set(newPoint.fPos)
						self.dragPoint = true
						self.doNotAddNewPoint = true
						mesh:PrepFixedHandles(moho.layerFrame)
						self.createdMidPoint = true
						self.step = 0
						self:FixHandles(moho, mesh)
						self:MakeFlipDirectionList(moho)
						self:PopulateSelList(moho, mesh)
						self:ClearPointKeys(moho, mesh:PointID(newPoint))
						local curve, ptID = newPoint:Curve(newPoint:CountCurves()-1, -1)
						if curve.fClosed then
							if ptID + 1 < curve:CountPoints() then
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
							else
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(0)))
							end
							if ptID - 1 >= 0 then
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
							else	
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1)))
							end
						else
							if ptID + 1 < curve:CountPoints() then
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
							end
							if ptID - 1 >= 0 then
								self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
							end
						end
						return
					end	
				end	
			end

			if self.firstPointID == -1 then
				local newPoint 
				local newPointID
				if self.autoWeld then
					newPoint= self:AddPointOnCurve(moho, mouseEvent)
					newPointID = mesh:PointID(newPoint)
				end	
				if newPoint then
					mesh:AddPoint(clickVec, -1, moho.layerFrame)
					self.firstPointID = mesh:CountPoints() - 2
					mesh:WeldPoints(self.firstPointID, newPointID, moho.layerFrame)
					mesh:PrepFixedHandles(moho.layerFrame)
					self.secondPointID = mesh:CountPoints() - 1
					self.firstPointID = newPointID
				else
					self.isNewCurve = true
					mesh:AddPoint(clickVec, -1, moho.layerFrame)
					self.firstPointID = mesh:CountPoints() - 2
					self.secondPointID = self.firstPointID + 1
				end	
			else
				local firstPoint = mesh:Point(self.firstPointID)
				if firstPoint:IsEndpoint() then
					mesh:AddPoint(clickVec, self.firstPointID, moho.layerFrame)
					self.secondPointID = mesh:CountPoints() - 1
				else
					mesh:AddPoint(clickVec, -1, moho.layerFrame)
					self.firstPointID = mesh:CountPoints() - 2
					mesh:WeldPoints(self.firstPointID, closestID, moho.layerFrame)
					mesh:PrepFixedHandles(moho.layerFrame)
					self.secondPointID = mesh:CountPoints() - 1
					self.firstPointID = closestID
				end	
			end
		end
		self.selectedPointID = self.secondPointID 
		return
	end
	
	if clickToSelect and closest < self.autoWeldRadius * 1.5 and closestID >= 0 and doubleClick and not self.drawingStatus then
		self.selectedPointID = -1
	end

	if self.selectedPointID < 0 then
		if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then
			if closest < self.autoWeldRadius then
				selectedPoint = mesh:Point(closestID)
				self.selectedPointID = closestID
				mesh:SelectNone()
				selectedPoint.fSelected = true
				self.startPoint = mesh:CountPoints()
				if selectedPoint:IsEndpoint() then
					if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
						selectedPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
					else
						selectedPoint:SetCurvature(self.curvature, moho.layerFrame)
					end
					selectedPoint:ResetControlHandles(moho.layerFrame)
					self:ClearPointKeys(moho, self.selectedPointID)
				end
				if closestID >= 0 then
					if (clickToSelect and not self.drawingStatus and doubleClick) or not clickToSelect then
						local testPoint = mesh:Point(closestID)
						if not testPoint:IsEndpoint() then
							-- Create new point from mid point
							local selectedPointPos = LM.Vector2:new_local()
							selectedPointPos:Set(selectedPoint.fAnimPos:GetValue(moho.layerFrame))
							local isEdgePoint = self:IsPointEdge(moho, mesh, mesh:Point(closestID), false)
							mesh:AddPoint(selectedPointPos, -1, moho.layerFrame)
							mesh:WeldPoints(mesh:CountPoints() - 1, closestID, moho.layerFrame)
							selectedPoint.fAnimPos:SetValue(moho.layerFrame, selectedPointPos)
							self.selectedPointID = mesh:CountPoints() - 1
							self.curvePointID = self.selectedPointID
							self.targetPointID = closestID
							self.startPoint = self.selectedPointID
							self.startCurvePointID = closestID
							self.lastSelectedPointID = self.selectedPointID
							local firstPoint = mesh:Point(closestID)
							local point = mesh:Point(self.startPoint)
							local where = -1
							local curve, where = point:Curve(point:CountCurves()-1, where)
							local curveID = mesh:CurveID(curve)
							point.fAnimPos:SetValue(moho.layerFrame, selectedPointPos)
							local screenPt = LM.Point:new_local()
							self.curveID = curveID
							self.startHandle = curve:GetControlHandle(self:FindLastCurvePoint(moho, point), moho.layerFrame, false)
							mouseEvent.view:Graphics():WorldToScreen(self.startHandle, screenPt)
							local curvePointID = curve:PointID(firstPoint)
							if curvePointID ~= 0 then
								curvePointID = self:FindLastCurvePoint(moho, firstPoint)
							end
							
							local handleWeight = curve:GetWeight(curvePointID, moho.layerFrame, false)
							local handleWeight2 = curve:GetWeight(curvePointID, moho.layerFrame, true)
							
							if (curvePointID == 0 and handleWeight == 0) 
							or (curvePointID > 0 and handleWeight2 == 0) 
							or (curvePointID == 0 and handleWeight == 1) 
							or (curvePointID > 0 and handleWeight2 == 1) then
								curve:ResetControlHandles(curvePointID, moho.layerFrame)
								curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame)
							else
								curve:ResetControlHandles(curvePointID, moho.layerFrame)
								curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame)
							end
							if not isEdgePoint then
								curve:SetCurvature(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
							end

							if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners)then
								curve:SetCurvature(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
								self.firstPointSharpCorner = true
								self.applyPeakedCorner = true
							end
							
							mesh:SelectNone()
							point.fSelected = true
							mesh:PrepFixedHandles(moho.layerFrame)
							
							self.drawingStatus = true
							self.isMousePressed = true
							self.isStartPoint = true
							self.isLastPointBezierMode = false
							self.isFirstClick = true
						else
							self.targetPointID = closestID
							self.startPointClick = true
							self.needCreateNewPoint = true
							mesh:PrepFixedHandles(moho.layerFrame)
						end
					end	
				end	
			else
				local newPoint = self:AddPointOnCurve(moho, mouseEvent)
				if newPoint then
					self.clickOffset:Set(newPoint.fPos - mouseEvent.drawingVec)
					if self.movePoints then
						mesh:SelectNone()
						self.selectedPointID = mesh:PointID(newPoint)
						newPoint.fSelected = true
						newPoint.fTempPos:Set(newPoint.fPos)
						self.dragPoint = true
						self.doNotAddNewPoint = true
						mesh:PrepFixedHandles(moho.layerFrame)
						self.createdMidPoint = true
						
						self:FixHandles(moho, mesh)
						self:MakeFlipDirectionList(moho)
						self:PopulateSelList(moho, mesh)
					else
						mesh:SelectNone()
						self.selectedPointID = - 1
						self.doNotAddNewPoint = true
						self.drawingStatus = false
						self.drawWeldPoint = false
					end
					self:ClearPointKeys(moho, mesh:PointID(newPoint))
					local curve, ptID = newPoint:Curve(newPoint:CountCurves()-1, -1)
					if curve.fClosed then
						if ptID + 1 < curve:CountPoints() then
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
						else
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(0)))
						end
						if ptID - 1 >= 0 then
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
						else	
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1)))
						end
					else
						if ptID + 1 < curve:CountPoints() then
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
						end
						if ptID - 1 >= 0 then
							self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
						end
					end	
				end
			end
		end
	else
		mesh:SelectNone()
	end

	if self.selectedPointID < 0 then
		if not self.doNotAddNewPoint then
			-- create start point
			mesh:SelectNone()
			mesh:AddPoint(mouseEvent.drawingVec, -1, moho.layerFrame)
			self.selectedPointID = mesh:CountPoints() - 1
			self.startPoint = self.selectedPointID
			self.startCurvePointID = mesh:CountPoints() - 2
			self.lastSelectedPointID = self.selectedPointID
			self.lastPointID = self.selectedPointID
			local firstPoint = mesh:Point(mesh:CountPoints() - 2)
			local point = mesh:Point(self.startPoint)
			if (moho.gridOn) then
				moho:SnapToGrid(firstPoint.fPos)
				firstPoint.fAnimPos:SetValue(moho.layerFrame, firstPoint.fPos)
			end
			point.fTempPos:Set(point.fPos)
			local curveID = mesh:CountCurves() - 1
			local curve = mesh:Curve(curveID)
			local screenPt = LM.Point:new_local()
			self.curveID = curveID
			self.startHandle = curve:GetControlHandle(curve:PointID(point), moho.layerFrame, false)
			mouseEvent.view:Graphics():WorldToScreen(self.startHandle, screenPt)
			
			self.handlePt2:Set(point.fPos)
			
			if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
				firstPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
				firstPoint:ResetControlHandles(moho.layerFrame)
				self.firstPointSharpCorner = true
				self.applyPeakedCorner = true
			else
				firstPoint:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
			end

			point:ResetControlHandles(moho.layerFrame)

			mesh:PrepFixedHandles(moho.layerFrame)
			self.selectedPointID = mesh:CountPoints() - 1
			self.drawingStatus = true
			self.isMousePressed = true
			self.isStartPoint = true
			self.isFirstClick = true
		end	
	else
		-- selected point found
		local testVec1 = LM.Vector2:new_local()
		testVec1:Set(mouseEvent.drawingVec)
		local drawingClosestID = mesh:ClosestPoint(testVec1, mesh:CountPoints() - 1)
		local testVec2 = LM.Vector2:new_local()
		testVec2:Set(self.lastClickVec)
		local dis = self:GetColosestVec(moho, mouseEvent.view, testVec1, testVec2)
		local drawingClosest = self:GetColosestVec(moho, mouseEvent.view, testVec1, mesh:Point(drawingClosestID).fPos)
		if dis < self.autoWeldRadius * 1.5 and self.drawingStatus and not self.isStartPoint then
			-- finish stroke
			self.drawingStatus = false
			self.drawWeldPoint = false
			local pointID = mesh:CountPoints() - 1
			local point = mesh:Point(pointID)
			local curve, curvePointId = point:Curve(point:CountCurves()-1, -1)
			local lastPointCurveID = curvePointId + 2
			local fromStart = true
			if curvePointId ~= 0 then
				lastPointCurveID = curvePointId - 2
				fromStart = false
			end

			local lastPointHandlePt = LM.Vector2:new_local()
			local lastPointHandlePt2 = LM.Vector2:new_local()
			local needCorrect = false
			if lastPointCurveID >= 0 and lastPointCurveID < curve:CountPoints() then
				lastPointHandlePt:Set(curve:GetControlHandle(lastPointCurveID, moho.layerFrame, true))
				lastPointHandlePt2:Set(curve:GetControlHandle(lastPointCurveID, moho.layerFrame, false))
				needCorrect = true
			end
			mesh:DeletePoint(pointID)
			mesh:SelectNone()
			local totalPoints = mesh:CountPoints()
			if totalPoints > 0 then
				local pt = mesh:Point(totalPoints - 1)
				pt:SetCurvature(self.curvature, moho.layerFrame)
				pt:ResetControlHandles(moho.layerFrame)
			end	
			if needCorrect then
				if fromStart then
					lastPointCurveID = lastPointCurveID -1
				end
				curve:SetControlHandle(lastPointCurveID, lastPointHandlePt, moho.layerFrame, true, true)
				curve:SetControlHandle(lastPointCurveID, lastPointHandlePt2, moho.layerFrame, false, true)
			end

			if self.lastSelectedPointID >= 0 and self.lastSelectedPointID < mesh:CountPoints() then
				local lastPoint = mesh:Point(self.lastSelectedPointID)
				if lastPoint then
					local lastCurve, lastCurvePointId = lastPoint:Curve(lastPoint:CountCurves()-1, -1)
					local prewCurvePointId = lastCurvePointId
					if lastCurvePointId ~= 0 then
						prewCurvePointId = prewCurvePointId - 1
					else
						prewCurvePointId = prewCurvePointId + 1
					end
					
					self:ClearPointKeys(moho, self.lastSelectedPointID)
					self:ClearPointKeys(moho, mesh:PointID(curve:Point(prewCurvePointId)))
				end	
			end	
			self.selectedPointID = -1
			self.lastSelectedPointID = -1
			self.lastPointID = -1
			self.isBezierChanged = false
			self.isLastPointBezierMode = false
			self.startPoint = 1000000
			if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then
				local shapeID = self:CreateShape(moho, mesh, curve, false)
			end

			moho:UpdateUI()
		else
			local targetPointID = mesh:CountPoints() - 1
			local targetPoint = mesh:Point(targetPointID)
			local targetCurve, targetWhere = targetPoint:Curve(targetPoint:CountCurves()-1, -1)
			local targeCurveID = mesh:CurveID(targetCurve)
			local targetPointCurveID = targetCurve:PointID(targetPoint)
			local lastCurvePointID = targetPointCurveID
			local targetCurvePointID = -1
			local curveDirection = true
			if targetCurve:PointID(targetPoint) == 0 then
				curveDirection = true
				targetCurvePointID = 0
				lastCurvePointID = 1
			else
				curveDirection = false
				targetCurvePointID = targetCurve:CountPoints()-1
				lastCurvePointID = targetCurvePointID - 1
			end 

			local lastPoint = targetCurve:Point(lastCurvePointID)

			if lastPointID == targetPointID and self.lastSelectedPointID ~= -1 then
				lastPointID = mesh:PointID(targetCurve:Point(targetCurve:PointID(lastPoint)-1))
				lastPoint = mesh:Point(lastPointID)
			end
			
			local pt = mesh:Point(drawingClosestID)
			
			if ((not self.autoWeld and mouseEvent.altKey) or self.autoWeld and not mouseEvent.altKey) and drawingClosest < self.autoWeldRadius * 1.5 and drawingClosestID ~= self.lastSelectedPointID
			and self.drawingStatus and not self.isStartPoint 
			and (not mesh:ArePointsAdjacent(drawingClosestID, mesh:PointID(lastPoint)) 
			or not self:ArePointsConnected(moho, mesh, targetPoint, pt))then
				-- weld point
				local curve, where = pt:Curve(pt:CountCurves()-1, -1)
				local originalWeightT = curve:GetWeight(where, moho.layerFrame, true)
				local originalWeightF = curve:GetWeight(where, moho.layerFrame, false)
				local originalOffsetT = curve:GetOffset(where, moho.layerFrame, true)
				local originalOffsetF = curve:GetOffset(where, moho.layerFrame, false)
				
				local curveIDpt = pt:CountCurves()-1
				local ptEdgeList = self:CollectEdgePoints(moho, mesh, pt)
				local curvePointID = curve:PointID(pt)
				local drawingClosestIDDirection = true
				if #ptEdgeList > 0 then
					curve, where = pt:Curve(ptEdgeList.curve[1], -1)
					curveIDpt = ptEdgeList.meshCurveID[1]
					curvePointID = ptEdgeList[1].curvePointID[1]
					drawingClosestIDDirection = ptEdgeList.direction[1]
				end
				
				local totalPointsOnCurve = curve:CountPoints()
				local isEndPoint = pt:IsEndpoint()
				
				local closestIdDirection = true
				if isEndPoint then
					if curvePointID == 0 then
						closestIdDirection = true
					else
						closestIdDirection = false
					end
				end
				local isOriginalCurveClosed = curve.fClosed
				local lastPointHandlePt = LM.Vector2:new_local()
				local lastPointHandlePt2 = LM.Vector2:new_local()
				lastPointHandlePt:Set(targetCurve:GetControlHandle(lastCurvePointID, moho.layerFrame, true))
				lastPointHandlePt2:Set(targetCurve:GetControlHandle(lastCurvePointID, moho.layerFrame, false))
				
				local isEdgePoint = self:IsPointEdge(moho, mesh, pt, false)
				local arePointsConnected = self:ArePointsConnected(moho, mesh, pt, lastPoint)
				local handleWeight = curve:GetWeight(curvePointID, moho.layerFrame, false)
				local handleWeight2 = curve:GetWeight(curvePointID, moho.layerFrame, true)
				local isPointsOnOneCurve = false
				isPointsOnOneCurve = self:ArePointsConnected(moho, mesh, pt, targetPoint)
				
				local curvePoints = curve:CountPoints()
	
				local lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1)
				
				local lastCurvesList = {}
				for i=0, lastPoint:CountCurves()-1 do
					local testCurve = lastPoint:Curve(i, -1)
					table.insert(lastCurvesList, testCurve)
				end
				
				local curvesList = {}
				for i=0, pt:CountCurves()-1 do
					local testCurve = pt:Curve(i, -1)
					table.insert(curvesList, testCurve)
				end
				local oldCurve = curve
				local oldLastCurve = lastCurve
				
				mesh:WeldPoints(targetPointID, drawingClosestID, moho.layerFrame)
				pt = mesh:Point(drawingClosestID)
				moho.layer:UpdateCurFrame()
				lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1)
				
				for i=0, lastPoint:CountCurves()-1 do
					local testCurve = lastPoint:Curve(i, -1)
					if pt:IsPointOnCurve(mesh:CurveID(testCurve)) then
						curve = testCurve
						lastCurve = testCurve
						break
					end
				end

				for i=0, pt:CountCurves()-1 do
					local testCurve = pt:Curve(i, -1)
					if testCurve == lastCurve then
						curve = testCurve
					end
				end
				
				self.handlePt2:Set(pt.fPos)
				
				local newCurvePointID = curve:PointID(pt)
				local ptCurveID = self:FindLastCurvePoint(moho, pt)
				local newLastCurvePointID = -1

				if curveDirection then
					newLastCurvePointID = lastCurve:PointID(lastPoint)
				else
					newLastCurvePointID = self:FindLastCurvePoint(moho, lastPoint)
				end
				
				lastCurve, lastWhere = lastPoint:Curve(lastPoint:CountCurves()-1, -1)
				curve, where = pt:Curve(pt:CountCurves()-1, -1)
				newLastCurvePointID = lastWhere
				ptCurveID = where
				
				local isLastCurveReversed = false
				
				if isPointsOnOneCurve and curve.fClosed then
					self.needCreateShape = true
					self.curveForCreateShape = curve
				elseif not isEdgePoint and not isEndPoint then
				elseif isEdgePoint and not isEndPoint then
					if drawingClosestIDDirection then
						newLastCurvePointID = totalPointsOnCurve
						ptCurveID = totalPointsOnCurve -1
						if not curveDirection then
							isLastCurveReversed = true
						end
					else
						newLastCurvePointID = totalPointsOnCurve
						ptCurveID = curvePointID
						if not curveDirection then
							isLastCurveReversed = true
						end	
					end
				elseif isEndPoint and not curve.fClosed then
					if not curveDirection then
						isLastCurveReversed = true
					end
					if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then
						local shapeID = self:CreateShape(moho, mesh, curve, false)
					end
				else
					if not curveDirection then
						isLastCurveReversed = true
					end	
				end
				
				self.curvePointID = ptCurveID
				self.curveIDForMove = mesh:CurveID(curve)
				if isEndPoint then
					if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
						if curve:GetCurvature(ptCurveID, moho.layerFrame) < self.peakedCorner then
						elseif originalWeightT == 1 and originalWeightF == 1 and originalOffsetT == 0 and originalOffsetF == 0 then
							curve:SetCurvature(ptCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
							curve:ResetControlHandles(ptCurveID, moho.layerFrame)
						else
							if isPointsOnOneCurve then
								if targetPointCurveID ~= 0 then
									curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, true)
									curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, true)
								else
									curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, false)
									curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, false)
								end
							end	
						end
					else
						if (curvePointID == 0 and handleWeight == 0) 
						or (curvePointID > 0 and handleWeight2 == 0) 
						or (curvePointID == 0 and handleWeight == 1) 
						or (curvePointID > 0 and handleWeight2 == 1) then
							curve:SetCurvature(ptCurveID, self.curvature, moho.layerFrame)
							curve:ResetControlHandles(ptCurveID, moho.layerFrame)
						else
							if curve.fClosed then
								if targetPointCurveID ~= 0 then
									local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, false)
									local handlePt2 = pt.fPos + (pt.fPos - handle)
									curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, true, true)
								else	
									local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true)
									local handlePt2 = pt.fPos + (pt.fPos - handle)
									curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true)
								end	
							else
								local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true)
								local handlePt2 = pt.fPos + (pt.fPos - handle)
								curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true)
							end	
						end	
					end
				else
					if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
						if curve:GetCurvature(ptCurveID, moho.layerFrame) < self.peakedCorner then
						elseif originalWeightT == 1 and originalWeightF == 1 and originalOffsetT == 0 and originalOffsetF == 0 then
							curve:SetCurvature(ptCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
							curve:ResetControlHandles(ptCurveID, moho.layerFrame)
						else
							if isPointsOnOneCurve then
								if targetPointCurveID ~= 0 then
									curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, true)
									curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, true)
								else
									curve:AimControlHandleAtNeighbor(ptCurveID, moho.layerFrame, false)
									curve:SetWeight(ptCurveID, 0.02, moho.layerFrame, false)
								end
							end	
						end
					else	
						if (curvePointID == 0 and handleWeight == 0) 
						or (curvePointID > 0 and handleWeight2 == 0) 
						or (curvePointID == 0 and handleWeight == 1) 
						or (curvePointID > 0 and handleWeight2 == 1) then
							curve:SetCurvature(ptCurveID, self.curvature, moho.layerFrame)
							curve:ResetControlHandles(ptCurveID, moho.layerFrame)
						else
							if curve.fClosed then
								if targetPointCurveID ~= 0 then
									local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, false)
									local handlePt2 = pt.fPos + (pt.fPos - handle)
									curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, true, true)
								else	
									local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true)
									local handlePt2 = pt.fPos + (pt.fPos - handle)
									curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true)
								end	
							else
								local handle = curve:GetControlHandle(ptCurveID, moho.layerFrame, true)
								local handlePt2 = pt.fPos + (pt.fPos - handle)
								curve:SetControlHandle(ptCurveID, handlePt2, moho.layerFrame, false, true)
							end	
						end		
					end
					local handle = curve:GetControlHandle(curve:PointID(pt), moho.layerFrame, true)
					local handlePt2 = pt.fPos + (pt.fPos - handle)
					local curvePointID = curve:PointID(pt)
					local lastPoint = self.selectedPointID
				end
				
				if ptCurveID >= 0 then
					self.weightTrue = curve:GetWeight(ptCurveID, moho.layerFrame, true)
					self.weightFalse = curve:GetWeight(ptCurveID, moho.layerFrame, false)
				end
				
				moho:Click()
				self.statusMode = 1
				self.selectedPointID = drawingClosestID
				self.lastPointID = drawingClosestID
				self.startPointClick = true
				self.needCreateNewPoint = false
				local point = mesh:Point(self.lastPointID)
				local curveID = self.curveID
				local segID = -1
				local where = -1
				local curve
				if curveID == -1 then
					if point:IsEndpoint() then
						curveID, segID = point:GetEndpointEdge(curveID, segID)
						curve = mesh:Curve(curveID)
					else
						curve, where = point:Curve(point:CountCurves()-1, where)
						curveID = mesh:CurveID(curve)
					end
				end	
				self.curveID = curveID
				local screenPt = LM.Point:new_local()
				self:ClearPointKeys(moho, self.lastPointID)

				if self.isFBF and self.isMoho13_5_3 then
					for i=0, mesh:CountPoints()-1 do
						local point = mesh:Point(i)
						for i = 0, point:CountCurves() - 1 do
							local curve = nil
							local ptPos = -1
							curve, ptPos = point:Curve(i, ptPos)
							curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.frame), 0)
							curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.frame, true), 0, true)
							curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.frame, false), 0, false)
							curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.frame, true), 0, true)
							curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.frame, false), 0, false)
							curve:DeleteCurvatureKey(ptPos, moho.frame)
						end	
					end
				end

				mesh:PrepFixedHandles(moho.layerFrame)
				self.isMousePressed = true
				self.drawingStatus = true
				self.statusMode = 1
			else
				if drawingClosest > self.autoWeldRadius * 1.5 then
					if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and self.drawingStatus and not self.isStartPoint then
						local m = LM.Matrix:new_local()
						local v = LM.Vector2:new_local()
						local pt = LM.Point:new_local()
						local curveID = -1
						local segID = -1
						local pickWidth = 5
						moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)
						v:Set(mesh:Point(self.selectedPointID).fPos)
						m:Transform(v)
						mouseEvent.view:Graphics():WorldToScreen(v, pt)
						curveID, segID = mesh:Point(self.selectedPointID):GetEndpointEdge(curveID, segID)
						curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth)
						if (curveID >= 0 and (self.autoWeld or (not self.autoWeld and mouseEvent.altKey))) then -- add a point in the middle of some curve
							if (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and
							(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and
							(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1)) then
								local curve = mesh:Curve(curveID)
								mesh:AddPoint(curve:ClosestPointOnSegment(segID, mesh:Point(self.selectedPointID).fPos, true, true), curveID, segID, moho.layerFrame)
								mesh:WeldPoints(self.selectedPointID, mesh:CountPoints() - 1, moho.layerFrame)
								moho:Click()
								self.drawingStatus = false
								self.drawWeldPoint = false
								local newPoint = mesh:Point(mesh:CountPoints() - 1)
								local curve, where = newPoint:Curve(newPoint:CountCurves()-1, -1)
								local newPointCurveID = curve:PointID(newPoint)
								if newPointCurveID ~= 0 then
									newPointCurveID = curve:CountPoints()-1
								end

								if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
									curve:SetCurvature(newPointCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
								end
								
								if self.autoStroke and mesh:IsCurveValid(curve) >= 0 then
									local shapeID = self:CreateShape(moho, mesh, curve, false)
								end

								self:ClearPointKeys(moho, self.selectedPointID)
								
								for i=0, newPoint:CountCurves()-1 do
									local curve, ptID = newPoint:Curve(i, -1)
									if curve.fClosed then
										if ptID + 1 < curve:CountPoints() then
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
										else
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(0)))
										end
										if ptID - 1 >= 0 then
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
										else	
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(curve:CountPoints()-1)))
										end
									else
										if ptID + 1 < curve:CountPoints() then
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID + 1)))
										end
										if ptID - 1 >= 0 then
											self:ClearPointKeys(moho, mesh:PointID(curve:Point(ptID - 1)))
										end
									end	
								end	
								
								self.selectedPointID = -1
								mesh:SelectNone()
								goto endOfOnClickFunction
							end
						end
					end
				end	
				::prepareToCursorDragging::

				self.needCreateNewPoint = true
				self.lastPointID = mesh:CountPoints() - 1
				if self.startPointClick and self.targetPointID >= 0 then
					self.lastPointID = self.targetPointID
					self.startPointClick = false
				end
				local point = mesh:Point(self.lastPointID)
				local curveID = -1
				local segID = -1
				local where = -1
				local curve
				if point:IsEndpoint() then
					curveID, segID = point:GetEndpointEdge(curveID, segID)
					curve = mesh:Curve(curveID)
				else
					curve, where = point:Curve(point:CountCurves()-1, where)
					curveID = mesh:CurveID(curve)
				end
				self.curveID = curveID
				
				local screenPt = LM.Point:new_local()
				point.fAnimPos:SetValue(moho.layerFrame, point.fPos)
				self:ClearPointKeys(moho, self.lastPointID)
				local curvePointID = curve:PointID(mesh:Point(self.lastPointID))
				if curvePointID > 0 then
					handle = curve:GetControlHandle(curvePointID, moho.layerFrame, false)
				else
					handle = curve:GetControlHandle(curvePointID, moho.layerFrame, true)
				end
				mouseEvent.view:Graphics():WorldToScreen(handle, screenPt)
				self.handlePt2:Set(point.fPos + (point.fPos - handle))
				if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
					point:SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
					self.applyPeakedCorner = true
				else
					if point:IsEndpoint() then
						point:SetCurvature(self.curvature, moho.layerFrame)
						point:ResetControlHandles(moho.layerFrame)
					end	
				end
				self.isMousePressed = true
				self.drawingStatus = true
				::endOfOnClickFunction::
			end	
		end	
	end
	::endOfFunction::
	self.lastClickVec:Set(clickVec)
	
	if self.fixedHandles then
		mesh:PrepFixedHandles(moho.layerFrame)
		self:FixHandles(moho, mesh)
	end
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	if (mesh:CountPoints() < 1) then
		return
	end
	if self.isMouseDragging then
		mouseEvent.view:Graphics():SelectionRect(self.selRect)
		self.selRect.right = mouseEvent.pt.x
		self.selRect.bottom = mouseEvent.pt.y
		mouseEvent.view:Graphics():SelectionRect(self.selRect)
		mouseEvent.view:RefreshView()
		mouseEvent.view:DrawMe()
		return
	end
	
	local frame = moho.layerFrame
		
	local clickVec = LM.Vector2:new_local()
	clickVec:Set(mouseEvent.drawingVec + self.clickOffset)
	
	if self.selectedPoints == 1 and not self.drawingStatus then
		mouseEvent.view:SetCursor(MOHO.moveCursor)
	end	
	
	if self.selectedPoints > 1 then
		if (not self.dragging) then
			self.centerVec = mesh:SelectedCenter()
			local mode = self:TestMousePoint(moho, mouseEvent)
			if (mode == 0) then
				mouseEvent.view:SetCursor(MOHO.moveCursor)
			elseif (mode == 1) then
				mouseEvent.view:SetCursor(MOHO.rotateCursor)
			elseif (mode == 11) then
				mouseEvent.view:SetCursor(MOHO.crosshairCursor)
			elseif (mode >= 20 and mode <= 23) then
				moho.view:SetCursor(self.skewCursor)
			elseif (mode >= 24 and mode <= 27) then
				moho.view:SetCursor(self.distortCursor)
			elseif (mode >= 2 and mode <= 9) then
				mouseEvent.view:SetCursor(MOHO.scaleCursor)
			end
			mouseEvent.view:DrawMe()
			return
		end
		
		if (mouseEvent.ctrlKey) then
			local testVec = LM.Vector2:new_local()
			testVec:Set(-10000, -10000)
			if self.prewVec ~= testVec then
				self.difVec = self.prewVec - mouseEvent.drawingVec
			end
			
			for i=0, mesh:CountPoints()-1 do
				local pt = mesh:Point(i)
				if pt.fSelected then
					local curve = nil
					local ptPos = -1
					
					for j = 0, pt:CountCurves() - 1 do
						curve, ptPos = pt:Curve(j, ptPos)
						local c = curve:GetCurvature(ptPos, moho.layerFrame)
						c = LM.Clamp(c + self.difVec.x, MOHO.PEAKED + self.peakedCorner, 1)
						curve:SetCurvature(ptPos, c, moho.layerFrame)
					end
				end	
			end
			mouseEvent.view:DrawMe()
			self.prewVec:Set(mouseEvent.drawingVec)
		else
			if (self.mode == 0) then -- translate
				self:OnMouseMoved_T(moho, mouseEvent)
			elseif (self.mode == 1) then -- rotate
				self:OnMouseMoved_R(moho, mouseEvent)
			elseif (self.mode == 11) then -- pivot
				self:OnMouseMoved_P(moho, mouseEvent)
			elseif (self.mode >= 20 and self.mode <= 23) then -- skew	
				 self:OnMouseMoved_Skew(moho, mouseEvent)
			elseif (self.mode >= 24 and self.mode <= 27) then -- distord	
				 self:OnMouseMoved_Distort(moho, mouseEvent)	 
			else -- scale
				self:OnMouseMoved_S(moho, mouseEvent)
			end
		end	
		return
	end

	if not self.drawingStatus then
		if moho.drawingLayer:CurrentAction() ~= "" then
			moho.view:SetCursor(MOHO.moveCursor)
		end
		return
	end
	
	self.closestID = -1
	self.closest = 1e6
	
	local pt = mesh:Point(self.selectedPointID)

	if self.dragPoint and self.movePoints then
		self.transformation = true
		local testVec = LM.Vector2:new_local()
		testVec:Set(-10000, -10000)
		if self.prewVec ~= testVec then
			self.difVec = self.prewVec - clickVec
		end
		if mouseEvent.ctrlKey then
			local curve = nil
			local ptPos = -1
			
			for j = 0, pt:CountCurves() - 1 do
				curve, ptPos = pt:Curve(j, ptPos)
				local c = curve:GetCurvature(ptPos, moho.layerFrame)
				c = LM.Clamp(c + self.difVec.x + self.difVec.y, MOHO.PEAKED + self.peakedCorner, 1)
				curve:SetCurvature(ptPos, c, moho.layerFrame)
			end
			moho:AddPointKeyframe(moho.layerFrame, moho.layer)
			mouseEvent.view:DrawMe()
			self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset)
			return
		end	
		
		if not (self.handleSide ~= 0) then
			if not mouseEvent.ctrlKey then	
				local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec
				if (mouseEvent.shiftKey) then
					if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then
						curVec.y = 0
					else
						curVec.x = 0
					end
				end
				
				if (moho.gridOn) then
					moho:SnapToGrid(curVec)
				end
				mesh:TranslatePoints(curVec)
				self:AddPointKeyframe(moho, frame, moho.drawingLayer)
				
				if self.fixedHandles and not mouseEvent.altKey then
					mesh:PreserveHandlePositions(frame)
				end
			end
			
			mouseEvent.view:DrawMe()
			self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset)
			
			if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and pt:IsEndpoint() then
				self:PreviewWeldPoint(moho, mouseEvent, pt)
			else	
				self.drawWeldPoint = false	
			end
			return
		else
			if self.selectedPoints == 1 then
				local newVal = (mouseEvent.pt.x - mouseEvent.startPt.x) / mouseEvent.view:Graphics():Width()
				if (self.handleSide ~= 0) then
					local curve = mesh:Curve(self.handleCurveID)
					local syncHandles = true
					if (mouseEvent.altKey) then
						syncHandles = false
					end

					local handlePt = self.startHandle + (mouseEvent.vec - mouseEvent.startVec)
					if (moho.gridOn) then
						moho:SnapToGrid(handlePt)
					end
					if (math.abs(curve:GetCurvature(self.handlePointID, moho.layerFrame)) < 0.001) then
						curve:SetCurvature(self.handlePointID, 0.001, moho.layerFrame)
					end
					
					local oldOffset = curve:GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == -1))
					local oldOppOffset = curve:GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == 1)) 

					if math.abs(oldOffset - oldOppOffset) > 0.01 then
						syncHandles = false
					end

					local newVector = handlePt - self.startFPos
					local weightMultiply = newVector:Mag()/self.startVectorMag
					local angleAdd = AE_Utilities:GetAngleBetween(self.startVector, newVector)
					
					if self.flipDirection then
						angleAdd = -angleAdd
					end
				
					local newOffset = self.startOffset + angleAdd  
					local newWeight = newVector:Mag()/self.weightMultiplier - self.weightDelta
					newWeight = newWeight - self.weightStartDelta

					curve:SetWeight(self.handlePointID, newWeight, moho.layerFrame, (self.handleSide == -1))
					curve:SetOffset(self.handlePointID, newOffset, moho.layerFrame, (self.handleSide == -1))
					if syncHandles then
						curve:SetOffset(self.handlePointID, newOffset, moho.layerFrame, (self.handleSide == 1))
					end
				end
			end
			self.savedVal = newVal
			moho.drawingLayer:UpdateCurFrame()
			mouseEvent.view:DrawMe()
			self.prewVec:Set(mouseEvent.drawingVec + self.clickOffset)
			return
		end	
	end

	self.prewVec:Set(mouseEvent.drawingVec)
	mouseEvent.view:SetCursor(MOHO.crosshairCursor)

	if moho.drawingLayer:CurrentAction() ~= "" then
		moho.view:SetCursor(MOHO.moveCursor)
		return
	end
	if self.singleCurveMode then
		local clickVec = LM.Vector2:new_local()
		clickVec:Set(mouseEvent.drawingVec + self.clickOffset)
		self.transformation = true
		if self.step == 1 and self.secondPointID >= 0 then
			local secondPoint = mesh:Point(self.secondPointID)
			if secondPoint then
				if mouseEvent.shiftKey then
					if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then
						clickVec.y = secondPoint.fTempPos.y
					else
						clickVec.x = secondPoint.fTempPos.x
					end
				end
				
				secondPoint.fPos:Set(clickVec)
				if clickVec ~= secondPoint.fTempPos then
					self.pointPoseChanged = true
				end	
				if (moho.gridOn) then
					moho:SnapToGrid(secondPoint.fPos)
				end
				
				if not self.isNewCurve then
					mesh:PreserveHandlePositions(moho.layerFrame)
				end	
				
				self:PreviewWeldPoint(moho, mouseEvent, secondPoint)
				mouseEvent.view:DrawMe()
			end	
		elseif self.step == 2 and self.firstPointID >= 0 and self.secondPointID >= 0 then
			local firstPoint = mesh:Point(self.firstPointID)
			local secondPoint = mesh:Point(self.secondPointID)
			if secondPoint and firstPoint then
				local curve, where = secondPoint:Curve(secondPoint:CountCurves()-1, -1)
				local curve2, where2 = firstPoint:Curve(firstPoint:CountCurves()-1, -1)
				local firstHandle = LM.Vector2:new_local()
				local secondHandle = LM.Vector2:new_local()
				local firstHandleDelta = LM.Vector2:new_local()
				local secondHandleDelta = LM.Vector2:new_local()
				local curveCenter = LM.Vector2:new_local()
				local firstHandleNewPos = LM.Vector2:new_local()
				local secondHandleNewPos = LM.Vector2:new_local()
				local curvature = self.curvatureSC * 2
				
				firstHandle:Set(firstPoint.fPos)
				secondHandle:Set(secondPoint.fPos)
				curveCenter:Set(firstHandle + (secondHandle - firstHandle) / 2)
				local distance = MR_Utilities:GetDistance(curveCenter, clickVec)
				
				firstHandleNewPos:Set((secondHandle - firstHandle) / 2)
				secondHandleNewPos:Set((secondHandle - firstHandle) / 2)
				
				secondHandleDelta:Set(clickVec.x + (firstHandleNewPos.x * curvature), clickVec.y + (firstHandleNewPos.y * curvature))
				firstHandleDelta:Set(clickVec.x - (secondHandleNewPos.x * curvature), clickVec.y - (secondHandleNewPos.y * curvature))
				
				firstHandle:Set(firstHandleDelta)
				secondHandle:Set(secondHandleDelta)
				
				if curve.fClosed then
					curve:SetControlHandle(where2, firstHandle, moho.layerFrame, where > where2, false)
					curve:SetControlHandle(where, secondHandle, moho.layerFrame, where2 > where, false)
				else	
					curve:SetControlHandle(where2, firstHandle, moho.layerFrame, where2 > where, false)
					curve:SetControlHandle(where, secondHandle, moho.layerFrame, where > where2, false)
				end	
				mouseEvent.view:DrawMe()
			end
		end
		return
	end

	if self.isMousePressed and not self.isStartPoint then
		local g = mouseEvent.view:Graphics()
		g:Push()
		local matrix = LM.Matrix:new_local()
		moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document)
		g:ApplyMatrix(matrix)
		local currentScale = g:CurrentScale(false)
		g:Pop()
		local mouseDist = MR_Utilities:GetDistance(mouseEvent.drawingStartVec, mouseEvent.drawingVec)
		mouseDist = mouseDist * currentScale
		if self.lastPointID >= 0 and not self.applyPeakedCorner then
			if (mouseDist > self.threshold or self.isBezierChanged) and self.useBezierHandles then
				local point = mesh:Point(self.lastPointID)
				local curveID = -1
				local segID = -1
				local where = -1
				local curve
				if point:IsEndpoint() then
					curveID, segID = point:GetEndpointEdge(curveID, segID)
					curve = mesh:Curve(curveID)
				else	
					curve, where = point:Curve(point:CountCurves()-1, where)
				end
				
				if self.curveIDForMove >= 0 then
					curve = mesh:Curve(self.curveIDForMove)
				end
				
				if not self.isBezierChanged then
					local testStartID
					local curvePointID = curve:PointID(point)
					if curvePointID == 0 then
						testStartID = mesh:PointID(curve:Point(1)) 
					elseif curvePointID > 0 then
						testStartID = mesh:CountPoints() - 2
					end
					self.selectedCurvePointID = ptCurveID
					if self.startCurvePointID > -1 and testStartID > -1 and not self.isLastPointBezierMode then
						if self.startCurvePointID == testStartID then
							local startCurvePoint = mesh:Point(self.startCurvePointID)
							local startCurvePointID = curve:PointID(startCurvePoint)
							if startCurvePointID == 0 then
								startCurvePointID = mesh:PointID(curve:Point(1)) 
							elseif startCurvePointID > 0 then
								startCurvePointID = self:FindLastCurvePoint(moho, startCurvePoint)
							end
							local startCurvePointID = self:FindLastCurvePoint(moho, startCurvePoint)
							if curvePointID == 0 then
								curve:SetControlHandle(startCurvePointID, startCurvePoint.fPos, moho.layerFrame, true, true)
							elseif curvePointID > 0 then	
								curve:SetControlHandle(startCurvePointID, startCurvePoint.fPos, moho.layerFrame, false, true)
							end
						end
					end
				end
				self.isBezierChanged = true
				self.curveID = curveID
				
				local curvePoint = curve:PointID(point)
				if self.curvePointID == -1 then
					if point:IsEndpoint() then
						self.curvePointID = curve:PointID(point)
					else
						if curvePoint == 0 then
							self.curvePointID = curvePoint
						else
							self.curvePointID = self:FindLastCurvePoint(moho, point)
						end
					end
				end
				self.meshPointID = self.lastPointID
				self.handlePt:Set(mouseEvent.vec)
				if not mouseEvent.altKey then
					self.handlePt2:Set(point.fPos + (point.fPos - mouseEvent.vec))
				end	
				
				self.midPt:Set(point.fPos)
				if point:IsEndpoint() then
					if curve:CountPoints() == 2 then
						local firstCurvePoint = 0
						if curvePoint == 0 then
							firstCurvePoint = 1
						end

						if curve:GetWeight(firstCurvePoint, moho.frame, firstCurvePoint > 0) == 1 then
							curve:SetWeight(firstCurvePoint, 0, moho.frame, firstCurvePoint > 0)
							self.correctFirstHandle = true
						end	
					end
						
					if curvePoint == 0 then
						curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
						if not mouseEvent.altKey then
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
						end	
					else
						curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
						if not mouseEvent.altKey then
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
						end	
					end
				else	
					if not mouseEvent.altKey then
						self.handlePt2:Set(mouseEvent.vec)
					end
					self.handlePt:Set(point.fPos + (point.fPos - mouseEvent.vec))
					
					
					if curve.fClosed then
						self.curvePointID = curve:PointID(point)
					end
					
					local areAdjacentPoints = false
					local curvePoints = curve:CountPoints()
					if curve.fClosed then
						areAdjacentPoints = true
					else
						if self.curvePointID ~= curvePoints -1 and self.curvePointID ~= 0 then
							areAdjacentPoints = true
						end
					end

					if areAdjacentPoints then
						if self.curvePointID == 0 then
							curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
							if not mouseEvent.altKey then
								curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
							end	
							if mouseEvent.shiftKey then
								curve:SetWeight(self.curvePointID, self.weightTrue, moho.layerFrame, false)
							end	
						else
							curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
							if not mouseEvent.altKey then
								curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
							end
							if mouseEvent.shiftKey then
								curve:SetWeight(self.curvePointID, self.weightFalse, moho.layerFrame, true)
							end	
						end
					else
						if self.curvePointID == 0 then
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
							if not mouseEvent.altKey then
								curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
							end	
							if mouseEvent.shiftKey then
								curve:SetWeight(self.curvePointID, self.weightTrue, moho.layerFrame, false)
							end	
						else
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
							if not mouseEvent.altKey then
								curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
							end
							if mouseEvent.shiftKey then
								curve:SetWeight(self.curvePointID, self.weightFalse, moho.layerFrame, true)
							end	
						end
					end
				end	

				if self.isLastPointBezierMode then
					mesh:PreserveHandlePositions(moho.layerFrame)
				end	
			end	
		end
	else
		if self.isBezierChanged and self.isMousePressed or not self.isMousePressed then
			local clickVec = LM.Vector2:new_local()
			clickVec:Set(mouseEvent.drawingVec)
			if (mouseEvent.shiftKey and not self.isFirstClick) then
				if (math.abs(mouseEvent.drawingVec.x - pt.fTempPos.x) > math.abs(mouseEvent.drawingVec.y - pt.fTempPos.y)) then
					clickVec.y = pt.fTempPos.y
				else
					clickVec.x = pt.fTempPos.x
				end
			end
			pt.fPos:Set(clickVec)
			if moho.gridOn and not self.isFirstClick then
				moho:SnapToGrid(pt.fPos)
			end
		end	
		
		if ((self.autoWeld and not mouseEvent.altKey) or (not self.autoWeld and mouseEvent.altKey)) and pt:IsEndpoint() then
			self:PreviewWeldPoint(moho, mouseEvent, pt)
		else	
			self.drawWeldPoint = false
		end
		
		if self.isStartPoint then
			local g = mouseEvent.view:Graphics()
			g:Push()
			local matrix = LM.Matrix:new_local()
			moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document)
			g:ApplyMatrix(matrix)
			local currentScale = g:CurrentScale(false)
			g:Pop()
			local mouseDist = MR_Utilities:GetDistance(mouseEvent.drawingStartVec, mouseEvent.drawingVec)
			mouseDist = mouseDist * currentScale
			if self.startCurvePointID >= 0 and not self.applyPeakedCorner then
				if (mouseDist > self.threshold or self.isBezierChanged and self.isMousePressed) and self.useBezierHandles then
					self.isBezierChanged = true
					local point = mesh:Point(self.startCurvePointID)
					local startPoint = mesh:Point(self.startCurvePointID)
					local curveID = -1
					local segID = -1
					local where = -1
					local curve
					
					if point:IsEndpoint() then
						curveID, segID = point:GetEndpointEdge(curveID, segID)
						curve = mesh:Curve(curveID)
					else	
						curve, where = point:Curve(point:CountCurves()-1, where)
					end
					self.curveID = mesh:CurveID(curve)
					self.curvePointID = curve:PointID(point)
					self.midPt:Set(startPoint.fPos)
					
					self.handlePt:Set(mouseEvent.vec)
					if not mouseEvent.altKey then
						self.handlePt2:Set(startPoint.fPos + (startPoint.fPos - mouseEvent.vec))
					end	

					local curvePointID = curve:PointID(mesh:Point(self.lastPointID))
					local curvePoint = curve:PointID(point)
					local curvePoints = curve:CountPoints()
					if curvePoint == 0 then
						for i = 0, curvePoints-1 do
							local curvePoint = curve:Point(curvePoints - i)
							if curvePoint == point then
								self.curvePointID = i
								break
							end
						end
					else
						for i = 0, curvePoints-1 do
							local curvePoint = curve:Point(curvePoints - i)
							if curvePoint == point then
								self.curvePointID = curvePoints - i
								break
							end
						end
					end
					if self.isMousePressed then
						if curvePointID == 0 then
							curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
						else
							curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
							curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
						end
					end	
				end	
			end
		end
		if self.isLastPointBezierMode then
			mesh:PreserveHandlePositions(moho.layerFrame)
		end	
		moho:AddPointKeyframe(moho.layerFrame, moho.layer)
	end
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseUp(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	local shapeID = -1
	self.selectedPoints = moho:CountSelectedPoints()

	if self.isMouseDragging then
		local v = LM.Vector2:new_local()
		local screenPt = LM.Point:new_local()
		local m = LM.Matrix:new_local()
		
		if not (mouseEvent.shiftKey or mouseEvent.altKey) then
			mesh:SelectNone()
		end

		local id = mouseEvent.view:PickPoint(mouseEvent.pt)
		if id ~= -1 then
			mesh:Point(id).fSelected = not (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey)
			if not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey then
				mesh:Point(id).fSelected = false
			end
		end
		
		self.selRect:Normalize()
		moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)
		for i = 0, mesh:CountPoints() - 1 do
			local pt = mesh:Point(i)
			if (not pt.fHidden) then
				v:Set(pt.fPos)
				m:Transform(v)
				mouseEvent.view:Graphics():WorldToScreen(v, screenPt)
				if (self.selRect:Contains(screenPt)) then
					pt.fSelected = not (self.selectedPoints > 1 and mouseEvent.altKey and mouseEvent.ctrlKey and not mouseEvent.shiftKey)
					if not mouseEvent.shiftKey and mouseEvent.altKey and mouseEvent.ctrlKey then
						pt.fSelected = false
					end
				end
			end
		end
		self.isMouseDragging = false
		self.selectedPoints = moho:CountSelectedPoints()
		if self.selectedPoints == 0 and moho.frame == 0 then
			mouseEvent.view:SetCursor(MOHO.crosshairCursor)
		end
		
		local isDrawingEnabled = true
		if not self.drawInZeroFrame and moho.frame == 0 or not self.drawInNonZeroFrame and moho.frame ~= 0 then
			isDrawingEnabled = false
		end
		
		if self.isFBF and self.alwaysDrawOnFBF then
			isDrawingEnabled = true
		end
		local arePointsSelected = false
		for i=0, mesh:CountPoints()-1 do
			local point = mesh:Point(i)
			if point.fSelected then
				arePointsSelected = true
				break
			end
		end
		
		if not arePointsSelected and not isDrawingEnabled then
			self:SingleClickSelect(moho, mouseEvent, false, true)
		end
		
		mouseEvent.view:DrawMe()
		moho.drawingLayer:UpdateCurFrame()
		return
	end
	
	if self.isCurveEnded and self.dragPoint and self.movePoints then
		return
	end
	
	if self.selectedPoints > 1 then
		if self.outside and not self.transformation then
			mesh:SelectNone()
			self.dragging = false
			return
		end
	
		if (self.mode ~= 11) then
			moho:NewKeyframe(CHANNEL_POINT)
			moho:UpdateUI()

			if (self.mode == 0) then
			elseif (self.mode == 1) then
				local v = mesh:SelectedCenter()
				self.pivotOffset = self.centerVec - v
			end
		end

		self.selID = -1
		self.dragging = false
		self:AddPointKeyframe(moho, moho.layerFrame)
		if self.fixedHandles and self.transformation then
			self:RepairFixedHandles(moho, mesh)
		end

		if self.isFBF then
			self:FixFBF(moho)
		end
		
		moho.layer:UpdateCurFrame()
		moho:UpdateUI()
		return
	end
	
	local bezierMode = false
	if self.dragPoint and self.movePoints and self.selectedPoints == 1 then
		if self.transformation then
			local point = mesh:Point(self.selectedPointID)
			self.weldedCurve = nil
			if self:WeldPoints(moho, mouseEvent, point.fPos, false) then
				if self.weldedCurve then
					shapeID = self:CreateShape(moho, mesh, self.weldedCurve, true)
				end
				if self.isFBF then
					self:FixFBF(moho)
				end
				
				moho.layer:UpdateCurFrame()
				moho:UpdateUI()
				return
			end
		end	

		if self.handleSide == 0 and self.transformation then
			self:AddPointKeyframe(moho, moho.layerFrame, nil, MOHO.MohoGlobals.EditMultipleKeys)
		end
		if self.fixedHandles and self.transformation then
			self:RepairFixedHandles(moho, mesh)
		end
		self.selectedPointID = - 1
		self.doNotAddNewPoint = true
		self.drawingStatus = false
		self.drawWeldPoint = false
		if self.createdMidPoint then
			mesh:SelectNone()
			self.createdMidPoint = false
		end
		if self.isFBF and self.transformation then
			self:FixFBF(moho)
		end	

		moho.layer:UpdateCurFrame()
		moho:UpdateUI()
		return
	end	
	
	if moho.drawingLayer:CurrentAction() ~= ""  then
		return
	end

	if self.singleCurveMode then
		if self.step == 1 then
			if not self.transformation then
				self.step = 0
				self.drawingStatus = false 
				moho.document:Undo()
				moho:UpdateUI()
				moho.layer:UpdateCurFrame()
				moho:UpdateSelectedChannels()
				mouseEvent.view:DrawMe()
				return
			end
			self.step = 2
			local firstPoint = mesh:Point(self.firstPointID)
			local secondPoint = mesh:Point(self.secondPointID)
			if secondPoint and firstPoint then
				local closestID = -1
				local closest = 1e6
				local testVec1 = LM.Vector2:new_local()
				testVec1:Set(secondPoint.fPos)
				closestID = mesh:ClosestPoint(testVec1)
				secondPoint.fAnimPos:SetValue(moho.layerFrame, secondPoint.fPos)
				self:ClearPointKeys(moho, self.firstPointID)
				self:ClearPointKeys(moho, self.secondPointID)
				if closestID >= 0 then
					if self.autoWeld then
						if self:WeldPoints(moho, mouseEvent, secondPoint.fPos, false) then
							self.isWelded = true
							self.selectedPointID = self.secondPointID
							self:ClearPointKeys(moho, self.secondPointID)
						end
					end	
				end
			end
		elseif self.step == 2 then
			self.drawingStatus = false 
			local firstPoint = mesh:Point(self.firstPointID)
			local secondPoint = mesh:Point(self.secondPointID)
			if secondPoint and firstPoint then
				mesh:SelectNone()
				firstPoint.fSelected = true
				secondPoint.fSelected = true
				MOHO:SplitSelectedSegments(mesh, self.points, moho.layerFrame)
				if (moho.frame > 0) then
					for i=0, mesh:CountPoints()-1 do
						local point = mesh:Point(i)
						if point.fSelected then
							self:ClearPointKeys(moho, i)
						end	
					end
				end
				if self.isWelded then
					self:CreateShape(moho, mesh, self.weldedCurve, true)
				end	
				self.isWelded = false
			end	
			mesh:SelectNone()
			if self.isFBF then
				self:FixFBF(moho)
			end
			self.step = 0
		end

		moho:UpdateUI()
		moho.layer:UpdateCurFrame()
		moho:UpdateSelectedChannels()
		mouseEvent.view:DrawMe()
		return
	end
	
	if self.selectedPointID >= 0 and not self.isStartPoint and self.statusMode == 0 then
		if self.needCreateNewPoint then
			local pt = mesh:Point(self.selectedPointID)
			local curve = mesh:Curve(self.curveID)
			local lastCurveID = curve:PointID(mesh:Point(self.lastPointID))
			local curvePointID = lastCurveID -1
			local startCurvePoint = false
			local startCurvePointOnCurveID = -1
			local fixFirstEdgePoint = false
			if curvePointID == 0  then
				startCurvePoint = true
				startCurvePointOnCurveID = curvePointID
			elseif lastCurveID == 0 and curve:CountPoints() == 2 then
				fixFirstEdgePoint = true
			end	
			local needCorrectHandles = false
			local handle1 = LM.Vector2:new_local()
			local handle2 = LM.Vector2:new_local()
			
			local startHandle = LM.Vector2:new_local()
			
			if startCurvePoint then
				if curve:CountPoints() == 2 then
					handle1 = curve:GetControlHandle(0, moho.layerFrame, false)
					handle2 = curve:GetControlHandle(1, moho.layerFrame, true)
					needCorrectHandles = true
				end
				if startCurvePointOnCurveID >= 0 then
					startHandle = curve:GetControlHandle(startCurvePointOnCurveID, moho.layerFrame, true)
				end	
			end	
			local newPoint
			local edgeHandlePt 
			local edgeHandlePt2
			local clickPointID = self.selectedPointID
			
			self:ClearPointKeys(moho, self.lastSelectedPointID)
		
			if not self.doNotAddNewPoint then
				local fromStart = false
				if lastCurveID ~= curve:CountPoints()-1 then
					curvePointID = curve:CountPoints() - lastCurveID - 1
					fromStart = true
				end
				local handlePt = curve:GetControlHandle(curvePointID, moho.layerFrame, false)
				local handlePt2 = curve:GetControlHandle(curvePointID, moho.layerFrame, true)
				
				mesh:AddPoint(mouseEvent.drawingVec, self.selectedPointID, moho.layerFrame)
				if fromStart then
					curvePointID = curvePointID +1
				end		
				
				self.lastSelectedPointID = self.selectedPointID
				self.selectedPointID = mesh:CountPoints() - 1
				newPoint = mesh:Point(self.selectedPointID)
				newPoint.fTempPos:Set(pt.fPos)
				mesh:SelectNone()
				newPoint.fSelected = true
				newPoint:ResetControlHandles(moho.layerFrame)
			else	
				self.lastSelectedPointID = self.selectedPointID
				self.selectedPointID = mesh:CountPoints() - 1
			end	

			if self.startPointClick then
				local clickPoint = mesh:Point(clickPointID)
				clickPoint:ResetControlHandles(moho.layerFrame)
				self.startPoint = self.selectedPointID
				self.startPointClick = false
			end	

			if self.isMousePressed and not self.applyPeakedCorner and self.isBezierChanged then
				local curvePointID = curve:PointID(mesh:Point(self.lastPointID))
				local curveNewPointID = curve:PointID(mesh:Point(self.selectedPointID))
				if curvePointID == 1 and curveNewPointID == 0 then
					curve:SetControlHandle(curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
					curve:SetControlHandle(curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
				else
					curve:SetControlHandle(curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
					curve:SetControlHandle(curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
				end
				if needCorrectHandles then
					if self.correctFirstHandle then
						curve:SetWeight(0, 1, moho.layerFrame, false)
						self.correctFirstHandle = false
					end	
					curve:SetControlHandle(1, handle2, moho.layerFrame, true, true)
					self:ClearPointKeys(moho, mesh:PointID(curve:Point(0)))
					self:ClearPointKeys(moho, mesh:PointID(curve:Point(1)))
				else
					if startCurvePoint then
						if not startCurvePoint:IsEndpoint()	and curvePointID - 1 == curveNewPointID and startCurvePointOnCurveID >= 0 then
							curve:SetControlHandle(startCurvePointOnCurveID, startHandle, moho.layerFrame, true, true)
						end	
					end	
				end
				
				if fixFirstEdgePoint then
					if self.correctFirstHandle then
						curve:SetWeight(2, 1, moho.layerFrame, true)
						self:ClearPointKeys(moho, mesh:PointID(curve:Point(2)))
						self.correctFirstHandle = false
					end
				end
				
				if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
					if curveNewPointID == 0 then
						curve:SetWeight(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame, true)
					else
						curve:SetWeight(curvePointID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame, false)
					end	
				end
				
				self:ClearPointKeys(moho, self.selectedPointID)
				self:ClearPointKeys(moho, self.lastSelectedPointID)
				self:ClearPointKeys(moho, self.lastPointID)
				
				mesh:PrepFixedHandles(moho.layerFrame)
			else
				if needCorrectHandles then
					if not self.firstPointSharpCorner then
						curve:SetCurvature(0, self.curvature, moho.layerFrame)
					end
				end
				if fixFirstEdgePoint then
					if not self.firstPointSharpCorner then	
						curve:SetCurvature(2, self.curvature, moho.layerFrame)
					end
				end
				self:ClearPointKeys(moho, mesh:PointID(curve:Point(0)))
				self:ClearPointKeys(moho, mesh:PointID(curve:Point(2)))
			end
			self.firstPointSharpCorner = false
			self:ClearPointKeys(moho, self.selectedPointID)
			self:ClearPointKeys(moho, self.lastSelectedPointID)
			self:ClearPointKeys(moho, self.lastPointID)
			self.drawingStatus = true
		end
	elseif self.isStartPoint and self.statusMode == 0 then
		local pt = mesh:Point(self.startCurvePointID)
		local secondPoint = mesh:Point(mesh:CountPoints() - 1)
		local curve = mesh:Curve(self.curveID)
		local secondPointID = curve:PointID(secondPoint)
		if self.isMousePressed and not self.applyPeakedCorner and self.isBezierChanged then
			local curvePointID = curve:PointID(mesh:Point(mesh:CountPoints() - 1))
			curve:SetCurvature(curvePointID, self.curvature, moho.layerFrame)
			curve:SetCurvature(curve:PointID(pt), self.curvature, moho.layerFrame)
			if curvePointID == 0 then
				curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, true, not mouseEvent.altKey)
				curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, false, not mouseEvent.altKey)
			else
				curve:SetControlHandle(self.curvePointID, self.handlePt, moho.layerFrame, false, not mouseEvent.altKey)
				curve:SetControlHandle(self.curvePointID, self.handlePt2, moho.layerFrame, true, not mouseEvent.altKey)
			end
			curve:SetControlHandle(secondPointID, secondPoint.fPos, moho.layerFrame, true, true)
			curve:SetControlHandle(secondPointID, secondPoint.fPos, moho.layerFrame, false, true)
			moho:NewKeyframe(CHANNEL_CURVE)
		else
			secondPoint:ResetControlHandles(moho.layerFrame)
		end
		self.selectedPointID = mesh:CountPoints() - 1
		self:ClearPointKeys(moho, self.startCurvePointID)
		self:ClearPointKeys(moho, self.selectedPointID)
		
		local point = mesh:Point(self.selectedPointID)
		local pointsOnCurve = curve:CountPoints()

		if self.isMoho13_5_3 and moho.drawingFrame > 0 then
			if pointsOnCurve > 2 then
				local curve, ptPos = point:Curve(point:CountCurves()-1, -1)
				for p=0, pointsOnCurve-1 do
					curve:DeleteCurvatureKey(p, moho.layerFrame)
				end
			end	
		end
		
		mesh:PrepFixedHandles(moho.layerFrame)
	elseif self.statusMode == 1 then
		local curveClosed = self.needCreateShape
		if self.autoFill or self.autoStroke then
			if self.needCreateShape and self.curveForCreateShape then
				shapeID = self:CreateShape(moho, mesh, self.curveForCreateShape, true)
				self.needCreateShape = false
			end
		end	
		mesh:SelectNone()
		self.drawingStatus = false
		self.drawWeldPoint = false
		self:ClearPointKeys(moho, self.selectedPointID)
		self:ClearPointKeys(moho, self.lastSelectedPointID)
		self:ClearPointKeys(moho, self.lastPointID)
		
		local selectedPoint = mesh:Point(self.selectedPointID)
		
		if moho.drawingFrame > 0 then
			if not curveClosed then
				for c=0, selectedPoint:CountCurves()-1 do
					local curve = selectedPoint:Curve(c, -1)
					if curve ~= nil then
						for ptPos=0, curve:CountPoints()-1 do
							curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.layerFrame), 0)
							curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, true), 0, true)
							curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, false), 0, false)
							curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, true), 0, true)
							curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, false), 0, false)
							if self.isMoho13_5_3  then
								curve:DeleteCurvatureKey(ptPos, moho.layerFrame)
							end
						end
					end	
				end
			end
			mesh:PrepFixedHandles(moho.layerFrame)
		end	
		self.selectedPointID = -1
	end	
	self.handlePt:Set(10000,10000)
	self.handlePt2:Set(10000,10000)
	self.midPt:Set(10000,10000)

	if self.isBezierChanged or bezierMode then
		self.isLastPointBezierMode = true
	else
		self.isLastPointBezierMode = false
	end
	self.isMousePressed = false
	self.isBezierChanged = false
	self.isFirstClick = false
	self.targetPointID = -1
	
	if self.selectedPoints == 0 and moho.frame == 0 then
		mouseEvent.view:SetCursor(MOHO.crosshairCursor)
	end
	
	if shapeID >= 0 then
		local shape = mesh:Shape(shapeID)
		shape.fSelected = true
	end
	
	moho:UpdateUI()
	moho.layer:UpdateCurFrame()
	moho:UpdateSelectedChannels()
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnKeyDown(moho, keyEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	if ((keyEvent.keyCode == LM.GUI.KEY_DELETE) or (keyEvent.keyCode == LM.GUI.KEY_BACKSPACE)) then
		if (not keyEvent.view:IsMouseDragging()) and not self.drawingStatus then
			moho.document:PrepUndo(moho.drawingLayer)
			moho.document:SetDirty()
			MOHO.DeleteSelectedPoints(mesh)
			self.selectedPoints = moho:CountSelectedPoints()
			keyEvent.view:DrawMe()
		end
	end

	if keyEvent.keyCode == LM.GUI.KEY_BIND then
		if self.drawingStatus and not (self.step == 1 or self.step == 2) then
			self.weldedCurve = nil
			local point = mesh:Point(self.selectedPointID)
			local shapeID = -1
			local lastPoint = mesh:Point(self.selectedPointID)
			local curve, where = point:Curve(point:CountCurves()-1, -1)
			local prewPoint = curve:Point(curve:CountPoints()-2)
			if self:WeldPoints(moho, keyEvent, point.fPos, true) then
				if self.weldedCurve then
					shapeID = self:CreateShape(moho, mesh, self.weldedCurve, true)
				end
				self:ClearPointKeys(moho, self.selectedPointID)
				self:ClearPointKeys(moho, self.lastSelectedPointID)
				self:ClearPointKeys(moho, self.lastPointID)
				self.drawingStatus = false
				self.drawWeldPoint = false

				self:CloseCurve(moho, prewPoint)

				self.selectedPointID = -1
				self.startPoint = -1
				mesh:SelectNone()
				
				if shapeID >= 0 then
					local shape = mesh:Shape(shapeID)
					shape.fSelected = true
				end

				moho:UpdateUI()
				moho.layer:UpdateCurFrame()
				moho:UpdateSelectedChannels()
				moho.view:DrawMe()
				return
			end
			local point = mesh:Point(self.selectedPointID)
			self:CloseCurve(moho, point)
		end	
	elseif keyEvent.keyCode == 27 or keyEvent.keyCode == -51 then
		if self.step == 1 or self.step == 2 then
			if self.step == 1 and self.selectedPointID > -1 then
				mesh:DeletePoint(self.selectedPointID)
				self:ClearPointKeys(moho, self.selectedPointID)
			elseif self.step == 2 then	
				moho.document:Undo()
			end
			if self.isFBF then
				self:FixFBF(moho)
			end
			self.step = 0
			self.drawingStatus = false 
			mesh:SelectNone()
		else
			local curveEnded = false
			if self.drawingStatus and self.selectedPointID >= 0 then
				local point = mesh:Point(self.selectedPointID)
				if point:IsEndpoint() and not (self.dragPoint and self.movePoints) then
					if self.targetPointID < 0 and not self.isMousePressed then
						local lastPoint = mesh:Point(self.selectedPointID)
						local curve, where = point:Curve(point:CountCurves()-1, -1)
						local prewPoint = curve:Point(curve:CountPoints()-2)
						mesh:DeletePoint(self.selectedPointID)
						if prewPoint then
							self:CloseCurve(moho, prewPoint)
						end
					end
				end
			end
			if not curveEnded then
				self:CloseCurve(moho)
			end	
		end	
	elseif keyEvent.keyCode == LM.GUI.KEY_BACKSPACE then
		local endPointID = mesh:CountPoints() -1
		if endPointID >= self.startPoint and self.drawingStatus then
			local endPoint = mesh:Point(endPointID)
			mesh:DeletePoint(endPointID)
			
			endPointID = mesh:CountPoints() -1
			if endPointID == self.startPoint then
				local endPoint = mesh:Point(endPointID)
				mesh:DeletePoint(endPointID) 
			end
			if mesh:CountPoints() -1 >= self.startPoint then
				self.selectedPointID = mesh:CountPoints() -1
				local point = mesh:Point(self.selectedPointID)
				point:ResetControlHandles(moho.layerFrame)
				self:ClearPointKeys(moho, self.selectedPointID)
				moho.layer:UpdateCurFrame()
				keyEvent.view:DrawMe()
			else
				self.selectedPointID = -1
				self.drawingStatus = false
				self.drawWeldPoint = false
				moho.layer:UpdateCurFrame()
				keyEvent.view:DrawMe()
				moho:UpdateUI()
			end
			self.lastClickVec:Set(100000, 100000)
		end
	end
end

function MR_CurveTool:OnKeyUp(moho, keyEvent)
end

function MR_CurveTool:DrawMe(moho, view)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	if (self.lastSelectedCount ~= moho:CountSelectedPoints()) then
		self.lastSelectedCount = moho:CountSelectedPoints()
		self.pivotOffset:Set(0, 0)
	end
	
	if self.isMouseDragging then
		local g = view:Graphics()
		g:SelectionRect(self.selRect)
		return
	end
	
	local g = view:Graphics()
	local matrix = LM.Matrix:new_local()

	moho.drawingLayer:GetFullTransform(moho.layerFrame, matrix, moho.document)
	g:Push()
	g:ApplyMatrix(matrix)
	
	if self.isMousePressed and self.isBezierChanged and self.drawingStatus then
		g:SetSmoothing(true)
		g:SetColor(240, 22, 22, 128)
		g:SetPenWidth(2)
		g:DrawLine(self.handlePt.x, self.handlePt.y, self.midPt.x, self.midPt.y)
		g:DrawLine(self.midPt.x, self.midPt.y, self.handlePt2.x, self.handlePt2.y)
		g:FillCirclePixelRadius(self.handlePt, 3.5)
		g:FillCirclePixelRadius(self.handlePt2, 3.5)
	end
	
	if not self.dragging and self.selectedPoints > 1 or self.mode == 11 then
		local min = LM.Vector2:new_local()
		local max = LM.Vector2:new_local()
		local matrix = LM.Matrix:new_local()
		local centerVec = LM.Vector2:new_local()
		local v = LM.Vector2:new_local()
		local vc1 = LM.ColorVector:new_local()
		local vc2 = LM.ColorVector:new_local()

		vc1:Set(MOHO.MohoGlobals.SelCol)
		vc2:Set(MOHO.MohoGlobals.BackCol)
		vc1 = (vc1 + vc2) / 2
		local col = vc1:AsColorStruct()

		local bbox = self:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, view)
		min:Set(bbox.fMin.x, bbox.fMin.y)
		max:Set(bbox.fMax.x, bbox.fMax.y)

		g:SetColor(col)
		g:SetPenWidth(1)
		g:SetSmoothing(true)
		g:DrawLine(min.x, min.y, max.x, min.y)
		g:DrawLine(min.x, max.y, max.x, max.y)
		g:DrawLine(min.x, min.y, min.x, max.y)
		g:DrawLine(max.x, min.y, max.x, max.y)

		g:SetPenWidth(1)
		local rotWidth = max.x - min.x
		if (max.y - min.y > rotWidth) then
			rotWidth = max.y - min.y
		end
		
		rotWidth = rotWidth * 0.1
		
		g:DrawLine(min.x - rotWidth, min.y - rotWidth, min.x - rotWidth, max.y + rotWidth)
		g:DrawLine(min.x - rotWidth, max.y + rotWidth, max.x + rotWidth, max.y + rotWidth)
		g:DrawLine(max.x + rotWidth, max.y + rotWidth, max.x + rotWidth, min.y - rotWidth)
		g:DrawLine(max.x + rotWidth, min.y - rotWidth, min.x - rotWidth, min.y - rotWidth)

		g:SetPenWidth(2)
		v:Set(min.x, min.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set(min.x, max.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set(max.x, min.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set(max.x, max.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set((min.x + max.x) / 2, min.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set((min.x + max.x) / 2, max.y) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set(min.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR)
		v:Set(max.x, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR)
		
		if self.enableSkewTransformation then
			v:Set((min.x + max.x) / 2, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set((min.x + max.x) / 2, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set(min.x - rotWidth, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set(max.x + rotWidth, (min.y + max.y) / 2) g:FrameCirclePixelRadius(v, self.markerR + 2)
		end
		
		if self.enableDistortTransformation and self.selectedPoints > 2 then
			v:Set(min.x - rotWidth, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set(min.x - rotWidth, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set(max.x + rotWidth, min.y - rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
			v:Set(max.x + rotWidth, max.y + rotWidth) g:FrameCirclePixelRadius(v, self.markerR + 2)
		end	
		
		g:SetPenWidth(1)

		if (self.dragging) then
			centerVec:Set(self.centerVec)
		else
			centerVec = mesh:SelectedCenter()
			centerVec = centerVec + self.pivotOffset
		end
		
		if self.selectedPoints > 1 then
			g:SetColor(col)
			g:SetSmoothing(true)
			g:DrawLine(centerVec.x - 0.05, centerVec.y, centerVec.x + 0.05, centerVec.y)
			g:DrawLine(centerVec.x, centerVec.y - 0.05, centerVec.x, centerVec.y + 0.05)
			v:Set(centerVec.x, centerVec.y) g:FrameCirclePixelRadius(v, self.markerR)
		end
	end	
	
	if self.drawWeldPoint then
		if (self.endWeldToPoint) then
			g:SetColor(0, 255, 0, 128)
		else
			g:SetColor(255, 0, 0, 128)
		end
		g:SetSmoothing(true)
		g:SetBezierTolerance(2)
		g:FillCircle(self.endWeldVec, moho:PixelToDoc(self.autoWeldRadius * 0.15) / g:CurrentScale(false))
		g:SetSmoothing(false)
	end
	
	if self.selectedPoints == 1 and self.showHandles and (self.dragPoint or not self.drawingStatus ) then
		local meshLayer = moho:LayerAsVector(moho.drawingLayer)
		meshLayer:DrawHandles(moho.document, g, not self.showAllHandles)
	end
	g:Pop()
end

-- **************************************************
-- Tool Panel Layout
-- **************************************************

local MR_CurveToolSettingsDialog = {}

MR_CurveToolSettingsDialog.DRAW_IN_ZERO_FRAME = MOHO.MSG_BASE
MR_CurveToolSettingsDialog.DRAW_IN_NON_ZERO_FRAME = MOHO.MSG_BASE + 1
MR_CurveToolSettingsDialog.ALWAYS_DRAW_ON_FBF = MOHO.MSG_BASE + 2
MR_CurveToolSettingsDialog.DRAW_BEHIND = MOHO.MSG_BASE + 3
MR_CurveToolSettingsDialog.USE_PEAK_FOR_CORNERS = MOHO.MSG_BASE + 4
MR_CurveToolSettingsDialog.SHOW_ALL_HANDLES = MOHO.MSG_BASE + 5
MR_CurveToolSettingsDialog.ENABLE_SKEW_TRANSFORMATION = MOHO.MSG_BASE + 6
MR_CurveToolSettingsDialog.ENABLE_DISTORT_TRANSFORMATION = MOHO.MSG_BASE + 7
MR_CurveToolSettingsDialog.CLICK_TO_SELECT = MOHO.MSG_BASE + 8

function MR_CurveToolSettingsDialog:new()
	local d = LM.GUI.SimpleDialog(MR_CurveTool:Localize('UILabel'), MR_CurveToolSettingsDialog)
    local l = d:GetLayout()
	
	d.drawInZeroFrameCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw in zero frame'), self.DRAW_IN_ZERO_FRAME)
    l:AddChild(d.drawInZeroFrameCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.drawInNonZeroFrameCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw in non zero frames'), self.DRAW_IN_NON_ZERO_FRAME)
    l:AddChild(d.drawInNonZeroFrameCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.alwaysDrawOnFBFCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Always draw on FBF'), self.ALWAYS_DRAW_ON_FBF)
    l:AddChild(d.alwaysDrawOnFBFCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.drawBehindCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Draw behind'), self.DRAW_BEHIND)
    l:AddChild(d.drawBehindCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.usePeakForCornersCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Use Peak for corners'), self.USE_PEAK_FOR_CORNERS)
	d.usePeakForCornersCheck:SetToolTip(MR_CurveTool:Localize('Use Peak for corners Tooltip'))
    l:AddChild(d.usePeakForCornersCheck, LM.GUI.ALIGN_LEFT, 0)
	
	l:AddChild(LM.GUI.Divider(false), LM.GUI.ALIGN_FILL)
	
	d.showAllHandlesCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Show all handles'), self.SHOW_ALL_HANDLES)
    l:AddChild(d.showAllHandlesCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.enableSkewTransformationCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Enable skew transformation'), self.ENABLE_SKEW_TRANSFORMATION)
    l:AddChild(d.enableSkewTransformationCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.enableDistortTransformationCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Enable distort transformation'), self.ENABLE_DISTORT_TRANSFORMATION)
    l:AddChild(d.enableDistortTransformationCheck, LM.GUI.ALIGN_LEFT, 0)
	
	d.clickToSelectCheck = LM.GUI.CheckBox(MR_CurveTool:Localize('Click to select'), self.CLICK_TO_SELECT)
    l:AddChild(d.clickToSelectCheck, LM.GUI.ALIGN_LEFT, 0)
	
	return d
end

function MR_CurveToolSettingsDialog:UpdateWidgets(moho)
    self.drawInZeroFrameCheck:SetValue(MR_CurveTool.drawInZeroFrame)
    self.drawInNonZeroFrameCheck:SetValue(MR_CurveTool.drawInNonZeroFrame)
    self.alwaysDrawOnFBFCheck:SetValue(MR_CurveTool.alwaysDrawOnFBF)
    self.drawBehindCheck:SetValue(MR_CurveTool.drawBehind)
    self.usePeakForCornersCheck:SetValue(MR_CurveTool.usePeakForCorners)
    self.showAllHandlesCheck:SetValue(MR_CurveTool.showAllHandles)
    self.enableSkewTransformationCheck:SetValue(MR_CurveTool.enableSkewTransformation)
    self.enableDistortTransformationCheck:SetValue(MR_CurveTool.enableDistortTransformation)
    self.clickToSelectCheck:SetValue(MR_CurveTool.clickToSelect)
end

function MR_CurveToolSettingsDialog:OnOK(moho)
    MR_CurveTool.drawInZeroFrame = self.drawInZeroFrameCheck:Value()
    MR_CurveTool.drawInNonZeroFrame = self.drawInNonZeroFrameCheck:Value()
    MR_CurveTool.alwaysDrawOnFBF = self.alwaysDrawOnFBFCheck:Value()
    MR_CurveTool.drawBehind = self.drawBehindCheck:Value()
    MR_CurveTool.usePeakForCorners = self.usePeakForCornersCheck:Value()
    MR_CurveTool.showAllHandles = self.showAllHandlesCheck:Value()
    MR_CurveTool.enableSkewTransformation = self.enableSkewTransformationCheck:Value()
    MR_CurveTool.enableDistortTransformation = self.enableDistortTransformationCheck:Value()
    MR_CurveTool.clickToSelect = self.clickToSelectCheck:Value()
end

function MR_CurveToolSettingsDialog:HandleMessage(msg)
	if msg == self.DRAW_IN_ZERO_FRAME then
		MR_CurveTool.drawInZeroFrame = self.drawInZeroFrameCheck:Value()
	elseif msg == self.DRAW_IN_NON_ZERO_FRAME then
		MR_CurveTool.drawInNonZeroFrame = self.drawInNonZeroFrameCheck:Value()
	elseif msg == self.ALWAYS_DRAW_ON_FBF then
		MR_CurveTool.alwaysDrawOnFBF = self.alwaysDrawOnFBFCheck:Value()	
	elseif msg == self.DRAW_BEHIND then
		MR_CurveTool.drawBehind = self.drawBehindCheck:Value()	
	elseif msg == self.USE_PEAK_FOR_CORNERS then
		MR_CurveTool.usePeakForCorners = self.usePeakForCornersCheck:Value()	
    elseif msg == self.SHOW_ALL_HANDLES then
		MR_CurveTool.showAllHandles = self.showAllHandlesCheck:Value()
		if MR_CurveTool.mohoVersion > 13 then
			local helper = MOHO.ScriptInterfaceHelper:new_local()
			local moho = helper:MohoObject()
			moho.view:DrawMe()
			helper:delete()
		end	
    elseif msg == self.ENABLE_SKEW_TRANSFORMATION then
		MR_CurveTool.enableSkewTransformation = self.enableSkewTransformationCheck:Value()
    elseif msg == self.ENABLE_DISTORT_TRANSFORMATION then
		MR_CurveTool.enableDistortTransformation = self.enableDistortTransformationCheck:Value()
    elseif msg == self.CLICK_TO_SELECT then
		MR_CurveTool.clickToSelect = self.clickToSelectCheck:Value()
	end	
end	

MR_CurveTool.SINGLE_CURVE_MODE = MOHO.MSG_BASE
MR_CurveTool.POINTS = MOHO.MSG_BASE + 1
MR_CurveTool.CURVATURE = MOHO.MSG_BASE + 2
MR_CurveTool.CURVATURE_SC = MOHO.MSG_BASE + 3
MR_CurveTool.SHOW_HANDLES = MOHO.MSG_BASE + 4
MR_CurveTool.FIXED_HANDLES = MOHO.MSG_BASE + 5
MR_CurveTool.USE_BEZIER_HANDLES = MOHO.MSG_BASE + 6
MR_CurveTool.THRESHOLD = MOHO.MSG_BASE + 7
MR_CurveTool.AUTOWELD = MOHO.MSG_BASE + 8
MR_CurveTool.SHARP_CORNERS = MOHO.MSG_BASE + 9
MR_CurveTool.AUTO_FILL = MOHO.MSG_BASE + 10
MR_CurveTool.FILLCOLOR = MOHO.MSG_BASE + 11
MR_CurveTool.AUTO_LINE = MOHO.MSG_BASE + 12
MR_CurveTool.LINECOLOR = MOHO.MSG_BASE + 13
MR_CurveTool.LINEWIDTH = MOHO.MSG_BASE + 14

MR_CurveTool.PIVOT_UP_LEFT = MOHO.MSG_BASE + 15
MR_CurveTool.PIVOT_MID_LEFT = MOHO.MSG_BASE + 16
MR_CurveTool.PIVOT_DOWN_LEFT = MOHO.MSG_BASE + 17

MR_CurveTool.PIVOT_UP_MID = MOHO.MSG_BASE + 18
MR_CurveTool.PIVOT_CENTER = MOHO.MSG_BASE + 19
MR_CurveTool.PIVOT_DOWN_MID = MOHO.MSG_BASE + 20

MR_CurveTool.PIVOT_UP_RIGHT = MOHO.MSG_BASE + 21
MR_CurveTool.PIVOT_MID_RIGHT = MOHO.MSG_BASE + 22
MR_CurveTool.PIVOT_DOWN_RIGHT = MOHO.MSG_BASE + 23

function MR_CurveTool:DoLayout(moho, layout)
	self.dlog = MR_CurveToolSettingsDialog:new()
    self.settingsPopup = LM.GUI.PopupDialog(self:Localize('Settings'), false, 0)
    self.settingsPopup:SetDialog(self.dlog)
    layout:AddChild(self.settingsPopup, LM.GUI.ALIGN_LEFT, 0)
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	if self.singleCurveMode then
		self.singleCurveModeImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_single_curve_mode', self:Localize('Single curve mode'), true, self.SINGLE_CURVE_MODE, false)
		layout:AddChild(self.singleCurveModeImageButton, LM.GUI.ALIGN_LEFT, 0)
	else
		self.singleCurveModeImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_curve_mode', self:Localize('Curve mode'), true, self.SINGLE_CURVE_MODE, false)
		layout:AddChild(self.singleCurveModeImageButton, LM.GUI.ALIGN_LEFT, 0)
	end
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	if self.singleCurveMode then
		self.curvatureSCInput = LM.GUI.TextControl(50, '0.3', self.CURVATURE_SC, LM.GUI.FIELD_FLOAT, self:Localize('Curvature'))
		self.curvatureSCInput:SetWheelInc(0.05)
		layout:AddChild(self.curvatureSCInput, LM.GUI.ALIGN_LEFT, 0)
		self.curvatureInput = nil
	else
		self.curvatureInput = LM.GUI.TextControl(50, '0.3', self.CURVATURE, LM.GUI.FIELD_FLOAT, self:Localize('Curvature'))
		self.curvatureInput:SetWheelInc(0.05)
		layout:AddChild(self.curvatureInput, LM.GUI.ALIGN_LEFT, 0)
		self.curvatureSCInput = nil
	end
	
	self.showHandlesButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_show_handles', self:Localize('Show handles tooltip'), true, self.SHOW_HANDLES, false)
	layout:AddChild(self.showHandlesButton, LM.GUI.ALIGN_LEFT, 0)
		
	self.fixedHandlesImageButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_fixed_handles', self:Localize('Fixed handles tooltip'), true, self.FIXED_HANDLES, false)
	layout:AddChild(self.fixedHandlesImageButton, LM.GUI.ALIGN_LEFT, 0)
		
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	if self.singleCurveMode then
		self.pointsInput = LM.GUI.TextControl(0, '100', self.POINTS, LM.GUI.FIELD_INT, self:Localize('Points'))
		layout:AddChild(self.pointsInput, LM.GUI.ALIGN_LEFT, 0)
	else
		self.useBezierHandlesCheck = LM.GUI.CheckBox(self:Localize('Bezier drawing mode'), self.USE_BEZIER_HANDLES)
		layout:AddChild(self.useBezierHandlesCheck)
		
		self.thresholdInput = LM.GUI.TextControl(50, '0.3', self.THRESHOLD, LM.GUI.FIELD_FLOAT, self:Localize('Threshold'))
		self.thresholdInput:SetWheelInc(0.01)
		layout:AddChild(self.thresholdInput, LM.GUI.ALIGN_LEFT, 0)
	end
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	self.autoWeldCheck = LM.GUI.CheckBox(self:Localize('Auto-weld'), self.AUTOWELD)
	layout:AddChild(self.autoWeldCheck)
	
	if not self.singleCurveMode then
		self.sharpCornersCheck = LM.GUI.CheckBox(self:Localize('Sharp corners'), self.SHARP_CORNERS)
		layout:AddChild(self.sharpCornersCheck)
	end
	
	self.fillCheck = LM.GUI.CheckBox(self:Localize('Auto-fill:'), self.AUTO_FILL)
	layout:AddChild(self.fillCheck)
	self.fillCol = LM.GUI.ShortColorSwatch(true, self.FILLCOLOR)
	layout:AddChild(self.fillCol)

	self.lineCheck = LM.GUI.CheckBox(self:Localize('Auto-stroke:'), self.AUTO_LINE)
	layout:AddChild(self.lineCheck)
	self.lineCol = LM.GUI.ShortColorSwatch(true, self.LINECOLOR)
	layout:AddChild(self.lineCol)

	layout:AddChild(LM.GUI.StaticText(self:Localize('Width:')))
	self.lineWidth = LM.GUI.TextControl(0, "00.0000", self.LINEWIDTH, LM.GUI.FIELD_UFLOAT)
	self.lineWidth:SetWheelInc(1.0)
	self.lineWidth:SetWheelInteger(true)
	layout:AddChild(self.lineWidth)
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	layout:PushV()
	
		self.pivotLUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left up corner'), false, self.PIVOT_UP_LEFT, false)
		layout:AddChild(self.pivotLUButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotLMButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left'), false, self.PIVOT_MID_LEFT, false)
		layout:AddChild(self.pivotLMButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotLDButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to left down corner'), false, self.PIVOT_DOWN_LEFT, false)
		layout:AddChild(self.pivotLDButton, LM.GUI.ALIGN_LEFT, 0)
	
	layout:Pop()
	
	layout:AddPadding(-14)
	
	layout:PushV()
	
		self.pivotMUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to up'), false, self.PIVOT_UP_MID, false)
		layout:AddChild(self.pivotMUButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotCButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to center'), false, self.PIVOT_CENTER, false)
		layout:AddChild(self.pivotCButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotMUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to down'), false, self.PIVOT_DOWN_MID, false)
		layout:AddChild(self.pivotMUButton, LM.GUI.ALIGN_LEFT, 0)
	
	layout:Pop()
	
	layout:AddPadding(-14)
	
	layout:PushV()
	
		self.pivotRUButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right up corner'), false, self.PIVOT_UP_RIGHT, false)
		layout:AddChild(self.pivotRUButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotRMButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right'), false, self.PIVOT_MID_RIGHT, false)
		layout:AddChild(self.pivotRMButton, LM.GUI.ALIGN_LEFT, 0)
		
		layout:AddPadding(-14)
		
		self.pivotRDButton = LM.GUI.ImageButton('ScriptResources/mr_curve_tool/mr_small_button', self:Localize('Set pivot to right down corner'), false, self.PIVOT_DOWN_RIGHT, false)
		layout:AddChild(self.pivotRDButton, LM.GUI.ALIGN_LEFT, 0)
	
	layout:Pop()
	
	layout:AddChild(LM.GUI.StaticText('v'..MR_CurveTool:Version()))
end

function MR_CurveTool:UpdateWidgets(moho)
	if self.reset then
		self.reset = false
		local frame = moho.frame
		if frame == 0 then
			moho:SetCurFrame(1)
			moho:SetCurFrame(0)
		elseif frame ~= 0 then
			moho:SetCurFrame(0)
			moho:SetCurFrame(frame)
		end
	end

	if self.skewCursor == nil then
		self.skewCursor = LM.GUI.Cursor("ScriptResources/mr_curve_tool/mr_cursor_skew", 1, 1)
	end	
	if self.distortCursor == nil then
		self.distortCursor = LM.GUI.Cursor("ScriptResources/mr_curve_tool/mr_cursor_distort", 1, 1)
	end
	
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	self.singleCurveModeImageButton:SetValue(self.singleCurveMode)
	self.showHandlesButton:SetValue(self.showHandles)
	self.fixedHandlesImageButton:SetValue(self.fixedHandles)

	if self.curvatureInput ~= nil then
		self.curvatureInput:SetValue(self.curvature)
		self.useBezierHandlesCheck:SetValue(self.useBezierHandles)
		self.thresholdInput:SetValue(self.threshold)
		self.thresholdInput:Enable(self.useBezierHandles)
		self.sharpCornersCheck:SetValue(self.sharpCorners)
	end

	if self.curvatureSCInput ~= nil then
		self.curvatureSCInput:SetValue(self.curvatureSC)
		self.pointsInput:SetValue(self.points)
	end	

	self.autoWeldCheck:SetValue(self.autoWeld)
	self.fillCheck:SetValue(self.autoFill)
	self.lineCheck:SetValue(self.autoStroke)
	
	if moho.drawingLayer:CurrentAction() ~= "" then
		self.curvatureInput:Enable(false)
		self.useBezierHandlesCheck:Enable(false)
		self.thresholdInput:Enable(false)
		self.autoWeldCheck:Enable(false)
		self.sharpCornersCheck:Enable(false)
		self.fillCheck:Enable(false)
		self.lineCheck:Enable(false)
		self.lineWidth:Enable(false)
	end
	
	local style = moho:CurrentEditStyle()
	if (style ~= nil) then
		self.fillCol:SetValue(style.fFillCol.value)
		self.lineCol:SetValue(style.fLineCol.value)
		self.lineWidth:SetValue(style.fLineWidth * moho.document:Height())
	else
		local fillColor = LM.rgb_color:new_local()
		fillColor.r = self.fillColorR
		fillColor.g = self.fillColorG
		fillColor.b = self.fillColorB
		fillColor.a = self.fillColorA
		
		local strokeColor = LM.rgb_color:new_local()
		strokeColor.r = self.strokeColorR
		strokeColor.g = self.strokeColorG
		strokeColor.b = self.strokeColorB
		strokeColor.a = self.strokeColorA
		
		self.fillCol:SetValue(fillColor)
		self.lineCol:SetValue(strokeColor)
		self.lineWidth:SetValue(self.strokeWidth)
	end
end

function MR_CurveTool:HandleMessage(moho, view, msg)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	local style = moho:CurrentEditStyle()
	
	if msg == self.SINGLE_CURVE_MODE then
		self.singleCurveMode = self.singleCurveModeImageButton:Value()
		local drawingToolsNonZero = MOHO.MohoGlobals.DisableDrawingToolsNonZero
		if not drawingToolsNonZero then
			MOHO.MohoGlobals.DisableDrawingToolsNonZero = true
		end
		local frame = moho.frame
		if frame == 0 then
			moho:SetCurFrame(1)
			moho:SetCurFrame(0)
		elseif frame ~= 0 then
			moho:SetCurFrame(0)
			moho:SetCurFrame(frame)
		end
		if not drawingToolsNonZero then
			MOHO.MohoGlobals.DisableDrawingToolsNonZero = drawingToolsNonZero
		end
	elseif msg == self.POINTS then
		self.points = LM.Clamp(self.pointsInput:Value(), 1, 100)
		self.pointsInput:SetValue(self.points)
	elseif msg == self.CURVATURE then
		self.curvature = LM.Clamp(self.curvatureInput:Value(), MOHO.PEAKED + self.peakedCorner, 1)
		self.curvatureInput:SetValue(self.curvature)
	elseif msg == self.CURVATURE_SC then
		self.curvatureSC = LM.Clamp(self.curvatureSCInput:Value(), 0, 1)
		self.curvatureSCInput:SetValue(self.curvatureSC)	
	elseif msg == self.SHOW_HANDLES then
		self.showHandles = self.showHandlesButton:Value()
	elseif msg == self.FIXED_HANDLES then
		self.fixedHandles = self.fixedHandlesImageButton:Value()
	elseif msg == self.USE_BEZIER_HANDLES then
		self.useBezierHandles = self.useBezierHandlesCheck:Value()
		self.thresholdInput:Enable(self.useBezierHandles)
	elseif msg == self.THRESHOLD then
		self.threshold = LM.Clamp(self.thresholdInput:Value(), 0.01, 0.3)
		self.thresholdInput:SetValue(self.threshold)
	elseif msg == self.AUTOWELD then
		self.autoWeld = self.autoWeldCheck:Value()
	elseif msg == self.SHARP_CORNERS then
		self.sharpCorners = self.sharpCornersCheck:Value()
	elseif msg == self.AUTO_FILL then
		self.autoFill = self.fillCheck:Value()
		moho:UpdateUI()
	elseif msg == self.FILLCOLOR then
		if (style ~= nil) then
			style.fFillCol:SetValue(moho.layerFrame, self.fillCol:Value())	
		end
		local fillColor = self.fillCol:Value()
		self.fillColorR = fillColor.r
		self.fillColorG = fillColor.g
		self.fillColorB = fillColor.b
		self.fillColorA = fillColor.a
		moho:UpdateUI()	
	elseif msg == self.AUTO_LINE then
		self.autoStroke = self.lineCheck:Value()
		moho:UpdateUI()	
	elseif msg == self.LINECOLOR then
		if (style ~= nil) then
			style.fLineCol:SetValue(moho.layerFrame, self.lineCol:Value())	
		end
		local strokeColor = self.lineCol:Value()
		self.strokeColorR = strokeColor.r
		self.strokeColorG = strokeColor.g
		self.strokeColorB = strokeColor.b
		self.strokeColorA = strokeColor.a	
		moho:UpdateUI()
	elseif (msg == self.LINEWIDTH) then
		local lineWidth = self.lineWidth:FloatValue()
		lineWidth = LM.Clamp(lineWidth, 0.25, 256)
		if (style ~= nil) then
			style.fLineWidth = lineWidth / moho.document:Height()
		end
		self.strokeWidth = lineWidth
		moho:UpdateUI()
	elseif (msg == self.PIVOT_UP_LEFT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMax.x, self.selectedMin.y)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_MID_LEFT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_DOWN_LEFT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMax.x, self.selectedMax.y)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_UP_MID) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_CENTER) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_DOWN_MID) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_UP_RIGHT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMin.x, self.selectedMin.y)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_MID_RIGHT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	elseif (msg == self.PIVOT_DOWN_RIGHT) then
		self.selectedMin = LM.Vector2:new_local()
		self.selectedMax = LM.Vector2:new_local()
		mesh:SelectedBounds(self.selectedMin, self.selectedMax)
		local centerVec = LM.Vector2:new_local()
		centerVec:Set(self.selectedMin.x, self.selectedMax.y)	
		self.centerVec = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - centerVec
		self.centerVec = self.centerVec + self.pivotOffset
	end
end

function MR_CurveTool:GetColosestVec(moho, view, vec1, vec2)
	local testVec1 = LM.Vector2:new_local()
	testVec1:Set(vec1)
	local testVec2 = LM.Vector2:new_local()
	testVec2:Set(vec2)
	
	local p1 = LM.Point:new_local()
	local p2 = LM.Point:new_local()
	local m = LM.Matrix:new_local()
	moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)
	m:Transform(testVec1)
	m:Transform(testVec2)
	view:Graphics():WorldToScreen(testVec1, p1)
	view:Graphics():WorldToScreen(testVec2, p2)
	p1.x = p1.x - p2.x
	p1.y = p1.y - p2.y
	local closest = (p1.x * p1.x) + (p1.y * p1.y)
	return closest
end

function MR_CurveTool:AddPointOnCurve(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	local sharpCorners = false
	if (mouseEvent.ctrlKey and not self.sharpCorners) or (not mouseEvent.ctrlKey and self.sharpCorners) then
		sharpCorners = true
	end
	
	local curveID = -1
	local segID = -1
	local newPoint
	
	if (not mouseEvent.altKey and self.autoWeld) or (mouseEvent.altKey and not self.autoWeld) then
		local pickWidth = 5
		curveID = -1
		segID = -1
		curveID, segID = mouseEvent.view:PickEdge(mouseEvent.pt, curveID, segID, pickWidth)
	end

	if segID >= 0 then
		if (curveID >= 0) then -- add a point in the middle of some curve
			local v = mesh:Curve(curveID):ClosestPointOnSegment(segID, mouseEvent.drawingVec, true, true)
			mesh:AddPoint(v, curveID, segID, moho.layerFrame, self.fixedHandles, true)
			newPoint = mesh:Point(mesh:CountPoints() - 1)
		else -- add a new curve segment
			mesh:AddPoint(mouseEvent.drawingVec, -1, moho.layerFrame)
			if (sharpCorners) then
				mesh:Point(mesh:CountPoints() - 1):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
				mesh:Point(mesh:CountPoints() - 2):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
			end
			self.secondPtID = mesh:CountPoints() - 2
			newPoint = mesh:Point(self.secondPtID)
		end
		if (sharpCorners) then
			mesh:Point(mesh:CountPoints() - 1):SetCurvature(MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
		end
	end	
	return newPoint
end

function MR_CurveTool:CleaUpAllPoints(moho)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	if (moho.layerFrame > 0) then
		for i=0, mesh:CountPoints()-1 do
			self:ClearPointKeys(moho, i)
		end
	end
end

function MR_CurveTool:ClearPointKeys(moho, ptID)
	local mesh = moho:DrawingMesh()
	if mesh == nil or not ptID then
		return
	end
	
	if (moho.layerFrame > 0) then
		if (ptID >= 0 and ptID < mesh:CountPoints()) then
			local point = mesh:Point(ptID)
			point.fAnimPos:SetValue(0, point.fAnimPos.value) point.fAnimPos:DeleteKey(moho.layerFrame)
			point.fWidth:SetValue(0, 1) point.fWidth:DeleteKey(moho.layerFrame)
			point.fColor:SetValue(0, point.fColor.value) point.fColor:DeleteKey(moho.layerFrame)
			point.fColorStrength:SetValue(0, point.fColorStrength.value) point.fColorStrength:DeleteKey(moho.layerFrame)
			for i = 0, point:CountCurves() - 1 do
				local curve = nil
				local ptPos = -1
				curve, ptPos = point:Curve(i, ptPos)
				if curve ~= nil then
					curve:SetCurvature(ptPos, curve:GetCurvature(ptPos, moho.layerFrame), 0)
					curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, true), 0, true)
					curve:SetWeight(ptPos, curve:GetWeight(ptPos, moho.layerFrame, false), 0, false)
					curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, true), 0, true)
					curve:SetOffset(ptPos, curve:GetOffset(ptPos, moho.layerFrame, false), 0, false)
					if self.isMoho13_5_3 then
						curve:DeleteCurvatureKey(ptPos, moho.layerFrame)
					end
				end
			end	
		end
	end
end

function MR_CurveTool:IsPointEdge(moho, mesh, point, endPoint)
	if point:IsEndpoint() and endPoint then
		return false
	end
	local edgePointsList = self:CollectEdgePoints(moho, mesh, point)
	if #edgePointsList > 0 then
		return true
	else	
		return false
	end
end

function MR_CurveTool:ArePointsConnected(moho, mesh, point1, point2)
	for i=0, point1:CountCurves()-1 do
		local curve = point1:Curve(i, -1)
		local curveID = mesh:CurveID(curve)
		if point2:IsPointOnCurve(curveID) then
			return true
		end
	end	
	return false
end

function MR_CurveTool:FindFirstEdgePointID(moho, mesh, point)
	if point:IsEndpoint() then
		return -1
	end
	local pointID = -1
	for i=0, point:CountCurves()-1 do
		local pointsList = {}
		pointsList.curvePointID = {}
		local curve = point:Curve(i, -1)
		local isCurveEdge = false
		local direction = true
		local curveLength = curve:CountPoints()
		for p=0, curveLength-1 do
			local curvePoint = curve:Point(p)
			local pointID = -1
			if curvePoint == point then
				if p == 0 then
					direction = true
					isCurveEdge = true
					pointID = 0
				elseif p == curveLength-1 then
					direction = false
					isCurveEdge = true
					pointID = p
				end
				if pointID >= 0 then
					return pointID
				end	
			end
		end
	end
	return -1
end

function MR_CurveTool:CollectEdgePoints(moho, mesh, point)
	local curvesList = {}
	curvesList.curve = {}
	curvesList.meshCurveID = {}
	curvesList.direction = {}
	for i=0, point:CountCurves()-1 do
		local pointsList = {}
		pointsList.curvePointID = {}
		local curve = point:Curve(i, -1)
		local isCurveEdge = false
		local direction = true
		local curveLength = curve:CountPoints()
		if not curve.fClosed then
			for p=0, curveLength-1 do
				local curvePoint = curve:Point(p)
				local pointID = -1
				if curvePoint == point then
					if p == 0 then
						direction = true
						isCurveEdge = true
						pointID = 0
					elseif p == curveLength-1 then
						direction = false
						isCurveEdge = true
						pointID = p
					end
					if pointID >= 0 then
						table.insert(pointsList.curvePointID, pointID)
					end	
				end
			end
			if isCurveEdge then
				table.insert(curvesList, pointsList)
				table.insert(curvesList.curve, i)
				table.insert(curvesList.meshCurveID, mesh:CurveID(curve))
				table.insert(curvesList.direction, direction)
			end
		end	
	end
	return curvesList
end

function MR_CurveTool:CreateShape(moho, mesh, curve, filled)
	mesh:SelectNone()
	
	if curve == nil then
		return
	end	
	
	curve:SelectCurvePoints()
	local style = moho:CurrentEditStyle()
	moho.view:DrawMe()
	local shapeID = moho:CreateShape(filled, false, 0)
	if (shapeID >= 0) then
		local shape = mesh:Shape(shapeID)
		
		shape.fSelected = true
		if (shape.fFillAllowed) then
			shape.fHasFill = self.autoFill
			if not style then
				local fillColor = LM.rgb_color:new_local()
				fillColor.r = self.fillColorR
				fillColor.g = self.fillColorG
				fillColor.b = self.fillColorB
				fillColor.a = self.fillColorA
				shape.fMyStyle.fFillCol:SetValue(0, fillColor)
			end
		end
		shape.fHasOutline = self.autoStroke
		if not style then
			local strokeColor = LM.rgb_color:new_local()
			strokeColor.r = self.strokeColorR
			strokeColor.g = self.strokeColorG
			strokeColor.b = self.strokeColorB
			strokeColor.a = self.strokeColorA
			shape.fMyStyle.fLineWidth = self.strokeWidth / moho.document:Height()
			shape.fMyStyle.fLineCol:SetValue(0, strokeColor)
		end
		if self.drawBehind then
			mesh:LowerShape(shapeID, true)
			shapeID = 0
		end
		moho:UpdateSelectedChannels()
	end
	mesh:SelectNone()
	return shapeID
end

function MR_CurveTool:CloseCurve(moho, point)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	self.drawingStatus = false
	self.drawWeldPoint = false
	self.startPoint = -1
	local lastPointID = mesh:CountPoints() -1
	if lastPointID >= 1 then
		local point = mesh:Point(lastPointID)
		point.fAnimPos:SetValue(moho.layerFrame, point.fPos)
	end
	self:ClearPointKeys(moho, self.selectedPointID)
	self:ClearPointKeys(moho, self.lastSelectedPointID)
	self:ClearPointKeys(moho, self.lastPointID)

	if self.autoStroke and point then
		local curve, where = point:Curve(point:CountCurves()-1, -1)
		local shapeID = self:CreateShape(moho, mesh, curve, false)
	end
	self.selectedPointID = -1

	mesh:SelectNone()
	moho.view:DrawMe()
	moho:UpdateUI()
	self.isCurveEnded = true
end

function MR_CurveTool:FindLastCurvePoint(moho, point)
	local where = -1
	local curve, where = point:Curve(point:CountCurves()-1, where)
	local curvePointID = curve:PointID(point)
	for i=0, curve:CountPoints()-1 do
		local curvePoint = curve:Point(i)
		if curvePoint == point and i > curvePointID then
			curvePointID = i
		end
	end
	return curvePointID
end

function MR_CurveTool:TestForClosestHandle(moho, mouseEvent)
	self.selID = -1
	self.handleSide = 0

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	local g = mouseEvent.view:Graphics()
	local layerMatrix = LM.Matrix:new_local()
	moho.drawingLayer:GetFullTransform(moho.layerFrame, layerMatrix, moho.document)
	g:Push()
	g:ApplyMatrix(layerMatrix)
	self.handleCurveID = 0
	local minDistance = 30
	local markerR = 6
	local pt = LM.Point:new_local()
	if self.showHandles then
		for i = 0, mesh:CountCurves() - 1 do
			local curve = mesh:Curve(i)
			for j = 0, curve:CountPoints() - 1 do
				if (not curve:Point(j).fHidden and ((curve:Point(j).fSelected and not self.showAllHandles) or self.showAllHandles)) then
					if (math.abs(curve:GetCurvature(j, moho.layerFrame)) > MOHO.PEAKED + 0.00001) then
						local testHandle = curve:GetControlHandle(j, moho.layerFrame, true)
						mouseEvent.view:Graphics():WorldToScreen(testHandle, pt)
						if (not(j == 0 and not curve.fClosed)) then
							local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
							if (distance < minDistance) then
								minDistance = distance
								self.selID = mesh:PointID(curve:Point(j))
								self.startHandle = testHandle
								self.handleSide = -1
								self.handleCurveID = i
								self.handlePointID = j
							end
						end
						testHandle = curve:GetControlHandle(j, moho.layerFrame, false)
						mouseEvent.view:Graphics():WorldToScreen(testHandle, pt)
						if (not(j == curve:CountPoints() - 1 and not curve.fClosed)) then
							local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
							if (distance < minDistance) then
								minDistance = distance
								self.selID = mesh:PointID(curve:Point(j))
								self.startHandle = testHandle
								self.handleSide = 1
								self.handleCurveID = i
								self.handlePointID = j
							end
						end
					end
				end
			end
		end
	end
	local ptID = mesh:ClosestPoint(mouseEvent.startVec)
	if (ptID >= 0) then
		local selPt = mesh:Point(ptID)
		mouseEvent.view:Graphics():WorldToScreen(selPt.fPos, pt)
		local distance = math.sqrt((pt.x - mouseEvent.pt.x) * (pt.x - mouseEvent.pt.x) + (pt.y - mouseEvent.pt.y) * (pt.y - mouseEvent.pt.y))
		if (distance < minDistance) then
			minDistance = distance
			self.selID = ptID
			self.handleSide = 0
		end
	end
	if self.selID >= 0 then
		mesh:SelectNone()
		mesh:Point(self.selID).fSelected = true
	end	
	
	-- This code is copied from Alexandra Evseeva's scripts.
	if not self.handlePointID then
		g:Pop()
		return
	end

	if self.showHandles and self.handleSide ~= 0 then
		local keyValue = AE_Utilities:GetBezierValue(mesh:Curve(self.handleCurveID), self.handlePointID, moho.layerFrame, (self.handleSide == -1))
		self.delta = self.startHandle - keyValue
		self.correctionMode = true

		local pointDelta = mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.layerFrame)
		self.pointDelta = pointDelta

		local keyLength
		local resultLength
		local pp = self.handlePointID + self.handleSide
		if mesh:Curve(self.handleCurveID).fClosed then
			if pp < 0 then
				pp = mesh:Curve(self.handleCurveID):CountPoints()-1
			end
			if pp >= mesh:Curve(self.handleCurveID):CountPoints() then
				pp = 0
			end
		else
			if pp < 0 then
				pp = 0
			end
			if pp >= mesh:Curve(self.handleCurveID):CountPoints() then
				pp = mesh:Curve(self.handleCurveID):CountPoints()-1
			end    
		end

		if(pp == self.handlePointID) then 
			self.lengthMultiply = 1
			keyLength = 0.00001
			resultLength = 0.00001
		else
			keyLength = (mesh:Curve(self.handleCurveID):Point(pp).fAnimPos:GetValue(moho.layerFrame) - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fAnimPos:GetValue(moho.layerFrame)):Mag()
			resultLength = (mesh:Curve(self.handleCurveID):Point(pp).fPos - mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos):Mag()
			self.lengthMultiply = resultLength/keyLength
		end

		self.startWeight = mesh:Curve(self.handleCurveID):GetWeight(self.handlePointID, moho.layerFrame, (self.handleSide == -1))
		self.startOffset = mesh:Curve(self.handleCurveID):GetOffset(self.handlePointID, moho.layerFrame, (self.handleSide == -1)) 
		self.startFPos =  mesh:Curve(self.handleCurveID):Point(self.handlePointID).fPos
		self.startVector = self.startHandle - self.startFPos
		self.startVectorMag = self.startVector:Mag()

		local channelNumberBase = 0
		for p=0, mesh:PointID(mesh:Curve(self.handleCurveID):Point(self.handlePointID))-1 do
			local nextPoint = mesh:Point(p)
			channelNumberBase = channelNumberBase + nextPoint:CountCurves() * 5
		end  
		local curvatureChannel = moho.drawingLayer:Channel(3,channelNumberBase, moho.document)
		local weightChannel = moho:ChannelAsAnimVal(moho.drawingLayer:Channel(3,channelNumberBase+1+self.handleSide/2+0.5, moho.document)) 
		local curvatureDelta = AE_Utilities:SumActionInfluences(moho, moho.layerFrame, moho:ChannelAsAnimVal(curvatureChannel), moho.drawingLayer)
		local weightDelta = weightChannel.value - weightChannel:GetValue(moho.layerFrame)

		self.weightDelta = weightDelta
		self.weightMultiplier = resultLength * (mesh:Curve(self.handleCurveID):GetCurvature(self.handlePointID, moho.layerFrame) + curvatureDelta)
	end	
	g:Pop()
end

function MR_CurveTool:SelectedMeshBounds(moho, layer, mesh, frame, view)
	local bbox = LM.BBox:new_local()
	local min = LM.Vector2:new_local()
	local max = LM.Vector2:new_local()
	mesh:SelectedBounds(min, max)
	bbox.fMin:Set(min.x, min.y, 0)
	bbox.fMax:Set(max.x, max.y, 0)

	-- make sure the bounding box is not too thin in one direction
	local xLen = bbox.fMax.x - bbox.fMin.x
	local yLen = bbox.fMax.y - bbox.fMin.y
	if (xLen < yLen / 10.0) then
		local center = (bbox.fMin.x + bbox.fMax.x) / 2.0
		bbox.fMin.x = center - yLen / 10.0
		bbox.fMax.x = center + yLen / 10.0
	elseif (yLen < xLen / 10.0) then
		local center = (bbox.fMin.y + bbox.fMax.y) / 2.0
		bbox.fMin.y = center - xLen / 10.0
		bbox.fMax.y = center + xLen / 10.0
	end

	-- make sure the bounding box is not too small
	local minLength = 150
	local m = LM.Matrix:new_local()
	local v = LM.Vector2:new_local()
	local pt1 = LM.Point:new_local()
	local pt2 = LM.Point:new_local()

	layer:GetFullTransform(frame, m, moho.document)
	v:Set(bbox.fMin.x, bbox.fMin.y)
	m:Transform(v)
	view:Graphics():WorldToScreen(v, pt1)
	v:Set(bbox.fMax.x, bbox.fMax.y)
	m:Transform(v)
	view:Graphics():WorldToScreen(v, pt2)
	pt1 = pt2 - pt1
	local length = math.sqrt(pt1.x * pt1.x + pt1.y * pt1.y)
	if (length < minLength) then
		center = (bbox.fMin + bbox.fMax) / 2.0
		v = bbox.fMax - center
		bbox.fMax = center + v * (minLength / length) / 2.0
		v = bbox.fMin - center
		bbox.fMin = center + v * (minLength / length) / 2.0
	end
	
	return bbox
end

function MR_CurveTool:TestMousePoint(moho, mouseEvent)
	-- Returns what mode the tool would be in if the user clicked at the current mouse location
	if (self.keyMovement) then
		return 0
	end

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return 0
	end

	local bbox = self:SelectedMeshBounds(moho, moho.drawingLayer, mesh, moho.drawingFrame, mouseEvent.view)
	local v = LM.Vector2:new_local()
	local pt = LM.Point:new_local()
	local m = LM.Matrix:new_local()
	
	moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)

	-- test for uniform scaling
	v:Set(bbox.fMin.x, bbox.fMin.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- bottom left
		return 4
	end
	v:Set(bbox.fMin.x, bbox.fMax.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- top left
		return 2
	end
	v:Set(bbox.fMax.x, bbox.fMax.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- top right
		return 3
	end
	v:Set(bbox.fMax.x, bbox.fMin.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- bottom right
		return 5
	end

	-- test for X scaling
	v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- left
		return 6
	end
	v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- right
		return 7
	end
	
	-- test for Y scaling
	v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- bottom
		return 9
	end
	v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y)
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- top
		return 8
	end

	-- test for pivot point
	if (self.dragging) then
		v:Set(self.centerVec)
	else
		v = mesh:SelectedCenter()
		v = v + self.pivotOffset
	end
	m:Transform(v)
	mouseEvent.view:Graphics():WorldToScreen(v, pt)
	if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
		-- pivot point
		return 11
	end

	local rotWidth = bbox.fMax.x - bbox.fMin.x
	if (bbox.fMax.y - bbox.fMin.y > rotWidth) then
		rotWidth = bbox.fMax.y - bbox.fMin.y
	end
	rotWidth = rotWidth * 0.1
	
	if self.enableSkewTransformation then
		-- test for X skew
		v:Set(bbox.fMin.x - rotWidth, (bbox.fMin.y + bbox.fMax.y) * 0.5)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- left
			return 20
		end
		v:Set(bbox.fMax.x + rotWidth, (bbox.fMin.y + bbox.fMax.y) * 0.5)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- right
			return 21
		end
		
		-- test for Y skew
		v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y - rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- bottom
			return 22
		end
		v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y + rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- top
			return 23
		end
	end
	
	if self.enableDistortTransformation and self.selectedPoints > 2 then
		-- test for Distord
		v:Set(bbox.fMin.x - rotWidth, bbox.fMin.y - rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- bottom left
			return 24
		end
		v:Set(bbox.fMin.x - rotWidth, bbox.fMax.y + rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- top left
			return 25
		end
		v:Set(bbox.fMax.x + rotWidth, bbox.fMax.y + rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- top right
			return 26
		end
		v:Set(bbox.fMax.x + rotWidth, bbox.fMin.y - rotWidth)
		m:Transform(v)
		mouseEvent.view:Graphics():WorldToScreen(v, pt)
		if (math.abs(pt.x - mouseEvent.pt.x) < self.markerR and math.abs(pt.y - mouseEvent.pt.y) < self.markerR) then
			-- bottom right
			return 27
		end
	end
	
	-- test for translation outside the bounding box
	if (mouseEvent.drawingVec.x < bbox.fMin.x - rotWidth or mouseEvent.drawingVec.x > bbox.fMax.x + rotWidth or mouseEvent.drawingVec.y < bbox.fMin.y - rotWidth or mouseEvent.drawingVec.y > bbox.fMax.y + rotWidth) then
		return 0, true
	end
	
	-- test for rotation
	if (mouseEvent.drawingVec.x < bbox.fMin.x or mouseEvent.drawingVec.x > bbox.fMax.x or mouseEvent.drawingVec.y < bbox.fMin.y or mouseEvent.drawingVec.y > bbox.fMax.y) then
		return 1
	end

	return 0 -- translation inside the bounding box
end

function MR_CurveTool:OnMouseMoved_T(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (mouseEvent.ctrlKey) then -- hold down the control key to just select a single point and not move it
		return
	end
	
	self.endWeldVec:Set(-10000000, -10000000)

	local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec
	if (mouseEvent.shiftKey) then
		if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then
			curVec.y = 0
		else
			curVec.x = 0
		end
	end

	if (moho.gridOn) then
		moho:SnapToGrid(curVec)
	end
	mesh:TranslatePoints(curVec)

	self:AddPointKeyframe(moho, moho.layerFrame)
	
	if self.fixedHandles then
		mesh:PreserveHandlePositions(moho.layerFrame)
	end
	self.transformation = true
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved_S(moho, mouseEvent)
	if (self.numSel < 2) then
		return
	end

	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	local center = LM.Vector2:new_local()
	center:Set(self.centerVec)
	if (mouseEvent.altKey) then
		center:Set(self.centerVec)
	else
		if (self.mode == 6) then -- LEFT
			center:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		elseif (self.mode == 7) then -- RIGHT
			center:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		elseif (self.mode == 8) then -- TOP
			center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y)
		elseif (self.mode == 9) then -- BOTTOM
			center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y)
		elseif (self.mode == 4) then -- BL
			center:Set(self.selectedMax.x, self.selectedMax.y)
		elseif (self.mode == 2) then -- TL
			center:Set(self.selectedMax.x, self.selectedMin.y)
		elseif (self.mode == 3) then -- TR
			center:Set(self.selectedMin.x, self.selectedMin.y)
		elseif (self.mode == 5) then -- BR
			center:Set(self.selectedMin.x, self.selectedMax.y)	
		end
	end

	local scaling = LM.Vector2:new_local()

	scaling:Set(1, 1)
	-- scaling connected to actual drag amount
	local v1 = mouseEvent.drawingStartVec - center
	local v2 = mouseEvent.drawingVec - center
	scaling.x = v2.x / v1.x
	scaling.y = v2.y / v1.y

	if (self.mode == 6 or self.mode == 7) then
		-- horizontal scaling
		scaling.y = 1
		if (mouseEvent.shiftKey) then
			scaling.y = 1 / scaling.x
		end
	elseif (self.mode == 8 or self.mode == 9) then
		-- vertical scaling
		scaling.x = 1
		if (mouseEvent.shiftKey) then
			scaling.x = 1 / scaling.y
		end
	else
		if (not mouseEvent.shiftKey) then
			scaling.x = (scaling.x + scaling.y) / 2
			scaling.y = scaling.x
		end
	end

	local flip = false
	if (scaling.x * self.lastScaleX < -0.0001) then
		if (scaling.y * self.lastScaleY > 0.0001) then
			flip = true
		end
	elseif (scaling.y * self.lastScaleY < -0.0001) then
		if (scaling.x * self.lastScaleX > 0.0001) then
			flip = true
		end
	end
	mesh:ScalePoints(scaling.x, scaling.y, center, flip)
	self:AddPointKeyframe(moho, moho.layerFrame)

	local k = 1
	if scaling.x * scaling.y < 0 then
		k = -1
	end
	
	if (mouseEvent.altKey) then
		local v = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - v
	else
		local v = self.centerVec - center
		v.x = v.x * scaling.x
		v.y = v.y * scaling.y
		v = v + center
		self.pivotOffset = v - mesh:SelectedCenter()
	end

	if (flip) then
		self.lastScaleX = scaling.x
		self.lastScaleY = scaling.y
	end

	if self.fixedHandles then
		mesh:PreserveHandlePositions(moho.layerFrame)
	end
	self.transformation = true
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved_R(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	local angle = self.startAngle
	local v1 = self.lastVec - self.centerVec
	local v2 = mouseEvent.drawingVec - self.centerVec
	v2:Rotate(-math.atan2(v1.y, v1.x))
	angle = angle + math.atan2(v2.y, v2.x)
	self.startAngle = angle
	if (mouseEvent.shiftKey) then
		angle = angle / (math.pi / 4)
		angle = (math.pi / 4) * LM.Round(angle)
	end

	mesh:RotatePoints(angle, self.centerVec)
	self:AddPointKeyframe(moho, moho.layerFrame)

	self.lastVec:Set(mouseEvent.drawingVec)

	if self.fixedHandles then
		mesh:PreserveHandlePositions(moho.layerFrame)
	end
	self.transformation = true
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved_P(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec
	if (mouseEvent.shiftKey) then
		if (math.abs(mouseEvent.drawingVec.x - mouseEvent.drawingStartVec.x) > math.abs(mouseEvent.drawingVec.y - mouseEvent.drawingStartVec.y)) then
			curVec.y = 0
		else
			curVec.x = 0
		end
	end

	self.pivotOffset = self.startPivotOffset + curVec
	self.centerVec = mesh:SelectedCenter()
	self.centerVec = self.centerVec + self.pivotOffset

	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved_Skew(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	local center = LM.Vector2:new_local()
	center:Set(self.centerVec)
	if (mouseEvent.altKey) then
		center:Set(self.centerVec)
	else
		if (self.mode == 20) then -- LEFT
			center:Set(self.selectedMax.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		elseif (self.mode == 21) then -- RIGHT
			center:Set(self.selectedMin.x, (self.selectedMin.y + self.selectedMax.y) / 2.0)
		elseif (self.mode == 22) then -- TOP
			center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMax.y)
		elseif (self.mode == 23) then -- BOTTOM
			center:Set((self.selectedMin.x + self.selectedMax.x) / 2.0, self.selectedMin.y)
		end
	end
	local scaling = LM.Vector2:new_local()

	scaling:Set(1, 1)
	
	local v1 = mouseEvent.drawingStartVec
	local v2 = mouseEvent.drawingVec
	scaling.x = v2.x - v1.x
	scaling.y = v2.y - v1.y

	if (self.mode == 20 or self.mode == 21) then
		scaling.x = 1
	elseif (self.mode == 22 or self.mode == 23) then
		scaling.y = 1
	end
	local curVec = mouseEvent.drawingVec - mouseEvent.drawingStartVec
	for i, point in pairs(self.selList)do
		if self.mode == 20 then
			local divisor = self.minVec.x - center.x
			local newPos = LM.Vector2:new_local()
			local newX = point.fTempPos.x
			local newY = point.fTempPos.y + scaling.y * (point.fTempPos.x - center.x) / divisor
			point.fPos.x = newX
			point.fPos.y = newY
		elseif self.mode == 21 then
			local divisor = self.maxVec.x - center.x
			local newPos = LM.Vector2:new_local()
			local newX = point.fTempPos.x
			local newY = point.fTempPos.y + scaling.y * (point.fTempPos.x - center.x) / divisor
			point.fPos.x = newX
			point.fPos.y = newY
		elseif self.mode == 22 then
			local divisor = self.minVec.y - center.y
			local newPos = LM.Vector2:new_local()
			local newX = point.fTempPos.x + scaling.x * (point.fTempPos.y - center.y) / divisor
			local newY = point.fTempPos.y
			point.fPos.x = newX
			point.fPos.y = newY
		elseif self.mode == 23 then
			local divisor = self.maxVec.y - center.y
			local newPos = LM.Vector2:new_local()
			local newX = point.fTempPos.x + scaling.x * (point.fTempPos.y - center.y) / divisor
			local newY = point.fTempPos.y
			point.fPos.x = newX
			point.fPos.y = newY
		end	
    end
	
	if (mouseEvent.altKey) then
		local v = mesh:SelectedCenter()
		self.pivotOffset = self.centerVec - v
	else
		if self.mode == 20 then
			local divisor = self.minVec.x - center.x
			local newPos = LM.Vector2:new_local()
			local newX = self.centerVec.x
			local newY = self.centerVec.y + scaling.y * (self.centerVec.x - center.x) / divisor
			newPos:Set(newX, newY)
			self.pivotOffset:Set(newPos - mesh:SelectedCenter())
		elseif self.mode == 21 then
			local divisor = self.maxVec.x - center.x
			local newPos = LM.Vector2:new_local()
			local newX = self.centerVec.x
			local newY = self.centerVec.y + scaling.y * (self.centerVec.x - center.x) / divisor
			newPos:Set(newX, newY)
			self.pivotOffset:Set(newPos - mesh:SelectedCenter())
		elseif self.mode == 22 then
			local divisor = self.minVec.y - center.y
			local newPos = LM.Vector2:new_local()
			local newX = self.centerVec.x + scaling.x * (self.centerVec.y - center.y) / divisor
			local newY = self.centerVec.y
			newPos:Set(newX, newY)
			self.pivotOffset:Set(newPos - mesh:SelectedCenter())
		elseif self.mode == 23 then
			local divisor = self.maxVec.y - center.y
			local newPos = LM.Vector2:new_local()
			local newX = self.centerVec.x + scaling.x * (self.centerVec.y - center.y) / divisor
			local newY = self.centerVec.y
			newPos:Set(newX, newY)
			self.pivotOffset:Set(newPos - mesh:SelectedCenter())	
		end	
	end
	
	self:AddPointKeyframe(moho, moho.layerFrame)
	self.lastVec:Set(mouseEvent.drawingVec)

	if self.fixedHandles then
		mesh:PreserveHandlePositions(moho.layerFrame)
	end
	self.transformation = true
	mouseEvent.view:DrawMe()
end

function MR_CurveTool:OnMouseMoved_Distort(moho, mouseEvent)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	self.transformation = true
	if self.mode == 25 then -- 'topLeft
		self.topLeft.x = mouseEvent.vec.x - (self.clickPos.x - self.minVec.x)
		self.topLeft.y = mouseEvent.vec.y - (self.clickPos.y - self.maxVec.y)
	elseif self.mode == 26 then -- topRight
		self.topRight.x = mouseEvent.vec.x - (self.clickPos.x - self.maxVec.x)
		self.topRight.y = mouseEvent.vec.y - (self.clickPos.y - self.maxVec.y)
	elseif self.mode == 27 then -- bottomRight
		self.bottomRight.x = mouseEvent.vec.x - (self.clickPos.x - self.maxVec.x)
		self.bottomRight.y = mouseEvent.vec.y - (self.clickPos.y - self.minVec.y)
	elseif self.mode == 24 then -- bottomLeft
		self.bottomLeft.x = mouseEvent.vec.x - (self.clickPos.x - self.minVec.x)
		self.bottomLeft.y = mouseEvent.vec.y - (self.clickPos.y - self.minVec.y)
	end
	
	for k, v in pairs(self.ptlist)do
		local topPoint = LM.Vector2:new_local()
		local bottomPoint = LM.Vector2:new_local()
		local leftPoint = LM.Vector2:new_local()
		local rightPoint = LM.Vector2:new_local()
		
		local topAngle = math.atan2(self.topRight.y - self.topLeft.y, self.topRight.x - self.topLeft.x)
		local dx = self.topRight.x - self.topLeft.x
		local dy = self.topRight.y - self.topLeft.y
		local topdist = math.sqrt(dx * dx + dy * dy)
		topPoint.x = self.topLeft.x + math.cos(topAngle) * (topdist * self.horizonPercent[k])
		topPoint.y = self.topLeft.y + math.sin(topAngle) * (topdist * self.horizonPercent[k])
		
		local bottomAngle = math.atan2(self.bottomRight.y - self.bottomLeft.y, self.bottomRight.x - self.bottomLeft.x)
		local dx = self.bottomRight.x - self.bottomLeft.x
		local dy = self.bottomRight.y - self.bottomLeft.y
		local bottomdist = math.sqrt(dx * dx + dy * dy)
		bottomPoint.x = self.bottomLeft.x + math.cos(bottomAngle) * (bottomdist * self.horizonPercent[k])
		bottomPoint.y = self.bottomLeft.y + math.sin(bottomAngle) * (bottomdist * self.horizonPercent[k])
		
		local leftAngle = math.atan2(self.bottomLeft.y - self.topLeft.y, self.bottomLeft.x - self.topLeft.x)
		local dx = self.bottomLeft.x - self.topLeft.x
		local dy = self.bottomLeft.y - self.topLeft.y
		local leftdist = math.sqrt(dx * dx + dy * dy)
		leftPoint.x = self.topLeft.x + math.cos(leftAngle) * (leftdist * self.vertPercent[k])
		leftPoint.y = self.topLeft.y + math.sin(leftAngle) * (leftdist * self.vertPercent[k])
		
		local rightAngle = math.atan2(self.bottomRight.y - self.topRight.y, self.bottomRight.x - self.topRight.x)
		local dx = self.bottomRight.x - self.topRight.x
		local dy = self.bottomRight.y - self.topRight.y
		local rightdist = math.sqrt(dx * dx + dy * dy)
		rightPoint.x = self.topRight.x + math.cos(rightAngle) * (rightdist * self.vertPercent[k])
		rightPoint.y = self.topRight.y + math.sin(rightAngle) * (rightdist * self.vertPercent[k])

		local a1, a2, b1, b2, c1, c2
 
		a1 = bottomPoint.y - topPoint.y
		b1 = topPoint.x - bottomPoint.x
		c1 = bottomPoint.x * topPoint.y - topPoint.x * bottomPoint.y
		a2 = rightPoint.y - leftPoint.y
		b2 = leftPoint.x - rightPoint.x
		c2 = rightPoint.x * leftPoint.y - leftPoint.x * rightPoint.y
 
		local denom =a1 * b2 - a2 * b1;
		local newPos = LM.Vector2:new_local()
		newPos:Set((b1 * c2 - b2 * c1) / denom, (a2 * c1 - a1 * c2) / denom)

		v.fPos.x = newPos.x
		v.fPos.y = newPos.y
	end
	self:AddPointKeyframe(moho, moho.layerFrame)
	
	local topPoint = LM.Vector2:new_local()
	local bottomPoint = LM.Vector2:new_local()
	local leftPoint = LM.Vector2:new_local()
	local rightPoint = LM.Vector2:new_local()
	
	local topAngle = math.atan2(self.topRight.y - self.topLeft.y, self.topRight.x - self.topLeft.x)
	local dx = self.topRight.x - self.topLeft.x
	local dy = self.topRight.y - self.topLeft.y
	local topdist = math.sqrt(dx * dx + dy * dy)
	topPoint.x = self.topLeft.x + math.cos(topAngle) * (topdist * self.horizonPercentCenter)
	topPoint.y = self.topLeft.y + math.sin(topAngle) * (topdist * self.horizonPercentCenter)
	
	local bottomAngle = math.atan2(self.bottomRight.y - self.bottomLeft.y, self.bottomRight.x - self.bottomLeft.x)
	local dx = self.bottomRight.x - self.bottomLeft.x
	local dy = self.bottomRight.y - self.bottomLeft.y
	local bottomdist = math.sqrt(dx * dx + dy * dy)
	bottomPoint.x = self.bottomLeft.x + math.cos(bottomAngle) * (bottomdist * self.horizonPercentCenter)
	bottomPoint.y = self.bottomLeft.y + math.sin(bottomAngle) * (bottomdist * self.horizonPercentCenter)
	
	local leftAngle = math.atan2(self.bottomLeft.y - self.topLeft.y, self.bottomLeft.x - self.topLeft.x)
	local dx = self.bottomLeft.x - self.topLeft.x
	local dy = self.bottomLeft.y - self.topLeft.y
	local leftdist = math.sqrt(dx * dx + dy * dy)
	leftPoint.x = self.topLeft.x + math.cos(leftAngle) * (leftdist * self.vertPercentCenter)
	leftPoint.y = self.topLeft.y + math.sin(leftAngle) * (leftdist * self.vertPercentCenter)
	
	local rightAngle = math.atan2(self.bottomRight.y - self.topRight.y, self.bottomRight.x - self.topRight.x)
	local dx = self.bottomRight.x - self.topRight.x
	local dy = self.bottomRight.y - self.topRight.y
	local rightdist = math.sqrt(dx * dx + dy * dy)
	rightPoint.x = self.topRight.x + math.cos(rightAngle) * (rightdist * self.vertPercentCenter)
	rightPoint.y = self.topRight.y + math.sin(rightAngle) * (rightdist * self.vertPercentCenter)

	local a1, a2, b1, b2, c1, c2

	a1 = bottomPoint.y - topPoint.y
	b1 = topPoint.x - bottomPoint.x
	c1 = bottomPoint.x * topPoint.y - topPoint.x * bottomPoint.y
	a2 = rightPoint.y - leftPoint.y
	b2 = leftPoint.x - rightPoint.x
	c2 = rightPoint.x * leftPoint.y - leftPoint.x * rightPoint.y

	local denom = a1 * b2 - a2 * b1
	local newPos = LM.Vector2:new_local()
	newPos:Set((b1 * c2 - b2 * c1) / denom, (a2 * c1 - a1 * c2) / denom)
	self.pivotOffset:Set(newPos - mesh:SelectedCenter())
	
	self.lastVec:Set(mouseEvent.drawingVec)

	if self.fixedHandles then
		mesh:PreserveHandlePositions(moho.layerFrame)
	end

	mouseEvent.view:DrawMe()
end

function MR_CurveTool:PreviewWeldPoint(moho, mouseEvent, point)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	local m = LM.Matrix:new_local()
	local testVec1 = LM.Vector2:new_local()
	local p1 = LM.Point:new_local()
	local testVec2 = LM.Vector2:new_local()
	local p2 = LM.Point:new_local()
	local dist = 0
	local curveID = -1
	local segID = -1
	local pickWidth = 5

	self.endWeldVec:Set(-10000000, -10000000)
	testVec1:Set(point.fPos)
	moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)
	m:Transform(testVec1)
	moho.view:Graphics():WorldToScreen(testVec1, p1)

	self.drawWeldPoint = false

	local closestID = mesh:ClosestPoint(point.fPos, self.selectedPointID)
	if (closestID >= 0) then
		testVec2:Set(mesh:Point(closestID).fPos)
		m:Transform(testVec2)
		moho.view:Graphics():WorldToScreen(testVec2, p2)
		dist = (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)
		local curve, where = point:Curve(point:CountCurves()-1, -1)
		local pointCurveID = curve:PointID(point)
		local prewPointID = -1
		if pointCurveID == 0 then
			pointCurveID = 1
		else
			pointCurveID = pointCurveID -1
		end
		local prewPoint = curve:Point(pointCurveID)
		if self.autoWeld or (not self.autoWeld and mouseEvent.altKey) then
			if (dist < self.autoWeldRadius * 1.5 and (not mesh:ArePointsAdjacent(self.selectedPointID, closestID))) 
			and (not mesh:ArePointsAdjacent(mesh:PointID(prewPoint), closestID)
			or not self:ArePointsConnected(moho, mesh, mesh:Point(self.selectedPointID), mesh:Point(closestID))) then
				self.endWeldToPoint = true
				self.endWeldVec:Set(mesh:Point(closestID).fPos)
				self.drawWeldPoint = true
			elseif dist > self.autoWeldRadius * 1.5 then
				curveID, segID = point:GetEndpointEdge(curveID, segID)
				curveID, segID = moho.view:PickEdge(p1, curveID, segID, pickWidth)
				if (curveID >= 0) then -- add a point in the middle of some curve
					if ((not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and
						(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and
						(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1))) then -- don't weld the point back on itself
						self.endWeldToPoint = false
						self.endWeldVec:Set(mesh:Curve(curveID):ClosestPointOnSegment(segID, point.fPos, true, true))
						self.drawWeldPoint = true
					end
				end
			end
		end	
	end
end

function MR_CurveTool:WeldPoints(moho, event, vec, forceWeld)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return false
	end
	if moho.drawingLayer:CurrentAction() ~= "" then
		return
	end
	local testVec1 = LM.Vector2:new_local()
	testVec1:Set(vec)
	
	local autoWeld = self.autoWeld
	if forceWeld then
		autoWeld = true
	end
	
	local drawingClosestID = mesh:ClosestPoint(testVec1, self.selectedPointID)
	local drawingClosest = self:GetColosestVec(moho, event.view, testVec1, mesh:Point(drawingClosestID).fPos)
	local point = mesh:Point(self.selectedPointID)

	if drawingClosest < self.autoWeldRadius * 1.5 then
		if ((autoWeld and not event.altKey) or (not autoWeld and event.altKey)) and self.drawingStatus then
			local curve, where = point:Curve(point:CountCurves()-1, -1)
			local pointCurveID = where
			if pointCurveID == 0 then
				pointCurveID = 1
			else
				pointCurveID = pointCurveID -1
			end
			local prewPoint = curve:Point(pointCurveID)
			local isPointsOnOneCurve = false
			isPointsOnOneCurve = self:ArePointsConnected(moho, mesh, mesh:Point(drawingClosestID), point)
			if not mesh:ArePointsAdjacent(drawingClosestID, self.selectedPointID) and not mesh:ArePointsAdjacent(mesh:PointID(prewPoint), drawingClosestID) then
				if mesh:WeldPoints(self.selectedPointID, drawingClosestID, moho.layerFrame) then
					if isPointsOnOneCurve then
						if curve.fClosed then
							self.weldedCurve = curve
						end	
					end
					if not self.singleCurveMode then
						self:ClearPointKeys(moho, self.selectedPointID)
						self.selectedPointID = -1
						mesh:SelectNone()
						self.drawingStatus = false
					else	
						self.secondPointID = drawingClosestID
					end	
					
					self.drawWeldPoint = false
					moho:Click()
					moho:UpdateUI()
					return true
				end
			end	
		end	
	elseif drawingClosest > self.autoWeldRadius * 1.5 then
		if ((autoWeld and not event.altKey) or (not autoWeld and event.altKey)) and self.drawingStatus then
			local m = LM.Matrix:new_local()
			local v = LM.Vector2:new_local()
			local pt = LM.Point:new_local()
			local curveID = -1
			local segID = -1
			local pickWidth = 5
			moho.drawingLayer:GetFullTransform(moho.layerFrame, m, moho.document)
			local point = mesh:Point(self.selectedPointID)
			v:Set(point.fPos)
			m:Transform(v)
			event.view:Graphics():WorldToScreen(v, pt)
			curveID, segID = point:GetEndpointEdge(curveID, segID)
			curveID, segID = moho.view:PickEdge(pt, curveID, segID, pickWidth)
			local originalCurve = point:Curve(0, -1)
			if (curveID >= 0 and (autoWeld or (not autoWeld and event.altKey))) then -- add a point in the middle of some curve
				if (not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID)) and
					(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID - 1)) and
					(not mesh:Curve(curveID):IsPointOnSegment(self.selectedPointID, segID + 1)) then 
					local curve = mesh:Curve(curveID)
					mesh:AddPoint(curve:ClosestPointOnSegment(segID, point.fPos, true, true), curveID, segID, moho.layerFrame)
					mesh:WeldPoints(self.selectedPointID, mesh:CountPoints() - 1, moho.layerFrame)
					moho:Click()
					self.drawWeldPoint = false
					local newPoint = mesh:Point(mesh:CountPoints() - 1)
					local curve, where = newPoint:Curve(newPoint:CountCurves()-1, -1)
					local newPointCurveID = curve:PointID(newPoint)
					if newPointCurveID ~= 0 then
						newPointCurveID = curve:CountPoints()-1
					end
					self.weldedCurve = originalCurve
					if (event.ctrlKey and not self.sharpCorners) or (not event.ctrlKey and self.sharpCorners) then
						curve:SetCurvature(newPointCurveID, MOHO.PEAKED + self.peakedCorner, moho.layerFrame)
					end
					
					self:ClearPointKeys(moho, self.selectedPointID)
					if not self.singleCurveMode then
						self.drawingStatus = false
						self.selectedPointID = -1
					end	
					mesh:SelectNone()
					moho:UpdateUI()
					return true
				end
			end
		end
	end	
	return false
end

function MR_CurveTool:AddPointKeyframe(moho, frame, layer, allSelectedKeys)
	for i, pt in pairs(self.selList) do
		self.fPoses[i]:Set(pt.fPos)
	end
	
	moho:AddPointKeyframe(frame, layer, allSelectedKeys)
	
	for i, pt in pairs(self.selList) do
		local delta = self.fPoses[i] - pt.fPos
		pt.fPos = self.fPoses[i] + delta
	end
	
	moho:AddPointKeyframe(frame, layer, allSelectedKeys)		
end

function MR_CurveTool:FixHandles(moho, mesh)
	-- This code is copied from Alexandra Evseeva's scripts. 
	self.bezierList = {}
	for c=0, mesh:CountCurves()-1 do
		local nextCurveArray = {}
		for p=0, mesh:Curve(c):CountPoints()-1 do
			local preVect = mesh:Curve(c):GetControlHandle(p, moho.layerFrame, true)
			local postVect = mesh:Curve(c):GetControlHandle(p, moho.layerFrame, false)
			local pointArray = {pre = preVect, post = postVect}
			nextCurveArray[p] = pointArray
		end 

		self.bezierList[c] = nextCurveArray
	end
end

function MR_CurveTool:PopulateSelList(moho, mesh)
	self.fPoses = {}
	self.selList = {}
	self.inOffsets = {}
	self.outOffsets = {}
	for i = 0, mesh:CountPoints() - 1 do
		local pt = mesh:Point(i)
		if pt.fSelected then 
			table.insert(self.selList, pt)
			table.insert(self.fPoses, LM.Vector2:new_local())
			local ins = {}
			local outs = {}
			for c = 0, pt:CountCurves() -1 do
				local curve, where = pt:Curve(c, -1)
				ins[c] = curve:GetOffset(where, moho.layerFrame, true)
				outs[c] = curve:GetOffset(where, moho.layerFrame, false)			
			end
			table.insert(self.inOffsets, ins)
			table.insert(self.outOffsets, outs)
		end
	end
end

function MR_CurveTool:RepairFixedHandles(moho, mesh)
	-- This code is copied from Alexandra Evseeva's scripts.
	if not self.bezierList then
		return
	end 
	
	local precision = 0.0000001
	for k,v in pairs(self.bezierList) do
		local nextCurve = mesh:Curve(k)
		if nextCurve == nil then
			return
		end
		for n,p in pairs(v) do
			local point = nextCurve:Point(n)
			if not point then return end
			if not point.fSelected then
				local preVect = nextCurve:GetControlHandle(n, moho.drawingLayerFrame, true)
				local postVect = nextCurve:GetControlHandle(n, moho.drawingLayerFrame, false)
				local preChanged = ((p.pre - preVect):Mag()>precision)
				local postChanged = ((p.post - postVect):Mag()>precision)
				if preChanged or postChanged then 
					for ind, isChanged in pairs({preChanged, postChanged}) do
						local isPreHandle = (ind == 1)
						local targetOffset = nextCurve:GetOffset(n, moho.layerFrame, isPreHandle)
						local targetWeight = nextCurve:GetWeight(n, moho.layerFrame, isPreHandle)
						local currentOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, nextCurve, n, isPreHandle).value
						local currentWeight = AE_Utilities:GetWeightChannel(moho, moho.drawingLayer, nextCurve, n, isPreHandle).value
						local offsetDelta = currentOffset - targetOffset

						if self.flipDirectionList[mesh:PointID(point) + 1] then
							offsetDelta = -currentOffset + targetOffset
						end	
						nextCurve:SetOffset(n, targetOffset - offsetDelta, moho.layerFrame, isPreHandle)
						local weightDelta = currentWeight - targetWeight
						nextCurve:SetWeight(n, targetWeight - weightDelta, moho.layerFrame, isPreHandle)
						moho.layer:UpdateCurFrame()
					end
				end
			end
		end
	end
end 

function MR_CurveTool:CheckFlipDirection(moho, point)
	if not point then
		return
	end
	local flipDirection = false
	local flipDirectionV = false
	local curve, where = point:Curve(0, -1)
	local parent = point.fParent
	
	local originalOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, curve, where, true).value
	point.fParent = -1
	moho.drawingLayer:UpdateCurFrame()
	local newOffset = AE_Utilities:GetOffsetChannel(moho, moho.drawingLayer, curve, where, true).value
	point.fParent = parent
	if self.mohoVersion >= 14 then
		if originalOffset ~= newOffset or (tostring(originalOffset) == '-0.0' and tostring(newOffset) == '0.0') or (tostring(originalOffset) == '0.0' and tostring(newOffset) == '-0.0') then
			flipDirection = true
		end
	else
		if originalOffset ~= newOffset or (originalOffset == -0 and newOffset == 0) or (originalOffset == 0 and newOffset == -0) then
			flipDirection = true
		end
	end

	return flipDirection
end

function MR_CurveTool:MakeFlipDirectionList(moho)
	self.flipDirectionList = {}
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	for c=0, mesh:CountCurves()-1 do
		local curve = mesh:Curve(c)
		if curve:IsPartiallySelected() then
			local curvePoints = curve:CountPoints()
			for p=0, curvePoints - 1 do
				local point = curve:Point(p)
				if not point.fSelected then
					local areAdjacentPointsSelected = false
					if curve.fClosed then
						if p == 0 then
							if curve:Point(curvePoints - 1).fSelected or curve:Point(p + 1).fSelected then
								areAdjacentPointsSelected = true
							end	
						elseif p == curvePoints - 1 then
							if curve:Point(0).fSelected or curve:Point(p - 1).fSelected then
								areAdjacentPointsSelected = true
							end	
						else
							if curve:Point(p + 1).fSelected or curve:Point(p - 1).fSelected then
								areAdjacentPointsSelected = true
							end
						end
					else
						if p == 0 then
							if curve:Point(p + 1).fSelected then
								areAdjacentPointsSelected = true
							end	
						elseif p == curvePoints - 1 then
							if curve:Point(p - 1).fSelected then
								areAdjacentPointsSelected = true
							end	
						else
							if curve:Point(p + 1).fSelected or curve:Point(p - 1).fSelected then
								areAdjacentPointsSelected = true
							end
						end
					end
					if areAdjacentPointsSelected then
						local flipDirection = self:CheckFlipDirection(moho, point)
						self.flipDirectionList[mesh:PointID(point)+1] = flipDirection
					end	
				end
			end	
		end
	end
	moho.drawingLayer:UpdateCurFrame()
end

function MR_CurveTool:FixFBF(moho)
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end
	
	local layer = moho.drawingLayer
	layer:CopyFrame(moho.layerFrame, 0, falae)
	layer:ClearAnimation(false, 0, falae)
end	

function MR_CurveTool:SingleClickSelect(moho, mouseEvent, tryToPreserveSelection, allowEmptySelection)
	-- if tryToPreserveSelection is true, then don't change the selection if some points will remain selected
	local mesh = moho:DrawingMesh()
	if (mesh == nil) then
		return
	end

	if (tryToPreserveSelection and moho:CountSelectedPoints() < 2) then
		mesh:SelectNone()
		moho:CountSelectedPoints(true)
	end
	if (not tryToPreserveSelection and not mouseEvent.shiftKey and not mouseEvent.altKey) then
		mesh:SelectNone()
	end

	local i = mouseEvent.view:PickPoint(mouseEvent.pt)
	if (i >= 0) then --pick a point
		self.selMode = self.SELMODE_PT
		if (tryToPreserveSelection) then
			if (not mesh:Point(i).fSelected) then
				mesh:SelectNone()
			end
		end
		if (mouseEvent.altKey) then
			mesh:Point(i).fSelected = false
		else
			mesh:Point(i).fSelected = true
		end
	else
		if (tryToPreserveSelection) then
			for i = 0, mesh:CountPoints() - 1 do
				local point = mesh:Point(i)
				point.fPrevSelected = point.fSelected
				point.fSelected = false
			end
		end
		local curveID = -1
		local segID = -1
		curveID, segID = mouseEvent.view:PickEdge(mouseEvent.pt, curveID, segID)
		if (curveID >= 0 and segID >= 0) then -- an edge was clicked on
			self.selMode = SELMODE_EDGE
			local curve = mesh:Curve(curveID)
			-- new method - select the points in the curve that was clicked on
			if (mouseEvent.altKey) then
				local isCurveSelected = true
				for i = 0, curve:CountPoints() - 1 do
					if (not curve:Point(i).fSelected) then
						isCurveSelected = false
						break
					end
				end
				for i = 0, curve:CountPoints() - 1 do
					local point = curve:Point(i)
					if ((not isCurveSelected) or (point:CountCurves() < 2)) then
						point.fSelected = false
						if (point.fHidden) then
							point.fSelected = false
						end
					end
				end
			else
				for i = 0, curve:CountPoints() - 1 do
					local point = curve:Point(i)
					if (not point.fHidden) then
						point.fSelected = true
					end
				end
			end
		elseif (self.allowShapePicking) then -- try to pick a shape
			local shapeID = mouseEvent.view:PickShape(mouseEvent.pt)
			if (shapeID >= 0) then
				self.selMode = SELMODE_SHAPE
				-- select (or deselect) everything connected to the shape
				local shape = mesh:Shape(shapeID)
				for i = 0, shape:CountEdges() - 1 do
					curveID, segID = shape:GetEdge(i, curveID, segID)
					local curve = mesh:Curve(curveID)
					if (mouseEvent.altKey) then
						curve:Point(segID).fSelected = false
						curve:Point(segID + 1).fSelected = false
					else
						curve:Point(segID).fSelected = true
						curve:Point(segID + 1).fSelected = true
					end
				end
			end
		end

		if (not allowEmptySelection) then
			local numSel = moho:CountSelectedPoints(true)
			if (numSel < 1) then
				for i = 0, mesh:CountPoints() - 1 do
					local point = mesh:Point(i)
					point.fSelected = point.fPrevSelected
					point.fPrevSelected = false
				end
			end
		end

		if (tryToPreserveSelection) then
			local preserveSelection = false
			-- pass 1 - check if any of the selection is still selected
			for i = 0, mesh:CountPoints() - 1 do
				local point = mesh:Point(i)
				if (point.fPrevSelected and point.fSelected) then
					preserveSelection = true
				end
			end
			-- pass 2 - preserve the selection
			if (preserveSelection) then
				for i = 0, mesh:CountPoints() - 1 do
					local point = mesh:Point(i)
					point.fSelected = point.fPrevSelected
					point.fPrevSelected = false
				end
			else
				for i = 0, mesh:CountPoints() - 1 do
					local point = mesh:Point(i)
					point.fPrevSelected = false
				end
			end
		end
	end
	moho:UpdateSelectedChannels()
end

-- **************************************************
-- Localization
-- **************************************************

function MR_CurveTool:Localize(text)
	local phrase = {}

	phrase['Description'] = 'Create points with a click. Ctrl - create a sharp corner. Alt - disable auto-welding. Backspace - remove the last point. Enter or double-click - finish the curve.'
	phrase['UILabel'] = 'Curve Tool 4.1'

	phrase['Settings'] = 'Settings'
	phrase['Draw in zero frame'] = 'Draw in zero frame'
	phrase['Draw in non zero frames'] = 'Draw in non zero frames'
	phrase['Always draw on FBF'] = 'Always draw on FBF'
	phrase['Draw behind'] = 'Draw behind'
	phrase['Use Peak for corners'] = 'Use Peak for corners'
	phrase['Use Peak for corners Tooltip'] = 'Sharp Corners will have a curvature value of 0 instead of 0.0001, however, this may lead to issues when adding new points to adjacent segments.'
	phrase['Show all handles'] = 'Show all handles'
	phrase['Enable skew transformation'] = 'Enable skew transformation'
	phrase['Enable distort transformation'] = 'Enable distort transformation'
	phrase['Click to select'] = 'Click to select'
	
	phrase['Single curve mode'] = 'Single curve mode'
	phrase['Curve mode'] = 'Curve mode'
	phrase['Points'] = 'Points:'
	phrase['Curvature'] = 'Curvature:'
	phrase['Show handles tooltip'] = 'Show handles'
	phrase['Fixed handles tooltip'] = 'Fixed bezier handles'
	phrase['Bezier drawing mode'] = 'Bezier drawing mode'
	phrase['Threshold'] = 'Threshold:'
	phrase['Auto-weld'] = 'Auto-weld'
	phrase['Sharp corners'] = 'Sharp corners'
	phrase['Auto-fill:'] = 'Auto-fill:'
	phrase['Auto-stroke:'] = 'Auto-stroke:'
	phrase['Width:'] = 'Width:'
	
	phrase['Set pivot to left up corner'] = 'Set pivot to left up corner'
	phrase['Set pivot to left'] = 'Set pivot to left'
	phrase['Set pivot to left down corner'] = 'Set pivot to left down corner'
	
	phrase['Set pivot to up'] = 'Set pivot to up'
	phrase['Set pivot to center'] = 'Set pivot to center'
	phrase['Set pivot to down'] = 'Set pivot to down'
	
	phrase['Set pivot to right up corner'] = 'Set pivot to right up corner'
	phrase['Set pivot to right'] = 'Set pivot to right'
	phrase['Set pivot to right down corner'] = 'Set pivot to right down corner'

	return phrase[text]
end

Icon
MR Curve Tool
Listed

Script type: Tool

Uploaded: Jun 19 2022, 08:59

Last modified: Nov 14 2024, 08:27

Script Version: 4.1.3

This tool allows you to create points in Moho by just clicking the left mouse button instead of dragging and holding.






This script, and all other scripts on this site are distributed as free software under the GNU General Public License 3.0 or later.
Downloads count: 3494