PrepMultiUndo()
Moderators: Víctor Paredes, Belgarath, slowtiger
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
PrepMultiUndo()
How do I use PrepMultiUndo()? I'm performing things that affect multiple layers, does this help undo those in one go?
I have a situation where I don't know in forehand which layers will be touched. Instead of force-adding PrepUndo() to each layer even if they're not touched, I was wishing this could maybe be a solution?
I have a situation where I don't know in forehand which layers will be touched. Instead of force-adding PrepUndo() to each layer even if they're not touched, I was wishing this could maybe be a solution?
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
PrepMultiUndo is a document class function, so just call it before making the changes you want to be undoable.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
Re: PrepMultiUndo()
I tried to use it like that, but for some reason this happened:synthsin75 wrote:PrepMultiUndo is a document class function, so just call it before making the changes you want to be undoable.
-When using only PrepMultiUndo, only one undo-step is added and it doesn't undo all the changes to different layers, only like for one layer
-If I try to use PrepUndo(layer) multiple times withing the document, then for some reason a right amount of undo steps is added, but they aren't undoed properly
-If I use PrepMultiUndo and add PrepUndo(layer) on each layer, then the amount of PrepUndo-steps is added and they are undoed properly.
I don't know what's happening, if I'm doing something wrong or is PrepMultiUndo supposed to be called if you use PrepUndo many times?
Or can I somehow use PrepMultiUndo to add only one undostep that undoes all the changes on separate layers? From your message I understand it's supposed to work like this but for some reason it doesn't undo changes on all layers.
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
Maybe you need to use it with the argument. PrepMultiUndo(true)
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
Re: PrepMultiUndo()
Doesn't seem to work. :/ Tried with both true and false and all the combinations of PrepMultiUndo() and PrepUndo() mentioned in my original post.synthsin75 wrote:Maybe you need to use it with the argument. PrepMultiUndo(true)
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
Then you may need to provide a working code snippet to test what you are actually looking to do.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
Re: PrepMultiUndo()
I can post my whole script, but this is how I'm trying to make it work:synthsin75 wrote:Then you may need to provide a working code snippet to test what you are actually looking to do.
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
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
Try removing ALL undos, both multi and single, and put moho.document:PrepMultiUndo() as the first line in your OnMouseDown function.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
Re: PrepMultiUndo()
I have:synthsin75 wrote:Try removing ALL undos, both multi and single, and put moho.document:PrepMultiUndo() as the first line in your OnMouseDown function.
-Group layer
---- Vector layer
-Bone layer
-Vector layer
PrepMultiUndo() (both with true and false as parameter) produces only one undo step which undoes the keyframe changes only on the first group layer (but not layers in it).
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
I don't have the time to delve too deeply into troubleshooting an entire script, but here's my suggestion. Select each layer before making changes to it. See if that helps.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
-
- Posts: 107
- Joined: Mon Jan 14, 2013 3:18 pm
Re: PrepMultiUndo()
I understand. Thanks for your help anyway.
The craziest thing is that when I finally gave up on it and decided to only do just one
at MouseDown, it works but of course it shouldn't. As a result of this, I get one undo step that undos every change on every layer I touch. (at least it looks that way). But PrepUndo(nil) is supposed to tell AS that no undo should be possible. Something's going south there, but it works now for some reason.
I have now posted the script for testing. It includes many of problems you guys helped me to solve. Thank you so much!
The craziest thing is that when I finally gave up on it and decided to only do just one
Code: Select all
PrepUndo(nil)
I have now posted the script for testing. It includes many of problems you guys helped me to solve. Thank you so much!
- synthsin75
- Posts: 9968
- Joined: Mon Jan 14, 2008 11:20 pm
- Location: Oklahoma
- Contact:
Re: PrepMultiUndo()
I found that I have used PrepUndo(nil) on some older scripts of mine. I've never seen PrepUndo tell AS something is not undoable. So I think you found the right way to do it.
- Wes
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/
Donations: https://www.paypal.com/paypalme/synthsin75 (Thx, everyone.)
https://www.youtube.com/user/synthsin75
Scripting reference: https://mohoscripting.com/