Wiki pages genlist_tutorial created: set-up, modifications + image + code c

Coming soon page also added.

Signed-off-by: Clément Bénier <clement.benier@openwide.fr>
Signed-off-by: Pierre Le Magourou <pierre.lemagourou@openwide.fr>
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
This commit is contained in:
Clément Bénier 2015-06-23 12:09:40 +02:00 committed by Cedric BAIL
parent fb7b68ff8b
commit 27308035b3
9 changed files with 766 additions and 0 deletions

View File

@ -0,0 +1,139 @@
#include <Elementary.h>
static char *
_genlist_text_get_size(void *data, Evas_Object *obj , const char *part)
{
char buf[20];
snprintf(buf, sizeof(buf), "Entry %d", (int)(uintptr_t)data);
return strdup(buf);
}
static char *
_genlist_text_get_nosize(void *data, Evas_Object *obj , const char *part)
{
char buf[20];
snprintf(buf, sizeof(buf), "OHOHO %d", (int)(uintptr_t)data);
return strdup(buf);
}
static Evas_Object *
_genlist_content_get_bg(void *data, Evas_Object *obj, const char *part)
{
int i = (int) (uintptr_t) data;
Evas_Object *bg = elm_bg_add(obj);
elm_bg_color_set(bg, 255 * cos(i / (double) 10), 0, i % 255);
return bg;
}
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);
}
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);
}
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
);
}
}
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);
}
EAPI_MAIN int
elm_main(int argc, char **argv)
{
Evas_Object *win;
win = elm_win_util_standard_add("Genlist", "Genlist Basic Tutorial");
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
elm_win_autodel_set(win, EINA_TRUE);
//win 400x400 px
evas_object_resize(win, 400, 400);
Evas_Object *list;
list = elm_genlist_add(win);
evas_object_resize(list, 400, 400);
Elm_Genlist_Item_Class *_itc_child = elm_genlist_item_class_new();
_itc_child->item_style = "default_style";
_itc_child->func.text_get = _genlist_text_get_size;
_itc_child->func.content_get = _genlist_content_get_bg;
_itc_child->func.state_get = NULL;
_itc_child->func.del = NULL;
Elm_Genlist_Item_Class *_itc_parent = elm_genlist_item_class_new();
_itc_parent->item_style = "default_style";
_itc_parent->func.text_get = _genlist_text_get_nosize;
_itc_parent->func.content_get = _genlist_content_get_bg;
_itc_parent->func.state_get = NULL;
_itc_parent->func.del = NULL;
int i,j;
Elm_Object_Item *it = NULL;
for (i = 0; i < 100; i++)
{
it = elm_genlist_item_append(list, _itc_parent,
(void *)(uintptr_t) (10 * i),
NULL,
ELM_GENLIST_ITEM_TREE,
NULL,
NULL
);
}
evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
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);
evas_object_show(list);
evas_object_show(win);
elm_run();
return 0;
}
ELM_MAIN()

View File

