@@ -33,6 +33,8 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
3333 self -> status_x = 0 ;
3434 self -> status_y = 0 ;
3535 self -> first_row = 0 ;
36+ self -> vt_scroll_top = 0 ;
37+ self -> vt_scroll_end = self -> scroll_area -> height_in_tiles - 1 ;
3638 common_hal_displayio_tilegrid_set_all_tiles (self -> scroll_area , 0 );
3739 if (self -> status_bar ) {
3840 common_hal_displayio_tilegrid_set_all_tiles (self -> status_bar , 0 );
@@ -42,6 +44,8 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self,
4244}
4345
4446size_t common_hal_terminalio_terminal_write (terminalio_terminal_obj_t * self , const byte * data , size_t len , int * errcode ) {
47+ #define scrnmod (x ) (((x) + (self->scroll_area->top_left_y)) % (self->scroll_area->height_in_tiles))
48+
4549 // Make sure the terminal is initialized before we do anything with it.
4650 if (self -> scroll_area == NULL ) {
4751 return len ;
@@ -114,7 +118,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
114118 }
115119 } else if (c == 0x1b ) {
116120 // Handle commands of the form [ESC].<digits><command-char> where . is not yet known.
117- uint8_t vt_args [3 ] = {0 , -1 , -1 };
121+ uint16_t vt_args [3 ] = {0 , -1 , -1 };
118122 uint8_t j = 1 ;
119123 #if CIRCUITPY_TERMINALIO_VT100
120124 uint8_t n_args = 1 ;
@@ -158,8 +162,8 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
158162 #endif
159163 } else {
160164 if (c == 'K' ) {
161- uint8_t clr_start = self -> cursor_x ;
162- uint8_t clr_end = self -> scroll_area -> width_in_tiles ;
165+ int16_t clr_start = self -> cursor_x ;
166+ int16_t clr_end = self -> scroll_area -> width_in_tiles ;
163167 #if CIRCUITPY_TERMINALIO_VT100
164168 if (vt_args [0 ] == 1 ) {
165169 clr_start = 0 ;
@@ -200,7 +204,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
200204 if (vt_args [1 ] >= self -> scroll_area -> width_in_tiles ) {
201205 vt_args [1 ] = self -> scroll_area -> width_in_tiles - 1 ;
202206 }
203- vt_args [0 ] = (vt_args [0 ] + self -> scroll_area -> top_left_y ) % self -> scroll_area -> height_in_tiles ;
207+ vt_args [0 ] = scrnmod (vt_args [0 ]) ;
204208 self -> cursor_x = vt_args [1 ];
205209 self -> cursor_y = vt_args [0 ];
206210 start_y = self -> cursor_y ;
@@ -215,39 +219,77 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
215219 common_hal_displayio_palette_set_color (terminal_palette , 1 , 0xffffff );
216220 }
217221 }
222+ } else if (c == 'r' ) {
223+ if (vt_args [0 ] < vt_args [1 ] && vt_args [0 ] >= 1 && vt_args [1 ] <= self -> scroll_area -> height_in_tiles ) {
224+ self -> vt_scroll_top = vt_args [0 ] - 1 ;
225+ self -> vt_scroll_end = vt_args [1 ] - 1 ;
226+ } else {
227+ self -> vt_scroll_top = 0 ;
228+ self -> vt_scroll_end = self -> scroll_area -> height_in_tiles - 1 ;
229+ }
230+ self -> cursor_x = 0 ;
231+ self -> cursor_y = self -> scroll_area -> top_left_y % self -> scroll_area -> height_in_tiles ;
232+ start_y = self -> cursor_y ;
218233 #endif
219234 }
220235 i += j + 1 ;
221236 }
222237 #if CIRCUITPY_TERMINALIO_VT100
223238 } else if (i [0 ] == 'M' ) {
224- if (self -> cursor_y != self -> scroll_area -> top_left_y ) {
239+ if (self -> cursor_y != scrnmod ( self -> vt_scroll_top ) ) {
225240 if (self -> cursor_y > 0 ) {
226241 self -> cursor_y = self -> cursor_y - 1 ;
227242 } else {
228243 self -> cursor_y = self -> scroll_area -> height_in_tiles - 1 ;
229244 }
230245 } else {
231- if (self -> cursor_y > 0 ) {
232- common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> cursor_y - 1 );
246+ if (self -> vt_scroll_top != 0 || self -> vt_scroll_end != self -> scroll_area -> height_in_tiles ) {
247+ // Scroll range defined, manually move tiles to perform scroll
248+ for (int16_t irow = self -> vt_scroll_end - 1 ; irow >= self -> vt_scroll_top ; irow -- ) {
249+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
250+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , scrnmod (irow + 1 ), common_hal_displayio_tilegrid_get_tile (self -> scroll_area , icol , scrnmod (irow )));
251+ }
252+ }
253+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
254+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
255+ }
233256 } else {
234- common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> scroll_area -> height_in_tiles - 1 );
235- }
236- for (uint8_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
237- common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> scroll_area -> top_left_y , 0 );
257+ // Full screen scroll, just set new top_y pointer and clear row
258+ if (self -> cursor_y > 0 ) {
259+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> cursor_y - 1 );
260+ } else {
261+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> scroll_area -> height_in_tiles - 1 );
262+ }
263+ for (uint16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
264+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> scroll_area -> top_left_y , 0 );
265+ }
266+ self -> cursor_y = self -> scroll_area -> top_left_y ;
238267 }
239-
240268 self -> cursor_x = 0 ;
241- self -> cursor_y = self -> scroll_area -> top_left_y ;
242269 }
243270 start_y = self -> cursor_y ;
244271 i ++ ;
245272 } else if (i [0 ] == 'D' ) {
246- self -> cursor_y = (self -> cursor_y + 1 ) % self -> scroll_area -> height_in_tiles ;
247- if (self -> cursor_y == self -> scroll_area -> top_left_y ) {
248- common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , (self -> cursor_y + 1 ) % self -> scroll_area -> height_in_tiles );
249- for (uint8_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
250- common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
273+ if (self -> cursor_y != scrnmod (self -> vt_scroll_end )) {
274+ self -> cursor_y = (self -> cursor_y + 1 ) % self -> scroll_area -> height_in_tiles ;
275+ } else {
276+ if (self -> vt_scroll_top != 0 || self -> vt_scroll_end != self -> scroll_area -> height_in_tiles ) {
277+ // Scroll range defined, manually move tiles to perform scroll
278+ for (int16_t irow = self -> vt_scroll_top ; irow < self -> vt_scroll_end ; irow ++ ) {
279+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
280+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , scrnmod (irow ), common_hal_displayio_tilegrid_get_tile (self -> scroll_area , icol , scrnmod (irow + 1 )));
281+ }
282+ }
283+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
284+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
285+ }
286+ } else {
287+ // Full screen scroll, just set new top_y pointer and clear row
288+ self -> cursor_y = (self -> cursor_y + 1 ) % self -> scroll_area -> height_in_tiles ;
289+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , (self -> cursor_y + 1 ) % self -> scroll_area -> height_in_tiles );
290+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
291+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
292+ }
251293 }
252294 self -> cursor_x = 0 ;
253295 }
@@ -276,12 +318,28 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
276318 self -> cursor_y %= self -> scroll_area -> height_in_tiles ;
277319 }
278320 if (self -> cursor_y != start_y ) {
279- // clear the new row in case of scroll up
280- if (self -> cursor_y == self -> scroll_area -> top_left_y ) {
281- for (uint16_t j = 0 ; j < self -> scroll_area -> width_in_tiles ; j ++ ) {
282- common_hal_displayio_tilegrid_set_tile (self -> scroll_area , j , self -> cursor_y , 0 );
321+ if (((self -> cursor_y + self -> scroll_area -> height_in_tiles ) - 1 ) % self -> scroll_area -> height_in_tiles == scrnmod (self -> vt_scroll_end )) {
322+ #if CIRCUITPY_TERMINALIO_VT100
323+ if (self -> vt_scroll_top != 0 || self -> vt_scroll_end != self -> scroll_area -> height_in_tiles ) {
324+ // Scroll range defined, manually move tiles to perform scroll
325+ self -> cursor_y = scrnmod (self -> vt_scroll_end );
326+
327+ for (int16_t irow = self -> vt_scroll_top ; irow < self -> vt_scroll_end ; irow ++ ) {
328+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
329+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , scrnmod (irow ), common_hal_displayio_tilegrid_get_tile (self -> scroll_area , icol , scrnmod (irow + 1 )));
330+ }
331+ }
332+ }
333+ #endif
334+ if (self -> vt_scroll_top == 0 && self -> vt_scroll_end == self -> scroll_area -> height_in_tiles ) {
335+ // Full screen scroll, just set new top_y pointer
336+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , (self -> cursor_y + self -> scroll_area -> height_in_tiles + 1 ) % self -> scroll_area -> height_in_tiles );
337+ }
338+ // clear the new row in case of scroll up
339+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
340+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
283341 }
284- common_hal_displayio_tilegrid_set_top_left ( self -> scroll_area , 0 , ( self -> cursor_y + self -> scroll_area -> height_in_tiles + 1 ) % self -> scroll_area -> height_in_tiles ) ;
342+ self -> cursor_x = 0 ;
285343 }
286344 start_y = self -> cursor_y ;
287345 }
0 commit comments