<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Topics tagged with s24]]></title><description><![CDATA[A list of topics that have been tagged with s24]]></description><link>http://developers.maxon.net/forum/tags/s24</link><generator>RSS for Node</generator><lastBuildDate>Mon, 11 May 2026 00:39:55 GMT</lastBuildDate><atom:link href="http://developers.maxon.net/forum/tags/s24.rss" rel="self" type="application/rss+xml"/><pubDate>Invalid Date</pubDate><ttl>60</ttl><item><title><![CDATA[Feedback on C4D Plugin – Mapping Textures to a Pixel Grid (Cinema 4D 2024 SDK)]]></title><description><![CDATA[Hey @Pheolix,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: How to Ask Questions.
About your First Question
Your code looks generally good, especially for someone who is starting out with the API you did really well. With that being said, I do not really understand what you want to do:

... plugin that maps and arranges textures onto a pixel grid. The goal is to make it easier to create voxel-style or Minecraft-like models by linking real-world units (e.g., centimeters) to pixels. (for example, 1 pixel = 6.25 cm)

A few pointers:

A CommandData plugin is the perfect choice when you want to manipulate the scene without any restrictions and are fine with always having to press a button run your logic. Scene element plugins, e.g., objects, tags, etc. on the other hand will carry out their logic on their own when a scene update is invoked. But they come with the restriction that their major payload functions (ObjectData::Execucte, ObjectData::GetVirtualObjects, TagData::Execute, etc.) run in their own threads (so that scene execution is parallelized) and therefore are subject to threading restrictions (I am aware that you are on C++, but the Python docs are better on this subject). So, for example, in a TagData::Execute you would not be allowed to allocate a new UVW tag on the object that is also hosting your plugin tag. But you could implement a button in the description of the tag, which when clicked cerates your setup (because TagData::Message runs on the main thread and you therefore are there allowed to add and remove scene data). With TagData:Execute you could then continuously update the UVW tag you are targeting on each scene update (changing parameter values of other scene elements is fine when tags are executed). This workflow is not necessarily better than a command, I am just showing you an option. Commands are also easier to implement for beginners than a scene element.
When you talk about units, you should be aware that both the object and texture coordinate system are unitless. What you see in edit fields, is just smoke and mirrors. We recently talked here about this subject.
You did get the major gist of our error handling but what you do with maxon::Failed is not quite correct. It is meant to test the return value of a Result&lt;T&gt; for having returned an error instance instead of T.  When you want to indicate an error, you must return an error, e.g.,:

// Not correct.
if (!doc || !selectedObject || !bitmap || !foundTag)
  return maxon::FAILED;T

// This is how one indicates that a function failed because something was a nullptr.
if (!doc || !selectedObject || !bitmap || !foundTag)
  return maxon::NullptrError(MAXON_SOURCE_LOCATION, "Could not get hold of scene data."_s);

// For a function which is of type Result&lt;void&gt;, its also totally fine to do this on an error. void functions
// can fail successfully, it is up to you to decide if an error is critical enough to halt execution of if you just
// want it to silently terminate. 
if (!doc || !selectedObject || !bitmap || !foundTag)
  return maxon::OK; // we are okay with failing here.

For details see Error handling and Error Types
Cheers,
Ferdinand
]]></description><link>http://developers.maxon.net/forum/topic/16333/feedback-on-c4d-plugin-mapping-textures-to-a-pixel-grid-cinema-4d-2024-sdk</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/16333/feedback-on-c4d-plugin-mapping-textures-to-a-pixel-grid-cinema-4d-2024-sdk</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Retrieve the current Unit and listen to changes]]></title><description><![CDATA[Hey @Cankar001,
Good to hear that you found your solution! One minor thing - you should avoid ApplicationOutput in production code, as it leads to console spam which we want to avoid in Cinema 4D. Using it in test code is fine. See Debug and Output Functions for alternatives.
An even better way to do what you did in your code would be to use error handling. E.g., your code could look like this:

// Your original function, I turned this into a function using our error system, indicated by the 
// Result&lt;T&gt; return type.
static maxon::Result&lt;maxon::Float&gt; GetCurrentUnitScale(const BaseDocument* const document)
{
    // The error scope handler for this function, i.e., all error returns exit through this handler.
    iferr_scope;

    // When there is no document, we return an error. When printed, this will then print the error 
    // message and the source code location, e.g., myfile.cpp:123.
    if (!document)
        return maxon::NullptrError(MAXON_SOURCE_LOCATION, "Invalid document pointer."_s);

    // Your code goes here.
    // ...
    return 1.0f;
}

// A function calling this function which does use error handling itself.
static maxon::Result&lt;void&gt; Foo(const BaseDocument* const document)
{
    iferr_scope;

    // Call the function and return, i.e., propagate the error upwards when there is one.
    const maxon::Float unitScale = GetCurrentUnitScale(document) iferr_return;

    // voids in the Result&lt;T&gt; return type are returned with maxon::OK.
    return maxon::OK;
}

// A function calling this function which does not use error handling itself, i.e., the error
// must terminate here.
static bool Bar(const BaseDocument* const document)
{
    // Here we use a manual scope handler to terminate the error chain. You have often to do this in
    // Cinema API (e.g., ObjectData::GetVirtualObjects), as methods there are not error handled 
    // opposed to the Maxon API.
    iferr_scope_handler
    {
        // Print a debug message with the passed in error #err and the name of this function. And
        // force a debugger to halt when some condition is met.
        WarningOutput("@ failed with error: @"_s, MAXON_FUNCTIONNAME, err);
        if (someErrorCondition)
            DebugStop();

        return false;
    };

    // Call the function (we still have to handle the error with an iferr_return), and then let it
    // terminate in our manual scope handler.
    const maxon::Float unitScale = GetCurrentUnitScale(document) iferr_return;

    return true;
}

Cheers,
Ferdinand
]]></description><link>http://developers.maxon.net/forum/topic/15902/retrieve-the-current-unit-and-listen-to-changes</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15902/retrieve-the-current-unit-and-listen-to-changes</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Making changes to the document through a websocket]]></title><description><![CDATA[@m_adam Thank you very much for your help in the last days! This worked as well as expected 
]]></description><link>http://developers.maxon.net/forum/topic/15886/making-changes-to-the-document-through-a-websocket</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15886/making-changes-to-the-document-through-a-websocket</guid><dc:creator><![CDATA[Cankar001]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[WebSocket usage in C++]]></title><description><![CDATA[Hi @m_adam, following your typescript example it worked now to connect! Thank you very much for your help 
Merry Christmas and a Happy New Year!
]]></description><link>http://developers.maxon.net/forum/topic/15883/websocket-usage-in-c</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15883/websocket-usage-in-c</guid><dc:creator><![CDATA[Cankar001]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Weight manager &#x2F; How create folder in weight manager]]></title><description><![CDATA[Hello @Hohlucha,
Welcome to the Maxon developers forum and its community, it is great to have you with us!
Getting Started
Before creating your next postings, we would recommend making yourself accustomed with our forum and support procedures. You did not do anything wrong, we point all new users to these rules.

Forum Overview: Provides a broad overview of the fundamental structure and rules of this forum, such as the purpose of the different sub-forums or the fact that we will ban users who engage in hate speech or harassment.
Support Procedures: Provides a more in detail overview of how we provide technical support for APIs here. This topic will tell you how to ask good questions and limits of our technical support.
Forum Features: Provides an overview of the technical features of this forum, such as Markdown markup or file uploads.

