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

ScriptName = "MR_PoseTool"

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

MR_PoseTool = {}

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

function MR_PoseTool:Version()
	return '1.0.4'
end

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

function MR_PoseTool:Creator()
	return 'Eugene Babich'
end

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

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

function MR_PoseTool:IsRelevant(moho)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return false
	end
	
	local v1, v2, v3 = self:GetMohoVersion(moho)
	self.mohoVersion = v1
	
	return true
end

function MR_PoseTool:IsEnabled(moho)
	return true
end

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

MR_PoseTool.keepSelection = false
MR_PoseTool.bakeAdjacentFrames = false
MR_PoseTool.firstBoneID = -1
MR_PoseTool.firstBonePos = LM.Vector2:new_local()
MR_PoseTool.firstBoneScalePercent = 50
MR_PoseTool.clickOffset = LM.Vector2:new_local()
MR_PoseTool.secondBoneID = -1
MR_PoseTool.isActive = true
MR_PoseTool.firstBoneOffset = 0
MR_PoseTool.secondBoneOffset = 0
MR_PoseTool.interval = 1
MR_PoseTool.showPath = false
MR_PoseTool.range = false
MR_PoseTool.rangeFrames = 10
MR_PoseTool.secondBonePos = LM.Vector2:new_local()
MR_PoseTool.secondBoneTipPos = LM.Vector2:new_local()
MR_PoseTool.firstDist = 0
MR_PoseTool.secondBoneDist = 0
MR_PoseTool.firstBoneParentID = -1
MR_PoseTool.firstBoneParentIBIK = false
MR_PoseTool.firstBoneSizeDelta = 0
MR_PoseTool.secondBoneSizeDelta = 0
MR_PoseTool.firstBoneAngleDelta = 0
MR_PoseTool.secondBoneAngleDelta = 0
MR_PoseTool.selectedBonesList = {}
MR_PoseTool.mousePickedID = -1
MR_PoseTool.dragging = false
MR_PoseTool.lastVec = LM.Vector2:new_local()
MR_PoseTool.lastVec2 = LM.Vector2:new_local()
MR_PoseTool.handlesDist = 0.075
MR_PoseTool.handlesDistY = 0.026
MR_PoseTool.handlesDistYMultiplier = 1
MR_PoseTool.additionmarkerDist = 0.05
MR_PoseTool.markerR = 6
MR_PoseTool.markerR2 = 6
MR_PoseTool.additionHandles = false
MR_PoseTool.startBonePos = LM.Vector2:new_local()
MR_PoseTool.startBoneAngleDelta = 0
MR_PoseTool.startBoneDist = 0
MR_PoseTool.TOLERANCE = 10
MR_PoseTool.transformPath = false
MR_PoseTool.drawMode = -1
MR_PoseTool.keepHandles = false
MR_PoseTool.height = 1080

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

function MR_PoseTool:LoadPrefs(prefs)
	self.keepSelection = prefs:GetBool("MR_PoseTool.keepSelection", false)
	self.bakeAdjacentFrames = prefs:GetBool("MR_PoseTool.bakeAdjacentFrames", false)
	self.interval = prefs:GetInt("MR_PoseTool.interval", 1)
	self.showPath = prefs:GetBool("MR_PoseTool.showPath", false)
	self.range = prefs:GetBool("MR_PoseTool.range", false)
	self.rangeFrames = prefs:GetInt("MR_PoseTool.rangeFrames", 10)
end

function MR_PoseTool:SavePrefs(prefs)
	prefs:SetBool("MR_PoseTool.keepSelection", self.keepSelection)
	prefs:SetBool("MR_PoseTool.bakeAdjacentFrames", self.bakeAdjacentFrames)
	prefs:SetInt("MR_PoseTool.interval", self.interval)
	prefs:SetBool("MR_PoseTool.showPath", self.showPath)
	prefs:SetBool("MR_PoseTool.range", self.range)
	prefs:SetInt("MR_PoseTool.rangeFrames", self.rangeFrames)
end

function MR_PoseTool:ResetPrefs()
	self.keepSelection = false
	self.bakeAdjacentFrames = false
	self.interval = 1
	self.showPath = false
	self.range = false
	self.rangeFrames = 10
end

function MR_PoseTool:NonDragMouseMove()
	return true -- Call MouseMoved() even if the mouse button is not down
end

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

function MR_PoseTool:OnMouseDown(moho, mouseEvent)
	local skel = moho:Skeleton()
	if skel == nil or moho.frame == 0 then
		return
	end

	if moho:CountSelectedBones() == 1 then
		selBoneID = skel:SelectedBoneID()
	end
	self.translationFrame = moho.frame
	if self.keepSelection then
		self.selectedBonesList = {}
		for i=0, skel:CountBones()-1 do
			local bone = skel:Bone(i)
			if bone.fSelected then
				table.insert(self.selectedBonesList, i)
			end
		end
	end
	self.trPathBone = nil
	self.keepHandles = false
	self.dragging = true
	self.lastVec:Set(mouseEvent.vec)

	local id = -1
	if self.handlesDistYMultiplier >= 1 then
		id = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, true, 8 * self.handlesDistYMultiplier)
	else
		id = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, true, 8)
	end	
	local firstBone
	local secondBone
	local firstBoneParent
	self.isActive = false
	self.transformPath = false
	if not (mouseEvent.ctrlKey) then
		self.mousePickedID = id
	else
		id = self.mousePickedID
	end
	self.secondBoneID = id
	self.mode = self:TestMousePoint(moho, mouseEvent, selBoneID)
	
	if id == -1 and self.mode ~= 5 then
		skel:SelectNone()
		return
	end

	moho.document:PrepUndo(moho.layer, true)
	moho.document:SetDirty()
	
	if mouseEvent.doubleClick and self.secondBoneID > -1 then
		local bone = skel:Bone(self.secondBoneID)
		if self.mode == 0 then
			if mouseEvent.altKey then
				bone.fTempScale = bone.fScale
				
				self.childBones = {}
				self.childBonesAngelP = {}
				self.childBonesAngelN = {}
				
				for i=0, skel:CountBones()-1 do
					local childBone = skel:Bone(i)
					if  childBone.fParent == self.secondBoneID and not childBone.fFixedAngle and not childBone.fIgnoredByIK then
						local angle = childBone.fAnimAngle:GetValue(moho.layerFrame)
						childBone.fTempAngle = angle
						table.insert(self.childBones, i)
						
						if moho.layerFrame - self.interval > 0 then
							table.insert(self.childBonesAngelP, childBone.fAnimAngle:GetValue(moho.layerFrame - self.interval))
						else
							table.insert(self.childBonesAngelP, 0)
						end
						
						if moho.layerFrame + self.interval > 0 then
							table.insert(self.childBonesAngelN, childBone.fAnimAngle:GetValue(moho.layerFrame + self.interval))
						else
							table.insert(self.childBonesAngelN, 0)
						end
					end
				end
				
				local secondBoneSizeDelta = bone.fScale - bone.fAnimScale:GetValue(moho.layerFrame)
				local secondBoneAngleDelta = bone.fAngle - bone.fAnimAngle:GetValue(moho.layerFrame)
				
				local secondTipVec = LM.Vector2:new_local()
				secondTipVec:Set(bone.fLength, 0)
				bone.fMovedMatrix:Transform(secondTipVec)
				
				local secondVec = LM.Vector2:new_local()
				secondVec:Set(0, 0)
				bone.fMovedMatrix:Transform(secondVec)
				
				local boneDist = self:GetDistance(secondVec, secondTipVec)
				
				bone.fAnimPos:SetValue(moho.layerFrame, bone.fAnimPos:GetValue(0))
				skel:UpdateBoneMatrix()
				moho.layer:UpdateCurFrame()
				secondVec:Set(0, 0)
				bone.fMovedMatrix:Transform(secondVec)
				
				local NewboneDist = self:GetDistance(secondVec, secondTipVec)
				local secondDelta = (NewboneDist / boneDist)
				local newScale = (bone.fTempScale * secondDelta) - secondBoneSizeDelta

				bone.fAnimScale:SetValue(moho.layerFrame, newScale)
				
				local isIgnoredByIK = bone.fIgnoredByIK
				bone.fIgnoredByIK = false
				moho.layer:UpdateCurFrame()
				
				skel:IKAngleSolver(self.secondBoneID, secondTipVec, 1, true, true)

				bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle - secondBoneAngleDelta)
				bone.fAnimAngle.value = bone.fAngle
				
				local angleSign = 1
				if (bone.fFlipH.value and not bone.fFlipV.value) or (not bone.fFlipH.value and bone.fFlipV.value) then
					angleSign = -1
				end

				local angleDelta = bone.fAngle - bone.fTempAngle
				
				for i, q in ipairs(self.childBones) do
					local childBone = skel:Bone(q)
					childBone.fAnimAngle:SetValue(moho.layerFrame, childBone.fTempAngle - (angleDelta * angleSign))
				end
				
				bone.fIgnoredByIK = isIgnoredByIK
			else	
				bone.fAnimPos:SetValue(moho.layerFrame, bone.fAnimPos:GetValue(0))
			end

			moho.layer:UpdateCurFrame()
			moho:NewKeyframe(CHANNEL_BONE_T)
			self:UpdateWidgets(moho)
			return
		elseif self.mode == 1 then
			bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAnimAngle:GetValue(0))
			moho.layer:UpdateCurFrame()
			moho:NewKeyframe(CHANNEL_BONE)
			self:UpdateWidgets(moho)
			return
		elseif self.mode == 2 then
			bone.fAnimScale:SetValue(moho.layerFrame, bone.fAnimScale:GetValue(0))
			moho.layer:UpdateCurFrame()
			moho:NewKeyframe(CHANNEL_BONE_S)
			self:UpdateWidgets(moho)
			return
		end
	end
	
	skel:SelectNone()
	self.startAngle = 0
	self.startAngle2 = 0
	secondBone = skel:Bone(self.secondBoneID)
	self.jointChain = false
	self.firstBoneID = -1
	
	if self.mode == 5 then
		local bone = skel:Bone(selBoneID)
		bone.fSelected = true
		self.selID = skel:BoneID(self.trPathBone)
		self.secondBoneID = selBoneID
		
		local boneVec = LM.Vector2:new_local()
		boneVec:Set(0, 0)
		bone.fRestMatrix:Transform(boneVec)
		boneVec = boneVec - mouseEvent.startVec
		local d = boneVec:Mag()
		self.boneEnd = 0
		boneVec:Set(bone.fLength, 0)
		bone.fRestMatrix:Transform(boneVec)
		boneVec = boneVec - mouseEvent.startVec
		if (boneVec:Mag() < d) then
			self.boneEnd = 1
		end

		if (self.translationFrame ~= 0 and bone.fSelected) then
			self.boneChanged = true
			bone.fTempPos = bone.fAnimPos:GetValue(self.translationFrame)
			bone.fAnimPos:SetValue(self.translationFrame, bone.fTempPos)
		end
		
		self.isActive = true
		return
	elseif self.mode == 4 then -- manipulate bones
		self.selID = id
		self.boneBakedA = false
		self.boneBakedP = false
		self.boneBakedS = false
		if self.bakeAdjacentFrames then
			self.boneSAngleP = secondBone.fAnimAngle:GetValue(moho.layerFrame - self.interval)
			self.boneSAngleN = secondBone.fAnimAngle:GetValue(moho.layerFrame + self.interval)
			self.boneSScaleP = secondBone.fAnimScale:GetValue(moho.layerFrame - self.interval)
			self.boneSScaleN = secondBone.fAnimScale:GetValue(moho.layerFrame + self.interval)
		end
		local bone = skel:Bone(id)
		
		bone.fTempPos:Set(bone.fAnimPos:GetValue(moho.layerFrame))
		bone.fTempAngle = bone.fAnimAngle:GetValue(moho.layerFrame)
		bone.fTempScale = bone.fAnimScale:GetValue(moho.layerFrame)
		
		self.secondTarget = skel:TargetOfBoneChain(id, moho.layerFrame)
	
		if self.secondTarget >= 0 then
			self.isChainTargeted = true
			local targetBone = skel:Bone(self.secondTarget)
			targetBone.fTempPos = targetBone.fAnimPos:GetValue(moho.layerFrame)
			
			self.targetBonePosP = targetBone.fAnimPos:GetValue(moho.layerFrame - self.interval)
			
			self.targetBonePosN = targetBone.fAnimPos:GetValue(moho.layerFrame + self.interval)
			
			self.isTargetBonePosPBaked = false
			self.isTargetBonePosNBaked = false
			
		else
			self.isChainTargeted = false
		end
		
		bone.fSelected = true
		local isSmartBone = moho.layer:IsSmartBoneAction(bone:Name())

		self.isParentBonesBaked = false
		self.lastVec:Set(mouseEvent.vec)
		self.parentBones = {}
		self.parentBonesAngleP = {}
		self.parentBonesAngleN = {}
		self.parentBonesScaleP = {}
		self.parentBonesScaleN = {}
		self.startAngle = 0
		self.boneStartAngles = {}
		self.boneStartActualAngles = {}
		table.insert(self.boneStartAngles, bone.fAnimAngle:GetValue(moho.layerFrame))
		table.insert(self.boneStartActualAngles, bone.fAnimAngle.value)

		while bone.fParent >= 0 do
			local parentBone = skel:Bone(bone.fParent)
			parentBone.fTempAngle = parentBone.fAnimAngle:GetValue(moho.layerFrame)
			parentBone.fTempScale = parentBone.fAnimScale:GetValue(moho.layerFrame)
			if (self:CountBoneChildren(skel, bone.fParent, true) > 1) or parentBone.fIgnoredByIK or parentBone.fFixedAngle then
				break
			end
			local parenBoneID = bone.fParent
			bone = skel:Bone(parenBoneID)
			bone.fTempScale = bone.fAnimScale:GetValue(moho.layerFrame)
			table.insert(self.parentBones, parenBoneID)
			
			if moho.layerFrame - self.interval > 0 then
				table.insert(self.parentBonesAngleP, bone.fAnimAngle:GetValue(moho.layerFrame - self.interval))
				table.insert(self.parentBonesScaleP, bone.fAnimScale:GetValue(moho.layerFrame - self.interval))
			else
				table.insert(self.parentBonesAngleP, 0)
				table.insert(self.parentBonesScaleP, 0)
			end
			
			if moho.layerFrame + self.interval > 0 then
				table.insert(self.parentBonesAngleN, bone.fAnimAngle:GetValue(moho.layerFrame + self.interval))
				table.insert(self.parentBonesScaleN, bone.fAnimScale:GetValue(moho.layerFrame + self.interval))
			else
				table.insert(self.parentBonesAngleN, 0)
				table.insert(self.parentBonesScaleN, 0)
			end
			
			table.insert(self.boneStartAngles, bone.fAnimAngle:GetValue(moho.layerFrame))
			table.insert(self.boneStartActualAngles, bone.fAnimAngle.value)
		end

		local startBoneID = self.parentBones[#self.parentBones]
		local startBone = skel:Bone(startBoneID)
		startBone.fTempAngle = startBone.fAnimAngle:GetValue(moho.layerFrame)

		local startBonePos = LM.Vector2:new_local()
		startBonePos:Set(0, 0)
		startBone.fMovedMatrix:Transform(startBonePos)
		self.startBonePos:Set(startBonePos)
		self.startBoneDist = self:GetDistance(startBonePos, mouseEvent.vec)
		
		self.isChildBonesBaked = false

		self.childBones = {}
		self.childBonesAngelP = {}
		self.childBonesAngelN = {}

		for i=0, skel:CountBones()-1 do
			local childBone = skel:Bone(i)

			if childBone.fParent == id and not childBone.fFixedAngle and not childBone.fIgnoredByIK then
				local angle = childBone.fAnimAngle:GetValue(moho.layerFrame)
				childBone.fTempAngle = angle
				table.insert(self.childBones, i)
				if moho.layerFrame - self.interval > 0 then
					table.insert(self.childBonesAngelP, childBone.fAnimAngle:GetValue(moho.layerFrame - self.interval))
				else
					table.insert(self.childBonesAngelP, 0)
				end
				
				if moho.layerFrame + self.interval > 0 then
					table.insert(self.childBonesAngelN, childBone.fAnimAngle:GetValue(moho.layerFrame + self.interval))
				else
					table.insert(self.childBonesAngelN, 0)
				end
			end
		end
		
		if self.mode == 4 then
			self.isActive = true
			moho:UpdateBonePointSelection()
			mouseEvent.view:DrawMe()
			moho:UpdateSelectedChannels()
			self.lastVec:Set(mouseEvent.vec)
			return
		end
		
	end

	if secondBone.fParent > -1 and not secondBone:IsZeroLength() then
		self.firstBoneID = secondBone.fParent
		firstBone = skel:Bone(self.firstBoneID)
		local firstBoneChilds = skel:CountBoneChildren(self.firstBoneID, true)
		local secondBonePos = LM.Vector2:new_local()
		secondBonePos:Set(secondBone.fAnimPos:GetValue(moho.layerFrame))
		if firstBone.fIgnoredByIK == false and not firstBone.fFixedAngle and not secondBone.fFixedAngle and secondBone.fIgnoredByIK == false and firstBoneChilds == 1 and self:Round(secondBone.fPos.y) == 0 
		and not self:IsEqual(secondBonePos.x, 0, 0.0001) and not firstBone:IsZeroLength() then
			self.jointChain = true
		end
	end	
	
	self.secondBoneID = id
	secondBone.fSelected = true
	
	local useFirstBone = self.jointChain and (self.mode == 0 or self.mode == 3)
	
	if self.bakeAdjacentFrames then
		self.boneBakedA = false
		self.boneBakedP = false
		self.boneBakedS = false
		
		if useFirstBone then
			self.boneFAngleP = firstBone.fAnimAngle:GetValue(moho.layerFrame - self.interval)
			self.boneFAngleN = firstBone.fAnimAngle:GetValue(moho.layerFrame + self.interval)
			self.boneFScaleP = firstBone.fAnimScale:GetValue(moho.layerFrame - self.interval)
			self.boneFScaleN = firstBone.fAnimScale:GetValue(moho.layerFrame + self.interval)
		end	
		
		self.boneSAngleP = secondBone.fAnimAngle:GetValue(moho.layerFrame - self.interval)
		self.boneSAngleN = secondBone.fAnimAngle:GetValue(moho.layerFrame + self.interval)
		
		
		self.boneSPosP = secondBone.fAnimPos:GetValue(moho.layerFrame - self.interval) 
		self.boneSPosN = secondBone.fAnimPos:GetValue(moho.layerFrame + self.interval)
		
		self.boneSScaleP = secondBone.fAnimScale:GetValue(moho.layerFrame - self.interval)
		self.boneSScaleN = secondBone.fAnimScale:GetValue(moho.layerFrame + self.interval)
	end
	
	moho.layer:UpdateCurFrame()
	
	self.secondTarget = skel:TargetOfBoneChain(self.secondBoneID, moho.layerFrame)
	
	if self.secondTarget >= 0 then
		self.isChainTargeted = true
		local targetBone = skel:Bone(self.secondTarget)
		targetBone.fTempPos = targetBone.fAnimPos:GetValue(moho.layerFrame)
		
		self.targetBonePosP = targetBone.fAnimPos:GetValue(moho.layerFrame - self.interval)
		
		self.targetBonePosN = targetBone.fAnimPos:GetValue(moho.layerFrame + self.interval)
		
		self.isTargetBonePosPBaked = false
		self.isTargetBonePosNBaked = false
		
	else
		self.isChainTargeted = false
	end
	
	local firstBoneAngleDelta = 0
	local secondBoneAngleDelta = 0

	if self.isChainTargeted then
		local firstBoneStretchDelta
		local firstBoneIKStratching
		if useFirstBone then
			firstBoneStretchDelta = 0
			firstBoneIKStratching = firstBone.fMaxAutoScaling
			firstBone.fMaxAutoScaling = 10000
		end
		
		local secondBoneStretchDelta = 0
		local secondBoneIKStratching = secondBone.fMaxAutoScaling
		
		secondBone.fMaxAutoScaling = 10000
		
		moho.layer:UpdateCurFrame()
		
		local firstBoneFSize
		local firstBoneFAngle
		local isFirstBoneIgnoredByIK
		if useFirstBone then
			firstBoneFSize = firstBone.fScale
			firstBoneFAngle = firstBone.fAngle
			isFirstBoneIgnoredByIK = firstBone.fIgnoredByIK
		end
		
		local secondBoneFSize = secondBone.fScale
		local secondBoneFAngle = secondBone.fAngle
		
		local isSecondBoneIgnoredByIK = secondBone.fIgnoredByIK
		if useFirstBone then
			firstBone.fIgnoredByIK = true
		end
		
		secondBone.fIgnoredByIK = true
		
		moho.layer:UpdateCurFrame()
		
		if useFirstBone then
			firstBoneStretchDelta = firstBoneFSize - firstBone.fScale
			firstBoneAngleDelta = firstBoneFAngle - firstBone.fAngle
		end
		
		secondBoneStretchDelta = secondBoneFSize - secondBone.fScale
		secondBoneAngleDelta = secondBoneFAngle - secondBone.fAngle
		
		if useFirstBone then
			firstBone.fIgnoredByIK = isFirstBoneIgnoredByIK
			firstBone.fMaxAutoScaling = firstBoneIKStratching
		end
		
		secondBone.fIgnoredByIK = isSecondBoneIgnoredByIK
		secondBone.fMaxAutoScaling = secondBoneIKStratching

		if useFirstBone then
			firstBone.fAnimScale:SetValue(moho.layerFrame, firstBone.fAnimScale:GetValue(moho.layerFrame) + firstBoneStretchDelta)
			firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBone.fAnimAngle:GetValue(moho.layerFrame) + firstBoneAngleDelta)
		end
		
		secondBone.fAnimScale:SetValue(moho.layerFrame, secondBone.fAnimScale:GetValue(moho.layerFrame) + secondBoneStretchDelta)
		secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBone.fAnimAngle:GetValue(moho.layerFrame) + secondBoneAngleDelta)
		
		moho.layer:UpdateCurFrame()
	end	
	self.isTargetMoved = false
	
	local secondTipVec = LM.Vector2:new_local()
	local firstVec = LM.Vector2:new_local()
	local secondVec = LM.Vector2:new_local()
	secondTipVec:Set(secondBone.fLength, 0)
	firstVec:Set(0, 0)
	secondVec:Set(0, 0)
	secondBone.fMovedMatrix:Transform(secondTipVec)
	secondBone.fMovedMatrix:Transform(secondVec)
	
	self.secondBonePos:Set(secondVec)
	
	if useFirstBone then
		firstBone.fMovedMatrix:Transform(firstVec)
		self.firstBonePos:Set(firstVec)
		self.firstDist = self:GetDistance(self.firstBonePos, self.secondBonePos)
	end
	
	self.secondBoneTipPos:Set(secondTipVec)
	self.secondBoneDist = self:GetDistance(self.secondBonePos, self.secondBoneTipPos)
	local mousePos = mouseEvent.vec
	
	self.clickOffset = self.secondBonePos - mousePos
	
	if self.mode == 2 then
		self.clickOffset = self.secondBoneTipPos - mousePos
	end
	
	if useFirstBone then
		self.firstBoneSizeDelta = firstBone.fScale - firstBone.fAnimScale:GetValue(moho.layerFrame)
	end	
	self.secondBoneSizeDelta = secondBone.fScale - secondBone.fAnimScale:GetValue(moho.layerFrame)
	
	self.isChildBonesBaked = false

	self.childBones = {}
	self.childBonesAngelP = {}
	self.childBonesAngelN = {}
	
	for i=0, skel:CountBones()-1 do
		local bone = skel:Bone(i)
		if  bone.fParent == self.secondBoneID and not bone.fFixedAngle and not bone.fIgnoredByIK then
			local angle = bone.fAnimAngle:GetValue(moho.layerFrame)
			bone.fTempAngle = angle
			table.insert(self.childBones, i)
			
			if moho.layerFrame - self.interval > 0 then
				table.insert(self.childBonesAngelP, bone.fAnimAngle:GetValue(moho.layerFrame - self.interval))
			else
				table.insert(self.childBonesAngelP, 0)
			end
			
			if moho.layerFrame + self.interval > 0 then
				table.insert(self.childBonesAngelN, bone.fAnimAngle:GetValue(moho.layerFrame + self.interval))
			else
				table.insert(self.childBonesAngelN, 0)
			end
		end
	end
	
	local firstBoneActualAngle
	
	if useFirstBone then
		firstBoneActualAngle = firstBone.fAngle
		self.firstBoneAngleDelta = firstBoneActualAngle - firstBone.fAnimAngle:GetValue(moho.layerFrame)
	end
	
	local secondBoneActualAngle = secondBone.fAngle
	self.secondBoneAngleDelta = secondBoneActualAngle - secondBone.fAnimAngle:GetValue(moho.layerFrame)
	
	self.lastVec2:Set(0, 0)
	skel:UpdateBoneMatrix()
	secondBone.fMovedMatrix:Transform(self.lastVec2)
	
	if self.mode > 1 then
		if useFirstBone then
			firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBone.fAnimAngle:GetValue(moho.layerFrame))
			firstBone.fAnimAngle.value = firstBoneActualAngle
		end
	
		secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBone.fAnimAngle:GetValue(moho.layerFrame))
		secondBone.fAnimAngle.value = secondBoneActualAngle
	end	
	
	if useFirstBone then
		firstBone.fTempScale = firstBone.fScale
		firstBone.fTempAngle = firstBone.fAngle
	end
	
	secondBone.fTempScale = secondBone.fScale
	secondBone.fTempAngle = secondBone.fAngle
	
	if self.mode == 0 then
		secondBone.fTempPos:Set(secondBone.fAnimPos:GetValue(moho.layerFrame))
	end
	
	self.isActive = true
	
	if useFirstBone then
		self.firstBoneParentID = firstBone.fParent
		if self.firstBoneParentID > -1 then
			firstBoneParent = skel:Bone(self.firstBoneParentID)
			self.firstBoneParentIBIK = firstBoneParent.fIgnoredByIK
			firstBoneParent.fIgnoredByIK = true
		end
	end
	
	local boneFirstLenght
	local boneFirstScale
	if useFirstBone then
		boneFirstLenght = secondBone.fPos.x
		boneFirstScale = firstBone.fScale
	end
	local boneSecondLenght = secondBone.fLength
	local boneSecondScale = secondBone.fScale
	if useFirstBone then
		self.firstBoneScalePercent = ((boneFirstLenght * boneFirstScale) / ((boneFirstLenght * boneFirstScale) + (boneSecondLenght * boneSecondScale))) * 100
		self.firstBoneOffset = firstBone.fScale - firstBone.fAnimScale:GetValue(moho.layerFrame)
	end
	self.secondBoneOffset = secondBone.fScale - secondBone.fAnimScale:GetValue(moho.layerFrame)
	moho.layer:UpdateCurFrame()
	moho:UpdateBonePointSelection()
	mouseEvent.view:DrawMe()
	moho:UpdateSelectedChannels()
