As mentioned above, the number of parts to fill depends on the item style that
is chosen when adding a new item. This is simply a matter of setting the right
value when filling the Elm_Genlist_Item_Class
struct:
itc->item_style = "default";
The Genlist Widget lists all available item styles:
Further customization is achieved by modifying the theme as explained in the Edje guide.
In case the customization is only visual, it is good practice to keep the same item style names for new themes. This makes it possible to change theme and keep the code the same while also retaining the same overall item placement.
So far the genlist examples have all featured bare lists while the genlist widget is able to display trees or even a “group” mode where scrolling keeps the item at the top of the widget until another group comes and replaces it.
The group mode makes it possible to keep an element visible as long as one of its children is visible. This is most useful for “title” items.
Mark some elements as ELM_GENLIST_ITEM_GROUP
and use the returned
Elm_Object_Item
to establish the parent-children relationship when adding the
children items.
Since there are two kind of items, create two item classes. Give them different styles and callback functions. The callback functions are visible in the example, they have no functionalities:
Elm_Genlist_Item_Class *_itc_child = elm_genlist_item_class_new(); _itc->item_style = "default_style"; _itc->func.text_get = _genlist_text_get_size; _itc->func.content_get = _genlist_content_get_bg; _itc->func.state_get = NULL; _itc->func.del = NULL; Elm_Genlist_Item_Class *_itc_parent = elm_genlist_item_class_new(); _itc2->item_style = "default_style"; _itc2->func.text_get = _genlist_text_get_nosize; _itc2->func.content_get = _genlist_content_get_icon; _itc2->func.state_get = NULL; _itc2->func.del = NULL;
Then add a group header and follow it with 10 children. This is repeated 10 times.
The parent has type ELM_GENLIST_ITEM_GROUP
while the children have type
ELM_GENLIST_ITEM_NONE
.
The other important point is that the value returned by
elm_genlist_item_append()
is stored in it and then sent to the
elm_genlist_item_append()
call that adds the children. This creates the
parent-children relationship.
for (i = 0; i < 1000; i++) { it = elm_genlist_item_append(list, _itc_parent, (void *)(uintptr_t) (10 * i), NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL ); for (j = 0; j < 10; j++) { elm_genlist_item_append(list, _itc_child, (void *)(uintptr_t) (10 * i + j), it, //parent item ELM_GENLIST_ITEM_NONE, NULL, NULL ); } }
Like group mode, tree mode uses the parenting relationship with other items.
Unlike group mode, the child elements are created on-demand when their parent
is expanded and deleted when it is contracted. This is done by using smart
callbacks: expand,request
, expanded
, contract,request
, and
contracted
. Like any smart callback, they are registered through
evas_object_smat_callback_add
on the genlist object:
evas_object_smart_callback_add(list, "expand,request", _tree_item_expand_request, _itc_parent); evas_object_smart_callback_add(list, "expanded", _tree_item_expanded, _itc_child); evas_object_smart_callback_add(list, "contract,request", _tree_item_contract_request, _itc_child); evas_object_smart_callback_add(list, "contracted", _tree_item_contracted, NULL);
The callbacks expand,request
and contract,request
do only one thing:
decide whether the element is expanded or contracted. This is done by using
elm_genlist_item_expanded_set()
function; if it changes the expansion
status of the item, the next callback is called (either expanded
or
contracted
, depending on whether it was an expand,request
or
contract,request
event). A minimal implementation of these callbacks is
therefore:
static void _tree_item_expand_request(void *data, Evas_Object *o, void *event_info) { Elm_Object_Item *it = (Elm_Object_Item*) event_info; elm_genlist_item_item_class_update(it, data); elm_genlist_item_expanded_set(it, EINA_TRUE); }
elm_genlist_item_item_class_update()
. It changes the item style and is explained in the Changing the item class of an item after its creation section.^
static void _tree_item_contract_request(void *data, Evas_Object *o, void *event_info) { Elm_Object_Item *it = (Elm_Object_Item*) event_info; elm_genlist_item_item_class_update(it, data); elm_genlist_item_expanded_set(it, EINA_FALSE); }
As said above, once the genlist item status is set to expanded
, the
expanded event is triggered and it is the duty of a callback for that event to
populate the list with the item's children. This relies on the parent
parameter of functions like elm_genlist_item_append()
, like for the group
mode.
The function below is a callback implementation for the expanded
event. It
adds items that are built similarly to previous items, the only change is the
parent parameter which is not NULL. Conveniently, the
parentElm_Object_Item
and Elm_Genlist_Item_Class
pointers that are passed to the
elm_genlist_item_append()
function are given in the event_info
and
data
callback and need to be cast.
static void _tree_item_expanded(void *data, Evas_Object *o, void *event_info) { Elm_Object_Item *it_parent = (Elm_Object_Item*) event_info; int i_parent = (int)(uintptr_t)elm_object_item_data_get(it_parent); Elm_Object_Item *list = o; Elm_Genlist_Item_Class *itc = data; int i; for (i = 0; i < 10; i++) { elm_genlist_item_append(list, itc, (void *)(uintptr_t) (i + i_parent), it_parent, ELM_GENLIST_ITEM_NONE, NULL, NULL ); } }
The following code has the callback function for the contracted
event. It
imply calls elm_genlist_item_subitems_clear()
to clear all children (including
their own children if they have any) of the given item. Again, the item that
is being contracted is available through the event_info
parameter to the
callback.
static void _tree_item_contracted(void *data, Evas_Object *o, void *event_info) { Elm_Object_Item *it_parent = (Elm_Object_Item*) event_info; elm_genlist_item_subitems_clear(it_parent); }
A common UI design is to mix group and tree modes. It allows for a tree behavior while also keeping the group header item. The EFLs do not do any magic here and the way to get such a behavior is to create an item of type group, an item of type tree which parent is the group item. Then add the callbacks to populate the children of the tree item in the regular way.
Because of the scroller, the actual height and/or width of the genlist must be computed. This means summing the sizes of all the items, the sizes must be computed. This obviously has a cost and slows down adding items to the genlist.
The elm_genlist_homogeneous_set()
function alleviates this issue by
assuming all the items are the same size as the first one of the list. It
speeds up large insertions. However, it may lead to serious graphical issues
if the items are not actually the same size. Use with care.
Changing the item class of a widget is an easy way to change the appearance
upon selection or others actions of the user. This is done by calling
elm_genlist_item_class_update()
:
static void _tree_item_expand_request(void *data, Evas_Object *o, void *event_info) { Elm_Object_Item *it = (Elm_Object_Item*) event_info; elm_genlist_item_item_class_update(it, data); elm_genlist_item_expanded_set(it, EINA_TRUE); }