1
1
use crate :: {
2
2
ansi:: { self , EraseMode , Op , OpStr } ,
3
3
color:: Rgb3 ,
4
- display:: { self , TextDisplay , ROWS } ,
4
+ display:: { self , TextDisplay , COLUMNS , ROWS } ,
5
5
CHARACTER_DRAW_CYCLES ,
6
6
} ;
7
7
use alloc:: string:: String ;
8
8
use embedded_graphics:: prelude:: DrawTarget ;
9
9
use esp32c3_hal:: systimer:: SystemTimer ;
10
- use esp_println:: println;
11
10
12
11
pub const IROWS : isize = display:: ROWS as isize ;
13
12
pub const ICOLS : isize = display:: COLUMNS as isize ;
@@ -63,6 +62,18 @@ impl CursorPos {
63
62
}
64
63
}
65
64
65
+ enum VerticalLocation {
66
+ Middle ,
67
+ Top ,
68
+ Bottom ,
69
+ }
70
+
71
+ enum HorizontalLocation {
72
+ Middle ,
73
+ Left ,
74
+ Right ,
75
+ }
76
+
66
77
#[ derive( Debug , Clone , Copy ) ]
67
78
pub struct Cursor {
68
79
pub pos : CursorPos ,
@@ -91,8 +102,20 @@ impl Cursor {
91
102
* self
92
103
}
93
104
94
- fn is_at_bottom ( & self ) -> bool {
95
- self . pos . row ( ) == ROWS - 1
105
+ fn location ( & self ) -> ( VerticalLocation , HorizontalLocation ) {
106
+ const BOT : usize = ROWS - 1 ;
107
+ const RIGHT : usize = COLUMNS - 1 ;
108
+ let vert = match self . pos . row ( ) {
109
+ BOT => VerticalLocation :: Bottom ,
110
+ 0 => VerticalLocation :: Top ,
111
+ _ => VerticalLocation :: Middle ,
112
+ } ;
113
+ let horz = match self . pos . col ( ) {
114
+ RIGHT => HorizontalLocation :: Right ,
115
+ 0 => HorizontalLocation :: Left ,
116
+ _ => HorizontalLocation :: Middle ,
117
+ } ;
118
+ ( vert, horz)
96
119
}
97
120
98
121
fn set_highlight ( & self , text : & mut TextDisplay ) {
@@ -216,52 +239,68 @@ impl TextField {
216
239
. write ( self . cursor . pos . row ( ) , self . cursor . pos . col ( ) , t) ;
217
240
self . move_cursor ( 0 , 1 ) ;
218
241
}
219
- '\n' => {
220
- if self . cursor . is_at_bottom ( ) {
242
+ '\n' => match self . cursor . location ( ) {
243
+ ( VerticalLocation :: Bottom , _ ) => {
221
244
self . cursor . unset_highlight ( & mut self . text ) ;
222
245
self . text . scroll_down ( 1 ) ;
223
246
self . move_cursor ( 0 , -( self . cursor . pos . col ( ) as isize ) )
224
- } else {
225
- self . move_cursor ( 1 , -( self . cursor . pos . col ( ) as isize ) )
226
247
}
227
- }
248
+ _ => self . move_cursor ( 1 , -( self . cursor . pos . col ( ) as isize ) ) ,
249
+ } ,
228
250
'\r' => self . move_cursor ( 0 , -( self . cursor . pos . col ( ) as isize ) ) ,
229
251
_ => {
230
252
for c in t. escape_default ( ) {
231
253
self . text . write ( self . cursor . pos . 0 , self . cursor . pos . 1 , c) ;
232
- self . move_cursor ( 0 , 1 ) ;
254
+ match self . cursor . location ( ) {
255
+ ( _, HorizontalLocation :: Left | HorizontalLocation :: Middle ) => {
256
+ self . move_cursor ( 0 , 1 ) ;
257
+ }
258
+ (
259
+ VerticalLocation :: Top | VerticalLocation :: Middle ,
260
+ HorizontalLocation :: Right ,
261
+ ) => self . move_cursor ( 1 , -( self . cursor . pos . col ( ) as isize ) ) ,
262
+ ( VerticalLocation :: Bottom , HorizontalLocation :: Right ) => {
263
+ self . cursor . unset_highlight ( & mut self . text ) ;
264
+ self . text . scroll_down ( 1 ) ;
265
+ self . cursor . set_highlight ( & mut self . text ) ;
266
+ self . move_cursor ( 0 , -( self . cursor . pos . col ( ) as isize ) ) ;
267
+ }
268
+ }
233
269
}
234
270
}
235
271
}
236
272
}
237
273
238
274
fn handle_op ( & mut self , op : Op ) {
239
- use core:: cmp:: min;
240
- use Op :: * ;
241
- match & op {
242
- TextOp ( v) => println ! (
243
- "TextOp({:?}{}) [{}]" ,
244
- & v[ ..min( v. len( ) , 5 ) ] ,
245
- if v. len( ) > 5 { "..." } else { "" } ,
246
- v. len( )
247
- ) ,
248
- DecPrivateSet ( v) => {
249
- println ! (
250
- "DecPrivateSet({:?}{}) [{}]" ,
275
+ #[ cfg( feature = "op_log" ) ]
276
+ {
277
+ use core:: cmp:: min;
278
+ use Op :: * ;
279
+ match & op {
280
+ TextOp ( v) => println ! (
281
+ "TextOp({:?}{}) [{}]" ,
251
282
& v[ ..min( v. len( ) , 5 ) ] ,
252
283
if v. len( ) > 5 { "..." } else { "" } ,
253
284
v. len( )
254
- )
255
- }
256
- DecPrivateReset ( v) => {
257
- println ! (
258
- "DecPrivateReset({:?}{}) [{}]" ,
259
- & v[ ..min( v. len( ) , 5 ) ] ,
260
- if v. len( ) > 5 { "..." } else { "" } ,
261
- v. len( )
262
- )
285
+ ) ,
286
+ DecPrivateSet ( v) => {
287
+ println ! (
288
+ "DecPrivateSet({:?}{}) [{}]" ,
289
+ & v[ ..min( v. len( ) , 5 ) ] ,
290
+ if v. len( ) > 5 { "..." } else { "" } ,
291
+ v. len( )
292
+ )
293
+ }
294
+ DecPrivateReset ( v) => {
295
+ println ! (
296
+ "DecPrivateReset({:?}{}) [{}]" ,
297
+ & v[ ..min( v. len( ) , 5 ) ] ,
298
+ if v. len( ) > 5 { "..." } else { "" } ,
299
+ v. len( )
300
+ )
301
+ }
302
+ _ => println ! ( "{:?}" , op) ,
263
303
}
264
- _ => println ! ( "{:?}" , op) ,
265
304
}
266
305
match op {
267
306
MoveCursorAbs { x, y } => {
@@ -274,7 +313,13 @@ impl TextField {
274
313
self . move_cursor ( 0 , x as isize - self . cursor . pos . col ( ) as isize ) ;
275
314
}
276
315
MoveCursorDelta { dx, dy } => {
277
- self . move_cursor ( dy, dx) ;
316
+ // Constrain dx and dy so that the result added to the current position
317
+ // stays within the window
318
+ let x = ( self . cursor . pos . col ( ) as isize + dx) . clamp ( 0 , COLUMNS as isize - 1 )
319
+ - self . cursor . pos . col ( ) as isize ;
320
+ let y = ( self . cursor . pos . row ( ) as isize + dy) . clamp ( 0 , ROWS as isize - 1 )
321
+ - self . cursor . pos . row ( ) as isize ;
322
+ self . move_cursor ( y, x) ;
278
323
}
279
324
MoveCursorBeginningAndLine { dy } => {
280
325
self . move_cursor ( dy, -( self . cursor . pos . col ( ) as isize ) ) ;
0 commit comments