Layout Dynamically Created GUI's



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 10:04, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   12 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hey Guys,

    I'm spawing LinkBox and EditNumber GUI's in a tag plugin. And I'm having trouble laying them out horizontally in pairs.
    By default, when they are created the LinkBox GUI's are all stacked linear from top to bottom. And so are the EditNumber GUI's. Which is not what I want.
    I want the EditNumber GUI's to be placed to the right of the LinkBox GUI's as they are spawned. But I can't find any way to do this.
    I've tried all manner of groups and column stuff. But I can't seem to get them to layout horizontally.

    Here's my .cpp code that spawns the GUI's. And attempts to lay them out horizontally.

      DescID cid = DescLevel(6001, DTYPE_GROUP, 0);   //Begin the Main Group code  
      if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
      {  
      BaseContainer maingroup = GetCustomDataTypeDefault(DTYPE_GROUP);  
      maingroup.SetString(DESC_NAME, "Main Group");  
      maingroup.SetBool(DESC_LAYOUTGROUP, TRUE);  
      maingroup.SetLong(DESC_COLUMNS, 2);  
      
        
      
      linkboxBc = GetCustomDataTypeDefault(DTYPE_LONG);     //Add this to the container  
      linkboxBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_LINKBOX);  //Add this to the container  
      linkboxBc.SetLong(DESC_FORBID_SCALING,TRUE);          //Add this to the container  
      linkboxBc.SetBool(DESC_REMOVEABLE,TRUE);              //Add this to the container  
      linkboxBc.SetBool(DESC_ALIGNLEFT,TRUE);  
      linkboxBc.SetBool(DESC_SCALEH,TRUE);  
        
      
      frameBc = GetCustomDataTypeDefault(DTYPE_REAL);       //Add this to the container  
      frameBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_REAL);          //Add this to the container  
      frameBc.SetBool(DESC_REMOVEABLE,TRUE);                //Add this to the container  
      frameBc.SetLong(DESC_FORBID_SCALING,TRUE);          //Add this to the container  
      frameBc.SetBool(DESC_REMOVEABLE,TRUE);              //Add this to the container  
      frameBc.SetBool(DESC_ALIGNLEFT,TRUE);  
      frameBc.SetBool(DESC_SCALEH,TRUE);  
      
      //Create LINKBOX GUI's  
      for (int i=4000L; i<index; i++)  
      {  
      if (!myswitch)  
       {  
        myswitch = TRUE;  
        DescID newLinkboxid = DescLevel(i,DTYPE_LONG,0);  
        if(!singleid || newLinkboxid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
         {  
          linkboxBc.SetString(DESC_NAME,"Controller Object" + LongToString(i));      //Set the LinkBox text name  
          linkboxBc.SetString(DESC_SHORT_NAME,"Controller Object" + LongToString(i));  
          description->SetParameter(newLinkboxid,linkboxBc,DescLevel(ID_OBJECTPROPERTIES)); //Update the changes made to the container  
         }  
       }  
        myswitch = FALSE;  //Reset the variable back to false  
      }  
      
      
      //Create editable number field GUI's with their own ID's separate from the LinkBox GUI's  
      index = data->GetReal(NUMofGUIS)+5000L;  
      for (int i=5000L; i<index; i++)  
      {  
      if (!myswitch)  
       {  
        myswitch = TRUE;      
        DescID newFrameid = DescLevel(i,DTYPE_REAL,0);  
        if(!singleid || newFrameid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
         {  
          frameBc.SetString(DESC_NAME,"Frame" + LongToString(i));        //Set the Frame text name  
          frameBc.SetString(DESC_NAME,"Frame" + LongToString(i));  
      
          description->SetParameter(newFrameid,frameBc,DescLevel(ID_OBJECTPROPERTIES)); //Update the changes made to the container  
         }  
       }  
        myswitch = FALSE;  //Reset the variable back to false  
      }  
      
      if (!description->SetParameter(cid, maingroup, DescLevel(0))) return TRUE;  //End of the main group code   
    }
    

    I'm wondering if I have to use the .res file to layout these GUI's horizontally?
    And If I do. Since I'm dynamically creating and removing these GUI's. How would I handle that kind of thing in the .res file?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 11:03, xxxxxxxx wrote:

    Use groups (GROUP) with COLUMNS element to enclose those descriptions that you want horizontally placed.  You can do this dynamically just like any other element (DTYPE_GROUP).

    BaseContainer    gbc =    GetCustomDataTypeDefault(DTYPE_GROUP);  
    gbc.SetBool(DESC_HIDE,                FALSE);  
    gbc.SetLong(DESC_COLUMNS,            2L);  
    DescID descID =    DescID(DescLevel(id));  
      
    if (!description->SetParameter(DescLevel(gidx,DTYPE_GROUP,0L), gbc, descID))        return FALSE;  
    

    Where descID is the id of the group into which to put this group.  You then add elements to the new group by using DescID gid = DescID(DescLevel(gidx) and putting gid as the last argument for the other elements.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 13:10, xxxxxxxx wrote:

    Thanks Robert,
    But as usual I'm too dumb to follow you.

    -I don't understand what you're saying about using "gidx" to add new elements?

    -QUOTE: "Where descID is the id of the group into which to put this group"
    Group into group?
    I don't understand what this means.
    Are you saying that I need to wrap each GUI in it's own group first. And then take those groups and put them into a main group?

    My head is spinning.

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 14:24, xxxxxxxx wrote:

    Just like every element you used in your example uses in SetParameter().  ID_OBJECTPROPERTIES is an enumerated value that represents a tab(bed group) in the Attributes Manager description display - it is a GROUP. :)  Groups placed under these tab groups are not tab groups but allow for some horizontal organization of elements in a tabbed group.

    gidx is simply a variable holding some number.  You can make an enum like ID_OBJECTPROPERTIES instead or, if the groups are more dynamic, use a variable like 'gidx' to hold unique, incremented numbers (say, if you need an unpredetermined number of horizontal sets of element).

    To illustrate, you have something like this:

    Object (tabbed group desc.)
    -- Group A (2 columns, group desc.)
    ---- Element1 (desc.)  Element2 (desc.)
    -- Group B ((2 columns, group desc.)
    ---- Element3 (desc.) Element4 (desc.)

    Every desc. needs to know its parent group desc..  This is set in SetParameter as the last argument.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 15:21, xxxxxxxx wrote:

    Ok. Thanks a lot for the information.
    It's enlightening. But I'm afraid it's not going to help me though. I'm just too green to use it.

    Once I have a basic framework to start from. I'm sure the information you've provided about how each part works will be very useful. But right now I'm just too lost on how to build even the most basic framework for this.

    I'll keep trying to figure it out. Maybe I'll eventually get lucky.

    Thanks for the help,
    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 17:50, xxxxxxxx wrote:

    Try it like this.  I've modified your code slightly.  Note the change to where the elements are added and where the maingroup is created.

      DescID cid = DescLevel(6001, DTYPE_GROUP, 0);   //Begin the Main Group code  
      if (!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
      {  
      BaseContainer maingroup = GetCustomDataTypeDefault(DTYPE_GROUP);  
      maingroup.SetString(DESC_NAME, "Main Group");  
      maingroup.SetBool(DESC_LAYOUTGROUP, TRUE);  
      maingroup.SetLong(DESC_COLUMNS, 2);  
      
      linkboxBc = GetCustomDataTypeDefault(DTYPE_LONG);     //Add this to the container  
      linkboxBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_LINKBOX);  //Add this to the container  
      linkboxBc.SetLong(DESC_FORBID_SCALING,TRUE);          //Add this to the container  
      linkboxBc.SetBool(DESC_REMOVEABLE,TRUE);              //Add this to the container  
      linkboxBc.SetBool(DESC_ALIGNLEFT,TRUE);  
      linkboxBc.SetBool(DESC_SCALEH,TRUE);  
        
      frameBc = GetCustomDataTypeDefault(DTYPE_REAL);       //Add this to the container  
      frameBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_REAL);          //Add this to the container  
      frameBc.SetBool(DESC_REMOVEABLE,TRUE);                //Add this to the container  
      frameBc.SetLong(DESC_FORBID_SCALING,TRUE);          //Add this to the container  
      frameBc.SetBool(DESC_REMOVEABLE,TRUE);              //Add this to the container  
      frameBc.SetBool(DESC_ALIGNLEFT,TRUE);  
      frameBc.SetBool(DESC_SCALEH,TRUE);  
      
          // NOTE: Group must be added FIRST and to some tabbed group (or other group)  
          description->SetParameter(DescLevel(cid), maingroup, DescLevel(ID_OBJECTPROPERTIES));  
      
      //Create LINKBOX GUI's  
      for (int i=4000L; i<index; i++)  
      {  
      if (!myswitch)  
       {  
        myswitch = TRUE;  
        DescID newLinkboxid = DescLevel(i,DTYPE_LONG,0);  
        if(!singleid || newLinkboxid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
         {  
          linkboxBc.SetString(DESC_NAME,"Controller Object" + LongToString(i));      //Set the LinkBox text name  
          linkboxBc.SetString(DESC_SHORT_NAME,"Controller Object" + LongToString(i));  
          description->SetParameter(newLinkboxid,linkboxBc,DescLevel(cid)); //Update the changes made to the container  
         }  
       }  
        myswitch = FALSE;  //Reset the variable back to false  
      }  
      
      
      //Create editable number field GUI's with their own ID's separate from the LinkBox GUI's  
      index = data->GetReal(NUMofGUIS)+5000L;  
      for (int i=5000L; i<index; i++)  
      {  
      if (!myswitch)  
       {  
        myswitch = TRUE;      
        DescID newFrameid = DescLevel(i,DTYPE_REAL,0);  
        if(!singleid || newFrameid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
         {  
          frameBc.SetString(DESC_NAME,"Frame" + LongToString(i));        //Set the Frame text name  
          frameBc.SetString(DESC_NAME,"Frame" + LongToString(i));  
      
          description->SetParameter(newFrameid,frameBc,DescLevel(cid)); //Update the changes made to the container  
         }  
       }  
        myswitch = FALSE;  //Reset the variable back to false  
      }  
    }
    


  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 18/05/2012 at 20:48, xxxxxxxx wrote:

    Thanks Robert,

    I'm getting DescLevel errors:
    description->SetParameter(DescLevel(cid), maingroup, DescLevel(ID_OBJECTPROPERTIES));
    description->SetParameter(newLinkboxid,linkboxBc,DescLevel(cid));
    description->SetParameter(newFrameid,frameBc,DescLevel(cid));

    If I replace DescLevel with DescID it compiles. But the tag acts very buggy. It stops letting me add GUI's when the subgroup is opened.
    I'm not sure if replacing DescLevel with DescID is the cause of those problems. Or something else in my plugin.

    I clearly didn't understand the basics about how this all works. So I started over from scratch and dumped all of my dynamic creation code stuff for the time being. And just focused on creating one linkbox and one NumEdit field laid out horizontally.
    After looking at your advice. And the LookAtCamera example in the SDK. I came up with this:

        BaseContainer linkboxBc;  
      BaseContainer frameBc;  
      
      DescID cid = DescLevel(6001, DTYPE_GROUP, 0);  //This is the maingroup's ID  
      
      if(!singleid || cid.IsPartOf(*singleid,NULL))  //important to check for speedup c4d!  
      {  
          BaseContainer maingroupBc = GetCustomDataTypeDefault(DTYPE_GROUP);  
          maingroupBc.SetString(DESC_NAME, "My Tab");  //The name of the group(AM tab)  
          maingroupBc.SetLong(DESC_COLUMNS, 2);  
          maingroupBc.SetReal(DESC_DEFAULT, 1);        //Makes this group(AM tab) selected by default  
          if(!description->SetParameter(cid, maingroupBc, DescLevel(0))) return TRUE;  
      }  
      
      cid = DescLevel(6002, DTYPE_REAL, 0);  
      if(!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
      {  
          frameBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_REAL);  
          frameBc.SetBool(DESC_FORBID_SCALING,TRUE);  
          frameBc.SetBool(DESC_FORBID_INLINE_FOLDING, FALSE);  
          frameBc.SetString(DESC_NAME,"Frame" + LongToString(1));    
          if(!description->SetParameter(cid, frameBc, DescLevel(6001))) return TRUE; //The DescLevel(id) is the maingroup's id so it's placed inside of that group  
      }  
      
      cid = DescLevel(6003, DTYPE_LONG, 0);  
      if(!singleid || cid.IsPartOf(*singleid,NULL)) // important to check for speedup c4d!  
      {  
          linkboxBc.SetLong(DESC_CUSTOMGUI,CUSTOMGUI_LINKBOX);    
          linkboxBc.SetBool(DESC_SCALEH,TRUE);  
          linkboxBc.SetString(DESC_NAME,"Controller Object" + LongToString(1));    
          if(!description->SetParameter(cid, linkboxBc, DescLevel(6001))) return TRUE;//The DescLevel(id) is the maingroup's id so it's placed inside of that group  
      }
    

    In this simpler version I can see and understand better how the IDs work to place the two GUI's inside of the maingroup using the 6001 ID to do that.
    But there is one minor problem. I don't see any way to scale GUI's like we can scale them with .res files.
    I would like to make my NumEdit GUI a littler shorter. But I don't see any options that will scale GUI's like that listed in the DESC_Items in the docs.
    _<_img src="http://img543.imageshack.us/img543/7253/c4dgui.jpg" border="0" /_>_

    It's not too bad the way it is. But it would be nicer if I could somehow make the NumEdit field a little bit shorter. Is there a way to do that?

    -ScottA



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 19/05/2012 at 05:58, xxxxxxxx wrote:

    My code typically uses DescID(DescLevel()).

    DESC_SCALEH, DESC_FITH, and DESC_ALIGNLEFT should act similarly to the BVH_SCALE, BVH_FIT, and BVH_LEFT for GeDialogs.  This may help or not.  Remember that GUI elements are automatically and dynamically positioned and sized.  If you change the width of your A.M., these elements will most likely stretch/shrink to fit unless you set their DESC_SCALEH to FALSE.



  • THE POST BELOW IS MORE THAN 5 YEARS OLD. RELATED SUPPORT INFORMATION MIGHT BE OUTDATED OR DEPRECATED

    On 19/05/2012 at 09:36, xxxxxxxx wrote:

    Unfortunately those don't really help.
    GUI layouts in C4D are very dependent upon their groups and their groups spacing values. That makes them very hard to work with. And limiting compared to every other program I use.
    It's frustrating for me to get everything where, and what size I want it (sometimes impossible) in C4D plugins. Compared to the other WYSIWYG layout tools I use to make plugins with ( VS and QT).

    Laying out plugins in C4D reminds me of trying to make a modern website using nothing but tables.🤢
    It would be really nice if they dumped this whole nasty group based thing and upgraded to a more modern pixel based WYSIWYG system like everyone else is using these days.

    I think I might have enough info now to get my dynamic GUI's working.
    Thank you so much for taking the time to explain things to me Robert. 🍺

    -ScottA


Log in to reply