Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_ui_widgets/src/button.rs
6849 views
1
use accesskit::Role;
2
use bevy_a11y::AccessibilityNode;
3
use bevy_app::{App, Plugin};
4
use bevy_ecs::query::Has;
5
use bevy_ecs::system::In;
6
use bevy_ecs::{
7
component::Component,
8
entity::Entity,
9
observer::On,
10
query::With,
11
system::{Commands, Query},
12
};
13
use bevy_input::keyboard::{KeyCode, KeyboardInput};
14
use bevy_input::ButtonState;
15
use bevy_input_focus::FocusedInput;
16
use bevy_picking::events::{Cancel, Click, DragEnd, Pointer, Press, Release};
17
use bevy_ui::{InteractionDisabled, Pressed};
18
19
use crate::{Activate, Callback, Notify};
20
21
/// Headless button widget. This widget maintains a "pressed" state, which is used to
22
/// indicate whether the button is currently being pressed by the user. It emits a `ButtonClicked`
23
/// event when the button is un-pressed.
24
#[derive(Component, Default, Debug)]
25
#[require(AccessibilityNode(accesskit::Node::new(Role::Button)))]
26
pub struct Button {
27
/// Callback to invoke when the button is clicked, or when the `Enter` or `Space` key
28
/// is pressed while the button is focused.
29
pub on_activate: Callback<In<Activate>>,
30
}
31
32
fn button_on_key_event(
33
mut event: On<FocusedInput<KeyboardInput>>,
34
q_state: Query<(&Button, Has<InteractionDisabled>)>,
35
mut commands: Commands,
36
) {
37
if let Ok((bstate, disabled)) = q_state.get(event.focused_entity)
38
&& !disabled
39
{
40
let input_event = &event.input;
41
if !input_event.repeat
42
&& input_event.state == ButtonState::Pressed
43
&& (input_event.key_code == KeyCode::Enter || input_event.key_code == KeyCode::Space)
44
{
45
event.propagate(false);
46
commands.notify_with(&bstate.on_activate, Activate(event.focused_entity));
47
}
48
}
49
}
50
51
fn button_on_pointer_click(
52
mut click: On<Pointer<Click>>,
53
mut q_state: Query<(&Button, Has<Pressed>, Has<InteractionDisabled>)>,
54
mut commands: Commands,
55
) {
56
if let Ok((bstate, pressed, disabled)) = q_state.get_mut(click.entity) {
57
click.propagate(false);
58
if pressed && !disabled {
59
commands.notify_with(&bstate.on_activate, Activate(click.entity));
60
}
61
}
62
}
63
64
fn button_on_pointer_down(
65
mut press: On<Pointer<Press>>,
66
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Button>>,
67
mut commands: Commands,
68
) {
69
if let Ok((button, disabled, pressed)) = q_state.get_mut(press.entity) {
70
press.propagate(false);
71
if !disabled && !pressed {
72
commands.entity(button).insert(Pressed);
73
}
74
}
75
}
76
77
fn button_on_pointer_up(
78
mut release: On<Pointer<Release>>,
79
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Button>>,
80
mut commands: Commands,
81
) {
82
if let Ok((button, disabled, pressed)) = q_state.get_mut(release.entity) {
83
release.propagate(false);
84
if !disabled && pressed {
85
commands.entity(button).remove::<Pressed>();
86
}
87
}
88
}
89
90
fn button_on_pointer_drag_end(
91
mut drag_end: On<Pointer<DragEnd>>,
92
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Button>>,
93
mut commands: Commands,
94
) {
95
if let Ok((button, disabled, pressed)) = q_state.get_mut(drag_end.entity) {
96
drag_end.propagate(false);
97
if !disabled && pressed {
98
commands.entity(button).remove::<Pressed>();
99
}
100
}
101
}
102
103
fn button_on_pointer_cancel(
104
mut cancel: On<Pointer<Cancel>>,
105
mut q_state: Query<(Entity, Has<InteractionDisabled>, Has<Pressed>), With<Button>>,
106
mut commands: Commands,
107
) {
108
if let Ok((button, disabled, pressed)) = q_state.get_mut(cancel.entity) {
109
cancel.propagate(false);
110
if !disabled && pressed {
111
commands.entity(button).remove::<Pressed>();
112
}
113
}
114
}
115
116
/// Plugin that adds the observers for the [`Button`] widget.
117
pub struct ButtonPlugin;
118
119
impl Plugin for ButtonPlugin {
120
fn build(&self, app: &mut App) {
121
app.add_observer(button_on_key_event)
122
.add_observer(button_on_pointer_down)
123
.add_observer(button_on_pointer_up)
124
.add_observer(button_on_pointer_click)
125
.add_observer(button_on_pointer_drag_end)
126
.add_observer(button_on_pointer_cancel);
127
}
128
}
129
130