It is strongly recommended to read the first two topics carefully, especially the section Support Procedures: Asking Questions.
About your First Question
This is a development forum and your question does not seem to be development related. Please read our forum guidelines lined out above. I have moved this topic into General Talk for now. When this is indeed an end user question we must ask you to use our Support Center, the developer forum is not the right place for end user questions. When this is a development question, then please line out the current code you have and provide a meaningful problem description.
Cheers,
Ferdinand
]]></description><link>http://developers.maxon.net/forum/topic/15691/weight-manager-how-create-folder-in-weight-manager</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15691/weight-manager-how-create-folder-in-weight-manager</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Importing pythonapi from ctypes freezes C4D]]></title><description><![CDATA[Hey @lasselauch,
We are not able to reproduce this crash on an Intel, M1, or M3 MacBook with 2024.4.0. Please provide and submit a crash report when this  is still a problem for you. I would also recommend reinstalling Cinema 4D to rule out that your installation was damaged.
Cheers,
Ferdinand
]]></description><link>http://developers.maxon.net/forum/topic/15601/importing-pythonapi-from-ctypes-freezes-c4d</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15601/importing-pythonapi-from-ctypes-freezes-c4d</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Error compiling S24 plugin]]></title><description><![CDATA[Hey @Cankar001,
thank you for reaching out to us. It is great to hear that you found your solution! But I have troubles understanding all details of the rest of your question. However:

PluginStart ist just an alias for the plugin message C4DPL_INIT.
A Cinema 4D instance has various stages in its startup and teardown sequence, as expressed by the plugin messages C4DPL_MESSAGES (see also: Plugin Messages).
Through out the startup and teardown of Cinema 4D not all systems are available, as binaries/modules are loaded and unloaded and the systems associated with them are being pulled up and torn down.
In the end it depends a bit on what you tried to do concretely, but generally speaking, it could very well be that something is not yet "up" when C4DPL_INIT is emitted. But in general, most modules, registries, etc. should be accessible at this point (plugins are loaded after the core and unloaded before the core).

To get here a more precise answer, I would recommend opening a new topic with concrete code.
Cheers,
Ferdinand
]]></description><link>http://developers.maxon.net/forum/topic/15518/error-compiling-s24-plugin</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15518/error-compiling-s24-plugin</guid><dc:creator><![CDATA[ferdinand]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[How do I create a menu item on the home screen next to the buttons.]]></title><description><![CDATA[@i_mazlov , Do you speak Russian?
]]></description><link>http://developers.maxon.net/forum/topic/15412/how-do-i-create-a-menu-item-on-the-home-screen-next-to-the-buttons</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/15412/how-do-i-create-a-menu-item-on-the-home-screen-next-to-the-buttons</guid><dc:creator><![CDATA[Cheba Name]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Plugin works with R23 and doesn&#x27;t work with S24.]]></title><description><![CDATA[Got it. Thank you.
]]></description><link>http://developers.maxon.net/forum/topic/14221/plugin-works-with-r23-and-doesn-t-work-with-s24</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/14221/plugin-works-with-r23-and-doesn-t-work-with-s24</guid><dc:creator><![CDATA[kisaf]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Updating my r20 C++ plugins to r21 and up]]></title><description><![CDATA[@kbar, thank SO MUCH.
I will look into it.
]]></description><link>http://developers.maxon.net/forum/topic/14165/updating-my-r20-c-plugins-to-r21-and-up</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/14165/updating-my-r20-c-plugins-to-r21-and-up</guid><dc:creator><![CDATA[rui_mac]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Multi threading in C4D python]]></title><description><![CDATA[thanks Ferdinand this cleared things up for me
]]></description><link>http://developers.maxon.net/forum/topic/14075/multi-threading-in-c4d-python</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/14075/multi-threading-in-c4d-python</guid><dc:creator><![CDATA[anamate]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[How to add Button User Data with a Button GUI in python script?]]></title><description><![CDATA[It works like a charm!
Thanks a lot!
]]></description><link>http://developers.maxon.net/forum/topic/13902/how-to-add-button-user-data-with-a-button-gui-in-python-script</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13902/how-to-add-button-user-data-with-a-button-gui-in-python-script</guid><dc:creator><![CDATA[eZioPan]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Create custom menu category for nodes?]]></title><description><![CDATA[Hi,
Categories are also assets. You can use the CategoryAssetInterface to create a category asset.
and you can "parent" this category to another category using SetAssetCategory.
maxon::Result&lt;maxon::AssetDescription&gt; CreateCategoryAsset(
  const maxon::AssetRepositoryRef&amp; repository, const maxon::String&amp; name, 
  const maxon::Id&amp; category)
{
  iferr_scope;

  if (name.IsEmpty())
    return maxon::IllegalArgumentError(MAXON_SOURCE_LOCATION, "Invalid category name."_s);

  // Create and store a new category asset.
  maxon::CategoryAsset categoryAsset = maxon::CategoryAssetInterface::Create() iferr_return;
  maxon::Id	categoryId = maxon::AssetInterface::MakeUuid("category", false) iferr_return;
  maxon::AssetDescription assetDescription = repository.StoreAsset(
    categoryId, categoryAsset) iferr_return;

  // Set the category name.
  maxon::LanguageRef language = maxon::Resource::GetCurrentLanguage();
  assetDescription.StoreMetaString(maxon::OBJECT::BASE::NAME, name, language) iferr_return;

  // Set the category of the asset when the category is not the empty id.
  if (!category.IsEmpty())
  {
    maxon::CategoryAssetInterface::SetAssetCategory(assetDescription, category) iferr_return;
  }

  ApplicationOutput("Created category asset with the id: '@'", assetDescription.GetId());

  return assetDescription;
}


