Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python 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

    Maxon..Can we please see the SliderGUI code?

    SDK Help
    0
    10
    893
    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 19/08/2013 at 15:22, xxxxxxxx wrote:

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

      ---------
      I've created my own custom slider GUI using a User Area.
      In my code I'm using the mouse's X position value to animate the size of a rectangle shape. Which is working well.
      I'm also able to output the slider's value (the mouse's x position) and use this to record keys and control things. Just like how the built-in slider works.
      The Xpresso output port also works. Reflecting the values of the slider.

      But...I cannot go the other way.
      I can't make the slider change according to the key frame values. When the user is not physically using the slider.
      It's a one way communication only. Once I have used the slider to set the keys. The slider just sits there and does not update itself. And I've been unable to figure out how to send any messages to my custom GUI's DrawMsg() function to change the slider (the rectangle shape).

      Is it possible to see the code for the custom slider GUI that ships with C4D?
      I need to see how they handled the receiving part of it.

      Thanks,
      -ScottA

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

        On 20/08/2013 at 01:45, xxxxxxxx wrote:

        Sorry, no internal code will be disclosed.

        Anyway, this seems to be a problem with your implementation, and is probably not actually related to the actual GUI part of the code. My guess is that you simply didn't implement virtual Bool iCustomGui::SetData(const TriState <GeData> &tristate;);

        Or did you implement your own CustomDataType and did not implement virtual Bool CustomDataTypeClass::InterpolateKeys(GeData & res, const GeData& t_data1, const GeData& t_data2, Real mix, LONG flags)?

        Without any information about what you are doing, we can only speculate.

        Cheers,
        Frank

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

          On 20/08/2013 at 08:57, xxxxxxxx wrote:

          Hi Frank,

          The problem is I don't know how to write the SetData() and the TriState code for this.
          That's probably what I'm missing.

          Maxon provided a CustomDataType example in the SDK.  So why can't they provide a custom GUI example also?
          I don't understand why one would be shareable knowledge. And the other one is a company secret?
          I'm not looking for company secrets. Just a working example of making a custom slider.
          I'd be happy to post my code though, if that's what Maxon requires.
          It's about 220 lines of code though. Kinda big.
          But if that's the only way to get a working example. I'm happy to do it.

          -ScottA

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

            On 20/08/2013 at 14:06, xxxxxxxx wrote:

            I think I've finally got it figured out.
            My slider is now updating.

            -ScottA

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

              On 25/08/2013 at 09:01, xxxxxxxx wrote:

              Hi Scott,

              would you share the solution with us?

              The description of your problem reminds me of some trouble I came across, too. iCustomGui::SetData() was called, but the visual didn't update. I figured it was due to
              the reason that no automatic refresh is invoked and you have to invoke this refresh yourself.

              Bool MyCustomGui::SetData(const TriState<GeData>& data) {
                  // ...
                
                  // Invoke a redraw on the user-area which is inside of our iCustomGui
                  // (which is a GeDialog subclass).
                  m_userarea.Refresh();
                  return TRUE;
              }
              
              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 25/08/2013 at 11:02, xxxxxxxx wrote:

                Old code example removed.

                -ScottA

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

                  On 25/08/2013 at 11:32, xxxxxxxx wrote:

                  Hi Scott,

                  some notes about your code:

                  1. Do not store the mouse position and the user area width globally, you can store it as an
                    attribute in your user-area. Furthermore, you can retrieve the width of a user-area at any
                    point by calling GetWidth().
                  2. You do not need to use the user-areas Timer() method. As I stated above, I have hit the
                    same problem before and implementing the example I have shown does fix the updating
                    problem (I tested it in your plugin source code you've linked). [See code-reference #1]
                  3. The mouse position does not reflect the value of the slider 1-by-1. You can  calculate a value
                    between 0 and 1 by dividing the mouse X position by the width of the user-area. To be more
                    precise:

                  Real v01 = static_cast<Real>(mx) / static_cast<Real>(this->GetWidth());

                  You can then scale the value to match your minimum and maximum slider value. This is simple
                  range mapping.

                  Real vmm = v01 * (slider_max - slider_min) + slider_min;

                  And then notify the parent about the value change as you have done properly in your code.
                  See code-reference #2 for a more contextual snippet.
                  4. The EventAdd() call from DrawMsg() is absolutely redundant and should be avoided.

                  code-references

                  #1

                  virtual Bool SetData(const TriState<GeData> &tristate)
                      {
                          const GeData &value = tristate.GetValue();  //The value of the gui(the data port in xpresso & the data animation track)
                          LONG data = value.GetLong();                //Assign the value to a long type variable so we can use it
                          MousePos = data;                            //Use this value to set the slider's position using the data
                          ua.Redraw();
                          return TRUE;
                      }

                  #2

                  class MyUserArea : public GeUserArea
                      {

                  public:

                  **        Real value;**
                  **        Real slider_min, slider_max;**

                  virtual void DrawMsg(LONG x1, LONG y1, LONG x2, LONG y2, const BaseContainer& msg)
                          {
                              /* ... original code left out ... */

                  LONG Left = static_cast <Real>(x2 - x1) * value;
                              LONG Top = 0;
                              LONG Bottom = 0;
                              LONG Right = 0;
                              DrawRectangle(x1+Left, y1+Top, x2-Right, y2-Bottom);

                  // EventAdd();
                          }

                  virtual Bool InputEvent(const BaseContainer& msg)
                          {
                              BaseContainer action;                 //Create an empty container
                              action.SetData(BFM_ACTION_ID, 1000);  //Store the ID for the active gizmo in the container

                  BaseContainer state;
                              while (GetInputState(BFM_INPUT_MOUSE, BFM_INPUT_MOUSELEFT, state)) //While the LMB is down 
                              {
                                  if (state.GetLong(BFM_INPUT_VALUE) == 0) break; //If the state value is 0 the LMB is no longer down..so don't continue

                  LONG mx = state.GetReal(BFM_INPUT_X);
                                  LONG my = state.GetReal(BFM_INPUT_Y);

                  Global2Local(&mx,&my);
                                  //GePrint("X Pos: " +LongToString(mx) + "   " +  "Y Pos: " +LongToString(my));

                  **                // Calculate the value based on the user-areas size.**
                  **                LONG width = GetWidth();**
                  **                if (width == 0) continue; // avoid zero-division error, if the width is zero, nothing of the following needs to be done.**

                  **                Real v01 = static_cast<Real>(mx) / static_cast<Real>(width);**
                  **                value = v01 * (slider_max - slider_min) + slider_min;**

                  **                // MousePos = mx;  //Send the position data to the global variable so that all the other classes and functions can use it**
                                  Redraw();       //Refreshes the UA slider changes while dragging. Instead of when finished dragging

                  //Send a message to the parent dialog telling it that the UA slider being used by the mouse in some manner and not finished
                                  action.SetData(BFM_ACTION_INDRAG, TRUE);
                                  SendParentMessage(action);

                  //GeDialog *dlg = GetDialog(); 
                                  BaseContainer actionmsg(BFM_ACTION);            //Create a container with the BFM_ACTION in it
                                  actionmsg.SetLong(BFM_ACTION_ID, MY_MESSAGE);   //Add the ID of the dialog gizmo that has changed to the container 
                                  BaseContainer actionresult;                     //Create another container to hold the result
                                  dlg->Message(actionmsg, actionresult);          //Send a custom message containing this value to the dialog
                              }

                  //Notify the parent dialog that the dragging is now finished
                              action.SetBool(BFM_ACTION_INDRAG, FALSE);
                              SendParentMessage(action);
                              Redraw();

                  return TRUE;
                          }
                      };

                  class MyCustomGui : public iCustomGui
                      {
                        typedef iCustomGui super;

                  private:
                          MyUserArea ua;   //A local copy of the User area so we can use it in this class

                  public:

                  MyCustomGui(const BaseContainer &settings, CUSTOMGUIPLUGIN *plug) : super(settings, plug) {
                  **            // Retrieve the minimum and maximum slider value from the **
                  **            ua.value = 0;**

                  **            Real min_default = settings.GetReal(DESC_MIN, 0.0);**
                  **            Real max_default = settings.GetReal(DESC_MAX, 1.0);**
                  **            ua.slider_min = settings.GetReal(DESC_MINSLIDER, min_default);**
                  **            ua.slider_max = settings.GetReal(DESC_MAXSLIDER, max_default);**
                          }

                  virtual Bool CreateLayout()
                          {
                              //Attach the User Area to the custom GUI gizmo
                              AddUserArea(1000, BFH_SCALEFIT, 0, 0);
                              AttachUserArea(ua, 1000);
                              return TRUE;
                          }
                          virtual Bool InitValues(){ return TRUE; };
                          virtual Bool Command(LONG id, const BaseContainer &msg)
                          {
                              if (id == MY_MESSAGE)
                              {
                                  valueChanged(this, msg);       //Execute this custom method when the LMB is pressed
                                  this->SendParentMessage(msg);
                              }

                  return TRUE;
                          }
                          virtual Bool SetData(const TriState<GeData> &tristate)
                          {
                              const GeData &value = tristate.GetValue();  //The value of the gui(the data port in xpresso & the data animation track)
                  **            // Real data = value.GetReal();                //Assign the value to a long type variable so we can use it**
                  **            // MousePos = data;                            //Use this value to set the slider's position using the data**
                  **            ua.value = value.GetReal();**
                  **            ua.Redraw();**
                              return TRUE;
                          }

                  };

                  > Note : You still have to handle the case where multiple values need to be displayed in the GUI. You can check if you have to switch to the "Multiple Values" display by calling TriState<T>::GetTri(). You have to handle this case respectively in your UI.

                  Best,
                  -Niklas

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

                    On 25/08/2013 at 13:32, xxxxxxxx wrote:

                    Thanks for the notes Nik.
                    I had tried using the gizmo's width value to control the slider's position. But I could not get it to work properly.
                    I used the SDK Sized() method for this rather than the GetWidth() function.
                    But when I do that. The slider no longer matches (lines up with) the mouse cursor. So I just gave up on it and left it as is.
                    It's really a minor thing. Because I can just set the max values to 300 in the UserData settings.
                    But it bugs that it's not correct. And not working exactly like the Maxon slider.

                    I tried using your code. But that just makes the gui flicker. Confused

                    From your reply. I can't tell whether your question was answered or not?

                    -ScottA

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

                      On 25/08/2013 at 13:49, xxxxxxxx wrote:

                      The flickering probably happened because I didn't point out all the places that needed to be adjusted. Replace your customgui.cpp with the file from this link and check it out. Work's like a charm here. The slider follows your mouse position correctly as long as you do the correct inverse calculation from InputEvent() inside DrawMsg(). You can of course also store the mouse position and draw the slider at this position, but this will make you unable to draw the slider when the value did not originate from mouse input but from a value in the objects container (for instance).

                      I changed quite a few lines, you should look at the file in a diff viewer (eg. http://prettydiff.com/) too see all the changes clearly.

                      https://dl.dropboxusercontent.com/u/99829745/stuff/2013-08-25-ScottA-slidercustomgui-changes-01.cpp

                      Originally posted by xxxxxxxx

                      From your reply. I can't tell whether your question was answered or not?

                      I am not sure what you are referring to.

                      -Niklas

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

                        On 25/08/2013 at 14:19, xxxxxxxx wrote:

                        Oh sorry. I thought you were asking a question about timers.

                        The full code example works much better. Thanks for posting that. 👍

                        I'm going to delete the link to my example. But there really should be a compiled example for other people to use. This is something that should have been included in the SDK examples.
                        Do you want to post one on your blog?
                        Or would you like me to post one on my site?

                        -ScottA

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