GUI: Disable keyboard events in buttons.

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

GUI: Disable keyboard events in buttons.

Post by christianclavet »

Hi, I just added buttons to my application but I also use the SPACE key to do other things...

Got this problem as in the source for CGUIButton.cpp there is this:

Code: Select all

bool CGUIButton::OnEvent(const SEvent& event)
{
    if (!isEnabled())
        return IGUIElement::OnEvent(event);
 
    switch(event.EventType)
    {
    case EET_KEY_INPUT_EVENT:
        if (event.KeyInput.PressedDown &&
            (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
        {
            if (!IsPushButton)
                setPressed(true);
            else
                setPressed(!Pressed);
 
            return true;
        }
        if (Pressed && !IsPushButton && event.KeyInput.PressedDown && event.KeyInput.Key == KEY_ESCAPE)
        {
            setPressed(false);
            return true;
        }
        else
        if (!event.KeyInput.PressedDown && Pressed &&
            (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE))
        {
 
            if (!IsPushButton)
                setPressed(false);
 
            if (Parent)
            {
                SEvent newEvent;
                newEvent.EventType = EET_GUI_EVENT;
                newEvent.GUIEvent.Caller = this;
                newEvent.GUIEvent.Element = 0;
                newEvent.GUIEvent.EventType = EGET_BUTTON_CLICKED;
                Parent->OnEvent(newEvent);
            }
            return true;
        }
        break;
    case EET_GUI_EVENT:
        if (event.GUIEvent.Caller == this)
        {
            if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUS_LOST)
            {
                if (!IsPushButton)
                    setPressed(false);
                FocusTime = os::Timer::getTime();
            }
            else if (event.GUIEvent.EventType == EGET_ELEMENT_FOCUSED)
            {
                FocusTime = os::Timer::getTime();
            }
            else if (event.GUIEvent.EventType == EGET_ELEMENT_HOVERED || event.GUIEvent.EventType == EGET_ELEMENT_LEFT)
            {
                HoverTime = os::Timer::getTime();
            }
        }
        break;
Got a couple of questions/requests about this:

- Could we have an enabler/disabler function for key input? (a simple bool variable with a method would do the trick). This would not change the default behavior of the button, with the method to disable it (key input) would fix my problem.

- Why are the keys are hard coded? Would be nice to define them... Theses one could be default values, and have override method or skin values to change the key values

- Would be nice to have a "hover" text/background texture (when the mouse is hovering the button, change the texture to another one)
CuteAlien
Admin
Posts: 9628
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: GUI: Disable keyboard events in buttons.

Post by CuteAlien »

You can catch those events in your eventreceiver (element->hasType(irr::gui::EGUIET_BUTTON) then catch EET_KEY_INPUT_EVENT and return true or handle your stuff first).

setSprite might allow setting sprites on hover (not tested myself yet).

In general you are right, but I see currently no way working on this myself.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: GUI: Disable keyboard events in buttons.

Post by christianclavet »

You can catch those events in your eventreceiver (element->hasType(irr::gui::EGUIET_BUTTON) then catch EET_KEY_INPUT_EVENT and return true or handle your stuff first).
:shock: Wow! Is there more informations how to achieve this?

I have some GUI stuff (Mostly a stretching window class that use mouse cursor changes) I'm working on in my project that I plan to give back (IRRext). I could create a version of the button gui with all the feature and add it also. This does not look too hard to implement (add on GUI). When I will do so (putting all my programming time on my own project now to get to alpha 0.3), you could perhaps "pick" some parts...
setSprite might allow setting sprites on hover (not tested myself yet).
Yes, I think this could be done externally... Theorically, as I've also not tested it myself. :D

Thanks!
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: GUI: Disable keyboard events in buttons.

Post by chronologicaldot »

christianclavet wrote:
You can catch those events in your eventreceiver (element->hasType(irr::gui::EGUIET_BUTTON) then catch EET_KEY_INPUT_EVENT and return true or handle your stuff first).
:shock: Wow! Is there more informations how to achieve this?
Funny, I just did this.

In your element's OnEvent function:

Code: Select all

 
MyGUIElem::OnEvent( const SEvent& event )
{
if ( event.EventType == EET_KEY_INPUT_EVENT && event.KeyInput.Key == KEY_SPACE )
{
// Do some stuff
return true; // Prevents the button from acting (see important note below).
}
 
/* Now call everything else. */
return IGUIElement::OnEvent(event);
}
 
IMPORTANT NOTE: In the constructor for your element, where you should be making your buttons, be sure to
1) set the parent to your element
2) set them to be sub-elements:
IGUIButton* button1 = environment->addButton( rectangle, this ); /* ID doesn't matter */
button1->setSubElement(true);

This tells the engine that when your element is hovered over, the buttons do NOT act as independent entities. The environment focus is set to your element, like it should be. :D
I have some GUI stuff (Mostly a stretching window class that use mouse cursor changes) I'm working on in my project that I plan to give back (IRRext).
Hurray!
setSprite might allow setting sprites on hover (not tested myself yet).
Yes, I think this could be done externally... Theorically, as I've also not tested it myself. :D
I'm not sure what you mean. If you're looking to give the buttons sprites for hovering then in the constructor for your element (that contains the buttons), you can give the buttons a pre-made sprite bank (from some external source), which is what I did for my buttons.

Currently, there is <insert: "no"> problem with sprites. <if you saw something here, pretend it didn't exist>
christianclavet
Posts: 1638
Joined: Mon Apr 30, 2007 3:24 am
Location: Montreal, CANADA
Contact:

Re: GUI: Disable keyboard events in buttons.

Post by christianclavet »

@chronologicaldot
Hi and thanks for the details! I'll try it so I will not have to write another GUI class (at least for 0.3) and give me more time to work in other areas.
I'm not sure what you mean. If you're looking to give the buttons sprites for hovering then in the constructor for your element (that contains the buttons), you can give the buttons a pre-made sprite bank
What I would like to do, is to do a similar thing that we have with Adobe Flash buttons. To change the picture when then mouse "get in" the button and set it back to it's last "button state" when the mouse pointer "get out" of the zone. I don't think it would be hard to do if I do my own button class, but was wondering if someone was able to do this externally (using the Irrlicht button, and doing this from outside the Irrlicht class)
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: GUI: Disable keyboard events in buttons.

Post by chronologicaldot »

christianclavet wrote:What I would like to do, is to do a similar thing that we have with Adobe Flash buttons. To change the picture when then mouse "get in" the button and set it back to it's last "button state" when the mouse pointer "get out" of the zone. I don't think it would be hard to do if I do my own button class, but was wondering if someone was able to do this externally (using the Irrlicht button, and doing this from outside the Irrlicht class)
Yes, I believe the sprite bank will do that.

You can set the button sprites one of two ways: 1) in your constructor or 2) make editing their sprite bank accessible after creation.

