Rename some pointer events and components (#19574)

# Objective

#19366 implemented core button widgets, which included the `Depressed`
state component.

`Depressed` was chosen instead of `Pressed` to avoid conflict with the
`Pointer<Pressed>` event, but it is problematic and awkward in many
ways:

- Using the word "depressed" for such a high-traffic type is not great
due to the obvious connection to "depressed" as in depression.
- "Depressed" is not what I would search for if I was looking for a
component like this, and I'm not aware of any other engine or UI
framework using the term.
- `Depressed` is not a very natural pair to the `Pointer<Pressed>`
event.
- It might be because I'm not a native English speaker, but I have very
rarely heard someone say "a button is depressed". Seeing it, my mind
initially goes from "depression??" to "oh, de-pressed, meaning released"
and definitely not "is pressed", even though that *is* also a valid
meaning for it.

A related problem is that the current `Pointer<Pressed>` and
`Pointer<Released>` event names use a different verb tense than all of
our other observer events such as `Pointer<Click>` or
`Pointer<DragStart>`. By fixing this and renaming `Pressed` (and
`Released`), we can then use `Pressed` instead of `Depressed` for the
state component.

Additionally, the `IsHovered` and `IsDirectlyHovered` components added
in #19366 use an inconsistent naming; the other similar components don't
use an `Is` prefix. It also makes query filters like `Has<IsHovered>`
and `With<IsHovered>` a bit more awkward.

This is partially related to Cart's [picking concept
proposal](https://gist.github.com/cart/756e48a149db2838028be600defbd24a?permalink_comment_id=5598154).

## Solution

- Rename `Pointer<Pressed>` to `Pointer<Press>`
- Rename `Pointer<Released>` to `Pointer<Release>`
- Rename `Depressed` to `Pressed`
- Rename `IsHovered` to `Hovered`
- Rename `IsDirectlyHovered` to `DirectlyHovered`
This commit is contained in:
Joona Aalto 2025-06-11 00:57:28 +03:00 committed by GitHub
parent 27b64c3bf1
commit 33c6f45a35
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 136 additions and 132 deletions

View File

@ -12,8 +12,8 @@ use bevy_ecs::{
};
use bevy_input::keyboard::{KeyCode, KeyboardInput};
use bevy_input_focus::{FocusedInput, InputFocus, InputFocusVisible};
use bevy_picking::events::{Cancel, Click, DragEnd, Pointer, Pressed, Released};
use bevy_ui::{Depressed, InteractionDisabled};
use bevy_picking::events::{Cancel, Click, DragEnd, Pointer, Press, Release};
use bevy_ui::{InteractionDisabled, Pressed};
/// Headless button widget. This widget maintains a "pressed" state, which is used to
/// indicate whether the button is currently being pressed by the user. It emits a `ButtonClicked`
@ -49,7 +49,7 @@ fn button_on_key_event(
fn button_on_pointer_click(
mut trigger: Trigger<Pointer<Click>>,
mut q_state: Query<(&CoreButton, Has<Depressed>, Has<InteractionDisabled>)>,
mut q_state: Query<(&CoreButton, Has<Pressed>, Has<InteractionDisabled>)>,
mut commands: Commands,
) {
if let Ok((bstate, pressed, disabled)) = q_state.get_mut(trigger.target().unwrap()) {
@ -63,17 +63,17 @@ fn button_on_pointer_click(
}
fn button_on_pointer_down(
mut trigger: Trigger<Pointer<Pressed>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Depressed>), With<CoreButton>>,
mut trigger: Trigger<Pointer<Press>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<CoreButton>>,
focus: Option<ResMut<InputFocus>>,
focus_visible: Option<ResMut<InputFocusVisible>>,
mut commands: Commands,
) {
if let Ok((button, disabled, depressed)) = q_state.get_mut(trigger.target().unwrap()) {
if let Ok((button, disabled, pressed)) = q_state.get_mut(trigger.target().unwrap()) {
trigger.propagate(false);
if !disabled {
if !depressed {
commands.entity(button).insert(Depressed);
if !pressed {
commands.entity(button).insert(Pressed);
}
// Clicking on a button makes it the focused input,
// and hides the focus ring if it was visible.
@ -88,40 +88,40 @@ fn button_on_pointer_down(
}
fn button_on_pointer_up(
mut trigger: Trigger<Pointer<Released>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Depressed>), With<CoreButton>>,
mut trigger: Trigger<Pointer<Release>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<CoreButton>>,
mut commands: Commands,
) {
if let Ok((button, disabled, depressed)) = q_state.get_mut(trigger.target().unwrap()) {
if let Ok((button, disabled, pressed)) = q_state.get_mut(trigger.target().unwrap()) {
trigger.propagate(false);
if !disabled && depressed {
commands.entity(button).remove::<Depressed>();
if !disabled && pressed {
commands.entity(button).remove::<Pressed>();
}
}
}
fn button_on_pointer_drag_end(
mut trigger: Trigger<Pointer<DragEnd>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Depressed>), With<CoreButton>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<CoreButton>>,
mut commands: Commands,
) {
if let Ok((button, disabled, depressed)) = q_state.get_mut(trigger.target().unwrap()) {
if let Ok((button, disabled, pressed)) = q_state.get_mut(trigger.target().unwrap()) {
trigger.propagate(false);
if !disabled && depressed {
commands.entity(button).remove::<Depressed>();
if !disabled && pressed {
commands.entity(button).remove::<Pressed>();
}
}
}
fn button_on_pointer_cancel(
mut trigger: Trigger<Pointer<Cancel>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Depressed>), With<CoreButton>>,
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<CoreButton>>,
mut commands: Commands,
) {
if let Ok((button, disabled, depressed)) = q_state.get_mut(trigger.target().unwrap()) {
if let Ok((button, disabled, pressed)) = q_state.get_mut(trigger.target().unwrap()) {
trigger.propagate(false);
if !disabled && depressed {
commands.entity(button).remove::<Depressed>();
if !disabled && pressed {
commands.entity(button).remove::<Pressed>();
}
}
}

View File

@ -94,8 +94,8 @@ impl Plugin for DebugPickingPlugin {
log_event_debug::<pointer::PointerInput>.run_if(DebugPickingMode::is_noisy),
log_pointer_event_debug::<Over>,
log_pointer_event_debug::<Out>,
log_pointer_event_debug::<Pressed>,
log_pointer_event_debug::<Released>,
log_pointer_event_debug::<Press>,
log_pointer_event_debug::<Release>,
log_pointer_event_debug::<Click>,
log_pointer_event_trace::<Move>.run_if(DebugPickingMode::is_noisy),
log_pointer_event_debug::<DragStart>,

View File

@ -31,7 +31,7 @@
//!
//! The events this module defines fall into a few broad categories:
//! + Hovering and movement: [`Over`], [`Move`], and [`Out`].
//! + Clicking and pressing: [`Pressed`], [`Released`], and [`Click`].
//! + Clicking and pressing: [`Press`], [`Release`], and [`Click`].
//! + Dragging and dropping: [`DragStart`], [`Drag`], [`DragEnd`], [`DragEnter`], [`DragOver`], [`DragDrop`], [`DragLeave`].
//!
//! When received by an observer, these events will always be wrapped by the [`Pointer`] type, which contains
@ -171,7 +171,7 @@ pub struct Out {
/// Fires when a pointer button is pressed over the `target` entity.
#[derive(Clone, PartialEq, Debug, Reflect)]
#[reflect(Clone, PartialEq)]
pub struct Pressed {
pub struct Press {
/// Pointer button pressed to trigger this event.
pub button: PointerButton,
/// Information about the picking intersection.
@ -181,7 +181,7 @@ pub struct Pressed {
/// Fires when a pointer button is released over the `target` entity.
#[derive(Clone, PartialEq, Debug, Reflect)]
#[reflect(Clone, PartialEq)]
pub struct Released {
pub struct Release {
/// Pointer button lifted to trigger this event.
pub button: PointerButton,
/// Information about the picking intersection.
@ -400,7 +400,7 @@ impl PointerState {
pub struct PickingEventWriters<'w> {
cancel_events: EventWriter<'w, Pointer<Cancel>>,
click_events: EventWriter<'w, Pointer<Click>>,
pressed_events: EventWriter<'w, Pointer<Pressed>>,
pressed_events: EventWriter<'w, Pointer<Press>>,
drag_drop_events: EventWriter<'w, Pointer<DragDrop>>,
drag_end_events: EventWriter<'w, Pointer<DragEnd>>,
drag_enter_events: EventWriter<'w, Pointer<DragEnter>>,
@ -412,7 +412,7 @@ pub struct PickingEventWriters<'w> {
move_events: EventWriter<'w, Pointer<Move>>,
out_events: EventWriter<'w, Pointer<Out>>,
over_events: EventWriter<'w, Pointer<Over>>,
released_events: EventWriter<'w, Pointer<Released>>,
released_events: EventWriter<'w, Pointer<Release>>,
}
/// Dispatches interaction events to the target entities.
@ -422,7 +422,7 @@ pub struct PickingEventWriters<'w> {
/// + [`DragEnter`] → [`Over`].
/// + Any number of any of the following:
/// + For each movement: [`DragStart`] → [`Drag`] → [`DragOver`] → [`Move`].
/// + For each button press: [`Pressed`] or [`Click`] → [`Released`] → [`DragDrop`] → [`DragEnd`] → [`DragLeave`].
/// + For each button press: [`Press`] or [`Click`] → [`Release`] → [`DragDrop`] → [`DragEnd`] → [`DragLeave`].
/// + For each pointer cancellation: [`Cancel`].
///
/// Additionally, across multiple frames, the following are also strictly
@ -430,7 +430,7 @@ pub struct PickingEventWriters<'w> {
/// + When a pointer moves over the target:
/// [`Over`], [`Move`], [`Out`].
/// + When a pointer presses buttons on the target:
/// [`Pressed`], [`Click`], [`Released`].
/// [`Press`], [`Click`], [`Release`].
/// + When a pointer drags the target:
/// [`DragStart`], [`Drag`], [`DragEnd`].
/// + When a pointer drags something over the target:
@ -452,7 +452,7 @@ pub struct PickingEventWriters<'w> {
/// In the context of UI, this is especially problematic. Additional hierarchy-aware
/// events will be added in a future release.
///
/// Both [`Click`] and [`Released`] target the entity hovered in the *previous frame*,
/// Both [`Click`] and [`Release`] target the entity hovered in the *previous frame*,
/// rather than the current frame. This is because touch pointers hover nothing
/// on the frame they are released. The end effect is that these two events can
/// be received sequentially after an [`Out`] event (but always on the same frame
@ -609,7 +609,7 @@ pub fn pointer_events(
pointer_id,
location.clone(),
hovered_entity,
Pressed {
Press {
button,
hit: hit.clone(),
},
@ -646,12 +646,12 @@ pub fn pointer_events(
commands.trigger_targets(click_event.clone(), hovered_entity);
event_writers.click_events.write(click_event);
}
// Always send the Released event
// Always send the Release event
let released_event = Pointer::new(
pointer_id,
location.clone(),
hovered_entity,
Released {
Release {
button,
hit: hit.clone(),
},

View File

@ -296,14 +296,14 @@ fn merge_interaction_states(
/// Typically, a simple hoverable entity or widget will have this component added to it. More
/// complex widgets can have this component added to each hoverable part.
///
/// The computational cost of keeping the `IsHovered` components up to date is relatively cheap, and
/// linear in the number of entities that have the [`IsHovered`] component inserted.
/// The computational cost of keeping the `Hovered` components up to date is relatively cheap, and
/// linear in the number of entities that have the [`Hovered`] component inserted.
#[derive(Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect)]
#[reflect(Component, Default, PartialEq, Debug, Clone)]
#[component(immutable)]
pub struct IsHovered(pub bool);
pub struct Hovered(pub bool);
impl IsHovered {
impl Hovered {
/// Get whether the entity is currently hovered.
pub fn get(&self) -> bool {
self.0
@ -314,24 +314,24 @@ impl IsHovered {
/// is directly hovering over an entity. Users should insert this component on an entity to indicate
/// interest in knowing about hover state changes.
///
/// This is similar to [`IsHovered`] component, except that it does not include descendants in the
/// This is similar to [`Hovered`] component, except that it does not include descendants in the
/// hover state.
#[derive(Component, Copy, Clone, Default, Eq, PartialEq, Debug, Reflect)]
#[reflect(Component, Default, PartialEq, Debug, Clone)]
#[component(immutable)]
pub struct IsDirectlyHovered(pub bool);
pub struct DirectlyHovered(pub bool);
impl IsDirectlyHovered {
impl DirectlyHovered {
/// Get whether the entity is currently hovered.
pub fn get(&self) -> bool {
self.0
}
}
/// Uses [`HoverMap`] changes to update [`IsHovered`] components.
/// Uses [`HoverMap`] changes to update [`Hovered`] components.
pub fn update_is_hovered(
hover_map: Option<Res<HoverMap>>,
mut hovers: Query<(Entity, &IsHovered)>,
mut hovers: Query<(Entity, &Hovered)>,
parent_query: Query<&ChildOf>,
mut commands: Commands,
) {
@ -343,11 +343,11 @@ pub fn update_is_hovered(
return;
}
// Algorithm: for each entity having a `IsHovered` component, we want to know if the current
// Algorithm: for each entity having a `Hovered` component, we want to know if the current
// entry in the hover map is "within" (that is, in the set of descenants of) that entity. Rather
// than doing an expensive breadth-first traversal of children, instead start with the hovermap
// entry and search upwards. We can make this even cheaper by building a set of ancestors for
// the hovermap entry, and then testing each `IsHovered` entity against that set.
// the hovermap entry, and then testing each `Hovered` entity against that set.
// A set which contains the hovered for the current pointer entity and its ancestors. The
// capacity is based on the likely tree depth of the hierarchy, which is typically greater for
@ -365,15 +365,15 @@ pub fn update_is_hovered(
for (entity, hoverable) in hovers.iter_mut() {
let is_hovering = hover_ancestors.contains(&entity);
if hoverable.0 != is_hovering {
commands.entity(entity).insert(IsHovered(is_hovering));
commands.entity(entity).insert(Hovered(is_hovering));
}
}
}
/// Uses [`HoverMap`] changes to update [`IsDirectlyHovered`] components.
/// Uses [`HoverMap`] changes to update [`DirectlyHovered`] components.
pub fn update_is_directly_hovered(
hover_map: Option<Res<HoverMap>>,
hovers: Query<(Entity, &IsDirectlyHovered)>,
hovers: Query<(Entity, &DirectlyHovered)>,
mut commands: Commands,
) {
// Don't do any work if there's no hover map.
@ -389,16 +389,14 @@ pub fn update_is_directly_hovered(
for (entity, hoverable) in hovers.iter() {
let is_hovering = map.contains_key(&entity);
if hoverable.0 != is_hovering {
commands
.entity(entity)
.insert(IsDirectlyHovered(is_hovering));
commands.entity(entity).insert(DirectlyHovered(is_hovering));
}
}
} else {
// No hovered entity, reset all hovers.
for (entity, hoverable) in hovers.iter() {
if hoverable.0 {
commands.entity(entity).insert(IsDirectlyHovered(false));
commands.entity(entity).insert(DirectlyHovered(false));
}
}
}
@ -417,7 +415,7 @@ mod tests {
// Setup entities
let hovered_child = world.spawn_empty().id();
let hovered_entity = world.spawn(IsHovered(false)).add_child(hovered_child).id();
let hovered_entity = world.spawn(Hovered(false)).add_child(hovered_child).id();
// Setup hover map with hovered_entity hovered by mouse
let mut hover_map = HoverMap::default();
@ -437,8 +435,8 @@ mod tests {
// Run the system
assert!(world.run_system_cached(update_is_hovered).is_ok());
// Check to insure that the hovered entity has the IsHovered component set to true
let hover = world.entity(hovered_entity).get_ref::<IsHovered>().unwrap();
// Check to insure that the hovered entity has the Hovered component set to true
let hover = world.entity(hovered_entity).get_ref::<Hovered>().unwrap();
assert!(hover.get());
assert!(hover.is_changed());
@ -446,7 +444,7 @@ mod tests {
world.increment_change_tick();
assert!(world.run_system_cached(update_is_hovered).is_ok());
let hover = world.entity(hovered_entity).get_ref::<IsHovered>().unwrap();
let hover = world.entity(hovered_entity).get_ref::<Hovered>().unwrap();
assert!(hover.get());
// Should not be changed
@ -458,7 +456,7 @@ mod tests {
world.increment_change_tick();
assert!(world.run_system_cached(update_is_hovered).is_ok());
let hover = world.entity(hovered_entity).get_ref::<IsHovered>().unwrap();
let hover = world.entity(hovered_entity).get_ref::<Hovered>().unwrap();
assert!(!hover.get());
assert!(hover.is_changed());
}
@ -469,7 +467,7 @@ mod tests {
let camera = world.spawn(Camera::default()).id();
// Setup entities
let hovered_entity = world.spawn(IsDirectlyHovered(false)).id();
let hovered_entity = world.spawn(DirectlyHovered(false)).id();
// Setup hover map with hovered_entity hovered by mouse
let mut hover_map = HoverMap::default();
@ -489,10 +487,10 @@ mod tests {
// Run the system
assert!(world.run_system_cached(update_is_directly_hovered).is_ok());
// Check to insure that the hovered entity has the IsDirectlyHovered component set to true
// Check to insure that the hovered entity has the DirectlyHovered component set to true
let hover = world
.entity(hovered_entity)
.get_ref::<IsDirectlyHovered>()
.get_ref::<DirectlyHovered>()
.unwrap();
assert!(hover.get());
assert!(hover.is_changed());
@ -503,7 +501,7 @@ mod tests {
assert!(world.run_system_cached(update_is_directly_hovered).is_ok());
let hover = world
.entity(hovered_entity)
.get_ref::<IsDirectlyHovered>()
.get_ref::<DirectlyHovered>()
.unwrap();
assert!(hover.get());
@ -518,7 +516,7 @@ mod tests {
assert!(world.run_system_cached(update_is_directly_hovered).is_ok());
let hover = world
.entity(hovered_entity)
.get_ref::<IsDirectlyHovered>()
.get_ref::<DirectlyHovered>()
.unwrap();
assert!(!hover.get());
assert!(hover.is_changed());
@ -532,7 +530,7 @@ mod tests {
// Setup entities
let hovered_child = world.spawn_empty().id();
let hovered_entity = world
.spawn(IsDirectlyHovered(false))
.spawn(DirectlyHovered(false))
.add_child(hovered_child)
.id();
@ -554,10 +552,10 @@ mod tests {
// Run the system
assert!(world.run_system_cached(update_is_directly_hovered).is_ok());
// Check to insure that the IsDirectlyHovered component is still false
// Check to insure that the DirectlyHovered component is still false
let hover = world
.entity(hovered_entity)
.get_ref::<IsDirectlyHovered>()
.get_ref::<DirectlyHovered>()
.unwrap();
assert!(!hover.get());
assert!(hover.is_changed());

View File

@ -393,7 +393,7 @@ impl Plugin for PickingPlugin {
.register_type::<Self>()
.register_type::<Pickable>()
.register_type::<hover::PickingInteraction>()
.register_type::<hover::IsHovered>()
.register_type::<hover::Hovered>()
.register_type::<pointer::PointerId>()
.register_type::<pointer::PointerLocation>()
.register_type::<pointer::PointerPress>()
@ -416,7 +416,7 @@ impl Plugin for InteractionPlugin {
.init_resource::<PointerState>()
.add_event::<Pointer<Cancel>>()
.add_event::<Pointer<Click>>()
.add_event::<Pointer<Pressed>>()
.add_event::<Pointer<Press>>()
.add_event::<Pointer<DragDrop>>()
.add_event::<Pointer<DragEnd>>()
.add_event::<Pointer<DragEnter>>()
@ -427,7 +427,7 @@ impl Plugin for InteractionPlugin {
.add_event::<Pointer<Move>>()
.add_event::<Pointer<Out>>()
.add_event::<Pointer<Over>>()
.add_event::<Pointer<Released>>()
.add_event::<Pointer<Release>>()
.add_event::<Pointer<Scroll>>()
.add_systems(
PreUpdate,

View File

@ -41,7 +41,7 @@ pub(crate) fn on_remove_disabled(
/// Component that indicates whether a button or widget is currently in a pressed or "held down"
/// state.
#[derive(Component, Default, Debug)]
pub struct Depressed;
pub struct Pressed;
/// Component that indicates whether a checkbox or radio button is in a checked state.
#[derive(Component, Default, Debug)]
@ -55,7 +55,7 @@ impl Checked {
}
}
pub(crate) fn on_insert_checked(trigger: Trigger<OnInsert, Checked>, mut world: DeferredWorld) {
pub(crate) fn on_insert_is_checked(trigger: Trigger<OnInsert, Checked>, mut world: DeferredWorld) {
let mut entity = world.entity_mut(trigger.target().unwrap());
let checked = entity.get::<Checked>().unwrap().get();
if let Some(mut accessibility) = entity.get_mut::<AccessibilityNode>() {
@ -66,7 +66,7 @@ pub(crate) fn on_insert_checked(trigger: Trigger<OnInsert, Checked>, mut world:
}
}
pub(crate) fn on_remove_checked(trigger: Trigger<OnRemove, Checked>, mut world: DeferredWorld) {
pub(crate) fn on_remove_is_checked(trigger: Trigger<OnRemove, Checked>, mut world: DeferredWorld) {
let mut entity = world.entity_mut(trigger.target().unwrap());
if let Some(mut accessibility) = entity.get_mut::<AccessibilityNode>() {
accessibility.set_toggled(accesskit::Toggled::False);

View File

@ -39,7 +39,7 @@ mod ui_node;
pub use focus::*;
pub use geometry::*;
pub use gradients::*;
pub use interaction_states::{Checked, Depressed, InteractionDisabled};
pub use interaction_states::{Checked, InteractionDisabled, Pressed};
pub use layout::*;
pub use measurement::*;
pub use render::*;
@ -323,8 +323,8 @@ fn build_text_interop(app: &mut App) {
app.add_observer(interaction_states::on_add_disabled)
.add_observer(interaction_states::on_remove_disabled)
.add_observer(interaction_states::on_insert_checked)
.add_observer(interaction_states::on_remove_checked);
.add_observer(interaction_states::on_insert_is_checked)
.add_observer(interaction_states::on_remove_is_checked);
app.configure_sets(
PostUpdate,

View File

@ -91,8 +91,8 @@ fn setup_scene(
))
.observe(update_material_on::<Pointer<Over>>(hover_matl.clone()))
.observe(update_material_on::<Pointer<Out>>(white_matl.clone()))
.observe(update_material_on::<Pointer<Pressed>>(pressed_matl.clone()))
.observe(update_material_on::<Pointer<Released>>(hover_matl.clone()))
.observe(update_material_on::<Pointer<Press>>(pressed_matl.clone()))
.observe(update_material_on::<Pointer<Release>>(hover_matl.clone()))
.observe(rotate_on_drag);
}
@ -114,8 +114,8 @@ fn setup_scene(
))
.observe(update_material_on::<Pointer<Over>>(hover_matl.clone()))
.observe(update_material_on::<Pointer<Out>>(white_matl.clone()))
.observe(update_material_on::<Pointer<Pressed>>(pressed_matl.clone()))
.observe(update_material_on::<Pointer<Released>>(hover_matl.clone()))
.observe(update_material_on::<Pointer<Press>>(pressed_matl.clone()))
.observe(update_material_on::<Pointer<Release>>(hover_matl.clone()))
.observe(rotate_on_drag);
}

View File

@ -63,8 +63,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
))
.observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 1.0)))
.observe(recolor_on::<Pointer<Out>>(Color::BLACK))
.observe(recolor_on::<Pointer<Pressed>>(Color::srgb(1.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Released>>(Color::srgb(0.0, 1.0, 1.0)));
.observe(recolor_on::<Pointer<Press>>(Color::srgb(1.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Release>>(Color::srgb(0.0, 1.0, 1.0)));
commands
.spawn((
@ -83,8 +83,8 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
))
.observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Out>>(Color::srgb(1.0, 0.0, 0.0)))
.observe(recolor_on::<Pointer<Pressed>>(Color::srgb(0.0, 0.0, 1.0)))
.observe(recolor_on::<Pointer<Released>>(Color::srgb(0.0, 1.0, 0.0)));
.observe(recolor_on::<Pointer<Press>>(Color::srgb(0.0, 0.0, 1.0)))
.observe(recolor_on::<Pointer<Release>>(Color::srgb(0.0, 1.0, 0.0)));
}
});
}
@ -145,8 +145,8 @@ fn setup_atlas(
))
.observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 1.0)))
.observe(recolor_on::<Pointer<Out>>(Color::srgb(1.0, 1.0, 1.0)))
.observe(recolor_on::<Pointer<Pressed>>(Color::srgb(1.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Released>>(Color::srgb(0.0, 1.0, 1.0)));
.observe(recolor_on::<Pointer<Press>>(Color::srgb(1.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Release>>(Color::srgb(0.0, 1.0, 1.0)));
}
// An observer listener that changes the target entity's color.

View File

@ -8,9 +8,9 @@ use bevy::{
tab_navigation::{TabGroup, TabIndex},
InputDispatchPlugin,
},
picking::hover::IsHovered,
picking::hover::Hovered,
prelude::*,
ui::{Depressed, InteractionDisabled},
ui::{InteractionDisabled, Pressed},
winit::WinitSettings,
};
@ -38,8 +38,8 @@ struct DemoButton;
fn update_button_style(
mut buttons: Query<
(
Has<Depressed>,
&IsHovered,
Has<Pressed>,
&Hovered,
Has<InteractionDisabled>,
&mut BackgroundColor,
&mut BorderColor,
@ -47,8 +47,8 @@ fn update_button_style(
),
(
Or<(
Changed<Depressed>,
Changed<IsHovered>,
Changed<Pressed>,
Changed<Hovered>,
Added<InteractionDisabled>,
)>,
With<DemoButton>,
@ -56,12 +56,12 @@ fn update_button_style(
>,
mut text_query: Query<&mut Text>,
) {
for (depressed, hovered, disabled, mut color, mut border_color, children) in &mut buttons {
for (pressed, hovered, disabled, mut color, mut border_color, children) in &mut buttons {
let mut text = text_query.get_mut(children[0]).unwrap();
set_button_style(
disabled,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -73,8 +73,8 @@ fn update_button_style(
fn update_button_style2(
mut buttons: Query<
(
Has<Depressed>,
&IsHovered,
Has<Pressed>,
&Hovered,
Has<InteractionDisabled>,
&mut BackgroundColor,
&mut BorderColor,
@ -82,19 +82,19 @@ fn update_button_style2(
),
With<DemoButton>,
>,
mut removed_depressed: RemovedComponents<Depressed>,
mut removed_depressed: RemovedComponents<Pressed>,
mut removed_disabled: RemovedComponents<InteractionDisabled>,
mut text_query: Query<&mut Text>,
) {
removed_depressed.read().for_each(|entity| {
if let Ok((depressed, hovered, disabled, mut color, mut border_color, children)) =
if let Ok((pressed, hovered, disabled, mut color, mut border_color, children)) =
buttons.get_mut(entity)
{
let mut text = text_query.get_mut(children[0]).unwrap();
set_button_style(
disabled,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -102,14 +102,14 @@ fn update_button_style2(
}
});
removed_disabled.read().for_each(|entity| {
if let Ok((depressed, hovered, disabled, mut color, mut border_color, children)) =
if let Ok((pressed, hovered, disabled, mut color, mut border_color, children)) =
buttons.get_mut(entity)
{
let mut text = text_query.get_mut(children[0]).unwrap();
set_button_style(
disabled,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -121,12 +121,12 @@ fn update_button_style2(
fn set_button_style(
disabled: bool,
hovered: bool,
depressed: bool,
pressed: bool,
color: &mut BackgroundColor,
border_color: &mut BorderColor,
text: &mut Text,
) {
match (disabled, hovered, depressed) {
match (disabled, hovered, pressed) {
// Disabled button
(true, _, _) => {
**text = "Disabled".to_string();
@ -192,7 +192,7 @@ fn button(asset_server: &AssetServer, on_click: SystemId) -> impl Bundle {
CoreButton {
on_click: Some(on_click),
},
IsHovered::default(),
Hovered::default(),
TabIndex(0),
BorderColor::all(Color::BLACK),
BorderRadius::MAX,

View File

@ -8,9 +8,9 @@ use bevy::{
tab_navigation::{TabGroup, TabIndex},
InputDispatchPlugin,
},
picking::hover::IsHovered,
picking::hover::Hovered,
prelude::*,
ui::{Depressed, InteractionDisabled},
ui::{InteractionDisabled, Pressed},
winit::WinitSettings,
};
@ -38,10 +38,10 @@ const PRESSED_BUTTON: Color = Color::srgb(0.35, 0.75, 0.35);
struct DemoButton;
fn on_add_pressed(
trigger: Trigger<OnAdd, Depressed>,
trigger: Trigger<OnAdd, Pressed>,
mut buttons: Query<
(
&IsHovered,
&Hovered,
Has<InteractionDisabled>,
&mut BackgroundColor,
&mut BorderColor,
@ -67,10 +67,10 @@ fn on_add_pressed(
}
fn on_remove_pressed(
trigger: Trigger<OnRemove, Depressed>,
trigger: Trigger<OnRemove, Pressed>,
mut buttons: Query<
(
&IsHovered,
&Hovered,
Has<InteractionDisabled>,
&mut BackgroundColor,
&mut BorderColor,
@ -99,8 +99,8 @@ fn on_add_disabled(
trigger: Trigger<OnAdd, InteractionDisabled>,
mut buttons: Query<
(
Has<Depressed>,
&IsHovered,
Has<Pressed>,
&Hovered,
&mut BackgroundColor,
&mut BorderColor,
&Children,
@ -109,14 +109,14 @@ fn on_add_disabled(
>,
mut text_query: Query<&mut Text>,
) {
if let Ok((depressed, hovered, mut color, mut border_color, children)) =
if let Ok((pressed, hovered, mut color, mut border_color, children)) =
buttons.get_mut(trigger.target().unwrap())
{
let mut text = text_query.get_mut(children[0]).unwrap();
set_button_style(
true,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -128,8 +128,8 @@ fn on_remove_disabled(
trigger: Trigger<OnRemove, InteractionDisabled>,
mut buttons: Query<
(
Has<Depressed>,
&IsHovered,
Has<Pressed>,
&Hovered,
&mut BackgroundColor,
&mut BorderColor,
&Children,
@ -138,14 +138,14 @@ fn on_remove_disabled(
>,
mut text_query: Query<&mut Text>,
) {
if let Ok((depressed, hovered, mut color, mut border_color, children)) =
if let Ok((pressed, hovered, mut color, mut border_color, children)) =
buttons.get_mut(trigger.target().unwrap())
{
let mut text = text_query.get_mut(children[0]).unwrap();
set_button_style(
false,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -154,11 +154,11 @@ fn on_remove_disabled(
}
fn on_change_hover(
trigger: Trigger<OnInsert, IsHovered>,
trigger: Trigger<OnInsert, Hovered>,
mut buttons: Query<
(
Has<Depressed>,
&IsHovered,
Has<Pressed>,
&Hovered,
Has<InteractionDisabled>,
&mut BackgroundColor,
&mut BorderColor,
@ -168,7 +168,7 @@ fn on_change_hover(
>,
mut text_query: Query<&mut Text>,
) {
if let Ok((depressed, hovered, disabled, mut color, mut border_color, children)) =
if let Ok((pressed, hovered, disabled, mut color, mut border_color, children)) =
buttons.get_mut(trigger.target().unwrap())
{
if children.is_empty() {
@ -180,7 +180,7 @@ fn on_change_hover(
set_button_style(
disabled,
hovered.get(),
depressed,
pressed,
&mut color,
&mut border_color,
&mut text,
@ -191,12 +191,12 @@ fn on_change_hover(
fn set_button_style(
disabled: bool,
hovered: bool,
depressed: bool,
pressed: bool,
color: &mut BackgroundColor,
border_color: &mut BorderColor,
text: &mut Text,
) {
match (disabled, hovered, depressed) {
match (disabled, hovered, pressed) {
// Disabled button
(true, _, _) => {
**text = "Disabled".to_string();
@ -262,7 +262,7 @@ fn button(asset_server: &AssetServer, on_click: SystemId) -> impl Bundle {
CoreButton {
on_click: Some(on_click),
},
IsHovered::default(),
Hovered::default(),
TabIndex(0),
BorderColor::all(Color::BLACK),
BorderRadius::MAX,

View File

@ -89,7 +89,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..default()
})
.observe(|
trigger: Trigger<Pointer<Pressed>>,
trigger: Trigger<Pointer<Press>>,
mut commands: Commands
| {
if trigger.event().button == PointerButton::Primary {

View File

@ -62,7 +62,7 @@ fn setup(mut commands: Commands) {
commands.spawn(background_and_button()).observe(
// any click bubbling up here should lead to closing any open menu
|_: Trigger<Pointer<Pressed>>, mut commands: Commands| {
|_: Trigger<Pointer<Press>>, mut commands: Commands| {
commands.trigger(CloseContextMenus);
},
);
@ -108,11 +108,11 @@ fn on_trigger_menu(trigger: Trigger<OpenContextMenu>, mut commands: Commands) {
],
))
.observe(
|trigger: Trigger<Pointer<Pressed>>,
|trigger: Trigger<Pointer<Press>>,
menu_items: Query<&ContextMenuItem>,
mut clear_col: ResMut<ClearColor>,
mut commands: Commands| {
// Note that we want to know the target of the `Pointer<Pressed>` event (Button) here.
// Note that we want to know the target of the `Pointer<Press>` event (Button) here.
// Not to be confused with the trigger `target`
let target = trigger.event().target;
@ -184,7 +184,7 @@ fn background_and_button() -> impl Bundle + use<> {
)],
))
.observe(
|mut trigger: Trigger<Pointer<Pressed>>, mut commands: Commands| {
|mut trigger: Trigger<Pointer<Press>>, mut commands: Commands| {
// by default this event would bubble up further leading to the `CloseContextMenus`
// event being triggered and undoing the opening of one here right away.
trigger.propagate(false);

View File

@ -0,0 +1,6 @@
---
title: Rename `Pointer<Pressed>` and `Pointer<Released>` to `Pointer<Press>` and `Pointer<Release>`
pull_requests: [19179]
---
The `Pointer<Pressed>` and `Pointer<Released>` events have been renamed to `Pointer<Press>` and `Pointer<Release>` for improved consistency. `Pressed` is now a marker component indicating that a button or other UI node is in a pressed or "held down" state.

View File

@ -44,12 +44,12 @@ These components include:
- `InteractionDisabled` - a boolean component used to indicate that a component should be
"grayed out" and non-interactive. Note that these disabled widgets are still visible and can
have keyboard focus (otherwise the user would have no way to discover them).
- `IsHovered` is a simple boolean component that allows detection of whether the widget is being
- `Hovered` is a simple boolean component that allows detection of whether the widget is being
hovered using regular Bevy change detection.
- `Checked` is a boolean component that stores the checked state of a checkbox or radio button.
- `Depressed` is used for a button-like widget, and will be true while the button is held down.
- `Pressed` is used for a button-like widget, and will be true while the button is held down.
The combination of `IsHovered` and `ButtonPressed` fulfills the same purpose as the old
The combination of `Hovered` and `Pressed` fulfills the same purpose as the old
`Interaction` component, except that now we can also represent "roll-off" behavior (the state where
you click on a button and then, while holding the mouse down, move the pointer out of the button's
bounds). It also provides additional flexibility in cases where a widget has multiple hoverable