@@ -11,12 +11,13 @@ use masonry_testing::{
1111
1212use crate :: core:: pointer:: { PointerButton , PointerEvent } ;
1313use crate :: core:: {
14- CursorIcon , Ime , NewWidget , PropertySet , TextEvent , Update , Widget , WidgetId , WidgetPod ,
15- WidgetTag ,
14+ CursorIcon , Handled , NewWidget , PropertySet , TextCursorAnchor , TextCursorOffset ,
15+ TextCursorPlacement , TextDeleteSurroundingEvent , TextEvent , TextInputAction , TextInputEvent ,
16+ TextInsertEvent , TextTargetRange , Update , Widget , WidgetId , WidgetPod , WidgetTag ,
1617} ;
1718use crate :: layout:: Length ;
1819use crate :: theme:: test_property_set;
19- use crate :: widgets:: { Button , Flex , Label , SizedBox , TextArea } ;
20+ use crate :: widgets:: { Button , Flex , InsertNewline , Label , SizedBox , TextAction , TextArea } ;
2021
2122// TREE
2223
@@ -496,16 +497,186 @@ fn ime_commit() {
496497
497498 harness. focus_on ( Some ( textbox_id) ) ;
498499
499- harness. process_text_event ( TextEvent :: Ime ( Ime :: Commit ( "New Text" . to_string ( ) ) ) ) ;
500+ harness. process_text_event ( TextEvent :: TextInput ( TextInputEvent :: insert ( "New Text" ) ) ) ;
500501 assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "New Text" ) ;
501502
502- harness. process_text_event ( TextEvent :: Ime ( Ime :: Commit ( " and more" . to_string ( ) ) ) ) ;
503+ harness. process_text_event ( TextEvent :: TextInput ( TextInputEvent :: insert ( " and more" ) ) ) ;
503504 assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "New Text and more" ) ;
504505
505506 let ime_area_size = harness. ime_rect ( ) . 1 ;
506507 assert ! ( ime_area_size. width > 0. && ime_area_size. height > 0. ) ;
507508}
508509
510+ #[ test]
511+ fn text_input_insert_replacement_range ( ) {
512+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
513+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "hello" ) , textbox_tag) ;
514+
515+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
516+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
517+ harness. focus_on ( Some ( textbox_id) ) ;
518+
519+ let handled = harness. process_text_event ( TextEvent :: TextInput ( TextInputEvent :: replace (
520+ "i" ,
521+ TextTargetRange :: utf8_bytes ( 1 , 4 ) ,
522+ ) ) ) ;
523+
524+ assert_eq ! ( handled, Handled :: Yes ) ;
525+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "hio" ) ;
526+ }
527+
528+ #[ test]
529+ fn text_input_delete_surrounding_utf8 ( ) {
530+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
531+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "abcdef" ) , textbox_tag) ;
532+
533+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
534+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
535+ harness. focus_on ( Some ( textbox_id) ) ;
536+
537+ assert_eq ! (
538+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: set_selection(
539+ TextTargetRange :: utf8_bytes( 3 , 3 ) ,
540+ ) ) ) ,
541+ Handled :: Yes
542+ ) ;
543+ assert_eq ! (
544+ harness. process_text_event( TextEvent :: TextInput (
545+ TextInputEvent :: delete_surrounding_utf8( 1 , 2 ) ,
546+ ) ) ,
547+ Handled :: Yes
548+ ) ;
549+
550+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "abf" ) ;
551+ }
552+
553+ #[ test]
554+ fn text_input_set_selection_replaces_selected_text ( ) {
555+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
556+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "hello" ) , textbox_tag) ;
557+
558+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
559+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
560+ harness. focus_on ( Some ( textbox_id) ) ;
561+
562+ assert_eq ! (
563+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: set_selection(
564+ TextTargetRange :: utf8_bytes( 1 , 4 ) ,
565+ ) ) ) ,
566+ Handled :: Yes
567+ ) ;
568+ assert_eq ! (
569+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: insert( "i" ) ) ) ,
570+ Handled :: Yes
571+ ) ;
572+
573+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "hio" ) ;
574+ }
575+
576+ #[ test]
577+ fn text_input_action_newline_inserts_when_enabled ( ) {
578+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
579+ let textbox = NewWidget :: new_with_tag (
580+ TextArea :: new_editable ( "hello" ) . with_insert_newline ( InsertNewline :: OnEnter ) ,
581+ textbox_tag,
582+ ) ;
583+
584+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
585+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
586+ harness. focus_on ( Some ( textbox_id) ) ;
587+
588+ assert_eq ! (
589+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: action(
590+ TextInputAction :: Newline ,
591+ ) ) ) ,
592+ Handled :: Yes
593+ ) ;
594+
595+ let ( action, widget_id) = harness. pop_action :: < TextAction > ( ) . unwrap ( ) ;
596+ assert_eq ! ( widget_id, textbox_id) ;
597+ assert_eq ! ( action, TextAction :: Changed ( "\n hello" . to_string( ) ) ) ;
598+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "\n hello" ) ;
599+ }
600+
601+ #[ test]
602+ fn text_input_actions_submit_entered ( ) {
603+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
604+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "query" ) , textbox_tag) ;
605+
606+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
607+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
608+ harness. focus_on ( Some ( textbox_id) ) ;
609+
610+ for action in [
611+ TextInputAction :: Done ,
612+ TextInputAction :: Search ,
613+ TextInputAction :: Send ,
614+ ] {
615+ assert_eq ! (
616+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: action( action) ) ) ,
617+ Handled :: Yes
618+ ) ;
619+ let ( emitted, widget_id) = harness. pop_action :: < TextAction > ( ) . unwrap ( ) ;
620+ assert_eq ! ( widget_id, textbox_id) ;
621+ assert_eq ! ( emitted, TextAction :: Entered ( "query" . to_string( ) ) ) ;
622+ }
623+ }
624+
625+ #[ test]
626+ fn text_input_non_utf8_delete_surrounding_is_unhandled ( ) {
627+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
628+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "abcdef" ) , textbox_tag) ;
629+
630+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
631+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
632+ harness. focus_on ( Some ( textbox_id) ) ;
633+
634+ assert_eq ! (
635+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: set_selection(
636+ TextTargetRange :: utf8_bytes( 3 , 3 ) ,
637+ ) ) ) ,
638+ Handled :: Yes
639+ ) ;
640+
641+ let handled = harness. process_text_event ( TextEvent :: TextInput (
642+ TextInputEvent :: DeleteSurrounding ( TextDeleteSurroundingEvent :: utf16_code_units ( 1 , 1 ) ) ,
643+ ) ) ;
644+
645+ assert_eq ! ( handled, Handled :: No ) ;
646+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "abcdef" ) ;
647+ }
648+
649+ #[ test]
650+ fn text_input_cursor_placement_is_currently_ignored ( ) {
651+ let textbox_tag = WidgetTag :: named ( "textbox" ) ;
652+ let textbox = NewWidget :: new_with_tag ( TextArea :: new_editable ( "" ) , textbox_tag) ;
653+
654+ let mut harness = TestHarness :: create ( test_property_set ( ) , textbox) ;
655+ let textbox_id = harness. get_widget ( textbox_tag) . id ( ) ;
656+ harness. focus_on ( Some ( textbox_id) ) ;
657+
658+ let placement = TextCursorPlacement :: Offset ( TextCursorOffset :: utf8_bytes (
659+ 0 ,
660+ TextCursorAnchor :: InsertedTextStart ,
661+ ) ) ;
662+
663+ assert_eq ! (
664+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: Insert (
665+ TextInsertEvent :: new( "ab" ) . with_cursor_placement( placement) ,
666+ ) ) ) ,
667+ Handled :: Yes
668+ ) ;
669+ assert_eq ! (
670+ harness. process_text_event( TextEvent :: TextInput ( TextInputEvent :: Insert (
671+ TextInsertEvent :: new( "X" ) ,
672+ ) ) ) ,
673+ Handled :: Yes
674+ ) ;
675+
676+ // If cursor placement were applied, the follow-up insert would land before "ab".
677+ assert_eq ! ( harness. get_widget( textbox_tag) . text( ) , "abX" ) ;
678+ }
679+
509680#[ test]
510681fn ime_removed ( ) {
511682 let textbox_tag = WidgetTag :: named ( "textbox" ) ;
@@ -543,7 +714,10 @@ fn ime_start_stop() {
543714
544715 let records = harness. take_records_of ( textbox_tag) ;
545716 assert_any ( records, |r| {
546- matches ! ( r, Record :: TextEvent ( TextEvent :: Ime ( Ime :: Disabled ) ) )
717+ matches ! (
718+ r,
719+ Record :: TextEvent ( TextEvent :: TextInput ( TextInputEvent :: CompositionEnd ) )
720+ )
547721 } ) ;
548722
549723 assert ! ( !harness. has_ime_session( ) ) ;
0 commit comments