link: display tooltip on colors like #ff00ff

This commit is contained in:
Boris Faure 2020-04-20 21:20:21 +02:00
parent f5fe32f70b
commit 127f0987ee
Signed by: borisfaure
GPG Key ID: 35C0410516166BE8
4 changed files with 296 additions and 5 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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);