BitmapButton in GeDialog not clickable



  • On 28/01/2016 at 13:00, xxxxxxxx wrote:

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

    ---------
    Hi,

    I have a GeDialog and add BitmapButtons to it like so:

    BaseContainer settings;  
              settings.SetBool(BITMAPBUTTON_BUTTON, TRUE);  
              settings.SetBool(BITMAPBUTTON_TOGGLE, FALSE);  
              settings.SetLong(BITMAPBUTTON_BORDER, BORDER_BLACK);  
              settings.SetLong(BITMAPBUTTON_ICONID1, GID_ICON1);  
              settings.SetLong(BITMAPBUTTON_ICONID2, GID_ICON2);  
      
              for(Int32_C4D a = 0; a < lCount; a++)   
              {  
                  BitmapButtonCustomGui* pBtn = (BitmapButtonCustomGui* )AddCustomGui(id+a, CUSTOMGUI_BITMAPBUTTON, String(), BFH_CENTER|BFV_FIT, 0, 0, settings);  
    }
    

    Clicking on the button does trigger a Command() message but visually it does not switch to the pressed state icon. I want this to be a clickable button and the search didn't help.

    Wow, didn't think this would steal so much time. I sat on this for 2 hours now, tried various ways e.g. using SetImage() which would work if there was a way to detect when the mouse click was released (if anybody knows...let me know!) so the image can be toggled accordingly. Using SetImage() with the "second" variable set to true also does not work. Tried various combinations of the settings data, also BITMAPBUTTON_OUTBORDER has no effect whatsoever...

    So how can I accomplish that the bitmap button shows the pressed state when the user clicks on it? Did I forget anything?

    Thanks



  • On 28/01/2016 at 14:26, xxxxxxxx wrote:

    not 100% sure about this, but I guess the problem is from how GeDialog works "it redraws itself so it recreates the button again and again"

    you need to set the initial state of the button. "after AddCustomGui"
    edit:
    try this, BitmapButtonCustomGui::SetToggleState(Bool state); //store the state somewhere in the class, and use it after creation of the button.



  • On 28/01/2016 at 15:15, xxxxxxxx wrote:

    This is an example of toggling between two different registered icon images on a GeDialog bitmap button.

    #include "c4d.h"  
    #include "c4d_symbols.h"  
      
    #define PLUGIN_ID 1000006  //Testing ID!!  
      
    enum  
    {  
      MY_BITMAP_BUTTON1 = 10001  
    };  
        
      
    class MyDialog : public GeDialog  
    {  
      private:  
          BitmapButtonCustomGui *myButton;    //The button with an image on it  
          Bool btnState = false;              //The state of the toggle button  
          MyDialog *dlg;  
      
      public:  
       MyDialog(void);  
      ~MyDialog(void);  
      virtual Bool CreateLayout(void);  
      virtual Bool InitValues(void);  
      virtual Bool Command(LONG id,const BaseContainer &msg);  
      
    };  
      
    Bool MyDialog::CreateLayout(void)  
    {  
      Bool res = TRUE;  
      res = LoadDialogResource(IDS_RESDIALOG,NULL,0);  
        
      //This is an example of creating a custom button locally(not in the .res file) with AddCustomGui()  
      GroupBegin(0,BFH_LEFT,2,0,"MyButtonGroup",0);  
      {  
          BaseContainer bbc;    //Create a container to hold our custom button gizmo              
      
          //bbc.SetBool(BITMAPBUTTON_BUTTON, true);    //Animates the pressed state of the button if desired  
          bbc.SetBool(BITMAPBUTTON_TOGGLE, true);  
          bbc.SetString(BITMAPBUTTON_TOOLTIP, "Click Me!");  
          bbc.SetLong(BITMAPBUTTON_ICONID1, RESOURCEIMAGE_ROTATE);  
          bbc.SetLong(BITMAPBUTTON_ICONID2, RESOURCEIMAGE_MOVE);  
          myButton = (BitmapButtonCustomGui* )AddCustomGui(MY_BITMAP_BUTTON1, CUSTOMGUI_BITMAPBUTTON, "Bitmap Button", BFH_SCALEFIT | BFH_SCALEFIT, 130, 30, bbc);  
      }  
      GroupEnd();  
      
      return res;  
    }  
      
    Bool MyDialog::InitValues(void)  
    {  
      if(!GeDialog::InitValues()) return FALSE;  
      
      return TRUE;  
    }  
      
    Bool MyDialog::Command(LONG id,const BaseContainer &msg)  
    {  
      switch (id)   
      {  
          case MY_BITMAP_BUTTON1:  
              GePrint("Bitmap Button1 Was Pressed");      
              btnState = !btnState;                    //Makes the variable toggle true / false  
              myButton->SetToggleState(btnState);      //Toggles the button image  
              break;  
      }  
      
      EventAdd();  
      return TRUE;  
    }  
    //...CommandData code stuff here...  
      
    

    -ScottA



  • On 28/01/2016 at 15:18, xxxxxxxx wrote:

    great example Scotta, also cleaner than my solution "though it should give the same result"



  • On 29/01/2016 at 04:47, xxxxxxxx wrote:

    Thanks Scott & Mohamed but actually I want a clickable button not a toggable button (see my code above). So once I pressed it, it should show the pressed state and once the click releases switch back to non-pressed state. Just like a normal button (which should imo be what the customgui should do by default but it doesn't...which kind of contradicts the purpose of a button).

    I check the state initialisation now (though I am not sure how it relates to the automatic button state).



  • On 29/01/2016 at 04:54, xxxxxxxx wrote:

    Setting the toggle state after AddCustomGui didn't change anything unfortunately. So I am still looking for a way to make the bitmap button behave like a normal button.

    If I have to do it myself I would need to know how I can detect when the user releases the mouse click. I will try now and see if BitmapButtonCallback can help out here.

    If there is no such event or message, I would also need to know so I can go down the route of an own customgui (which would feel like reinventing the wheel).



  • On 29/01/2016 at 08:22, xxxxxxxx wrote:

    Oh that....yeah... they broke the hell out of that in R13.
    I asked about it here many times. And they just looked at me like I had bugs crawling out of my teeth.

    In R12. When you clicked on a bitmap button. It stayed down automatically.
    Another thing that we could do in R12 was use a raised border on the button and it would still animate up/down like how a real physical button works. That got clobbered in R13 too.

    I brought this up several times. And people thought I was nuts.
    I guess I found another nut.😉

    -ScottA



  • On 29/01/2016 at 08:39, xxxxxxxx wrote:

    You are not alone.  Toggle buttons (on/off state) work great with two bitmaps.  As you and Katachi noticed, this doesn't work for non-Toggle buttons.  You get a thin down border when you click one but that is it.  Add me to the nut collection.



  • On 29/01/2016 at 10:21, xxxxxxxx wrote:

    Thanks guys, at least I know now that I am nuts and in good company! :D

    Btw. I tried using the callback but it is only triggered for right mouse clicks so no solution there either.



  • On 29/01/2016 at 10:25, xxxxxxxx wrote:

    Oooopsy, when looking into this thread this morning, I thought it would actually be solved.
    Sorry guys, I will look into this on Monday.



  • On 29/01/2016 at 14:29, xxxxxxxx wrote:

    Ok, after fiddling with this all day and trying all possible combinations, I think I have it working now.

    I have wrapped it all into a class too and I have uploaded the code for it into Navié's GitHub repository: https://github.com/Naviee/c4d_bitmapbutton

    You can decide if the class adds a non-button image, a toggable button or a clickable button.

    I tried this only on Windows with C4D R16 yet though. I'd be glad to hear if it works for you as well.
    Hopefully this prevents others from suffering in the same way. :)

    Enjoy



  • On 29/01/2016 at 16:34, xxxxxxxx wrote:

    Hope that it works more universally.  The amount of T&E; is oft times frustrating for such small gains.  Thank you for the work and frustration!



  • On 29/01/2016 at 19:23, xxxxxxxx wrote:

    I'm having a hard time using that code in R13.
    Too many specialized things in there that need to be changed.

    All I really need is a way to toggle the border style as well as the IconID.
    Something like this:
      settings.SetLong(BITMAPBUTTON_BORDER, btnState == false? BORDER_IN : BORDER_NONE);

    But I've never been able to make it work.
    Are you doing something like that in your code? Or something different?

    -ScottA



  • On 30/01/2016 at 03:59, xxxxxxxx wrote:

    There's not much special to it really. It's just using R15+ SDK and C++11 language features. I am not switching between border styles with this but between two icons (registered with RegisterIcon).

    I have updated the github code so it should be compatible with R13 and also to work with non-C++11 compliant compilers (such as VS 2012 and before). See the comments in DialogBitmapButton.h (top of file) for this. Haven't tested it yet though.



  • On 30/01/2016 at 07:31, xxxxxxxx wrote:

    Oh Ok. You're still switching between icons.
    The problem that I was referring to (and thought you were referring to) that Maxon broke sing R13 was the button's border.
    In older versions. The button's border style could be swapped raised/lowered. But now all we can do is swap the icons. And that sucks.
    Now the only way to create an actual real looking animated button is to create 2 images that have painted raised/lowered borders on them. And register them with unique ID#s.
    It was much nicer the old way.

    Thanks for posting your code.
    I've never used the RMB callback before. That might come in handy some day.

    -ScottA



  • On 30/01/2016 at 10:12, xxxxxxxx wrote:

    I have updated the class so you it supports what you want (pass false for 'custom_border' variable when calling AddToLayout). This doesn't work with border styles though because the customgui has its own border effect for it (and for switching the border styles manually there is not enough access/messages).

    You can also now pass a tooltip string and overwrite fading effect with a background color too.
    github repository is updated.

    Hope this helps but I will leave this now. I already spent too much time with it. :)



  • On 30/01/2016 at 10:18, xxxxxxxx wrote:

    I found a way to toggle the border of the button. But it's a bit heavy handed and long in the tooth.
    I'll post it here in case anyone needs this kind of behavior.

      
    //The SDK BITMAPBUTTON_TOGGLE option does not let you keep the button looking like it's in a pressed state  
    //This code creates a GeDialog plugin with a bitmap button on it  
    //The button's image and border style toggles like an actual physical button (it stays pressed or unpressed)  
    //To make the border style change. I had to use LayoutFlushGroup() to destroy and re-make the entire button  
    //It works...But it requires a lot of code for something as trivial as toggeling a button's border  
      
      
      
    #include "c4d.h"  
    #include "c4d_symbols.h"  
      
    #define PLUGIN_ID 1000006  // be sure to use a unique ID obtained from www.plugincafe.com  
      
    enum  
    {  
      BTN_GRP           = 10001,  
      MY_BITMAP_BUTTON1 = 10002  
    };      
      
    class MyDialog : public GeDialog  
    {  
      public:  
          MyDialog(void);  
          ~MyDialog(void);  
          virtual Bool CreateLayout(void);  
          virtual Bool InitValues(void);          
          virtual Bool Command(LONG id,const BaseContainer &msg);  
      
      private:  
          MyDialog *dlg;  
          BitmapButtonCustomGui *myButton;    //The button with an image on it  
          Bool btnState = false;              //The state of the toggle button  
          void ReLayout(void);                //Used to redraw the GeDialog  
          void CreateButton(void);            //Used to create the bitmap button dynamically  
    };  
      
    MyDialog::MyDialog(void)  
    {      
    }  
      
    MyDialog::~MyDialog(void)  
    {      
      GeFree(dlg);  
    }  
      
    Bool MyDialog::CreateLayout(void)  
    {  
      Bool res = TRUE;  
      res = LoadDialogResource(IDS_RESDIALOG,NULL,0);  
        
      //This is an example of creating a custom button locally(not in the .res file) with AddCustomGui()  
      GroupBegin(BTN_GRP, BFH_LEFT, 2, 0, "MyButtonGroup", 0);  
      {  
          CreateButton();  
      }  
      GroupEnd();  
      
      return res;  
    }  
      
    Bool MyDialog::InitValues(void)  
    {  
      if (!GeDialog::InitValues()) return FALSE;  
      
      return TRUE;  
    }  
      
    void MyDialog::ReLayout(void)  
    {  
      LayoutFlushGroup(BTN_GRP);  
      CreateButton();  
      LayoutChanged(BTN_GRP);  
    }  
      
    void MyDialog::CreateButton(void)  
    {  
      BaseContainer bbc;    //Create a container to hold our custom button gizmo  
      
      if(btnState == false)  
      {  
          bbc.SetBool(BITMAPBUTTON_BORDER, BORDER_OUT);  
          bbc.SetString(BITMAPBUTTON_TOOLTIP, "I'm Up");  
          bbc.SetLong(BITMAPBUTTON_ICONID1, RESOURCEIMAGE_ROTATE);  
      }         
            
      else  
      {  
          bbc.SetBool(BITMAPBUTTON_BORDER, BORDER_IN);  
          bbc.SetString(BITMAPBUTTON_TOOLTIP, "I'm Down");  
          bbc.SetLong(BITMAPBUTTON_ICONID1, RESOURCEIMAGE_MOVE);  
      }  
      
      myButton = static_cast<BitmapButtonCustomGui*>(this->AddCustomGui(MY_BITMAP_BUTTON1, CUSTOMGUI_BITMAPBUTTON, "Bitmap Button", BFH_SCALEFIT | BFH_SCALEFIT, 130, 30, bbc));  
    }  
      
    Bool MyDialog::Command(LONG id,const BaseContainer &msg)  
    {  
      switch (id)   
      {  
          case MY_BITMAP_BUTTON1:  
              GePrint("Bitmap Button Was Pressed");      
              btnState = !btnState;                 //Makes the variable toggle true / false  
              myButton->SetToggleState(btnState);   //Toggles the button image  
      
              ReLayout();                           //Run the custom method that creates the button dynamically  
       
              break;  
      }  
      
      EventAdd();  
      return TRUE;  
    }  
      
      
    class MyDialogCMD : public CommandData   
    {  
      private:  
          MyDialog dlg;  
      
      public:  
          virtual Bool Execute(BaseDocument *doc);  
          virtual Bool RestoreLayout(void *secret);          
    };  
      
    Bool MyDialogCMD::Execute(BaseDocument *doc)  
    {  
      StopAllThreads();  
      return dlg.Open(DLG_TYPE_ASYNC,PLUGIN_ID, -1, -1, 200,200);  
    }  
      
    Bool MyDialogCMD::RestoreLayout(void *secret)  
    {  
      return dlg.RestoreLayout(PLUGIN_ID,0,secret);  
    }  
      
    Bool RegisterMyDialogCMD(void)  
    {           
      String Help = "Toggles Bitmap Button's border style";      //This string appears in the status bar when the user hovers over the plugin name in the menu  
      
      //Register the plugin  
      return RegisterCommandPlugin(PLUGIN_ID, GeLoadString(IDS_RESDIALOG), 0, AutoBitmap("icon.tif"), Help, gNew MyDialogCMD);  
    }
    

    -ScottA

    *Edit- Oops. Cross posted with you there.
    Thanks again for the code Katachi


Log in to reply