Compare commits

...

9 Commits

Author SHA1 Message Date
Marcel Hollerbach 3e9e03403d efl_ui_position_manager_grid: start to honor group items
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
2019-08-18 10:20:22 +02:00
Marcel Hollerbach 774b4ff24b efl_ui_position_manager_common: fix buffer_id
the buffer was accessed with the wrong id, buffer_id should be used.

Differential Revision: https://phab.enlightenment.org/D9607
2019-08-18 10:20:22 +02:00
Marcel Hollerbach 9d1a693d29 efl_ui_position_manager_list: make it handle group items
this makes the group items stick at the top of the viewport, if the
corresponding items in there do have the item available.
For now items between two groups are not really handled, the group
header will still just be displayed.

The code for this feature is explicitly written in a single block, it
was said that we might want to have this able to be enabled / disabled
later on.

This commit also shuffels the code here a bit, one single method just
got too long.

ref T8115

Differential Revision: https://phab.enlightenment.org/D9587
2019-08-18 10:20:21 +02:00
Marcel Hollerbach a50c30a8bc efl_ui_position_manager: pass on information about group ids
every batched call will now contain the id of the first item, if the
conditions in the documentation are met.

ref T8115

Differential Revision: https://phab.enlightenment.org/D9586
2019-08-18 10:20:21 +02:00
Marcel Hollerbach 1587f0ce46 elm_test: add group items
this is just to showcase them for now, for now they are positioned
wrong. later revisions will handle the correct positioning

Differential Revision: https://phab.enlightenment.org/D9585
2019-08-18 10:20:21 +02:00
Marcel Hollerbach 91a279e560 elm_test: rename file and remove wrong names
additionally, we can just use efl_ui_list and grid class here, no need
for more complex stuff

Differential Revision: https://phab.enlightenment.org/D9584
2019-08-18 10:20:21 +02:00
Marcel Hollerbach d6a62c36ae introduce group item
this brings a group item in the style of genlist / gengrid group items.

The group item theme does currently not provide the signals in the theme
that would be needed for selecting it. This is kind of intended, but we
might need API to express that.

ref T8115

Differential Revision: https://phab.enlightenment.org/D9583
2019-08-18 10:20:21 +02:00
Marcel Hollerbach 9cd1a27987 efl_ui_default_item: remove item parts
these parts are hard copies of the part implementations given from the
layouts. Replacing them with the layout implementation just works

ref T8115

Differential Revision: https://phab.enlightenment.org/D9582
2019-08-18 10:20:21 +02:00
Marcel Hollerbach a2bd17b736 introduce default item
default item is used as base class for all "normal style" efl items.

A "normal style" efl item does have a text,content & extra part.

- The text part is usally used to express some text in the item
- Content part is the *main* content part where the user attention is
on.
- Extra can be used to display some elements that are not directly
getting the attention of the user, it can be seen as something more than
the decoration item field.

ref T8115
2019-08-18 10:20:11 +02:00
35 changed files with 1483 additions and 565 deletions

View File

@ -208,4 +208,5 @@ collections {
#include "edc/efl/tab_bar.edc"
#include "edc/efl/tab_page.edc"
#include "edc/efl/item_container.edc"
#include "edc/efl/group_item.edc"
}

View File

@ -0,0 +1,115 @@
group { "efl/group_item"; nomouse; program_source: "efl";
images.image: "shadow_square_tiny.png" COMP;
images.image: "bevel_out.png" COMP;
images.image: "horizontal_separated_bar_small_glow.png" COMP;
parts {
image { "shadow_vbar";
desc { "default";
rel1.offset: -3 -2;
rel1.to: "base_vbar";
rel2.offset: 2 4;
rel2.to: "base_vbar";
image.normal: "shadow_square_tiny.png";
image.border: 6 6 6 6;
fill.smooth: 0;
}
}
image { "base_vbar";
desc { "default";
image.normal: "vgrad_med_lighter.png";
fill.smooth: 0;
min: 5 13;
TILED_HORIZ(120)
}
}
image { "bevel_vbar";
desc { "default";
rel1.to: "base_vbar";
rel2.to: "base_vbar";
image.normal: "bevel_out.png";
image.border: 1 1 1 1;
image.middle: 0;
fill.smooth: 0;
min: 5 5;
}
}
text { "efl.text";
effect: SHADOW BOTTOM;
scale;
desc { "default";
rel1.offset: 2 3;
rel1.relative: 1.0 0.0;
rel1.to_x: "efl.icon";
rel2.offset: -3 -3;
rel2.relative: 0.0 1.0;
rel2.to_x: "efl.extra";
color: FN_COL_DEFAULT;
color_class: "list_group_item";
text { font: FNBD; size: 10;
min: 1 1;
ellipsis: -1;
align: 0.0 0.5;
text_class: "list_group_item";
}
link.base: "efl,state,enabled";
}
desc { "disabled";
inherit: "default";
color: FN_COL_DISABLE;
color_class: "list_group_item_disabled";
link.base: "efl,state,disabled";
}
}
swallow { "pad"; mouse;
desc { "default";
fixed: 1 0;
align: 0.0 0.5;
rel1.offset: 2 2;
rel2.relative: 0.0 1.0;
rel2.offset: 2 -3;
}
}
swallow { "efl.icon"; mouse;
desc { "default";
fixed: 1 0;
align: 0.0 0.5;
rel1.to_x: "pad";
rel1.relative: 1.0 0.0;
rel1.offset: -1 2;
rel2.to_x: "pad";
rel2.relative: 1.0 1.0;
rel2.offset: -1 -3;
}
}
swallow { "efl.extra"; mouse;
desc { "default";
fixed: 1 0;
align: 1.0 0.5;
rel1.offset: -3 2;
rel1.relative: 1.0 0.0;
rel2.offset: -3 -3;
}
}
image { "bar";
desc { "default";
image.normal: "horizontal_separated_bar_small_glow.png";
image.border: 4 4 4 4;
fill.smooth: 0;
fixed: 0 1;
rel1.relative: 0.0 1.0;
rel1.offset: -3 -6;
rel2.offset: 2 3;
link.base: "efl,state,enabled";
}
desc { "disabled";
inherit: "default";
color: 255 255 255 64;
link.base: "efl,state,disabled";
}
}
}
}

View File

