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 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