14 Replies - 1191 Views - Last Post: 29 June 2014 - 09:17 AM Rate Topic: -----

#1 ToLiGa  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 27-June 14

How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:01 AM

We are developing a GUI system. How can we handle the input of front panel, if it has also a panel under it? I mean, if i click on the front panel, the mouse input also effects on the lower panel. How can i avoid it? We have searched that problem on the net. For example, z-indexing systems or layering systems. But they are not ended up well. There are not much resources about it.
Is This A Good Question/Topic? 0
  • +

Replies To: How to handle overlapping mouse input in GUI?

#2 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:04 AM

It depends on what you mean by "the mouse input also effects on the lower panel.". What is that panel (underneath/lower zindex) doing with the mouse?
Was This Post Helpful? 0
  • +
  • -

#3 ToLiGa  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 27-June 14

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:06 AM

Say for example, there is a button under a button. When i click the top one, it also clicks the bottom one.
Was This Post Helpful? 0
  • +
  • -

#4 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:10 AM

A few things.. first - why would there be a button under a button?

Second - what is this using? opengl? something home brewed? directx?
Was This Post Helpful? 0
  • +
  • -

#5 ToLiGa  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 27-June 14

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:32 AM

It was an example. We are making a game in XNA, so there are lots of situations that GUI overlaps.
For example, when i check the "Find" button in the Debug Panel, the pathfinder system should find the path to wherever mouse clicks from a given constant point. When i uncheck it, it should do nothing.
But the problem is, as i click the Find button, it also clicks the map under the panel, so it finds the path to the square under the find button.
Because the mouse input works like this :

IF MouseLeftClicked AND SquareContains(MousePosition) THEN
FindPath() // Finds the path from constant square to clicked square
END IF

The code doesn't check if it mouse is over a gui or not. It just checks the mouse position and mouse click.

Posted Image
Posted Image
Was This Post Helpful? 0
  • +
  • -

#6 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:36 AM

Okay.. then you need to shoehorn in some logic to see if there is some sort of popup open, and if so it is it over the a given clickable area. If so then do not process any mouse clicks.
Was This Post Helpful? 0
  • +
  • -

#7 ToLiGa  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 27-June 14

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:40 AM

Yeah we know but how? :D There aren't any source or tutorial for this. This is just the beggining. When we make in game menus like (not debug)shopping interface, character info interface etc etc, the problem will grow up. There are methods like z-indexing or layering but there are no source for it or any tutorial.
Was This Post Helpful? 0
  • +
  • -

#8 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 581
  • View blog
  • Posts: 1,292
  • Joined: 24-April 12

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:43 AM

I would strongly question whether there is ever a case where it's permisible for there to be a button beneath another button. The best I can come up with is a pop-up menu that has buttons.

I'm actually building a GUI system in XNA right now. There are probably many ways you "could" handle it.

The way I handle it is in the design. I have a class hiearchy that starts with the GameObject class. GUIElement is inherited from GameObject. And then I have all sorts of GUI elements including buttons and windows.

Now, I don't currently have any need to do any overlays where elements are on top of one another. It's not called for in the design. However, we may add popup windows at some point, and I would not get rid of any elements, such as buttons, that are partially covered by the popup window.

So, it probably would need to determine which element should receive the mouse event (not just clicking, but hovering, and such).

I would have to go back through the code to see exactly the best way to handle it, but all of the elements are children of GUIElement. I have a GUIManager class that maintain's a List<GUIElement> of GUIElements to be drawn on the screen. The GUIManager class calls every element in the list to draw itself. (It also calls every element every frame to Update() itself.)

I about half expect that the design would make dealing with this pretty easy. But one solution might be to process them according to Z depth and stop processing them the first time one of the elements handles the event.

This post has been edited by BBeck: 27 June 2014 - 09:45 AM

Was This Post Helpful? 1
  • +
  • -

#9 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 09:44 AM

Yes - you are now encountering problems that are not 100% mapped out and ready to be dolled out with a spoon. Break the issue down into manageable chunks, and see what to do. I do not know your code nor do I know your game states, but there options.

One being if there is a menu up - freeze everything but the menu. You would need to trigger this in the global update to propagate to all other screen objects. The other option is do what I said by checking a given click.. and if that click is inside a menu *AND* a button then do not do the button.
Was This Post Helpful? 0
  • +
  • -

#10 ToLiGa  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 5
  • Joined: 27-June 14

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 10:01 AM

Thanks for the responses but i am not meaning an esc menu or something like that with buttons in it. It was an example. I am meaning more like an in game menu like in the picture below.
Posted Image
In our game, when we click that in game menu, it also effect beneath.
Was This Post Helpful? 0
  • +
  • -

#11 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 10:08 AM

