Save/Restore Dialog Settings for Document [SOLVED]



  • On 22/07/2014 at 18:01, xxxxxxxx wrote:

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

    ---------
    Hi PluginCafe,

    I have a CommandPlugin that opens a GeDialog with various Reals/Checkboxes/etc. and I want that all settings are saved even when the document is closed and reopened. The behavior should basically be the same as, for example, the width and height of the RenderSettings from C4D.

    I've read this:
    https://plugincafe.maxon.net/topic/7735/9792_container-owners
    So do I have to store all parameters of my dialog in a container and then the container as a subcontainer in the document's container? Therefore, I would need an additional unique ID, right? This feels a bit strange in my opinion?! Right now this is the way I do it, so I have a unique ID for my CommandPlugin, a unique ID for my Tag and a unique ID for my "Unique I want my dialog to remember its stuff ID".

    I've read this:
    https://plugincafe.maxon.net/topic/7860/10194_undo-basedocument-container-changes
    So they store their own container in the SceneHook. Are we supposed to do so? The thread reads like somebody is experimenting with places to store their data?!

    The thing is, that my tags work like a charm, I simply write this:
    Bool MyTag::Init(GeListNode* node)
    {
    BaseTag* tag = (BaseTag* )node;
    BaseContainer* baseContainer = tag->GetDataInstance();
    baseContainer->SetInt32( MY_INT, 0 );
    return true;
    }
    And the tag is initialized with the correct value when I create one and all values are stored on a per-object-basis even when I close and reopen the whole document. I guess that this works because I store the data in the node's container and the node is the object the tag is attached to, right? And this object lives the whole time so no data is lost and it is even restored when a document is closed?

    Maybe I'm using the GeDialog in a wrong manner?
    I inherit a MyDialog from GeDialog and override Bool MyDialog::InitValues(). As far as my understanding of C4D and containers goes is that I lose my values because InitValues() is called everytime I reopen the dialog (checked with the debugger). So I would have to store the values in a container, but where should I put this container?

    Thanks, and sorry if this question was asked before, but it seems that the whole container-concept is a little riddle for many programmers here ;-)



  • On 23/07/2014 at 04:18, xxxxxxxx wrote:

    So do I have to store all parameters of my dialog in a container [...]

    Not necessarily a BaseContainer, but you need to take care of storing the data in the dialog persistently and restoring it by yourself. A BaseContainer is convenient, though.

    You have multiple options on  where to store it.

    • Create your own SceneHook that will carry the data. You could even let the SceneHook have a description that will then automatically be displayed in the Project Settings (so no need for a dialog, and storing/restoring the data will be automatic, just like for a Tag)
    • Store the data in the ID_BS_HOOK SceneHook of a document or the document container itself. Using the SceneHook has the advantage that you can use it together with BaseDocument::AddUndo() which does not work with the document itself.

    Note that you must use a unique Plugin ID wherever you store data in a foreign context to make sure that it doesn't collide with existing entries.

    Best,
    -Niklas



  • On 23/07/2014 at 07:40, xxxxxxxx wrote:

    Howdy,

    You can also use your CommandData plugin's ID for the document's container ID, if you're concerned about how many ID's you have to have. 😉

    Adios,
    Cactus Dan



  • On 25/07/2014 at 14:39, xxxxxxxx wrote:

    @NiklasR:
    The solution with the custom SceneHook sounds cool. I might take a look if there is time and replace my current implementation :-)

    @Cactus Dan:
    I read somewhere that you should not use your plugin's ID for such containers. It is possible that the comment was wrong. I use an additional one for now to be save ;-)



  • On 25/07/2014 at 15:14, xxxxxxxx wrote:

    Howdy,

    Hmmmm, I haven't heard about that, but it seems to me that an ID is an ID and as long as the ID is not used twice on the same level, then it shouldn't matter how many times a particular ID is used.

    Since 2006, I've used the ID's to my CommandData plugins for their World Containers to store their settings, which hasn't caused any issues so far. For me it seems to keep everything more organized in my head. 😉

    Adios,
    Cactus Dan



  • On 29/07/2014 at 15:10, xxxxxxxx wrote:

    Here is some code for anybody who is interested in a solution that fits nicely into the C4D settings.

    class SettingsSceneHook : public SceneHookData
    {
    \> public:
    \> > static NodeData* Alloc(void);
    \>
    \>> virtual Bool Init(GeListNode* node);
    \>
    \>> virtual Bool Message(GeListNode* node, Int32 type, void* data);
    }
      
    // register the SceneHook, check out the PLUGINFLAG_SCENEHOOK_SUPPORT_DOCUMENT_DESCRIPTION flag, this is required so that we can add a description to the SceneHook
    Bool Register_SettingsSceneHook(void)
    {
    \> return RegisterSceneHookPlugin(SCENE_HOOK_ID,GeLoadString(IDS_SETTINGS), 
    \> 
    \> PLUGINFLAG_SCENEHOOK_SUPPORT_DOCUMENT_DESCRIPTION, SettingsSceneHook::Alloc, EXECUTIONFLAGS::EXECUTIONFLAGS_EXPRESSION, 0);
    }
      
    NodeData* SettingsSceneHook::Alloc(void) 
    { 
    \> return NewObjClear(SettingsSceneHook); 
    }
      
    Bool SettingsSceneHook::Init(GeListNode* node)
    {
    \> BaseTag* tag = (BaseTag* )node;
    \> 
    \> BaseContainer* baseContainer = tag->GetDataInstance();
    \> 
    \> baseContainer->SetInt32(MY_INT_VALUE, 3);
    \> 
    \> return true;
    }
      
    Bool SettingsSceneHook::Message(GeListNode* node, Int32 type, void* data)
    {
    \> BaseDocument* pDocument = node->GetDocument();
    \> 
    \> BaseObject* pBaseObject = (BaseObject* )node;
    \> 
    \> BaseContainer* pBaseContainer = pBaseObject->GetDataInstance();
    \> 
    \>   
    \> 
    \> 
    \> if (type == MSG_DESCRIPTION_COMMAND)
    \> 
    \> {
    \> > DescriptionCommand* dc = (DescriptionCommand* ) data;
    \>
    \>> if (dc->id[0].id == MY_BUTTON)
    \>
    \>> {
    \> > > if (!pDocument)
    \> > > > return true;
    \> > >   
    \> 
    \>
    \>> > Int32 myIntValue = pBaseContainer->GetInt32l(MY_INT_VALUE));
    \>
    \>> > GePrint("MyButton pressed!");
    \> > }
    \> }
    \> 
    \> return true;
    }
      
    // To add/attach/register a description for your SceneHook, you need to do this:
    Bool PluginMessage(Int32 id, void * data) 
    {   
    \> switch (id) 
    \> 
    \> {
    \> > case C4DPL_INIT_SYS:
    \>
    \>> {
    \> > > if( !resource.Init() ) // don't start plugin without resource
    \> > > > return false;
    \> > >   
    \> 
    \>
    \>> > if (!RegisterDescription(SCENE_HOOK_ID, "Dscenehooksettings")) 
    \> > > > return false;
    \> > >   
    \> 
    \>
    \>> > return true;
    \> > }
    \> 
    \> }
    \> return true;
    }
    

Log in to reply