efl/src/lib/edje/edje_entry.c

5162 lines
158 KiB
C
Raw Normal View History

#include "edje_private.h"
#ifdef HAVE_ECORE_IMF
static Eina_Bool _edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
static void _edje_entry_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
static void _edje_entry_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
static void _edje_entry_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx, void *event);
static void _edje_entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx, void *event_info);
static Eina_Bool _edje_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Context *ctx, char **text);
#endif
typedef struct _Entry Entry;
typedef struct _Sel Sel;
typedef struct _Anchor Anchor;
typedef struct _Item_Obj Item_Obj;
static void _edje_entry_imf_cursor_location_set(Entry *en);
static void _edje_entry_imf_cursor_info_set(Entry *en);
static void _range_del_emit(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en);
static void _text_filter_format_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c, const char *text);
static void _free_entry_change_info(void *_info);
struct _Entry
{
Edje_Real_Part *rp;
Edje *ed;
Evas_Coord ox, oy;
Evas_Object *cursor_bg;
Evas_Object *cursor_fg, *cursor_fg2;
/* CHANGE EDJE_ENTRY_NUM_CURSOR_OBJS IF YOU ADD MORE OBJECTS HERE */
Evas_Textblock_Cursor *cursor;
Evas_Textblock_Cursor *sel_start, *sel_end;
Evas_Textblock_Cursor *cursor_user, *cursor_user_extra;
Evas_Textblock_Cursor *preedit_start, *preedit_end;
Ecore_Timer *pw_timer;
Eina_List *sel;
Eina_List *anchors;
Eina_List *anchorlist;
Eina_List *itemlist;
Eina_List *seq;
Item_Obj *item_objs;
char *selection;
Edje_Input_Panel_Lang input_panel_lang;
Eina_Bool composing : 1;
Eina_Bool selecting : 1;
Eina_Bool have_selection : 1;
Eina_Bool select_allow : 1;
Eina_Bool select_mod_start : 1;
Eina_Bool select_mod_end : 1;
Eina_Bool had_sel : 1;
Eina_Bool input_panel_enable : 1;
Eina_Bool prediction_allow : 1;
Eina_Bool anchors_updated : 1;
Eina_Bool have_link_pressed : 1;
#ifdef HAVE_ECORE_IMF
Eina_Bool have_preedit : 1;
Eina_Bool commit_cancel : 1; // For skipping useless commit
Ecore_IMF_Context *imf_context;
#endif
};
struct _Sel
{
Evas_Textblock_Rectangle rect;
Evas_Object *obj_fg, *obj_bg, *obj, *sobj;
};
struct _Anchor
{
Entry *en;
char *name;
Evas_Textblock_Cursor *start, *end;
Eina_List *sel;
Eina_Bool item : 1;
};
struct _Item_Obj
{
EINA_INLIST;
Anchor *an;
char *name;
Evas_Object *obj;
};
#ifdef HAVE_ECORE_IMF
static void
_preedit_clear(Entry *en)
{
if (en->preedit_start)
{
evas_textblock_cursor_free(en->preedit_start);
en->preedit_start = NULL;
}
if (en->preedit_end)
{
evas_textblock_cursor_free(en->preedit_end);
en->preedit_end = NULL;
}
en->have_preedit = EINA_FALSE;
}
static void
_preedit_del(Entry *en)
{
if (!en || !en->have_preedit) return;
if (!en->preedit_start || !en->preedit_end) return;
if (!evas_textblock_cursor_compare(en->preedit_start, en->preedit_end)) return;
/* delete the preedit characters */
evas_textblock_cursor_range_delete(en->preedit_start, en->preedit_end);
}
static void
_edje_entry_focus_in_cb(void *data, Evas_Object *o, const char *emission, const char *source EINA_UNUSED)
{
Efl_Input_Device *seat;
const char *seat_name;
2009-08-24 10:20:33 -07:00
Edje_Real_Part *rp;
Entry *en;
Edje *ed;
2009-08-24 10:20:33 -07:00
rp = data;
if ((!rp) || (rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
if (!rp->typedata.text->entry_data) return;
ed = _edje_fetch(o);
if (!ed) return;
en = rp->typedata.text->entry_data;
if (!en || !en->imf_context) return;
seat_name = emission + sizeof("focus,part,in,") - 1;
seat = _edje_seat_get(ed, seat_name);
if (efl_canvas_object_seat_focus_check(ed->obj, seat))
{
ecore_imf_context_focus_in(en->imf_context);
_edje_entry_imf_cursor_info_set(en);
}
}
static void
_edje_entry_focus_out_cb(void *data, Evas_Object *o EINA_UNUSED, const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
{
2009-08-24 10:20:33 -07:00
Edje_Real_Part *rp;
Entry *en;
rp = data;
if ((!rp) || (rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
if (!rp->typedata.text->entry_data) return;
en = rp->typedata.text->entry_data;
if (!en || !en->imf_context) return;
ecore_imf_context_reset(en->imf_context);
ecore_imf_context_focus_out(en->imf_context);
}
#endif
static void
_edje_focus_in(Edje *ed, Efl_Input_Device *seat)
{
#ifdef HAVE_ECORE_IMF
Edje_Real_Part *rp;
Entry *en;
#endif
_edje_seat_emit(ed, seat, "focus,in", "");
#ifdef HAVE_ECORE_IMF
rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
if (!rp) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
return;
if (!en->imf_context) return;
ecore_imf_context_focus_in(en->imf_context);
_edje_entry_imf_cursor_info_set(en);
#endif
}
static void
_edje_focus_in_cb(void *data, const Efl_Event *event)
{
Efl_Input_Focus *ev = event->info;
_edje_focus_in(data, efl_input_device_get(ev));
}
static void
_edje_focus_out(Edje *ed, Efl_Input_Device *seat)
{
#ifdef HAVE_ECORE_IMF
Edje_Real_Part *rp;
Entry *en;
#endif
_edje_seat_emit(ed, seat, "focus,out", "");
#ifdef HAVE_ECORE_IMF
rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
if (!rp) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
return;
if (!en->imf_context) return;
ecore_imf_context_reset(en->imf_context);
ecore_imf_context_focus_out(en->imf_context);
#endif
}
static void
_edje_focus_out_cb(void *data, const Efl_Event *event)
{
Efl_Input_Focus *ev = event->info;
_edje_focus_out(data, efl_input_device_get(ev));
}
static Edje_Entry_Change_Info *
_text_filter_markup_prepend_internal(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
char *text,
const char *fmtpre, const char *fmtpost,
Eina_Bool clearsel, Eina_Bool changeinfo)
{
Edje_Markup_Filter_Callback *cb;
Eina_List *l;
Eina_Bool have_sel = EINA_FALSE;
if ((clearsel) && (en->have_selection))
{
_range_del_emit(ed, en->cursor, en->rp->object, en);
have_sel = EINA_TRUE;
}
EINA_LIST_FOREACH(ed->markup_filter_callbacks, l, cb)
{
if (!strcmp(cb->part, en->rp->part->name))
{
cb->func(cb->data, ed->obj, cb->part, &text);
if (!text) break;
}
}
#ifdef HAVE_ECORE_IMF
// For skipping useless commit
if (en->have_preedit && (!text || !strcmp(text, "")))
en->commit_cancel = EINA_TRUE;
else
en->commit_cancel = EINA_FALSE;
#endif
if (text)
{
Edje_Entry_Change_Info *info = NULL;
2013-04-10 20:30:04 -07:00
if (changeinfo)
{
info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
}
else
{
info->insert = EINA_TRUE;
info->change.insert.content = eina_stringshare_add(text);
2013-04-10 20:30:04 -07:00
info->change.insert.plain_length =
eina_unicode_utf8_get_len(info->change.insert.content);
}
}
if (info)
{
if (have_sel)
{
info->merge = EINA_TRUE;
}
info->change.insert.pos =
evas_textblock_cursor_pos_get(en->cursor);
}
if (fmtpre) _text_filter_format_prepend(ed, en, en->cursor, fmtpre);
evas_object_textblock_text_markup_prepend(c, text);
free(text);
if (fmtpost) _text_filter_format_prepend(ed, en, en->cursor, fmtpost);
return info;
}
return NULL;
}
static Edje_Entry_Change_Info *
2013-04-10 20:30:04 -07:00
_text_filter_text_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
const char *text,
const char *fmtpre, const char *fmtpost,
Eina_Bool clearsel, Eina_Bool changeinfo)
{
char *text2 = NULL;
Edje_Text_Insert_Filter_Callback *cb;
Eina_List *l;
EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
if ((clearsel) && (en->have_selection))
{
_range_del_emit(ed, en->cursor, en->rp->object, en);
}
text2 = strdup(text);
EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
{
if (!strcmp(cb->part, en->rp->part->name))
{
cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_TEXT, &text2);
if (!text2) break;
}
}
if (text2)
{
char *markup_text;
Edje_Entry_Change_Info *info = NULL;
2013-04-10 20:30:04 -07:00
markup_text = evas_textblock_text_utf8_to_markup(NULL, text2);
free(text2);
if (markup_text)
info = _text_filter_markup_prepend_internal(ed, en, c, markup_text,
fmtpre, fmtpost,
clearsel, changeinfo);
return info;
}
return NULL;
}
static void
_text_filter_format_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c, const char *text)
{
char *text2;
Edje_Text_Insert_Filter_Callback *cb;
Eina_List *l;
EINA_SAFETY_ON_NULL_RETURN(text);
text2 = strdup(text);
EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
{
if (!strcmp(cb->part, en->rp->part->name))
{
cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_FORMAT, &text2);
if (!text2) break;
}
}
if (text2)
{
char *s, *markup_text;
size_t size;
s = text2;
if (*s == '+')
{
s++;
while (*s == ' ')
s++;
if (!*s)
{
free(text2);
return;
}
size = strlen(s);
markup_text = (char *)malloc(size + 3);
if (markup_text)
{
*(markup_text) = '<';
memcpy((markup_text + 1), s, size);
*(markup_text + size + 1) = '>';
*(markup_text + size + 2) = '\0';
}
}
else if (s[0] == '-')
{
s++;
while (*s == ' ')
s++;
if (!*s)
{
free(text2);
return;
}
size = strlen(s);
markup_text = (char *)malloc(size + 4);
if (markup_text)
{
*(markup_text) = '<';
*(markup_text + 1) = '/';
memcpy((markup_text + 2), s, size);
*(markup_text + size + 2) = '>';
*(markup_text + size + 3) = '\0';
}
}
else
{
size = strlen(s);
markup_text = (char *)malloc(size + 4);
if (markup_text)
{
*(markup_text) = '<';
memcpy((markup_text + 1), s, size);
*(markup_text + size + 1) = '/';
*(markup_text + size + 2) = '>';
*(markup_text + size + 3) = '\0';
}
}
free(text2);
if (markup_text)
_text_filter_markup_prepend_internal(ed, en, c, markup_text,
NULL, NULL,
EINA_FALSE, EINA_FALSE);
}
}
static Edje_Entry_Change_Info *
_text_filter_markup_prepend(Edje *ed, Entry *en, Evas_Textblock_Cursor *c,
const char *text,
const char *fmtpre, const char *fmtpost,
Eina_Bool clearsel, Eina_Bool changeinfo)
{
char *text2;
Edje_Text_Insert_Filter_Callback *cb;
Eina_List *l;
EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
if ((clearsel) && (en->have_selection))
{
_range_del_emit(ed, en->cursor, en->rp->object, en);
}
text2 = strdup(text);
EINA_LIST_FOREACH(ed->text_insert_filter_callbacks, l, cb)
{
if (!strcmp(cb->part, en->rp->part->name))
{
cb->func(cb->data, ed->obj, cb->part, EDJE_TEXT_FILTER_MARKUP, &text2);
if (!text2) break;
}
}
if (text2)
{
Edje_Entry_Change_Info *info;
2013-04-10 20:30:04 -07:00
info = _text_filter_markup_prepend_internal(ed, en, c, text2,
fmtpre, fmtpost,
clearsel, changeinfo);
return info;
}
return NULL;
}
static void
_curs_update_from_curs(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED, Entry *en, Evas_Coord *cx, Evas_Coord *cy)
{
Evas_Coord cw, ch;
Evas_Textblock_Cursor_Type cur_type;
if (c != en->cursor) return;
switch (en->rp->part->cursor_mode)
{
case EDJE_ENTRY_CURSOR_MODE_BEFORE:
cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
break;
case EDJE_ENTRY_CURSOR_MODE_UNDER:
/* no break for a reason */
default:
cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
}
evas_textblock_cursor_geometry_get(c, cx, cy, &cw, &ch, NULL, cur_type);
*cx += (cw / 2);
*cy += (ch / 2);
}
static int
_curs_line_last_get(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en EINA_UNUSED)
{
Evas_Textblock_Cursor *cc;
int ln;
cc = evas_object_textblock_cursor_new(o);
evas_textblock_cursor_paragraph_last(cc);
ln = evas_textblock_cursor_line_geometry_get(cc, NULL, NULL, NULL, NULL);
evas_textblock_cursor_free(cc);
return ln;
}
static void
_curs_lin_start(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
Entry *en EINA_UNUSED)
{
evas_textblock_cursor_line_char_first(c);
}
static void
_curs_lin_end(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
Entry *en EINA_UNUSED)
{
evas_textblock_cursor_line_char_last(c);
}
static void
_curs_start(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED,
Entry *en EINA_UNUSED)
{
evas_textblock_cursor_paragraph_first(c);
}
static void
_curs_end(Evas_Textblock_Cursor *c, Evas_Object *o EINA_UNUSED, Entry *en EINA_UNUSED)
{
evas_textblock_cursor_paragraph_last(c);
}
static Eina_Bool
_curs_jump_line(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int ln)
{
Evas_Coord cx, cy;
Evas_Coord lx, ly, lw, lh;
int last = _curs_line_last_get(c, o, en);
if (ln < 0) return EINA_FALSE;
if (ln > last) return EINA_FALSE;
_curs_update_from_curs(c, o, en, &cx, &cy);
if (!evas_object_textblock_line_number_geometry_get(o, ln, &lx, &ly, &lw, &lh))
return EINA_FALSE;
if (evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
return EINA_TRUE;
evas_textblock_cursor_line_set(c, ln);
if (cx < (lx + (lw / 2)))
{
if (ln == last) _curs_end(c, o, en);
_curs_lin_start(c, o, en);
}
else
{
if (ln == last)
_curs_end(c, o, en);
else
_curs_lin_end(c, o, en);
}
return EINA_TRUE;
}
static Eina_Bool
_curs_jump_line_by(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int by)
{
int ln;
ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL) + by;
return _curs_jump_line(c, o, en, ln);
}
static Eina_Bool
_curs_up(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
return _curs_jump_line_by(c, o, en, -1);
}
static Eina_Bool
_curs_down(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
return _curs_jump_line_by(c, o, en, 1);
}
static void
_sel_start(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
if (en->sel_start) return;
en->sel_start = evas_object_textblock_cursor_new(o);
evas_textblock_cursor_copy(c, en->sel_start);
en->sel_end = evas_object_textblock_cursor_new(o);
evas_textblock_cursor_copy(c, en->sel_end);
en->have_selection = EINA_FALSE;
2008-11-18 18:14:50 -08:00
if (en->selection)
{
free(en->selection);
en->selection = NULL;
2008-11-18 18:14:50 -08:00
}
}
static void
2013-04-10 20:30:04 -07:00
_sel_enable(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED,
Evas_Object *o EINA_UNUSED, Entry *en)
{
if (en->have_selection) return;
en->have_selection = EINA_TRUE;
2008-11-18 18:14:50 -08:00
if (en->selection)
{
free(en->selection);
en->selection = NULL;
2008-11-18 18:14:50 -08:00
}
_edje_entry_imf_context_reset(en->rp);
_edje_emit(ed, "selection,start", en->rp->part->name);
}
static void
_emit_sel_state(Edje *ed, Entry *en)
{
if (!evas_textblock_cursor_compare(en->sel_start, en->sel_end))
{
_edje_emit(ed, "selection,reset", en->rp->part->name);
}
else
{
_edje_emit(ed, "selection,changed", en->rp->part->name);
}
}
static void
_sel_extend(Edje *ed, Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
if (!en->sel_end) return;
_sel_enable(ed, c, o, en);
if (!evas_textblock_cursor_compare(c, en->sel_end)) return;
evas_textblock_cursor_copy(c, en->sel_end);
_edje_entry_imf_cursor_info_set(en);
2008-11-18 18:14:50 -08:00
if (en->selection)
{
free(en->selection);
en->selection = NULL;
2008-11-18 18:14:50 -08:00
}
_emit_sel_state(ed, en);
}
static void
_sel_preextend(Edje *ed, Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
if (!en->sel_end) return;
_sel_enable(ed, c, o, en);
if (!evas_textblock_cursor_compare(c, en->sel_start)) return;
evas_textblock_cursor_copy(c, en->sel_start);
_edje_entry_imf_cursor_info_set(en);
if (en->selection)
{
free(en->selection);
en->selection = NULL;
}
_emit_sel_state(ed, en);
}
static void
_sel_clear(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
{
en->had_sel = EINA_FALSE;
if (en->sel_start)
{
evas_textblock_cursor_free(en->sel_start);
evas_textblock_cursor_free(en->sel_end);
en->sel_start = NULL;
en->sel_end = NULL;
}
if (en->selection)
{
free(en->selection);
en->selection = NULL;
}
while (en->sel)
{
Sel *sel;
sel = en->sel->data;
if (sel->obj_bg) evas_object_del(sel->obj_bg);
if (sel->obj_fg) evas_object_del(sel->obj_fg);
free(sel);
en->sel = eina_list_remove_list(en->sel, en->sel);
}
if (en->have_selection)
{
en->have_selection = EINA_FALSE;
_edje_emit(ed, "selection,cleared", en->rp->part->name);
}
}
static void
_sel_update(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en)
{
Evas_Coord x, y;
Evas_Object *smart, *clip;
smart = evas_object_smart_parent_get(o);
clip = evas_object_clip_get(o);
if (!en->sel_start)
return;
evas_object_geometry_get(o, &x, &y, NULL, NULL);
if (en->have_selection)
{
Eina_Iterator *range = NULL;
Eina_List *l;
Sel *sel = NULL;
Evas_Textblock_Rectangle *r;
range = evas_textblock_cursor_range_simple_geometry_get(en->sel_start,
en->sel_end);
l = en->sel;
EINA_ITERATOR_FOREACH(range, r)
{
if (!l)
{
Evas_Object *ob;
sel = calloc(1, sizeof(Sel));
if (!sel)
{
ERR("Running very low on memory");
break;
}
en->sel = eina_list_append(en->sel, sel);
if (en->rp->part->source)
{
ob = edje_object_add(ed->base.evas);
edje_object_file_set(ob, ed->path, en->rp->part->source);
evas_object_smart_member_add(ob, smart);
evas_object_stack_below(ob, o);
evas_object_clip_set(ob, clip);
evas_object_pass_events_set(ob, EINA_TRUE);
evas_object_show(ob);
sel->obj_bg = ob;
_edje_subobj_register(ed, sel->obj_bg);
}
if (en->rp->part->source2)
{
ob = edje_object_add(ed->base.evas);
edje_object_file_set(ob, ed->path, en->rp->part->source2);
evas_object_smart_member_add(ob, smart);
evas_object_stack_above(ob, o);
evas_object_clip_set(ob, clip);
evas_object_pass_events_set(ob, EINA_TRUE);
evas_object_show(ob);
sel->obj_fg = ob;
_edje_subobj_register(ed, sel->obj_fg);
}
}
else
{
sel = eina_list_data_get(l);
l = l->next;
}
*(&(sel->rect)) = *r;
if (sel->obj_bg)
{
evas_object_move(sel->obj_bg, x + r->x, y + r->y);
evas_object_resize(sel->obj_bg, r->w, r->h);
}
if (sel->obj_fg)
{
evas_object_move(sel->obj_fg, x + r->x, y + r->y);
evas_object_resize(sel->obj_fg, r->w, r->h);
}
}
eina_iterator_free(range);
/* delete redundant selection rects */
while (l)
{
Eina_List *temp = l->next;
sel = eina_list_data_get(l);
if (sel)
{
if (sel->obj_bg) evas_object_del(sel->obj_bg);
if (sel->obj_fg) evas_object_del(sel->obj_fg);
free(sel);
}
en->sel = eina_list_remove_list(en->sel, l);
l = temp;
}
}
}
static Eina_Bool
_edje_entry_style_tag_check(Edje_Real_Part *rp, const char *tag)
{
const Evas_Textblock_Style *ts = NULL;
ts = evas_object_textblock_style_user_peek(rp->object);
if (ts)
{
if (strstr(evas_textblock_style_get(ts), tag)) return EINA_TRUE;
}
else
{
ts = evas_object_textblock_style_get(rp->object);
if (ts)
{
if (strstr(evas_textblock_style_get(ts), tag)) return EINA_TRUE;
}
}
return EINA_FALSE;
}
static void
_edje_anchor_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Anchor *an = data;
Evas_Event_Mouse_Down *ev = event_info;
Edje_Real_Part *rp = an->en->rp;
char *buf, *n;
size_t len;
int ignored;
Entry *en;
Edje *ed = an->en->ed;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
(en->select_allow))
return;
ignored = rp->ignore_flags & ev->event_flags;
if ((!ev->event_flags) || (!ignored))
{
n = an->name;
if (!n) n = "";
len = 200 + strlen(n);
buf = alloca(len);
if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
snprintf(buf, len, "anchor,mouse,down,%i,%s,triple", ev->button, n);
else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
snprintf(buf, len, "anchor,mouse,down,%i,%s,double", ev->button, n);
else
snprintf(buf, len, "anchor,mouse,down,%i,%s", ev->button, n);
_edje_emit(ed, buf, rp->part->name);
/* Link Pressed effect */
if (_edje_entry_style_tag_check(rp, "link_pressed="))
{
an->en->have_link_pressed = EINA_TRUE;
evas_textblock_cursor_format_append(an->start, "<link_pressed>");
evas_textblock_cursor_format_prepend(an->end, "</>");
}
}
ev->event_flags |= rp->mask_flags;
}
static void
_edje_anchor_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Anchor *an = data;
Evas_Event_Mouse_Up *ev = event_info;
Edje_Real_Part *rp = an->en->rp;
char *buf, *n;
size_t len;
int ignored;
Entry *en;
Edje *ed = an->en->ed;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
ignored = rp->ignore_flags & ev->event_flags;
n = an->name;
if (!n) n = "";
len = 200 + strlen(n);
buf = alloca(len);
if ((rp->part->select_mode != EDJE_ENTRY_SELECTION_MODE_EXPLICIT) ||
(!en->select_allow))
{
if ((!ev->event_flags) || (!ignored))
{
snprintf(buf, len, "anchor,mouse,up,%i,%s", ev->button, n);
_edje_emit(ed, buf, rp->part->name);
/* Link Pressed effect */
if (an->en->have_link_pressed)
{
const Evas_Object_Textblock_Node_Format *node;
node = evas_textblock_node_format_first_get(rp->object);
for (; node; node = evas_textblock_node_format_next_get(node))
{
const char *text = evas_textblock_node_format_text_get(node);
if (text)
{
if (!strcmp(text, "+ link_pressed"))
{
evas_textblock_node_format_remove_pair(rp->object,
(Evas_Object_Textblock_Node_Format *)node);
break;
}
}
}
}
}
}
if ((rp->still_in) && (rp->clicked_button == ev->button) && (!ignored))
{
snprintf(buf, len, "anchor,mouse,clicked,%i,%s", ev->button, n);
_edje_emit(ed, buf, rp->part->name);
}
ev->event_flags |= rp->mask_flags;
}
static void
_edje_anchor_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Anchor *an = data;
Evas_Event_Mouse_Move *ev = event_info;
Edje_Real_Part *rp = an->en->rp;
char *buf, *n;
size_t len;
int ignored;
Entry *en;
Edje *ed = an->en->ed;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
(en->select_allow))
return;
ignored = rp->ignore_flags & ev->event_flags;
if ((!ev->event_flags) || (!ignored))
{
n = an->name;
if (!n) n = "";
len = 200 + strlen(n);
buf = alloca(len);
snprintf(buf, len, "anchor,mouse,move,%s", n);
_edje_emit(ed, buf, rp->part->name);
}
ev->event_flags |= rp->mask_flags;
}
static void
_edje_anchor_mouse_in_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Anchor *an = data;
Evas_Event_Mouse_In *ev = event_info;
Edje_Real_Part *rp = an->en->rp;
Edje *ed = an->en->ed;
char *buf, *n;
size_t len;
int ignored;
ignored = rp->ignore_flags & ev->event_flags;
if ((!ev->event_flags) || (!ignored))
{
/* set to allow handling in elementary, in case we have
* an unwanted event propagation */
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
n = an->name;
if (!n) n = "";
len = 200 + strlen(n);
buf = alloca(len);
snprintf(buf, len, "anchor,mouse,in,%s", n);
_edje_emit(ed, buf, rp->part->name);
}
ev->event_flags |= rp->mask_flags;
}
static void
_edje_anchor_mouse_out_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Anchor *an = data;
Evas_Event_Mouse_Out *ev = event_info;
Edje_Real_Part *rp = an->en->rp;
char *buf, *n;
size_t len;
int ignored;
Edje *ed = an->en->ed;
ignored = rp->ignore_flags & ev->event_flags;
if ((!ev->event_flags) || (!ignored))
{
/* set to allow handling in elementary, in case we have
* an unwanted event propagation */
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
n = an->name;
if (!n) n = "";
len = 200 + strlen(n);
buf = alloca(len);
snprintf(buf, len, "anchor,mouse,out,%s", n);
_edje_emit(ed, buf, rp->part->name);
}
ev->event_flags |= rp->mask_flags;
}
static void
_item_obj_del_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Item_Obj *io = data;
Anchor *an = io->an;
Entry *en;
if (!an)
{
ERR("Failed to free item object struct. Anchor is NULL!");
return;
}
en = an->en;
en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs),
EINA_INLIST_GET(io));
io->an = NULL;
free(io->name);
free(io);
}
static Evas_Object *
_item_obj_get(Anchor *an, Evas_Object *o, Evas_Object *smart, Evas_Object *clip)
{
Evas_Object *obj;
Item_Obj *io;
Entry *en = an->en;
Edje *ed = en->ed;
EINA_INLIST_FOREACH(en->item_objs, io)
{
if (!io->an && io->name && !strcmp(an->name ? an->name : "", io->name))
{
io->an = an;
return io->obj;
}
}
io = calloc(1, sizeof(Item_Obj));
if (!io)
{
ERR("Running very low on memory");
return NULL;
}
obj = ed->item_provider.func
(ed->item_provider.data, smart,
en->rp->part->name, an->name);
evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io);
evas_object_smart_member_add(obj, smart);
evas_object_stack_above(obj, o);
evas_object_clip_set(obj, clip);
evas_object_pass_events_set(obj, EINA_TRUE);
io->an = an;
io->name = strdup(an->name ? an->name : "");
io->obj = obj;
en->item_objs = (Item_Obj *)eina_inlist_append(EINA_INLIST_GET(en->item_objs),
EINA_INLIST_GET(io));
return io->obj;
}
static void
_unused_item_objs_free(Entry *en)
{
Item_Obj *io;
Eina_Inlist *l;
EINA_INLIST_FOREACH_SAFE(en->item_objs, l, io)
{
if (!io->an)
{
if (io->obj)
{
evas_object_event_callback_del_full(io->obj, EVAS_CALLBACK_DEL, _item_obj_del_cb, io);
evas_object_del(io->obj);
}
en->item_objs = (Item_Obj *)eina_inlist_remove(EINA_INLIST_GET(en->item_objs),
EINA_INLIST_GET(io));
free(io->name);
free(io);
}
}
}
static Eina_Bool
_is_anchors_outside_viewport(Evas_Coord oxy, Evas_Coord axy, Evas_Coord awh,
Evas_Coord vxy, Evas_Coord vwh)
{
if (((oxy + axy + awh) < vxy) || ((oxy + axy) > vwh))
{
return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_anchors_update(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o, Entry *en)
{
Eina_List *l, *ll, *range = NULL;
Evas_Coord x, y, w, h;
Evas_Coord vx, vy, vw, vh;
Evas_Coord tvh, tvw;
Evas_Object *smart, *clip;
Sel *sel = NULL;
Anchor *an;
Edje *ed = en->ed;
/* Better not to update anchors outside the view port. */
if (en->anchors_updated) return;
smart = evas_object_smart_parent_get(o);
clip = evas_object_clip_get(o);
x = y = w = h = -1;
evas_object_geometry_get(o, &x, &y, &w, &h);
evas_output_viewport_get(en->ed->base.evas, &vx, &vy, &vw, &vh);
tvw = vx + vw;
tvh = vy + vh;
EINA_LIST_FOREACH(en->anchors, l, an)
{
// for item anchors
if (an->item)
{
Evas_Coord cx, cy, cw, ch;
if (!evas_textblock_cursor_format_item_geometry_get
(an->start, &cx, &cy, &cw, &ch))
{
continue;
}
if (_is_anchors_outside_viewport(y, cy, ch, vy, tvh) ||
_is_anchors_outside_viewport(x, cx, cw, vx, tvw))
{
if (an->sel)
{
sel = an->sel->data;
evas_object_hide(sel->obj);
}
continue;
}
if (!an->sel)
{
Evas_Object *ob;
sel = calloc(1, sizeof(Sel));
if (!sel)
{
ERR("Running very low on memory");
break;
}
an->sel = eina_list_append(an->sel, sel);
if (!an->sel)
{
ERR("Running very low on memory");
break;
}
if (ed->item_provider.func)
{
ob = _item_obj_get(an, o, smart, clip);
sel->obj = ob;
}
}
/* We have only one sel per item */
sel = an->sel->data;
evas_object_move(sel->obj, x + cx, y + cy);
evas_object_resize(sel->obj, cw, ch);
evas_object_show(sel->obj);
}
// for link anchors
else
{
range =
evas_textblock_cursor_range_geometry_get(an->start, an->end);
if (eina_list_count(range) != eina_list_count(an->sel))
{
while (an->sel)
{
sel = an->sel->data;
if (sel->obj_bg) evas_object_del(sel->obj_bg);
if (sel->obj_fg) evas_object_del(sel->obj_fg);
if (sel->obj) evas_object_del(sel->obj);
free(sel);
an->sel = eina_list_remove_list(an->sel, an->sel);
}
Evas_Textblock_Rectangle *r, *r_last;
r = range->data;
r_last = eina_list_last_data_get(range);
if (r->y != r_last->y)
{
/* For multiple range */
r->h = r->y + r_last->y + r_last->h;
}
/* For vertically layout entry */
if (_is_anchors_outside_viewport(y, r->y, r->h, vy, tvh))
{
EINA_LIST_FREE(range, r)
free(r);
continue;
}
else
{
/* XXX: Should consider for horizontal entry but has
* very minimal usage. Probably we should get the min x
* and max w for range and then decide whether it is in
* the viewport or not. Unnecessary calculation for this
* minimal usage. Please test with large number of anchors
* after implementing it, if its needed to be.
*/
}
for (ll = range; ll; ll = eina_list_next(ll))
{
Evas_Object *ob;
sel = calloc(1, sizeof(Sel));
if (!sel)
{
ERR("Running very low on memory");
break;
}
an->sel = eina_list_append(an->sel, sel);
if (en->rp->part->source5)
{
ob = edje_object_add(ed->base.evas);
edje_object_file_set(ob, ed->path, en->rp->part->source5);
evas_object_smart_member_add(ob, smart);
evas_object_stack_below(ob, o);
evas_object_clip_set(ob, clip);
evas_object_pass_events_set(ob, EINA_TRUE);
sel->obj_bg = ob;
_edje_subobj_register(ed, sel->obj_bg);
}
if (en->rp->part->source6)
{
ob = edje_object_add(ed->base.evas);
edje_object_file_set(ob, ed->path, en->rp->part->source6);
evas_object_smart_member_add(ob, smart);
evas_object_stack_above(ob, o);
evas_object_clip_set(ob, clip);
evas_object_pass_events_set(ob, EINA_TRUE);
sel->obj_fg = ob;
_edje_subobj_register(ed, sel->obj_fg);
}
ob = evas_object_rectangle_add(ed->base.evas);
evas_object_color_set(ob, 0, 0, 0, 0);
evas_object_smart_member_add(ob, smart);
evas_object_stack_above(ob, o);
evas_object_clip_set(ob, clip);
evas_object_repeat_events_set(ob, EINA_TRUE);
evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_DOWN, _edje_anchor_mouse_down_cb, an);
evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_UP, _edje_anchor_mouse_up_cb, an);
evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_MOVE, _edje_anchor_mouse_move_cb, an);
evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_IN, _edje_anchor_mouse_in_cb, an);
evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_OUT, _edje_anchor_mouse_out_cb, an);
sel->obj = ob;
}
}
EINA_LIST_FOREACH(an->sel, ll, sel)
{
Evas_Textblock_Rectangle *r;
r = range->data;
*(&(sel->rect)) = *r;
if (_is_anchors_outside_viewport(y, r->y, r->h, vy, tvh) ||
_is_anchors_outside_viewport(x, r->x, r->w, vx, tvw))
{
range = eina_list_remove_list(range, range);
free(r);
evas_object_hide(sel->obj_bg);
evas_object_hide(sel->obj_fg);
evas_object_hide(sel->obj);
continue;
}
if (sel->obj_bg)
{
evas_object_move(sel->obj_bg, x + r->x, y + r->y);
evas_object_resize(sel->obj_bg, r->w, r->h);
evas_object_show(sel->obj_bg);
}
if (sel->obj_fg)
{
evas_object_move(sel->obj_fg, x + r->x, y + r->y);
evas_object_resize(sel->obj_fg, r->w, r->h);
evas_object_show(sel->obj_fg);
}
if (sel->obj)
{
evas_object_move(sel->obj, x + r->x, y + r->y);
evas_object_resize(sel->obj, r->w, r->h);
evas_object_show(sel->obj);
}
range = eina_list_remove_list(range, range);
free(r);
}
}
}
_unused_item_objs_free(en);
}
static void
_anchors_update_check(Edje *ed, Edje_Real_Part *rp)
{
Evas_Coord x, y, w, h;
Evas_Coord vx, vy, vw, vh;
Eina_Bool anchors_updated = EINA_FALSE;
Entry *en;
en = rp->typedata.text->entry_data;
x = y = w = h = -1;
vx = vy = vw = vh = -1;
evas_object_geometry_get(rp->object, &x, &y, &w, &h);
evas_output_viewport_get(ed->base.evas, &vx, &vy, &vw, &vh);
if (((y + h) <= vy) || (y >= (vy + vh)))
anchors_updated = EINA_TRUE;
else if (((x + w) <= vx) || (x >= (vx + vw)))
anchors_updated = EINA_TRUE;
if (en->anchors_updated)
en->anchors_updated = anchors_updated;
_anchors_update(en->cursor, rp->object, en);
en->anchors_updated = anchors_updated;
}
static void
_anchors_need_update(Edje_Real_Part *rp)
{
Entry *en;
Eina_Bool anchors_updated;
en = rp->typedata.text->entry_data;
anchors_updated = en->anchors_updated;
en->anchors_updated = EINA_FALSE;
_anchors_update(en->cursor, rp->object, en);
en->anchors_updated = anchors_updated;
}
static void
_anchors_clear(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
{
Item_Obj *io;
while (en->anchorlist)
{
free(en->anchorlist->data);
en->anchorlist = eina_list_remove_list(en->anchorlist, en->anchorlist);
}
while (en->itemlist)
{
free(en->itemlist->data);
en->itemlist = eina_list_remove_list(en->itemlist, en->itemlist);
}
while (en->anchors)
{
Anchor *an = en->anchors->data;
while (an->sel)
{
Sel *sel = an->sel->data;
if (sel->obj_bg) evas_object_del(sel->obj_bg);
if (sel->obj_fg) evas_object_del(sel->obj_fg);
if (!an->item && sel->obj) evas_object_del(sel->obj);
free(sel);
an->sel = eina_list_remove_list(an->sel, an->sel);
}
evas_textblock_cursor_free(an->start);
evas_textblock_cursor_free(an->end);
free(an->name);
free(an);
en->anchors = eina_list_remove_list(en->anchors, en->anchors);
}
EINA_INLIST_FOREACH(en->item_objs, io)
io->an = NULL;
}
/* FIXME: This is horrible. It's just a copy&paste (with some adjustments)
* from textblock. I didn't want to introduce any non-API links between the
* libs so I just copied it. Should have been handled differently. */
static char *
_anchor_format_parse(const char *item)
{
const char *start, *end;
char *tmp;
size_t len;
start = strchr(item, '=');
if (!start) return NULL;
start++; /* Advance after the '=' */
/* If we can find a quote as the first non-space char,
* our new delimiter is a quote, not a space. */
while (*start == ' ')
start++;
if (*start == '\'')
{
start++;
end = strchr(start, '\'');
while ((end) && (end > start) && (end[-1] == '\\'))
end = strchr(end + 1, '\'');
}
else
{
end = strchr(start, ' ');
while ((end) && (end > start) && (end[-1] == '\\'))
end = strchr(end + 1, ' ');
}
/* Null terminate before the spaces */
if (end) len = end - start;
else len = strlen(start);
tmp = malloc(len + 1);
if (!tmp)
{
ERR("Running out of memory when allocating %lu byte string", (unsigned long)len + 1);
return NULL;
}
strncpy(tmp, start, len);
tmp[len] = '\0';
return tmp;
}
static void
_anchors_get(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
{
const Eina_List *anchors_a, *anchors_item;
Anchor *an = NULL;
_anchors_clear(c, o, en);
anchors_a = evas_textblock_node_format_list_get(o, "a");
anchors_item = evas_textblock_node_format_list_get(o, "item");
if (anchors_a)
{
const Evas_Object_Textblock_Node_Format *node;
const Eina_List *itr;
EINA_LIST_FOREACH(anchors_a, itr, node)
{
const char *s = evas_textblock_node_format_text_get(node);
char *p;
an = calloc(1, sizeof(Anchor));
if (!an)
{
ERR("Running very low on memory");
break;
}
an->en = en;
p = strstr(s, "href=");
if (p)
{
an->name = _anchor_format_parse(p);
}
en->anchors = eina_list_append(en->anchors, an);
an->start = evas_object_textblock_cursor_new(o);
an->end = evas_object_textblock_cursor_new(o);
evas_textblock_cursor_at_format_set(an->start, node);
evas_textblock_cursor_copy(an->start, an->end);
/* Close the anchor, if the anchor was without text,
* free it as well */
node = evas_textblock_node_format_next_get(node);
for (; node; node = evas_textblock_node_format_next_get(node))
{
s = evas_textblock_node_format_text_get(node);
if ((!strcmp(s, "- a")) || (!strcmp(s, "-a")))
break;
}
if (node)
{
evas_textblock_cursor_at_format_set(an->end, node);
}
else if (!evas_textblock_cursor_compare(an->start, an->end))
{
free(an->name);
evas_textblock_cursor_free(an->start);
evas_textblock_cursor_free(an->end);
en->anchors = eina_list_remove(en->anchors, an);
free(an);
}
an = NULL;
}
}
if (anchors_item)
{
const Evas_Object_Textblock_Node_Format *node;
const Eina_List *itr;
EINA_LIST_FOREACH(anchors_item, itr, node)
{
const char *s = evas_textblock_node_format_text_get(node);
char *p;
an = calloc(1, sizeof(Anchor));
if (!an)
{
ERR("Running very low on memory");
break;
}
an->en = en;
an->item = 1;
p = strstr(s, "href=");
if (p)
{
an->name = _anchor_format_parse(p);
}
en->anchors = eina_list_append(en->anchors, an);
an->start = evas_object_textblock_cursor_new(o);
an->end = evas_object_textblock_cursor_new(o);
evas_textblock_cursor_at_format_set(an->start, node);
evas_textblock_cursor_copy(an->start, an->end);
/* Although needed in textblock, don't bother with finding the end
* here cause it doesn't really matter. */
}
}
}
static void
_free_entry_change_info(void *_info)
{
Edje_Entry_Change_Info *info = (Edje_Entry_Change_Info *)_info;
if (info->insert)
{
eina_stringshare_del(info->change.insert.content);
}
else
{
eina_stringshare_del(info->change.del.content);
}
free(info);
}
static void
_range_del_emit(Edje *ed, Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
{
size_t start, end;
char *tmp;
Edje_Entry_Change_Info *info;
start = evas_textblock_cursor_pos_get(en->sel_start);
end = evas_textblock_cursor_pos_get(en->sel_end);
if (start == end)
goto noop;
info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
goto noop;
}
info->insert = EINA_FALSE;
info->change.del.start = start;
info->change.del.end = end;
tmp = evas_textblock_cursor_range_text_get(en->sel_start, en->sel_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
info->change.del.content = eina_stringshare_add(tmp);
if (tmp) free(tmp);
evas_textblock_cursor_range_delete(en->sel_start, en->sel_end);
_edje_emit(ed, "entry,changed", en->rp->part->name);
_edje_emit_full(ed, "entry,changed,user", en->rp->part->name, info,
_free_entry_change_info);
noop:
_sel_clear(ed, en->cursor, en->rp->object, en);
}
//static void
//_range_del(Evas_Textblock_Cursor *c EINA_UNUSED, Evas_Object *o EINA_UNUSED, Entry *en)
//{
// evas_textblock_cursor_range_delete(en->sel_start, en->sel_end);
// _sel_clear(ed, en->cursor, en->rp->object, en);
//}
2010-03-25 01:17:51 -07:00
static void
_delete_emit(Edje *ed, Evas_Textblock_Cursor *c, Entry *en, size_t pos,
Eina_Bool backspace)
2010-03-25 01:17:51 -07:00
{
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
if (backspace)
{
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
if (!evas_textblock_cursor_char_prev(c))
{
return;
}
evas_textblock_cursor_char_next(c);
}
else
{
if (!evas_textblock_cursor_char_next(c))
{
return;
}
evas_textblock_cursor_char_prev(c);
}
Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
return;
}
char *tmp = NULL;
info->insert = EINA_FALSE;
if (backspace)
{
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_copy(c, cc);
Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_FALSE);
if (remove_cluster)
{
evas_textblock_cursor_cluster_prev(cc);
}
else
{
evas_textblock_cursor_char_prev(cc);
}
info->change.del.start = evas_textblock_cursor_pos_get(cc);
info->change.del.end = pos;
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
tmp = evas_textblock_cursor_range_text_get(c, cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
evas_textblock_cursor_range_delete(c, cc);
evas_textblock_cursor_free(cc);
}
else
{
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_copy(c, cc);
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
Eina_Bool remove_cluster = evas_textblock_cursor_at_cluster_as_single_glyph(cc,EINA_TRUE);
if (remove_cluster)
{
evas_textblock_cursor_cluster_next(cc);
}
else
{
evas_textblock_cursor_char_next(cc);
}
info->change.del.start = evas_textblock_cursor_pos_get(cc);
info->change.del.end = pos;
tmp = evas_textblock_cursor_range_text_get(c, cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
evas_textblock_cursor_range_delete(c, cc);
evas_textblock_cursor_free(cc);
}
info->change.del.content = eina_stringshare_add(tmp);
if (tmp) free(tmp);
_edje_emit(ed, "entry,changed", en->rp->part->name);
_edje_emit_full(ed, "entry,changed,user", en->rp->part->name,
info, _free_entry_change_info);
2010-03-25 01:17:51 -07:00
}
Eina_Bool
_edje_entry_hide_visible_password(Edje *ed, Edje_Real_Part *rp)
{
Eina_Bool int_ret = EINA_FALSE;
const Evas_Object_Textblock_Node_Format *node;
node = evas_textblock_node_format_first_get(rp->object);
for (; node; node = evas_textblock_node_format_next_get(node))
{
const char *text = evas_textblock_node_format_text_get(node);
if (text)
{
if (!strcmp(text, "+ password=off"))
{
evas_textblock_node_format_remove_pair(rp->object,
(Evas_Object_Textblock_Node_Format *)node);
_edje_emit(ed, "entry,changed", rp->part->name);
int_ret = EINA_TRUE;
break;
}
}
}
_edje_entry_real_part_configure(ed, rp);
return int_ret;
}
static Eina_Bool
_password_timer_cb(void *data)
{
Entry *en = (Entry *)data;
_edje_entry_hide_visible_password(en->ed, en->rp);
en->pw_timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool
_is_modifier(const char *key)
{
if ((!strncmp(key, "Shift", 5)) ||
(!strncmp(key, "Control", 7)) ||
(!strncmp(key, "Alt", 3)) ||
(!strncmp(key, "Meta", 4)) ||
(!strncmp(key, "Super", 5)) ||
(!strncmp(key, "Hyper", 5)) ||
(!strcmp(key, "Scroll_Lock")) ||
(!strcmp(key, "Num_Lock")) ||
(!strcmp(key, "Caps_Lock")))
return EINA_TRUE;
return EINA_FALSE;
}
static void
_compose_seq_reset(Entry *en)
{
char *str;
EINA_LIST_FREE(en->seq, str)
eina_stringshare_del(str);
en->composing = EINA_FALSE;
}
static void
_edje_key_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Edje *ed = data;
Evas_Event_Key_Down *ev = event_info;
Edje_Real_Part *rp;
Efl_Input_Device *seat;
Entry *en;
Eina_Bool control, alt, shift;
#if defined(__APPLE__) && defined(__MACH__)
Eina_Bool super, altgr;
#endif
Eina_Bool multiline;
Eina_Bool cursor_changed;
int old_cur_pos;
seat = efl_input_device_seat_get(ev->dev);
rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
if (!rp) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
return;
if (!ev->key) return;
_edje_emit(ed, "entry,keydown", rp->part->name);
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Ecore_IMF_Event_Key_Down ecore_ev;
ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
if (!en->composing)
{
if (ecore_imf_context_filter_event(en->imf_context,
ECORE_IMF_EVENT_KEY_DOWN,
(Ecore_IMF_Event *)&ecore_ev))
{
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
return;
}
}
}
#endif
old_cur_pos = evas_textblock_cursor_pos_get(en->cursor);
#if defined(__APPLE__) && defined(__MACH__)
super = evas_key_modifier_is_set(ev->modifiers, "Super");
altgr = evas_key_modifier_is_set(ev->modifiers, "AltGr");
#endif
control = evas_key_modifier_is_set(ev->modifiers, "Control");
alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
multiline = rp->part->multiline;
cursor_changed = EINA_FALSE;
if (!strcmp(ev->key, "Escape"))
{
_compose_seq_reset(en);
// dead keys here. Escape for now (should emit these)
_edje_emit(ed, "entry,key,escape", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (!strcmp(ev->key, "Up") ||
(!strcmp(ev->key, "KP_Up") && !ev->string))
{
_compose_seq_reset(en);
if (multiline)
{
if (en->have_selection &&
(evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
if (shift)
{
_sel_start(en->cursor, rp->object, en);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (en->have_selection)
{
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
evas_textblock_cursor_copy(en->sel_start, en->cursor);
else
evas_textblock_cursor_copy(en->sel_end, en->cursor);
_sel_clear(ed, en->cursor, rp->object, en);
}
}
if (_curs_up(en->cursor, rp->object, en))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
2013-04-10 20:30:04 -07:00
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
}
_edje_emit(ed, "entry,key,up", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
}
else if (!strcmp(ev->key, "Down") ||
(!strcmp(ev->key, "KP_Down") && !ev->string))
{
_compose_seq_reset(en);
if (multiline)
{
if (en->have_selection &&
(evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
if (shift)
{
_sel_start(en->cursor, rp->object, en);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (en->have_selection)
{
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
evas_textblock_cursor_copy(en->sel_end, en->cursor);
else
evas_textblock_cursor_copy(en->sel_start, en->cursor);
_sel_clear(ed, en->cursor, rp->object, en);
}
}
if (_curs_down(en->cursor, rp->object, en))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
2013-04-10 20:30:04 -07:00
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
}
_edje_emit(ed, "entry,key,down", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
}
else if (!strcmp(ev->key, "Left") ||
(!strcmp(ev->key, "KP_Left") && !ev->string))
{
_compose_seq_reset(en);
if (en->have_selection &&
(evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
if (shift)
{
_sel_start(en->cursor, rp->object, en);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else
{
if (en->have_selection)
{
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
evas_textblock_cursor_copy(en->sel_start, en->cursor);
else
evas_textblock_cursor_copy(en->sel_end, en->cursor);
_sel_clear(ed, en->cursor, rp->object, en);
}
}
}
if (evas_textblock_cursor_cluster_prev(en->cursor))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
#if defined(__APPLE__) && defined(__MACH__)
if (altgr) evas_textblock_cursor_word_start(en->cursor);
#else
/* If control is pressed, go to the start of the word */
if (control) evas_textblock_cursor_word_start(en->cursor);
#endif
if (en->select_allow)
{
2013-04-10 20:30:04 -07:00
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,left", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
}
else if (!strcmp(ev->key, "Right") ||
(!strcmp(ev->key, "KP_Right") && !ev->string))
{
_compose_seq_reset(en);
if (en->have_selection &&
(evas_textblock_cursor_pos_get(en->sel_start) != evas_textblock_cursor_pos_get(en->sel_end)))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
if (shift)
{
_sel_start(en->cursor, rp->object, en);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else
{
if (en->have_selection)
{
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
evas_textblock_cursor_copy(en->sel_end, en->cursor);
else
evas_textblock_cursor_copy(en->sel_start, en->cursor);
_sel_clear(ed, en->cursor, rp->object, en);
}
}
}
/* If control is pressed, go to the end of the word */
#if defined(__APPLE__) && defined(__MACH__)
if (altgr) evas_textblock_cursor_word_end(en->cursor);
#else
if (control) evas_textblock_cursor_word_end(en->cursor);
#endif
if (evas_textblock_cursor_cluster_next(en->cursor))
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
if (en->select_allow)
{
2013-04-10 20:30:04 -07:00
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,right", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
}
else if (!strcmp(ev->key, "BackSpace"))
{
_compose_seq_reset(en);
if (control && !en->have_selection)
{
// del to start of previous word
_sel_start(en->cursor, rp->object, en);
evas_textblock_cursor_cluster_prev(en->cursor);
evas_textblock_cursor_word_start(en->cursor);
_sel_preextend(ed, en->cursor, rp->object, en);
_range_del_emit(ed, en->cursor, rp->object, en);
}
else if ((alt) && (shift))
{
// undo last action
}
else
{
if (en->have_selection)
{
_range_del_emit(ed, en->cursor, rp->object, en);
}
else
{
elm_entry: handle cursor delete/backspace with clusters consist of one or multible glyphs Summary: Cluster consist of one glyph, expected to be removed on backspace or delete key. Cluster consist of multible glyph, expectd to remove part of on backspace or delete key. This is behaviour founded in Android. (our current way of handling similar to Qt) **New Behaviour** {F3750386} **Old Behaviour** {F3750387} Test Plan: Auto Testing is challenging because there are no easy way to emulate keyboard down on elm_entry ``` #include <Elementary.h> EAPI_MAIN int elm_main(int argc, char **argv) { Evas_Object *win,*box,*entry; elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED); win = elm_win_util_standard_add("", ""); elm_win_autodel_set(win, EINA_TRUE); box = elm_box_add(win); entry = elm_entry_add(box); evas_object_size_hint_weight_set(box,EVAS_HINT_EXPAND,EVAS_HINT_EXPAND); evas_object_size_hint_align_set(box,EVAS_HINT_FILL,EVAS_HINT_FILL); elm_entry_entry_set(entry,"<font=NotoColorEmoji wrap=mixed >🇧🇬อั🇧🇬อั&#x1F600;&#x1F600;&#x1F600;&#x1F600;&#x1F600;อั</font>"); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.9); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(entry); evas_object_show(box); elm_box_pack_end(box,entry); elm_win_resize_object_add(win,box); evas_object_resize(win,320,480); evas_object_size_hint_weight_set(entry,EVAS_HINT_EXPAND,0.1); evas_object_size_hint_align_set(entry,EVAS_HINT_FILL,EVAS_HINT_FILL); evas_object_show(win); elm_run(); return 0; } ELM_MAIN() ``` Reviewers: tasn, woohyun, bowonryu Subscribers: cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D9628
2019-09-04 22:52:51 -07:00
//if (evas_textblock_cursor_char_prev(en->cursor))
{
_delete_emit(ed, en->cursor, en, old_cur_pos, EINA_TRUE);
}
}
}
_sel_clear(ed, en->cursor, rp->object, en);
_anchors_get(en->cursor, rp->object, en);
_edje_emit(ed, "entry,key,backspace", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (!strcmp(ev->key, "Delete") ||
(!strcmp(ev->key, "KP_Delete") && !ev->string))
{
_compose_seq_reset(en);
if (control)
{
// del to end of next word
_sel_start(en->cursor, rp->object, en);
evas_textblock_cursor_word_end(en->cursor);
evas_textblock_cursor_cluster_next(en->cursor);
_sel_extend(ed, en->cursor, rp->object, en);
_range_del_emit(ed, en->cursor, rp->object, en);
}
else if (shift)
{
// cut
}
else
{
if (en->have_selection)
{
_range_del_emit(ed, en->cursor, rp->object, en);
}
else
{
_delete_emit(ed, en->cursor, en, old_cur_pos, EINA_FALSE);
}
}
_sel_clear(ed, en->cursor, rp->object, en);
_anchors_get(en->cursor, rp->object, en);
_edje_emit(ed, "entry,key,delete", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if ((!alt) &&
(!strcmp(ev->key, "Home") ||
((!strcmp(ev->key, "KP_Home")) && !ev->string)))
{
_compose_seq_reset(en);
if (en->select_allow)
{
if (shift) _sel_start(en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
if ((control) && (multiline))
_curs_start(en->cursor, rp->object, en);
else
_curs_lin_start(en->cursor, rp->object, en);
if (en->select_allow)
{
2013-04-10 20:30:04 -07:00
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,home", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if ((!alt) &&
(!strcmp(ev->key, "End") ||
((!strcmp(ev->key, "KP_End")) && !ev->string)))
{
_compose_seq_reset(en);
if (en->select_allow)
{
if (shift) _sel_start(en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
if ((control) && (multiline))
_curs_end(en->cursor, rp->object, en);
else
_curs_lin_end(en->cursor, rp->object, en);
if (en->select_allow)
{
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,end", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (!shift) && (!strcmp(ev->keyname, "v")))
#else
else if ((control) && (!shift) && (!strcmp(ev->keyname, "v")))
#endif
{
_compose_seq_reset(en);
_edje_emit(ed, "entry,paste,request", rp->part->name);
_edje_emit(ed, "entry,paste,request,3", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (!strcmp(ev->keyname, "a")))
#else
else if ((control) && (!strcmp(ev->keyname, "a")))
#endif
{
_compose_seq_reset(en);
if (shift)
{
_edje_emit(ed, "entry,selection,none,request", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else
{
_edje_emit(ed, "entry,selection,all,request", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (((!shift) && !strcmp(ev->keyname, "c")) || !strcmp(ev->key, "Insert")))
#else
else if ((control) && (((!shift) && !strcmp(ev->keyname, "c")) || !strcmp(ev->key, "Insert")))
#endif
{
_compose_seq_reset(en);
_edje_emit(ed, "entry,copy,notify", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (!shift) && ((!strcmp(ev->keyname, "x") || (!strcmp(ev->keyname, "m")))))
#else
else if ((control) && (!shift) && ((!strcmp(ev->keyname, "x") || (!strcmp(ev->keyname, "m")))))
#endif
{
_compose_seq_reset(en);
_edje_emit(ed, "entry,cut,notify", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (!strcmp(ev->keyname, "z")))
#else
else if ((control) && (!strcmp(ev->keyname, "z")))
#endif
{
_compose_seq_reset(en);
if (shift)
{
// redo
_edje_emit(ed, "entry,redo,request", rp->part->name);
}
else
{
// undo
_edje_emit(ed, "entry,undo,request", rp->part->name);
}
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
#if defined(__APPLE__) && defined(__MACH__)
else if ((super) && (!shift) && (!strcmp(ev->keyname, "y")))
#else
else if ((control) && (!shift) && (!strcmp(ev->keyname, "y")))
#endif
{
_compose_seq_reset(en);
// redo
_edje_emit(ed, "entry,redo,request", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
//else if ((control) && (!shift) && (!strcmp(ev->key, "w")))
//{
//_compose_seq_reset(en);
//_sel_clear(ed, en->cursor, rp->object, en);
//select current word?
//ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
//}
else if (!strcmp(ev->key, "Tab"))
{
_compose_seq_reset(en);
if (multiline)
{
if (shift)
{
// remove a tab
}
else
{
Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
}
else
{
info->insert = EINA_TRUE;
info->change.insert.plain_length = 1;
if (en->have_selection)
{
_range_del_emit(ed, en->cursor, rp->object, en);
info->merge = EINA_TRUE;
}
info->change.insert.pos =
evas_textblock_cursor_pos_get(en->cursor);
info->change.insert.content = eina_stringshare_add("<tab/>");
_text_filter_format_prepend(ed, en, en->cursor, "tab");
_anchors_get(en->cursor, rp->object, en);
_edje_emit(ed, "entry,changed", rp->part->name);
_edje_emit_full(ed, "entry,changed,user", rp->part->name,
info, _free_entry_change_info);
}
}
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
_edje_emit(ed, "entry,key,tab", rp->part->name);
}
else if ((!strcmp(ev->key, "ISO_Left_Tab")) && (multiline))
{
_compose_seq_reset(en);
// remove a tab
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (!strcmp(ev->key, "Prior") ||
(!strcmp(ev->key, "KP_Prior") && !ev->string))
{
_compose_seq_reset(en);
if (en->select_allow)
{
if (shift) _sel_start(en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
if (!_curs_jump_line_by(en->cursor, rp->object, en, -10))
{
evas_textblock_cursor_line_set(en->cursor, 0);
_curs_lin_start(en->cursor, rp->object, en);
}
if (en->select_allow)
{
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,pgup", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if (!strcmp(ev->key, "Next") ||
(!strcmp(ev->key, "KP_Next") && !ev->string))
{
_compose_seq_reset(en);
if (en->select_allow)
{
if (shift) _sel_start(en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
if (!_curs_jump_line_by(en->cursor, rp->object, en, 10))
{
int last = _curs_line_last_get(en->cursor, rp->object, en);
evas_textblock_cursor_line_set(en->cursor, last);
_curs_lin_end(en->cursor, rp->object, en);
}
if (en->select_allow)
{
if (shift) _sel_extend(ed, en->cursor, rp->object, en);
else _sel_clear(ed, en->cursor, rp->object, en);
}
_edje_emit(ed, "entry,key,pgdn", rp->part->name);
_edje_emit(ed, "cursor,changed,manual", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
{
_compose_seq_reset(en);
if (multiline)
{
Edje_Entry_Change_Info *info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
}
else
{
info->insert = EINA_TRUE;
info->change.insert.plain_length = 1;
if (en->have_selection)
{
_range_del_emit(ed, en->cursor, rp->object, en);
info->merge = EINA_TRUE;
}
info->change.insert.pos =
evas_textblock_cursor_pos_get(en->cursor);
if (shift ||
evas_object_textblock_legacy_newline_get(rp->object))
{
_text_filter_format_prepend(ed, en, en->cursor, "br");
info->change.insert.content = eina_stringshare_add("<br/>");
}
else
{
_text_filter_format_prepend(ed, en, en->cursor, "ps");
info->change.insert.content = eina_stringshare_add("<ps/>");
}
_anchors_get(en->cursor, rp->object, en);
_edje_emit(ed, "entry,changed", rp->part->name);
_edje_emit_full(ed, "entry,changed,user", rp->part->name,
info, _free_entry_change_info);
_edje_emit(ed, "cursor,changed", rp->part->name);
cursor_changed = EINA_TRUE;
}
}
_edje_emit(ed, "entry,key,enter", rp->part->name);
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
else
{
char *compres = NULL, *string = (char *)ev->string;
Eina_Bool free_string = EINA_FALSE;
Ecore_Compose_State state;
if (control) goto end;
if (!en->composing)
{
_compose_seq_reset(en);
en->seq = eina_list_append(en->seq, eina_stringshare_add(ev->key));
state = ecore_compose_get(en->seq, &compres);
if (state == ECORE_COMPOSE_MIDDLE) en->composing = EINA_TRUE;
else en->composing = EINA_FALSE;
if (!en->composing)
{
free(compres);
compres = NULL;
_compose_seq_reset(en);
if (ev->string && (!ev->string[1]) &&
((ev->string[0] < 0x20) || (ev->string[0] == 0x7f)))
goto end;
}
else
{
free(compres);
compres = NULL;
goto end;
}
}
else
{
if (_is_modifier(ev->key)) goto end;
en->seq = eina_list_append(en->seq, eina_stringshare_add(ev->key));
state = ecore_compose_get(en->seq, &compres);
if (state == ECORE_COMPOSE_NONE)
{
_compose_seq_reset(en);
free(compres);
compres = NULL;
}
else if (state == ECORE_COMPOSE_DONE)
{
_compose_seq_reset(en);
if (compres)
{
string = compres;
free_string = EINA_TRUE;
}
compres = NULL;
}
else
{
free(compres);
compres = NULL;
goto end;
}
}
if (string)
{
Edje_Entry_Change_Info *info = NULL;
// if PASSWORD_SHOW_LAST mode, appending text with password=off tag
if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
_edje_password_show_last)
{
2013-04-10 20:30:04 -07:00
_edje_entry_hide_visible_password(ed, en->rp);
info = _text_filter_text_prepend(ed, en, en->cursor, string,
"+ password=off",
"- password",
EINA_TRUE, EINA_TRUE);
if (info)
{
if (en->pw_timer)
{
ecore_timer_del(en->pw_timer);
en->pw_timer = NULL;
}
if (_edje_password_show_last_timeout >= 0)
en->pw_timer = ecore_timer_add
(_edje_password_show_last_timeout,
_password_timer_cb, en);
}
}
else
info = _text_filter_text_prepend(ed, en, en->cursor, string,
NULL, NULL,
EINA_TRUE, EINA_TRUE);
_anchors_get(en->cursor, rp->object, en);
if (info)
{
_edje_emit(ed, "entry,changed", rp->part->name);
_edje_emit_full(ed, "entry,changed,user", rp->part->name,
info, _free_entry_change_info);
_edje_emit(ed, "cursor,changed", rp->part->name);
cursor_changed = EINA_TRUE;
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
}
if (free_string) free(string);
}
}
end:
2013-04-10 20:30:04 -07:00
if (!cursor_changed &&
(old_cur_pos != evas_textblock_cursor_pos_get(en->cursor)))
_edje_emit(ed, "cursor,changed", rp->part->name);
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(ed, rp);
}
static void
_edje_key_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Event_Key_Up *ev = event_info;
Efl_Input_Device *seat;
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en;
seat = efl_input_device_seat_get(ev->dev);
rp = _edje_focused_part_get(ed, _edje_seat_name_get(ed, seat));
if (!rp) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
return;
_edje_emit(ed, "entry,keyup", rp->part->name);
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Ecore_IMF_Event_Key_Up ecore_ev;
ecore_imf_evas_event_key_up_wrap(ev, &ecore_ev);
if (ecore_imf_context_filter_event(en->imf_context,
ECORE_IMF_EVENT_KEY_UP,
(Ecore_IMF_Event *)&ecore_ev))
return;
}
#else
(void)event_info;
#endif
}
static Evas_Textblock_Cursor *
_edje_cursor_cluster_coord_set(Edje_Real_Part *rp, Evas_Coord canvasx, Evas_Coord canvasy, Evas_Coord *cx, Evas_Coord *cy)
{
Entry *en;
Evas_Coord x, y, lh = 0, cly = 0;
Evas_Textblock_Cursor *line_cur;
Evas_Textblock_Cursor *tc;
en = rp->typedata.text->entry_data;
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
evas_object_geometry_get(rp->object, &x, &y, NULL, NULL);
*cx = canvasx - x;
*cy = canvasy - y;
line_cur = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_paragraph_last(line_cur);
evas_textblock_cursor_line_geometry_get(line_cur, NULL, &cly, NULL, &lh);
/* Consider a threshold of half the line height */
if (*cy > (cly + lh) && *cy < (cly + lh + lh / 2))
{
*cy = cly + lh - 1; // Make it inside Textblock
}
evas_textblock_cursor_paragraph_first(line_cur);
evas_textblock_cursor_line_geometry_get(line_cur, NULL, &cly, NULL, NULL);
if (*cy < cly && *cy > (cly - lh / 2))
{
*cy = cly;
}
evas_textblock_cursor_free(line_cur);
/* No need to check return value if not able to set the char coord Textblock
* will take care */
evas_textblock_cursor_cluster_coord_set(en->cursor, *cx, *cy);
return tc;
}
static void
_edje_part_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Edje_Real_Part *rp = data;
Entry *en;
if (!rp) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_edje_entry_imf_cursor_location_set(en);
}
static void
_edje_part_mouse_down_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Coord cx, cy;
Edje_Real_Part *rp = data;
Evas_Event_Mouse_Down *ev = event_info;
Entry *en;
// Eina_Bool multiline;
Evas_Textblock_Cursor *tc = NULL;
Eina_Bool dosel = EINA_FALSE;
Eina_Bool shift;
if ((!rp) || (!ev)) return;
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
if ((ev->button != 1) && (ev->button != 2)) return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Ecore_IMF_Event_Mouse_Down ecore_ev;
ecore_imf_evas_event_mouse_down_wrap(ev, &ecore_ev);
if (ecore_imf_context_filter_event(en->imf_context,
ECORE_IMF_EVENT_MOUSE_DOWN,
(Ecore_IMF_Event *)&ecore_ev))
return;
}
#endif
_edje_entry_imf_context_reset(rp);
shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
en->select_mod_start = EINA_FALSE;
en->select_mod_end = EINA_FALSE;
if (en->select_allow && ev->button != 2) dosel = EINA_TRUE;
if (dosel)
{
if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
{
if (shift)
{
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
if (evas_textblock_cursor_compare(en->cursor, en->sel_start) < 0)
evas_textblock_cursor_line_char_first(en->cursor);
else
evas_textblock_cursor_line_char_last(en->cursor);
_sel_extend(en->ed, en->cursor, rp->object, en);
}
else
{
en->have_selection = EINA_FALSE;
en->selecting = EINA_FALSE;
_sel_clear(en->ed, en->cursor, rp->object, en);
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
evas_textblock_cursor_line_char_first(en->cursor);
_sel_start(en->cursor, rp->object, en);
evas_textblock_cursor_line_char_last(en->cursor);
_sel_extend(en->ed, en->cursor, rp->object, en);
}
goto end;
}
else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
{
if (shift)
{
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
if (evas_textblock_cursor_compare(en->cursor, en->sel_start) < 0)
evas_textblock_cursor_word_start(en->cursor);
else
{
evas_textblock_cursor_word_end(en->cursor);
evas_textblock_cursor_cluster_next(en->cursor);
}
_sel_extend(en->ed, en->cursor, rp->object, en);
}
else
{
en->have_selection = EINA_FALSE;
en->selecting = EINA_FALSE;
_sel_clear(en->ed, en->cursor, rp->object, en);
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
evas_textblock_cursor_word_start(en->cursor);
_sel_start(en->cursor, rp->object, en);
evas_textblock_cursor_word_end(en->cursor);
evas_textblock_cursor_cluster_next(en->cursor);
_sel_extend(en->ed, en->cursor, rp->object, en);
}
goto end;
}
}
tc = _edje_cursor_cluster_coord_set(rp, ev->canvas.x, ev->canvas.y, &cx, &cy);
if (dosel)
{
if ((en->have_selection) &&
(rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT))
{
if (shift)
_sel_extend(en->ed, en->cursor, rp->object, en);
else
{
Eina_List *first, *last;
FLOAT_T sc;
first = en->sel;
last = eina_list_last(en->sel);
if (first && last)
{
Evas_Textblock_Rectangle *r1, *r2;
Evas_Coord d, d1, d2;
r1 = first->data;
r2 = last->data;
d = r1->x - cx;
d1 = d * d;
d = (r1->y + (r1->h / 2)) - cy;
d1 += d * d;
d = r2->x + r2->w - 1 - cx;
d2 = d * d;
d = (r2->y + (r2->h / 2)) - cy;
d2 += d * d;
sc = DIV(en->ed->scale, en->ed->file->base_scale);
if (EQ(sc, ZERO)) sc = DIV(_edje_scale, en->ed->file->base_scale);
d = (Evas_Coord)MUL(FROM_INT(20), sc); // FIXME: maxing number!
d = d * d;
if (d1 < d2)
{
if (d1 <= d)
{
en->select_mod_start = EINA_TRUE;
en->selecting = EINA_TRUE;
}
}
else
{
if (d2 <= d)
{
en->select_mod_end = EINA_TRUE;
en->selecting = EINA_TRUE;
}
}
}
}
}
else
{
if (shift)
{
_sel_extend(en->ed, en->cursor, rp->object, en);
}
else
{
en->selecting = EINA_TRUE;
_sel_clear(en->ed, en->cursor, rp->object, en);
_sel_start(en->cursor, rp->object, en);
}
}
}
end:
if (evas_textblock_cursor_compare(tc, en->cursor))
{
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
}
evas_textblock_cursor_free(tc);
_edje_entry_real_part_configure(en->ed, rp);
if (ev->button == 2)
{
_edje_emit(en->ed, "entry,paste,request", rp->part->name);
_edje_emit(en->ed, "entry,paste,request,1", rp->part->name);
}
}
static void
_edje_part_mouse_up_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Coord cx, cy;
Edje_Real_Part *rp = data;
Evas_Event_Mouse_Up *ev = event_info;
Entry *en;
Evas_Textblock_Cursor *tc;
if ((!ev) || (ev->button != 1)) return;
if (!rp) return;
if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK) return;
if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
/* We don't check for ON_HOLD because we'd like to end selection anyway when
* mouse is up, even if it's held. */
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Ecore_IMF_Event_Mouse_Up ecore_ev;
ecore_imf_evas_event_mouse_up_wrap(ev, &ecore_ev);
if (ecore_imf_context_filter_event(en->imf_context,
ECORE_IMF_EVENT_MOUSE_UP,
(Ecore_IMF_Event *)&ecore_ev))
return;
}
#endif
/* cx cy are unused but needed in mouse down, please bear with it */
tc = _edje_cursor_cluster_coord_set(rp, ev->canvas.x, ev->canvas.y, &cx, &cy);
if (en->select_allow)
{
if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
{
if (en->had_sel)
{
if (en->select_mod_end)
_sel_extend(en->ed, en->cursor, rp->object, en);
else if (en->select_mod_start)
_sel_preextend(en->ed, en->cursor, rp->object, en);
}
else
_sel_extend(en->ed, en->cursor, rp->object, en);
//evas_textblock_cursor_copy(en->cursor, en->sel_end);
}
else
{
evas_textblock_cursor_copy(en->cursor, en->sel_end);
}
}
if (en->selecting)
{
if (en->have_selection)
en->had_sel = EINA_TRUE;
en->selecting = EINA_FALSE;
}
if (evas_textblock_cursor_compare(tc, en->cursor))
{
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
}
_edje_entry_imf_cursor_info_set(en);
evas_textblock_cursor_free(tc);
_edje_entry_real_part_configure(en->ed, rp);
}
static void
_edje_part_mouse_move_cb(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
{
Evas_Coord cx, cy;
Edje_Real_Part *rp = data;
Evas_Event_Mouse_Move *ev = event_info;
Entry *en;
Evas_Coord x, y, w, h;
Evas_Textblock_Cursor *tc;
if ((!rp) || (!ev)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Ecore_IMF_Event_Mouse_Move ecore_ev;
ecore_imf_evas_event_mouse_move_wrap(ev, &ecore_ev);
if (ecore_imf_context_filter_event(en->imf_context,
ECORE_IMF_EVENT_MOUSE_MOVE,
(Ecore_IMF_Event *)&ecore_ev))
return;
}
#endif
if (en->selecting)
{
tc = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, tc);
evas_object_geometry_get(rp->object, &x, &y, &w, &h);
cx = ev->cur.canvas.x - x;
cy = ev->cur.canvas.y - y;
if (!evas_textblock_cursor_cluster_coord_set(en->cursor, cx, cy))
{
Evas_Coord lx, ly, lw, lh;
if (evas_textblock_cursor_line_coord_set(en->cursor, cy) < 0)
{
if (rp->part->multiline)
_curs_end(en->cursor, rp->object, en);
else
{
evas_textblock_cursor_paragraph_first(en->cursor);
evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
if (!evas_textblock_cursor_cluster_coord_set(en->cursor, cx, ly + (lh / 2)))
_curs_end(en->cursor, rp->object, en);
}
}
else
{
evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
if (cx <= lx)
_curs_lin_start(en->cursor, rp->object, en);
else
_curs_lin_end(en->cursor, rp->object, en);
}
}
if (en->select_allow)
{
if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
{
if (en->had_sel)
{
if (en->select_mod_end)
_sel_extend(en->ed, en->cursor, rp->object, en);
else if (en->select_mod_start)
_sel_preextend(en->ed, en->cursor, rp->object, en);
}
else
_sel_extend(en->ed, en->cursor, rp->object, en);
}
else
{
_sel_extend(en->ed, en->cursor, rp->object, en);
}
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) != 0)
_sel_enable(en->ed, en->cursor, rp->object, en);
if (en->have_selection)
_sel_update(en->ed, en->cursor, rp->object, en);
}
if (evas_textblock_cursor_compare(tc, en->cursor))
{
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_emit(en->ed, "cursor,changed,manual", rp->part->name);
}
evas_textblock_cursor_free(tc);
_edje_entry_real_part_configure(en->ed, rp);
}
}
static void
_canvas_viewport_resize_cb(void *data, Evas *e EINA_UNUSED, void *event_info EINA_UNUSED)
{
Edje_Real_Part *rp = data;
Entry *en;
if ((!rp)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
_anchors_need_update(rp);
}
static void
_evas_focus_in_cb(void *data, const Efl_Event *event)
{
Efl_Input_Focus *ev = event->info;
Evas *e = event->object;
Efl_Input_Device *seat;
Edje *ed = data;
if (!ed) return;
seat = efl_input_device_get(ev);
if (evas_canvas_seat_focus_get(e, seat) == ed->obj)
{
_edje_focus_in(data, seat);
}
}
static void
_evas_focus_out_cb(void *data, const Efl_Event *event)
{
Efl_Input_Focus *ev = event->info;
Evas *e = event->object;
Efl_Input_Device *seat;
Edje *ed = data;
if (!ed) return;
seat = efl_input_device_get(ev);
if (evas_canvas_seat_focus_get(e, seat) == ed->obj)
{
_edje_focus_out(data, seat);
}
}
/***************************************************************/
void
_edje_entry_init(Edje *ed)
{
if (!ed->has_entries)
return;
if (ed->entries_inited)
return;
ed->entries_inited = EINA_TRUE;
efl_event_callback_add(ed->obj, EFL_EVENT_FOCUS_IN, _edje_focus_in_cb, ed);
efl_event_callback_add(ed->obj, EFL_EVENT_FOCUS_OUT, _edje_focus_out_cb, ed);
evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_DOWN,
_edje_key_down_cb, ed);
evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_UP,
_edje_key_up_cb, ed);
efl_event_callback_add(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_IN,
_evas_focus_in_cb, ed);
efl_event_callback_add(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_OUT,
_evas_focus_out_cb, ed);
}
void
_edje_entry_shutdown(Edje *ed)
{
if ((!ed) || (!ed->has_entries))
return;
if (!ed->entries_inited)
return;
ed->entries_inited = EINA_FALSE;
efl_event_callback_del(ed->obj, EFL_EVENT_FOCUS_IN, _edje_focus_in_cb, ed);
efl_event_callback_del(ed->obj, EFL_EVENT_FOCUS_OUT, _edje_focus_out_cb, ed);
evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_DOWN,
_edje_key_down_cb);
evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_UP,
_edje_key_up_cb);
efl_event_callback_del(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_IN,
_evas_focus_in_cb, ed);
efl_event_callback_del(ed->base.evas, EFL_CANVAS_SCENE_EVENT_SCENE_FOCUS_OUT,
_evas_focus_out_cb, ed);
}
int
_edje_entry_real_part_cursor_objs_get(Edje_Real_Part *rp, Evas_Object **cursor_objs)
{
Entry *en;
int ret = 0;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text) || (!rp->typedata.text->entry_data)) return -1;
en = rp->typedata.text->entry_data;
if (en->cursor_bg) cursor_objs[ret++] = en->cursor_bg;
if (en->cursor_fg) cursor_objs[ret++] = en->cursor_fg;
if (en->cursor_fg2) cursor_objs[ret++] = en->cursor_fg2;
return ret;
}
void
_edje_entry_real_part_init(Edje *ed, Edje_Real_Part *rp)
{
Entry *en;
#ifdef HAVE_ECORE_IMF
const char *ctx_id;
const Ecore_IMF_Context_Info *ctx_info;
#endif
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = calloc(1, sizeof(Entry));
if (!en)
{
ERR("Running very low on memory");
return;
}
rp->typedata.text->entry_data = en;
en->rp = rp;
en->ed = ed;
evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOVE, _edje_part_move_cb, rp);
evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_DOWN, _edje_part_mouse_down_cb, rp);
evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_UP, _edje_part_mouse_up_cb, rp);
evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_MOVE, _edje_part_mouse_move_cb, rp);
evas_event_callback_add(ed->base.evas, EVAS_CALLBACK_CANVAS_VIEWPORT_RESIZE, _canvas_viewport_resize_cb, rp);
if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_DEFAULT)
en->select_allow = EINA_TRUE;
2008-10-24 00:08:08 -07:00
if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
{
Edje_Part_Description_Text *txt;
txt = (Edje_Part_Description_Text *)rp->chosen_description;
en->select_allow = EINA_FALSE;
if (txt && edje_string_get(&txt->text.repch))
evas_object_textblock_replace_char_set(rp->object, edje_string_get(&txt->text.repch));
else
evas_object_textblock_replace_char_set(rp->object, "*");
}
if (rp->part->source3)
{
en->cursor_bg = edje_object_add(ed->base.evas);
edje_object_file_set(en->cursor_bg, ed->path, rp->part->source3);
evas_object_smart_member_add(en->cursor_bg, ed->obj);
evas_object_stack_below(en->cursor_bg, rp->object);
evas_object_clip_set(en->cursor_bg, evas_object_clip_get(rp->object));
evas_object_pass_events_set(en->cursor_bg, EINA_TRUE);
_edje_subobj_register(ed, en->cursor_bg);
}
if (rp->part->source4)
{
en->cursor_fg = edje_object_add(ed->base.evas);
edje_object_file_set(en->cursor_fg, ed->path, rp->part->source4);
evas_object_smart_member_add(en->cursor_fg, ed->obj);
evas_object_stack_above(en->cursor_fg, rp->object);
evas_object_clip_set(en->cursor_fg, evas_object_clip_get(rp->object));
evas_object_pass_events_set(en->cursor_fg, EINA_TRUE);
_edje_subobj_register(ed, en->cursor_fg);
/* A proxy to the main cursor. */
if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
{
en->cursor_fg2 = edje_object_add(ed->base.evas);
edje_object_file_set(en->cursor_fg2, ed->path, rp->part->source4);
evas_object_smart_member_add(en->cursor_fg2, ed->obj);
evas_object_stack_above(en->cursor_fg2, rp->object);
evas_object_clip_set(en->cursor_fg2, evas_object_clip_get(rp->object));
evas_object_pass_events_set(en->cursor_fg2, EINA_TRUE);
_edje_subobj_register(ed, en->cursor_fg2);
}
}
evas_object_textblock_legacy_newline_set(rp->object, EINA_TRUE);
if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
{
if (en->cursor_bg) evas_object_show(en->cursor_bg);
if (en->cursor_fg) evas_object_show(en->cursor_fg);
if (en->cursor_fg2) evas_object_show(en->cursor_fg2);
en->input_panel_enable = EINA_TRUE;
#ifdef HAVE_ECORE_IMF
_edje_need_imf();
en->commit_cancel = EINA_FALSE;
edje_object_signal_callback_add(ed->obj, "focus,part,in,*",
rp->part->name,
_edje_entry_focus_in_cb, rp);
edje_object_signal_callback_add(ed->obj, "focus,part,out,*",
rp->part->name,
_edje_entry_focus_out_cb, rp);
ctx_id = ecore_imf_context_default_id_get();
if (ctx_id)
{
ctx_info = ecore_imf_context_info_by_id_get(ctx_id);
if (!ctx_info->canvas_type ||
strcmp(ctx_info->canvas_type, "evas") == 0)
{
en->imf_context = ecore_imf_context_add(ctx_id);
}
else
{
ctx_id = ecore_imf_context_default_id_by_canvas_type_get("evas");
if (ctx_id)
{
en->imf_context = ecore_imf_context_add(ctx_id);
}
}
}
else
en->imf_context = NULL;
if (!en->imf_context) goto done;
ecore_imf_context_client_window_set
(en->imf_context,
(void *)ecore_evas_window_get
(ecore_evas_ecore_evas_get(ed->base.evas)));
ecore_imf_context_client_canvas_set(en->imf_context, ed->base.evas);
ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context,
_edje_entry_imf_retrieve_surrounding_cb, ed);
ecore_imf_context_retrieve_selection_callback_set(en->imf_context, _edje_entry_imf_retrieve_selection_cb, ed);
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _edje_entry_imf_event_commit_cb, ed);
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _edje_entry_imf_event_delete_surrounding_cb, ed);
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _edje_entry_imf_event_preedit_changed_cb, ed);
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_SELECTION_SET, _edje_entry_imf_event_selection_set_cb, ed);
ecore_imf_context_input_mode_set(en->imf_context,
rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD ?
ECORE_IMF_INPUT_MODE_INVISIBLE : ECORE_IMF_INPUT_MODE_FULL);
if (rp->part->multiline)
ecore_imf_context_input_hint_set(en->imf_context,
ecore_imf_context_input_hint_get(en->imf_context) | ECORE_IMF_INPUT_HINT_MULTILINE);
if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
ecore_imf_context_input_panel_language_set(en->imf_context, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
#endif
}
2011-11-20 06:39:34 -08:00
#ifdef HAVE_ECORE_IMF
done:
#endif
en->cursor = (Evas_Textblock_Cursor *)evas_object_textblock_cursor_get(rp->object);
}
void
_edje_entry_real_part_shutdown(Edje *ed, Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
rp->typedata.text->entry_data = NULL;
_sel_clear(ed, en->cursor, rp->object, en);
_anchors_clear(en->cursor, rp->object, en);
_unused_item_objs_free(en);
#ifdef HAVE_ECORE_IMF
_preedit_clear(en);
#endif
evas_object_del(en->cursor_bg);
evas_object_del(en->cursor_fg);
evas_object_del(en->cursor_fg2);
if (en->cursor_user)
evas_textblock_cursor_free(en->cursor_user);
if (en->cursor_user_extra)
evas_textblock_cursor_free(en->cursor_user_extra);
if (en->pw_timer)
{
ecore_timer_del(en->pw_timer);
en->pw_timer = NULL;
}
evas_event_callback_del_full(ed->base.evas, EVAS_CALLBACK_CANVAS_VIEWPORT_RESIZE, _canvas_viewport_resize_cb, rp);
#ifdef HAVE_ECORE_IMF
if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
{
if (en->imf_context)
{
ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _edje_entry_imf_event_commit_cb);
ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _edje_entry_imf_event_delete_surrounding_cb);
ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _edje_entry_imf_event_preedit_changed_cb);
ecore_imf_context_event_callback_del(en->imf_context, ECORE_IMF_CALLBACK_SELECTION_SET, _edje_entry_imf_event_selection_set_cb);
ecore_imf_context_del(en->imf_context);
en->imf_context = NULL;
}
edje_object_signal_callback_del(ed->obj, "focus,part,in,*",
rp->part->name,
_edje_entry_focus_in_cb);
edje_object_signal_callback_del(ed->obj, "focus,part,out,*",
rp->part->name,
_edje_entry_focus_out_cb);
}
#endif
_compose_seq_reset(en);
free(en);
}
void
_edje_entry_real_part_configure(Edje *ed, Edje_Real_Part *rp)
{
Evas_Coord x, y, w, h, xx, yy, ww, hh, xx2, yy2;
Entry *en;
Evas_Textblock_Cursor_Type cur_type;
Eina_Bool bidi_cursor = EINA_FALSE;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_sel_update(ed, en->cursor, rp->object, en);
_anchors_update_check(ed, rp);
if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
{
switch (rp->part->cursor_mode)
{
case EDJE_ENTRY_CURSOR_MODE_BEFORE:
cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
break;
case EDJE_ENTRY_CURSOR_MODE_UNDER:
/* no break for a reason */
default:
cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
}
x = y = w = h = -1;
xx = yy = ww = hh = -1;
evas_object_geometry_get(rp->object, &x, &y, &w, &h);
bidi_cursor = evas_textblock_cursor_geometry_bidi_get(en->cursor, &xx, &yy, &ww, &hh, &xx2, &yy2, NULL, NULL, cur_type);
if (ww < 1) ww = 1;
if (hh < 1) hh = 1;
if (en->cursor_bg)
{
int bg_w = ww;
if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
edje_object_size_min_restricted_calc(en->cursor_bg, &bg_w, NULL, ww, 0);
evas_object_move(en->cursor_bg, x + xx, y + yy);
evas_object_resize(en->cursor_bg, bg_w, hh);
}
if (en->cursor_fg)
{
int fg_w = ww;
if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
edje_object_size_min_restricted_calc(en->cursor_fg, &fg_w, NULL, ww, 0);
evas_object_move(en->cursor_fg, x + xx, y + yy);
if (bidi_cursor)
{
if (en->cursor_fg2)
{
evas_object_move(en->cursor_fg2, x + xx2, y + yy2 + (hh / 2));
evas_object_resize(en->cursor_fg, fg_w, hh / 2);
evas_object_resize(en->cursor_fg2, fg_w, hh / 2);
evas_object_show(en->cursor_fg2);
}
}
else
{
evas_object_resize(en->cursor_fg, fg_w, hh);
if (en->cursor_fg2)
evas_object_hide(en->cursor_fg2);
}
}
}
}
const char *
_edje_entry_selection_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
// get selection - convert to markup
if ((!en->selection) && (en->have_selection))
en->selection = evas_textblock_cursor_range_text_get
(en->sel_start, en->sel_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
return en->selection;
}
const char *
_edje_entry_text_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
// get text - convert to markup
return evas_object_textblock_text_markup_get(rp->object);
}
void
_edje_entry_text_markup_set(Edje_Real_Part *rp, const char *text)
{
Entry *en;
const char *ptext;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
ptext = evas_object_textblock_text_markup_get(rp->object);
// some simple "do nothing if the text is the same" logic
if (ptext == text) return;
// if prev and cur is empty
if (!ptext) ptext = "";
if (!text) text = "";
if ((!ptext[0]) && (!text[0])) return;
// same content
if (!strcmp(ptext, text)) return;
_edje_entry_imf_context_reset(rp);
// set text as markup
_sel_clear(en->ed, en->cursor, rp->object, en);
evas_object_textblock_text_markup_set(rp->object, text);
_edje_entry_set_cursor_start(rp);
_anchors_get(en->cursor, rp->object, en);
_edje_emit(en->ed, "entry,changed", rp->part->name);
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(en->ed, rp);
#if 0
/* Don't emit cursor changed cause it didn't. It's just init to 0. */
_edje_emit(en->ed, "cursor,changed", rp->part->name);
#endif
}
void
_edje_entry_text_markup_append(Edje_Real_Part *rp, const char *text)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
Evas_Textblock_Cursor *end_cur;
if (!en) return;
end_cur = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_paragraph_last(end_cur);
_text_filter_markup_prepend(en->ed, en, end_cur, text, NULL, NULL,
EINA_TRUE, EINA_FALSE);
evas_textblock_cursor_free(end_cur);
/* We are updating according to the real cursor on purpose */
_anchors_get(en->cursor, rp->object, en);
_edje_emit(en->ed, "entry,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_text_markup_insert(Edje_Real_Part *rp, const char *text)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_edje_entry_imf_context_reset(rp);
_text_filter_markup_prepend(en->ed, en, en->cursor, text, NULL, NULL,
EINA_TRUE, EINA_FALSE);
_anchors_get(en->cursor, rp->object, en);
_edje_emit(en->ed, "entry,changed", rp->part->name);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_set_cursor_start(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_curs_start(en->cursor, rp->object, en);
_edje_entry_imf_cursor_info_set(en);
}
void
_edje_entry_set_cursor_end(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_curs_end(en->cursor, rp->object, en);
_edje_entry_imf_cursor_info_set(en);
}
void
_edje_entry_select_none(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_sel_clear(en->ed, en->cursor, rp->object, en);
}
void
_edje_entry_select_all(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_edje_entry_imf_context_reset(rp);
_sel_clear(en->ed, en->cursor, rp->object, en);
_curs_start(en->cursor, rp->object, en);
_edje_entry_imf_context_reset(en->rp);
_sel_start(en->cursor, rp->object, en);
_curs_end(en->cursor, rp->object, en);
_sel_extend(en->ed, en->cursor, rp->object, en);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_select_begin(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_sel_clear(en->ed, en->cursor, rp->object, en);
_sel_enable(en->ed, en->cursor, rp->object, en);
_sel_start(en->cursor, rp->object, en);
_sel_extend(en->ed, en->cursor, rp->object, en);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_select_extend(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_sel_extend(en->ed, en->cursor, rp->object, en);
_edje_entry_real_part_configure(en->ed, rp);
}
const Eina_List *
_edje_entry_anchor_geometry_get(Edje_Real_Part *rp, const char *anchor)
{
Entry *en;
Eina_List *l;
Anchor *an;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
/* Update the anchors first in case entry is not inside the canvas
* viewport */
_anchors_need_update(rp);
EINA_LIST_FOREACH(en->anchors, l, an)
{
const char *n = an->name;
if ((an->item) || (!n)) continue;
if (!strcmp(anchor, n))
return an->sel;
}
return NULL;
}
const Eina_List *
_edje_entry_anchors_list(Edje_Real_Part *rp)
{
Entry *en;
Eina_List *l, *anchors = NULL;
Anchor *an;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
/* Update the anchors first in case entry is not inside the canvas
* viewport */
_anchors_need_update(rp);
if (!en->anchorlist)
{
EINA_LIST_FOREACH(en->anchors, l, an)
{
const char *n = an->name;
if ((an->item) || (!n)) continue;
anchors = eina_list_append(anchors, strdup(n));
}
en->anchorlist = anchors;
}
return en->anchorlist;
}
Eina_Bool
_edje_entry_item_geometry_get(Edje_Real_Part *rp, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
{
Entry *en;
Eina_List *l;
Anchor *an;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
EINA_LIST_FOREACH(en->anchors, l, an)
{
const char *n = an->name;
if (!an->item) continue;
if (!n) n = "";
if (!strcmp(item, n))
{
evas_textblock_cursor_format_item_geometry_get(an->start, cx, cy, cw, ch);
return EINA_TRUE;
}
}
return EINA_FALSE;
}
const Eina_List *
_edje_entry_items_list(Edje_Real_Part *rp)
{
Entry *en;
Eina_List *l, *items = NULL;
Anchor *an;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
/* Update the anchors first in case entry is not inside the canvas
* viewport */
_anchors_need_update(rp);
if (!en->itemlist)
{
EINA_LIST_FOREACH(en->anchors, l, an)
{
const char *n = an->name;
if (!an->item) continue;
if (!n) n = "";
items = eina_list_append(items, strdup(n));
}
en->itemlist = items;
}
return en->itemlist;
}
void
_edje_entry_cursor_geometry_get(Edje_Real_Part *rp, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch, Evas_BiDi_Direction *cdir)
{
Evas_Coord x, y, w, h, xx, yy, ww, hh;
Entry *en;
Evas_Textblock_Cursor_Type cur_type;
Evas_BiDi_Direction dir;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
switch (rp->part->cursor_mode)
{
case EDJE_ENTRY_CURSOR_MODE_BEFORE:
cur_type = EVAS_TEXTBLOCK_CURSOR_BEFORE;
break;
case EDJE_ENTRY_CURSOR_MODE_UNDER:
/* no break for a reason */
default:
cur_type = EVAS_TEXTBLOCK_CURSOR_UNDER;
}
x = y = w = h = -1;
xx = yy = ww = hh = -1;
evas_object_geometry_get(rp->object, &x, &y, &w, &h);
evas_textblock_cursor_geometry_get(en->cursor, &xx, &yy, &ww, &hh, &dir, cur_type);
if (ww < 1) ww = 1;
if (rp->part->cursor_mode == EDJE_ENTRY_CURSOR_MODE_BEFORE)
edje_object_size_min_restricted_calc(en->cursor_fg, &ww, NULL, ww, 0);
if (hh < 1) hh = 1;
if (cx) *cx = x + xx;
if (cy) *cy = y + yy;
if (cw) *cw = ww;
if (ch) *ch = hh;
if (cdir) *cdir = dir;
}
void
_edje_entry_user_insert(Edje_Real_Part *rp, const char *text)
{
Entry *en;
Edje_Entry_Change_Info *info;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
_edje_entry_imf_context_reset(rp);
info = _text_filter_markup_prepend(en->ed, en, en->cursor, text, NULL, NULL,
EINA_TRUE, EINA_TRUE);
_anchors_get(en->cursor, rp->object, en);
if (info)
{
_edje_emit(en->ed, "entry,changed", rp->part->name);
_edje_emit_full(en->ed, "entry,changed,user", rp->part->name,
info, _free_entry_change_info);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
}
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_select_allow_set(Edje_Real_Part *rp, Eina_Bool allow)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
en->select_allow = allow;
}
new program action PARAM_COPY, awesome crazy stuff! :-) Edje got a new program action called PARAM_COPY in the form: action: PARAM_COPY "src_part" "src_param" "dst_part" "dst_param"; This will copy the parameter "src_param" from part "src_part" to parameter "dst_param" of part "dst_part". So far so good, why the "crazy" in the first line? Because this also: * do type conversion! * set properties of native parts, not just EXTERNAL! The type conversion allows one to get an integer and display that in a text property, or get an string and convert into a float. The set of native parts is quite simple, basically a map of Edje.h edje_object_part_*_set(). With that one can set the string to be used by a TEXT, or set drag page/step/size/value! (page/step increments are not supported at the moment, if it is worth, they may be supported in future). Sample EDC: {{{ // test.edc, compile with edje_cc and run with edje_player externals { external: "elm"; } collections { group { name: "main"; parts { part { name: "bg"; type: RECT; description { state: "default" 0.0; color: 255 255 255 255; } } part { name: "entry"; type: EXTERNAL; source: "elm/scrolled_entry"; description { state: "default" 0.0; rel2.relative: 1.0 0.5; } } part { name: "display"; type: TEXT; description { state: "default" 0.0; color: 0 128 0 255; rel1.relative: 0.0 0.5; text { font: "Sans"; size: 16; } } } programs { program { signal: "changed"; source: "entry"; action: PARAM_COPY "entry" "text" "display" "text"; } } } } } }}} SVN revision: 47500
2010-03-26 18:26:10 -07:00
Eina_Bool
_edje_entry_select_allow_get(const Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
return en->select_allow;
new program action PARAM_COPY, awesome crazy stuff! :-) Edje got a new program action called PARAM_COPY in the form: action: PARAM_COPY "src_part" "src_param" "dst_part" "dst_param"; This will copy the parameter "src_param" from part "src_part" to parameter "dst_param" of part "dst_part". So far so good, why the "crazy" in the first line? Because this also: * do type conversion! * set properties of native parts, not just EXTERNAL! The type conversion allows one to get an integer and display that in a text property, or get an string and convert into a float. The set of native parts is quite simple, basically a map of Edje.h edje_object_part_*_set(). With that one can set the string to be used by a TEXT, or set drag page/step/size/value! (page/step increments are not supported at the moment, if it is worth, they may be supported in future). Sample EDC: {{{ // test.edc, compile with edje_cc and run with edje_player externals { external: "elm"; } collections { group { name: "main"; parts { part { name: "bg"; type: RECT; description { state: "default" 0.0; color: 255 255 255 255; } } part { name: "entry"; type: EXTERNAL; source: "elm/scrolled_entry"; description { state: "default" 0.0; rel2.relative: 1.0 0.5; } } part { name: "display"; type: TEXT; description { state: "default" 0.0; color: 0 128 0 255; rel1.relative: 0.0 0.5; text { font: "Sans"; size: 16; } } } programs { program { signal: "changed"; source: "entry"; action: PARAM_COPY "entry" "text" "display" "text"; } } } } } }}} SVN revision: 47500
2010-03-26 18:26:10 -07:00
}
void
_edje_entry_select_abort(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->selecting)
{
en->selecting = EINA_FALSE;
_edje_entry_imf_context_reset(rp);
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(en->ed, rp);
}
}
void *
_edje_entry_imf_context_get(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
return en->imf_context;
#else
return NULL;
(void)rp;
#endif
}
void
_edje_entry_autocapital_type_set(Edje_Real_Part *rp, Edje_Text_Autocapital_Type autocapital_type)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
autocapital_type = EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
if (en->imf_context)
ecore_imf_context_autocapital_type_set(en->imf_context, (Ecore_IMF_Autocapital_Type)autocapital_type);
#else
(void)rp;
(void)autocapital_type;
#endif
}
Edje_Text_Autocapital_Type
_edje_entry_autocapital_type_get(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
en = rp->typedata.text->entry_data;
if (!en) return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
if (en->imf_context)
return (Edje_Text_Autocapital_Type)ecore_imf_context_autocapital_type_get(en->imf_context);
return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
#else
return EDJE_TEXT_AUTOCAPITAL_TYPE_NONE;
(void)rp;
#endif
}
void
_edje_entry_prediction_allow_set(Edje_Real_Part *rp, Eina_Bool prediction)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
en->prediction_allow = prediction;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_prediction_allow_set(en->imf_context, prediction);
#endif
}
Eina_Bool
_edje_entry_prediction_allow_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
return en->prediction_allow;
}
void
_edje_entry_input_hint_set(Edje_Real_Part *rp, Edje_Input_Hints input_hints)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_input_hint_set(en->imf_context, (Ecore_IMF_Input_Hints)input_hints);
#else
(void)input_hints;
#endif
}
Edje_Input_Hints
_edje_entry_input_hint_get(const Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EDJE_INPUT_HINT_NONE;
en = rp->typedata.text->entry_data;
if (!en) return EDJE_INPUT_HINT_NONE;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
return (Edje_Input_Hints)ecore_imf_context_input_hint_get(en->imf_context);
#endif
return EDJE_INPUT_HINT_NONE;
}
void
_edje_entry_input_panel_enabled_set(Edje_Real_Part *rp, Eina_Bool enabled)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
en->input_panel_enable = enabled;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_input_panel_enabled_set(en->imf_context, enabled);
#endif
}
Eina_Bool
_edje_entry_input_panel_enabled_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
return en->input_panel_enable;
}
void
_edje_entry_input_panel_show(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_show(en->imf_context);
#else
(void)rp;
#endif
}
void
_edje_entry_input_panel_hide(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_hide(en->imf_context);
#else
(void)rp;
#endif
}
void
_edje_entry_input_panel_language_set(Edje_Real_Part *rp, Edje_Input_Panel_Lang lang)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
en->input_panel_lang = lang;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_input_panel_language_set(en->imf_context, (Ecore_IMF_Input_Panel_Lang)lang);
#endif
}
Edje_Input_Panel_Lang
_edje_entry_input_panel_language_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EDJE_INPUT_PANEL_LANG_AUTOMATIC;
en = rp->typedata.text->entry_data;
if (!en) return EDJE_INPUT_PANEL_LANG_AUTOMATIC;
return en->input_panel_lang;
}
void
_edje_entry_input_panel_imdata_set(Edje_Real_Part *rp, const void *data, int len)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_imdata_set(en->imf_context, data, len);
#else
(void)rp;
(void)data;
(void)len;
#endif
}
void
_edje_entry_input_panel_imdata_get(Edje_Real_Part *rp, void *data, int *len)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_imdata_get(en->imf_context, data, len);
#else
(void)rp;
(void)data;
(void)len;
#endif
}
void
_edje_entry_input_panel_return_key_type_set(Edje_Real_Part *rp, Edje_Input_Panel_Return_Key_Type return_key_type)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_return_key_type_set(en->imf_context, (Ecore_IMF_Input_Panel_Return_Key_Type)return_key_type);
#else
(void)rp;
(void)return_key_type;
#endif
}
Edje_Input_Panel_Return_Key_Type
_edje_entry_input_panel_return_key_type_get(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
en = rp->typedata.text->entry_data;
if (!en) return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
if (en->imf_context)
return (Edje_Input_Panel_Return_Key_Type)ecore_imf_context_input_panel_return_key_type_get(en->imf_context);
return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
#else
return EDJE_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
(void)rp;
#endif
}
void
_edje_entry_input_panel_return_key_disabled_set(Edje_Real_Part *rp, Eina_Bool disabled)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_return_key_disabled_set(en->imf_context, disabled);
#else
(void)rp;
(void)disabled;
#endif
}
Eina_Bool
_edje_entry_input_panel_return_key_disabled_get(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
if (en->imf_context)
return ecore_imf_context_input_panel_return_key_disabled_get(en->imf_context);
return EINA_FALSE;
#else
return EINA_FALSE;
(void)rp;
#endif
}
#ifdef HAVE_ECORE_IMF
void
_edje_entry_input_panel_show_on_demand_set(Edje_Real_Part *rp, Eina_Bool ondemand)
#else
void
_edje_entry_input_panel_show_on_demand_set(Edje_Real_Part *rp, Eina_Bool ondemand EINA_UNUSED)
#endif
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_input_panel_show_on_demand_set(en->imf_context, ondemand);
#endif
}
Eina_Bool
_edje_entry_input_panel_show_on_demand_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
{
Eina_Bool ret = ecore_imf_context_input_panel_show_on_demand_get(en->imf_context);
return ret;
}
#endif
return EINA_FALSE;
}
static Evas_Textblock_Cursor *
_cursor_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return NULL;
en = rp->typedata.text->entry_data;
if (!en) return NULL;
switch (cur)
{
case EDJE_CURSOR_MAIN:
return en->cursor;
case EDJE_CURSOR_SELECTION_BEGIN:
return en->sel_start;
case EDJE_CURSOR_SELECTION_END:
return en->sel_end;
case EDJE_CURSOR_PREEDIT_START:
if (!en->preedit_start)
en->preedit_start = evas_object_textblock_cursor_new(rp->object);
return en->preedit_start;
case EDJE_CURSOR_PREEDIT_END:
if (!en->preedit_end)
en->preedit_end = evas_object_textblock_cursor_new(rp->object);
return en->preedit_end;
case EDJE_CURSOR_USER:
if (!en->cursor_user)
en->cursor_user = evas_object_textblock_cursor_new(rp->object);
return en->cursor_user;
case EDJE_CURSOR_USER_EXTRA:
if (!en->cursor_user_extra)
en->cursor_user_extra = evas_object_textblock_cursor_new(rp->object);
return en->cursor_user_extra;
default:
break;
}
return NULL;
}
Eina_Bool
_edje_text_cursor_next(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
if (!c) return EINA_FALSE;
_edje_entry_imf_context_reset(rp);
if (!evas_textblock_cursor_cluster_next(c))
{
return EINA_FALSE;
}
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
return EINA_TRUE;
}
Eina_Bool
_edje_entry_cursor_next(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
return _edje_text_cursor_next(rp, c);
}
Eina_Bool
_edje_text_cursor_prev(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
if (!c) return EINA_FALSE;
_edje_entry_imf_context_reset(rp);
if (!evas_textblock_cursor_cluster_prev(c))
{
if (evas_textblock_cursor_paragraph_prev(c)) goto ok;
else return EINA_FALSE;
}
ok:
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
return EINA_TRUE;
}
Eina_Bool
_edje_entry_cursor_prev(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
return _edje_text_cursor_prev(rp, c);
}
Eina_Bool
_edje_text_cursor_up(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
int ln;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
if (!c) return EINA_FALSE;
_edje_entry_imf_context_reset(rp);
ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
ln--;
if (ln < 0) return EINA_FALSE;
if (!evas_object_textblock_line_number_geometry_get(rp->object, ln,
&lx, &ly, &lw, &lh))
return EINA_FALSE;
evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
if (!evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
2015-02-02 02:12:42 -08:00
evas_textblock_cursor_line_char_last(c);
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
return EINA_TRUE;
}
Eina_Bool
_edje_entry_cursor_up(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
return _edje_text_cursor_up(rp, c);
}
Eina_Bool
_edje_text_cursor_down(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
int ln;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
if (!c) return EINA_FALSE;
_edje_entry_imf_context_reset(rp);
ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
ln++;
if (!evas_object_textblock_line_number_geometry_get(rp->object, ln,
&lx, &ly, &lw, &lh))
return EINA_FALSE;
evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
if (!evas_textblock_cursor_cluster_coord_set(c, cx, ly + (lh / 2)))
evas_textblock_cursor_line_char_last(c);
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
return EINA_TRUE;
}
Eina_Bool
_edje_entry_cursor_down(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
return _edje_text_cursor_down(rp, c);
}
void
_edje_text_cursor_begin(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
int old_cur_pos;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (!c) return;
_edje_entry_imf_context_reset(rp);
old_cur_pos = evas_textblock_cursor_pos_get(c);
evas_textblock_cursor_paragraph_first(c);
if (old_cur_pos == evas_textblock_cursor_pos_get(c))
return;
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_begin(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
_edje_text_cursor_begin(rp, c);
}
void
_edje_text_cursor_end(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
int old_cur_pos;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (!c) return;
_edje_entry_imf_context_reset(rp);
old_cur_pos = evas_textblock_cursor_pos_get(c);
_curs_end(c, rp->object, rp->typedata.text->entry_data);
if (old_cur_pos == evas_textblock_cursor_pos_get(c))
return;
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_end(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
_edje_text_cursor_end(rp, c);
}
void
_edje_text_cursor_copy(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *d, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
evas_textblock_cursor_copy(c, d);
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_context_reset(rp);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_copy(Edje_Real_Part *rp, Edje_Cursor cur, Edje_Cursor dst)
{
Evas_Textblock_Cursor *c;
Evas_Textblock_Cursor *d;
c = _cursor_get(rp, cur);
if (!c) return;
d = _cursor_get(rp, dst);
if (!d) return;
_edje_text_cursor_copy(rp, d, c);
}
void
_edje_text_cursor_line_begin(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
int old_cur_pos;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (!c) return;
_edje_entry_imf_context_reset(rp);
old_cur_pos = evas_textblock_cursor_pos_get(c);
evas_textblock_cursor_line_char_first(c);
if (old_cur_pos == evas_textblock_cursor_pos_get(c))
return;
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_line_begin(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
_edje_text_cursor_line_begin(rp, c);
}
void
_edje_text_cursor_line_end(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c)
{
Entry *en;
int old_cur_pos;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (!c) return;
_edje_entry_imf_context_reset(rp);
old_cur_pos = evas_textblock_cursor_pos_get(c);
evas_textblock_cursor_line_char_last(c);
if (old_cur_pos == evas_textblock_cursor_pos_get(c))
return;
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_line_end(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
_edje_text_cursor_line_end(rp, c);
}
Eina_Bool
_edje_text_cursor_coord_set(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c,
Evas_Coord x, Evas_Coord y)
{
Entry *en = rp->typedata.text->entry_data;
if ((c == _cursor_get(rp, EDJE_CURSOR_SELECTION_BEGIN)) ||
(c == _cursor_get(rp, EDJE_CURSOR_SELECTION_END)))
{
if (en->have_selection)
2015-11-25 23:52:48 -08:00
{
if (en->selection)
{
free(en->selection);
en->selection = NULL;
}
_edje_emit(en->ed, "selection,changed", rp->part->name);
}
}
return evas_textblock_cursor_cluster_coord_set(c, x, y);
}
Eina_Bool
_edje_entry_cursor_coord_set(Edje_Real_Part *rp, Edje_Cursor cur,
Evas_Coord x, Evas_Coord y)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
if (!c) return EINA_FALSE;
return _edje_text_cursor_coord_set(rp, c, x, y);
}
Eina_Bool
_edje_entry_cursor_is_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
if (!c) return EINA_FALSE;
if (evas_textblock_cursor_is_format(c)) return EINA_TRUE;
return EINA_FALSE;
}
Eina_Bool
_edje_entry_cursor_is_visible_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
if (!c) return EINA_FALSE;
return evas_textblock_cursor_format_is_visible_get(c);
}
char *
_edje_text_cursor_content_get(Edje_Real_Part *rp EINA_UNUSED, Efl_Text_Cursor_Cursor *c)
{
return evas_textblock_cursor_content_get(c);
}
char *
_edje_entry_cursor_content_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
if (!c) return NULL;
return _edje_text_cursor_content_get(rp, c);
}
void
_edje_text_cursor_pos_set(Edje_Real_Part *rp, Efl_Text_Cursor_Cursor *c, int pos)
{
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
Entry *en = rp->typedata.text->entry_data;
if (!en) return;
if (!c) return;
/* Abort if cursor position didn't really change */
if (evas_textblock_cursor_pos_get(c) == pos)
return;
_edje_entry_imf_context_reset(rp);
evas_textblock_cursor_pos_set(c, pos);
_sel_update(en->ed, c, rp->object, rp->typedata.text->entry_data);
_edje_entry_imf_cursor_info_set(en);
_edje_emit(en->ed, "cursor,changed", rp->part->name);
_edje_entry_real_part_configure(en->ed, rp);
}
void
_edje_entry_cursor_pos_set(Edje_Real_Part *rp, Edje_Cursor cur, int pos)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
_edje_text_cursor_pos_set(rp, c, pos);
}
int
_edje_text_cursor_pos_get(Edje_Real_Part *rp EINA_UNUSED, Efl_Text_Cursor_Cursor *c)
{
return evas_textblock_cursor_pos_get(c);
}
int
_edje_entry_cursor_pos_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
if (!c) return 0;
return _edje_text_cursor_pos_get(rp, c);
}
void
_edje_entry_input_panel_layout_set(Edje_Real_Part *rp, Edje_Input_Panel_Layout layout)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_input_panel_layout_set(en->imf_context, (Ecore_IMF_Input_Panel_Layout)layout);
#else
(void)rp;
(void)layout;
#endif
}
Edje_Input_Panel_Layout
_edje_entry_input_panel_layout_get(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EDJE_INPUT_PANEL_LAYOUT_INVALID;
en = rp->typedata.text->entry_data;
if (!en) return EDJE_INPUT_PANEL_LAYOUT_INVALID;
if (en->imf_context)
return (Edje_Input_Panel_Layout)ecore_imf_context_input_panel_layout_get(en->imf_context);
return EDJE_INPUT_PANEL_LAYOUT_INVALID;
#else
return EDJE_INPUT_PANEL_LAYOUT_INVALID;
(void)rp;
#endif
}
void
_edje_entry_input_panel_layout_variation_set(Edje_Real_Part *rp, int variation)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_input_panel_layout_variation_set(en->imf_context, variation);
#else
(void)variation;
#endif
}
int
_edje_entry_input_panel_layout_variation_get(Edje_Real_Part *rp)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return 0;
en = rp->typedata.text->entry_data;
if (!en) return 0;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
return ecore_imf_context_input_panel_layout_variation_get(en->imf_context);
#endif
return 0;
}
void
_edje_entry_imf_context_reset(Edje_Real_Part *rp)
{
#ifdef HAVE_ECORE_IMF
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
if (en->imf_context)
ecore_imf_context_reset(en->imf_context);
if (en->commit_cancel)
en->commit_cancel = EINA_FALSE;
#else
(void)rp;
#endif
}
static void
_edje_entry_imf_cursor_location_set(Entry *en)
{
#ifdef HAVE_ECORE_IMF
edje entry: fix gcc warnings about possibly uninitialized variables this fixes warnings from gcc specifically: lib/edje/edje_entry.c: In function ‘_edje_entry_imf_cursor_info_set’: lib/edje/edje_entry.c:4104:4: warning: ‘dir’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir); ^ lib/edje/edje_entry.c:4099:24: note: ‘dir’ was declared here Evas_BiDi_Direction dir; ^ lib/edje/edje_entry.c:4103:4: warning: ‘ch’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:27: note: ‘ch’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cw’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:23: note: ‘cw’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cy’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:19: note: ‘cy’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cx’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:15: note: ‘cx’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c: In function ‘_edje_part_move_cb’: lib/edje/edje_entry.c:4104:4: warning: ‘dir’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir); ^ lib/edje/edje_entry.c:4099:24: note: ‘dir’ was declared here Evas_BiDi_Direction dir; ^ lib/edje/edje_entry.c:4103:4: warning: ‘ch’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:27: note: ‘ch’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cw’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:23: note: ‘cw’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cy’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:19: note: ‘cy’ was declared here Evas_Coord cx, cy, cw, ch; ^ lib/edje/edje_entry.c:4103:4: warning: ‘cx’ may be used uninitialized in this function [-Wmaybe-uninitialized] ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch); ^ lib/edje/edje_entry.c:4098:15: note: ‘cx’ was declared here Evas_Coord cx, cy, cw, ch; ^ and the likes...
2016-02-29 20:19:08 -08:00
Evas_Coord cx = 0, cy = 0, cw = 0, ch = 0;
Evas_BiDi_Direction dir = 0;
if (!en || !en->rp || !en->imf_context) return;
_edje_entry_cursor_geometry_get(en->rp, &cx, &cy, &cw, &ch, &dir);
ecore_imf_context_cursor_location_set(en->imf_context, cx, cy, cw, ch);
ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir);
#else
(void)en;
#endif
}
static void
_edje_entry_imf_cursor_info_set(Entry *en)
{
int cursor_pos;
#ifdef HAVE_ECORE_IMF
if (!en || !en->rp || !en->imf_context) return;
if (en->have_selection)
{
if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) < 0)
cursor_pos = evas_textblock_cursor_pos_get(en->sel_start);
else
cursor_pos = evas_textblock_cursor_pos_get(en->sel_end);
}
else
cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos);
_edje_entry_imf_cursor_location_set(en);
#else
(void)en;
#endif
}
void
_edje_entry_prediction_hint_set(Edje_Real_Part *rp, const char *prediction_hint)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
en = rp->typedata.text->entry_data;
if (!en) return;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
ecore_imf_context_prediction_hint_set(en->imf_context, prediction_hint);
#else
(void)prediction_hint;
#endif
}
Eina_Bool
_edje_entry_prediction_hint_hash_set(Edje_Real_Part *rp, const char *key, const char *value)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
return ecore_imf_context_prediction_hint_hash_set(en->imf_context, key, value);
#else
(void)key;
(void)value;
#endif
return EINA_FALSE;
}
Eina_Bool
_edje_entry_prediction_hint_hash_del(Edje_Real_Part *rp, const char *key)
{
Entry *en;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
en = rp->typedata.text->entry_data;
if (!en) return EINA_FALSE;
#ifdef HAVE_ECORE_IMF
if (en->imf_context)
return ecore_imf_context_prediction_hint_hash_del(en->imf_context, key);
#else
(void)key;
#endif
return EINA_FALSE;
}
#ifdef HAVE_ECORE_IMF
static Edje_Real_Part *
_edje_entry_imf_default_focused_rp_get(Edje *ed)
{
Eina_Stringshare *seat_name;
Efl_Input_Device *seat;
Evas *e;
e = evas_object_evas_get(ed->obj);
seat = evas_default_device_get(e, EFL_INPUT_DEVICE_TYPE_SEAT);
seat_name = _edje_seat_name_get(ed, seat);
return _edje_focused_part_get(ed, seat_name);
}
static Eina_Bool
_edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text, int *cursor_pos)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
const char *str;
char *plain_text;
rp = _edje_entry_imf_default_focused_rp_get(ed);
if (!rp) return EINA_FALSE;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return EINA_FALSE;
if (text)
{
str = _edje_entry_text_get(rp);
if (str)
{
plain_text = evas_textblock_text_markup_to_utf8(NULL, str);
if (plain_text)
{
if (ecore_imf_context_input_hint_get(ctx) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA)
{
char *itr = NULL;
for (itr = plain_text; itr && *itr; ++itr)
*itr = '*';
}
*text = strdup(plain_text);
free(plain_text);
plain_text = NULL;
}
else
{
*text = strdup("");
}
}
else
{
*text = strdup("");
}
}
if (cursor_pos)
{
if (en->have_selection && en->sel_start)
*cursor_pos = evas_textblock_cursor_pos_get(en->sel_start);
else if (en->cursor)
*cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
else
*cursor_pos = 0;
}
return EINA_TRUE;
}
static void
_edje_entry_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
char *commit_str = event_info;
Edje_Entry_Change_Info *info = NULL;
2013-04-10 20:30:04 -07:00
rp = _edje_entry_imf_default_focused_rp_get(ed);
if ((!rp)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
if (en->have_selection)
{
if (strcmp(commit_str, ""))
{
/* delete selected characters */
_range_del_emit(ed, en->cursor, rp->object, en);
_sel_clear(ed, en->cursor, rp->object, en);
}
}
/* delete preedit characters */
_preedit_del(en);
_preedit_clear(en);
// Skipping commit process when it is useless
if (en->commit_cancel)
{
en->commit_cancel = EINA_FALSE;
return;
}
if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
_edje_password_show_last)
_edje_entry_hide_visible_password(ed, en->rp);
if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
_edje_password_show_last && (!en->preedit_start))
{
info = _text_filter_text_prepend(ed, en, en->cursor, commit_str,
"+ password=off", "- password",
EINA_TRUE, EINA_TRUE);
if (info)
{
if (en->pw_timer)
{
ecore_timer_del(en->pw_timer);
en->pw_timer = NULL;
}
if (_edje_password_show_last_timeout >= 0)
en->pw_timer = ecore_timer_add
(_edje_password_show_last_timeout,
_password_timer_cb, en);
}
}
else
{
info = _text_filter_text_prepend(ed, en, en->cursor, commit_str,
2013-04-10 20:30:04 -07:00
NULL, NULL,
EINA_TRUE, EINA_TRUE);
}
_edje_entry_imf_cursor_info_set(en);
_anchors_get(en->cursor, rp->object, en);
if (info)
{
_edje_emit(ed, "entry,changed", rp->part->name);
_edje_emit_full(ed, "entry,changed,user", rp->part->name,
info, _free_entry_change_info);
_edje_emit(ed, "cursor,changed", rp->part->name);
}
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(ed, rp);
}
static void
_edje_entry_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info EINA_UNUSED)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
Edje_Entry_Change_Info *info = NULL;
int cursor_pos;
int preedit_start_pos, preedit_end_pos;
char *preedit_string;
char *markup_txt = NULL;
char *tagname[] = {
NULL, "preedit",
// XXX: FIXME: EFL2 - make these 2 preedit_sel's different for efl
// 2.0 and beyond. maybe use "preedit_sel", "preedit_hilight",
// See https://phab.enlightenment.org/D2980 for this issue
"preedit_sel", "preedit_sel",
"preedit_sub1", "preedit_sub2", "preedit_sub3", "preedit_sub4"
};
int i;
size_t preedit_type_size = sizeof(tagname) / sizeof(tagname[0]);
Eina_Bool preedit_end_state = EINA_FALSE;
Eina_List *attrs = NULL, *l = NULL;
Ecore_IMF_Preedit_Attr *attr;
Eina_Strbuf *buf;
Eina_Strbuf *preedit_attr_str;
rp = _edje_entry_imf_default_focused_rp_get(ed);
if ((!rp)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
if (!en->imf_context) return;
ecore_imf_context_preedit_string_with_attributes_get(en->imf_context,
&preedit_string,
&attrs, &cursor_pos);
if (!preedit_string) return;
if (!strcmp(preedit_string, ""))
preedit_end_state = EINA_TRUE;
if (en->have_selection && !preedit_end_state)
_range_del_emit(ed, en->cursor, rp->object, en);
/* delete preedit characters */
_preedit_del(en);
preedit_start_pos = evas_textblock_cursor_pos_get(en->cursor);
/* insert preedit character(s) */
if (strlen(preedit_string) > 0)
{
buf = eina_strbuf_new();
if (attrs)
{
EINA_LIST_FOREACH(attrs, l, attr)
{
if (attr->preedit_type < preedit_type_size &&
tagname[attr->preedit_type])
{
preedit_attr_str = eina_strbuf_new();
if (preedit_attr_str)
{
eina_strbuf_append_n(preedit_attr_str, preedit_string + attr->start_index, attr->end_index - attr->start_index);
markup_txt = evas_textblock_text_utf8_to_markup(NULL, eina_strbuf_string_get(preedit_attr_str));
if (markup_txt)
{
eina_strbuf_append_printf(buf, "<%s>%s</%s>", tagname[attr->preedit_type], markup_txt, tagname[attr->preedit_type]);
free(markup_txt);
}
eina_strbuf_free(preedit_attr_str);
}
}
else
eina_strbuf_append(buf, preedit_string);
}
}
else
{
eina_strbuf_append(buf, preedit_string);
}
// For skipping useless commit
if (!preedit_end_state)
en->have_preedit = EINA_TRUE;
if ((rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD) &&
_edje_password_show_last)
{
_edje_entry_hide_visible_password(ed, en->rp);
info = _text_filter_markup_prepend(ed, en, en->cursor,
eina_strbuf_string_get(buf),
"+ password=off",
"- password",
EINA_TRUE, EINA_TRUE);
if (info)
{
if (en->pw_timer)
{
ecore_timer_del(en->pw_timer);
en->pw_timer = NULL;
}
if (_edje_password_show_last_timeout >= 0)
en->pw_timer = ecore_timer_add
(_edje_password_show_last_timeout,
_password_timer_cb, en);
}
}
else
info = _text_filter_markup_prepend(ed, en, en->cursor,
eina_strbuf_string_get(buf),
NULL, NULL,
EINA_TRUE, EINA_TRUE);
eina_strbuf_free(buf);
}
if (!preedit_end_state)
{
/* set preedit start cursor */
if (!en->preedit_start)
en->preedit_start = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, en->preedit_start);
/* set preedit end cursor */
if (!en->preedit_end)
en->preedit_end = evas_object_textblock_cursor_new(rp->object);
evas_textblock_cursor_copy(en->cursor, en->preedit_end);
preedit_end_pos = evas_textblock_cursor_pos_get(en->cursor);
for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++)
{
evas_textblock_cursor_char_prev(en->preedit_start);
}
en->have_preedit = EINA_TRUE;
/* set cursor position */
evas_textblock_cursor_pos_set(en->cursor, preedit_start_pos + cursor_pos);
}
_edje_entry_imf_cursor_info_set(en);
_anchors_get(en->cursor, rp->object, en);
_edje_emit_full(ed, "preedit,changed", rp->part->name, info,
_free_entry_change_info);
_edje_emit(ed, "cursor,changed", rp->part->name);
/* delete attribute list */
if (attrs)
{
EINA_LIST_FREE(attrs, attr)
free(attr);
}
free(preedit_string);
}
static void
_edje_entry_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
Ecore_IMF_Event_Delete_Surrounding *ev = event_info;
Evas_Textblock_Cursor *del_start, *del_end;
Edje_Entry_Change_Info *info;
int cursor_pos;
int start, end;
char *tmp;
rp = _edje_entry_imf_default_focused_rp_get(ed);
if ((!rp)) return;
if ((!rp) || (!ev)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
del_start = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_pos_set(del_start, cursor_pos + ev->offset);
del_end = evas_object_textblock_cursor_new(en->rp->object);
evas_textblock_cursor_pos_set(del_end, cursor_pos + ev->offset + ev->n_chars);
start = evas_textblock_cursor_pos_get(del_start);
end = evas_textblock_cursor_pos_get(del_end);
if (start == end) goto end;
info = calloc(1, sizeof(*info));
if (!info)
{
ERR("Running very low on memory");
return;
}
info->insert = EINA_FALSE;
info->change.del.start = start;
info->change.del.end = end;
tmp = evas_textblock_cursor_range_text_get(del_start, del_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
info->change.del.content = eina_stringshare_add(tmp);
if (tmp) free(tmp);
evas_textblock_cursor_range_delete(del_start, del_end);
_anchors_get(en->cursor, rp->object, en);
_anchors_update_check(ed, rp);
_edje_emit(ed, "entry,changed", en->rp->part->name);
_edje_emit_full(ed, "entry,changed,user", en->rp->part->name, info,
_free_entry_change_info);
_edje_emit(ed, "cursor,changed", en->rp->part->name);
_edje_emit(ed, "cursor,changed,manual", en->rp->part->name);
_edje_entry_imf_cursor_info_set(en);
_edje_entry_real_part_configure(ed, rp);
end:
evas_textblock_cursor_free(del_start);
evas_textblock_cursor_free(del_end);
}
static void
_edje_entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
Ecore_IMF_Event_Selection *ev = event_info;
rp = _edje_entry_imf_default_focused_rp_get(ed);
if ((!rp) || (!ev)) return;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return;
if (ev->start == ev->end)
{
_edje_entry_cursor_pos_set(rp, EDJE_CURSOR_MAIN, ev->start);
}
else
{
_sel_clear(ed, en->cursor, rp->object, en);
evas_textblock_cursor_pos_set(en->cursor, ev->start);
_sel_enable(ed, en->cursor, rp->object, en);
_sel_start(en->cursor, rp->object, en);
evas_textblock_cursor_pos_set(en->cursor, ev->end);
_sel_extend(ed, en->cursor, rp->object, en);
}
_edje_entry_real_part_configure(en->ed, rp);
}
static Eina_Bool
_edje_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text)
{
Edje *ed = data;
Edje_Real_Part *rp;
Entry *en = NULL;
const char *selection_text = NULL;
rp = _edje_entry_imf_default_focused_rp_get(ed);
if (!rp) return EINA_FALSE;
if ((rp->type != EDJE_RP_TYPE_TEXT) ||
(!rp->typedata.text)) return EINA_FALSE;
else
en = rp->typedata.text->entry_data;
if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
(rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
return EINA_FALSE;
if (en->have_selection)
{
selection_text = _edje_entry_selection_get(rp);
if (text)
*text = selection_text ? strdup(selection_text) : NULL;
return selection_text ? EINA_TRUE : EINA_FALSE;
}
else
return EINA_FALSE;
}
#endif
Evas_Textblock_Cursor *
_edje_text_cursor_get(Edje_Real_Part *rp, Edje_Cursor cur)
{
return _cursor_get(rp, cur);
}
/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/