1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use bevy::{
picking::{hover::PickingInteraction, pointer::PointerPress},
prelude::*,
};
/// Marks an entity as focusable
#[derive(Component, Default, Debug, Clone, Copy)]
pub struct Focusable;
/// A resource used to keep track of the currently focused entity.
#[derive(Resource, Debug, Clone, Copy)]
pub struct CurrentFocus(Entity);
impl CurrentFocus {
/// Create a new CurrentFocus.
pub fn new(entity: Entity) -> Self {
Self(entity)
}
/// Gets the entity that has focus.
pub fn get(&self) -> Entity {
self.0
}
/// Sets the entity that has focus.
pub fn set(&mut self, entity: Entity) {
self.0 = entity;
}
#[allow(dead_code)]
pub(crate) fn find_next_focus() {
// TODO: Write system to find next focused object
todo!();
}
#[allow(dead_code)]
pub(crate) fn find_prev_focus() {
// TODO: Write system to find prev focused object
todo!();
}
pub(crate) fn click_focus(
mut commands: Commands,
mut current_focus: ResMut<CurrentFocus>,
mouse_input: Res<ButtonInput<MouseButton>>,
query: Query<
(Entity, Option<&PickingInteraction>),
(With<Focusable>, Changed<PickingInteraction>),
>,
pointer_query: Query<&PointerPress>,
) {
let mut none_selected = true;
for (entity, picking_interaction) in query.iter() {
if let Some(picking_interaction) = picking_interaction {
// Check if pressed
if mouse_input.just_pressed(MouseButton::Left) {
if matches!(picking_interaction, PickingInteraction::Pressed) {
// Blur previously focused entity.
if current_focus.get() != entity {
commands.trigger_targets(
WidgetBlur {
target: current_focus.get(),
},
current_focus.get(),
);
}
// Focus new entity
*current_focus = CurrentFocus::new(entity);
commands
.trigger_targets(WidgetFocus { target: entity }, current_focus.get());
none_selected = false;
}
}
}
}
if mouse_input.just_pressed(MouseButton::Left) {
if none_selected && pointer_query.iter().any(|press| press.is_primary_pressed()) {
// Blur if we have a focused entity because we had no "hits" this frame.
if current_focus.get() != Entity::PLACEHOLDER {
commands.trigger_targets(
WidgetBlur {
target: current_focus.get(),
},
current_focus.get(),
);
}
// Remove current focus.
*current_focus = CurrentFocus::new(Entity::PLACEHOLDER);
}
}
}
}
/// A bevy_eventlistener Event that triggers when a widget has focus.
/// Note: The widget must have the Focusable component tag.
#[derive(Clone, PartialEq, Debug, Reflect, Event)]
pub struct WidgetFocus {
/// The target of this event
pub target: Entity,
}
/// A bevy_eventlistener Event that triggers when a widget has lost focus.
/// Note: The widget must have the Focusable component tag.
#[derive(Clone, PartialEq, Debug, Reflect, Event)]
pub struct WidgetBlur {
/// The target of this event
pub target: Entity,
}