Hello; (followup to previous Custom GUI question)
setting up a linkbox in a dialog through a CUSTOMGUI_LINKBOX
is easy enough programmatically, and it works fine. However, by default that linkbox accepts any BaseList2D
class, object, material, or tag (and more).
If I were in a Resource, I could use the ACCEPT notation to define the accepted types, but I want to keep the whole micro-plugin in one file, so I am building the GUI through Python code... and the LinkBoxGui
class has no Accept method, nor an Accept key for the setup BaseContainer, nor is there anything in the class hierarchy that looks like it.
On this forum, I found on older post telling me to evaluate the MSG_DESCRIPTION_CHECKDRAGANDDROP
message. This apparently needs to be done in the dialog's Message() function, and yes, I do receive this message:
import c4d
import ctypes
import _ctypes
PLUGIN_ID = 1000001 # this is a test ID, get your own!
ID_BUTTON_CLOSE = 1001
ID_BUTTON_CHECK = 1002
ID_LINKBOX = 1003
class LinkDialog(c4d.gui.GeDialog):
def CreateLayout(self):
self.SetTitle("Link Test")
self.GroupBorderSpace(10, 10, 10, 10)
if self.GroupBegin(id=0, flags=c4d.BFH_SCALEFIT, cols=1, title="", groupflags=0):
bc = c4d.BaseContainer()
bc[c4d.LINKBOX_HIDE_ICON] = False
bc[c4d.LINKBOX_NO_PICKER] = False
bc[c4d.LINKBOX_LAYERMODE] = False
self.linkControl = self.AddCustomGui(ID_LINKBOX, c4d.CUSTOMGUI_LINKBOX,
name="A link", flags = c4d.BFH_SCALEFIT | c4d.BFV_FIT,
minw=10, minh=10, customdata=bc)
self.GroupEnd()
if self.GroupBegin(id=0, flags=c4d.BFH_CENTER, cols=2, title="", groupflags=0):
self.GroupBorderSpace(0, 20, 0, 0)
self.AddButton(ID_BUTTON_CLOSE, c4d.BFH_SCALEFIT, name="Close")
self.AddButton(ID_BUTTON_CHECK, c4d.BFH_SCALEFIT, name="Check")
self.GroupEnd()
return True
def Command(self, messageId, bc):
if messageId == ID_BUTTON_CLOSE:
self.Close()
if messageId == ID_BUTTON_CHECK:
obj = self.linkControl.GetLink(c4d.documents.GetActiveDocument())
if obj == None:
print("No object linked!")
else:
print("Name: ", obj.GetName())
print("Class: ", type(obj))
print("# of direct children: ", len(obj.GetChildren()))
return True
def Message(self, msg, result):
if msg.GetId() == c4d.MSG_DESCRIPTION_CHECKDRAGANDDROP: # = numerically 26
ctrlID = msg.GetLong(c4d.LINKBOX_ACCEPT_MESSAGE_CONTROL_ID)
print (ctrlID)
if ctrlID == ID_LINKBOX:
print ("Type ID: ", msg[c4d.LINKBOX_ACCEPT_MESSAGE_TYPE]) # 201, not MSG_DESCRIPTION_CHECKDRAGANDDROP !
print ("Element: ", msg[c4d.LINKBOX_ACCEPT_MESSAGE_ELEMENT])
print ("Element type: ", type(msg[c4d.LINKBOX_ACCEPT_MESSAGE_ELEMENT]))
print ("Accept: ", msg[c4d.LINKBOX_ACCEPT_MESSAGE_ACCEPT])
# ptr = ctypes.pythonapi.PyCapsule_GetPointer(msg[c4d.LINKBOX_ACCEPT_MESSAGE_ELEMENT], None)
obj = self.linkControl.GetLink(c4d.documents.GetActiveDocument())
if obj != None:
print (obj.GetName())
if not isinstance (obj, c4d.BaseObject):
print ("Delete dragged object!")
self.linkControl.SetLink(None)
else:
print ("Accepted.")
return c4d.gui.GeDialog.Message(self, msg, result)
class LinkCommandData(c4d.plugins.CommandData):
dialog = None
def Execute(self, doc):
if self.dialog is None:
self.dialog = LinkDialog()
return self.dialog.Open(dlgtype=c4d.DLG_TYPE_ASYNC, pluginid=PLUGIN_ID, defaulth=40, defaultw=200)
def RestoreLayout(self, sec_ref):
if self.dialog is None:
self.dialog = LinkDialog()
return self.dialog.Restore(pluginid=PLUGIN_ID, secret=sec_ref)
if __name__ == "__main__":
c4d.plugins.RegisterCommandPlugin(
id=PLUGIN_ID,
str="Link custom GUI test",
help="Demonstrates Link field usage",
info=0,
dat=LinkCommandData(),
icon=None)
Unfortunately, that post seems to be too old (8 years or so) to be of use, because it says I would receive this message after the value in the control is changed. That is not the case.
The message appears once when I use the Pick functionality, and many times when I drag an object into the link box. Apparently, I receive this message as long as I hover the mouse over the link field.
It is unclear under the circumstances which of these message is chronologically the last one (on releasing the mouse button). The object returned by GetLink()
on the control is always the old/previous object, not the one I drag into the link field. The dragged object from the message itself, received as "Element", is a PyCapsule
(for Python3).
So, how to proceed? To inspect the dragged object, I need to unwrap it from the PyCapsule
; sadly, that class is not documented. I understand that I need to call PyCapsule_GetPointer
somehow, and that's where my understanding ends (trying samples from this forum all end in a crash of C4D).
Then, I am probably(?) required to store a key/value in result (a BaseContainer
)... and return False? (Returning False alone does not do anything.)
And is the evaluation of this method the same for Pick and for Drag activities? Am I even in the correct message?