This section is the core of GUI implementation. Window messages are the events that get sent to a window when the user performs certain actions - clicking the mouse, moving it, hitting a key, etc. Some messages (like wm_keydown) are sent to the active window, some (wm_mousemove) are sent to the window the mouse is over, and some (wm_update) are always sent to the desktop, regardless.
Microsoft Windows has a message queue. My GUI does not - when calcall() figures out that it needs to send a message to a window, it stops right there and “sends” it - it calls the appropriate wm_xxxx() virtual function for that window. I’ve found that this method is just fine for simple GUIs. Unless you have a really good reason, don’t bother with implementing a full-blown message queue, storing things into it, and having separate threads pick up the messages and dispatch them. For most game GUIs, it isn’t worth it.
As much as I’d like to, I can’t go into very much detail about calcall(), the function that polls all the input devices and sends out the messages. It does many things, and implements many behaviors that are specific to my GUI. For example, you might want your GUI to behave like X-Windows, where the window the mouse is over is always the active window. Or, you might want to make the active window system modal (meaning nothing else can happen until the user gets rid of it), like several Mac-based programs do. You might want the ability to move windows by clicking anywhere in them, instead of just in their title bar, like WinAmp. The implementation of calcall() will vary wildly depending on which behaviors you decide to incorporate into your GUI.
I’ll give you a hint, though - the calcall() function is not stateless, in fact, your calcall() function will probably end up being a rather complex state machine. The perfect example of this is dragging and dropping things. In order to properly calculate the difference between a normal “mouse button released” event, and a similar but completely different “whatever the user was dragging has just been dropped” event, calcall() must maintain a state. If you’re rusty on finite state machines, save yourself a lot of headaches and brush up on them before you tackle calcall()’s implementation.
The wm_xxx() functions included in the window header file were the ones I felt represented the minimum set of messages a GUI would need to calculate and dispatch. Your needs may differ, and there’s no reason why you have to stick to the Microsoft Windows set of messages; if a custom message would be perfect for you, now’s the time to implement it.
Wrapping It Up
In the first part of this article I PDL’d out a function called CApplication::RenderGUI(), the master function behind calculating and drawing our GUI:
void CApplication::RenderGUI(void) {
// get position and button status of mouse cursor
// calculate mouse cursor’s effects on windows / send messages
// render all windows
// render mouse
// flip to screen
}
Now, finally, we’re at a position where we can begin filling in some of that PDL. Check it out:
void CApplication::RenderGUI(void) {
// get position and button status of mouse cursor
m_mouse.Refresh();
// calculate mouse cursor’s effects on windows / send messages
GetDesktop()-›PumpMessages();
// render all windows
GetDesktop()-›RenderAll();
// render mouse
m_mouse.Render();
// flip to screen
GetBackBuffer()-›Flip();
}
Hopefully, seeing this code now will show you how things are starting to come together.
Part III: Implementing Controls
This section doesn’t have as much code as the others - this is mainly because we programmers are fairly picky when it comes to the appearance of our GUI. We like to code things up so that our buttons, our textboxes, and our GUI appear unique, and fit our own aesthetic tastes. Consequently, everyone’s control code will be slightly (or maybe drastically different), and it wouldn’t make sense to include my particular drawing code. Besides, writing code to draw all the GUI elements is fun, in fact, in my opinion, it’s the most fun you can have implementing a GUI. Go wild.
That being said, let’s start by determining which GUI controls we need.
GUI Controls We’ll Need
I didn’t want to spend a lot of time implementing controls for my game GUI; I wanted to stick with the smallest set of controls that I could. So, I came up with a list of controls that I consider the minimum set for game GUIs…