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 ? 😄


  • Global Moderator

    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