1 #ifdef HAVE_CONFIG_H
2 #include "elementary_config.h"
3 #endif
4 
5 
6 #include <Efl_Ui.h>
7 #include <Elementary.h>
8 #include "elm_widget.h"
9 #include "elm_priv.h"
10 #include "efl_ui_position_manager_common.h"
11 
12 #define MY_CLASS      EFL_UI_POSITION_MANAGER_LIST_CLASS
13 #define MY_DATA_GET(obj, pd) \
14   Efl_Ui_Position_Manager_List_Data *pd = efl_data_scope_get(obj, MY_CLASS);
15 
16 typedef struct {
17    Api_Callbacks callbacks;
18 
19    Eina_Future *rebuild_absolut_size;
20    int *size_cache;
21    Efl_Gfx_Entity *last_group;
22    Efl_Ui_Win *window;
23    Evas *canvas;
24 
25    Vis_Segment prev_run;
26 
27    Eina_Rect viewport;
28    Eina_Size2D abs_size;
29    Eina_Vector2 scroll_position;
30 
31    Efl_Ui_Layout_Orientation dir;
32 
33    unsigned int size;
34    int average_item_size;
35    int maximum_min_size;
36 } Efl_Ui_Position_Manager_List_Data;
37 
38 /*
39  * The here used cache is a sum map
40  * Every element in the cache contains the sum of the previous element, and the size of the current item
41  * This is usefull as a lookup of all previous items is O(1).
42  * The tradeoff that makes the cache performant here is, that we only need to walk the whole list of items once in the beginning.
43  * Every other walk of the items is at max the maximum number of items you get into the maximum distance between the average item size and a actaul item size.
44  */
45 
46 static void
cache_invalidate(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd)47 cache_invalidate(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
48 {
49    if (pd->size_cache)
50      free(pd->size_cache);
51    pd->size_cache = NULL;
52 }
53 
54 static void
cache_require(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd)55 cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
56 {
57    unsigned int i;
58    const int len = 100;
59    Efl_Ui_Position_Manager_Size_Batch_Entity size_buffer[len];
60    Efl_Ui_Position_Manager_Size_Batch_Result size_result;
61 
62    if (pd->size_cache) return;
63 
64    if (pd->size == 0)
65      {
66         pd->size_cache = NULL;
67         pd->average_item_size = 0;
68         return;
69      }
70 
71    pd->size_cache = calloc(pd->size + 1, sizeof(int));
72    if (!pd->size_cache) return;
73    pd->size_cache[0] = 0;
74    pd->maximum_min_size = 0;
75 
76    for (i = 0; i < pd->size; ++i)
77      {
78         Eina_Size2D size;
79         int step;
80         int min;
81         int buffer_id = i % len;
82 
83         if (buffer_id == 0)
84           {
85              BATCH_ACCESS_SIZE(pd->callbacks, i, pd->size, MIN(len, pd->size - i), EINA_TRUE, size_buffer);
86           }
87        size = size_buffer[buffer_id].size;
88 
89         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
90           {
91              step = size.h;
92              min = size.w;
93           }
94         else
95           {
96              step = size.w;
97              min = size.h;
98           }
99         pd->size_cache[i + 1] = pd->size_cache[i] + step;
100         pd->maximum_min_size = MAX(pd->maximum_min_size, min);
101         /* no point iterating further if size calc can't be done yet */
102         //if ((!i) && (!pd->maximum_min_size)) break;
103      }
104    pd->average_item_size = pd->size_cache[pd->size]/pd->size;
105    if ((!pd->average_item_size) && (!pd->maximum_min_size))
106      cache_invalidate(obj, pd);
107 }
108 
109 static int
cache_access(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd,unsigned int idx)110 cache_access(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, unsigned int idx)
111 {
112    EINA_SAFETY_ON_FALSE_RETURN_VAL(idx <= pd->size, 0);
113    return pd->size_cache[idx];
114 }
115 
116 static void
recalc_absolut_size(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd)117 recalc_absolut_size(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd)
118 {
119    Eina_Size2D min_size = EINA_SIZE2D(-1, -1);
120    Eina_Size2D pabs_size = pd->abs_size;
121    int pmin_size = pd->maximum_min_size;
122 
123    cache_require(obj, pd);
124    /* deferred */
125    if (!pd->size_cache) return;
126 
127    pd->abs_size = pd->viewport.size;
128 
129    if (pd->size)
130      {
131         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
132           pd->abs_size.h = MAX(cache_access(obj, pd, pd->size), pd->abs_size.h);
133         else
134           pd->abs_size.w = MAX(cache_access(obj, pd, pd->size), pd->abs_size.w);
135      }
136    if ((pabs_size.w != pd->abs_size.w) || (pabs_size.h != pd->abs_size.h))
137      efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_CONTENT_SIZE_CHANGED, &pd->abs_size);
138 
139    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
140      {
141         min_size.w = pd->maximum_min_size;
142      }
143    else
144      {
145         min_size.h = pd->maximum_min_size;
146      }
147    if ((pd->maximum_min_size > 0) && (pd->maximum_min_size != pmin_size))
148      efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_CONTENT_MIN_SIZE_CHANGED, &min_size);
149 }
150 
151 static inline Vis_Segment
_search_visual_segment(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,int relevant_space_size,int relevant_viewport)152 _search_visual_segment(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int relevant_space_size, int relevant_viewport)
153 {
154    Vis_Segment cur;
155    //based on the average item size, we jump somewhere into the sum cache.
156    //After beeing in there, we are walking back, until we have less space then viewport size
157    cur.start_id = MIN((unsigned int)(relevant_space_size / pd->average_item_size), pd->size);
158    for (; cache_access(obj, pd, cur.start_id) >= relevant_space_size && cur.start_id > 0; cur.start_id --) { }
159 
160    //starting on the start id, we are walking down until the sum of elements is bigger than the lower part of the viewport.
161    cur.end_id = cur.start_id;
162    for (; cur.end_id <= pd->size && cache_access(obj, pd, cur.end_id) <= relevant_space_size + relevant_viewport ; cur.end_id ++) { }
163    cur.end_id = MAX(cur.end_id, cur.start_id + 1);
164    cur.end_id = MIN(cur.end_id, pd->size);
165 
166    #ifdef DEBUG
167    printf("space_size %d : starting point : %d : cached_space_starting_point %d end point : %d cache_space_end_point %d\n", space_size.h, cur.start_id, pd->size_cache[cur.start_id], cur.end_id, pd->size_cache[cur.end_id]);
168    #endif
169    if (relevant_space_size > 0)
170      EINA_SAFETY_ON_FALSE_GOTO(cache_access(obj, pd, cur.start_id) <= relevant_space_size, err);
171    if (cur.end_id != pd->size)
172      EINA_SAFETY_ON_FALSE_GOTO(cache_access(obj, pd, cur.end_id) >= relevant_space_size + relevant_viewport, err);
173    EINA_SAFETY_ON_FALSE_GOTO(cur.start_id <= cur.end_id, err);
174 
175    return cur;
176 
177 err:
178    cur.start_id = cur.end_id = 0;
179 
180    return cur;
181 }
182 
183 static inline void
_position_items(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd,Vis_Segment new,int relevant_space_size)184 _position_items(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, Vis_Segment new, int relevant_space_size)
185 {
186    Efl_Gfx_Entity *first_group = NULL, *first_fully_visual_group = NULL;
187    Eina_Size2D first_group_size;
188    Eina_Rect geom;
189    const int len = 100;
190    Efl_Ui_Position_Manager_Size_Batch_Entity size_buffer[len];
191    Efl_Ui_Position_Manager_Size_Batch_Result size_result;
192    Efl_Ui_Position_Manager_Object_Batch_Entity obj_buffer[len];
193    Efl_Ui_Position_Manager_Object_Batch_Result object_result;
194    unsigned int i;
195 
196    //placement of the plain items
197    geom = pd->viewport;
198 
199    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
200      geom.y -= (relevant_space_size - cache_access(obj, pd, new.start_id));
201    else
202      geom.x -= (relevant_space_size - cache_access(obj, pd, new.start_id));
203 
204    evas_event_freeze(pd->canvas);
205 
206    for (i = new.start_id; i < new.end_id; ++i)
207      {
208         Eina_Size2D size;
209         Efl_Gfx_Entity *ent = NULL;
210         int buffer_id = (i-new.start_id) % len;
211 
212         if (buffer_id == 0)
213           {
214              BATCH_ACCESS_SIZE(pd->callbacks, i, new.end_id, len, EINA_FALSE, size_buffer);
215              BATCH_ACCESS_OBJECT(pd->callbacks, i, new.end_id, len, obj_buffer);
216 
217              if (i == new.start_id)
218                {
219                   first_group = object_result.group;
220                   first_group_size = size_result.parent_size;
221                   if (obj_buffer[0].depth_leader)
222                     {
223                        first_group = obj_buffer[0].entity;
224                        first_group_size = size_buffer[0].size;
225                     }
226                }
227           }
228 
229         size = size_buffer[buffer_id].size;
230         ent = obj_buffer[buffer_id].entity;
231 
232         int diff = cache_access(obj, pd, i + 1) - cache_access(obj, pd, i);
233         int real_diff = 0;
234         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
235           real_diff = size.h;
236         else
237           real_diff = size.w;
238         if (real_diff != diff)
239           ERR("Reported sizes changed during caching and placement %d %d %d", i, real_diff, diff);
240 
241         if (ent == pd->last_group)
242           {
243              pd->last_group = NULL;
244           }
245 
246         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
247           geom.h = size.h;
248         else
249           geom.w = size.w;
250 
251         if (!first_fully_visual_group && obj_buffer[buffer_id].depth_leader &&
252              eina_spans_intersect(geom.x, geom.w, pd->viewport.x, pd->viewport.w) &&
253              eina_spans_intersect(geom.y, geom.h, pd->viewport.y, pd->viewport.h))
254           {
255              first_fully_visual_group = obj_buffer[buffer_id].entity;
256           }
257 
258         if (ent)
259           {
260              const char *signal;
261              efl_gfx_entity_visible_set(ent, EINA_TRUE);
262              efl_gfx_entity_geometry_set(ent, geom);
263              if (i % 2 == 0)
264                signal = "efl,state,even";
265              else
266                signal = "efl,state,odd";
267              efl_layout_signal_emit(ent, signal, "efl");
268           }
269         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
270           geom.y += size.h;
271         else
272           geom.x += size.w;
273      }
274    //Now place group items
275    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
276      first_group_size.w = pd->viewport.w;
277    else
278      first_group_size.h = pd->viewport.h;
279 
280    //if there is a new group item, display the new one, and hide the old one
281    if (first_group != pd->last_group)
282      {
283         efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
284         efl_gfx_stack_raise_to_top(first_group);
285         pd->last_group = first_group;
286      }
287    //we have to set the visibility again here, as changing the visual segments might overwrite our visibility state
288    efl_gfx_entity_visible_set(first_group, EINA_TRUE);
289 
290    //in case there is another group item coming in, the new group item (which is placed as normal item) moves the group item to the top
291    Eina_Position2D first_group_pos = EINA_POSITION2D(pd->viewport.x, pd->viewport.y);
292    if (first_fully_visual_group && first_fully_visual_group != first_group)
293      {
294         Eina_Position2D first_visual_group;
295         first_visual_group = efl_gfx_entity_position_get(first_fully_visual_group);
296         if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
297           first_group_pos.y = MIN(first_group_pos.y, first_visual_group.y - first_group_size.h);
298         else
299           first_group_pos.x = MIN(first_group_pos.x, first_visual_group.x - first_group_size.w);
300      }
301 
302    efl_gfx_entity_position_set(first_group, first_group_pos);
303    efl_gfx_entity_size_set(first_group, first_group_size);
304 
305    evas_event_thaw(pd->canvas);
306    evas_event_thaw_eval(pd->canvas);
307 }
308 
309 
310 static void
position_content(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd)311 position_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
312 {
313    Eina_Size2D space_size;
314    Vis_Segment cur;
315    int relevant_space_size, relevant_viewport;
316    Efl_Ui_Position_Manager_Range_Update ev;
317 
318    if (!pd->size) return;
319    if (pd->average_item_size <= 0) return;
320 
321    cache_require(obj, pd);
322 
323    //space size contains the amount of space that is outside the viewport (either to the top or to the left)
324    space_size.w = (MAX(pd->abs_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
325    space_size.h = (MAX(pd->abs_size.h - pd->viewport.h, 0))*pd->scroll_position.y;
326 
327    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
328      {
329         relevant_space_size = space_size.h;
330         relevant_viewport = pd->viewport.h;
331      }
332    else
333      {
334         relevant_space_size = space_size.w;
335         relevant_viewport = pd->viewport.w;
336      }
337 
338    cur = _search_visual_segment(obj, pd, relevant_space_size, relevant_viewport);
339    //to performance optimize the whole widget, we are setting the objects that are outside the viewport to visibility false
340    //The code below ensures that things outside the viewport are always hidden, and things inside the viewport are visible
341    vis_segment_swap(pd->callbacks, cur, pd->prev_run);
342 
343    _position_items(obj, pd, cur, relevant_space_size);
344 
345    if (pd->prev_run.start_id != cur.start_id || pd->prev_run.end_id != cur.end_id)
346      {
347         ev.start_id = pd->prev_run.start_id = cur.start_id;
348         ev.end_id = pd->prev_run.end_id = cur.end_id;
349         efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_VISIBLE_RANGE_CHANGED, &ev);
350      }
351 
352 }
353 
354 static Eina_Value
_rebuild_job_cb(Eo * obj,void * data,const Eina_Value v)355 _rebuild_job_cb(Eo *obj, void *data, const Eina_Value v)
356 {
357    Efl_Ui_Position_Manager_List_Data *pd = data;
358 
359    cache_require(obj, pd);
360    recalc_absolut_size(obj, pd);
361    position_content(obj, pd);
362 
363    return v;
364 }
365 
366 static void
_rebuild_job_free(Eo * o EINA_UNUSED,void * data,const Eina_Future * dead_future EINA_UNUSED)367 _rebuild_job_free(Eo *o EINA_UNUSED, void *data, const Eina_Future *dead_future EINA_UNUSED)
368 {
369    Efl_Ui_Position_Manager_List_Data *pd = data;
370 
371    pd->rebuild_absolut_size = NULL;
372 }
373 
374 static void
schedule_recalc_absolut_size(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd)375 schedule_recalc_absolut_size(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd)
376 {
377    if (pd->rebuild_absolut_size) return;
378 
379    pd->rebuild_absolut_size = efl_future_then(obj, efl_loop_job(efl_app_main_get()),
380                                               .success = _rebuild_job_cb,
381                                               .data = pd,
382                                               .free = _rebuild_job_free);
383 }
384 
385 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_viewport_set(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,Eina_Rect size)386 _efl_ui_position_manager_list_efl_ui_position_manager_entity_viewport_set(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, Eina_Rect size)
387 {
388    if (pd->viewport.x == size.x &&
389        pd->viewport.y == size.y &&
390        pd->viewport.w == size.w &&
391        pd->viewport.h == size.h)
392      return;
393 
394    pd->viewport = size;
395 
396    recalc_absolut_size(obj, pd);
397    position_content(obj, pd);
398 }
399 
400 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_scroll_position_set(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,double x,double y)401 _efl_ui_position_manager_list_efl_ui_position_manager_entity_scroll_position_set(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, double x, double y)
402 {
403    pd->scroll_position.x = x;
404    pd->scroll_position.y = y;
405    position_content(obj, pd);
406 }
407 
408 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_item_added(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,int added_index EINA_UNUSED,Efl_Gfx_Entity * subobj)409 _efl_ui_position_manager_list_efl_ui_position_manager_entity_item_added(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int added_index EINA_UNUSED, Efl_Gfx_Entity *subobj)
410 {
411    if (pd->size == 0)
412      {
413         pd->prev_run.start_id = 0;
414         pd->prev_run.end_id = 0;
415      }
416    pd->size ++;
417    if (subobj)
418      {
419         efl_gfx_entity_visible_set(subobj, EINA_FALSE);
420      }
421    cache_invalidate(obj, pd);
422    schedule_recalc_absolut_size(obj, pd);
423 }
424 
425 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_item_removed(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,int removed_index EINA_UNUSED,Efl_Gfx_Entity * subobj)426 _efl_ui_position_manager_list_efl_ui_position_manager_entity_item_removed(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int removed_index EINA_UNUSED, Efl_Gfx_Entity *subobj)
427 {
428    pd->size --;
429    if (subobj)
430      {
431         efl_gfx_entity_visible_set(subobj, EINA_TRUE);
432      }
433    cache_invalidate(obj, pd);
434    schedule_recalc_absolut_size(obj, pd);
435 }
436 
437 EOLIAN static Eina_Rect
_efl_ui_position_manager_list_efl_ui_position_manager_entity_position_single_item(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,int idx)438 _efl_ui_position_manager_list_efl_ui_position_manager_entity_position_single_item(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int idx)
439 {
440    Eina_Rect geom;
441    Eina_Size2D space_size;
442    int relevant_space_size;
443    Eina_Size2D size;
444    Efl_Ui_Position_Manager_Size_Batch_Entity size_buffer[1];
445    Efl_Ui_Position_Manager_Size_Batch_Result size_result;
446 
447    if (!pd->size) return EINA_RECT(0,0,0,0);
448 
449    cache_require(obj, pd);
450 
451    //space size contains the amount of space that is outside the viewport (either to the top or to the left)
452    space_size.w = (MAX(pd->abs_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
453    space_size.h = (MAX(pd->abs_size.h - pd->viewport.h, 0))*pd->scroll_position.y;
454 
455    EINA_SAFETY_ON_FALSE_RETURN_VAL(space_size.w >= 0 && space_size.h >= 0, EINA_RECT(0, 0, 0, 0));
456    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
457      {
458         relevant_space_size = space_size.h;
459      }
460    else
461      {
462         relevant_space_size = space_size.w;
463      }
464 
465    geom = pd->viewport;
466 
467    BATCH_ACCESS_SIZE_VAL(pd->callbacks, idx, idx + 1, 1, EINA_FALSE, size_buffer, EINA_RECT_EMPTY());
468 
469    size = size_buffer[0].size;
470 
471    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
472      {
473         geom.y -= (relevant_space_size - cache_access(obj, pd, idx));
474         geom.h = size.h;
475      }
476    else
477      {
478         geom.x -= (relevant_space_size - cache_access(obj, pd, idx));
479         geom.w = size.w;
480      }
481    return geom;
482 }
483 
484 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_item_size_changed(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,int start_id EINA_UNUSED,int end_id EINA_UNUSED)485 _efl_ui_position_manager_list_efl_ui_position_manager_entity_item_size_changed(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int start_id EINA_UNUSED, int end_id EINA_UNUSED)
486 {
487    cache_invalidate(obj, pd);
488    schedule_recalc_absolut_size(obj, pd);
489 }
490 
491 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_layout_orientable_orientation_set(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd,Efl_Ui_Layout_Orientation dir)492 _efl_ui_position_manager_list_efl_ui_layout_orientable_orientation_set(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, Efl_Ui_Layout_Orientation dir)
493 {
494    pd->dir = dir;
495    //in order to reset the state of the visible items, just hide everything and set the old segment accordingly
496    vis_change_segment(pd->callbacks, pd->prev_run.start_id, pd->prev_run.end_id, EINA_FALSE);
497    pd->prev_run.start_id = 0;
498    pd->prev_run.end_id = 0;
499 
500    cache_invalidate(obj, pd);
501    cache_require(obj,pd);
502    if (!efl_finalized_get(obj)) return;
503    recalc_absolut_size(obj, pd);
504    position_content(obj, pd);
505 }
506 
507 EOLIAN static Efl_Ui_Layout_Orientation
_efl_ui_position_manager_list_efl_ui_layout_orientable_orientation_get(const Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd)508 _efl_ui_position_manager_list_efl_ui_layout_orientable_orientation_get(const Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
509 {
510    return pd->dir;
511 }
512 
513 EOLIAN static void
_efl_ui_position_manager_list_efl_object_invalidate(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd)514 _efl_ui_position_manager_list_efl_object_invalidate(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd)
515 {
516    if (pd->rebuild_absolut_size)
517      eina_future_cancel(pd->rebuild_absolut_size);
518 
519    efl_ui_position_manager_data_access_v1_data_access_set(obj, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0);
520 
521    efl_invalidate(efl_super(obj, MY_CLASS));
522 }
523 
524 EOLIAN static Eina_Bool
_efl_ui_position_manager_list_efl_ui_position_manager_entity_relative_item(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd,unsigned int current_id,Efl_Ui_Focus_Direction direction,unsigned int * index)525 _efl_ui_position_manager_list_efl_ui_position_manager_entity_relative_item(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, unsigned int current_id, Efl_Ui_Focus_Direction direction, unsigned int *index)
526 {
527    switch(direction)
528      {
529         case EFL_UI_FOCUS_DIRECTION_RIGHT:
530         case EFL_UI_FOCUS_DIRECTION_NEXT:
531         case EFL_UI_FOCUS_DIRECTION_DOWN:
532            if (current_id + 1 >= pd->size) return EINA_FALSE;
533            current_id +=  1;
534            break;
535         case EFL_UI_FOCUS_DIRECTION_LEFT:
536         case EFL_UI_FOCUS_DIRECTION_PREVIOUS:
537         case EFL_UI_FOCUS_DIRECTION_UP:
538            if (current_id == 0) return EINA_FALSE;
539            current_id -=  1;
540            break;
541         default:
542            ERR("Uncaught case!");
543            return EINA_FALSE;
544      }
545 
546    if (index) *index = current_id;
547    return EINA_TRUE;
548 }
549 
550 EOLIAN static int
_efl_ui_position_manager_list_efl_ui_position_manager_entity_version(Eo * obj EINA_UNUSED,Efl_Ui_Position_Manager_List_Data * pd EINA_UNUSED,int max EINA_UNUSED)551 _efl_ui_position_manager_list_efl_ui_position_manager_entity_version(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd EINA_UNUSED, int max EINA_UNUSED)
552 {
553    return 1;
554 }
555 
556 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_data_access_v1_data_access_set(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,Efl_Ui_Win * canvas,void * obj_access_data,Efl_Ui_Position_Manager_Object_Batch_Callback obj_access,Eina_Free_Cb obj_access_free_cb,void * size_access_data,Efl_Ui_Position_Manager_Size_Batch_Callback size_access,Eina_Free_Cb size_access_free_cb,int size)557 _efl_ui_position_manager_list_efl_ui_position_manager_data_access_v1_data_access_set(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, Efl_Ui_Win *canvas, void *obj_access_data, Efl_Ui_Position_Manager_Object_Batch_Callback obj_access, Eina_Free_Cb obj_access_free_cb, void *size_access_data, Efl_Ui_Position_Manager_Size_Batch_Callback size_access, Eina_Free_Cb size_access_free_cb, int size)
558 {
559    // Cleanup cache first
560    cache_invalidate(obj, pd);
561 
562    // Clean callback if they were set
563    if (pd->callbacks.object.free_cb)
564      pd->callbacks.object.free_cb(pd->callbacks.object.data);
565    if (pd->callbacks.size.free_cb)
566      pd->callbacks.size.free_cb(pd->callbacks.size.data);
567 
568    // Set them
569    efl_replace(&pd->window, canvas);
570    efl_replace(&pd->canvas, canvas ? evas_object_evas_get(canvas) : NULL);
571 
572    pd->callbacks.object.data = obj_access_data;
573    pd->callbacks.object.access = obj_access;
574    pd->callbacks.object.free_cb = obj_access_free_cb;
575    pd->callbacks.size.data = size_access_data;
576    pd->callbacks.size.access = size_access;
577    pd->callbacks.size.free_cb = size_access_free_cb;
578    pd->size = size;
579 }
580 
581 
582 EOLIAN static void
_efl_ui_position_manager_list_efl_ui_position_manager_entity_entities_ready(Eo * obj,Efl_Ui_Position_Manager_List_Data * pd,unsigned int start_id,unsigned int end_id)583 _efl_ui_position_manager_list_efl_ui_position_manager_entity_entities_ready(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, unsigned int start_id, unsigned int end_id)
584 {
585    Eina_Size2D space_size;
586    int relevant_space_size;
587 
588    if (end_id < pd->prev_run.start_id || start_id > pd->prev_run.end_id)
589      return;
590 
591    if (!pd->size) return;
592    if (pd->average_item_size <= 0) return;
593 
594    cache_require(obj, pd);
595 
596    //space size contains the amount of space that is outside the viewport (either to the top or to the left)
597    space_size.w = (MAX(pd->abs_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
598    space_size.h = (MAX(pd->abs_size.h - pd->viewport.h, 0))*pd->scroll_position.y;
599 
600    if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
601      {
602         relevant_space_size = space_size.h;
603      }
604    else
605      {
606         relevant_space_size = space_size.w;
607      }
608    _position_items(obj, pd, pd->prev_run, relevant_space_size);
609 }
610 
611 
612 #include "efl_ui_position_manager_list.eo.c"
613