From c11a7cf227d6f07ef8ca166f11fc649037708e1c Mon Sep 17 00:00:00 2001 From: Dave Andreoli Date: Tue, 9 Aug 2016 15:39:35 +0200 Subject: [PATCH] New 1.18 API: elm Genlist reusable content functionality with a FAILING test (failing also in C) (I love to implement broken stuff) --- efl/elementary/genlist.pxi | 24 +++++++ efl/elementary/genlist_cdef.pxi | 12 ++-- efl/elementary/genlist_item_class.pxi | 35 ++++++++- examples/elementary/test.py | 1 + examples/elementary/test_genlist_reusable.py | 76 ++++++++++++++++++++ 5 files changed, 142 insertions(+), 6 deletions(-) create mode 100644 examples/elementary/test_genlist_reusable.py diff --git a/efl/elementary/genlist.pxi b/efl/elementary/genlist.pxi index 2a2d78f..5ba857d 100644 --- a/efl/elementary/genlist.pxi +++ b/efl/elementary/genlist.pxi @@ -62,6 +62,30 @@ cdef Evas_Object *_py_elm_genlist_item_content_get(void *data, Evas_Object *obj, else: return NULL +cdef Evas_Object *_py_elm_genlist_item_reusable_content_get(void *data, Evas_Object *obj, const char *part, Evas_Object *old) with gil: + cdef: + GenlistItem item = data + unicode u = _ctouni(part) + evasObject icon + + func = item.item_class._reusable_content_get_func + if func is None: + return NULL + + o = object_from_instance(obj) + old_content = object_from_instance(old) + + try: + icon = func(o, u, item.item_data, old_content) + except Exception: + traceback.print_exc() + return NULL + + if icon is not None: + return icon.obj + else: + return NULL + cdef Eina_Bool _py_elm_genlist_item_state_get(void *data, Evas_Object *obj, const char *part) with gil: cdef: GenlistItem item = data diff --git a/efl/elementary/genlist_cdef.pxi b/efl/elementary/genlist_cdef.pxi index 0476ffb..d76fd05 100644 --- a/efl/elementary/genlist_cdef.pxi +++ b/efl/elementary/genlist_cdef.pxi @@ -62,15 +62,17 @@ cdef extern from "Elementary.h": pass - ctypedef char *(*GenlistItemLabelGetFunc) (void *data, Evas_Object *obj, const char *part) - ctypedef Evas_Object *(*GenlistItemIconGetFunc) (void *data, Evas_Object *obj, const char *part) - ctypedef Eina_Bool (*GenlistItemStateGetFunc) (void *data, Evas_Object *obj, const char *part) - ctypedef Eina_Bool (*GenlistItemFilterGetFunc) (void *data, Evas_Object *obj, void *key) - ctypedef void (*GenlistItemDelFunc) (void *data, Evas_Object *obj) + ctypedef char *(*GenlistItemLabelGetFunc) (void *data, Evas_Object *obj, const char *part) + ctypedef Evas_Object *(*GenlistItemIconGetFunc) (void *data, Evas_Object *obj, const char *part) + ctypedef Evas_Object *(*GenlistItemReusableIconGetFunc)(void *data, Evas_Object *obj, const char *part, Evas_Object *old) + ctypedef Eina_Bool (*GenlistItemStateGetFunc) (void *data, Evas_Object *obj, const char *part) + ctypedef Eina_Bool (*GenlistItemFilterGetFunc) (void *data, Evas_Object *obj, void *key) + ctypedef void (*GenlistItemDelFunc) (void *data, Evas_Object *obj) ctypedef struct Elm_Genlist_Item_Class_Func: GenlistItemLabelGetFunc text_get GenlistItemIconGetFunc content_get + GenlistItemReusableIconGetFunc reusable_content_get GenlistItemStateGetFunc state_get GenlistItemFilterGetFunc filter_get GenlistItemDelFunc del_ "del" diff --git a/efl/elementary/genlist_item_class.pxi b/efl/elementary/genlist_item_class.pxi index 68875d3..950f219 100644 --- a/efl/elementary/genlist_item_class.pxi +++ b/efl/elementary/genlist_item_class.pxi @@ -18,6 +18,7 @@ cdef class GenlistItemClass(object): Elm_Genlist_Item_Class *cls object _text_get_func object _content_get_func + object _reusable_content_get_func object _state_get_func object _filter_get_func object _del_func @@ -29,6 +30,7 @@ cdef class GenlistItemClass(object): self.cls = elm_genlist_item_class_new() self.cls.func.text_get = _py_elm_genlist_item_text_get self.cls.func.content_get = _py_elm_genlist_item_content_get + self.cls.func.reusable_content_get = _py_elm_genlist_item_reusable_content_get self.cls.func.state_get = _py_elm_genlist_item_state_get self.cls.func.filter_get = _py_elm_genlist_item_filter_get # In C the struct member is del but we rename it to del_ in pxd @@ -41,7 +43,8 @@ cdef class GenlistItemClass(object): def __init__(self, item_style=None, text_get_func=None, content_get_func=None, state_get_func=None, del_func=None, decorate_item_style=None, decorate_all_item_style=None, - filter_get_func=None, *args, **kwargs): + filter_get_func=None, reusable_content_get_func=None, + *args, **kwargs): """GenlistItemClass constructor. @@ -76,6 +79,14 @@ cdef class GenlistItemClass(object): and similar. This function should have the signature: ``func(obj, part, item_data)`` + :param reusable_content_get_func: if provided will override the behavior + defined by :py:func:`reusable_content_get()` in this class. + Its purpose is to return the icon object to be used (swallowed) by a + given part and row. This can be used to reuse (cache) contents + (since 1.18) + This function should have the signature: + ``func(obj, part, item_data, old_content) -> obj`` + .. note:: In all these signatures, 'obj' means Genlist and 'item_data' is the value given to Genlist item append/prepend methods, it should represent your row model as you want. @@ -100,6 +111,14 @@ cdef class GenlistItemClass(object): else: self._content_get_func = self.content_get + if reusable_content_get_func is not None: + if callable(reusable_content_get_func): + self._reusable_content_get_func = reusable_content_get_func + else: + raise TypeError("reusable_content_get_func is not callable!") + else: + self._reusable_content_get_func = self.reusable_content_get + if state_get_func is not None: if callable(state_get_func): self._state_get_func = state_get_func @@ -236,6 +255,20 @@ cdef class GenlistItemClass(object): """ return None + def reusable_content_get(self, evasObject obj, part, item_data, old_content): + """To be called by Genlist for each row to get its icon. + + :param obj: the Genlist instance + :param part: the part that is being handled. + :param item_data: the value given to genlist append/prepend. + :param old_content: the old (if available) content that can be used + instead of creating a new object every time. + + :return: icon object to be used and swallowed. + :rtype: evas Object or None + """ + return None + def state_get(self, evasObject obj, part, item_data): """To be called by Genlist for each row to get its state. diff --git a/examples/elementary/test.py b/examples/elementary/test.py index f2e984d..f66f0d3 100755 --- a/examples/elementary/test.py +++ b/examples/elementary/test.py @@ -181,6 +181,7 @@ items = [ ("Genlist Decorate All Mode", "test_genlist_decorate_all", "test_genlist_decorate_all"), ("Genlist Search by Text", "test_genlist_search", "test_genlist_search"), ("Genlist Reorder Mode", "test_genlist_reorder", "test_genlist_reorder"), + ("Genlist Reusable Contents", "test_genlist_reusable", "test_genlist_reusable"), ]), ("Lists - List", [ ("List", "test_list", "list_clicked"), diff --git a/examples/elementary/test_genlist_reusable.py b/examples/elementary/test_genlist_reusable.py new file mode 100644 index 0000000..8d83904 --- /dev/null +++ b/examples/elementary/test_genlist_reusable.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# encoding: utf-8 + + +from efl.evas import EXPAND_BOTH, EXPAND_HORIZ, FILL_BOTH +from efl import elementary as elm + + +class MyItemClass(elm.GenlistItemClass): + def __init__(self): + elm.GenlistItemClass.__init__(self, item_style='default') + + def text_get(self, obj, part, item_data): + return 'Item # %i' % item_data + + def content_get(self, obj, part, item_data): + if part == 'elm.swallow.icon': + return elm.Icon(obj, standard='user-home') + if part == 'elm.swallow.end': + print('Creating NEW content for item #%d' % item_data) + txt = 'Content for item %i' % item_data + return elm.Label(obj, text=txt) + return None + + def reusable_content_get(self, obj, part, item_data, old_content): + if part == 'elm.swallow.end' and old_content: + if obj.data['reusable_enabled'] == True: + print('REUSING content for item # %i' % item_data) + return old_content + return None + +itc = MyItemClass() + + +def check_changed_cb(ck, gl): + gl.data['reusable_enabled'] = ck.state + gl.realized_items_update() + +def test_genlist_reusable(parent): + win = elm.StandardWindow('GenlistReusable', 'Genlist Reusable Contents', + size=(400, 400), autodel=True) + + # main vertical box + box = elm.Box(win, size_hint_weight=EXPAND_BOTH) + win.resize_object_add(box) + box.show() + + # info frame + fr = elm.Frame(win, text='Information', size_hint_expand=EXPAND_HORIZ, + size_hint_fill=FILL_BOTH) + fr.content = elm.Label(fr, text='Numbers on the left should always match the one on the right') + box.pack_end(fr) + fr.show() + + # genlist + gl = elm.Genlist(win, homogeneous=True, mode=elm.ELM_LIST_COMPRESS, + size_hint_expand=EXPAND_BOTH, size_hint_fill=FILL_BOTH) + box.pack_end(gl) + for i in range(0, 2000): + gl.item_append(itc, i) + gl.show() + gl.data['reusable_enabled'] = True + + # buttons + ck = elm.Check(win, text='Enable reusable contents', state=True) + ck.callback_changed_add(check_changed_cb, gl) + box.pack_end(ck) + ck.show() + + win.show() + + +if __name__ == '__main__': + elm.policy_set(elm.ELM_POLICY_QUIT, elm.ELM_POLICY_QUIT_LAST_WINDOW_CLOSED) + test_genlist_reusable(None) + elm.run()