Modal GUI and ongoing events

Started by
8 comments, last by Kylotan 7 years, 8 months ago

What is the normal way to handle events when a GUI becomes modal, for instance because a modal dialog appears? This can happen while the user is clicking, dragging, resizing or whatever.

How should the events be terminated or aborted? For instance, if the user is dragging something when the modal dialog appears, there will be no mouse up event because the GUI has gone modal. Only the modal dialog receives events. So his cursor will show a resizing sprite forever.

Advertisement

IMHO: From an UX point of view, your GUI has a design flaw when it regularly causes such a break. Why should a modal dialog appear without a causing user interaction? You should definitely avoid that. It can be accepted in seriously problematic situations, but then the pointer's shape should be your least problem. That said, what are the specific use cases you have in mind?

The modal dialog appears when an event happens in the game that the player has to decide on. The game is a realtime simulation strategy game.

In the past I've deal with this like a 'focus lost' type situation. I'd send an internal event saying the focus was lost (I can't recall the exact wording) and anything that found that useful could listen for it do something with it. The system that is handling whatever the mouse is dragging could listen for the event and deal with it (drop the item for example).

Interested in Fractals? Check out my App, Fractal Scout, free on the Google Play store.

The modal dialog appears when an event happens in the game that the player has to decide on. The game is a realtime simulation strategy game.

An often seen strategy here is to make it clear to the user that a message or a decision is waiting for him, and wait for the user to finish whatever he is doing, and click on the "let me see the message" button.

In a realtime game, there are moments of intense activity, and users generally don't like getting unexpected popups in the middle of that.

Some of the events indicate meetings or funerals. It makes more sense to interrupt the game than sticking them in an interface somewhere.

It seems to me that the cursor icon system should be reacting to the event that triggers the modal popup as well - placing the correct icon and making sure the state is set correctly before the modal pops up

The normal way for a GUI to handle this is that the GUI knows that there is a modal window, routes all events to that, and doesn't propagate them to anything else.

If the user was dragging something when the modal dialog box appears, then the eventual mouse-up event will be swallowed by the modal dialog and nothing happens.

It should not be the responsibility of the dialogs to change your mouse cursor, so there's no reason why the swallowing of that event should mean a broken mouse cursor. The GUI system as a whole should be watching for these operations and knows that a drag operation ends on mouse-up regardless of where that occurs. Dialogs can advise the GUI that a drag operation is valid in the beginning, but they don't get to decide when the operation ends.

I have a component class called ResizableArea that can be placed on a form. Currently it has these event methods:

 /// <summary>
        /// Change to resize cursor.
        /// </summary>
        /// <param name="args">Mouse event arguments.</param>
        protected override void OnMouseOver(UIComponent sender, MouseEventArgs args)
        {
            base.OnMouseOver(sender, args);
            ShowResizeCursor();
        }


        /// <summary>
        /// Put cursor back to normal.
        /// </summary>
        /// <param name="args">Mouse event arguments.</param>
        protected override void OnMouseOut(UIComponent sender, MouseEventArgs args)
        {
            base.OnMouseOut(sender, args);


            // Set back mouse cursor
            GUIManager.SetMouseCursor(MouseSprites.Normal);
        }


        /// <summary>
        /// Starts dragging, and invokes the StartResizing event.
        /// </summary>
        /// <param name="args">Mouse event arguments.</param>
        protected override void OnMouseDown(MouseEventArgs args)
        {
            if (args.Button == MouseButtons.Left)
            {
                this.dragging = true;
                this.lastLocation = args.Position;


                if (StartResizing != null)
                    StartResizing.Invoke(this);
            }
        }


        /// <summary>
        /// Finishes dragging, and invokes the EndResizing event.
        /// </summary>
        /// <param name="args">Mouse event arguments.</param>
        protected override void OnMouseUp(MouseEventArgs args)
        {
            if (args.Button == MouseButtons.Left)
            {
                this.dragging = false;


                if (EndResizing != null)
                    EndResizing.Invoke(this);
            }
        }

Should this kind of code be moved to the GUIManager class (how), or should I change the logic globally so all event methods can handle a situation where an expected event never occurs?

Looking at it again, it would probably be better if the component handled a "focus lost" event that could place it back in a normal state.

Your component should not be telling the GUIManager what to do, ever. Usually it should be the other way around. The only bit of code you really need to remove is where the component tells the GUIManager when to change cursor styles. However the main problem is that you also do that based on assumptions made about events arriving in a certain order, which you can't guarantee. You might want to have the GUIManager send OnDragStart and OnDragStop messages to the component instead.

This topic is closed to new replies.

Advertisement