Seeking AM CustomGui help/example



  • On 11/08/2013 at 12:45, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    nr::CustomGuiBase inherits directly from iCustomGui and does not override any methods.

    This means you can replace nr::CustomGuiBase directly with iCustomGui. As mentioned in the same posted I quoted above, the implementation of nr::CustomGuiBase::SendValueChanged() is one post before.

       // in class nr::CustomGuiBase
        void SendValueChanged(BaseContainer msg) {
            msg.SetLong(BFM_ACTION_ID, GetId());
            msg.RemoveData(BFM_ACTION_VALUE);
            msg.SetData(BFM_ACTION_VALUE, GetData().GetValue());
            SendParentMessage(msg);
        }
    

    You can use this method directly by pasting it in your class. It is called somewhere else in the code and you do not have to substitute the call.

    You only need to replace nr::InvokeCommandCall() by the following (also in the post I just quoted code from).

                GeDialog* dlg = GetDialog();
                BaseContainer actionmsg(BFM_ACTION), actionresult;
                actionmsg.SetLong(BFM_ACTION_ID, COMMANDMSG_VALUECHANGED);
                if (dlg) dlg->Message(actionmsg, actionresult);
    

    Originally posted by xxxxxxxx

    I can't find the ObjectData class anywhere in your code.

    Because there is none!

    Screw it, I won't upload it tomorrow because I did it just now:
    https://github.com/nr-plugins/example-tristate-gui

    -Niklas



  • On 11/08/2013 at 13:31, xxxxxxxx wrote:

    Thanks Nik.
    I downloaded the code and it complied fine without any problems.
    However..This is not the end of the story. You're still leaving out a major piece of information.
    There is no plugin in my plugins menu now. Which makes perfect sense to me because there's no plugin class's in your code.

    So what do I do next?
    Am I supposed to call to this customGUI from inside one of my plugins in order to use it?
    I've never done anything like this before.

    -ScottA

    *Edit--Sorry. I just read what you posted and you did say to call to it.
            I'm currently in the process of trying to figure out how to do that.



  • On 11/08/2013 at 13:33, xxxxxxxx wrote:

    You don't call it. You do not interact with it from code. It customises the interface. Check your User Data Manager for the "Integer" datatype. Under the "Interface" drop-down menu, there's a new entry called "Tristate". Your plugin doesn't care about the interface as long as it's got its values stored in the container and can use them to do whatever it implements.



  • On 11/08/2013 at 13:50, xxxxxxxx wrote:

    Doh!
    Now I get it.
    For some reason I was thinking a customGUI was something different.Embarrassed

    I'm going to step through it and try to learn how it all works and make some notes.
    Hopefully I can make other things like sliders when I'm done going through it.

    Thanks a lot for the code Nik. 👍
    -ScottA



  • On 11/08/2013 at 14:24, xxxxxxxx wrote:

    Thanks Niklas,

    your efforts are invaluable. I'll need to spend a bit of time going through the reference code.

    I've just had a peep at the SDK examples and found the datatype example. I didn't realise that one used some icustomgui stuff. Argh.

    I think what Scott was querying is how do you add it to your description method (or res file?) of your own plugin? I.e. how do you get the customgui to show up in the AM when your object is selected (without having to add a userdata element). For instance, can we do something like this in the GetDDescription() of an object plugin:

      
    // MY_CUSTOMGUI_GUI = the registered customgui plugin ID...   
    cid = DescLevel(ID_TAB_MAIN_CUSTOMGUI_ELEMENT, DTYPE_CUSTOMGUI, 0);   
    if(!id_tab || cid.IsPartOf(*id_tab,NULL))   
    {   
        BaseContainer bc = GetCustomDataTypeDefault(CUSTOMGUI_DESCRIPTION);   
        bc.GetCustomDataType( CUSTOMGUI_DESCRIPTION, MY_CUSTOMGUI_GUI);   
        bc.SetString(DESC_NAME, "My CustomGui Element");   
        bc.SetString(DESC_SHORT_NAME, "My CustomGui Element");   
        if(!description->SetParameter(cid, bc, DescLevel(ID_TAB_MAIN_GROUP))) return TRUE;   
    }   
    

    I'll have to pick this up in the morning again and run some experiments. But is this kind of thing possible (from inside the GetDDescription())?

    I'm about to conk out. Thanks as always,

    WP.



  • On 11/08/2013 at 15:04, xxxxxxxx wrote:

    Yeah. I'm still not able to get it to work in a plugin.
    He did post this .res code earlier: LONG MY_PARAM { CUSTOMGUI PROXYTRISTATE; }
    But that code doesn't work for me.
    C4D does not recognize the new gizmo using this code.

    The gizmo works fine from the UserData.
    But getting it to work in a plugin is still not happening for me yet.

    -ScottA



  • On 11/08/2013 at 21:37, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    For instance, can we do something like this in the GetDDescription() of an object plugin:

     
    // MY_CUSTOMGUI_GUI = the registered customgui plugin ID...   
    cid = DescLevel(ID_TAB_MAIN_CUSTOMGUI_ELEMENT, DTYPE_CUSTOMGUI, 0);   
    if(!id_tab || cid.IsPartOf(*id_tab,NULL))   
    {   
      BaseContainer bc = GetCustomDataTypeDefault(CUSTOMGUI_DESCRIPTION);   
      bc.GetCustomDataType( CUSTOMGUI_DESCRIPTION, MY_CUSTOMGUI_GUI);   
      bc.SetString(DESC_NAME, "My CustomGui Element");   
      bc.SetString(DESC_SHORT_NAME, "My CustomGui Element");   
      if(!description->SetParameter(cid, bc, DescLevel(ID_TAB_MAIN_GROUP))) return TRUE;   
    }   
    

    Yes this is possible, but you are doing it wrong. The datatype should be DA_LONG for this tri-state custom GUI and BaseContainer::GetCustomDataType() does something very different. Also, CUSTOMGUI_DESCRIPTION is not a plugin ID for a datatype but a pluginid for a custom GUI (as the name implies).

        BaseContainer bc = GetCustomDataTypeDefault(DA_LONG); 
        bc.SetLong(DESC_CUSTOMGUI, CUSTOMGUI_TRISTATE);  // defined in TriStateCustomGui.cpp, grab it from there
    // ...
    


  • On 11/08/2013 at 21:41, xxxxxxxx wrote:

    Originally posted by xxxxxxxx

    Yeah. I'm still not able to get it to work in a plugin.
    He did post this .res code earlier: LONG MY_PARAM { CUSTOMGUI PROXYTRISTATE; }
    But that code doesn't work for me.
    C4D does not recognize the new gizmo using this code.

    The gizmo works fine from the UserData.
    But getting it to work in a plugin is still not happening for me yet.

    -ScottA

    Sorry for this. 😉 The custom GUI was part of a plugin that was called "Proxy Tag" but I stripped this part of the plugin and only left the custom GUI. I renamed it to "TriStateCustomGui" and the resource identifier is "TRISTATE" only now. Just look at TriStateCustomGui::GetResourceSym()!



  • On 12/08/2013 at 07:37, xxxxxxxx wrote:

    OK, I've managed to get the SDK's datatype to show up through my plugin's GetDDescription().So I can do that much. I've also managed to add that code into my own plugin's code files (not much more than a copy & paste really).

    The gap now is moving between the SDK's pre-made gizmos, to being able to write my own _GetDescription() function of the CustomDataTypeClass. Or more precisely, being able to 'draw' into it. I can't seem to do either at this stage.

    I noticed one example on here used a GeUserArea (that was for a dialog example), but can this method of making your own gui be used and displayed in the AM (I thought UAs were dialog only..)?

    WP.

    UPDATE: I can now add elements through the customgui's _GetDecription(). It's a little different than the normal GetDDescription() function. More to come..



  • On 12/08/2013 at 07:44, xxxxxxxx wrote:

    That's ok Nik.
    I did look through the code and I tried all kinds of combinations. But I just couldn't nail it.
    After a lot of tries I finally I hit upon the winning combination:  LONG MY_PARAM { CUSTOMGUI TRISTATE; }

    One other thing that you might want to be aware of.
    You included a strange .dll file in your git hub files. I deleted it and everything runs fine without it.
    So I'm guessing it's from something else you were doing?
    I don't know if you intentionally put it in there for some reason. Or just forgot to remove it. But I just wanted to let you know about it.

    Once again. Thanks for posting the code.,
    -ScottA



  • On 11/09/2013 at 03:16, xxxxxxxx wrote:

    Hi Folks,

    just a quick follow-up for this, everything is going well, except I'm needing to refresh/redraw the userarea associated with the customgui when I change a description cycle. Currently I have to initiate a redraw by re-clicking in the userarea. But I'd like an auto-update.

    I've tried things like the below:

      
    ListCustomData:: // any custom function here   
    ListCustomGui::CustomGuiRedraw();   
    MyDescriptionUA::Redraw();   
    MyDescriptionUA::LayoutChanged()   
    

    but all give me compile errors concerning illegal calls of non-static member function. Should I be redrawing/recalling the tool's GetDDesription() or refreshing the AM somehow?

    What's the correct way to go about this?

    WP.



  • On 11/09/2013 at 09:47, xxxxxxxx wrote:

    Hi WickedP,

    From when and where exactly do you need the refresh? The methods you have listed are member
    methods, you should call them on instances of the class, like

    class MyCustomGui : public iCustomGui {
      
        MyDescriptionUA m_ua;
      
    public:
      
        //| iCustomGui Overrides
      
        void CustomGuiRedraw() {
            m_ua.Redraw();
        }
      
        // ...
      
    };
    

    This by the way is the exact thing you should do when creating an iCustomGui subclass. The documentation
    contains this information:

    Originally posted by xxxxxxxx

    virtual void CustomGuiRedraw()_<_h4_>_

    Called when the GUI is redrawn. Use this to for example update your user areas.

    Best,
    -Niklas



  • On 11/09/2013 at 16:09, xxxxxxxx wrote:

    Hi there Niklas,

    I'm calling this from my tool plugin's SetDParameter() - so that when my cycle element changes it's id, an update is triggered on the userarea to redraw itself.

    I thought it would have something to do with calling them on an instance, but the userarea is instanced in the icustomgui and not the tool plugin's class - so I couldn't work out how that was done. The customgui plugin itself is inserted via the tool's GetDDescription() using the customgui's plugin id. How do I make a call to the customgui element if the userarea is not instanced in the tool plugin's class itself?

      
    // Registered customgui plugin:   
      
    class MyCustomUA : public GeUserArea   
    {   
        //functions etc..   
    }   
      
    class MyCustomGui : public iCustomGui   
    {   
        MyCustomUA MCU;   
        // functions etc.. including the following   
        void CustomGuiRedraw()   
        {   
            MCY.Redraw()   
        }   
    }   
      
    class MyCustomData : public CustomGuiData   
    {   
        // functions etc..   
    }   
      
    // Registered tool plugin:   
      
    class MyTool : public DescriptionToolData   
    {   
        // functions etc.. no instances to the customgui is used anywhere,   
        // the only reference to the customgui at all is in the description below   
        GetDDescription(doc, data, description, flags)   
        {   
            .....   
            cid = DescLevel(ID_HOME_GROUP_CUSTOMGUI, DTYPE_LONG, 0);   
            if(!id_Home || cid.IsPartOf(*id_Home,NULL))   
            {   
                BaseContainer bc = GetCustomDataTypeDefault(DTYPE_LONG);   
             bc.SetLong(DESC_CUSTOMGUI,ID_MY_CUSTOMGUI); // registered plugin   
             bc.SetBool(DESC_GROUPSCALEV, TRUE);   
             bc.SetBool(DESC_GUIOPEN, TRUE);   
             bc.SetLong(DESC_SCALEH, TRUE);   
             bc.SetString(DESC_NAME, "");   
                bc.SetString(DESC_SHORT_NAME, "");   
                if(!description->SetParameter(cid, bc, DescLevel(ID_HOME_GROUP_CUSTOMGUI_GROUP))) return TRUE;   
            }          
            return SUPER::GetDDescription(doc, data, description, flags);   
        }   
    }   
    

    WP.

    P.s. on a slightly different note, I've been meaning to send you a PM sometime too regarding a topic here from some time a go. I'll try whizzing one over in the next few weeks, hope that is o.k.



  • On 12/09/2013 at 05:41, xxxxxxxx wrote:

    Hi WP,

    do you redraw the UserArea on iCustomGui::SetData()?

    If it's not something you can ask in the forum, go ahead and contact me via PM.

    Cheers,
    -Niklas



  • On 12/09/2013 at 06:58, xxxxxxxx wrote:

    Oooo no, I've missed that function.. I may have even removed it at one stage..

    Is this what I'm needing? Can this be called without an instance? Below are the functions used in my iCustomGui thus far:

      
    class MyCustomGui : public iCustomGui   
    {   
        typedef iCustomGui super;   
      
    private:   
      
        LONG Height;   
        MyUserArea UserArea; // instance of GeUserArea   
      
    public:   
      
        MyCustomGui(const BaseContainer& settings, CUSTOMGUIPLUGIN* plug) : super(settings, plug);   
        virtual LONG CustomGuiWidth();   
        virtual LONG CustomGuiHeight();   
        virtual void CustomGuiRedraw();   
        virtual Bool CreateLayout();   
        virtual Bool InitValues();   
        virtual Bool Command(LONG id, const BaseContainer& msg);   
        virtual LONG Message(const BaseContainer& msg, BaseContainer& result);   
    };   
    

    WP.



  • On 13/09/2013 at 13:37, xxxxxxxx wrote:

    Hi WP,

    well the SetData() method is called to give you the data you should display in your custom GUI. It is
    called when the data was changed and the AM is updated (for instance). You need to redraw your
    user-area(s) from this method, CustomGuiRedraw() is not called automatically afterwards.

    Simply do

    UserArea.Redraw();

    from MyCustomGui::SetData().

    -Niklas



  • On 24/09/2013 at 03:31, xxxxxxxx wrote:

    Ok, I've stumped myself on this one. I can't get SetData() to call, or any auto-refreshing of the user area happening. I've tried my own custom functions and sending messages... and I just can't seem to get it to work without having to click in the user area itself in the attributes manager. Come to think of it, I don't think SetData() is even called when I 'load' the tool plugin.

    So, bare bones question - how do I refresh a customgui element in the AM (one that incorporates a GeUserArea)?

    WP.



  • On 24/09/2013 at 04:25, xxxxxxxx wrote:

    Have you registered a fake library for your CustomGuiData plugin as described in the documentation?

    See the CustomGuiData class on http://www.maxonexchange.de/sdk/CINEMA4DSDK/index.html

    That might explain why SetData() is not called.

    Best,
    -Niklas



  • On 24/09/2013 at 05:04, xxxxxxxx wrote:

    Hi Niklas,

    yep, I have. I played around with a few flags (and no flags) in the RegisterCustomGuiPlugin() to no avail.

    I've done some more looking over the posted examples, and I notice there's some custom functions which I haven't incorporated. I thought this was to do with sending data to the GeUserArea, but as I'm using separate structs to house necessary data I didn't think I'd need them. Could that be what I'm needing?

    Examples (I don't have these anywhere) :

      
    static Bool SendValueChanged(iCustomGui* dlg, BaseContainer msg) {   
        msg.SetLong(BFM_ACTION_ID, dlg->GetId());   
        msg.RemoveData(BFM_ACTION_VALUE);   
        msg.SetData(BFM_ACTION_VALUE, dlg->GetData().GetValue());   
        return dlg->SendParentMessage(msg);   
    }   
      
    static Bool InvokeCommandCall(GeDialog* dialog, LONG id) {   
        BaseContainer actionmsg(BFM_ACTION), actionresult;   
        actionmsg.SetLong(BFM_ACTION_ID, id);   
        return dialog->Message(actionmsg, actionresult);   
    }   
      
    

    WP.



  • On 26/09/2013 at 04:59, xxxxxxxx wrote:

    The functions you have quoted are from my TriState Custom GUI example code and are not part
    of the Cinema 4D SDK. View the code on github.

    Without seeing your full code, I can only tell you to skim the examples you have available and look
    out for the issue. SetData() is called when set up correctly, but the issues can reside in very
    different locations, that is why snippets help certainly rare.

    Best,
    -Niklas


Log in to reply