Writing custom UI system for game...

Started by
15 comments, last by Toolmaker 17 years ago
I'm currently in the process of writing a UI system for my game. While most of it works, I'm concerned about handling the mouse events throughout controls. For instance, I need to know which control my mouse is over when I click or move the mouse(So I can send enter/leave/mouse messages). Right now, i'm having a list of all Windows in game, and check if the mouse is in one of these Windows. If it is, I send a message to the Window about what happened(MouseEnter, MouseLeave, MouseMove, MouseDown/Up/Click). However, this is only the Window. Each window can have multiple siblings, which in return can have siblings of themselfs. How would I go in notifying these siblings about said action too? I technically could add all controls I have to a list and walk this list, check if the mouse is over any of those controls, and from there-on walk the list up via the Parent property, or have the event cascade down from the WindowManager to the control and have the control pass it on to it's siblings. What would be most efficient in this case? Toolmaker

Advertisement
I've been pondering the idea of a custom GUI of late myself, and while I'm as yet to write any code personally I'd go from the parent down to the children.

This effectively gives you an 'early out' when you click on a parent but don't have a child under it which needs to respond under the click.

I have the widgets in a n-tree and recurse through the tree hunting for the last object which would catch the event. It's certainly good/responsive enough, even with a few thousand widgets in the scene. If you place the constraint that child rectangles must be within their parent's that would allow much faster handling since you can not recurse if the mouse misses the parent. I don't place that constraint and things are still plenty fast.
I do it the way Telastyn does. There are materials on GUI design on the web, and you should look at how existing GUI frameworks do stuff.

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.
In my GUI system every actual control inherits from ComponentContainer and Component. Every ComponentContainer holds a list of direct child Components.

If i detect mouse events inside a Component i call upon ComponentContainers routine to find the child below the mouse. If there is a child Component found the mouse event is modified (relativate position) and passed on. If there is no child found the message is handled in the Component.

The GUI top parent is simply a ComponentContainer without the Component part. This allows me to simply pass the mouse event to the top parent. From there on it's passed down in the hierarchy.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Quote:Original post by Deyja
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.


Care to expand upon that a bit?
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).
I use a hierarchy like this in my engine: CActor -> CGuiWidget -> CButtonWidget (or CEditWidget, CStaticPictureWidget, etc.) -> (custom user controls).

Event handling is still in progress, maybe I'll make a post on my gui once it's finished. BTW, the icon for the GUI editor in my map editor is... gooey... a bottle of glue :)
hackerkey://v4sw7+8CHS$hw6+8ln6pr8O$ck4ma4+9u5Lw7VX$m0l5Ri8ONotepad++/e3+8t3b8AORTen7+9a17s0r4g8OP
My setup is pretty similar to what has already been described, a sort of scene graph for widgets. My inheritance hierarchy is like this: Rectangle->Widget->Container->Panel. "Normal" widgets such as buttons inherit directly from Widget. Container keeps track of which child has keyboard focus and which child is being hovered over, and delegates input events to its children. At the top of the tree I have a Desktop widget covering the whole display which either passes input events on or handles the special cases for the Console window or does general-case input to the game, like keyboard shortcuts or picking.

Reading over this thread, it seems that I'm going to have some problems implementing scroll bars, so I might have to re-design some of the event passing mechanisms. But the general idea of a widget tree still holds, so I'll add my voice to the others recommending it.
Quote:Care to expand upon that a bit?


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.

This topic is closed to new replies.

Advertisement