forked from enlightenment/efl
elementary: make Efl.Ui.Factory.create asynchronous.
Reviewers: felipealmeida, SanghyeonLee, vitor.sousa, bu5hm4n, segfaultxavi Reviewed By: felipealmeida, vitor.sousa, segfaultxavi Subscribers: segfaultxavi, #reviewers, #committers Tags: #efl Maniphest Tasks: T7472 Differential Revision: https://phab.enlightenment.org/D7332
This commit is contained in:
parent
89683f49ca
commit
4d6f20d714
|
@ -8,7 +8,7 @@ interface Efl.Ui.Factory (Efl.Ui.Model.Connect)
|
|||
model: Efl.Model; [[Efl model]]
|
||||
parent: Efl.Gfx.Entity; [[Efl canvas]]
|
||||
}
|
||||
return: Efl.Gfx.Entity; [[Created UI object]]
|
||||
return: future<Efl.Gfx.Entity>; [[Created UI object]]
|
||||
}
|
||||
release {
|
||||
[[Release a UI object and disconnect from models.]]
|
||||
|
|
|
@ -32,10 +32,11 @@ _efl_ui_image_factory_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Ui_Image_Fa
|
|||
efl_destructor(efl_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Gfx_Entity *
|
||||
_efl_ui_image_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Image_Factory_Data *pd, Efl_Model *model, Efl_Gfx_Entity *parent)
|
||||
EOLIAN static Eina_Future *
|
||||
_efl_ui_image_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Image_Factory_Data *pd, Efl_Model *model, Efl_Gfx_Entity *parent)
|
||||
{
|
||||
Efl_Gfx_Entity *ui_view;
|
||||
Eina_Value r;
|
||||
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(pd->property, NULL);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
|
||||
|
@ -43,7 +44,9 @@ _efl_ui_image_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Image_Fa
|
|||
efl_ui_view_model_set(ui_view, model);
|
||||
efl_ui_model_connect(ui_view, "filename", pd->property);
|
||||
|
||||
return ui_view;
|
||||
r = eina_value_object_init(ui_view);
|
||||
|
||||
return eina_future_resolved(efl_loop_future_scheduler_get(obj), r);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
|
|
|
@ -69,6 +69,15 @@ static const char *_efl_ui_layout_swallow_parts[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
typedef struct _Efl_Ui_Layout_Factory_Tracking Efl_Ui_Layout_Factory_Tracking;
|
||||
|
||||
struct _Efl_Ui_Layout_Factory_Tracking
|
||||
{
|
||||
Efl_Ui_Factory *factory;
|
||||
Eina_Future *in_flight;
|
||||
Eina_Stringshare *name;
|
||||
};
|
||||
|
||||
|
||||
/* these are data operated by layout's class functions internally, and
|
||||
* should not be messed up by inhering classes */
|
||||
|
@ -2034,13 +2043,68 @@ on_error:
|
|||
free(value);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Factory *factory, const char *name)
|
||||
typedef struct _Efl_Ui_Layout_Factory_Request Efl_Ui_Layout_Factory_Request;
|
||||
struct _Efl_Ui_Layout_Factory_Request
|
||||
{
|
||||
Efl_Gfx_Entity *content;
|
||||
Efl_Ui_Layout_Factory_Tracking *tracking;
|
||||
Efl_Ui_Layout *obj;
|
||||
Efl_Ui_Layout_Data *pd;
|
||||
Efl_Ui_Factory *factory;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
content = efl_ui_factory_create(factory, pd->connect.model, pd->obj);
|
||||
elm_layout_content_set(pd->obj, name, content);
|
||||
static Eina_Value
|
||||
_content_created(void *data, const Eina_Value value)
|
||||
{
|
||||
Efl_Ui_Layout_Factory_Request *request = data;
|
||||
Efl_Gfx_Entity *content = NULL;
|
||||
Efl_Gfx_Entity *old_content;
|
||||
|
||||
eina_value_get(&value, &content);
|
||||
|
||||
// Recycle old content
|
||||
old_content = elm_layout_content_get(request->obj, request->name);
|
||||
if (old_content) efl_ui_factory_release(request->factory, old_content);
|
||||
|
||||
// Set new content
|
||||
elm_layout_content_set(request->obj, request->name, content);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
Efl_Ui_Layout_Factory_Request *request = data;
|
||||
|
||||
request->tracking->in_flight = NULL;
|
||||
eina_stringshare_del(request->name);
|
||||
efl_unref(request->factory);
|
||||
free(request);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_layout_view_model_content_update(Efl_Ui_Layout_Data *pd, Efl_Ui_Layout_Factory_Tracking *tracking, const char *name)
|
||||
{
|
||||
Efl_Ui_Layout_Factory_Request *request = calloc(1, sizeof (Efl_Ui_Layout_Factory_Request));
|
||||
Eina_Future *f;
|
||||
|
||||
if (!request) return ;
|
||||
|
||||
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
|
||||
|
||||
request->name = eina_stringshare_ref(name);
|
||||
request->pd = pd;
|
||||
request->obj = pd->obj;
|
||||
request->factory = efl_ref(tracking->factory);
|
||||
request->tracking = tracking;
|
||||
|
||||
f = efl_ui_factory_create(tracking->factory, pd->connect.model, pd->obj);
|
||||
f = eina_future_then_from_desc(efl_future_then(pd->obj, f),
|
||||
eina_future_cb_easy(.success = _content_created,
|
||||
.success_type = EINA_VALUE_TYPE_OBJECT,
|
||||
.data = request,
|
||||
.free = _clean_request));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2063,7 +2127,11 @@ _efl_ui_layout_view_model_update(Efl_Ui_Layout_Data *pd)
|
|||
|
||||
it = eina_hash_iterator_tuple_new(pd->connect.factories);
|
||||
EINA_ITERATOR_FOREACH(it, tuple)
|
||||
_efl_ui_layout_view_model_content_update(pd, tuple->data, tuple->key);
|
||||
{
|
||||
Efl_Ui_Layout_Factory_Tracking *factory = tuple->data;
|
||||
|
||||
_efl_ui_layout_view_model_content_update(pd, factory, tuple->key);
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
}
|
||||
|
||||
|
@ -2083,7 +2151,7 @@ _efl_model_properties_changed_cb(void *data, const Efl_Event *event)
|
|||
Eina_Stringshare *sprop = eina_stringshare_add(prop);
|
||||
const char *part;
|
||||
const char *signal;
|
||||
Efl_Ui_Factory *factory;
|
||||
Efl_Ui_Layout_Factory_Tracking *factory;
|
||||
|
||||
part = eina_hash_find(pd->connect.properties, sprop);
|
||||
if (part) _efl_ui_layout_view_model_property_update(pd, part, sprop);
|
||||
|
@ -2098,6 +2166,15 @@ _efl_model_properties_changed_cb(void *data, const Efl_Event *event)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_layout_factory_free(Efl_Ui_Layout_Factory_Tracking *tracking)
|
||||
{
|
||||
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
|
||||
efl_unref(tracking->factory);
|
||||
eina_stringshare_del(tracking->name);
|
||||
free(tracking);
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_ui_layout_connect_hash(Efl_Ui_Layout_Data *pd)
|
||||
{
|
||||
|
@ -2105,7 +2182,7 @@ _efl_ui_layout_connect_hash(Efl_Ui_Layout_Data *pd)
|
|||
|
||||
pd->connect.properties = eina_hash_stringshared_new(EINA_FREE_CB(free)); // Hash of property targeting a part
|
||||
pd->connect.signals = eina_hash_stringshared_new(EINA_FREE_CB(free)); // Hash of property triggering a signal
|
||||
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref)); // Hash of property triggering a content creation
|
||||
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(_efl_ui_layout_factory_free)); // Hash of property triggering a content creation
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
|
@ -2139,15 +2216,21 @@ _efl_ui_layout_efl_ui_view_model_set(Eo *obj, Efl_Ui_Layout_Data *pd, Efl_Model
|
|||
it = eina_hash_iterator_tuple_new(pd->connect.factories);
|
||||
EINA_ITERATOR_FOREACH(it, tuple)
|
||||
{
|
||||
Efl_Ui_Factory *factory;
|
||||
Efl_Ui_Layout_Factory_Tracking *factory;
|
||||
Efl_Gfx_Entity *content;
|
||||
|
||||
name = tuple->key;
|
||||
factory = tuple->data;
|
||||
content = elm_layout_content_get(obj, name);
|
||||
|
||||
// Cancel in flight creation request
|
||||
if (factory->in_flight) eina_future_cancel(factory->in_flight);
|
||||
|
||||
// Cleanup content
|
||||
content = elm_layout_content_get(obj, name);
|
||||
elm_layout_content_set(obj, name, NULL);
|
||||
efl_ui_factory_release(factory, content);
|
||||
|
||||
// And recycle it
|
||||
efl_ui_factory_release(factory->factory, content);
|
||||
}
|
||||
eina_iterator_free(it);
|
||||
|
||||
|
@ -2215,31 +2298,48 @@ _efl_ui_layout_efl_ui_factory_model_connect(Eo *obj EINA_UNUSED, Efl_Ui_Layout_D
|
|||
const char *name, Efl_Ui_Factory *factory)
|
||||
{
|
||||
EINA_SAFETY_ON_NULL_RETURN(name);
|
||||
Efl_Ui_Layout_Factory_Tracking *tracking;
|
||||
Eina_Stringshare *ss_name;
|
||||
Efl_Ui_Factory *old_factory;
|
||||
Evas_Object *new_ev, *old_ev;
|
||||
|
||||
if (!_elm_layout_part_aliasing_eval(obj, &name, EINA_TRUE))
|
||||
return;
|
||||
|
||||
if (!pd->connect.factories)
|
||||
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(_efl_ui_layout_factory_free));
|
||||
|
||||
ss_name = eina_stringshare_add(name);
|
||||
|
||||
if (!pd->connect.factories)
|
||||
pd->connect.factories = eina_hash_stringshared_new(EINA_FREE_CB(efl_unref));
|
||||
|
||||
new_ev = efl_ui_factory_create(factory, pd->connect.model, obj);
|
||||
EINA_SAFETY_ON_NULL_RETURN(new_ev);
|
||||
|
||||
old_factory = eina_hash_set(pd->connect.factories, ss_name, efl_ref(factory));
|
||||
if (old_factory)
|
||||
// First undo the old one if there is one
|
||||
tracking = eina_hash_find(pd->connect.factories, ss_name);
|
||||
if (tracking)
|
||||
{
|
||||
old_ev = elm_layout_content_get(obj, name);
|
||||
if (old_ev)
|
||||
efl_ui_factory_release(old_factory, old_ev);
|
||||
efl_unref(old_factory);
|
||||
Efl_Gfx_Entity *old;
|
||||
|
||||
// Unset and recycle
|
||||
old = elm_layout_content_get(obj, ss_name);
|
||||
elm_layout_content_set(obj, ss_name, NULL);
|
||||
if (old) efl_ui_factory_release(tracking->factory, old);
|
||||
|
||||
// Stop in flight request
|
||||
if (tracking->in_flight) eina_future_cancel(tracking->in_flight);
|
||||
|
||||
// Release previous factory
|
||||
efl_replace(&tracking->factory, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
tracking = calloc(1, sizeof (Efl_Ui_Layout_Factory_Tracking));
|
||||
if (!tracking) return ;
|
||||
|
||||
tracking->name = ss_name;
|
||||
|
||||
eina_hash_add(pd->connect.factories, ss_name, tracking);
|
||||
}
|
||||
|
||||
elm_layout_content_set(obj, name, new_ev);
|
||||
// And update content with the new factory
|
||||
tracking->factory = efl_ref(factory);
|
||||
|
||||
_efl_ui_layout_view_model_content_update(pd, tracking, ss_name);
|
||||
}
|
||||
|
||||
EOLIAN static Eo *
|
||||
|
|
|
@ -64,10 +64,11 @@ _efl_ui_layout_factory_efl_object_destructor(Eo *obj, Efl_Ui_Layout_Factory_Data
|
|||
efl_destructor(efl_super(obj, MY_CLASS));
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Gfx_Entity *
|
||||
_efl_ui_layout_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Layout_Factory_Data *pd
|
||||
, Efl_Model *model, Efl_Gfx_Entity *parent)
|
||||
EOLIAN static Eina_Future *
|
||||
_efl_ui_layout_factory_efl_ui_factory_create(Eo *obj, Efl_Ui_Layout_Factory_Data *pd,
|
||||
Efl_Model *model, Efl_Gfx_Entity *parent)
|
||||
{
|
||||
Eina_Value r;
|
||||
Efl_Gfx_Entity *layout;
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
|
||||
|
||||
|
@ -81,7 +82,9 @@ _efl_ui_layout_factory_efl_ui_factory_create(Eo *obj EINA_UNUSED, Efl_Ui_Layout_
|
|||
evas_object_size_hint_weight_set(layout, EVAS_HINT_EXPAND, 0);
|
||||
evas_object_size_hint_align_set(layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
|
||||
|
||||
return layout;
|
||||
r = eina_value_object_init(layout);
|
||||
|
||||
return eina_future_resolved(efl_loop_future_scheduler_get(obj), r);
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
|
|
|
@ -902,18 +902,25 @@ _efl_ui_list_view_efl_ui_widget_focus_state_apply(Eo *obj, Efl_Ui_List_View_Data
|
|||
return efl_ui_widget_focus_state_apply(efl_super(obj, MY_CLASS), current_state, configured_state, obj);
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Ui_List_View_Layout_Item *
|
||||
_efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data *pd, Efl_Ui_List_View_Layout_Item *item)
|
||||
typedef struct _Efl_Ui_List_Vuew_Layout_Item_Tracking Efl_Ui_List_View_Layout_Item_Tracking;
|
||||
struct _Efl_Ui_List_Vuew_Layout_Item_Tracking
|
||||
{
|
||||
Efl_Ui_List_View_Layout_Item *item;
|
||||
Eo *obj;
|
||||
Efl_Ui_List_View_Data *pd;
|
||||
};
|
||||
|
||||
static Eina_Value
|
||||
_content_created(void *data, const Eina_Value value)
|
||||
{
|
||||
Efl_Ui_List_View_Layout_Item_Tracking *tracking = data;
|
||||
Efl_Ui_List_View_Layout_Item *item = tracking->item;
|
||||
Eo *obj = tracking->obj;
|
||||
Efl_Ui_List_View_Item_Event evt;
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(item, NULL);
|
||||
|
||||
if (!item->children)
|
||||
return item;
|
||||
eina_value_pget(&value, &item->layout);
|
||||
|
||||
item->layout = efl_ui_factory_create(pd->factory, item->children, obj);
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(item->layout, NULL);
|
||||
evas_object_smart_member_add(item->layout, pd->pan_obj);
|
||||
evas_object_smart_member_add(item->layout, tracking->pd->pan_obj);
|
||||
evas_object_event_callback_add(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item);
|
||||
|
||||
if (_elm_config->atspi_mode)
|
||||
|
@ -929,6 +936,44 @@ _efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data
|
|||
efl_ui_focus_composition_dirty(obj);
|
||||
|
||||
evas_object_show(item->layout);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void
|
||||
_clean_request(void *data, const Eina_Future *dead_future EINA_UNUSED)
|
||||
{
|
||||
Efl_Ui_List_View_Layout_Item_Tracking *tracking = data;
|
||||
|
||||
tracking->item->layout_request = NULL;
|
||||
free(tracking);
|
||||
}
|
||||
|
||||
EOLIAN static Efl_Ui_List_View_Layout_Item *
|
||||
_efl_ui_list_view_efl_ui_list_view_model_realize(Eo *obj, Efl_Ui_List_View_Data *pd, Efl_Ui_List_View_Layout_Item *item)
|
||||
{
|
||||
Efl_Ui_List_View_Layout_Item_Tracking *tracking;
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(item->children, item);
|
||||
|
||||
if (!item->children) return item;
|
||||
|
||||
if (item->layout_request) eina_future_cancel(item->layout_request);
|
||||
|
||||
tracking = calloc(1, sizeof (Efl_Ui_List_View_Layout_Item_Tracking));
|
||||
if (!tracking) return item;
|
||||
|
||||
tracking->item = item;
|
||||
tracking->obj = obj;
|
||||
tracking->pd = pd;
|
||||
|
||||
item->layout_request = efl_ui_factory_create(pd->factory, item->children, obj);
|
||||
item->layout_request = efl_future_then(obj, item->layout_request);
|
||||
item->layout_request = eina_future_then_from_desc(item->layout_request,
|
||||
eina_future_cb_easy(.success = _content_created,
|
||||
.success_type = EINA_VALUE_TYPE_OBJECT,
|
||||
.data = tracking,
|
||||
.free = _clean_request));
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
|
@ -941,6 +986,13 @@ _efl_ui_list_view_efl_ui_list_view_model_unrealize(Eo *obj, Efl_Ui_List_View_Dat
|
|||
if (!item->layout)
|
||||
return;
|
||||
|
||||
// First check if the item has been fully realized
|
||||
if (item->layout_request)
|
||||
{
|
||||
eina_future_cancel(item->layout_request);
|
||||
return ;
|
||||
}
|
||||
|
||||
evas_object_event_callback_del_full(item->layout, EVAS_CALLBACK_MOUSE_UP, _on_item_mouse_up, item);
|
||||
if (elm_object_focus_allow_get(item->layout))
|
||||
{
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#ifndef EFL_UI_LIST_VIEW_SEG_ARRAY_H
|
||||
#define EFL_UI_LIST_VIEW_SEG_ARRAY_H
|
||||
|
||||
typedef struct _Efl_Ui_List_View_Item Efl_Ui_List_View_Item;
|
||||
|
||||
typedef struct _Efl_Ui_List_View_SegArray_Node
|
||||
{
|
||||
EINA_RBTREE;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
struct Efl.Ui.List_View_Layout_Item {
|
||||
layout: Efl.Ui.Layout;
|
||||
layout_request: future<Efl.Ui.Layout>;
|
||||
children: Efl.Model;
|
||||
index_offset: int;
|
||||
tree_node: void_ptr;
|
||||
|
|
Loading…
Reference in New Issue