billiob pushed a commit to branch master.

http://git.enlightenment.org/apps/terminology.git/commit/?id=127f0987eeaa8905aae3a71454a0e28c42503e53

commit 127f0987eeaa8905aae3a71454a0e28c42503e53
Author: Boris Faure <[email protected]>
Date:   Mon Apr 20 21:20:21 2020 +0200

    link: display tooltip on colors like #ff00ff
---
 src/bin/termio.c          |  62 ++++++++++++-
 src/bin/termiointernals.h |   7 ++
 src/bin/termiolink.c      | 228 ++++++++++++++++++++++++++++++++++++++++++++++
 src/bin/termiolink.h      |   4 +
 4 files changed, 296 insertions(+), 5 deletions(-)

diff --git a/src/bin/termio.c b/src/bin/termio.c
index 3c82b79..fb5d16c 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 59e4adc..4c6196e 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 42e5d9d..b941ef8 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 7228119..3c0ed58 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);

-- 


Reply via email to