Table of Contents

Input, focus and navigation

IcyUI takes input from the mouse, keyboard, gamepad and touch through the engine integration, and routes it to the element it's meant for: the element under the pointer, or the element with focus. A game played with a gamepad can use every control without a mouse.

Pointer input

The mouse and touch go to the topmost element under the pointer: overlays first (popups, dialogs), then root elements from the top of the drawing order down. An element with IsHitTestVisible off, hidden, or fully transparent is skipped, and so is everything outside a ClipToBounds parent.

Touch adds gestures, recognized from the raw touches and the mouse alike: a tap, a hold, a drag, and a two-finger pinch. ConfigureGestures tunes them: HoldDelay (0.5 s), MultiTapDelay (0.3 s) and Slop (10 px of movement before a press becomes a drag).

Note

MonoGame's DesktopGL backend reports no touch input; the mouse still works.

Focus

One element at a time has keyboard and gamepad focus: the canvas's FocusedElement. Controls the player can operate are focusable (IsFocusable); a click or tap focuses them, and Canvas.Focus(element) does it from code, for example to start a menu on its first button.

Keyboard Gamepad Does
Arrow keys D-pad Move focus to the nearest focusable element in that direction.
Tab, Shift+Tab Right / left stick click Move focus to the next / previous element.
Enter A Activate the focused element (press a button, toggle a check box, open a list).
Escape B Close the open dialog or list.

Arrow-key navigation is spatial: it picks the nearest element in the pressed direction on screen, so it works for any layout without setting an order. A focused element is scrolled into view. Some controls use the arrows themselves while focused (a text box moves its caret, a tree view moves between rows) and pass them on at their edges.

Note

The gamepad's X and Y raise back and forward events (INavigationEvents.NavigateBack and NavigateForward) for your own code to handle, but a Frame doesn't act on them yet. Give a page a Back button that calls Frame.Navigation.TryNavigateBack().

A focus scope (IsFocusScope) keeps navigation inside it: an open Window or Dialog is one, and focus returns to where it was when it closes. Set Canvas.IsKeyboardNavigationEnabled to false to turn arrow and Tab navigation off, for example while gameplay uses those keys.

Drag and drop

Moving data between elements (an item from one inventory slot to another) uses two interfaces. A source implements IDragSource and decides, when a drag starts on it, what it carries and what follows the pointer; a target implements IDropTarget and decides whether it accepts the drop:

/// <summary>An inventory slot: drag its item to another slot.</summary>
public sealed class InventorySlot : Border, IDragSource, IDropTarget
{
    public string? Item { get; set; }

    public bool TryBeginDrag(Point screenPoint, out object? payload, out UIElement? preview)
    {
        payload = Item;
        preview = Item is null ? null : new TextBlock { Text = Item };
        return Item is not null;
    }

    public bool CanDrop(DragDropSession session) => Item is null && session.Payload is string;

    public void OnDragEnter(DragDropSession session) => Opacity = 0.7f;

    public void OnDragOver(DragDropSession session)
    {
    }

    public void OnDragLeave(DragDropSession session) => Opacity = 1f;

    public void OnDrop(DragDropSession session)
    {
        Item = (string)session.Payload;
        ((InventorySlot)session.Source).Item = null;
        Opacity = 1f;
    }
}

The canvas finds the source by walking up from the element under the pointer, moves the preview with the pointer, and asks the target under it at each step. Dragging that only moves something inside one control (a slider's thumb, a split pane's divider) is built into those controls.

Pitfalls

  • UI input and game input. Check IsMouseOverGUI before your game reacts to a click; see Canvas, the host and the element tree.
  • Nothing focused, nothing to navigate. A menu opened for a gamepad should focus its first control.
  • Some controls aren't keyboard-operable yet: list box items, tab headers and a slider's value; see each control's page.

See also