-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "AE_Magnet" -- ************************************************** -- General information about this script -- ************************************************** AE_Magnet = {} AE_Magnet.BASE_STR = 2145 function AE_Magnet:Name() return "Magnet" end function AE_Magnet:Version() return "6.45" end function AE_Magnet:Description() return MOHO.Localize("/Scripts/Tool/Magnet/Description=Move points within a radius of influence (hold to adjust radius, to select points)") end function AE_Magnet:Creator() return "Smith Micro Software, improved by Alexandra Evseeva" end function AE_Magnet:UILabel() return(MOHO.Localize("/Scripts/Tool/Magnet/Magnet=Magnet")) end function AE_Magnet:LoadPrefs(prefs) self.magnetRadius = prefs:GetFloat("AE_Magnet.magnetRadius", 0.5) self.selectedOnly = prefs:GetBool("AE_Magnet.selectedOnly", false) self.multilayerMode = prefs:GetBool("AE_Magnet.multilayerMode", false) end function AE_Magnet:SavePrefs(prefs) prefs:SetFloat("AE_Magnet.magnetRadius", self.magnetRadius) prefs:SetBool("AE_Magnet.selectedOnly", self.selectedOnly) prefs:SetBool("AE_Magnet.multilayerMode", self.multilayerMode) end function AE_Magnet:NonDragMouseMove() return true -- Call MouseMoved() even if the mouse button is not down end function AE_Magnet:ResetPrefs() self.magnetRadius = 0.5 self.selectedOnly = false self.multilayerMode = false end -- ************************************************** -- Recurring values -- ************************************************** AE_Magnet.newMethod = false AE_Magnet.magnetRadius = 0.5 AE_Magnet.selectedOnly = true AE_Magnet.dragging = false AE_Magnet.dragVec = LM.Vector2:new_local() AE_Magnet.dragVec:Set(10000.0, 10000.0) AE_Magnet.dragResize = false AE_Magnet.selectionMode = false AE_Magnet.multilayerMode = false AE_Magnet.startRadius = 0 AE_Magnet.wasMoved = false AE_Magnet.minVec = LM.Vector2:new_local() AE_Magnet.maxVec = LM.Vector2:new_local() -- ************************************************** -- The guts of this script -- ************************************************** function AE_Magnet:IsEnabled(moho) --[[ if (moho:CountPoints() > 0) then return true end return false --]] return true end function AE_Magnet:IsRelevant(moho) --[[ local mesh = moho:DrawingMesh() if (mesh == nil) then return false end --]] return true end function AE_Magnet:OnInputDeviceEvent(moho, deviceEvent) return LM_TransformPoints:OnInputDeviceEvent(moho, deviceEvent) end function AE_Magnet:OnMouseDown(moho, mouseEvent) self.wasMoved = false local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (mouseEvent.altKey) then self.dragResize = true self.startRadius = self.magnetRadius self.dragVec:Set(mouseEvent.drawingVec) mouseEvent.view:DrawMe() return elseif (mouseEvent.ctrlKey) then self.selectionMode = true mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseDown(moho, mouseEvent) return end self.dragging = true self.dragVec:Set(mouseEvent.drawingVec) if not self.multilayerMode then moho.document:PrepUndo(moho.drawingLayer) else moho.document:PrepMultiUndo() end moho.document:SetDirty() --print("Mouse down") self.scaleList = {} self.endFPos = {} self.selList = {} self.layers = {} --deltas is from the previous version. It can be deleted now. self.deltas = {} --print("mouse: ", mouseEvent.drawingVec.x, ", ", mouseEvent.drawingVec.y) local vec = LM.Vector2:new_local() local m = LM.Matrix:new_local() local absMouse = LM.Vector2:new_local() vec:Set(mouseEvent.drawingVec) moho.layer:GetFullTransform(moho.frame, m, moho.document) m:Transform(vec) absMouse:Set(vec) --print("abs: ", absMouse.x, ", ", absMouse.y) for la = 0, moho.document:CountSelectedLayers()-1 do local layer = moho.document:GetSelectedLayer(la) layer:GetFullTransform(moho.frame, m, moho.document) m:Invert() m:Transform(vec) m:Invert() --print(layer:Name(), "\n", vec.x, ", ", vec.y) if (self.multilayerMode or layer == moho.layer) and layer:LayerType() == MOHO.LT_VECTOR then mesh = moho:LayerAsVector(layer):Mesh() for i = 0, mesh:CountPoints() - 1 do local pt = mesh:Point(i) if (not pt.fHidden and not (self.selectedOnly and not pt.fSelected)) then local v = pt.fPos - mouseEvent.drawingVec if(self.multilayerMode and layer~=moho.layer) then vec:Set(pt.fPos) m:Transform(vec) v = vec - absMouse end local magInfluence = v:Mag() --print(magInfluence) if (self.newMethod) then -- new method (more similar to how bones work) -- however, the "strength" is set to a constant 0.5 - the user would need to be able to change this magInfluence = magInfluence * magInfluence magInfluence = 0.5 / (1 + magInfluence * magInfluence * 1000) if (magInfluence > 0.001 or (self.selectedOnly and pt.fSelected)) then pt.fSelected = true if (magInfluence <= 0.001) then magInfluence = 0.0 end table.insert(self.scaleList, magInfluence) table.insert(self.endFPos, LM.Vector2:new_local()) table.insert(self.layers, layer) --------------------------- from the previous version. Can be deleted now table.insert(self.deltas, LM.Vector2:new_local()) self.deltas[#self.deltas]:Set(pt.fPos - pt.fAnimPos:GetValue(moho.frame)) ------------------------------------------------------------------------- else pt.fSelected = false end else -- old method if (magInfluence <= self.magnetRadius or (self.selectedOnly and pt.fSelected)) then -- mark the point as selected, and compute the magnet's influence over it pt.fSelected = true magInfluence = magInfluence / self.magnetRadius if (magInfluence > 1.0) then magInfluence = 1.0 end table.insert(self.scaleList, LM.Slerp(magInfluence, 1, 0)) table.insert(self.endFPos, LM.Vector2:new_local()) table.insert(self.layers, layer) --------------------------- from the previous version. Can be deleted now table.insert(self.deltas, LM.Vector2:new_local()) self.deltas[#self.deltas]:Set(pt.fPos - pt.fAnimPos:GetValue(moho.frame)) ------------------------------------------------------------------------- else pt.fSelected = false end end end end mesh:PrepMovePoints() for p=0, mesh:CountPoints()-1 do if mesh:Point(p).fSelected then table.insert(self.selList, mesh:Point(p)) end end end end mouseEvent.view:DrawMe() end function AE_Magnet:OnMouseMoved(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (self.dragResize) then self.magnetRadius = self.startRadius + (mouseEvent.pt.x - mouseEvent.startPt.x) / 600 if (self.magnetRadius < 0.01) then self.magnetRadius = 0.01 end if (self.magnetRadius > 5.0) then self.magnetRadius = 5.0 end mouseEvent.view:DrawMe() return elseif (self.selectionMode) then mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseMoved(moho, mouseEvent) return end self.dragVec:Set(mouseEvent.drawingVec) if (not self.dragging) then mouseEvent.view:DrawMe() return end local offset = mouseEvent.drawingVec - mouseEvent.drawingStartVec local vec = LM.Vector2:new_local() local vec2 = LM.Vector2:new_local() local m = LM.Matrix:new_local() local mloc = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, m, moho.document) for i, pt in ipairs(self.selList) do local pointOffset = offset if(self.multilayerMode and self.layers[i]~=moho.layer)then vec:Set(mouseEvent.drawingVec) vec2:Set(mouseEvent.drawingStartVec) self.layers[i]:GetFullTransform(moho.frame, mloc, moho.document) mloc:Invert() mloc:Multiply(m) mloc:Transform(vec) mloc:Transform(vec2) pointOffset = vec - vec2 --print("moving for ", pointOffset.x, ", ", pointOffset.y) end pt.fPos = pt.fTempPos + pointOffset * self.scaleList[i] if(self.endFPos[i]~=nil)then self.endFPos[i]:Set(pt.fPos) end end self.wasMoved = true mouseEvent.view:DrawMe() end function AE_Magnet:OnMouseUp(moho, mouseEvent) local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.dragging = false self.dragVec:Set(mouseEvent.drawingVec) if (self.dragResize) then self.dragResize = false mouseEvent.view:DrawMe() return elseif (self.selectionMode) then mouseEvent.ctrlKey = false LM_SelectPoints:OnMouseUp(moho, mouseEvent) self.selectionMode = false mouseEvent.view:DrawMe() return end --print("Without correcting") for la = 0, moho.document:CountSelectedLayers()-1 do local layer = moho.document:GetSelectedLayer(la) moho:AddPointKeyframe(moho.drawingFrame, layer, MOHO.MohoGlobals.EditMultipleKeys) end --moho:NewKeyframe(CHANNEL_POINT) if self.wasMoved then self:CorrectPointPos(moho) end for la = 0, moho.document:CountSelectedLayers()-1 do local layer = moho.document:GetSelectedLayer(la) moho:AddPointKeyframe(moho.drawingFrame, layer, MOHO.MohoGlobals.EditMultipleKeys) end moho:UpdateUI() self.selList = nil self.scaleList = nil end function AE_Magnet:OnKeyDown(moho, keyEvent) if (not self.dragging) then LM_SelectPoints:OnKeyDown(moho, keyEvent) end end function AE_Magnet:DrawMe(moho, view) local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (self.selectionMode) then LM_SelectPoints:DrawMe(moho, view) return end MOHO.DrawToolSizeCircle(moho, view, self.dragVec, self.magnetRadius, self.dragResize) end -- ************************************************** -- Tool options - create and respond to tool's UI -- ************************************************** AE_Magnet.CHANGE = MOHO.MSG_BASE AE_Magnet.DUMMY = MOHO.MSG_BASE + 1 AE_Magnet.RESET = MOHO.MSG_BASE + 2 AE_Magnet.SELECTITEM = MOHO.MSG_BASE + 3 AE_Magnet.SELECTCHILDREN = MOHO.MSG_BASE + 4 function AE_Magnet:DoLayout(moho, layout) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/Magnet/MagnetRadius=Magnet radius"))) self.radius = LM.GUI.TextControl(0, "00.0000", self.CHANGE, LM.GUI.FIELD_UFLOAT) self.radius:SetWheelInc(0.01) layout:AddChild(self.radius) self.selectedCheck = LM.GUI.CheckBox(MOHO.Localize("/Scripts/Tool/Magnet/SelectedPointsOnly=Selected points only"), self.CHANGE) layout:AddChild(self.selectedCheck) self.multilayerCheck = LM.GUI.CheckBox("Multi layer", self.CHANGE) layout:AddChild(self.multilayerCheck) self.selectChildrenButton = LM.GUI.Button("Select child layers", self.SELECTCHILDREN) layout:AddChild(self.selectChildrenButton) end function AE_Magnet:UpdateWidgets(moho) local mesh = moho:DrawingMesh() if (mesh == nil) then return end self.radius:SetValue(self.magnetRadius) self.selectedCheck:SetValue(self.selectedOnly) self.multilayerCheck:SetValue(self.multilayerMode) end function AE_Magnet:HandleMessage(moho, view, msg) if(msg == self.SELECTCHILDREN) then local layerCollection = self:SelectChildLayers(moho, moho.layer, MOHO.LT_VECTOR) if moho.layer:LayerType() ~= MOHO.LT_VECTOR and #layerCollection > 0 then moho:SetSelLayer(layerCollection[1]) for k,v in pairs(layerCollection) do moho:SetSelLayer(v, true) end end moho:UpdateUI() return end local mesh = moho:DrawingMesh() if (mesh == nil) then return end if (msg == self.RESET) then self.magnetRadius = 0.5 moho:UpdateUI() elseif (msg == self.CHANGE) then self.magnetRadius = self.radius:FloatValue() if (self.magnetRadius < 0.001) then self.magnetRadius = 0.001 end self.selectedOnly = self.selectedCheck:Value() self.multilayerMode = self.multilayerCheck:Value() elseif (msg >= self.SELECTITEM) then mesh:SelectNone() local i = msg - self.SELECTITEM local name = mesh:Group(i):Name() mesh:SelectGroup(name) moho:UpdateUI() end end function AE_Magnet:CorrectPointPos(moho) for i, pt in ipairs(self.selList) do if(self.endFPos[i]~=nil) then local delta = self.endFPos[i] - pt.fPos pt.fPos = self.endFPos[i] + delta end end end function AE_Magnet:printPos(moho, pos) print("x = ", pos.x, " y = ", pos.y) local layerMatrix = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, layerMatrix, moho.document) local getAbsPos = LM.Vector2:new_local() getAbsPos:Set(pos) layerMatrix:Transform(getAbsPos) print("x = ", getAbsPos.x, " y = ", getAbsPos.y) end function AE_Magnet:SelectChildLayers(moho, layer, layer_type) local layerCollection = {} layer:SetSecondarySelection(true) if layer_type and layer:LayerType() ~= layer_type then layer:SetSecondarySelection(false) end if not layer_type or layer:LayerType() == layer_type then table.insert(layerCollection, layer) end if layer:IsGroupType() then local group = moho:LayerAsGroup(layer) for child = 0, group:CountLayers()-1 do local childCollection = self:SelectChildLayers(moho, group:Layer(child), layer_type) for k,v in pairs(childCollection) do table.insert(layerCollection, v) end end end return layerCollection end