Canvas, the host and the element tree
Everything IcyUI draws lives on a Canvas: a surface the size of your game's window that lays out its
elements, draws them every frame and routes mouse, keyboard, gamepad and touch input to them. UseIcyUI() creates the
host that connects canvases to your engine and gives you the first canvas.
The host
UseIcyUI() returns the engine's host: MonoGameIcyHost or StrideIcyHost. Both are an IIcyHost:
- Configuration: the settings every element is created with (see Configuration);
- MainCanvas: the canvas
UseIcyUI()created, with input enabled; - Canvases: every canvas the host draws each frame, in order.
The host pumps input and follows the display scale every frame. On MonoGame it's a game component that draws during
base.Draw(), after your own drawing; on Stride it draws through the graphics compositor, after the scene. Other code
reaches the same host with GetIcyHost() (or GetIcyCanvas() for the main canvas) on the game.
A later canvas in Canvases draws on top of an earlier one. A second canvas is useful for a HUD that stays above menus, or a debug layer:
// A second canvas for a HUD, drawn above the main one; a background canvas at index 0 would draw below.
public static Canvas AddHudCanvas(IIcyHost ui)
{
var hud = new Canvas(ui.Configuration);
ui.Canvases.Add(hud);
return hud;
}
The element tree
A canvas holds root elements (Add(UIElement), or LoadMarkup for a markup file). Panels and
controls hold children, so the whole UI is a tree. Each element knows its Parent; a root's
parent is null, and it belongs to the canvas.
- Drawing order: children draw after their parent, in order; ZIndex moves an element above or below its siblings.
- Overlays: popups, dropdown lists, tooltips and dialogs go to the canvas's Overlays, which draw above every root element and receive input first.
- Visibility: IsVisible hides an element and its children and stops their input, but
they keep their space in the layout; Opacity fades them (at 0 they aren't drawn or hit);
IsHitTestVisible set to
falselets clicks pass through.
UI input and game input
The canvas takes the input that's meant for the UI. Your game should ignore a click that landed on a button: check IsMouseOverGUI before acting on the mouse.
// In your game's update: don't fire when the player clicks a button.
public static bool ShouldFire(IIcyHost ui, bool mousePressed) => mousePressed && !ui.MainCanvas.IsMouseOverGUI;
Which element has keyboard and gamepad focus is FocusedElement; see Input, focus and navigation.
Pitfalls
- An element belongs to one parent. Adding an element that is still in a panel, a border, a control's content or
the canvas throws
InvalidOperationException. Remove it from there first (Children.Remove,Content = null,Canvas.Remove), then add it somewhere else. - Elements created in code have no theme until they're attached. The theme's styles apply when an element joins a
canvas, so read
Templateor theme colors afterAdd, not before. - Hidden still takes space. To take an element out of the layout, remove it from its panel; set IsVisible back when it should only reappear in place.
- Draw your own content before the UI. On MonoGame, anything you draw after
base.Draw()covers the UI.
See also
- Configuration: what
UseIcyUI()sets up. - Layout: how elements on a canvas get their size and position.
- Getting started with Stride and with MonoGame.