@@ -40,6 +40,8 @@ widget_style!{
40
40
- restrict_to_height: bool { true }
41
41
/// The font used for the `Text`.
42
42
- font_id: Option <text:: font:: Id > { theme. font_id }
43
+ /// Display text with all characters replaced by this
44
+ - char_replace: Option <char > { None }
43
45
}
44
46
}
45
47
@@ -164,6 +166,7 @@ impl<'a> TextEdit<'a> {
164
166
pub line_wrap { style. line_wrap = Some ( Wrap ) }
165
167
pub line_spacing { style. line_spacing = Some ( Scalar ) }
166
168
pub restrict_to_height { style. restrict_to_height = Some ( bool ) }
169
+ pub hide_with_char { style. char_replace = Some ( Option <char >) }
167
170
}
168
171
169
172
}
@@ -275,6 +278,10 @@ impl<'a> Widget for TextEdit<'a> {
275
278
}
276
279
}
277
280
281
+ let mut replacement_string = style. char_replace
282
+ . and_then ( |opt| opt)
283
+ . map ( |c : char | text. chars ( ) . map ( |_| c) . collect :: < String > ( ) . into ( ) ) ;
284
+
278
285
// Check to see if the given text has changed since the last time the widget was updated.
279
286
{
280
287
let maybe_new_line_infos = {
@@ -441,7 +448,8 @@ impl<'a> Widget for TextEdit<'a> {
441
448
let abs_xy = utils:: vec2_add ( rel_xy, rect. xy ( ) ) ;
442
449
let infos = & state. line_infos ;
443
450
let font = ui. fonts . get ( font_id) . unwrap ( ) ;
444
- let closest = closest_cursor_index_and_xy ( abs_xy, & text, infos, font) ;
451
+ let closest = closest_cursor_index_and_xy ( abs_xy, & replacement_string. as_ref ( ) . unwrap_or ( & text) ,
452
+ infos, font) ;
445
453
if let Some ( ( closest_cursor, _) ) = closest {
446
454
cursor = Cursor :: Idx ( closest_cursor) ;
447
455
}
@@ -506,6 +514,8 @@ impl<'a> Widget for TextEdit<'a> {
506
514
* text. to_mut ( ) = text. chars ( ) . take ( start_idx)
507
515
. chain ( text. chars ( ) . skip ( end_idx) )
508
516
. collect ( ) ;
517
+ replacement_string = style. char_replace . and_then ( |opt| opt)
518
+ . map ( |c : char | text. chars ( ) . map ( |_| c) . collect :: < String > ( ) . into ( ) ) ;
509
519
state. update ( |state| {
510
520
let font = ui. fonts . get ( font_id) . unwrap ( ) ;
511
521
let w = rect. w ( ) ;
@@ -526,28 +536,30 @@ impl<'a> Widget for TextEdit<'a> {
526
536
Cursor :: Selection { start, end } => ( start, end) ,
527
537
} ;
528
538
539
+ let displayed_text = replacement_string. as_ref ( ) . unwrap_or ( & text) ;
540
+
529
541
let new_cursor_idx = {
530
542
let line_infos = state. line_infos . iter ( ) . cloned ( ) ;
531
543
match ( key, move_word) {
532
544
( input:: Key :: Left , true ) => cursor_idx
533
- . previous_word_start ( & text , line_infos) ,
545
+ . previous_word_start ( & displayed_text , line_infos) ,
534
546
( input:: Key :: Right , true ) => cursor_idx
535
- . next_word_end ( & text , line_infos) ,
547
+ . next_word_end ( & displayed_text , line_infos) ,
536
548
( input:: Key :: Left , false ) => cursor_idx
537
549
. previous ( line_infos) ,
538
550
( input:: Key :: Right , false ) => cursor_idx
539
551
. next ( line_infos) ,
540
552
541
553
// Up/Down movement
542
- _ => cursor_xy_at ( cursor_idx, & text , & state. line_infos , font)
554
+ _ => cursor_xy_at ( cursor_idx, & displayed_text , & state. line_infos , font)
543
555
. and_then ( |( x_pos, _) | {
544
556
let text:: cursor:: Index { line, .. } = cursor_idx;
545
557
let next_line = match key {
546
558
input:: Key :: Up => line. saturating_sub ( 1 ) ,
547
559
input:: Key :: Down => line + 1 ,
548
560
_ => unreachable ! ( ) ,
549
561
} ;
550
- closest_cursor_index_on_line ( x_pos, next_line, & text , & state. line_infos , font)
562
+ closest_cursor_index_on_line ( x_pos, next_line, & displayed_text , & state. line_infos , font)
551
563
} )
552
564
} . unwrap_or ( cursor_idx)
553
565
} ;
@@ -581,10 +593,10 @@ impl<'a> Widget for TextEdit<'a> {
581
593
let line_infos = state. line_infos . iter ( ) . cloned ( ) ;
582
594
match key {
583
595
input:: Key :: Left | input:: Key :: Up => {
584
- cursor_idx. previous_word_start ( & text , line_infos)
596
+ cursor_idx. previous_word_start ( & displayed_text , line_infos)
585
597
} ,
586
598
input:: Key :: Right | input:: Key :: Down => {
587
- cursor_idx. next_word_end ( & text , line_infos)
599
+ cursor_idx. next_word_end ( & displayed_text , line_infos)
588
600
}
589
601
_ => unreachable ! ( ) ,
590
602
} . unwrap_or ( cursor_idx)
@@ -656,6 +668,8 @@ impl<'a> Widget for TextEdit<'a> {
656
668
match insert_text ( "\n " , cursor, & text, & state. line_infos , font) {
657
669
Some ( ( new_text, new_cursor, new_line_infos) ) => {
658
670
* text. to_mut ( ) = new_text;
671
+ replacement_string = style. char_replace . and_then ( |opt| opt)
672
+ . map ( |c : char | text. chars ( ) . map ( |_| c) . collect :: < String > ( ) . into ( ) ) ;
659
673
cursor = new_cursor;
660
674
state. update ( |state| state. line_infos = new_line_infos) ;
661
675
} , _ => ( )
@@ -698,6 +712,8 @@ impl<'a> Widget for TextEdit<'a> {
698
712
match insert_text ( & string, cursor, & text, & state. line_infos , font) {
699
713
Some ( ( new_text, new_cursor, new_line_infos) ) => {
700
714
* text. to_mut ( ) = new_text;
715
+ replacement_string = style. char_replace . and_then ( |opt| opt)
716
+ . map ( |c : char | text. chars ( ) . map ( |_| c) . collect :: < String > ( ) . into ( ) ) ;
701
717
cursor = new_cursor;
702
718
state. update ( |state| state. line_infos = new_line_infos) ;
703
719
} , _ => ( )
@@ -706,8 +722,9 @@ impl<'a> Widget for TextEdit<'a> {
706
722
707
723
// Check whether or not we need to extend a text selection or drag some text.
708
724
event:: Widget :: Drag ( drag_event) if drag_event. button == input:: MouseButton :: Left => {
709
- match drag {
725
+ let displayed_text = replacement_string . as_ref ( ) . unwrap_or ( & text ) ;
710
726
727
+ match drag {
711
728
Some ( Drag :: Selecting ) => {
712
729
let start_cursor_idx = match cursor {
713
730
Cursor :: Idx ( idx) => idx,
@@ -716,7 +733,7 @@ impl<'a> Widget for TextEdit<'a> {
716
733
let abs_xy = utils:: vec2_add ( drag_event. to , rect. xy ( ) ) ;
717
734
let infos = & state. line_infos ;
718
735
let font = ui. fonts . get ( font_id) . unwrap ( ) ;
719
- match closest_cursor_index_and_xy ( abs_xy, & text , infos, font) {
736
+ match closest_cursor_index_and_xy ( abs_xy, & displayed_text , infos, font) {
720
737
Some ( ( end_cursor_idx, _) ) =>
721
738
cursor = Cursor :: Selection {
722
739
start : start_cursor_idx,
@@ -763,20 +780,26 @@ impl<'a> Widget for TextEdit<'a> {
763
780
let text_y_range = Range :: new ( 0.0 , text_height) . align_to ( y_align, rect. y ) ;
764
781
let text_rect = Rect { x : rect. x , y : text_y_range } ;
765
782
766
- match line_wrap {
767
- Wrap :: Whitespace => widget:: Text :: new ( & text) . wrap_by_word ( ) ,
768
- Wrap :: Character => widget:: Text :: new ( & text) . wrap_by_character ( ) ,
783
+ {
784
+ let display_text = match replacement_string {
785
+ Some ( ref s) => s,
786
+ None => & text,
787
+ } ;
788
+ match line_wrap {
789
+ Wrap :: Whitespace => widget:: Text :: new ( display_text) . wrap_by_word ( ) ,
790
+ Wrap :: Character => widget:: Text :: new ( display_text) . wrap_by_character ( ) ,
791
+ }
792
+ . font_id ( font_id)
793
+ . wh ( text_rect. dim ( ) )
794
+ . xy ( text_rect. xy ( ) )
795
+ . justify ( justify)
796
+ . parent ( id)
797
+ . graphics_for ( id)
798
+ . color ( color)
799
+ . line_spacing ( line_spacing)
800
+ . font_size ( font_size)
801
+ . set ( state. ids . text , ui) ;
769
802
}
770
- . font_id ( font_id)
771
- . wh ( text_rect. dim ( ) )
772
- . xy ( text_rect. xy ( ) )
773
- . justify ( justify)
774
- . parent ( id)
775
- . graphics_for ( id)
776
- . color ( color)
777
- . line_spacing ( line_spacing)
778
- . font_size ( font_size)
779
- . set ( state. ids . text , ui) ;
780
803
781
804
// Draw the line for the cursor.
782
805
let cursor_idx = match cursor {
@@ -791,7 +814,7 @@ impl<'a> Widget for TextEdit<'a> {
791
814
792
815
let ( cursor_x, cursor_y_range) = {
793
816
let font = ui. fonts . get ( font_id) . unwrap ( ) ;
794
- cursor_xy_at ( cursor_idx, & text, & state. line_infos , font)
817
+ cursor_xy_at ( cursor_idx, replacement_string . as_ref ( ) . unwrap_or ( & text) , & state. line_infos , font)
795
818
. unwrap_or_else ( || {
796
819
let x = rect. left ( ) ;
797
820
let y = Range :: new ( 0.0 , font_size as Scalar ) . align_to ( y_align, rect. y ) ;
@@ -839,7 +862,7 @@ impl<'a> Widget for TextEdit<'a> {
839
862
840
863
let selected_rects: Vec < Rect > = {
841
864
let line_infos = state. line_infos . iter ( ) . cloned ( ) ;
842
- let lines = line_infos. clone ( ) . map ( |info| & text[ info. byte_range ( ) ] ) ;
865
+ let lines = line_infos. clone ( ) . map ( |info| & replacement_string . as_ref ( ) . unwrap_or ( & text) [ info. byte_range ( ) ] ) ;
843
866
let line_rects = text:: line:: rects ( line_infos. clone ( ) , font_size, rect,
844
867
justify, y_align, line_spacing) ;
845
868
let lines_with_rects = lines. zip ( line_rects. clone ( ) ) ;
@@ -867,6 +890,7 @@ impl<'a> Widget for TextEdit<'a> {
867
890
}
868
891
}
869
892
893
+
870
894
take_if_owned ( text)
871
895
}
872
896
0 commit comments