How to change a real slider's max value



  • On 01/02/2014 at 17:58, xxxxxxxx wrote:

    User Information:
    Cinema 4D Version:   13,14,15 
    Platform:   Windows  ;   
    Language(s) :     C++  ;

    ---------
    Hi, I try to change a real slider's max value when the user changes the status of a checkbox. But after I have changed the value, t he slider behaves strange. The normal real real editor box behaves normal.

    Bool MyTag::GetDDescription (GeListNode* node, Description* description, DESCFLAGS_DESC &flags)
    {
        DescID cid = DescLevel(MYTAG_REAL_VALUE, DTYPE_REAL, 0);
        BaseContainer bc = GetCustomDataTypeDefault(DTYPE_REAL);
        bc.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER);
        bc.SetLong(DESC_UNIT, DESC_UNIT_PERCENT);
        bc.SetLong(DESC_MAX, 100);
        bc.SetLong(DESC_MAXSLIDER, 100);
        bc.SetLong(DESC_MIN, 0);
        bc.SetLong(DESC_MINSLIDER, 100);
        bc.SetString(DESC_NAME, "Foo");
        description->SetParameter(cid, bc, DescLevel(0));
    }
    

    The code is somewhat simplified.
    I am sure I do something wrong here. Because I just want to change a specific parameter. But if I do not include the " bc.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER)", no slider appears.
    So I definitely do something wrong, since the slider already is defined in the RES file, I just want to alter the MAX values for both the Real and for the Slider.

    Anyone who knows how to do this correctly?



  • On 02/02/2014 at 13:20, xxxxxxxx wrote:

    Hi,
    I really think it would be a good idea if you delete the second thread you created about this. Because it will be confusing to have two threads running for the same question.

    Here's an example of how to dynamically change the max value of a dynamically created slider:

    Bool SimpleTag::GetDDescription(GeListNode *node, Description *description,DESCFLAGS_DESC &flags)  
    {      
      BaseContainer *data = ((BaseList2D* )node)->GetDataInstance();       //Get the container for the tag  
      if(!description->LoadDescription(node->GetType())) return FALSE;    //Loads the .res file stuff  
      
      //Get the state of the checkbox and assign it to a local variable  
      //NOTE: The checkbox is created in the .res file  
      Bool enabled = data->GetBool(MYBOX);  
      
      //Set up some logic that changes the max value depending if the checkbox is pressed  
      LONG dynamicMax;  
      if(enabled) dynamicMax = 10;  //If the checkbox is enabled the max value will be 1,000  
      else dynamicMax = 1;          //If the checkbox is not enabled the max value will be 100  
      
           
      //Create a dynamic slider gizmo here without using the .res file at all   
      //Mixing the .res file with this code will just make it more confusing than it needs to be!   
      DescID sliderId = DescLevel(MYSLIDER, DTYPE_REAL, 0);   //Assign the slider GUI item to this description variable  
      BaseContainer sliderBC = GetCustomDataTypeDefault(DTYPE_REAL);  
      sliderBC.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_REALSLIDER);  
      sliderBC.SetReal(DESC_STEP, 0.01);  
      sliderBC.SetLong(DESC_UNIT, DESC_UNIT_PERCENT);  
      sliderBC.SetLong(DESC_MAX, dynamicMax);                 //<--- Use the dynamic value here  
      sliderBC.SetLong(DESC_MAXSLIDER, dynamicMax);           //<--- Use the dynamic value here  
      sliderBC.SetLong(DESC_MIN, 0);   
      sliderBC.SetLong(DESC_MINSLIDER, 0);  
      sliderBC.SetString(DESC_NAME, "Foo");  
      //sliderBC.SetBool(DESC_HIDE, enabled);   //<--- Use this to hide the slider if desired  
      description->SetParameter(sliderId, sliderBC, DescLevel(ID_OBJECTPROPERTIES));  
        
      
      flags |= DESCFLAGS_DESC_LOADED;  
      return TRUE;  
    }
    

    If you would like the entire plugin to play around with.
    Send me an e-mail at: scottasba@hotmail.com.  And I'll zip it up and send it to the address you send me.

    -ScottA



  • On 02/02/2014 at 13:40, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Hi,
    I really think it would be a good idea if you delete the second thread you created about this.

    Done.

    Thanks for the code!
    What you really do here, is creating a new control.
    I had thought it would be possible just to alter one parameter, and leave the rest as described in the RES file. 
    Like this:

        const DescID* singleDesciptionId = description->GetSingleDescID();
        DescID customDataTypeId = DescLevel(FOO_ID, DTYPE_GROUP, 0);
        if (!singleDesciptionId || customDataTypeId.IsPartOf(*singleDesciptionId, NULL)) 
        {
    		BaseContainer bc = GetCustomDataTypeDefault(DTYPE_GROUP);
    		bc.SetString(DESC_NAME, "Foobar");
    		description->SetParameter(customDataTypeId, bc, DescLevel(0));
        }
    

    But my impression that I am altering just one parameter may be wrong? Am I creating a new group? The controls inside the group remain though..
    This is what I wanted, use what is there as described in the RES file, and just alter what needs to be altered, nothing more, nothing less.

    Mail is on its way!



  • On 02/02/2014 at 13:52, xxxxxxxx wrote:

    You could probably mix them without a problem.
    Having some things set in the .res file and some things set in the .cpp file for the same gizmo.
    But trying to keep track of what's where like that could potentially make you crazy trying to find a bug in a more complicated setup.

    The main reason I try to do everything in one or the other as much as possible. Is just a personal preference. To keep things organized.

    -ScottA



  • On 02/02/2014 at 13:57, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    You could probably mix them without a problem.

    When I try to use just one of the values, like the DESC_MAXSLIDER or the DESC_MAX, the slider control disappears. Other misbehaves in other ways.

    Apart from that, I agree with what you say, it might complicate things, although I in this particular case do this only once in the complete plugin, and what I want to alter is only the DESC_MAXSLIDER and the DESC_MAX parameters.



  • On 03/02/2014 at 07:24, xxxxxxxx wrote:

    Hi Ingvarai,

    you can obtain the description container of a parameter via the Description::GetParameterI() method.
    The returned pointer to a BaseContainer can be altered and it will be reflected in the resulting description.
    Keep in mind that NodeData::GetDDescription() always creates a new Description and does never operate
    on a previous state of the node's description.

    Best,
    -Niklas



  • On 03/02/2014 at 10:28, xxxxxxxx wrote:

    Hi Niklas, thanks for your reply!
    I am, however, sorry to say that I am as far (short) as I was when I started this thread.
    Please look at this code:

    This works, I am able to show and hide the control
    Example A

    Bool ShowDescriptionElement(GeListNode* node, Description* descr, LONG MyDescID, Bool show)
    {
        AutoAlloc<AtomArray> ar;
        if(!ar) return FALSE;
        ar->Append(static_cast<C4DAtom*>(node));
       BaseContainer* bc = descr->GetParameterI(DescLevel(MyDescID), ar);
        if(bc)
        bc->SetBool(DESC_HIDE, !show);
     }
    

    This does not work , I am not able to set the name (change the caption) of the control
    Example B

    Bool SetDescriptionElementName(GeListNode* node, Description* descr, LONG MyDescID, String  name)
    {
        AutoAlloc<AtomArray> ar;
        if(!ar) return FALSE;
        ar->Append(static_cast<C4DAtom*>(node));
       BaseContainer* bc = descr->GetParameterI(DescLevel(MyDescID), ar);
        if(bc)
        bc->SetString(DESC_NAME, name);
     }
    

    It is obvious that I am doing it wrong here. But I am using GetParameterI as you suggested. I would be very interested in finding out what is wrong with Example B!



  • On 03/02/2014 at 12:08, xxxxxxxx wrote:

    Because the AM displays the DESC_SHORT_NAME property, not DESC_NAME

    Best,
    -Niklas



  • On 03/02/2014 at 14:00, xxxxxxxx wrote:

    Ok, as usual I feel a little silly and stupid, having worked with this on and off for 24 hours now.
    And as usual, the solution is simple, when you know it.
    Here is the answer to my original question in this thread:

    Bool MyTag::GetDDescription (GeListNode* node, Description* description, DESCFLAGS_DESC &flags)
    {
            BaseContainer* bc = descr->GetParameterI(DescLevel(FOO_REAL_SLIDER), NULL);
            if(bc)
            {
                      bc->SetLong(DESC_MAX, 2);
                      bc->SetLong(DESC_MAXSLIDER, 2);
            }  
    }
    

    The code will set the MAX value to 200% and the Max Slider value to 200%, since the unit in this case is percent.
    And this code can certainly be optimized for performance, since C4D will call it more than necessary. 
    But it works!
    I hope this will be of help to to others, who just need to change description element values at runtime. And I am not looking forward to the next time I run into an unsolved task which has a solution that is so hard to find [for me], and at the same time has a super simple solution ..



  • On 03/02/2014 at 15:45, xxxxxxxx wrote:

    You could've known if you were more into the software. When creating User Data, you have the
    option to set separate values for the short and long name of the property. The name is displayed in
    the Attributes Manager while the long name is used in XPresso (for instance). The SDK doc page
    about the Description class contains all the description property IDs, DESC_NAME and
    DESC_SHORT_NAME listed as the first two.

    Best,
    -Niklas



  • On 03/02/2014 at 17:27, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    You could've known if you were more into the software.

    If worked for Maxon, I would not need this forum :)
    I really miss a C4D Plugin Writer's Wiki. Where I can look up how-to articles, code snippets for common tasks, etc. I think we all could benefit from such a thing. A Wiki.

    I program a lot (it is my profession), and whenever a problem, a particular issue comes up in C#, I have the solution in minutes. Because the universe is full of code examples on how to carry out all imaginable tasks in C#. And a whole bunch of unimaginable tasks too, to boot.

    In Cinema 4D on the other hand.. Even the simplest tasks, like in this case, alter a specific property of a control, takes hours, days, to find out about. Well, I do not know. Making it so difficult is perhaps one reason C4D is so rock solid and stable. Because only the most stubborn programmers have the patience to write a complex plugin. The others have fallen off the wagon long before something works..

    What happens now - i build up my own skills, my own library of reusable code snippets and common methods. And while they come in handy for me, often, others seldom will benefit from my knowledge. Unless there is  post here in the forum I feel I have the solution to.


Log in to reply