Jump to content

Sign in to follow this  
Hexbob

Executing Functions from Popup Script

Recommended Posts

I am writing a small script that will serve as a quick-access popup dialog for certain functions in C4D, using Python (relevant documentation). These functions include adding primitives, etc, and the popup itself is imported as a user script and bound to a keyboard shortcut for ease-of-use.

 

As the script is growing I am wanting to add a method to quickly add tags to selected objects when an option from the popup is selected, however I am having trouble executing the commands/functions necessary from within the script.

 

Here is a stripped back example of the script:

import c4d
from c4d import gui

# Define Menu Item IDs
IDM_MENU_TITLE = c4d.FIRST_POPUP_ID

IDM_MENU1 = c4d.FIRST_POPUP_ID+1

IDM_DROPDOWN1 = c4d.FIRST_POPUP_ID+4

# Menu Creation
menu = c4d.BaseContainer()
menu.InsData(IDM_MENU_TITLE, 'Popup Dialog &d&')
menu.InsData(0,'')

add_tag_to_objs = c4d.BaseContainer()
add_tag_to_objs.InsData(1, 'Add Protection Tag')  # This tag is arbitrary 

dropdown_menu = c4d.BaseContainer()
dropdown_menu.InsData(1, 'Add Objects/Mograph')
dropdown_menu.InsData(c4d.Ocube, 'CMD')     # Adds a Cube Primitive
dropdown_menu.InsData(1018544, 'CMD')       # Adds a Cloner Object

menu.InsData(IDM_MENU1, add_tag_to_objs)
menu.InsData(0, '')
menu.InsData(IDM_DROPDOWN1, dropdown_menu)


# Show Popup Dialog
result = gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS)
print result

When executed this returns the following result:

 

2019-08-24_02h22_19.png.d1d4784b43d93fe6b0ef12a2443da447.png

 

Accessing the commands that add a Cloner or Cube was simple, one can simply open the script log, add an object to the scene and then take the resulting .CallCommand() ID outputted in the log and add it to the script with the .InsData() function (as shown above). When adding tags, however, the resulting script log shows several commands being executed, in a way that I can't figure out how to replicate with .InsData() :

c4d.CallCommand(5629) #
c4d.CallCommand(100004788, 50018) # New Tag

As a result, I can see it being necessary to define a function that loops through the selected objects in the scene whilst adding the relevant tags to them. However I cannot figure out firstly what this function should look like, and secondly how to execute it when clicking the 'Add Protection Tag' option from the popup script?

 

I'm still fairly new to Python scripting and C4D in general so detailed/commented answers would be much appreciated- but I'll take all the help I can get! 🙂 Thanks in advance!

 

Share this post


Link to post
Share on other sites

@kbar @C4DS Should know somthing about this one! :)


| MAXON Quality Assurance Specialist | 3D Asset Creatior | C4D Cafe Manager | Gamer in Heart | :compEnjoy:

Share this post


