highlight links on mouseover

+ related fixes
This commit is contained in:
Boris Faure 2018-10-13 19:15:57 +02:00
parent e3faaab83d
commit dc5c291bb9
8 changed files with 207 additions and 40 deletions

View File

@ -54,6 +54,7 @@ struct _Termio
char *string;
int x1, y1, x2, y2;
int suspend;
uint16_t id;
Eina_List *objs;
struct {
Evas_Object *dndobj;
@ -1389,8 +1390,133 @@ _remove_links(Termio *sd, Evas_Object *obj)
sd->link.y2 = -1;
sd->link.suspend = EINA_FALSE;
_update_link(obj, sd, same_link, same_geom);
sd->link.id = 0;
}
static void
_hyperlink_end(Termio *sd,
Term_Link *hl,
Evas_Object *o,
Eina_Bool add_tooltip)
{
Eina_Bool popup_exists;
sd->link.objs = eina_list_append(sd->link.objs, o);
elm_object_cursor_set(o, "hand2");
evas_object_show(o);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
_cb_link_down, sd->self);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_UP,
_cb_link_up, sd->self);
evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_MOVE,
_cb_link_move, sd->self);
popup_exists = main_term_popup_exists(sd->term);
if (!popup_exists && add_tooltip)
{
if (link_is_email(hl->url))
{
gravatar_tooltip(o, sd->config, hl->url);
}
/* display tooltip */
elm_object_tooltip_text_set(o, hl->url);
}
}
static void
_hyperlink_mouseover(Evas_Object *obj, Termio *sd,
uint16_t link_id)
{
Evas_Coord ox, oy, ow, oh;
Evas_Object *o;
int x, y;
Term_Link *hl;
EINA_SAFETY_ON_NULL_RETURN(sd);
/* If it's the same link, consider we already have the correct links
* displayed */
if (sd->link.id == link_id)
return;
if (sd->link.suspend)
return;
evas_object_geometry_get(obj, &ox, &oy, &ow, &oh);
EINA_LIST_FREE(sd->link.objs, o)
{
if (sd->link.down.dndobj == o)
{
sd->link.down.dndobjdel = EINA_TRUE;
evas_object_hide(o);
}
else
evas_object_del(o);
}
hl = &sd->pty->hl.links[link_id];
if (!hl->url)
return;
/* Scan the whole screen and display links as needed */
termpty_backlog_lock();
termpty_backscroll_adjust(sd->pty, &sd->scroll);
for (y = 0; y < sd->grid.h; y++)
{
ssize_t w = 0;
Termcell *cells;
int start_x = -1;
o = NULL;
cells = termpty_cellrow_get(sd->pty, y - sd->scroll, &w);
if (!cells)
continue;
for (x = 0; x < w; x++)
{
Termcell *c = cells + x;
if (term_link_eq(sd->pty, hl, c->att.link_id))
{
if (!o)
{
o = elm_layout_add(sd->win);
evas_object_smart_member_add(o, obj);
theme_apply(elm_layout_edje_get(o), sd->config,
"terminology/link");
evas_object_move(o,
ox + (x * sd->font.chw),
oy + (y * sd->font.chh));
start_x = x;
}
}
else
{
if (o)
{
evas_object_resize(o,
(x - start_x) * sd->font.chw,
sd->font.chh);
_hyperlink_end(sd, hl, o,
(y == sd->mouse.cy) &&
((start_x <= sd->mouse.cx) &&
(sd->mouse.cx <= x)));
o = NULL;
}
}
}
if (o)
{
evas_object_resize(o,
(x - start_x + 1) * sd->font.chw,
sd->font.chh);
_hyperlink_end(sd, hl, o,
(y == sd->mouse.cy) &&
((start_x <= sd->mouse.cx) &&
(sd->mouse.cx <= x)));
}
}
termpty_backlog_unlock();
}
/* }}} */
/* {{{ Blocks */
@ -3573,6 +3699,7 @@ _smart_mouseover_apply(Evas_Object *obj)
Eina_Bool same_link = EINA_FALSE, same_geom = EINA_FALSE;
Termio *sd = evas_object_smart_data_get(obj);
Config *config;
Termcell *cell = NULL;
EINA_SAFETY_ON_NULL_RETURN(sd);
config = sd->config;
@ -3584,6 +3711,18 @@ _smart_mouseover_apply(Evas_Object *obj)
_remove_links(sd, obj);
return;
}
cell = termpty_cell_get(sd->pty, sd->mouse.cy - sd->scroll, sd->mouse.cx);
if (!cell)
{
_remove_links(sd, obj);
return;
}
if (cell->att.link_id)
{
_hyperlink_mouseover(obj, sd, cell->att.link_id);
return;
}
s = termio_link_find(obj, sd->mouse.cx, sd->mouse.cy,
&x1, &y1, &x2, &y2);

