synthsin75 wrote:Then you may need to provide a working code snippet to test what you are actually looking to do.
I can post my whole script, but this is how I'm trying to make it work:
PrepMultiUndo(true)
... code to move keyframes around in multiple layers
I would like this to produce only one undo step that undos all the keyframe changes. For some reason, this only undos changes for one layer.
If you want to have a look, here's the whole tool script. Currently I'm adding a PrepUndo(layer) for every layer I go through because I couldn't get the multiundo to work. Of course, this is pain when there are tens of layers. It doesn't even check if they are changed, currently. Work in progress. It's currently using my own function to find keyframes, I'll switch to your technique but haven't done it yet.
This script will make it really easy to insert and cut time in ASPRO, undo is now the only thing that's not working...
Code: Select all
-- **************************************************
-- Provide Moho with the name of this script object
-- **************************************************
ScriptName = "JL_time_tool"
-- **************************************************
-- General information about this script
-- **************************************************
JL_time_tool = {}
function JL_time_tool:Name()
return "Time tool"
end
function JL_time_tool:Version()
return "1.0"
end
function JL_time_tool:Description()
return "Insert or delete time by dragging in the viewport. Insert by dragging right, delete by dragging left."
end
function JL_time_tool:Creator()
return "Juhana Lehtiniemi - www.juhanalehtiniemi.com"
end
function JL_time_tool:UILabel()
return "Time tool"
end
-- **************************************************
-- Recurring values
-- **************************************************
JL_time_tool.startFrame=0
JL_time_tool.endFrame=0
JL_time_tool.originaLayerPos=nil
JL_time_tool.originaBonePos=nil
JL_time_tool.selectedBone=nil
JL_time_tool.selectedLayer=nil
JL_MSG_not_a_bone_layer = "Current layer is not a bone layer."
JL_MSG_select_one_bone_only = "Please select 1 bone only. You can select a bone by ALT-clicking it."
-- **************************************************
-- The guts of this script
-- **************************************************
function JL_time_tool:FindKey(moho, selectedVec, startFrame, direction)
local keyframe = 0
local frameCount = selectedVec:Duration()
if (direction < 0) -- backwards
then
for i = startFrame, 0, -1 do
-- Start from one frame before current frame
if (selectedVec:HasKey(i)) then
-- bone.fAnimPos:HasKey(curFrame - i)==true
keyframe = i
break
end
end
else -- forward
for i = startFrame, frameCount do
-- Start from one frame before current frame
if (selectedVec:HasKey(i)) then
-- bone.fAnimPos:HasKey(curFrame - i)==true
keyframe = i
break
end
end
end
return(keyframe)
end
function JL_time_tool:InsertTimeToChannel(moho, channel, startFrame, endFrame)
-- Add AMOUNT to animation length or not?
local nextKeyframe, nextKeyframeID
local modified = false
if channel:CountKeys() > 1 then
-- Chronological start and end frames
local newStartFrame, newEndFrame
-- Calculate loop direction
local direction, offset
-- If user selection is from left to right, then we're starting from the end to insert time
if (startFrame < endFrame) then
direction = -1
newStartFrame = startFrame
newEndFrame = endFrame
offset = endFrame-startFrame
-- Search next keyframe backwards from the end of the channel
local foundKeyframe = self:FindKey(moho, channel, channel:Duration(), direction)
-- Repeat until given frame reached
while (foundKeyframe >= newStartFrame) do
nextKeyframeID = channel:GetClosestKeyID(foundKeyframe)
channel:SetKeyWhen(nextKeyframeID, foundKeyframe+offset)
-- Search backwards for next keyframe after the last found keyframe
foundKeyframe = self:FindKey(moho, channel, foundKeyframe-1, direction)
-- if (foundKeyframe == 0) then break end
-- Changes to channels done
modified = true
end
else
-- If user selected the range backwards, then we have to start from left to right to delete time
direction = 1
newStartFrame = endFrame
newEndFrame = startFrame
offset = endFrame-startFrame
-- Search next keyframe backwards from the end of the channel
local foundKeyframe = self:FindKey(moho, channel, newStartFrame, direction)
-- Repeat until given frame reached
while (foundKeyframe <= channel:Duration() and foundKeyframe ~= 0) do
nextKeyframeID = channel:GetClosestKeyID(foundKeyframe)
channel:SetKeyWhen(nextKeyframeID, foundKeyframe+offset)
-- Search for next keyframe after the last found keyframe
foundKeyframe = self:FindKey(moho, channel, foundKeyframe+1, direction)
-- Changes to channels done
modified = true
end
end
end
return modified
end
function JL_time_tool:InsertTimeToLayer(moho, layer, startFrame, endFrame)
local numCh = layer:CountChannels()
local modified = false
-- Currently prepping undo for every channel because I can't check if they will be changed
moho.document:PrepUndo(layer)
for i = 0, numCh - 2 do
local chInfo = MOHO.MohoLayerChannel:new_local()
layer:GetChannelInfo(i, chInfo)
if (chInfo.subChannelCount == 1) then
local ch = layer:Channel(i, 0, moho.document)
-- print(MOHO.Localize("/Scripts/Menu/ListChannels/Channel=Channel ") .. i .. ": " .. chInfo.name:Buffer() .. MOHO.Localize("/Scripts/Menu/ListChannels/Keyframes= Keyframes: ") .. ch:CountKeys())
if (self:InsertTimeToChannel(moho, ch, startFrame, endFrame)) then
modified = true
end
else
-- print(MOHO.Localize("/Scripts/Menu/ListChannels/Channel=Channel ") .. i .. ": " .. chInfo.name:Buffer())
for subID = 0, chInfo.subChannelCount - 1 do
local ch = layer:Channel(i, subID, moho.document)
if (self:InsertTimeToChannel(moho, ch, startFrame, endFrame)) then
modified = true
end
-- print(MOHO.Localize("/Scripts/Menu/ListChannels/SubChannel= Sub-channel ") .. subID .. MOHO.Localize("/Scripts/Menu/ListChannels/Keyframes= Keyframes: ") .. ch:CountKeys())
end
end
end
-- if (modified) then
-- moho.document:PrepUndo(layer)
-- end
return modified
end
function JL_time_tool:InsertTimeToGroupLayer(moho, groupLayer, startFrame, endFrame)
local modified = false
for i = 0, groupLayer:CountLayers()-1 do
local currentLayer = groupLayer:Layer(i)
if (self:InsertTimeToLayer(moho, currentLayer, startFrame, endFrame)) then
modified = true
end
if (currentLayer:IsGroupType()) then
-- Go through the group layer as well
if (self:InsertTimeToGroupLayer(moho, moho:LayerAsGroup(currentLayer), startFrame, endFrame)) then
modified = true
end
end
end
return modified
end
function JL_time_tool:OnMouseDown(moho, mouseEvent)
local curFrame = moho.layer:CurFrame()
self.startFrame = curFrame
if (self.startFrame == 0) then
LM.GUI.Alert(LM.GUI.ALERT_INFO, "Start frame number has to be other than 0.", nil, nil, "OK", nil, nil)
return false
end
return true
end
function JL_time_tool:OnMouseMoved(moho, mouseEvent)
if (self.startFrame == 0) then return false end
local mouseGenValue=mouseEvent.pt.x-mouseEvent.startPt.x
if (mouseEvent.shiftKey) then
self.endFrame = self.startFrame+math.floor(mouseGenValue/50)
else
self.endFrame = self.startFrame+math.floor(mouseGenValue/25)
end
if (self.endFrame < 0) then
self.endFrame = 0
end
local range = self.endFrame-self.startFrame
if (range > 0) then
self.selectionRangeText:SetValue(self.InsertText.." "..math.abs(range).." frames")
elseif (range < 0) then
self.selectionRangeText:SetValue(self.DeleteText.." "..math.abs(range).." frames")
else
self.selectionRangeText:SetValue(self.DefaultText)
end
moho:SetCurFrame(self.endFrame)
mouseEvent.view:DrawMe()
return true
end
function JL_time_tool:OnMouseUp(moho, mouseEvent)
if (self.startFrame == 0) then return false end
-- Go through the range
local newStartFrame
local newEndFrame
-- if scrubbing backwards, let's start looping from the endframe instead and go forwards
if (self.startFrame > self.endFrame) then
newStartFrame = self.endFrame
newEndFrame = self.startFrame
else
newStartFrame = self.startFrame
newEndFrame = self.endFrame
end
-- go through each frame in the range and compensate the layer movement by the bone movement
local frameAmount = newEndFrame-newStartFrame
-- print ("moving frames by ", frameAmount)
local modified = false
-- print ("top levels layers found: ", moho.document:CountLayers())
moho.document:PrepMultiUndo(false)
local layerList
-- If going through only selected layers
if not (self.editAllLayers) then
for i = 0, moho.document:CountSelectedLayers()-1 do
-- All contained group layers will be included automatically and selection doesn't affect there
if (self:InsertTimeToLayer(moho, moho.document:GetSelectedLayer(i), self.startFrame, self.endFrame)) then
modified = true
end
end
else
if (self:InsertTimeToGroupLayer(moho, moho.document, self.startFrame, self.endFrame)) then
modified = true
end
end
if (modified) then moho.document:SetDirty() end
self.selectionRangeText:SetValue(self.DefaultText)
-- self.selectionRange:SetValue(0)
moho:SetCurFrame(self.startFrame)
-- moho:NewKeyframe(CHANNEL_LAYER_T)
-- moho:UpdateSelectedChannels()
-- moho.layer:UpdateCurFrame()
moho:UpdateUI()
return true
end
JL_time_tool.RANGE_CHANGED = MOHO.MSG_BASE
JL_time_tool.EDIT_ALL_LAYERS = MOHO.MSG_BASE+1
JL_time_tool.DefaultText = "Select time to insert/delete."
JL_time_tool.InsertText = "Inserting time"
JL_time_tool.DeleteText = "Deleting time"
-- First init before LoadPrefs starts to work
JL_time_tool.editAllLayers = true
function JL_time_tool:DoLayout(moho, layout)
self.selectionRangeText = LM.GUI.DynamicText(self.DefaultText, 0)
layout:AddChild(self.selectionRangeText)
layout:AddPadding()
layout:AddPadding()
self.editAllLayersCheckbox = LM.GUI.CheckBox("Edit all layers", self.EDIT_ALL_LAYERS)
self.editAllLayersCheckbox:SetValue(self.editAllLayers)
layout:AddChild(self.editAllLayersCheckbox)
end
function JL_time_tool:HandleMessage(moho, view, msg)
if (msg == self.EDIT_ALL_LAYERS) then
self.editAllLayers = self.editAllLayersCheckbox:Value()
end
end
function JL_time_tool:SavePrefs(prefs)
prefs:SetBool("JL_time_tool.editAllLayers", self.editAllLayers)
end
function JL_time_tool:LoadPrefs(prefs)
self.editAllLayers = prefs:GetBool("JL_time_tool.editAllLayers", JL_time_tool.editAllLayers)
end
function JL_time_tool:ResetPrefs(prefs)
JL_time_tool.editAllLayers = true
end