Getting Modal Dialogs to Work


In X-COM, all dialogs are modal. That is, when the dialog is up, everything else stops. (Actually, this might not be 100% true. It could be argued that the "click on base position" dialog that comes up when you want to create a base is a modeless dialog. However, it can be implemented by just adding a couple of widgets to the geoscreen, so I'm going to ignore it.)

OK, so start with a simple dialog, say the screen that pops up when the UFO that an aircraft is chasing disappears. It has some text, and two buttons "patrol last position of UFO" and "return to base" that the user can click. Depending on which button is clicked, the craft will change its behaviour from "intercept" to either "patrol" or "return to base".
Now, there are a couple of points we need to note here.
  1. Currently the "message pump" in Xenocide has the game object calling the screen manager's "update()" and "draw()" members every frame. And the screen manager delegates the calls to the geoscreen's update() and draw().
  2. The geoscreen's update() calls the gamestate's update() to update the state of the game.
  3. The message box will need to be put up because of something happening during this update() event.
  4. Now, in windows, dialogs are synchronous. That is, you call a DoModal() function of the dialog, and the "flow of control" halts while the dialog runs. When the user finally clicks on a button, the DoModal() call returns and the logic continues. That is, the logic looks something like:

    gamestate.Update()
    {
        …
        Update UFO positions
        …
        if (ufo.Escapes)
        {
            ufoEscapedDialog.DoModal();
            if (ufoEscapedDialog.UsersChoice == "Patrol")
            {
                aircraft.SetMission(Patrol);
            }
            else if (ufoEscapedDialog.UsersChoice == "ReturnToBase")
            {
                aircraft.SetMission(ReturnToBase);
            }
        }
        …
        Update Aircraft positions
    }
  5. Unfortunately, I can't see any simple way to implement a synchronous dialog, (because of the update()/draw() pump.)
  6. However, the dialog behaviour we want isn't that different from how screens behave. That is, if we switch from the geoscreen to the base management screen, game time stops, because the base management screen does not call the gamestate's update() function.
  7. So, a possible implementation of a modal dialog would be to add a "dialog" member to the screen manager class. We set this member when there is a dialog to show. When the dialog is set, the screen manager will draw both the screen and the dialog, but it won't call the screen's update() method.
  8. So, the implementation goes (conceptually) like this:

This is complicated by three additional factors:
Nesting dialogs
This is probably the easiest problem to solve. Instead of the screen manager having a single "dialog" member, we make it a stack.

Disabling Parent
Trivial. CeGui# has commands for disabling and enabling the widgets on a Window.

Multiple Events requiring a dialog
What do we do if during an update(), multiple events occur that require user interaction? This can happen, because our updates() can "contain" up to a minute of game time. So: assume during an update the following events all occur:
Here's my thoughts on the matter: