Skip to content

Multi-Event observers #19572

Closed as duplicate of#14649
Closed as duplicate of#14649
@viridia

Description

@viridia

What problem does this solve or what need does it fill?

We're moving towards a model of widget design that is driven by dynamic components to represent the state of a widget: "pressed", "hovered", "disabled", "checked" and so on can all be modeled as individual components.

Unfortunately, when using an observer-based approach for reacting to these changes results in an untenable number of observer registrations, since we need to listen for both OnAdd and OnRemove for each marker component. Moreover, all of these observers are in effect identical, since they all compute the widget's visual appearance from the current state.

What solution would you like?

A solution that has been proposed is to allow for a single observer which monitors multiple lifecycle events on multiple components.

from @cart :

we now have increased need for something like @doot's static multi-event-listening proposal: #14674

While the newer dynamic proposal is flexible, I think we will want the ease of use / directness of the static API, as these are likely to be defined "in context" next to widgets. Ex: currently this requires six different identical observers, which isn't defensible:

fn on_button_change(
    trigger: Trigger<(
        OnAdd<Pressed>,
        OnRemove<Pressed>,
        OnAdd<InteractionDisabled>,
        OnRemove<InteractionDisabled>,
        OnInsert<Hovered>,
    )>,
    mut buttons: Query<
        (
            Has<Depressed>,
            &IsHovered,
            Has<InteractionDisabled>,
            &mut BackgroundColor,
            &mut BorderColor,
            &Children,
        ),
        With<DemoButton>,
    >,
    mut text_query: Query<&mut Text>,
) {
    if let Ok((pressed, hovered, disabled, mut color, mut border_color, children)) =
        buttons.get_mut(trigger.target())
    {
        let mut text = text_query.get_mut(children[0]).unwrap();
        set_button_style(
            disabled,
            hovered.get(),
            pressed,
            &mut color,
            &mut border_color,
            &mut text,
        );
    }
}

Notice that I switched to Trigger<OnAdd> instead of Trigger<OnAdd, Pressed>, as the current interface only supports a single component-target, which doesn't lend itself to expressing multiple events

What alternative(s) have you considered?

The current prototype registers separate observers, which are effectively identical.

Additional context

Discord thread: https://discord.com/channels/691052431525675048/1381791436126687326

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-FeatureA new feature, making something new possibleD-ComplexQuite challenging from either a design or technical perspective. Ask for help!S-Needs-DesignThis issue requires design work to think about how it would best be accomplished

    Type

    No type

    Projects

    Status

    Observer overhaul

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions