Python-EFL: implemented decorators for edje.

Decorators implemented in a much more simple and generic
way than before, we can use them in other place too.

3 deco implemented:
@on_signal(emission, source)
@message_handler
@on_text_change

I choosed the 'strange' on_* naming convention to not
clash/confuse with normal callback functions, tell
me if you don't like.
This commit is contained in:
Davide Andreoli 2013-05-14 21:51:29 +02:00
parent 236d66caf8
commit 5913721de9
8 changed files with 130 additions and 35 deletions

1
TODO
View File

@ -54,7 +54,6 @@ STUFF LEFT OUT
* python-evas/evas/decorators.py
* python-evas/evas/debug.py
* python-evas old hack to rotate objects
* edje decorators callbacks
CHANGES FROM 1.7 to 1.8

View File

@ -21,8 +21,9 @@ import warnings
from cpython cimport PyMem_Malloc, PyMem_Free, PyUnicode_AsUTF8String
cimport libc.stdlib
from efl.eo cimport _object_mapping_register, object_from_instance
from efl.eo cimport _ctouni, _touni, convert_eina_list_strings_to_python_list
from efl.eo cimport _object_mapping_register, object_from_instance, \
_register_decorated_callbacks, _ctouni, _touni, \
convert_eina_list_strings_to_python_list
# Edje_Message_Type:
@ -318,36 +319,6 @@ def module_load(name):
return bool(edje_module_load(
<const_char *>name if name is not None else NULL))
# class EdjeObjectMeta(evas.c_evas.EvasObjectMeta):
# def __init__(cls, name, bases, dict_):
# evas.c_evas.EvasObjectMeta.__init__(cls, name, bases, dict_)
# cls._fetch_callbacks()
#
# def _fetch_callbacks(cls):
# if "__edje_signal_callbacks__" in cls.__dict__:
# return
#
# cls.__edje_signal_callbacks__ = []
# cls.__edje_message_callbacks__ = []
# cls.__edje_text_callbacks__ = []
#
# sig_append = cls.__edje_signal_callbacks__.append
# msg_append = cls.__edje_message_callbacks__.append
# txt_append = cls.__edje_text_callbacks__.append
#
# for name in dir(cls):
# val = getattr(cls, name)
# if not callable(val):
# continue
#
# if hasattr(val, "edje_signal_callback"):
# sig_data = getattr(val, "edje_signal_callback")
# sig_append((name, sig_data))
# elif hasattr(val, "edje_message_handler"):
# msg_append(name)
# elif hasattr(val, "edje_text_change_callback"):
# txt_append(name)
include "efl.edje_message.pxi"
include "efl.edje_external.pxi"

View File

@ -15,6 +15,7 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
cdef void text_change_cb(void *data,
Evas_Object *obj,
const_char *part) with gil:
@ -127,6 +128,7 @@ cdef class Edje(Object):
def __init__(self, Canvas canvas not None, **kargs):
self._set_obj(edje_object_add(canvas.obj))
_register_decorated_callbacks(self)
self._set_common_params(**kargs)
def __free_wrapper_resources(self, ed):
@ -1206,4 +1208,26 @@ cdef class Edje(Object):
<const_char *>source if source is not None else NULL)
# decorators
def on_signal(emission, source):
def decorator(func):
if not hasattr(func, "__decorated_callbacks__"):
func.__decorated_callbacks__ = list()
func.__decorated_callbacks__.append(("signal_callback_add", emission, source, func))
return func
return decorator
def message_handler(func):
if not hasattr(func, "__decorated_callbacks__"):
func.__decorated_callbacks__ = list()
func.__decorated_callbacks__.append(("message_handler_set", func))
return func
def on_text_change(func):
if not hasattr(func, "__decorated_callbacks__"):
func.__decorated_callbacks__ = list()
func.__decorated_callbacks__.append(("text_change_cb_set", func))
return func
_object_mapping_register("edje", Edje)

View File

