Default startup settings



  • Hello everyone,
    I wanted to have some settings which will behave as "global" parameters. What I mean is that after I change one of these parameters it will remain changed even after I close and reopen Cinema4D and even if the file is not being saved. If I use "save as default scene" It will store all the changes, including the ones in the scene which is not what I am looking for.
    I just want to do this for only some settings in a GeDialog UI. Is it possible to do this?
    Thank you.



  • hello,

    Are you asking for a plugin you are creating or a more general part of cinema 4D ?
    What kind of plugin are you creating ? (dialog box, generator, tag, something else)

    Could you also add a tag to know if you are using python or c++ :)

    Cheers,
    Manuel



  • Hi,

    I am not quite sure if I understood you correctly.

    1. As you have flagged your posting as maxon api, I assume you are using C++?
    2. You have a GeDialog and you want the dialog values to be persistent over multiple sessions?
    3. Also saving the document cannot be assumed to always happen?
    4. I also think, and I might be wrong here, that the whole implicit saving of settings via 'save as default' or 'startup document' only works for description resources and not for dialog resources.

    Without condition three I would go for registering a plugin ID and storing the data under that ID in the documents BaseContainer. With that condition you probably have no other choice and have to serialize your dialogs settings yourself when the dialog is being closed. When your dialog is instantiated again you deserialize the data from that file into the dialog. The API offers the HyperFile type for custom serialization tasks. But I do not think a binary serialization is necessary and helpful here. I would go for a text serialization like JSON or XML and ignore HyperFile.

    Cheers,
    zipit



  • Hello @m_magalhaes
    Yes I am asking for a plugin that I am creating and it is a dialog box.
    So once again what I am trying to do is that after changing the settings in this dialog box (changing value of the dropdown for example) that new value will now be the dafult value of that dropdown even after restarting c4d with a different scene.
    Sorry for not tagging the language that I am using but seems that when I have the bookmarks bar shown on my browser(chrome) it covers c++ tag and there is no way of selecting it without removing the bookmarks bar as the tags are unscrollable.



  • Hello,

    well, if you want to store information that last between documents and once you switch off cinema4D and relaunch it :
    i see two solutions :

    • The first one is to use the WorldContainer() (The preferences dialog box use that to store its data)
      You have to use PrefsDialogObject::Register to register your preferences, and it's pretty simple. Use GetDDescription to react to the "ask default" interaction, GetDParameter and SetDParameter to store the data. Using also Init and InitValues.
      You need to store your data in a BaseContainer inside the WorldContainer. You have to store it in your own ID (it has to be unique so grab it on plugincafe's page . You can use the same as your plugins's ID but's you can use a different one. It just have to be unique
      The problem is that you can only store Maxon data type.
      You can change those values anywhere from cinema4D.

    • Another possibility, as zipit said, is to create your own file structure. The advantage is that you can store what ever data you need. It can be binary, text...
      Another advantage is that you can easily "copy paste" and share them from computer to computer. (you don't have to create "export/import" command like with the world Container)
      You could load that file on PluginStart and store that in memory or read it when ever you need it (to be determine) and write the file on PluginEnd

    If something is not clear, just ask, I may have forgotten something.

    I've created a simple example for the preferences :

    #include "c4d_basedocument.h"
    #include "lib_prefs.h"
    #include "c4d_customdatatypeplugin.h"
    #include "c4d_general.h"
    #include "Ppc11737_Pref.h"
    
    // Unique plugin ID for world preference container obtained from www.plugincafe.com
    #define WPREF_ID 1053240
    
    
    class PC11737_Pref : public PrefsDialogObject
    {
    	INSTANCEOF(PC11737_Pref, PrefsDialogObject)
    
    public:
    	static NodeData* Alloc() { return NewObjClear(PC11737_Pref); }
    
    
    	virtual Bool Init(GeListNode* node) 
    	{
    		InitValues(MY_CYCLE);
    		InitValues(ANOTHER_LONG);
    		return true;
    	}
    
    	virtual Bool InitValues(const DescID &id, Description *description = nullptr) 
    	{
    		// Retrieves our container inside the world Container
    		BaseContainer* bc = GetMyPreference();
    		if (bc == nullptr)
    			return false;
    
    		switch (id[0].id)
    		{
    			case MY_CYCLE:
    			{
    				InitPrefsValue(MY_CYCLE, GeData(FIRST_VALUE), description, id, bc);
    				break;
    			}
    			case ANOTHER_LONG:
    			{
    				InitPrefsValue(ANOTHER_LONG, GeData(150), description, id, bc);
    				break;
    			}
    		}
    
    		return true;
    	}
    
    	virtual Bool GetDDescription(GeListNode* node, Description* description, DESCFLAGS_DESC& flags) 
    	{
    		
    		if (!description->LoadDescription(WPREF_ID))
    			return false;
    
    		// Checks if the default value have been asked by a right click -> "default value"
    		if (flags & DESCFLAGS_DESC::NEEDDEFAULTVALUE)
    		{
    			InitValues(MY_CYCLE, description);
    			InitValues(ANOTHER_LONG, description);
    		}
    
    		flags |= DESCFLAGS_DESC::LOADED;
    
    		return SUPER::GetDDescription(node, description, flags);
    	}
    
    	virtual Bool GetDParameter(GeListNode* node, const DescID& id, GeData& t_data, DESCFLAGS_GET& flags) 
    	{
    		// Retrieves our container inside the world Container
    		BaseContainer* bc = GetMyPreference();
    		if (bc == nullptr)
    			return SUPER::GetDParameter(node, id, t_data, flags);
    
    		switch (id[0].id)
    		{
    			case MY_CYCLE:
    			case ANOTHER_LONG:
    			{
    				t_data = bc->GetInt32(id[0].id);
    				flags |= DESCFLAGS_GET::PARAM_GET;
    				return true;
    				break;
    			}
    		}
    
    
    		return SUPER::GetDParameter(node, id, t_data, flags);
    	}
    
    
    	virtual Bool SetDParameter(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags) 
    	{
    		// Retrieves our container inside the world Container
    		BaseContainer* bc = GetMyPreference();
    		if (bc == nullptr)
    			return SUPER::SetDParameter(node, id, t_data, flags);
    
    		switch (id[0].id)
    		{
    			case MY_CYCLE:
    			case ANOTHER_LONG:
    			{
    				bc->SetInt32(id[0].id, t_data.GetInt32());
    				flags |= DESCFLAGS_SET::PARAM_SET;
    				GeUpdateUI();
    				return true;
    				break;
    			}
    		}
    
    		return SUPER::SetDParameter(node, id, t_data, flags);;
    	}
    
    
    	virtual Bool GetDEnabling(GeListNode* node, const DescID& id, const GeData& t_data, DESCFLAGS_ENABLE flags, const BaseContainer* itemdesc) 
    	{
    		return SUPER::GetDEnabling(node, id, t_data, flags, itemdesc);
    	}
    
    private: 
    	BaseContainer* GetMyPreference()
    	{
    		// Retrieves our container inside the world Container
    		BaseContainer* bc = GetWorldContainerInstance()->GetContainerInstance(WPREF_ID);
    		// Doesn't exist ? Create it
    		if (!bc)
    		{
    				GetWorldContainerInstance()->SetContainer(WPREF_ID, BaseContainer());
    				bc = GetWorldContainerInstance()->GetContainerInstance(WPREF_ID);
    				if (!bc) return nullptr;
    		}
    
    		return bc;
    	}
    
    };
    
    static maxon::Result<void> RegisterPC11737()
    {
    	iferr_scope;
    
    
    	if (!PrefsDialogObject::Register(WPREF_ID, PC11737_Pref::Alloc, "My pref"_s, "Ppc11737_Pref", 0, 0))
    		return maxon::UnexpectedError(MAXON_SOURCE_LOCATION);
    
    	return maxon::OK;
    }
    
    

    .res

    CONTAINER Ppc11737_Pref
    {
    	NAME Ppc11737_Pref;
    
    
    	GROUP
    	{
            LONG MY_CYCLE { 
    
            	CYCLE
            	{
            		FIRST_VALUE;
            		SECOND_VALUE;
            	}
              }
            LONG ANOTHER_LONG {}
    	}
    }
    
    

    .h

    #ifndef _PPC11737_PREF_
    #define _PPC11737_PREF_
    
    enum
    {
    	FIRST_VALUE 	= 1,
       	SECOND_VALUE 	= 2,
     	MY_CYCLE 		= 1000,
     	ANOTHER_LONG
    
    };
    
    #endif // _PPC11737_PREF_
    

    .str

    STRINGTABLE Ppc11737_Pref
    {
    	Ppc11737_Pref                      "My preferences";
    	MY_CYCLE				"This is my cycle";
     	FIRST_VALUE 					 	"My First Value";
       	SECOND_VALUE 					 	"My Second Value";
       	ANOTHER_LONG						"Another Value";
    }
    
    

    Cheers,
    Manuel



  • Hello @m_magalhaes.
    Thank you for your help. I understand it and I tried it, works fine.
    But what if I am using GeDialog class instead, that is being called using a CommandData. How can I store the changes on that GeDialog the same way you did here?
    Is this method with the WorldContainer() used only for the preferences dialog box, because GetDDescription, GetDParameter and SetDParameter functions are not part of GeDialog class.
    Thank you again.



  • hello,

    if you change a parameter in your dialog box, it will trigger the Command function see this manual for dialog box interaction

    You can do the same there, get the WorldContainer that is a BaseContainer (see manual) and change the data inside it.

    You could have a button on your dialog (or a menu) that say "set default". Or when you change a DropBox.
    That's up to you. But you should keep the preference part just to let people know it's there or if they want to create script that will change them.

    Cheers
    Manuel



  • Thank you for the help @m_magalhaes