Implemented Genlist filter ability

It is somehow not perfectly working, see TODO for more info
This commit is contained in:
Davide Andreoli 2016-01-20 22:55:43 +01:00
parent 90595ffdca
commit 005dd26f73
7 changed files with 170 additions and 5 deletions

4
TODO
View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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:
"""

View File

@ -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()