Proud to announce the c4dtools library!

On 07/01/2013 at 09:25, xxxxxxxx wrote:


i am to lazzy to write a wall of text, so just a list:


1. return the results of the RegisterXyzData() methods in some form.

2. add a member which let you print some text to the console when RegisterXyzData() is True.

3. provide a reference to the actual instance of the registered plugin class.

Symbols :

1. it would be nice if the text length required to call a member of res would be shorter.
i am currently using a module which is just called con, where all my constants are sitting.
so it would be cool if it would be possible just to type res.IDC_MYELEMENTID.

2. i really like the feature that you can add manually constants. at least i am reading
string_2 = res.string.IDC_MYSTRING_2("Peter") in that way (or is it a dict search value) ?

3. another cool feature would be an automatic attribute initialization (InitAttr()) for ressource
based GUIs by parsing the res file and choosing the correct attribute type.

On 07/01/2013 at 10:18, xxxxxxxx wrote:

Hi Ferdinand,


@1: Don't get it.
@2: You can overwrite the register() method for this.

class MyCommand(c4dtools.plugins.Command) :
      # ...
     def register(self) :
          if super(MyCommand, self).register() :
              print "Plugin Successfully registered."
                return True
          return False

@3: You can prevent the class from being registered by c4dtools.plugins.main() and
register it yourself. This information is contained in the source-code inline documentation,

class MyCommand(c4dtools.plugins.Command) :
      # ...
      autoregister = False

instance = MyCommand()


@1: This is the way to access the symbols. You can of course call the variable whatever you
like, con as well of course.

con, importer = c4dtools.prepare(__file__)
    print con.IDC_MYSYMBOL

@2: The res.string slot points to a c4dtools.resource.StringLoader instance. Requesting an
attribute will return a callable object wrapping c4d.plugins.GeLoadString with the symbol-id
already set. Therefore, the returned callable object accepts 4 parameters (like the GeLoadString
function does, minus 1 because the id is already set).

@3: Don't get it. Do you mean calling a function for each symbol and instead of taking the symbols
id, taking the functions return value as value for the symbol?


On 07/01/2013 at 15:40, xxxxxxxx wrote:

Originally posted by xxxxxxxx

@3: Don't get it. Do you mean calling a function for each symbol and instead of taking the symbols
id, taking the functions return value as value for the symbol?

It would be a new functionality completely unrelated to the dialog ressource loading features.

res file :



class mynode(plugins.ObjectData) :
    def Init(self, node) :
        self.InitAttr(node, c4d.DateTimeData, c4d.STAGE_BUDGET)

what would be cool :

class mynode(plugins.ObjectData) :
    def Init(self, node) :
	# does the same as the example above
	res.InitAttributes(self, node, relatedRessourcFile)

On 08/01/2013 at 03:56, xxxxxxxx wrote:

Hello Ferdinand,

I did not know you were not referring to dialogs, but to descriptions. The current implementation
does not parse the description symbols as they are automatically loaded in to the c4d module.
Although it would not be a problem parsing the descriptions' symbol-files (*.h), it would be very
much work parsing the *.res files, which is required to get the information how to initialize the
attributes in the node.

PS: I know about the symbolcache issue.. Still not a reason for me to include the description
symbols in the res parser.


On 08/01/2013 at 08:25, xxxxxxxx wrote:

I admit that parsing the description symbols as well might be useful sometimes, but I don't
want it to be the default behavior. One can now optionally parse the description symbols. The
code has been committed to the development branch. See
The argument parse_descriptions must be set to True on c4dtools.prepare() for this.

Thanks for your feedback Ferdinand 😉


On 14/01/2013 at 06:56, xxxxxxxx wrote:

Hey Niklas, fantastic stuff as always. I don't have the time to look into it right now, but if it does what you say it should be a very handy timesaver in the future.
Thank you for sharing!

On 30/01/2013 at 04:08, xxxxxxxx wrote:

I like the initiative!
Do you have an overview / documentation of all functions in this library?

On 01/02/2013 at 09:48, xxxxxxxx wrote:

Hi pgroof,

I've added a Sphinx documentation to the repository. You can find it under docs/build/html.

