No, not an instruction to a guy working a projector but the concept in GUI terms as to where the input goes.
Let me back up as I've come in half way through my thoughts, which is pretty normal for me.
About two weeks back, before the mad dash which was my 2D Java game project's hand in date, I wrote a couple of entries regarding my thoughts about putting together a GUI system built up of script and XML mostly with some C++ glue to hold it together.
One of the things I didn't mention was the message sending system, simply because I hadn't really given any thougth about how I was going todo it.
The hooking up of event sending, well there are a couple of ways to go;
- Firstly mandate what the functions are called and have the GUI-glue code search for them in script which controls each component. While reasonably simple to do it lacks a certain degree of flexibility and somewhat make a mockery of having the stuff in script anyways.
- The second idea was to name the function in the XML file. The XML file and the script file exist, more or less, as a pair anyways so you can't find one without the other. It also allows for the usage of the same base code but with two responces for free. The down side is the burden of assigning names falls on the programmer and they have to get it right in two places, not just one; this could be mitigated with a gui-designer which would ensure things were sane.
Currently, I'm favoring the latter of the two schemes because it's less hardcoding and I prefer 'soft' coding things more these days [smile]
So, focus, where does that come in?
Well, having got your event model hooked up how do you figure out what messages to send who? Toolmaker had a thread asking a question very much like this a few days back, in which I posted my inital idea which can be summed up as; Given that you have a parent-child relationship between controls and containers you can use this to quickly run down a tree to find out who should be getting the messages.
To me it seemed simple and it targets the messages at who requires them, job done right?
Well, no... in the same thread Deyja & Ezbez threw a spanner into the works.
Deyja started it by saying:
Some events everyone gets, whether the mouse is over them or not. Such as mouse motion, and mouse button releases. In fact, the only event that should really be restricted to the hover widget is mouse button down. You'll understand why if you ever write a scrollbar widget.
This intriged me, perticulary the last bit about the scrollbar widget so I asked for more details, which is where Ezbez enters into the picture:
Scrollbars almost always let you move the mouse to the side while your scrolling. This would mean that the mouse movement even is now off of the scrollbar. If you don't let the scrollbar handle movement events that are out of its bounds, it won't know this and will stop working the moment you move your mouse out of the thin bar. And if it can't handle mouse releases, it's even worse. It'd never know that the mouse was released, and so it could start being dragged again if you move your mouse over the scrollbar (eg: I drag the bar a bit, move my mouse to the side, release the mouse button. Later on, I click and hold down somewhere else and then move my mouse over the scrollbar and the scrollbar would start moving again without me ever clicking on it).
and followed again by Deyja
Ezbez got it. It can also be helpful to maintain a record of which widget the mouse is over, and of which widget the mouse was over when the button was depressed. This allows you to implement a click event when the mouse is released, and only call it if depressed on == hover.
Emphasis is mine, and it's somewhat the key point; focus.
Having read the above I went away to think for a while about the problem (I like thinking, mostly when I'm walking to place and as I was out last night it was a handy distraction during the 40min walk there) and tonight I sat down and played with things a bit, with the main thought in my mind being 'do we really want to send all message to all components all the time?'.
Lets take the humble button; you click on it and it does something, much like the reply button below this post I'm currently making. But, as we should all know, if you click and hold on it, move the mouse off and THEN release nothing happens, it's like... magic! Or not. The button looks like it's being pressed down still, but instead of it doing its action when released it appears to cancel it, either by not getting the message or by not carrying out the action when the message is sent.
On the topic of scrollbars, while I've done it many times the fact that you don't have to be on the scrollbar while moving to have an effect was never something which really registered with me. After the above to posts I played wiht it a bit to see how things worked, and yes of course it does work in that manner but I noticed some things about it;
- There seems to be a maximum distance you can move from the scroll bar before it defaults to 0 and stops responding
- While the scrollbar has focus nothing else responds to mouse over events, the only widget which responds is the scrollbar
So, when a scrollbar has focus and is being moved all other messages are off, everything goes directly to them, does not pass go and does not collect GBP200/$200 etc etc.
So, how does this help our GUI?
Well, for starters we don't need to send mouse messages to everyone all the time, infact it would seem we only need to send two classes of messages; the first to the compoent with focus, the second to componets we mouse over but only if we currently don't have mouse-down focus on someone else.
Although 'focus', despite me using it all this time, is techinically the wrong term; what is infact happening is the mouse has been 'captured' by a component to take all mouse input.
So, with all this in mind the problem seems to pretty easy to handle, code wise, as all you need to do is check for a 'mouse input captured' flag and only route messages to the 'captured'd object if set.
// find out who we are over and send the message down the tree
Every other mouse event relies on us just being over something and it responding correctly when it needs to capture things.
Certain events do required a 'focus'd component, such as text input and the ability to tab around the controls, however that's simply another tracking flag for keyboard events and not everyone can take keyboard focus (scrollbars for example don't).
So, thats where I feel I'm at right now, ideas wise;
- mouse events only to those below
-- mouse can be 'captured' for things such as scrollbars however
- text events require a focus'd component
-- requested, return value indicating if they want to hold focus or just have it removed from someone else (true, false?)
- XML defines event handlers in code as well as layout
- Script defines actions and handles changes for redrawing
- C++ code provides glue (technically, this could be anything, I just know C++ the best but C#, Java or even a scripting system itself could act as glue)
Comments anyone? [smile]