@@ -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) ]
6170pub 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
210212trait CursorResource : Resource {
0 commit comments