@ -0,0 +1,96 @@
#include <Elementary.h>
static char *
_genlist_text_get(void *data, Evas_Object *obj , const char *part)
{
if (strcmp(part, "elm.text") == 0)
{
char *buf = malloc(16);
snprintf(buf, 16, "Entry %d.", (int)(uintptr_t)data);
return buf;
}
else return NULL;
}
static Evas_Object *
_genlist_content_get(void *data, Evas_Object *obj, const char *part)
{
int i = (int) (uintptr_t) data;
if (strcmp(part, "elm.swallow.icon") == 0)
{
Evas_Object *bg = elm_bg_add(obj);
elm_bg_color_set(bg, 255 * cos(i / (double) 10), 0, i % 255);
return bg;
}
else if (strcmp(part, "elm.swallow.end") == 0)
{
Evas_Object *bg = elm_bg_add(obj);
elm_bg_color_set(bg, 0, 255 * sin(i / (double) 10), i % 255);
return bg;
}
else return NULL;
}
static void
_genlist_selected_cb(void *data, Evas_Object *obj, void *event_info)
{
Elm_Object_Item *it = (Elm_Object_Item*) event_info;
elm_genlist_item_item_class_update(it, data);
}
EAPI_MAIN int
elm_main(int argc, char **argv)
{
Evas_Object *win;
win = elm_win_util_standard_add("Genlist", "Genlist Basic Tutorial");
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
elm_win_autodel_set(win, EINA_TRUE);
//win 400x400 px
evas_object_resize(win, 400, 400);
//GENLIST here
Evas_Object *list;
list = elm_genlist_add(win);
Elm_Genlist_Item_Class *_itc = elm_genlist_item_class_new();
_itc->item_style = "default";
_itc->func.text_get = _genlist_text_get;
_itc->func.content_get = _genlist_content_get;
_itc->func.state_get = NULL;
_itc->func.del = NULL;
Elm_Genlist_Item_Class *_itc2 = elm_genlist_item_class_new();
_itc2->item_style = "group_index";
_itc2->func.text_get = _genlist_text_get;
_itc2->func.content_get = _genlist_content_get;
_itc2->func.state_get = NULL;
_itc2->func.del = NULL;
int i=0;
for (i=0; i<20; i++)
{
elm_genlist_item_append(list,
_itc,
(void *)(uintptr_t) i, // Item data
NULL, // Parent item for trees, NULL if none
ELM_GENLIST_ITEM_NONE, // Item type; this is the common one
_genlist_selected_cb, // Callback on selection of the item
_itc2 // Data for that callback function
);
}
evas_object_size_hint_weight_set(list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, list);
evas_object_show(list);
evas_object_show(win);
elm_run();
return 0;
}
ELM_MAIN()

BIN
media/coming_soon.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

BIN
media/genlist.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

6
pages/coming_soon.txt Normal file
View File

@ -0,0 +1,6 @@
~~Title: Coming Soon~~
==== Coming soon! ====
:{{ coming_soon.jpg?direct&500 }}

View File

@ -38,6 +38,7 @@ Go check the current available version of EFL on each distro/platform:
=== Tutorials ===
* [[tutorial/basic_tutorial|Basic Tutorial]]
* [[tutorial/genlist_tutorial|Genlist Tutorial]]
----

View File

@ -0,0 +1,252 @@
~~Title: Genlist Modifications~~
==== Genlist Modifications ====
=== Choosing Another Item Style to Add or Remove Parts ===
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:
<code c>
itc->item_style = "default";
</code>
The Genlist Widget lists all available item styles:
* default
* default_style - The text part is a textblock
* double_label
* icon_top_text_bottom
* group_index
* one_icon - Only 1 icon at left
* end_icon - Only 1 icon at end/right
* no_icon - No icon at end/right
* full - Only 1 icon, elm.swallow.content, which consumes whole area of genlist item
Further customization is achieved by modifying the theme as explained in the
[[/coming_soon|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.
==== Using Item Modes ====
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.
//**__Group Mode__**//
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:
<code c>
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;
</code>
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.
<code c>
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
);
}
}
</code>
//**__Tree Mode__**//
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:
<code c>
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);
</code>
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:
<code c>
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);
}
</code>
<note>
The example above has an extra line: the call to ''elm_genlist_item_item_class_update()''. It changes the item style and is explained in the [[/tutorial/genlist/modifications#Using_Other_APIs|Changing the item class of an item after its creation section]].^
</note>
<code c>
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);
}
</code>
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
parent''Elm_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.
<code c>
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
);
}
}
</code>
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.
<code c>
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);
}
</code>
//**__Mixing Group and Tree Modes__**//
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.
=== Using Other APIs ===
//**__Homogeneous Item Size__**//
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 an Item After Its Creation__**//
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()'' :
<code c>
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);
}
</code>
\\
//**__The whole code__**// : {{/code_c/tutorial/genlist/modifications_genlist.c}}

View File

