diff --git a/src/bin/termio.c b/src/bin/termio.c index 3c82b797..fb5d16cc 100644 --- a/src/bin/termio.c +++ b/src/bin/termio.c @@ -549,7 +549,9 @@ _should_inline(const Evas_Object *obj) return EINA_TRUE; } -/* Need to be freed */ +/* + * Returned string needs to be freed. + * Does not handle colors */ const char * termio_link_get(const Evas_Object *obj, Eina_Bool *from_escape_code) @@ -1341,6 +1343,31 @@ _cb_link_move(void *data, } } +static Evas_Object * +_color_tooltip_content(void *data, + Evas_Object *obj, + Evas_Object *_tt EINA_UNUSED) +{ + Termio *sd = data; + Evas_Object *o; + + o = evas_object_rectangle_add(evas_object_evas_get(obj)); + evas_object_size_hint_min_set(o, 80, 80); + evas_object_color_set(o, + sd->link.color.r, + sd->link.color.g, + sd->link.color.b, + sd->link.color.a); + return o; +} + +static void +_color_tooltip(Evas_Object *obj, + Termio *sd) +{ + elm_object_tooltip_content_cb_set(obj, _color_tooltip_content, sd, NULL); +} + static void _update_link(Termio *sd, Eina_Bool same_geom) { @@ -1353,7 +1380,7 @@ _update_link(Termio *sd, Eina_Bool same_geom) EINA_SAFETY_ON_NULL_RETURN(sd); obj = sd->self; - if (sd->link.id) + if (sd->link.id || sd->link.is_color) { same_geom = EINA_FALSE; } @@ -1376,7 +1403,7 @@ _update_link(Termio *sd, Eina_Bool same_geom) else evas_object_del(o); } - if (!sd->link.string) + if (!sd->link.string && !sd->link.is_color) return; popup_exists = main_term_popup_exists(sd->term); @@ -1422,9 +1449,16 @@ _update_link(Termio *sd, Eina_Bool same_geom) _cb_link_up, obj); evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE, _cb_link_move, obj); - if ((!popup_exists) && link_is_email(sd->link.string)) + if (!popup_exists) { - gravatar_tooltip(o, sd->config, sd->link.string); + if (link_is_email(sd->link.string)) + { + gravatar_tooltip(o, sd->config, sd->link.string); + } + if (sd->link.is_color) + { + _color_tooltip(o, sd); + } } } } @@ -1443,6 +1477,11 @@ termio_remove_links(Termio *sd) sd->link.y2 = -1; sd->link.suspend = 0; sd->link.id = 0; + sd->link.is_color = EINA_FALSE; + sd->link.color.r = 0; + sd->link.color.g = 0; + sd->link.color.b = 0; + sd->link.color.a = 0; _update_link(sd, same_geom); } @@ -2362,6 +2401,18 @@ _smart_mouseover_apply(Termio *sd) &x1, &y1, &x2, &y2); if (!s) { + uint8_t r = 0, g = 0, b = 0, a = 0; + /* TODO: boris: check config */ + if (termio_color_find(sd->self, sd->mouse.cx, sd->mouse.cy, + &x1, &y1, &x2, &y2, &r, &g, &b, &a)) + { + sd->link.is_color = EINA_TRUE; + sd->link.color.r = r; + sd->link.color.g = g; + sd->link.color.b = b; + sd->link.color.a = a; + goto found; + } termio_remove_links(sd); return; } @@ -2393,6 +2444,7 @@ _smart_mouseover_apply(Termio *sd) eina_stringshare_del(sd->link.string); sd->link.string = eina_stringshare_add(s); +found: if ((x1 == sd->link.x1) && (y1 == sd->link.y1) && (x2 == sd->link.x2) && (y2 == sd->link.y2)) same_geom = EINA_TRUE; diff --git a/src/bin/termiointernals.h b/src/bin/termiointernals.h index 59e4adc6..4c6196ed 100644 --- a/src/bin/termiointernals.h +++ b/src/bin/termiointernals.h @@ -34,9 +34,16 @@ struct _Termio struct { const char *string; int x1, y1, x2, y2; + Eina_Bool is_color; int suspend; uint16_t id; Eina_List *objs; + struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; + } color; struct { Evas_Object *dndobj; Evas_Coord x, y; diff --git a/src/bin/termiolink.c b/src/bin/termiolink.c index 42e5d9d4..b941ef88 100644 --- a/src/bin/termiolink.c +++ b/src/bin/termiolink.c @@ -625,3 +625,231 @@ end: ty_sb_free(&sb); return s; } + +static Eina_Bool +_is_authorized_in_color(const int codepoint) +{ + switch (codepoint) + { + case '#': EINA_FALLTHROUGH; + case '0': EINA_FALLTHROUGH; + case '1': EINA_FALLTHROUGH; + case '2': EINA_FALLTHROUGH; + case '3': EINA_FALLTHROUGH; + case '4': EINA_FALLTHROUGH; + case '5': EINA_FALLTHROUGH; + case '6': EINA_FALLTHROUGH; + case '7': EINA_FALLTHROUGH; + case '8': EINA_FALLTHROUGH; + case '9': EINA_FALLTHROUGH; + case 'a': EINA_FALLTHROUGH; + case 'A': EINA_FALLTHROUGH; + case 'b': EINA_FALLTHROUGH; + case 'B': EINA_FALLTHROUGH; + case 'c': EINA_FALLTHROUGH; + case 'C': EINA_FALLTHROUGH; + case 'd': EINA_FALLTHROUGH; + case 'D': EINA_FALLTHROUGH; + case 'e': EINA_FALLTHROUGH; + case 'E': EINA_FALLTHROUGH; + case 'f': EINA_FALLTHROUGH; + case 'F': + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_parse_hex(char c, uint8_t *v) +{ + if (c < '0') + return EINA_FALSE; + if (c <= '9') + { + *v = c - '0'; + return EINA_TRUE; + } + if (c < 'A') + return EINA_FALSE; + if (c <= 'F') + { + *v = 10 + c - 'A'; + return EINA_TRUE; + } + if (c < 'a') + return EINA_FALSE; + if (c <= 'f') + { + *v = 10 + c - 'a'; + return EINA_TRUE; + } + return EINA_FALSE; +} + +static Eina_Bool +_parse_2hex(char *s, uint8_t *v) +{ + uint8_t v0, v1; + if (!_parse_hex(s[0], &v0)) + return EINA_FALSE; + if (!_parse_hex(s[1], &v1)) + return EINA_FALSE; + *v = v0 << 4 | v1; + return EINA_TRUE; +} + +Eina_Bool +termio_color_find(const Evas_Object *obj, int cx, int cy, + int *x1r, int *y1r, int *x2r, int *y2r, + uint8_t *rp, uint8_t *gp, uint8_t *bp, uint8_t *ap) +{ + int x1, x2, y1, y2, w = 0, h = 0, sc; + //const char authorized[] = "#0123456789aAbBcCdDeEfFrghsoltun() ,+/"; + Eina_Bool goback = EINA_TRUE, + goforward = EINA_FALSE; + struct ty_sb sb = {.buf = NULL, .gap = 0, .len = 0, .alloc = 0}; + Termpty *ty = termio_pty_get(obj); + int res; + char txt[8]; + int txtlen = 0; + Eina_Bool found = EINA_FALSE; + int codepoint; + uint8_t r, g, b, a = 255; + + + EINA_SAFETY_ON_NULL_RETURN_VAL(ty, EINA_FALSE); + + x1 = x2 = cx; + y1 = y2 = cy; + termio_size_get(obj, &w, &h); + if ((w <= 0) || (h <= 0)) goto end; + + sc = termio_scroll_get(obj); + + termpty_backlog_lock(); + + y1 -= sc; + y2 -= sc; + + /* TODO: boris */ + res = _txt_at(ty, &x1, &y1, txt, &txtlen, &codepoint); + if ((res != 0) || (txtlen == 0)) + goto end; + if (!_is_authorized_in_color(codepoint)) + goto end; + res = ty_sb_add(&sb, txt, txtlen); + if (res < 0) goto end; + + while (goback) + { + int new_x1 = x1, new_y1 = y1; + + res = _txt_prev_at(ty, &new_x1, &new_y1, txt, &txtlen, &codepoint); + if ((res != 0) || (txtlen == 0)) + { + goback = EINA_FALSE; + goforward = EINA_TRUE; + break; + } + res = ty_sb_prepend(&sb, txt, txtlen); + if (res < 0) goto end; + if (!_is_authorized_in_color(codepoint)) + { + ty_sb_lskip(&sb, txtlen); + goback = EINA_FALSE; + goforward = EINA_TRUE; + break; + } + + x1 = new_x1; + y1 = new_y1; + } + + while (goforward) + { + int new_x2 = x2, new_y2 = y2; + + /* Check if the previous char is a delimiter */ + res = _txt_next_at(ty, &new_x2, &new_y2, txt, &txtlen, &codepoint); + if ((res != 0) || (txtlen == 0)) + { + goforward = EINA_FALSE; + break; + } + + if (!_is_authorized_in_color(codepoint)) + { + goforward = EINA_FALSE; + break; + } + + res = ty_sb_add(&sb, txt, txtlen); + if (res < 0) goto end; + + x2 = new_x2; + y2 = new_y2; + } + + if (!sb.len) + goto end; + + if (sb.buf[0] == '#') + { + ty_sb_lskip(&sb, 1); + switch (sb.len) + { + case 3: + if ((!_parse_hex(sb.buf[0], &r)) || + (!_parse_hex(sb.buf[1], &g)) || + (!_parse_hex(sb.buf[2], &b))) + goto end; + r <<= 4; + g <<= 4; + b <<= 4; + break; + case 4: + if ((!_parse_hex(sb.buf[0], &r)) || + (!_parse_hex(sb.buf[1], &g)) || + (!_parse_hex(sb.buf[2], &b)) || + (!_parse_hex(sb.buf[3], &a))) + goto end; + r <<= 4; + g <<= 4; + b <<= 4; + a <<= 4; + break; + case 6: + if ((!_parse_2hex(&sb.buf[0], &r)) || + (!_parse_2hex(&sb.buf[2], &g)) || + (!_parse_2hex(&sb.buf[4], &b))) + goto end; + break; + case 8: + if ((!_parse_2hex(&sb.buf[0], &r)) || + (!_parse_2hex(&sb.buf[2], &g)) || + (!_parse_2hex(&sb.buf[4], &b)) || + (!_parse_2hex(&sb.buf[6], &a))) + goto end; + break; + default: + goto end; + } + found = EINA_TRUE; + } + +end: + termpty_backlog_unlock(); + ty_sb_free(&sb); + if (found) + { + if (rp) *rp = r; + if (gp) *gp = g; + if (bp) *bp = b; + if (ap) *ap = a; + if (x1r) *x1r = x1; + if (y1r) *y1r = y1 + sc; + if (x2r) *x2r = x2; + if (y2r) *y2r = y2 + sc; + } + return found; +} diff --git a/src/bin/termiolink.h b/src/bin/termiolink.h index 72281193..3c0ed583 100644 --- a/src/bin/termiolink.h +++ b/src/bin/termiolink.h @@ -2,6 +2,10 @@ #define _TERMIO_LINK_H__ 1 char *termio_link_find(const Evas_Object *obj, int cx, int cy, int *x1r, int *y1r, int *x2r, int *y2r); +Eina_Bool +termio_color_find(const Evas_Object *obj, int cx, int cy, + int *x1r, int *y1r, int *x2r, int *y2r, + uint8_t *rp, uint8_t *gp, uint8_t *bp, uint8_t *ap); Eina_Bool link_is_protocol(const char *str); Eina_Bool link_is_file(const char *str); Eina_Bool link_is_url(const char *str);