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
    • Login

    ShowPopupDialog in SceneLoaderData

    Cinema 4D SDK
    s26 python
    3
    6
    982
    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.
    • K
      kalugin
      last edited by

      Hi. I have a sceneloader plugin that shows a popup menu in it's Load function. Until S26 it was working fine, but in S26 I get the following error when I call it:

      result = gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS)
      RuntimeError:must be called from the main thread
      

      I guess this has something to do with the new task management system, but how can approach this issue?
      Thanks.

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

        This post is deleted!
        1 Reply Last reply Reply Quote 0
        • ManuelM
          Manuel
          last edited by

          Hi,

          things changed a bit for s26 as we can now load files asynchronously. I've send an email to our dev, because one solution would be to use ExecuteOnMainThread but this function does not exist on the python API.

          Cheers,
          Manuel

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

            Hi,

            in s26, it is not possible to perform any GUI operation as the SceneLoaderData will not be called from the mainthread anymore.

            Instead, you must use the description file when you register the plugin. Those options will be displayed when the user want to import the corresponding file, and they will be accessible from the preferences. The user will be able to save or load presets.
            I created an example that we will post on github after being reviewed.

            Why you were displaying a dialog box that way in the first place?

            import c4d
            PLUGIN_ID = 1059408
            IES_IMPORT_PRINT_TO_CONSOLE = 10001
            
            class ExampleDialog(c4d.gui.GeDialog):
            
                def CreateLayout(self):
                    """
                   This Method is called automatically when Cinema 4D creates the Layout of the Dialog.
                    Returns:
                        bool: False if there was an error, otherwise True.
                    """
                    # Defines the title of the Dialog
                    self.SetTitle("This is an example Dialog")
            
                    # Creates a Ok and Cancel Button
                    self.AddDlgGroup(c4d.DLG_OK | c4d.DLG_CANCEL)
            
                    return True
            
                def Command(self, messageId, bc):
                    """
                    This Method is called automatically when the user clicks on a gadget and/or changes 
                    its value this function will be called. It is also called when a string menu item is selected.
            
                    Args:
                        messageId (int): The ID of the gadget that triggered the event.
                        bc (c4d.BaseContainer): The original message container.
            
                    Returns:
                        bool: False if there was an error, otherwise True.
                    """
                    # User click on Ok buttonG
                    if messageId == c4d.DLG_OK:
                        print("User Click on Ok")
                        return True
            
                    # User click on Cancel button
                    elif messageId == c4d.DLG_CANCEL:
                        print("User Click on Cancel")
            
                        # Close the Dialog
                        self.Close()
                        return True
            
                    return True
            
            
            
            class IESMetaLoader(c4d.plugins.SceneLoaderData):
                """IESMeta Loader"""
                dialog = None
            
                def Init(self, node):
                    """
                    Called when a new instance of this object is created. In this context, this allow to define
                    the option by default for the SceneLoaderPlugin that will be displayed to the user.
                    
                    Returns:
                        bool: False if there was an error, otherwise True.
                    """
                    # Define the default value for the parameters.
                    self.InitAttr(node, bool, c4d.IES_IMPORT_PRINT_TO_CONSOLE)
                    node[c4d.IES_IMPORT_PRINT_TO_CONSOLE] = True
                    return True
            
                def Identify(self, node, name, probe, size):
                    """
                    Cinema 4D calls this function for every registered scene loader plugin. This function
                    should return True only if this plugin can handle the file. The parameter 'probe' contain a 
                    small part of the file, usually the 1024 first characters. This allow to check if the header 
                    of the file starts as expected, validating the fact this file can be read by the load 
                    function.
                    Args:
                        node (c4d.BaseList2D): The node object.
                        name (str): The name of the loader.
                        probe (memoryview): The start of a small chunk of data from the start of the file for 
                        testing this file type. Usually the probe size is 1024 bytes. Never call the buffer 
                        outside this method!
                        size (int): The size of the chunk for testing this file type.
                    Returns:
                        bool: True if the SceneLoaderData can load this kind of files.
                    """
                    # Check if the last three character are equal to 'txt'
                    if "txt" in name[-3:]:
                        # Check if the txt file start with the correct header.
                        if bytes(probe[0:17]).decode().upper() == "IES Meta Exporter".upper():
                            return True
                    return False
            
                def Load(self, node, name, doc, filterflags, error, bt):
                    """
                    Called by Cinema 4D to load the file. This method is only called if the identify function
                    returned True. The parameter 'node' allows to retrieve the options the user defined for this
                    import.
            
                    Args:
                        node (c4d.BaseList2D): The node object representing the exporter.
                        name (str): The filename of the file to save.
                        doc (c4d.documents.BaseDocument): The document that should be saved.
                        filterflags (SCENEFILTER): Options for the exporter.
                        error (None): Not supported.
                        bt (c4d.threading.BaseThread): The calling thread.
            
                    Returns:
                        FILEERROR: Status of the import process.
                    """
            
                    dialogAllowed = bool(filterflags & c4d.SCENEFILTER_DIALOGSALLOWED)
                    isMainThread = c4d.threading.GeIsMainThread()
            
                    print ("is main thread  {}".format(isMainThread))
                    print ("is dialog allowed? {}".format(dialogAllowed))
                    # GUI operation are not allowed if they are not executed from the main thread, always check
                    # if this is the main thread. Check also if the flag is set to SCENEFILTER_DIALOGSALLOWED to
                    # sure dialog can be displayed.
                    if isMainThread:
                        if dialogAllowed:
                            # Open a GeDialog
                            if self.dialog is None:
                                self.dialog = ExampleDialog()
                            self.dialog.Open(
                                                dlgtype=c4d.DLG_TYPE_ASYNC, 
                                                pluginid=PLUGIN_ID, 
                                                defaultw=400, 
                                                defaulth=32
                                            )
                            # Create and display a Popup Menu
                            menu = c4d.BaseContainer()
                            menu.InsData(1001, 'Item 1')
                            menu.InsData(1002, 'Item 2')
                            menu.InsData(0, '')  # Append separator
                            c4d.gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS)
                    
                    # Display the content of the file if the user check the option in the import options.
                    # Opens the file in read mode and print all the lines
                    if node[c4d.IES_IMPORT_PRINT_TO_CONSOLE]:
                        with open(name, "r") as f:
                            for line in f:
                                print (line)
                    return c4d.FILEERROR_NONE
            
            if __name__ == '__main__':
                c4d.plugins.RegisterSceneLoaderPlugin(id=PLUGIN_ID,
                                                     str="Py-IES Meta (*.txt)",
                                                     info = 0,
                                                     g=IESMetaLoader,
                                                     description="fies_loader",
                                                     )
            
            

            res file

            CONTAINER fies_loader
            {
            	INCLUDE Fbase;
            	NAME fies_loader;
            	
            	GROUP IES_IMPORT_GROUP
            	{
            		DEFAULT 1;
            		BOOL IES_IMPORT_PRINT_TO_CONSOLE {}
            	}
            }
            

            header file

            #ifndef _FIES_LOADER_H__
            #define _FIES_LOADER_H__
            
            enum 
            {
            	fies_loader = 10000,
            	IES_IMPORT_PRINT_TO_CONSOLE,
            	IES_IMPORT_GROUP
            };
            
            #endif
            
            
            

            str file

            STRINGTABLE fies_loader
            {
            	fies_loader			       "IES Import Settings";
                   IES_IMPORT_GROUP                   "IES option group";
            	IES_IMPORT_PRINT_TO_CONSOLE		"Print to console?";
            }
            

            Cheers,
            Manuel

            1 Reply Last reply Reply Quote 0
            • K
              kalugin
              last edited by

              I didn't display a dialog box, but a popup menu. I used it for drag&drop of a custom extension file. It was very convenient to prompt the user what to do with the dropped file. Anyway, I moved that logic to a messagedata plugin that gets called from the sceneloader and that way I can show the popup menu 🙂

              1 Reply Last reply Reply Quote 1
              • ferdinandF
                ferdinand
                last edited by

                Hello @kalugin,

                without any further questions or other postings, we will consider this topic as solved and flag it as such by Friday, 17/06/2022.

                Thank you for your understanding,
                Ferdinand

                MAXON SDK Specialist
                developers.maxon.net

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