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
    • Register
    • Register
    • Login

    Item selection in GvOperatorData::FillPortsMenu

    SDK Help
    0
    6
    1.1k
    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 30/08/2016 at 13:26, xxxxxxxx wrote:

      User Information:
      Cinema 4D Version:   17 
      Platform:    Mac  ;  
      Language(s) :     C++  ;

      ---------
      Following up from my other thread:

      https://developers.maxon.net/forum/topic/9659/12991_gvnodesettitle

      I've now have my own GvOperatorData plugin and can create my own nodes in the graph. I've also been able to add my own items to both the output and input ports menu via GvOperatorData::FillPortsMenu.

      One thing I'm not sure about is to how to add a port to the node. If I click on one of the items in the menu, nothing happens, which makes me think I need to add another method to my plugin, but I'm not sure which one I need to implement. I did see GvOperateorData::PortMenuCommand, but that seems to be associated with GvOperatorData::FillPortMenu.

      Thanks,
      Ian

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

        On 31/08/2016 at 03:23, xxxxxxxx wrote:

        Hi Ian,

        first of all, just in case you overlooked the option, you can define the available ports in the resource file and don't need to use FillPortsMenu() at all (as described in the thread you probably already know).
        Or in other words, is there a reason you need to use FillPortsMenu()?
        I will need to verify a few things on FillPortsMenu() and will get back to you hopefully later today.

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

          On 31/08/2016 at 07:58, xxxxxxxx wrote:

          Hi Andreas,

          Correct me if I'm wrong, but I was under the assumption that you can only have one .res file associated with a plugin? I was trying to just have one GvOperatorData to be able to represent any of our materials/patterns and using the FillPortsMenu method so that the ports can be dynamic.

          If the only solution is to have one GvOperatorData for each of our materials/patterns, I guess I could try to work with that, but it would make the code a lot more complicated.

          Thanks!
          Ian

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

            On 31/08/2016 at 08:50, xxxxxxxx wrote:

            Hi Ian,

            you are right, there's only one .res file associated with one GvOperatorData plugin. But you could register the same GvOperatorData several times with different unique plugin IDs and different resource files. So maybe that's an option as well.

            For me it still seems to lead to the simplest implementation to have one OperatorData class per node type, but of course I don't know the details of your implementation.

            On the other hand it should also be possible dynamically, but I will need time to come up with an example.
            So long at least a few infos on FillPortsMenu() :
            Make sure to use first_menu_id as a base when building the menu.
            Then you need to implement Message() and in there check type for GV_MESSAGE_PORTS_MENU. The data pointer is pointing to a BaseContainer, wherein you receive two things:
            A link to the GvNode (GV_MESSAGE_FIRST_DATA_ID) and the index of the selected menu item (GV_MESSAGE_FIRST_DATA_ID + 1, with first_menu_id already subtracted).
            So basically:

            case GV_MESSAGE_PORTS_MENU:
            {
            	BaseContainer* bcMsg = static_cast<BaseContainer*>(data);
            	GvNode* myNode = static_cast<GvNode*>(bcMsg->GetLink(GV_MESSAGE_FIRST_DATA_ID + 0, node->GetDocument()));
            	Int32 selected = bcMsg->GetInt32(GV_MESSAGE_FIRST_DATA_ID + 1);
            	// ...
            }
            

            As mentioned above, for some more complete example, I will need some more time, not sure I'll get it done today.

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

              On 31/08/2016 at 14:54, xxxxxxxx wrote:

              Thanks, Andreas. It sounds like it'll be less of a headache if I made one OperatorData per node type. I'll run with that for now and see where that takes me.

              Cheers!
              Ian

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

                On 01/09/2016 at 02:42, xxxxxxxx wrote:

                Hi Ian,

                even if you chose to take another approach, I'll add my findings here for completeness.

                So with FillPortsMenu() you can override the menus in the top corners of a node. There are only two things to be considered: The menu is overwritten completely, so if has already ports defined in a resource file, one has to list these in the menu manually. Furthermore all menu IDs need to be greater or equal first_menu_id, otherwise it won't work.

                So FillPortsMenu() could look like so:

                Int32 GvOperatorDataExample::FillPortsMenu(GvNode* bn, BaseContainer& names, BaseContainer &ids, GvValueID value_type, GvPortIO port, Int32 first_menu_id)
                {
                	// Init defaults for inputs (port == GV_PORT_INPUT)
                	Int32 portIdBase = ID_DYNAMIC_IN_PORT_BASE;
                	Int32 menuIdBase = 0; // Different menu IDs for in and out in order to be able to differentiate in Message() (if the message is needed at all)
                	String nameBase = "My in port #";
                	Int32 numPorts = 2;
                  
                	if (port == GV_PORT_OUTPUT)
                	{
                		portIdBase = ID_DYNAMIC_OUT_PORT_BASE;
                		menuIdBase = 1000;
                		nameBase = "My out port #";
                		numPorts = 3;
                	}
                  
                	for (Int32 idxPort = 0; idxPort < numPorts; ++idxPort)
                	{
                		const Int32 menuId = first_menu_id + menuIdBase + idxPort;
                		const Int32 portId = portIdBase + idxPort;
                		String nameMenuEntry = nameBase + String::IntToString(idxPort);
                  
                		// Deactivate entries for existing ports
                		GvPort* port = nullptr;
                		if (portIdBase < ID_DYNAMIC_OUT_PORT_BASE)
                			port = bn->GetInPortFirstMainID(portId);
                		else
                			port = bn->GetOutPortFirstMainID(portId);
                		if (port)
                			nameMenuEntry += "&d&";
                  
                		names.SetString(menuId, nameMenuEntry);
                		ids.SetInt32(menuId, portId);
                	}
                	return numPorts; // Number of added entries
                }
                

                If you need to, you could react to the user clicking a menu entry by the message GV_MESSAGE_PORTS_MENU described in my last post. But you actually don't have to. All you need to do to make it work, is to implement iGetPortDescription() and care for the ports there:
                For example like so, only inports shown:

                if ((id >= ID_DYNAMIC_IN_PORT_BASE) && (id < (ID_DYNAMIC_IN_PORT_BASE + ID_DYNAMIC_PORT_RANGE)))
                {
                	pd->name = "My custom in port " + String::IntToString(id - ID_DYNAMIC_IN_PORT_BASE);
                	pd->flags = (GvPortDescFlags)(GV_PORTDESCRIPTION_PORTONLY);
                	pd->data_id = ID_GV_DATA_TYPE_INTEGER;
                	pd->ports_min = 0; // only needed with GV_PORTDESCRIPTION_MULTIPLE
                	pd->ports_max = 0;
                	pd->parent_id = bn->GetNodeID();
                	return true;
                }
                
                1 Reply Last reply Reply Quote 0
                • F Filip referenced this topic on
                • First post
                  Last post