aboutsummaryrefslogtreecommitdiffstats
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
parentefl_ui_position_manager_common: fix buffer_id (diff)
downloadefl-devs/bu5hm4n/items_work.tar.gz
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 https://phab.enlightenment.org/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 @@
Efl_Ui_Position_Manager_Grid_Data *pd = efl_data_scope_get(obj, MY_CLASS);
typedef struct {
+ unsigned int start_id, end_id;
+} Vis_Segment;
+
+typedef struct {
Api_Callback min_size, object;
unsigned int size;
+ unsigned int groups;
Eina_Rect viewport;
Eina_Vector2 scroll_position;
Efl_Ui_Layout_Orientation dir;
- struct {
- unsigned int start_id, end_id;
- } prev_run;
+ Vis_Segment prev_run;
Eina_Size2D max_min_size;
Eina_Size2D last_viewport_size;
Eina_Size2D prev_min_size;
- struct {
- int columns;
- int rows;
- } current_display_table;
+
+ Eina_Inarray *group_cache;
+ Eina_Bool group_cache_dirty;
+ int *size_cache;
+ Eina_Bool size_cache_dirty;
+ Eo *last_group;
+ Eina_Future *rebuild_absolut_size;
} Efl_Ui_Position_Manager_Grid_Data;
+typedef struct {
+ Eina_Bool real_group;
+ Eina_Size2D group_header_size;
+ int items;
+} Group_Cache_Line;
+
static void
-_reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
+_group_cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
{
- Eina_Size2D space_size;
- int relevant_space_size, relevant_viewport;
- unsigned int start_id, end_id, step;
+ unsigned int i;
const int len = 100;
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[len];
+ Group_Cache_Line line = { 0 };
+
+ if (!pd->group_cache_dirty)
+ return;
+
+ pd->group_cache_dirty = EINA_FALSE;
+ if (pd->group_cache)
+ eina_inarray_free(pd->group_cache);
+ pd->group_cache = eina_inarray_new(sizeof(Group_Cache_Line), 10);
+
+ for (i = 0; i < pd->size; ++i)
+ {
+ int buffer_id = i % len;
+
+ if (buffer_id == 0)
+ {
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, len, NULL, size_buffer) > 0);
+ }
+
+ if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
+ {
+ eina_inarray_push(pd->group_cache, &line);
+ line.real_group = EINA_TRUE;
+ line.group_header_size = size_buffer[buffer_id].size;
+ line.items = 1;
+ }
+ else if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_PART_OF_GROUP ||
+ (!line.real_group && size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_NO_GROUP))
+ {
+ line.items ++;
+ }
+ else if (size_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_NO_GROUP && line.real_group)
+ {
+ eina_inarray_push(pd->group_cache, &line);
+ line.real_group = EINA_FALSE;
+ line.group_header_size = EINA_SIZE2D(0, 0);
+ line.items = 0;
+ }
+ }
+ eina_inarray_push(pd->group_cache, &line);
+}
+
+static inline void
+_group_cache_invalidate(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
+{
+ pd->group_cache_dirty = EINA_TRUE;
+ pd->size_cache_dirty = EINA_TRUE;
+}
+
+static void
+_size_cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
+{
+ if (!pd->size_cache_dirty) return;
+
+ _group_cache_require(obj, pd);
+
+ pd->size_cache_dirty = EINA_FALSE;
+ if (pd->size_cache)
+ free(pd->size_cache);
+ pd->size_cache = calloc(sizeof(int), eina_inarray_count(pd->group_cache));
+
+ for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
+ {
+ Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
+ int header_out = 0;
+ if (line->real_group)
+ header_out = 1;
+
+ if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
+ pd->size_cache[i] = line->group_header_size.h +
+ (ceil(
+ (double)(line->items - header_out)/ /* the number of real items in the group (- the group item) */
+ (int)(pd->viewport.w/pd->max_min_size.w))) /* devided by the number of items per row */
+ *pd->max_min_size.h;
+ else
+ pd->size_cache[i] = (ceil((double)(line->items - header_out)/
+ (int)((pd->viewport.h-line->group_header_size.h)/pd->max_min_size.h)))*pd->max_min_size.w;
+ }
+}
+
+static inline void
+_size_cache_invalidate(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
+{
+ pd->size_cache_dirty = EINA_TRUE;
+}
+
+typedef struct {
+ int resulting_id;
+ int consumed_space;
+} Search_Result;
+
+static inline Search_Result
+_search_id(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, int relevant_space_size)
+{
+ int consumed_space = 0;
+ int consumed_groups = -1;
+ int consumed_ids = 0;
+ int sub_ids = 0;
+ Search_Result res;
+
+ //first we search how many blocks we can skip
+ for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
+ {
+ Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
+ if (consumed_space + pd->size_cache[i] > relevant_space_size)
+ break;
+ consumed_space += pd->size_cache[i];
+ consumed_groups = i;
+ consumed_ids += line->items;
+ }
+ Group_Cache_Line *line = NULL;
+ if (consumed_groups > -1 && consumed_groups + 1 < (int)eina_inarray_count(pd->group_cache))
+ line = eina_inarray_nth(pd->group_cache, consumed_groups + 1);
+ if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
+ {
+ //now we have relevant_space_size - consumed_space left maybe we are searching the group item
+
+ if (line && line->real_group)
+ {
+ if (consumed_space + line->group_header_size.h > relevant_space_size)
+ {
+ res.resulting_id = consumed_ids;
+ res.consumed_space = consumed_space;
+ return res;
+ }
+ else
+ {
+ consumed_space += line->group_header_size.h;
+ consumed_ids += 1;
+ }
+ }
+ //now we need to locate at which id we are starting
+ int space_top = relevant_space_size - consumed_space;
+ consumed_space += floor(space_top/pd->max_min_size.h)*pd->max_min_size.h;
+ sub_ids = floor(space_top/pd->max_min_size.h)*(pd->viewport.w/pd->max_min_size.w);
+ }
+ else
+ {
+ int header_height = 0;
+ if (line && line->real_group)
+ {
+ header_height = line->group_header_size.h;
+ }
+ //now we need to locate at which id we are starting
+ const int space_left = relevant_space_size - consumed_space;
+ consumed_space += floor(space_left/pd->max_min_size.w)*pd->max_min_size.w;
+ sub_ids = floor(space_left/pd->max_min_size.w)*((pd->viewport.h-header_height)/pd->max_min_size.h);
+ if (line && line->real_group &&
+ 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 */
+ {
+ sub_ids += 1;
+ }
+ }
+ res.resulting_id = consumed_ids + sub_ids;
+ res.consumed_space = consumed_space;
+ return res;
+}
+
+static inline Eina_Bool
+_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)
+{
+ Search_Result start = _search_id(obj, pd, MAX(relevant_space_size, 0));
+ Search_Result end = _search_id(obj, pd, MAX(relevant_space_size, 0)+relevant_viewport+step*2);
+ cur->start_id = MIN(MAX(start.resulting_id, 0), (int)pd->size);
+ cur->end_id = MAX(MIN(end.resulting_id, (int)pd->size), 0);
+
+ *consumed_space = start.consumed_space;
+
+ return EINA_TRUE;
+}
+
+typedef struct {
+ int relevant_space_size;
+ int consumed_space;
+ Vis_Segment new;
+ Eo *floating_group;
+ Eina_Size2D floating_size;
+ Eo *placed_item;
+} Item_Position_Context;
+
+
+static inline void
+_place_grid_item(Eina_Rect *geom, Efl_Ui_Position_Manager_Grid_Data *pd, int x, int y)
+{
+ geom->x += x*pd->max_min_size.w;
+ geom->y += y*pd->max_min_size.h;
+ geom->size = pd->max_min_size;
+}
+
+static inline void
+_position_items_vertical(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
+{
+ Eina_Position2D start = pd->viewport.pos;
+ unsigned int i;
+ const int len = 100;
+ int columns, last_block_start = ctx->new.start_id;
Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len];
+
+ if (!pd->viewport.w || !pd->viewport.h) return;
+
+ start.y -= (ctx->relevant_space_size - ctx->consumed_space);
+ columns = pd->viewport.w/pd->max_min_size.w;
+
+ for (i = ctx->new.start_id; i < ctx->new.end_id; ++i)
+ {
+ int buffer_id = (i-ctx->new.start_id) % len;
+ if (buffer_id == 0)
+ {
+ int tmp_group;
+
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, &tmp_group, obj_buffer) > 0);
+ if (tmp_group != -1 && i == ctx->new.start_id)
+ {
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
+ Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[1];
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, tmp_group, 1, NULL, size_buffer) != 0);
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, tmp_group, 1, NULL, obj_buffer) != 0);
+ ctx->floating_group = obj_buffer[0].entity;
+ ctx->floating_size.h = size_buffer[0].size.h;
+ ctx->floating_size.w = pd->viewport.w;
+ }
+ }
+ Eina_Rect geom;
+ geom.pos = start;
+ int x = (i - last_block_start)%columns;
+ int y = (i - last_block_start)/columns;
+
+ if (obj_buffer[buffer_id].entity == pd->last_group)
+ pd->last_group = NULL;
+
+ if (obj_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
+ {
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, 1, NULL, size_buffer) == 1);
+
+ if (x != 0)
+ y += 1;
+
+ last_block_start = i + 1;
+ start.y += size_buffer[0].size.h + y*pd->max_min_size.h;
+
+ geom.size = pd->viewport.size;
+ geom.h = size_buffer[0].size.h;
+ geom.y += y*pd->max_min_size.h;
+ if (!ctx->placed_item)
+ ctx->placed_item = obj_buffer[buffer_id].entity;
+ }
+ else
+ {
+ _place_grid_item(&geom, pd, x, y);
+ }
+
+ efl_gfx_entity_geometry_set(obj_buffer[buffer_id].entity, geom);
+ }
+}
+
+static inline void
+_position_items_horizontal(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
+{
+ Eina_Position2D start = pd->viewport.pos;
+ unsigned int i;
+ const int len = 100;
+ int columns, last_block_start = ctx->new.start_id;
+ Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len];
+
+ if (!pd->viewport.w || !pd->viewport.h) return;
+
+ start.x -= (ctx->relevant_space_size - ctx->consumed_space);
+ columns = (pd->viewport.h)/pd->max_min_size.h;
+
+ for (i = ctx->new.start_id; i < ctx->new.end_id; ++i)
+ {
+ int buffer_id = (i-ctx->new.start_id) % len;
+ if (buffer_id == 0)
+ {
+ int tmp_group;
+
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, &tmp_group, obj_buffer) > 0);
+ if (tmp_group != -1 && i == ctx->new.start_id && pd->dir != EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
+ {
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
+ Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[1];
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, tmp_group, 1, NULL, size_buffer) != 0);
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, tmp_group, 1, NULL, obj_buffer) != 0);
+ start.y += size_buffer[0].size.h;
+ columns = (pd->viewport.h - size_buffer[0].size.h)/pd->max_min_size.h;
+ ctx->floating_group = obj_buffer[0].entity;
+ ctx->floating_size.h = size_buffer[0].size.h;
+ ctx->floating_size.w = pd->viewport.w;
+ }
+ }
+ Eina_Rect geom;
+ geom.pos = start;
+
+ int x = (i - last_block_start)/columns;
+ int y = (i - last_block_start)%columns;
+
+ if (obj_buffer[buffer_id].entity == pd->last_group)
+ pd->last_group = NULL;
+
+ if (obj_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
+ {
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
+ EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, 1, NULL, size_buffer) == 1);
+
+ last_block_start = i + 1;
+ start.y = pd->viewport.y + size_buffer[0].size.h;
+ start.x += x*pd->max_min_size.w;
+
+ geom.size.h = size_buffer[0].size.h;
+ geom.size.w = pd->viewport.w;
+ geom.x += x*pd->max_min_size.w;
+ geom.y = pd->viewport.y;
+
+ columns = (pd->viewport.h - size_buffer[0].size.h)/pd->max_min_size.h;
+ if (!ctx->placed_item)
+ ctx->placed_item = obj_buffer[buffer_id].entity;
+ }
+ else
+ {
+ _place_grid_item(&geom, pd, x, y);
+ }
+ efl_gfx_entity_geometry_set(obj_buffer[buffer_id].entity, geom);
+ }
+}
+
+static inline void
+_position_group_items(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd, Item_Position_Context *ctx)
+{
+ //floating group is not yet positioned, in case it is there, we need to position it there
+ Eina_Rect geom;
+
+ if (!ctx->floating_group && pd->last_group)
+ {
+ efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
+ pd->last_group = NULL;
+ }
+
+ if (ctx->floating_group)
+ {
+ geom.pos = pd->viewport.pos;
+ geom.size = ctx->floating_size;
+
+ if (ctx->placed_item)
+ {
+ Eina_Rect placed = efl_gfx_entity_geometry_get(ctx->placed_item);
+ if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
+ {
+ geom.y = MIN(geom.y, placed.y-geom.h);
+ }
+ else
+ {
+ geom.x = MIN(geom.x, placed.x-geom.w);
+ }
+ }
+
+ if (pd->last_group != ctx->floating_group)
+ {
+ efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
+ pd->last_group = ctx->floating_group;
+ }
+
+ efl_gfx_entity_visible_set(ctx->floating_group, EINA_TRUE);
+ efl_gfx_stack_raise_to_top(ctx->floating_group);
+ efl_gfx_entity_geometry_set(ctx->floating_group, geom);
+ }
+ else if (ctx->placed_item)
+ {
+ Eina_Rect placed = efl_gfx_entity_geometry_get(ctx->placed_item);
+
+ placed.x = MAX(placed.x, pd->viewport.x);
+ placed.y = MAX(placed.y, pd->viewport.y);
+ efl_gfx_entity_geometry_set(ctx->placed_item, placed);
+ efl_gfx_stack_raise_to_top(ctx->placed_item);
+ }
+}
+
+static void
+_reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
+{
+ Eina_Size2D space_size;
+ int relevant_space_size, relevant_viewport, consumed_space;
+ Vis_Segment cur;
+ unsigned int step;
Efl_Ui_Position_Manager_Range_Update ev;
+ Item_Position_Context ctx;
if (!pd->size) return;
if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return;
- if (pd->current_display_table.columns <= 0 || pd->current_display_table.rows <= 0) return;
+ if (!eina_inarray_count(pd->group_cache)) return;
//space size contains the amount of space that is outside the viewport (either to the top or to the left)
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)
relevant_viewport = pd->viewport.w;
step = pd->max_min_size.w;
}
- start_id = MIN((MAX(relevant_space_size,0) / step)*pd->current_display_table.columns, pd->size);
- end_id = MIN((((MAX(relevant_space_size,0) + relevant_viewport + step) / step)*pd->current_display_table.columns)+1, pd->size);
-
- EINA_SAFETY_ON_FALSE_RETURN(start_id <= end_id);
- EINA_SAFETY_ON_FALSE_RETURN(start_id <= pd->size);
+ if (!_search_start_end(obj, pd, relevant_viewport, relevant_space_size, step, &cur, &consumed_space))
+ return;
//to performance optimize the whole widget, we are setting the objects that are outside the viewport to visibility false
//The code below ensures that things outside the viewport are always hidden, and things inside the viewport are visible
- if (end_id < pd->prev_run.start_id || start_id > pd->prev_run.end_id)
+ if (cur.end_id < pd->prev_run.start_id || cur.start_id > pd->prev_run.end_id)
{
//it is important to first make the segment visible here, and then hide the rest
//otherwise we get a state where item_container has 0 subchildren, which triggers a lot of focus logic.
- vis_change_segment(&pd->object, start_id, end_id, EINA_TRUE);
+ vis_change_segment(&pd->object, cur.start_id, cur.end_id, EINA_TRUE);
vis_change_segment(&pd->object, pd->prev_run.start_id, pd->prev_run.end_id, EINA_FALSE);
}
else
{
- vis_change_segment(&pd->object, pd->prev_run.start_id, start_id, (pd->prev_run.start_id > start_id));
- vis_change_segment(&pd->object, pd->prev_run.end_id, end_id, (pd->prev_run.end_id < end_id));
+ vis_change_segment(&pd->object, pd->prev_run.start_id, cur.start_id, (pd->prev_run.start_id > cur.start_id));
+ vis_change_segment(&pd->object, pd->prev_run.end_id, cur.end_id, (pd->prev_run.end_id < cur.end_id));
}
- for (unsigned int i = start_id; i < end_id; ++i)
- {
- Eina_Rect geom;
- Efl_Gfx_Entity *ent;
- int buffer_id = (i-start_id) % len;
- geom.size = pd->max_min_size;
- geom.pos = pd->viewport.pos;
-
- if (buffer_id == 0)
- {
- EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, i, len, NULL, obj_buffer) > 0);
- }
-
- if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
- {
- geom.x += pd->max_min_size.w*(i%pd->current_display_table.columns);
- geom.y += pd->max_min_size.h*(i/pd->current_display_table.columns);
- geom.y -= (relevant_space_size);
- }
- else
- {
- geom.x += pd->max_min_size.w*(i/pd->current_display_table.columns);
- geom.y += pd->max_min_size.h*(i%pd->current_display_table.columns);
- geom.x -= (relevant_space_size);
- }
-
- ent = obj_buffer[buffer_id].entity;
+ ctx.new = cur;
+ ctx.consumed_space = consumed_space;
+ ctx.relevant_space_size = relevant_space_size;
+ ctx.floating_group = NULL;
+ ctx.placed_item = NULL;
- //printf(">%d (%d, %d, %d, %d) %p\n", i, geom.x, geom.y, geom.w, geom.h, ent);
- efl_gfx_entity_geometry_set(ent, geom);
+ if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
+ {
+ _position_items_vertical(obj, pd, &ctx);
+ _position_group_items(obj, pd, &ctx);
}
- if (pd->prev_run.start_id != start_id || pd->prev_run.end_id != end_id)
+ else
+ {
+ _position_items_horizontal(obj, pd, &ctx);
+ _position_group_items(obj, pd, &ctx);
+ }
+
+ if (pd->prev_run.start_id != cur.start_id || pd->prev_run.end_id != cur.end_id)
{
- ev.start_id = pd->prev_run.start_id = start_id;
- ev.end_id = pd->prev_run.end_id = end_id;
+ ev.start_id = pd->prev_run.start_id = cur.start_id;
+ ev.end_id = pd->prev_run.end_id = cur.end_id;
efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_VISIBLE_RANGE_CHANGED, &ev);
}
}
@@ -123,44 +501,27 @@ _reposition_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
static inline void
_flush_abs_size(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd)
{
- int minor, major;
Eina_Size2D vp_size;
+ int sum_of_cache = 0;
if (!pd->size) return;
if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return;
- if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
- {
- major = pd->viewport.w/pd->max_min_size.w;
- pd->current_display_table.columns = major;
- }
- else
+ _size_cache_require(obj, pd);
+ for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
{
- major = pd->viewport.h/pd->max_min_size.h;
- pd->current_display_table.columns = major;
+ sum_of_cache += pd->size_cache[i];
}
- if (major <= 0) return;
- minor = ceil((double)pd->size/(double)major);
-
- if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
- pd->current_display_table.rows = minor;
- else
- pd->current_display_table.rows = minor;
-
- /*
- * calculate how much size we need with major in the given orientation.
- * The
- */
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
{
vp_size.w = pd->viewport.w;
- vp_size.h = minor*pd->max_min_size.h;
+ vp_size.h = sum_of_cache;
}
else
{
vp_size.h = pd->viewport.h;
- vp_size.w = minor*pd->max_min_size.w;
+ vp_size.w = sum_of_cache;
}
if (vp_size.h != pd->last_viewport_size.h || vp_size.w != pd->last_viewport_size.w)
{
@@ -208,6 +569,7 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_data_access_set(Eo
EOLIAN static void
_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)
{
+ _size_cache_invalidate(obj, pd);
pd->viewport = viewport;
_flush_abs_size(obj, pd);
_reposition_content(obj, pd);
@@ -221,6 +583,29 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_scroll_position_set
_reposition_content(obj, pd);
}
+static Eina_Value
+_rebuild_job_cb(void *data, Eina_Value v EINA_UNUSED, const Eina_Future *f EINA_UNUSED)
+{
+ MY_DATA_GET(data, pd);
+
+ if (!efl_alive_get(data)) return EINA_VALUE_EMPTY;
+
+ _flush_abs_size(data, pd);
+ _reposition_content(data, pd);
+ pd->rebuild_absolut_size = NULL;
+
+ return EINA_VALUE_EMPTY;
+}
+
+static void
+_schedule_recalc_abs_size(Eo *obj, Efl_Ui_Position_Manager_Grid_Data *pd)
+{
+ if (pd->rebuild_absolut_size) return;
+
+ pd->rebuild_absolut_size = efl_loop_job(efl_app_main_get());
+ eina_future_then(pd->rebuild_absolut_size, _rebuild_job_cb, obj);
+}
+
EOLIAN static void
_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)
{
@@ -228,27 +613,26 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_added(Eo *obj,
pd->size ++;
efl_gfx_entity_visible_set(subobj, EINA_FALSE);
+ _group_cache_invalidate(obj, pd);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, added_index, 1, NULL, &size) == 1);
_update_min_size(obj, pd, added_index, size[0].size);
_flush_min_size(obj, pd);
- _flush_abs_size(obj, pd);
- _reposition_content(obj, pd); //FIXME we might can skip that
+ _schedule_recalc_abs_size(obj, pd);
}
EOLIAN static void
_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)
{
+ //we ignore here that we might loose the item giving the current max min size
EINA_SAFETY_ON_FALSE_RETURN(pd->size > 0);
pd->size --;
+ _group_cache_invalidate(obj, pd);
pd->prev_run.start_id = MIN(pd->prev_run.start_id, pd->size);
pd->prev_run.end_id = MIN(pd->prev_run.end_id, pd->size);
- //we ignore here that we might loose the item giving the current max min size
- _flush_abs_size(obj, pd);
- _reposition_content(obj, pd); //FIXME we might can skip that
+ _schedule_recalc_abs_size(obj, pd);
efl_gfx_entity_visible_set(subobj, EINA_TRUE);
}
-
EOLIAN static void
_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)
{
@@ -264,10 +648,9 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_item_size_changed(E
}
_update_min_size(obj, pd, i, data[i-start_id].size);
}
-
+ _size_cache_invalidate(obj, pd);
_flush_min_size(obj, pd);
- _flush_abs_size(obj, pd);
- _reposition_content(obj, pd); //FIXME we could check if this is needed or not
+ _schedule_recalc_abs_size(obj, pd);
}
EOLIAN static void
@@ -292,38 +675,69 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_position_single_ite
Eina_Rect geom;
Eina_Size2D space_size;
unsigned int relevant_space_size;
+ unsigned int group_consumed_size = 0;
+ unsigned int group_consumed_ids = 0;
+ Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
if (!pd->size) return EINA_RECT(0, 0, 0, 0);
if (pd->max_min_size.w <= 0 || pd->max_min_size.h <= 0) return EINA_RECT(0, 0, 0, 0);
- if (pd->current_display_table.columns <= 0 || pd->current_display_table.rows <= 0) return EINA_RECT(0, 0, 0, 0);
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(_fill_buffer(&pd->min_size, idx, 1, NULL, size_buffer) == 1, EINA_RECT_EMPTY());
+
+ _size_cache_require(obj, pd);
+ _flush_abs_size(obj, pd);
- //space size contains the amount of space that is outside the viewport (either to the top or to the left)
space_size.w = (MAX(pd->last_viewport_size.w - pd->viewport.w, 0))*pd->scroll_position.x;
space_size.h = (MAX(pd->last_viewport_size.h - pd->viewport.h, 0))*pd->scroll_position.y;
-
- EINA_SAFETY_ON_FALSE_RETURN_VAL(space_size.w >= 0 && space_size.h >= 0, EINA_RECT(0, 0, 0, 0));
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
- {
- relevant_space_size = space_size.h;
- }
+ relevant_space_size = space_size.h;
else
- {
- relevant_space_size = space_size.w;
- }
+ relevant_space_size = space_size.w;
+
geom.size = pd->max_min_size;
geom.pos = pd->viewport.pos;
+ for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
+ {
+ Group_Cache_Line *line = eina_inarray_nth(pd->group_cache, i);
+ if ((int)group_consumed_ids + line->items > idx)
+ break;
+
+ group_consumed_size += pd->size_cache[i];
+ group_consumed_ids += line->items;
+ if (line->real_group && idx == (int)group_consumed_ids + 1)
+ {
+ geom.y = (relevant_space_size - group_consumed_size);
+ geom.size = size_buffer[0].size;
+
+ return geom;
+ }
+ else if (line->real_group)
+ group_consumed_size += line->group_header_size.h;
+ }
+
+ if (idx > 0)
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(group_consumed_ids < (unsigned int)idx, EINA_RECT(0, 0, 0, 0));
+ else if (idx == 0)
+ EINA_SAFETY_ON_FALSE_RETURN_VAL(group_consumed_ids == 0, EINA_RECT(0, 0, 0, 0));
+
+ int columns = pd->viewport.w/pd->max_min_size.w;
+ int sub_pos_id = idx - group_consumed_ids;
+ int x = (sub_pos_id)%columns;
+ int y = (sub_pos_id)/columns;
+
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
{
- geom.x += pd->max_min_size.w*(idx%pd->current_display_table.columns);
- geom.y += pd->max_min_size.h*(idx/pd->current_display_table.columns);
- geom.y -= (relevant_space_size);
+ geom.y -= relevant_space_size;
+ geom.x += pd->max_min_size.w*x;
+ geom.y += group_consumed_size;
+ geom.y += pd->max_min_size.h*y;
+
}
else
{
- geom.x += pd->max_min_size.w*(idx/pd->current_display_table.columns);
+ /*geom.x += pd->max_min_size.w*(idx/pd->current_display_table.columns);
geom.y += pd->max_min_size.h*(idx%pd->current_display_table.columns);
- geom.x -= (relevant_space_size);
+ geom.x -= (relevant_space_size);*/
}
return geom;
@@ -344,10 +758,10 @@ _efl_ui_position_manager_grid_efl_ui_position_manager_entity_relative_item(Eo *o
new_id -= 1;
break;
case EFL_UI_FOCUS_DIRECTION_UP:
- new_id -= pd->current_display_table.columns;
+ //FIXME
break;
case EFL_UI_FOCUS_DIRECTION_DOWN:
- new_id += pd->current_display_table.columns;
+ //FIXME
break;
default:
new_id = -1;