end

function MR_PoseTool:OnMouseMoved(moho, mouseEvent)
	local skel = moho:Skeleton()
	if skel == nil or moho.frame == 0 then
		mouseEvent.view:SetCursor(MOHO.disabledCursor)
		return
	end
	
	local boneID
	local bone
	if moho:CountSelectedBones() == 1 then
		boneID = skel:SelectedBoneID()
		bone = skel:Bone(boneID)
	end
	
	if (not self.dragging) then
		if not (mouseEvent.ctrlKey) then
			if self.handlesDistYMultiplier >= 1 then
				self.mousePickedID = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, true, 8 * self.handlesDistYMultiplier)
			else
				self.mousePickedID = mouseEvent.view:PickBone(mouseEvent.pt, mouseEvent.vec, moho.layer, true, 8)
			end	
			self.additionHandles = self:CheckBone(moho, self.mousePickedID)
		end	

		if self.mousePickedID > -1 or bone ~= nil then
			local mode = self:TestMousePoint(moho, mouseEvent, boneID)
			self.drawMode = mode
			if not (self.mousePickedID < 0 and mode ~= 5) then
				if mode == 0 or mode == 5 then
					mouseEvent.view:SetCursor(MOHO.moveCursor)
				elseif (mode == 1) then
					mouseEvent.view:SetCursor(MOHO.rotateCursor)
				elseif (mode == 2) then
					mouseEvent.view:SetCursor(MOHO.scaleCursor)
				elseif (mode == 3) then
					mouseEvent.view:SetCursor(self.mjCursor)
				elseif (mode == 4) then
					mouseEvent.view:SetCursor(self.mbCursor)		
				end
			else
				mouseEvent.view:SetCursor(self.mainCursor)
			end
		else
			mouseEvent.view:SetCursor(self.mainCursor)
		end
		
		mouseEvent.view:DrawMe()
		return
	end
	
	if self.isActive == false then
		return
	end

	if self.mode == 0 or self.mode == 5 then -- move
		self:OnMouseMovedT(moho, mouseEvent)
	elseif self.mode == 1 then -- rotate
		self:OnMouseMovedR(moho, mouseEvent)
	elseif self.mode == 2 then -- scale rotate
		self:OnMouseMovedS(moho, mouseEvent)
	elseif self.mode == 3 then -- move joint
		if self.jointChain then
			self:OnMouseMovedJ(moho, mouseEvent)
		end
	elseif self.mode == 4 then -- manipulate bones
		self:OnMouseMovedM(moho, mouseEvent)
	end
end