For example:

First, make a sprite bank:

Code: Select all

 
/* We use a function that could be a member function of a class which is called during or after initialization of the GUI element whose buttons use this sprite bank. We use the same sprite bank in this example so that all of the buttons receive the same hover effect. */
IGUISpriteBank* getMenuSpriteBank() /* or myClass::getMenuSpriteBank() . You may be able to make this class const - I haven't checked */
{
/* If this is the member function of a class, we can conveniently pre-save a sprite bank so we don't have to create it each time. Or, while I haven't checked, I believe you can get a named sprite bank from the GUI environment, and that way you don't have to save a pointer to it and this function does not have to be a member function of some class. */
if ( spriteBank ) { return spriteBank; }
/* Otherwise, we initialize it */
IGUISpriteBank* spriteBank;
 
/* Now we get a new sprite bank from the GUI environment.
For in classes, this is convenient. We call getEnvironment() . Otherwise, we would have to pass in the environment as a parameter. */
spriteBank = getEnvironment()->addEmptySpriteBank( "mybank" ); /* This is an io::path, so it should be unique. I believe you can use this name to find the bank again if it has already been made. */
 
/* In order to prevent our sprite bank from drawing anything when the button is not being hovered over, we add a blank frame. */
SGUISpriteFrame noHoverFrame;
noHoverFrame.rectNumber = 0;
noHoverFrame.textureNumber = 0;
 
/* Repeat the following for the number of frames you want */
SGUISpriteFrame hoverFrame0;
hoverFrame.rectNumber = 0;
hoverFrame.textureNumber = 1;
/* Notably, the rectNumber is the same for all frames. This is because our button doesn't change size, so why should the image rectangle? */
 
SGUISprite hoverSprite;
hoverSprite.frameTime = 100; /* A good time length for about 5 frames or so */
hoverSprite.Frames.push_back( noHoverFrame );
hoverSprite.Frames.push_back( hoverFrame0 );
// ... etc.
 
/* For smooth transitions, I also add a hover-off sprite, which is made the same way as the hover-on sprite but with the frames added in the reverse order. */
 
// Add the sprites to the bank
spriteBank->getSprites().push_back( hoverSprite );
// ... etc
 
// button area rectangle
spriteBank->getPositions().push_back( recti( position2di(), myDimension ) );
 
// add textures
/* Notice the first one is blank. This is the texture when the button is not being hovered over, so we just want a blank texture of the same type as the other textures. */
spriteBank->addTexture( getEnvironment()->getVideoDriver()->getTexture( "" ) );
spriteBank->addTexture( getEnvironment()->getVideoDriver()->getTexture( hoverTexturePath ) );
 
return spriteBank;
 
}
 

