Filter input text in entries.

Users can set filters of their own (text only, no format now) or use the
predefined ones.


SVN revision: 53141
This commit is contained in:
Iván Briano 2010-10-07 12:50:00 +00:00
parent 4f3090af01
commit 4c8980e47e
4 changed files with 638 additions and 2 deletions

View File

@ -229,6 +229,8 @@ void
test_entry_scrolled(void *data, Evas_Object *obj, void *event_info)
{
Evas_Object *win, *bg, *bx, *bx2, *bt, *en, *en_p, *sp;
static Elm_Entry_Filter_Accept_Set digits_filter_data, digits_filter_data2;
static Elm_Entry_Filter_Limit_Size limit_filter_data, limit_filter_data2;
win = elm_win_add(NULL, "entry-scrolled", ELM_WIN_BASIC);
elm_win_title_set(win, "Entry Scrolled");
@ -300,6 +302,62 @@ test_entry_scrolled(void *data, Evas_Object *obj, void *event_info)
evas_object_show(en);
elm_box_pack_end(bx, en);
/* Only digits entry */
en = elm_scrolled_entry_add(win);
evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(en, EVAS_HINT_FILL, 0.5);
elm_scrolled_entry_entry_set(en, "01234");
elm_scrolled_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
elm_scrolled_entry_single_line_set(en, 1);
evas_object_show(en);
elm_box_pack_end(bx, en);
digits_filter_data.accepted = "0123456789";
digits_filter_data.rejected = NULL;
elm_scrolled_entry_text_filter_append(en, elm_entry_filter_accept_set, &digits_filter_data);
/* No digits entry */
en = elm_scrolled_entry_add(win);
evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(en, EVAS_HINT_FILL, 0.5);
elm_scrolled_entry_entry_set(en, "No numbers here");
elm_scrolled_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
elm_scrolled_entry_single_line_set(en, 1);
evas_object_show(en);
elm_box_pack_end(bx, en);
digits_filter_data2.accepted = NULL;
digits_filter_data2.rejected = "0123456789";
elm_scrolled_entry_text_filter_append(en, elm_entry_filter_accept_set, &digits_filter_data2);
/* Size limited entry */
en = elm_scrolled_entry_add(win);
evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(en, EVAS_HINT_FILL, 0.5);
elm_scrolled_entry_entry_set(en, "Just 20 chars");
elm_scrolled_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
elm_scrolled_entry_single_line_set(en, 1);
evas_object_show(en);
elm_box_pack_end(bx, en);
limit_filter_data.max_char_count = 20;
limit_filter_data.max_byte_count = 0;
elm_scrolled_entry_text_filter_append(en, elm_entry_filter_limit_size, &limit_filter_data);
/* Byte size limited entry */
en = elm_scrolled_entry_add(win);
evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(en, EVAS_HINT_FILL, 0.5);
elm_scrolled_entry_entry_set(en, "And now only 30 bytes");
elm_scrolled_entry_scrollbar_policy_set(en, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);
elm_scrolled_entry_single_line_set(en, 1);
evas_object_show(en);
elm_box_pack_end(bx, en);
limit_filter_data2.max_char_count = 0;
limit_filter_data2.max_byte_count = 30;
elm_scrolled_entry_text_filter_append(en, elm_entry_filter_limit_size, &limit_filter_data2);
/* Single line password entry */
en_p = elm_scrolled_entry_add(win);
evas_object_size_hint_weight_set(en_p, EVAS_HINT_EXPAND, 0.0);

View File

@ -866,8 +866,26 @@ extern "C" {
EAPI void elm_entry_item_provider_append(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_entry_item_provider_prepend(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_entry_item_provider_remove(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_entry_text_filter_append(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI void elm_entry_text_filter_prepend(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI void elm_entry_text_filter_remove(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI char *elm_entry_markup_to_utf8(const char *s);
EAPI char *elm_entry_utf8_to_markup(const char *s);
/* pre-made filters for entries */
typedef struct _Elm_Entry_Filter_Limit_Size Elm_Entry_Filter_Limit_Size;
struct _Elm_Entry_Filter_Limit_Size
{
int max_char_count;
int max_byte_count;
};
EAPI void elm_entry_filter_limit_size(void *data, Evas_Object *entry, char **text);
typedef struct _Elm_Entry_Filter_Accept_Set Elm_Entry_Filter_Accept_Set;
struct _Elm_Entry_Filter_Accept_Set
{
const char *accepted;
const char *rejected;
};
EAPI void elm_entry_filter_accept_set(void *data, Evas_Object *entry, char **text);
/* smart callbacks called:
* "changed" - the text content changed
* "selection,start" - the user started selecting text
@ -1753,6 +1771,12 @@ extern "C" {
EAPI const Evas_Object *elm_scrolled_entry_end_get(Evas_Object *obj);
EAPI Evas_Object *elm_scrolled_entry_end_unset(Evas_Object *obj);
EAPI void elm_scrolled_entry_end_visible_set(Evas_Object *obj, Eina_Bool setting);
EAPI void elm_scrolled_entry_item_provider_append(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_scrolled_entry_item_provider_prepend(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_scrolled_entry_item_provider_remove(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data);
EAPI void elm_scrolled_entry_text_filter_append(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI void elm_scrolled_entry_text_filter_prepend(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI void elm_scrolled_entry_text_filter_remove(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data);
EAPI Evas_Object *elm_conformant_add(Evas_Object *parent);
EAPI void elm_conformant_content_set(Evas_Object *obj, Evas_Object *content);

View File

@ -31,6 +31,9 @@
*/
typedef struct _Widget_Data Widget_Data;
typedef struct _Elm_Entry_Context_Menu_Item Elm_Entry_Context_Menu_Item;
typedef struct _Elm_Entry_Item_Provider Elm_Entry_Item_Provider;
typedef struct _Elm_Entry_Text_Filter Elm_Entry_Text_Filter;
struct _Widget_Data
{
@ -39,9 +42,31 @@ struct _Widget_Data
Evas_Object *icon;
Evas_Object *end;
Elm_Scroller_Policy policy_h, policy_v;
Eina_List *items;
Eina_List *item_providers;
Eina_List *text_filters;
Eina_Bool single_line : 1;
};
struct _Elm_Entry_Context_Menu_Item
{
Evas_Object *obj;
Evas_Smart_Cb func;
void *data;
};
struct _Elm_Entry_Item_Provider
{
Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item);
void *data;
};
struct _Elm_Entry_Text_Filter
{
void (*func) (void *data, Evas_Object *entry, char **text);
void *data;
};
static const char *widtype = NULL;
static const char SIG_CHANGED[] = "changed";
@ -83,7 +108,19 @@ static const Evas_Smart_Cb_Description _signals[] = {
static void
_del_hook(Evas_Object *obj)
{
Elm_Entry_Context_Menu_Item *ci;
Elm_Entry_Item_Provider *ip;
Elm_Entry_Text_Filter *tf;
Widget_Data *wd = elm_widget_data_get(obj);
EINA_LIST_FREE(wd->items, ci)
free(ci);
EINA_LIST_FREE(wd->item_providers, ip)
free(ip);
EINA_LIST_FREE(wd->text_filters, tf)
free(tf);
if (!wd) return;
free(wd);
}
@ -256,6 +293,42 @@ _entry_unfocused(void *data, Evas_Object *obj __UNUSED__, void *event_info)
evas_object_smart_callback_call(data, SIG_UNFOCUSED, event_info);
}
static void
_context_item_wrap_cb(void *data, Evas_Object *obj __UNUSED__, void *event_info)
{
Elm_Entry_Context_Menu_Item *ci = data;
ci->func(ci->data, ci->obj, event_info);
}
static Evas_Object *
_item_provider_wrap_cb(void *data, Evas_Object *obj __UNUSED__, const char *item)
{
Widget_Data *wd = elm_widget_data_get(data);
Eina_List *l;
Elm_Entry_Item_Provider *ip;
EINA_LIST_FOREACH(wd->item_providers, l, ip)
{
Evas_Object *o;
o = ip->func(ip->data, data, item);
if (o) return o;
}
return NULL;
}
static void
_text_filter_wrap_cb(void *data, Evas_Object *obj __UNUSED__, char **text)
{
Widget_Data *wd = elm_widget_data_get(data);
Eina_List *l;
Elm_Entry_Text_Filter *tf;
EINA_LIST_FOREACH(wd->text_filters, l, tf)
{
tf->func(tf->data, data, text);
if (!*text) break;
}
}
/**
* This adds a scrolled entry to @p parent object.
@ -302,7 +375,8 @@ elm_scrolled_entry_add(Evas_Object *parent)
elm_scroller_content_set(wd->scroller, wd->entry);
evas_object_show(wd->entry);
wd->icon = wd->end = NULL;
elm_entry_text_filter_prepend(wd->entry, _text_filter_wrap_cb, obj);
elm_entry_item_provider_prepend(wd->entry, _item_provider_wrap_cb, obj);
evas_object_smart_callback_add(wd->entry, "changed", _entry_changed, obj);
evas_object_smart_callback_add(wd->entry, "activated", _entry_activated, obj);
@ -1109,10 +1183,18 @@ elm_scrolled_entry_context_menu_clear(Evas_Object *obj)
EAPI void
elm_scrolled_entry_context_menu_item_add(Evas_Object *obj, const char *label, const char *icon_file, Elm_Icon_Type icon_type, Evas_Smart_Cb func, const void *data)
{
Elm_Entry_Context_Menu_Item *ci;
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
elm_entry_context_menu_item_add(wd->entry, label, icon_file, icon_type, func, data);
ci = malloc(sizeof(Elm_Entry_Context_Menu_Item));
if (!ci) return;
ci->func = func;
ci->data = (void *)data;
ci->obj = obj;
wd->items = eina_list_append(wd->items, ci);
elm_entry_context_menu_item_add(wd->entry, label, icon_file, icon_type, _context_item_wrap_cb, ci);
}
/**
@ -1186,3 +1268,190 @@ elm_scrolled_entry_bounce_set(Evas_Object *obj, Eina_Bool h_bounce, Eina_Bool v_
if (!wd) return;
elm_scroller_bounce_set(wd->scroller, h_bounce, v_bounce);
}
/**
* This appends a custom item provider to the list for that entry
*
* This appends the given callback. The list is walked from beginning to end
* with each function called given the item href string in the text. If the
* function returns an object handle other than NULL (it should create an
* and object to do this), then this object is used to replace that item. If
* not the next provider is called until one provides an item object, or the
* default provider in entry does.
*
* @param obj The entry object
* @param func The function called to provide the item object
* @param data The data passed to @p func
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_item_provider_append(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
if (!func) return;
Elm_Entry_Item_Provider *ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
if (!ip) return;
ip->func = func;
ip->data = data;
wd->item_providers = eina_list_append(wd->item_providers, ip);
}
/**
* This prepends a custom item provider to the list for that entry
*
* This prepends the given callback. See elm_scrolled_entry_item_provider_append() for
* more information
*
* @param obj The entry object
* @param func The function called to provide the item object
* @param data The data passed to @p func
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_item_provider_prepend(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return;
if (!func) return;
Elm_Entry_Item_Provider *ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
if (!ip) return;
ip->func = func;
ip->data = data;
wd->item_providers = eina_list_prepend(wd->item_providers, ip);
}
/**
* This removes a custom item provider to the list for that entry
*
* This removes the given callback. See elm_scrolled_entry_item_provider_append() for
* more information
*
* @param obj The entry object
* @param func The function called to provide the item object
* @param data The data passed to @p func
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_item_provider_remove(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *entry, const char *item), void *data)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *l;
Elm_Entry_Item_Provider *ip;
if (!wd) return;
if (!func) return;
EINA_LIST_FOREACH(wd->item_providers, l, ip)
{
if ((ip->func == func) && (ip->data == data))
{
wd->item_providers = eina_list_remove_list(wd->item_providers, l);
free(ip);
return;
}
}
}
/**
* Append a filter function for text inserted in the entry
*
* Append the given callback to the list. This functions will be called
* whenever any text is inserted into the entry, with the text to be inserted
* as a parameter. The callback function is free to alter the text in any way
* it wants, but it must remember to free the given pointer and update it.
* If the new text is to be discarded, the function can free it and set it text
* parameter to NULL. This will also prevent any following filters from being
* called.
*
* @param obj The entry object
* @param func The function to use as text filter
* @param data User data to pass to @p func
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_text_filter_append(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
tf = ELM_NEW(Elm_Entry_Text_Filter);
if (!tf) return;
tf->func = func;
tf->data = data;
wd->text_filters = eina_list_append(wd->text_filters, tf);
}
/**
* Prepend a filter function for text insdrted in the entry
*
* Prepend the given callback to the list. See elm_scrolled_entry_text_filter_append()
* for more information
*
* @param obj The entry object
* @param func The function to use as text filter
* @param data User data to pass to @p func
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_text_filter_prepend(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
tf = ELM_NEW(Elm_Entry_Text_Filter);
if (!tf) return;
tf->func = func;
tf->data = data;
wd->text_filters = eina_list_prepend(wd->text_filters, tf);
}
/**
* Remove a filter from the list
*
* Removes the given callback from the filter list. See elm_scrolled_entry_text_filter_append()
* for more information.
*
* @param obj The entry object
* @param func The filter function to remove
* @param data The user data passed when adding the function
*
* @ingroup Scrolled_Entry
*/
EAPI void
elm_scrolled_entry_text_filter_remove(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Eina_List *l;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
EINA_LIST_FOREACH(wd->text_filters, l, tf)
{
if ((tf->func == func) && (tf->data == data))
{
wd->text_filters = eina_list_remove_list(wd->text_filters, l);
free(tf);
return;
}
}
}

View File

@ -91,6 +91,7 @@ typedef struct _Mod_Api Mod_Api;
typedef struct _Widget_Data Widget_Data;
typedef struct _Elm_Entry_Context_Menu_Item Elm_Entry_Context_Menu_Item;
typedef struct _Elm_Entry_Item_Provider Elm_Entry_Item_Provider;
typedef struct _Elm_Entry_Text_Filter Elm_Entry_Text_Filter;
struct _Widget_Data
{
@ -108,6 +109,7 @@ struct _Widget_Data
Evas_Coord cx, cy, cw, ch;
Eina_List *items;
Eina_List *item_providers;
Eina_List *text_filters;
Ecore_Job *hovdeljob;
Mod_Api *api; // module api if supplied
Eina_Bool changed : 1;
@ -142,6 +144,12 @@ struct _Elm_Entry_Item_Provider
void *data;
};
struct _Elm_Entry_Text_Filter
{
void (*func) (void *data, Evas_Object *entry, char **text);
void *data;
};
static const char *widtype = NULL;
static Eina_Bool _drag_drop_cb(void *data, Evas_Object *obj, Elm_Drop_Data *);
@ -231,6 +239,7 @@ _del_hook(Evas_Object *obj)
Widget_Data *wd = elm_widget_data_get(obj);
Elm_Entry_Context_Menu_Item *it;
Elm_Entry_Item_Provider *ip;
Elm_Entry_Text_Filter *tf;
if (wd->hovdeljob) ecore_job_del(wd->hovdeljob);
if ((wd->api) && (wd->api->obj_unhook)) wd->api->obj_unhook(obj); // module - unhook
@ -255,6 +264,10 @@ _del_hook(Evas_Object *obj)
{
free(ip);
}
EINA_LIST_FREE(wd->text_filters, tf)
{
free(tf);
}
free(wd);
}
@ -1322,6 +1335,24 @@ _get_item(void *data, Evas_Object *edje __UNUSED__, const char *part __UNUSED__,
return o;
}
static void
_text_filter(void *data, Evas_Object *edje __UNUSED__, const char *part __UNUSED__, Edje_Text_Filter_Type type, char **text)
{
Widget_Data *wd = elm_widget_data_get(data);
Eina_List *l;
Elm_Entry_Text_Filter *tf;
if (type == EDJE_TEXT_FILTER_FORMAT)
return;
EINA_LIST_FOREACH(wd->text_filters, l, tf)
{
tf->func(tf->data, data, text);
if (!*text)
break;
}
}
/**
* This adds an entry to @p parent object.
*
@ -1363,6 +1394,7 @@ elm_entry_add(Evas_Object *parent)
wd->ent = edje_object_add(e);
edje_object_item_provider_set(wd->ent, _get_item, obj);
edje_object_text_insert_filter_callback_add(wd->ent,"elm.text", _text_filter, obj);
evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOVE, _move, obj);
evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_RESIZE, _resize, obj);
evas_object_event_callback_add(wd->ent, EVAS_CALLBACK_MOUSE_DOWN,
@ -2220,6 +2252,105 @@ elm_entry_item_provider_remove(Evas_Object *obj, Evas_Object *(*func) (void *dat
}
}
/**
* Append a filter function for text inserted in the entry
*
* Append the given callback to the list. This functions will be called
* whenever any text is inserted into the entry, with the text to be inserted
* as a parameter. The callback function is free to alter the text in any way
* it wants, but it must remember to free the given pointer and update it.
* If the new text is to be discarded, the function can free it and set it text
* parameter to NULL. This will also prevent any following filters from being
* called.
*
* @param obj The entry object
* @param func The function to use as text filter
* @param data User data to pass to @p func
*
* @ingroup Entry
*/
EAPI void
elm_entry_text_filter_append(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
tf = ELM_NEW(Elm_Entry_Text_Filter);
if (!tf) return;
tf->func = func;
tf->data = data;
wd->text_filters = eina_list_append(wd->text_filters, tf);
}
/**
* Prepend a filter function for text insdrted in the entry
*
* Prepend the given callback to the list. See elm_entry_text_filter_append()
* for more information
*
* @param obj The entry object
* @param func The function to use as text filter
* @param data User data to pass to @p func
*
* @ingroup Entry
*/
EAPI void
elm_entry_text_filter_prepend(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
tf = ELM_NEW(Elm_Entry_Text_Filter);
if (!tf) return;
tf->func = func;
tf->data = data;
wd->text_filters = eina_list_prepend(wd->text_filters, tf);
}
/**
* Remove a filter from the list
*
* Removes the given callback from the filter list. See elm_entry_text_filter_append()
* for more information.
*
* @param obj The entry object
* @param func The filter function to remove
* @param data The user data passed when adding the function
*
* @ingroup Entry
*/
EAPI void
elm_entry_text_filter_remove(Evas_Object *obj, void (*func) (void *data, Evas_Object *entry, char **text), void *data)
{
Widget_Data *wd;
Eina_List *l;
Elm_Entry_Text_Filter *tf;
ELM_CHECK_WIDTYPE(obj, widtype);
wd = elm_widget_data_get(obj);
if (!func) return;
EINA_LIST_FOREACH(wd->text_filters, l, tf)
{
if ((tf->func == func) && (tf->data == data))
{
wd->text_filters = eina_list_remove_list(wd->text_filters, l);
free(tf);
return;
}
}
}
/**
* This converts a markup (HTML-like) string into UTF-8.
*
@ -2252,6 +2383,160 @@ elm_entry_utf8_to_markup(const char *s)
return ss;
}
/**
* Filter inserted text based on user defined character and byte limits
*
* Add this filter to an entry to limit the characters that it will accept
* based the the contents of the provided Elm_Entry_Filter_Limit_Size.
* The funtion works on the UTF-8 representation of the string, converting
* it from the set markup, thus not accounting for any format in it.
*
* The user must create an Elm_Entry_Filter_Limit_Size structure and pass
* it as data when setting the filter. In it it's possible to set limits
* by character count or bytes (any of them is disabled if 0), and both can
* be set at the same time. In that case, it first checks for characters,
* then bytes.
*
* The function will cut the inserted text in order to allow only the first
* number of characters that are still allowed. The cut is made in
* characters, even when limiting by bytes, in order to always contain
* valid ones and avoid half unicode characters making it in.
*
* @ingroup Entry
*/
EAPI void
elm_entry_filter_limit_size(void *data, Evas_Object *entry, char **text)
{
Elm_Entry_Filter_Limit_Size *lim = data;
char *current;
int len, newlen;
const char *(*text_get)(const Evas_Object *);
const char *widget_type;
if (!lim) return;
/* hack. I don't want to copy the entire function to work with
* scrolled_entry */
widget_type = elm_widget_type_get(entry);
if (!strcmp(widget_type, "entry"))
text_get = elm_entry_entry_get;
else if (!strcmp(widget_type, "scrolled_entry"))
text_get = elm_scrolled_entry_entry_get;
else /* huh? */
return;
current = elm_entry_markup_to_utf8(text_get(entry));
if (lim->max_char_count > 0)
{
int cut;
len = evas_string_char_len_get(current);
if (len >= lim->max_char_count)
{
free(*text);
free(current);
*text = NULL;
return;
}
newlen = evas_string_char_len_get(*text);
cut = strlen(*text);
while ((len + newlen) > lim->max_char_count)
{
cut = evas_string_char_prev_get(*text, cut, NULL);
newlen--;
}
(*text)[cut] = 0;
}
if (lim->max_byte_count > 0)
{
len = strlen(current);
if (len >= lim->max_byte_count)
{
free(*text);
free(current);
*text = NULL;
return;
}
newlen = strlen(*text);
while ((len + newlen) > lim->max_byte_count)
{
int p = evas_string_char_prev_get(*text, newlen, NULL);
newlen -= (newlen - p);
}
if (newlen)
(*text)[newlen] = 0;
else
{
free(*text);
*text = NULL;
}
}
free(current);
}
/**
* Filter inserted text based on accepted or rejected sets of characters
*
* Add this filter to an entry to restrict the set of accepted characters
* based on the sets in the provided Elm_Entry_Filter_Accept_Set.
* This structure contains both accepted and rejected sets, but they are
* mutually exclusive. If accepted is set, it will be used, otherwise it
* goes on to the rejected set.
*/
EAPI void
elm_entry_filter_accept_set(void *data, Evas_Object *entry, char **text)
{
Elm_Entry_Filter_Accept_Set *as = data;
const char *set;
char *insert;
Eina_Bool goes_in;
int read_idx, last_read_idx = 0, read_char, copy_count;
if (!as || (!as->accepted && !as->rejected))
return;
if (as->accepted)
{
set = as->accepted;
goes_in = EINA_TRUE;
}
else
{
set = as->rejected;
goes_in = EINA_FALSE;
}
insert = *text;
read_idx = evas_string_char_next_get(*text, 0, &read_char);
copy_count = read_idx;
while (read_char)
{
int cmp_idx, cmp_char;
Eina_Bool in_set = EINA_FALSE;
cmp_idx = evas_string_char_next_get(set, 0, &cmp_char);
while (cmp_char)
{
if (read_char == cmp_char)
{
in_set = EINA_TRUE;
break;
}
cmp_idx = evas_string_char_next_get(set, cmp_idx, &cmp_char);
}
if (in_set == goes_in)
{
int size = read_idx - last_read_idx;
const char *src = (*text) + last_read_idx;
if (src != insert)
memcpy(insert, *text + last_read_idx, size);
insert += size;
}
last_read_idx = read_idx;
read_idx = evas_string_char_next_get(*text, read_idx, &read_char);
}
*insert = 0;
}
/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/