function MR_PoseTool:OnMouseMovedJ(moho, mouseEvent)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end
	local firstBone = skel:Bone(self.firstBoneID)
	local secondBone = skel:Bone(self.secondBoneID)
	
	if self.bakeAdjacentFrames and not self.boneBakedA then
		self:BakeFrames(moho, secondBone, firstBone, true, false, true)
		self.boneBakedA = true
	end
	
	local vectorMousePos = (mouseEvent.vec + self.clickOffset)

	local firstCursorDist = self:GetDistance(vectorMousePos, self.firstBonePos)

	local firstDelta = (firstCursorDist / self.firstDist)
	firstBone.fAnimScale:SetValue(moho.layerFrame, (firstBone.fTempScale * firstDelta) - self.firstBoneSizeDelta)
	
	if self.isChainTargeted then
		local secondCursorDist = self:GetDistance(vectorMousePos, self.secondBoneTipPos)
		local secondDelta = (secondCursorDist / self.secondBoneDist)
		secondBone.fAnimScale:SetValue(moho.layerFrame, (secondBone.fTempScale * secondDelta) - self.secondBoneSizeDelta)
		
		if mouseEvent.shiftKey then
			local totalDist = firstCursorDist + secondCursorDist
			local distP = (totalDist / 100) * self.firstBoneScalePercent
			distP = distP / firstBone.fLength
			local secondDistP = (totalDist / 100) * (100 - self.firstBoneScalePercent)
			secondDistP = secondDistP / secondBone.fLength
			firstBone.fAnimScale:SetValue(moho.layerFrame, distP - self.firstBoneOffset)
			secondBone.fAnimScale:SetValue(moho.layerFrame, secondDistP - self.secondBoneOffset)
		end
		
		skel:IKAngleSolver(self.firstBoneID, vectorMousePos, 1, true, false)
		local firstBoneNewAngle = firstBone.fAngle - self.firstBoneAngleDelta
		
		firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBoneNewAngle)
		firstBone.fAnimAngle.value = firstBone.fAngle

		if not secondBone.fFixedAngle then
			firstBone.fIgnoredByIK = true
			skel:IKAngleSolver(self.secondBoneID, self.secondBoneTipPos, 1, true, true)
			
			secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBone.fAngle - self.secondBoneAngleDelta)
			secondBone.fAnimAngle.value = secondBone.fAngle

			firstBone.fIgnoredByIK = false

			moho.layer:UpdateCurFrame()

			skel:IKAngleSolver(self.secondBoneID, self.secondBoneTipPos, 1, true, true)
			
			local secondBoneNewAngle = secondBone.fAngle - self.secondBoneAngleDelta
			
			secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBoneNewAngle)
			secondBone.fAnimAngle.value = secondBone.fAngle

			firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBone.fAngle - self.firstBoneAngleDelta)
			firstBone.fAnimAngle.value = firstBone.fAngle
			
			firstBone.fIgnoredByIK = currentIgnoredByIK
		end
	else
		if mouseEvent.shiftKey then
			local firstCursorDist = self:GetDistance(vectorMousePos, self.firstBonePos)
			local secondCursorDist = self:GetDistance(vectorMousePos, self.secondBoneTipPos)

			local firstDelta = (firstCursorDist / self.firstDist)
			local secondDelta = (secondCursorDist / self.secondBoneDist)
			firstBone.fAnimScale:SetValue(moho.layerFrame, (firstBone.fTempScale * firstDelta) - self.firstBoneSizeDelta)
			secondBone.fAnimScale:SetValue(moho.layerFrame, (secondBone.fTempScale * secondDelta) - self.secondBoneSizeDelta)
			
			local totalDist = firstCursorDist + secondCursorDist
			local distP = (totalDist / 100) * self.firstBoneScalePercent
			distP = distP / firstBone.fLength
			local secondDistP = (totalDist / 100) * (100 - self.firstBoneScalePercent)
			secondDistP = secondDistP / secondBone.fLength
			firstBone.fAnimScale:SetValue(moho.layerFrame, distP - self.firstBoneOffset)
			secondBone.fAnimScale:SetValue(moho.layerFrame, secondDistP - self.secondBoneOffset)
			
			skel:IKAngleSolver(self.firstBoneID, vectorMousePos, 1, true, false)
			
			local originalAngle = firstBone.fTempAngle
			local correctedAngle = firstBone.fAngle
			local delta = originalAngle - correctedAngle

			while math.abs(delta) > math.rad(180) do
				if delta > math.rad(180) then
					correctedAngle = correctedAngle + math.rad(360)
				elseif delta < math.rad(-180) then
					correctedAngle = correctedAngle - math.rad(360)
				end
				delta = originalAngle - correctedAngle
			end

			local restoredAngle = correctedAngle - self.firstBoneAngleDelta
			
			firstBone.fAnimAngle:SetValue(moho.layerFrame, restoredAngle)
			firstBone.fAnimAngle.value = firstBone.fAngle
			
			secondBone.fAnimScale.value = secondBone.fScale
			local currentIgnoredByIK = firstBone.fIgnoredByIK
			
			if not secondBone.fFixedAngle then
				firstBone.fIgnoredByIK = true
				skel:IKAngleSolver(self.secondBoneID, self.secondBoneTipPos, 10, true, true)
				
				secondBone.fAnimAngle:SetValue(moho.layerFrame, secondBone.fAngle - self.secondBoneAngleDelta)
				secondBone.fAnimAngle.value = secondBone.fAngle

				firstBone.fIgnoredByIK = false

				moho.layer:UpdateCurFrame()

				skel:IKAngleSolver(self.secondBoneID, self.secondBoneTipPos, 10, true, true)
				
				originalAngle = secondBone.fTempAngle
				correctedAngle = secondBone.fAngle
				delta = originalAngle - correctedAngle

				while math.abs(delta) > math.rad(180) do
					if delta > math.rad(180) then
						correctedAngle = correctedAngle + math.rad(360)
					elseif delta < math.rad(-180) then
						correctedAngle = correctedAngle - math.rad(360)
					end
					delta = originalAngle - correctedAngle
				end

				restoredAngle = correctedAngle - self.secondBoneAngleDelta
				
				secondBone.fAnimAngle:SetValue(moho.layerFrame, restoredAngle)
				secondBone.fAnimAngle.value = secondBone.fAngle

				originalAngle = firstBone.fTempAngle
				correctedAngle = firstBone.fAngle
				delta = originalAngle - correctedAngle

				while math.abs(delta) > math.rad(180) do
					if delta > math.rad(180) then
						correctedAngle = correctedAngle + math.rad(360)
					elseif delta < math.rad(-180) then
						correctedAngle = correctedAngle - math.rad(360)
					end
					delta = originalAngle - correctedAngle
				end

				restoredAngle = correctedAngle - self.firstBoneAngleDelta
				
				firstBone.fAnimAngle:SetValue(moho.layerFrame, restoredAngle)
				firstBone.fAnimAngle.value = firstBone.fAngle
				
				firstBone.fIgnoredByIK = currentIgnoredByIK
			end
		else
			local bone = firstBone
			local center = LM.Vector2:new_local()
			center:Set(0, 0)
			skel:UpdateBoneMatrix(self.firstBoneID)
			bone.fMovedMatrix:Transform(center)
			
			local mousePos = mouseEvent.vec
			
			local angle = self.startAngle
			local v1 = self.lastVec - center
			local v2 = mousePos - center
			v2:Rotate(-math.atan2(v1.y, v1.x))
			angle = angle + math.atan2(v2.y, v2.x)
			self.startAngle = angle
			self.lastVec:Set(mousePos)
			local angleSign = 1.0
			if (not bone.fFixedAngle) then
				angleSign = bone:ParentalFlipFactor()
			end

			local newAgle = (bone.fTempAngle + (angle * angleSign)) - self.firstBoneAngleDelta

			if not bone.fFixedAngle then
				if bone.fConstraints then
					local min = bone.fAnimAngle:GetValue(0) - self.firstBoneAngleDelta
					local max = min + bone.fMaxConstraint
					min = min + bone.fMinConstraint
					newAgle = LM.Clamp(newAgle, min, max)
				end
			end
			if not self:IsEqual(newAgle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAgle)
				bone.fAnimAngle.value = bone.fAngle
				if self.bakeAdjacentFrames and not self.boneBakedA then
					self:BakeFrames(moho, firstBone, nil, true, false, false)
					self.boneBakedA = true
				end
			end
			
			moho.layer:UpdateCurFrame()

			local bone = secondBone
			local center = LM.Vector2:new_local()

			center:Set(0, 0)
			skel:UpdateBoneMatrix(self.secondBoneID)
			bone.fMovedMatrix:Transform(center)
			
			local angle2 = self.startAngle2
			local v1 = self.lastVec2 - self.secondBoneTipPos
			local v2 = center - self.secondBoneTipPos
			v2:Rotate(-math.atan2(v1.y, v1.x))
			angle2 = angle2 + math.atan2(v2.y, v2.x)
			self.startAngle2 = angle2
			self.lastVec2:Set(center)
			
			local angleSign2 = 1.0
			if (not bone.fFixedAngle) then
				angleSign2 = bone:ParentalFlipFactor()
			end

			local newAgle2 = (bone.fTempAngle + (angle2 * angleSign2)) - (angle * angleSign2) - self.secondBoneAngleDelta
			if not bone.fFixedAngle then
				if bone.fConstraints then
					local min = bone.fAnimAngle:GetValue(0) - self.secondBoneAngleDelta
					local max = min + bone.fMaxConstraint
					min = min + bone.fMinConstraint
					newAgle2 = LM.Clamp(newAgle2, min, max)
				end
			end
			if not self:IsEqual(newAgle2, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAgle2)
				bone.fAnimAngle.value = bone.fAngle
				if self.bakeAdjacentFrames and not self.boneBakedA then
					self:BakeFrames(moho, secondBone, nil, true, false, false)
					self.boneBakedA = true
				end
			end

			moho.layer:UpdateCurFrame()
		
			local center = LM.Vector2:new_local()
			center:Set(0, 0)
			skel:UpdateBoneMatrix()
			secondBone.fMovedMatrix:Transform(center)
			local secondCursorDist = self:GetDistance(center, self.secondBoneTipPos)
			local secondDelta = (secondCursorDist / self.secondBoneDist)
			secondBone.fAnimScale:SetValue(moho.layerFrame, (secondBone.fTempScale * secondDelta) - self.secondBoneSizeDelta)
		end
		
		local angleSign = 1
		if (secondBone.fFlipH.value and not secondBone.fFlipV.value) or (not secondBone.fFlipH.value and secondBone.fFlipV.value) then
			angleSign = -1
		end
	end
	
	if self.isChainTargeted and self.isTargetMoved then
		local targetBone = skel:Bone(self.secondTarget)
		targetBone.fAnimPos:SetValue(moho.layerFrame, targetBone.fTempPos)
	end
	secondBone.fAnimScale.value = secondBone.fScale
	
	if mouseEvent.altKey then
		local angleSign = 1
		local angleSignS = 1
		if (secondBone.fFlipH.value and not secondBone.fFlipV.value) or (not secondBone.fFlipH.value and secondBone.fFlipV.value) then
			angleSignS = -1
		end
		local angleSignF = 1
		if (firstBone.fFlipH.value and not firstBone.fFlipV.value) or (not firstBone.fFlipH.value and firstBone.fFlipV.value) then
			angleSignF = -1
		end
		
		local angleDelta = 0
		if angleSignF == 1 and angleSignS == -1 then
			angleSign = -1
			angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + (secondBone.fAngle - secondBone.fTempAngle)
		elseif angleSignF == 1 and angleSignS == 1 then
			angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + (secondBone.fAngle - secondBone.fTempAngle)	
		elseif angleSignF == -1 and angleSignS == -1 then
			angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + ((secondBone.fAngle - secondBone.fTempAngle) * angleSignF)
		elseif angleSignF == -1 and angleSignS == 1 then
			angleSign = -1
			angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + ((secondBone.fAngle - secondBone.fTempAngle) * angleSignF)
		end
		
		while angleDelta > math.rad(180) do
			angleDelta = angleDelta - math.rad(360)
		end
		
		while angleDelta < math.rad(-180) do
			angleDelta = angleDelta + math.rad(360)
		end

		if not self.isChildBonesBaked and self.bakeAdjacentFrames then
			for i, q in ipairs(self.childBones) do
				local bone = skel:Bone(q)
				if not self.isChildBonesBaked then
					if moho.layerFrame - self.interval > 0 then
						bone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.childBonesAngelP[i])
					end
				end
				if not self.isChildBonesBaked then
					if moho.layerFrame + self.interval > 0 then
						bone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.childBonesAngelN[i])
					end
				end
			end
			self.isChildBonesBaked = true
		end	
		for i, q in ipairs(self.childBones) do
			local bone = skel:Bone(q)
			local newAngle = bone.fTempAngle - (angleDelta * angleSign)
			bone.fAnimAngle:SetValue(moho.layerFrame, newAngle)
		end
	else
		for i, q in ipairs(self.childBones) do
			local firstBone = skel:Bone(q)
			if not self:IsEqual(firstBone.fTempAngle, firstBone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBone.fTempAngle)
			end	
		end
	end
	
	moho.layer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function MR_PoseTool:OnMouseMovedT(moho, mouseEvent)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local bone = skel:Bone(self.secondBoneID)
	bone.fPos:Set(bone.fTempPos)

	local offset = mouseEvent.vec - mouseEvent.startVec
	
	local boneVec = LM.Vector2:new_local()
	local inverseM = LM.Matrix:new_local()
	
	local parent = nil
	boneVec:Set(0, 0)
	if (bone.fParent >= 0) then
		parent = skel:Bone(bone.fParent)
		parent.fMovedMatrix:Transform(boneVec)
	end
	boneVec = boneVec + offset
	if (parent) then
		inverseM:Set(parent.fMovedMatrix)
		inverseM:Invert()
		inverseM:Transform(boneVec)
	end
	if (mouseEvent.shiftKey) then
		if (math.abs(boneVec.x) > math.abs(boneVec.y)) then
			boneVec.y = 0
		else
			boneVec.x = 0
		end
	end
	local v = nil
	v = bone.fPos + boneVec
	if self.mode == 5 then
			bone.fAnimPos:SetValue(self.translationFrame, v)
	elseif self.mode == 0 then
		local bonePos = bone.fAnimPos:GetValue(moho.layerFrame)
		if not self:IsEqual(v.x, bonePos.x, 0.0001) or not self:IsEqual(v.y, bonePos.y, 0.0001) then
			bone.fAnimPos:SetValue(moho.layerFrame, v)
			if self.bakeAdjacentFrames and not self.boneBakedP then
				self:BakeFrames(moho, bone, nil, false, true, false)
				self.boneBakedP = true
			end
		end	
	end	
	if self.mode == 0 then
		if mouseEvent.altKey and bone.fLength > 0 then
			local vectorMousePos = mouseEvent.vec + self.clickOffset
			local secondCursorDist = self:GetDistance(vectorMousePos, self.secondBoneTipPos)
			local secondDelta = (secondCursorDist / self.secondBoneDist)
			local newScale = (bone.fTempScale * secondDelta) - self.secondBoneSizeDelta
			if not self:IsEqual(newScale, bone.fAnimScale:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimScale:SetValue(moho.layerFrame, newScale)
				if self.bakeAdjacentFrames and not self.boneBakedS then
					self:BakeFrames(moho, bone, nil, false, false, true)
					self.boneBakedS = true
				end
			end
			moho.layer:UpdateCurFrame()

			local center = LM.Vector2:new_local()

			center:Set(0, 0)
			skel:UpdateBoneMatrix(self.secondBoneID)
			bone.fMovedMatrix:Transform(center)
			
			local angle = self.startAngle2
			local v1 = self.lastVec2 - self.secondBoneTipPos
			local v2 = center - self.secondBoneTipPos
			v2:Rotate(-math.atan2(v1.y, v1.x))
			angle = angle + math.atan2(v2.y, v2.x)
			self.startAngle2 = angle
			self.lastVec2:Set(center)

			local angleSign = 1.0
			if (not bone.fFixedAngle) then
				angleSign = bone:ParentalFlipFactor()
			end
			
			local newAgle = (bone.fTempAngle + (angle * angleSign)) - self.secondBoneAngleDelta
			if not bone.fFixedAngle then
				if bone.fConstraints then
					local min = bone.fAnimAngle:GetValue(0) - self.secondBoneAngleDelta
					local max = min + bone.fMaxConstraint
					min = min + bone.fMinConstraint
					newAgle = LM.Clamp(newAgle, min, max)
				end
			end
			if not self:IsEqual(newAgle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAgle)
				bone.fAnimAngle.value = bone.fAngle
			end
			if self.bakeAdjacentFrames and not self.boneBakedA then
				self:BakeFrames(moho, bone, nil, true, false, false)
				self.boneBakedA = true
				if not self.isChildBonesBaked then
					for i, q in ipairs(self.childBones) do
						local bone = skel:Bone(q)
						if moho.layerFrame - self.interval > 0 then
							bone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.childBonesAngelP[i])
							bone.fAnimAngle.value = bone.fAngle
						end
						if moho.layerFrame + self.interval > 0 then
							bone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.childBonesAngelN[i])
							bone.fAnimAngle.value = bone.fAngle
						end
					end
					self.isChildBonesBaked = true
				end
				
			end

			local angleSign = 1
			if (bone.fFlipH.value and not bone.fFlipV.value) or (not bone.fFlipH.value and bone.fFlipV.value) then
				angleSign = -1
			end
			
			moho.layer:UpdateCurFrame()
			
			local angleDelta = bone.fAngle - bone.fTempAngle
			
			for i, q in ipairs(self.childBones) do
				local bone = skel:Bone(q)
				bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle - (angleDelta * angleSign))
				bone.fAnimAngle.value = bone.fAngle
			end
		else
			if not self:IsEqual(bone.fTempScale - self.secondBoneSizeDelta, bone.fAnimScale:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimScale:SetValue(moho.layerFrame, bone.fTempScale)
			end
			local newAngle = bone.fTempAngle - self.secondBoneAngleDelta
			if not self:IsEqual(newAngle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAngle)
			end	
			for i, q in ipairs(self.childBones) do
				local bone = skel:Bone(q)
				if not self:IsEqual(bone.fTempAngle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
					bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle)
				end	
			end
		end
	end
	
	moho.layer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function MR_PoseTool:OnMouseMovedR(moho, mouseEvent)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local secondBone = skel:Bone(self.secondBoneID)

	local bone = secondBone
	local center = LM.Vector2:new_local()
	center:Set(0, 0)
	skel:UpdateBoneMatrix()
	bone.fMovedMatrix:Transform(center)
	
	local layerMatrix = LM.Matrix:new_local()
	local mousePos = mouseEvent.vec
	local angle = self.startAngle
	local v1 = self.lastVec - center
	local v2 = mousePos - center
	v2:Rotate(-math.atan2(v1.y, v1.x))
	angle = angle + math.atan2(v2.y, v2.x)
	self.startAngle = angle
	self.lastVec:Set(mousePos)
	local angleSign = 1.0
	if (not bone.fFixedAngle) then
		angleSign = bone:ParentalFlipFactor()
	end

	local newAgle = (bone.fTempAngle + (angle * angleSign)) - self.secondBoneAngleDelta
	
	if not bone.fFixedAngle then
		if bone.fConstraints then
			local min = bone.fAnimAngle:GetValue(0) - self.secondBoneAngleDelta
			local max = min + bone.fMaxConstraint
			min = min + bone.fMinConstraint
			newAgle = LM.Clamp(newAgle, min, max)
		end
	end
	
	if (mouseEvent.shiftKey) then
		newAgle = newAgle / (math.pi / 4)
		newAgle = (math.pi / 4) * LM.Round(newAgle)
	end
	
	if not self:IsEqual(newAgle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
		bone.fAnimAngle:SetValue(moho.layerFrame, newAgle)
		if self.bakeAdjacentFrames and not self.boneBakedA then
			self:BakeFrames(moho, secondBone, nil, true, false, false)
			self.boneBakedA = true
		end
	end	

	local angleSign = 1
	if (bone.fFlipH.value and not bone.fFlipV.value) or (not bone.fFlipH.value and bone.fFlipV.value) then
		angleSign = -1
	end
	
	if self.isChainTargeted then
		local targetBone = skel:Bone(self.secondTarget)
		local newTargetPos = targetBone.fTempPos - (mouseEvent.startVec - mouseEvent.vec)
		targetBone.fAnimPos:SetValue(moho.layerFrame, newTargetPos)
		self.isTargetMoved = true
		if self.bakeAdjacentFrames then
			if not self.isTargetBonePosPBaked then
				if moho.layerFrame - self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame - self.interval, self.targetBonePosP)
				end
				self.isTargetBonePosPBaked = true
			end
			
			if not self.isTargetBonePosNBaked then
				if moho.layerFrame + self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame + self.interval, self.targetBonePosN)
				end
				self.isTargetBonePosNBaked = true
			end
		end	
	end
	
	if mouseEvent.altKey then
		moho.layer:UpdateCurFrame()
		local angleDelta = secondBone.fAngle - secondBone.fTempAngle
		
		if self.bakeAdjacentFrames and not self.isChildBonesBaked then
			for i, q in ipairs(self.childBones) do
				local childBone = skel:Bone(q)
				if moho.layerFrame - self.interval > 0 then
					childBone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.childBonesAngelP[i])
				end
				if moho.layerFrame + self.interval > 0 then
					childBone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.childBonesAngelN[i])
				end
			end	
			self.isChildBonesBaked = true
		end
		
		for i, q in ipairs(self.childBones) do
			local childBone = skel:Bone(q)
			childBone.fAnimAngle:SetValue(moho.layerFrame, childBone.fTempAngle - (angleDelta * angleSign))
		end
	else
		for i, q in ipairs(self.childBones) do
			local childBone = skel:Bone(q)
			if not self:IsEqual(childBone.fTempAngle, childBone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				childBone.fAnimAngle:SetValue(moho.layerFrame, childBone.fTempAngle)
			end	
		end
	end
	
	moho.layer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function MR_PoseTool:OnMouseMovedS(moho, mouseEvent)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end
	local secondBone = skel:Bone(self.secondBoneID)
	if secondBone:IsZeroLength() then
		local scaleFactor = (mouseEvent.pt.x - mouseEvent.startPt.x) / 100
		if (scaleFactor < 0) then
			scaleFactor = 1 / (-scaleFactor + 1)
		else
			scaleFactor = scaleFactor + 1
		end
		local newScale = (secondBone.fTempScale * scaleFactor) - self.secondBoneSizeDelta
		
		if not self:IsEqual(newScale, secondBone.fAnimScale:GetValue(moho.layerFrame), 0.0001) then
			secondBone.fAnimScale:SetValue(moho.layerFrame, newScale)
			if self.bakeAdjacentFrames and not self.boneBakedS then
				self:BakeFrames(moho, secondBone, nil, false, false, true)
				self.boneBakedS = true
			end
		end
	else
		local vectorMousePos = mouseEvent.vec + self.clickOffset
		local secondCursorDist = self:GetDistance(vectorMousePos, self.secondBonePos)
		local secondDelta = (secondCursorDist / self.secondBoneDist)
		local newScale = (secondBone.fTempScale * secondDelta) - self.secondBoneSizeDelta
		if not self:IsEqual(newScale, secondBone.fAnimScale:GetValue(moho.layerFrame), 0.0001) then
			secondBone.fAnimScale:SetValue(moho.layerFrame, newScale)
			if self.bakeAdjacentFrames and not self.boneBakedS then
				self:BakeFrames(moho, secondBone, nil, false, false, true)
				self.boneBakedS = true
			end
		end
		
		if not mouseEvent.shiftKey then
			local bone = secondBone
			local center = LM.Vector2:new_local()
			center:Set(0, 0)
			skel:UpdateBoneMatrix()
			bone.fMovedMatrix:Transform(center)
			
			local mousePos = mouseEvent.vec
			
			local angle = self.startAngle
			local v1 = self.lastVec - center
			local v2 = mousePos - center
			v2:Rotate(-math.atan2(v1.y, v1.x))
			angle = angle + math.atan2(v2.y, v2.x)
			self.startAngle = angle
			self.lastVec:Set(mousePos)
			local angleSign = 1.0
			if (not bone.fFixedAngle) then
				angleSign = bone:ParentalFlipFactor()
			end

			local newAgle = (bone.fTempAngle + (angle * angleSign)) - self.secondBoneAngleDelta
			
			if not bone.fFixedAngle then
				if bone.fConstraints then
					local min = bone.fAnimAngle:GetValue(0) - self.secondBoneAngleDelta
					local max = min + bone.fMaxConstraint
					min = min + bone.fMinConstraint
					newAgle = LM.Clamp(newAgle, min, max)
				end
			end
			if not self:IsEqual(newAgle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAgle)
				if self.bakeAdjacentFrames and not self.boneBakedA then
					self:BakeFrames(moho, secondBone, nil, true, false, false)
					self.boneBakedA = true
				end
			end	
		else
			local bone = secondBone
			local newAngle = bone.fTempAngle - self.secondBoneAngleDelta
			if not self:IsEqual(newAngle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, newAngle)
				if self.bakeAdjacentFrames and not self.boneBakedA then
					self:BakeFrames(moho, secondBone, nil, true, false, false)
					self.boneBakedA = true
				end
			end	
		end
	end
	
	local angleSign = 1
	if (secondBone.fFlipH.value and not secondBone.fFlipV.value) or (not secondBone.fFlipH.value and secondBone.fFlipV.value) then
		angleSign = -1
	end
	
	if self.isChainTargeted then
		local targetBone = skel:Bone(self.secondTarget)
		local newTargetPos = targetBone.fTempPos - (mouseEvent.startVec - mouseEvent.vec)
		targetBone.fAnimPos:SetValue(moho.layerFrame, newTargetPos)
		self.isTargetMoved = true
		if self.bakeAdjacentFrames then
			if not self.isTargetBonePosPBaked then
				if moho.layerFrame - self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame - self.interval, self.targetBonePosP)
				end
				self.isTargetBonePosPBaked = true
			end
			
			if not self.isTargetBonePosNBaked then
				if moho.layerFrame + self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame + self.interval, self.targetBonePosN)
				end
				self.isTargetBonePosNBaked = true
			end
		end	
	end
	
	if mouseEvent.altKey then
		moho.layer:UpdateCurFrame()
		if self.bakeAdjacentFrames and not self.isChildBonesBaked then
			for i, q in ipairs(self.childBones) do
				local bone = skel:Bone(q)
				if moho.layerFrame - self.interval > 0 then
					bone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.childBonesAngelP[i])
				end
				if moho.layerFrame + self.interval > 0 then
					bone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.childBonesAngelN[i])
				end
			end
			self.isChildBonesBaked = true
		end

		local angleDelta = secondBone.fAngle - secondBone.fTempAngle
		
		for i, q in ipairs(self.childBones) do
			local bone = skel:Bone(q)
			bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle - (angleDelta * angleSign))
		end
	else
		for i, q in ipairs(self.childBones) do
			local bone = skel:Bone(q)
			if not self:IsEqual(bone.fTempAngle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle)
			end	
		end
	end
	
	moho.layer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
