From 8c5c62432a76879b0d09647830dab1a8f4d6c014 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 4 Mar 2025 15:08:54 -0500 Subject: [PATCH 1/7] Add VT100 ranged scroll --- shared-bindings/terminalio/Terminal.c | 2 + shared-module/terminalio/Terminal.c | 104 ++++++++++++++++++++------ shared-module/terminalio/Terminal.h | 2 + 3 files changed, 85 insertions(+), 23 deletions(-) diff --git a/shared-bindings/terminalio/Terminal.c b/shared-bindings/terminalio/Terminal.c index 5d79c88c60839..570449ad424a4 100644 --- a/shared-bindings/terminalio/Terminal.c +++ b/shared-bindings/terminalio/Terminal.c @@ -39,6 +39,8 @@ //| * ``ESC [ H`` - Move the cursor to 0,0. //| * ``ESC M`` - Move the cursor up one line, scrolling if necessary. //| * ``ESC D`` - Move the cursor down one line, scrolling if necessary. +//| * ``ESC [ r`` - Disable scrolling range (set to fullscreen). +//| * ``ESC [ nnnn ; mmmm r`` - Set scrolling range between rows nnnn and mmmm. //| * ``ESC [ ## m`` - Set the terminal display attributes. //| * ``ESC [ ## ; ## m`` - Set the terminal display attributes. //| * ``ESC [ ## ; ## ; ## m`` - Set the terminal display attributes. diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index d2cedf0661874..edbf2e2fc0e79 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -33,6 +33,8 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, self->status_x = 0; self->status_y = 0; self->first_row = 0; + self->vt_scroll_top = 0; + self->vt_scroll_end = self->scroll_area->height_in_tiles - 1; common_hal_displayio_tilegrid_set_all_tiles(self->scroll_area, 0); if (self->status_bar) { 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, } size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, const byte *data, size_t len, int *errcode) { + #define scrnmod(x) (((x) + (self->scroll_area->top_left_y)) % (self->scroll_area->height_in_tiles)) + // Make sure the terminal is initialized before we do anything with it. if (self->scroll_area == NULL) { return len; @@ -114,7 +118,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } } else if (c == 0x1b) { // Handle commands of the form [ESC]. where . is not yet known. - uint8_t vt_args[3] = {0, -1, -1}; + uint16_t vt_args[3] = {0, -1, -1}; uint8_t j = 1; #if CIRCUITPY_TERMINALIO_VT100 uint8_t n_args = 1; @@ -158,8 +162,8 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con #endif } else { if (c == 'K') { - uint8_t clr_start = self->cursor_x; - uint8_t clr_end = self->scroll_area->width_in_tiles; + int16_t clr_start = self->cursor_x; + int16_t clr_end = self->scroll_area->width_in_tiles; #if CIRCUITPY_TERMINALIO_VT100 if (vt_args[0] == 1) { clr_start = 0; @@ -200,7 +204,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con if (vt_args[1] >= self->scroll_area->width_in_tiles) { vt_args[1] = self->scroll_area->width_in_tiles - 1; } - vt_args[0] = (vt_args[0] + self->scroll_area->top_left_y) % self->scroll_area->height_in_tiles; + vt_args[0] = scrnmod(vt_args[0]); self->cursor_x = vt_args[1]; self->cursor_y = vt_args[0]; start_y = self->cursor_y; @@ -215,39 +219,77 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con common_hal_displayio_palette_set_color(terminal_palette, 1, 0xffffff); } } + } else if (c == 'r') { + if (vt_args[0] < vt_args[1] && vt_args[0] >= 1 && vt_args[1] <= self->scroll_area->height_in_tiles) { + self->vt_scroll_top = vt_args[0] - 1; + self->vt_scroll_end = vt_args[1] - 1; + } else { + self->vt_scroll_top = 0; + self->vt_scroll_end = self->scroll_area->height_in_tiles - 1; + } + self->cursor_x = 0; + self->cursor_y = self->scroll_area->top_left_y % self->scroll_area->height_in_tiles; + start_y = self->cursor_y; #endif } i += j + 1; } #if CIRCUITPY_TERMINALIO_VT100 } else if (i[0] == 'M') { - if (self->cursor_y != self->scroll_area->top_left_y) { + if (self->cursor_y != scrnmod(self->vt_scroll_top)) { if (self->cursor_y > 0) { self->cursor_y = self->cursor_y - 1; } else { self->cursor_y = self->scroll_area->height_in_tiles - 1; } } else { - if (self->cursor_y > 0) { - common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->cursor_y - 1); + if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) { + // Scroll range defined, manually move tiles to perform scroll + for (int16_t irow = self->vt_scroll_end - 1; irow >= self->vt_scroll_top; irow--) { + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + 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))); + } + } + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); + } } else { - common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->scroll_area->height_in_tiles - 1); - } - for (uint8_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->scroll_area->top_left_y, 0); + // Full screen scroll, just set new top_y pointer and clear row + if (self->cursor_y > 0) { + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->cursor_y - 1); + } else { + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, self->scroll_area->height_in_tiles - 1); + } + for (uint16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->scroll_area->top_left_y, 0); + } + self->cursor_y = self->scroll_area->top_left_y; } - self->cursor_x = 0; - self->cursor_y = self->scroll_area->top_left_y; } start_y = self->cursor_y; i++; } else if (i[0] == 'D') { - self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; - if (self->cursor_y == self->scroll_area->top_left_y) { - common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, (self->cursor_y + 1) % self->scroll_area->height_in_tiles); - for (uint8_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); + if (self->cursor_y != scrnmod(self->vt_scroll_end)) { + self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; + } else { + if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) { + // Scroll range defined, manually move tiles to perform scroll + for (int16_t irow = self->vt_scroll_top; irow < self->vt_scroll_end; irow++) { + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + 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))); + } + } + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); + } + } else { + // Full screen scroll, just set new top_y pointer and clear row + self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; + common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, (self->cursor_y + 1) % self->scroll_area->height_in_tiles); + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); + } } self->cursor_x = 0; } @@ -276,12 +318,28 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con self->cursor_y %= self->scroll_area->height_in_tiles; } if (self->cursor_y != start_y) { - // clear the new row in case of scroll up - if (self->cursor_y == self->scroll_area->top_left_y) { - for (uint16_t j = 0; j < self->scroll_area->width_in_tiles; j++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, j, self->cursor_y, 0); + if (((self->cursor_y + self->scroll_area->height_in_tiles) - 1) % self->scroll_area->height_in_tiles == scrnmod(self->vt_scroll_end)) { + #if CIRCUITPY_TERMINALIO_VT100 + if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) { + // Scroll range defined, manually move tiles to perform scroll + self->cursor_y = scrnmod(self->vt_scroll_end); + + for (int16_t irow = self->vt_scroll_top; irow < self->vt_scroll_end; irow++) { + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + 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))); + } + } + } + #endif + if (self->vt_scroll_top == 0 && self->vt_scroll_end == self->scroll_area->height_in_tiles) { + // Full screen scroll, just set new top_y pointer + 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); + } + // clear the new row in case of scroll up + for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { + common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); } - 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); + self->cursor_x = 0; } start_y = self->cursor_y; } diff --git a/shared-module/terminalio/Terminal.h b/shared-module/terminalio/Terminal.h index 17230a74066c1..d617f571aed7d 100644 --- a/shared-module/terminalio/Terminal.h +++ b/shared-module/terminalio/Terminal.h @@ -23,6 +23,8 @@ typedef struct { uint16_t status_x; uint16_t status_y; uint16_t first_row; + uint16_t vt_scroll_top; + uint16_t vt_scroll_end; uint16_t osc_command; bool in_osc_command; } terminalio_terminal_obj_t; From 98117645e13f938320ce828e9ac80e9099d5247e Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 4 Mar 2025 15:26:36 -0500 Subject: [PATCH 2/7] vt_args can be negative --- shared-module/terminalio/Terminal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index edbf2e2fc0e79..4dd3e1168c2c7 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -118,7 +118,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } } else if (c == 0x1b) { // Handle commands of the form [ESC]. where . is not yet known. - uint16_t vt_args[3] = {0, -1, -1}; + int16_t vt_args[3] = {0, -1, -1}; uint8_t j = 1; #if CIRCUITPY_TERMINALIO_VT100 uint8_t n_args = 1; From 2f26ca65d7f2392d8201b82ee2904a611d76e325 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Tue, 4 Mar 2025 20:20:55 -0500 Subject: [PATCH 3/7] Disable new VT100 features for two samd51 boards --- ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk | 1 + ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk | 1 + 2 files changed, 2 insertions(+) diff --git a/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk b/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk index a786b5ebc654a..a0f5ada80be5a 100644 --- a/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk +++ b/ports/atmel-samd/boards/openbook_m4/mpconfigboard.mk @@ -14,3 +14,4 @@ CIRCUITPY_KEYPAD = 1 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_JPEGIO = 0 CIRCUITPY_FLOPPYIO = 0 +CIRCUITPY_TERMINALIO_VT100 = 0 diff --git a/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk b/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk index 4b23566f71fd0..c3626ab98f3bb 100644 --- a/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk +++ b/ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk @@ -12,3 +12,4 @@ LONGINT_IMPL = MPZ CIRCUITPY_SPITARGET = 0 CIRCUITPY_SYNTHIO = 0 CIRCUITPY_JPEGIO = 0 +CIRCUITPY_TERMINALIO_VT100 = 0 From 2259731e2b5d4ed69946d33f44ed1e167fa40ad3 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Wed, 5 Mar 2025 07:59:37 -0500 Subject: [PATCH 4/7] down arrow code is redundant --- shared-module/terminalio/Terminal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 4dd3e1168c2c7..2de81e465f55b 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -118,7 +118,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } } else if (c == 0x1b) { // Handle commands of the form [ESC]. where . is not yet known. - int16_t vt_args[3] = {0, -1, -1}; + int16_t vt_args[3] = {0, 0, 0}; uint8_t j = 1; #if CIRCUITPY_TERMINALIO_VT100 uint8_t n_args = 1; @@ -192,9 +192,6 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con if (vt_args[0] > 0) { vt_args[0]--; } - if (vt_args[1] == -1) { - vt_args[1] = 0; - } if (vt_args[1] > 0) { vt_args[1]--; } @@ -270,6 +267,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con start_y = self->cursor_y; i++; } else if (i[0] == 'D') { +/* if (self->cursor_y != scrnmod(self->vt_scroll_end)) { self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; } else { @@ -294,6 +292,8 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con self->cursor_x = 0; } start_y = self->cursor_y; +*/ + self->cursor_y++; i++; #endif } else if (i[0] == ']' && c == ';') { From 1c643bd3e56b7ac76ddf8a398c9b125406d8ee44 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Wed, 5 Mar 2025 08:02:07 -0500 Subject: [PATCH 5/7] local pre-commit run.... --- shared-module/terminalio/Terminal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 2de81e465f55b..bb26220524a1c 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -292,7 +292,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con self->cursor_x = 0; } start_y = self->cursor_y; -*/ +*/ self->cursor_y++; i++; #endif From a52d35744d92428a82c67e0d81d61e567fc5a37f Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Wed, 5 Mar 2025 09:21:54 -0500 Subject: [PATCH 6/7] remove redundant code --- shared-module/terminalio/Terminal.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index bb26220524a1c..32fc33b4ebc01 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -267,32 +267,6 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con start_y = self->cursor_y; i++; } else if (i[0] == 'D') { -/* - if (self->cursor_y != scrnmod(self->vt_scroll_end)) { - self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; - } else { - if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) { - // Scroll range defined, manually move tiles to perform scroll - for (int16_t irow = self->vt_scroll_top; irow < self->vt_scroll_end; irow++) { - for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - 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))); - } - } - for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); - } - } else { - // Full screen scroll, just set new top_y pointer and clear row - self->cursor_y = (self->cursor_y + 1) % self->scroll_area->height_in_tiles; - common_hal_displayio_tilegrid_set_top_left(self->scroll_area, 0, (self->cursor_y + 1) % self->scroll_area->height_in_tiles); - for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - common_hal_displayio_tilegrid_set_tile(self->scroll_area, icol, self->cursor_y, 0); - } - } - self->cursor_x = 0; - } - start_y = self->cursor_y; -*/ self->cursor_y++; i++; #endif From f02a3dc850feb0aab7aa62e10a61ff4452bfa468 Mon Sep 17 00:00:00 2001 From: RetiredWizard Date: Wed, 5 Mar 2025 10:11:37 -0500 Subject: [PATCH 7/7] Circuitpython standard for function macros is upper case --- shared-module/terminalio/Terminal.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/shared-module/terminalio/Terminal.c b/shared-module/terminalio/Terminal.c index 32fc33b4ebc01..2828d0d3800c5 100644 --- a/shared-module/terminalio/Terminal.c +++ b/shared-module/terminalio/Terminal.c @@ -44,7 +44,7 @@ void common_hal_terminalio_terminal_construct(terminalio_terminal_obj_t *self, } size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, const byte *data, size_t len, int *errcode) { - #define scrnmod(x) (((x) + (self->scroll_area->top_left_y)) % (self->scroll_area->height_in_tiles)) + #define SCRNMOD(x) (((x) + (self->scroll_area->top_left_y)) % (self->scroll_area->height_in_tiles)) // Make sure the terminal is initialized before we do anything with it. if (self->scroll_area == NULL) { @@ -201,7 +201,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con if (vt_args[1] >= self->scroll_area->width_in_tiles) { vt_args[1] = self->scroll_area->width_in_tiles - 1; } - vt_args[0] = scrnmod(vt_args[0]); + vt_args[0] = SCRNMOD(vt_args[0]); self->cursor_x = vt_args[1]; self->cursor_y = vt_args[0]; start_y = self->cursor_y; @@ -233,7 +233,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con } #if CIRCUITPY_TERMINALIO_VT100 } else if (i[0] == 'M') { - if (self->cursor_y != scrnmod(self->vt_scroll_top)) { + if (self->cursor_y != SCRNMOD(self->vt_scroll_top)) { if (self->cursor_y > 0) { self->cursor_y = self->cursor_y - 1; } else { @@ -244,7 +244,7 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con // Scroll range defined, manually move tiles to perform scroll for (int16_t irow = self->vt_scroll_end - 1; irow >= self->vt_scroll_top; irow--) { for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - 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))); + 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))); } } for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { @@ -292,15 +292,15 @@ size_t common_hal_terminalio_terminal_write(terminalio_terminal_obj_t *self, con self->cursor_y %= self->scroll_area->height_in_tiles; } if (self->cursor_y != start_y) { - if (((self->cursor_y + self->scroll_area->height_in_tiles) - 1) % self->scroll_area->height_in_tiles == scrnmod(self->vt_scroll_end)) { + if (((self->cursor_y + self->scroll_area->height_in_tiles) - 1) % self->scroll_area->height_in_tiles == SCRNMOD(self->vt_scroll_end)) { #if CIRCUITPY_TERMINALIO_VT100 if (self->vt_scroll_top != 0 || self->vt_scroll_end != self->scroll_area->height_in_tiles) { // Scroll range defined, manually move tiles to perform scroll - self->cursor_y = scrnmod(self->vt_scroll_end); + self->cursor_y = SCRNMOD(self->vt_scroll_end); for (int16_t irow = self->vt_scroll_top; irow < self->vt_scroll_end; irow++) { for (int16_t icol = 0; icol < self->scroll_area->width_in_tiles; icol++) { - 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))); + 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))); } } }