Solved 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

MAXON SDK Specialist

MAXON Registered Developer

@m_magalhaes Thank you! and it makes sense.:+1: 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. :blush: :+1:
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

MAXON SDK Specialist

MAXON Registered Developer