Make handleEvent return a bool indicating if the event should be ignored

Started by wizzard, 29 July 2013, 06:53:11

wizzard

In my game editor, I want events that the GUI uses to be ignored by the game editor. So, if there is a window there and you have the object placing tool in use, objects won't be placed behind the window when you are clicking on the window. I can do this currently but it requires doing a bunch of bounds checking and stuff outside of TGUI that TGUI already does internally. It'd be nice if a bool was returned that told me whether an event was a GUI-only event or not.

wizzard

Also, why not use a union here?

// Only one of these things can be filled at a given time
bool checked;
int value;
Vector2f value2d;
Vector2f position;
Vector2f size;
unsigned int index;

texus

I'll look into the possibility of returning a bool. It might be harder than it looks at first sight.

As a quick workaround, something like this should be enough. (I didn't try to compile the code, so it might contain small errors)
bool mouseOnGuiWidget = false;
if ((event.type == sf::Event::MouseMoved) || (event.type == sf::Event::MouseButtonPressed) || (event.type == sf::Event::MouseButtonReleased))
{
    std::Vector2i mousePosition;
    if ((event.type == sf::Event::MouseMoved)
        mousePosition = sf::Vector2i(event.mouseMove.x, event.mouseMove.y);
    else
        mousePosition = sf::Vector2i(event.mouseButton.x, event.mouseButton.y);

    std::vector<tgui::Widget::Ptr> widgets = gui.getWidgets();
    while (unsigned int i = 0; i < widgets.size(); ++i)
    {
        if (widgets[i]->mouseOnWidget(mousePosition.x, mousePosition.y))
        {
            mouseOnGuiWidget = true;
            break;
        }
    }
}

That might be a bit smaller than the piece of code you've written.

QuoteAlso, why not use a union here?
You can't have Vector2f in a union. There was a union before with structs that just had an x and y member, but it seemed easier to use if it was a Vector2f directly so I removed the union.

texus

handleEvent could return a bool, but I will have to change a couple of lines for that.
But I won't do that if your problem can be solved with only a few lines.

If the only thing you need to check is if the mouse is on top of the child window, then it could be done like this:
while (window.pollEvent(event))
{
    gui.handleEvent();

    if ((event.type == sf::Event::MouseMoved) && (childWindow->mouseOnWidget(event.mouseMove.x, event.mouseMove.y)))
        continue;
    else if ((event.type == sf::Event::MouseButtonPressed) || (event.type == sf::Event::MouseButtonReleased))
    {
        if (childWindow->mouseOnWidget(event.mouseButton.x, event.mouseButton.y))
            continue;
    }

    // Handle the event here
}


Or is there something that I don't know yet and does it require you to write a lot more code than that?
Because I'm willing to make the change if it makes some difference, I just don't want to do it to only replace a line or five in your code.

wizzard

I have used both GWEN and libRocket before trying this library and they both had bools returning when an event was "consumed" by the GUI.
Check out the prototypes for libRocket's input functions here.
Notice that ProcessKeyDown, ProcessKeyUp, ProcessTextInput, and ProcessMouseWheel return booleans.
For some reason ProcessMouseDown and ProcessMouseUp do not have this happening in libRocket.
GWEN definitely has functions for mouse button down and mouse button up events being ignored,
but it has no proper online documentation for me to link here to show you.

Anyways, I think it is currently possible in TGUI to ignore the events that the GUI "consumes".
It just takes a lot of extra code because it is not just the mouse events.
Note that I am unsure if mouse move events should be considered in events that are potentially ignored.
I actually recommend leaving mouse move events up to me whether they are ignored or not by forcing me to manually implement ignoring of them.

To sum up the events that are potentially consumed, they are:

  • TextEntered
  • KeyPressed
  • KeyReleased
  • MouseWheelMoved
  • MouseButtonPressed
  • MouseButtonReleased
  • MouseMoved (maybe)

Key and text events are only consumed if a widget has focus that takes text(?).

texus

Alright, those are more convincing arguments, I'll see what I can do.

I'm not sure about mouse move, they look like they do belong to the gui to me and should thus be treated the same way as mouse clicks.

texus

The changes have been made. The function will now return true when the gui didn't handle the event and false when the event was consumed.

Currently MouseMoved is also consumed, but this can always be changed later. And it shouldn't be too much trouble to manually check if the event was a mouse move and then still executing your code instead of ignoring the event.

The current solution isn't perfect though. Key presses are also consumed when e.g. a button is selected.
It will require a bit more changes to fix that. In every widget, the functions that are used to tell the widget about the event would have to return a bool whether or not they actually handled the event.

But this should do for now.

wizzard

Awesome stuff! Thanks!

Quote from: texus on 30 July 2013, 01:02:06
The function will now return true when the gui didn't handle the event and false when the event was consumed.
Doesn't the inverse make a bit more sense though? If the event was handled when calling handle event, handle event should return true. If the event was not handled when calling handle event, handle event should return false. It seems backwards to me because usually when a function fails it returns false.


if (!gui.handleEvent(event)) {
    // The GUI did not handle the event, and so we will
}

wizzard

I know libRocket does it the "backwards" way too. GWEN does it the "right" way.
Just a minor style choice, so it does not really matter

gupas

I'm agree with wizzard to say that it is a more common way to return true when the event was handled and false when it was not consumed.

texus

Grrrr, I did it the right way first, then I looked at the librocket documentation and saw that they did it the other way around, which is why I changed it.

Fixed.