Cheers,
Manuel
]]></description><link>http://developers.maxon.net/forum/topic/13899/create-custom-menu-category-for-nodes</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13899/create-custom-menu-category-for-nodes</guid><dc:creator><![CDATA[Manuel]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Collapse&#x2F;Fold groups by default in nodegraph UI]]></title><description><![CDATA[This is already fixed now, but i can't say when the update will be available to public.
]]></description><link>http://developers.maxon.net/forum/topic/13898/collapse-fold-groups-by-default-in-nodegraph-ui</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13898/collapse-fold-groups-by-default-in-nodegraph-ui</guid><dc:creator><![CDATA[Manuel]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[PYTHONPATH not appended to sys.path in Cinema 4D 24]]></title><description><![CDATA[Excellent! Thanks you a lot
Regards,
]]></description><link>http://developers.maxon.net/forum/topic/13885/pythonpath-not-appended-to-sys-path-in-cinema-4d-24</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13885/pythonpath-not-appended-to-sys-path-in-cinema-4d-24</guid><dc:creator><![CDATA[f2b]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Unique ID for maxon::nodes::Node]]></title><description><![CDATA[Hello,
When translating the nodes in our system we need each of them to have a unique ID or name. That's how we identify each node, e.g if I have two or more texture nodes (with the same ID) used on different materials and assigned to different objects, it would only show one texture rendered to all objects as all textures are assigned one similar ID.
For now, I solved this by finding a uniqueID for the corresponding material and concatenating it with the node's ID.
As for the error message it only says Error and nothing more. I will send the text via email.
Thank you.
]]></description><link>http://developers.maxon.net/forum/topic/13884/unique-id-for-maxon-nodes-node</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13884/unique-id-for-maxon-nodes-node</guid><dc:creator><![CDATA[Ogers]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Bitmaps module missing from Auto Completion Dummy Package]]></title><description><![CDATA[Ok, thanks for the confirmation. Already fixed it manually myself.
]]></description><link>http://developers.maxon.net/forum/topic/13855/bitmaps-module-missing-from-auto-completion-dummy-package</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13855/bitmaps-module-missing-from-auto-completion-dummy-package</guid><dc:creator><![CDATA[heilei]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Layers checker]]></title><description><![CDATA[@mogh I didn't know about this function 
@ferdinand Thank you a lot for your detailed response. I will chek posts which you recommended
]]></description><link>http://developers.maxon.net/forum/topic/13824/layers-checker</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13824/layers-checker</guid><dc:creator><![CDATA[ROMAN]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[Invoke Parent Function inside &#x2F; outside class (TreeView)]]></title><description><![CDATA[     Thank You @ferdinand
Access an Enclosing Entity from a Subordinate Entity, was the solution I was searching for hence I needed to alter the GeDialog from inside the TreeViewFunctions. This seems to be the only solution hence these checkboxes belong to the treeview ?!?
Anyway its working and I am very happy 
User sets checkbox -&gt; Sum is calculated -&gt; button is activated.
I updated the example code (and removed the now unnecessary button to prevent further confusion) with the desired behavior for future readers.
kind regards
mogh
"""
Adapted from:
    https://developers.maxon.net/forum/topic/10654/14102_using-customgui-listview/2
"""
import c4d
import random
 
