16
16
17
17
use crate :: kurbo:: Point ;
18
18
use crate :: piet:: TextLayout as _;
19
+ pub use crate :: shell:: text:: { Direction , Movement , VerticalMovement , WritingDirection } ;
19
20
use crate :: text:: { EditableText , Selection , TextLayout , TextStorage } ;
20
21
21
- /// The specification of a movement.
22
- #[ derive( Debug , PartialEq , Clone , Copy ) ]
23
- pub enum Movement {
24
- /// Move to the left by one grapheme cluster.
25
- Left ,
26
- /// Move to the right by one grapheme cluster.
27
- Right ,
28
- /// Move up one visible line.
29
- Up ,
30
- /// Move down one visible line.
31
- Down ,
32
- /// Move to the left by one word.
33
- LeftWord ,
34
- /// Move to the right by one word.
35
- RightWord ,
36
- /// Move to left end of visible line.
37
- PrecedingLineBreak ,
38
- /// Move to right end of visible line.
39
- NextLineBreak ,
40
- /// Move to the beginning of the document
41
- StartOfDocument ,
42
- /// Move to the end of the document
43
- EndOfDocument ,
44
- }
45
-
46
- //FIXME: we should remove this whole file, and use the Movement type defined in druid-shell?
47
- impl From < crate :: shell:: text:: Movement > for Movement {
48
- fn from ( src : crate :: shell:: text:: Movement ) -> Movement {
49
- use crate :: shell:: text:: { Direction , Movement as SMovemement , VerticalMovement } ;
50
- match src {
51
- SMovemement :: Grapheme ( Direction :: Left ) | SMovemement :: Grapheme ( Direction :: Upstream ) => {
52
- Movement :: Left
53
- }
54
- SMovemement :: Grapheme ( _) => Movement :: Right ,
55
- SMovemement :: Word ( Direction :: Left ) => Movement :: LeftWord ,
56
- SMovemement :: Word ( _) => Movement :: RightWord ,
57
- SMovemement :: Line ( Direction :: Left ) | SMovemement :: ParagraphStart => {
58
- Movement :: PrecedingLineBreak
59
- }
60
- SMovemement :: Line ( _) | SMovemement :: ParagraphEnd => Movement :: NextLineBreak ,
61
- SMovemement :: Vertical ( VerticalMovement :: LineUp )
62
- | SMovemement :: Vertical ( VerticalMovement :: PageUp ) => Movement :: Up ,
63
- SMovemement :: Vertical ( VerticalMovement :: LineDown )
64
- | SMovemement :: Vertical ( VerticalMovement :: PageDown ) => Movement :: Down ,
65
- SMovemement :: Vertical ( VerticalMovement :: DocumentStart ) => Movement :: StartOfDocument ,
66
- SMovemement :: Vertical ( VerticalMovement :: DocumentEnd ) => Movement :: EndOfDocument ,
67
- // the source enum is non_exhaustive
68
- _ => panic ! ( "unhandled movement {:?}" , src) ,
69
- }
70
- }
71
- }
72
-
73
22
/// Compute the result of movement on a selection.
74
23
///
75
24
/// returns a new selection representing the state after the movement.
@@ -91,8 +40,14 @@ pub fn movement<T: EditableText + TextStorage>(
91
40
}
92
41
} ;
93
42
43
+ let writing_direction = if crate :: piet:: util:: first_strong_rtl ( text. as_str ( ) ) {
44
+ WritingDirection :: RightToLeft
45
+ } else {
46
+ WritingDirection :: LeftToRight
47
+ } ;
48
+
94
49
let ( offset, h_pos) = match m {
95
- Movement :: Left => {
50
+ Movement :: Grapheme ( d ) if d . is_upstream_for_direction ( writing_direction ) => {
96
51
if s. is_caret ( ) || modify {
97
52
text. prev_grapheme_offset ( s. active )
98
53
. map ( |off| ( off, None ) )
@@ -101,7 +56,7 @@ pub fn movement<T: EditableText + TextStorage>(
101
56
( s. min ( ) , None )
102
57
}
103
58
}
104
- Movement :: Right => {
59
+ Movement :: Grapheme ( _ ) => {
105
60
if s. is_caret ( ) || modify {
106
61
text. next_grapheme_offset ( s. active )
107
62
. map ( |off| ( off, None ) )
@@ -110,8 +65,7 @@ pub fn movement<T: EditableText + TextStorage>(
110
65
( s. max ( ) , None )
111
66
}
112
67
}
113
-
114
- Movement :: Up => {
68
+ Movement :: Vertical ( VerticalMovement :: LineUp ) => {
115
69
let cur_pos = layout. hit_test_text_position ( s. active ) ;
116
70
let h_pos = s. h_pos . unwrap_or ( cur_pos. point . x ) ;
117
71
if cur_pos. line == 0 {
@@ -123,7 +77,7 @@ pub fn movement<T: EditableText + TextStorage>(
123
77
( up_pos. idx , Some ( point_above. x ) )
124
78
}
125
79
}
126
- Movement :: Down => {
80
+ Movement :: Vertical ( VerticalMovement :: LineDown ) => {
127
81
let cur_pos = layout. hit_test_text_position ( s. active ) ;
128
82
let h_pos = s. h_pos . unwrap_or ( cur_pos. point . x ) ;
129
83
if cur_pos. line == layout. line_count ( ) - 1 {
@@ -137,29 +91,47 @@ pub fn movement<T: EditableText + TextStorage>(
137
91
( up_pos. idx , Some ( point_below. x ) )
138
92
}
139
93
}
94
+ Movement :: Vertical ( VerticalMovement :: DocumentStart ) => ( 0 , None ) ,
95
+ Movement :: Vertical ( VerticalMovement :: DocumentEnd ) => ( text. len ( ) , None ) ,
140
96
141
- Movement :: PrecedingLineBreak => ( text. preceding_line_break ( s. active ) , None ) ,
142
- Movement :: NextLineBreak => ( text. next_line_break ( s. active ) , None ) ,
143
-
144
- Movement :: StartOfDocument => ( 0 , None ) ,
145
- Movement :: EndOfDocument => ( text. len ( ) , None ) ,
97
+ Movement :: ParagraphStart => ( text. preceding_line_break ( s. active ) , None ) ,
98
+ Movement :: ParagraphEnd => ( text. next_line_break ( s. active ) , None ) ,
146
99
147
- Movement :: LeftWord => {
100
+ Movement :: Line ( d) => {
101
+ let hit = layout. hit_test_text_position ( s. active ) ;
102
+ let lm = layout. line_metric ( hit. line ) . unwrap ( ) ;
103
+ let offset = if d. is_upstream_for_direction ( writing_direction) {
104
+ lm. start_offset
105
+ } else {
106
+ lm. end_offset
107
+ } ;
108
+ ( offset, None )
109
+ }
110
+ Movement :: Word ( d) if d. is_upstream_for_direction ( writing_direction) => {
148
111
let offset = if s. is_caret ( ) || modify {
149
112
text. prev_word_offset ( s. active ) . unwrap_or ( 0 )
150
113
} else {
151
114
s. min ( )
152
115
} ;
153
116
( offset, None )
154
117
}
155
- Movement :: RightWord => {
118
+ Movement :: Word ( _ ) => {
156
119
let offset = if s. is_caret ( ) || modify {
157
120
text. next_word_offset ( s. active ) . unwrap_or ( s. active )
158
121
} else {
159
122
s. max ( )
160
123
} ;
161
124
( offset, None )
162
125
}
126
+
127
+ // These two are not handled; they require knowledge of the size
128
+ // of the viewport.
129
+ Movement :: Vertical ( VerticalMovement :: PageDown )
130
+ | Movement :: Vertical ( VerticalMovement :: PageUp ) => ( s. active , s. h_pos ) ,
131
+ other => {
132
+ tracing:: warn!( "unhandled movement {:?}" , other) ;
133
+ ( s. anchor , s. h_pos )
134
+ }
163
135
} ;
164
136
165
137
let start = if modify { s. anchor } else { offset } ;
0 commit comments