summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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;