# Be sure to use a unique ID obtained from [URL-REMOVED]
PLUGIN_ID = 1000010  # TEST ID ONLY
 
# TreeView Column IDs.
ID_CHECKBOX = 1
ID_NAME = 2
ID_OTHER = 3
ID_LONGFILENAME = 4
MY_BUTON = 5
HOW_MANY = 6
ID_FILESIZE = 7
HOW_MANY_MB = 8
MY_CALC = 9

TREEVIEW = 99

# A tuple of characters to select from (a-z).
CHARACTERS = tuple( chr ( n) for n in range(97, 122))


class TextureObject(object):
    """
    Class which represent a texture, aka an Item in our list
    """
    def __init__(self):
        self.texturePath = TextureObject.RandomString(5, 10)
        self.otherData = TextureObject.RandomString(5, 20)
        self.longfilename = "-"
        self._selected = False
        self.filesize = TextureObject.RandomNumber()

    @staticmethod
    def RandomString(minLength, maxLength):
        """Returns a string of random characters with a length between 
        #minLength and #maxLength.

        The characters are taken from the 97 (a) to 122 (z) ASCII range.
        """
        return "".join(
            (random.choice(CHARACTERS) for _ in range(minLength, maxLength)))

    @staticmethod
    def RandomNumber():
        return random.randrange(1, 99)

    @property
    def IsSelected(self):
        return self._selected
 
    def Select(self):
        self._selected = True
 
    def Deselect(self):
        self._selected = False

    def __repr__(self):
        return str(self)
 
    def __str__(self):
        return self.texturePath
 
 
