efl_ui_widget: introduce a new API

Summary:
this new API can be used to get a easy to use iterator, to iterate
through all the children of a specific widget.

ref T7553

Reviewers: stefan_schmidt, zmike, cedric, segfaultxavi

Reviewed By: segfaultxavi

Subscribers: woohyun, cedric, #reviewers, #committers

Tags: #efl

Maniphest Tasks: T7553

Differential Revision: https://phab.enlightenment.org/D8014
This commit is contained in:
Marcel Hollerbach 2019-02-27 13:29:08 -05:00 committed by Mike Blumenkrantz
parent a5e183ad5d
commit aef19e9017
9 changed files with 399 additions and 0 deletions

View File

@ -347,6 +347,7 @@ includesunstable_HEADERS = \
lib/elementary/elm_interface_scrollable.h \
lib/elementary/elm_interfaces.h \
lib/elementary/elm_widget.h \
lib/elementary/efl_ui_widget_common.h \
lib/elementary/elm_widget_actionslider.h \
lib/elementary/elm_widget_box.h \
lib/elementary/elm_widget_bubble.h \
@ -816,6 +817,7 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/elm_view_form.c \
lib/elementary/elm_web2.c \
lib/elementary/efl_ui_widget.c \
lib/elementary/efl_ui_widget_common.c \
lib/elementary/efl_ui_win.c \
lib/elementary/efl_ui_win_inlined.c \
lib/elementary/efl_ui_win_socket.c \
@ -1630,6 +1632,7 @@ tests_elementary_efl_ui_suite_SOURCES = \
tests/elementary/efl_ui_test_image.c \
tests/elementary/efl_ui_test_image_zoomable.c \
tests/elementary/efl_ui_test_layout.c \
tests/elementary/efl_ui_test_widget.c \
tests/elementary/efl_ui_suite.h \
tests/elementary/efl_ui_model.c

View File

@ -170,6 +170,8 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel);
# include <efl_ui_theme.eo.h>
# include <efl_config_global.eo.h>
# include <efl_ui_widget.eo.h>
# include <efl_ui_widget_common.h>
# include <efl_ui_widget_part.eo.h>
# include <efl_ui_layout_base.eo.h>
# include <efl_ui_layout.eo.h>

View File