I have also merged the development branch into the master branch, c4dtools is now on Version 1.0.1.


On 14/02/2013 at 06:48, xxxxxxxx wrote:

UPDATE: 1.1.0

The c4dtools library has been improved and is now licensed under the Simplified BSD License,
allowing it to be  used in commercial projects! The documentation has been updated as well and
is included in the repository.

Grab it from github!


On 22/03/2013 at 11:12, xxxxxxxx wrote:


The c4dtools library has been updated to 1.2.8. The new version includes some extremely cool new
features. The documentation has also been updated.

Some of the new features include:

  • Menu resource parser: Don't fuzz with GeDialog.MenuAddString(), ~MenuAddSeparator() etc. anymore! Easily create menu resource files, automatically enabling multilanguage support! (requires scan module) [c4dtools.resource.menuparser]
  • Dialog parameter manager: Store and restore values of parameters in dialogs! Retrieve and set dialog parameters in a comfortable and elegant way. (c4dtools.misc.dialog)
  • c4dtools.utils.AtomDict: Dictionary-like object. Enables to use c4d.C4DAtom objects to be used as dictionary keys!
  • Updated the c4dtools.utils.Importer class to behave correctly regarding to importing external dependencies. (see this post).
  • Polygon-normal alignment: Utility functions for finding normals facing into the wrong direction! (c4dtools.misc.normalalign)


Here's a small code-snippet that demonstrates using the c4dtools.misc.dialog module:

class MainDialog(c4d.gui.GeDialog) :
    # Must be a unique plugincafe identifier!
    ID_DATA = 1001204
    def __init__(self) :
        super(MainDialog, self).__init__()
        self.params = c4dtools.misc.dialog.DefaultParameterManager()
        # Initialize the Parameter Manager.
        p = self.params
        p.add('reset_axes', res.CHK_RESETAXES, 'b', True)
        p.add('optimize', res.CHK_OPTIMIZE, 'b', True)
        p.add('optimize_tolerance', res.EDT_OPTIMIZE_TOLERANCE, 'm', 0.01)
        p.add('set_phong_angle', res.CHK_SETPHONGANGLES, 'b', True)
        p.add('phong_angle', res.EDT_PHONGANGLE, 'd', math.radians(21))
        p.add('untri', res.CMB_UNTRIANGULATE, 'i', res.CMB_UNTRIANGULATE_NGONS)
    def InitValues(self) :
        # Load saved values.
        bc = c4d.plugins.GetWorldPluginData(self.ID_DATA)
        self.params.load_container(self, bc)
        return True
    def AskClose(self) :
        # Store the dialog values.
        params = getattr(self, 'params', None)
        if params:
            bc = params.to_container(self)
            c4d.plugins.SetWorldPluginData(self.ID_DATA, bc, False)
        # Close the dialog.
        return False


Since this module requires the scan module, it is not imported implcitly and the c4dtools library can safely be used without this dependency installed!

Here's a small code-snippet on how to use MENU resources:

res, imp = c4dtools.prepare(__file__, __res__)
class MyDialog(c4d.gui.GeDialog) :
    MENU_FILE = res.file('menu', '')
    RECENTS_START = 1000000
    def CreateLayout(self) :
        menu = c4dtools.resource.menuparser.parse_file(self.MENU_FILE)
        recents = menu.find_node(res.MENU_FILE_RECENTS)
        item_id = self.RECENTS_START
        for fn in get_recent_files() : # arbitrary function
            node = c4dtools.resource.menuparser.MenuItem(item_id, str(fn))
        # Render the menu on the dialog, passing the dialog itself
        # and the c4dtools resource.
        menu.render(self, res)
        # ...
        return True

The corresponding MENU resource looks like this:

# Write comments like in Python.
    --------------;         # Adds a separator.
    COMMAND COMMAND_ID;     # Uses GeDialog.MenuAddCommand().
    COMMAND 5159;           # Same here.
    # Create a sub-menu.
        # Will be filled programatically.
# More menus may follow ...

The symbols used in the menu resource must be defined in the res variable passed to the render() method.

Online Documentation

The c4dtools library now has an index in the Python Package Index and the 1.2.8 documentation is hosted online at

Edit: corrected example code