Solved Adding items to a LONG/CYCLE description container.

Hi !

I'm finishing developing my first python tag plugin but there's one thing that I can't figure out how to do.... I've read the documentation and searched for some examples, but no success :(

Basically I want to add a list of string to the File LONG CYCLE container.
0_1540075049978_ask.png

This is the part on my .py file where I get the strings:

datafilename = tag.GetDataInstance()
path = datafilename.GetFilename(STRINGTEST)

extensions = ["exr","hdr","jpg","png"]
c = 0
files = os.listdir(path)
for names in files:
    ext = names.rsplit(".",1)
    if ext[1] in extensions:
        c = c + 1
        lista = c
        lista = str(c)+';'+path+'\\'+names
        print lista

This is the part of my .res file where the cointainer is:

FILENAME STRINGTEST {DIRECTORY;}
LONG TESTSCALE 
{
    CYCLE
    {

    }
}

I think I would be able to do this with GetDDescription, but I have no idea and haven't found examples in how to do it :(

Does anyone know how to do it ? :smile:

Hi @FlavioDiniz, first of all, welcome in the plugincafe community!

Don't worry, since it's your first topic, I've set up your topic correctly. But please for your next topics, use the Q&A functionnaly, make sure to also read How to Post Questions.

With that's said you can find the manual about SetDParameter in the C++ docs which will be trigger each time a user changes a value in the description of your tag. And also the C++ manual about GetDDescription.
Here a quick example of the implementation in python

    extensions = ["exr","hdr","jpg","png"]

    # Called by C4D when loading description
    def GetDDescription(self, node, description, flags):
        data = node.GetDataInstance()
        if data is None:
            return False

        # Load the description
        if not description.LoadDescription(node.GetType()):
            return False

        # If there is no description for c4d.TESTSCALE, we create it. Otherwise we override it and set DESC_CYCLE with our extensions list.
        singleID = description.GetSingleDescID()
        paramID = c4d.DescID(c4d.TESTSCALE)
        if singleID is None or paramID.IsPartOf(singleID)[0]:
            bcParam = description.GetParameterI(c4d.TESTSCALE)

            items = c4d.BaseContainer()
            for i, extension in enumerate(self.extensions):
                items.SetString(i, extension)

            bcParam[c4d.DESC_CYCLE] = items

        return (True, flags | c4d.DESCFLAGS_DESC_LOADED)

    # Called when a parameter is Set
    def SetDParameter(self, node, id, t_data, flags):
        if not node:
            return

        # called when the filename is changed. We add the path to our list and we return c4d.DESCFLAGS_PARAM_SET to inform c4d the paramaters is just sets
        if id[0].id == c4d.STRINGTEST:
            self.extensions.append(t_data)
            return (True, flags | c4d.DESCFLAGS_PARAM_SET)

        return False

If you have any questions, please let me know!
Cheers,
Maxime.

Hi @FlavioDiniz, first of all, welcome in the plugincafe community!

Don't worry, since it's your first topic, I've set up your topic correctly. But please for your next topics, use the Q&A functionnaly, make sure to also read How to Post Questions.

With that's said you can find the manual about SetDParameter in the C++ docs which will be trigger each time a user changes a value in the description of your tag. And also the C++ manual about GetDDescription.
Here a quick example of the implementation in python

    extensions = ["exr","hdr","jpg","png"]

    # Called by C4D when loading description
    def GetDDescription(self, node, description, flags):
        data = node.GetDataInstance()
        if data is None:
            return False

        # Load the description
        if not description.LoadDescription(node.GetType()):
            return False

        # If there is no description for c4d.TESTSCALE, we create it. Otherwise we override it and set DESC_CYCLE with our extensions list.
        singleID = description.GetSingleDescID()
        paramID = c4d.DescID(c4d.TESTSCALE)
        if singleID is None or paramID.IsPartOf(singleID)[0]:
            bcParam = description.GetParameterI(c4d.TESTSCALE)

            items = c4d.BaseContainer()
            for i, extension in enumerate(self.extensions):
                items.SetString(i, extension)

            bcParam[c4d.DESC_CYCLE] = items

        return (True, flags | c4d.DESCFLAGS_DESC_LOADED)

    # Called when a parameter is Set
    def SetDParameter(self, node, id, t_data, flags):
        if not node:
            return

        # called when the filename is changed. We add the path to our list and we return c4d.DESCFLAGS_PARAM_SET to inform c4d the paramaters is just sets
        if id[0].id == c4d.STRINGTEST:
            self.extensions.append(t_data)
            return (True, flags | c4d.DESCFLAGS_PARAM_SET)

        return False

If you have any questions, please let me know!
Cheers,
Maxime.

hi @m_adam, thanks a lot for your answer!

I spent two days trying to implement the function in my code, but no success again :(
I think the problem now is more related to python than the C4D SDK,i'm not that experienced on it...

The error i'm getting is:
AttributeError: 'testplugin' object has no attribute 'hdrs'
alt text

hdrs is the list of strings (file paths), but seems that this list cannot be read by the GetDDescription function....
I've tried putting it as a global variable, also putting under testplugin class, under Execute, etc..
Tried putting the GetDDescription and SetDParameter as a inner function of Execute (I think this is wrong.. didn't give me errors, but updating the cycle doesn't work too haha).

Here's the structure of my plugin, I removed some irrelevant parts so we can focus better where the error is...
Do you think the structure is correct or am I missing something ?

the .res file is the same as in my first post.

import c4d
import os
import sys
from c4d import gui, plugins, bitmaps

PLUGIN_ID = 1000001
TESTSCALE = 1001
STRINGTEST = 1003

class testplugin(plugins.TagData):
    
    def Init(self, node):
        tag = node
        data = tag.GetDataInstance()
        FDWhite = c4d.Vector(1,1,1)
        data.SetBool(FDENABLEBG, True)
        data.SetInt32(FDSATURATION, 100)
        data.SetVector(FDTINT, FDWhite)
        data.SetInt32(FDSAMPLES, 64)

    def Execute(self, tag, doc, op, bt, priority, flags):
        datafilename = tag.GetDataInstance() #FD Folder path
        path = datafilename.GetFilename(STRINGTEST)

        extensions = ["exr","hdr"]
        hdrs = []
        if path != "":
            files = os.listdir(path)
            for names in files:
                ext = names.rsplit(".",1)
                if ext[1] in extensions:
                    hdrs.append(path+'\\'+names)

        return c4d.EXECUTIONRESULT_OK

    def GetDDescription(self, node, description, flags): # Called by C4D when loading description
        data2 = node.GetDataInstance()
        if data2 is None:
            return False

        if not description.LoadDescription(node.GetType()): # Load the description
            return False

        singleID = description.GetSingleDescID()
        paramID = c4d.DescID(c4d.TESTSCALE)
        if singleID is None or paramID.IsPartOf(singleID)[0]:
            bcParam = description.GetParameterI(c4d.TESTSCALE)

            items = c4d.BaseContainer()
            for i, hdrs in enumerate(self.hdrs):
                items.SetString(i, hdrs)

            bcParam[c4d.DESC_CYCLE] = items
        return (True, flags | c4d.DESCFLAGS_DESC_LOADED)

    
    def SetDParameter(self, node, id, t_data, flags): # Called when a parameter is Set
        if not node:
            return

        if id[0].id == c4d.STRINGTEST:
            self.hdrs.append(t_data)
            return (True, flags | c4d.DESCFLAGS_PARAM_SET)
        return False

if __name__ == "__main__":
    bmp = bitmaps.BaseBitmap()
    dir, file = os.path.split(__file__)
    bitmapfile = os.path.join(dir, "res", "icon.tif")
    result = bmp.InitWith(bitmapfile)
    plugins.RegisterTagPlugin(id=PLUGIN_ID, str="FD HDR", info=c4d.TAG_EXPRESSION|c4d.TAG_VISIBLE, g=testplugin, description="testplugin", icon=bmp)
    

thanks again :)

You have to declare hdrs as a member variable. See 9.3.5: https://docs.python.org/2/tutorial/classes.html