Seperator Tag Plugin



  • On 03/06/2016 at 11:56, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   12 
    Platform:   Windows  ;   
    Language(s) :   C.O.F.F.E.E  ;

    ---------
    Hi

    I always have objects with enormous numbers of vertex map tags and because all of these vertex tags look the same, I would like to write a plugin that will simply add a seperator between the tags so that I can kind of group them into sections. One should be able to select the tag and, in the attributes manager, one must then have a field where one can specify an icon for the tag and maybe a list of the vertex tags that is between the selected seperator tag and the next seperator tag (or the end of the row of tags.)

    I have, over the course of the year so far, gained quite a bit of COFFEE scripting knowledge but I don't have the faintest idea as to how to even start on creating such a plugin. My delema lies in that, I don't know how to create the unique tag, its attribute manager interface or how to specify the icon.

    There are some cool tutorials for Python but I want to do this in COFFEE as I regularly still go back to R10.5 for certain things that require plugins for which there weren't upgrades beyond R10.5 and I'd like to duplicate the plugin there.

    Can someone please help me with this or point me towards a tutorial that can assist me? I would appreciate that tremendously.

    Thanks in advance.



  • On 03/06/2016 at 12:25, xxxxxxxx wrote:

    There are a few examples in the online SDK:
    https://developers.maxon.net/docs/Cinema4DCOFFEESDK/index.htm

    Tags are under Delta Time Plugins section
    Not much in there. But it's a start.

    -ScottA



  • On 04/06/2016 at 12:19, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    There are a few examples in the online SDK:
    https://developers.maxon.net/docs/Cinema4DCOFFEESDK/index.htm

    Tags are under Delta Time Plugins section
    Not much in there. But it's a start.

    -ScottA

    Hi Scott
    Thank you very much for your help yet again. I checked out the examples in the SDK and I gained some knowledge as to how to construct the plugin. However, neither of the 2 examples appears to show how to define an interface that should display in the attributes manager when one clicks on the tag and how to access it. And that's really my biggest headache in this case?

    Could you perhaps shed some light in regard to the interface, please? Even if you know of a really simple open source tag plugin I could examine, it would help me a great deal.



  • On 04/06/2016 at 16:56, xxxxxxxx wrote:

    It's been a very long time since I've used COFFEE. So I could be wrong about this.
    But if I remember correctly. COFFEE can't make tag plugin's that have an AM GUI.
    Someone please correct me if I'm wrong.

    I can show you how to manipulate the host object with a GeDialog that pops up when you click on the tag if you want.  But AFAIK AM GUI's are not possible with COFFEE.
    You're going to keep on running into these limitations with COFFEE. It's fairly weak at making plugins.

    C++ was really the only good plugin writing option in C4D before Python came along.

    -ScottA



  • On 05/06/2016 at 09:28, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    It's been a very long time since I've used COFFEE. So I could be wrong about this.
    But if I remember correctly. COFFEE can't make tag plugin's that have an AM GUI.
    Someone please correct me if I'm wrong.

    I can show you how to manipulate the host object with a GeDialog that pops up when you click on the tag if you want.  But AFAIK AM GUI's are not possible with COFFEE.
    You're going to keep on running into these limitations with COFFEE. It's fairly weak at making plugins.

    C++ was really the only good plugin writing option in C4D before Python came along.

    -ScottA

    Thank you for your help & your patience. It would be awesome if you could show me GeDialog manipulation, please. Would it be difficult to make it non-modal? The reason I initially wanted it in the AM, is because I'd like to lock it & select maps from the list that I mentioned I wanted to put into the interface. With a non-modal dialog, I wouldn't need the AM interface because I'd be able to have the dialog float and select maps from the list without having to double-click on the tag everytime.



  • On 05/06/2016 at 11:16, xxxxxxxx wrote:

    I don't think you can use a non modal dialog that way.
    A tag's AM GUI is linked to the object the tag is on via descriptions. And if you did that with an Async GeDialog you would probably lock up C4D. Because GeDialogs run in the main thread. Thus blocking the user from doing anything. Even if it was set to Async.
    A dialog typically needs to execute some task/tasks and then finish. Not run continuously like an expression or a tag.
    You might be better off writing a GeDialog plugin that's in the plugins folder. And make it target the active object. Just don't try to make the dialog continuously execute like a tag.

    Here is an example of a tag plugin with a dialog.
    But the dialog is modal.

      
    //This is a sample plugin that opens a dialog when the tag is double clicked so you can attach GUI items to the tags using Coffee  
      
    //INSTRUCTIONS:  
    //Create a new folder named whatever you want  
    //Copy all of this code into a text file with the file extension .cof and put it in that folder  
    //Create a 32x32 .tif image named "plugintagicon.tif" and put it that folder  
    //Then put the folder in your C4D plugins folder  
      
      
    const var PLUGIN_ID = 10000009; // THIS id IS FOR TESTING PURPOSES ONLY!!!!  
      
    enum // Assigns id numbers to your GUI items so you don't have to create them on the fly later on  
    {  
      PLUGIN_DIALOG = 10000,  
      group1,  
      X_POSITION,  
      Y_POSITION,  
      Z_POSITION,  
      X_ROTATION,  
      Y_ROTATION,  
      Z_ROTATION,  
      METHOD_TYPE,  
      METHOD_ENABLE,  
          
      _DUMMY01_  
    };  
      
      
    //A custom method that moves and rotates the object this tag plugin is on  
    DoThis(obj, bc)  
    {  
      //Sets the position of the obj  
      var pos = obj->GetPosition();  
      pos.x = bc->GetFloat(X_POSITION);  
      pos.y = bc->GetFloat(Y_POSITION);  
      pos.z = bc->GetFloat(Z_POSITION);  
      obj->SetPosition(pos);  
      obj->Message(MSG_UPDATE);  
        
      var rot = obj->GetRotation();  
      rot.x = bc->GetFloat(X_ROTATION);  
      rot.y = bc->GetFloat(Y_ROTATION);  
      rot.z = bc->GetFloat(Z_ROTATION);  
      obj->SetRotation(rot);  
      obj->Message(MSG_UPDATE);  
    }  
      
    //////////////////////////////////  
    //The dialog class for the plugin  
    //////////////////////////////////  
    class PluginDialog : GeModalDialog  
    {  
      public:  
      var bc;  
      PluginDialog();  
      GetContainer();  
      SetContainer(_bc);  
      CreateLayout();  
      Init();    
      Command(id, msg);  
        
      private:    
      ContainerToDialog();  
      DialogToContainer();  
    }  
      
    PluginDialog::PluginDialog()   
    {   
      super();  
      bc = new(BaseContainer);  
    }  
      
    PluginDialog::GetContainer() { return bc->GetClone(); }  
    PluginDialog::SetContainer(_bc) { bc = _bc->GetClone(); }  
      
    PluginDialog::CreateLayout()  
    {  
      AddGroupBeginV(800, BFV_SCALEFIT, 1, "Position Group", 0);  
      AddGroupBorder(BORDER_GROUP_IN);  
      AddGroupBorderSpace(10, 10, 10, 10);   
      AddGroupSpace(4, 4);  
      
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "X slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"X Position",0);  
      AddEditSlider(X_POSITION, BFH_SCALEFIT, 100, 10); //id, flags, width,height  
        
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "Y slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"Y Position",0);  
      AddEditSlider(Y_POSITION, BFH_SCALEFIT, 100, 10); //id, flags, width,height  
        
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "Z slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"Z Position",0);  
      AddEditSlider(Z_POSITION, BFH_SCALEFIT, 100, 10); //id, flags, width,height  
      
      AddGroupEnd();    
      AddGroupEnd();  
      AddGroupEnd();  
      AddGroupEnd();  
      
      AddGroupBeginV(800, BFV_SCALEFIT, 1, "Rotation Group", 0);  
      AddGroupBorder(BORDER_GROUP_IN);  
      AddGroupBorderSpace(10, 10, 10, 10);   
      AddGroupSpace(4, 4);  
        
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "Y slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"Y Rotation",0);  
      AddEditSlider(X_ROTATION, BFH_SCALEFIT, 100, 10); //id, flags, width,height    
      
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "X slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"X Rotation",0);  
      AddEditSlider(Y_ROTATION, BFH_SCALEFIT, 100, 10); //id, flags, width,height   
        
      AddGroupBeginH(group1, BFH_SCALEFIT, 3, "Z slider", 0);  
      AddStaticText(0,BFH_LEFT,0,0,"Z Rotation",0);  
      AddEditSlider(Z_ROTATION, BFH_SCALEFIT, 100, 10); //id, flags, width,height  
      
      AddGroupEnd();    
      AddGroupEnd();  
      AddGroupEnd();  
      AddGroupEnd();  
      
      AddDlgGroup(DR_DLGGROUP_OK);  
      AddDlgGroup(DR_DLGGROUP_CANCEL);  
    }  
      
      
    PluginDialog::Init()  
    {   
      ContainerToDialog();  
    }  
      
    PluginDialog::ContainerToDialog()  
    {  
      //Transfer data from the container to the dialog  
      SetMeter(X_POSITION, bc->GetFloat(X_POSITION), -1000, 1000, .1); // id, value, min, max, step  
      SetMeter(Y_POSITION, bc->GetFloat(Y_POSITION), -1000, 1000, .1); // id, value, min, max, step  
      SetMeter(Z_POSITION, bc->GetFloat(Z_POSITION), -1000, 1000, .1); // id, value, min, max, step  
        
      SetRadians(X_ROTATION, bc->GetFloat(X_ROTATION), -6.28319, 6.28319, .0174533); // id, value, min, max, step  
      SetRadians(Y_ROTATION, bc->GetFloat(Y_ROTATION), -6.28319, 6.28319, .0174533); // id, value, min, max, step    
      SetRadians(Z_ROTATION, bc->GetFloat(Z_ROTATION), -6.28319, 6.28319, .0174533); // id, value, min, max, step  
        
      Enable(METHOD_TYPE, bc->GetInt(METHOD_ENABLE, FALSE));  
    }  
      
    PluginDialog::DialogToContainer()  
    {  
      //Transfer data from the dialog to the container  
      bc->SetData(X_POSITION, GetMeter(X_POSITION));  
      bc->SetData(Y_POSITION, GetMeter(Y_POSITION));  
      bc->SetData(Z_POSITION, GetMeter(Z_POSITION));  
        
      bc->SetData(X_ROTATION, GetRadians(X_ROTATION));  
      bc->SetData(Y_ROTATION, GetRadians(Y_ROTATION));  
      bc->SetData(Z_ROTATION, GetRadians(Z_ROTATION));    
      bc->SetData(METHOD_TYPE, GetItem(METHOD_TYPE));  
    }  
      
    PluginDialog::Command(id, msg)  
    {  
      DialogToContainer(); //Get the current state      
    }  
      
      
    //////////////////////  
    //The Tag's class  
    //////////////////////  
    var tagIcon;  
      
    class MyExpressionTag : ExpressionPluginTag  
    {  
      public:  
      MyExpressionTag();    
      GetID();    
      GetIcon();  
      MultipleAllowed();  
      DisplayAllowed();  
      GetHelpText();  
      Edit();  
      Execute(doc, op);    
      UseMenu();  
      GetName();  
    }  
      
    MyExpressionTag::MyExpressionTag() { super(); }  
    MyExpressionTag::GetID()               { return PLUGIN_ID; }  
    MyExpressionTag::GetIcon()             { return tagIcon; }  
    MyExpressionTag::MultipleAllowed()     { return TRUE; } //Don't allow multiple tags  
    MyExpressionTag::DisplayAllowed()      { return TRUE; }  
    MyExpressionTag::GetHelpText()         { return "My GUI Coffee Tag Plugin"; }  
    MyExpressionTag::UseMenu() { return TRUE; }  
    MyExpressionTag::GetName() { return "My GUI Tag"; }  
      
    MyExpressionTag::Edit()  
    {  
      //This function executes only when the open tag dialog is closed using the Enter action  
        
      var bc = GetContainer();  
      bc->SetData(METHOD_ENABLE, FALSE);  
      
      var dialog = new(PluginDialog);  
      dialog->SetContainer(bc);  
      dialog->Open(-1,-1);  
      
      if (dialog->GetResult())  
          SetContainer(dialog->GetContainer());  
      else return FALSE;  
      
      return TRUE;  
    }  
      
    MyExpressionTag::Execute(doc, op)  
    {      
      //This function executes when the timeline is running. Or something is changed in the scene  
      //If you need to monitor an object's current state. This is where to put the code.    
      
      DoThis(op, GetContainer());   
                
      return TRUE;  
    }  
      
    /////////////////////////////////////////////  
    //This section registers the plugin with C4D   
    /////////////////////////////////////////////  
    main()  
    {   
      // Get the icon  
      var fn = GeGetRootFilename();  
      fn->RemoveLast();  
      fn->AddLast("plugintagicon.tif"); //<----Change this to your own image file  
      tagIcon = new(BaseBitmap,1,1);  
      tagIcon->Load(fn);  
      
      Register(MyExpressionTag);    
    }
    

    -ScottA



  • On 06/06/2016 at 12:12, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I don't think you can use a non modal dialog that way.
    A tag's AM GUI is linked to the object the tag is on via descriptions. And if you did that with an Async GeDialog you would probably lock up C4D. Because GeDialogs run in the main thread. Thus blocking the user from doing anything. Even if it was set to Async.
    A dialog typically needs to execute some task/tasks and then finish. Not run continuously like an expression or a tag.
    You might be better off writing a GeDialog plugin that's in the plugins folder. And make it target the active object. Just don't try to make the dialog continuously execute like a tag.

    Here is an example of a tag plugin with a dialog.

    -ScottA

    Wow, that is very, very kind of you, thank you so much. I'm very sure this will help me immensely.

    Thank you



  • On 07/06/2016 at 04:26, xxxxxxxx wrote:

    Not 100% sure if Scott was saying the same thing: You can make the dialog exchange data with the tag,
    and the tag does its work as an expression. You can make a button in the Tag's description (ie. in the
    attribute manager) to open the dialog that edits the tag (similar to the Expression Editor for COFFEE and
    Python Tags/Python Generators).



  • On 07/06/2016 at 07:09, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    You can make a button in the Tag's description (ie. in the
    attribute manager) to open the dialog that edits the tag).

    According to my notes. We can't do that with COFFEE. It's not supported.
    I think this question was as asked on CGTalk a long time ago. And that's where I got the "Not Supported" answer from.

    -ScottA



  • On 07/06/2016 at 07:55, xxxxxxxx wrote:

    My bad for not recognizing it's about COFFEE. 😊 You're example that implements PluginTag::Edit()
    is probably the best available option then. :)



  • On 10/06/2016 at 05:10, xxxxxxxx wrote:

    Scott & NiklasR, thank you very much for your replies and sorry for only replying now.

    It only occurred to me last night that there's a free COFFEE plugin which has a dialog setup exactly like what I want to make with mine. The dialog of Fabian's MirrorPointPosition plugin has a non-modal dialog when you double-click on the plugin. However, even though he kindly supplies the COFFEE code with his plugin, his scripting skills are so many light years beyond mine that I can't seem to figure out how he does it.



  • On 10/06/2016 at 08:02, xxxxxxxx wrote:

    I took a quick look at that plugin's code. And he's doing what I said earlier about using a GeDialog to target the active object. Only he goes one step farther, and targets a custom tag on the active object.

    The tag in his plugin is only there to hold some data.
    C4D creates these kinds of vertex tags automatically when you make a new object. But they are hidden by default.
    But you can also make your own tag to hold the data like he did.

    The key components are:
    1- GeDialog class: The non modal dialog with all the gizmos in it
    2- Command class: Launches the GeDialog from the C4D plugins menu (hosts the GeDialog when it's closed)
    3- ExpressionPluginTag class: The tag plugin

    Depending on what you want to do. You might not need the tag plugin part. It's only there to hold some specific data.
    But in any case. If you want to write plugins in any language. You will need to get a good grip on writing classes and class methods.
    Scripts don't use classes very often. But that's what plugins are all about. Classes and methods.
    There's a ton of tutorials about that on the internet. But it will probably take you a bit of head banging before it finally clicks. It's a necessary thing to learn to make plugins.

    -ScottA



  • On 10/06/2016 at 16:23, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    I took a quick look at that plugin's code. And he's doing what I said earlier about using a GeDialog to target the active object. Only he goes one step farther, and targets a custom tag on the active object.

    The tag in his plugin is only there to hold some data.
    C4D creates these kinds of vertex tags automatically when you make a new object. But they are hidden by default.
    But you can also make your own tag to hold the data like he did.

    The key components are:
    1- GeDialog class: The non modal dialog with all the gizmos in it
    2- Command class: Launches the GeDialog from the C4D plugins menu (hosts the GeDialog when it's closed)
    3- ExpressionPluginTag class: The tag plugin

    Depending on what you want to do. You might not need the tag plugin part. It's only there to hold some specific data.
    But in any case. If you want to write plugins in any language. You will need to get a good grip on writing classes and class methods.
    Scripts don't use classes very often. But that's what plugins are all about. Classes and methods.
    There's a ton of tutorials about that on the internet. But it will probably take you a bit of head banging before it finally clicks. It's a necessary thing to learn to make plugins.

    -ScottA

    Hi Scott

    Thank you very much for having a look at the code and giving your insights.

    I suspected that a full fledged plugin would be much more complex than the scripts I've been delving into. It appears I'll have to start looking into C++ as that will also help me overcome some of the limitations associated with COFFEE. However, just the thought of it, makes my hair stand on end. I think I'll have to follow your course on Youtube to begin with and work from there but that will have to wait untill I've got more time on my hands. Untill then I'll see if I can grasp the classes and stuff as that really makes my head spin.

    Thanks again.



  • On 10/06/2016 at 17:21, xxxxxxxx wrote:

    Many of COFFEEs limitations can be circumvented with Python already. While it's still limiting in some areas, it's certainly powerful in most others.



  • On 10/06/2016 at 18:00, xxxxxxxx wrote:

    And the slight learning curve for Python and the C4D Python API is well worth the power gained over COFFEE.



  • On 10/06/2016 at 18:18, xxxxxxxx wrote:

    He's stuck with R12 which doesn't support Python.
    So Python is not an option for him guys.

    -ScottA



  • On 10/06/2016 at 18:24, xxxxxxxx wrote:

    There was Py4D but it wasn't integrated into C4D yet and probably not totally compatible with the integrated API, I agree.



  • On 13/06/2016 at 08:51, xxxxxxxx wrote:

    Hey guys,

    nice discussion you have going on here.

    Not sure the SDK team can contribute much more here.
    In general we recommend to use the latest version of C4D (which seems to be no option here) and from our point of view Python would be the road to go. Also we can support only the latest version of C4D. While we usually try to stretch this rule as far as possible, I'm afraid R12 or even R10.5 are completely out of our scope. Sorry.



  • On 13/06/2016 at 23:08, xxxxxxxx wrote:

    Thank you to everyone who responded. I really appreciate the help & insights tremendously.

    Originally posted by xxxxxxxx

    Hey guys,

    nice discussion you have going on here.

    Not sure the SDK team can contribute much more here.
    In general we recommend to use the latest version of C4D (which seems to be no option here) and from our point of view Python would be the road to go. Also we can support only the latest version of C4D. While we usually try to stretch this rule as far as possible, I'm afraid R12 or even R10.5 are completely out of our scope. Sorry.

    Hi Andreas

    I didn't intend to upset the forum guidelines so could you please clarify: Should I rather not pose questions about COFFEE scripting here? Should I rather post on a 3rd party forum like CGTalk? I don't think my question was version specific and I only mentioned my version situation so that it would be clear that I was specifically seeking COFFEE help.



  • On 14/06/2016 at 00:37, xxxxxxxx wrote:

    Hi Uncle-Ox,

    I'm sorry, that wasn't my intention.
    You didn't upset any forum guidelines. Everything's alright. It's fine to post COFFEE questions in here. I just wanted to say, that we have no better ideas, than already discussed.
    And of course you are also free to discuss older versions (only partly the case here, I know), even if the SDK team might not be able to help in such cases.


Log in to reply