As bbeck said - a hierarchy of events. An object's click event will need validation now. Validate if a popup is open, and validate if it is above it. If both are true then do not continue with the event.
Was This Post Helpful? 0
  • +
  • -

#12 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 581
  • View blog
  • Posts: 1,292
  • Joined: 24-April 12

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 10:09 AM

Well, I stick with what I said. However, I might add that this reminds me of the game screen/state manager I did during the Pong Challenge. The XNA code for that is in that thread.

That game state manager allowed for layered screens. Specifically, I tested it with a "pause" screen that was on top of the game screen and transparent so that you could still see the game screen. In that case, the lower screen was frozen. But, I think that was a boolean variable where you could choose to freeze the lower screen or not.

That's kind of like modi123_1 said about making the dialog box model and freezing everything other then the box/window.

Just because you can't click on the background screen, does not mean the background screen can't Update(). That's two seperate things.

Of course, if you just want that popup screen without disabling anything other then what the popup screen actually covers, you need to intercept the mouse event (probably by processing what's on top and killing the event at that point). No matter what you do there, you're going to have to determine what's on top somehow. Z depth is the obvious way.
Was This Post Helpful? 1
  • +
  • -

#13 BerkayD  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 16
  • Joined: 28-December 13

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 10:15 AM

Hello, i am the co-worker in the project. Thanks for the helpful responses.
We tried the z-indexing and layering with enumaration. But we couldn't implemented it properly. Are there any source codes or tutorial series for that subject that we can learn from? If so, i would be glad if you can share with us. Thank you :)
Was This Post Helpful? 0
  • +
  • -

#14 modi123_1  Icon User is online

  • Suitor #2
  • member icon



Reputation: 9393
  • View blog
  • Posts: 35,273
  • Joined: 12-June 08

Re: How to handle overlapping mouse input in GUI?

Posted 27 June 2014 - 10:17 AM

Again - there probably isn't a specific tutorial to fit your state diagram, game play, game interaction, etc. You'll need to determine how your game events work and how to best put validation for click events into them.
Was This Post Helpful? 0
  • +
  • -

#15 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 581
  • View blog
  • Posts: 1,292
  • Joined: 24-April 12

Re: How to handle overlapping mouse input in GUI?

Posted 29 June 2014 - 09:17 AM

As modi123_1 stated, you're probably not going to find a specific tutorial on that. At best, you might find it buried in some tutorial somewhere. I certainly would not know where to point you on that.

However, I happen to be working on an XNA GUI right now, and I'll share with you what I'm doing. I specifically overlapped several of my GUI elements to create this problem, since so far I don't actually need or want any of them to overlap. But I figure I will probably want to do popup windows at some point, so I should incorporate Z depth into the design. I had already somewhat planned for this even though I had not implemented it yet; my parent class already had a depth member that I just wasn't using and I had been specifying the depth of most of my objects when instantiating them.

The problem actually turned out to be a little more difficult then I expected, as I've spent several hours implementing it across 2 days even though it was already partially in the original design. I encountered some interesting problems and tried a few things that didn't work out, which may be kind of what you're going through.

On the surface, the answer on "How do you make a mouse event only go to the top layer object?" is "You make the object keep track of it's depth, process the objects in depth order, and stop processing the first time you process an object. So the object most near will be the only one receiving the mouse event."

You could theoretically kill the mouse event, but in XNA the mouse event is not actually an event. It's more of a state and it's a read-only state at that. So, you can't kill it. I encountered a problem with the mouse state initially when trying to make the positions of elements contained in a window relative to the containing window's position. In other words, a button contained in the window should have a position that is within the window; when I move the window the button should move with it without specifically moving the button. And this means the mouse screen position must be dependent on the position within the window. So, I wanted to change the mouse position when inside a window and found out it's read-only. Instead I added offset parameters to be added to the mouse position to handle it.

But my point there is that you can't change the mouse state; you're stuck with it and just have to deal with it. And that means you can't kill the mouse event because it's not an event.

I suppose you could turn it into an actual event, but that's not what I'm doing.

One of the last problems that I had to address is the fact that you actually need to draw from back to front, but you need to process the mouse from front to back and stop processing with the top most element.

Anyway, the way my program works is with a class hierarchy that is heavily influenced by working in Unity and having seen similar designs elsewhere. In Unity, everything is either a Game Object or is attached to a Game Object. Almost every game object is going to be a child of other game objects forming a tree of Game Objects that compose the scene/game.

I took that concept, and tried to divide it out into 3D game objects and 2D GUI elements. It could also be 2D in both cases, but GUI elements are probably going to be 2D always.

Here's my definition of a GUIElement. Notice that there is a float for ScreenDepth. I put that in the original design before I started working on this problem of overlapping. Also, note that every GUIElement child class must implement an Update() and Draw() method to know how to update and draw themselves. The MouseState is passed as part of that Update() so that each GUIElement can process mouse events. I'm also passing a HandledMouse boolean flag so that the Update can tell me whether it felt like the mouse was within it's screen rectangle. All I'm doing there is returning true if the mouse is over that particular GUI element. The first time that returns true, I stop processing the elements. You may need something a bit more complex then that if an element must still be processed even if the mouse cursor is no where near it. HandledMouse is passed by reference so that the value can be returned to the caller and the caller can decide what to do with that info. This could probably be extended to tell lower elements that the Mouse has already been processed and that they can Update but should not process the mouse. With mine, I just stop updating the first time it returns true.

public abstract class GUIElement:GameObject
    {
        private Rectangle ActualScreenCoordinates;
        protected float ScreenDepth;


        public float Depth
        {
            get { return ScreenDepth; }
            set { ScreenDepth = value; }
        }


        protected virtual Rectangle Coordinates
        {
            get { return ActualScreenCoordinates; }
            set { ActualScreenCoordinates = value; }
        }


        public bool Contains(int X, int Y)
        {
            Point PointToCheck;

            PointToCheck.X = X;
            PointToCheck.Y = Y;

            return ActualScreenCoordinates.Contains(PointToCheck);
        }


        public abstract void Update(GameTime gameTime, MouseState CurrentMouseState, MouseState PreviousMouseState, 
            int XOffset, int YOffset, ref bool HandledMouse, SoundEffect ClickSound, SoundEffectInstance ClickSoundInstance);
        public abstract void Draw(GameTime gameTime, SpriteBatch Batch);

    }



Update() and Draw() in the main code simply call the Update() and Draw() of the GUIManager object. This is the code that really does the overlap work. The GUIManager class has a List<GUIElement> of GUI elements that are on the screen. I order that list every time a new element is added to the list according to screen depth. Notice the SelectableElement.OrderBy. This reorders the list according to ScreenDepth (ScreenDepth is exposed as a property called Depth but it's actually the ScreenDepth member shown above). Keep in mind I'm hacking up this code a bit to make it shorter and easier to read by excluding things that aren't particularly relevant to this discussion; so look at this more as pseudo code rather then actual working code. You might also notice that all GUIElements here are children of GUIElement.

        public void AddGUIElement(GUIElement Element)
        {
            if (Element is Button) SelectableElement.Add(Element as Button);
            if (Element is SelectionBar) SelectableElement.Add(Element as SelectionBar);
            if (Element is Label) StaticElementList.Add(Element as Label);
            if (Element is WindowContainer) SelectableElement.Add(Element as WindowContainer);
            SelectableElement = SelectableElement.OrderByDescending(o => o.Depth).ToList();
        }




Here's the actual Update() and Draw() code. Notice that the update is done in reverse order from shallow to deep so that the most shallow will be processed first. While the draw is done in standard order from deep to shallow. The "foreach (GUIElement UIElement in SelectableElement.Reverse<GUIElement>())" does a foreach loop in reverse order. I break out of the loop the first time the MouseEventHandled flag is set which is just checking if the mouse is inside that element's rectangle whether it is actually processed or not. I really hate the fact that I'm using a break here to break a foreach loop but I'm too lazy right now to correct it. I should probably decide if I really want to stop processing at that point or continue through the loop letting every future element know the mouse has already been previously captured by a topmost element. Then I could get rid of the ugly loop break that is bugging me. Or I could use something other than a foreach loop although foreach is just so handy. In this code the break is pretty straight forward but it's possible to have a loop exiting at multiple points and in more complex code it could be confusing that the loop exits some place other then the end.

        public void Update(GameTime gameTime, MouseState CurrentMouseState, MouseState PreviousMouseState)
        {
            bool MouseEventHandled = false;
            foreach (GUIElement UIElement in SelectableElement.Reverse<GUIElement>())   //Draw back to front, but process front to back.
            {
                UIElement.Update(gameTime, CurrentMouseState, PreviousMouseState, 0, 0, ref MouseEventHandled, ClickSound, ClickSoundInstance);
                if (MouseEventHandled == true)
                {
                    break;
                }
            }
        }


        public void Draw(GameTime gameTime, SpriteBatch Batch)
        {
            foreach (GUIElement UIElement in SelectableElement)
            {
                UIElement.Draw(gameTime, Batch);
            }
        }



Anyway, that's pretty much it. I just stop updating when the topmost element has the cursor, but I draw everything regardless of where the cursor is.

This post has been edited by BBeck: 29 June 2014 - 09:24 AM

Was This Post Helpful? 1
  • +
  • -

Page 1 of 1