# Copyright (C) 2007-2013 various contributors (see AUTHORS)
#
# This file is part of Python-EFL.
#
# Python-EFL is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# Python-EFL is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this Python-EFL. If not, see .
# cdef int _canvas_free_wrapper_resources(Canvas canvas) except 0:
# cdef int i
# for i from 0 <= i < evas_canvas_event_callbacks_len:
# canvas._callbacks[i] = None
# return 1
#
#
cdef int _canvas_unregister_callbacks(Canvas canvas) except 0:
cdef Evas *e
cdef Evas_Event_Cb cb
e = canvas.obj
if e != NULL:
for i, lst in enumerate(canvas._callbacks):
if lst is not None:
cb = evas_canvas_event_callbacks[i]
evas_event_callback_del(e, i, cb)
return 1
cdef _canvas_add_callback_to_list(Canvas canvas, int type, func, args, kargs):
if type < 0 or type >= evas_canvas_event_callbacks_len:
raise ValueError("Invalid callback type")
r = (func, args, kargs)
lst = canvas._callbacks[type]
if lst is not None:
lst.append(r)
return False
else:
canvas._callbacks[type] = [r]
return True
cdef _canvas_del_callback_from_list(Canvas canvas, int type, func):
if type < 0 or type >= evas_canvas_event_callbacks_len:
raise ValueError("Invalid callback type")
lst = canvas._callbacks[type]
if not lst:
raise ValueError("Callback %s was not registered with type %d" %
(func, type))
i = None
for i, r in enumerate(lst):
if func == r[0]:
break
else:
raise ValueError("Callback %s was not registered with type %d" %
(func, type))
lst.pop(i)
if len(lst) == 0:
canvas._callbacks[type] = None
return True
else:
return False
cdef class Canvas(Eo):
""" The Evas Canvas.
Canvas is the base drawing area and scene manager, it should have
a number of objects (or actors) that will be managed. Object state
is monitored and redraw is optimized based on changes.
:ivar rect: :py:class:`efl.evas.Rect` describing object geometry, for
easy manipulation. Changing this :py:class:`evas.rect.Rect` will not
affect current geometry, you have to set it again to have this
behavior.
.. attention:: Canvas must be associated with an Input/Output system in
order to be functional. So far it's impossible to do this
association directly from Python, so you should create Canvas
indirectly using ``efl.elementary`` classes, like
:py:class:`efl.elementary.Window`.
"""
def __cinit__(self, *a, **ka):
self._callbacks = [None] * evas_canvas_event_callbacks_len
def __init__(self, method=None, size=None, viewport=None):
self._set_obj(evas_new())
if method:
self.output_method_set(method)
if size:
self.size_set(*size)
if viewport:
self.viewport_set(*viewport)
def __dealloc__(self):
if self.obj != NULL:
_canvas_unregister_callbacks(self)
self._callbacks = None
def __str__(self):
return ("%s Canvas(size=%s, method=%r)") % (Eo.__repr__(self),
self.size_get(), self.output_method_get())
def __repr__(self):
return ("%s Canvas(size=%s, method=%r)") % (Eo.__repr__(self),
self.size_get(), self.output_method_get())
def delete(self):
evas_free(self.obj)
def output_method_set(self, method):
"""Set canvas render method, can be either a name or id.
:param method: name(str) or id(int) of the method to set
"""
cdef int engine_id
if isinstance(method, (int, long)):
engine_id = method
elif isinstance(method, str):
engine_id = evas_render_method_lookup(_cfruni(method))
else:
raise TypeError("method must be integer or string")
evas_output_method_set(self.obj, engine_id)
def output_method_get(self):
return evas_output_method_get(self.obj)
property output_method:
def __set__(self, method):
self.output_method_set(method)
def __get__(self):
return self.output_method_get()
def engine_info_set(self, unsigned long ptr):
"""Set the engine information pointer.
Note that given value is a pointer, usually acquired with
:py:func:`engine_info_get() and is totally engine and platform
dependent.
This call is very low level and is meant for extension to use,
they usually do the machinery in C and just handle pointers as
integers.
If in doubt, don't mess with it.
"""
evas_engine_info_set(self.obj, ptr)
def engine_info_get(self):
"""Get the engine information pointer.
Note that given value is a pointer and is totally engine and
platform dependent.
This call is very low level and is meant for extension to use,
they usually do the machinery in C and just handle pointers as
integers.
If in doubt, don't mess with it.
:return: pointer as integer (unsigned long).
"""
return evas_engine_info_get(self.obj)
property engine_info:
def __set__(self, ptr):
self.engine_info_set(ptr)
def __get__(self):
return self.engine_info_get()
def size_set(self, int w, int h):
"""Set canvas size.
:param w:
:param h:
"""
evas_output_size_set(self.obj, w, h)
def size_get(self):
""":return: the tuple of int: (w, h)"""
cdef int w, h
evas_output_size_get(self.obj, &w, &h)
return (w, h)
property size:
def __set__(self, spec):
self.size_set(*spec)
def __get__(self):
return self.size_get()
property rect:
def __set__(self, spec):
cdef Rect r
r = Rect(spec)
self.size_set(r.w, r.h)
def __get__(self):
cdef int w, h
w, h = self.size_get()
return Rect(0, 0, w, h)
def viewport_set(self, int x, int y, int w, int h):
"""Sets the output viewport of the given evas in evas units.
:param x:
:param y:
:param w:
:param h:
The output viewport is the area of the evas that will be visible to
the viewer. The viewport will be stretched to fit the output target
of the evas when rendering is performed.
.. note:: The coordinate values do not have to map 1-to-1 with the
output target. However, it is generally advised that it is done
for ease of use.
"""
evas_output_viewport_set(self.obj, x, y, w, h)
def viewport_get(self):
""":return: the tuple of int: (x, y, w, h)"""
cdef int x, y, w, h
evas_output_viewport_get(self.obj, &x, &y, &w, &h)
return (x, y, w, h)
property viewport:
def __set__(self, spec):
self.viewport_set(*spec)
def __get__(self):
return self.viewport_get()
def coord_screen_x_to_world(self, int x):
""":rtype: int"""
return evas_coord_screen_x_to_world(self.obj, x)
def coord_screen_y_to_world(self, int y):
""":rtype: int"""
return evas_coord_screen_y_to_world(self.obj, y)
def coord_world_x_to_screen(self, int x):
""":rtype: int"""
return evas_coord_world_x_to_screen(self.obj, x)
def coord_world_y_to_screen(self, int y):
""":rtype: int"""
return evas_coord_world_y_to_screen(self.obj, y)
def pointer_output_xy_get(self):
"""Returns the pointer's (x, y) relative to output."""
cdef int x, y
evas_pointer_output_xy_get(self.obj, &x, &y)
return (x, y)
property pointer_output_xy:
def __get__(self):
return self.pointer_output_xy_get()
def pointer_canvas_xy_get(self):
"""Returns the pointer's (x, y) relative to canvas."""
cdef int x, y
evas_pointer_canvas_xy_get(self.obj, &x, &y)
return (x, y)
property pointer_canvas_xy:
def __get__(self):
return self.pointer_canvas_xy_get()
def pointer_button_down_mask_get(self):
"""Returns a bitmask with the mouse buttons currently pressed set to 1.
The least significant bit corresponds to the first mouse button
(button 1) and the most significant bit corresponds to the last mouse
button (button 32).
:rtype: int
"""
return evas_pointer_button_down_mask_get(self.obj)
property pointer_button_down_mask:
def __get__(self):
return self.pointer_button_down_mask_get()
def pointer_inside_get(self):
"""Returns whether the mouse pointer is logically inside the canvas.
:rtype: bool
"""
return bool(evas_pointer_inside_get(self.obj))
property pointer_inside:
def __get__(self):
return self.pointer_inside_get()
def top_at_xy_get(self, int x, int y,
include_pass_events_objects=False,
include_hidden_objects=False):
"""Get the topmost object at (x, y).
:param x:
:param y:
:param include_pass_events_objects: if to include objects passing events.
:param include_hidden_objects: if to include hidden objects.
:return: child object.
:rtype: :py:class:`efl.evas.Object`
"""
cdef int ip, ih
cdef Evas_Object *o
ip = include_pass_events_objects
ih = include_hidden_objects
o = evas_object_top_at_xy_get(self.obj, x, y, ip, ih)
return object_from_instance(o)
def top_at_pointer_get(self):
"""Get the topmost object at pointer position.
:return: child object.
:rtype: :py:class:`efl.evas.Object`
"""
cdef Evas_Object *o
o = evas_object_top_at_pointer_get(self.obj)
return object_from_instance(o)
def top_in_rectangle_get(self, int x, int y, int w, int h,
include_pass_events_objects=False,
include_hidden_objects=False):
"""Get the topmost object at given geometry.
:param x:
:param y:
:param w:
:param h:
:param include_pass_events_objects: if to include objects passing events.
:param include_hidden_objects: if to include hidden objects.
:return: child object.
:rtype: :py:class:`efl.evas.Object`
"""
cdef int ip, ih
cdef Evas_Object *o
ip = include_pass_events_objects
ih = include_hidden_objects
o = evas_object_top_in_rectangle_get(self.obj, x, y, w, h, ip, ih)
return object_from_instance(o)
def objects_at_xy_get(self, int x, int y,
include_pass_events_objects=False,
include_hidden_objects=False):
"""Get all children at (x, y).
:param x:
:param y:
:param include_pass_events_objects: if to include objects passing events.
:param include_hidden_objects: if to include hidden objects.
:return: children objects.
:rtype: List of :py:class:`efl.evas.Object`
"""
cdef Eina_List *objs, *itr
cdef int ip, ih
cdef Evas_Object *o
ip = include_pass_events_objects
ih = include_hidden_objects
objs = evas_objects_at_xy_get(self.obj, x, y, ip, ih)
lst = []
itr = objs
while itr != NULL:
o = itr.data
lst.append(object_from_instance(o))
itr = itr.next
eina_list_free(objs)
return lst
def objects_in_rectangle_get(self, int x, int y, int w, int h,
include_pass_events_objects=False,
include_hidden_objects=False):
"""Get all children at given geometry.
:param x:
:param y:
:param w:
:param h:
:param include_pass_events_objects: if to include objects passing events.
:param include_hidden_objects: if to include hidden objects.
:return: children objects.
:rtype: List of :py:class:`efl.evas.Object`
"""
cdef Eina_List *objs, *itr
cdef int ip, ih
cdef Evas_Object *o
ip = include_pass_events_objects
ih = include_hidden_objects
objs = evas_objects_in_rectangle_get(self.obj, x, y, w, h, ip, ih)
lst = []
itr = objs
while itr != NULL:
o = itr.data
lst.append(object_from_instance(o))
itr = itr.next
eina_list_free(objs)
return lst
def damage_rectangle_add(self, int x, int y, int w, int h):
evas_damage_rectangle_add(self.obj, x, y, w, h)
def obscured_rectangle_add(self, int x, int y, int w, int h):
evas_obscured_rectangle_add(self.obj, x, y, w, h)
def obscured_clear(self):
evas_obscured_clear(self.obj)
def render_updates(self):
cdef Eina_List *lst
lst = evas_render_updates(self.obj)
evas_render_updates_free(lst)
def render(self):
"""Force canvas to redraw pending updates."""
evas_render(self.obj)
def norender(self):
evas_norender(self.obj)
def top_get(self):
""":rtype: :py:class:`efl.evas.Object`"""
return object_from_instance(evas_object_top_get(self.obj))
property top:
def __get__(self):
return object_from_instance(evas_object_top_get(self.obj))
def bottom_get(self):
""":rtype: :py:class:`efl.evas.Object`"""
return object_from_instance(evas_object_bottom_get(self.obj))
property bottom:
def __get__(self):
return object_from_instance(evas_object_bottom_get(self.obj))
def focus_get(self):
""":rtype: :py:class:`efl.evas.Object`"""
return object_from_instance(evas_focus_get(self.obj))
property focus:
def __get__(self):
return object_from_instance(evas_focus_get(self.obj))
def object_name_find(self, name):
"""Find object by name.
:param name:
:rtype: :py:class:`efl.evas.Object`
"""
return object_from_instance(evas_object_name_find(self.obj, _cfruni(name)))
def image_cache_flush(self):
evas_image_cache_flush(self.obj)
def image_cache_reload(self):
evas_image_cache_reload(self.obj)
def image_cache_set(self, int size):
evas_image_cache_set(self.obj, size)
def image_cache_get(self):
""":rtype: int"""
return evas_image_cache_get(self.obj)
property image_cache:
def __get__(self):
return self.image_cache_get()
def __set__(self, int value):
self.image_cache_set(value)
def font_cache_flush(self):
evas_font_cache_flush(self.obj)
def font_cache_get(self):
""":rtype: int"""
return evas_font_cache_get(self.obj)
def font_cache_set(self, int value):
evas_font_cache_set(self.obj, value)
property font_cache:
def __get__(self):
return self.font_cache_get()
def __set__(self, int value):
self.font_cache_set(value)
def font_path_clear(self):
evas_font_path_clear(self.obj)
def font_path_append(self, path):
evas_font_path_append(self.obj, _cfruni(path))
def font_path_prepend(self, path):
evas_font_path_prepend(self.obj, _cfruni(path))
def font_path_list(self):
""":rtype: list of str"""
cdef const_Eina_List *itr
lst = []
itr = evas_font_path_list(self.obj)
while itr != NULL:
lst.append(itr.data)
itr = itr.next
return lst
def font_available_list(self):
""":rtype: list of str"""
cdef void *p
cdef Eina_List *itr, *head
lst = []
p = evas_font_available_list(self.obj) # avoid warning
head = p
itr = head
while itr != NULL:
lst.append(itr.data)
itr = itr.next
evas_font_available_list_free(self.obj, head)
return lst
def font_hinting_can_hint(self, int flags):
""":rtype: bool"""
return bool(evas_font_hinting_can_hint(self.obj,
flags))
def font_hinting_set(self, int flags):
""":param flags: one of EVAS_FONT_HINTING_NONE,
EVAS_FONT_HINTING_AUTO or EVAS_FONT_HINTING_BYTECODE
"""
evas_font_hinting_set(self.obj, flags)
def font_hinting_get(self):
""":rtype: int"""
return evas_font_hinting_get(self.obj)
property font_hinting:
def __get__(self):
return self.font_hinting_get()
def __set__(self, int value):
self.font_hinting_set(value)
def freeze(self):
"""Freeze event processing"""
evas_event_freeze(self.obj)
def thaw(self):
"""Thaw (unfreeze) event processing"""
evas_event_thaw(self.obj)
def freeze_get(self):
""":rtype: int"""
return evas_event_freeze_get(self.obj)
def key_modifier_is_set(self, modifier):
""":rtype: bool"""
return bool(evas_key_modifier_is_set(evas_key_modifier_get(self.obj),
modifier))
def event_callback_add(self, Evas_Callback_Type type, func, *args, **kargs):
"""Add a new callback for the given event.
:param type: an integer with event type code, like
*EVAS_CALLBACK_CANVAS_FOCUS_IN*,
*EVAS_CALLBACK_RENDER_FLUSH_PRE* and other
*EVAS_CALLBACK_* constants.
:param func: function to call back, this function will have one of
the following signatures::
function(object, event, *args, **kargs)
function(object, *args, **kargs)
The former is used by events that provide more data
(none so far), while the second is used by events
without. Parameters given at the end of
*event_callback_add()* will be given to the callback.
Note that the object passed to the callback in **event**
parameter will only be valid during the callback, using
it after callback returns will raise an ValueError.
:raise ValueError: if **type** is unknown.
:raise TypeError: if **func** is not callable.
"""
cdef Evas_Event_Cb cb
if not callable(func):
raise TypeError("func must be callable")
if _canvas_add_callback_to_list(self, type, func, args, kargs):
cb = evas_canvas_event_callbacks[type]
evas_event_callback_add(self.obj, type, cb, self)
def event_callback_del(self, Evas_Callback_Type type, func):
"""Remove callback for the given event.
:param type: an integer with event type code.
:param func: function used with :py:func:`event_callback_add()`.
:precond: **type** and **func** must be used as parameter for
:py:func:`event_callback_add()`.
:raise ValueError: if **type** is unknown or if there was no
**func** connected with this type.
"""
cdef Evas_Event_Cb cb
if _canvas_del_callback_from_list(self, type, func):
cb = evas_canvas_event_callbacks[type]
evas_event_callback_del(self.obj, type, cb)
def on_canvas_focus_in_add(self, func, *a, **k):
"""Same as event_callback_add(EVAS_CALLBACK_CANVAS_FOCUS_IN, ...)
Expected signature::
function(object, *args, **kargs)
"""
self.event_callback_add(EVAS_CALLBACK_CANVAS_FOCUS_IN, func, *a, **k)
def on_canvas_focus_in_del(self, func):
"""Same as event_callback_del(EVAS_CALLBACK_CANVAS_FOCUS_IN, ...)"""
self.event_callback_del(EVAS_CALLBACK_CANVAS_FOCUS_IN, func)
def on_canvas_focus_out_add(self, func, *a, **k):
"""Same as event_callback_add(EVAS_CALLBACK_CANVAS_FOCUS_OUT, ...)
Expected signature::
function(object, *args, **kargs)
"""
self.event_callback_add(EVAS_CALLBACK_CANVAS_FOCUS_OUT, func, *a, **k)
def on_canvas_focus_out_del(self, func):
"""Same as event_callback_del(EVAS_CALLBACK_CANVAS_FOCUS_OUT, ...)"""
self.event_callback_del(EVAS_CALLBACK_CANVAS_FOCUS_OUT, func)
def on_render_flush_pre_add(self, func, *a, **k):
"""Same as event_callback_add(EVAS_CALLBACK_RENDER_FLUSH_PRE, ...)
Expected signature::
function(object, *args, **kargs)
"""
self.event_callback_add(EVAS_CALLBACK_RENDER_FLUSH_PRE, func, *a, **k)
def on_render_flush_pre_del(self, func):
"""Same as event_callback_del(EVAS_CALLBACK_RENDER_FLUSH_PRE, ...)"""
self.event_callback_del(EVAS_CALLBACK_RENDER_FLUSH_PRE, func)
def on_render_flush_post_add(self, func, *a, **k):
"""Same as event_callback_add(EVAS_CALLBACK_RENDER_FLUSH_POST, ...)
Expected signature::
function(object, *args, **kargs)
"""
self.event_callback_add(EVAS_CALLBACK_RENDER_FLUSH_POST, func, *a, **k)
def on_render_flush_post_del(self, func):
"""Same as event_callback_del(EVAS_CALLBACK_RENDER_FLUSH_POST, ...)"""
self.event_callback_del(EVAS_CALLBACK_RENDER_FLUSH_POST, func)
# Event feeding
def feed_mouse_down(self, int b, Evas_Button_Flags flags,
unsigned int timestamp):
""" Emit a mouse_down event in the canvas """
evas_event_feed_mouse_down(self.obj, b, flags, timestamp, NULL)
def feed_mouse_up(self, int b, Evas_Button_Flags flags,
unsigned int timestamp):
""" Emit a mouse_up event in the canvas """
evas_event_feed_mouse_up(self.obj, b, flags, timestamp, NULL)
def feed_mouse_cancel(self, unsigned int timestamp):
""" Emit a mouse_cancel event in the canvas """
evas_event_feed_mouse_cancel(self.obj, timestamp, NULL)
def feed_mouse_wheel(self, int direction, int z, unsigned int timestamp):
""" Emit a mouse_wheel event in the canvas """
evas_event_feed_mouse_wheel(self.obj, direction, z, timestamp, NULL)
def feed_mouse_move(self, int x, int y, unsigned int timestamp):
""" Emit a mouse_move event in the canvas """
evas_event_feed_mouse_move(self.obj, x, y, timestamp, NULL)
def feed_mouse_in(self, unsigned int timestamp):
""" Emit a mouse_in event in the canvas """
evas_event_feed_mouse_in(self.obj, timestamp, NULL)
def feed_mouse_out(self, unsigned int timestamp):
""" Emit a mouse_out event in the canvas """
evas_event_feed_mouse_out(self.obj, timestamp, NULL)
def feed_multi_down(self, int d, int x, int y,
double rad, double radx, double rady,
double pres, double ang,
double fx, double fy,
Evas_Button_Flags flags,
unsigned int timestamp):
""" Emit a multi_down event in the canvas """
evas_event_feed_multi_down(self.obj, d, x, y, rad, radx, rady, pres,
ang, fx, fy, flags, timestamp, NULL)
def feed_multi_up(self, int d, int x, int y,
double rad, double radx, double rady,
double pres, double ang,
double fx, double fy,
Evas_Button_Flags flags,
unsigned int timestamp):
""" Emit a multi_up event in the canvas """
evas_event_feed_multi_up(self.obj, d, x, y, rad, radx, rady, pres,
ang, fx, fy, flags, timestamp, NULL)
def feed_multi_move(self, int d, int x, int y,
double rad, double radx, double rady,
double pres, double ang,
double fx, double fy,
unsigned int timestamp):
""" Emit a multi_move event in the canvas """
evas_event_feed_multi_move(self.obj, d, x, y, rad, radx, rady, pres,
ang, fx, fy, timestamp, NULL)
def feed_key_down(self, char *keyname, char *key, char *string,
char *compose, int timestamp):
""" Emit a key_down event in the canvas """
evas_event_feed_key_down(self.obj, keyname, key, string,
compose, timestamp, NULL)
def feed_key_up(self, char *keyname, char *key, char *string,
char *compose, int timestamp):
""" Emit a key_up event in the canvas """
evas_event_feed_key_up(self.obj, keyname, key, string,
compose, timestamp, NULL)
def feed_hold(self, int hold, unsigned int timestamp):
""" Emit a feed_hold event in the canvas """
evas_event_feed_hold(self.obj, hold, timestamp, NULL)
# Factory
def Rectangle(self, **kargs):
"""Factory of :py:class:`efl.evas.Rectangle` associated with this
canvas.
:rtype: :py:class:`efl.evas.Rectangle`
"""
return Rectangle(self, **kargs)
def Line(self, **kargs):
"""Factory of :py:class:`efl.evas.Line` associated with this
canvas.
:rtype: :py:class:`efl.evas.Line`
"""
return Line(self, **kargs)
def Image(self, **kargs):
"""Factory of :py:class:`efl.evas.Image` associated with this
canvas.
:rtype: :py:class:`efl.evas.Image`
"""
return Image(self, **kargs)
def FilledImage(self, **kargs):
"""Factory of :py:class:`efl.evas.FilledImage` associated with this
canvas.
:rtype: :py:class:`efl.evas.FilledImage`
"""
return FilledImage(self, **kargs)
def Polygon(self, **kargs):
"""Factory of :py:class:`efl.evas.Polygon` associated with this
canvas.
:rtype: :py:class:`efl.evas.Polygon`
"""
return Polygon(self, **kargs)
def Text(self, **kargs):
"""Factory of :py:class:`efl.evas.Text` associated with this
canvas.
:rtype: :py:class:`efl.evas.Text`
"""
return Text(self, **kargs)
def Textblock(self, **kargs):
"""Factory of :py:class:`efl.evas.Textblock` associated with this
canvas.
:rtype: :py:class:`efl.evas.Textblock`
"""
return Textblock(self, **kargs)
def Box(self, **kargs):
"""Factory of :py:class:`efl.evas.Box` associated with this
canvas.
:rtype: :py:class:`efl.evas.Box`
"""
return Box(self, **kargs)
_object_mapping_register("Evas", Canvas)