summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2019-08-17 14:32:36 +0200
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2019-08-18 10:20:22 +0200
commit3e9e03403d57a14052ba7d4075629d0316fcf8a9 (patch)
tree3d244eb50bd86c70e1a527a8d5645ceffad9d408
parent774b4ff24b5a227b426b57a606384dc18b4e6f6f (diff)
efl_ui_position_manager_grid: start to honor group itemsdevs/bu5hm4n/items_work
This commit introduces the correct placement of group items and normal items. The gruop items are also floating on the top of there child items in case they are not visible on theire own. Items without group items between items with groups are right now a little bit troublesome and might display the wrong group, we *need* to check later on if this case is even needed or not. The whole placement code now uses 2 different caches, one cache is counting how many groups we have, and how many items each group has. Additionally, the size of the header + the state of the header is safes. The second cache does translate that into how much size one full group needs on the screen to be placed, this makes the calculation of the correct item placement a lot faster. The invalidation of the caches is also quite good. The size cache only depends on the viewport size and the group cache, which means its *never* recaclulated on a normal scroll operation. Only if items are added, or the widget is resized (The later case can also be more optimized). The group cache is only invalidated when new items are added (Which is normally not happening during rendering) ref T8115 Differential Revision: https://phab.enlightenment.org/D9608
-rw-r--r--src/lib/elementary/efl_ui_position_manager_grid.c618
1 files changed, 516 insertions, 102 deletions
diff --git a/src/lib/elementary/efl_ui_position_manager_grid.c b/src/lib/elementary/efl_ui_position_manager_grid.c
index 38b205c414..993bd3606c 100644
--- a/src/lib/elementary/efl_ui_position_manager_grid.c
+++ b/src/lib/elementary/efl_ui_position_manager_grid.c
@@ -13,36 +13,431 @@
13 Efl_Ui_Position_Manager_Grid_Data *pd = efl_data_scope_get(obj, MY_CLASS); 13 Efl_Ui_Position_Manager_Grid_Data *pd = efl_data_scope_get(obj, MY_CLASS);
14 14
15typedef struct { 15typedef struct {
16 unsigned int start_id, end_id;
17} Vis_Segment;
18
19typedef struct {
16 Api_Callback min_size, object; 20 Api_Callback min_size, object;
17 unsigned int size; 21 unsigned int size;
22 unsigned int groups;
18 Eina_Rect viewport; 23 Eina_Rect viewport;
19 Eina_Vector2 scroll_position; 24 Eina_Vector2 scroll_position;
20 Efl_Ui_Layout_Orientation dir; 25 Efl_Ui_Layout_Orientation dir;
21 struct { 26 Vis_Segment prev_run;
22 unsigned int start_id, end_id;
23 } prev_run;
24 Eina_Size2D max_min_size; 27 Eina_Size2D max_min_size;
25 Eina_Size2D last_viewport_size; 28 Eina_Size2D last_viewport_size;
26 Eina_Size2D prev_min_size; 29 Eina_Size2D prev_min_size;
27 struct { 30
28 int columns; 31 Eina_Inarray *group_cache;
29 int rows; 32 Eina_Bool group_cache_dirty;
30 } current_display_table; 33 int *size_cache;
34 Eina_Bool size_cache_dirty;
35 Eo *last_group;
36 Eina_Future *rebuild_absolut_size;
31} Efl_Ui_Position_Manager_Grid_Data; 37} Efl_Ui_Position_Manager_Grid_Data;
32 38
39typedef struct {
40 Eina_Bool real_group;
41 Eina_Size2D group_header_size;
42 int items;
43} Group_Cache_Line;
44
33static void 45static void
34_reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd) 46_group_cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
35{ 47{
36 Eina_Size2D space_size; 48 unsigned int i;
37 int relevant_space_size, relevant_viewport;
38 unsigned int start_id, end_id, step;
39 const int len = 100; 49 const int len = 100;
50 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[len];
51 Group_Cache_Line line = { 0 };
52
53 if (!pd->group_cache_dirty)
54 return;
55
56 pd->group_cache_dirty = EINA_FALSE;
57 if (pd->group_cache)
58 eina_inarray_free(pd->group_cache);
59 pd->group_cache = eina_inarray_new(sizeof(Group_Cache_Line), 10);
60
61 for (i = 0; i < pd->size; ++i)
62 {
63 int buffer_id = i % len;
64
65 if (buffer_id == 0)
66 {
67 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, len, NULL, size_buffer) > 0);
68 }
69
70 if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
71 {
72 eina_inarray_push(pd->group_cache, &line);
73 line.real_group = EINA_TRUE;
74 line.group_header_size = size_buffer[buffer_id].size;
75 line.items = 1;
76 }
77 else if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_PART_OF_GROUP ||
78 (!line.real_group && size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_NO_GROUP))
79 {
80 line.items ++;
81 }
82 else if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_NO_GROUP && line.real_group)
83 {
84 eina_inarray_push(pd->group_cache, &line);
85 line.real_group = EINA_FALSE;
86 line.group_header_size = EINA_SIZE2D(0, 0);
87 line.items = 0;
88 }
89 }
90 eina_inarray_push(pd->group_cache, &line);
91}
92
93static inline void
94_group_cache_invalidate(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
95{
96 pd->group_cache_dirty = EINA_TRUE;
97 pd->size_cache_dirty = EINA_TRUE;
98}
99
100static void
101_size_cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
102{
103 if (!pd->size_cache_dirty) return;
104
105 _group_cache_require(obj, pd);
106
107 pd->size_cache_dirty = EINA_FALSE;
108 if (pd->size_cache)
109 free(pd->size_cache);
110 pd->size_cache = calloc(sizeof(int), eina_inarray_count(pd->group_cache));
111
112 for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
113 {
114 Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
115 int header_out = 0;
116 if (line->real_group)
117 header_out = 1;
118
119 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
120 pd->size_cache[i] = line->group_header_size.h +
121 (ceil(
122 (double)(line->items - header_out)/ /* the number of real items in the group (- the group item) */
123 (int)(pd->viewport.w/pd->max_min_size.w))) /* devided by the number of items per row */
124 *pd->max_min_size.h;
125 else
126 pd->size_cache[i] = (ceil((double)(line->items - header_out)/
127 (int)((pd->viewport.h-line->group_header_size.h)/pd->max_min_size.h)))*pd->max_min_size.w;
128 }
129}
130
131static inline void
132_size_cache_invalidate(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
133{
134 pd->size_cache_dirty = EINA_TRUE;
135}
136
137typedef struct {
138 int resulting_id;
139 int consumed_space;
140} Search_Result;
141
142static inline Search_Result
143_search_id(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, int relevant_space_size)
144{
145 int consumed_space = 0;
146 int consumed_groups = -1;
147 int consumed_ids = 0;
148 int sub_ids = 0;
149 Search_Result res;
150
151 //first we search how many blocks we can skip
152 for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
153 {
154 Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
155 if (consumed_space + pd->size_cache[i] > relevant_space_size)
156 break;
157 consumed_space += pd->size_cache[i];
158 consumed_groups = i;
159 consumed_ids += line->items;
160 }
161 Group_Cache_Line *line = NULL;
162 if (consumed_groups > -1 && consumed_groups + 1 < (int)eina_inarray_count(pd->group_cache))
163 line = eina_inarray_nth(pd->group_cache, consumed_groups + 1);
164 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
165 {
166 //now we have relevant_space_size - consumed_space left maybe we are searching the group item
167
168 if (line && line->real_group)
169 {
170 if (consumed_space + line->group_header_size.h > relevant_space_size)
171 {
172 res.resulting_id = consumed_ids;
173 res.consumed_space = consumed_space;
174 return res;
175 }
176 else
177 {
178 consumed_space += line->group_header_size.h;
179 consumed_ids += 1;
180 }
181 }
182 //now we need to locate at which id we are starting
183 int space_top = relevant_space_size - consumed_space;
184 consumed_space += floor(space_top/pd->max_min_size.h)*pd->max_min_size.h;
185 sub_ids = floor(space_top/pd->max_min_size.h)*(pd->viewport.w/pd->max_min_size.w);
186 }
187 else
188 {
189 int header_height = 0;
190 if (line && line->real_group)
191 {
192 header_height = line->group_header_size.h;
193 }
194 //now we need to locate at which id we are starting
195 const int space_left = relevant_space_size - consumed_space;
196 consumed_space += floor(space_left/pd->max_min_size.w)*pd->max_min_size.w;
197 sub_ids = floor(space_left/pd->max_min_size.w)*((pd->viewport.h-header_height)/pd->max_min_size.h);
198 if (line && line->real_group &&
199 sub_ids > 0) /* if we are in the first row, we need the group item to be visible, otherwise, we need to add that to the consumed ids */
200 {
201 sub_ids += 1;
202 }
203 }
204 res.resulting_id = consumed_ids + sub_ids;
205 res.consumed_space = consumed_space;
206 return res;
207}
208
209static inline Eina_Bool
210_search_start_end(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, int relevant_viewport, int relevant_space_size, unsigned int step, Vis_Segment *cur, int *consumed_space)
211{
212 Search_Result start = _search_id(obj, pd, MAX(relevant_space_size, 0));
213 Search_Result end = _search_id(obj, pd, MAX(relevant_space_size, 0)+relevant_viewport+step*2);
214 cur->start_id = MIN(MAX(start.resulting_id, 0), (int)pd->size);
215 cur->end_id = MAX(MIN(end.resulting_id, (int)pd->size), 0);
216
217 *consumed_space = start.consumed_space;
218
219 return EINA_TRUE;
220}
221
222typedef struct {
223 int relevant_space_size;
224 int consumed_space;
225 Vis_Segment new;
226 Eo *floating_group;
227 Eina_Size2D floating_size;
228 Eo *placed_item;
229} Item_Position_Context;
230
231
232static inline void
233_place_grid_item(Eina_Rect *geom, Efl_Ui_Position_Manager_Grid_Data *pd, int x, int y)
234{
235 geom->x += x*pd->max_min_size.w;
236 geom->y += y*pd->max_min_size.h;
237 geom->size = pd->max_min_size;
238}
239
240static inline void
241_position_items_vertical(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
242{
243 Eina_Position2D start = pd->viewport.pos;
244 unsigned int i;
245 const int len = 100;
246 int columns, last_block_start = ctx->new.start_id;
40 Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len]; 247 Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len];
248
249 if (!pd->viewport.w || !pd->viewport.h) return;
250
251 start.y -= (ctx->relevant_space_size - ctx->consumed_space);
252 columns = pd->viewport.w/pd->max_min_size.w;
253
254 for (i = ctx->new.start_id; i < ctx->new.end_id; ++i)
255 {
256 int buffer_id = (i-ctx->new.start_id) % len;
257 if (buffer_id == 0)
258 {
259 int tmp_group;
260
261 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, &tmp_group, obj_buffer) > 0);
262 if (tmp_group != -1 && i == ctx->new.start_id)
263 {
264 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
265 Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[1];
266 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, tmp_group, 1, NULL, size_buffer) != 0);
267 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, tmp_group, 1, NULL, obj_buffer) != 0);
268 ctx->floating_group = obj_buffer[0].entity;
269 ctx->floating_size.h = size_buffer[0].size.h;
270 ctx->floating_size.w = pd->viewport.w;
271 }
272 }
273 Eina_Rect geom;
274 geom.pos = start;
275 int x = (i - last_block_start)%columns;
276 int y = (i - last_block_start)/columns;
277
278 if (obj_buffer[buffer_id].entity == pd->last_group)
279 pd->last_group = NULL;
280
281 if (obj_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
282 {
283 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
284 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, 1, NULL, size_buffer) == 1);
285
286 if (x != 0)
287 y += 1;
288
289 last_block_start = i + 1;
290 start.y += size_buffer[0].size.h + y*pd->max_min_size.h;
291
292 geom.size = pd->viewport.size;
293 geom.h = size_buffer[0].size.h;
294 geom.y += y*pd->max_min_size.h;
295 if (!ctx->placed_item)
296 ctx->placed_item = obj_buffer[buffer_id].entity;
297 }
298 else
299 {
300 _place_grid_item(&geom, pd, x, y);
301 }
302
303 efl_gfx_entity_geometry_set(obj_buffer[buffer_id].entity, geom);
304 }
305}
306
307static inline void
308_position_items_horizontal(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
309{
310 Eina_Position2D start = pd->viewport.pos;
311 unsigned int i;
312 const int len = 100;
313 int columns, last_block_start = ctx->new.start_id;
314 Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len];
315
316 if (!pd->viewport.w || !pd->viewport.h) return;
317
318 start.x -= (ctx->relevant_space_size - ctx->consumed_space);
319 columns = (pd->viewport.h)/pd->max_min_size.h;
320
321 for (i = ctx->new.start_id; i < ctx->new.end_id; ++i)
322 {
323 int buffer_id = (i-ctx->new.start_id) % len;
324 if (buffer_id == 0)
325 {
326 int tmp_group;
327
328 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, &tmp_group, obj_buffer) > 0);
329 if (tmp_group != -1 && i == ctx->new.start_id && pd->dir != EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
330 {
331 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
332 Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[1];
333 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, tmp_group, 1, NULL, size_buffer) != 0);
334 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, tmp_group, 1, NULL, obj_buffer) != 0);
335 start.y += size_buffer[0].size.h;
336 columns = (pd->viewport.h - size_buffer[0].size.h)/pd->max_min_size.h;
337 ctx->floating_group = obj_buffer[0].entity;
338 ctx->floating_size.h = size_buffer[0].size.h;
339 ctx->floating_size.w = pd->viewport.w;
340 }
341 }
342 Eina_Rect geom;
343 geom.pos = start;
344
345 int x = (i - last_block_start)/columns;
346 int y = (i - last_block_start)%columns;
347
348 if (obj_buffer[buffer_id].entity == pd->last_group)
349 pd->last_group = NULL;
350
351 if (obj_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
352 {
353 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
354 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, 1, NULL, size_buffer) == 1);
355
356 last_block_start = i + 1;
357 start.y = pd->viewport.y + size_buffer[0].size.h;
358 start.x += x*pd->max_min_size.w;
359
360 geom.size.h = size_buffer[0].size.h;
361 geom.size.w = pd->viewport.w;
362 geom.x += x*pd->max_min_size.w;
363 geom.y = pd->viewport.y;
364
365 columns = (pd->viewport.h - size_buffer[0].size.h)/pd->max_min_size.h;
366 if (!ctx->placed_item)
367 ctx->placed_item = obj_buffer[buffer_id].entity;
368 }
369 else
370 {
371 _place_grid_item(&geom, pd, x, y);
372 }
373 efl_gfx_entity_geometry_set(obj_buffer[buffer_id].entity, geom);
374 }
375}
376
377static inline void
378_position_group_items(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
379{
380 //floating group is not yet positioned, in case it is there, we need to position it there
381 Eina_Rect geom;
382
383 if (!ctx->floating_group && pd->last_group)
384 {
385 efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
386 pd->last_group = NULL;
387 }
388
389 if (ctx->floating_group)
390 {
391 geom.pos = pd->viewport.pos;
392 geom.size = ctx->floating_size;
393
394 if (ctx->placed_item)
395 {
396 Eina_Rect placed = efl_gfx_entity_geometry_get(ctx->placed_item);
397 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
398 {
399 geom.y = MIN(geom.y, placed.y-geom.h);
400 }
401 else
402 {
403 geom.x = MIN(geom.x, placed.x-geom.w);
404 }
405 }
406
407 if (pd->last_group != ctx->floating_group)
408 {
409 efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
410 pd->last_group = ctx->floating_group;
411 }
412
413 efl_gfx_entity_visible_set(ctx->floating_group, EINA_TRUE);
414 efl_gfx_stack_raise_to_top(ctx->floating_group);
415 efl_gfx_entity_geometry_set(ctx->floating_group, geom);
416 }
417 else if (ctx->placed_item)
418 {
419 Eina_Rect placed = efl_gfx_entity_geometry_get(ctx->placed_item);
420
421 placed.x = MAX(placed.x, pd->viewport.x);
422 placed.y = MAX(placed.y, pd->viewport.y);
423 efl_gfx_entity_geometry_set(ctx->placed_item, placed);
424 efl_gfx_stack_raise_to_top(ctx->placed_item);
425 }
426}
427
428static void
429_reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
430{
431 Eina_Size2D space_size;
432 int relevant_space_size, relevant_viewport, consumed_space;
433 Vis_Segment cur;
434 unsigned int step;
41 Efl_Ui_Position_Manager_Range_Update ev; 435 Efl_Ui_Position_Manager_Range_Update ev;
436 Item_Position_Context ctx;
42 437
43 if (!pd->size) return; 438 if (!pd->size) return;
44 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return; 439 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return;
45 if (pd->current_display_table.columns <= 0 || pd->current_display_table.rows <= 0) return; 440 if (!eina_inarray_count(pd->group_cache)) return;
46 441
47 //space size contains the amount of space that is outside the viewport (either to the top or to the left) 442 //space size contains the amount of space that is outside the viewport (either to the top or to the left)
48 space_size.w = (MAX(pd->last_viewport_size.w - pd->viewport.w, 0))*pd->scroll_position.x; 443 space_size.w = (MAX(pd->last_viewport_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
@@ -60,62 +455,45 @@ _reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
60 relevant_viewport = pd->viewport.w; 455 relevant_viewport = pd->viewport.w;
61 step = pd->max_min_size.w; 456 step = pd->max_min_size.w;
62 } 457 }
63 start_id = MIN((MAX(relevant_space_size,0) / step)*pd->current_display_table.columns, pd->size); 458 if (!_search_start_end(obj, pd, relevant_viewport, relevant_space_size, step, &cur, &consumed_space))
64 end_id = MIN((((MAX(relevant_space_size,0) + relevant_viewport + step) / step)*pd->current_display_table.columns)+1, pd->size); 459 return;
65
66 EINA_SAFETY_ON_FALSE_RETURN(start_id <= end_id);
67 EINA_SAFETY_ON_FALSE_RETURN(start_id <= pd->size);
68 460
69 //to performance optimize the whole widget, we are setting the objects that are outside the viewport to visibility false 461 //to performance optimize the whole widget, we are setting the objects that are outside the viewport to visibility false
70 //The code below ensures that things outside the viewport are always hidden, and things inside the viewport are visible 462 //The code below ensures that things outside the viewport are always hidden, and things inside the viewport are visible
71 if (end_id < pd->prev_run.start_id || start_id > pd->prev_run.end_id) 463 if (cur.end_id < pd->prev_run.start_id || cur.start_id > pd->prev_run.end_id)
72 { 464 {
73 //it is important to first make the segment visible here, and then hide the rest 465 //it is important to first make the segment visible here, and then hide the rest
74 //otherwise we get a state where item_container has 0 subchildren, which triggers a lot of focus logic. 466 //otherwise we get a state where item_container has 0 subchildren, which triggers a lot of focus logic.
75 vis_change_segment(&pd->object, start_id, end_id, EINA_TRUE); 467 vis_change_segment(&pd->object, cur.start_id, cur.end_id, EINA_TRUE);
76 vis_change_segment(&pd->object, pd->prev_run.start_id, pd->prev_run.end_id, EINA_FALSE); 468 vis_change_segment(&pd->object, pd->prev_run.start_id, pd->prev_run.end_id, EINA_FALSE);
77 } 469 }
78 else 470 else
79 { 471 {
80 vis_change_segment(&pd->object, pd->prev_run.start_id, start_id, (pd->prev_run.start_id > start_id)); 472 vis_change_segment(&pd->object, pd->prev_run.start_id, cur.start_id, (pd->prev_run.start_id > cur.start_id));
81 vis_change_segment(&pd->object, pd->prev_run.end_id, end_id, (pd->prev_run.end_id < end_id)); 473 vis_change_segment(&pd->object, pd->prev_run.end_id, cur.end_id, (pd->prev_run.end_id < cur.end_id));
82 } 474 }
83 475
84 for (unsigned int i = start_id; i < end_id; ++i) 476 ctx.new = cur;
85 { 477 ctx.consumed_space = consumed_space;
86 Eina_Rect geom; 478 ctx.relevant_space_size = relevant_space_size;
87 Efl_Gfx_Entity *ent; 479 ctx.floating_group = NULL;
88 int buffer_id = (i-start_id) % len; 480 ctx.placed_item = NULL;
89 geom.size = pd->max_min_size;
90 geom.pos = pd->viewport.pos;
91
92 if (buffer_id == 0)
93 {
94 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, NULL, obj_buffer) > 0);
95 }
96
97 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
98 {
99 geom.x += pd->max_min_size.w*(i%pd->current_display_table.columns);
100 geom.y += pd->max_min_size.h*(i/pd->current_display_table.columns);
101 geom.y -= (relevant_space_size);
102 }
103 else
104 {
105 geom.x += pd->max_min_size.w*(i/pd->current_display_table.columns);
106 geom.y += pd->max_min_size.h*(i%pd->current_display_table.columns);
107 geom.x -= (relevant_space_size);
108 }
109
110 ent = obj_buffer[buffer_id].entity;
111 481
112 //printf(">%d (%d, %d, %d, %d) %p\n", i, geom.x, geom.y, geom.w, geom.h, ent); 482 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
113 efl_gfx_entity_geometry_set(ent, geom); 483 {
484 _position_items_vertical(obj, pd, &ctx);
485 _position_group_items(obj, pd, &ctx);
114 } 486 }
115 if (pd->prev_run.start_id != start_id || pd->prev_run.end_id != end_id) 487 else
488 {
489 _position_items_horizontal(obj, pd, &ctx);
490 _position_group_items(obj, pd, &ctx);
491 }
492
493 if (pd->prev_run.start_id != cur.start_id || pd->prev_run.end_id != cur.end_id)
116 { 494 {
117 ev.start_id = pd->prev_run.start_id = start_id; 495 ev.start_id = pd->prev_run.start_id = cur.start_id;
118 ev.end_id = pd->prev_run.end_id = end_id; 496 ev.end_id = pd->prev_run.end_id = cur.end_id;
119 efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_VISIBLE_RANGE_CHANGED, &ev); 497 efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_VISIBLE_RANGE_CHANGED, &ev);
120 } 498 }
121} 499}
@@ -123,44 +501,27 @@ _reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
123static inline void 501static inline void
124_flush_abs_size(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd) 502_flush_abs_size(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd)
125{ 503{
126 int minor, major;
127 Eina_Size2D vp_size; 504 Eina_Size2D vp_size;
505 int sum_of_cache = 0;
128 506
129 if (!pd->size) return; 507 if (!pd->size) return;
130 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return; 508 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return;
131 509
132 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL) 510 _size_cache_require(obj, pd);
133 { 511 for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
134 major = pd->viewport.w/pd->max_min_size.w;
135 pd->current_display_table.columns = major;
136 }
137 else
138 { 512 {
139 major = pd->viewport.h/pd->max_min_size.h; 513 sum_of_cache += pd->size_cache[i];
140 pd->current_display_table.columns = major;
141 } 514 }
142 515
143 if (major <= 0) return;
144 minor = ceil((double)pd->size/(double)major);
145
146 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
147 pd->current_display_table.rows = minor;
148 else
149 pd->current_display_table.rows = minor;
150
151 /*
152 * calculate how much size we need with major in the given orientation.
153 * The
154 */
155 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL) 516 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
156 { 517 {
157 vp_size.w = pd->viewport.w; 518 vp_size.w = pd->viewport.w;
158 vp_size.h = minor*pd->max_min_size.h; 519 vp_size.h = sum_of_cache;
159 } 520 }
160 else 521 else
161 { 522 {
162 vp_size.h = pd->viewport.h; 523 vp_size.h = pd->viewport.h;
163 vp_size.w = minor*pd->max_min_size.w; 524 vp_size.w = sum_of_cache;
164 } 525 }
165 if (vp_size.h != pd->last_viewport_size.h || vp_size.w != pd->last_viewport_size.w) 526 if (vp_size.h != pd->last_viewport_size.h || vp_size.w != pd->last_viewport_size.w)
166 { 527 {
@@ -208,6 +569,7 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_data_access_set(Eo
208EOLIAN static void 569EOLIAN static void
209_efl_ui_position_manager_grid_efl_ui_position_manager_entity_viewport_set(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Eina_Rect viewport) 570_efl_ui_position_manager_grid_efl_ui_position_manager_entity_viewport_set(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Eina_Rect viewport)
210{ 571{
572 _size_cache_invalidate(obj, pd);
211 pd->viewport = viewport; 573 pd->viewport = viewport;
212 _flush_abs_size(obj, pd); 574 _flush_abs_size(obj, pd);
213 _reposition_content(obj, pd); 575 _reposition_content(obj, pd);
@@ -221,6 +583,29 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_scroll_position_set
221 _reposition_content(obj, pd); 583 _reposition_content(obj, pd);
222} 584}
223 585
586static Eina_Value
587_rebuild_job_cb(void *data, Eina_Value v EINA_UNUSED, const Eina_Future *f EINA_UNUSED)
588{
589 MY_DATA_GET(data, pd);
590
591 if (!efl_alive_get(data)) return EINA_VALUE_EMPTY;
592
593 _flush_abs_size(data, pd);
594 _reposition_content(data, pd);
595 pd->rebuild_absolut_size = NULL;
596
597 return EINA_VALUE_EMPTY;
598}
599
600static void
601_schedule_recalc_abs_size(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd)
602{
603 if (pd->rebuild_absolut_size) return;
604
605 pd->rebuild_absolut_size = efl_loop_job(efl_app_main_get());
606 eina_future_then(pd->rebuild_absolut_size, _rebuild_job_cb, obj);
607}
608
224EOLIAN static void 609EOLIAN static void
225_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_added(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd, int added_index, Efl_Gfx_Entity *subobj EINA_UNUSED) 610_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_added(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd, int added_index, Efl_Gfx_Entity *subobj EINA_UNUSED)
226{ 611{
@@ -228,27 +613,26 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_added(Eo *obj,
228 pd->size ++; 613 pd->size ++;
229 614
230 efl_gfx_entity_visible_set(subobj, EINA_FALSE); 615 efl_gfx_entity_visible_set(subobj, EINA_FALSE);
616 _group_cache_invalidate(obj, pd);
231 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, added_index, 1, NULL, &size) == 1); 617 EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, added_index, 1, NULL, &size) == 1);
232 _update_min_size(obj, pd, added_index, size[0].size); 618 _update_min_size(obj, pd, added_index, size[0].size);
233 _flush_min_size(obj, pd); 619 _flush_min_size(obj, pd);
234 _flush_abs_size(obj, pd); 620 _schedule_recalc_abs_size(obj, pd);
235 _reposition_content(obj, pd); //FIXME we might can skip that
236} 621}
237 622
238EOLIAN static void 623EOLIAN static void
239_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_removed(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, int removed_index EINA_UNUSED, Efl_Gfx_Entity *subobj EINA_UNUSED) 624_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_removed(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, int removed_index EINA_UNUSED, Efl_Gfx_Entity *subobj EINA_UNUSED)
240{ 625{
626 //we ignore here that we might loose the item giving the current max min size
241 EINA_SAFETY_ON_FALSE_RETURN(pd->size > 0); 627 EINA_SAFETY_ON_FALSE_RETURN(pd->size > 0);
242 pd->size --; 628 pd->size --;
629 _group_cache_invalidate(obj, pd);
243 pd->prev_run.start_id = MIN(pd->prev_run.start_id, pd->size); 630 pd->prev_run.start_id = MIN(pd->prev_run.start_id, pd->size);
244 pd->prev_run.end_id = MIN(pd->prev_run.end_id, pd->size); 631 pd->prev_run.end_id = MIN(pd->prev_run.end_id, pd->size);
245 //we ignore here that we might loose the item giving the current max min size 632 _schedule_recalc_abs_size(obj, pd);
246 _flush_abs_size(obj, pd);
247 _reposition_content(obj, pd); //FIXME we might can skip that
248 efl_gfx_entity_visible_set(subobj, EINA_TRUE); 633 efl_gfx_entity_visible_set(subobj, EINA_TRUE);
249} 634}
250 635
251
252EOLIAN static void 636EOLIAN static void
253_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_size_changed(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd, int start_id, int end_id) 637_efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_size_changed(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd, int start_id, int end_id)
254{ 638{
@@ -264,10 +648,9 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_size_changed(E
264 } 648 }
265 _update_min_size(obj, pd, i, data[i-start_id].size); 649 _update_min_size(obj, pd, i, data[i-start_id].size);
266 } 650 }
267 651 _size_cache_invalidate(obj, pd);
268 _flush_min_size(obj, pd); 652 _flush_min_size(obj, pd);
269 _flush_abs_size(obj, pd); 653 _schedule_recalc_abs_size(obj, pd);
270 _reposition_content(obj, pd); //FIXME we could check if this is needed or not
271} 654}
272 655
273EOLIAN static void 656EOLIAN static void
@@ -292,38 +675,69 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_position_single_ite
292 Eina_Rect geom; 675 Eina_Rect geom;
293 Eina_Size2D space_size; 676 Eina_Size2D space_size;
294 unsigned int relevant_space_size; 677 unsigned int relevant_space_size;
678 unsigned int group_consumed_size = 0;
679 unsigned int group_consumed_ids = 0;
680 Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
295 681
296 if (!pd->size) return EINA_RECT(0, 0, 0, 0); 682 if (!pd->size) return EINA_RECT(0, 0, 0, 0);
297 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return EINA_RECT(0, 0, 0, 0); 683 if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return EINA_RECT(0, 0, 0, 0);
298 if (pd->current_display_table.columns <= 0 || pd->current_display_table.rows <= 0) return EINA_RECT(0, 0, 0, 0); 684 EINA_SAFETY_ON_FALSE_RETURN_VAL(_fill_buffer(&pd->min_size, idx, 1, NULL, size_buffer) == 1, EINA_RECT_EMPTY());
685
686 _size_cache_require(obj, pd);
687 _flush_abs_size(obj, pd);
299 688
300 //space size contains the amount of space that is outside the viewport (either to the top or to the left)
301 space_size.w = (MAX(pd->last_viewport_size.w - pd->viewport.w, 0))*pd->scroll_position.x; 689 space_size.w = (MAX(pd->last_viewport_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
302 space_size.h = (MAX(pd->last_viewport_size.h - pd->viewport.h, 0))*pd->scroll_position.y; 690 space_size.h = (MAX(pd->last_viewport_size.h - pd->viewport.h, 0))*pd->scroll_position.y;
303
304 EINA_SAFETY_ON_FALSE_RETURN_VAL(space_size.w >= 0 && space_size.h >= 0, EINA_RECT(0, 0, 0, 0));
305 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL) 691 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
306 { 692 relevant_space_size = space_size.h;
307 relevant_space_size = space_size.h;
308 }
309 else 693 else
310 { 694 relevant_space_size = space_size.w;
311 relevant_space_size = space_size.w; 695
312 }
313 geom.size = pd->max_min_size; 696 geom.size = pd->max_min_size;
314 geom.pos = pd->viewport.pos; 697 geom.pos = pd->viewport.pos;
315 698
699 for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
700 {
701 Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
702 if ((int)group_consumed_ids + line->items > idx)
703 break;
704
705 group_consumed_size += pd->size_cache[i];
706 group_consumed_ids += line->items;
707 if (line->real_group && idx == (int)group_consumed_ids + 1)
708 {
709 geom.y = (relevant_space_size - group_consumed_size);
710 geom.size = size_buffer[0].size;
711
712 return geom;
713 }
714 else if (line->real_group)
715 group_consumed_size += line->group_header_size.h;
716 }
717
718 if (idx > 0)
719 EINA_SAFETY_ON_FALSE_RETURN_VAL(group_consumed_ids < (unsigned int)idx, EINA_RECT(0, 0, 0, 0));
720 else if (idx == 0)
721 EINA_SAFETY_ON_FALSE_RETURN_VAL(group_consumed_ids == 0, EINA_RECT(0, 0, 0, 0));
722
723 int columns = pd->viewport.w/pd->max_min_size.w;
724 int sub_pos_id = idx - group_consumed_ids;
725 int x = (sub_pos_id)%columns;
726 int y = (sub_pos_id)/columns;
727
316 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL) 728 if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
317 { 729 {
318 geom.x += pd->max_min_size.w*(idx%pd->current_display_table.columns); 730 geom.y -= relevant_space_size;
319 geom.y += pd->max_min_size.h*(idx/pd->current_display_table.columns); 731 geom.x += pd->max_min_size.w*x;
320 geom.y -= (relevant_space_size); 732 geom.y += group_consumed_size;
733 geom.y += pd->max_min_size.h*y;
734
321 } 735 }
322 else 736 else
323 { 737 {
324 geom.x += pd->max_min_size.w*(idx/pd->current_display_table.columns); 738 /*geom.x += pd->max_min_size.w*(idx/pd->current_display_table.columns);
325 geom.y += pd->max_min_size.h*(idx%pd->current_display_table.columns); 739 geom.y += pd->max_min_size.h*(idx%pd->current_display_table.columns);
326 geom.x -= (relevant_space_size); 740 geom.x -= (relevant_space_size);*/
327 } 741 }
328 742
329 return geom; 743 return geom;
@@ -344,10 +758,10 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_relative_item(Eo *o
344 new_id -= 1; 758 new_id -= 1;
345 break; 759 break;
346 case EFL_UI_FOCUS_DIRECTION_UP: 760 case EFL_UI_FOCUS_DIRECTION_UP:
347 new_id -= pd->current_display_table.columns; 761 //FIXME
348 break; 762 break;
349 case EFL_UI_FOCUS_DIRECTION_DOWN: 763 case EFL_UI_FOCUS_DIRECTION_DOWN:
350 new_id += pd->current_display_table.columns; 764 //FIXME
351 break; 765 break;
352 default: 766 default:
353 new_id = -1; 767 new_id = -1;