> For the complete documentation index, see [llms.txt](https://docs.flatredball.com/gum/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.flatredball.com/gum/code/events-and-interactivity/visual-events.md).

# Visual Events

## Introduction

Visuals in Gum provide a large number of events. Most Forms events are based on the events provided by their underlying visuals. Visual events may be needed if you intend to:

* Handle events specific to certain visuals
* Create custom controls, such as a button "from scratch"
* Access additional events which are not exposed by the event, such as HoverOver on a Button
* Access events on controls which normally do not have events, such as click events on a Label

## Visual Types with Events

Not all Visual Types support events. To support events, the visual type must inherit from InteractiveGue. Furthermore, HasEvents must be set to true. The following shows which types have support for events:

| Type                    | Supports Events | Default HasEvents |
| ----------------------- | --------------- | ----------------- |
| CircleRuntime           | ❌ Not Supported | -                 |
| ColoredRectangleRuntime | ❌ Not Supported | -                 |
| ContainerRuntime        | ✅Supported      | true              |
| NineSliceRuntime        | ✅Supported      | false             |
| PolygonRuntime          | ✅Supported      | false             |
| RectangleRuntime        | ❌ Not Supported | -                 |
| SpriteRuntime           | ❌ Not Supported | -                 |
| TextRuntime             | ✅Supported      | false             |

{% hint style="info" %}
Note that future versions of Gum may add support for events on runtimes so the table above may change, however, if this happens the HasEvents property will still default to false as to not break existing behavior. If your project needs events on any types which are not supported, please file an issue on GitHub or let us know on Discord.
{% endhint %}

## Available Events

The following events are available on visuals:

<table><thead><tr><th width="234">Event Name</th><th>Description</th></tr></thead><tbody><tr><td><code>Click</code></td><td>Event raised when this is clicked by a cursor. A click occurs when the cursor is over this and is first pushed, then released.</td></tr><tr><td><code>ClickBubbling</code></td><td>Event raised when this is clicked by a cursor. Unlike <code>Click</code>, which is only raised on the clicked element, this event is raised first on the clicked element, then bubbles up to its parents in sequence. If a control sets the argument <code>RoutedEventArgs</code> Handled to true, then parent objects will not have this event raised. This is useful for responding to a click anywhere on an element's surface, even when the click lands on a child.</td></tr><tr><td><code>ClickPreview</code></td><td>Event raised when this is clicked by a cursor. A click occurs when the cursor is over this and is first pushed, then released. Preview events are received by parents before children, and if the event is handled, children do not receive the event.</td></tr><tr><td><code>DoubleClick</code></td><td>Event raised when this is double-clicked by a cursor. A double-click occurs when the cursor is over this and the left moue button is clicked twice in rapid succession.</td></tr><tr><td><code>Dragging</code></td><td>Event raised when the cursor pushes on an object and moves. This is similar to RollOver, but is raised even if outside of the bounds of the object. This can be used if an object is to be moved by dragging since it will be raised even if the user moves the cursor quickly outside of its bounds.</td></tr><tr><td><code>EnabledChange</code></td><td>Event raised when the Enabled property changed.</td></tr><tr><td><code>HoverOver</code></td><td>Event raised every frame the cursor is over this object whether the cursor has changed positions or not.</td></tr><tr><td><code>LosePush</code></td><td>Event raised when this loses a push. A push occurs when the cursor is over this and the left mouse button is pushed. A push is lost if the left mouse button is released or if the user moves the cursor so that it is no longer over this while the mouse button is pressed.</td></tr><tr><td><code>MouseWheelScroll</code></td><td>Event raised when the mouse wheel has been scrolled while the cursor is over this instance. This event is first raised on children, then bubbles up to parents. If a control sets the argument Handled to true, then parent objects will not receive this event.</td></tr><tr><td><code>Push</code></td><td>Event raised when this is pushed by a cursor. A push occurs when the cursor is over this and the left mouse button is pushed (not down last frame, down this frame).</td></tr><tr><td><code>PushPreview</code></td><td>Event raised when this is pushed by a cursor. A push occurs when the cursor is over this and the left mouse button is pushed (not down last frame, down this frame). Preview events are received by parents before children, and if the event is handled, children do not receive the event.</td></tr><tr><td><code>RemovedAsPushed</code></td><td>Event raised when this is pushed, then is no longer the pushed visual due to a cursor releasing the primary button. This can be used to detect the end of a drag operation, or to reset the state of a button.</td></tr><tr><td><code>RightClick</code></td><td>Event raised when this is right-clicked by a cursor. A right-click occurs when the cursor is over this and is first pushed, then released.</td></tr><tr><td><code>RollOff</code></td><td>Event raised when the cursor first leaves this object.</td></tr><tr><td><code>RollOn</code></td><td>Event raised when the cursor first moves over this object. This is only received if the cursor is moved directly over this object. If it is instead moved over a child object which has its own events, then the parent will receive this event.</td></tr><tr><td><code>RollOver</code></td><td>Event raised every frame the cursor is over this object and the Cursor has changed position. This event is not raised if the cursor has moved off of the object. For events raised when the cursor is not over this instance, see Dragging.</td></tr><tr><td><code>RollOverBubbling</code></td><td>Event raised when the mouse rolls over this instance. This event is raised top-down, with the child object having the opportunity to handle the roll over first. If a control sets the argument <code>RoutedEventArgs</code> Handled to true, then parent objects will not have this event raised.</td></tr></tbody></table>

## Event Examples

The following table provides examples on which events are raised when the user performs various actions. This can help provide context for how visual events are raised.

| User Action                                                                                                                                                                           | Events                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| User moves cursor over a Button, pushes, then releases the left mouse button.                                                                                                         | <ol><li><code>RollOn</code> is raised when the cursor moves over the button</li><li><code>RollOver</code> and <code>RollOverBubbling</code> are raised as the cursor moves over the button every frame, but are not raised if the cursor is stationary</li><li><code>HoverOver</code> is raised every frame the cursor is over the button, even if it is not moving</li><li><code>PushPreview</code> and <code>Push</code> are raised when the user first presses the left mouse button</li><li><code>ClickPreview</code>, <code>Click</code>, and <code>ClickBubbling</code> are raised when the user releases the button</li><li><code>LosePush</code> and <code>RemoveAsPushed</code> are raised when the user releases the left mouse button</li></ol>                                                                                                                                                                                                                         |
| User moves the cursor over a Button, pushes the left mouse button, moves the cursor off of the button while still holding the left mouse button, then releases the left mouse button. | <ol><li><code>RollOn</code> is raised when the cursor moves over the button</li><li><code>RollOver</code> and <code>RollOverBubbling</code> are raised as the cursor moves over the button every frame, but are not raised if the cursor is stationary</li><li><code>HoverOver</code> is raised every frame the cursor is over the button, even if it is not moving</li><li><code>PushPreview</code> and <code>Push</code> are raised when the user first presses the left mouse button</li><li><code>RollOver</code> and <code>Dragging</code> are raised every frame as the cursor moves over the button while the button is held</li><li><code>LosePush</code> is raised when the cursor moves outside of the Button's bounds</li><li><code>Dragging</code> is still raised ever frame as the user holds the left mouse button while moving outside of the Button's bounds</li><li><code>RemoveAsPushed</code> is raised when the user releases the left mouse button</li></ol> |

## Code Example: Handling Visual Events

Visual events can be subscribed to on any control. The following code shows how to subscribe to a `Visual.HoverOver` event which is raised every frame that the cursor is hovering over the `Button`.

```csharp
// Initialize
Button button = new();
button.AddToRoot();
button.Anchor(Anchor.Center);
button.Visual.HoverOver += (_, _) =>
{
    button.Text = 
        $"Hovered at {DateTime.Now:HH:mm:ss.fff}";
};
```

<figure><img src="/files/4cCBwgk7NQIfQHaeHAJP" alt=""><figcaption></figcaption></figure>

## Code Example: Bubbling Click Events

The `Click` event is only raised on the element that was clicked. If you want to respond to a click anywhere on a container's surface — even when the click lands on a child — subscribe to `ClickBubbling` instead. It is raised first on the clicked element, then bubbles up to each parent in sequence.

The following code subscribes to `ClickBubbling` on a `StackPanel`. The handler runs whenever either child `Button` is clicked, because the event bubbles from the clicked button up to the panel.

```csharp
// Initialize
StackPanel panel = new();
panel.AddToRoot();
panel.Anchor(Anchor.Center);

Button first = new();
first.Text = "First";
panel.AddChild(first);

Button second = new();
second.Text = "Second";
panel.AddChild(second);

Label status = new();
status.AddToRoot();
status.Anchor(Anchor.Bottom);

// ClickBubbling is raised on the panel even though the click lands on a child Button.
panel.Visual.ClickBubbling += (sender, args) =>
{
    status.Text = "A button in the panel was clicked";
};
```

A handler can set `args.Handled` to `true` to stop the event from bubbling to further parents. For example, a child can mark the event handled so its parent's `ClickBubbling` handler does not run.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.flatredball.com/gum/code/events-and-interactivity/visual-events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
