I'm developing an application that produces "files" that are ultimately just a list of groups of transactions: an event store. I was wondering if there was a name for the way I'm handling undo/redo. Or if there's another common way to implement such functionality.
For example, a file with three "nodes" might look something like this:
"transactionGroups": [
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 132,
"length": 435,
"scale": 100
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 144,
"length": 363,
"scale": 100
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 163,
"length": 311,
"scale": 100
}
]
}
In the spirit of "there is no delete", I have devised a way to implement undo/redo by adding an "undo" transaction that references a transaction relative to its position in the store. Basically, it tells the file builder to ignore a referenced transaction when constructing the current state of the file.
To redo an operation, an undo transaction is just undone again.
"transactionGroups": [
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 132,
"length": 435,
"scale": 100
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 144,
"length": 363,
"scale": 100
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "nodeAdded",
"frame": 0,
"rotation": 163,
"length": 311,
"scale": 100
}
]
},
// Undoes the last two transactions
{
"isUserOwned": true,
"transactions": [
{
"op": "undo",
"transaction": 1
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "undo",
"transaction": 3
}
]
},
// Redoes the last two undo transactions
{
"isUserOwned": true,
"transactions": [
{
"op": "undo",
"transaction": 1
}
]
},
{
"isUserOwned": true,
"transactions": [
{
"op": "undo",
"transaction": 3
}
]
}
]