@ -0,0 +1,229 @@
~~Title: Genlist Set-up~~
==== Genlist Set-up ====
=== Creating a Genlist ===
Call ''elm_genlist_add()'' to create a genlist. Then, new entries can be added.
In this example, the basic windows is created first, then a genlist is added
to it, and then 100 elements with text and a colored block on each side of
it.
<code c>
Evas_Object *list = elm_genlist_add(win);
</code>
=== Adding New Entries ===
Before adding new entries, it is necessary to build a basic item class.
//**__Building a Basic Item Class__**//
When adding an item, genlist_item_{append, prepend, insert} function needs
item class of the item. Given callback parameters are used at retrieving
{text, content} of added item. Set as NULL if it's not used. If there's no
available memory, return can be NULL.
The code for the minimal genlist item class is below:
<code c>
Elm_Genlist_Item_Class *_itc = elm_genlist_item_class_new();
_itc->item_style = "default";
_itc->func.text_get = NULL;
_itc->func.content_get = NULL;
_itc->func.state_get = NULL;
_itc->func.del = NULL;
</code>
It creates a simple item class, sets the ''item_style'' to "default" and
every other field to NULL. However, this leaves out the ''text_get'' and
''content_get'' fields which are used to add text and an icon to the list
entry. This is explained in another section.
//**__Adding the Element__**//
Once the genlist item class object is created, a new element is added to the
list by calling ''elm_genlist_item_append()''.
<code c>
elm_genlist_item_append(list,
_itc,
NULL, // Item data
NULL, // Parent item for trees, NULL if none
ELM_GENLIST_ITEM_NONE, // Item type; this is the common one
NULL, // Callback on selection of the item
NULL // Data for that callback function
);
</code>
With most parameters as NULL and ''_itc'' having most of its members NULL,
too, the elements of that list are blank and will not trigger anything when
selected.
//**__Text in the List Elements__**//
Use ''text_get'' field to add text in the items in the
''Elm_Genlist_Item_Class'' structure.
<code c>
_itc->func.text_get = text_get;
</code>
These callbacks must have a prototype matching to the following:
<code c>
char * text_get(void *data, Evas_Object *obj, const char *part);
</code>
This callback returns a C string that is displayed in the part named after the
''part'' parameter. This callback is called for each user-settable text part
according to the current theme.
If you are not familiar with the concept of parts in the EFLs, read
[[/coming_soon|the Write a Simple EDC File]] section.
<note>
The value returned is freed by the EFLs: the value must be freshly-allocated, do not free it yourself and do not re-use it across list elements.
</note>
For the default theme there is one part named ''elm.text''. A possible
implementation of the ''text_get'' callback is therefore:
<code c>
static char *
_genlist_text_get(void *data, Evas_Object *obj, const char *part)
{
// Check this is text for the part we're expecting
if (strcmp(part, "elm.text") == 0)
{
return strdup("Some text");
}
else return NULL;
}
</code>
<note>
The names and positions of parts depends on the item_style chosen when adding new items to the genlist. Setting a custom theme makes it possible to completely change genlists by adding and moving parts. The [[/coming_soon|Edje]] guide explains how to do that.
</note>
It is possible to behave differently according to data
that is given to the EFLs during the call to ''elm_genlist_item_append()'' in the
''data'' parameter. For example, given an integer in that field through casting
with ''(void *)(uintptr_t) i'', its value is got back using
''(int)(uintptr_t)data'':
<code c>
static char *
_genlist_text_get(void *data, Evas_Object *obj __UNUSED__, const char *part)
{
if (strcmp(part, "elm.text") == 0)
{
char *buf = malloc(16);
snprintf(buf, 16, "Entry %d.", (int)(uintptr_t)data);
return buf;
}
else return NULL;
}
</code>
//**__Evas_Object in the List Elements__**//
Icons are added in a similar fashion: there is a callback named
''content_get'' which returns a pointer to an ''Evas_Object'' and is called
for each part which contents can be set.
<code c>
_itc->func.content_get = content_get;
</code>
The prototype of the callback must match this one:
<code c>
Evas_Object * content_get(void *data, Evas_Object *obj, const char *part);
</code>
The only difference with the ''text_get'' callback is that it returns an
''Evas_Object*'' rather than a ''char *''.
This leads to a fairly simple dummy implementation with colored rectangles in
the parts that are to be set:
<code c>
static Evas_Object *
_genlist_content_get(void *data, Evas_Object *obj, const char *part)
{
int i = (int) (uintptr_t) data;
//the left part
if (strcmp(part, "elm.swallow.icon") == 0)
{
Evas_Object *bg = elm_bg_add(obj);
elm_bg_color_set(bg, 255 * cos(i / (double) 10), 0, i % 255);
return bg;
}
//the right part
else if (strcmp(part, "elm.swallow.end") == 0)
{
Evas_Object *bg = elm_bg_add(obj);
elm_bg_color_set(bg, 0, 255 * sin(i / (double) 10), i % 255);
return bg;
}
else return NULL;
}
</code>
For the default theme, this displays a red rectangle on the left of each list
item and a green one on their right.
//**__Event on Gentlist Items__**//
Genlist items triggers a callback when clicked. This callback is chosen when
adding the new item (for example, when calling ''elm_genlist_item_append()''):
<code c>
Elm_Genlist_Item_Class *_itc2 = elm_genlist_item_class_new();
_itc2->item_style = "group_index";
_itc2->func.text_get = _genlist_text_get;
_itc2->func.content_get = _genlist_content_get;
_itc2->func.state_get = NULL;
_itc2->func.del = NULL;
elm_genlist_item_append(list,
itc,
NULL, // item data
NULL, // parent item for trees, NULL if none
ELM_GENLIST_ITEM_NONE, // item type, other values are used for trees
_genlist_selected_cb, // callback on selection of the item
_itc2 // data for that callback function
);
</code>
This callback adheres to the following prototype:
<code c>
void _contact_selected_cb(void *data, Evas_Object *obj, void *event_info)
</code>
The implementation below changes the item style of items when they are
selected:
<code c>
static void
_genlist_selected_cb(void *data, Evas_Object *obj, void *event_info)
{
Elm_Object_Item *it = (Elm_Object_Item*) event_info;
Elm_Genlist_Item_Class *itc2 = (Elm_Genlist_Item_Class *)data;
te
//change to group index style
elm_genlist_item_item_class_update(it, itc2);
}
</code>
\\
//**__The whole code__**// : {{/code_c/tutorial/genlist/set-up_genlist.c}}
==== Next Part ====
[[/tutorial/genlist/modifications|Modifications]]