Link to post
Share on other sites
  • Topic Author
  • Brilliant, thanks for the speedy reply and heads-up, @Igor! 🙂 

    Share this post


    Link to post
    Share on other sites
    1 minute ago, Hexbob said:

    Brilliant, thanks for the speedy reply and heads-up, @Igor! 🙂 

    One unrelated question if you dont mind. Can you see new forum update? :)


    | MAXON Quality Assurance Specialist | 3D Asset Creatior | C4D Cafe Manager | Gamer in Heart | :compEnjoy:

    Share this post


    Link to post
    Share on other sites
  • Topic Author
  • Just now, Igor said:

    One unrelated question if you dont mind. Can you see new forum update? 🙂

    I can indeed, that explains why I couldn't access the site for a few minutes! 😛 

    Share this post


    Link to post
    Share on other sites
    5 minutes ago, Hexbob said:

    I can indeed, that explains why I couldn't access the site for a few minutes! 😛 

    Cool, I hope you like it! :)


    | MAXON Quality Assurance Specialist | 3D Asset Creatior | C4D Cafe Manager | Gamer in Heart | :compEnjoy:

    Share this post


    Link to post
    Share on other sites

    The commands as shown in the script log will help you only so far. If you want to execute a command on several objects, or perform complex operations, you will need to delve a bit deeper into Python.

    In this case: When you use an ID for the menu item that is also a C4D command ID and the string is 'CMD', then the ShowPopupDialog will execute that command. In all other cases, the ShowPopupDialog will just return the ID that you passed, and you will need to create some code to execute in these cases.

     

    In your sample, this would look like this:

     

    import c4d
    from c4d import gui
    
    # Define Menu Item IDs
    IDM_MENU_TITLE = c4d.FIRST_POPUP_ID
    IDM_MENU1 = c4d.FIRST_POPUP_ID+1
    IDM_DROPDOWN1 = c4d.FIRST_POPUP_ID+4
    IDM_ADDPROTECTION = c4d.FIRST_POPUP_ID + 10
    
    def main():
        # Menu Creation
        menu = c4d.BaseContainer()
        menu.InsData(IDM_MENU_TITLE, 'Popup Dialog &d&')
        menu.InsData(0,'')
        menu.InsData(IDM_ADDPROTECTION, 'Add Protection Tag')  # Execute code below
    
        dropdown_menu = c4d.BaseContainer()
        dropdown_menu.InsData(1, 'Add Objects/Mograph')
        dropdown_menu.InsData(c4d.Ocube, 'CMD')     # Adds a Cube Primitive
        dropdown_menu.InsData(1018544, 'CMD')       # Adds a Cloner Object
    
        menu.InsData(0, '')
        menu.InsData(IDM_DROPDOWN1, dropdown_menu)
    
        # Show Popup Dialog
        result = gui.ShowPopupDialog(cd=None, bc=menu, x=c4d.MOUSEPOS, y=c4d.MOUSEPOS)
        print result
        if result == IDM_ADDPROTECTION :
            objlist = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
            if objlist:
                doc.StartUndo()
                for obj in objlist:
                    newTag = c4d.BaseTag(c4d.Tprotection)
                    doc.AddUndo(c4d.UNDOTYPE_NEW, newTag)
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
                    obj.InsertTag(newTag)
                    obj.Message(c4d.MSG_UPDATE)
                doc.EndUndo()
                c4d.EventAdd()
    
    if __name__=='__main__':
        main()

    I kept your basic structure here but added a new ID IDM_ADDPROTECTION for the execution of the menu. The actual execution starts after the menu closes with 'if result == IDM_ADDPROTECTION', here's the relevant code again commented:

        # check for the ID of the menu to execute; use muliple IFs or CASE to distinguish
        # between several commands
        if result == IDM_ADDPROTECTION : 
            # fetch the list of selected objects from the document. The sequence
            # of selection is not relevant, but you want the selected children as well,
            # as each object needs a separate protection tag
            objlist = doc.GetActiveObjects(c4d.GETACTIVEOBJECTFLAGS_CHILDREN)
            # check whether there are any objects selected; if not, the code
            # is skipped altogether
            if objlist:
                # For UNDOs, you may want to consult the documentation, I just
                # inserted all the undo commands here because of style ;-)
                doc.StartUndo()
                # go through the list of selected objects one by one
                for obj in objlist:
                    # create a new protection tag (I'm not using the command
                    # from the command ID list here but the proper "new")
                    newTag = c4d.BaseTag(c4d.Tprotection)
                    doc.AddUndo(c4d.UNDOTYPE_NEW, newTag)
                    doc.AddUndo(c4d.UNDOTYPE_CHANGE, obj)
                    # put the new tag on the current object. Note that this
                    # will delete an old tag of the same type unless the tag
                    # can be applied as MULTIPLE. The protection tag can't
                    # so you need to be careful (the best style is to check whether
                    # the object already has a protection tag)
                    obj.InsertTag(newTag)
                    # send the current object a message that it needs updating
                    obj.Message(c4d.MSG_UPDATE)
                # send the document the message that the undo block ends here.
                # This is done after the loop through all selected objects so
                # the undo will need to be executed only once to delete all the
                # created protection tags in one fell swoop.
                doc.EndUndo()
                # tell C4D to update everything so any attribute manager, object manager, 
                # and viewport will be refreshed
                c4d.EventAdd()

     

    (oh, and could someone explain to me why the whole block XPresso, Python and Plugin Development in the Forum list is marked as "Private Section" im the overview, and made inaccessible? Now obviously that is no serious block but I can't find an explanation for that either)

    Share this post


    Link to post
    Share on other sites

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Reply to this topic...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    Sign in to follow this  

    • Recently Browsing   0 members

      No registered users viewing this page.

    ×
    ×
    • Create New...