end

function MR_PoseTool:OnMouseMovedM(moho, mouseEvent)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local riggingFrame = 0
	local bone = skel:Bone(self.selID)
	local secondBone = skel:Bone(self.selID)
	
	if self.bakeAdjacentFrames and not self.boneBakedA then
		self:BakeFrames(moho, secondBone, nil, true, false, false)
		self.boneBakedA = true
	end
	skel:UpdateBoneMatrix(self.selID)

	local tipVec = LM.Vector2:new_local()

	tipVec:Set(bone.fLength, 0)
	bone.fMovedMatrix:Transform(tipVec)
	tipVec = tipVec + (mouseEvent.vec - self.lastVec)
	
	local startBone = skel:Bone(self.parentBones[#self.parentBones])
	local center = LM.Vector2:new_local()
	center:Set(0, 0)
	skel:UpdateBoneMatrix()
	startBone.fMovedMatrix:Transform(center)

	local mousePos = mouseEvent.vec
	
	local angle = self.startAngle
	local v1 = self.lastVec - center
	local v2 = mousePos - center
	v2:Rotate(-math.atan2(v1.y, v1.x))
	angle = angle + math.atan2(v2.y, v2.x)
	self.startAngle = angle
	self.lastVec:Set(mousePos)
	local angleSign = 1.0
	if (not startBone.fFixedAngle) then
		angleSign = startBone:ParentalFlipFactor()
	end

	local newAgle = (startBone.fTempAngle + (angle * angleSign))
	if mouseEvent.shiftKey then
		if self.bakeAdjacentFrames and not self.boneBakedS then
			self:BakeFrames(moho, secondBone, nil, false, false, true)
			for i, q in ipairs(self.parentBones) do
				local bone = skel:Bone(q)
				if moho.layerFrame - self.interval > 0 then
					bone.fAnimScale:SetValue(moho.layerFrame - self.interval, self.parentBonesScaleP[i])
				end
				if moho.layerFrame + self.interval > 0 then
					bone.fAnimScale:SetValue(moho.layerFrame + self.interval, self.parentBonesScaleN[i])
				end
			end	
			self.boneBakedS = true
		end
	
		if self.bakeAdjacentFrames and not self.boneBakedS then
			self:BakeFrames(moho, secondBone, nil, false, false, true)
			self.boneBakedS = true
		end
		
		local newStartBoneDist = self:GetDistance(self.startBonePos, mouseEvent.vec)
		local startBoneDistDelta = newStartBoneDist / self.startBoneDist
		bone.fAnimScale:SetValue(moho.layerFrame, bone.fTempScale * startBoneDistDelta)
		
		if not startBone.fFixedAngle then
			if startBone.fConstraints then
				local min = startBone.fAnimAngle:GetValue(0) - self.startBoneAngleDelta
				local max = min + startBone.fMaxConstraint
				min = min + startBone.fMinConstraint
				newAgle = LM.Clamp(newAgle, min, max)
			end
		end

		for i, q in ipairs(self.parentBones) do
			local parentBone = skel:Bone(q)
			parentBone.fAnimScale:SetValue(moho.layerFrame, parentBone.fTempScale * startBoneDistDelta)
			if not self:IsEqual(parentBone.fTempAngle, parentBone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
				parentBone.fAnimAngle:SetValue(moho.layerFrame, parentBone.fTempAngle)
			end	
		end	
		if not self:IsEqual(bone.fTempAngle, bone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
			bone.fAnimAngle:SetValue(moho.layerFrame, bone.fTempAngle)
		end	
		startBone.fAnimAngle:SetValue(moho.layerFrame, newAgle)
	else
		skel:IKAngleSolver(self.selID, tipVec)
		local boneID = 1
		bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle - (self.boneStartActualAngles[boneID] - self.boneStartAngles[boneID]))
		bone.fAnimAngle.value = bone.fAngle
		boneID = boneID + 1
		while bone.fParent >= 0 do
			if (self:CountBoneChildren(skel, bone.fParent, true) > 1) then
				break
			end
			local parentBone = skel:Bone(bone.fParent)
			if self.mohoVersion >= 14 then
				if (parentBone.fAngleControlParent >= 0 or
					parentBone.fPosControlParent >= 0 or
					parentBone.fScaleControlParent >= 0 or
					parentBone:AreDynamicsActive() or
					parentBone.fFixedAngle or
					parentBone.fIgnoredByIK) then
					break
				end
			else
				if (parentBone.fAngleControlParent >= 0 or
					parentBone.fPosControlParent >= 0 or
					parentBone.fScaleControlParent >= 0 or
					parentBone.fBoneDynamics.value or
					parentBone.fFixedAngle or
					parentBone.fIgnoredByIK) then
					break
				end
			end	

			bone = skel:Bone(bone.fParent)
			bone.fAnimAngle:SetValue(moho.layerFrame, bone.fAngle - (self.boneStartActualAngles[boneID] - self.boneStartAngles[boneID]))
			bone.fAnimAngle.value = bone.fAngle
			boneID = boneID + 1
		end
	end

	if #self.parentBones == 1 then
		local firstBone = skel:Bone(self.parentBones[1])
		if mouseEvent.altKey then
			moho.layer:UpdateCurFrame()
			local angleSign = 1
			local angleSignS = 1
			if (secondBone.fFlipH.value and not secondBone.fFlipV.value) or (not secondBone.fFlipH.value and secondBone.fFlipV.value) then
				angleSignS = -1
			end
			local angleSignF = 1
			if (firstBone.fFlipH.value and not firstBone.fFlipV.value) or (not firstBone.fFlipH.value and firstBone.fFlipV.value) then
				angleSignF = -1
			end
			
			local angleDelta = 0
			if angleSignF == 1 and angleSignS == -1 then
				angleSign = -1
				angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + (secondBone.fAngle - secondBone.fTempAngle)
			elseif angleSignF == 1 and angleSignS == 1 then
				angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + (secondBone.fAngle - secondBone.fTempAngle)	
			elseif angleSignF == -1 and angleSignS == -1 then
				angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + ((secondBone.fAngle - secondBone.fTempAngle) * angleSignF)
			elseif angleSignF == -1 and angleSignS == 1 then
				angleSign = -1
				angleDelta = (firstBone.fAngle - firstBone.fTempAngle) + ((secondBone.fAngle - secondBone.fTempAngle) * angleSignF)
			end
		
			moho.layer:UpdateCurFrame()

			if not self.isChildBonesBaked and self.bakeAdjacentFrames then
				for i, q in ipairs(self.childBones) do
					local bone = skel:Bone(q)
					if not self.isChildBonesBaked then
						if moho.layerFrame - self.interval > 0 then
							bone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.childBonesAngelP[i])
						end
					end
					if not self.isChildBonesBaked then
						if moho.layerFrame + self.interval > 0 then
							bone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.childBonesAngelN[i])
						end
					end
				end
				self.isChildBonesBaked = true
			end	
			for i, q in ipairs(self.childBones) do
				local bone = skel:Bone(q)
				local newAngle = bone.fTempAngle - (angleDelta * angleSign)
				bone.fAnimAngle:SetValue(moho.layerFrame, newAngle)
			end
		else
			for i, q in ipairs(self.childBones) do
				local firstBone = skel:Bone(q)
				if not self:IsEqual(firstBone.fTempAngle, firstBone.fAnimAngle:GetValue(moho.layerFrame), 0.0001) then
					firstBone.fAnimAngle:SetValue(moho.layerFrame, firstBone.fTempAngle)
				end	
			end
		end
	end
	
	if self.bakeAdjacentFrames and not self.isParentBonesBaked then
		for i, q in ipairs(self.parentBones) do
			local bone = skel:Bone(q)
			if moho.layerFrame - self.interval > 0 then
				bone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.parentBonesAngleP[i])
			end
			if moho.layerFrame + self.interval > 0 then
				bone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.parentBonesAngleN[i])
			end
		end	
		self.isParentBonesBaked = true
	end
	
	if self.isChainTargeted then
		local targetBone = skel:Bone(self.secondTarget)
		local newTargetPos = targetBone.fTempPos - (mouseEvent.startVec - mouseEvent.vec)
		targetBone.fAnimPos:SetValue(moho.layerFrame, newTargetPos)
		self.isTargetMoved = true
		if self.bakeAdjacentFrames then
			if not self.isTargetBonePosPBaked then
				if moho.layerFrame - self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame - self.interval, self.targetBonePosP)
				end
				self.isTargetBonePosPBaked = true
			end
			
			if not self.isTargetBonePosNBaked then
				if moho.layerFrame + self.interval > 0 then
					targetBone.fAnimPos:SetValue(moho.layerFrame + self.interval, self.targetBonePosN)
				end
				self.isTargetBonePosNBaked = true
			end
		end	
	end
	
	skel:UpdateBoneMatrix()
	moho.layer:UpdateCurFrame()
	mouseEvent.view:DrawMe()
	self.lastVec:Set(mouseEvent.vec)