class ListView(c4d.gui.TreeViewFunctions):
 
    def __init__(self, host):
        """Initializes a ListView with a host.

        Args:
            host (c4d.gui.GeDialog): The hosting dialog.
        """
        # Add ten mock data texture objects.
        self.listOfTexture = [TextureObject() for _ in range(10)]
        if not isinstance(host, c4d.gui.GeDialog):
            raise TypeError("Expected {} for argument 'host'. Received: {}".format(c4d.gui.GeDialog, host))
        else:
            self._host = host

    def DoSomethingWithDialog(self):
        """Calls the dialog over the stored reference.
        """
        self._host.calc_selected()

    def IsResizeColAllowed(self, root, userdata, lColID):
        return True
 
    def IsTristate(self, root, userdata):
        return False
 
    def GetColumnWidth(self, root, userdata, obj, col, area):
        """Measures the width of cells.

        Although this function is called #GetColumnWidth and has a #col, it is
        not only executed by column but by cell. So, when there is a column
        with items requiring the width 5, 10, and 15, then there is no need
        for evaluating all items. Each item can return its ideal width and
        Cinema 4D will then pick the largest value.

        Args:
            root (any): The root node of the tree view.
            userdata (any): The user data of the tree view.
            obj (any): The item for the current cell.
            col (int): The index of the column #obj is contained in.
            area (GeUserArea): An already initialized GeUserArea to measure
             the width of strings.
        
        Returns:
            TYPE: Description
        """
        # The default width of a column is 80 units.
        width = 80
        # Replace the width with the text width. area is a prepopulated
        # user area which has already setup all the font stuff, we can
        # measure right away.

        if col == ID_NAME:
            return area.DrawGetTextWidth(obj.texturePath) + 5
        if col == ID_OTHER:
            return area.DrawGetTextWidth(obj.otherData) + 5
        if col == ID_LONGFILENAME:
            return area.DrawGetTextWidth(obj.longfilename) + 5
            
        return width

    def IsMoveColAllowed(self, root, userdata, lColID):
        # The user is allowed to move all columns.
        # TREEVIEW_MOVE_COLUMN must be set in the container of AddCustomGui.
        return True
 
    def GetFirst(self, root, userdata):
        """
        Return the first element in the hierarchy, or None if there is no element.
        """
        rValue = None if not self.listOfTexture else self.listOfTexture[0]
        return rValue
 
    def GetDown(self, root, userdata, obj):
        """
        Return a child of a node, since we only want a list, we return None everytime
        """
        return None
 
    def GetNext(self, root, userdata, obj):
        """
        Returns the next Object to display after arg:'obj'
        """
        rValue = None
        currentObjIndex = self.listOfTexture.index(obj)
        nextIndex = currentObjIndex + 1
        if nextIndex &lt; len(self.listOfTexture):
            rValue = self.listOfTexture[nextIndex]
 
        return rValue
 
    def GetPred(self, root, userdata, obj):
        """
        Returns the previous Object to display before arg:'obj'
        """
        rValue = None
        currentObjIndex = self.listOfTexture.index(obj)
        predIndex = currentObjIndex - 1
        if 0 &lt;= predIndex &lt; len(self.listOfTexture):
            rValue = self.listOfTexture[predIndex]
 
        return rValue
 
    def GetId(self, root, userdata, obj):
        """
        Return a unique ID for the element in the TreeView.
        """
        return hash(obj)
 
    def Select(self, root, userdata, obj, mode):
        """
        Called when the user selects an element.
        """
        # I only use the checkbox to select list elemenmts
        """
        if mode == c4d.SELECTION_NEW:
            for tex in self.listOfTexture:
                tex.Deselect()
            obj.Select()
        elif mode == c4d.SELECTION_ADD:
            obj.Select()
        elif mode == c4d.SELECTION_SUB:
            obj.Deselect()
        """

    def IsSelected(self, root, userdata, obj):
        """
        Returns: True if *obj* is selected, False if not.
        """
        return obj.IsSelected
 
    def SetCheck(self, root, userdata, obj, column, checked, msg):
        """
        Called when the user clicks on a checkbox for an object in a
        `c4d.LV_CHECKBOX` column.
        """
        if checked:
            obj.Select()
        else:
            obj.Deselect()

        self.DoSomethingWithDialog()

 
    def IsChecked(self, root, userdata, obj, column):
        """
        Returns: (int): Status of the checkbox in the specified *column* for *obj*.
        """
        if obj.IsSelected:
            return c4d.LV_CHECKBOX_CHECKED | c4d.LV_CHECKBOX_ENABLED
        else:
            return c4d.LV_CHECKBOX_ENABLED
 
    def GetName(self, root, userdata, obj):
        """
        Returns the name to display for arg:'obj', only called for column of type LV_TREE
        """
        return str(obj)  # Or obj.texturePath
 
    def DrawCell(self, root, userdata, obj, col, drawinfo, bgColor):
        """
        Draw into a Cell, only called for column of type LV_USER
        """
        if col in (ID_OTHER, ID_LONGFILENAME):
            text = obj.otherData if col == ID_OTHER else obj.longfilename
            canvas = drawinfo["frame"]
            textWidth = canvas.DrawGetTextWidth(text)
            textHeight = canvas.DrawGetFontHeight()
            xpos = drawinfo["xpos"]
            ypos = drawinfo["ypos"] + drawinfo["height"]

            if (drawinfo["width"] &lt; textWidth):
                while (drawinfo["width"] &lt; textWidth):
                    if len(text) &lt;= 4:
                        text = "..."
                        break
                    text = text[:-4] + "..."
                    textWidth = canvas.DrawGetTextWidth(text)

            textWidth = canvas.DrawGetTextWidth(text)
            drawinfo["frame"].DrawText(text, xpos, ypos - int(textHeight * 1.1))

        if col == ID_FILESIZE:
            text = obj.filesize
            canvas = drawinfo["frame"]
            # w = geUserArea.DrawGetTextWidth(name)
            h = canvas.DrawGetFontHeight()
            # xpos = drawinfo["xpos"] + 10
            xpos = drawinfo["xpos"] + drawinfo["width"] - canvas.DrawGetTextWidth(text)
            ypos = drawinfo["ypos"] + drawinfo["height"]
            drawinfo["frame"].DrawText(text, xpos, ypos - int(h * 1.1))

    def DoubleClick(self, root, userdata, obj, col, mouseinfo):
        """
        Called when the user double-clicks on an entry in the TreeView.
 
        Returns:
          (bool): True if the double-click was handled, False if the
            default action should kick in. The default action will invoke
            the rename procedure for the object, causing `SetName()` to be
            called.
        """
        c4d.gui.MessageDialog("You clicked on " + str(obj))
        return True
 
    def DeletePressed(self, root, userdata):
        "Called when a delete event is received."
        for tex in reversed(self.listOfTexture):
            if tex.IsSelected:
                self.listOfTexture.remove(tex)


