Object Plugin position in manager
-
On 30/09/2013 at 06:22, xxxxxxxx wrote:
when i create my Object , by default it's inserted at the top of the object manager.
if i try to do this:def Message(self, node, type, data) : doc = c4d.documents.GetActiveDocument() if type == c4d.MSG_MENUPREPARE: node.InsertUnder(doc.GetActiveObject()) return True
cinema4d just locks up... Why ?
-
On 30/09/2013 at 08:16, xxxxxxxx wrote:
the code does look okish, however two ideas:
1. The return value of Message() methods in c4d does remain a tricky thing. It is easy
to freeze c4d with missing calls, even though there have been made some changes in
R14. I cannot remember to have ran into that problem for NodeData yet, but I guess it
is worth a try. Replace your return statement with one of the following:return super(MyNodeDataType, self).Message(node, type, data)
return NodeData.Message(self, node, type, data)You should also be aware that the Message() return value follows in c4d the consumption logic
and is not indicating the success of the operation.2. I am not sure when MSG_MENUPREPARE is being sent, but c4d.documents.GetActiveDocument()
is a statement you usually want to avoid in plugins, as it can easily invoke several problems
(cloned documents, livetime and so on.) Better sources for the document are either the doc
parameter or a node we know (or suspect) to be in the targeted document. So if you do change
your code to doc = node.GetDocument() and doc is still None, I would not try to insert the object
manually at that point. A better solution might be then a small MessageData plugin. -
On 30/09/2013 at 12:02, xxxxxxxx wrote:
MSG_MENUPREAPRE is sent when the node is first inserted into a document. Primitive objects for
instance create a Phong Tag on themselves with this message. You can send it manually when
creating an object in a script.As I already said, the node is already inserted. You can't insert a node twice, that leads to critical
reference issues. You first need to remove the node, then insert it again.You are of course free to do this, but I do not recommend it. In Cinema 4D, the user is free to
choose at what place the object should be created. If he would like your object to be inserted
under the selected object, he'd hold the SHIFT key while pressing the menu button.Best,
-Niklas -
On 30/09/2013 at 12:48, xxxxxxxx wrote:
Originally posted by xxxxxxxx
MSG_MENUPREAPRE is sent when the node is first inserted into a document. Primitive objects for
instance create a Phong Tag on themselves with this message. You can send it manually when
creating an object in a script.As I already said, the node is already inserted. You can't insert a node twice, that leads to critical
reference issues. You first need to remove the node, then insert it again.You are of course free to do this, but I do not recommend it. In Cinema 4D, the user is free to
choose at what place the object should be created. If he would like your object to be inserted
under the selected object, he'd hold the SHIFT key while pressing the menu button.Best,
-NiklasHey,
I guess I was a bit unclear about the line ' I am not sure when MSG_MENUPREPARE is being sent', as
I did know the occasion and meant I did not know when it is sent, after or before the object
has been inserted into the document.1. At least in python you do not have to invoke Remove() before invoking any of the InsertXYZ()
methods.2. I did a little test with an ObjectData plugin of mine (a SplineObject to be more specific ). These
lines -def Message(self, node, mtype, data) : """ """ [...] if mtype == c4d.MSG_MENUPREPARE: print node.GetDocument() [...]
will print None to the console for me, indicating that the object is still 'floating' and has not been
inserted yet. So it is porting towards my assumption, that c4d does not expect the object to be
inserted at that point yet and doing it manually does not seem to be a good idea ( considering
the problems the op did report).So I am not quite sure if your suggestions do really apply, but I might be wrong.
-
On 30/09/2013 at 13:04, xxxxxxxx wrote:
Hi Ferdinand,
Thanks for paying attention, you are correct.
I somehow had this construct in mind (see below) which leads to Cinema go into an infinite loop.
But you are absolutely correct about your statement, that it is not necessary to call the Remove()
method.op.InsertUnder(op) # Invalid, will result in an infinite loop
Seems like I also had #2 wrong in my mind. I thought I was remembering a part where I
successfully called GetDocument() in MSG_MENUPREPARE, this is why I came to the above
conclusion which is obviously wrong.Drawing a new conclusion from the corrected information, MSG_MENUPREPARE is called before the
object is inserted into the document, which explains why GetDocument() returns None and why
Cinema runs into an infinite loop. Cinema probably does not expect you to insert the object in
MSG_MENUPREPARE, then after it has sent the message, it simply inserts the object and thus
some objects have invalid references.Thanks again Ferdinand,
Best - Niklas -
On 30/09/2013 at 13:40, xxxxxxxx wrote:
Well, for me, it's stuck on the return for sure.
def Message(self, node, type, data) : if type == c4d.MSG_MENUPREPARE: doc = c4d.documents.GetActiveDocument() print doc place = doc.GetActiveObject() print place node.InsertUnder(place) print "success" return True
and console prints this:
<c4d.documents.BaseDocument object called '' with ID 110059 at 0x000000000F1ED670>
<c4d.BaseObject object called 'Cube/Cube' with ID 5159 at 0x0000000006AE4890>
successand AFTER that it locks. So you can define the active document in the MENUPREPARE for sure.
but if I use node.GetDocument() it equals to None, so the object itself isn't in the document yet.
So any ideas how to do it ?
@ Niklas: I need to insert it before the selected object i don't know why i started testing with InsertAfter(). So any ALT or SHIFT will not do it. -
On 30/09/2013 at 15:09, xxxxxxxx wrote:
Do not use doc = c4d.documents.GetActiveDocument()in plugin code (except for command data
plugins). C4d does duplicate the document for rendering which will render that code useless as
GetActiveDoucment() will always return the active document in the editor (so that you are using
the wrong document). It also does introduce possible problems with dead objects. If you cannot
get hold of the document a node is sitting in with GeListNode.GetDocument(), it is a strong
indicator that you should look for a later point of interception.As I wrote already in my first posing the most straight forward option would be a MessageData
plugin monitoring your scene structure (or more specifically the top object and the current
selection). If you do REALLY want to do it from within your ObjectData plugin you could do the
following.1. To be extra sure that the whole process is only invoked once I would add a virtual element to
the objects description, indicating if the object has already been moved once or not. You will also
need some boolean flag value in your class indicating that the node has to be moved.2. In the Message method ( you could also use Init(), the object isn't yet alive there either ) store
the active object selection as a class member, using some clunky GetActiveDocument() code.3. One of the first things which will happen after the node has been initialized is that c4d will build
its cache and call GVO. So check in GVO if your object is flagged for being relocated, if so, use the
stored object selection to modify the location of the node passed to GVO.Please let me stress again, that this actually rather HACKY and BAD code. The separate
MessageData plugin would be a much cleaner solution.edit : the general flaw in the logic of your code is ( now i do understand what niklas meant with
op.InsertUnder(op)), that at the point when the object is alive the active selection will be the
object itself, as c4d is selecting new objects. that is why you will need that 2 step approach and
also why a MessageData solution would be much better, as it wouldn't need such hacks. -
On 30/09/2013 at 15:31, xxxxxxxx wrote:
thanks for the hints. I'm just starting with python, so obviously i have some digging to do
actually the "data" entry from Message(self, node, type, data) also returns the document, but it seems that this will not help me in anyway. I'll try to figure out the Message plugin solution. -
On 30/09/2013 at 16:09, xxxxxxxx wrote:
You mean data is a BaseDocument for MSG_MENUPREPARE ? The type of data actually depends on the
type of the message, I didn't know that it is a BaseDocument for MSG_MENUPREPARE, but it does make
sense, as the ID is there to let you do additional setup stuff.Just to be clear, using the hacky way wouldn't let the world end, its just rather hacky and you should
be aware of it. Generally directly modifying the active scene from within a NodeData plugin is a
rather unusual thing to do. -
On 01/10/2013 at 02:02, xxxxxxxx wrote:
MessageData plugin didn't helped. I couldn't find a message to listen that will suit my needs. But I managed to do it with CommandData plugin. Now it seems so logical to do it that way Thanks a lot for the hints. Till now I only made some simple python scripts to help my work, but i got so hooked up with python, that i really want to learn it in depth. I'll show you what is the plugin that i'm trying to make later. Actually I think it will be quite usefull.
-
On 01/10/2013 at 08:01, xxxxxxxx wrote:
The core message you would use in MessageData plugin would be simply EVMSG_CHANGE.
A very rough layout would be :1. when the class instance is constructed store the active selection and the topmost object.
2. each time EVMSG_CHANGE occurs, update your topmost object, if it is of the desired type
and the current selection move it to your previously stored selection. if not, overwrite your
selection cache.
3. to cover some special cases you could also add a general monitoring of your object type
XYZ so that it doesn't get accidentally moved, when the user does select it and moves it to
the top of the scene hierarchy.A CommandData is of course also a good solution however it won't work if you would instantiate
your type programmatically (and use the actual object and not directly your CommandData plugin ID).Happy rendering,
Ferdinand -
On 01/10/2013 at 13:53, xxxxxxxx wrote:
yes, i that's what I did, but I didn't like that it EVMSG_CHANGE occurs all the time, I didn't feel that's what i need. With the CommandData plugin the code is called only once, on creation of the object, so it's cleaner for me. Also there won't be a problem with the actual ObjectPlugin, cause it has the flag "c4d.PLUGINFLAG_HIDE", so you can't find it as a button and you can't even call it as a command. Or am I wrong ?
-
On 02/10/2013 at 12:20, xxxxxxxx wrote:
http://rapidgator.net/file/73b4cf9bd384f1c3069d228786850219/Group_Object.zip.html
here it is
-
On 03/10/2013 at 04:51, xxxxxxxx wrote:
Originally posted by xxxxxxxx
yes, i that's what I did, but I didn't like that it EVMSG_CHANGE occurs all the time, I didn't feel that's what i need. With the CommandData plugin the code is called only once, on creation of the object, so it's cleaner for me. Also there won't be a problem with the actual ObjectPlugin, cause it has the flag "c4d.PLUGINFLAG_HIDE", so you can't find it as a button and you can't even call it as a command. Or am I wrong ?
no you are absolutely right, it is a perfectly valid way. about EVMSG_CHANGE and that it does
seem unreasonably computational expensive - it is a bit weird and I was also irritated at first,
but it is actually the intended way. I did ask here some time ago on how to get notified, if
the active document has been changed and the answer of one of the devs was EVMSG_CHANGE.
EVMSG_CHANGE is there to check such stuff like oldx != newx, so it is ok to use it in that way.