@@ -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+ int16_t vt_args [3 ] = {0 , 0 , 0 };
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 ;
@@ -188,9 +192,6 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
188192 if (vt_args [0 ] > 0 ) {
189193 vt_args [0 ]-- ;
190194 }
191- if (vt_args [1 ] == -1 ) {
192- vt_args [1 ] = 0 ;
193- }
194195 if (vt_args [1 ] > 0 ) {
195196 vt_args [1 ]-- ;
196197 }
@@ -200,7 +201,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
200201 if (vt_args [1 ] >= self -> scroll_area -> width_in_tiles ) {
201202 vt_args [1 ] = self -> scroll_area -> width_in_tiles - 1 ;
202203 }
203- vt_args [0 ] = (vt_args [0 ] + self -> scroll_area -> top_left_y ) % self -> scroll_area -> height_in_tiles ;
204+ vt_args [0 ] = SCRNMOD (vt_args [0 ]) ;
204205 self -> cursor_x = vt_args [1 ];
205206 self -> cursor_y = vt_args [0 ];
206207 start_y = self -> cursor_y ;
@@ -215,43 +216,58 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
215216 common_hal_displayio_palette_set_color (terminal_palette , 1 , 0xffffff );
216217 }
217218 }
219+ } else if (c == 'r' ) {
220+ if (vt_args [0 ] < vt_args [1 ] && vt_args [0 ] >= 1 && vt_args [1 ] <= self -> scroll_area -> height_in_tiles ) {
221+ self -> vt_scroll_top = vt_args [0 ] - 1 ;
222+ self -> vt_scroll_end = vt_args [1 ] - 1 ;
223+ } else {
224+ self -> vt_scroll_top = 0 ;
225+ self -> vt_scroll_end = self -> scroll_area -> height_in_tiles - 1 ;
226+ }
227+ self -> cursor_x = 0 ;
228+ self -> cursor_y = self -> scroll_area -> top_left_y % self -> scroll_area -> height_in_tiles ;
229+ start_y = self -> cursor_y ;
218230 #endif
219231 }
220232 i += j + 1 ;
221233 }
222234 #if CIRCUITPY_TERMINALIO_VT100
223235 } else if (i [0 ] == 'M' ) {
224- if (self -> cursor_y != self -> scroll_area -> top_left_y ) {
236+ if (self -> cursor_y != SCRNMOD ( self -> vt_scroll_top ) ) {
225237 if (self -> cursor_y > 0 ) {
226238 self -> cursor_y = self -> cursor_y - 1 ;
227239 } else {
228240 self -> cursor_y = self -> scroll_area -> height_in_tiles - 1 ;
229241 }
230242 } else {
231- if (self -> cursor_y > 0 ) {
232- common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> cursor_y - 1 );
243+ if (self -> vt_scroll_top != 0 || self -> vt_scroll_end != self -> scroll_area -> height_in_tiles ) {
244+ // Scroll range defined, manually move tiles to perform scroll
245+ for (int16_t irow = self -> vt_scroll_end - 1 ; irow >= self -> vt_scroll_top ; irow -- ) {
246+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
247+ 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 )));
248+ }
249+ }
250+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
251+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
252+ }
233253 } 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 );
254+ // Full screen scroll, just set new top_y pointer and clear row
255+ if (self -> cursor_y > 0 ) {
256+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> cursor_y - 1 );
257+ } else {
258+ common_hal_displayio_tilegrid_set_top_left (self -> scroll_area , 0 , self -> scroll_area -> height_in_tiles - 1 );
259+ }
260+ for (uint16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
261+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> scroll_area -> top_left_y , 0 );
262+ }
263+ self -> cursor_y = self -> scroll_area -> top_left_y ;
238264 }
239-
240265 self -> cursor_x = 0 ;
241- self -> cursor_y = self -> scroll_area -> top_left_y ;
242266 }
243267 start_y = self -> cursor_y ;
244268 i ++ ;
245269 } 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 );
251- }
252- self -> cursor_x = 0 ;
253- }
254- start_y = self -> cursor_y ;
270+ self -> cursor_y ++ ;
255271 i ++ ;
256272 #endif
257273 } else if (i [0 ] == ']' && c == ';' ) {
@@ -276,12 +292,28 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con
276292 self -> cursor_y %= self -> scroll_area -> height_in_tiles ;
277293 }
278294 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 );
295+ if (((self -> cursor_y + self -> scroll_area -> height_in_tiles ) - 1 ) % self -> scroll_area -> height_in_tiles == SCRNMOD (self -> vt_scroll_end )) {
296+ #if CIRCUITPY_TERMINALIO_VT100
297+ if (self -> vt_scroll_top != 0 || self -> vt_scroll_end != self -> scroll_area -> height_in_tiles ) {
298+ // Scroll range defined, manually move tiles to perform scroll
299+ self -> cursor_y = SCRNMOD (self -> vt_scroll_end );
300+
301+ for (int16_t irow = self -> vt_scroll_top ; irow < self -> vt_scroll_end ; irow ++ ) {
302+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
303+ 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 )));
304+ }
305+ }
306+ }
307+ #endif
308+ if (self -> vt_scroll_top == 0 && self -> vt_scroll_end == self -> scroll_area -> height_in_tiles ) {
309+ // Full screen scroll, just set new top_y pointer
310+ 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 );
311+ }
312+ // clear the new row in case of scroll up
313+ for (int16_t icol = 0 ; icol < self -> scroll_area -> width_in_tiles ; icol ++ ) {
314+ common_hal_displayio_tilegrid_set_tile (self -> scroll_area , icol , self -> cursor_y , 0 );
283315 }
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 ) ;
316+ self -> cursor_x = 0 ;
285317 }
286318 start_y = self -> cursor_y ;
287319 }
0 commit comments