How to avoid "click through" when the mouse is on a widget?

Started by DiabeticWaffle, 08 December 2017, 01:05:56

DiabeticWaffle

Hey y'all! I'm a newcomer here and I would like a little help. :)
Here's the situation: I'm making an electric field simulation in which the user is able to create "charges"(represented by sf::CircleShape) in real-time.When he clicks anywhere on the SFML canvas, keeping the mouse button pressed, he is able to drag a "velocity vector" that points from the initial click to the current position of the mouse. As soon as he releases the left mouse button, the newly created charge will have a velocity represented by that vector.
Now onto the actual problem: once I click on a GUI element, say a button, that same behavior is repeatedâ€"so the user ends up accidentally creating a charge.What I actually want is for the simulation to ignore the mouse click & release altogether, but I don't know how to do it.
How should I go about implementing that?

texus

The handleEvent function returns a boolean which contains whether the gui responded to the event. So you should first call gui.handleEvent(event) and check the return value, only handle the event in your own code when handleEvent returned false.

DiabeticWaffle

Oh wow that was simple, thanks! I guess that's why I didn't find it in the forums & tutorials. :P
Now I have one more question: what about input that is handled continuouslyâ€"not through eventsâ€" such as in camera movement? How would I make it so that when the mouse hovers over the GUI those inputs are ignored? I know that widgets have MouseEntered and MouseLeft signals, but checking every widget doesn't sound like fun.There's a simpler solution that I'm probably too noobish to see.  :-\

texus

I assume the gui elements are on top of your game, because if all gui widgets were in a bar at a side of the screen then it would be a simple as just checking whether the mouse is on top of this sidebar.
You would have to check every widget if you really need to know whether the mouse is on top of the gui or not. But first you should ask yourself the question whether you really must check this. Why would you need continuous mouse events that interfere with the gui? If for camera movement, should the camera stop moving just because you hover over a widget but start moving again once you move the mouse next to it? I can't give you a better alternative to looping over the widgets if I don't know what the real situation is.

But at least there is a simpler way than connecting MouseEntered and MouseLeft signals, so looping over the widgets isn't actually that bad:
Code (cpp) Select
bool mouseOnWidget = false;
for (const auto& widget : gui.getWidgets())
{
    if (widget->mouseOnWidget(currentMousePosition))
    {
        mouseOnWidget = true;
        break;
    }
}


Or if you prefer a one-liner:
Code (cpp) Select
bool mouseOnWidget = std::any_of(gui.getWidgets().begin(), gui.getWidgets().end(), [=](const auto& w){ return w->mouseOnWidget(currentMousePosition); });

After that you simply don't execute your code if mouseOnWidget is true.

DiabeticWaffle

Yeah I just expressed myself really poorly.Instead of giving an actual concrete example, I invented a silly one that doesn't leave much room for a satisfactory answer.What I actually wanted to describe is something akin to those gui-heavy games(such as StarCraft), where there's a "zone" where input is handled by the gui(some games lock camera movement when the mouse hovers over the gui, so that's where I got that example), and the other is basically the game "canvas".In that case, your idea of putting widgets in a container and just checking that container for mouse overlap seems to solve the problem.I don't plan on implementing a gui in that fashion on my project, just wanted to know more in case I need that feature in the future.