Next, we use the sprite bank in the class, either in the constructor,

Code: Select all

 
// Sample GUI class
 
class myElem :: public IGUIElement
{
protected:
IGUIButton* button;
 
public:
myElem( IGUIEnvironment* environment, /* Optionally: */ mySpriteBank // ... etc. )
{
button = environment->addButton( button_rectangle, this );
button->setSubElement( true );
 
/* At this point, you can add your images to your buttons. I discovered that setting useAlphaChannel does nothing to the sprite's alpha channel settings (thankfully). */
 
// Here, you can add the sprite bank, if you want
button->setSpriteBank( mySpriteBank );
 
// Now set the hover sprite
button->setSprite( EGBS_BUTTON_MOUSE_OVER, 0 /* hover sprite index */, SColor() /* specific hover color */, false /* don't loop frames */ );
 
// Now set the hover-off sprite - same as above but with the sprite index set to 1
}
 
/* Or, you can set it externally.
I have not tested this, but given how sprites work, I can't imagine why it wouldn't work. */
void setButtonSpriteBank( IGUISpriteBank* mySpriteBank )
{
button->setSpriteBank( mySpriteBank );
 
// Now set the hover sprite
button->setSprite( EGBS_BUTTON_MOUSE_OVER, 0 /* hover sprite index */, SColor() /* specific hover color */, false /* don't loop frames */ );
 
// Now set the hover-off sprite - same as above but with the sprite index set to 1
}
 
};
 
 
In my example, there is only one button, though you can obviously do this for every button, even simplifying your code by passing your buttons to a single function like so:

Code: Select all

 
void setButtonSpriteBank( IGUIButton* button, IGUISpriteBank* bank )
{
// ... same code as setButtonSpriteBank() given above
}
 
You don't ever have to grab or drop the sprite bank. The GUI environment and the GUI buttons will do all of that (see docs for addEmptySpriteBank() ).

I think this should get you what you want. Of course, you'll have to make the hover button textures yourself.
chronologicaldot
Competition winner
Posts: 684
Joined: Mon Sep 10, 2012 8:51 am

Re: GUI: Disable keyboard events in buttons.

Post by chronologicaldot »

One last note about sprite textures:
If you set the sprite color to 255,255,255,255, it is ignored and the original colors of the texture are used (The alpha channel can vary and the original colors still be used). Otherwise, the only thing that really matters is the alpha channel.
Post Reply