From 89e314d5101ac17b55978fac296f1a5905251085 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 11 Mar 2022 20:19:48 +0100 Subject: [PATCH] [draw] Overloaded version draw functions. Functions with suffix _node instead of struct color_pair * take as parameter node_number. --- src/terminal/draw.c | 380 ++++++++++++++++++++++++++++++++++++++++++++ src/terminal/draw.h | 36 +++++ 2 files changed, 416 insertions(+) diff --git a/src/terminal/draw.c b/src/terminal/draw.c index 0828baf6..b6571a65 100644 --- a/src/terminal/draw.c +++ b/src/terminal/draw.c @@ -74,11 +74,46 @@ draw_border_cross(struct terminal *term, int x, int y, } else if (screen_char->data == border_trans[d][2 - (dir & 1)]) { screen_char->data = BORDER_SCROSS; } + screen_char->is_node = 0; set_term_color(screen_char, color, 0, get_opt_int_tree(term->spec, "colors", NULL)); } +void +draw_border_cross_node(struct terminal *term, int x, int y, + enum border_cross_direction dir, unsigned int node_number) +{ + static const unsigned char border_trans[2][4] = { + /* Used for BORDER_X_{RIGHT,LEFT}: */ + { BORDER_SVLINE, BORDER_SRTEE, BORDER_SLTEE }, + /* Used for BORDER_X_{DOWN,UP}: */ + { BORDER_SHLINE, BORDER_SDTEE, BORDER_SUTEE }, + }; + struct screen_char *screen_char = get_char(term, x, y); + unsigned int d; + + if (!screen_char) return; + if (!(screen_char->attr & SCREEN_ATTR_FRAME)) return; + + /* First check if there is already a horizontal/vertical line, so that + * we will have to replace with a T char. Example: if there is a '|' + * and the direction is right, replace with a '|-' T char. + * + * If this is not the case check if there is a T char and we are adding + * the direction so that we end up with a cross. Example : if there is + * a '|-' and the direction is left, replace with a '+' (cross) char. */ + d = dir>>1; + if (screen_char->data == border_trans[d][0]) { + screen_char->data = border_trans[d][1 + (dir & 1)]; + + } else if (screen_char->data == border_trans[d][2 - (dir & 1)]) { + screen_char->data = BORDER_SCROSS; + } + screen_char->c.node_number = node_number; + screen_char->is_node = 1; +} + void draw_border_char(struct terminal *term, int x, int y, border_char_T border, struct color_pair *color) @@ -89,11 +124,28 @@ draw_border_char(struct terminal *term, int x, int y, screen_char->data = (unsigned char) border; screen_char->attr = SCREEN_ATTR_FRAME; + screen_char->is_node = 0; set_term_color(screen_char, color, 0, get_opt_int_tree(term->spec, "colors", NULL)); set_screen_dirty(term->screen, y, y); } +void +draw_border_char_node(struct terminal *term, int x, int y, + border_char_T border, unsigned int node_number) +{ + struct screen_char *screen_char = get_char(term, x, y); + + if (!screen_char) return; + + screen_char->data = (unsigned char) border; + screen_char->attr = SCREEN_ATTR_FRAME; + screen_char->c.node_number = node_number; + screen_char->is_node = 1; + set_screen_dirty(term->screen, y, y); +} + + void draw_char_color(struct terminal *term, int x, int y, struct color_pair *color) { @@ -103,6 +155,19 @@ draw_char_color(struct terminal *term, int x, int y, struct color_pair *color) set_term_color(screen_char, color, 0, get_opt_int_tree(term->spec, "colors", NULL)); + screen_char->is_node = 0; + set_screen_dirty(term->screen, y, y); +} + +void +draw_char_color_node(struct terminal *term, int x, int y, unsigned int node_number) +{ + struct screen_char *screen_char = get_char(term, x, y); + + if (!screen_char) return; + + screen_char->c.node_number = node_number; + screen_char->is_node = 1; set_screen_dirty(term->screen, y, y); } @@ -259,6 +324,73 @@ draw_border(struct terminal *term, struct el_box *box, set_screen_dirty(term->screen, borderbox.y, borderbox.y + borderbox.height); } +void +draw_border_node(struct terminal *term, struct el_box *box, + unsigned int node_number, int width) +{ + static const border_char_T p1[] = { + BORDER_SULCORNER, + BORDER_SURCORNER, + BORDER_SDLCORNER, + BORDER_SDRCORNER, + BORDER_SVLINE, + BORDER_SHLINE, + }; + static const border_char_T p2[] = { + BORDER_DULCORNER, + BORDER_DURCORNER, + BORDER_DDLCORNER, + BORDER_DDRCORNER, + BORDER_DVLINE, + BORDER_DHLINE, + }; + const border_char_T *p = (width > 1) ? p2 : p1; + struct el_box borderbox; + + set_box(&borderbox, box->x - 1, box->y - 1, + box->width + 2, box->height + 2); + + if (borderbox.width > 2) { + struct el_box bbox; + + /* Horizontal top border */ + set_box(&bbox, box->x, borderbox.y, box->width, 1); + draw_box_node(term, &bbox, p[5], SCREEN_ATTR_FRAME, node_number); + + /* Horizontal bottom border */ + bbox.y += borderbox.height - 1; + draw_box_node(term, &bbox, p[5], SCREEN_ATTR_FRAME, node_number); + } + + if (borderbox.height > 2) { + struct el_box bbox; + + /* Vertical left border */ + set_box(&bbox, borderbox.x, box->y, 1, box->height); + draw_box_node(term, &bbox, p[4], SCREEN_ATTR_FRAME, node_number); + + /* Vertical right border */ + bbox.x += borderbox.width - 1; + draw_box_node(term, &bbox, p[4], SCREEN_ATTR_FRAME, node_number); + } + + if (borderbox.width > 1 && borderbox.height > 1) { + int right = borderbox.x + borderbox.width - 1; + int bottom = borderbox.y + borderbox.height - 1; + + /* Upper left corner */ + draw_border_char_node(term, borderbox.x, borderbox.y, p[0], node_number); + /* Upper right corner */ + draw_border_char_node(term, right, borderbox.y, p[1], node_number); + /* Lower left corner */ + draw_border_char_node(term, borderbox.x, bottom, p[2], node_number); + /* Lower right corner */ + draw_border_char_node(term, right, bottom, p[3], node_number); + } + + set_screen_dirty(term->screen, borderbox.y, borderbox.y + borderbox.height); +} + #ifdef CONFIG_UTF8 /** Checks cells left and right to the box for broken double-width chars. * Replace it with UCS_ORPHAN_CELL. @@ -351,12 +483,37 @@ draw_char(struct terminal *term, int x, int y, screen_char->data = data; screen_char->attr = attr; + screen_char->is_node = 0; set_term_color(screen_char, color, 0, get_opt_int_tree(term->spec, "colors", NULL)); set_screen_dirty(term->screen, y, y); } +#ifdef CONFIG_UTF8 +void +draw_char_node(struct terminal *term, int x, int y, + unicode_val_T data, int attr, + unsigned int node_number) +#else +void +draw_char_node(struct terminal *term, int x, int y, + unsigned char data, int attr, + unsigned int node_number) +#endif /* CONFIG_UTF8 */ +{ + struct screen_char *screen_char = get_char(term, x, y); + + if (!screen_char) return; + + screen_char->data = data; + screen_char->attr = attr; + screen_char->is_node = 1; + screen_char->c.node_number = node_number; + set_screen_dirty(term->screen, y, y); +} + + void draw_box(struct terminal *term, struct el_box *box, unsigned char data, int attr, @@ -378,6 +535,7 @@ draw_box(struct terminal *term, struct el_box *box, end->attr = attr; end->data = data; if (color) { + end->is_node = 0; set_term_color(end, color, 0, get_opt_int_tree(term->spec, "colors", NULL)); } else { @@ -400,6 +558,51 @@ draw_box(struct terminal *term, struct el_box *box, set_screen_dirty(term->screen, box->y, box->y + box->height); } + +void +draw_box_node(struct terminal *term, struct el_box *box, + unsigned char data, int attr, + unsigned int node_number) +{ + struct screen_char *line, *pos, *end; + int width, height; + + line = get_char(term, box->x, box->y); + if (!line) return; + + height = int_min(box->height, term->height - box->y); + width = int_min(box->width, term->width - box->x); + + if (height <= 0 || width <= 0) return; + + /* Compose off the ending screen position in the areas first line. */ + end = &line[width - 1]; + end->attr = attr; + end->data = data; + if (node_number) { + end->is_node = 1; + end->c.node_number = node_number; + } else { + clear_screen_char_color(end); + } + + /* Draw the first area line. */ + for (pos = line; pos < end; pos++) { + copy_screen_chars(pos, end, 1); + } + + /* Now make @end point to the last line */ + /* For the rest of the area use the first area line. */ + pos = line; + while (--height) { + pos += term->width; + copy_screen_chars(pos, line, width); + } + + set_screen_dirty(term->screen, box->y, box->y + box->height); +} + + void draw_shadow(struct terminal *term, struct el_box *box, struct color_pair *color, int width, int height) @@ -419,6 +622,26 @@ draw_shadow(struct terminal *term, struct el_box *box, draw_box(term, &dbox, ' ', 0, color); } +void +draw_shadow_node(struct terminal *term, struct el_box *box, + unsigned int node_number, int width, int height) +{ + struct el_box dbox; + + /* (horizontal) */ + set_box(&dbox, box->x + width, box->y + box->height, + box->width - width, height); + + draw_box_node(term, &dbox, ' ', 0, node_number); + + /* (vertical) */ + set_box(&dbox, box->x + box->width, box->y + height, + width, box->height); + + draw_box_node(term, &dbox, ' ', 0, node_number); +} + + #ifdef CONFIG_UTF8 static void draw_text_utf8(struct terminal *term, int x, int y, @@ -492,6 +715,79 @@ draw_text_utf8(struct terminal *term, int x, int y, set_screen_dirty(term->screen, y, y); } + +static void +draw_text_utf8_node(struct terminal *term, int x, int y, + const char *text2, int length, + int attr, unsigned int node_number) +{ + struct screen_char *start, *pos; + char *text = (char *)text2; + char *end = text + length; + unicode_val_T data; + + assert(text && length >= 0); + if_assert_failed return; + + if (length <= 0) return; + if (x >= term->width) return; + + data = utf8_to_unicode(&text, end); + if (data == UCS_NO_CHAR) return; + start = get_char(term, x, y); + if (node_number) { + start->attr = attr; + start->is_node = 1; + start->c.node_number = node_number; + } + + if (start->data == UCS_NO_CHAR && x - 1 > 0) + draw_char_data(term, x - 1, y, UCS_ORPHAN_CELL); + + pos = start; + + if (unicode_to_cell(data) == 2) { + /* Is there enough room for whole double-width char? */ + if (x + 1 < term->width) { + pos->data = data; + pos++; + x++; + + pos->data = UCS_NO_CHAR; + pos->attr = 0; + } else { + pos->data = UCS_ORPHAN_CELL; + } + } else { + pos->data = data; + } + pos++; + x++; + + for (; x < term->width; x++, pos++) { + data = utf8_to_unicode(&text, end); + if (data == UCS_NO_CHAR) break; + if (node_number) copy_screen_chars(pos, start, 1); + + if (unicode_to_cell(data) == 2) { + /* Is there enough room for whole double-width char? */ + if (x + 1 < term->width) { + pos->data = data; + + x++; + pos++; + pos->data = UCS_NO_CHAR; + pos->attr = 0; + } else { + pos->data = UCS_ORPHAN_CELL; + } + } else { + pos->data = data; + } + } + set_screen_dirty(term->screen, y, y); +} + #endif /* CONFIG_UTF8 */ void @@ -560,6 +856,73 @@ draw_text(struct terminal *term, int x, int y, set_screen_dirty(term->screen, y, y); } +void +draw_text_node(struct terminal *term, int x, int y, + const char *text, int length, + int attr, unsigned int node_number) +{ + int end_pos; + struct screen_char *pos, *end; + + assert(text && length >= 0); + if_assert_failed return; + + if (x >= term->width || y >= term->height) return; + +#ifdef CONFIG_UTF8 + if (term->utf8_cp) { + draw_text_utf8_node(term, x, y, text, length, attr, node_number); + return; + } +#endif /* CONFIG_UTF8 */ + + if (length <= 0) return; + pos = get_char(term, x, y); + if (!pos) return; + + end_pos = int_min(length, term->width - x) - 1; + +#ifdef CONFIG_DEBUG + /* Detect attempt to set @end to a point outside @text, + * it may occur in case of bad calculations. --Zas */ + if (end_pos < 0) { + INTERNAL("end_pos < 0 !!"); + end_pos = 0; + } else { + int textlen = strlen(text); + + if (end_pos >= textlen) { + INTERNAL("end_pos (%d) >= text length (%d) !!", end_pos, textlen); + end_pos = textlen - 1; + } + } +#endif + + end = &pos[int_max(0, end_pos)]; + + if (node_number) { + /* Use the last char as template. */ + end->attr = attr; + end->is_node = 1; + end->c.node_number = node_number; + + for (; pos < end && *text; text++, pos++) { + end->data = *text; + copy_screen_chars(pos, end, 1); + } + + end->data = *text; + + } else { + for (; pos <= end && *text; text++, pos++) { + pos->data = *text; + } + } + + set_screen_dirty(term->screen, y, y); +} + + void draw_dlg_text(struct dialog_data *dlg_data, int x, int y, const char *text, int length, @@ -577,6 +940,23 @@ draw_dlg_text(struct dialog_data *dlg_data, int x, int y, draw_text(term, x, y, text, length, attr, color); } +void +draw_dlg_text_node(struct dialog_data *dlg_data, int x, int y, + const char *text, int length, + int attr, unsigned int node_number) +{ + struct terminal *term = dlg_data->win->term; + struct el_box *box = &dlg_data->real_box; + + if (box->height) { + int y_max = box->y + box->height; + + y -= dlg_data->y; + if (y < box->y || y >= y_max) return; + } + draw_text_node(term, x, y, text, length, attr, node_number); +} + void set_cursor(struct terminal *term, int x, int y, int blockable) diff --git a/src/terminal/draw.h b/src/terminal/draw.h index 609567c2..b4a54a83 100644 --- a/src/terminal/draw.h +++ b/src/terminal/draw.h @@ -245,6 +245,8 @@ struct screen_char *get_char(struct terminal *, int x, int y); void draw_char_color(struct terminal *term, int x, int y, struct color_pair *color); +void draw_char_color_node(struct terminal *term, int x, int y, unsigned int node_number); + /** Sets the data of a screen position. */ #ifdef CONFIG_UTF8 void draw_char_data(struct terminal *term, int x, int y, unicode_val_T data); @@ -256,19 +258,34 @@ void draw_char_data(struct terminal *term, int x, int y, unsigned char data); void draw_border_char(struct terminal *term, int x, int y, border_char_T border, struct color_pair *color); +void draw_border_char_node(struct terminal *term, int x, int y, + border_char_T border, unsigned int node_number); + /** Sets the cross position of two borders. */ void draw_border_cross(struct terminal *, int x, int y, enum border_cross_direction, struct color_pair *color); +void draw_border_cross_node(struct terminal *, int x, int y, + enum border_cross_direction, unsigned int node_number); + /** Draws a char. */ #ifdef CONFIG_UTF8 void draw_char(struct terminal *term, int x, int y, unicode_val_T data, int attr, struct color_pair *color); + +void draw_char_node(struct terminal *term, int x, int y, + unicode_val_T data, int attr, + unsigned int node_number); #else void draw_char(struct terminal *term, int x, int y, unsigned char data, int attr, struct color_pair *color); + +void draw_char_node(struct terminal *term, int x, int y, + unsigned char data, int attr, + unsigned int node_number); + #endif /* CONFIG_UTF8 */ /** Draws area defined by @a box using the same colors and attributes. */ @@ -276,15 +293,25 @@ void draw_box(struct terminal *term, struct el_box *box, unsigned char data, int attr, struct color_pair *color); +void draw_box_node(struct terminal *term, struct el_box *box, + unsigned char data, int attr, + unsigned int node_number); + /** Draws a shadow of @a width and @a height with color @a color * around @a box. */ void draw_shadow(struct terminal *term, struct el_box *box, struct color_pair *color, int width, int height); +void draw_shadow_node(struct terminal *term, struct el_box *box, + unsigned int node_number, int width, int height); + /** Draw borders. */ void draw_border(struct terminal *term, struct el_box *box, struct color_pair *color, int width); +void draw_border_node(struct terminal *term, struct el_box *box, + unsigned int node_number, int width); + #ifdef CONFIG_UTF8 void fix_dwchar_around_box(struct terminal *term, struct el_box *box, int border, int shadow_width, int shadow_height); @@ -296,11 +323,20 @@ void draw_text(struct terminal *term, int x, int y, int attr, struct color_pair *color); +void draw_text_node(struct terminal *term, int x, int y, + const char *text, int length, + int attr, + unsigned int node_number); + /** Draws text for dialogs. */ void draw_dlg_text(struct dialog_data *dlg_data, int x, int y, const char *text, int length, int attr, struct color_pair *color); +void draw_dlg_text_node(struct dialog_data *dlg_data, int x, int y, + const char *text, int length, + int attr, unsigned int node_number); + /** Draws @a length chars from @a line on the screen. */ void draw_line(struct terminal *term, int x, int y, int length,