Acessing CustomDataType parameters

On 24/11/2017 at 19:42, xxxxxxxx wrote:

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

---------
Hi,
I'm using custom data types, but there are some things that I'm not working as I expected.
Here's what I'm doing and what's missing. Please correct me if I'm doing anything wrong.

I have a custom data class (MyData) derived from CustomDataType, that holds multiple arrays.
Its defined by a CustomDataTypeClass (MyDataType), with a unique plugin ID (ID_MY_DATA).
It declares a custom resource type (MYDATA , from GetResourceSym()) that I use on a tag (T_MY_DATA).

To read and write MyData on the tag, I created 2 functions that work very fine:

GeData holder;
CustomDataType* customData = GetUserData( Get(), ID_MY_DATA, T_MY_DATA, holder );
MyData* myData = static_cast< MyData*>( customData );
  
	// holder will keep a valid pointer while in context
	CustomDataType* GetUserData( GeListNode* node, const Int32 dataType, const Int32 refId, GeData& holder )
	{
		DescID desc( DescLevel( ID_USERDATA, DTYPE_SUBCONTAINER, 0 ), DescLevel(refId, dataType, 0 ) );
		node->GetParameter( desc, holder, DESCFLAGS_GET_0 );
		CustomDataType* customData = holder.GetCustomDataType(dataType);
		return customData;
	}
  
SetUserData( Get(), ID_MY_DATA, T_MY_DATA, static_cast<CustomDataType*>( myData ) );
  
	void SetUserData( GeListNode* node, const Int32 dataType, const Int32 refId, const CustomDataType* customData )
	{
		if (customData != nullptr)
		{
			GeData holder;
			holder.SetCustomDataType( dataType, *customData );
			DescID desc( DescLevel( ID_USERDATA, DTYPE_SUBCONTAINER, 0 ), DescLevel( refId, dataType, 0 ) );
			node->SetParameter( desc, holder, DESCFLAGS_SET_FORCESET );
		}
	}
  1. My CustomDataTypeClass also defines some LONG parameters. How do I set and get them from outside the class? I tried many DescID configurations and no success. Since the CustomDataType I have access is an empty shell, not a NodeData or C4DAtom, I can't use SetParameter() and GetParameter(). Is this only exposed thru the Attributes Manager?

  2. CustomDataTypeClass does have GetParameter() and SetDParameter(), but is there a way get it instead of CustomDataType?

  3. I tried to set/set the LONGs from GetParameter() and SetDParameter(), but the data pointer points to an empty MyData. Is there a catch here? Compare() and CopyData() are implemented.

  4. GetEnabling() also seems to have no effect, even always returning false the attribute fields are always enabled.

On 27/11/2017 at 03:38, xxxxxxxx wrote:

Hello,

could you post the code of your custom data type? This would help to understand what you are doing.

Please notice the the custom data stored in a custom data type is typically based on iCustomDataType. You find an example in customdata_customgui.cpp.

A simple data type that defines a sub-parameters can look like this:

  
class ExampleCustomDataClass;  
  
class iExampleData : public iCustomDataType<iExampleData>  
{  
 friend class ExampleCustomDataClass;  
  
public:  
 String _string;  
 Int32     _int;  
  
 iExampleData()  
 {  
     _string = "";  
     _int = 0;  
 }  
};  
  
const Int g_customDataID = 1000001;  
  
class ExampleCustomDataClass : public CustomDataTypeClass  
{  
 INSTANCEOF(ExampleCustomData, CustomDataTypeClass)  
  
public:  
 virtual Int32 GetId()  
 {  
     return g_customDataID;  
 }  
  
 virtual CustomDataType* AllocData()  
 {  
     iExampleData* data = NewObjClear(iExampleData);  
     return data;  
 };  
  
 virtual void FreeData(CustomDataType* data)  
 {  
     iExampleData* d = static_cast<iExampleData*>(data);  
     DeleteObj(d);  
 }  
  
 virtual Bool CopyData(const CustomDataType* src, CustomDataType* dst, AliasTrans* aliastrans)  
 {  
     const iExampleData* s = static_cast<const iExampleData*>(src);  
     iExampleData*                d = static_cast<iExampleData*>(dst);  
     if (!s || !d)  
         return false;  
     d->_int = s->_int;  
     d->_string = d->_string;  
     return true;  
 }  
  
 virtual Int32 Compare(const CustomDataType* d1, const CustomDataType* d2)  
 {  
     const    iExampleData* const s = static_cast<const    iExampleData*>(d1);  
     const    iExampleData* const d = static_cast<const    iExampleData*>(d2);  
     if (!s || !d)  
         return 0;  
     // just compare the int because I'm lazy  
     const maxon::Int countd1 = s->_int;  
     const maxon::Int countd2 = d->_int;  
  
     if (countd1 == countd2)  
         return 0;  
     if (countd1 < countd2)  
         return -1;  
     if (countd1 > countd2)  
         return 1;  
  
     return 0;  
 }  
  
