View Full Version : The philosophy of UNDO's
Scott Ayers 10-17-2010, 06:49 PM Hey guys,
One of the things that I've been avoiding using is UNDO's for two reasons:
1- They are distracting for newbies who are trying to learn the guts of how a script works
2- I don't fully understand how to use them myself. :blush:
I understand that the StartUndo() and EndUndo() collects all of the UNDOs listed throughout the script to execute them as a group.
And I know about the various types and flags that UNDO's have from the SDK.
But I often find it very confusing when and where to put the UNDOs in my scripts. Sometimes I see them listed at the end of a script. And other times they are peppered throughout the script.
Plus I also find that very often more than one UNDO type will work on something which confuses me.
Whenever I use UNDO's. I basically just guess at it and keep moving them around and trying different variations until I get lucky and find the right combination of type, flags, and placement. But sometimes I can't manage to get lucky.
I recently created this script that creates a material and tags. And I found it very hard to create undo's for it so everything undoes in one step: //This script creates and places an override material and tags on objects except nulls
//The tag is the last one in the list
searchOM(op)
{
if (!op) return;
if (op->GetDown()) return op->GetDown();
while (!op->GetNext() && op->GetUp()) op = op->GetUp();
return op->GetNext();
}
main(doc,op)
{
var obj = doc->GetFirstObject();
if (!obj) return;//error handeling
CallCommand(13015); //Create New Material
var fmt = doc->GetFirstMaterial();
fmt#ID_BASELIST_NAME="override";//set the name of the material
fmt#MATERIAL_COLOR_COLOR = vector(1,1,1);// set color to white
CallCommand(12252); // Render Materials updates the ICON color
while(obj)
{
if(obj->GetType() != 5140) //If it's a null object don't add a tag
{
obj->SetBit(BIT_ACTIVE); // Select it
}
if (!obj) return;//error handling
obj = searchOM(obj); // Call to and execute the searchOM method
}
CallCommand(12169); // Apply
CallCommand(100004767); // Deselect All
}
Do you guys have any little tricks you use that helps you know when, where, and what type of Undo to use that might help me understand them better?
-ScottA
|
|
Scott Ayers
10-18-2010, 04:21 PM
Nobody has any advice about this?
Is this too broad of a question?
Here's a more direct question. Hopefully this one will be easier to answer.
I noticed that most of my UNDO problems seem to revolve around CallCommands.
Since they have built in UNDOs inside of them. Could this be why I'm having so much trouble getting my scripts to undo-redo in one click?
Can CallCommands be packaged into the doc->StartUndo-------doc->EndUndo structure?
-ScottA
Per-Anders
10-18-2010, 05:39 PM
You gave it less than a day, on a weekend, patience.
Undos are explained fairly well in the documentation but they can be tricky, each type is used in a specific way.
The whole Undo operation as seen by the user (by clicking the undo/redo button) is encapsulated in the code with the BaseDocument::StartUndo and BaseDocument::EndUndo functions. Undo's themselves operate on BaseList2D objects (that's the passed data) that exist within the document used, so you can't apply them to objects that are outside of the document.
The placement of the BaseDocument::AddUndo(UNDOTYPE, Object) is covered in the SDK docs, for instance when you make a new object then you must place the UNDOTYPE_NEW after the object has been created (and of course inserted into the document), the placement of UNDOTYPE_CHANGE is before you do the change to the object, or UNDOTYPE_DELETE also before you remove and delete the object.
The reason becomes very clear when you think of how the undo works, in very simplified terms it creates a duplicate of the object and it's data at the point where you call the AddUndo function, when the user presses undo it swaps the duplicate on the Undo Stack for the in document version (or just removes the document version for an UNDOTYPE_NEW). That's why it's important to fill in the CopyTo function in your NodeData based plugins if you ever store any data outside of the BaseContainer, as that's called for each duplication when doing undo and redo. So obviously for this to work you have to make that duplicate before you make changes, and after a new object is inserted, when the object is in the document at the state you want to record it at basically. The system also handles the Redo in a somewhat similar way.
Hopefully that helps explain things a little bit better.
Scott Ayers
10-18-2010, 07:00 PM
Thanks Anders.
I must not be understanding it properly.
The doc->(UNDOTYPE_NEW, op) is the only type I don't have too much trouble with most of the time because the SDK spells out exactly where to put it. But the rest of them are very hit and miss when I use them.
I keep running into situations where if I place an undo either before or after something in the middle of the script (like creating a new material with CallCommand(13015) for example) it doesn't work.
But if I use something like doc->AddUndo(UNDOTYPE_CHANGE, op); at the end of the script. I can cheat around that and remove the material that way. But This doesn't get me to a one click undo result.
I'm not a very experienced programmer(about 6months). So some of this stuff you're saying is a bit over my head. Although I think I understand most of it in theory.
When you say this: "Undo's themselves operate on BaseList2D objects (that's the passed data) that exist within the document used, so you can't apply them to objects that are outside of the document."
Does that mean the CallCommands I'm using are outside of the BaseList2D class? And that's why they don't undo with as a group under the StartUndo---EndUndo() ?
-ScottA
Scott Ayers
10-18-2010, 09:08 PM
I think I just got it....Maybe. :)
If I use a CallCommand then I'm stuck when it comes to using the UNDOs because the CallCommand is outside of the Base2D class.
But...If I then use one of the Get functions to select the item I just created with that CallCommand. I can then use an UNDO on that Get function to undo what the CallCommand created.
Does that sound right?
I've just started to test this and it seems to be working so far. Am I on the right track?
-ScottA
Per-Anders
10-18-2010, 10:18 PM
CallCommand may invoke that commands own set of Undo's, including the EndUndo, which may create mutliple undos, possibly send a suggestion through to MAXON via PluginCafe or normal support that call command should skip the undos. You can get around this in some cases by using SendModelingCommand functions and in a few more using the SendCoreMessage/SpecialEventAdd system.
Scott Ayers
10-18-2010, 10:45 PM
It's funny that you said this Anders because this whole time I've been thinking that having an option to turn of the internal UNDOs for them might be simplest way to wrap them into your own custom UNDO stack.
I thought it was just me being a stupid newb and not understanding how they work.:)
I just wish I had more examples of this kind of thing to see how it's done and to learn from.
Something like my script where it's manipulating both the OM and the material manager. Instead of the basic examples I've seen of just undoing only one thing from the OM. Or one thing from the material manager.
-ScottA
xfon5168
10-19-2010, 07:53 PM
I don't do any COFFEE Scripting, so I've only found myself in the Python SDK which does a pretty good job of explaining when and where things should go:
UNDOTYPE_0 No flags.
UNDOTYPE_CHANGE Any change to an object, including hierarchy modifications; modification in positioning (object has been moved from A to B), substructures etc. (Needs to be called BEFORE action.)
UNDOTYPE_CHANGE_NOCHILDREN Same as UNDOTYPE_CHANGE, but without child modifications. (Needs to be called BEFORE action.)
UNDOTYPE_CHANGE_SMALL Change to local data only (e.g. data container), no substructures (e.g. no tags on an object). Also no childs. (Needs to be called BEFORE action.)
UNDOTYPE_CHANGE_SELECTION Change to point/poly/edge selection only. (Needs to be called BEFORE action.)
UNDOTYPE_NEW New object/node/tag etc. was created. (Needs to be called AFTER action.)
UNDOTYPE_DELETE Object/node/tag etc. to be deleted. (Needs to be called BEFORE action.)
UNDOTYPE_ACTIVATE Automatically managed by SetActiveObject()/Tag()/Material() etc. No need to use manually.
UNDOTYPE_DEACTIVATE Automatically managed by SetActiveObject()/Tag()/Material() etc. No need to use manually.
UNDOTYPE_BITS Change to object bits, e.g. selection status.
UNDOTYPE_PRIVATE_MULTISELECTIONAXIS Private.
UNDOTYPE_START Private.
UNDOTYPE_END Private.
rustEdge
10-21-2010, 03:02 AM
I've only worked on the C++ SDK for just around three weeks, but it seems that the undos there are pretty much the same for both COFFEE and Py4D.
Unfortunately the only reliable way I could see how they work is by adding them inside methods and just trying to figure out which states they actually undo. For example, a dummy script that creates an object, does a few actions on it, then have a tag attach to that. Then I type in the AddUndo commands in several spots and see if they affect anything.
But you're right. I think we need more sample code besides the pre-installed cinema4dsdk source code. Building dummy scripts just to see how stuff works is pretty inefficient.
Scott Ayers
10-21-2010, 04:19 PM
The CallCommands were giving me the most troubles. I think I've got better understanding of them now.
I was also confused by why some people put their Undos in the middle of their code. And some do it at the end of the code. But I think I understand that a little bit better too.
It seems to come down to a personal work flow issue.
So what I'm doing now is trying to put all of my Undos at the end of my scripts as much as possible. And if I do something in my scripts where I can't get away with that work flow. Then, and only then, will I add them inside the script.
I thrive on rules like this. I must have them. I must have order and discipline or I get confused and lose focus on the task I'm trying to do.
Partially because I'm still fairly new at this stuff. But also because I'm an organization freak and can't focus inside of a mess.;)
-ScottA
CGTalk Moderation
10-21-2010, 04:19 PM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.
vBulletin v3.0.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.