summaryrefslogtreecommitdiff
path: root/src/lib/elementary/efl_ui_widget_common.c
blob: 020848887b49de24184cb48d82df08a1733ff314 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
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;
}