Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Add/Remove Groups of User Data

    Cinema 4D SDK
    python
    3
    12
    2.7k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • mrittmanM
      mrittman
      last edited by mrittman

      I've set up a user data interface, and would like to be able to click the add/remove buttons at the top, which would create additional tracks. Is this possible, or would one need to resort to C++ for this kind of behavior?
      user data.png

      For clarification, I am trying to do the Add/Remove behavior similar to how Constraint tags work:
      constraint.png

      1 Reply Last reply Reply Quote 0
      • ManuelM
        Manuel
        last edited by

        Hello,

        we need a bit more informations regarding where you are trying to create this UI :

        Are you writing your code in a python tag, a python generator or a python plugin ?

        Cheers

        MAXON SDK Specialist

        MAXON Registered Developer

        mrittmanM 1 Reply Last reply Reply Quote 0
        • mrittmanM
          mrittman @Manuel
          last edited by

          @m_magalhaes I am writing it in a python tag.

          I should note that when it comes to programming, I’m not all that smart 😛

          1 Reply Last reply Reply Quote 0
          • ManuelM
            Manuel
            last edited by Manuel

            Hello,

            After some research in the forum, i've found this post that show how to react to a button pressed.

            With that, it juste a matter of using AddUserData and his friend RemoveUserData

            Let me try to explain a bit more what i've done.
            In the UserData tab, i've a got a group that will be used as a container, so i can add or remove thing inside without touching other userdata. I just browse through all user data using GetUserDataContainer and check the parent of the fields with DESC_PARENTGROUP

            I'm pretty sure you will go through this code easily but if you got any questions, feel free to ask.

            i'm adding the file so you can play with the code directly
            AddRemoveGroup.c4d

            And the code. At the top, i've got the ID of both button and the group that will serve as a container.

            import c4d
            
            
            # the group id where all the fiels will be created.
            addButtonID = 1
            removeButtonID = 2
            mainGroupID  = 3
            
            
            
            def AddGroupOfUserData():
                """
                Creating the group with differents field.
                Called by button Add
                """
                obj = op.GetObject() # get the object where we want the user data
                parentGroup = obj.GetUserDataContainer()[mainGroupID][0]
                newGroup = CreateGroup(parentGroup)
            
                nameString = AddString(newGroup, "Name")
                check = AddBool (newGroup, "Use Sound")
                timeField = AddTime(newGroup, "StartTime")
                AddSoundPath(newGroup, "Sound")
                
                #as function are returning the id of the userdata we can change their value
                obj[nameString] = "Default value for the string"
                #Set the bool to tru by default
                obj[check] = True
                #set the time to 0 
                obj[timeField] = c4d.BaseTime(0)
            
            def RemoveGroupOfUserData():
                """
                this will iterate trough all group and remove the last one
                including his children
                """
                obj = op.GetObject() # get the object where we want the user data
                lastGroupID, count = GetLastGroupID()
            
            
                if lastGroupID > -1:
                    # we find a group so let remove all the child of that group we found
                    for descID, bc in op.GetObject().GetUserDataContainer():
            
                        if IsChildOfGroup(bc, lastGroupID):
                           obj.RemoveUserData(descID)
                           del(obj[descID]) #remove the information in the basecontainer
            
                    obj.RemoveUserData(lastGroupID)
                    del(obj[lastGroupID])
                    obj.Message(c4d.MSG_UPDATE)
            
            
            def IsChildOfGroup(bc, groupID = mainGroupID):
                """
                Check if the parent is the same id of groupID
                """
                if bc[c4d.DESC_PARENTGROUP].GetDepth() > 1:
                    if bc[c4d.DESC_PARENTGROUP][1].id == groupID:
                        return True
                return False
            
            
            def GetLastGroupID(parent = None):
                """
                get the last group in the user data
                """
                groupID = -1
                count = 0
                for descID, bc in op.GetObject().GetUserDataContainer():
                    if descID[1].dtype == c4d.DTYPE_GROUP:
                        if IsChildOfGroup(bc):
                                count += 1
                                groupID = descID[1].id
            
                return groupID, count
            
            
            def CreateGroup(parent, trackNumber = -1):
                """
                this will create a group in the user data below "myGroup" with all the different data needed
                """
                if trackNumber < 0:
                    # we must calculate the track number
                    lastGroupID, trackNumber = GetLastGroupID()
            
                #Get the default container for the group type
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_GROUP)
                longName  = "Track " + str(trackNumber)
                shortName = "Track"  + str(trackNumber)
            
                bc[c4d.DESC_NAME] = longName
                bc[c4d.DESC_SHORT_NAME] = shortName
                bc[c4d.DESC_TITLEBAR] = True
                bc[c4d.DESC_GUIOPEN] = False
                bc[c4d.DESC_PARENTGROUP] = parent
                #return the group id added so we can add other element to it
                return op.GetObject().AddUserData(bc)
            
            
            
            def AddBool (group, name):
                """
                this will create a boolean gadget in the group
                """
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_BOOL)
                bc[c4d.DESC_NAME] = name
                bc[c4d.DESC_SHORT_NAME] = name
                bc[c4d.DESC_PARENTGROUP] = group
                return op.GetObject().AddUserData(bc)
            
            
            def AddTime(group, name):
                """
                this will add the field start time for exemple
                """
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_TIME)
                bc[c4d.DESC_NAME] = name
                bc[c4d.DESC_SHORT_NAME] = name
                #bc[c4d.DESC_UNIT] = c4d.DESC_UNIT_TIME
                bc[c4d.DESC_PARENTGROUP] = group
                return op.GetObject().AddUserData(bc)
            
            def AddSoundPath(group, name):
                """
                this will add the field for file
                """
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_FILENAME)
                bc[c4d.DESC_NAME] = name
                bc[c4d.DESC_SHORT_NAME] = name
                bc[c4d.DESC_PARENTGROUP] = group
                return op.GetObject().AddUserData(bc)
            
            
            def AddString(group, name):
                """
                this will add a static string to a group
                """
                bc = c4d.GetCustomDatatypeDefault(c4d.DTYPE_STATICTEXT)
                bc[c4d.DESC_NAME] = name
                bc[c4d.DESC_SHORT_NAME] = name
                #bc[c4d.DESC_CUSTOMGUI] = c4d.CUSTOMGUI_STATICTEXT
                bc[c4d.DESC_PARENTGROUP] = group
                return op.GetObject().AddUserData(bc)
            
            
            
            def message(msg_type, data) :
                if msg_type == c4d.MSG_NOTIFY_EVENT:
                    event_data = data['event_data']
                    if event_data['msg_id'] == c4d.MSG_DESCRIPTION_COMMAND:
                        desc_id = event_data['msg_data']['id']
                        if desc_id[1].id == addButtonID:
                            AddGroupOfUserData()
                        elif desc_id[1].id == removeButtonID:
                            RemoveGroupOfUserData()
                            
            
            
            def main() :
                pass
            

            MAXON SDK Specialist

            MAXON Registered Developer

            1 Reply Last reply Reply Quote 4
            • ManuelM
              Manuel
              last edited by

              hello,

              if you don't have anything else to add, i'll mark this topic as "solved"

              Cheers
              Manuel

              MAXON SDK Specialist

              MAXON Registered Developer

              mrittmanM 1 Reply Last reply Reply Quote 0
              • mrittmanM
                mrittman @Manuel
                last edited by

                @m_magalhaes Hey man I'm so sorry I didn't see your reply! This was extremely helpful! Pretty much exactly what I was looking for.

                Do you know if this can be converted to a Python script so that I can drop it into any project?

                1 Reply Last reply Reply Quote 0
                • ManuelM
                  Manuel
                  last edited by

                  hello,

                  you can surely create a script that will put in place the user data and the python tag (+ his code)

                  But it's likely what a plugin tagData could do also.

                  So you could just attach a tag to an object.

                  MAXON SDK Specialist

                  MAXON Registered Developer

                  mrittmanM 1 Reply Last reply Reply Quote 0
                  • mrittmanM
                    mrittman @Manuel
                    last edited by

                    @m_magalhaes I see, but how do you create a script that generates a python tag with that code already in it?

                    ferdinandF 1 Reply Last reply Reply Quote 0
                    • ferdinandF
                      ferdinand @mrittman
                      last edited by ferdinand

                      @mrittman said in Add/Remove Groups of User Data:

                      @m_magalhaes I see, but how do you create a script that generates a python tag with that code already in it?

                      I think @m_magalhaes was referring to plugins.TagData the base class for python plugins that implement a tag. This is different from the Python Scripting Tag as it appears in the C4D desktop application. For your question: Yes it possible, but I am not sure if things are what you expect them to be. Building dynamic interfaces is always quite a hassle and Cinema4D is certainty no exception to that rule.

                      The first bit of information is that the Python Scripting Tag also supports implementing a message function which will allow you to listen for button clicks. The second piece would be that c4d.BaseList2D implements methods for adding and removing user data. Here is a short snippet which shows how to manipulate user data sitting on a Python Scripting Tag with that tags python code:

                      import c4d
                      #Welcome to the world of Python
                      
                      
                      def main():
                          pass  #put in your code here
                      
                      def message(mid, data):
                          """
                          """
                          # Check if the message data contain a UserData event
                          if isinstance(data, dict) and "id" in data:
                              if data["id"][0].id == c4d.ID_USERDATA:
                      
                                  # Here you have to check for the ID of the Add/Remove button IDs as they appear in
                                  # your user data editor. For me it was the IDs 1(Add) and 2(Remove).
                      
                                  # Add button adds a UserData element to the tag. Code as in SDK example code of
                                  # BaseList2D.AddUserData().
                                  if data["id"][1].id == 1:
                                      bc = c4d.GetCustomDataTypeDefault(c4d.DTYPE_LONG) # Create default container
                                      bc[c4d.DESC_NAME] = "Test"                        # Rename the entry
                                      element = op.AddUserData(bc)                      # Add userdata container
                                      op[element] = 30                                  # Assign a value
                                      c4d.EventAdd()                                    # Update
                      
                                  # Remove button removes the last element of your user data. For details see
                                  # BaseList2D.RemoveUserData() int the SDK.
                                  elif data["id"][1].id == 2:
                                      _desc_id_last_item = op.GetUserDataContainer()[-1][0]
                                      op.RemoveUserData(_desc_id_last_item)
                                      c4d.EventAdd()
                      

                      Cheers,
                      zipit

                      MAXON SDK Specialist
                      developers.maxon.net

                      mrittmanM 1 Reply Last reply Reply Quote 0
                      • mrittmanM
                        mrittman @ferdinand
                        last edited by

                        @zipit Thanks so much man, this is really quite helpful! I sure appreciate all the help!

                        1 Reply Last reply Reply Quote 0
                        • ManuelM
                          Manuel
                          last edited by

                          Hello,

                          I was also talking about something like this. But it's not the best way to go. I suggest a TagData (plugin) with his own UI.

                          pyTagCode = '\
                          import c4d \n\
                          #Welcome to the world of Python \n\
                          \n\
                          def main():\n\
                              print "this ia a message"\n\
                          \n\
                          '
                          
                          
                          
                          import c4d
                          
                          # Main function
                          def main():
                              if op is None:
                                  gui.MessageDialog("Please selecte a target object")
                              tag = c4d.BaseTag(c4d.Tpython)
                              tag[c4d.TPYTHON_CODE] = pyTagCode
                              op.InsertTag(tag)
                              c4d.EventAdd()   
                          
                          # Execute main()
                          if __name__=='__main__':
                              main()
                          

                          By the way, don't forget you can save tag presets, that include python tags. You can simple add them with right click on your object in OM and "Load tag preset"

                          Cheers,
                          Manuel

                          MAXON SDK Specialist

                          MAXON Registered Developer

                          mrittmanM 1 Reply Last reply Reply Quote 0
                          • mrittmanM
                            mrittman @Manuel
                            last edited by

                            @m_magalhaes said in Add/Remove Groups of User Data:

                            Hello,

                            I was also talking about something like this. But it's not the best way to go. I suggest a TagData (plugin) with his own UI.

                            pyTagCode = '\
                            import c4d \n\
                            #Welcome to the world of Python \n\
                            \n\
                            def main():\n\
                                print "this ia a message"\n\
                            \n\
                            '
                            
                            
                            
                            import c4d
                            
                            # Main function
                            def main():
                                if op is None:
                                    gui.MessageDialog("Please selecte a target object")
                                tag = c4d.BaseTag(c4d.Tpython)
                                tag[c4d.TPYTHON_CODE] = pyTagCode
                                op.InsertTag(tag)
                                c4d.EventAdd()   
                            
                            # Execute main()
                            if __name__=='__main__':
                                main()
                            

                            By the way, don't forget you can save tag presets, that include python tags. You can simple add them with right click on your object in OM and "Load tag preset"

                            Cheers,
                            Manuel

                            Oh this is good to know! Thanks so much for the information, this is quite helpful!

                            Matt

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post