Implement elm index sorted insert

- Name index item as Elm_Index_Item
 - Add some other index functions:
   + Item find
   + Data get/set
   + Letter get

I think this stuff will make easier to create index for
dynamically created lists.


SVN revision: 49171
This commit is contained in:
Bruno Dilly 2010-05-23 23:41:32 +00:00
parent de41ec04e3
commit 0fa431bcc0
2 changed files with 147 additions and 20 deletions

View File

@ -1266,6 +1266,7 @@ extern "C" {
* vertical (two up/down buttons at the right side and text left aligned) * vertical (two up/down buttons at the right side and text left aligned)
*/ */
typedef struct _Elm_Index_Item Elm_Index_Item;
EAPI Evas_Object *elm_index_add(Evas_Object *parent); EAPI Evas_Object *elm_index_add(Evas_Object *parent);
EAPI void elm_index_active_set(Evas_Object *obj, Eina_Bool active); EAPI void elm_index_active_set(Evas_Object *obj, Eina_Bool active);
EAPI void elm_index_item_level_set(Evas_Object *obj, int level); EAPI void elm_index_item_level_set(Evas_Object *obj, int level);
@ -1275,9 +1276,14 @@ extern "C" {
EAPI void elm_index_item_prepend(Evas_Object *obj, const char *letter, const void *item); EAPI void elm_index_item_prepend(Evas_Object *obj, const char *letter, const void *item);
EAPI void elm_index_item_append_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative); EAPI void elm_index_item_append_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative);
EAPI void elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative); EAPI void elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void *item, const void *relative);
EAPI void elm_index_item_sorted_insert(Evas_Object *obj, const char *letter, const void *item, Eina_Compare_Cb cmp_func, Eina_Compare_Cb cmp_data_func);
EAPI void elm_index_item_del(Evas_Object *obj, const void *item); EAPI void elm_index_item_del(Evas_Object *obj, const void *item);
EAPI Elm_Index_Item *elm_index_item_find(Evas_Object *obj, const void *item);
EAPI void elm_index_item_clear(Evas_Object *obj); EAPI void elm_index_item_clear(Evas_Object *obj);
EAPI void elm_index_item_go(Evas_Object *obj, int level); EAPI void elm_index_item_go(Evas_Object *obj, int level);
EAPI void *elm_index_item_data_get(const Elm_Index_Item *item);
EAPI void elm_index_item_data_set(Elm_Index_Item *it, const void *data);
EAPI const char *elm_index_item_letter_get(const Elm_Index_Item *item);
/* smart callbacks called: /* smart callbacks called:
* "changed" - when the selected index item changes * "changed" - when the selected index item changes
* "delay,changed" - when the selected index item changes, but after some small idle period * "delay,changed" - when the selected index item changes, but after some small idle period

View File

@ -9,7 +9,6 @@
*/ */
typedef struct _Widget_Data Widget_Data; typedef struct _Widget_Data Widget_Data;
typedef struct _Item Item;
struct _Widget_Data struct _Widget_Data
{ {
@ -26,7 +25,7 @@ struct _Widget_Data
Eina_Bool down : 1; Eina_Bool down : 1;
}; };
struct _Item struct _Elm_Index_Item
{ {
Evas_Object *obj; Evas_Object *obj;
const char *letter; const char *letter;
@ -42,13 +41,13 @@ static void _theme_hook(Evas_Object *obj);
static void _sizing_eval(Evas_Object *obj); static void _sizing_eval(Evas_Object *obj);
static void _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level); static void _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level);
static void _index_box_clear(Evas_Object *obj, Evas_Object *box, int level); static void _index_box_clear(Evas_Object *obj, Evas_Object *box, int level);
static void _item_free(Item *it); static void _item_free(Elm_Index_Item *it);
static void static void
_del_hook(Evas_Object *obj) _del_hook(Evas_Object *obj)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
Eina_List *l, *clear = NULL; Eina_List *l, *clear = NULL;
if (!wd) return; if (!wd) return;
_index_box_clear(obj, wd->bx[wd->level], wd->level); _index_box_clear(obj, wd->bx[wd->level], wd->level);
@ -138,13 +137,13 @@ _sizing_eval(Evas_Object *obj)
evas_object_size_hint_max_set(obj, maxw, maxh); evas_object_size_hint_max_set(obj, maxw, maxh);
} }
static Item * static Elm_Index_Item *
_item_new(Evas_Object *obj, const char *letter, const void *item) _item_new(Evas_Object *obj, const char *letter, const void *item)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
if (!wd) return NULL; if (!wd) return NULL;
it = calloc(1, sizeof(Item)); it = calloc(1, sizeof(Elm_Index_Item));
if (!it) return NULL; if (!it) return NULL;
it->obj = obj; it->obj = obj;
it->letter = eina_stringshare_add(letter); it->letter = eina_stringshare_add(letter);
@ -153,12 +152,12 @@ _item_new(Evas_Object *obj, const char *letter, const void *item)
return it; return it;
} }
static Item * static Elm_Index_Item *
_item_find(Evas_Object *obj, const void *item) _item_find(Evas_Object *obj, const void *item)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *l; Eina_List *l;
Item *it; Elm_Index_Item *it;
if (!wd) return NULL; if (!wd) return NULL;
EINA_LIST_FOREACH(wd->items, l, it) EINA_LIST_FOREACH(wd->items, l, it)
if (it->data == item) return it; if (it->data == item) return it;
@ -166,7 +165,7 @@ _item_find(Evas_Object *obj, const void *item)
} }
static void static void
_item_free(Item *it) _item_free(Elm_Index_Item *it)
{ {
Widget_Data *wd = elm_widget_data_get(it->obj); Widget_Data *wd = elm_widget_data_get(it->obj);
if (!wd) return; if (!wd) return;
@ -182,7 +181,7 @@ _index_box_auto_fill(Evas_Object *obj, Evas_Object *box, int level)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *l; Eina_List *l;
Item *it; Elm_Index_Item *it;
Evas_Coord mw, mh, w, h; Evas_Coord mw, mh, w, h;
int i = 0; int i = 0;
if (!wd) return; if (!wd) return;
@ -235,7 +234,7 @@ _index_box_clear(Evas_Object *obj, Evas_Object *box __UNUSED__, int level)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *l; Eina_List *l;
Item *it; Elm_Index_Item *it;
if (!wd) return; if (!wd) return;
if (!wd->level_active[level]) return; if (!wd->level_active[level]) return;
EINA_LIST_FOREACH(wd->items, l, it) EINA_LIST_FOREACH(wd->items, l, it)
@ -264,7 +263,7 @@ static void
_sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy) _sel_eval(Evas_Object *obj, Evas_Coord evx, Evas_Coord evy)
{ {
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it, *it_closest, *it_last; Elm_Index_Item *it, *it_closest, *it_last;
Eina_List *l; Eina_List *l;
Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy; Evas_Coord x, y, w, h, bx, by, bw, bh, xx, yy;
double cdv = 0.5; double cdv = 0.5;
@ -614,7 +613,7 @@ elm_index_item_selected_get(const Evas_Object *obj, int level)
ELM_CHECK_WIDTYPE(obj, widtype) NULL; ELM_CHECK_WIDTYPE(obj, widtype) NULL;
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *l; Eina_List *l;
Item *it; Elm_Index_Item *it;
if (!wd) return NULL; if (!wd) return NULL;
EINA_LIST_FOREACH(wd->items, l, it) EINA_LIST_FOREACH(wd->items, l, it)
if ((it->selected) && (it->level == level)) return it->data; if ((it->selected) && (it->level == level)) return it->data;
@ -635,7 +634,7 @@ elm_index_item_append(Evas_Object *obj, const char *letter, const void *item)
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
if (!wd) return; if (!wd) return;
it = _item_new(obj, letter, item); it = _item_new(obj, letter, item);
if (!it) return; if (!it) return;
@ -657,7 +656,7 @@ elm_index_item_prepend(Evas_Object *obj, const char *letter, const void *item)
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
if (!wd) return; if (!wd) return;
it = _item_new(obj, letter, item); it = _item_new(obj, letter, item);
@ -681,7 +680,7 @@ elm_index_item_append_relative(Evas_Object *obj, const char *letter, const void
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it, *it_rel; Elm_Index_Item *it, *it_rel;
if (!wd) return; if (!wd) return;
if (!relative) if (!relative)
{ {
@ -715,7 +714,7 @@ elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it, *it_rel; Elm_Index_Item *it, *it_rel;
if (!wd) return; if (!wd) return;
if (!relative) if (!relative)
{ {
@ -734,6 +733,62 @@ elm_index_item_prepend_relative(Evas_Object *obj, const char *letter, const void
_index_box_clear(obj, wd->bx[wd->level], wd->level); _index_box_clear(obj, wd->bx[wd->level], wd->level);
} }
/**
* Insert a new @p item into the sorted index @p obj in @p letter.
*
* @param obj The index object
* @param letter Letter under which the item should be indexed
* @param item The item to put in the index
* @param cmp_func The function called for the sort of index items.
* @param cmp_data_func The function called for the sort of the data. It will
* be used when cmp_func return 0. It means the index item already exists.
* So, to decide which data item should be pointed by the index item, a function
* to compare them is needed. If this function is not provided, index items
* will be duplicated.
*
* @ingroup Index
*/
EAPI void
elm_index_item_sorted_insert(Evas_Object *obj, const char *letter, const void *item, Eina_Compare_Cb cmp_func, Eina_Compare_Cb cmp_data_func)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
Eina_List *lnear;
Elm_Index_Item *it;
int cmp;
if (!wd) return;
if (!(wd->items))
{
elm_index_item_append(obj, letter, item);
return;
}
it = _item_new(obj, letter, item);
if (!it) return;
lnear = eina_list_search_sorted_near_list(wd->items, cmp_func, it, &cmp);
if (cmp < 0)
wd->items = eina_list_append_relative_list(wd->items, it, lnear);
else if (cmp > 0)
wd->items = eina_list_prepend_relative_list(wd->items, it, lnear);
else
{
/* If cmp_data_func is not provided, append a duplicated item */
if (!cmp_data_func)
wd->items = eina_list_append_relative_list(wd->items, it, lnear);
else
{
Elm_Index_Item *p_it = eina_list_data_get(lnear);
if (cmp_data_func(p_it->data, it->data) >= 0)
p_it->data = it->data;
_item_free(it);
}
}
_index_box_clear(obj, wd->bx[wd->level], wd->level);
}
/** /**
* Remove an item from the index. * Remove an item from the index.
* *
@ -747,7 +802,7 @@ elm_index_item_del(Evas_Object *obj, const void *item)
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
if (!wd) return; if (!wd) return;
it = _item_find(obj, item); it = _item_find(obj, item);
if (!it) return; if (!it) return;
@ -755,6 +810,24 @@ elm_index_item_del(Evas_Object *obj, const void *item)
_index_box_clear(obj, wd->bx[wd->level], wd->level); _index_box_clear(obj, wd->bx[wd->level], wd->level);
} }
/**
* Find an index item using item data.
*
* @param obj The index object
* @param item The item pointed by index item
* @return The index item pointing to @p item
*
* @ingroup Index
*/
EAPI Elm_Index_Item *
elm_index_item_find(Evas_Object *obj, const void *item)
{
ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj);
if (!wd) return NULL;
return _item_find(obj, item);
}
/** /**
* Clears an index of its items. * Clears an index of its items.
* *
@ -767,7 +840,7 @@ elm_index_item_clear(Evas_Object *obj)
{ {
ELM_CHECK_WIDTYPE(obj, widtype); ELM_CHECK_WIDTYPE(obj, widtype);
Widget_Data *wd = elm_widget_data_get(obj); Widget_Data *wd = elm_widget_data_get(obj);
Item *it; Elm_Index_Item *it;
Eina_List *l, *clear = NULL; Eina_List *l, *clear = NULL;
if (!wd) return; if (!wd) return;
_index_box_clear(obj, wd->bx[wd->level], wd->level); _index_box_clear(obj, wd->bx[wd->level], wd->level);
@ -796,3 +869,51 @@ elm_index_item_go(Evas_Object *obj, int level __UNUSED__)
_index_box_auto_fill(obj, wd->bx[0], 0); _index_box_auto_fill(obj, wd->bx[0], 0);
if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1); if (wd->level == 1) _index_box_auto_fill(obj, wd->bx[1], 1);
} }
/**
* Returns the data associated with the item.
*
* @param it The list item
* @return The data associated with @p it
*
* @ingroup Index
*/
EAPI void *
elm_index_item_data_get(const Elm_Index_Item *it)
{
if (!it) return NULL;
return (void *)it->data;
}
/**
* Set the data item from the index item
*
* This set a new data value.
*
* @param it The item
* @param data The new data pointer to set
*
* @ingroup Index
*/
EAPI void
elm_index_item_data_set(Elm_Index_Item *it, const void *data)
{
if (!it) return;
it->data = data;
}
/**
* Gets the letter of the item.
*
* @param it The list item
* @return The letter of @p it
*
* @ingroup Index
*/
EAPI const char *
elm_index_item_letter_get(const Elm_Index_Item *it)
{
if (!it) return NULL;
return it->letter;
}