Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    node interface similar to xpresso

    SDK Help
    0
    15
    2.5k
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      Helper
      last edited by

      On 31/12/2014 at 14:45, xxxxxxxx wrote:

      thanks a lot Sebastian , and happy new year 🙂

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 07/01/2015 at 15:12, xxxxxxxx wrote:

        Can some please post an example  of using the GvNodeGUI element to create a custom xpresso window in a GeDialog plugin?

        Nothing too fancy or elaborate. Just something quick and dirty without error checking to help me understand the basics of creating the master window. An how to add a node to it.
        I think I can use the SDK from there if I see how write the basic framework.

        Thanks,
        -ScottA

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 08/01/2015 at 07:10, xxxxxxxx wrote:

          Hello,

          a GvNodeGUI returns a GeUserArea that has to be added to the host dialog. A simple example can look like this:

            
          virtual Bool CreateLayout()  
          {  
           SetTitle("My Dialog");  
            
           if(_nodeGUI == nullptr)  
           {  
               _shape= GvGetWorld()->AllocShape();  
               _group= GvGetWorld()->AllocGroupShape();  
            
               _nodeGUI = GvGetWorld()->AllocNodeGUI(_shape,_group,1000);  
           }  
            
           if(_nodeMaster && _nodeGUI)  
           {  
               _nodeGUI->Attach(this,_nodeMaster);  
            
               AddUserArea(1000, BFH_SCALEFIT | BFV_SCALEFIT);  
               AttachUserArea(*_nodeGUI->GetUserArea(), 1000, USERAREA_TABSTOP|USERAREA_HANDLEFOCUS);  
           }  
            
           return true;  
          };  
          

          where _nodeGUI is the GVNodeGUI and _nodeMaster is the GvNodeMaster.

          Best wishes,
          Sebastian

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 08/01/2015 at 08:53, xxxxxxxx wrote:

            Thank you Sebastian. But that's not quite enough information.
            I still don't understand how to create _nodeGUI and _nodeMaster.

            Here is my entire working GeDialog plugin with a User Area attached to it.
            I'm trying to figure out how to use the UA as an xpresso window. But I'm having trouble understanding how to set up the basic framework for it.

            #include "c4d.h"  
            #include "c4d_symbols.h"  
            #include "ge_dynamicarray.h"  
              
            #define PLUGIN_ID 1000006  // be sure to use a unique ID obtained from www.plugincafe.com  
              
            enum  
            {  
              USERAREA = 3001  
            };  
              
            class MyUserArea : public GeUserArea  
            {  
              //For the mouse positions within the User Area while LMB dragging  
              LONG mouseX;  
              LONG mouseY;  
              LONG prevX;  
              LONG prevY;  
              
              public:  
                  MyUserArea(void);  
                  virtual Bool Init(void);  
                  virtual Bool GetMinSize(LONG &w,LONG &h);  
                  virtual void DrawMsg(LONG x1,LONG y1,LONG x2,LONG y2, const BaseContainer &msg);  
                  virtual Bool InputEvent(const BaseContainer& msg);  
                  virtual LONG Message(const BaseContainer &msg, BaseContainer &result);  
            };  
              
            MyUserArea::MyUserArea(void)  
            {}  
              
            Bool MyUserArea::Init(void)  
            {  
              return TRUE;  
            }  
              
            Bool MyUserArea::GetMinSize(LONG &w,LONG &h)  
            {  
              w = 200;  
              h = 200;  
              return TRUE;  
            }  
              
            void MyUserArea::DrawMsg(LONG x1,LONG y1,LONG x2,LONG y2, const BaseContainer &msg)  
            {  
              //To make the bitmaps more stable. Use OffScreenOn() before drawning them in GUI's  
              OffScreenOn();  
              DrawSetPen(COLOR_TEXT);          //Set a color for the UA  
              DrawRectangle(x1, y1, x2, y2);   //Draws the rectangle UserArea using the color  
            }  
              
            Bool MyUserArea::InputEvent(const BaseContainer& msg)  
            {  
              LONG dev = msg.GetLong(BFM_INPUT_DEVICE);     //Get the device being used (mouse, keyboard, etc...)  
              LONG chn = msg.GetLong(BFM_INPUT_CHANNEL);    //Get the device's component (LMB, MWheel, keyboard key, etc...)  
              
              if (dev==BFM_INPUT_MOUSE)  
              {  
                  //Create an action message and also get the UserArea's id. And store them in a container called action  
                  //This will be used later to tell the parent dialog that the UA has been changed in some manner  
                  BaseContainer action(BFM_ACTION);  
                  action.SetLong(BFM_ACTION_ID, GetId());  
                  action.SetLong(BFM_ACTION_VALUE, 0);  
              
                  //If the left mouse button is down...do some desired action  
                  if(chn==BFM_INPUT_MOUSELEFT)  
                  {   
                      LONG mx = msg.GetLong(BFM_INPUT_X);            //Get the mouses's X position  
                      LONG my = msg.GetLong(BFM_INPUT_Y);            //Get the mouses's Y position  
                      Bool dc = msg.GetBool(BFM_INPUT_DOUBLECLICK);  //Checks if the LMB was double clicked or not  
              
                      Global2Local(&mx,&my);                       //Converts the mouse positions to screen values relative to the UA                  
              
                      BaseContainer mState;                        //Create a container that we will store the mouse actions we do in this next loop  
                      while (GetInputState(BFM_INPUT_MOUSE,BFM_INPUT_MOUSELEFT, mState))  
                      {  
                          if (mState.GetLong(BFM_INPUT_VALUE)==0) break;  //If the state value is 0. The LMB is no longer down..so exit the loop  
              
                          LONG dx = mState.GetLong(BFM_INPUT_X);        //Store the mouse positions only while dragging it  
                          LONG dy = mState.GetLong(BFM_INPUT_Y);        //Store the mouse positions only while dragging it  
                          Global2Local(&dx,&dy);  
              
                          //We can't use any Draw functions in the  InputEvent() method. We have to do it in the DrawMsg() method  
                          //So we must pass the mouse coords to class level variables so the DrawMsg() method can use them  
                          prevX=dx;  
                          prevY=dy;  
                          mouseX=dx;  
                          mouseY=dy;  
              
                          GePrint("X Pos: " +LongToString(dx) + "   " +  "Y Pos: " +LongToString(dy));  
                          Redraw();  
                          //action.SetLong(BFM_ACTION_INDRAG,TRUE);  
                          //SendParentMessage(action);  
                      }  
                      Redraw();  
              
                      //Notify the parent dialog that the dragging is now finished  
                      action.SetLong(BFM_ACTION_INDRAG, FALSE);  
                      SendParentMessage(action);  
                  }  
              }  
              return TRUE;  
            }  
              
            LONG MyUserArea::Message(const BaseContainer &msg, BaseContainer &result)  
            {  
              switch (msg.GetId())  
              {  
                  //This code block returns the mouse's position in the UserArea without the LMB being pressed  
                  case BFM_GETCURSORINFO:  
                  {  
                      LONG mouseX = msg.GetLong(BFM_DRAG_SCREENX);  
                      LONG mouseY = msg.GetLong(BFM_DRAG_SCREENY);  
                      if (Screen2Local(&mouseX, &mouseY))  GePrint(LongToString(mouseX) + ", " + LongToString(mouseY));  
                  }  
                  break;    
              
              }  
              
              return GeUserArea::Message(msg, result);  
            }  
              
              
            enum  
            {  
              MY_TEXT = 1001  
            };  
            class MyDialog : public GeDialog  
            {  
              private:  
                 MyDialog *dlg;  
                 MyUserArea ua;        //Create an instance of the MyUserArea class to use in this dialog's class  
                 C4DGadget *ua_gui;    //Create a gizmo variable here so we can use it in all methods. Not just in CreateLayout()  
              
              public:  
                  MyDialog(void);  
                  ~MyDialog(void);  
                  virtual Bool CreateLayout(void);  
                  virtual Bool InitValues(void);  
                  virtual Bool Command(LONG id,const BaseContainer &msg);  
                  virtual LONG Message(const BaseContainer &msg,BaseContainer &result);  
              
            };  
              
            MyDialog::MyDialog(void)  
            {      
            }  
              
            MyDialog::~MyDialog(void)  
            {      
              GeFree(dlg);  
              GeFree(ua);  
            }  
              
            Bool MyDialog::CreateLayout(void)  
            {  
              Bool res = TRUE;  
              res = LoadDialogResource(IDS_RESDIALOG,NULL,0);  
              
              //This text box we'll add here in this .cpp file. And not from the external .res file  
              AddStaticText(MY_TEXT, BFH_SCALEFIT, 0,0, "my text", 0);  
              
              
              //Trying to create an Xpresso based UserArea...Not working!!!  
              if(_nodeGUI == nullptr)  
              {  
                  _shape = GvGetWorld()->AllocShape();  
                  _group = GvGetWorld()->AllocGroupShape();  
              
                  _nodeGUI = GvGetWorld()->AllocNodeGUI(_shape,_group,1000);  
              }  
              
              if(_nodeMaster && _nodeGUI)  
              {  
                  _nodeGUI->Attach(this,_nodeMaster);         
              
                  ua_gui = AddUserArea(USERAREA, BFH_SCALEFIT | BFV_SCALEFIT);  
                  //if(ua_gui) AttachUserArea(ua, ua_gui);  <---this works fine  
                  if(ua_gui) AttachUserArea(*_nodeGUI->GetUserArea(), 1000, USERAREA_TABSTOP|USERAREA_HANDLEFOCUS);  
              }  
              
              return res;  
            }  
              
            Bool MyDialog::InitValues(void)  
            {  
              //first call the parent instance  
              if (!GeDialog::InitValues()) return FALSE;      
              
              this->SetString(MY_TEXT,"Xpresso Node Example");  
              
              return TRUE;  
            }  
              
            Bool MyDialog::Command(LONG id,const BaseContainer &msg)  //This is where the code that does something goes  
            {  
              BaseDocument *doc = GetActiveDocument(); //Get the active document  
              
              //Set up some actions that will tell c4d that a gizmo has been triggered..We'll used those action variables later on in the switch code block  
              LONG myBtn = msg.GetLong(BFM_ACTION_VALUE);    //Assigns an action to a variable  
              GePrint(LongToString(myBtn));  
              
              EventAdd();  
              return TRUE;  
            }  
              
            LONG MyDialog::Message(const BaseContainer &msg, BaseContainer &result)  
            {  
              switch(msg.GetId())  
               {  
                 case BFM_INPUT:   //A dialog/userarea receives this message if any mouse or keyboard input is received  
              
                    if(msg.GetLong(BFM_INPUT_DEVICE) == BFM_INPUT_KEYBOARD) //If the input is from the keyboard  
                     {  
                       String input = msg.GetString(BFM_INPUT_ASC);     //Create a string type variable...   
                       GePrint(input);                                  //and assign it to the pressed key's unicode-text value  
                     }  
              
                    break;  
               }  //End the key pressed case loop /////////////////////////  
              
               return GeDialog::Message(msg,result);  
            }  
              
            class XnodeDialog : public CommandData  
            {  
              private:  
                  MyDialog dlg;  
              public:  
                  virtual Bool Execute(BaseDocument *doc);  
                  virtual Bool RestoreLayout(void *secret);          
            };  
              
            Bool XnodeDialog::Execute(BaseDocument *doc)  
            {  
              StopAllThreads();  
              return dlg.Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 300,150);  
            }  
              
            Bool XnodeDialog::RestoreLayout(void *secret)  
            {  
              return dlg.RestoreLayout(PLUGIN_ID,0,secret);  
            }  
              
            Bool RegisterXnodeDialog(void)  
            {           
              String Help = "Status bar text here...";  
              //Register the plugin  
              return RegisterCommandPlugin(PLUGIN_ID, "XNode Dialog Example", 0, AutoBitmap("icon.tif"),Help, gNew XnodeDialog);  
            }
            

            -ScottA

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 08/01/2015 at 09:27, xxxxxxxx wrote:

              Hello,

              as you can see in the code example _nodeGUI is created using AllocNodeGUI()[URL-REMOVED]. A GvNodeMaster can be created using AllocNodeMaster()[URL-REMOVED]. Both functions are part of GvWorld which can be obtained using GvGetWorld()[URL-REMOVED]. Make sure to properly manage the GvNodeMaster in a parent object by handling its creation, destruction and functions like ReadObject(), WriteObject() and CopyTo().

              Best wishes,
              Sebastian


              [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 08/01/2015 at 10:04, xxxxxxxx wrote:

                Oh I think I see.
                I don't need to create a UA gizmo myself. The GvGetWorld()->AllocNodeGUI() creates it?

                I added these class member variables to try to make your code work.
                     GvShape *_shape;
                     GvShape *_group;
                     GvNodeGUI *_nodeGUI;

                But I don't know who should be the master ("_nodeMaster") holding the GvNodeGUI?
                Do I have to use a BaseObject as the master or can it be the dialog?

                It's all very confusing without some simple example to see who goes where. And who does what.

                -ScottA

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 08/01/2015 at 12:02, xxxxxxxx wrote:

                  Made some progress...I think.🙂
                  But it crashes when the owner object is deleted. Or if I close C4D. Ouch!

                  #include "c4d.h"  
                  #include "c4d_symbols.h"  
                  #include "ge_dynamicarray.h"  
                  #include "c4d_graphview.h"  
                    
                  #define PLUGIN_ID 1000006  // be sure to use a unique ID obtained from www.plugincafe.com  
                    
                  enum  
                  {  
                    MY_TEXT = 1001  
                  };  
                  class MyDialog : public GeDialog  
                  {  
                    private:  
                       MyDialog *dlg;  
                    
                       //xpresso node stuff  
                       GvShape *_shape;  
                       GvShape *_group;  
                       GvNodeGUI *_nodeGUI;  
                       GvNodeMaster *_nodeMaster;  
                    
                    public:  
                        MyDialog(void);  
                        ~MyDialog(void);  
                        virtual Bool CreateLayout(void);  
                        virtual Bool InitValues(void);  
                        virtual Bool Command(LONG id,const BaseContainer &msg);  
                        virtual LONG Message(const BaseContainer &msg,BaseContainer &result);  
                    
                  };  
                    
                  MyDialog::MyDialog(void)  
                  {}  
                    
                  MyDialog::~MyDialog(void)  
                  {      
                    GeFree(dlg);  
                    GvGetWorld()->FreeShape(_shape);  
                    GvGetWorld()->FreeShape(_group);  
                    GvGetWorld()->FreeNodeGUI(_nodeGUI);  
                    GvGetWorld()->FreeNodeMaster(_nodeMaster);  //<---Not sure if this is freeing them properly?    
                  }  
                    
                  Bool MyDialog::CreateLayout(void)  
                  {  
                    Bool res = TRUE;  
                    res = LoadDialogResource(IDS_RESDIALOG,NULL,0);  
                    
                    //This text box we'll add here in this .cpp file. And not from the external .res file  
                    AddStaticText(MY_TEXT, BFH_SCALEFIT, 0,0, "my text", 0);  
                    
                    
                    //Create an Xpresso based UserArea  
                    if(_nodeGUI == nullptr)  
                    {  
                        GvShape *_shape = GvGetWorld()->AllocShape();  
                        GvShape *_group = GvGetWorld()->AllocGroupShape();  
                        _nodeGUI = GvGetWorld()->AllocNodeGUI(_shape,_group,1000);  
                    }  
                    
                    GvNodeMaster *_nodeMaster = GvGetWorld()->AllocNodeMaster(GetActiveDocument()->GetFirstObject(), TRUE, TRUE);  //Allocates a node master. Must be freed with FreeNodeMaster().  
                    if(_nodeMaster && _nodeGUI)  
                    {  
                        _nodeGUI->Attach(this,_nodeMaster);  
                        if(_nodeGUI) AttachUserArea(*_nodeGUI->GetUserArea(), 1000, USERAREA_TABSTOP|USERAREA_HANDLEFOCUS);  
                    }  
                    
                    return res;  
                  }  
                    
                  Bool MyDialog::InitValues(void)  
                  {  
                    //first call the parent instance  
                    if (!GeDialog::InitValues()) return FALSE;      
                    
                    this->SetString(MY_TEXT,"Xpresso Node Example");  
                    
                    return TRUE;  
                  }  
                    
                  Bool MyDialog::Command(LONG id,const BaseContainer &msg)  //This is where the code that does something goes  
                  {  
                    BaseDocument *doc = GetActiveDocument(); //Get the active document  
                    
                    //Set up some actions that will tell c4d that a gizmo has been triggered..We'll used those action variables later on in the switch code block  
                    LONG myBtn = msg.GetLong(BFM_ACTION_VALUE);    //Assigns an action to a variable  
                    GePrint(LongToString(myBtn));  
                    
                    EventAdd();  
                    return TRUE;  
                  }  
                    
                  LONG MyDialog::Message(const BaseContainer &msg, BaseContainer &result)  
                  {  
                    switch(msg.GetId())  
                     {  
                       case BFM_INPUT:   //A dialog/userarea receives this message if any mouse or keyboard input is received  
                    
                          if(msg.GetLong(BFM_INPUT_DEVICE) == BFM_INPUT_KEYBOARD) //If the input is from the keyboard  
                           {  
                             String input = msg.GetString(BFM_INPUT_ASC);     //Create a string type variable...   
                             GePrint(input);                                  //and assign it to the pressed key's unicode-text value  
                           }  
                    
                          break;  
                     }  //End the key pressed case loop /////////////////////////  
                    
                     return GeDialog::Message(msg,result);  
                  }  
                    
                  class XnodeDialog : public CommandData  
                  {  
                    private:  
                        MyDialog dlg;  
                    public:  
                        virtual Bool Execute(BaseDocument *doc);  
                        virtual Bool RestoreLayout(void *secret);          
                  };  
                    
                  Bool XnodeDialog::Execute(BaseDocument *doc)  
                  {  
                    StopAllThreads();  
                    return dlg.Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 300,150);  
                  }  
                    
                  Bool XnodeDialog::RestoreLayout(void *secret)  
                  {  
                    return dlg.RestoreLayout(PLUGIN_ID,0,secret);  
                  }  
                    
                  Bool RegisterXnodeDialog(void)  
                  {           
                    String Help = "Status bar text here...";  
                    //Register the plugin  
                    return RegisterCommandPlugin(PLUGIN_ID, "XNode Dialog Example", 0, AutoBitmap("icon.tif"),Help, gNew XnodeDialog);  
                  }
                  

                  -ScottA

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 09/01/2015 at 05:28, xxxxxxxx wrote:

                    Hello,

                    _nodeMaster  is a GvNodeMaster[URL-REMOVED] object that stores a node system. The GvNodeGUI is just a GUI to display that node system.

                    The GvNodeMaster object must be saved somewhere. Typically it is a member of a parent object, like the Xpresso tag that hosts a node system. When you call AllocNodeMaster()[URL-REMOVED] you must define that parent object.

                    This parent object must make sure that the GvNodeMaster object is handled correctly, that it is created and properly deleted and that it's content is written into a file and written to a file using ReadObject()[URL-REMOVED] and WriteObject()[URL-REMOVED] .

                    Best wishes,
                    Sebastian


                    [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 09/01/2015 at 07:22, xxxxxxxx wrote:

                      I tried assigning _nodeMaster to an xpresso tag. But it didn't work.
                      Also _nodeGUI is not producing anything in my GeDialog.

                      I think I know what all the parts are supposed to do.
                      I've written some xpresso code before.
                      But I can't figure out how to create the GUI in my GeDialog.

                      -ScottA

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 12/01/2015 at 01:05, xxxxxxxx wrote:

                        Hello,

                        you cannot "assign" a GvNodeMaster object to an existing object-intsance. As said before, it should be a member of an object so for example your own plugin object, material or tag class.

                        best wishes,
                        Sebastian

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 12/01/2015 at 07:15, xxxxxxxx wrote:

                          Thanks for trying Sebastian.

                          Even though I can't figure out how to put the xpresso window in my dialog. I was able to launch one from a button in my dialog. And when I do that I the nodes don't return any values. And I'm also getting memory leaks from the nodes I add with code.
                          They also get deleted when the dialog is closed. But I'm guessing that happens because I don't have the Read(),Write(), CopyTo() code in place yet.

                          At this pace it would take me a year for me to figure this all out.
                          I really need to see a working example. So I'm giving up on this for now.
                          All I can do is ask to please consider adding an example of this to the SDK in the future.

                          Thanks for trying,
                          -ScottA

                          1 Reply Last reply Reply Quote 0
                          • First post
                            Last post