PreferenceData plugin, Text disappears when directory is set



  • Hello everyone,

    I am having this problem that when I try to use a Filename parameter to get the path of a directory,

    It either, in case I don't override the GetDParameter and SetDParameter functions does not save the path,
    or, in case I do override these functions and set and get the plugin container myself, the path text in the UI disappears.

    If someone can have a look I will greatly appreciate it. I created a self contained project illustrating the problem. Just unzip it in the plugins folder and it should work.

    I am also going to go ahead and paste the python code here, in case some one can find something just by looking at the code, there is also of course accompanying resource files that are included in the zip file.

    Thank you,
    Alamgir Nasir

    import c4d
    
    PREFERENCE_PLUGIN_ID = 1040402
    PREFERENCE_RENDER_PATH = 1000
    def GetPreferenceContainer():
      world = c4d.GetWorldContainerInstance()
      if world is None:
        return None
    
      bc = world.GetContainerInstance(PREFERENCE_PLUGIN_ID)
      if bc is None:
        world.SetContainer(PREFERENCE_PLUGIN_ID, c4d.BaseContainer())
        bc = world.GetContainerInstance(PREFERENCE_PLUGIN_ID)
        if bc is None:
          return None
    
      return bc
    
    class TestPreference(c4d.plugins.PreferenceData):
    
      def GetDParameter(self, node, id, flags):
        bc = GetPreferenceContainer()
        if bc is None:
          return False
    
        # Retrieves either check or number preference value
        paramID = id[0].id
        if paramID == PREFERENCE_RENDER_PATH:
          return (True, bc.GetFilename(PREFERENCE_RENDER_PATH), flags | c4d.DESCFLAGS_GET_PARAM_GET)
        return False
    
      def SetDParameter(self, node, id, data, flags):
        bc = GetPreferenceContainer()
        if bc is None:
          logger.error("SetDParameter: bc is none.")
          return False
    
        # Changes either check or number preference value
        paramID = id[0].id
        if paramID == PREFERENCE_RENDER_PATH:
          bc.SetFilename(PREFERENCE_RENDER_PATH, data)
          return (True, flags | c4d.DESCFLAGS_SET_PARAM_SET)
        return False
    
      def Register(self):
        print("Registered test preferences")
        return c4d.plugins.RegisterPreferencePlugin(
          id=PREFERENCE_PLUGIN_ID, g=TestPreference, name="TEST",
          description="testpreference", parentid=0, sortid=0)
    
    TestPreference().Register()
    


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

    Regarding the issue, as you may know, in Python there is no Filename object. So when you call

    return (True, bc.GetFilename(PREFERENCE_RENDER_PATH), flags | c4d.DESCFLAGS_GET_PARAM_GET)
    

    bc.GetFilename(PREFERENCE_RENDER_PATH) returns str, so it set a string as a parameter while the description expects a Filename.

    To do so simply replace by GetCustomDataType (note it will print an error, but it's actually working, so you will need a try/except block. But I will investigate the error and fix it for a future release).

    Then with that's said your GetPreferenceContainer is actually wrong. I replaced it with GetContainer.
    Here the full code working

    import c4d
    
    PREFERENCE_PLUGIN_ID = 1040402
    PREFERENCE_RENDER_PATH = 1000
    
    def GetContainer(node=None):
      bc = None
      if node is None:
        plug = c4d.plugins.FindPlugin(PREFERENCE_PLUGIN_ID, c4d.PLUGINTYPE_PREFS)
        if plug is None:
            return
        bc = plug.GetDataInstance()
      
      else:
        bc = node.GetDataInstance()
    
      return bc
    
    class TestPreference(c4d.plugins.PreferenceData):
    
      def GetDParameter(self, node, id, flags):
        bc = GetContainer(node)
        if bc is None:
          return False
    
        # Retrieves either check or number preference value
        paramID = id[0].id
        if paramID == PREFERENCE_RENDER_PATH:
          try:
            return (True, bc.GetCustomDataType(PREFERENCE_RENDER_PATH), flags | c4d.DESCFLAGS_GET_PARAM_GET)
          except:
            return False
        return False
    
      def SetDParameter(self, node, id, data, flags):
        bc = GetContainer()
        if bc is None:
          print ("SetDParameter: bc is none.")
          return False
    
        # Changes either check or number preference value
        paramID = id[0].id
        if paramID == PREFERENCE_RENDER_PATH:
          bc.SetFilename(PREFERENCE_RENDER_PATH, data)
          return (True, flags | c4d.DESCFLAGS_SET_PARAM_SET)
        return False
    
      def Register(self):
        print("Registered test preferences")
        return c4d.plugins.RegisterPreferencePlugin(
          id=PREFERENCE_PLUGIN_ID, g=TestPreference, name="TEST",
          description="testpreference", parentid=0, sortid=0)
    
    TestPreference().Register()
    

    I will add a note in the documentation about Filename.

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



  • Thank you for your help @m_adam, but I am still having the same problem.

    Using GetCustomDataType doesn't give me any errors but it doesn't work either. It still clears the string immediately after I set the field.

    It does seem like the problem is still with the GetDParameter, because if I comment it out everything works except that the filename isn't loaded when cinema is restarted.



  • Hi @potashalum did you update your GetPreferenceContainer function as well?

    By copy/pasting the code provided you also get the issue?
    Cheers,
    Maxime.



  • Hi @m_adam,

    I updated the GetPreferenceContainer function as well, it did help in that the SetDParameter function works now, which didn't before. So that is definitely better. But the GetDParameter function didn't work, even if I only use your code.

    Could it be a problem in the res files? Would you mind taking a look please. I tried my best to get those right but maybe I still have an error there.

    Regards,
    Alamgir



  • Hi @potashalum, I'm terribly sorry I missed your reply when I came back from holiday.

    After digging more into this, it's currently not possible to handle Filename from python in GetDParameter of a world preference.
    A workaround would be to store parameter as a string, display a string instead of a FileName and make a button to define this string parameter.

    Cheers,
    Maxime.



  • Hi @m_adam,

    No problem, I hope you had great holidays and thank you for confirming the problem.

    Regards,
    Alamgir