[Py4D] SubDialogs in ToolData plugins

THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

On 30/01/2012 at 08:24, xxxxxxxx wrote:

User Information:
Cinema 4D Version:    
Platform:      
Language(s) :

---------
When using a SubDialog to display a settings-dialog for a ToolData plugin, make sure to save the options somewhere while the user is changin them. As soon as the user selects another object/tag or alike, the options-dialog will disappear. This will cause any call's to GetReal, GetLong, etc. to freeze Cinema 4D. Actually, I had a long time to figure this out as it isn't any remark about this in the documentation.

Here is an example that easen's the use of a SubDialog:

  
import c4d  
import copy  
  
class PreparedSubDialog(c4d.gui.SubDialog) :  
  
  BASEDATA = dict()  
  data     = None  
  
  def __init__(self, data = None) :  
      if not data:  
          self.data = copy.deepcopy(self.BASEDATA)  
      elif isinstance(data, PreparedSubDialog) :  
          self.data = data.data  
      else:  
          self.data = data  
  
  def __getattr__(self, name) :  
      item = self.data.get(name, None)  
      if not item:  
          raise AttributeError('No such dialog-element %r.' %name)  
      id, type, value, min, max = item  
      return value  
  
  # ---- overwritten from ``c4d.gui.GeDialog`` -------------------------------  
  
  def InitValues(self) :  
      for name, (id, type, default, min, max) in self.data.iteritems() :  
          if type == 'str':  
              self.SetString(id, default)  
          elif type == 'm':  
              self.SetMeter(id, default, min, max)  
          elif type == 'p':  
              self.SetPercent(id, default, min, max)  
          elif type == 'b':  
              self.SetBool(id, default)  
          elif type == 'l':  
              self.SetLong(id, default, min, max)  
          elif type == 'r':  
              self.SetReal(id, default, min, max)  
          elif type == 'd':  
              self.SetDegree(id, default, min, max)  
          elif type == 't':  
              self.SetTime(id, default, min, max)  
          elif type == 'f':  
              self.SetFilename(id, default)  
          else:  
              raise ValueError('Unknown element-type %r.' % type)  
      return True  
  
  def Command(self, id, msg) :  
      # save the values  
      for name, v in self.data.iteritems() :  
          if v[0] == id:  
              v[2] = self.__getattr__(name)  
              break  
      return True

A possible subclass could look like this:

class MySubDialog(PreparedSubDialog) :  
  
  ID_MYREAL   = 1001  
  ID_MYSTRING = 1002  
  ID_MYMETER  = 1003  
  ID_MYBOOL   = 1004  
  
  BASEDATA    = dict( myreal   = [ID_MYREAL, 'r', 0, 0, 1000],  
                      mystring = [ID_MYSTRING, 's', 'String here', None, None],  
                      mymeter  = [ID_MYMETER, 'm', 100, -500, 500],  
                      mybool   = [ID_MYBOOL, 'b', True, None, None] )  
  
  def CreateLayout(self) :  
      self.AddStaticString(self.ID_MYSTRING, c4d.BFH_FIT)  
      self.AddEditNumberArrows(self.ID_MYREAL, c4d.BFH_FIT)  
      self.AddEditNumberArrows(self.ID_MYMETER, c4d.BFH_FIT)  
      self.AddCheckbox(self.ID_MYBOOL, c4d.BFH_FIT)

And used like this:

class MyToolPlugin(c4d.plugins.ToolData) :  
  
  dlg = None  
  
  def MouseInput(self, doc, data, bd, win, msg) :  
      myreal   = self.dlg.myreal  
      mystring = self.dlg.mystring  
      mymeter  = self.dlg.mymeter  
      mybool   = self.dlg.mybool  
  
      # ...  
  
  def AllocSubDialog(self, bc) :  
      self.dlg = MySubDialog(self.dlg)  
      return self.dlg

Any problems understanding the code? Ask. 🙂

Greetz, Niklas