Can I catch Ctrl + C in a Scene Hook?
-
On 03/02/2015 at 14:48, xxxxxxxx wrote:
Hi Niklas,
actually I may currently be working in a similar area. It sounds like you want to hook the Copy and Paste in your Scenehook. Can you provide me with some more info, what you are actually trying to achieve?
Maybe checkout MSG_DOCUMENTINFO with
DocumentInfoData
[URL-REMOVED] (types: MSG_DOCUMENTINFO_TYPE_COPY and MSG_DOCUMENTINFO_TYPE_PASTE) in conjunction with the DocumentInfoClipData structure. Sorry, documentation is poor.Regarding the core of your question, I'll do some testing tomorrow, I had though, that this would be possible by checking the modifiers, but in the end Ctrl-C is special... we'll see.
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 15/09/2015 at 15:38, xxxxxxxx wrote:
Hi there,
is there change to see any sample code to catch copy/paste operations. I wish to add some extra materials copy buffer when material copy operation is done. Also i need to make some connections when these are pasted to other document. -
On 16/09/2015 at 06:16, xxxxxxxx wrote:
Hi Ahmet,
currently we have no example. I will do my best to provide you with one in the next few days (not sure, I'll make it this week).
-
On 16/09/2015 at 08:02, xxxxxxxx wrote:
Hi Andreas,
Thanks for reply. After asking that i solved to catch COPY message. Please see my first codes. I hope that's correct way. Also trying to catch pasted objects and materials. You can see in second part of codes. In the case "MSG_DOCUMENTINFO_TYPE_PASTE", data->arr is always NULL. Is it expected behaviour? How can we get pasted C4DAtom's?case MSG_DOCUMENTINFO: { DocumentInfoData \*docinfo = (DocumentInfoData\* )data; Int32 docInfoType = docinfo->type; BaseList2D \*bl = docinfo->bl; String str=LS(docInfoType); switch(docInfoType) { case MSG_DOCUMENTINFO_TYPE_COPY: { //---- CATCH MATERIAL COPY OPERATION AND CLONE/STORE LINKED MATERIALS ----// DocumentInfoClipData \*d = (DocumentInfoClipData\* ) docinfo->data; for(int j=0;j<OCTLIVE->clonedMatLinks.GetCount();j++) { BaseLink \*link = OCTLIVE->clonedMatLinks[j]; if(!link) continue; BaseMaterial \*mat = (BaseMaterial\* ) link->ForceGetLink(); //if(mat) info("Delete stored mat:"+mat->GetName()); if(mat) BaseMaterial::Free(mat); BaseLink::Free(link); } OCTLIVE->clonedMatLinks.FreeArray(); OCTLIVE->copyOperationDoc = adoc; //---- CHECK COPYBUFFER FOR MATS/OBJECTS, ADD TO MATS ARRAY ----// GeDynamicArray<BaseMaterial\*> mats; for(int i=0;i<d->arr->GetCount();i++) { C4DAtom \*atom=d->arr->GetIndex(i); if(atom->IsInstanceOf(Obase)) //--- IT'S BASEOBJECT, GET MATERIALS ----// { BaseObject \*op = static_cast<BaseObject\*> (atom); for (BaseTag\* tag=op->GetFirstTag(); tag; tag=tag->GetNext()) { if(tag && tag->GetType()==Ttexture) { BaseMaterial \*mat = (Material\* )getParameterLink(\*tag, TEXTURETAG_MATERIAL, 0); if(mat && mats.Find(mat)==NOTOK) mats.Push(mat); } } } if(atom->IsInstanceOf(Mbase)) //---- BASEMATERIAL ----// { BaseMaterial \*mat = static_cast<BaseMaterial\*> (atom); if(mats.Find(mat)==NOTOK) mats.Push(mat); } } ...... ...... ...... ...... //---- CATCH MATERIAL PASTE OPERATION AND CREATE COPIED MATERIALS ----// case MSG_DOCUMENTINFO_TYPE_PASTE: { DocumentInfoClipData \*data = (DocumentInfoClipData\* ) docinfo->data; if(data) info("PASTE data:"+PS(data)+" "+PS(data->arr)); //--- avoid handling on same document ---// if(adoc==OCTLIVE->copyOperationDoc) return false; matPastePath=adoc->GetDocumentPath().GetDirectory().GetString();
-
On 16/09/2015 at 08:07, xxxxxxxx wrote:
Hi Ahmet,
I'm not sure, that it's the intended behavior, but unfortunately it is the behavior... you don't get the array on paste. But DocumentInfoClipData contains a BaseContainer (bcdata), which you can use to pass any data you need from copy to paste.
-
On 16/09/2015 at 08:22, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Hi Ahmet,
I'm not sure, that it's the intended behavior, but unfortunately it is the behavior... you don't get the array on paste. But DocumentInfoClipData contains a BaseContainer (bcdata), which you can use to pass any data you need from copy to paste.
So, how can i add additional materials to BaseContainer to be pasted? Thanks
-
On 16/09/2015 at 08:26, xxxxxxxx wrote:
To be honest, that's everything else than straight forward. One way might be to store the materials BaseContainer in the copy/paste BaseContainer and recreate it from there on paste.
You could be tempted to simply store a BaseLink on copy and then use ForceGetLink() on paste. But be warned, that will fail, if the user closes the original document after copy.
-
On 16/09/2015 at 08:32, xxxxxxxx wrote:
So what i understand that we don't have any info about pasted objects/materials in MSG_DOCUMENTINFO_TYPE_PASTE message. So should I do it manually copy them in COPY message and use in PASTE message?
-
On 16/09/2015 at 08:37, xxxxxxxx wrote:
I'm afraid, yes. At least that's what I am doing and I haven't found a better solution, yet.
-
On 16/09/2015 at 08:40, xxxxxxxx wrote:
Just to warn you, you will need a similar mechanism in order to get "Merge..." to work (MSG_DOCUMENTINFO_TYPE_BEFOREMERGE and MSG_DOCUMENTINFO_TYPE_MERGE), except that there's no BaseContainer prepared for you...
As said before, I plan to provide a "simple" example in the near future. -
On 16/09/2015 at 08:45, xxxxxxxx wrote:
Ok i see. Situations is a bit complex here. I'm duplicating linked materials which are linked to mix materials and i should remove the doubled copy of same mix material on paste and make relink. I think solutions should be to modify this "const AtomArray* arr" in DocumentInfoClipData. Thought is as an advice for future. I'll try to do with current way.
Thanks for all your helps,
Best regards -
On 16/09/2015 at 08:59, xxxxxxxx wrote:
I had to walk the road that lies ahead of you and I didn't like it...
Especially identifying the materials on paste can be really tricky. Can you perhaps give me some more detail on the materials and how they are linked? I mean, is it your own MaterialData material, that needs special handling? Or is it about special shaders linked into the standard material?
Here I had the situation, that I had my own shader, which then linked to some special resource. On Copy/Paste I needed to make sure, that on every copied material (actually every copied object, that may contain a shader), not only the material got copied, but also the special resource that was linked by the shader.
The copy part was actually quite easy (similar to your code above). But then on paste I needed to identify the pasted shaders, in order to repair the links. In the end I stored a pointer to my special resource inside of the shader (special care needs to be taken in CopyTo of the shader). Side note: Never ever dereference such a pointer! On copy I stored this pointer in the BaseContainer and on paste I could then walk all shaders looking for that pointer (using the pointer just as a compare key) and thus repair the link.
Not sure, if the above makes sense. It's a bit hard to explain in a few words.
-
On 16/09/2015 at 09:19, xxxxxxxx wrote:
I understand what you mean with pointers. I remember that i did similar tricks to store pointers to be sure. Because material pointers always change on previews, etc... I wrote them to BaseContainer from a Hook.
Here is my all code for pasting and fixing the links. This works as expected but problem is that Also C4D copies same mix material with empty linkage. I should find and replace with my cloned materials.//---- CATCH MATERIAL PASTE OPERATION AND CREATE COPIED MATERIALS ----// case MSG_DOCUMENTINFO_TYPE_PASTE: { DocumentInfoClipData \*data = (DocumentInfoClipData\* ) docinfo->data; if(data) info("PASTE data:"+PS(data)+" "+PS(data->arr)); //--- avoid handling on same document ---// if(adoc==OCTLIVE->copyOperationDoc) return false; matPastePath=adoc->GetDocumentPath().GetDirectory().GetString(); GeDynamicArray<BaseMaterial\*> mats; Int cnt = OCTLIVE->clonedMatLinks.GetCount(); adoc->StartUndo(); std::vector<BaseMaterial\*> pastedMats; //---- PASTE STORED MATERIALS TO DOCUMENT ----// for(int j=0;j<cnt;j++) { BaseLink \*link = OCTLIVE->clonedMatLinks[j]; if(!link) continue; BaseMaterial \*mat = (BaseMaterial\* ) link->ForceGetLink(); if(mat) { // info("Paste "+mat->GetName()); AutoAlloc<AliasTrans> aliasTrans; if (!aliasTrans || !aliasTrans->Init(mat->GetDocument())) return FALSE; BaseMaterial \*newMat=NULL; newMat = (BaseMaterial\* ) mat->GetClone(COPYFLAGS_RECURSIONCHECK, aliasTrans); aliasTrans->Translate(TRUE); if(newMat) adoc->InsertMaterial(newMat, NULL, false); if(newMat) adoc->AddUndo(UNDOTYPE_NEW, newMat); pastedMats.push_back(newMat); } } //---- MAKE NEW LINKS ----// for(int j=0;j<cnt;j++) { BaseLink \*link = OCTLIVE->clonedMatLinks[j]; if(!link) continue; BaseMaterial \*mat = (BaseMaterial\* ) link->ForceGetLink(); if(mat && mat->IsInstanceOf(ID_OCTANE_MIX_MATERIAL)) { BaseMaterial\* m1 = static_cast<BaseMaterial\*> (getParameterLink(\*mat, MIXMATERIAL_TEXTURE1, Mbase)); BaseMaterial\* m2 = static_cast<BaseMaterial\*> (getParameterLink(\*mat, MIXMATERIAL_TEXTURE2, Mbase)); Int n1=-1, n2=-1; for(int k=0;k<cnt;k++) if(m1==OCTLIVE->clonedMatLinks[k]->ForceGetLink()) n1=k; for(int k=0;k<cnt;k++) if(m2==OCTLIVE->clonedMatLinks[k]->ForceGetLink()) n2=k; if(n1!=-1) pastedMats[j]->SetParameter(DescLevel(MIXMATERIAL_TEXTURE1), GeData(pastedMats[n1]), DESCFLAGS_SET_0); if(n2!=-1) pastedMats[j]->SetParameter(DescLevel(MIXMATERIAL_TEXTURE2), GeData(pastedMats[n2]), DESCFLAGS_SET_0); } } EventAdd(); adoc->EndUndo(); } break;
-
On 16/09/2015 at 09:22, xxxxxxxx wrote:
Just remember that ForceGetLink() won't work, if the user closed the source document before pasting.
-
On 16/09/2015 at 09:25, xxxxxxxx wrote:
Originally posted by xxxxxxxx
Just remember that ForceGetLink() won't work, if the user closed the source document before pasting.
Yes thanks. I think that we face up to if there's not any other way?