66//! Event handling: mouse events
77
88use super :: { GrabMode , Press , PressSource } ;
9- use crate :: event:: { Event , EventCx , FocusSource , ScrollDelta } ;
9+ use crate :: event:: { Event , EventCx , EventState , FocusSource , ScrollDelta } ;
1010use crate :: geom:: { Coord , DVec2 } ;
1111use crate :: { Action , Id , NavAdvance , Node , Widget , Window } ;
1212use cast:: { Cast , Conv , ConvApprox } ;
@@ -19,10 +19,20 @@ const DOUBLE_CLICK_TIMEOUT: Duration = Duration::from_secs(1);
1919
2020const FAKE_MOUSE_BUTTON : MouseButton = MouseButton :: Other ( 0 ) ;
2121
22+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
23+ enum PanMode {
24+ Pan ,
25+ Rotate ,
26+ Scale ,
27+ Full ,
28+ }
29+
2230#[ derive( Clone , Debug ) ]
2331struct PanDetails {
2432 c0 : Coord ,
2533 c1 : Coord ,
34+ moved : bool ,
35+ mode : PanMode ,
2636}
2737
2838#[ derive( Clone , Debug ) ]
@@ -36,6 +46,15 @@ impl GrabDetails {
3646 fn is_pan ( & self ) -> bool {
3747 matches ! ( self , GrabDetails :: Pan ( _) )
3848 }
49+
50+ fn pan ( coord : Coord , mode : PanMode ) -> Self {
51+ GrabDetails :: Pan ( PanDetails {
52+ c0 : coord,
53+ c1 : coord,
54+ moved : false ,
55+ mode,
56+ } )
57+ }
3958}
4059
4160#[ derive( Clone , Debug ) ]
@@ -56,7 +75,8 @@ pub(in crate::event::cx) struct Mouse {
5675 last_click_button : MouseButton ,
5776 last_click_repetitions : u32 ,
5877 last_click_timeout : Instant ,
59- pub ( super ) mouse_grab : Option < MouseGrab > ,
78+ last_pin : Option < ( Id , Coord ) > ,
79+ pub ( super ) grab : Option < MouseGrab > ,
6080}
6181
6282impl Default for Mouse {
@@ -69,15 +89,16 @@ impl Default for Mouse {
6989 last_click_button : FAKE_MOUSE_BUTTON ,
7090 last_click_repetitions : 0 ,
7191 last_click_timeout : Instant :: now ( ) ,
72- mouse_grab : None ,
92+ last_pin : None ,
93+ grab : None ,
7394 }
7495 }
7596}
7697
7798impl Mouse {
7899 /// Clear all focus and grabs on `target`
79100 pub ( in crate :: event:: cx) fn cancel_event_focus ( & mut self , target : & Id ) {
80- if let Some ( grab) = self . mouse_grab . as_mut ( ) {
101+ if let Some ( grab) = self . grab . as_mut ( ) {
81102 if grab. start_id == target {
82103 grab. cancel = true ;
83104 }
@@ -86,24 +107,51 @@ impl Mouse {
86107
87108 pub ( in crate :: event:: cx) fn update_hover_icon ( & mut self ) -> Option < CursorIcon > {
88109 let mut icon = None ;
89- if self . hover_icon != self . old_hover_icon && self . mouse_grab . is_none ( ) {
110+ if self . hover_icon != self . old_hover_icon && self . grab . is_none ( ) {
90111 icon = Some ( self . hover_icon ) ;
91112 }
92113 self . old_hover_icon = self . hover_icon ;
93114 icon
94115 }
95116
96117 pub fn frame_update ( & mut self ) -> Option < ( Id , Event ) > {
97- if let Some ( grab) = self . mouse_grab . as_mut ( ) {
118+ if let Some ( grab) = self . grab . as_mut ( ) {
98119 if let GrabDetails :: Pan ( details) = & mut grab. details {
99120 // Terminology: pi are old coordinates, qi are new coords
100121 let ( p1, q1) = ( DVec2 :: conv ( details. c0 ) , DVec2 :: conv ( details. c1 ) ) ;
101122 details. c0 = details. c1 ;
102123
103- let delta = q1 - p1;
104- if delta != DVec2 :: ZERO {
124+ let alpha;
125+ let delta;
126+
127+ if details. mode == PanMode :: Pan {
128+ alpha = DVec2 ( 1.0 , 0.0 ) ;
129+ delta = q1 - p1;
130+ } else if let Some ( ( _, coord) ) = self . last_pin . as_ref ( ) {
131+ let p2 = DVec2 :: conv ( * coord) ;
132+ let ( pd, qd) = ( p2 - p1, p2 - q1) ;
133+
134+ alpha = match details. mode {
135+ PanMode :: Full => qd. complex_div ( pd) ,
136+ PanMode :: Scale => DVec2 ( ( qd. sum_square ( ) / pd. sum_square ( ) ) . sqrt ( ) , 0.0 ) ,
137+ PanMode :: Rotate => {
138+ let a = qd. complex_div ( pd) ;
139+ a / a. sum_square ( ) . sqrt ( )
140+ }
141+ _ => unreachable ! ( ) ,
142+ } ;
143+
144+ // Average delta from both movements:
145+ delta = ( q1 - alpha. complex_mul ( p1) + p2 - alpha. complex_mul ( p2) ) * 0.5 ;
146+ } else {
147+ unreachable ! ( )
148+ }
149+
150+ if alpha. is_finite ( )
151+ && delta. is_finite ( )
152+ && ( alpha != DVec2 ( 1.0 , 0.0 ) || delta != DVec2 :: ZERO )
153+ {
105154 let id = grab. start_id . clone ( ) ;
106- let alpha = DVec2 ( 1.0 , 0.0 ) ;
107155 let event = Event :: Pan { alpha, delta } ;
108156 return Some ( ( id, event) ) ;
109157 }
@@ -119,7 +167,7 @@ impl Mouse {
119167
120168 fn update_hover ( & mut self ) -> ( bool , bool ) {
121169 let ( mut cancel, mut redraw) = ( false , false ) ;
122- if let Some ( grab) = self . mouse_grab . as_mut ( ) {
170+ if let Some ( grab) = self . grab . as_mut ( ) {
123171 cancel = grab. cancel ;
124172 if let GrabDetails :: Click = grab. details {
125173 let hover = self . hover . as_ref ( ) ;
@@ -146,18 +194,19 @@ impl Mouse {
146194 coord : Coord ,
147195 mode : GrabMode ,
148196 ) -> bool {
197+ let have_pin = matches ! ( & self . last_pin, Some ( ( id2, _) ) if id == * id2) ;
149198 let details = match mode {
150199 GrabMode :: Click => GrabDetails :: Click ,
151200 GrabMode :: Grab => GrabDetails :: Grab ,
201+ GrabMode :: PanRotate if have_pin => GrabDetails :: pan ( coord, PanMode :: Rotate ) ,
202+ GrabMode :: PanScale if have_pin => GrabDetails :: pan ( coord, PanMode :: Scale ) ,
203+ GrabMode :: PanFull if have_pin => GrabDetails :: pan ( coord, PanMode :: Full ) ,
152204 mode => {
153205 assert ! ( mode. is_pan( ) ) ;
154- GrabDetails :: Pan ( PanDetails {
155- c0 : coord,
156- c1 : coord,
157- } )
206+ GrabDetails :: pan ( coord, PanMode :: Pan )
158207 }
159208 } ;
160- if let Some ( ref mut grab) = self . mouse_grab {
209+ if let Some ( ref mut grab) = self . grab {
161210 if grab. start_id != id
162211 || grab. button != button
163212 || grab. details . is_pan ( ) != mode. is_pan ( )
@@ -171,7 +220,7 @@ impl Mouse {
171220 grab. depress = Some ( id. clone ( ) ) ;
172221 grab. details = details;
173222 } else {
174- self . mouse_grab = Some ( MouseGrab {
223+ self . grab = Some ( MouseGrab {
175224 button,
176225 repetitions,
177226 start_id : id. clone ( ) ,
@@ -184,6 +233,22 @@ impl Mouse {
184233 }
185234}
186235
236+ impl EventState {
237+ pub ( crate ) fn mouse_pin ( & self ) -> Option < ( Coord , bool ) > {
238+ if let Some ( ( _, coord) ) = self . mouse . last_pin . as_ref ( ) {
239+ let used = self
240+ . mouse
241+ . grab
242+ . as_ref ( )
243+ . map ( |grab| grab. details . is_pan ( ) )
244+ . unwrap_or ( false ) ;
245+ Some ( ( * coord, used) )
246+ } else {
247+ None
248+ }
249+ }
250+ }
251+
187252impl < ' a > EventCx < ' a > {
188253 // Clear old hover, set new hover, send events.
189254 // If there is a popup, only permit descendands of that.
@@ -212,17 +277,23 @@ impl<'a> EventCx<'a> {
212277
213278 // Clears mouse grab and pan grab, resets cursor and redraws
214279 fn remove_mouse_grab ( & mut self , success : bool ) -> Option < ( Id , Event ) > {
215- if let Some ( grab) = self . mouse . mouse_grab . take ( ) {
280+ if let Some ( grab) = self . mouse . grab . take ( ) {
216281 log:: trace!(
217282 "remove_mouse_grab: start_id={}, success={success}" ,
218283 grab. start_id
219284 ) ;
220285 self . window . set_cursor_icon ( self . mouse . hover_icon ) ;
221286 self . opt_action ( grab. depress . clone ( ) , Action :: REDRAW ) ;
222- if grab. details . is_pan ( ) {
287+ if let GrabDetails :: Pan ( details) = & grab. details {
288+ if !details. moved {
289+ self . mouse . last_pin = Some ( ( grab. start_id . clone ( ) , self . mouse . last_coord ) ) ;
290+ } else {
291+ self . mouse . last_pin = None ;
292+ }
223293 // Pan grabs do not receive Event::PressEnd
224294 None
225295 } else {
296+ self . mouse . last_pin = None ;
226297 let press = Press {
227298 source : PressSource :: Mouse ( grab. button , grab. repetitions ) ,
228299 id : self . mouse . hover . clone ( ) ,
@@ -268,7 +339,7 @@ impl<'a> EventCx<'a> {
268339 let id = win. try_probe ( coord) ;
269340 self . set_hover ( win. as_node ( data) , id. clone ( ) ) ;
270341
271- if let Some ( grab) = self . mouse . mouse_grab . as_mut ( ) {
342+ if let Some ( grab) = self . mouse . grab . as_mut ( ) {
272343 match & mut grab. details {
273344 GrabDetails :: Click => ( ) ,
274345 GrabDetails :: Grab => {
@@ -284,6 +355,8 @@ impl<'a> EventCx<'a> {
284355 }
285356 GrabDetails :: Pan ( details) => {
286357 details. c1 = coord;
358+ details. moved = true ;
359+ self . need_frame_update = true ;
287360 }
288361 }
289362 } else if let Some ( popup_id) = self . popups . last ( ) . map ( |( _, p, _) | p. id . clone ( ) ) {
@@ -309,7 +382,7 @@ impl<'a> EventCx<'a> {
309382 pub ( in crate :: event:: cx) fn handle_cursor_left ( & mut self , node : Node < ' _ > ) {
310383 self . mouse . last_click_button = FAKE_MOUSE_BUTTON ;
311384
312- if self . mouse . mouse_grab . is_none ( ) {
385+ if self . mouse . grab . is_none ( ) {
313386 // If there's a mouse grab, we will continue to receive
314387 // coordinates; if not, set a fake coordinate off the window
315388 self . mouse . last_coord = Coord ( -1 , -1 ) ;
@@ -360,7 +433,7 @@ impl<'a> EventCx<'a> {
360433
361434 if self
362435 . mouse
363- . mouse_grab
436+ . grab
364437 . as_ref ( )
365438 . map ( |g| g. button == button)
366439 . unwrap_or ( false )
@@ -373,6 +446,9 @@ impl<'a> EventCx<'a> {
373446 if state == ElementState :: Pressed {
374447 if let Some ( start_id) = self . mouse . hover . clone ( ) {
375448 // No mouse grab but have a hover target
449+ if matches ! ( self . mouse. last_pin. as_ref( ) , Some ( ( id, _) ) if * id != start_id) {
450+ self . mouse . last_pin = None ;
451+ }
376452 if self . config . event ( ) . mouse_nav_focus ( ) {
377453 if let Some ( id) = self . nav_next ( node. re ( ) , Some ( & start_id) , NavAdvance :: None ) {
378454 self . set_nav_focus ( id, FocusSource :: Pointer ) ;
0 commit comments