Undo question?



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 01/04/2008 at 11:00, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   9+ 
    Platform:   Windows  ; Mac  ;  Mac OSX  ; 
    Language(s) :     C++  ;

    ---------
    Howdy,

    Well, I'm having a bit of a time understanding how to optimize this.

    I have a tag that changes its parameter when the object changes. It can also change the object when the user changes the parameter. OK, that all works fine normally, except for undo when the user changes the tag's AM parameter. It won't undo the change to the object.

    So, to get the undo to work I added this code to the TagData::Message() function:

    > switch (type) \> { \>      case MSG_DESCRIPTION_USERINTERACTION_END: \>      { \>           doc->AddUndo(UNDO_CHANGE,op); \>           break; \>      } \> }

    That seems to work, but it will add an object undo onto the undo stack, no matter which AM parameter in the tag was changed by the user.

    So, it needs to be optimized to only add the object undo to the undo stack when the one parameter is changed. I did a message poll to see which messages are received by the tag when a parameter is changed.
    The tag received these messages in this order:
    MSG_DESCRIPTION_INITUNDO
    MSG_DESCRIPTION_CHECKUPDATE
    MSG_DESCRIPTION_VALIDATE
    MSG_DESCRIPTION_USERINTERACTION_END

    Now it looks like the thing to do would be to first poll for the message "MSG_DESCRIPTION_INITUNDO" and set a flag in the tag's BaseContainer so we know that something might need undoing.

    Then poll for the message "MSG_DESCRIPTION_CHECKUPDATE" to see which parameter was changed by the user, and if it was the parameter in question, set a flag in the tag's BaseContainer so we know that parameter was changed by the user.

    Then poll for the message "MSG_DESCRIPTION_USERINTERACTION_END" and check the two flags. If both flags are set, add an undo for the object, and unset the flags.

    Now the problem I have is in understanding the "DescriptionCheckUpdate" data and how to retrieve the description id. There's no example code in the docs and also none in the cinema4dsdk project. :o(

    I did a search here and this was the only thread I found:
    [url]http://www.plugincafe.com/forum/display_topic_threads.asp?ForumID=4&TopicID;=2237&SearchPagePosition;=1&search;=DescID&searchMode;=allwords&searchIn;=Topic&forum;=4&searchSort;=dateDESC&ReturnPage;=Search[/url]
    ... which doesn't have an answer. :o(

    Now with a "DescriptionCommand" data you can do it like this:

    > DescriptionCommand \*dc = (DescriptionCommand\* ) data; \> if(dc->id[0].id == MY_TAG_PARAMETER)

    ... but a "DescriptionCheckUpdate" data structure uses a pointer to the id where a "DescriptionCommand" data structure doesn't.

    So, the question is does anyone have an example of how to retrieve the id from the "DescriptionCheckUpdate" data, and is polling for those messages and setting flags the best way to optimize the code?

    Adios,
    Cactus Dan



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 01/04/2008 at 12:53, xxxxxxxx wrote:

    MSG_DESCRIPTION_INITUNDO is the place to add undos for a plugin object/tag. Your tag will receive these BEFORE the action is completed (as you note with your message receipt order). In my case, no, I'm not being picky about which AM changes should trigger an AddUndo().

    The DescriptionCheckUpdate is sort of like the DescriptionCommand.

    > // One of the Sliders \> case MSG_DESCRIPTION_CHECKUPDATE: \> { \>      if (CheckIsRunning(CHECKISRUNNING_EXTERNALRENDERING) || CheckIsRunning(CHECKISRUNNING_EDITORRENDERING))          return TRUE; \>      if (!data)                         return TRUE; \>      DescriptionCheckUpdate\*     dcu =     static_cast<DescriptionCheckUpdate\*>(data); \>      DescID     descID =               \*(dcu->descid); \>      return MsgCheckUpdate((BaseObject\* )node, descID[0].id); \>      break; \> }

    You just need to get the data being pointed to with a '*' pointer dereference.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 01/04/2008 at 13:29, xxxxxxxx wrote:

    Howdy,

    Hehe, sometimes I just can't get my head around pointers. :o(

    OK, now it works perfectly (in an obsessive compulsive sort of way :oD ).

    Here's the code:

    > case MSG_DESCRIPTION_INITUNDO: \> { \>      tData->SetBool(START_INTERACTION,TRUE); \>      break; \> } \> case MSG_DESCRIPTION_CHECKUPDATE: \> { \>      if(tData->GetBool(START_INTERACTION)) \>      { \>           DescriptionCheckUpdate \*dch = (DescriptionCheckUpdate\* ) data; \>           DescID descID = \*(dch->descid); \>           LONG paramID = descID[0].id; \>           if(paramID == MY_TAG_PARAMETER) tData->SetBool(INTERACTION_UNDO,TRUE); \>      } \>      break; \> } \> case MSG_DESCRIPTION_USERINTERACTION_END: \> { \>      if(tData->GetBool(START_INTERACTION) && tData->GetBool(INTERACTION_UNDO)) \>      { \>           doc->AddUndo(UNDO_CHANGE,op); \>           tData->SetBool(START_INTERACTION,FALSE); \>           tData->SetBool(INTERACTION_UNDO,FALSE); \>           GePrint("Object undo added"); \>      } \>      else GePrint("No object undo needed"); \>      break; \> }

    ... the START_INTERACTION and INTERACTION_UNDO are the custom flags in the tag's BaseContainer. If any other parameter is changed by the user it prints "No object undo needed".

    Thanks Robert! ;o)

    Adios,
    Cactus Dan



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 01/04/2008 at 14:09, xxxxxxxx wrote:

    thanks for posting your findings.

    cheers,
    Matthias



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 01/04/2008 at 20:39, xxxxxxxx wrote:

    Howdy,

    > Quote: Originally posted by Matthias Bober on 01 April 2008
    >
    > * * *
    >
    > thanks for posting your findings.
    >
    > * * *

    You're welcome. ;o)

    Adios,
    Cactus Dan



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 08/04/2008 at 08:08, xxxxxxxx wrote:

    Howdy,

    OK, there is a problem with the undo, still. It seems that MSG_DESCRIPTION_INITUNDO is called once and then not called again as long as the tag's AM is still active. So if I punch in a number in the parameter and hit enter, and then punch in another number and hit enter, and then call an undo, it will undo all the way back to the first time. :o(

    Why is that? I would've thought that receiving the MSG_DESCRIPTION_USERINTERACTION_END message would end the interaction and end the undo cycle. But it doesn't seem to do that. This also causes problems for when the user uses the arrow sliders to change the parameter instead of punching in a value and hitting enter. :o(

    Adios,
    Cactus Dan



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 08/04/2008 at 08:34, xxxxxxxx wrote:

    Howdy,

    OK, I'm going back to the first method, and adding the object undo when the tag receives the MSG_DESCRIPTION_INITUNDO message. Even thought a parameter is changed that doesn't change the object, the object undo at that point doesn't really change the object in anyway, so I reckon it really doesn't matter. I was going under the assumption that MSG_DESCRIPTION_INITUNDO would be called again after you hit the enter key, but it seems like that is not the case. :o(

    Looks like you were right, Robert. ;o)

    Adios,
    Cactus Dan
    P.S. At least I learned something in the process. ;o)


Log in to reply