Skip to content

Commit 266af8f

Browse files
committed
refactor - remove now unnecessary logic, write interaction state in fewer spots:
- reset everything that should be reset - find hovered nodes - write Hovered/Clicked states
1 parent 0c7e305 commit 266af8f

File tree

1 file changed

+46
-44
lines changed

1 file changed

+46
-44
lines changed

crates/bevy_ui/src/focus.rs

+46-44
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,17 @@ pub struct State {
5656
entities_to_reset: SmallVec<[Entity; 1]>,
5757
}
5858

59-
/// The system that sets Interaction for all UI elements based on the mouse and touch cursor
60-
/// activity
59+
pub type NodeQuery<'a> = (
60+
Entity,
61+
&'a Node,
62+
&'a GlobalTransform,
63+
&'a mut Interaction,
64+
Option<&'a FocusPolicy>,
65+
Option<&'a CalculatedClip>,
66+
);
67+
68+
/// The system that sets Interaction for all UI elements based on the mouse cursor activity
69+
#[allow(clippy::type_complexity)]
6170
pub fn ui_focus_system(
6271
state: Local<State>,
6372
windows: Res<Windows>,
@@ -96,40 +105,29 @@ fn focus_ui<Cursor: CursorResource>(
96105
Option<&CalculatedClip>,
97106
)>,
98107
) {
108+
reset_interactions(
109+
&mut node_query,
110+
&mouse_button_input,
111+
&touches_input,
112+
&windows.get_cursor_position(),
113+
&mut state,
114+
);
115+
99116
let cursor_position = match windows.get_cursor_position() {
100-
None => {
101-
set_all_interactions_to_none(node_query);
102-
return;
103-
}
117+
None => return,
104118
Some(cursor_position) => cursor_position,
105119
};
106120

107-
// reset entities that were both clicked and released in the last frame
108-
for entity in state.entities_to_reset.drain(..) {
109-
if let Ok(mut interaction) = node_query.get_component_mut::<Interaction>(entity) {
110-
*interaction = Interaction::None;
111-
}
112-
}
113-
114121
let mouse_released =
115122
mouse_button_input.just_released(MouseButton::Left) || touches_input.just_released(0);
116-
if mouse_released {
117-
for (_entity, _node, _global_transform, mut interaction, _focus_policy, _clip) in
118-
node_query.iter_mut()
119-
{
120-
if *interaction == Interaction::Clicked {
121-
*interaction = Interaction::None;
122-
}
123-
}
124-
}
125123

126124
let mouse_clicked =
127125
mouse_button_input.just_pressed(MouseButton::Left) || touches_input.just_released(0);
128126

129127
let mut moused_over_z_sorted_nodes = node_query
130128
.iter_mut()
131129
.filter_map(
132-
|(entity, node, global_transform, mut interaction, focus_policy, clip)| {
130+
|(entity, node, global_transform, interaction, focus_policy, clip)| {
133131
let position = global_transform.translation;
134132
let ui_position = position.truncate();
135133
let extents = node.size / 2.0;
@@ -147,9 +145,6 @@ fn focus_ui<Cursor: CursorResource>(
147145
if contains_cursor {
148146
Some((entity, focus_policy, interaction, FloatOrd(position.z)))
149147
} else {
150-
if *interaction == Interaction::Hovered {
151-
*interaction = Interaction::None;
152-
}
153148
None
154149
}
155150
},
@@ -158,19 +153,14 @@ fn focus_ui<Cursor: CursorResource>(
158153

159154
moused_over_z_sorted_nodes.sort_by_key(|(_, _, _, z)| -*z);
160155

161-
let mut moused_over_z_sorted_nodes = moused_over_z_sorted_nodes.into_iter();
162156
// set Clicked or Hovered on top nodes
163-
for (entity, focus_policy, mut interaction, _) in moused_over_z_sorted_nodes.by_ref() {
157+
for (entity, focus_policy, mut interaction, _) in moused_over_z_sorted_nodes {
164158
if mouse_clicked {
165-
// only consider nodes with Interaction "clickable"
166-
if *interaction != Interaction::Clicked {
167-
*interaction = Interaction::Clicked;
168-
// if the mouse was simultaneously released, reset this Interaction in the next
169-
// frame
170-
if mouse_released {
171-
state.entities_to_reset.push(entity);
172-
}
159+
// if the mouse was simultaneously released, reset this Interaction in the next frame
160+
if *interaction != Interaction::Clicked && mouse_released {
161+
state.entities_to_reset.push(entity);
173162
}
163+
*interaction = Interaction::Clicked;
174164
} else if *interaction == Interaction::None {
175165
*interaction = Interaction::Hovered;
176166
}
@@ -182,29 +172,41 @@ fn focus_ui<Cursor: CursorResource>(
182172
FocusPolicy::Pass => { /* allow the next node to be hovered/clicked */ }
183173
}
184174
}
185-
// reset lower nodes to None
186-
for (_entity, _focus_policy, mut interaction, _) in moused_over_z_sorted_nodes {
187-
if *interaction != Interaction::None {
188-
*interaction = Interaction::None;
189-
}
190-
}
191175
}
192176

193-
fn set_all_interactions_to_none(
194-
mut node_query: Query<(
177+
fn reset_interactions(
178+
node_query: &mut Query<(
195179
Entity,
196180
&Node,
197181
&GlobalTransform,
198182
&mut Interaction,
199183
Option<&FocusPolicy>,
200184
Option<&CalculatedClip>,
201185
)>,
186+
mouse_button_input: &Input<MouseButton>,
187+
touches_input: &Touches,
188+
cursor_position: &Option<Vec2>,
189+
state: &mut State,
202190
) {
191+
let mouse_release =
192+
mouse_button_input.just_released(MouseButton::Left) || touches_input.just_released(0);
193+
let input_should_leave_button_clicked = cursor_position.is_some() && !mouse_release;
194+
203195
for (_entity, _node, _global_transform, mut interaction, _focus_policy, _clip) in
204196
node_query.iter_mut()
205197
{
198+
if input_should_leave_button_clicked && *interaction == Interaction::Clicked {
199+
continue;
200+
}
206201
*interaction = Interaction::None;
207202
}
203+
204+
// reset entities that were both clicked and released in the last frame
205+
for entity in state.entities_to_reset.drain(..) {
206+
if let Ok(mut interaction) = node_query.get_component_mut::<Interaction>(entity) {
207+
*interaction = Interaction::None;
208+
}
209+
}
208210
}
209211

210212
trait CursorResource: Resource {

0 commit comments

Comments
 (0)