end	

function MR_PoseTool:OnMouseUp(moho, mouseEvent)
	self.dragging = false
	local skel = moho:Skeleton()
	if skel == nil or moho.frame == 0 then
		return
	end
	
	if self.isActive == false then
		return
	end
	
	local bone
	if self.firstBoneID > -1 then
		bone = skel:Bone(self.firstBoneID)
	end	
	local secondBoneID = skel:Bone(self.secondBoneID)
	
	if self.firstBoneParentID > -1 then
		local firstBoneParent = skel:Bone(self.firstBoneParentID)
		if firstBoneParent then
			firstBoneParent.fIgnoredByIK = self.firstBoneParentIBIK
		end	
	end
	
	if self.keepSelection then
		skel:SelectNone()
		for i, boneID in ipairs(self.selectedBonesList) do
			local bone = skel:Bone(boneID)
			bone.fSelected = true
		end
	end
	
	moho.layer:UpdateCurFrame()
	moho:UpdateUI()
	mouseEvent.view:DrawMe()
	moho:UpdateSelectedChannels()
end

function MR_PoseTool:DrawMe(moho, view)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return
	end

	local markerR = self.markerR
	
	if self.additionHandles then
		markerR = self.markerR2
	end
	
	local v = LM.Vector2:new_local()
	local g = view:Graphics()
	local layerMatrix = LM.Matrix:new_local()
	local vc1 = LM.ColorVector:new_local()
	local vc2 = LM.ColorVector:new_local()
	local interp = MOHO.InterpSetting:new_local()
	local center = LM.Vector2:new_local()
	local tip = LM.Vector2:new_local()
	local offset = LM.Vector2:new_local()
	local angle = 0
	local newAngle = 0
	local offsetAngle = 0

	vc1:Set(MOHO.MohoGlobals.SelCol)
	vc2:Set(MOHO.MohoGlobals.BackCol)
	
	local colorExtraHandle = LM.rgb_color:new_local()
	colorExtraHandle.r = 255
	colorExtraHandle.g = 189
	colorExtraHandle.b = 46
	colorExtraHandle.a = 255
	
	local whiteColor = LM.rgb_color:new_local()
	whiteColor.r = 255
	whiteColor.g = 255
	whiteColor.b = 255
	whiteColor.a = 255
	
	vc1 = (vc1 + vc2) / 2
	local fillCol = vc1:AsColorStruct()
	
	local colorExtraHandleHL = LM.rgb_color:new_local()
	colorExtraHandleHL.r = ((colorExtraHandle.r * 3) + whiteColor.r) / 4
	colorExtraHandleHL.g = ((colorExtraHandle.g * 3) + whiteColor.g) / 4
	colorExtraHandleHL.b = ((colorExtraHandle.b * 3) + whiteColor.b) / 4
	colorExtraHandleHL.a = 255
	
	local colorExtraHandleOutlineHL = LM.rgb_color:new_local()
	colorExtraHandleOutlineHL.r = (colorExtraHandleHL.r + (MOHO.MohoGlobals.SelCol.r * 2)) / 3
	colorExtraHandleOutlineHL.g = (colorExtraHandleHL.g + (MOHO.MohoGlobals.SelCol.g * 2)) / 3
	colorExtraHandleOutlineHL.b = (colorExtraHandleHL.b + (MOHO.MohoGlobals.SelCol.b * 2)) / 3
	colorExtraHandleOutlineHL.a = 255
	
	local fillColHL = LM.rgb_color:new_local()
	fillColHL.r = ((fillCol.r * 3) + whiteColor.r) / 4
	fillColHL.g = ((fillCol.g * 3) + whiteColor.g) / 4
	fillColHL.b = ((fillCol.b * 3) + whiteColor.b) / 4
	fillColHL.a = 255
	
	local hlDelta = 1
	
	moho.layer:GetFullTransform(moho.frame, layerMatrix, moho.document)
	g:Push()
	g:ApplyMatrix(layerMatrix)
	local height = g:Height() / moho.document:Height()
	height = g:Height() / self.height
	local markerMultiplier = 0.002
	local additionMarker1 = self.additionHandles
	local currentScale = g:CurrentScale(false)
	g:SetSmoothing(true)
	g:SetBezierTolerance(2)
	
	if self.mousePickedID > -1 and not (self.dragging or moho:IsPlaying()) then
		local bone = skel:Bone(self.mousePickedID)
		if bone ~= nil then
			local isPin = bone:IsZeroLength()
			if not bone.fHidden and bone:IsGroupVisible() then
				v:Set(bone.fLength - bone.fLength * self.handlesDist, 0)
				bone.fMovedMatrix:Transform(v)
				
				if additionMarker1 then
					center:Set(0, 0)
					tip:Set(1, 0)
					bone.fMovedMatrix:Transform(center)
					bone.fMovedMatrix:Transform(tip)
					
					offset:Set(v.x, v.y - ((markerR * markerMultiplier) / currentScale / height))
					angle = math.atan2(tip.y - center.y, tip.x - center.x)
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					angle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, angle))
				end
				if self.drawMode == 2 then
					if isPin then
						g:SetColor(colorExtraHandleHL)
					else
						g:SetColor(fillColHL)
					end	
					markerR = self.markerR + hlDelta
				else
					if isPin then
						g:SetColor(colorExtraHandle)
					else
						g:SetColor(fillCol)
					end	
					markerR = self.markerR
				end
				
				if bone.fLength == 0 and self.keepHandles then
					markerR = markerR * 3
				end
				
				g:FillCirclePixelRadius(v, markerR)
				g:SetColor(MOHO.MohoGlobals.SelCol)
				g:FrameCirclePixelRadius(v, markerR)
				markerR = self.markerR
				if additionMarker1 then
					v:Set(bone.fLength - (bone.fLength * self.handlesDist), 0)
					bone.fMovedMatrix:Transform(v)
					
					offset:Set(v.x, v.y + ((markerR * markerMultiplier) / currentScale / height))
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					newAngle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, newAngle))
					
					if self.drawMode == 4 then
						g:SetColor(colorExtraHandleHL)
						markerR = self.markerR + hlDelta
					else
						g:SetColor(colorExtraHandle)
						markerR = self.markerR
					end
					g:FillCirclePixelRadius(v, markerR)
					g:SetColor(colorExtraHandleOutlineHL)
					g:FrameCirclePixelRadius(v, markerR)
					markerR = self.markerR
				end	
					v:Set(bone.fLength * self.handlesDist, 0)
					bone.fMovedMatrix:Transform(v)
					
					if additionMarker1 then
						offset:Set(v.x, v.y - ((markerR * markerMultiplier) / currentScale / height))
						offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
						newAngle = offsetAngle + (angle - offsetAngle)
						v:Set(self:RotateVector2(moho, offset, v, newAngle))
					end

					if self.drawMode == 0 or self.drawMode == 5 then
						g:SetColor(fillColHL)
						markerR = self.markerR + hlDelta
					else
						g:SetColor(fillCol)
						markerR = self.markerR
					end
					g:FillCirclePixelRadius(v, markerR)
					g:SetColor(MOHO.MohoGlobals.SelCol)
					g:FrameCirclePixelRadius(v, markerR)
					markerR = self.markerR
				if not isPin then
					if additionMarker1 then
						v:Set(bone.fLength * self.handlesDist, 0)
						bone.fMovedMatrix:Transform(v)
						
						offset:Set(v.x, v.y + ((markerR * markerMultiplier) / currentScale / height))
						offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
						newAngle = offsetAngle + (angle - offsetAngle)
						v:Set(self:RotateVector2(moho, offset, v, newAngle))
						
						if self.drawMode == 3 then
							g:SetColor(colorExtraHandleHL)
							markerR = self.markerR + hlDelta
						else
							g:SetColor(colorExtraHandle)
							markerR = self.markerR
						end
						g:FillCirclePixelRadius(v, markerR)
						g:SetColor(colorExtraHandleOutlineHL)
						g:FrameCirclePixelRadius(v, markerR)
						markerR = self.markerR
					end	
				end
			end
		end
	end
	if moho:CountSelectedBones() == 1 then
		local bone = skel:Bone(skel:SelectedBoneID())
		if bone ~= nil then
			if (bone.fSelected and self.showPath and bone.fParent < 0) then
				-- draw path
				local channelPos = bone.fAnimPos
				local startFrame = channelPos:GetKeyWhen(0)
				local channelDuration = channelPos:Duration()
				local endFrame = channelDuration
				local totalTimingOffset = moho.layer:TotalTimingOffset()

				if (startFrame - totalTimingOffset < 0) then
					startFrame = totalTimingOffset
				end
				channelPos:GetKeyInterp(endFrame, interp)
				if (interp:IsAdditiveCycle()) then
					endFrame = moho.document:EndFrame() + totalTimingOffset
				end

				if (endFrame > startFrame) then
					local vec = LM.Vector2:new_local()
					local oldVec = LM.Vector2:new_local()
					if self.range then
						startFrame = LM.Clamp(moho.layerFrame - self.rangeFrames, 1, channelDuration)
						endFrame = LM.Clamp(moho.layerFrame + self.rangeFrames, 1, channelDuration)
					end
					g:SetColor(102, 152, 203)
					for frame = startFrame, endFrame do
						vec = channelPos:GetValue(frame)
						if (frame > startFrame) then
							g:DrawLine(oldVec.x, oldVec.y, vec.x, vec.y)
						end
						if (channelPos:HasKey(frame)) then
							g:DrawFatMarker(vec.x, vec.y, 5)
						else
							g:DrawMarker(vec.x, vec.y)
						end
						oldVec:Set(vec)
					end
				end
			end
		end	
	end	
	g:Pop()
