Undo System

The editor has a history (undo/redo) system that allows us to register editing actions and be able to undo/redo them at any time.

The editor APIs do NOT have undo inside the functions, you must handle undo on the GUI side of the editor tools.

You also need to make sure you encapsulate the data and the undo/redo procedure inside the undo/redo functions.

Do not do any modification of the scene or data outside those functions, because it will break the reproduction of undo/redo for that operation.

The redo function is called inside the history:commitAction, so no need to call it yourself.

If you add a function that is also adding a history action, it will be better to call it: addSomeThingWithUndo(.….) the postfix WithUndo will hint everyone, that the function is also registering undo operations. The other functions, by default will be considered without undo support. That function can be on the API side or on UI, as long as it has that postfix to be easily understood what it does.

Action names should be PascalCase, without the Action as postfix, and should be unique globally, \"AddSomeThing\" instead of just "Add".

Check the history API for more complex usage or transactions of actions and so forth. See History Class

To create an undoable action you need to write two functions, like so:

-- undo the action of naming an object
local function setObjectNameUndo(actionData)
    local obj = scenetree.findObjectById(actionData.objectId)
    if obj then
        -- for undo, we set the old name
        obj:setName(actionData.oldName)
    end
end

-- redo the action of naming an object
local function setObjectNameRedo(actionData)
    local obj = scenetree.findObjectById(actionData.objectId)
    if obj then
        -- for redo we set the new name
        obj:setName(actionData.newName)
    end
end

-- our GUI-side and undo enabled editor function that sets the name of an object
local function setObjectNameWithUndo(objectId, name)
    local obj = scenetree.findObjectById(objectId)
    local oldName = ""
    if obj then
        oldName = obj:getName(objectId)
    end
    -- add the action to the history, first argument is the name of the action,
    -- second is the action data where you store your undo/redo info
    -- last arguments are the undo redo functions
    editor.history:commitAction("SetObjectName", {objectId = objectId, newName = name, oldName = oldName}, setObjectNameUndo, setObjectNameRedo)
    -- the redo function WILL BE EXECUTED in the addAction function right away
    -- thus doing the actual operation
end

The function is added to the editor table (see Extending Editor ), and we can call from anywhere: editor.setObjectNameWithUndo(3422, "MyName"). After that, anytime we call editor.undo() the old name will be set, and if we call editor.redo() the new name will be restored.

Last modified: 7/12/2021 19:55

Any further questions?

Join our discord