I'm designing a GUI framework based on trees of widgets. Widgets are general control and container structures that are everything from panels to buttons to file dialogs. Widgets have an array of child widgets; a button contains a label and maybe an icon. Widgets are fed input events where the widget first does its own logic with the event then passes it on to its children. The application feeds input events to a single root widget, which can be anything from a single button in the middle of the screen to a full control window.
I need a way to handle which widget(s) receives keyboard events. I've decided that one of the widgets in a given widget tree would be the focused widget. Widgets would have a gainFocus method and a loseFocus method, which would be used in response to mouse click events or manually by the application. It's unlikely I'll implement tabbing. When one widget gains focus, any existing focused widget would naturally lose focus.
I still want each ancestor of the focused widget to see a given keyboard event in turn before it's given to the focused widget itself. So if I have a panel with a text box in it, the panel would see the event before the text box does. Therefore I really need to keep track of the chain of widgets from the root widget to the focused widget. I also need to maintain data integrity when I change focus so that all widgets in a tree can correctly tell whether or not they're the focused widget or an ancestor of the focused widget.
I've so far come up with giving widgets a hasFocus boolean and a focusedChildIndex integer. hasFocus would be set to true when the widget has focus. focusedChildIndex would be set to the index of the focused child in its child array, which could be the focused widget itself or the next widget in the chain leading to the focused widget, or -1 to indicate that there's no focused child. Setting these variables when one widget in the tree gets its gainFocus or loseFocus method invoked is something I'm stumped on though.
So we're clear, this is what I think my widget class will be like:
class Widget private Widget parent private Array<Widget> children // Methods for getters, adding widgets to widget trees, etc. ... public void mouseClick(int x, int y) doMouseClickEvent(x, y) for c in children c.mouseClick(int x, int y)
As you can see in
mouseClick the widget sees the event before its children does. I want keyboard inputs to work the same way, except this time I want to only have a single chain from the root to the focused widget to see the event. Plus I need to make sure that when one widget gains focus the currently focused widget in the tree loses focus.