end

function MR_PoseTool:Round(x, n)
	n = 10 ^ (n or 3)
	x = x * n
	if x >= 0 then x = math.floor(x + 0.5) else x = math.ceil(x - 0.5) end
	return x / n
end

function MR_PoseTool:GetDistance(Pos1, Pos2)
	return math.sqrt((Pos2.x-Pos1.x)^2+(Pos2.y-Pos1.y)^2)
end

function MR_PoseTool:GetMohoVersion(moho)
	local numVers = {}
	local vers = moho:AppVersion()
	for n in string.gmatch (vers, "%d+") do
		table.insert(numVers, tonumber(n))
	end
	return numVers[1], numVers[2], numVers[3]
end

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

MR_PoseTool.KEEP_SELECTION = MOHO.MSG_BASE
MR_PoseTool.BAKE_ADJACENT_FRAMES = MOHO.MSG_BASE + 1
MR_PoseTool.INTERVAL_1 = MOHO.MSG_BASE + 2
MR_PoseTool.INTERVAL_2 = MOHO.MSG_BASE + 3
MR_PoseTool.INTERVAL_3 = MOHO.MSG_BASE + 4
MR_PoseTool.INTERVAL_4 = MOHO.MSG_BASE + 5
MR_PoseTool.SHOW_PATH = MOHO.MSG_BASE + 6
MR_PoseTool.RANGE = MOHO.MSG_BASE + 7
MR_PoseTool.RANGE_FRAMES = MOHO.MSG_BASE + 8
MR_PoseTool.FLIP_H = MOHO.MSG_BASE + 9
MR_PoseTool.FLIP_V = MOHO.MSG_BASE + 10

function MR_PoseTool:DoLayout(moho, layout)
	self.keepSelectionCheckbox = LM.GUI.CheckBox(self:Localize('Keep selection'), self.KEEP_SELECTION)
    layout:AddChild(self.keepSelectionCheckbox, LM.GUI.ALIGN_LEFT, 0)

	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	self.bakeAdjacentFramesCheckbox = LM.GUI.CheckBox(self:Localize('Bake Adjacent Frames'), self.BAKE_ADJACENT_FRAMES)
    layout:AddChild(self.bakeAdjacentFramesCheckbox, LM.GUI.ALIGN_LEFT, 0)
	
	layout:AddChild(LM.GUI.StaticText(self:Localize("Interval")))

	self.intervalMenu = LM.GUI.Menu(MOHO.Localize("Interval=Interval"))
	self.intervalMenu:AddItem(MOHO.Localize("1=1"), 0, self.INTERVAL_1)
	self.intervalMenu:AddItemAlphabetically(MOHO.Localize("2=2"), 0, self.INTERVAL_2)
	self.intervalMenu:AddItemAlphabetically(MOHO.Localize("3=3"), 0, self.INTERVAL_3)
	self.intervalMenu:AddItemAlphabetically(MOHO.Localize("4=4"), 0, self.INTERVAL_4)

	self.intervalPopup = LM.GUI.PopupMenu(50, true)
	self.intervalPopup:SetMenu(self.intervalMenu)
	layout:AddChild(self.intervalPopup)
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	self.showPathCheckbox = LM.GUI.CheckBox(self:Localize('Show path'), self.SHOW_PATH)
    layout:AddChild(self.showPathCheckbox, LM.GUI.ALIGN_LEFT, 0)
	
	self.rangeCheckbox = LM.GUI.CheckBox(self:Localize('Range'), self.RANGE)
    layout:AddChild(self.rangeCheckbox, LM.GUI.ALIGN_LEFT, 0)
	
	self.rangeFramesInput = LM.GUI.TextControl(0, '1000', self.RANGE_FRAMES, LM.GUI.FIELD_INT, self:Localize('Range frames:'))
    layout:AddChild(self.rangeFramesInput, LM.GUI.ALIGN_LEFT, 0)
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
	
	layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_bone_h", self:Localize('End flip'), false, self.FLIP_H, true))
	layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_bone_v", self:Localize('Side flip'), false, self.FLIP_V, true))
	
	layout:AddChild(LM.GUI.Divider(true), LM.GUI.ALIGN_FILL)
end

function MR_PoseTool:UpdateWidgets(moho)
	if self.mainCursor == nil then
		self.mainCursor = LM.GUI.Cursor(moho:UserContentDir()..'/Scripts/Tool/mr_pose_tool_cursor', 1, 1)
	end	
	if self.mjCursor == nil then
		self.mjCursor = LM.GUI.Cursor(moho:UserContentDir()..'/Scripts/ScriptResources/mr_pose_tool/mr_mj_cursor', 1, 1)
	end	
	if self.mbCursor == nil then
		self.mbCursor = LM.GUI.Cursor(moho:UserContentDir()..'/Scripts/ScriptResources/mr_pose_tool/mr_mb_cursor', 1, 1)
	end	

	self.keepSelectionCheckbox:SetValue(self.keepSelection)
	self.bakeAdjacentFramesCheckbox:SetValue(self.bakeAdjacentFrames)
	if self.interval < 1 or self.interval > 4 or self.interval == nil then
		self.interval = 1
	end
	
	self.intervalMenu:SetChecked(self.INTERVAL_1, false)
	self.intervalMenu:SetChecked(self.INTERVAL_2, false)
	self.intervalMenu:SetChecked(self.INTERVAL_3, false)
	self.intervalMenu:SetChecked(self.INTERVAL_4, false)
	if (self.interval == 1) then
		self.intervalMenu:SetChecked(self.INTERVAL_1, true)
	elseif (self.interval == 2) then
		self.intervalMenu:SetChecked(self.INTERVAL_2, true)
	elseif (self.interval == 3) then
		self.intervalMenu:SetChecked(self.INTERVAL_3, true)
	elseif (self.interval == 4) then
		self.intervalMenu:SetChecked(self.INTERVAL_4, true)
	end
	self.intervalPopup:Enable(self.bakeAdjacentFrames)
	self.intervalPopup:Redraw()
	self.showPathCheckbox:SetValue(self.showPath)
	self.rangeCheckbox:SetValue(self.range)
	self.rangeFramesInput:SetValue(self.rangeFrames)
	self.rangeCheckbox:Enable(self.showPath)
	self.rangeFramesInput:Enable(self.range and self.showPath)
end

function MR_PoseTool:HandleMessage(moho, view, msg)
	if msg == self.KEEP_SELECTION then
        self.keepSelection = self.keepSelectionCheckbox:Value()
	elseif msg == self.BAKE_ADJACENT_FRAMES then
		self.bakeAdjacentFrames = self.bakeAdjacentFramesCheckbox:Value()
		self.intervalPopup:Enable(self.bakeAdjacentFrames)
	elseif (msg >= self.INTERVAL_1 and msg <= self.INTERVAL_4) then
		local int = 1
		if (msg == self.INTERVAL_1) then
			int = 1
		elseif (msg == self.INTERVAL_2) then
			int = 2
		elseif (msg == self.INTERVAL_3) then
			int = 3
		elseif (msg == self.INTERVAL_4) then
			int = 4
		end	
		self.interval = int
		self:UpdateWidgets(moho)
	elseif msg == self.SHOW_PATH then
        self.showPath = self.showPathCheckbox:Value()
		self.rangeCheckbox:Enable(self.showPath)
		self.rangeFramesInput:Enable(self.range and self.showPath)
	elseif msg == self.RANGE then
        self.range = self.rangeCheckbox:Value()	
		self.rangeCheckbox:Enable(self.showPath)
		self.rangeFramesInput:Enable(self.range and self.showPath)
	elseif msg == self.RANGE_FRAMES then
        self.rangeFrames = LM.Clamp(self.rangeFramesInput:Value(), 1, 1000)	
		self.rangeFramesInput:SetValue(self.rangeFrames)
	elseif (msg == self.FLIP_H) then
		self:FlipBones(moho, true)
	elseif (msg == self.FLIP_V) then
		self:FlipBones(moho, false)
	end	
end

function MR_PoseTool:IsEqual(a, b, epsilon)
    local absA = math.abs(a)
    local absB = math.abs(b)
    local diff = math.abs(a - b)

    if a == b then 
        return true 
    elseif diff < epsilon then 
        return true
    else 
        return false
    end
end

function MR_PoseTool:CheckBone(moho, id)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return false
	end
	if id < 0 or not id then
		return false
	end
	local secondBone = skel:Bone(id)
	if secondBone then
		if secondBone.fParent > -1 and not secondBone:IsZeroLength() and not secondBone.fFixedAngle then
			local firstBoneID = secondBone.fParent
			local firstBone = skel:Bone(firstBoneID)
			local firstBoneChilds = skel:CountBoneChildren(firstBoneID, true)
			local secondBonePos = LM.Vector2:new_local()
			secondBonePos:Set(secondBone.fAnimPos:GetValue(moho.layerFrame))
			if firstBone.fIgnoredByIK == false and secondBone.fIgnoredByIK == false and firstBoneChilds == 1 and self:Round(secondBone.fPos.y) == 0 
			and not self:IsEqual(secondBonePos.x, 0, 0.0001) and not firstBone:IsZeroLength() and not firstBone.fFixedAngle then
				return true
			end
		end
	end	
	return false
end