class TestDialog(c4d.gui.GeDialog):
    _treegui = None  # Our CustomGui TreeView
    # _listView = ListView()  # Our Instance of c4d.gui.TreeViewFunctions

    def __init__(self):
        """
        """
        # Create an instance of ListView and give it access to the dialog
        # which carries it.
        self._listView = ListView(host=self)
        self.overall = len(self._listView.listOfTexture)

    def CreateLayout(self):
        # Create the TreeView GUI.
        customgui = c4d.BaseContainer()
        customgui.SetBool(c4d.TREEVIEW_BORDER, c4d.BORDER_THIN_IN)
        customgui.SetBool(c4d.TREEVIEW_HAS_HEADER, True)  # True if the tree view may have a header line.
        customgui.SetBool(c4d.TREEVIEW_HIDE_LINES, True)  # True if no lines should be drawn.
        customgui.SetBool(c4d.TREEVIEW_MOVE_COLUMN, True)  # True if the user can move the columns.
        customgui.SetBool(c4d.TREEVIEW_RESIZE_HEADER, True)  # True if the column width can be changed by the user.
        customgui.SetBool(c4d.TREEVIEW_FIXED_LAYOUT, True)  # True if all lines have the same height.
        customgui.SetBool(c4d.TREEVIEW_ALTERNATE_BG, True)  # Alternate background per line.
        customgui.SetBool(c4d.TREEVIEW_CURSORKEYS, True)  # True if cursor keys should be processed.
        customgui.SetBool(c4d.TREEVIEW_NOENTERRENAME, False)  # Suppresses the rename popup when the user presses enter.

        if self.GroupBegin(id=1000, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=2, cols=1, groupflags=c4d.BORDER_OUT):
            self.GroupBorderSpace(left=5, top=5, right=5, bottom=5)
            self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)

            if self.GroupBegin(id=1001, flags=c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)
                self._treegui = self.AddCustomGui(TREEVIEW, c4d.CUSTOMGUI_TREEVIEW, "", c4d.BFH_SCALEFIT | c4d.BFV_SCALEFIT, minw=430, minh=160, customdata=customgui)
                if not self._treegui:
                    print("[ERROR]: Could not create TreeView")
                    return False
                self.GroupEnd()

            if self.GroupBegin(id=1002, flags=c4d.BFH_FIT | c4d.BFV_FIT, rows=2, cols=3, groupflags=c4d.BORDER_OUT):
                self.GroupBorderNoTitle(borderstyle=c4d.BORDER_NONE)

                self.AddStaticText(HOW_MANY, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Selected: 0 / " + str(self.overall))
                self.AddStaticText(HOW_MANY_MB, flags=c4d.BFV_CENTER | c4d.BFV_SCALE | c4d.BFH_LEFT | c4d.BFH_SCALE, name="Filesize Sum: __________")
                self.AddButton(MY_BUTON, c4d.BFH_CENTER, name="Enable me by check-boxing")
                self.Enable(MY_BUTON, False)
                self.GroupEnd()

            self.GroupEnd()

        return True

    def calc_selected(self):
        """this is a helper to calculate the selected elements and to enable the button

        :return: # slected and sum of the selecteed filsize
        """
        selected = 0
        filsizesum = 0
        self.overall = len(self._listView.listOfTexture)  # update our count

        for fileitem in self._listView.listOfTexture:
            if fileitem.IsSelected is True:
                filsizesum += fileitem.filesize
                selected += 1

        if selected &gt; 0:
            self.Enable(MY_BUTON, True)
        else:
            self.Enable(MY_BUTON, False)

        sel_string = "Selected: " + str(selected) + " / " + str(self.overall)
        self.SetString(HOW_MANY, sel_string)

        mb_string = "Filesize Sum: " + str(filsizesum)
        self.SetString(HOW_MANY_MB, mb_string)

        return selected, filsizesum

    def InitValues(self):
        # Initialize the column layout for the TreeView.
        layout = c4d.BaseContainer()
        layout.SetLong(ID_CHECKBOX, c4d.LV_CHECKBOX)
        layout.SetLong(ID_NAME, c4d.LV_TREE)
        layout.SetLong(ID_LONGFILENAME, c4d.LV_USER)
        layout.SetLong(ID_OTHER, c4d.LV_USER)
        layout.SetLong(ID_FILESIZE, c4d.LV_USER)
        self._layout = layout
        self._treegui.SetLayout(5, layout)
 
        # Set the header titles.
        self._treegui.SetHeaderText(ID_CHECKBOX, "Check")
        self._treegui.SetHeaderText(ID_NAME, "Name")
        self._treegui.SetHeaderText(ID_LONGFILENAME, "Long Filename")
        self._treegui.SetHeaderText(ID_OTHER, "Other")
        self._treegui.SetHeaderText(ID_FILESIZE, "Filesize")

        self._treegui.Refresh()
 
        # Set TreeViewFunctions instance used by our CUSTOMGUI_TREEVIEW
        self._treegui.SetRoot(self._treegui, self._listView, None)

        return True
 
    def Command(self, id, msg):
        # Click on button
        if id == MY_BUTON:
            newID = int(len(self._listView.listOfTexture) + 1)
            tex = TextureObject()
            tex.texturePath = "Some new data " + str(newID)
            tex.longfilename = TextureObject.RandomString(20, 40)
            self._listView.listOfTexture.append(tex)
            self.calc_selected()
            self._treegui.Refresh()

        return True

 
class MenuCommand(c4d.plugins.CommandData):
    dialog = None
 
    def Execute(self, doc):
        if self.dialog is None:
            self.dialog = TestDialog()
        return self.dialog.Open(c4d.DLG_TYPE_ASYNC, PLUGIN_ID, defaulth=300, defaultw=430)
 
    def RestoreLayout(self, sec_ref):
        if self.dialog is None:
            self.dialog = TestDialog()
        return self.dialog.Restore(PLUGIN_ID, secret=sec_ref)
 
 
def main():
    c4d.plugins.RegisterCommandPlugin(
        PLUGIN_ID, "Python TreeView Example", 0, None, "Python TreeView Example", MenuCommand())


if __name__ == "__main__":
    main()



[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
]]></description><link>http://developers.maxon.net/forum/topic/13817/invoke-parent-function-inside-outside-class-treeview</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13817/invoke-parent-function-inside-outside-class-treeview</guid><dc:creator><![CDATA[mogh]]></dc:creator><pubDate>Invalid Date</pubDate></item><item><title><![CDATA[particle direction driven by texture]]></title><description><![CDATA[Thank you alot Ferdinand for your time, thoughs and help.
I really appreciate that:)'
I will get my head in it and try to figure it out.
]]></description><link>http://developers.maxon.net/forum/topic/13798/particle-direction-driven-by-texture</link><guid isPermaLink="true">http://developers.maxon.net/forum/topic/13798/particle-direction-driven-by-texture</guid><dc:creator><![CDATA[Hannes Weikert]]></dc:creator><pubDate>Invalid Date</pubDate></item></channel></rss>