@ -233,6 +233,22 @@ cdef object object_from_instance(cEo *obj):
return o
cdef void _register_decorated_callbacks(object obj):
""" Serach every attrib of the pyobj for a __decorated_callbacks__ object,
a list actually. If found then exec the functions listed there, with their
arguments. Must be called just after the _set_obj call.
List items signature: ("function_name", *args)
"""
cdef object attr_name, attrib, func_name, func
for attr_name in dir(obj):
attrib = getattr(obj, attr_name)
if hasattr(attrib, "__decorated_callbacks__"):
for (func_name, *args) in getattr(attrib, "__decorated_callbacks__"):
func = getattr(obj, func_name)
func(*args)
######################################################################

View File

@ -16,7 +16,6 @@
# along with this Python-EFL. If not, see <http://www.gnu.org/licenses/>.
from efl.c_eo cimport Eo as cEo
from efl.c_eo cimport Eo_Class
from efl cimport Eina_List, const_Eina_List
from libc.string cimport const_char
@ -35,6 +34,8 @@ cdef object object_from_instance(cEo *obj)
cdef void _object_mapping_register(char *name, object cls) except *
cdef void _object_mapping_unregister(char *name)
cdef void _register_decorated_callbacks(object obj)
cdef unicode _touni(char* s)
cdef unicode _ctouni(const_char *s)

View File

@ -0,0 +1,84 @@
#!/usr/bin/env python
from efl import evas
from efl import ecore
from efl import edje
from efl.edje import Edje
import os, unittest
theme_file = os.path.join(os.path.dirname(__file__), "theme.edj")
expected_signals = ["edje,state,ltr", "load", "edje,state,ltr", "resize",
"cursor,changed", "changed", "zoom,stop", "emit,message",
"emit,message"]
expected_signals2 = ["load", "resize"]
expected_messages = [33, 33]
expected_text_parts = ["label", "label"]
class MyEdje(Edje):
def __init__(self, canvas):
Edje.__init__(self, canvas, file=theme_file, group="main")
@edje.on_signal("*", "*")
def cb_signal_all(self, emission, source):
expected_signals.remove(emission)
@edje.on_signal("load", "*")
@edje.on_signal("resize", "*")
def cb_signal_load_resize(self, emission, source):
expected_signals2.remove(emission)
@edje.message_handler
def message_handler(self, msg):
expected_messages.remove(msg.val)
@edje.on_text_change
def text_change(self, part):
expected_text_parts.remove(part)
class TestEdjeDecoratedCallbacks(unittest.TestCase):
def setUp(self):
self.canvas = evas.Canvas(method="buffer",
size=(400, 500),
viewport=(0, 0, 400, 500))
self.canvas.engine_info_set(self.canvas.engine_info_get())
def tearDown(self):
self.canvas.delete()
def testDecorators(self):
o = MyEdje(self.canvas)
self.assertIsInstance(o, Edje)
# this should trigger text_change, two times
ecore.Timer(0.1, lambda: o.part_text_set("label", "asd"))
ecore.Timer(0.1, lambda: o.part_text_set("label", "asd2"))
# ask the edje obj to send a messagge, two times
ecore.Timer(0.1, lambda: o.signal_emit("emit,message", ""))
ecore.Timer(0.1, lambda: o.signal_emit("emit,message", ""))
# and then quit the main loop
ecore.Timer(0.2, lambda: ecore.main_loop_quit())
ecore.main_loop_begin()
self.assertEqual(expected_signals, [])
self.assertEqual(expected_signals2, [])
self.assertEqual(expected_messages, [])
self.assertEqual(expected_text_parts, [])
o.delete()
self.assertTrue(o.is_deleted())
if __name__ == '__main__':
unittest.main(verbosity=2)
edje.shutdown()
ecore.shutdown()
evas.shutdown()

View File

@ -534,7 +534,7 @@ collections {
program { name: "emit_back_message";
signal: "emit,message";
script {
send_message(MSG_INT, 1, 1);
send_message(MSG_INT, 1, 33);
}
}
program { name: "prog1";

Binary file not shown.