davemds pushed a commit to branch master. http://git.enlightenment.org/bindings/python/python-efl.git/commit/?id=005dd26f73f0a634d16286362b80ce98e2e277a8
commit 005dd26f73f0a634d16286362b80ce98e2e277a8 Author: Dave Andreoli <d...@gurumeditation.it> Date: Wed Jan 20 22:55:43 2016 +0100 Implemented Genlist filter ability It is somehow not perfectly working, see TODO for more info --- TODO | 4 +- doc/elementary/genlist.rst | 1 + efl/elementary/genlist.pxi | 18 +++++++ efl/elementary/genlist_cdef.pxi | 3 ++ efl/elementary/genlist_item_class.pxi | 27 +++++++++- efl/elementary/genlist_widget.pxi | 38 +++++++++++++- examples/elementary/test_genlist_filter.py | 84 ++++++++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 5 deletions(-) diff --git a/TODO b/TODO index 516d3c5..4e41a98 100644 --- a/TODO +++ b/TODO @@ -3,12 +3,14 @@ BUGS ==== * EdjeEdit: PartState API does not work * Elm.Map: overlays_show segfaults, scrollers in examples are jumpy +* Genlist: "filter,done" event is not always fired (see the genlist_filter.py test) * Elementary: when we use custom function callbacks we usually leak some reference around, some examples: - Fileselector.custom_filter_append() - Multibuttonentry.format_function_set() - Multibuttonentry.filter_append() - Multibuttonentry.filterprepend() + ... maybe do like is done in genlist filter_set() ?? Failing unit tests ------------------ @@ -22,8 +24,6 @@ TODO http://www.freedesktop.org/wiki/Software/DBusBindings (requires fd.org shell account?) * Review the internal functions and name them consistently -* Evas: SmartObject needs testing -* Improve ethumb * edje: complete the unit tests * Initial Evas GL support (for Elm) * Add more documentation for callbacks, events, etc. diff --git a/doc/elementary/genlist.rst b/doc/elementary/genlist.rst index e6cb8d0..1d1b482 100644 --- a/doc/elementary/genlist.rst +++ b/doc/elementary/genlist.rst @@ -348,6 +348,7 @@ Emitted signals - ``item,unfocused`` - When the genlist item has lost focus. (since 1.10) - ``changed`` - Genlist is now changed their items and properties and all calculation is finished. (since 1.16) +- ``filter,done`` - Genlist filter operation is completed.. (since 1.17) Enumerations diff --git a/efl/elementary/genlist.pxi b/efl/elementary/genlist.pxi index 71935a0..d395297 100644 --- a/efl/elementary/genlist.pxi +++ b/efl/elementary/genlist.pxi @@ -80,6 +80,24 @@ cdef Eina_Bool _py_elm_genlist_item_state_get(void *data, Evas_Object *obj, cons return ret if ret is not None else 0 +cdef Eina_Bool _py_elm_genlist_item_filter_get(void *data, Evas_Object *obj, void *key) with gil: + cdef: + GenlistItem item = <GenlistItem>data + object pykey = <object>key + + func = item.item_class._filter_get_func + if func is None: + return 1 + + try: + o = object_from_instance(obj) + ret = func(o, pykey, item.item_data) + except Exception: + traceback.print_exc() + return 0 + + return 1 if ret else 0 + cdef void _py_elm_genlist_object_item_del(void *data, Evas_Object *obj) with gil: cdef GenlistItem item = <GenlistItem>data diff --git a/efl/elementary/genlist_cdef.pxi b/efl/elementary/genlist_cdef.pxi index c990620..89779d3 100644 --- a/efl/elementary/genlist_cdef.pxi +++ b/efl/elementary/genlist_cdef.pxi @@ -64,12 +64,14 @@ cdef extern from "Elementary.h": 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 struct Elm_Genlist_Item_Class_Func: GenlistItemLabelGetFunc text_get GenlistItemIconGetFunc content_get GenlistItemStateGetFunc state_get + GenlistItemFilterGetFunc filter_get GenlistItemDelFunc del_ "del" ctypedef struct Elm_Genlist_Item_Class: @@ -155,3 +157,4 @@ cdef extern from "Elementary.h": Elm_Object_Item * elm_genlist_nth_item_get(const Evas_Object *obj, unsigned int nth) void elm_genlist_focus_on_selection_set(Evas_Object *obj, Eina_Bool enabled) Eina_Bool elm_genlist_focus_on_selection_get(const Evas_Object *obj) + void elm_genlist_filter_set(Evas_Object *obj, void *key) diff --git a/efl/elementary/genlist_item_class.pxi b/efl/elementary/genlist_item_class.pxi index 06546ba..68875d3 100644 --- a/efl/elementary/genlist_item_class.pxi +++ b/efl/elementary/genlist_item_class.pxi @@ -19,6 +19,7 @@ cdef class GenlistItemClass(object): object _text_get_func object _content_get_func object _state_get_func + object _filter_get_func object _del_func object _item_style object _decorate_item_style @@ -29,6 +30,7 @@ cdef class GenlistItemClass(object): 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.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 self.cls.func.del_ = _py_elm_genlist_object_item_del @@ -39,7 +41,7 @@ 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, - *args, **kwargs): + filter_get_func=None, *args, **kwargs): """GenlistItemClass constructor. @@ -106,6 +108,14 @@ cdef class GenlistItemClass(object): else: self._state_get_func = self.state_get + if filter_get_func is not None: + if callable(filter_get_func): + self._filter_get_func = filter_get_func + else: + raise TypeError("filter_get_func is not callable!") + else: + self._filter_get_func = self.filter_get + if del_func is not None: if callable(del_func): self._del_func = del_func @@ -136,7 +146,7 @@ cdef class GenlistItemClass(object): def __repr__(self): return ("<%s(%#x, refcount=%d, Elm_Genlist_Item_Class=%#x, " "item_style=%r, text_get_func=%s, content_get_func=%s, " - "state_get_func=%s, del_func=%s)>") % \ + "state_get_func=%s, filter_get_func=%s, del_func=%s)>") % \ (type(self).__name__, <uintptr_t><void *>self, PY_REFCOUNT(self), @@ -145,6 +155,7 @@ cdef class GenlistItemClass(object): self._text_get_func, self._content_get_func, self._state_get_func, + self._filter_get_func, self._del_func) def ref(self): @@ -237,3 +248,15 @@ cdef class GenlistItemClass(object): """ return False + def filter_get(self, evasObject obj, key, item_data): + """To be called by Genlist for each row when filter is enabled. + + :param obj: the Genlist instance + :param key: the filter key given in the filter_set function + :param item_data: the value given to genlist append/prepend. + + :return: Wheter the item should be visible or not + :rtype: bool + """ + return True + diff --git a/efl/elementary/genlist_widget.pxi b/efl/elementary/genlist_widget.pxi index 6961255..416678b 100644 --- a/efl/elementary/genlist_widget.pxi +++ b/efl/elementary/genlist_widget.pxi @@ -685,7 +685,6 @@ cdef class Genlist(Object): <const char *>pattern if pattern is not None else NULL, flags)) - property focus_on_selection: """ @@ -709,6 +708,33 @@ cdef class Genlist(Object): def __get__(self): return bool(elm_genlist_focus_on_selection_get(self.obj)) + property filter: + """ Set filter mode with key. + + This initiates the filter mode of genlist with user/application + provided key. If key is None, the filter mode is turned off. + + The given key will be passed back in the filter_get function of + the GenlistItemClass + + :type: any python object + + .. versionadded:: 1.17 + + """ + def __set__(self, object key): + self.data['__filterkeyref'] = key # keep a reference for key + elm_genlist_filter_set(self.obj, <void *>key if key is not None else NULL) + + def __get__(self): + return self.data['__filterkeyref'] + + def filter_set(self, key): + self.data['__filterkeyref'] = key + elm_genlist_filter_set(self.obj, <void*>key if key is not None else NULL) + def filter_get(self): + return self.data['__filterkeyref'] + # # Drag and Drop # ============= @@ -1070,6 +1096,16 @@ cdef class Genlist(Object): def callback_changed_del(self, func): self._callback_del("changed", func) + def callback_filter_done_add(self, func, *args, **kwargs): + """Genlist filter operation is completed. + + .. versionadded:: 1.17 + """ + self._callback_add("filter,done", func, args, kwargs) + + def callback_filter_done_del(self, func): + self._callback_del("filter,done", func) + property scroller_policy: """ diff --git a/examples/elementary/test_genlist_filter.py b/examples/elementary/test_genlist_filter.py new file mode 100644 index 0000000..7b35491 --- /dev/null +++ b/examples/elementary/test_genlist_filter.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# encoding: utf-8 + +import os + +from efl.evas import EXPAND_BOTH, FILL_BOTH, EXPAND_HORIZ, FILL_HORIZ + +from efl import elementary as elm +from efl.elementary import StandardWindow, Box, Entry, Genlist, GenlistItemClass + + +names = [ + "Aaliyah", "Aamir", "Aaralyn", "Aaron", "Abagail", + "Babitha", "Bahuratna", "Bandana", "Bulbul", "Cade", "Caldwell", + "Chandan", "Caster", "Dagan", "Daulat", "Dag", "Earl", "Ebenzer", + "Ellison", "Elizabeth", "Filbert", "Fitzpatrick", "Florian", "Fulton", + "Frazer", "Gabriel", "Gage", "Galen", "Garland", "Gauhar", "Hadden", + "Hafiz", "Hakon", "Haleem", "Hank", "Hanuman", "Jabali", "Jaimini", + "Jayadev", "Jake", "Jayatsena", "Jonathan", "Kamaal", "Jeirk", + "Jasper", "Jack", "Mac", "Macy", "Marlon", "Milson" +] + + +# item class functions +def gl_text_get(obj, part, item_data): + return item_data + +def gl_filter_get(obj, key, item_data): + print('"%s" -> "%s"' % (item_data, key)) + if not key: + return True + if key.lower() in item_data.lower(): + return True + return False + + +def entry_changed_cb(en, gl): + gl.filter = en.text or None + + +def test_genlist_filter(parent): + win = StandardWindow("genlist-filter", "Genlist Filter", autodel=True, + size=(420, 600), focus_highlight_enabled=True) + + # main vertical box + box = Box(win, size_hint_expand=EXPAND_BOTH) + win.resize_object_add(box) + box.show() + + + # the Genlist widget + gl = Genlist(win, mode=elm.ELM_LIST_COMPRESS, homogeneous=True, + select_mode=elm.ELM_OBJECT_SELECT_MODE_ALWAYS, + size_hint_expand=EXPAND_BOTH, size_hint_fill=FILL_BOTH) + gl.callback_filter_done_add(lambda g: print("filter,done")) + gl.show() + box.pack_end(gl) + + itc = GenlistItemClass(item_style="default", + text_get_func=gl_text_get, + filter_get_func=gl_filter_get) + + for i in range(500): + gl.item_append(itc, names[i % len(names)]) + + + # the entry + en = Entry(box, single_line=True, + size_hint_expand=EXPAND_HORIZ, size_hint_fill=FILL_HORIZ) + en.part_text_set('guide', 'Type here to filter items') + en.callback_changed_user_add(entry_changed_cb, gl) + box.pack_start(en) + en.show() + + + # + win.show() + en.focus = True + + +if __name__ == "__main__": + elm.policy_set(elm.ELM_POLICY_QUIT, elm.ELM_POLICY_QUIT_LAST_WINDOW_CLOSED) + test_genlist_filter(None) + elm.run() --