@ -0,0 +1,173 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_ACCESS_OBJECT_PROTECTED
#define EFL_ACCESS_COMPONENT_PROTECTED
#define ELM_WIDGET_PROTECTED
#define ELM_WIDGET_ITEM_PROTECTED
#define EFL_INPUT_EVENT_PROTECTED
#define EFL_UI_L10N_PROTECTED
#define EFL_UI_FOCUS_OBJECT_PROTECTED
#define EFL_UI_WIDGET_PART_BG_PROTECTED
#define EFL_PART_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_widget_container.h"
#include "elm_interface_scrollable.h"
#include "elm_part_helper.h"
#include "elm_widget_combobox.h"
typedef struct {
Eina_Iterator iterator;
Efl_Ui_Widget *origin; //where we started
Efl_Ui_Widget *current; // the current widget where the iterator is
} Widget_Iterator;
static Widget_Iterator*
iter_init(Efl_Ui_Widget *origin)
{
Widget_Iterator *it;
it = calloc(1, sizeof(Widget_Iterator));
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->origin = origin;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(NULL);
it->iterator.free = FUNC_ITERATOR_FREE(free);
return it;
}
static Efl_Ui_Widget*
_fetch_parent_widget(Efl_Gfx_Entity* o)
{
Efl_Ui_Widget *parent;
if (efl_isa(o, EFL_UI_WIDGET_CLASS))
parent = efl_ui_widget_parent_get(o);
else
parent = evas_object_data_get(o, "elm-parent");
return parent;
}
static Efl_Ui_Widget*
_next_widget(Efl_Gfx_Entity* o)
{
Efl_Ui_Widget *parent;
Eina_List *rel;
parent = _fetch_parent_widget(o);
ELM_WIDGET_DATA_GET_OR_RETURN(parent, pd, NULL);
rel = eina_list_data_find_list(pd->subobjs, o);
return eina_list_data_get(eina_list_next(rel));
}
static Eina_Bool
_widget_next(Widget_Iterator *it, void **data)
{
Efl_Ui_Widget *runner;
Efl_Ui_Widget_Data *pd = NULL;
//Init case
if (!it->current)
{
it->current = it->origin;
goto deliver;
}
if (efl_isa(it->current, EFL_UI_WIDGET_CLASS))
{
pd = efl_data_scope_safe_get(it->current, EFL_UI_WIDGET_CLASS);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINA_FALSE);
}
//If there is a child, go there
if (pd && pd->subobjs)
{
it->current = eina_list_data_get(pd->subobjs);
goto deliver;
}
//If there is no child, then iterate up the parents until we find a widget with a next widget
runner = it->current;
do
{
Efl_Ui_Widget *tmp = _next_widget(runner);
if (tmp)
{
it->current = tmp;
goto deliver;
}
runner = _fetch_parent_widget(runner);
}
while(runner && runner != it->origin);
//Reaching this point here means that there is no widget left, as there is no more parent we can explore
it->current = NULL;
deliver:
*data = (void*)it->current;
return !!it->current;
}
EAPI Eina_Iterator*
efl_ui_widget_tree_iterator(Efl_Ui_Widget *obj)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, pd, NULL);
Widget_Iterator *it = iter_init(obj);
it->iterator.next = FUNC_ITERATOR_NEXT(_widget_next);
return &it->iterator;
}
static Eina_Bool
_only_widget(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
{
return efl_isa(data, EFL_UI_WIDGET_CLASS);
}
EAPI Eina_Iterator*
efl_ui_widget_tree_widget_iterator(Efl_Ui_Widget *obj)
{
Eina_Iterator *tree_iterator = efl_ui_widget_tree_iterator(obj);
ELM_WIDGET_DATA_GET_OR_RETURN(obj, pd, NULL);
return eina_iterator_filter_new(tree_iterator, _only_widget, NULL, NULL);
}
static Eina_Bool
_parent_next(Widget_Iterator *it, void **data)
{
if (!it->current)
{
*data = it->origin;
it->current = *data;
}
else
{
Efl_Ui_Widget *parent = efl_ui_widget_parent_get(it->current);
*data = parent;
it->current = parent;
}
return !!*data;
}
EAPI Eina_Iterator*
efl_ui_widget_parent_iterator(Efl_Ui_Widget *obj)
{
ELM_WIDGET_DATA_GET_OR_RETURN(obj, pd, NULL);
Widget_Iterator *it = iter_init(obj);
it->iterator.next = FUNC_ITERATOR_NEXT(_parent_next);
return &it->iterator;
}

View File

@ -0,0 +1,35 @@
#ifndef EFL_UI_WIDGET_COMMON_H
#define EFL_UI_WIDGET_COMMON_H
/**
* @brief Get an iterator over all subelements located at obj.
*
* This iterator contains also the canvas objects which are part of the widgets,
* be aware that the construction of this tree is internal and might change heavily
* inbetween versions.
*
* @param obj The widget which is the root of the subtree.
*
* @return A iterator that contains subelement widgets and canvas objects of the root widget. Every contained object is a Efl.Gfx.Entity.
*/
EAPI Eina_Iterator* efl_ui_widget_tree_iterator(Efl_Ui_Widget *obj);
/**
* @brief Get an iterator over all subelements located at obj.
*
* @param obj The widget which is the root of the subtree.
*
* @return A iterator that contains subelement widgets of the root widget. Every contained object is a Efl.Ui.Widget.
*/
EAPI Eina_Iterator* efl_ui_widget_tree_widget_iterator(Efl_Ui_Widget *obj);
/**
* @brief Get an iterator that contains all parents of the passed object.
*
* @param obj The object to fetch the parents from.
*
* @return A iterator that contains all parents of the object. Every contained object is a Efl.Ui.Widget.
*/
EAPI Eina_Iterator* efl_ui_widget_parent_iterator(Efl_Ui_Widget *obj);
#endif

View File

@ -837,6 +837,7 @@ elementary_src = [
'elm_view_form.c',
'elm_web2.c',
'efl_ui_widget.c',
'efl_ui_widget_common.c',
'efl_ui_win.c',
'efl_ui_win_inlined.c',
'efl_ui_win_socket.c',

View File

@ -19,6 +19,7 @@ static const Efl_Test_Case etc[] = {
{ "efl_ui_image_zoomable", efl_ui_test_image_zoomable},
{ "efl_ui_layout", efl_ui_test_layout},
{ "Efl_Ui_Model", efl_ui_model },
{ "efl_ui_widget", efl_ui_test_widget },
{ NULL, NULL }
};

View File

@ -31,6 +31,7 @@ void efl_ui_test_focus(TCase *tc);
void efl_ui_test_focus_sub(TCase *tc);
void efl_ui_model(TCase *tc);
void efl_ui_test_widget(TCase *tc);
void loop_timer_interval_set(Eo *obj, double in);

View File

@ -0,0 +1,182 @@
//#define EFL_NOLEGACY_API_SUPPORT
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include "elm_widget.h"
#include <Efl_Ui.h>
#include "efl_ui_suite.h"
typedef struct {
Efl_Ui_Widget *btn1, *btn2;
Efl_Ui_Widget *box;
Efl_Ui_Widget *win;
Efl_Ui_Widget *ic;
} State;
static void
_small_ui(State *s)
{
s->win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(),
efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
efl_text_set(efl_added, "Hello World"));
s->ic = efl_add(EFL_UI_IMAGE_CLASS, s->win,
efl_ui_win_icon_object_set(s->win, efl_added));
s->box = efl_add(EFL_UI_BOX_CLASS, s->win,
efl_content_set(s->win, efl_added));
s->btn1 = efl_add(EFL_UI_BUTTON_CLASS, s->box,
efl_text_set(efl_added, "Quit1"),
efl_pack(s->box, efl_added));
s->btn2 = efl_add(EFL_UI_BUTTON_CLASS, s->box,
efl_text_set(efl_added, "Quit"),
efl_pack(s->box, efl_added));
}
EFL_START_TEST(efl_ui_test_widget_parent_iterator)
{
Eina_Iterator *it;
Efl_Ui_Widget *o;
Eina_Array *a;
State s;
a = eina_array_new(10);
_small_ui(&s);
eina_array_push(a, s.win);
eina_array_push(a, s.box);
eina_array_push(a, s.btn1);
it = efl_ui_widget_parent_iterator(s.btn1);
EINA_ITERATOR_FOREACH(it, o)
{
ck_assert_ptr_eq(eina_array_pop(a), o);
}
eina_iterator_free(it);
ck_assert_int_eq(eina_array_count(a), 0);
}
EFL_END_TEST
EFL_START_TEST(efl_ui_test_widget_widget_iterator)
{
Eina_Iterator *it;
Efl_Ui_Widget *o;
Eina_Array *a;
State s;
a = eina_array_new(10);
_small_ui(&s);
eina_array_push(a, s.btn2);
eina_array_push(a, s.btn1);
eina_array_push(a, s.box);
eina_array_push(a, s.ic); //Hack arround the icon of the window
eina_array_push(a, s.win);
it = efl_ui_widget_tree_widget_iterator(s.win);
EINA_ITERATOR_FOREACH(it, o)
{
Eo *c = eina_array_pop(a);
ck_assert_ptr_eq(c, o);
}
eina_iterator_free(it);
ck_assert_int_eq(eina_array_count(a), 0);
}
EFL_END_TEST
static Evas_Object*
resize_object(Efl_Canvas_Object *o)
{
Efl_Ui_Widget_Data *pd = efl_data_scope_safe_get(o, EFL_UI_WIDGET_CLASS);
return eina_list_data_get(pd->subobjs);
}
EFL_START_TEST(efl_ui_test_widget_widget_sub_iterator)
{
Eina_Iterator *it;
Efl_Ui_Widget *o;
Eina_Array *a;
State s;
a = eina_array_new(10);
_small_ui(&s);
eina_array_push(a, s.btn2);
eina_array_push(a, s.btn1);
eina_array_push(a, s.box);
it = efl_ui_widget_tree_widget_iterator(s.box);
EINA_ITERATOR_FOREACH(it, o)
{
ck_assert_ptr_eq(eina_array_pop(a), o);
}
eina_iterator_free(it);
ck_assert_int_eq(eina_array_count(a), 0);
}
EFL_END_TEST
EFL_START_TEST(efl_ui_test_widget_iterator)
{
Eina_Iterator *it;
Efl_Ui_Widget *o;
Eina_Array *a;
State s;
a = eina_array_new(10);
_small_ui(&s);
eina_array_push(a, resize_object(s.btn2));
eina_array_push(a, s.btn2);
eina_array_push(a, resize_object(s.btn1));
eina_array_push(a, s.btn1);
eina_array_push(a, resize_object(s.box));
eina_array_push(a, s.box);
eina_array_push(a, resize_object(s.ic));
eina_array_push(a, s.ic);
eina_array_push(a, s.win);
it = efl_ui_widget_tree_iterator(s.win);
EINA_ITERATOR_FOREACH(it, o)
{
ck_assert_ptr_eq(eina_array_pop(a), o);
}
eina_iterator_free(it);
ck_assert_int_eq(eina_array_count(a), 0);
}
EFL_END_TEST
EFL_START_TEST(efl_ui_test_widget_sub_iterator)
{
Eina_Iterator *it;
Efl_Ui_Widget *o;
Eina_Array *a;
State s;
a = eina_array_new(10);
_small_ui(&s);
eina_array_push(a, resize_object(s.btn2));
eina_array_push(a, s.btn2);
eina_array_push(a, resize_object(s.btn1));
eina_array_push(a, s.btn1);
eina_array_push(a, resize_object(s.box));
eina_array_push(a, s.box);
it = efl_ui_widget_tree_iterator(s.box);
EINA_ITERATOR_FOREACH(it, o)
{
ck_assert_ptr_eq(eina_array_pop(a), o);
}
eina_iterator_free(it);
ck_assert_int_eq(eina_array_count(a), 0);
}
EFL_END_TEST
void efl_ui_test_widget(TCase *tc)
{
tcase_add_test(tc, efl_ui_test_widget_parent_iterator);
tcase_add_test(tc, efl_ui_test_widget_widget_iterator);
tcase_add_test(tc, efl_ui_test_widget_widget_sub_iterator);
tcase_add_test(tc, efl_ui_test_widget_iterator);
tcase_add_test(tc, efl_ui_test_widget_sub_iterator);
}

View File

@ -130,6 +130,7 @@ efl_ui_suite_src = [
'efl_ui_test_layout.c',
'efl_ui_suite.h',
'efl_ui_model.c',
'efl_ui_test_widget.c',
]
efl_ui_suite = executable('efl_ui_suite',