diff --git a/legacy/elementary/src/bin/test.c b/legacy/elementary/src/bin/test.c index 9ff36fd8d5..ada5c25163 100644 --- a/legacy/elementary/src/bin/test.c +++ b/legacy/elementary/src/bin/test.c @@ -112,6 +112,7 @@ void test_genlist16(void *data, Evas_Object *obj, void *event_info); void test_genlist17(void *data, Evas_Object *obj, void *event_info); void test_genlist18(void *data, Evas_Object *obj, void *event_info); void test_genlist19(void *data, Evas_Object *obj, void *event_info); +void test_genlist20(void *data, Evas_Object *obj, void *event_info); void test_genlist_focus(void *data, Evas_Object *obj, void *event_info); void test_genlist_item_styles(void *data, Evas_Object *obj, void *event_info); void test_genlist_multi_select(void *data, Evas_Object *obj, void *event_info); @@ -652,6 +653,7 @@ add_tests: ADD_TEST(NULL, "Lists - Genlist", "Genlist Decorate Modes", test_genlist17); ADD_TEST(NULL, "Lists - Genlist", "Genlist Tree and Decorate All Mode", test_genlist18); ADD_TEST(NULL, "Lists - Genlist", "Genlist Full Widget", test_genlist19); + ADD_TEST(NULL, "Lists - Genlist", "Genlist Item Search By Text", test_genlist20); ADD_TEST(NULL, "Lists - Genlist", "Genlist Focus", test_genlist_focus); ADD_TEST(NULL, "Lists - Genlist", "Genlist Item Styles", test_genlist_item_styles); ADD_TEST(NULL, "Lists - Genlist", "Genlist Multi Select", test_genlist_multi_select); diff --git a/legacy/elementary/src/bin/test_genlist.c b/legacy/elementary/src/bin/test_genlist.c index ea9a4c6d12..d78f6455bb 100644 --- a/legacy/elementary/src/bin/test_genlist.c +++ b/legacy/elementary/src/bin/test_genlist.c @@ -3468,6 +3468,278 @@ test_genlist_multi_select(void *data EINA_UNUSED, evas_object_show(win); } +/* test genlist item search by text */ + +typedef struct _gl20_Event_Data gl20_Event_Data; +struct _gl20_Event_Data +{ + Evas_Object *gl_obj; + Evas_Object *tg_obj; + Evas_Object *en_obj; + Elm_Object_Item *last_item_found; +}; + +static const char *_gl20_items_text[] = { + "Albany", "Annapolis", + "Atlanta", "Augusta", + "Austin", "Baton Rouge", + "Bismarck", "Boise", + "Boston", "Carson City", + "Charleston", "Cheyenne", + "Columbia", "Columbus", + "Concord", "Denver", + "Des Moines", "Dover", + "Frankfort", "Harrisburg", + "Hartford", "Helena", + "Honolulu", "Indianapolis", + "Jackson", "Jefferson City", + "Juneau", "Lansing", + "Lincoln", "Little Rock", + "Madison", "Montgomery", + "Montpelier", "Nashville", + "Oklahoma City", "Olympia", + "Phoenix", "Pierre", + "Providence", "Raleigh", + "Richmond", "Sacramento", + "Saint Paul", "Salem", + "Salt Lake City", "Santa Fe", + "Springfield", "Tallahassee", + "Topeka", "Trenton" }; + +static char * +_gl20_search_text_get(void *data, Evas_Object *obj EINA_UNUSED, + const char *part EINA_UNUSED) +{ + char buf[32]; + int item_index = (int)(uintptr_t)data; + + if (item_index < 50) + { + snprintf(buf, sizeof(buf), "%s", _gl20_items_text[item_index]); + return strdup(buf); + } + else if (item_index < 100) + { + snprintf(buf, sizeof(buf), "%X", (item_index - 50)); + return strdup(buf); + } + else if (item_index == 100) + return strdup("Tree Item"); + + return NULL; +} + +static char * +_gl20_text_get(void *data, Evas_Object *obj EINA_UNUSED, + const char *part EINA_UNUSED) +{ + char buf[64]; + snprintf(buf, sizeof(buf), "(this text is not uset for search) %s", + _gl20_search_text_get(data, NULL, NULL)); + return strdup(buf); +} + +static void +_gl20_searsh_item(gl20_Event_Data *event_data, Elm_Object_Item * it) +{ + const char *str = elm_entry_entry_get(event_data->en_obj); + if (!str || !strlen(str)) return; + + int flag = 0; + if (!elm_check_state_get(event_data->tg_obj)) + flag = FNM_CASEFOLD; + + printf("Looking for \"%s\". ", str); + event_data->last_item_found = elm_genlist_search_by_text_item_get(event_data->gl_obj, + it, _gl20_search_text_get, NULL, str, flag); + + if (event_data->last_item_found) + { + printf("Found.\n"); + elm_genlist_item_selected_set(event_data->last_item_found, EINA_TRUE); + elm_genlist_item_bring_in(event_data->last_item_found, + ELM_GENLIST_ITEM_SCROLLTO_MIDDLE); + elm_object_focus_set(event_data->en_obj, EINA_TRUE); + } + else + printf("Not Found.\n"); +} + +static void +_gl20_search_settings_changed_cb(void *data, Evas_Object *obj EINA_UNUSED, + void *einfo EINA_UNUSED) +{ + _gl20_searsh_item(data, NULL); +} + +static Elm_Genlist_Item_Class * +_gl20_item_class_create(const char *item_style) +{ + Elm_Genlist_Item_Class * itc = elm_genlist_item_class_new(); + itc->item_style = item_style; + itc->func.text_get = _gl20_text_get; + itc->func.content_get = gl_content_get; + itc->func.state_get = gl_state_get; + itc->func.del = NULL; + return itc; +} + +static void +_gl20_expand_cb(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED, + void *event_info) +{ + Elm_Object_Item *glit = event_info; + Evas_Object *gl = elm_object_item_widget_get(glit); + Elm_Genlist_Item_Class *itc = NULL; + int i = 0; + + itc = _gl20_item_class_create("default"); + + for (i = 50; i < 100; i++) + { + elm_genlist_item_append(gl, itc, + (void *)(uintptr_t) i/* item data */, + glit/* parent */, + ELM_GENLIST_ITEM_NONE, NULL/* func */, + NULL/* func data */); + } + elm_genlist_item_class_free(itc); +} + +static void _gl20_on_keydown(void *data, Evas *evas EINA_UNUSED, + Evas_Object *o EINA_UNUSED, void *einfo) +{ + Evas_Event_Key_Down *ev = einfo; + gl20_Event_Data * event_data = (gl20_Event_Data *)data; + + if (!strcmp(ev->key, "Return")) + { + printf("Looking for next item\n"); + _gl20_searsh_item(data, event_data->last_item_found); + } +} + +void +test_genlist20(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, + void *event_info EINA_UNUSED) +{ + Evas_Object *win, *bx, *gl; + Evas_Object *fr, *lb_frame; // info frame + Evas_Object *bx_entry, *lb_entry, *en; // search line + Evas_Object *tg; // "case sensitive" toggle + Elm_Genlist_Item_Class *itc = NULL; + gl20_Event_Data* event_data = NULL; + int i = 0; + + win = elm_win_util_standard_add("genlist-item-search-by-text", + "Genlist Item Search By Text"); + elm_win_autodel_set(win, EINA_TRUE); + + bx = elm_box_add(win); + evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, bx); + evas_object_show(bx); + + fr = elm_frame_add(bx); + evas_object_size_hint_weight_set(fr, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(fr, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_object_text_set(fr, "Information"); + elm_box_pack_end(bx, fr); + evas_object_show(fr); + + lb_frame = elm_label_add(fr); + elm_object_text_set(lb_frame, + "This is an example of " + "elm_genlist_search_by_text_item_get() usage.
" + "Enter search string to the entry and press Enter to " + "show next search result.
"); + elm_object_content_set(fr, lb_frame); + evas_object_show(lb_frame); + + tg = elm_check_add(win); + elm_object_style_set(tg, "toggle"); + elm_object_text_set(tg, " Case Sensitive Search"); + elm_check_state_set(tg, EINA_TRUE); + elm_box_pack_end(bx, tg); + evas_object_show(tg); + + bx_entry = elm_box_add(win); + elm_box_horizontal_set(bx_entry, EINA_TRUE); + evas_object_size_hint_weight_set(bx_entry, EVAS_HINT_EXPAND, 0.0); + evas_object_size_hint_align_set(bx_entry, EVAS_HINT_FILL, 0.0); + elm_box_pack_end(bx, bx_entry); + evas_object_show(bx_entry); + + lb_entry = elm_label_add(win); + elm_object_text_set(lb_entry, " Search:"); + evas_object_size_hint_weight_set(lb_entry, 0.0, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(lb_entry, 0.0, EVAS_HINT_FILL); + elm_box_pack_end(bx_entry, lb_entry); + evas_object_show(lb_entry); + + en = elm_entry_add(win); + elm_entry_single_line_set(en, EINA_TRUE); + elm_entry_scrollable_set(en, EINA_TRUE); + elm_object_part_text_set(en, "guide", "Type item's name here to search."); + evas_object_size_hint_weight_set(en, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(en, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(bx_entry, en); + evas_object_show(en); + elm_object_focus_set(en, EINA_TRUE); + + gl = elm_genlist_add(bx); + + evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(bx, gl); + evas_object_show(gl); + + event_data = calloc(1, sizeof(gl20_Event_Data)); + event_data->tg_obj = tg; + event_data->en_obj = en; + event_data->gl_obj = gl; + event_data->last_item_found = NULL; + + evas_object_event_callback_add(en, EVAS_CALLBACK_KEY_DOWN, + _gl20_on_keydown, (void*)event_data); + evas_object_event_callback_add(gl, EVAS_CALLBACK_FREE, + _cleanup_cb, (void*)event_data); + evas_object_smart_callback_add(en, "changed,user", + _gl20_search_settings_changed_cb, (void*)event_data); + evas_object_smart_callback_add(tg, "changed", + _gl20_search_settings_changed_cb, (void*)event_data); + evas_object_smart_callback_add(gl, "expand,request", gl4_exp_req, gl); + evas_object_smart_callback_add(gl, "contract,request", gl4_con_req, gl); + evas_object_smart_callback_add(gl, "contracted", gl4_con, gl); + evas_object_smart_callback_add(gl, "expanded", _gl20_expand_cb, gl); + + itc = _gl20_item_class_create("tree_effect"); + + elm_genlist_item_append(gl, itc, + (void *)100/* item data */, + NULL/* parent */, + ELM_GENLIST_ITEM_TREE, + NULL/* func */, + NULL/* func data */); + + itc->item_style = "default"; + + for (i = 0; i < 50; i++) + { + elm_genlist_item_append(gl, itc, + (void *)(uintptr_t)i/* item data */, + NULL/* parent */, + ELM_GENLIST_ITEM_NONE, + NULL/* func */, + NULL/* func data */); + } + + elm_genlist_item_class_free(itc); + + evas_object_resize(win, 320, 500); + evas_object_show(win); +} + /* test genlist deletion */ static void _gl_del_sel(void *data, Evas_Object *obj, void *event_info); diff --git a/legacy/elementary/src/lib/elm_genlist.c b/legacy/elementary/src/lib/elm_genlist.c index 5f73def7ea..0e26793f84 100644 --- a/legacy/elementary/src/lib/elm_genlist.c +++ b/legacy/elementary/src/lib/elm_genlist.c @@ -7496,6 +7496,35 @@ _elm_genlist_elm_widget_focus_highlight_geometry_get(Eo *obj EINA_UNUSED, Elm_Ge } } +EOLIAN static Elm_Object_Item * +_elm_genlist_search_by_text_item_get(Eo *obj EINA_UNUSED, + Elm_Genlist_Data *sd, + Elm_Object_Item * item_to_search_from, + Elm_Gen_Item_Text_Get_Cb _text_get, + const char * part_name, + const char * pattern, + int flags) +{ + Elm_Gen_Item *it = NULL; + const char * str = NULL; + Eina_Bool search_flag = (item_to_search_from) ? EINA_FALSE : EINA_TRUE; + + if (!_text_get || !pattern) return NULL; + if (!sd->items) return NULL; + + EINA_INLIST_FOREACH(sd->items, it) + { + if (search_flag) + { + str = _text_get((void *)it->base.data, VIEW(it), part_name); + if (!fnmatch(pattern, str, flags)) return (Elm_Object_Item *)it; + } + else if (item_to_search_from == (Elm_Object_Item *)it) + search_flag = EINA_TRUE; + } + return NULL; +} + EOLIAN static Elm_Object_Item* _elm_genlist_elm_widget_focused_item_get(Eo *obj EINA_UNUSED, Elm_Genlist_Data *sd) { diff --git a/legacy/elementary/src/lib/elm_genlist.eo b/legacy/elementary/src/lib/elm_genlist.eo index 0a2d74af31..5f04a22f44 100644 --- a/legacy/elementary/src/lib/elm_genlist.eo +++ b/legacy/elementary/src/lib/elm_genlist.eo @@ -681,6 +681,51 @@ class Elm_Genlist (Elm_Layout, Elm_Interface_Scrollable, Evas_Clickable_Interfac @in const void *func_data; /*@ Data passed to @p func above. */ } } + search_by_text_item_get { + /*@ + Get genlist item by given string. + + @return Pointer to the genlist item which matches search_string in case of success, otherwise returns NULL. + + This function takes pointer to the function that returns + comparison string for item (it could be the same function as used for setting text for labels). + Also it takes pointer to the genlist item that will be used to start search from it. + + This function uses fnmatch() for searching and takes it's seatcing flags as last parameter. + The list of available flags: +
+
FNM_NOESCAPE
+
If this flag is set, treat backslash as an ordinary character, instead of an escape character.
+
FNM_PATHNAME
+
If this flag is set, match a slash in string only with a slash in pattern and not by an asterisk (*) + or a question mark (?) metacharacter, nor by a bracket expression ([]) containing a slash.
+
FNM_PERIOD
+
If this flag is set, a leading period in string has to be matched exactly by a period in pattern. + A period is considered to be leading if it is the first character in string, or if both + FNM_PATHNAME is set and the period immediately follows a slash.
+
FNM_FILE_NAME
+
This is a GNU synonym for FNM_PATHNAME.
+
FNM_LEADING_DIR
+
If this flag (a GNU extension) is set, the pattern is considered to be matched if it matches an + initial segment of string which is followed by a slash. This flag is mainly for the internal + use of glibc and is only implemented in certain cases.
+
FNM_CASEFOLD
+
If this flag (a GNU extension) is set, the pattern is matched case-insensitively.
+
+ For more details see Linux Programmer's Manual. FNMATCH() + + @ingroup Genlist + @since 1.10 */ + + return Elm_Object_Item *; + params { + @in Elm_Object_Item * item_to_search_from; /*@ Pointer to item to start search from. If NULL search will be started from the first item of the genlist. */ + @in Elm_Gen_Item_Text_Get_Cb _text_get; /*@ Pointer to Elm_Gen_Item_Text_Get_Cb function to get text for comparison. */ + @in const char * part_name; /*@ Name of the TEXT part of genlist item to search string in. */ + @in const char * pattern; /*@ The search pattern. */ + @in int flags; /*@ fnmatch search flags */ + } + } } implements { class::constructor; diff --git a/legacy/elementary/src/lib/elm_genlist_legacy.h b/legacy/elementary/src/lib/elm_genlist_legacy.h index 61be1f9638..c83667e0e8 100644 --- a/legacy/elementary/src/lib/elm_genlist_legacy.h +++ b/legacy/elementary/src/lib/elm_genlist_legacy.h @@ -31,4 +31,4 @@ EAPI Evas_Object *elm_genlist_add(Evas_Object *parent); EAPI Elm_Object_Item * elm_genlist_nth_item_get(const Evas_Object *obj, unsigned int nth); -#include "elm_genlist.eo.legacy.h" \ No newline at end of file +#include "elm_genlist.eo.legacy.h"