@@ -371,18 +371,49 @@ impl<'a> Widget for DragValue<'a> {
371
371
let shift = ui. input ( ) . modifiers . shift_only ( ) ;
372
372
let is_slow_speed = shift && ui. memory ( ) . is_being_dragged ( ui. next_auto_id ( ) ) ;
373
373
374
+ let kb_edit_id = ui. next_auto_id ( ) ;
375
+ // The following call ensures that when a `DragValue` receives focus,
376
+ // it is immediately rendered in edit mode, rather than being rendered
377
+ // in button mode for just one frame. This is important for
378
+ // screen readers.
379
+ ui. memory ( ) . interested_in_focus ( kb_edit_id) ;
380
+ let is_kb_editing = ui. memory ( ) . has_focus ( kb_edit_id) ;
381
+
374
382
let old_value = get ( & mut get_set_value) ;
375
- let value = clamp_to_range ( old_value, clamp_range. clone ( ) ) ;
376
- if old_value != value {
377
- set ( & mut get_set_value, value) ;
378
- }
383
+ let mut value = old_value;
379
384
let aim_rad = ui. input ( ) . aim_radius ( ) as f64 ;
380
385
381
386
let auto_decimals = ( aim_rad / speed. abs ( ) ) . log10 ( ) . ceil ( ) . clamp ( 0.0 , 15.0 ) as usize ;
382
387
let auto_decimals = auto_decimals + is_slow_speed as usize ;
383
-
384
388
let max_decimals = max_decimals. unwrap_or ( auto_decimals + 2 ) ;
385
389
let auto_decimals = auto_decimals. clamp ( min_decimals, max_decimals) ;
390
+
391
+ if is_kb_editing {
392
+ let mut input = ui. input_mut ( ) ;
393
+ // This deliberately doesn't listen for left and right arrow keys,
394
+ // because when editing, these are used to move the caret.
395
+ // This behavior is consistent with other editable spinner/stepper
396
+ // implementations, such as Chromium's (for HTML5 number input).
397
+ // It is also normal for such controls to go directly into edit mode
398
+ // when they receive keyboard focus, and some screen readers
399
+ // assume this behavior, so having a separate mode for incrementing
400
+ // and decrementing, that supports all arrow keys, would be
401
+ // problematic.
402
+ let change = input. count_and_consume_key ( Modifiers :: NONE , Key :: ArrowUp ) as f64
403
+ - input. count_and_consume_key ( Modifiers :: NONE , Key :: ArrowDown ) as f64 ;
404
+
405
+ if change != 0.0 {
406
+ value += speed * change;
407
+ value = emath:: round_to_decimals ( value, auto_decimals) ;
408
+ }
409
+ }
410
+
411
+ value = clamp_to_range ( value, clamp_range. clone ( ) ) ;
412
+ if old_value != value {
413
+ set ( & mut get_set_value, value) ;
414
+ ui. memory ( ) . drag_value . edit_string = None ;
415
+ }
416
+
386
417
let value_text = match custom_formatter {
387
418
Some ( custom_formatter) => custom_formatter ( value, auto_decimals..=max_decimals) ,
388
419
None => {
@@ -394,9 +425,6 @@ impl<'a> Widget for DragValue<'a> {
394
425
}
395
426
} ;
396
427
397
- let kb_edit_id = ui. next_auto_id ( ) ;
398
- let is_kb_editing = ui. memory ( ) . has_focus ( kb_edit_id) ;
399
-
400
428
let mut response = if is_kb_editing {
401
429
let button_width = ui. spacing ( ) . interact_size . x ;
402
430
let mut value_text = ui
@@ -419,14 +447,10 @@ impl<'a> Widget for DragValue<'a> {
419
447
let parsed_value = clamp_to_range ( parsed_value, clamp_range) ;
420
448
set ( & mut get_set_value, parsed_value) ;
421
449
}
422
- if ui. input ( ) . key_pressed ( Key :: Enter ) {
423
- ui. memory ( ) . surrender_focus ( kb_edit_id) ;
424
- ui. memory ( ) . drag_value . edit_string = None ;
425
- } else {
426
- ui. memory ( ) . drag_value . edit_string = Some ( value_text) ;
427
- }
450
+ ui. memory ( ) . drag_value . edit_string = Some ( value_text) ;
428
451
response
429
452
} else {
453
+ ui. memory ( ) . drag_value . edit_string = None ;
430
454
let button = Button :: new (
431
455
RichText :: new ( format ! ( "{}{}{}" , prefix, value_text, suffix) ) . monospace ( ) ,
432
456
)
@@ -448,7 +472,6 @@ impl<'a> Widget for DragValue<'a> {
448
472
449
473
if response. clicked ( ) {
450
474
ui. memory ( ) . request_focus ( kb_edit_id) ;
451
- ui. memory ( ) . drag_value . edit_string = None ; // Filled in next frame
452
475
} else if response. dragged ( ) {
453
476
ui. output ( ) . cursor_icon = CursorIcon :: ResizeHorizontal ;
454
477
@@ -483,18 +506,6 @@ impl<'a> Widget for DragValue<'a> {
483
506
drag_state. last_dragged_value = Some ( stored_value) ;
484
507
ui. memory ( ) . drag_value = drag_state;
485
508
}
486
- } else if response. has_focus ( ) {
487
- let change = ui. input ( ) . num_presses ( Key :: ArrowUp ) as f64
488
- + ui. input ( ) . num_presses ( Key :: ArrowRight ) as f64
489
- - ui. input ( ) . num_presses ( Key :: ArrowDown ) as f64
490
- - ui. input ( ) . num_presses ( Key :: ArrowLeft ) as f64 ;
491
-
492
- if change != 0.0 {
493
- let new_value = value + speed * change;
494
- let new_value = emath:: round_to_decimals ( new_value, auto_decimals) ;
495
- let new_value = clamp_to_range ( new_value, clamp_range) ;
496
- set ( & mut get_set_value, new_value) ;
497
- }
498
509
}
499
510
500
511
response
0 commit comments