Why ToolData Plugin Not Keeping the Input Data Values to the GUI Widgets SubDialog?



  • User Information:
    Cinema 4D Version: R19/R21;
    Platform: Windows ;
    Language(s) : Python ;

    Hello Everyone!
    This my first time making a tool data plugin. Now the problem is in R21 I drag the object into the link box and it don't stay and when I change the tool data or the settings dont stay , and i did this with other c4d gui widgets , eg: combobox, it just reset to the default value you set in the GeDialog.InitValues(). Now in R19 I drag the object into the link box and it stay but when I change the tool data or the settings dont stay.
    You can see the short streamable videos below on what is happen inside C4D and take look at the code also. I hope there a easy fix for this problem and not a bug. lol
    Inside R21: Video
    Inside R19: Video

    Code:

    import c4d
    from c4d import plugins, gui, bitmaps, documents, storage, utils
    import os
    import sys
    
    PLUGIN_ID = 1054512
    
    def GetDataFromLinkBox(ui_ins, uiLinkID):
        DATA = ui_ins.FindCustomGui(uiLinkID, c4d.CUSTOMGUI_LINKBOX).GetLink()
        objDATA = DATA
        objName = DATA.GetName()
        objGUID = DATA.GetGUID()
        return objDATA, objName, objGUID
    
    class DemoDialog(gui.SubDialog):
    
        UIDATA_PARAMETERS = {}
        LinkBC = c4d.BaseContainer()
        IDUI_CUSTOMGRP_LINK1 = 1003
    
        def __init__(self, arg):
            # Checks if the argument passed is a dictionary
            if not isinstance(arg, dict):
                raise TypeError("arg is not a dict.")
            self.UIDATA_PARAMETERS = arg
    
        def CreateLayout(self):
            ui = self
            ui.GroupBegin(0, c4d.BFH_SCALEFIT, 2, 0, "")
            ui.AddStaticText(0, c4d.BFH_RIGHT, 0, 12, "Object:", c4d.BORDER_WITH_TITLE_BOLD)
            ui.AddCustomGui(ui.IDUI_CUSTOMGRP_LINK1, c4d.CUSTOMGUI_LINKBOX, "", c4d.BFH_MASK, 240, 12, ui.LinkBC)            
            ui.GroupEnd()
            return True
    
        def Command(self, id, msg):
    
            if id == self.IDUI_CUSTOMGRP_LINK1:
               obj, objName, objID = GetDataFromLinkBox(ui_ins=self, uiLinkID=self.IDUI_CUSTOMGRP_LINK1)
               self.UIDATA_PARAMETERS['grouplink'] = obj
               self.UIDATA_PARAMETERS['grouplinkGUID'] = objID
               print("Linked Object:{0} | ID:{1} | GUI-ID:{2}").format( objName, objID, id )
    
            return True
    
    class ToolDemo(plugins.ToolData):
    
        def __init__(self):
            self.UI_DATA = { 'grouplink':None, 'grouplinkGUID':None }
    
        def GetState(self, doc):
            if doc.GetMode()==c4d.Mpaint:
                return 0
            return c4d.CMD_ENABLED 
        def InitDefaultSettings(self, doc, data):
            pass
            # expects None as return value
        def InitTool(self, doc, data, bt):
            return True
        def KeyboardInput(self, doc, data, bd, win, msg):
            return True
        def MouseInput(self, doc, data, bd, win, msg):
            return True
        def GetCursorInfo(self, doc, data, bd, x, y, bc):
            return True
            
        def AllocSubDialog(self, bc):     
            return DemoDialog(getattr(self, "UI_DATA", self.UI_DATA))
    
    if __name__ == "__main__":
        bmp = bitmaps.BaseBitmap()
        dir, file = os.path.split(__file__)
        fn = os.path.join(dir, "res", "tool_icon.tif")
        bmp.InitWith(fn)
        plugins.RegisterToolPlugin(id=PLUGIN_ID, 
                                    str="MyPyToolDemo",
                                    info=0, 
                                    icon=bmp, 
                                    help="Tool",
                                    dat=ToolDemo())
    

    And I am just wondering is c4d.plugins.SculptBrushToolData is better system than c4d.plugins.ToolData. Cause it look like description .res.. UI is for the tool plugin is more easy, like Node Data, Object Data Tags etc....
    Any help would be very much appreciated.

    cheers, Ashton



  • hi,

    you have to store a link to your gadget and add an InitValues function to your dialog like so

    in the create layout:

    self.link = ui.AddCustomGui(ui.IDUI_CUSTOMGRP_LINK1, c4d.CUSTOMGUI_LINKBOX, "", c4d.BFH_MASK, 240, 12, ui.LinkBC)            
    

    and add that function

       def InitValues(self):
        
            self.link.SetLink(self.UIDATA_PARAMETERS['grouplink'])
            return True
    

    Cheers,
    Manuel



  • @m_magalhaes Thank you! and it makes sense.👍 Heres a update of the code and Demo Video. And hope it helps anyone who might need this or was wondering how a simple Tool Data GUI works.
    172b5199-9a7e-42d0-bf04-85d53307e59e-image.png
    You see I just add the AddComboBox, AddEditText for testing also. 😊 👍
    Code in .pyp file:

    #  // Imports for Cinema 4D //
    import c4d
    from c4d import plugins, gui, bitmaps, documents, storage, utils
    import os
    import sys
    
    PLUGIN_ID = 1054512
    
    def GetDataFromLinkBox(ui_ins, uiLinkID):
        DATA = ui_ins.FindCustomGui(uiLinkID, c4d.CUSTOMGUI_LINKBOX).GetLink()
        objDATA = DATA
        objName = DATA.GetName()
        objGUID = DATA.GetGUID()
        return objDATA, objName, objGUID
    
    def SetDataFromLinkBox(ui_ins, uiLinkID, Data):
        LinkWidget = ui_ins.FindCustomGui(uiLinkID, c4d.CUSTOMGUI_LINKBOX)
        LinkWidget.SetLink(Data)
        return True
    
    
    class DemoDialog(gui.SubDialog):
        # Main Properties
        UIDATA_PARAMETERS = {}
        LinkBC = c4d.BaseContainer()
        IDUI_CUSTOMGRP_LINK1 = 1003
        IDUI_GRG_OBJ_GUID = 1004
        MODE_MENU = 1005
        MODE_MENU_LIST = {
                            "Mode 1":{'id':1, 'icon':"&i12298&"}, # (12298) # Model Icon Id (Eg:"&i12298&Model")
                            "Mode 2":{'id':2, 'icon':"&i12139&"}, # (12139) # Points Icon Id
                            "Mode 3":{'id':3, 'icon':"&i12187&"}  # (12187) # Polygons Icon Id
                         }
    
        def __init__(self, arg):
            # Checks if the argument passed is a dictionary
            if not isinstance(arg, dict):
                raise TypeError("arg is not a dict.")
            self.UIDATA_PARAMETERS = arg
    
        def CreateLayout(self):
            """ Window GUI elements layout that display to the User. """
            ui = self
            ui.GroupBegin(0, c4d.BFH_MASK, 2, 2, "", c4d.BFV_GRIDGROUP_EQUALCOLS)
            ui.AddStaticText(0, c4d.BFH_RIGHT, 0, 12, "Object:", c4d.BORDER_WITH_TITLE_BOLD)
            ui.AddCustomGui(ui.IDUI_CUSTOMGRP_LINK1, c4d.CUSTOMGUI_LINKBOX, "", c4d.BFH_MASK, 240, 12, ui.LinkBC) 
            ui.AddStaticText(0, c4d.BFH_RIGHT, 0, 12, "Object GUID:", c4d.BORDER_WITH_TITLE_BOLD)
            ui.AddEditText(ui.IDUI_GRG_OBJ_GUID, c4d.BFH_MASK, 240, 12)   
            ui.AddStaticText(0, c4d.BFH_RIGHT, 0, 12, "Modes:", c4d.BORDER_WITH_TITLE_BOLD)
            ui.AddComboBox(ui.MODE_MENU, c4d.BFH_SCALEFIT, 100, 15, False)
            for eachMode in sorted(ui.MODE_MENU_LIST):
                itemMode = ui.MODE_MENU_LIST.get(str(eachMode))           
                ui.AddChild(ui.MODE_MENU, itemMode['id'],  itemMode['icon']+str(eachMode))         
            ui.GroupEnd()
            return True
    
        def InitValues(self):
            """ Called when the dialog is initialized by the GUI / GUI's startup values basically. """
            SetDataFromLinkBox(ui_ins=self, uiLinkID=self.IDUI_CUSTOMGRP_LINK1, Data=self.UIDATA_PARAMETERS['grouplink'])
            self.SetString(self.IDUI_GRG_OBJ_GUID, self.UIDATA_PARAMETERS['grouplinkGUID'])
            self.SetLong(self.MODE_MENU, self.UIDATA_PARAMETERS['modeSelect'])
            return True
    
        def Command(self, id, msg):
            """ Excuting Commands for UI Widget Elements Functions. """
            if id == self.IDUI_CUSTOMGRP_LINK1:
                obj, objName, objID = GetDataFromLinkBox(ui_ins=self, uiLinkID=self.IDUI_CUSTOMGRP_LINK1)
                self.UIDATA_PARAMETERS['grouplink'] = obj
                self.UIDATA_PARAMETERS['grouplinkGUID'] = objID
                self.SetString(self.IDUI_GRG_OBJ_GUID, str(objID))
                print("Linked Object:{0} | ID:{1} | GUI-ID:{2}").format( objName, objID, id )
    
            if id == self.MODE_MENU:
                for i in self.MODE_MENU_LIST:
                    getModeID = self.MODE_MENU_LIST.get(str(i))
                    if self.GetLong(self.MODE_MENU) == getModeID["id"]:
                        self.UIDATA_PARAMETERS['modeSelect']=getModeID["id"]
            return True
    
    class PyToolDemo(plugins.ToolData):
    
        def __init__(self):
            self.UI_DATA = { 'grouplink':None, 
                             'grouplinkGUID':None,
                             'modeSelect':2 }
    
        def GetState(self, doc):
            if doc.GetMode()==c4d.Mpaint:
                return 0
            return c4d.CMD_ENABLED 
        def InitDefaultSettings(self, doc, data):
            pass
        def InitTool(self, doc, data, bt):
            return True
        def KeyboardInput(self, doc, data, bd, win, msg):
            return True
        def MouseInput(self, doc, data, bd, win, msg):
            return True
        def GetCursorInfo(self, doc, data, bd, x, y, bc):
            return True
    
        def AllocSubDialog(self, bc):     
            return DemoDialog(getattr(self, "UI_DATA", self.UI_DATA))
    
    if __name__ == "__main__":
        bmp = bitmaps.BaseBitmap()
        dir, file = os.path.split(__file__)
        fn = os.path.join(dir, "res", "tool_icon.tif")
        bmp.InitWith(fn)
        plugins.RegisterToolPlugin(id=PLUGIN_ID, 
                                    str="MyPyToolDemo",
                                    info=0, 
                                    icon=bmp, 
                                    help="Your Data Staying ToolData UI",
                                    dat=PyToolDemo())
    


  • hi,

    thanks a lot for sharing your code :)

    Don't forget to change the state of this thread to solved. (if it is)

    cheers,
    Manuel