-- ************************************************** -- Provide Moho with the name of this script object -- ************************************************** ScriptName = "LM_TransformLayerModified" -- ************************************************** -- General information about this script -- ************************************************** LM_TransformLayerModified = {} LM_TransformLayerModified.BASE_STR = 2370 function LM_TransformLayerModified:Name() return "Transform Layer" end function LM_TransformLayerModified:Version() return "9.0" -- modified for Moho 12 end function LM_TransformLayerModified:IsBeginnerScript() return true end function LM_TransformLayerModified:Description() return MOHO.Localize("/Scripts/Tool/TransformLayer/Description=Transform entire layer (hold <shift> to constrain, <alt> to move forward and back, <ctrl/cmd> to edit motion path, <shift> + <alt> to move in Z and maintain visual size)") end function LM_TransformLayerModified:BeginnerDescription() return MOHO.Localize("/Scripts/Tool/TransformLayer/BeginnerDescription=Transform an entire layer or select multiple layers in the Layers window to transform them all at once. Transform your layer around on your screen and advance through the Timeline to animate your layer.") end function LM_TransformLayerModified:BeginnerDisabledDescription() return MOHO.Localize("/Scripts/Tool/TransformLayer/BeginnerDisabledDescription=") end function LM_TransformLayerModified:Creator() return "Smith Micro Software, Inc." -- modified by Mike Kelley, later by Stan end function LM_TransformLayerModified:UILabel() return(MOHO.Localize("/Scripts/Tool/TransformLayer/TransformLayer=Transform Layer")) end function LM_TransformLayerModified:LoadPrefs(prefs) self.displayOn = prefs:GetBool("LM_TransformLayerModified.displayOn", true) end function LM_TransformLayerModified:SavePrefs(prefs) prefs:SetBool("LM_TransformLayerModified.displayOn", self.displayOn) end function LM_TransformLayerModified:ResetPrefs() self.displayOn = true end function LM_TransformLayerModified:NonDragMouseMove() return true -- Call MouseMoved() even if the mouse button is not down end -- ************************************************** -- Recurring values -- ************************************************** LM_TransformLayerModified.dragging = false LM_TransformLayerModified.keyMovement = false LM_TransformLayerModified.selCount = 1 LM_TransformLayerModified.mode = 0 -- 0:translate, 1:rotate, 2:uniform scale, 3:x scale/x left, 4:y scale/y top, 5:x right, 6:y bottom LM_TransformLayerModified.startVal = LM.Vector3:new_local() LM_TransformLayerModified.dragPath = false LM_TransformLayerModified.when = -10000 LM_TransformLayerModified.startAngle = 0 LM_TransformLayerModified.startScale = LM.Vector3:new_local() LM_TransformLayerModified.matrix = LM.Matrix:new_local() LM_TransformLayerModified.lastVec = LM.Vector2:new_local() LM_TransformLayerModified.rotate3D = false LM_TransformLayerModified.TOLERANCE = 10 -- ************************************************** -- The guts of this script -- ************************************************** function LM_TransformLayerModified:LayerBounds(moho, layer, frame, view) local halfWidth = 0.5 local bbox = nil -- we used to not consider the contents of a group when showing a bounding box - maybe we should -- if (layer:IsGroupType()) then -- bbox = LM.BBox:new_local() -- bbox.fMin:Set(-halfWidth, -halfWidth, 0.0) -- bbox.fMax:Set(halfWidth, halfWidth, 0.0) -- else bbox = layer:Bounds(frame) if (bbox.fMin.x > bbox.fMax.x or bbox.fMin.y > bbox.fMax.y or (bbox.fMax.x - bbox.fMin.x < 0.0001 and bbox.fMax.y - bbox.fMin.y < 0.0001)) then local origin = layer:Origin() bbox.fMin:Set(origin.x - halfWidth, origin.y - halfWidth, 0.0) bbox.fMax:Set(origin.x + halfWidth, origin.y + halfWidth, 0.0) end -- end halfWidth = ((bbox.fMax.x - bbox.fMin.x) + (bbox.fMax.y - bbox.fMin.y)) / 4.0 local origin = layer:Origin() if (bbox.fMin.x > origin.x) then bbox.fMin.x = origin.x - halfWidth end if (bbox.fMin.y > origin.y) then bbox.fMin.y = origin.y - halfWidth end if (bbox.fMax.x < origin.x) then bbox.fMax.x = origin.x + halfWidth end if (bbox.fMax.y < origin.y) then bbox.fMax.y = origin.y + halfWidth end -- make sure the bounding box is not too thin in one direction local xLen = bbox.fMax.x - bbox.fMin.x local yLen = bbox.fMax.y - bbox.fMin.y if (xLen < yLen / 10.0) then local center = (bbox.fMin.x + bbox.fMax.x) / 2.0 bbox.fMin.x = center - yLen / 10.0 bbox.fMax.x = center + yLen / 10.0 elseif (yLen < xLen / 10.0) then local center = (bbox.fMin.y + bbox.fMax.y) / 2.0 bbox.fMin.y = center - xLen / 10.0 bbox.fMax.y = center + xLen / 10.0 end -- make sure the bounding box is not too small local minLength = 150 local m = LM.Matrix:new_local() local v = LM.Vector2:new_local() local pt1 = LM.Point:new_local() local pt2 = LM.Point:new_local() layer:GetFullTransform(frame, m, moho.document) v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) view:Graphics():WorldToScreen(v, pt1) v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) view:Graphics():WorldToScreen(v, pt2) pt1 = pt2 - pt1 local length = math.sqrt(pt1.x * pt1.x + pt1.y * pt1.y) if (length < minLength) then center = (bbox.fMin + bbox.fMax) / 2.0 v = bbox.fMax - center bbox.fMax = center + v * (minLength / length) / 2.0 v = bbox.fMin - center bbox.fMin = center + v * (minLength / length) / 2.0 end return bbox end function LM_TransformLayerModified:TestMousePoint(moho, mouseEvent) if (self.keyMovement) then return 0 end -- Returns what mode the tool would be in if the user clicked at the current mouse location local markerR = 4 local bbox = self:LayerBounds(moho, moho.layer, moho.frame, mouseEvent.view) local v = LM.Vector2:new_local() local pt = LM.Point:new_local() local m = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, m, moho.document) -- test for uniform scaling v:Set(bbox.fMin.x, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 2 end v:Set(bbox.fMin.x, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 2 end v:Set(bbox.fMax.x, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 2 end v:Set(bbox.fMax.x, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 2 end -- test for X scaling v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 3 end v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 5 end -- test for Y scaling v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 6 end v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y) m:Transform(v) mouseEvent.view:Graphics():WorldToScreen(v, pt) if (math.abs(pt.x - mouseEvent.pt.x) < markerR and math.abs(pt.y - mouseEvent.pt.y) < markerR) then return 4 end -- test for translation outside the bounding box local rotWidth = bbox.fMax.x - bbox.fMin.x if (bbox.fMax.y - bbox.fMin.y > rotWidth) then rotWidth = bbox.fMax.y - bbox.fMin.y end rotWidth = rotWidth * 0.1 if (mouseEvent.vec.x < bbox.fMin.x - rotWidth or mouseEvent.vec.x > bbox.fMax.x + rotWidth or mouseEvent.vec.y < bbox.fMin.y - rotWidth or mouseEvent.vec.y > bbox.fMax.y + rotWidth) then return 0 end -- test for rotation if (mouseEvent.vec.x < bbox.fMin.x or mouseEvent.vec.x > bbox.fMax.x or mouseEvent.vec.y < bbox.fMin.y or mouseEvent.vec.y > bbox.fMax.y) then return 1 end return 0 -- translation inside the bounding box end function LM_TransformLayerModified:OnMouseDown(moho, mouseEvent) self.dragging = true self.mode = 0 -- translate by default self.selCount = moho.document:CountSelectedLayers() self.dragPath = false self.depthShift = false moho.document:PrepMultiUndo(true) moho.document:SetDirty() self.selCount = moho.document:CountSelectedLayers() self.when = -10000 if (mouseEvent.ctrlKey and self.selCount == 1) then -- Not sure if this should require a modifier key or not... self.when = -20000 local g = mouseEvent.view:Graphics() local m = LM.Matrix:new_local() local vec = LM.Vector2:new_local() local origin = moho.layer:Origin() local pt = LM.Point:new_local() local totalTimingOffset = moho.layer:TotalTimingOffset() -- First see if any keyframes were picked for i = 0, moho.layer.fTranslation:CountKeys() - 1 do local frame = moho.layer.fTranslation:GetKeyWhen(i) moho.layer:GetFullTransform(frame - totalTimingOffset, m, moho.document) vec:Set(origin.x, origin.y) m:Transform(vec) if (moho.layer.fTranslation:HasKey(frame)) then g:WorldToScreen(vec, pt) if (math.abs(pt.x - mouseEvent.startPt.x) < self.TOLERANCE and math.abs(pt.y - mouseEvent.startPt.y) < self.TOLERANCE) then self.when = frame break end end end -- If no keyframes were picked, try picking a random point along the curve. if (self.when <= -10000) then local startFrame = moho.layer.fTranslation:GetKeyWhen(0) local endFrame = moho.layer.fTranslation:Duration() if (endFrame > startFrame) then local vec3 = LM.Vector3:new_local() local oldVec3 = LM.Vector3:new_local() g:Clear(0, 0, 0, 0) g:SetColor(255, 255, 255) g:BeginPicking(mouseEvent.startPt, 4) for frame = startFrame, endFrame do moho.layer:GetFullTransform(frame - totalTimingOffset, m, moho.document) vec3:Set(origin.x, origin.y, 0) m:Transform(vec3) if (frame > startFrame) then g:DrawLine(oldVec3.x, oldVec3.y, vec3.x, vec3.y) end if (g:Pick()) then self.when = frame break end oldVec3:Set(vec3) end if (self.when > -10000) then -- We picked a point on the curve. if (self.selCount > 1) then return end moho.layer.fTranslation:AddKey(self.when) end end end if (self.when > -10000) then self.dragPath = true end end if (self.when == -20000) then return end if (not self.dragPath) then self.mode = self:TestMousePoint(moho, mouseEvent) end if (self.mode == 0) then -- translate self.startVal = {} if (self.when > -10000) then local startVal = LM.Vector3:new_local() startVal:Set(moho.layer.fTranslation:GetValue(self.when)) table.insert(self.startVal, startVal) -- Put the keyframe time in terms of document time, so that it works as expected during mouse dragging. self.when = self.when - moho.layer:TotalTimingOffset() else self.startVal = {} for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local startVal = LM.Vector3:new_local() startVal:Set(layer.fTranslation.value) table.insert(self.startVal, startVal) if (not layer:IsAncestorSelected()) then layer.fTranslation:AddKey(moho.frame + layer:TotalTimingOffset()) end end -- for i end if (mouseEvent.altKey and mouseEvent.shiftKey) then self.depthShift = true self.startScale = LM.Vector3:new_local() self.startScale:Set(moho.layer.fScale.value) self.layerScales = {} for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local layerScale = LM.Vector3:new_local() layerScale:Set(layer.fScale.value) table.insert(self.layerScales, layerScale) end end elseif (self.mode == 1) then -- rotate self.startAngle = moho.layer.fRotationZ.value self.originalAngle = moho.layer.fRotationZ.value self.layerAngles = {} for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) table.insert(self.layerAngles, layer.fRotationZ.value) if (not layer:IsAncestorSelected()) then layer.fRotationZ:AddKey(moho.frame + layer:TotalTimingOffset()) end end -- for i else -- scale self.startScale = LM.Vector3:new_local() self.startScale:Set(moho.layer.fScale.value) self.layerScales = {} for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local layerScale = LM.Vector3:new_local() layerScale:Set(layer.fScale.value) table.insert(self.layerScales, layerScale) if (not layer:IsAncestorSelected()) then layer.fScale:AddKey(moho.frame + layer:TotalTimingOffset()) end end -- for i end moho.layer:GetFullTransform(moho.frame, self.matrix, moho.document) self.lastVec:Set(mouseEvent.view:Point2Vec(mouseEvent.pt, self.matrix)) mouseEvent.view:DrawMe() end function LM_TransformLayerModified:OnMouseMoved(moho, mouseEvent) if (not self.dragging) then local mode = self:TestMousePoint(moho, mouseEvent) if (mode == 0) then mouseEvent.view:SetCursor(MOHO.moveCursor) elseif (mode == 1) then mouseEvent.view:SetCursor(MOHO.rotateCursor) else mouseEvent.view:SetCursor(MOHO.scaleCursor) end mouseEvent.view:DrawMe() return end if (self.mode == 0) then self:OnMouseMoved_T(moho, mouseEvent) elseif (self.mode == 1) then self:OnMouseMoved_R(moho, mouseEvent) else self:OnMouseMoved_S(moho, mouseEvent) end end function LM_TransformLayerModified:OnMouseMoved_T(moho, mouseEvent) if (self.when == -20000) then return end local frame = self.when if (frame > -10000 and self.selCount > 1) then return end if (frame <= -10000) then frame = moho.frame end if (not moho.layer:IsImmuneToCamera()) then local v1 = LM.Vector3:new_local() local v2 = LM.Vector3:new_local() local vec = LM.Vector3:new_local() local origin = LM.Vector3:new_local() local m = LM.Matrix:new_local() for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local tempO = moho.layer:Origin() origin:Set(tempO.x, tempO.y, 0) moho.layer:GetFullTransform(moho.frame, m, moho.document) m:Transform(origin) m:Identity() if (layer:Parent()) then layer:Parent():GetFullTransform(moho.frame, m, moho.document) elseif (moho.document:IsOutsideViewEnabled()) then moho.document:GetOutsideViewMatrix(m) else moho.document:GetCameraMatrix(moho.frame, m) end if (layer:LayerParentBone() ~= -1 and layer:Parent() and layer:Parent():IsBoneType()) then local parentM = LM.Matrix:new_local() layer:GetParentBoneTransform(moho.frame, parentM, moho.document) m:Multiply(parentM) end m:Invert() mouseEvent.view:Graphics():ScreenToWorld(mouseEvent.startPt, v1) mouseEvent.view:Graphics():ScreenToWorld(mouseEvent.pt, v2) if (not mouseEvent.altKey) then v1.z = origin.z v2.z = origin.z end vec.x = v2.x - v1.x vec.y = v2.y - v1.y if (mouseEvent.altKey) then v2.z = v1.z - (v2.y - v1.y) * 0.25 v2.x = 0.0 v1.x = 0.0 v2.y = 0.0 v1.y = 0.0 else if (mouseEvent.shiftKey) then if (math.abs(vec.x) > math.abs(vec.y)) then v2.y = v1.y else v2.x = v1.x end end end if (mouseEvent.altKey) then v1.z = v1.z - 0.885 ---0.95 v2.z = v2.z - 0.885 ---0.95 end m:Transform(v1) m:Transform(v2) if (self.depthShift) then -- move in Z, but try to preserve the visual size of the layer local layerFrame = frame + layer:TotalTimingOffset() vec = v2 - v1 local distance = vec:Mag() local layerM = LM.Matrix:new_local() local parentM = LM.Matrix:new_local() layer.fTranslation:SetValue(layerFrame, self.startVal[i + 1]) layer:GetFullTransform(frame, layerM, nil) if (layer:Parent()) then layer:Parent():GetFullTransform(frame, parentM, nil) end local origin2D = layer:Origin() local origin = LM.Vector3:new_local() origin:Set(origin2D.x, origin2D.y, 0) layerM:Transform(origin) vec = origin - moho.document.fCameraTrack.value vec:NormMe() if (v2.z > v1.z) then distance = -distance end vec = origin + vec * distance parentM:Invert() parentM:Transform(origin) parentM:Transform(vec) layer.fTranslation:SetValue(layerFrame, self.startVal[i + 1] + vec - origin) else vec = self.startVal[i + 1] + v2 - v1 layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) end end end -- for i else for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), self.startVal[i + 1]) local layerM = LM.Matrix:new_local() local tempLayer = MOHO.MohoLayer:new_local() tempLayer.fTranslation:SetValue(0, layer.fTranslation.value) if (layer:Parent()) then local parentM = LM.Matrix:new_local() tempLayer:GetFullTransform(moho.frame, layerM, nil) layer:Parent():GetFullTransform(moho.frame, parentM, moho.document) layerM:Multiply(parentM) if (layer:LayerParentBone() ~= -1 and layer:Parent():IsBoneType()) then layer:GetParentBoneTransform(moho.frame, parentM, moho.document) layerM:Multiply(parentM) end elseif (layer:IsImmuneToCamera()) then tempLayer:GetFullTransform(moho.frame, layerM, nil) else tempLayer:GetFullTransform(moho.frame, layerM, moho.document) end self.startVec = mouseEvent.view:Point2Vec(mouseEvent.startPt, layerM) self.nextVec = mouseEvent.view:Point2Vec(mouseEvent.pt, layerM) local vec = LM.Vector3:new_local() if (mouseEvent.altKey) then mouseEvent.view:Graphics():ScreenToWorld(mouseEvent.startPt, self.startVec) mouseEvent.view:Graphics():ScreenToWorld(mouseEvent.pt, self.nextVec) vec:Set(self.startVal[i + 1]) vec.z = self.startVal[i + 1].z - (self.nextVec.y - self.startVec.y) layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) if (layer:Parent()) then layer:Parent():DepthSort(moho.document) end else vec.x = self.nextVec.x - self.startVec.x vec.y = self.nextVec.y - self.startVec.y if (mouseEvent.shiftKey) then if (math.abs(vec.x) > math.abs(vec.y)) then vec.y = 0 else vec.x = 0 end end vec = vec + self.startVal[i + 1] layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) end end end -- for i end if (frame ~= moho.frame) then moho:SetCurFrame(moho.frame) -- force a refresh when editing a key at a different frame end moho.document:DepthSort() mouseEvent.view:DrawMe() end function LM_TransformLayerModified:OnMouseMoved_S(moho, mouseEvent) moho.layer.fScale:SetValue(moho.layerFrame, self.startScale) local startVec = mouseEvent.view:Point2Vec(mouseEvent.startPt, self.matrix) local nextVec = mouseEvent.view:Point2Vec(mouseEvent.pt, self.matrix) -- scaling connected to actual drag amount local origin = moho.layer:Origin() local v1 = startVec - origin local v2 = nextVec - origin local scaling = LM.Vector3:new_local() scaling:Set(v2.x / v1.x, v2.y / v1.y, 1) if (self.mode == 3 or self.mode == 5) then -- X scaling scaling.y = 1 if (mouseEvent.shiftKey) then scaling.y = 1 / scaling.x end elseif (self.mode == 4 or self.mode == 6) then -- Y scaling scaling.x = 1 if (mouseEvent.shiftKey) then scaling.x = 1 / scaling.y end elseif (self.mode == 2) then scaling.z = (scaling.x + scaling.y) / 2 if (not mouseEvent.shiftKey) then scaling.x = scaling.z scaling.y = scaling.z end else scaling.z = v2:Mag() / v1:Mag() scaling.x = scaling.z scaling.y = scaling.z end local vec = LM.Vector3:new_local() for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then vec:Set(self.layerScales[i + 1]) vec.x = vec.x * scaling.x vec.y = vec.y * scaling.y vec.z = vec.z * scaling.z layer.fScale:SetValue(moho.frame + layer:TotalTimingOffset(), vec) end end moho.document:DepthSort() mouseEvent.view:DrawMe() end function LM_TransformLayerModified:OnMouseMoved_R(moho, mouseEvent) local nextVec = mouseEvent.view:Point2Vec(mouseEvent.pt, self.matrix) local angle = self.startAngle local origin = moho.layer:Origin() local v1 = self.lastVec - origin local v2 = nextVec - origin v2:Rotate(-math.atan2(v1.y, v1.x)) local dAngle = math.atan2(v2.y, v2.x) local flipH = moho.layer.fFlipH.value local flipV = moho.layer.fFlipV.value if ((flipH and not flipV) or (flipV and not flipH)) then dAngle = -dAngle end self.startAngle = angle + dAngle for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then angle = self.layerAngles[i + 1] angle = angle + dAngle self.layerAngles[i + 1] = angle if (mouseEvent.shiftKey) then angle = angle / (math.pi / 4) angle = (math.pi / 4) * LM.Round(angle) end layer.fRotationZ:SetValue(moho.frame + layer:TotalTimingOffset(), angle) end end self.lastVec:Set(nextVec) moho.document:DepthSort() mouseEvent.view:DrawMe() end function LM_TransformLayerModified:OnMouseUp(moho, mouseEvent) if (not self.dragging) then return end if (self.when == -2) then return end if (self.when < 0) then if (self.mode == 0) then if (MOHO.MohoGlobals.EditMultipleKeys) then for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local timingOffset = layer:TotalTimingOffset() local offset = layer.fTranslation:GetValue(moho.frame + timingOffset) if (self.startVal[i + 1] ~= nil) then offset = offset - self.startVal[i + 1] end for j = 0, layer.fTranslation:CountKeys() - 1 do if (layer.fTranslation:IsKeySelectedByID(j) and layer.fTranslation:GetKeyWhen(j) ~= moho.frame + timingOffset) then local vec = layer.fTranslation:GetValueByID(j) + offset layer.fTranslation:SetValueByID(j, vec) end end end end -- for i end moho:NewKeyframe(CHANNEL_LAYER_T) if (self.depthShift) then local frame = self.when if (frame <= -10000) then frame = moho.frame end for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local layerFrame = frame + layer:TotalTimingOffset() local scale = 1 local newTranslation = LM.Vector3:new_local() newTranslation:Set(layer.fTranslation.value) local layerM = LM.Matrix:new_local() layer.fTranslation:SetValue(layerFrame, self.startVal[i + 1]) layer:GetFullTransform(frame, layerM, nil) local origin2D = layer:Origin() local oldOrigin = LM.Vector3:new_local() oldOrigin:Set(origin2D.x, origin2D.y, 0) layerM:Transform(oldOrigin) layer.fTranslation:SetValue(layerFrame, newTranslation) layer:GetFullTransform(frame, layerM, nil) origin2D = layer:Origin() local newOrigin = LM.Vector3:new_local() newOrigin:Set(origin2D.x, origin2D.y, 0) layerM:Transform(newOrigin) scale = (newOrigin - moho.document.fCameraTrack.value):Mag() / (oldOrigin - moho.document.fCameraTrack.value):Mag() local vec = self.layerScales[i + 1] * scale layer.fScale:SetValue(layerFrame, vec) end end -- for i if (MOHO.MohoGlobals.EditMultipleKeys) then local offset = LM.Vector3:new_local() offset.x = moho.layer.fScale.value.x / self.startScale.x offset.y = moho.layer.fScale.value.y / self.startScale.y offset.z = moho.layer.fScale.value.z / self.startScale.z for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local timingOffset = layer:TotalTimingOffset() offset.x = layer.fScale.value.x / self.layerScales[i + 1].x offset.y = layer.fScale.value.y / self.layerScales[i + 1].y offset.z = layer.fScale.value.z / self.layerScales[i + 1].z for j = 0, layer.fScale:CountKeys() - 1 do if (layer.fScale:IsKeySelectedByID(j) and layer.fScale:GetKeyWhen(j) ~= moho.frame + timingOffset) then local scale = layer.fScale:GetValueByID(j) scale.x = scale.x * offset.x scale.y = scale.y * offset.y scale.z = scale.z * offset.z layer.fScale:SetValueByID(j, scale) end end end end -- for i end moho:NewKeyframe(CHANNEL_LAYER_S) end elseif (self.mode == 1) then if (MOHO.MohoGlobals.EditMultipleKeys) then local offset = moho.layer.fRotationZ.value if (self.originalAngle ~= nil) then offset = offset - self.originalAngle end for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local timingOffset = layer:TotalTimingOffset() for j = 0, layer.fRotationZ:CountKeys() - 1 do if (layer.fRotationZ:IsKeySelectedByID(j) and layer.fRotationZ:GetKeyWhen(j) ~= moho.frame + timingOffset) then local angle = layer.fRotationZ:GetValueByID(j) + offset layer.fRotationZ:SetValueByID(j, angle) end end end end -- for i end moho:NewKeyframe(CHANNEL_LAYER_ROT_Z) else if (MOHO.MohoGlobals.EditMultipleKeys) then local offset = LM.Vector3:new_local() offset.x = moho.layer.fScale.value.x / self.startScale.x offset.y = moho.layer.fScale.value.y / self.startScale.y offset.z = moho.layer.fScale.value.z / self.startScale.z for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) if (not layer:IsAncestorSelected()) then local timingOffset = layer:TotalTimingOffset() offset.x = layer.fScale.value.x / self.layerScales[i + 1].x offset.y = layer.fScale.value.y / self.layerScales[i + 1].y offset.z = layer.fScale.value.z / self.layerScales[i + 1].z for j = 0, layer.fScale:CountKeys() - 1 do if (layer.fScale:IsKeySelectedByID(j) and layer.fScale:GetKeyWhen(j) ~= moho.frame + timingOffset) then local scale = layer.fScale:GetValueByID(j) scale.x = scale.x * offset.x scale.y = scale.y * offset.y scale.z = scale.z * offset.z layer.fScale:SetValueByID(j, scale) end end end end -- for i end moho:NewKeyframe(CHANNEL_LAYER_S) end end moho:UpdateUI() self.dragging = false end function LM_TransformLayerModified:OnKeyDown(moho, keyEvent) if (keyEvent.ctrlKey) then local inc = 1 if (keyEvent.shiftKey) then inc = 10 end local m = LM.Matrix:new_local() moho.layer:GetFullTransform(moho.frame, m, moho.document) local fakeME = {} fakeME.view = keyEvent.view fakeME.pt = LM.Point:new_local() fakeME.pt:Set(keyEvent.view:Graphics():Width() / 2, keyEvent.view:Graphics():Height() / 2) fakeME.startPt = LM.Point:new_local() fakeME.startPt:Set(fakeME.pt) fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.startVec = keyEvent.view:Point2Vec(fakeME.pt, m) fakeME.shiftKey = false fakeME.ctrlKey = false fakeME.altKey = keyEvent.altKey fakeME.penPressure = 0 self.keyMovement = true if (keyEvent.keyCode == LM.GUI.KEY_UP) then self:OnMouseDown(moho, fakeME) fakeME.pt.y = fakeME.pt.y - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_DOWN) then self:OnMouseDown(moho, fakeME) fakeME.pt.y = fakeME.pt.y + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_LEFT) then self:OnMouseDown(moho, fakeME) fakeME.pt.x = fakeME.pt.x - inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) elseif (keyEvent.keyCode == LM.GUI.KEY_RIGHT) then self:OnMouseDown(moho, fakeME) fakeME.pt.x = fakeME.pt.x + inc fakeME.vec = keyEvent.view:Point2Vec(fakeME.pt, m) self:OnMouseMoved(moho, fakeME) self:OnMouseUp(moho, fakeME) end self.keyMovement = false end end function LM_TransformLayerModified:OnInputDeviceEvent(moho, deviceEvent) if (deviceEvent.inputData:GetString("DeviceType") == "Wacom Multitouch") then local mtState = deviceEvent.inputData:GetInt("MultitouchState") local mtMousePt = deviceEvent.inputData:GetPoint("MultitouchCenterPoint") if (mtState == 1) then -- first finger down self.rotate3D = false self.mtFingersTouching = 0 -- we'll get the correct number on the next event self.mtTranslate = LM.Point:new_local() self.mtStartPt = deviceEvent.inputData:GetPoint("MultitouchCenterPoint") self.mtAccumTranslate = LM.Point:new_local() self.mtScale = 1.0 self.mtStartScale = 1.0 self.mtAccumScale = 1.0 self.mtAngle = 0.0 self.mtStartAngle = 0.0 self.mtAccumAngle = 0.0 self.selCount = moho.document:CountSelectedLayers() self.when = -10000 moho.document:SetDirty() moho.document:PrepMultiUndo(true) self.startVal = {} self.startAngle = {} self.startScale = {} self.startAngleX = {} self.startAngleY = {} for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local startVal = LM.Vector3:new_local() startVal:Set(layer.fTranslation.value) table.insert(self.startVal, startVal) layer.fTranslation:AddKey(moho.frame + layer:TotalTimingOffset()) table.insert(self.startAngle, layer.fRotationZ.value) table.insert(self.startAngleX, layer.fRotationX.value) table.insert(self.startAngleY, layer.fRotationY.value) startVal = LM.Vector3:new_local() startVal:Set(layer.fScale.value) table.insert(self.startScale, startVal) end self.mtTranslate:Set(0.0, 0.0) self.mtScale = 1.0 self.mtAngle = 0.0 elseif (mtState == 3) then -- last finger up self.mtFingersTouching = 0 if (self.when < 0) then moho:NewKeyframe(CHANNEL_LAYER_T) end moho:UpdateUI() elseif (mtState == 2) then -- dragging local fingersTouching = deviceEvent.inputData:GetInt("FingersTouching") if (fingersTouching ~= self.mtFingersTouching) then self.mtAccumTranslate = self.mtAccumTranslate + self.mtTranslate self.mtAccumScale = self.mtAccumScale * self.mtScale self.mtAccumAngle = self.mtAccumAngle + self.mtAngle self.mtFingersTouching = fingersTouching self.mtStartPt = deviceEvent.inputData:GetPoint("MultitouchCenterPoint") self.mtStartAngle = deviceEvent.inputData:GetFloat("MultitouchAngle") self.mtStartScale = deviceEvent.inputData:GetFloat("MultitouchScale") end self.mtTranslate = mtMousePt - self.mtStartPt self.mtScale = 1.0 self.mtAngle = 0.0 if (self.mtFingersTouching > 1) then self.mtAngle = deviceEvent.inputData:GetFloat("MultitouchAngle") - self.mtStartAngle self.mtScale = deviceEvent.inputData:GetFloat("MultitouchScale") / self.mtStartScale end local frame = self.when if (frame <= -10000) then frame = moho.frame end if (deviceEvent.inputData:GetBool("DoubleTouch")) then if (fingersTouching == 2) then self:HandleMessage(moho, deviceEvent.view, self.RESET_T) self:HandleMessage(moho, deviceEvent.view, self.RESET_S) self:HandleMessage(moho, deviceEvent.view, self.RESET_R) if (frame ~= moho.frame) then moho:SetCurFrame(moho.frame) -- force a refresh when editing a key at a different frame end moho.document:DepthSort() end return true end if (self.mtFingersTouching >= 4 or self.rotate3D) then self.rotate3D = true for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local angleX = self.startAngleX[i + 1] angleX = angleX + math.pi * (mtMousePt.y + self.mtAccumTranslate.y - self.mtStartPt.y) / deviceEvent.view:Graphics():Height() local angleY = self.startAngleY[i + 1] angleY = angleY + math.pi * (mtMousePt.x + self.mtAccumTranslate.x - self.mtStartPt.x) / deviceEvent.view:Graphics():Width() layer.fRotationX:SetValue(frame + layer:TotalTimingOffset(), angleX) layer.fRotationY:SetValue(frame + layer:TotalTimingOffset(), angleY) end if (frame ~= moho.frame) then moho:SetCurFrame(moho.frame) -- force a refresh when editing a key at a different frame end moho.document:DepthSort() elseif (not moho.layer:IsImmuneToCamera()) then local v1 = LM.Vector3:new_local() local v2 = LM.Vector3:new_local() local vec = LM.Vector3:new_local() local m = LM.Matrix:new_local() for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) m:Identity() if (layer:Parent()) then layer:Parent():GetFullTransform(moho.frame, m, moho.document) elseif (moho.document:IsOutsideViewEnabled()) then moho.document:GetOutsideViewMatrix(m) else moho.document:GetCameraMatrix(moho.frame, m) end if (layer:LayerParentBone() ~= -1 and layer:Parent() and layer:Parent():IsBoneType()) then local parentM = LM.Matrix:new_local() layer:GetParentBoneTransform(moho.frame, parentM, moho.document) m:Multiply(parentM) end m:Invert() deviceEvent.view:Graphics():ScreenToWorld(self.mtStartPt, v1) deviceEvent.view:Graphics():ScreenToWorld(mtMousePt + self.mtAccumTranslate, v2) vec.x = v2.x - v1.x vec.y = v2.y - v1.y if (deviceEvent.altKey) then v2.z = v1.z - (v2.y - v1.y) * 0.25 v2.x = 0.0 v1.x = 0.0 v2.y = 0.0 v1.y = 0.0 else if (deviceEvent.shiftKey) then if (math.abs(vec.x) > math.abs(vec.y)) then v2.y = v1.y else v2.x = v1.x end end end v1.z = v1.z - 0.885 ---0.95 v2.z = v2.z - 0.885 ---0.95 m:Transform(v1) m:Transform(v2) vec = self.startVal[i + 1] + v2 - v1 layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) if (self.mtFingersTouching > 1) then layer.fRotationZ:SetValue(frame + layer:TotalTimingOffset(), self.startAngle[i + 1] + self.mtAccumAngle + self.mtAngle) layer.fScale:SetValue(frame + layer:TotalTimingOffset(), self.startScale[i + 1] * self.mtAccumScale * self.mtScale) end end -- for i else for i = 0, self.selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), self.startVal[i + 1]) local layerM = LM.Matrix:new_local() local tempLayer = MOHO.MohoLayer:new_local() tempLayer.fTranslation:SetValue(0, layer.fTranslation.value) if (layer:Parent()) then local parentM = LM.Matrix:new_local() tempLayer:GetFullTransform(moho.frame, layerM, nil) layer:Parent():GetFullTransform(moho.frame, parentM, moho.document) layerM:Multiply(parentM) if (layer:LayerParentBone() ~= -1 and layer:Parent():IsBoneType()) then layer:GetParentBoneTransform(moho.frame, parentM, moho.document) layerM:Multiply(parentM) end elseif (layer:IsImmuneToCamera()) then tempLayer:GetFullTransform(moho.frame, layerM, nil) else tempLayer:GetFullTransform(moho.frame, layerM, moho.document) end self.startVec = deviceEvent.view:Point2Vec(self.mtStartPt, layerM) self.nextVec = deviceEvent.view:Point2Vec(mtMousePt + self.mtAccumTranslate, layerM) local vec = LM.Vector3:new_local() if (deviceEvent.altKey) then deviceEvent.view:Graphics():ScreenToWorld(self.mtStartPt, self.startVec) deviceEvent.view:Graphics():ScreenToWorld(mtMousePt, self.nextVec) vec:Set(self.startVal[i + 1]) vec.z = self.startVal[i + 1].z - (self.nextVec.y - self.startVec.y) layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) if (layer:Parent()) then layer:Parent():DepthSort(moho.document) end else vec.x = self.nextVec.x - self.startVec.x vec.y = self.nextVec.y - self.startVec.y if (deviceEvent.shiftKey) then if (math.abs(vec.x) > math.abs(vec.y)) then vec.y = 0 else vec.x = 0 end end vec = vec + self.startVal[i + 1] layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) end vec = vec + self.startVal[i + 1] layer.fTranslation:SetValue(frame + layer:TotalTimingOffset(), vec) if (self.mtFingersTouching > 1) then layer.fRotationZ:SetValue(frame + layer:TotalTimingOffset(), self.startAngle[i + 1] + self.mtAccumAngle + self.mtAngle) layer.fScale:SetValue(frame + layer:TotalTimingOffset(), self.startScale[i + 1] * self.mtAccumScale * self.mtScale) end end -- for i end if (frame ~= moho.frame) then moho:SetCurFrame(moho.frame) -- force a refresh when editing a key at a different frame end moho.document:DepthSort() end return true end return false end function LM_TransformLayerModified:DrawMe(moho, view) if (moho.layer == nil or moho:IsPlaying()) then return end local layer = nil local bbox = nil local selCount = moho.document:CountSelectedLayers() local g = view:Graphics() local markerR = 4 local matrix = LM.Matrix:new_local() local originWidth = 0.05 local v = LM.Vector2:new_local() local vc1 = LM.ColorVector:new_local() local vc2 = LM.ColorVector:new_local() -- vc1:Set(MOHO.MohoGlobals.SelCol) vc1:Set(0, .3, 0) vc2:Set(MOHO.MohoGlobals.BackCol) --vc1 = (vc1 * 3 + vc2 * 4) / 7 vc1 = (vc1 + vc2) / 2 local col = vc1:AsColorStruct() if (not self.dragging) then for i = 0, selCount - 1 do --layer = moho.layer layer = moho.document:GetSelectedLayer(i) local isPrimaryLayer = (layer == moho.layer) bbox = self:LayerBounds(moho, layer, moho.frame, view) local origin = layer:Origin() layer:GetFullTransform(moho.frame, matrix, moho.document) g:Push() g:ApplyMatrix(matrix) g:SetSmoothing(true) g:SetColor(col) g:SetPenWidth(1) g:DrawLine(origin.x - originWidth, origin.y, origin.x + originWidth, origin.y) g:DrawLine(origin.x, origin.y - originWidth, origin.x, origin.y + originWidth) if (not isPrimaryLayer) then g:SetPenWidth(1) g:SetColor(col) end g:DrawLine(bbox.fMin.x, bbox.fMin.y, bbox.fMin.x, bbox.fMax.y) g:DrawLine(bbox.fMin.x, bbox.fMax.y, bbox.fMax.x, bbox.fMax.y) g:DrawLine(bbox.fMax.x, bbox.fMax.y, bbox.fMax.x, bbox.fMin.y) g:DrawLine(bbox.fMax.x, bbox.fMin.y, bbox.fMin.x, bbox.fMin.y) if (isPrimaryLayer) then g:SetPenWidth(1) if (selCount == 1) then g:SetColor(col) end local rotWidth = bbox.fMax.x - bbox.fMin.x if (bbox.fMax.y - bbox.fMin.y > rotWidth) then rotWidth = bbox.fMax.y - bbox.fMin.y end rotWidth = rotWidth * 0.1 g:DrawLine(bbox.fMin.x - rotWidth, bbox.fMin.y - rotWidth, bbox.fMin.x - rotWidth, bbox.fMax.y + rotWidth) g:DrawLine(bbox.fMin.x - rotWidth, bbox.fMax.y + rotWidth, bbox.fMax.x + rotWidth, bbox.fMax.y + rotWidth) g:DrawLine(bbox.fMax.x + rotWidth, bbox.fMax.y + rotWidth, bbox.fMax.x + rotWidth, bbox.fMin.y - rotWidth) g:DrawLine(bbox.fMax.x + rotWidth, bbox.fMin.y - rotWidth, bbox.fMin.x - rotWidth, bbox.fMin.y - rotWidth) end g:SetPenWidth(1) if (isPrimaryLayer) then g:SetColor(col) g:SetPenWidth(2) local v = LM.Vector2:new_local() v:Set(bbox.fMin.x, bbox.fMin.y) g:FrameCirclePixelRadius(v, markerR) v:Set(bbox.fMin.x, bbox.fMax.y) g:FrameCirclePixelRadius(v, markerR) v:Set(bbox.fMax.x, bbox.fMax.y) g:FrameCirclePixelRadius(v, markerR) v:Set(bbox.fMax.x, bbox.fMin.y) g:FrameCirclePixelRadius(v, markerR) v:Set(bbox.fMin.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) g:FrameCirclePixelRadius(v, markerR) v:Set(bbox.fMax.x, (bbox.fMin.y + bbox.fMax.y) * 0.5) g:FrameCirclePixelRadius(v, markerR) v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMin.y) g:FrameCirclePixelRadius(v, markerR) v:Set((bbox.fMin.x + bbox.fMax.x) * 0.5, bbox.fMax.y) g:FrameCirclePixelRadius(v, markerR) end g:SetSmoothing(false) g:SetPenWidth(1) g:Pop() end end if (not self.displayOn or selCount > 1) then return end if (moho.layer:PhysicsParent(-1) ~= nil) then return end local startFrame = moho.layer.fTranslation:GetKeyWhen(0) local endFrame = moho.layer.fTranslation:Duration() local totalTimingOffset = moho.layer:TotalTimingOffset() local interp = MOHO.InterpSetting:new_local() moho.layer.fTranslation:GetKeyInterp(endFrame, interp) if (interp:IsAdditiveCycle()) then endFrame = moho.document:EndFrame() + totalTimingOffset end if (startFrame < 0) then startFrame = 0 end if (endFrame > startFrame) then local g = view:Graphics() local m = LM.Matrix:new_local() local vec = LM.Vector3:new_local() local oldVec = LM.Vector3:new_local() local origin = moho.layer:Origin() local splitDimensions = moho.layer.fTranslation:AreDimensionsSplit() g:SetColor(102, 152, 203) g:SetSmoothing(true) for frame = startFrame, endFrame do moho.layer:GetFullTransform(frame - totalTimingOffset, m, moho.document) vec:Set(origin.x, origin.y, 0) m:Transform(vec) if (frame > startFrame) then -- g:SetColor(102, 152, 203) g:DrawLine(oldVec.x, oldVec.y, vec.x, vec.y) end -- color the path points before and after the current time -- if (frame < moho.layerFrame) then -- g:SetColor(255, 0, 0) -- elseif (frame > moho.layerFrame) then -- g:SetColor(0, 255, 0) -- end if ((not splitDimensions) and moho.layer.fTranslation:HasKey(frame)) then g:DrawFatMarker(vec.x, vec.y, 5) else g:DrawMarker(vec.x, vec.y) end oldVec:Set(vec) end g:SetSmoothing(false) end end -- ************************************************** -- Tool options - create and respond to tool's UI -- ************************************************** LM_TransformLayerModified.CHANGE_T = MOHO.MSG_BASE LM_TransformLayerModified.CHANGE_S = MOHO.MSG_BASE + 1 LM_TransformLayerModified.CHANGE_R = MOHO.MSG_BASE + 2 LM_TransformLayerModified.RESET_T = MOHO.MSG_BASE + 3 LM_TransformLayerModified.RESET_S = MOHO.MSG_BASE + 4 LM_TransformLayerModified.RESET_R = MOHO.MSG_BASE + 5 LM_TransformLayerModified.TOGGLE_DISPLAY = MOHO.MSG_BASE + 6 LM_TransformLayerModified.FLIP_H = MOHO.MSG_BASE + 7 LM_TransformLayerModified.FLIP_V = MOHO.MSG_BASE + 8 LM_TransformLayerModified.SELECTALIGNMENT = MOHO.MSG_BASE + 9 -- through MOHO.MSG_BASE + 14 LM_TransformLayerModified.TRANSPARENCY = MOHO.MSG_BASE + 15 LM_TransformLayerModified.BLUR = MOHO.MSG_BASE + 16 LM_TransformLayerModified.TOGGLE_VISIBLE = MOHO.MSG_BASE + 17 LM_TransformLayerModified.displayOn = true function LM_TransformLayerModified:DoLayout(moho, layout) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Position=Position"))) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/X=X:"))) self.text_TX = LM.GUI.TextControl(0, "00.00", self.CHANGE_T, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_TX) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Y=Y:"))) self.text_TY = LM.GUI.TextControl(0, "00.00", self.CHANGE_T, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_TY) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Z=Z:"))) self.text_TZ = LM.GUI.TextControl(0, "00.00", self.CHANGE_T, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_TZ) layout:AddChild(LM.GUI.Button(MOHO.Localize("/Scripts/Tool/TransformLayer/Reset=Reset"), self.RESET_T)) -- ***************************** layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Scale=Scale"))) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/X=X:"))) self.text_SX = LM.GUI.TextControl(0, "00.00", self.CHANGE_S, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_SX) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Y=Y:"))) self.text_SY = LM.GUI.TextControl(0, "00.00", self.CHANGE_S, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_SY) layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Z=Z:"))) self.text_SZ = LM.GUI.TextControl(0, "00.00", self.CHANGE_S, LM.GUI.FIELD_FLOAT) layout:AddChild(self.text_SZ) layout:AddChild(LM.GUI.Button(MOHO.Localize("/Scripts/Tool/TransformLayer/Reset=Reset"), self.RESET_S)) -- ***************************** layout:AddChild(LM.GUI.StaticText(MOHO.Localize("/Scripts/Tool/TransformLayer/Angle=Angle:"))) self.text_R = LM.GUI.TextControl(0, "000.00", self.CHANGE_R, LM.GUI.FIELD_FLOAT) self.text_R:SetWheelInc(1) layout:AddChild(self.text_R) layout:AddChild(LM.GUI.Button(MOHO.Localize("/Scripts/Tool/TransformLayer/Reset=Reset"), self.RESET_R)) -- ***************************** self.displayCheck = LM.GUI.CheckBox(MOHO.Localize("/Scripts/Tool/TransformLayer/ShowPath=Show path"), self.TOGGLE_DISPLAY) layout:AddChild(self.displayCheck) layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_layer_h", MOHO.Localize("/Scripts/Tool/SetOrigin/FlipH=Flip Layer Horizontally"), false, self.FLIP_H, true)) layout:AddChild(LM.GUI.ImageButton("ScriptResources/flip_layer_v", MOHO.Localize("/Scripts/Tool/SetOrigin/FlipV=Flip Layer Vertically"), false, self.FLIP_V, true)) -- ***************************** self.menu = LM.GUI.Menu(MOHO.Localize("/Scripts/Tool/TransformLayer/Align=Align")) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/Left=Left"), 0, LM_TransformLayerModified.SELECTALIGNMENT) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/Right=Right"), 0, LM_TransformLayerModified.SELECTALIGNMENT + 1) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/CenterHorizontally=Center Horizontally"), 0, LM_TransformLayerModified.SELECTALIGNMENT + 2) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/Top=Top"), 0, LM_TransformLayerModified.SELECTALIGNMENT + 3) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/Bottom=Bottom"), 0, LM_TransformLayerModified.SELECTALIGNMENT + 4) self.menu:AddItem(MOHO.Localize("/Scripts/Tool/CenterVertically=Center Vertically"), 0 , LM_TransformLayerModified.SELECTALIGNMENT + 5) self.popup = LM.GUI.ImagePopupMenu("ScriptResources/align_layers", false, true) self.popup:SetMenu(self.menu) self.popup:SetToolTip(MOHO.Localize("/Scripts/Tool/TransformLayer/AlignLayers=Align Layers")) layout:AddChild(self.popup) -- Custom controls: -- layout:AddChild(LM.GUI.StaticText("Opacity:")) self.transP = LM.GUI.TextControl(0, "000", self.TRANSPARENCY, LM.GUI.FIELD_UINT, "Opacity:") layout:AddChild(self.transP) -- layout:AddChild(LM.GUI.StaticText("Blur:")) self.blurred = LM.GUI.TextControl(0, "000", self.BLUR, LM.GUI.FIELD_UFLOAT, "Blur:") layout:AddChild(self.blurred) self.isVisible = LM.GUI.CheckBox("Visible", self.TOGGLE_VISIBLE) layout:AddChild(self.isVisible) end function LM_TransformLayerModified:UpdateWidgets(moho) local enableAlignmentPopup = moho.document:CountSelectedLayers() > 1 self.text_TX:SetValue(moho.layer.fTranslation.value.x) self.text_TY:SetValue(moho.layer.fTranslation.value.y) self.text_TZ:SetValue(moho.layer.fTranslation.value.z) self.text_SX:SetValue(moho.layer.fScale.value.x) self.text_SY:SetValue(moho.layer.fScale.value.y) self.text_SZ:SetValue(moho.layer.fScale.value.z) self.text_R:SetValue(math.deg(moho.layer.fRotationZ.value)) self.displayCheck:SetValue(self.displayOn) self.menu:UncheckAll() for i = 0, 5 do self.menu:SetEnabled(LM_TransformLayerModified.SELECTALIGNMENT + i, enableAlignmentPopup) end self.popup:Redraw() local transValue = moho.layer.fAlpha.value * 100 transValue = LM.Clamp(transValue, 0, 100) self.transP:SetValue(transValue) self.blurred:SetValue(moho.layer.fBlur.value * moho.document:Height()) self.isVisible:SetValue(moho.layer.fVisibility.value) end function LM_TransformLayerModified:HandleMessage(moho, view, msg) local newVal = LM.Vector3:new_local() local selCount = moho.document:CountSelectedLayers() if (msg == self.RESET_T) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() if (moho.frame == 0) then newVal:Set(0, 0, 0) layer.fTranslation:SetValue(0, newVal) else newVal:Set(layer.fTranslation:GetValue(0)) layer.fTranslation:SetValue(moho.frame + timingOffset, newVal) end end self:UpdateWidgets(moho) moho:NewKeyframe(CHANNEL_LAYER_T) moho.document:DepthSort() moho:UpdateUI() elseif (msg == self.RESET_S) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() if (moho.frame == 0) then newVal:Set(1, 1, 1) layer.fScale:SetValue(0, newVal) else newVal:Set(layer.fScale:GetValue(0)) layer.fScale:SetValue(moho.frame + timingOffset, newVal) end end self:UpdateWidgets(moho) moho:NewKeyframe(CHANNEL_LAYER_S) moho.document:DepthSort() moho:UpdateUI() elseif (msg == self.RESET_R) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() if (moho.frame == 0) then layer.fRotationZ:SetValue(0, 0.0) else layer.fRotationZ:SetValue(moho.frame + timingOffset, layer.fRotationZ:GetValue(0)) end end self:UpdateWidgets(moho) moho:NewKeyframe(CHANNEL_LAYER_ROT_Z) moho.document:DepthSort() moho:UpdateUI() elseif (msg == self.CHANGE_T) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() newVal.x = self.text_TX:FloatValue() newVal.y = self.text_TY:FloatValue() newVal.z = self.text_TZ:FloatValue() local offset = newVal - moho.layer.fTranslation:GetValue(moho.frame + moho.layer:TotalTimingOffset()) for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() if (offset:Mag() > 0.0001) then layer.fTranslation:SetValue(moho.frame + layer:TotalTimingOffset(), newVal) for j = 0, layer.fTranslation:CountKeys() - 1 do if (layer.fTranslation:IsKeySelectedByID(j) and layer.fTranslation:GetKeyWhen(j) ~= moho.frame + timingOffset) then local vec = layer.fTranslation:GetValueByID(j) + offset layer.fTranslation:SetValueByID(j, vec) end end moho:NewKeyframe(CHANNEL_LAYER_T) end end moho.document:DepthSort() moho:UpdateUI() elseif (msg == self.CHANGE_S) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() newVal.x = self.text_SX:FloatValue() newVal.y = self.text_SY:FloatValue() newVal.z = self.text_SZ:FloatValue() local offset = moho.layer.fScale:GetValue(moho.frame + moho.layer:TotalTimingOffset()) offset.x = newVal.x / offset.x offset.y = newVal.y / offset.y offset.z = newVal.z / offset.z for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() local vec = moho.layer.fScale:GetValue(moho.frame + moho.layer:TotalTimingOffset()) - newVal if (vec:Mag() > 0.0001) then layer.fScale:SetValue(moho.frame + timingOffset, newVal) for j = 0, layer.fScale:CountKeys() - 1 do if (layer.fScale:IsKeySelectedByID(j) and layer.fScale:GetKeyWhen(j) ~= moho.frame + timingOffset) then local scale = layer.fScale:GetValueByID(j) scale.x = scale.x * offset.x scale.y = scale.y * offset.y scale.z = scale.z * offset.z layer.fScale:SetValueByID(j, scale) end end moho:NewKeyframe(CHANNEL_LAYER_S) end end moho:UpdateUI() elseif (msg == self.CHANGE_R) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() newVal = math.rad(self.text_R:FloatValue()) local d = newVal - moho.layer.fRotationZ:GetValue(moho.frame + moho.layer:TotalTimingOffset()) for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) local timingOffset = layer:TotalTimingOffset() if (math.abs(d) > 0.0001) then layer.fRotationZ:SetValue(moho.frame + timingOffset, newVal) for j = 0, layer.fRotationZ:CountKeys() - 1 do if (layer.fRotationZ:IsKeySelectedByID(j) and layer.fRotationZ:GetKeyWhen(j) ~= moho.frame + timingOffset) then local angle = layer.fRotationZ:GetValueByID(j) + d layer.fRotationZ:SetValueByID(j, angle) end end moho:NewKeyframe(CHANNEL_LAYER_ROT_Z) end end elseif (msg == self.TOGGLE_DISPLAY) then self.displayOn = self.displayCheck:Value() elseif (msg == self.FLIP_H) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fFlipH:SetValue(moho.frame + layer:TotalTimingOffset(), not layer.fFlipH.value) moho:NewKeyframe(CHANNEL_LAYER_FLIP_H) end elseif (msg == self.FLIP_V) then moho.document:PrepMultiUndo(true) moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fFlipV:SetValue(moho.frame + layer:TotalTimingOffset(), not layer.fFlipV.value) moho:NewKeyframe(CHANNEL_LAYER_FLIP_V) end elseif (msg >= LM_TransformLayerModified.SELECTALIGNMENT and msg <= LM_TransformLayerModified.SELECTALIGNMENT + 5) then moho:AlignLayers(msg - LM_TransformLayerModified.SELECTALIGNMENT) elseif (msg == self.TOGGLE_VISIBLE) then moho.document:PrepMultiUndo() moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fVisibility:SetValue(moho.frame + layer:TotalTimingOffset(), not layer.fVisibility.value) moho:NewKeyframe(CHANNEL_LAYER_VIS) moho:UpdateUI() end elseif (msg == self.TRANSPARENCY) then local alphaValue = 0.0 if self.transP == 0 then alphaValue = 0.0 else alphaValue = self.transP:IntValue()/100 end moho.document:PrepMultiUndo() moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fAlpha:SetValue(moho.frame + layer:TotalTimingOffset(), alphaValue) moho:NewKeyframe(CHANNEL_LAYER_ALPHA) moho:UpdateUI() end elseif (msg == self.BLUR) then local blurValue = 0.0 if self.blurred == 0 then blurValue = 0.0 else blurValue = self.blurred:FloatValue()/moho.document:Height() end moho.document:PrepMultiUndo() moho.document:SetDirty() for i = 0, selCount - 1 do local layer = moho.document:GetSelectedLayer(i) layer.fBlur:SetValue(moho.frame + layer:TotalTimingOffset(), blurValue) moho:NewKeyframe(CHANNEL_LAYER_BLUR) moho:UpdateUI() end end end
Modified LM Transform Layer
Listed
Author: Stan
View Script
Script type: Tool
Uploaded: Dec 24 2020, 09:29
Last modified: Jan 19 2021, 07:28
Script Version: 0
Added opacity, visibility and blur controls, and also the bounding box color is changed to green
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: 1161
Modified LM Transform Layer
Listed
Author: Stan
View Script
Script type: Tool
Uploaded: Dec 24 2020, 09:29
Last modified: Jan 19 2021, 07:28
Script Version: 0
Added opacity, visibility and blur controls, and also the bounding box color is changed to green
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: 1161