2470 lines
76 KiB
C
2470 lines
76 KiB
C
#ifdef HAVE_CONFIG_H
|
|
# include "elementary_config.h"
|
|
#endif
|
|
|
|
#include "elm_priv.h"
|
|
#include "efl_ui_internal_text_interactive.h"
|
|
#include "efl_canvas_textblock_internal.h"
|
|
|
|
#define MY_CLASS EFL_UI_INTERNAL_TEXT_INTERACTIVE_CLASS
|
|
|
|
#define _PARAGRAPH_SEPARATOR_UTF8 "\xE2\x80\xA9"
|
|
|
|
|
|
typedef struct _Efl_Ui_Internal_Text_Interactive_Data
|
|
{
|
|
Efl_Text_Cursor_Object *sel_start, *sel_end;
|
|
Eina_Bool watch_selection;
|
|
Efl_Text_Cursor_Object *main_cursor;
|
|
Efl_Text_Cursor_Object *preedit_start, *preedit_end;
|
|
Ecore_Timer *pw_timer;
|
|
Eina_List *seq;
|
|
char *selection;
|
|
const char *file;
|
|
Elm_Text_Format format;
|
|
Eina_Bool composing : 1;
|
|
Eina_Bool selecting : 1;
|
|
Eina_Bool have_selection : 1;
|
|
Eina_Bool select_allow : 1;
|
|
Eina_Bool editable : 1;
|
|
Eina_Bool had_sel : 1;
|
|
Eina_Bool auto_save : 1;
|
|
Eina_Bool prediction_allow : 1;
|
|
Eina_Bool anchors_updated : 1;
|
|
Eina_Bool auto_return_key : 1;
|
|
int input_panel_layout_variation;
|
|
Efl_Input_Text_Panel_Layout_Type input_panel_layout;
|
|
Efl_Input_Text_Capitalize_Type autocapital_type;
|
|
Efl_Input_Text_Panel_Language_Type input_panel_lang;
|
|
Efl_Input_Text_Panel_Return_Key_Type input_panel_return_key_type;
|
|
Efl_Input_Text_Content_Type input_hints;
|
|
Efl_Input_Text_Panel_Return_Key_State input_panel_return_key_state;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
Eina_Bool have_preedit : 1;
|
|
Eina_Bool commit_cancel : 1; // For skipping useless commit
|
|
Ecore_IMF_Context *imf_context;
|
|
#endif
|
|
} Efl_Ui_Internal_Text_Interactive_Data;
|
|
|
|
static void _sel_range_del_emit(Evas_Object *obj, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _sel_init(Efl_Text_Cursor_Object *c, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _sel_enable(Evas_Object *o,Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _sel_extend(Efl_Text_Cursor_Object *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _sel_clear(Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static const char *_entry_selection_get(Efl_Ui_Internal_Text_Interactive *obj, Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _entry_imf_cursor_info_set(Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
|
|
static void _sel_watch_freeze(Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
static void _sel_watch_thaw(Efl_Ui_Internal_Text_Interactive_Data *en);
|
|
|
|
static void
|
|
_text_filter_format_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c, const char *text);
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_text_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
const char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo);
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_markup_prepend_internal(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo);
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_markup_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
const char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo);
|
|
|
|
static void
|
|
_cur_pos_copy(Efl_Text_Cursor_Object *src, Efl_Text_Cursor_Object *dest)
|
|
{
|
|
efl_text_cursor_object_position_set(dest, efl_text_cursor_object_position_get(src));
|
|
}
|
|
|
|
static void
|
|
_sel_watch_freeze(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
en->watch_selection = EINA_FALSE;
|
|
}
|
|
|
|
static void
|
|
_sel_watch_thaw(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
en->watch_selection = EINA_TRUE;
|
|
}
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
static void
|
|
_preedit_clear(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (en->preedit_start)
|
|
{
|
|
efl_del(en->preedit_start);
|
|
en->preedit_start = NULL;
|
|
}
|
|
|
|
if (en->preedit_end)
|
|
{
|
|
efl_del(en->preedit_end);
|
|
en->preedit_end = NULL;
|
|
}
|
|
|
|
en->have_preedit = EINA_FALSE;
|
|
}
|
|
|
|
static void
|
|
_preedit_del(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (!en || !en->have_preedit) return;
|
|
if (!en->preedit_start || !en->preedit_end) return;
|
|
if (efl_text_cursor_object_equal(en->preedit_start, en->preedit_end)) return;
|
|
|
|
/* delete the preedit characters */
|
|
efl_text_cursor_object_range_delete(en->preedit_start, en->preedit_end);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text, int *cursor_pos)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
const char *str;
|
|
|
|
if (text)
|
|
{
|
|
str = efl_text_get(obj);
|
|
if (str)
|
|
{
|
|
*text = strdup(str);
|
|
}
|
|
else
|
|
*text = strdup("");
|
|
}
|
|
|
|
if (cursor_pos)
|
|
{
|
|
if (cur)
|
|
*cursor_pos = efl_text_cursor_object_position_get(cur);
|
|
else
|
|
*cursor_pos = 0;
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
}
|
|
|
|
static void
|
|
_return_key_update(Evas_Object *obj)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
Eina_Bool return_key_disabled = EINA_FALSE;
|
|
Efl_Ui_Internal_Text_Interactive_Data *sd = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (sd->input_panel_return_key_state != EFL_INPUT_TEXT_PANEL_RETURN_KEY_STATE_AUTO) return;
|
|
|
|
if (efl_canvas_textblock_is_empty_get(obj) == EINA_TRUE)
|
|
return_key_disabled = EINA_TRUE;
|
|
|
|
if (sd->imf_context)
|
|
ecore_imf_context_input_panel_return_key_disabled_set(sd->imf_context, return_key_disabled);
|
|
#else
|
|
(void)obj;
|
|
#endif
|
|
}
|
|
|
|
Eina_Bool
|
|
_entry_hide_visible_password(Eo *obj)
|
|
{
|
|
Eina_Bool b_ret = EINA_FALSE;
|
|
const Evas_Object_Textblock_Node_Format *node, *node_next;
|
|
node = evas_textblock_node_format_first_get(obj);
|
|
|
|
if (!node) return EINA_FALSE;
|
|
|
|
do
|
|
{
|
|
node_next = 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(obj, (Evas_Object_Textblock_Node_Format *)node);
|
|
b_ret = EINA_TRUE;
|
|
}
|
|
}
|
|
node = node_next;
|
|
} while (node);
|
|
|
|
return b_ret;
|
|
}
|
|
|
|
static void
|
|
_entry_imf_event_commit_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
char *commit_str = event_info;
|
|
Efl_Text_Change_Info *info = NULL;
|
|
|
|
if (en->have_selection)
|
|
{
|
|
if (strcmp(commit_str, ""))
|
|
{
|
|
/* delete selected characters */
|
|
_sel_range_del_emit(obj, en);
|
|
_sel_clear(obj, en);
|
|
}
|
|
}
|
|
|
|
/* delete preedit characters */
|
|
_preedit_del(obj, en);
|
|
_preedit_clear(en);
|
|
|
|
// Skipping commit process when it is useless
|
|
if (en->commit_cancel)
|
|
{
|
|
en->commit_cancel = EINA_FALSE;
|
|
return;
|
|
}
|
|
|
|
if (efl_text_password_get(obj) && (!en->preedit_start))
|
|
{
|
|
info = _text_filter_text_prepend(obj, en, en->main_cursor, commit_str,
|
|
"+ password=off", "- password",
|
|
EINA_TRUE, EINA_TRUE);
|
|
}
|
|
else
|
|
{
|
|
info = _text_filter_text_prepend(obj, en, en->main_cursor, commit_str,
|
|
NULL, NULL,
|
|
EINA_TRUE, EINA_TRUE);
|
|
}
|
|
|
|
_entry_imf_cursor_info_set(en);
|
|
if (info)
|
|
{
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, info);
|
|
eina_stringshare_del(info->content);
|
|
free(info);
|
|
info = NULL;
|
|
}
|
|
_entry_imf_cursor_info_set(en);
|
|
}
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_markup_prepend_internal(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo)
|
|
{
|
|
Eina_Bool have_sel = EINA_FALSE;
|
|
|
|
if ((clearsel) && (en->have_selection))
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
have_sel = EINA_TRUE;
|
|
}
|
|
|
|
#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)
|
|
{
|
|
Efl_Text_Change_Info *info = NULL;
|
|
|
|
if (changeinfo)
|
|
{
|
|
info = calloc(1, sizeof(*info));
|
|
info->type = EFL_TEXT_CHANGE_TYPE_INSERT;
|
|
info->content = eina_stringshare_add(text);
|
|
info->length =
|
|
eina_unicode_utf8_get_len(info->content);
|
|
}
|
|
if (info)
|
|
{
|
|
if (have_sel)
|
|
{
|
|
info->mergeable = EINA_TRUE;
|
|
}
|
|
info->position =
|
|
efl_text_cursor_object_position_get(efl_text_interactive_main_cursor_get(obj));
|
|
}
|
|
if (fmtpre) _text_filter_format_prepend(obj, en, efl_text_interactive_main_cursor_get(obj), fmtpre);
|
|
//evas_object_textblock_text_markup_prepend(c, text);
|
|
efl_text_cursor_object_text_insert(c, text);
|
|
free(text);
|
|
if (fmtpost) _text_filter_format_prepend(obj, en, efl_text_interactive_main_cursor_get(obj), fmtpost);
|
|
return info;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_markup_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
const char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo)
|
|
{
|
|
char *text2;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
|
|
|
|
if ((clearsel) && (en->have_selection))
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
}
|
|
|
|
text2 = strdup(text);
|
|
if (text2)
|
|
{
|
|
Efl_Text_Change_Info *info;
|
|
|
|
info = _text_filter_markup_prepend_internal(obj, en, c, text2,
|
|
fmtpre, fmtpost,
|
|
clearsel, changeinfo);
|
|
return info;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static Efl_Text_Change_Info *
|
|
_text_filter_text_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c,
|
|
const char *text,
|
|
const char *fmtpre, const char *fmtpost,
|
|
Eina_Bool clearsel, Eina_Bool changeinfo)
|
|
{
|
|
char *markup_text;
|
|
Efl_Text_Change_Info *info = NULL;
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(text, NULL);
|
|
|
|
if ((clearsel) && (en->have_selection))
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
}
|
|
|
|
markup_text = evas_textblock_text_utf8_to_markup(NULL, text);
|
|
if (markup_text)
|
|
info = _text_filter_markup_prepend_internal(obj, en, c, markup_text,
|
|
fmtpre, fmtpost,
|
|
clearsel, changeinfo);
|
|
return info;
|
|
}
|
|
|
|
static void
|
|
_text_filter_format_prepend(Efl_Canvas_Textblock *obj, Efl_Ui_Internal_Text_Interactive_Data *en,
|
|
Efl_Text_Cursor_Object *c, const char *text)
|
|
{
|
|
EINA_SAFETY_ON_NULL_RETURN(text);
|
|
|
|
if (text)
|
|
{
|
|
const char *s;
|
|
char *markup_text;
|
|
size_t size;
|
|
|
|
s = text;
|
|
if (*s == '+')
|
|
{
|
|
s++;
|
|
while (*s == ' ')
|
|
s++;
|
|
if (!*s)
|
|
{
|
|
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)
|
|
{
|
|
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';
|
|
}
|
|
}
|
|
if (markup_text)
|
|
_text_filter_markup_prepend_internal(obj, en, c, markup_text,
|
|
NULL, NULL,
|
|
EINA_FALSE, EINA_FALSE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_entry_imf_event_preedit_changed_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info EINA_UNUSED)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Efl_Text_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;
|
|
|
|
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)
|
|
_sel_range_del_emit(obj, en);
|
|
|
|
/* delete preedit characters */
|
|
_preedit_del(obj, en);
|
|
|
|
preedit_start_pos = efl_text_cursor_object_position_get(cur);
|
|
|
|
/* 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 (efl_text_password_get(obj))
|
|
{
|
|
_entry_hide_visible_password(obj);
|
|
info = _text_filter_markup_prepend(obj, en, cur,
|
|
eina_strbuf_string_get(buf),
|
|
"+ password=off",
|
|
"- password",
|
|
EINA_TRUE, EINA_TRUE);
|
|
}
|
|
else
|
|
_text_filter_markup_prepend(obj, en, cur,
|
|
eina_strbuf_string_get(buf),
|
|
NULL, NULL,
|
|
EINA_TRUE, EINA_FALSE);
|
|
|
|
eina_strbuf_free(buf);
|
|
}
|
|
|
|
if (!preedit_end_state)
|
|
{
|
|
/* set preedit start cursor */
|
|
if (!en->preedit_start)
|
|
en->preedit_start = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, en->preedit_start);
|
|
|
|
/* set preedit end cursor */
|
|
if (!en->preedit_end)
|
|
en->preedit_end = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, en->preedit_end);
|
|
|
|
preedit_end_pos = efl_text_cursor_object_position_get(cur);
|
|
|
|
for (i = 0; i < (preedit_end_pos - preedit_start_pos); i++)
|
|
{
|
|
efl_text_cursor_object_move(en->preedit_start, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_PREVIOUS);
|
|
}
|
|
|
|
en->have_preedit = EINA_TRUE;
|
|
|
|
/* set cursor position */
|
|
efl_text_cursor_object_position_set(cur, preedit_start_pos + cursor_pos);
|
|
}
|
|
|
|
if (info)
|
|
{
|
|
_entry_imf_cursor_info_set(en);
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_PREEDIT_CHANGED, info);
|
|
eina_stringshare_del(info->content);
|
|
free(info);
|
|
info = NULL;
|
|
}
|
|
|
|
/* delete attribute list */
|
|
if (attrs)
|
|
{
|
|
EINA_LIST_FREE(attrs, attr)
|
|
free(attr);
|
|
}
|
|
|
|
free(preedit_string);
|
|
}
|
|
|
|
static void
|
|
_entry_imf_event_delete_surrounding_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Ecore_IMF_Event_Delete_Surrounding *ev = event_info;
|
|
Efl_Text_Cursor_Object *del_start, *del_end;
|
|
Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
|
|
int cursor_pos;
|
|
int start, end;
|
|
char *tmp;
|
|
|
|
cursor_pos = efl_text_cursor_object_position_get(cur);
|
|
|
|
del_start = efl_canvas_textblock_cursor_create(obj);
|
|
efl_text_cursor_object_position_set(del_start, cursor_pos + ev->offset);
|
|
|
|
del_end = efl_canvas_textblock_cursor_create(obj);
|
|
efl_text_cursor_object_position_set(del_end, cursor_pos + ev->offset + ev->n_chars);
|
|
|
|
start = efl_text_cursor_object_position_get(del_start);
|
|
end = efl_text_cursor_object_position_get(del_end);
|
|
if (start == end) goto end;
|
|
|
|
tmp = efl_text_cursor_object_range_text_get(del_start, del_end);
|
|
|
|
info.type = EFL_TEXT_CHANGE_TYPE_REMOVE;
|
|
info.position = start;
|
|
info.length = end - start;
|
|
info.content = tmp;
|
|
|
|
efl_text_cursor_object_range_delete(del_start, del_end);
|
|
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
|
|
free(tmp);
|
|
|
|
_entry_imf_cursor_info_set(en);
|
|
|
|
end:
|
|
efl_del(del_start);
|
|
efl_del(del_end);
|
|
}
|
|
|
|
static void
|
|
_entry_imf_event_selection_set_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, void *event_info)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Ecore_IMF_Event_Selection *ev = event_info;
|
|
|
|
if (ev->start == ev->end)
|
|
{
|
|
efl_text_cursor_object_position_set(cur, ev->start);
|
|
}
|
|
else
|
|
{
|
|
_sel_clear(obj, en);
|
|
efl_text_cursor_object_position_set(cur, ev->start);
|
|
_sel_enable(obj, en);
|
|
_sel_init(cur, en);
|
|
efl_text_cursor_object_position_set(cur, ev->end);
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
}
|
|
|
|
static Eina_Bool
|
|
_entry_imf_retrieve_selection_cb(void *data, Ecore_IMF_Context *ctx EINA_UNUSED, char **text)
|
|
{
|
|
Efl_Canvas_Textblock *obj = data;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
const char *selection_text = NULL;
|
|
|
|
if (en->have_selection)
|
|
{
|
|
selection_text = _entry_selection_get(obj, en);
|
|
|
|
if (text)
|
|
*text = selection_text ? strdup(selection_text) : NULL;
|
|
|
|
return selection_text ? EINA_TRUE : EINA_FALSE;
|
|
}
|
|
else
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
static void
|
|
_entry_imf_cursor_location_set(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
Eina_Rect rect;
|
|
if (!en->imf_context) return;
|
|
|
|
rect = efl_text_cursor_object_cursor_geometry_get(en->main_cursor ,EFL_TEXT_CURSOR_TYPE_BEFORE);
|
|
ecore_imf_context_cursor_location_set(en->imf_context, rect.x, rect.y, rect.w, rect.h);
|
|
// FIXME: ecore_imf_context_bidi_direction_set(en->imf_context, (Ecore_IMF_BiDi_Direction)dir);
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
_entry_imf_cursor_info_set(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
int cursor_pos;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (!en->imf_context) return;
|
|
|
|
if (en->have_selection)
|
|
{
|
|
if (efl_text_cursor_object_compare(en->sel_start, en->sel_end) < 0)
|
|
cursor_pos = efl_text_cursor_object_position_get(en->sel_start);
|
|
else
|
|
cursor_pos = efl_text_cursor_object_position_get(en->sel_end);
|
|
}
|
|
else
|
|
cursor_pos = efl_text_cursor_object_position_get(en->main_cursor);
|
|
|
|
ecore_imf_context_cursor_position_set(en->imf_context, cursor_pos);
|
|
|
|
_entry_imf_cursor_location_set(en);
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
_focus_in_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (!en->imf_context) return;
|
|
|
|
ecore_imf_context_focus_in(en->imf_context);
|
|
_entry_imf_cursor_info_set(en);
|
|
|
|
_return_key_update(obj);
|
|
#endif
|
|
}
|
|
|
|
void
|
|
_entry_imf_context_reset(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_reset(en->imf_context);
|
|
if (en->commit_cancel)
|
|
en->commit_cancel = EINA_FALSE;
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
static void
|
|
_focus_out_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
if (!en->imf_context) return;
|
|
|
|
ecore_imf_context_reset(en->imf_context);
|
|
ecore_imf_context_focus_out(en->imf_context);
|
|
#endif
|
|
}
|
|
|
|
static const char *
|
|
_entry_selection_get(Efl_Ui_Internal_Text_Interactive *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if ((!en->selection) && (en->have_selection))
|
|
en->selection = efl_text_cursor_object_range_text_get(en->sel_start, en->sel_end);
|
|
return en->selection;
|
|
}
|
|
|
|
static void
|
|
_sel_reset(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en){
|
|
|
|
if (!en->watch_selection)
|
|
return;
|
|
|
|
if (!en->have_selection && efl_text_cursor_object_equal(en->sel_start, en->sel_end))
|
|
return;
|
|
|
|
if (en->have_selection)
|
|
{
|
|
if (efl_text_cursor_object_equal(en->sel_start, en->sel_end))
|
|
{
|
|
_sel_clear(obj, en);
|
|
}
|
|
else
|
|
{
|
|
_entry_imf_cursor_info_set(en);
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
_emit_sel_state(obj, en);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!efl_text_cursor_object_equal(en->sel_start, en->sel_end))
|
|
{
|
|
_sel_enable(obj, en);
|
|
_entry_imf_cursor_info_set(en);
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
_emit_sel_state(obj, en);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_sel_cursor_changed(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED)
|
|
{
|
|
Efl_Ui_Internal_Text_Interactive *obj = data;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (!efl_text_interactive_selection_allowed_get(obj))
|
|
return;
|
|
|
|
_sel_reset(obj, en);
|
|
}
|
|
|
|
static void
|
|
_sel_init(Efl_Text_Cursor_Object *c, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (en->have_selection)
|
|
return;
|
|
|
|
_sel_watch_freeze(en);
|
|
_cur_pos_copy(c, en->sel_start);
|
|
_cur_pos_copy(c, en->sel_end);
|
|
_sel_watch_thaw(en);
|
|
|
|
en->have_selection = EINA_FALSE;
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
_sel_enable(Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (en->have_selection) return;
|
|
en->have_selection = EINA_TRUE;
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
|
|
Eina_Bool b_value = EINA_TRUE;
|
|
efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, &b_value);
|
|
_entry_imf_context_reset(en);
|
|
}
|
|
|
|
static void
|
|
_emit_sel_state( Eo *o, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (!efl_text_cursor_object_compare(en->sel_start, en->sel_end))
|
|
{
|
|
_sel_clear(o, en);
|
|
}
|
|
else
|
|
{
|
|
Eina_Range range = eina_range_from_to(efl_text_cursor_object_position_get(en->sel_start),
|
|
efl_text_cursor_object_position_get(en->sel_end));
|
|
efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_SELECTION_CHANGED, &range);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_sel_extend(Efl_Text_Cursor_Object *c, Evas_Object *o, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
_sel_enable(o, en);
|
|
if (efl_text_cursor_object_equal(c, en->sel_end)) return;
|
|
|
|
_sel_watch_freeze(en);
|
|
_cur_pos_copy(c, en->sel_end);
|
|
_sel_watch_thaw(en);
|
|
|
|
_entry_imf_cursor_info_set(en);
|
|
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
|
|
_emit_sel_state(o, en);
|
|
}
|
|
|
|
static void
|
|
_sel_clear(Evas_Object *o EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
en->had_sel = EINA_FALSE;
|
|
if (en->selection)
|
|
{
|
|
free(en->selection);
|
|
en->selection = NULL;
|
|
}
|
|
if (en->have_selection)
|
|
{
|
|
en->have_selection = EINA_FALSE;
|
|
Eina_Bool b_value = en->have_selection;
|
|
_sel_watch_freeze(en);
|
|
_cur_pos_copy(en->sel_start, en->sel_end);
|
|
_sel_watch_thaw(en);
|
|
efl_event_callback_call(o, EFL_TEXT_INTERACTIVE_EVENT_HAVE_SELECTION_CHANGED, &b_value);
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_all_unselect(
|
|
Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
_sel_clear(obj, en);
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_have_selection_get(
|
|
const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
if (!en->have_selection) return en->have_selection;
|
|
return !efl_text_cursor_object_equal(en->sel_start, en->sel_end);
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_all_select(
|
|
Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en EINA_UNUSED)
|
|
{
|
|
if (!efl_text_interactive_selection_allowed_get(obj))
|
|
return;
|
|
|
|
Eo *c1 = efl_canvas_textblock_cursor_create(obj);
|
|
Eo *c2 = efl_canvas_textblock_cursor_create(obj);
|
|
|
|
efl_text_cursor_object_move(c1, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
|
|
efl_text_cursor_object_move(c2, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
|
|
|
|
efl_text_interactive_selection_cursors_set(obj, c1, c2);
|
|
|
|
efl_del(c1);
|
|
efl_del(c2);
|
|
}
|
|
|
|
|
|
static void
|
|
_range_del_emit(Evas_Object *obj, Efl_Text_Cursor_Object *cur1, Efl_Text_Cursor_Object *cur2)
|
|
{
|
|
size_t start, end;
|
|
char *tmp;
|
|
Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
|
|
|
|
start = efl_text_cursor_object_position_get(cur1);
|
|
end = efl_text_cursor_object_position_get(cur2);
|
|
if (start == end)
|
|
return;
|
|
|
|
info.type = EFL_TEXT_CHANGE_TYPE_REMOVE;
|
|
info.position = start;
|
|
info.length = end - start;
|
|
|
|
tmp = efl_text_cursor_object_range_text_get(cur1, cur2);
|
|
info.content = tmp;
|
|
|
|
efl_text_cursor_object_range_delete(cur1, cur2);
|
|
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
|
|
if (tmp) free(tmp);
|
|
}
|
|
|
|
static void
|
|
_sel_range_del_emit(Evas_Object *obj, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
_range_del_emit(obj, en->sel_start, en->sel_end);
|
|
_sel_clear(obj, en);
|
|
}
|
|
|
|
static void
|
|
_delete_emit(Eo *obj, Efl_Text_Cursor_Object *c, Efl_Ui_Internal_Text_Interactive_Data *en EINA_UNUSED, size_t pos,
|
|
Eina_Bool backspace)
|
|
{
|
|
Eo * cur = efl_duplicate(c);
|
|
if (backspace)
|
|
{
|
|
if (!efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_PREVIOUS))
|
|
{
|
|
return;
|
|
}
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
|
|
}
|
|
else
|
|
{
|
|
if (!efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT))
|
|
{
|
|
return;
|
|
}
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_PREVIOUS);
|
|
}
|
|
efl_del(cur);
|
|
cur = NULL;
|
|
|
|
Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
|
|
char *tmp = NULL;
|
|
info.type = EFL_TEXT_CHANGE_TYPE_REMOVE;
|
|
if (backspace)
|
|
{
|
|
|
|
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(obj);
|
|
evas_textblock_cursor_copy(efl_text_cursor_object_handle_get(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.position = evas_textblock_cursor_pos_get(cc);
|
|
info.length = pos -info.position;
|
|
|
|
tmp = evas_textblock_cursor_range_text_get(efl_text_cursor_object_handle_get(c), cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
|
|
evas_textblock_cursor_range_delete(efl_text_cursor_object_handle_get(c), cc);
|
|
evas_textblock_cursor_free(cc);
|
|
}
|
|
else
|
|
{
|
|
Evas_Textblock_Cursor *cc = evas_object_textblock_cursor_new(obj);
|
|
evas_textblock_cursor_copy(efl_text_cursor_object_handle_get(c), cc);
|
|
|
|
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.position = pos;
|
|
info.length = evas_textblock_cursor_pos_get(cc) - info.position;
|
|
|
|
tmp = evas_textblock_cursor_range_text_get(efl_text_cursor_object_handle_get(c), cc, EVAS_TEXTBLOCK_TEXT_MARKUP);
|
|
evas_textblock_cursor_range_delete(efl_text_cursor_object_handle_get(c), cc);
|
|
evas_textblock_cursor_free(cc);
|
|
}
|
|
|
|
info.type = EFL_TEXT_CHANGE_TYPE_REMOVE;
|
|
info.position = pos;
|
|
info.length = 1;
|
|
info.content = tmp;
|
|
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
|
|
if (tmp) free(tmp);
|
|
}
|
|
|
|
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(Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
char *str;
|
|
|
|
EINA_LIST_FREE(en->seq, str)
|
|
eina_stringshare_del(str);
|
|
en->composing = EINA_FALSE;
|
|
}
|
|
|
|
/*
|
|
* shift: if shift is pressed.
|
|
* movement_forward: if the movement we are going to do is forward (towards the end of the textblock)
|
|
*/
|
|
static void
|
|
_key_down_sel_pre(Efl_Ui_Internal_Text_Interactive *obj, Efl_Text_Cursor_Object *cur, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Bool shift, Eina_Bool movement_forward)
|
|
{
|
|
if (en->select_allow)
|
|
{
|
|
if (shift)
|
|
{
|
|
_sel_init(cur, en);
|
|
}
|
|
else if (en->have_selection)
|
|
{
|
|
Eina_Bool sel_forward = efl_text_cursor_object_compare(en->sel_start, en->sel_end);
|
|
if ((sel_forward && movement_forward) || (!sel_forward && !movement_forward))
|
|
_cur_pos_copy(en->sel_end, cur);
|
|
else
|
|
_cur_pos_copy(en->sel_start, cur);
|
|
|
|
_sel_clear(obj, en);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
_key_down_sel_post(Efl_Ui_Internal_Text_Interactive *obj, Efl_Text_Cursor_Object *cur, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Bool shift)
|
|
{
|
|
if (en->select_allow)
|
|
{
|
|
if (shift) _sel_extend(cur, obj, en);
|
|
else _sel_clear(obj, en);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_key_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
|
|
{
|
|
Evas_Event_Key_Down *ev = event_info;
|
|
Efl_Text_Cursor_Object *cur;
|
|
Eina_Bool control, alt, shift;
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
Eina_Bool super, altgr;
|
|
#endif
|
|
Eina_Bool multiline;
|
|
int old_cur_pos;
|
|
char *string = (char *)ev->string;
|
|
Eina_Bool free_string = EINA_FALSE;
|
|
Eina_Bool changed_user = EINA_FALSE;
|
|
Efl_Text_Change_Info info = { NULL, 0, 0, 0, 0 };
|
|
|
|
if (!ev->key) return;
|
|
if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
|
|
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
/* FIXME: Maybe allow selctions to happen even when not editable. */
|
|
if (!en->editable) return;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
{
|
|
Ecore_IMF_Event_Key_Down ecore_ev;
|
|
//FIXME
|
|
//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
|
|
|
|
cur = efl_text_interactive_main_cursor_get(obj);
|
|
old_cur_pos = efl_text_cursor_object_position_get(cur);
|
|
if (old_cur_pos < 0) return;
|
|
|
|
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");
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
super = evas_key_modifier_is_set(ev->modifiers, "Super");
|
|
altgr = evas_key_modifier_is_set(ev->modifiers, "AltGr");
|
|
#endif
|
|
multiline = efl_text_multiline_get(obj);
|
|
|
|
/* Translate some keys to strings. */
|
|
if (!strcmp(ev->key, "Tab"))
|
|
{
|
|
if (multiline)
|
|
{
|
|
string = "\t";
|
|
}
|
|
}
|
|
else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
|
|
{
|
|
if (multiline)
|
|
{
|
|
//FIXME this should be Fixed when multiline set works fine with PARAGRAPH_SEPARATOR
|
|
//Now only \n can work with multiline set
|
|
//if (shift || efl_canvas_textblock_newline_as_paragraph_separator_get(obj))
|
|
{
|
|
string = "\n";
|
|
}
|
|
/*else
|
|
{
|
|
string = _PARAGRAPH_SEPARATOR_UTF8;
|
|
}*/
|
|
}
|
|
}
|
|
|
|
|
|
/* Key handling */
|
|
if (!strcmp(ev->key, "Escape"))
|
|
{
|
|
_compose_seq_reset(en);
|
|
// dead keys here. Escape for now (should emit these)
|
|
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)
|
|
{
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_FALSE);
|
|
|
|
if (efl_text_interactive_have_selection_get(obj))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
if (efl_text_cursor_object_line_jump_by(cur, -1))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
}
|
|
}
|
|
else if (!strcmp(ev->key, "Down") ||
|
|
(!strcmp(ev->key, "KP_Down") && !ev->string))
|
|
{
|
|
_compose_seq_reset(en);
|
|
if (multiline)
|
|
{
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_TRUE);
|
|
|
|
if (efl_text_interactive_have_selection_get(obj))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
if (efl_text_cursor_object_line_jump_by(cur, 1))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
}
|
|
}
|
|
else if (!strcmp(ev->key, "Left") ||
|
|
(!strcmp(ev->key, "KP_Left") && !ev->string))
|
|
{
|
|
_compose_seq_reset(en);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_FALSE);
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
if (altgr) efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
|
|
#else
|
|
/* If control is pressed, go to the start of the word */
|
|
if (control) efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
|
|
#endif
|
|
if (efl_text_interactive_have_selection_get(obj))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
if (efl_text_cursor_object_move(cur,EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_PREVIOUS))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
}
|
|
else if (!strcmp(ev->key, "Right") ||
|
|
(!strcmp(ev->key, "KP_Right") && !ev->string))
|
|
{
|
|
_compose_seq_reset(en);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_TRUE);
|
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
|
if (altgr) efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
|
|
#else
|
|
/* If control is pressed, go to the end of the word */
|
|
if (control) efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
|
|
#endif
|
|
if (efl_text_interactive_have_selection_get(obj))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
if (efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT))
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
}
|
|
else if (!strcmp(ev->key, "BackSpace"))
|
|
{
|
|
_compose_seq_reset(en);
|
|
if (control && !en->have_selection)
|
|
{
|
|
// del to start of previous word
|
|
Efl_Text_Cursor_Object *tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_PREVIOUS);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
|
|
|
|
_range_del_emit(obj, cur, tc);
|
|
|
|
efl_del(tc);
|
|
}
|
|
else if ((alt) && (shift))
|
|
{
|
|
// undo last action
|
|
}
|
|
else
|
|
{
|
|
if (en->have_selection)
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
}
|
|
else
|
|
{
|
|
_delete_emit(obj, cur, en, old_cur_pos, EINA_TRUE);
|
|
}
|
|
}
|
|
_sel_clear(obj, en);
|
|
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
|
|
Efl_Text_Cursor_Object *tc = efl_canvas_textblock_cursor_create(obj);
|
|
|
|
_cur_pos_copy(cur, tc);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
|
|
|
|
_range_del_emit(obj, cur, tc);
|
|
|
|
//efl_del(tc);
|
|
efl_del(tc);
|
|
}
|
|
else if (shift)
|
|
{
|
|
// cut
|
|
}
|
|
else
|
|
{
|
|
if (en->have_selection)
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
}
|
|
else
|
|
{
|
|
_delete_emit(obj, cur, en, old_cur_pos, EINA_FALSE);
|
|
}
|
|
}
|
|
_sel_clear(obj, en);
|
|
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);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_FALSE);
|
|
|
|
if ((control) && (multiline))
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
|
|
else
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START);
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
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);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_TRUE);
|
|
|
|
if ((control) && (multiline))
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
|
|
else
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
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)
|
|
{
|
|
efl_text_interactive_all_unselect(obj);
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
}
|
|
else
|
|
{
|
|
efl_text_interactive_all_select(obj);
|
|
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
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_REDO_REQUEST, NULL);
|
|
}
|
|
else
|
|
{
|
|
// undo
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_UNDO_REQUEST, NULL);
|
|
}
|
|
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
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_REDO_REQUEST, NULL);
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
}
|
|
else if (shift && !strcmp(ev->key, "Tab"))
|
|
{
|
|
_compose_seq_reset(en);
|
|
if (multiline)
|
|
{
|
|
// remove a tab
|
|
}
|
|
}
|
|
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);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_FALSE);
|
|
|
|
efl_text_cursor_object_line_jump_by(cur, -10);
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
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);
|
|
_key_down_sel_pre(obj, cur, en, shift, EINA_TRUE);
|
|
|
|
efl_text_cursor_object_line_jump_by(cur, 10);
|
|
|
|
_key_down_sel_post(obj, cur, en, shift);
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
}
|
|
else
|
|
{
|
|
char *compres = NULL;
|
|
Ecore_Compose_State state;
|
|
|
|
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 defined(__APPLE__) && defined(__MACH__)
|
|
if (super ||
|
|
(string && (!string[1]) &&
|
|
(string[0] != 0xa) && (string[0] != 0x9) &&
|
|
((string[0] < 0x20) || (string[0] == 0x7f))))
|
|
#else
|
|
if (string && (!string[1]) &&
|
|
(string[0] != 0xa) && (string[0] != 0x9) &&
|
|
((string[0] < 0x20) || (string[0] == 0x7f)))
|
|
#endif
|
|
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)
|
|
{
|
|
if (en->have_selection)
|
|
{
|
|
_sel_range_del_emit(obj, en);
|
|
info.mergeable = EINA_TRUE;
|
|
}
|
|
info.type = EFL_TEXT_CHANGE_TYPE_INSERT;
|
|
info.content = string;
|
|
info.position = efl_text_cursor_object_position_get(cur);
|
|
info.length = eina_unicode_utf8_get_len(string);
|
|
|
|
efl_text_cursor_object_text_insert(cur, string);
|
|
changed_user = EINA_TRUE;
|
|
|
|
ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
|
|
|
|
if (free_string) free(string);
|
|
}
|
|
}
|
|
end:
|
|
if (changed_user)
|
|
{
|
|
efl_event_callback_call(obj, EFL_TEXT_INTERACTIVE_EVENT_CHANGED_USER, &info);
|
|
}
|
|
(void) 0;
|
|
}
|
|
|
|
static void
|
|
_cursor_char_coord_set(Efl_Canvas_Textblock *obj, Efl_Text_Cursor_Object *cur, Evas_Coord canvasx, Evas_Coord canvasy, Evas_Coord *_cx, Evas_Coord *_cy)
|
|
{
|
|
Evas_Coord cx, cy;
|
|
Evas_Coord x, y, lh = 0, cly = 0;
|
|
Efl_Text_Cursor_Object *line_cur;
|
|
Efl_Text_Cursor_Object *tc;
|
|
|
|
tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
evas_object_geometry_get(obj, &x, &y, NULL, NULL);
|
|
cx = canvasx - x;
|
|
cy = canvasy - y;
|
|
|
|
line_cur = efl_canvas_textblock_cursor_create(obj);
|
|
efl_text_cursor_object_move(line_cur, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
|
|
evas_textblock_cursor_line_geometry_get(efl_text_cursor_object_handle_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
|
|
}
|
|
efl_text_cursor_object_move(line_cur, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
|
|
evas_textblock_cursor_line_geometry_get(efl_text_cursor_object_handle_get(line_cur), NULL, &cly, NULL, NULL);
|
|
|
|
if (cy < cly && cy > (cly - lh / 2))
|
|
{
|
|
cy = cly;
|
|
}
|
|
efl_del(line_cur);
|
|
/* No need to check return value if not able to set the char coord Textblock
|
|
* will take care */
|
|
efl_text_cursor_object_char_coord_set(cur, EINA_POSITION2D(cx, cy));
|
|
if (_cx) *_cx = cx;
|
|
if (_cy) *_cy = cy;
|
|
}
|
|
|
|
static void
|
|
_mouse_down_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
|
|
{
|
|
Evas_Coord cx, cy;
|
|
Evas_Event_Mouse_Down *ev = event_info;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Efl_Text_Cursor_Object *tc = NULL;
|
|
Eina_Bool dosel = EINA_FALSE;
|
|
Eina_Bool shift;
|
|
|
|
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
|
|
|
|
_entry_imf_context_reset(en);
|
|
|
|
shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
|
|
|
|
if (en->select_allow && ev->button != 2) dosel = EINA_TRUE;
|
|
if (dosel)
|
|
{
|
|
if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
|
|
{
|
|
if (shift)
|
|
{
|
|
tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
if (efl_text_cursor_object_compare(cur, en->sel_start) < 0)
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START);
|
|
else
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
else
|
|
{
|
|
en->have_selection = EINA_FALSE;
|
|
en->selecting = EINA_FALSE;
|
|
_sel_clear(obj, en);
|
|
tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_START);
|
|
_sel_init(cur, en);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_LINE_END);
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
goto end;
|
|
}
|
|
else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
|
|
{
|
|
if (shift)
|
|
{
|
|
tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
if (efl_text_cursor_object_compare(cur, en->sel_start) < 0)
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
|
|
else
|
|
{
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
|
|
}
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
else
|
|
{
|
|
en->have_selection = EINA_FALSE;
|
|
en->selecting = EINA_FALSE;
|
|
_sel_clear(obj, en);
|
|
tc = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_START);
|
|
_sel_init(cur, en);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_WORD_END);
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_CHARACTER_NEXT);
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
goto end;
|
|
}
|
|
}
|
|
_cursor_char_coord_set(obj, cur, ev->canvas.x, ev->canvas.y, &cx, &cy);
|
|
|
|
if (dosel)
|
|
{
|
|
if ((en->have_selection) && (shift))
|
|
{
|
|
_sel_extend(cur, obj, en);
|
|
}
|
|
else
|
|
{
|
|
en->selecting = EINA_TRUE;
|
|
_sel_clear(obj, en);
|
|
_sel_init(cur, en);
|
|
}
|
|
}
|
|
|
|
end:
|
|
(void) 0;
|
|
}
|
|
|
|
static void
|
|
_mouse_up_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
|
|
{
|
|
Evas_Coord cx, cy;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Evas_Event_Mouse_Up *ev = event_info;
|
|
|
|
if ((!ev) || (ev->button != 1)) 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
|
|
|
|
_cursor_char_coord_set(obj, cur, ev->canvas.x, ev->canvas.y, &cx, &cy);
|
|
|
|
if (en->select_allow)
|
|
{
|
|
_cur_pos_copy(en->sel_end, cur);
|
|
}
|
|
if (en->selecting)
|
|
{
|
|
if (en->have_selection)
|
|
en->had_sel = EINA_TRUE;
|
|
en->selecting = EINA_FALSE;
|
|
}
|
|
|
|
_entry_imf_cursor_info_set(en);
|
|
}
|
|
|
|
static void
|
|
_mouse_move_cb(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info)
|
|
{
|
|
Evas_Coord cx, cy;
|
|
Efl_Ui_Internal_Text_Interactive_Data *en = efl_data_scope_get(obj, MY_CLASS);
|
|
Efl_Text_Cursor_Object *cur = efl_text_interactive_main_cursor_get(obj);
|
|
Evas_Event_Mouse_Move *ev = event_info;
|
|
Evas_Coord x, y, w, h;
|
|
Efl_Text_Cursor_Object *tc;
|
|
Eina_Bool multiline;
|
|
|
|
multiline = efl_text_multiline_get(obj);
|
|
|
|
#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 = efl_canvas_textblock_cursor_create(obj);
|
|
_cur_pos_copy(cur, tc);
|
|
evas_object_geometry_get(obj, &x, &y, &w, &h);
|
|
cx = ev->cur.canvas.x - x;
|
|
cy = ev->cur.canvas.y - y;
|
|
|
|
if (multiline)
|
|
{
|
|
efl_text_cursor_object_char_coord_set(cur, EINA_POSITION2D(cx, cy));
|
|
}
|
|
else
|
|
{
|
|
Evas_Coord lx, ly, lw, lh;
|
|
efl_text_cursor_object_move(cur, EFL_TEXT_CURSOR_MOVE_TYPE_FIRST);
|
|
evas_textblock_cursor_line_geometry_get(efl_text_cursor_object_handle_get(cur), &lx, &ly, &lw, &lh);
|
|
efl_text_cursor_object_char_coord_set(cur, EINA_POSITION2D(cx, ly + (lh / 2)));
|
|
}
|
|
|
|
if (en->select_allow)
|
|
{
|
|
_sel_extend(cur, obj, en);
|
|
|
|
if (!efl_text_cursor_object_equal(en->sel_start, en->sel_end))
|
|
_sel_enable(obj, en);
|
|
}
|
|
efl_del(tc);
|
|
}
|
|
}
|
|
|
|
EOLIAN static Efl_Text_Cursor_Object *
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_main_cursor_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *pd)
|
|
{
|
|
return pd->main_cursor;
|
|
}
|
|
|
|
EOLIAN static Efl_Object *
|
|
_efl_ui_internal_text_interactive_efl_object_constructor(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
obj = efl_constructor(efl_super(obj, MY_CLASS));
|
|
en->select_allow = EINA_TRUE;
|
|
en->editable = EINA_TRUE;
|
|
en->watch_selection = EINA_TRUE;
|
|
return obj;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_object_destructor(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *sd)
|
|
{
|
|
eina_stringshare_del(sd->file);
|
|
sd->file = NULL;
|
|
efl_destructor(efl_super(obj, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static Efl_Object *
|
|
_efl_ui_internal_text_interactive_efl_object_finalize(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_IN, _focus_in_cb, NULL);
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_FOCUS_OUT, _focus_out_cb, NULL);
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_KEY_DOWN, _key_down_cb, NULL);
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, NULL);
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, _mouse_up_cb, NULL);
|
|
evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_MOVE, _mouse_move_cb, NULL);
|
|
|
|
en->main_cursor = efl_canvas_textblock_cursor_create(obj);
|
|
en->sel_start = efl_canvas_textblock_cursor_create(obj);
|
|
en->sel_end = efl_canvas_textblock_cursor_create(obj);
|
|
|
|
efl_event_callback_add(en->sel_start, EFL_TEXT_CURSOR_OBJECT_EVENT_CHANGED,
|
|
_sel_cursor_changed, obj);
|
|
efl_event_callback_add(en->sel_end, EFL_TEXT_CURSOR_OBJECT_EVENT_CHANGED,
|
|
_sel_cursor_changed, obj);
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
{
|
|
const char *ctx_id;
|
|
const Ecore_IMF_Context_Info *ctx_info;
|
|
Evas *evas = evas_object_evas_get(obj);
|
|
// _need_imf();
|
|
|
|
en->commit_cancel = EINA_FALSE;
|
|
|
|
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(evas)));
|
|
ecore_imf_context_client_canvas_set(en->imf_context, evas);
|
|
|
|
ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context,
|
|
_entry_imf_retrieve_surrounding_cb, obj);
|
|
ecore_imf_context_retrieve_selection_callback_set(en->imf_context, _entry_imf_retrieve_selection_cb, obj);
|
|
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_COMMIT, _entry_imf_event_commit_cb, obj);
|
|
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, _entry_imf_event_delete_surrounding_cb, obj);
|
|
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_PREEDIT_CHANGED, _entry_imf_event_preedit_changed_cb, obj);
|
|
ecore_imf_context_event_callback_add(en->imf_context, ECORE_IMF_CALLBACK_SELECTION_SET, _entry_imf_event_selection_set_cb, obj);
|
|
#if 0
|
|
// FIXME
|
|
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->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
|
|
ecore_imf_context_input_panel_language_set(en->imf_context, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET);
|
|
#endif
|
|
|
|
if (efl_text_multiline_get(obj))
|
|
ecore_imf_context_input_hint_set(en->imf_context,
|
|
ecore_imf_context_input_hint_get(en->imf_context) | ECORE_IMF_INPUT_HINT_MULTILINE);
|
|
}
|
|
#endif
|
|
|
|
done:
|
|
return efl_finalize(efl_super(obj, MY_CLASS));
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_text_set(Eo *eo_obj, Efl_Ui_Internal_Text_Interactive_Data *o,
|
|
const char *text)
|
|
{
|
|
efl_text_set(efl_super(eo_obj, MY_CLASS), text);
|
|
efl_text_cursor_object_move(o->main_cursor, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
|
|
}
|
|
|
|
EOLIAN void
|
|
_efl_ui_internal_text_interactive_efl_text_markup_markup_set(Eo *eo_obj, Efl_Ui_Internal_Text_Interactive_Data *o,
|
|
const char *text)
|
|
{
|
|
efl_text_markup_set(efl_super(eo_obj, MY_CLASS), text);
|
|
efl_text_cursor_object_move(o->main_cursor, EFL_TEXT_CURSOR_MOVE_TYPE_LAST);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_selection_allowed_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *pd, Eina_Bool allowed)
|
|
{
|
|
if (pd->select_allow == allowed)
|
|
return;
|
|
|
|
pd->select_allow = allowed;
|
|
if (!allowed)
|
|
{
|
|
_sel_clear(obj, pd);
|
|
}
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_selection_allowed_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *pd)
|
|
{
|
|
return pd->select_allow;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_selection_cursors_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *pd, Efl_Text_Cursor_Object **start, Efl_Text_Cursor_Object **end)
|
|
{
|
|
if (efl_text_cursor_object_position_get(pd->sel_start) >
|
|
efl_text_cursor_object_position_get(pd->sel_end))
|
|
{
|
|
if (start) *start = pd->sel_end;
|
|
if (end) *end = pd->sel_start;
|
|
}
|
|
else
|
|
{
|
|
if (start) *start = pd->sel_start;
|
|
if (end) *end = pd->sel_end;
|
|
}
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_selection_cursors_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Text_Cursor_Object *start, Efl_Text_Cursor_Object *end)
|
|
{
|
|
if (!efl_text_interactive_selection_allowed_get(obj))
|
|
return;
|
|
|
|
int new_sel_start_pos = efl_text_cursor_object_position_get(start);
|
|
int new_sel_end_pos = efl_text_cursor_object_position_get(end);
|
|
|
|
int current_sel_start_pos = efl_text_cursor_object_position_get(en->sel_start);
|
|
int current_sel_end_pos = efl_text_cursor_object_position_get(en->sel_end);
|
|
|
|
Eina_Bool b_start_changed = (new_sel_start_pos == current_sel_start_pos);
|
|
Eina_Bool b_end_changed = (new_sel_end_pos == current_sel_end_pos);
|
|
|
|
if (b_start_changed && b_end_changed)
|
|
return;
|
|
|
|
_sel_watch_freeze(en);
|
|
efl_text_cursor_object_position_set(en->sel_start, new_sel_start_pos);
|
|
efl_text_cursor_object_position_set(en->sel_end, new_sel_end_pos);
|
|
_sel_watch_thaw(en);
|
|
_sel_reset(obj, en);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_editable_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd, Eina_Bool editable)
|
|
{
|
|
sd->editable = editable;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_text_interactive_editable_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd)
|
|
{
|
|
return sd->editable;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_hide(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_panel_hide(en->imf_context);
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_language_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Input_Text_Panel_Language_Type lang)
|
|
{
|
|
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);
|
|
#else
|
|
(void)en;
|
|
(void)lang;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Efl_Input_Text_Panel_Language_Type
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_language_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
return en->input_panel_lang;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_imdata_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Slice slice)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_panel_imdata_set(en->imf_context, slice.mem, slice.len);
|
|
#else
|
|
(void)en;
|
|
(void)data;
|
|
(void)len;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Eina_Slice
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_imdata_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
Eina_Slice slice = {0};
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
{
|
|
int len;
|
|
ecore_imf_context_input_panel_imdata_get(en->imf_context, &slice.mem, &len);
|
|
slice.len = (size_t)len;
|
|
}
|
|
#else
|
|
(void)en;
|
|
(void)data;
|
|
(void)len;
|
|
#endif
|
|
return slice;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_return_key_type_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Input_Text_Panel_Return_Key_Type return_key_type)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
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)en;
|
|
(void)return_key_type;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Efl_Input_Text_Panel_Return_Key_Type
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_return_key_type_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
return (Efl_Input_Text_Panel_Return_Key_Type)ecore_imf_context_input_panel_return_key_type_get(en->imf_context);
|
|
return EFL_INPUT_TEXT_PANEL_RETURN_KEY_TYPE_DEFAULT;
|
|
#else
|
|
return EFL_INPUT_TEXT_PANEL_RETURN_KEY_TYPE_DEFAULT;
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_return_key_state_set(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Input_Text_Panel_Return_Key_State state)
|
|
{
|
|
if (en->input_panel_return_key_state == state)
|
|
return;
|
|
|
|
en->input_panel_return_key_state = state;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
{
|
|
switch (state)
|
|
{
|
|
case EFL_INPUT_TEXT_PANEL_RETURN_KEY_STATE_ENABLED:
|
|
ecore_imf_context_input_panel_return_key_disabled_set(en->imf_context, EINA_TRUE);
|
|
break;
|
|
case EFL_INPUT_TEXT_PANEL_RETURN_KEY_STATE_DISABLED:
|
|
ecore_imf_context_input_panel_return_key_disabled_set(en->imf_context, EINA_FALSE);
|
|
break;
|
|
case EFL_INPUT_TEXT_PANEL_RETURN_KEY_STATE_AUTO:
|
|
_return_key_update(obj);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
(void)obj;
|
|
(void)en;
|
|
(void)disabled;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Efl_Input_Text_Panel_Return_Key_State
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_return_key_state_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
return en->input_panel_return_key_state;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_show_on_demand_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Bool ondemand)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_panel_show_on_demand_set(en->imf_context, ondemand);
|
|
#else
|
|
(void)en;
|
|
(void)ondemand;
|
|
#endif
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_layout_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd, Efl_Input_Text_Panel_Layout_Type layout)
|
|
{
|
|
sd->input_panel_layout = layout;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (sd->imf_context)
|
|
ecore_imf_context_input_panel_layout_set(sd->imf_context, (Ecore_IMF_Input_Panel_Layout)layout);
|
|
#endif
|
|
|
|
if (layout == EFL_INPUT_TEXT_PANEL_LAYOUT_TYPE_PASSWORD)
|
|
efl_input_text_input_content_type_set(obj, ((sd->input_hints & ~EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE) | EFL_INPUT_TEXT_CONTENT_TYPE_SENSITIVE_DATA));
|
|
else if (layout == EFL_INPUT_TEXT_PANEL_LAYOUT_TYPE_TERMINAL)
|
|
efl_input_text_input_content_type_set(obj, (sd->input_hints & ~EFL_INPUT_TEXT_CONTENT_TYPE_AUTO_COMPLETE));
|
|
}
|
|
|
|
EOLIAN static Efl_Input_Text_Panel_Layout_Type
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_layout_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd)
|
|
{
|
|
return sd->input_panel_layout;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_layout_variation_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd, int variation)
|
|
{
|
|
sd->input_panel_layout_variation = variation;
|
|
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (sd->imf_context)
|
|
ecore_imf_context_input_panel_layout_variation_set(sd->imf_context, variation);
|
|
#else
|
|
(void)variation;
|
|
#endif
|
|
|
|
if (sd->input_panel_layout == EFL_INPUT_TEXT_PANEL_LAYOUT_TYPE_NORMAL &&
|
|
variation == EFL_INPUT_TEXT_PANEL_LAYOUT_NORMAL_VARIATION_TYPE_PERSON_NAME)
|
|
efl_input_text_autocapitalization_set(obj, EFL_INPUT_TEXT_CAPITALIZE_TYPE_WORD);
|
|
}
|
|
|
|
EOLIAN static int
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_layout_variation_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *sd)
|
|
{
|
|
return sd->input_panel_layout_variation;
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_show(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_panel_show(en->imf_context);
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_autoshow_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Bool enabled)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_panel_enabled_set(en->imf_context, enabled);
|
|
#else
|
|
(void)en;
|
|
(void)enabled;
|
|
#endif
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_autoshow_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
return ecore_imf_context_input_panel_enabled_get(en->imf_context);
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_panel_show_on_demand_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#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;
|
|
}
|
|
#else
|
|
(void)en;
|
|
#endif
|
|
return EINA_FALSE;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_predictable_set(Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en, Eina_Bool prediction)
|
|
{
|
|
en->prediction_allow = prediction;
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_prediction_allow_set(en->imf_context, prediction);
|
|
#else
|
|
(void)en;
|
|
(void)prediction;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Eina_Bool
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_predictable_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
return en->prediction_allow;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_content_type_set(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Input_Text_Content_Type input_hints)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
ecore_imf_context_input_hint_set(en->imf_context, (Ecore_IMF_Input_Hints)input_hints);
|
|
(void)obj;
|
|
#else
|
|
(void)obj;
|
|
(void)en;
|
|
(void)input_hints;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Efl_Input_Text_Content_Type
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_input_content_type_get(const Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
return (Efl_Input_Text_Content_Type)ecore_imf_context_input_hint_get(en->imf_context);
|
|
(void)obj;
|
|
#else
|
|
(void)obj;
|
|
(void)en;
|
|
#endif
|
|
|
|
return ELM_INPUT_HINT_NONE;
|
|
}
|
|
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_autocapitalization_set(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *en, Efl_Input_Text_Capitalize_Type autocapital_type)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (efl_text_password_get(obj) == EINA_TRUE)
|
|
autocapital_type = EFL_INPUT_TEXT_CAPITALIZE_TYPE_NONE;
|
|
|
|
if (en->imf_context)
|
|
ecore_imf_context_autocapital_type_set(en->imf_context, (Ecore_IMF_Autocapital_Type)autocapital_type);
|
|
#else
|
|
(void)obj;
|
|
(void)en;
|
|
(void)autocapital_type;
|
|
#endif
|
|
}
|
|
|
|
|
|
EOLIAN static Efl_Input_Text_Capitalize_Type
|
|
_efl_ui_internal_text_interactive_efl_input_text_entity_autocapitalization_get(const Eo *obj EINA_UNUSED, Efl_Ui_Internal_Text_Interactive_Data *en)
|
|
{
|
|
#ifdef HAVE_ECORE_IMF
|
|
if (en->imf_context)
|
|
return (Efl_Input_Text_Capitalize_Type)ecore_imf_context_autocapital_type_get(en->imf_context);
|
|
return EFL_INPUT_TEXT_CAPITALIZE_TYPE_NONE;
|
|
#else
|
|
(void)en;
|
|
return EFL_INPUT_TEXT_CAPITALIZE_TYPE_NONE;
|
|
#endif
|
|
}
|
|
|
|
|
|
static char *
|
|
_file_load(Eo *obj)
|
|
{
|
|
Eina_File *f;
|
|
char *text = NULL;
|
|
void *tmp = NULL;
|
|
|
|
f = eina_file_dup(efl_file_mmap_get(obj));
|
|
|
|
tmp = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
|
|
if (!tmp) goto on_error;
|
|
|
|
text = malloc(eina_file_size_get(f) + 1);
|
|
if (!text) goto on_error;
|
|
|
|
memcpy(text, tmp, eina_file_size_get(f));
|
|
text[eina_file_size_get(f)] = 0;
|
|
|
|
if (eina_file_map_faulted(f, tmp))
|
|
{
|
|
ELM_SAFE_FREE(text, free);
|
|
}
|
|
|
|
on_error:
|
|
if (tmp) eina_file_map_free(f, tmp);
|
|
eina_file_close(f);
|
|
|
|
return text;
|
|
}
|
|
|
|
static char *
|
|
_plain_load(Eo *obj)
|
|
{
|
|
return _file_load(obj);
|
|
}
|
|
|
|
static Eina_Error
|
|
_load_do(Evas_Object *obj)
|
|
{
|
|
char *text;
|
|
Eina_Error err = 0;
|
|
|
|
Efl_Ui_Internal_Text_Interactive_Data * sd = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (!sd->file)
|
|
{
|
|
efl_text_set(obj, "");
|
|
return 0;
|
|
}
|
|
|
|
switch (sd->format)
|
|
{
|
|
/* Only available format */
|
|
case ELM_TEXT_FORMAT_PLAIN_UTF8:
|
|
text = _plain_load(obj);
|
|
if (!text)
|
|
{
|
|
err = errno;
|
|
if (!err) err = ENOENT;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
text = NULL;
|
|
break;
|
|
}
|
|
|
|
if (text)
|
|
{
|
|
efl_text_set(obj, text);
|
|
free(text);
|
|
return 0;
|
|
}
|
|
efl_text_set(obj, "");
|
|
return err;
|
|
}
|
|
|
|
static void
|
|
_text_save(const char *file,
|
|
const char *text)
|
|
{
|
|
FILE *f;
|
|
|
|
if (!text)
|
|
{
|
|
ecore_file_unlink(file);
|
|
return;
|
|
}
|
|
|
|
f = fopen(file, "wb");
|
|
if (!f)
|
|
{
|
|
ERR("Failed to open %s for writing", file);
|
|
return;
|
|
}
|
|
|
|
if (fputs(text, f) == EOF)
|
|
ERR("Failed to write text to file %s", file);
|
|
fclose(f);
|
|
}
|
|
|
|
static void
|
|
_save_do(Evas_Object *obj)
|
|
{
|
|
Efl_Ui_Internal_Text_Interactive_Data * sd = efl_data_scope_get(obj, MY_CLASS);
|
|
|
|
if (!sd->file) return;
|
|
switch (sd->format)
|
|
{
|
|
/* Only supported format */
|
|
case ELM_TEXT_FORMAT_PLAIN_UTF8:
|
|
_text_save(sd->file, efl_text_get(obj));
|
|
break;
|
|
|
|
case ELM_TEXT_FORMAT_MARKUP_UTF8:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
EOLIAN static Eina_Error
|
|
_efl_ui_internal_text_interactive_efl_file_file_set(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *sd, const char *file)
|
|
{
|
|
eina_stringshare_replace(&sd->file, file);
|
|
return efl_file_set(efl_super(obj, MY_CLASS), file);
|
|
}
|
|
|
|
EOLIAN static void
|
|
_efl_ui_internal_text_interactive_efl_file_unload(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *sd EINA_UNUSED)
|
|
{
|
|
efl_file_unload(efl_super(obj, MY_CLASS));
|
|
efl_text_set(obj, "");
|
|
}
|
|
|
|
EOLIAN static Eina_Error
|
|
_efl_ui_internal_text_interactive_efl_file_load(Eo *obj, Efl_Ui_Internal_Text_Interactive_Data *sd)
|
|
{
|
|
Eina_Error err;
|
|
|
|
if (efl_file_loaded_get(obj)) return 0;
|
|
err = efl_file_load(efl_super(obj, MY_CLASS));
|
|
if (err) return err;
|
|
if (sd->auto_save) _save_do(obj);
|
|
return _load_do(obj);
|
|
}
|
|
|
|
|
|
#include "efl_ui_internal_text_interactive.eo.c"
|
|
#include "efl_text_interactive.eo.c"
|