View File

@ -0,0 +1,43 @@
~~Title: Genlist Tutorial~~
==== Genlist Tutorial ====
This tutorial deals with Elementary genlist, a list widget for large sets of
elements. Its API to populate entries reflects that as it uses callbacks.
Also keep in mind that the same widget handles both flat lists and trees and
this is obviously seen in the API.
=== Initialize the Application ===
The code below shows a typical Elementary application that creates a window
entitled "Genlist Basic Tutorial". The genlist goes inside.
<code c>
#include <Elementary.h>
EAPI_MAIN int
elm_main(int argc, char **argv)
{
Evas_Object *win;
win = elm_win_util_standard_add("Genlist", "Genlist Basic Tutorial");
elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
elm_win_autodel_set(win, EINA_TRUE);
//win 400x400 px
evas_object_resize(win, 400, 400);
//GENLIST here
evas_object_show(win);
elm_run();
return 0;
}
ELM_MAIN()
</code>
Genlist example :{{ :genlist.png?direct |list}}
=== Table of contents ===
* [[/tutorial/genlist/set-up|Set-up]] : {{/code_c/tutorial/genlist/set-up_genlist.c}}
* [[/tutorial/genlist/modifications|Modifications]] : {{/code_c/tutorial/genlist/modifications_genlist.c}}