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