View File

@ -85,7 +85,7 @@ _txt_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
cell = cells[*x];
}
if (cell.codepoint == 0)
if ((cell.codepoint == 0) || (cell.att.link_id))
goto empty;
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
@ -146,7 +146,7 @@ _txt_prev_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
cell = cells[*x];
}
if (cell.codepoint == 0)
if ((cell.codepoint == 0) || (cell.att.link_id))
goto empty;
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
@ -210,7 +210,7 @@ _txt_next_at(Termpty *ty, int *x, int *y, char *txt, int *txtlenp)
}
cell = cells[*x];
if (cell.codepoint == 0)
if ((cell.codepoint == 0) || (cell.att.link_id))
goto empty;
*txtlenp = codepoint_to_utf8(cell.codepoint, txt);
@ -235,7 +235,9 @@ termio_link_find(const Evas_Object *obj, int cx, int cy,
char *s = NULL;
char endmatch = 0;
int x1, x2, y1, y2, w = 0, h = 0, sc;
Eina_Bool goback = EINA_TRUE, goforward = EINA_FALSE, escaped = EINA_FALSE;
Eina_Bool goback = EINA_TRUE,
goforward = EINA_FALSE,
escaped = EINA_FALSE;
struct ty_sb sb = {.buf = NULL, .gap = 0, .len = 0, .alloc = 0};
Termpty *ty = termio_pty_get(obj);
int res;
@ -525,9 +527,9 @@ term_link_free(Termpty *ty, Term_Link *link)
return;
uint16_t id = (link - ty->hl.links);
free(link->key);
eina_stringshare_del(link->key);
link->key = NULL;
free(link->url);
eina_stringshare_del(link->url);
link->url = NULL;
/* Remove from bitmap */

View File

@ -817,7 +817,7 @@ termpty_free(Termpty *ty)
size_t i;
for (i = 0; i < ty->backsize; i++)
termpty_save_free(&ty->back[i]);
termpty_save_free(ty, &ty->back[i]);
free(ty->back);
}
free(ty->screen);
@ -962,7 +962,7 @@ _backlog_remove_latest_nolock(Termpty *ty)
ty->backlog_beacon.backlog_y = 0;
verify_beacon(ty, 0);
termpty_save_free(ts);
termpty_save_free(ty, ts);
}
@ -993,7 +993,7 @@ termpty_text_save_top(Termpty *ty, Termcell *cells, ssize_t w_max)
if (ts->w && ts->cells[ts->w - 1].att.autowrapped)
{
int old_len = ts->w;
termpty_save_expand(ts, cells, w);
termpty_save_expand(ty, ts, cells, w);
ty->backlog_beacon.screen_y += (ts->w + ty->w - 1) / ty->w
- (old_len + ty->w - 1) / ty->w;
verify_beacon(ty, 0);
@ -1003,7 +1003,7 @@ termpty_text_save_top(Termpty *ty, Termcell *cells, ssize_t w_max)
add_new_ts:
ts = BACKLOG_ROW_GET(ty, 0);
ts = termpty_save_new(ts, w);
ts = termpty_save_new(ty, ts, w);
if (!ts)
return;
TERMPTY_CELL_COPY(ty, cells, ts->cells, w);
@ -1485,7 +1485,7 @@ termpty_backlog_size_set(Termpty *ty, size_t size)
size_t i;
for (i = 0; i < ty->backsize; i++)
termpty_save_free(&ty->back[i]);
termpty_save_free(ty, &ty->back[i]);
free(ty->back);
}
if (size > 0)
@ -1677,6 +1677,9 @@ termpty_cells_att_fill_preserve_colors(Termpty *ty, Termcell *cells,
int i;
Termcell local = { .codepoint = codepoint, .att = ty->termstate.att};
if (EINA_UNLIKELY(local.att.link_id))
term_link_refcount_inc(ty, local.att.link_id, count);
for (i = 0; i < count; i++)
{
Termatt att = cells[i].att;
@ -1696,8 +1699,6 @@ termpty_cells_att_fill_preserve_colors(Termpty *ty, Termcell *cells,
cells[i].att.bgintense = att.bgintense;
}
}
if (EINA_UNLIKELY(local.att.link_id))
term_link_refcount_inc(ty, local.att.link_id, count);
}
@ -1708,6 +1709,9 @@ termpty_cell_codepoint_att_fill(Termpty *ty, Eina_Unicode codepoint,
Termcell local = { .codepoint = codepoint, .att = att };
int i;
if (EINA_UNLIKELY(local.att.link_id))
term_link_refcount_inc(ty, local.att.link_id, n);
for (i = 0; i < n; i++)
{
HANDLE_BLOCK_CODEPOINT_OVERWRITE(ty, dst[i].codepoint, codepoint);
@ -1716,8 +1720,6 @@ termpty_cell_codepoint_att_fill(Termpty *ty, Eina_Unicode codepoint,
dst[i] = local;
}
if (EINA_UNLIKELY(local.att.link_id))
term_link_refcount_inc(ty, local.att.link_id, n);
}
Config *

View File

@ -311,10 +311,10 @@ do { \
HANDLE_BLOCK_CODEPOINT_OVERWRITE(Tpty, \
(Tdst)[__i].codepoint, \
(Tsrc)[__i].codepoint); \
if (EINA_UNLIKELY((Tsrc)[__i].att.link_id)) \
term_link_refcount_dec(ty, (Tsrc)[__i].att.link_id, 1); \
if (EINA_UNLIKELY((Tdst)[__i].att.link_id)) \
term_link_refcount_inc(ty, (Tdst)[__i].att.link_id, 1); \
term_link_refcount_dec(ty, (Tdst)[__i].att.link_id, 1); \
if (EINA_UNLIKELY((Tsrc)[__i].att.link_id)) \
term_link_refcount_inc(ty, (Tsrc)[__i].att.link_id, 1); \
} \
memcpy(Tdst, Tsrc, N * sizeof(Termcell)); \
} while (0)
@ -340,6 +340,25 @@ term_link_refcount_dec(Termpty *ty, uint16_t link_id, uint16_t count)
term_link_free(ty, link);
}
static inline Eina_Bool
term_link_eq(Termpty *ty, Term_Link *hl, uint16_t link_id)
{
Term_Link *hl2;
uint16_t hl_id;
if (link_id == 0)
return EINA_FALSE;
hl_id = hl - ty->hl.links;
if (hl_id == link_id)
return EINA_TRUE;
hl2 = &ty->hl.links[link_id];
if (!hl->key || !hl2->key ||
strcmp(hl->key, hl2->key) != 0)
return EINA_FALSE;
return EINA_TRUE;
}
static inline void
termpty_cell_fill(Termpty *ty, Termcell *src, Termcell *dst, int n)
{
@ -356,7 +375,7 @@ termpty_cell_fill(Termpty *ty, Termcell *src, Termcell *dst, int n)
dst[i] = src[0];
}
if (src[0].att.link_id)
term_link_refcount_inc(ty, dst[i].att.link_id, n);
term_link_refcount_inc(ty, src[0].att.link_id, n);
}
else
{

View File

@ -1852,7 +1852,7 @@ _handle_hyperlink(Termpty *ty,
s += 3;
len -= 3;
key = strndup(s, end_param - s);
key = eina_stringshare_add_length(s, end_param - s);
}
len -= end_param - s;
s = end_param;
@ -1868,7 +1868,7 @@ _handle_hyperlink(Termpty *ty,
s++;
len--;
url = strndup(s, len);
url = eina_stringshare_add_length(s, len);
if (!url)
goto end;
@ -1885,8 +1885,8 @@ _handle_hyperlink(Termpty *ty,
end:
term_link_free(ty, hl);
free(url);
free(key);
eina_stringshare_del(url);
eina_stringshare_del(key);
}
static void

View File

@ -319,7 +319,7 @@ termpty_clear_backlog(Termpty *ty)
{
size_t i;
for (i = 0; i < ty->backsize; i++)
termpty_save_free(&ty->back[i]);
termpty_save_free(ty, &ty->back[i]);
free(ty->back);
ty->back = NULL;
}
@ -421,7 +421,6 @@ termpty_reset_att(Termatt *att)
att->framed = 0;
att->encircled = 0;
att->overlined = 0;
att->link_id = 0;
}
void
@ -442,6 +441,7 @@ termpty_soft_reset_state(Termpty *ty)
ty->termstate.had_cr_y = 0;
ty->termstate.restrict_cursor = 0;
termpty_reset_att(&(ty->termstate.att));
ty->termstate.att.link_id = 0;
ty->termstate.charset = 0;
ty->termstate.charsetch = 'B';
ty->termstate.chset[0] = 'B';

View File

@ -3,11 +3,6 @@
#include "termpty.h"
#include "termptysave.h"
static void
_ts_free(void *ptr)
{
free(ptr);
}
static int ts_comp = 0;
static int ts_uncomp = 0;
@ -38,9 +33,9 @@ termpty_save_extract(Termsave *ts)
}
Termsave *
termpty_save_new(Termsave *ts, int w)
termpty_save_new(Termpty *ty, Termsave *ts, int w)
{
termpty_save_free(ts);
termpty_save_free(ty, ts);
Termcell *cells = calloc(1, w * sizeof(Termcell));
if (!cells ) return NULL;
@ -50,7 +45,7 @@ termpty_save_new(Termsave *ts, int w)
}
Termsave *
termpty_save_expand(Termsave *ts, Termcell *cells, size_t delta)
termpty_save_expand(Termpty *ty, Termsave *ts, Termcell *cells, size_t delta)
{
Termcell *newcells;
@ -58,20 +53,29 @@ termpty_save_expand(Termsave *ts, Termcell *cells, size_t delta)
if (!newcells)
return NULL;
memcpy(&newcells[ts->w], cells, delta * sizeof(Termcell));
memset(newcells + ts->w,
0, delta * sizeof(Termcell));
TERMPTY_CELL_COPY(ty, cells, &newcells[ts->w], (int)delta);
ts->w += delta;
ts->cells = newcells;
return ts;
}
void
termpty_save_free(Termsave *ts)
termpty_save_free(Termpty *ty, Termsave *ts)
{
unsigned int i;
if (!ts) return;
if (ts->comp) ts_comp--;
else ts_uncomp--;
ts_freeops++;
_ts_free(ts->cells);
for (i = 0; i < ts->w; i++)
{
if (EINA_UNLIKELY(ts->cells[i].att.link_id))
term_link_refcount_dec(ty, ts->cells[i].att.link_id, 1);
}
free(ts->cells);
ts->cells = NULL;
ts->w = 0;
}

View File

@ -4,8 +4,9 @@
void termpty_save_register(Termpty *ty);
void termpty_save_unregister(Termpty *ty);
Termsave *termpty_save_extract(Termsave *ts);
Termsave *termpty_save_new(Termsave *ts, int w);
void termpty_save_free(Termsave *ts);
Termsave *termpty_save_expand(Termsave *ts, Termcell *cells, size_t delta);
Termsave *termpty_save_new(Termpty *ty, Termsave *ts, int w);
void termpty_save_free(Termpty *ty, Termsave *ts);
Termsave *termpty_save_expand(Termpty *ty, Termsave *ts,
Termcell *cells, size_t delta);
#endif