 virtual Bool _GetDescription(const CustomDataType* data, Description& res, DESCFLAGS_DESC& flags, const BaseContainer& parentdescription, DescID* singledescid)  
 {  
     BaseContainer stringSettings = GetCustomDataTypeDefault(DTYPE_STRING);  
     stringSettings.SetString(DESC_NAME, "String Data");  
     stringSettings.SetString(DESC_SHORT_NAME, "String Data");  
     stringSettings.SetFloat(DESC_MIN, 0.0f);  
     stringSettings.SetFloat(DESC_MAX, 1.0f);  
     stringSettings.SetFloat(DESC_STEP, 0.01f);  
     if (!res.SetParameter(DescLevel(1000, DTYPE_STRING, g_customDataID), stringSettings, DESCID_ROOT))  
         return false;  
  
  
     BaseContainer intSettings = GetCustomDataTypeDefault(DTYPE_LONG);  
     intSettings.SetString(DESC_NAME, "Int data");  
     intSettings.SetString(DESC_SHORT_NAME, "Intdata");  
     if (!res.SetParameter(DescLevel(1001, DTYPE_LONG, g_customDataID), intSettings, DESCID_ROOT))  
         return false;  
  
     flags |= DESCFLAGS_DESC_LOADED;  
     return CustomDataTypeClass::_GetDescription(data, res, flags, parentdescription, singledescid);  
 }  
  
 virtual Bool GetParameter(const CustomDataType* data, const DescID& id, GeData& t_data, DESCFLAGS_GET& flags)  
 {  
     iExampleData* s = (iExampleData* )data;  
     if (!s)  
         return false;  
  
     const Int32 subID = id[0].id;  
  
     if (subID == 1000)  
         t_data = GeData(s->_string);  
     else if (subID == 1001)  
         t_data = GeData((Int32)s->_int);  
  
     flags |= DESCFLAGS_GET_PARAM_GET;  
     return CustomDataTypeClass::GetParameter(data, id, t_data, flags);  
 }  
  
 virtual Bool SetDParameter(CustomDataType* data, const DescID& id, const GeData& t_data, DESCFLAGS_SET& flags)  
 {  
     iExampleData* s = (iExampleData* )data;  
     if (!s)  
         return false;  
  
     const Int32 subID = id[0].id;  
     if (subID == 1000)  
     {  
         s->_string = t_data.GetString();  
     }  
     else if (subID == 1001)  
     {  
         s->_int = t_data.GetInt32();  
     }  
     flags |= DESCFLAGS_SET_PARAM_SET;  
     return CustomDataTypeClass::SetDParameter(data, id, t_data, flags);  
 }  
  
 virtual Bool GetEnabling(const CustomDataType* data, const DescID& id, const GeData& t_data, DESCFLAGS_ENABLE& flags, const BaseContainer* itemdesc)  
 {  
     const iExampleData* s = static_cast<const iExampleData*>(data);  
     if (!s)  
         return false;  
  
     const Int32 subID = id[0].id;;  
  
     if (subID == 1001)  
     {  
         if (s->_string.Content())  
             return true;  
         else  
             return false;  
     }  
  
     return SUPER::GetEnabling(data, id, t_data, flags, itemdesc);  
 }  
  
 virtual const Char* GetResourceSym()  
 {  
     return "EXAMPLE";  
 }  
  
 virtual void GetDefaultProperties(BaseContainer& data)  
 {  
     // the default values of this datatype  
     data.SetInt32(DESC_ANIMATE, DESC_ANIMATE_ON);  
 }  
  
 virtual Bool WriteData(const CustomDataType* t_d, HyperFile* hf)  
 {  
     // skip that to make this example easy  
     return true;  
 }  
  
 virtual Bool ReadData(CustomDataType* t_d, HyperFile* hf, Int32 level)  
 {  
     // skip that to make this example easy  
     return true;  
 }  
};  

The sub-parameter can then be accessed with a properly created DescID:

  
GeData data;  
  
DescID desc(DescLevel(ID_USERDATA, DTYPE_SUBCONTAINER, 0), DescLevel(1, g_customDataID, 0), DescLevel(1000, DTYPE_STRING, 0));  
  
node->GetParameter(desc, data, DESCFLAGS_GET_0);  
  
const String str = data.GetString();  
GePrint(str);  

To work with the CustomDataType returned by GetCustomDataType() you would have to define a public class based on CustomDataType that exposes internal functionality using the library system. But that's quite an advanced topic.

From a quick look, it seems that GetEnabling() is not used at all.

best wishes,
Sebastian

On 11/12/2017 at 12:38, xxxxxxxx wrote:

Hi Sebastian,

I'm sure I wrote an answer to this topic, but probably never sent.

The description to access user data works, thanks!

Found out my problem in GetParameter and SetDParameter was because of my _GetDescription(). I copied it exactly like the datatype.cpp example, and just removing it allowed me to finally see the actual data in Get/Set. Seems like the UI was resetting it, but I could not find any mistake in my code. Now I'm using a _GetDescription() like yours and data is fine, I don't see the values in the attributes manager. I don't want the user to change the attributes, just show some chewed up data from the userdata.