function MR_PoseTool:TestMousePoint(moho, mouseEvent, id)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return 1
	end

	local markerR = self.markerR
	if self.additionHandles then
		markerR = self.markerR2
	end
	
	local v = LM.Vector2:new_local()
	local pt = LM.Point:new_local()
	local m = LM.Matrix:new_local()
	local center = LM.Vector2:new_local()
	local tip = LM.Vector2:new_local()
	local offset = LM.Vector2:new_local()
	local angle = 0
	local newAngle = 0
	local offsetAngle = 0

	moho.layer:GetFullTransform(moho.frame, m, moho.document)
	local g = mouseEvent.view:Graphics()
	g:Push()
	g:ApplyMatrix(m)
	local height = g:Height() / moho.document:Height()
	height = g:Height() / self.height
	local markerMultiplier = 0.002

	local additionMarker1 = self.additionHandles
	local currentScale = g:CurrentScale(false)
	g:Pop()
	
	self.keepHandles = mouseEvent.ctrlKey
	
	if self.mousePickedID > -1 then
		local bone = skel:Bone(self.mousePickedID)
		if bone ~= nil then
			if not bone.fHidden and bone:IsGroupVisible() then
				v:Set(bone.fLength * self.handlesDist, 0)
				bone.fMovedMatrix:Transform(v)
				
				if additionMarker1 then
					center:Set(0, 0)
					tip:Set(1, 0)
					bone.fMovedMatrix:Transform(center)
					bone.fMovedMatrix:Transform(tip)
					
					offset:Set(v.x, v.y - ((markerR * markerMultiplier) / currentScale / height))
					angle = math.atan2(tip.y - center.y, tip.x - center.x)
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					newAngle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, newAngle))
				end
				
				m:Transform(v)
				
				mouseEvent.view:Graphics():WorldToScreen(v, pt)
				if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then
					return 0
				end
				
				if additionMarker1 then	
					v:Set(bone.fLength * self.handlesDist, 0)
					bone.fMovedMatrix:Transform(v)
					
					offset:Set(v.x, v.y + ((markerR * markerMultiplier) / currentScale / height))
					angle = math.atan2(tip.y - center.y, tip.x - center.x)
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					newAngle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, newAngle))
					
					m:Transform(v)
					mouseEvent.view:Graphics():WorldToScreen(v, pt)
					if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then
						return 3
					end
				end
			end	

			if not bone.fHidden and bone:IsGroupVisible() then
				v:Set(bone.fLength - bone.fLength * self.handlesDist, 0)

				bone.fMovedMatrix:Transform(v)
				
				if additionMarker1 then
					offset:Set(v.x, v.y - ((markerR * markerMultiplier) / currentScale / height))
					angle = math.atan2(tip.y - center.y, tip.x - center.x)
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					newAngle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, newAngle))
				end
				m:Transform(v)
				mouseEvent.view:Graphics():WorldToScreen(v, pt)
				if bone:IsZeroLength() and mouseEvent.ctrlKey then
					if (math.abs(pt.x - mouseEvent.pt.x) < markerR * 3 and math.abs(pt.y - mouseEvent.pt.y) < markerR * 3) then
						return 2
					end
				else
					if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then
						return 2
					end
				end	
				
				if additionMarker1 then
					v:Set(bone.fLength - (bone.fLength * self.handlesDist), 0)
					bone.fMovedMatrix:Transform(v)
				
					offset:Set(v.x, v.y + ((markerR * markerMultiplier) / currentScale / height))
					offsetAngle = math.atan2(offset.y - center.y, offset.x - center.x)
					newAngle = offsetAngle + (angle - offsetAngle)
					v:Set(self:RotateVector2(moho, offset, v, newAngle))
					m:Transform(v)
					mouseEvent.view:Graphics():WorldToScreen(v, pt)
					if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then
						return 4
					end
				end
			end
		end
	end

	if id then
		if id > -1 and self.showPath then
			local bone = skel:Bone(id)
			if bone ~= nil then
				local channelPos = bone.fAnimPos
				local translationWhen = -20000
				local g = mouseEvent.view:Graphics()
				local m = LM.Matrix:new_local()
				local vec = LM.Vector2:new_local()
				local pt = LM.Point:new_local()
				local totalTimingOffset = moho.layer:TotalTimingOffset()
				moho.layer:GetFullTransform(moho.frame, m, moho.document)
				-- First see if any keyframes were picked
				for i = 0, bone.fAnimPos:CountKeys() - 1 do
					local frame = bone.fAnimPos:GetKeyWhen(i)
					if frame > 0 then
						vec = bone.fAnimPos:GetValue(frame)
						m:Transform(vec)
						g:WorldToScreen(vec, pt)
						if (math.abs(pt.x - mouseEvent.pt.x) < self.TOLERANCE and math.abs(pt.y - mouseEvent.pt.y) < self.TOLERANCE) then
							translationWhen = frame
							self.trPathBone = bone
							break
						end
					end	
				end
				-- If no keyframes were picked, try picking a random point along the curve.
				if (translationWhen <= -10000) then
					local startFrame = channelPos:GetKeyWhen(0)
					local channelDuration = channelPos:Duration()
					local endFrame = channelDuration
					if self.range then
						startFrame = LM.Clamp(moho.layerFrame - self.rangeFrames, 1, channelDuration)
						endFrame = LM.Clamp(moho.layerFrame + self.rangeFrames, 1, channelDuration)
					end
					if (endFrame > startFrame) then
						local oldVec = LM.Vector2:new_local()
						g:Clear(0, 0, 0, 0)
						g:SetColor(255, 255, 255)
						g:BeginPicking(mouseEvent.pt, 4)
						for frame = startFrame, endFrame do
							vec = channelPos:GetValue(frame)
							m:Transform(vec)
							if (frame > startFrame) then
								g:DrawLine(oldVec.x, oldVec.y, vec.x, vec.y)
							end
							if (g:Pick()) then
								translationWhen = frame
								self.trPathBone = bone
								break
							end
							oldVec:Set(vec)
						end
					end
				end
				if (translationWhen > -10000) then
					self.translationFrame = translationWhen
					return 5
				end
			end	
		end
	end
	return 1
end

function MR_PoseTool:FlipBones(moho, horizontal)
	local skel = moho:Skeleton()
	if (skel == nil) then
		return 1
	end
	
	if (moho:CountSelectedBones(true) < 1) then
		return
	end

	moho.document:PrepUndo(moho.layer, true)
	moho.document:SetDirty()
	for i = 0, skel:CountBones() - 1 do
		local bone = skel:Bone(i)
		if (bone.fSelected) then
			if (horizontal) then
				bone.fFlipH:SetValue(moho.layerFrame, not bone.fFlipH.value)
			else
				bone.fFlipV:SetValue(moho.layerFrame, not bone.fFlipV.value)
			end
		end
	end
	moho.layer:UpdateCurFrame()
	if (horizontal) then
		moho:NewKeyframe(CHANNEL_BONE_FLIPH)
	else
		moho:NewKeyframe(CHANNEL_BONE_FLIPV)
	end
end

function MR_PoseTool:BakeFrames(moho, secondBone, firstBone, angle, pos, scale)
	if moho.layerFrame - self.interval > 0 then
		if firstBone then
			if angle and self.boneFAngleP then
				firstBone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.boneFAngleP)
			end	
			if pos and self.boneFPosP then
				local channel = firstBone.fAnimPos
				if channel:AreDimensionsSplit() then
					local channelX = channel:DimensionChannel(0)
					local channelY = channel:DimensionChannel(1)
					channelX:SetValue(moho.layerFrame - self.interval, self.boneFPosP.x)
					channelY:SetValue(moho.layerFrame - self.interval, self.boneFPosP.y)
				else
					firstBone.fAnimPos:SetValue(moho.layerFrame - self.interval, self.boneFPosP)
				end	
			end	
			if scale and self.boneFScaleP then
				firstBone.fAnimScale:SetValue(moho.layerFrame - self.interval, self.boneFScaleP)
			end	
		end
		if secondBone then
			if angle and self.boneSAngleP then
				secondBone.fAnimAngle:SetValue(moho.layerFrame - self.interval, self.boneSAngleP)
			end
			if pos and self.boneSPosP then
				local channel = secondBone.fAnimPos
				if channel:AreDimensionsSplit() then
					local channelX = channel:DimensionChannel(0)
					local channelY = channel:DimensionChannel(1)
					channelX:SetValue(moho.layerFrame - self.interval, self.boneSPosP.x)
					channelY:SetValue(moho.layerFrame - self.interval, self.boneSPosP.y)
				else
					secondBone.fAnimPos:SetValue(moho.layerFrame - self.interval, self.boneSPosP)
				end
			end	
			if scale and self.boneSScaleP then
				secondBone.fAnimScale:SetValue(moho.layerFrame - self.interval, self.boneSScaleP)
			end	
		end	
	end
	if moho.layerFrame + self.interval > 0 then
		if firstBone then
			if angle and self.boneFAngleN then
				firstBone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.boneFAngleN)
			end	
			if pos and self.boneFPosN then
				local channel = firstBone.fAnimPos
				if channel:AreDimensionsSplit() then
					local channelX = channel:DimensionChannel(0)
					local channelY = channel:DimensionChannel(1)
					channelX:SetValue(moho.layerFrame + self.interval, self.boneFPosN.x)
					channelY:SetValue(moho.layerFrame + self.interval, self.boneFPosN.y)
				else
					firstBone.fAnimPos:SetValue(moho.layerFrame + self.interval, self.boneFPosN)
				end
			end
			if scale and self.boneFScaleN then
				firstBone.fAnimScale:SetValue(moho.layerFrame + self.interval, self.boneFScaleN)
			end	
		end
		if secondBone then
			if angle and self.boneSAngleN then
				secondBone.fAnimAngle:SetValue(moho.layerFrame + self.interval, self.boneSAngleN)
			end
			if pos and self.boneSPosN then
				local channel = secondBone.fAnimPos
				if channel:AreDimensionsSplit() then
					local channelX = channel:DimensionChannel(0)
					local channelY = channel:DimensionChannel(1)
					channelX:SetValue(moho.layerFrame + self.interval, self.boneSPosN.x)
					channelY:SetValue(moho.layerFrame + self.interval, self.boneSPosN.y)
				else
					secondBone.fAnimPos:SetValue(moho.layerFrame + self.interval, self.boneSPosN)
				end	
			end	
			if scale and self.boneSScaleN then
				secondBone.fAnimScale:SetValue(moho.layerFrame + self.interval, self.boneSScaleN)
			end	
		end	
	end
end

function MR_PoseTool:CountBoneChildren(skel, boneID, ignoreControlledBones)
	local n = 0
	for i = 0, skel:CountBones() - 1 do
		local bone = skel:Bone(i)
		if (bone.fParent == boneID) then
			n = n + 1
			if (ignoreControlledBones) then
				if self.mohoVersion >= 14 then
					if (bone.fAngleControlParent >= 0 or bone.fPosControlParent >= 0 or bone.fScaleControlParent >= 0 
					or (bone.fBoneDynamics.value and (bone.fAngleDynamics or bone.fPosDynamics or bone.fScaleDynamics)) or bone.fIgnoredByIK) then
						n = n - 1 -- ignore this bone, as it is not free to move by itself
					end
				else
					if (bone.fAngleControlParent >= 0 or bone.fPosControlParent >= 0 or bone.fScaleControlParent >= 0 or bone.fBoneDynamics.value or bone.fIgnoredByIK) then
						n = n - 1 -- ignore this bone, as it is not free to move by itself
					end
				end
			end
		end
	end
	return n
end

function MR_PoseTool:RotateVector2(moho, vector2, center, angle)
	local centerVec = LM.Vector2:new_local()
	local newVector2 = LM.Vector2:new_local()
	local dif = LM.Vector2:new_local()
	centerVec:Set(center)
	dif:Set(vector2 - centerVec)
	local px = dif.x * math.cos(angle) - dif.y * math.sin(angle)
	local py = dif.x * math.sin(angle) + dif.y * math.cos(angle)
	newVector2:Set(px + centerVec.x, py + centerVec.y)
	return newVector2
end

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

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

	phrase['Description'] = 'Set up the pose of your character (hold <ctrl/cmd> to keep active handles visible, <alt> for compensation of child bone transformation, <shift> for additional transformation variations)'
	phrase['UILabel'] = 'MR Pose Tool 1.0'
	
	phrase['Keep selection'] = 'Keep selection'
	phrase['Hide bones while moving'] = 'Hide'
	phrase['Keep previous selection'] = 'Keep previous selection'
	phrase['Bake Adjacent Frames'] = 'Smart bake'
	phrase['Interval'] = 'Interval:'
	phrase['Show path'] = 'Show path'
	phrase['Range'] = 'Range'
	phrase['Range frames:'] = 'Range frames:'
	phrase['End flip'] = 'End flip'
	phrase['Side flip'] = 'Side flip'

	return phrase[text]
end

Icon
MR Pose Tool
Listed

Script type: Tool

Uploaded: Aug 14 2023, 06:38

Last modified: Sep 25 2023, 11:14

Plan and polish your animation with ease!
MR Pose Tool allows you to minimize the routine and spend more effort on creativity. This script combines the tools Transform Bone, Manipulate Bones, MR Move Targeted Joint, and even more.



To work correctly the lower bone (the shin or the forearm) must not have any Y-axis translation.
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: 857