@@ -569,6 +569,7 @@ impl Tui {
569
569
&& next_state != InputMouseState :: None ;
570
570
let mouse_up = self . mouse_state != InputMouseState :: None
571
571
&& next_state == InputMouseState :: None ;
572
+ let is_scroll = next_scroll != Point :: default ( ) ;
572
573
let is_drag = self . mouse_state == InputMouseState :: Left
573
574
&& next_state == InputMouseState :: Left
574
575
&& next_position != self . mouse_position ;
@@ -607,7 +608,11 @@ impl Tui {
607
608
}
608
609
}
609
610
610
- if mouse_down {
611
+ if is_scroll {
612
+ next_state = self . mouse_state ;
613
+ } else if is_drag {
614
+ self . mouse_is_drag = true ;
615
+ } else if mouse_down {
611
616
// Transition from no mouse input to some mouse input --> Record the mouse down position.
612
617
Self :: build_node_path ( hovered_node, & mut self . mouse_down_node_path ) ;
613
618
@@ -662,8 +667,6 @@ impl Tui {
662
667
}
663
668
664
669
self . mouse_up_timestamp = now;
665
- } else if is_drag {
666
- self . mouse_is_drag = true ;
667
670
}
668
671
669
672
input_mouse_modifiers = mouse. modifiers ;
@@ -2186,120 +2189,120 @@ impl<'a> Context<'a, '_> {
2186
2189
let mut make_cursor_visible = false ;
2187
2190
let mut change_preferred_column = false ;
2188
2191
2189
- if self . tui . mouse_state != InputMouseState :: None
2190
- && self . tui . was_mouse_down_on_node ( node_prev. id )
2192
+ // Scrolling works even if the node isn't focused.
2193
+ if self . input_scroll_delta != Point :: default ( )
2194
+ && node_prev. inner_clipped . contains ( self . tui . mouse_position )
2191
2195
{
2192
- // Scrolling works even if the node isn't focused.
2193
- if self . tui . mouse_state == InputMouseState :: Scroll {
2194
- tc. scroll_offset . x += self . input_scroll_delta . x ;
2195
- tc. scroll_offset . y += self . input_scroll_delta . y ;
2196
- self . set_input_consumed ( ) ;
2197
- } else if self . tui . is_node_focused ( node_prev. id ) {
2198
- let mouse = self . tui . mouse_position ;
2199
- let inner = node_prev. inner ;
2200
- let text_rect = Rect {
2201
- left : inner. left + tb. margin_width ( ) ,
2202
- top : inner. top ,
2203
- right : inner. right - !single_line as CoordType ,
2204
- bottom : inner. bottom ,
2205
- } ;
2206
- let track_rect = Rect {
2207
- left : text_rect. right ,
2208
- top : inner. top ,
2209
- right : inner. right ,
2210
- bottom : inner. bottom ,
2211
- } ;
2212
- let pos = Point {
2213
- x : mouse. x - inner. left - tb. margin_width ( ) + tc. scroll_offset . x ,
2214
- y : mouse. y - inner. top + tc. scroll_offset . y ,
2215
- } ;
2196
+ tc. scroll_offset . x += self . input_scroll_delta . x ;
2197
+ tc. scroll_offset . y += self . input_scroll_delta . y ;
2198
+ self . set_input_consumed ( ) ;
2199
+ return make_cursor_visible;
2200
+ } else if self . tui . mouse_state != InputMouseState :: None
2201
+ && self . tui . is_node_focused ( node_prev. id )
2202
+ {
2203
+ let mouse = self . tui . mouse_position ;
2204
+ let inner = node_prev. inner ;
2205
+ let text_rect = Rect {
2206
+ left : inner. left + tb. margin_width ( ) ,
2207
+ top : inner. top ,
2208
+ right : inner. right - !single_line as CoordType ,
2209
+ bottom : inner. bottom ,
2210
+ } ;
2211
+ let track_rect = Rect {
2212
+ left : text_rect. right ,
2213
+ top : inner. top ,
2214
+ right : inner. right ,
2215
+ bottom : inner. bottom ,
2216
+ } ;
2217
+ let pos = Point {
2218
+ x : mouse. x - inner. left - tb. margin_width ( ) + tc. scroll_offset . x ,
2219
+ y : mouse. y - inner. top + tc. scroll_offset . y ,
2220
+ } ;
2216
2221
2217
- if text_rect. contains ( self . tui . mouse_down_position ) {
2218
- if self . tui . mouse_is_drag {
2219
- tb. selection_update_visual ( pos) ;
2220
- tc. preferred_column = tb. cursor_visual_pos ( ) . x ;
2222
+ if text_rect. contains ( self . tui . mouse_down_position ) {
2223
+ if self . tui . mouse_is_drag {
2224
+ tb. selection_update_visual ( pos) ;
2225
+ tc. preferred_column = tb. cursor_visual_pos ( ) . x ;
2221
2226
2222
- let height = inner. height ( ) ;
2227
+ let height = inner. height ( ) ;
2223
2228
2224
- // If the editor is only 1 line tall we can't possibly scroll up or down.
2225
- if height >= 2 {
2226
- fn calc ( min : CoordType , max : CoordType , mouse : CoordType ) -> CoordType {
2227
- // Otherwise, the scroll zone is up to 3 lines at the top/bottom.
2228
- let zone_height = ( ( max - min) / 2 ) . min ( 3 ) ;
2229
+ // If the editor is only 1 line tall we can't possibly scroll up or down.
2230
+ if height >= 2 {
2231
+ fn calc ( min : CoordType , max : CoordType , mouse : CoordType ) -> CoordType {
2232
+ // Otherwise, the scroll zone is up to 3 lines at the top/bottom.
2233
+ let zone_height = ( ( max - min) / 2 ) . min ( 3 ) ;
2229
2234
2230
- // The .y positions where the scroll zones begin:
2231
- // Mouse coordinates above top and below bottom respectively.
2232
- let scroll_min = min + zone_height;
2233
- let scroll_max = max - zone_height - 1 ;
2235
+ // The .y positions where the scroll zones begin:
2236
+ // Mouse coordinates above top and below bottom respectively.
2237
+ let scroll_min = min + zone_height;
2238
+ let scroll_max = max - zone_height - 1 ;
2234
2239
2235
- // Calculate the delta for scrolling up or down.
2236
- let delta_min = ( mouse - scroll_min) . clamp ( -zone_height, 0 ) ;
2237
- let delta_max = ( mouse - scroll_max) . clamp ( 0 , zone_height) ;
2240
+ // Calculate the delta for scrolling up or down.
2241
+ let delta_min = ( mouse - scroll_min) . clamp ( -zone_height, 0 ) ;
2242
+ let delta_max = ( mouse - scroll_max) . clamp ( 0 , zone_height) ;
2238
2243
2239
- // If I didn't mess up my logic here, only one of the two values can possibly be !=0.
2240
- let idx = 3 + delta_min + delta_max;
2244
+ // If I didn't mess up my logic here, only one of the two values can possibly be !=0.
2245
+ let idx = 3 + delta_min + delta_max;
2241
2246
2242
- const SPEEDS : [ CoordType ; 7 ] = [ -9 , -3 , -1 , 0 , 1 , 3 , 9 ] ;
2243
- let idx = idx. clamp ( 0 , SPEEDS . len ( ) as CoordType ) as usize ;
2244
- SPEEDS [ idx]
2245
- }
2247
+ const SPEEDS : [ CoordType ; 7 ] = [ -9 , -3 , -1 , 0 , 1 , 3 , 9 ] ;
2248
+ let idx = idx. clamp ( 0 , SPEEDS . len ( ) as CoordType ) as usize ;
2249
+ SPEEDS [ idx]
2250
+ }
2246
2251
2247
- let delta_x = calc ( text_rect. left , text_rect. right , mouse. x ) ;
2248
- let delta_y = calc ( text_rect. top , text_rect. bottom , mouse. y ) ;
2252
+ let delta_x = calc ( text_rect. left , text_rect. right , mouse. x ) ;
2253
+ let delta_y = calc ( text_rect. top , text_rect. bottom , mouse. y ) ;
2249
2254
2250
- tc. scroll_offset . x += delta_x;
2251
- tc. scroll_offset . y += delta_y;
2255
+ tc. scroll_offset . x += delta_x;
2256
+ tc. scroll_offset . y += delta_y;
2252
2257
2253
- if delta_x != 0 || delta_y != 0 {
2254
- self . tui . read_timeout = time:: Duration :: from_millis ( 25 ) ;
2255
- }
2258
+ if delta_x != 0 || delta_y != 0 {
2259
+ self . tui . read_timeout = time:: Duration :: from_millis ( 25 ) ;
2256
2260
}
2257
- } else {
2258
- match self . input_mouse_click {
2259
- 5 .. => { }
2260
- 4 => tb. select_all ( ) ,
2261
- 3 => tb. select_line ( ) ,
2262
- 2 => tb. select_word ( ) ,
2263
- _ => match self . tui . mouse_state {
2264
- InputMouseState :: Left => {
2265
- if self . input_mouse_modifiers . contains ( kbmod:: SHIFT ) {
2266
- // TODO: Untested because Windows Terminal surprisingly doesn't support Shift+Click.
2267
- tb. selection_update_visual ( pos) ;
2268
- } else {
2269
- tb. cursor_move_to_visual ( pos) ;
2270
- }
2271
- tc. preferred_column = tb. cursor_visual_pos ( ) . x ;
2272
- make_cursor_visible = true ;
2261
+ }
2262
+ } else {
2263
+ match self . input_mouse_click {
2264
+ 5 .. => { }
2265
+ 4 => tb. select_all ( ) ,
2266
+ 3 => tb. select_line ( ) ,
2267
+ 2 => tb. select_word ( ) ,
2268
+ _ => match self . tui . mouse_state {
2269
+ InputMouseState :: Left => {
2270
+ if self . input_mouse_modifiers . contains ( kbmod:: SHIFT ) {
2271
+ // TODO: Untested because Windows Terminal surprisingly doesn't support Shift+Click.
2272
+ tb. selection_update_visual ( pos) ;
2273
+ } else {
2274
+ tb. cursor_move_to_visual ( pos) ;
2273
2275
}
2274
- _ => return false ,
2275
- } ,
2276
- }
2276
+ tc. preferred_column = tb. cursor_visual_pos ( ) . x ;
2277
+ make_cursor_visible = true ;
2278
+ }
2279
+ _ => return false ,
2280
+ } ,
2281
+ }
2282
+ }
2283
+ } else if track_rect. contains ( self . tui . mouse_down_position ) {
2284
+ if self . tui . mouse_state == InputMouseState :: Release {
2285
+ tc. scroll_offset_y_drag_start = CoordType :: MIN ;
2286
+ } else if self . tui . mouse_is_drag {
2287
+ if tc. scroll_offset_y_drag_start == CoordType :: MIN {
2288
+ tc. scroll_offset_y_drag_start = tc. scroll_offset . y ;
2277
2289
}
2278
- } else if track_rect. contains ( self . tui . mouse_down_position ) {
2279
- if self . tui . mouse_state == InputMouseState :: Release {
2280
- tc. scroll_offset_y_drag_start = CoordType :: MIN ;
2281
- } else if self . tui . mouse_is_drag {
2282
- if tc. scroll_offset_y_drag_start == CoordType :: MIN {
2283
- tc. scroll_offset_y_drag_start = tc. scroll_offset . y ;
2284
- }
2285
2290
2286
- // The textarea supports 1 height worth of "scrolling beyond the end".
2287
- // `track_height` is the same as the viewport height.
2288
- let scrollable_height = tb. visual_line_count ( ) - 1 ;
2291
+ // The textarea supports 1 height worth of "scrolling beyond the end".
2292
+ // `track_height` is the same as the viewport height.
2293
+ let scrollable_height = tb. visual_line_count ( ) - 1 ;
2289
2294
2290
- if scrollable_height > 0 {
2291
- let trackable = track_rect. height ( ) - tc. thumb_height ;
2292
- let delta_y = mouse. y - self . tui . mouse_down_position . y ;
2293
- tc. scroll_offset . y = tc. scroll_offset_y_drag_start
2294
- + ( delta_y as i64 * scrollable_height as i64 / trackable as i64 )
2295
- as CoordType ;
2296
- }
2295
+ if scrollable_height > 0 {
2296
+ let trackable = track_rect. height ( ) - tc. thumb_height ;
2297
+ let delta_y = mouse. y - self . tui . mouse_down_position . y ;
2298
+ tc. scroll_offset . y = tc. scroll_offset_y_drag_start
2299
+ + ( delta_y as i64 * scrollable_height as i64 / trackable as i64 )
2300
+ as CoordType ;
2297
2301
}
2298
2302
}
2299
-
2300
- self . set_input_consumed ( ) ;
2301
2303
}
2302
2304
2305
+ self . set_input_consumed ( ) ;
2303
2306
return make_cursor_visible;
2304
2307
}
2305
2308
@@ -2806,9 +2809,15 @@ impl<'a> Context<'a, '_> {
2806
2809
}
2807
2810
2808
2811
if !self . input_consumed {
2809
- if self . tui . mouse_state != InputMouseState :: None {
2810
- let container_rect = prev_container. inner ;
2812
+ let container_rect = prev_container. inner ;
2811
2813
2814
+ if self . input_scroll_delta != Point :: default ( )
2815
+ && container_rect. contains ( self . tui . mouse_position )
2816
+ {
2817
+ sc. scroll_offset . x += self . input_scroll_delta . x ;
2818
+ sc. scroll_offset . y += self . input_scroll_delta . y ;
2819
+ self . set_input_consumed ( ) ;
2820
+ } else if self . tui . mouse_state != InputMouseState :: None {
2812
2821
match self . tui . mouse_state {
2813
2822
InputMouseState :: Left => {
2814
2823
if self . tui . mouse_is_drag {
@@ -2848,13 +2857,6 @@ impl<'a> Context<'a, '_> {
2848
2857
InputMouseState :: Release => {
2849
2858
sc. scroll_offset_y_drag_start = CoordType :: MIN ;
2850
2859
}
2851
- InputMouseState :: Scroll => {
2852
- if container_rect. contains ( self . tui . mouse_position ) {
2853
- sc. scroll_offset . x += self . input_scroll_delta . x ;
2854
- sc. scroll_offset . y += self . input_scroll_delta . y ;
2855
- self . set_input_consumed ( ) ;
2856
- }
2857
- }
2858
2860
_ => { }
2859
2861
}
2860
2862
} else if self . tui . is_subtree_focused_alt ( container_id, container_depth)
@@ -3586,7 +3588,7 @@ impl<'a> NodeMap<'a> {
3586
3588
}
3587
3589
3588
3590
/// Gets a node by its ID.
3589
- fn get ( & mut self , id : u64 ) -> Option < & ' a NodeCell < ' a > > {
3591
+ fn get ( & self , id : u64 ) -> Option < & ' a NodeCell < ' a > > {
3590
3592
let shift = self . shift ;
3591
3593
let mask = self . mask ;
3592
3594
let mut slot = id >> shift;
0 commit comments