@ -156,7 +156,7 @@ elementary_test_src = [
'test_gesture_framework.c',
'test_ui_tab_pager.c',
'test_ui_relative_layout.c',
'test_ui_item_container.c',
'test_ui_collection.c',
'test_ui_items.c',
'test_ui_frame.c',
'test.h'

View File

@ -86,7 +86,7 @@ _widget_del_cb(void *data, const Efl_Event *ev EINA_UNUSED)
}
static void
_add_item(Efl_Ui_Collection *c)
_add_item(Efl_Ui_Collection *c, Eo *cont)
{
Efl_Class *itc = efl_key_data_get(c, "__item_class");
char buf[PATH_MAX];
@ -126,7 +126,7 @@ _add_item(Efl_Ui_Collection *c)
efl_gfx_hint_size_min_set(il, EINA_SIZE2D(100, 180));
else
efl_gfx_hint_size_min_set(il, EINA_SIZE2D(40, 40+(i%2)*40));
efl_pack_end(c, il);
efl_pack_end(cont, il);
}
static void
@ -138,7 +138,7 @@ _remove_all_cb(void *data, const Efl_Event *ev EINA_UNUSED)
static void
_add_one_item(void *data, const Efl_Event *ev EINA_UNUSED)
{
_add_item(data);
_add_item(data, data);
}
static void
@ -146,7 +146,7 @@ _add_thousend_items(void *data, const Efl_Event *ev EINA_UNUSED)
{
for (int i = 0; i < 1000; ++i)
{
_add_item(data);
_add_item(data, data);
}
}
@ -158,9 +158,9 @@ _select_value_cb(void *data, const Efl_Event *ev)
efl_ui_select_mode_set(c, efl_ui_radio_group_selected_value_get(ev->object));
}
void create_item_container_ui(Efl_Ui_Position_Manager_Entity *manager, const Efl_Class *item, const char *name)
void create_item_container_ui(const Efl_Class *collection_class, const Efl_Class *item, const char *name)
{
Efl_Ui_Win *win, *o, *tbl, *item_container, *bx;
Efl_Ui_Win *win, *o, *tbl, *item_container, *bx, *git;
Match_Content_Ctx *ctx = calloc(1, sizeof(*ctx));
win = efl_add(EFL_UI_WIN_CLASS, efl_main_loop_get(),
@ -170,14 +170,28 @@ void create_item_container_ui(Efl_Ui_Position_Manager_Entity *manager, const Efl
tbl = efl_add(EFL_UI_TABLE_CLASS, win);
efl_content_set(win, tbl);
item_container = o = efl_add(EFL_UI_COLLECTION_CLASS, win,
efl_ui_collection_position_manager_set(efl_added, manager));
item_container = o = efl_add(collection_class, win);
efl_key_data_set(o, "__item_class", item);
efl_event_callback_add(o, EFL_EVENT_DEL, _widget_del_cb, ctx);
for (int i = 0; i < 2000; ++i)
for (int i = 0; i < 200; ++i)
{
_add_item(o);
_add_item(o, o);
}
for (int j = 0; j < 5; ++j)
{
Eina_Strbuf *buf = eina_strbuf_new();
eina_strbuf_append_printf(buf, "Group #%d", j);
git = efl_add(EFL_UI_GROUP_ITEM_CLASS, o);
efl_text_set(git, eina_strbuf_release(buf));
efl_pack_end(o, git);
efl_gfx_hint_size_min_set(git, EINA_SIZE2D(40, 40+40));
for (int i = 0; i < 200; ++i)
{
_add_item(o, git);
}
}
efl_pack_table(tbl, o, 1, 0, 1, 12);
ctx->c = o;
@ -278,12 +292,12 @@ void test_efl_ui_collection_grid(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
create_item_container_ui(efl_new(EFL_UI_POSITION_MANAGER_GRID_CLASS), EFL_UI_GRID_DEFAULT_ITEM_CLASS, "Efl.Ui.Item_Container Grid");
create_item_container_ui(EFL_UI_GRID_CLASS, EFL_UI_GRID_DEFAULT_ITEM_CLASS, "Efl.Ui.Grid");
}
void test_efl_ui_collection_list(void *data EINA_UNUSED,
Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
create_item_container_ui(efl_new(EFL_UI_POSITION_MANAGER_LIST_CLASS), EFL_UI_LIST_DEFAULT_ITEM_CLASS, "Efl.Ui.Item_Container List");
create_item_container_ui(EFL_UI_LIST_CLASS, EFL_UI_LIST_DEFAULT_ITEM_CLASS, "Efl.Ui.List");
}

View File

@ -84,4 +84,13 @@ void test_efl_ui_item(void *data EINA_UNUSED,
efl_gfx_hint_size_min_set(o, EINA_SIZE2D(40, 40));
efl_ui_widget_disabled_set(o, EINA_TRUE);
efl_pack_end(box, o);
o = _item_add(box, EFL_UI_GROUP_ITEM_CLASS, 5);
efl_gfx_hint_size_min_set(o, EINA_SIZE2D(40, 40+40));
efl_pack_end(box, o);
o = _item_add(box, EFL_UI_GROUP_ITEM_CLASS, 6);
efl_gfx_hint_size_min_set(o, EINA_SIZE2D(40, 40));
efl_ui_widget_disabled_set(o, EINA_TRUE);
efl_pack_end(box, o);
}

View File

@ -182,6 +182,8 @@ EAPI void efl_ui_focus_relation_free(Efl_Ui_Focus_Relations *rel);
# include <efl_ui_layout_part_text.eo.h>
# include <efl_ui_layout_part_table.eo.h>
# include <efl_ui_item.eo.h>
# include <efl_ui_default_item.eo.h>
# include <efl_ui_group_item.eo.h>
# include <efl_ui_win_part.eo.h>
# include <efl_ui_bg.eo.h>
# include <efl_ui_box.eo.h>
@ -268,7 +270,8 @@ typedef Eo Efl_Ui_Spotlight_Indicator;
# include <efl_ui_text_alert_popup.eo.h>
# include <efl_ui_anchor_popup.eo.h>
# include <efl_ui_popup_part_backwall.eo.h>
# include <efl_ui_grid.eo.h>
# include <efl_ui_list.eo.h>
/**
* Initialize Elementary
*

View File

@ -330,10 +330,6 @@ typedef Eo Efl_Ui_Focus_Manager;
# include <efl_ui_slider.eo.h>
# include <efl_ui_slider_interval.eo.h>
# include <efl_ui_layout_factory.eo.h>
# include <efl_ui_item_part_text.eo.h>
# include <efl_ui_item_part_icon.eo.h>
# include <efl_ui_item_part_extra.eo.h>
# include <efl_ui_item_part_content.eo.h>
# include <efl_ui_item.eo.h>
# include <efl_ui_list_default_item.eo.h>
# include <efl_ui_list_placeholder_item.eo.h>

View File

@ -263,21 +263,40 @@ _efl_ui_collection_efl_ui_multi_selectable_selected_items_get(Eo *obj EINA_UNUSE
return eina_list_iterator_new(pd->selected);
}
static int
static inline void
_fill_group_flag(Eo *item, Efl_Ui_Position_Manager_Batch_Group_State *flag)
{
if (efl_isa(item, EFL_UI_GROUP_ITEM_CLASS))
*flag = EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP;
else if (efl_ui_item_parent_get(item))
*flag = EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_PART_OF_GROUP;
else
*flag = EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_NO_GROUP;
}
static Efl_Ui_Position_Manager_Batch_Result
_size_accessor_get_at(void *data, int start_id, Eina_Rw_Slice memory)
{
Fast_Accessor *accessor = data;
size_t i;
const Eina_List *lst = _fast_accessor_get_at(accessor, start_id);
Efl_Ui_Position_Manager_Batch_Size_Access *sizes = memory.mem;
Efl_Ui_Position_Manager_Batch_Result result = {-1, 0};
EINA_SAFETY_ON_NULL_RETURN_VAL(lst, -1);
EINA_SAFETY_ON_NULL_RETURN_VAL(lst, result);
for (i = 0; i < memory.len; ++i)
{
Efl_Gfx_Entity *geom = eina_list_data_get(lst);
Efl_Gfx_Entity *geom = eina_list_data_get(lst), *parent;
Eina_Size2D size = efl_gfx_hint_size_min_get(geom);
((Eina_Size2D*)memory.mem)[i] = size;
parent = efl_ui_item_parent_get(geom);
sizes[i].size = size;
_fill_group_flag(geom, &sizes[i].group);
if (i == 0 && sizes[0].group != EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP && parent)
{
result.group_id = efl_pack_index_get(efl_ui_item_container_get(parent), parent);
}
lst = eina_list_next(lst);
if (!lst)
{
@ -285,22 +304,32 @@ _size_accessor_get_at(void *data, int start_id, Eina_Rw_Slice memory)
break;
}
}
result.filled_items = i;
return i;
return result;
}
static int
static Efl_Ui_Position_Manager_Batch_Result
_obj_accessor_get_at(void *data, int start_id, Eina_Rw_Slice memory)
{
Fast_Accessor *accessor = data;
size_t i;
const Eina_List *lst = _fast_accessor_get_at(accessor, start_id);
Efl_Ui_Position_Manager_Batch_Entity_Access *objs = memory.mem;
Efl_Ui_Position_Manager_Batch_Result result = {-1, 0};
for (i = 0; i < memory.len; ++i)
{
Efl_Gfx_Entity *geom = eina_list_data_get(lst);
Efl_Gfx_Entity *geom = eina_list_data_get(lst), *parent;
parent = efl_ui_item_parent_get(geom);
objs[i].entity = geom;
_fill_group_flag(geom, &objs[i].group);
if (i == 0 && objs[0].group != EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP && parent)
{
result.group_id = efl_pack_index_get(efl_ui_item_container_get(parent), parent);
}
((Efl_Gfx_Entity**)memory.mem)[i] = geom;
lst = eina_list_next(lst);
if (!lst)
{
@ -308,7 +337,9 @@ _obj_accessor_get_at(void *data, int start_id, Eina_Rw_Slice memory)
break;
}
}
return i;
result.filled_items = i;
return result;
}
EOLIAN static Efl_Object*

View File

@ -0,0 +1,43 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_UI_LIST_DEFAULT_ITEM_PROTECTED
#define EFL_PART_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_part_helper.h"
#define MY_CLASS EFL_UI_DEFAULT_ITEM_CLASS
#define MY_CLASS_PFX efl_ui_default_item
#define MY_CLASS_NAME "Efl.Ui.Default_Item"
ELM_PART_TEXT_DEFAULT_GET(efl_ui_default_item, "efl.text")
ELM_PART_TEXT_DEFAULT_IMPLEMENT(efl_ui_default_item, void)
ELM_PART_MARKUP_DEFAULT_IMPLEMENT(efl_ui_default_item, void)
ELM_PART_CONTENT_DEFAULT_GET(efl_ui_default_item, "efl.icon")
ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_default_item, void)
EOLIAN static Efl_Object *
_efl_ui_default_item_efl_part_part_get(const Eo *obj, void *pd EINA_UNUSED, const char *part)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
if (eina_streq(part, "text"))
return ELM_PART_IMPLEMENT(EFL_UI_LAYOUT_PART_TEXT_CLASS, obj, "efl.text");
else if (eina_streq(part, "icon"))
return ELM_PART_IMPLEMENT(EFL_UI_LAYOUT_PART_CONTENT_CLASS, obj, "efl.icon");
else if (eina_streq(part, "extra"))
return ELM_PART_IMPLEMENT(EFL_UI_LAYOUT_PART_CONTENT_CLASS, obj, "efl.extra");
return efl_part_get(efl_super(obj, MY_CLASS), part);
}
#define EFL_UI_DEFAULT_ITEM_EXTRA_OPS \
ELM_PART_TEXT_DEFAULT_OPS(efl_ui_default_item), \
ELM_PART_CONTENT_DEFAULT_OPS(efl_ui_default_item)
#include "efl_ui_default_item.eo.c"

View File

@ -0,0 +1,32 @@
abstract @beta Efl.Ui.Default_Item extends Efl.Ui.Item implements
Efl.Text,
Efl.Text_Markup,
Efl.Ui.L10n,
Efl.Content
{
[[Default Item Class.
This class defines the standard parts of casual efl items.
The details about placement or item layout preferences are left to the extending classes.
Every text property related changes are mirrored to the text part. Content changes are mirrored to the content part.
]]
data: null;
parts {
text: Efl.Ui.Layout_Part_Text; [[The text part for default item.
text part is the caption of the item.]]
icon: Efl.Ui.Layout_Part_Content; [[The icon content part for default item.
icon part is the main content of item.]]
end: Efl.Ui.Layout_Part_Content; [[The extra content part for default item.
extra part is the spare content of item.
you can swallow small badge widget such as check, radio.]]
}
implements {
Efl.Text.text { get; set; }
Efl.Text_Markup.markup { get; set; }
Efl.Ui.L10n.l10n_text { get; set; }
Efl.Content.content { get; set; }
Efl.Content.content_unset;
Efl.Part.part_get;
}
}

View File

@ -16,50 +16,16 @@
#define MY_CLASS_NAME "Efl.Ui.Grid_Default_Item"
EOLIAN static Efl_Object *
_efl_ui_grid_default_item_efl_object_finalize(Eo *obj, void *pd EINA_UNUSED)
_efl_ui_grid_default_item_efl_object_constructor(Eo *obj, void *pd EINA_UNUSED)
{
Eo *eo;
eo = efl_finalize(efl_super(obj, MY_CLASS));
ELM_WIDGET_DATA_GET_OR_RETURN(eo, wd, eo);
Eina_Error theme_apply = efl_ui_layout_theme_set(obj, "grid_item", NULL, NULL);
if (theme_apply == EFL_UI_THEME_APPLY_ERROR_GENERIC)
CRI("Default Item(%p) failed to set theme [efl/grid_item]!", eo);
eo = efl_constructor(efl_super(obj, MY_CLASS));
if (!elm_widget_theme_klass_get(obj))
elm_widget_theme_klass_set(obj, "grid_item");
return eo;
}
EOLIAN static void
_efl_ui_grid_default_item_efl_object_destructor(Eo *obj, void *pd EINA_UNUSED)
{
efl_destructor(efl_super(obj, MY_CLASS));
}
/* Efl.Part */
ELM_PART_TEXT_DEFAULT_GET(efl_ui_grid_default_item, "efl.text")
ELM_PART_TEXT_DEFAULT_IMPLEMENT(efl_ui_grid_default_item, void)
ELM_PART_MARKUP_DEFAULT_IMPLEMENT(efl_ui_grid_default_item, void)
ELM_PART_CONTENT_DEFAULT_GET(efl_ui_grid_default_item, "efl.icon")
ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_grid_default_item, void)
EOLIAN static Efl_Object *
_efl_ui_grid_default_item_efl_part_part_get(const Eo *obj, void *wd EINA_UNUSED, const char *part)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
if (eina_streq(part, "text"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_TEXT_CLASS, obj, "efl.text");
else if (eina_streq(part, "icon"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_ICON_CLASS, obj, "efl.icon");
else if (eina_streq(part, "extra"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_EXTRA_CLASS, obj, "efl.extra");
return efl_part_get(efl_super(obj, MY_CLASS), part);
}
/* Efl.Part end */
/* Internal EO APIs and hidden overrides */
#define EFL_UI_GRID_DEFAULT_ITEM_EXTRA_OPS \
ELM_PART_TEXT_DEFAULT_OPS(efl_ui_grid_default_item), \
ELM_PART_CONTENT_DEFAULT_OPS(efl_ui_grid_default_item)
#include "efl_ui_grid_default_item.eo.c"

View File

@ -1,33 +1,9 @@
class @beta Efl.Ui.Grid_Default_Item extends Efl.Ui.Item implements
Efl.Text,
Efl.Text_Markup,
Efl.Ui.L10n,
Efl.Content
class @beta Efl.Ui.Grid_Default_Item extends Efl.Ui.Default_Item
{
[[Grid Default Item class.
This class need to be sub object of list widget.
Text and contents can be set using @Efl.Text,
@Efl.Content or @Efl.Part.]]
[[Grid Default Item class.]]
data: null;
parts {
text: Efl.Ui.Item_Part_Text; [[The text part for grid default item.
text part is the caption of grid item.]]
icon: Efl.Ui.Item_Part_Icon; [[The icon content part for grid default item.
icon part is the main content of grid item.]]
end: Efl.Ui.Item_Part_Extra; [[The extra content part for grid default item.
extra part is the spare content of grid item.
you can swallow small badge widget such as check, radio.]]
}
implements {
//Efl.Object
Efl.Object.finalize;
Efl.Object.destructor;
Efl.Text.text { get; set; }
Efl.Text_Markup.markup { get; set; }
Efl.Ui.L10n.l10n_text { get; set; }
Efl.Content.content { get; set; }
Efl.Content.content_unset;
Efl.Part.part_get;
Efl.Object.constructor;
}
}

View File

@ -0,0 +1,303 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#define EFL_UI_LIST_DEFAULT_ITEM_PROTECTED
#define EFL_PART_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "elm_part_helper.h"
#define MY_CLASS EFL_UI_GROUP_ITEM_CLASS
#define MY_CLASS_PFX efl_ui_group_item
#define MY_CLASS_NAME "Efl.Ui.Grid_Default_Item"
typedef struct {
Eina_List *registered_items;
} Efl_Ui_Group_Item_Data;
EOLIAN static Efl_Object*
_efl_ui_group_item_efl_object_constructor(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED)
{
if (!elm_widget_theme_klass_get(obj))
elm_widget_theme_klass_set(obj, "group_item");
return efl_constructor(efl_super(obj, MY_CLASS));
}
EOLIAN static void
_efl_ui_group_item_efl_object_invalidate(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED)
{
efl_pack_clear(obj);
efl_invalidate(efl_super(obj, MY_CLASS));
}
static void _unregister_item(Eo *obj EINA_UNUSED, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj);
static void
_invalidate(void *data, const Efl_Event *ev)
{
Efl_Ui_Group_Item_Data *pd = efl_data_scope_safe_get(data, MY_CLASS);
if (!pd) return;
_unregister_item(data, pd, ev->object);
}
static void
_register_item(Eo *obj, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj)
{
efl_ui_item_parent_set(subobj, obj);
efl_event_callback_add(subobj, EFL_EVENT_INVALIDATE, _invalidate, obj);
pd->registered_items = eina_list_append(pd->registered_items, subobj);
}
static void
_unregister_item(Eo *obj EINA_UNUSED, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj)
{
efl_ui_item_container_set(subobj, NULL);
efl_event_callback_del(subobj, EFL_EVENT_INVALIDATE, _invalidate, obj);
pd->registered_items = eina_list_remove(pd->registered_items, subobj);
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_pack_clear(Eo *obj EINA_UNUSED, Efl_Ui_Group_Item_Data *pd)
{
Eo *item;
while(pd->registered_items)
{
item = eina_list_data_get(pd->registered_items);
efl_del(item);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_unpack_all(Eo *obj, Efl_Ui_Group_Item_Data *pd)
{
Eo *item;
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
EINA_LIST_FREE(pd->registered_items, item)
{
efl_pack_unpack(container, item);
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_unpack(Eo *obj, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj)
{
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
if (!efl_pack_unpack(container, subobj))
return EINA_FALSE;
_unregister_item(obj, pd, subobj);
return EINA_TRUE;
}
#define HANDLE_REG_CALL(cond) \
if (!(cond)) \
{ \
_unregister_item(obj, pd, subobj); \
return EINA_FALSE; \
} \
return EINA_TRUE;
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_pack(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED, Efl_Gfx_Entity *subobj)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
return efl_pack_end(obj, subobj);
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_linear_pack_end(Eo *obj, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
int group_index = efl_pack_index_get(container, obj);
_register_item(obj, pd, subobj);
HANDLE_REG_CALL(efl_pack_at(container, subobj, group_index + eina_list_count(pd->registered_items) + 1));
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_linear_pack_begin(Eo *obj, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
int group_index = efl_pack_index_get(container, obj);
_register_item(obj, pd, subobj);
HANDLE_REG_CALL(efl_pack_at(container, subobj, group_index + 1));
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_linear_pack_before(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED, Efl_Gfx_Entity *subobj, const Efl_Gfx_Entity *existing)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
//FIXME, maybe we should check if existing is really part of this group
_register_item(obj, pd, subobj);
HANDLE_REG_CALL(efl_pack_before(container, subobj, existing));
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_linear_pack_after(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED, Efl_Gfx_Entity *subobj, const Efl_Gfx_Entity *existing)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
//FIXME, maybe we should check if existing is really part of this group
_register_item(obj, pd, subobj);
HANDLE_REG_CALL(efl_pack_after(container, subobj, existing));
}
EOLIAN static Eina_Bool
_efl_ui_group_item_efl_pack_linear_pack_at(Eo *obj, Efl_Ui_Group_Item_Data *pd, Efl_Gfx_Entity *subobj, int index)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(subobj == obj, EINA_FALSE);
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, EINA_FALSE);
int group_index = efl_pack_index_get(container, obj);
int count = eina_list_count(pd->registered_items);
if (index < -count)
return efl_pack_begin(obj, subobj);
if (index >= count)
return efl_pack_end(obj, subobj);
if (index < 0)
index += count;
_register_item(obj, pd, subobj);
HANDLE_REG_CALL(efl_pack_at(container, subobj, group_index + 1 + index));
}
EOLIAN static Efl_Gfx_Entity*
_efl_ui_group_item_efl_pack_linear_pack_unpack_at(Eo *obj, Efl_Ui_Group_Item_Data *pd, int index)
{
Eo *result, *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, NULL);
int group_index = efl_pack_index_get(container, obj);
int count = eina_list_count(pd->registered_items);
if (index <= -count)
index = 0;
else if (index >= count)
index = eina_list_count(pd->registered_items);
else if (index < 0)
index += count;
result = efl_pack_unpack_at(container, group_index + 1 + index);
if (result)
_unregister_item(obj, pd, result);
return result;
}
EOLIAN static int
_efl_ui_group_item_efl_pack_linear_pack_index_get(Eo *obj, Efl_Ui_Group_Item_Data *pd, const Efl_Gfx_Entity *subobj)
{
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, -1);
int first_index = efl_pack_index_get(container, obj) + 1;
int subobj_index = efl_pack_index_get(container, subobj);
if (subobj_index == -1) return -1;
EINA_SAFETY_ON_FALSE_RETURN_VAL(first_index <= subobj_index && subobj_index < (first_index + (int)eina_list_count(pd->registered_items)), -1);
return subobj_index - (first_index);
}
EOLIAN static Efl_Gfx_Entity*
_efl_ui_group_item_efl_pack_linear_pack_content_get(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED, int index)
{
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, NULL);
int group_index = efl_pack_index_get(container, obj);
int count = eina_list_count(pd->registered_items);
if (index <= -count)
return eina_list_data_get(pd->registered_items);
if (index >= count)
return eina_list_last_data_get(pd->registered_items);
if (index < 0)
index += count;
return efl_pack_content_get(container, group_index + 1 + index);
}
typedef struct {
Eina_Iterator iterator;
unsigned int current;
unsigned int max;
Eo *container;
} Efl_Ui_Group_Item_Iterator;
static Eina_Bool
_next_item(Efl_Ui_Group_Item_Iterator *it, void **data)
{
if (it->current >= it->max) return EINA_FALSE;
*data = efl_pack_content_get(it->container, it->current);
it->current++;
return EINA_TRUE;
}
EOLIAN static Eina_Iterator*
_efl_ui_group_item_efl_container_content_iterate(Eo *obj, Efl_Ui_Group_Item_Data *pd EINA_UNUSED)
{
Eo *container = efl_ui_item_container_get(obj);
EINA_SAFETY_ON_NULL_RETURN_VAL(container, NULL);
Efl_Ui_Group_Item_Iterator *it;
it = calloc(1, sizeof (Efl_Ui_Group_Item_Iterator));
if (!it) return NULL;
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->current = efl_pack_index_get(container, obj) + 1;
it->max = it->current + eina_list_count(pd->registered_items);
it->container = container;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(_next_item);
it->iterator.get_container = NULL;
it->iterator.free = FUNC_ITERATOR_FREE(free);
return &it->iterator;
}
EOLIAN static int
_efl_ui_group_item_efl_container_content_count(Eo *obj EINA_UNUSED, Efl_Ui_Group_Item_Data *pd)
{
return eina_list_count(pd->registered_items);
}
#include "efl_ui_group_item.eo.c"

View File

@ -0,0 +1,22 @@
class @beta Efl.Ui.Group_Item extends Efl.Ui.Default_Item implements Efl.Pack_Linear
{
[[Group item for grids and lists]]
implements {
Efl.Object.constructor;
Efl.Object.invalidate;
Efl.Pack.pack_clear;
Efl.Pack.unpack_all;
Efl.Pack.unpack;
Efl.Pack.pack;
Efl.Pack_Linear.pack_end;
Efl.Pack_Linear.pack_begin;
Efl.Pack_Linear.pack_before;
Efl.Pack_Linear.pack_after;
Efl.Pack_Linear.pack_at;
Efl.Pack_Linear.pack_unpack_at;
Efl.Pack_Linear.pack_index_get;
Efl.Pack_Linear.pack_content_get;
Efl.Container.content_iterate;
Efl.Container.content_count;
}
}

View File

@ -2,150 +2,24 @@
# include "elementary_config.h"
#endif
#define EFL_ACCESS_PROTECTED
#define EFL_UI_WIDGET_PART_BG_PROTECTED
#include <Elementary.h>
#include "elm_priv.h"
#include "efl_ui_item_private.h"
//part
#include "efl_ui_item_part_text.eo.h"
#include "efl_ui_item_part_icon.eo.h"
#include "efl_ui_item_part_extra.eo.h"
#include "efl_ui_item_part_content.eo.h"
#include "elm_part_helper.h"
#define MY_CLASS EFL_UI_ITEM_CLASS
#define MY_CLASS_PFX efl_ui_item
#define MY_CLASS_NAME "Efl.Ui.Item"
/* Efl.Part */
EOLIAN static void
_efl_ui_item_part_text_efl_text_text_set(Eo *obj, void *pd EINA_UNUSED, const char *text)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
efl_text_set(efl_part(efl_super(wd->obj, MY_CLASS), wd->part), text);
efl_canvas_group_change(wd->obj);
}
EOLIAN static const char*
_efl_ui_item_part_text_efl_text_text_get(const Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_text_get(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
EOLIAN static void
_efl_ui_item_part_text_efl_text_markup_markup_set(Eo *obj, void *pd EINA_UNUSED, const char *markup)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
efl_text_markup_set(efl_part(efl_super(wd->obj, MY_CLASS), wd->part), markup);
efl_canvas_group_change(obj);
}
EOLIAN static const char*
_efl_ui_item_part_text_efl_text_markup_markup_get(const Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_text_markup_get(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
EOLIAN static const char *
_efl_ui_item_part_text_efl_ui_l10n_l10n_text_get(const Eo *obj, void *_pd EINA_UNUSED, const char **domain)
{
Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return elm_widget_part_translatable_text_get(pd->obj, pd->part, domain);
}
EOLIAN static void
_efl_ui_item_part_text_efl_ui_l10n_l10n_text_set(Eo *obj, void *_pd EINA_UNUSED, const char *text, const char *domain)
{
Elm_Part_Data *pd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
elm_widget_part_translatable_text_set(pd->obj, pd->part, text, domain);
}
#include "efl_ui_item_part_text.eo.c"
/* Efl.Ui.List_Default_Item_Part_Icon */
Eina_Bool
_efl_ui_item_part_icon_efl_content_content_set(Eo *obj, void *pd EINA_UNUSED, Efl_Gfx_Entity *content)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_set(efl_part(efl_super(wd->obj, MY_CLASS), wd->part), content);
}
Efl_Gfx_Entity *
_efl_ui_item_part_icon_efl_content_content_get(const Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_get(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
Efl_Gfx_Entity *
_efl_ui_item_part_icon_efl_content_content_unset(Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_unset(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
#include "efl_ui_item_part_icon.eo.c"
Eina_Bool
_efl_ui_item_part_extra_efl_content_content_set(Eo *obj, void *pd EINA_UNUSED, Efl_Gfx_Entity *content)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_set(efl_part(efl_super(wd->obj, MY_CLASS), wd->part), content);
}
Efl_Gfx_Entity *
_efl_ui_item_part_extra_efl_content_content_get(const Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_get(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
Efl_Gfx_Entity *
_efl_ui_item_part_extra_efl_content_content_unset(Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_unset(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
#include "efl_ui_item_part_extra.eo.c"
Eina_Bool
_efl_ui_item_part_content_efl_content_content_set(Eo *obj, void *pd EINA_UNUSED, Efl_Gfx_Entity *content)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_set(efl_part(efl_super(wd->obj, MY_CLASS), wd->part), content);
}
Efl_Gfx_Entity *
_efl_ui_item_part_content_efl_content_content_get(const Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_get(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
Efl_Gfx_Entity *
_efl_ui_item_part_content_efl_content_content_unset(Eo *obj, void *pd EINA_UNUSED)
{
Elm_Part_Data *wd = efl_data_scope_get(obj, EFL_UI_WIDGET_PART_CLASS);
return efl_content_unset(efl_part(efl_super(wd->obj, MY_CLASS), wd->part));
}
#include "efl_ui_item_part_content.eo.c"
/* Efl.Part */
static void
_item_select(Eo *obj, Efl_Ui_Item_Data *pd)
{
Efl_Ui_Select_Mode m;
if (pd->parent)
if (pd->container)
{
m = efl_ui_select_mode_get(pd->parent);
m = efl_ui_select_mode_get(pd->container);
if (m == EFL_UI_SELECT_MODE_NONE || (pd->selected && m != EFL_UI_SELECT_MODE_SINGLE_ALWAYS))
return;
}
@ -245,7 +119,7 @@ _efl_ui_item_efl_object_destructor(Eo *obj, Efl_Ui_Item_Data *pd EINA_UNUSED)
EOLIAN static int
_efl_ui_item_index_get(const Eo *obj, Efl_Ui_Item_Data *pd)
{
return efl_pack_index_get(pd->parent, obj);
return efl_pack_index_get(pd->container, obj);
}
EOLIAN static void
@ -268,15 +142,48 @@ _efl_ui_item_efl_ui_selectable_selected_get(const Eo *obj EINA_UNUSED, Efl_Ui_It
EOLIAN static void
_efl_ui_item_container_set(Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd, Efl_Ui_Widget *container)
{
pd->parent = container;
pd->container = container;
if (!pd->container)
{
pd->parent = NULL;
}
}
EOLIAN static Efl_Ui_Widget*
_efl_ui_item_container_get(const Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd)
{
return pd->container;
}
EOLIAN static void
_efl_ui_item_item_parent_set(Eo *obj, Efl_Ui_Item_Data *pd, Efl_Ui_Item *parent)
{
if (pd->parent)
{
ERR("Parent is already set on object %p", obj);
return;
}
if (efl_invalidated_get(obj) || efl_invalidating_get(obj))
{
ERR("Parent cannot be set during invalidate");
return;
}
if (pd->container)
{
ERR("Parent must be set before adding the object to the container");
return;
}
pd->parent = parent;
}
EOLIAN static Efl_Ui_Item*
_efl_ui_item_item_parent_get(const Eo *obj EINA_UNUSED, Efl_Ui_Item_Data *pd)
{
return pd->parent;
}
#include "efl_ui_item.eo.c"
#include "efl_ui_selectable.eo.c"
#include "efl_ui_multi_selectable.eo.c"

View File

@ -40,6 +40,15 @@ abstract @beta Efl.Ui.Item extends Efl.Ui.Layout_Base implements Efl.Ui.Selectab
container : Efl.Ui.Widget; [[The container this item is in.]]
}
}
@property item_parent {
[[The parent of the item.
This property expresses a tree structure of items. If the parent is NULL the item is added in the root level of the content. The item parent can only be set once, when the object is invalidated, the item parent is set to NULL and still cannot be reset.
]]
values {
parent : Efl.Ui.Item;
}
}
}
implements {
Efl.Object.constructor;

View File

@ -1,9 +0,0 @@
class @beta Efl.Ui.Item_Part_Content extends Efl.Ui.Layout_Part implements Efl.Content
{
[[Item internal content part class]]
data: null;
implements {
Efl.Content.content { get; set; }
Efl.Content.content_unset;
}
}

View File

@ -1,9 +0,0 @@
class @beta Efl.Ui.Item_Part_Extra extends Efl.Ui.Layout_Part implements Efl.Content
{
[[Item internal content of extra part class]]
data: null;
implements {
Efl.Content.content { get; set; }
Efl.Content.content_unset;
}
}

View File

@ -1,9 +0,0 @@
class @beta Efl.Ui.Item_Part_Icon extends Efl.Ui.Layout_Part implements Efl.Content
{
[[Item internal content of icon part class]]
data: null;
implements {
Efl.Content.content { get; set; }
Efl.Content.content_unset;
}
}

View File

@ -1,11 +0,0 @@
class @beta Efl.Ui.Item_Part_Text extends Efl.Ui.Layout_Part implements
Efl.Text, Efl.Text_Markup, Efl.Ui.L10n
{
[[Item internal text part class]]
data: null;
implements {
Efl.Text.text { set; get; }
Efl.Text_Markup.markup { get; set; }
Efl.Ui.L10n.l10n_text { get; set; }
}
}

View File

@ -6,7 +6,8 @@
typedef struct _Efl_Ui_Item_Data
{
// Eo Objects
Eo *parent; /* Parent Widget */
Eo *container; /* Parent Widget */
Efl_Ui_Item *parent;
// Boolean Data
Eina_Bool selected : 1; /* State for item selected */

View File

@ -16,47 +16,15 @@
#define MY_CLASS_NAME "Efl.Ui.List_Default_Item"
EOLIAN static Efl_Object *
_efl_ui_list_default_item_efl_object_finalize(Eo *obj, void *pd EINA_UNUSED)
_efl_ui_list_default_item_efl_object_constructor(Eo *obj, void *pd EINA_UNUSED)
{
Eo *eo;
eo = efl_finalize(efl_super(obj, MY_CLASS));
ELM_WIDGET_DATA_GET_OR_RETURN(eo, wd, eo);
Eina_Error theme_apply_ret = efl_ui_layout_theme_set(obj, "list_item", NULL, NULL);
if (theme_apply_ret == EFL_UI_THEME_APPLY_ERROR_GENERIC)
CRI("Default Item(%p) failed to set theme [efl/list_item]!", eo);
eo = efl_constructor(efl_super(obj, MY_CLASS));
if (!elm_widget_theme_klass_get(obj))
elm_widget_theme_klass_set(obj, "list_item");
return eo;
}
EOLIAN static void
_efl_ui_list_default_item_efl_object_destructor(Eo *obj, void *pd EINA_UNUSED)
{
efl_destructor(efl_super(obj, MY_CLASS));
}
ELM_PART_TEXT_DEFAULT_GET(efl_ui_list_default_item, "efl.text")
ELM_PART_TEXT_DEFAULT_IMPLEMENT(efl_ui_list_default_item, void)
ELM_PART_MARKUP_DEFAULT_IMPLEMENT(efl_ui_list_default_item, void)
ELM_PART_CONTENT_DEFAULT_GET(efl_ui_list_default_item, "efl.icon")
ELM_PART_CONTENT_DEFAULT_IMPLEMENT(efl_ui_list_default_item, void)
EOLIAN static Efl_Object *
_efl_ui_list_default_item_efl_part_part_get(const Eo *obj, void *wd EINA_UNUSED, const char *part)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
if (eina_streq(part, "text"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_TEXT_CLASS, obj, "efl.text");
else if (eina_streq(part, "icon"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_ICON_CLASS, obj, "efl.icon");
else if (eina_streq(part, "extra"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_EXTRA_CLASS, obj, "efl.extra");
return efl_part_get(efl_super(obj, MY_CLASS), part);
}
/* Internal EO APIs and hidden overrides */
#define EFL_UI_LIST_DEFAULT_ITEM_EXTRA_OPS \
ELM_PART_TEXT_DEFAULT_OPS(efl_ui_list_default_item), \
ELM_PART_CONTENT_DEFAULT_OPS(efl_ui_list_default_item)
#include "efl_ui_list_default_item.eo.c"

View File

@ -1,30 +1,9 @@
class @beta Efl.Ui.List_Default_Item extends Efl.Ui.Item implements
Efl.Text,
Efl.Text_Markup,
Efl.Content
class @beta Efl.Ui.List_Default_Item extends Efl.Ui.Default_Item
{
[[List Default Item class.
This class need to be sub object of list widget.
text and contents can be appliable by efl_text,
efl_content or efl_part APIs.]]
[[List Default Item class.]]
data: null;
parts {
text: Efl.Ui.Item_Part_Text; [[The text part for list default item.]]
icon: Efl.Ui.Item_Part_Icon; [[The icon content part for list default item.
icon part is the left-side content of list item.]]
extra: Efl.Ui.Item_Part_Extra; [[The extra content part for list default item.
extra part is the right-side content of list item.]]
}
implements {
//Efl.Object
Efl.Object.finalize;
Efl.Object.destructor;
Efl.Text.text { get; set; }
Efl.Text_Markup.markup { get; set; }
Efl.Ui.L10n.l10n_text { get; set; }
Efl.Content.content { get; set; }
Efl.Content.content_unset;
Efl.Part.part_get;
Efl.Object.constructor;
}
}

View File

@ -44,7 +44,7 @@ _efl_ui_list_placeholder_item_efl_part_part_get(const Eo *obj, void *wd EINA_UNU
{
EINA_SAFETY_ON_NULL_RETURN_VAL(part, NULL);
if (eina_streq(part, "content"))
return ELM_PART_IMPLEMENT(EFL_UI_ITEM_PART_CONTENT_CLASS, obj, "efl.content");
return ELM_PART_IMPLEMENT(EFL_UI_LAYOUT_PART_CONTENT_CLASS, obj, "efl.content");
return efl_part_get(efl_super(obj, MY_CLASS), part);
}

View File

@ -6,7 +6,7 @@ class @beta Efl.Ui.List_Placeholder_Item extends Efl.Ui.Item implements Efl.Cont
any kind of container.]]
data: null;
parts {
content: Efl.Ui.Item_Part_Content; [[the content part for list placeholder item.
content: Efl.Ui.Layout_Part_Content; [[the content part for list placeholder item.
the content part is empty slot for user customizing.
fill the place with container widget such as layout, box, table.]]
}

View File

@ -12,20 +12,26 @@ typedef struct {
} Api_Callback;
static inline int
_fill_buffer(Api_Callback *cb , int start_id, int len, void *data)
_fill_buffer(Api_Callback *cb , int start_id, int len, int *group_id, void *data)
{
Efl_Ui_Position_Manager_Batch_Result res;
Eina_Rw_Slice slice;
slice.mem = data;
slice.len = len;
return cb->access(cb->data, start_id, slice);
res = cb->access(cb->data, start_id, slice);
if (group_id)
*group_id = res.group_id;
return res.filled_items;
}
static inline void
vis_change_segment(Api_Callback *cb, int a, int b, Eina_Bool flag)
{
const int len = 50;
Efl_Gfx_Entity *data[len];
Efl_Ui_Position_Manager_Batch_Entity_Access data[len];
if (a == b) return;
@ -36,9 +42,9 @@ vis_change_segment(Api_Callback *cb, int a, int b, Eina_Bool flag)
if (buffer_id == 0)
{
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(cb, MIN(a,b), len, data) >= 0);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(cb, MIN(a,b), len, NULL, data) >= 0);
}
ent = data[i - MIN(a,b)];
ent = data[buffer_id].entity;
if (ent && !flag && (efl_ui_focus_object_focus_get(ent) || efl_ui_focus_object_child_focus_get(ent)))
{
//we should not make focused object invisible, rather move it to some parking lot

View File

@ -1,25 +1,51 @@
import efl_ui;
enum Efl.Ui.Position_Manager.Batch_Group_State{
[[Enum expressing the group related state of a item.]]
no_group = 0, [[This item is not a group item and is not part of any group.]]
group = 1, [[This item is a group item.]]
part_of_group = 2 [[This item is part of a group.]]
}
struct Efl.Ui.Position_Manager.Batch_Entity_Access{
[[Struct that is getting filled by the object function callback.]]
entity : Efl.Gfx.Entity; [[The canvas object.]]
group : Efl.Ui.Position_Manager.Batch_Group_State; [[If this is a group item.]]
}
struct Efl.Ui.Position_Manager.Batch_Size_Access{
[[Struct that is getting filled by the size function callback.]]
size : Eina.Size2D; [[The size of the element.]]
group : Efl.Ui.Position_Manager.Batch_Group_State; [[If this is a group item.]]
}
struct Efl.Ui.Position_Manager.Batch_Result {
[[Struct that is returned by the function callbacks.]]
group_id : int; [[The group of the first item. If the first item is a group, or the first item does not have a group, -1 will be the id]]
filled_items : int; [[The number of items that are filled into the slice]]
}
function Efl.Ui.Position_Manager.Batch_Access_Entity {
[[ Function callback for getting a batch of items]]
[[ Function callback for getting a batch of items.]]
params {
start_id : int; [[The id of the first item to fetch]]
memory : rw_slice<Efl.Gfx.Entity>; [[The slice to fill the information in, the full slice will be filled if there are enough items]]
memory : rw_slice<Efl.Ui.Position_Manager.Batch_Entity_Access>; [[The slice to fill the information in, the full slice will be filled if there are enough items]]
}
return: int; [[The number of filled elements in the slice]]
return: Efl.Ui.Position_Manager.Batch_Result; [[The returned stats of this function call.]]
};
function Efl.Ui.Position_Manager.Batch_Access_Size {
[[ Function callback for getting sizes of a batch of items]]
params {
start_id : int; [[The id of the first item to fetch]]
memory : rw_slice<Efl.Gfx.Entity>; [[The slice to fill the information in, the full slice will be filled if there are enough items]]
memory : rw_slice<Efl.Ui.Position_Manager.Batch_Size_Access>; [[The slice to fill the information in, the full slice will be filled if there are enough items]]
}
return: int; [[The number of filled elements in the slice]]
return: Efl.Ui.Position_Manager.Batch_Result; [[The returned stats of this function call]]
};
struct Efl.Ui.Position_Manager.Range_Update {
[[A struct containing the the updated range of visible items in this position manger]]
[[A struct containing the the updated range of visible items in this position manger.]]
start_id : uint; [[The first item that is visible]]
end_id : uint; [[The last item that is visible]]
}

View File

@ -12,37 +12,432 @@
#define MY_DATA_GET(obj, pd) \
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
_group_cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_Grid_Data *pd)
{
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;
unsigned int start_id, end_id, step;
const int len = 100;
Efl_Gfx_Entity *obj_buffer[len];
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)
ctx.new = cur;
ctx.consumed_space = consumed_space;
ctx.relevant_space_size = relevant_space_size;
ctx.floating_group = NULL;
ctx.placed_item = NULL;
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
{
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, 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 = ((Efl_Gfx_Entity**)obj_buffer)[buffer_id];
//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);
_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
{
ev.start_id = pd->prev_run.start_id = start_id;
ev.end_id = pd->prev_run.end_id = end_id;
_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 = 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)
_size_cache_require(obj, pd);
for (unsigned int i = 0; i < eina_inarray_count(pd->group_cache); ++i)
{
major = pd->viewport.w/pd->max_min_size.w;
pd->current_display_table.columns = major;
}
else
{
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,53 +583,74 @@ _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)
{
Eina_Size2D size[1];
Efl_Ui_Position_Manager_Batch_Size_Access size[1];
pd->size ++;
efl_gfx_entity_visible_set(subobj, EINA_FALSE);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, added_index, 1, &size) == 1);
_update_min_size(obj, pd, added_index, size[0]);
_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)
{
const int len = 50;
Eina_Size2D data[len];
Efl_Ui_Position_Manager_Batch_Size_Access data[len];
for (int i = start_id; i <= end_id; ++i)
{
int buffer_id = (i-start_id) % len;
if (buffer_id == 0)
{
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, start_id, len, data) >= 0);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, start_id, len, NULL, data) >= 0);
}
_update_min_size(obj, pd, i, data[i-start_id]);
_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;

View File

@ -13,6 +13,11 @@
#define MY_DATA_GET(obj, pd) \
Efl_Ui_Position_Manager_List_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;
@ -24,9 +29,8 @@ typedef struct {
int *size_cache;
int average_item_size;
int maximum_min_size;
struct {
unsigned int start_id, end_id;
} prev_run;
Vis_Segment prev_run;
Efl_Gfx_Entity *last_group;
} Efl_Ui_Position_Manager_List_Data;
/*
@ -42,7 +46,7 @@ cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
{
unsigned int i;
const int len = 100;
Eina_Size2D size_buffer[100];
Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[100];
if (pd->size_cache) return;
@ -67,9 +71,9 @@ cache_require(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
if (buffer_id == 0)
{
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, len, size_buffer) > 0);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, i, len, NULL, size_buffer) > 0);
}
size = size_buffer[buffer_id];
size = size_buffer[buffer_id].size;
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
{
@ -132,16 +136,174 @@ recalc_absolut_size(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd)
efl_event_callback_call(obj, EFL_UI_POSITION_MANAGER_ENTITY_EVENT_CONTENT_MIN_SIZE_CHANGED, &min_size);
}
static inline Vis_Segment
_search_visual_segment(Eo *obj, Efl_Ui_Position_Manager_List_Data *pd, int relevant_space_size, int relevant_viewport)
{
Vis_Segment cur;
//based on the average item size, we jump somewhere into the sum cache.
//After beeing in there, we are walking back, until we have less space then viewport size
cur.start_id = MIN((unsigned int)(relevant_space_size / pd->average_item_size), pd->size);
for (; cache_access(obj, pd, cur.start_id) >= relevant_space_size && cur.start_id > 0; cur.start_id --) { }
//starting on the start id, we are walking down until the sum of elements is bigger than the lower part of the viewport.
cur.end_id = cur.start_id;
for (; cur.end_id <= pd->size && cache_access(obj, pd, cur.end_id) <= relevant_space_size + relevant_viewport ; cur.end_id ++) { }
cur.end_id = MAX(cur.end_id, cur.start_id + 1);
cur.end_id = MIN(cur.end_id, pd->size);
#ifdef DEBUG
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]);
#endif
if (relevant_space_size > 0)
EINA_SAFETY_ON_FALSE_GOTO(cache_access(obj, pd, cur.start_id) <= relevant_space_size, err);
if (cur.end_id != pd->size)
EINA_SAFETY_ON_FALSE_GOTO(cache_access(obj, pd, cur.end_id) >= relevant_space_size + relevant_viewport, err);
EINA_SAFETY_ON_FALSE_GOTO(cur.start_id <= cur.end_id, err);
return cur;
err:
cur.start_id = cur.end_id = 0;
return cur;
}
static inline void
_visual_segment_swap(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, Vis_Segment new, Vis_Segment old)
{
if (new.end_id <= old.start_id || new.start_id >= old.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, new.start_id, new.end_id, EINA_TRUE);
vis_change_segment(&pd->object, old.start_id, old.end_id, EINA_FALSE);
}
else
{
vis_change_segment(&pd->object, old.start_id, new.start_id, (old.start_id > new.start_id));
vis_change_segment(&pd->object, old.end_id, new.end_id, (old.end_id < new.end_id));
}
}
static inline void
_position_items(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd, Vis_Segment new, int relevant_space_size)
{
int group_id = -1;
Efl_Gfx_Entity *first_group = NULL, *first_fully_visual_group = NULL;
Eina_Size2D first_group_size;
Eina_Rect geom;
const int len = 100;
Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[len];
Efl_Ui_Position_Manager_Batch_Entity_Access obj_buffer[len];
unsigned int i;
//placement of the plain items
geom = pd->viewport;
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.y -= (relevant_space_size - cache_access(obj, pd, new.start_id));
else
geom.x -= (relevant_space_size - cache_access(obj, pd, new.start_id));
for (i = new.start_id; i < new.end_id; ++i)
{
Eina_Size2D size;
Efl_Gfx_Entity *ent = NULL;
int buffer_id = (i-new.start_id) % len;
if (buffer_id == 0)
{
int tmp_group;
int res1, res2;
res1 = _fill_buffer(&pd->object, i, len, &tmp_group, obj_buffer);
res2 = _fill_buffer(&pd->min_size, i, len, NULL, size_buffer);
EINA_SAFETY_ON_FALSE_RETURN(res1 == res2);
EINA_SAFETY_ON_FALSE_RETURN(res2 > 0);
if (i == new.start_id)
{
if (tmp_group > 0)
group_id = tmp_group;
else if (obj_buffer[0].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP)
group_id = i;
}
}
size = size_buffer[buffer_id].size;
ent = obj_buffer[buffer_id].entity;
if (ent == pd->last_group)
{
pd->last_group = NULL;
}
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.h = size.h;
else
geom.w = size.w;
if (!first_fully_visual_group && obj_buffer[buffer_id].group == EFL_UI_POSITION_MANAGER_BATCH_GROUP_STATE_GROUP &&
eina_spans_intersect(geom.x, geom.w, pd->viewport.x, pd->viewport.w) &&
eina_spans_intersect(geom.y, geom.h, pd->viewport.y, pd->viewport.h))
{
first_fully_visual_group = obj_buffer[buffer_id].entity;
}
if (ent)
efl_gfx_entity_geometry_set(ent, geom);
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.y += size.h;
else
geom.x += size.w;
}
//Now place group items
if (group_id > 0)
{
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->object, group_id, 1, NULL, obj_buffer) == 1);
EINA_SAFETY_ON_FALSE_RETURN(_fill_buffer(&pd->min_size, group_id, 1, NULL, size_buffer) == 1);
first_group = obj_buffer[0].entity;
first_group_size = size_buffer[0].size;
}
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
first_group_size.w = pd->viewport.w;
else
first_group_size.h = pd->viewport.h;
//if there is a new group item, display the new one, and hide the old one
if (first_group != pd->last_group)
{
efl_gfx_entity_visible_set(pd->last_group, EINA_FALSE);
efl_gfx_stack_raise_to_top(first_group);
pd->last_group = first_group;
}
//we have to set the visibility again here, as changing the visual segments might overwrite our visibility state
efl_gfx_entity_visible_set(first_group, EINA_TRUE);
//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
Eina_Position2D first_group_pos = EINA_POSITION2D(pd->viewport.x, pd->viewport.y);
if (first_fully_visual_group && first_fully_visual_group != first_group)
{
Eina_Position2D first_visual_group;
first_visual_group = efl_gfx_entity_position_get(first_fully_visual_group);
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
first_group_pos.y = MIN(first_group_pos.y, first_visual_group.y - first_group_size.h);
else
first_group_pos.x = MIN(first_group_pos.x, first_visual_group.x - first_group_size.w);
}
efl_gfx_entity_position_set(first_group, first_group_pos);
efl_gfx_entity_size_set(first_group, first_group_size);
}
static void
position_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
{
Eina_Rect geom;
Eina_Size2D space_size;
unsigned int start_id = 0, end_id = 0, i;
Vis_Segment cur;
int relevant_space_size, relevant_viewport;
const int len = 100;
Eina_Size2D size_buffer[len];
Efl_Gfx_Entity *obj_buffer[len];
Efl_Ui_Position_Manager_Range_Update ev;
if (!pd->size) return;
@ -162,82 +324,17 @@ position_content(Eo *obj EINA_UNUSED, Efl_Ui_Position_Manager_List_Data *pd)
relevant_viewport = pd->viewport.w;
}
//based on the average item size, we jump somewhere into the sum cache.
//After beeing in there, we are walking back, until we have less space then viewport size
start_id = MIN((unsigned int)(relevant_space_size / pd->average_item_size), pd->size);
for (; cache_access(obj, pd, start_id) >= relevant_space_size && start_id > 0; start_id --) { }
//starting on the start id, we are walking down until the sum of elements is bigger than the lower part of the viewport.
end_id = start_id;
for (; end_id <= pd->size && cache_access(obj, pd, end_id) <= relevant_space_size + relevant_viewport ; end_id ++) { }
end_id = MAX(end_id, start_id + 1);
end_id = MIN(end_id, pd->size);
#ifdef DEBUG
printf("space_size %d : starting point : %d : cached_space_starting_point %d end point : %d cache_space_end_point %d\n", space_size.h, start_id, pd->size_cache[start_id], end_id, pd->size_cache[end_id]);
#endif
if (relevant_space_size > 0)
EINA_SAFETY_ON_FALSE_RETURN(cache_access(obj, pd, start_id) <= relevant_space_size);
if (end_id != pd->size)
EINA_SAFETY_ON_FALSE_RETURN(cache_access(obj, pd, end_id) >= relevant_space_size + relevant_viewport);
EINA_SAFETY_ON_FALSE_RETURN(start_id <= end_id);
cur = _search_visual_segment(obj, pd, relevant_space_size, relevant_viewport);
//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)
_visual_segment_swap(obj, pd, cur, pd->prev_run);
_position_items(obj, pd, cur, relevant_space_size);
if (pd->prev_run.start_id != cur.start_id || pd->prev_run.end_id != cur.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, 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));
}
geom = pd->viewport;
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.y -= (relevant_space_size - cache_access(obj, pd, start_id));
else
geom.x -= (relevant_space_size - cache_access(obj, pd, start_id));
for (i = start_id; i < end_id; ++i)
{
Eina_Size2D size;
Efl_Gfx_Entity *ent = NULL;
int buffer_id = (i-start_id) % len;
if (buffer_id == 0)
{
int res1, res2;
res1 = _fill_buffer(&pd->object, i, len, obj_buffer);
res2 = _fill_buffer(&pd->min_size, i, len, size_buffer);
EINA_SAFETY_ON_FALSE_RETURN(res1 == res2);
EINA_SAFETY_ON_FALSE_RETURN(res2 > 0);
}
size = size_buffer[buffer_id];
ent = obj_buffer[buffer_id];
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.h = size.h;
else
geom.w = size.w;
if (ent)
efl_gfx_entity_geometry_set(ent, geom);
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
geom.y += size.h;
else
geom.x += size.w;
}
if (pd->prev_run.start_id != start_id || pd->prev_run.end_id != 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);
}
@ -333,7 +430,7 @@ _efl_ui_position_manager_list_efl_ui_position_manager_entity_position_single_ite
Eina_Size2D space_size;
int relevant_space_size;
Eina_Size2D size;
Eina_Size2D size_buffer[1];
Efl_Ui_Position_Manager_Batch_Size_Access size_buffer[1];
if (!pd->size) return EINA_RECT(0,0,0,0);
@ -353,9 +450,9 @@ _efl_ui_position_manager_list_efl_ui_position_manager_entity_position_single_ite
geom = pd->viewport;
EINA_SAFETY_ON_FALSE_RETURN_VAL(_fill_buffer(&pd->min_size, idx, 1, size_buffer) == 1, EINA_RECT_EMPTY());
EINA_SAFETY_ON_FALSE_RETURN_VAL(_fill_buffer(&pd->min_size, idx, 1, NULL, size_buffer) == 1, EINA_RECT_EMPTY());
size = size_buffer[0];
size = size_buffer[0].size;
if (pd->dir == EFL_UI_LAYOUT_ORIENTATION_VERTICAL)
{

View File

@ -116,11 +116,9 @@ pub_eo_files = [
'efl_ui_list_view.eo',
'efl_ui_list_view_model.eo',
'efl_ui_list_view_pan.eo',
'efl_ui_item_part_text.eo',
'efl_ui_item_part_icon.eo',
'efl_ui_item_part_extra.eo',
'efl_ui_item_part_content.eo',
'efl_ui_item.eo',
'efl_ui_default_item.eo',
'efl_ui_group_item.eo',
'efl_ui_list_default_item.eo',
'efl_ui_list_placeholder_item.eo',
'efl_ui_list.eo',
@ -895,6 +893,8 @@ elementary_src = [
'efl_ui_focus_util.c',
'elm_widget_item_static_focus.c',
'efl_ui_item.c',
'efl_ui_default_item.c',
'efl_ui_group_item.c',
'efl_ui_list_default_item.c',
'efl_ui_list_placeholder_item.c',
'efl_ui_list.c',

View File

@ -25,33 +25,42 @@ item_container_teardown()
win = NULL;
}
static int
static Efl_Ui_Position_Manager_Batch_Result
_size_accessor_get_at(void *data EINA_UNUSED, int start_id, Eina_Rw_Slice memory)
{
int i;
Efl_Ui_Position_Manager_Batch_Size_Access *sizes = memory.mem;
Efl_Ui_Position_Manager_Batch_Result result;
for (i = start_id; i < (int)(MIN(start_id + memory.len, eina_inarray_count(arr_size))); ++i)
{
Eina_Size2D *size = eina_inarray_nth(arr_size, i);
Eina_Size2D *size = eina_inarray_nth(arr_size, i);
((Eina_Size2D*)memory.mem)[i - start_id] = *size;
sizes[i - start_id].size = *size;
sizes[i - start_id].group = 0;
}
return i - start_id;
result.filled_items = i - start_id;
result.group_id = -1;
return result;
}
static int
static Efl_Ui_Position_Manager_Batch_Result
_obj_accessor_get_at(void *data EINA_UNUSED, int start_id, Eina_Rw_Slice memory)
{
int i;
Efl_Ui_Position_Manager_Batch_Entity_Access *objs = memory.mem;
Efl_Ui_Position_Manager_Batch_Result result;
for (i = start_id; i < (int)(MIN(start_id + memory.len, eina_array_count(arr_obj))); ++i)
{
Efl_Gfx_Entity *geom = eina_array_data_get(arr_obj, i);
((Efl_Gfx_Entity**)memory.mem)[i - start_id] = geom;
objs[i - start_id].entity = geom;
objs[i - start_id].group = 0;
}
return i - start_id;
result.filled_items = i - start_id;
result.group_id = -1;
return result;
}
static void
_initial_setup(void)

View File

@ -6,6 +6,21 @@
#include "efl_ui_spec_suite.h"
#include "suite_helpers.h"
Efl_Ui_Widget*
efl_test_parent_get(Eo *obj)
{
if (efl_isa(widget, EFL_UI_GROUP_ITEM_CLASS))
{
return efl_ui_item_parent_get(obj);
}
else
{
return efl_ui_widget_parent_get(obj);
}
}
void
efl_test_container_content_equal(Efl_Ui_Widget **wid, unsigned int len)
{

View File

@ -137,7 +137,7 @@ EFL_START_TEST(unpack1)
_setup_std_pack(wid);
ck_assert_int_eq(efl_pack_unpack(widget, wid[2]), EINA_TRUE);
ck_assert_ptr_ne(efl_ui_widget_parent_get(wid[2]), widget);
ck_assert_ptr_ne(efl_test_parent_get(wid[2]), widget);
ck_assert_int_eq(efl_ref_count(wid[2]), 1);
efl_test_container_content_equal(wid, 2);
}
@ -198,7 +198,7 @@ EFL_START_TEST(pack1)
for (i = 0; i < sizeof(wid)/sizeof(Efl_Ui_Widget*); ++i)
{
ck_assert_int_eq(efl_ref_count(wid[i]), 1);
ck_assert_ptr_eq(efl_ui_widget_parent_get(wid[i]), widget);
ck_assert_ptr_eq(efl_test_parent_get(wid[i]), widget);
}
efl_test_container_content_equal(wid, 3);
@ -292,6 +292,7 @@ EFL_END_TEST
void
efl_pack_behavior_test(TCase *tc)
{
tcase_add_test(tc, pack2);
tcase_add_test(tc, base2);
tcase_add_test(tc, pack_clear1);
tcase_add_test(tc, pack_clear2);
@ -301,7 +302,6 @@ efl_pack_behavior_test(TCase *tc)
tcase_add_test(tc, unpack2);
tcase_add_test(tc, unpack3);
tcase_add_test(tc, pack1);
tcase_add_test(tc, pack2);
tcase_add_test(tc, pack3);
tcase_add_test(tc, evt_content_added);
tcase_add_test(tc, evt_content_removed);

View File

@ -9,10 +9,11 @@
/* spec-meta-start
{"test-interface":"Efl.Pack_Linear",
"test-widgets": ["Efl.Ui.Box", "Efl.Ui.Grid", "Efl.Ui.Spotlight.Container", "Efl.Ui.List"],
"test-widgets": ["Efl.Ui.Box", "Efl.Ui.Grid", "Efl.Ui.Spotlight.Container", "Efl.Ui.List", "Efl.Ui.Group_Item" ],
"custom-mapping" : {
"Efl.Ui.Grid" : "EFL_UI_GRID_DEFAULT_ITEM_CLASS",
"Efl.Ui.List" : "EFL_UI_LIST_DEFAULT_ITEM_CLASS"
"Efl.Ui.List" : "EFL_UI_LIST_DEFAULT_ITEM_CLASS",
"Efl.Ui.Group_Item" : "EFL_UI_LIST_DEFAULT_ITEM_CLASS"
}
}
spec-meta-end */
@ -46,7 +47,7 @@ EFL_START_TEST(pack_begin1)
for (int i = 2; i >= 0; i--)
{
efl_pack_begin(widget, wid[i]);
ck_assert_ptr_eq(efl_ui_widget_parent_get(wid[i]), widget);
ck_assert_ptr_eq(efl_test_parent_get(wid[i]), widget);
}
_ordering_equals(wid, 3);
efl_pack_begin(widget, inv);
@ -65,7 +66,7 @@ EFL_START_TEST(pack_begin2)
for (int i = 2; i >= 0; i--)
{
efl_pack_begin(widget, wid[i]);
ck_assert_ptr_eq(efl_ui_widget_parent_get(wid[i]), widget);
ck_assert_ptr_eq(efl_test_parent_get(wid[i]), widget);
}
EXPECT_ERROR_START;
@ -85,7 +86,7 @@ EFL_START_TEST(pack_end1)
for (int i = 0; i < 3; i++)
{
efl_pack_end(widget, wid[i]);
ck_assert_ptr_eq(efl_ui_widget_parent_get(wid[i]), widget);
ck_assert_ptr_eq(efl_test_parent_get(wid[i]), widget);
}
_ordering_equals(wid, 3);
@ -105,7 +106,7 @@ EFL_START_TEST(pack_end2)
for (int i = 0; i < 3; i++)
{
efl_pack_end(widget, wid[i]);
ck_assert_ptr_eq(efl_ui_widget_parent_get(wid[i]), widget);
ck_assert_ptr_eq(efl_test_parent_get(wid[i]), widget);
}
EXPECT_ERROR_START;
@ -126,13 +127,13 @@ EFL_START_TEST(pack_before1)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_before(widget, inv, wid[0]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid2[] = {inv, wid[0], wid[1], wid[2]};
_ordering_equals(wid2, 4);
efl_pack_unpack(widget, inv);
ck_assert_int_eq(efl_pack_before(widget, inv, wid[2]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid3[] = {wid[0], wid[1], inv, wid[2]};
_ordering_equals(wid3, 4);
}
@ -149,7 +150,7 @@ EFL_START_TEST(pack_before2)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_before(widget, inv, wid[0]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid2[] = {inv, wid[0], wid[1], wid[2]};
_ordering_equals(wid2, 4);
@ -170,13 +171,13 @@ EFL_START_TEST(pack_after1)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_after(widget, inv, wid[0]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid2[] = {wid[0], inv, wid[1], wid[2]};
_ordering_equals(wid2, 4);
efl_pack_unpack(widget, inv);
ck_assert_int_eq(efl_pack_after(widget, inv, wid[2]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid3[] = {wid[0], wid[1], wid[2], inv};
_ordering_equals(wid3, 4);
}
@ -193,7 +194,7 @@ EFL_START_TEST(pack_after2)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_after(widget, inv, wid[0]), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
Efl_Ui_Widget *wid2[] = {wid[0], inv, wid[1], wid[2]};
_ordering_equals(wid2, 4);
@ -216,7 +217,7 @@ EFL_START_TEST(pack_at1)
efl_pack_end(widget, wid[i]);
efl_pack_at(widget, inv, x);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
for (i = 0; i < 4; ++i)
{
@ -247,7 +248,7 @@ EFL_START_TEST(pack_at2)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_at(widget, inv, x), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
EXPECT_ERROR_START;
ck_assert_int_eq(efl_pack_at(widget, inv, x - 1), EINA_FALSE);
@ -281,9 +282,9 @@ EFL_START_TEST(pack_at3)
efl_pack_end(widget, wid[i]);
ck_assert_int_eq(efl_pack_at(widget, inv,-100000), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv), widget);
ck_assert_int_eq(efl_pack_at(widget, inv2, 100000), EINA_TRUE);
ck_assert_ptr_eq(efl_ui_widget_parent_get(inv2), widget);
ck_assert_ptr_eq(efl_test_parent_get(inv2), widget);
Efl_Ui_Widget *wid2[] = {inv, wid[0], wid[1], wid[2], inv2};
_ordering_equals(wid2, 5);
}
@ -377,15 +378,27 @@ EFL_START_TEST(pack_unpack_at3)
efl_pack_end(widget, wid[i]);
ck_assert_ptr_eq(efl_pack_unpack_at(widget, x), wid[(3+x)%3]);
ck_assert_int_eq(efl_content_count(widget), 2);
ck_assert_ptr_ne(efl_ui_widget_parent_get(wid[(3+x)%3]), widget);
ck_assert_ptr_ne(efl_test_parent_get(wid[(3+x)%3]), widget);
efl_pack_unpack_all(widget);
}
}
EFL_END_TEST
void
object_setup(void)
{
if (efl_isa(widget, EFL_UI_GROUP_ITEM_CLASS))
{
Efl_Ui_Collection *collection = efl_add(EFL_UI_GRID_CLASS, win);
efl_content_set(win, collection);
efl_pack_end(collection, widget);
}
}
void
efl_pack_linear_behavior_test(TCase *tc)
{
tcase_add_checked_fixture(tc, object_setup, NULL);
tcase_add_test(tc, pack_begin1);
tcase_add_test(tc, pack_begin2);
tcase_add_test(tc, pack_end1);

View File

@ -25,6 +25,7 @@ void efl_ui_selectable_behavior_test(TCase *tc);
void efl_test_container_content_equal(Efl_Ui_Widget **wid, unsigned int len);
void efl_test_container_expect_evt_content_added(Efl_Ui_Widget *widget, const Efl_Event_Description *ev, Eina_Bool *flag, void *event_data);
Efl_Ui_Widget* efl_test_parent_get(Eo *obj);
Eo* create_test_widget(void);