davemds pushed a commit to branch master.

http://git.enlightenment.org/bindings/python/python-efl.git/commit/?id=17df9e69aa34477574f80e1599eca1721a3e6dfd

commit 17df9e69aa34477574f80e1599eca1721a3e6dfd
Author: Dave Andreoli <d...@gurumeditation.it>
Date:   Sun Jan 3 18:50:33 2016 +0100

    Revamp old and broken EthumbClient module
    
    This was not functional at all, so I broke the API "a bit"
---
 doc/ethumb/class-ethumb_client.rst  |   6 +
 doc/ethumb/ethumb.rst               |   1 +
 doc/ethumb/module-ethumb.rst        |  14 +-
 doc/ethumb/module-ethumb_client.rst |   3 +
 efl/ethumb/efl.ethumb.pyx           |  14 +-
 efl/ethumb/efl.ethumb_client.pyx    | 835 ++++++++++++++++++++----------------
 examples/ethumb/ethumb_client.py    | 110 +++++
 include/efl.ethumb_client.pxd       |  52 ++-
 setup.py                            |   5 +-
 9 files changed, 651 insertions(+), 389 deletions(-)

diff --git a/doc/ethumb/class-ethumb_client.rst 
b/doc/ethumb/class-ethumb_client.rst
new file mode 100644
index 0000000..71f4d60
--- /dev/null
+++ b/doc/ethumb/class-ethumb_client.rst
@@ -0,0 +1,6 @@
+.. currentmodule:: efl.ethumb_client
+
+:class:`efl.ethumb_client.EthumbClient` Class
+=============================================
+
+.. autoclass:: efl.ethumb_client.EthumbClient
diff --git a/doc/ethumb/ethumb.rst b/doc/ethumb/ethumb.rst
index 9f33fe0..35e19f8 100644
--- a/doc/ethumb/ethumb.rst
+++ b/doc/ethumb/ethumb.rst
@@ -44,6 +44,7 @@ API Reference
    :titlesonly:
 
    module-ethumb.rst
+   module-ethumb_client.rst
 
 
 Inheritance diagram
diff --git a/doc/ethumb/module-ethumb.rst b/doc/ethumb/module-ethumb.rst
index 2891d11..eb94bea 100644
--- a/doc/ethumb/module-ethumb.rst
+++ b/doc/ethumb/module-ethumb.rst
@@ -1,11 +1,3 @@
-diff --git doc/ethumb/ethumb_module.rst doc/ethumb/ethumb_module.rst
-deleted file mode 100644
-index a7189f9..0000000
---- doc/ethumb/ethumb_module.rst
-+++ /dev/null
-@@ -1,5 +0,0 @@
--:mod:`efl.ethumb` Module
--========================
--
--.. automodule:: efl.ethumb
--   :exclude-members: PyEthumb
+
+.. automodule:: efl.ethumb
+   :exclude-members: Ethumb
diff --git a/doc/ethumb/module-ethumb_client.rst 
b/doc/ethumb/module-ethumb_client.rst
new file mode 100644
index 0000000..81f64c7
--- /dev/null
+++ b/doc/ethumb/module-ethumb_client.rst
@@ -0,0 +1,3 @@
+
+.. automodule:: efl.ethumb_client
+   :exclude-members: EthumbClient
diff --git a/efl/ethumb/efl.ethumb.pyx b/efl/ethumb/efl.ethumb.pyx
index d9f3d5b..6cc6ce8 100644
--- a/efl/ethumb/efl.ethumb.pyx
+++ b/efl/ethumb/efl.ethumb.pyx
@@ -338,7 +338,7 @@ cdef class Ethumb(object):
                 const char *group
                 const char *swallow
             ethumb_frame_get(self.obj, &theme, &group, &swallow)
-            return tuple(_ctouni(theme), _ctouni(group), _ctouni(swallow))
+            return _ctouni(theme), _ctouni(group), _ctouni(swallow)
 
     # destination thumb properties
     property thumb_path:
@@ -412,9 +412,7 @@ cdef class Ethumb(object):
                     <const char *>cat if cat is not None else NULL)
 
         def __get__(self):
-            cdef const char *cat
-            cat = ethumb_thumb_category_get(self.obj)
-            return _ctouni(cat)
+            return _ctouni(ethumb_thumb_category_get(self.obj))
 
     property thumb_fdo:
         """ Set a standard FDO thumbnail size
@@ -441,11 +439,9 @@ cdef class Ethumb(object):
             ethumb_thumb_size_set(self.obj, w, h)
 
         def __get__(self):
-            cdef:
-                int w
-                int h
+            cdef int w, h
             ethumb_thumb_size_get(self.obj, &w, &h)
-            return tuple(w, h)
+            return w, h
 
     property thumb_format:
         """ The fileformat for the thumbnails.
@@ -511,7 +507,7 @@ cdef class Ethumb(object):
                 float x
                 float y
             ethumb_thumb_crop_align_get(self.obj, &x, &y)
-            return tuple(x, y)
+            return x, y
 
     property thumb_quality:
         """ The thumbnail compression quality.
diff --git a/efl/ethumb/efl.ethumb_client.pyx b/efl/ethumb/efl.ethumb_client.pyx
index 569a176..f36132c 100644
--- a/efl/ethumb/efl.ethumb_client.pyx
+++ b/efl/ethumb/efl.ethumb_client.pyx
@@ -14,19 +14,132 @@
 #
 # 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/>.
+"""
 
-from cpython cimport Py_INCREF, Py_DECREF
+:mod:`efl.ethumb_client` Module
+###############################
+
+
+Classes
+=======
+
+.. toctree::
+
+   class-ethumb_client.rst
+
+
+Enumerations
+============
+
+.. _Ethumb_Client_Thumb_FDO_Size:
+
+Ethumb_Thumb_FDO_Size
+---------------------
+
+.. data:: ETHUMB_THUMB_NORMAL
+
+    128x128 as defined by FreeDesktop.Org standard 
+
+.. data:: ETHUMB_THUMB_LARGE
+
+    256x256 as defined by FreeDesktop.Org standard 
+
+
+.. _Ethumb_Client_Thumb_Format:
+
+Ethumb_Thumb_Format
+-------------------
+
+.. data:: ETHUMB_THUMB_FDO
+
+    PNG as defined by FreeDesktop.Org standard. 
+
+.. data:: ETHUMB_THUMB_JPEG
+
+    JPEGs are often smaller and faster to read/write. 
+
+.. data:: ETHUMB_THUMB_EET 
+
+    EFL's own storage system, supports key parameter.
+
+
+.. _Ethumb_Client_Thumb_Aspect:
+
+Ethumb_Thumb_Aspect
+-------------------
+
+.. data:: ETHUMB_THUMB_KEEP_ASPECT
+
+    Keep original proportion between width and height
+
+.. data:: ETHUMB_THUMB_IGNORE_ASPECT 
+
+    Ignore aspect and foce it to match thumbnail's width and height 
+
+.. data:: ETHUMB_THUMB_CROP 
+
+    keep aspect but crop (cut) the largest dimension
+
+
+.. _Ethumb_Client_Thumb_Orientation:
+
+Ethumb_Thumb_Orientation
+------------------------
+
+.. data:: ETHUMB_THUMB_ORIENT_NONE 
+
+    Keep orientation as pixel data is 
+
+.. data:: ETHUMB_THUMB_ROTATE_90_CW 
+
+    Rotate 90° clockwise 
+
+.. data:: ETHUMB_THUMB_ROTATE_180 
+
+    Rotate 180° 
+
+.. data:: ETHUMB_THUMB_ROTATE_90_CCW 
+
+    Rotate 90° counter-clockwise 
+
+.. data:: ETHUMB_THUMB_FLIP_HORIZONTAL 
+
+    Flip horizontally 
+
+.. data:: ETHUMB_THUMB_FLIP_VERTICAL 
+
+    Flip vertically 
+
+.. data:: ETHUMB_THUMB_FLIP_TRANSPOSE 
+
+    Transpose
+
+.. data:: ETHUMB_THUMB_FLIP_TRANSVERSE 
+
+    Transverse
+
+.. data:: ETHUMB_THUMB_ORIENT_ORIGINAL 
+
+    Use orientation from metadata (EXIF-only currently) 
+
+
+Module level functions
+======================
+
+"""
+
+from cpython cimport Py_INCREF, Py_DECREF, PyUnicode_AsUTF8String
 from libc.stdint cimport uintptr_t
+
 import traceback
+import atexit
 
-def shutdown():
-    ethumb_client_shutdown()
+from efl.utils.conversions cimport _ctouni, _touni
+from efl.ethumb_client cimport Ethumb_Thumb_Orientation
 
-def init():
-    return ethumb_client_init()
 
 cdef void _connect_cb(void *data, Ethumb_Client *client, Eina_Bool success) 
with gil:
-    cdef Client self = <Client>data
+    cdef EthumbClient self = <EthumbClient>data
     s = bool(success)
     try:
         func, args, kargs = self._on_connect_callback
@@ -34,14 +147,8 @@ cdef void _connect_cb(void *data, Ethumb_Client *client, 
Eina_Bool success) with
     except Exception:
         traceback.print_exc()
 
-    if not s and self.obj != NULL:
-        ethumb_client_disconnect(self.obj)
-        self.obj = NULL
-    self._on_connect_callback = None
-
-
 cdef void _on_server_die_cb(void *data, Ethumb_Client *client) with gil:
-    cdef Client self = <Client>data
+    cdef EthumbClient self = <EthumbClient>data
     if self._on_server_die_callback is not None:
         try:
             func, args, kargs = self._on_server_die_callback
@@ -49,22 +156,15 @@ cdef void _on_server_die_cb(void *data, Ethumb_Client 
*client) with gil:
         except Exception:
             traceback.print_exc()
 
-    if self.obj != NULL:
-        ethumb_client_disconnect(self.obj)
-        self.obj = NULL
-    self._on_server_die_callback = None
-
+    self.disconnect()
 
 cdef void _generated_cb(void *data, Ethumb_Client *client, int id, const char 
*file, const char *key, const char *thumb_path, const char *thumb_key, 
Eina_Bool success) with gil:
     obj = <object>data
     (self, func, args, kargs) = obj
-    f = str_from_c(file)
-    k = str_from_c(key)
-    tp = str_from_c(thumb_path)
-    tk = str_from_c(thumb_key)
-    s = bool(success != 0)
+    status = bool(success != 0)
     try:
-        func(self, id, f, k, tp, tk, s, *args, **kargs)
+        func(self, id, _ctouni(file), _ctouni(key), _ctouni(thumb_path),
+             _ctouni(thumb_key), status, *args, **kargs)
     except Exception:
         traceback.print_exc()
 
@@ -75,21 +175,28 @@ cdef void _generated_cb_free_data(void *data) with gil:
 cdef void _thumb_exists_cb(void *data, Ethumb_Client *client, Ethumb_Exists 
*thread, Eina_Bool exists) with gil:
     #TODO
     print("Not implemented")
-    #pass
 
-cdef char *str_to_c(object s):
-    cdef char *mystr
-    if s is None:
-        mystr = NULL
-    else:
-        mystr = s
-    return mystr
 
-cdef object str_from_c(const char *mystr):
-    if mystr != NULL:
-        return mystr
+def init():
+    """ Initialize the ethumb_client library.
+
+    .. note:: You never need to call this function, it is automatically called
+              on module import.
+
+    """
+    return ethumb_client_init()
+
+def shutdown():
+    """ Shutdown the ethumb_client library.
+
+    .. note:: You never need to call this function, it is automatically called
+              at exit.
 
-cdef class Client:
+    """
+    ethumb_client_shutdown()
+
+
+cdef class EthumbClient:
     """
 
     Client for Ethumbd server.
@@ -99,22 +206,20 @@ cdef class Client:
     be connected to server, configure thumbnail parameters and then
     start feed it with file_set(), exists() generate(). Basic steps are:
 
-    - instantiate Client, wait for func to be called with success.
+    - instantiate EthumbClient, wait for func to be called with success.
     - set various parameters, like format and size.
     - loop on original files:
 
       - ``c.file_set(file)``
       - ``if not c.exists(): c.generate(generated_cb)``
 
-    When the last reference to client is released, server is
-    automatically disconnected. Since callback may contain references
-    to server itself, it is recommended explicit call to
-    :py:func:`disconnect` function.
+    It is recommended explicit call to :py:func:`disconnect` function when
+    you don't need the thumbnailer anymore.
 
     """
 
     def __init__(self, func, *args, **kargs):
-        """Client(...)
+        """ EthumbClient thumbnail generator.
 
         :param func: function to call when connection with server is
                      established.
@@ -147,15 +252,12 @@ cdef class Client:
                 ethumb_client_on_server_die_callback_set(
                     self.obj, _on_server_die_cb, <void*>self, NULL)
 
-    def __dealloc__(self):
-        if self.obj != NULL:
-            ethumb_client_disconnect(self.obj)
-
     def disconnect(self):
         """Explicitly request server disconnection.
 
         After this call object becomes shallow, that is operations
         will be void.
+
         """
         if self.obj != NULL:
             ethumb_client_disconnect(self.obj)
@@ -173,14 +275,13 @@ cdef class Client:
         if self.aspect == 2:
             aspect = "CROP[%f, %f]" % self.crop
         return (
-            "<%s(obj=%#x, file=(%r, %r), thumb=(%r, %r), exists=%s, "
+            "<%s(obj=%#x, file=(%r, %r), thumb=(%r, %r), "
             "size=%dx%d, format=%s, aspect=%s, quality=%d, compress=%d, "
-            "directory=%r, category=%r)>"
+            "dir_path=%r, category=%r)>"
             ) % (
             type(self).__name__, <uintptr_t><void *>self, f, k,
-            tf, tk, self.thumb_exists(),
-            w, h, format, aspect, self.quality, self.compress,
-            self.directory, self.category
+            tf, tk, w, h, format, aspect, self.quality, self.compress,
+            self.dir_path, self.category
             )
 
     def on_server_die_callback_set(self, func, *args, **kargs):
@@ -205,72 +306,221 @@ cdef class Client:
         else:
             raise TypeError("Parameter 'func' must be callable or None")
 
-    def fdo_set(self, int s):
-        """Configure future requests to use FreeDesktop.Org preset.
+    def thumb_exists(self, callback=None, *args, **kwargs):
+        """Checks if thumbnail already exists.
 
-        This is a preset to provide freedesktop.org (fdo) standard
-        compliant thumbnails. That is, files are stored as JPEG under
-        ~/.thumbnails/SIZE, with size being either normal (128x128) or
-        large (256x256).
+        If you want to avoid regenerating thumbnails, check if they
+        already exist with this function.
 
-        :param s: size identifier, either ETHUMB_THUMB_NORMAL (0) or
-           ETHUMB_THUMB_LARGE.
+        """
+        cdef Ethumb_Client_Thumb_Exists_Cb cb = NULL
+        cdef Ethumb_Exists *res
 
-        .. seealso:: :py:func:`size_set`, :py:func:`format_set`, 
:py:func:`aspect_set`, :py:func:`crop_set`,
-           :py:func:`category_set`, :py:func:`directory_set`.
+        if callback:
+            if not callable(callback):
+                raise TypeError("callback is not callable")
+            cb = _thumb_exists_cb
+
+            data = (args, kwargs)
+            res = ethumb_client_thumb_exists(self.obj, cb, <void *>data)
+
+        return False
+        #TODO: handle return value
+
+    def generate(self, func, *args, **kargs):
+        """Ask EThumb server to generate the specified thumbnail.
+
+        Thumbnail generation is asynchronous and depend on ecore main
+        loop running. Given function will be called back with
+        generation status if True is returned by this call. If False
+        is returned, given function will not be called.
+
+        Existing thumbnails will be overwritten with this call. Check
+        if they already exist with :py:func:`exists` before calling.
+
+        :param func: function to call on generation completion, even
+            if failed or succeeded. Signature is::
+
+                func(self, id, file, key, thumb_path, thumb_key, status, 
*args, **kargs)
+
+            with status being True for successful generation or
+            False on failure.
+
+        :return: request identifier. Request can be canceled calling
+            :py:func:`cancel` with given id. If an identifier is returned (>=
+            0), then func is guaranteed to be called unless it is
+            explicitly canceled.
+
+        :raise TypeError: if **func** is not callable.
+        :raise SystemError: if could not generate thumbnail, probably
+           no :py:func:`file_set`.
+
+        .. seealso:: :py:func:`cancel`, :py:func:`clear`, :py:func:`exists`
         """
-        ethumb_client_fdo_set(self.obj, s)
+        if not callable(func):
+            raise TypeError("func must be callable")
+
+        targs = (self, func, args, kargs)
+        r = ethumb_client_generate(self.obj, _generated_cb, <void*>targs,
+                                   _generated_cb_free_data)
+        if r >= 0:
+            Py_INCREF(targs)
+            return r
+        else:
+            raise SystemError("could not generate thumbnail. "
+                              "Did you set the file?")
 
-    def size_set(self, int w, int h):
-        """Configure future request to use custom size.
+    def generate_cancel(self, int id):
+        """Cancel thumbnail request given its id.
 
-        :param w: width, default is 128.
-        :param h: height, default is 128.
+        Calling this function aborts thumbnail generation and **func**
+        given to :py:func:`generate` will not be called!
+
+        :param id: identifier returned by :py:func:`generate`
         """
-        ethumb_client_size_set(self.obj, w, h)
+        ethumb_client_generate_cancel(self.obj, id, NULL, NULL, NULL)
 
-    def size_get(self):
-        """Get current size being used by requests.
+    def generate_cancel_all(self):
+        """Clear request queue, canceling all generation requests.
+
+        This will abort all existing requests, no **func** given to
+        :py:func:`generate` will be called.
 
-        :rtype: tuple of int.
+        Same as calling :py:func:`cancel` in all exising requests.
         """
-        cdef int w, h
-        ethumb_client_size_get(self.obj, &w, &h)
-        return (w, h)
+        ethumb_client_generate_cancel_all(self.obj)
 
-    property size:
+    ## source file setup
+    property file:
+        """ The file to thumbnail.
+
+        This is a tuple of 2 strings: ``path`` and ``key``.
+
+        For convenience you can also assign a single string value (``path``),
+        ignoring the key.
+
+        :type: **str** or (**str**, **str**)
+
+        :param path: path to thumbnail subject.
+        :param key: path to key inside **path**, this is used to
+           generate thumbnail of edje groups or images inside EET.
+
+        :raise RuntimeError: on failure setting the property
+
+        .. note:: setting this property will reset other thumbnail
+            specifications. This is done to avoid one using the last thumb
+            path for new images.
+
+        """
         def __set__(self, value):
-            cdef int w, h
-            w, h = value
-            self.size_set(w, h)
+            if isinstance(value, tuple):
+                path, key = value
+            else:
+                path, key = value, None
+            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
+            if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
+            if ethumb_client_file_set(self.obj,
+                    <const char *>path if path is not None else NULL,
+                    <const char *>key if key is not None else NULL) == 0:
+                raise RuntimeError("Cannot set file")
 
         def __get__(self):
-            return self.size_get()
+            cdef:
+                const char *path
+                const char *key
+            ethumb_client_file_get(self.obj, &path, &key)
+            return (_ctouni(path), _ctouni(key))
+
+    def file_free(self):
+        """Zero/Reset file parameters.
+
+        This call will reset file and thumb specifications.
+
+        .. seealso:: :py:func:`file_set` and :py:func:`thumb_set`
+        """
+        ethumb_client_file_free(self.obj)
+
+    property frame:
+        """ The optional edje file used to generate a frame around the 
thumbnail
+
+        This will create an edje object that will have image swallowed
+        in. This can be used to simulate Polaroid or wood frames in
+        the generated image. Remember it is bad to modify the original
+        contents of thumbnails, but sometimes it's useful to have it
+        composited and avoid runtime overhead.
 
-    def format_set(self, int f):
-        """Configure format to use for future requests.
+        :type: (**str**, **str**, **str**) **writeonly**
+
+        :param file: file path to edje.
+        :param group: group inside edje to use.
+        :param swallow: name of swallow part.
+
+        :raise RuntimeError: on failure setting the property
 
-        :param f: format identifier to use, either ETHUMB_THUMB_FDO (0),
-           ETHUMB_THUMB_JPEG (1) or ETHUMB_THUMB_EET (2). Default is FDO.
         """
-        ethumb_client_format_set(self.obj, f)
+        def __set__(self, tuple value):
+            theme, group, swallow = value
+            if isinstance(theme, unicode): theme = 
PyUnicode_AsUTF8String(theme)
+            if isinstance(group, unicode): group = 
PyUnicode_AsUTF8String(group)
+            if isinstance(swallow, unicode): swallow = 
PyUnicode_AsUTF8String(swallow)
+            if ethumb_client_frame_set(self.obj,
+                    <const char *>theme if theme is not None else NULL,
+                    <const char *>group if group is not None else NULL,
+                    <const char *>swallow if swallow is not None else NULL) == 
0:
+                raise RuntimeError("Cannot set frame")
+
+    ## fine tune setup
+    property fdo:
+        """ Configure future requests to use FreeDesktop.Org preset.
+
+        This is a preset to provide freedesktop.org (fdo) standard
+        compliant thumbnails. That is, files are stored as JPEG under
+        ~/.thumbnails/SIZE, with size being either normal (128x128) or
+        large (256x256).
+
+        :type: :ref:`Ethumb_Client_Thumb_FDO_Size` **writeonly**
 
-    def format_get(self):
-        """Get current format in use for requests.
+        .. seealso:: :attr:`size`, :attr:`format`, :attr:`aspect`,
+            :attr:`crop_align`, :attr:`category`, :attr:`dir_path`.
 
-        :rtype: int
         """
-        return ethumb_client_format_get(self.obj)
+        def __set__(self, Ethumb_Thumb_FDO_Size value):
+            ethumb_client_fdo_set(self.obj, value)
+
+    property size:
+        """ The (custom) size of thumbnails.
+
+        :type: (int **w**, int **w**)
+
+        :param w: width, default is 128.
+        :param h: height, default is 128.
+
+        """
+        def __set__(self, tuple value):
+            w, h = value
+            ethumb_client_size_set(self.obj, w, h)
+
+        def __get__(self):
+            cdef int w, h
+            ethumb_client_size_get(self.obj, &w, &h)
+            return w, h
 
     property format:
-        def __set__(self, value):
-            self.format_set(value)
+        """ The fileformat for the thumbnails.
+
+        Thumbnails are compressed; possible formats are PNG, JPEG and EET.
+
+        :type: :ref:`Ethumb_Client_Thumb_Format`
+
+        """
+        def __set__(self, Ethumb_Thumb_Format value):
+            ethumb_client_format_set(self.obj, value)
 
         def __get__(self):
-            return self.format_get()
+            return ethumb_client_format_get(self.obj)
 
-    def aspect_set(self, int a):
-        """Configure aspect mode to use.
+    property aspect:
+        """ The aspect ratio policy.
 
         If aspect is kept (ETHUMB_THUMB_KEEP_ASPECT), then image will
         be rescaled so the largest dimension is not bigger than it's
@@ -294,361 +544,216 @@ cdef class Client:
         just the 500x500 central pixels of image will be considered
         for scaling.
 
-        :param a: aspect mode identifier, either ETHUMB_THUMB_KEEP_ASPECT (0),
-           ETHUMB_THUMB_IGNORE_ASPECT (1) or ETHUMB_THUMB_CROP (2).
+        :type: :ref:`Ethumb_Client_Thumb_Aspect`
 
         """
-        ethumb_client_aspect_set(self.obj, a)
+        def __set__(self, Ethumb_Thumb_Aspect value):
+            ethumb_client_aspect_set(self.obj, value)
 
-    def aspect_get(self):
-        """Get current aspect in use for requests.
+        def __get__(self):
+            return ethumb_client_aspect_get(self.obj)
 
-        :rtype: int
-        """
-        return ethumb_client_aspect_get(self.obj)
+    property orientation:
+        """ The thumbnail rotation or flip.
 
-    property aspect:
-        def __set__(self, value):
-            self.aspect_set(value)
+        :type: :ref:`Ethumb_Client_Thumb_Orientation`
+
+        """
+        def __set__(self, Ethumb_Thumb_Orientation value):
+            ethumb_client_orientation_set(self.obj, value)
 
         def __get__(self):
-            return self.aspect_get()
+            return ethumb_client_orientation_get(self.obj)
 
-    def crop_set(self, float x, float y):
-        """Configure crop alignment in use for future requests.
+    property crop_align:
+        """ Crop alignment in use.
 
         :param x: horizontal alignment. 0.0 means left side will be
-           visible or right side is being lost. 1.0 means right
-           side will be visible or left side is being lost. 0.5
-           means just center is visible, both sides will be lost.
-           Default is 0.5.
+                  visible or right side is being lost. 1.0 means right side
+                  will be visible or left side is being lost. 0.5 means just
+                  center is visible, both sides will be lost. Default is 0.5.
         :param y: vertical alignment. 0.0 is top visible, 1.0 is
-           bottom visible, 0.5 is center visible. Default is 0.5
-        """
-        ethumb_client_crop_align_set(self.obj, x, y)
+                  bottom visible, 0.5 is center visible. Default is 0.5
 
-    def crop_get(self):
-        """Get current crop alignment in use for requests.
+        :type: (float **x**, float **y**)
 
-        :rtype: tuple of float
         """
-        cdef float x, y
-        ethumb_client_crop_align_get(self.obj, &x, &y)
-        return (x, y)
-
-    property crop:
-        def __set__(self, value):
-            cdef float x, y
+        def __set__(self, tuple value):
             x, y = value
-            self.crop_set(x, y)
+            ethumb_client_crop_align_set(self.obj, x, y)
 
         def __get__(self):
-            return self.crop_get()
-
-    def quality_set(self, int quality):
-        """Configure quality to be used in thumbnails.
-
-        :param quality: value from 0 to 100, default is 80. The
-           effect depends on the format being used, PNG will not
-           use it.
-        """
-        ethumb_client_quality_set(self.obj, quality)
-
-    def quality_get(self):
-        """Get current quality in use for requests.
-
-        :rtype: int
-        """
-        return ethumb_client_quality_get(self.obj)
+            cdef float x, y
+            ethumb_client_crop_align_get(self.obj, &x, &y)
+            return x, y
 
     property quality:
-        def __set__(self, value):
-            self.quality_set(value)
+        """ The thumbnail compression quality.
 
-        def __get__(self):
-            return self.quality_get()
+        Value from 0 to 100, default is 80. The effect depends on the format
+        being used, PNG will not use it.
 
-    def compress_set(self, int compress):
-        """Configure compression level used in requests.
+        :type: int
 
-        :param compress: value from 0 to 9, default is 9. The effect
-           depends on the format being used, JPEG will not use it.
         """
-        ethumb_client_compress_set(self.obj, compress)
-
-    def compress_get(self):
-        """Get current compression level in use for requests.
-
-        :rtype: int
-        """
-        return ethumb_client_compress_get(self.obj)
-
-    property compress:
-        def __set__(self, value):
-            self.compress_set(value)
+        def __set__(self, int value):
+            ethumb_client_quality_set(self.obj, value)
 
         def __get__(self):
-            return self.compress_get()
-
-    def directory_set(self, path):
-        """Configure where to store thumbnails in future requests.
+            return ethumb_client_quality_get(self.obj)
 
-        Note that this is the base, a category is added to this path
-        as a sub directory.
+    property compress:
+        """ The thumbnail compression rate.
 
-        :param path: base directory where to store
-           thumbnails. Default is ~/.thumbnails
-        """
-        ethumb_client_dir_path_set(self.obj, str_to_c(path))
+        Value from 0 to 9, default is 9. The effect depends on the format being
+        used, JPEG will not use it.
 
-    def directory_get(self):
-        """Get current base directory to store thumbnails.
+        :type: int
 
-        :rtype: str or None
         """
-        return str_from_c(ethumb_client_dir_path_get(self.obj))
-
-    property directory:
-        def __set__(self, value):
-            self.directory_set(value)
+        def __set__(self, int value):
+            ethumb_client_compress_set(self.obj, value)
 
         def __get__(self):
-            return self.directory_get()
+            return ethumb_client_compress_get(self.obj)
 
-    def category_set(self, category):
-        """Category directory to store thumbnails.
+    property dir_path:
+        """ Configure where to store thumbnails in future requests.
 
-        :param category: category sub directory to store
-           thumbnail. Default is either "normal" or "large" for FDO
-           compliant thumbnails or
-           WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT. It can be a string or
-           None to use auto generated names.
-        """
-        ethumb_client_category_set(self.obj, str_to_c(category))
+        This is the base folder, a category folder is added to this path
+        as a sub directory. Default is ``~/.thumbnails``
 
-    def category_get(self):
-        """Get current category sub directory to store thumbnails.
+        :type: **str**
 
-        :rtype: str or None
         """
-        return str_from_c(ethumb_client_category_get(self.obj))
-
-    property category:
-        def __set__(self, value):
-            self.category_set(value)
+        def __set__(self, path):
+            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
+            ethumb_client_dir_path_set(self.obj,
+                    <const char *>path if path is not None else NULL)
 
         def __get__(self):
-            return self.category_get()
+            cdef const char *path
+            path = ethumb_client_dir_path_get(self.obj)
+            return _ctouni(path)
 
-    def frame_set(self, file, group, swallow):
-        """Set frame to apply to future thumbnails.
+    property category:
+        """ Category directory to store thumbnails.
 
-        This will create an edje object that will have image swallowed
-        in. This can be used to simulate Polaroid or wood frames in
-        the generated image. Remember it is bad to modify the original
-        contents of thumbnails, but sometimes it's useful to have it
-        composited and avoid runtime overhead.
+        Category sub directory to store thumbnail. Default is either "normal"
+        or "large" for FDO compliant thumbnails or
+        ``WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT``. It can be a string or None to
+        use auto generated names.
 
-        :param file: file path to edje.
-        :param group: group inside edje to use.
-        :param swallow: name of swallow part.
-        """
-        cdef:
-            char *f
-            char *g
-            char *s
-        f = str_to_c(file)
-        g = str_to_c(group)
-        s = str_to_c(swallow)
-        return ethumb_client_frame_set(self.obj, f, g, s)
-
-    def file_set(self, path, key=None):
-        """Set file to thumbnail.
-
-        Calling this function will zero :py:func:`thumb_set`
-        specifications. This is done to avoid one using the last thumb
-        path for new images.
+        :type: **str**
 
-        :param path: path to thumbnail subject.
-        :param key: path to key inside **path**, this is used to
-           generate thumbnail of edje groups or images inside EET.
         """
-        cdef:
-            char *p
-            char *k
-        p = str_to_c(path)
-        k = str_to_c(key)
-        ethumb_client_file_set(self.obj, p, k)
-
-    def file_get(self):
-        """Get current file to thumbnail.
-
-        :rtype: tuple of str
-        """
-        cdef:
-            const char *p
-            const char *k
-        ethumb_client_file_get(self.obj, &p, &k)
-        return (str_from_c(p), str_from_c(k))
-
-    property file:
-        def __set__(self, value):
-            p, k = value
-            self.file_set(p, k)
+        def __set__(self, cat):
+            if isinstance(cat, unicode): cat = PyUnicode_AsUTF8String(cat)
+            ethumb_client_category_set(self.obj,
+                    <const char *>cat if cat is not None else NULL)
 
         def __get__(self):
-            return self.file_get()
+            return _ctouni(ethumb_client_category_get(self.obj))
 
-    def file_free(self):
-        """Zero/Reset file parameters.
-
-        This call will reset file and thumb specifications.
+    property thumb_path:
+        """ The complete path of the generated thumbnail.
 
-        .. seealso:: :py:func:`file_set` and :py:func:`thumb_set`
-        """
-        ethumb_client_file_free(self.obj)
+        This is a tuple of 2 strings: ``path`` and ``key``.
 
-    def thumb_set(self, path, key=None):
-        """Set thumbnail path and key.
+        For convenience you can also assign a single string value (``path``),
+        ignoring the key.
 
-        Note that these parameters are forgotten (reset) after
-        :py:func:`file_set`.
+        :type: **str** or (**str**, **str**)
 
         :param path: path to generated thumbnail to use, this is an
            absolute path to file, overriding directory and category.
         :param key: path to key inside **path**, this is used to
            generate thumbnail inside EET files.
-        """
-        cdef:
-            const char *p
-            const char *k
-        p = str_to_c(path)
-        k = str_to_c(key)
-        ethumb_client_thumb_path_set(self.obj, p, k)
 
-    def thumb_get(self):
-        """Get current path and key of thumbnail.
-
-        Note that if no explicit :py:func:`thumb_set` was called, it will
-        auto generate path based on existing parameters such as
-        directory, category and others.
-
-        :rtype: tuple of str
         """
-        cdef:
-            const char *p
-            const char *k
-        ethumb_client_thumb_path_get(self.obj, &p, &k)
-        return (str_from_c(p), str_from_c(k))
-
-    property thumb_path:
         def __set__(self, value):
-            p, k = value
-            self.thumb_set(p, k)
-        def __get__(self):
-            return self.thumb_get()
-
-    def video_time_set(self, float time):
-        ethumb_client_video_time_set(self.obj, time)
-
-    def video_start_set(self, float start):
-        ethumb_client_video_start_set(self.obj, start)
-
-    def video_interval_set(self, float interval):
-        ethumb_client_video_interval_set(self.obj, interval)
-
-    def video_ntimes_set(self, int ntimes):
-        ethumb_client_video_ntimes_set(self.obj, ntimes)
+            if isinstance(value, tuple):
+                path, key = value
+            else:
+                path, key = value, None
+            if isinstance(path, unicode): path = PyUnicode_AsUTF8String(path)
+            if isinstance(key, unicode): key = PyUnicode_AsUTF8String(key)
+            ethumb_client_thumb_path_set(self.obj,
+                    <const char *>path if path is not None else NULL,
+                    <const char *>key if key is not None else NULL)
 
-    def video_fps_set(self, int fps):
-        ethumb_client_video_fps_set(self.obj, fps)
+        def __get__(self):
+            cdef:
+                const char *path
+                const char *key
+            ethumb_client_thumb_path_get(self.obj, &path, &key)
+            return (_ctouni(path), _ctouni(key))
 
-    # document_page
-    def document_page_set(self, int page):
-        ethumb_client_document_page_set(self.obj, page)
+    ## video setup
+    property video_time:
+        """ The video time (duration) in seconds.
 
-    def thumb_exists(self, callback = None, *args, **kwargs):
-        """Checks if thumbnail already exists.
-
-        If you want to avoid regenerating thumbnails, check if they
-        already exist with this function.
+        :type: float  (**readonly**)
 
         """
-        cdef Ethumb_Client_Thumb_Exists_Cb cb = NULL
-        cdef Ethumb_Exists *res
-
-        if callback:
-            if not callable(callback):
-                raise TypeError("callback is not callable")
-            cb = _thumb_exists_cb
+        def __set__(self, float value):
+            ethumb_client_video_time_set(self.obj, value)
 
-            data = (args, kwargs)
-            res = ethumb_client_thumb_exists(self.obj, cb, <void *>data)
+    property video_start:
+        """ The start point for video thumbnails.
 
-        return False
-        #TODO: handle return value
+        :type: float (from 0.0 to 1.0) (**readonly**)
 
-    def generate(self, func, *args, **kargs):
-        """Ask EThumb server to generate the specified thumbnail.
-
-        Thumbnail generation is asynchronous and depend on ecore main
-        loop running. Given function will be called back with
-        generation status if True is returned by this call. If False
-        is returned, given function will not be called.
+        """
+        def __set__(self, float value):
+            ethumb_client_video_start_set(self.obj, value)
 
-        Existing thumbnails will be overwritten with this call. Check
-        if they already exist with :py:func:`exists` before calling.
+    property video_interval:
+        """ The video frame interval, in seconds.
 
-        :param func: function to call on generation completion, even
-            if failed or succeeded. Signature is::
+        This is useful for animated thumbnail and will define skip time before
+        going to the next frame.
 
-                func(self, id, file, key, thumb_path, thumb_key, status, 
*args, **kargs)
+        .. note:: that video backends might not be able to
+                  precisely skip that amount as it will depend on various
+                  factors, including video encoding.
+ 
+        :type: float (**readonly**)
 
-            with status being True for successful generation or
-            False on failure.
+        """
+        def __set__(self, float value):
+            ethumb_client_video_interval_set(self.obj, value)
 
-        :return: request identifier. Request can be canceled calling
-            :py:func:`cancel` with given id. If an identifier is returned (>=
-            0), then func is guaranteed to be called unless it is
-            explicitly canceled.
+    property video_ntimes:
+        """ The number of times the video loops (if applicable).
 
-        :raise TypeError: if **func** is not callable.
-        :raise SystemError: if could not generate thumbnail, probably
-           no :py:func:`file_set`.
+        :type: int (**readonly**)
 
-        .. seealso:: :py:func:`cancel`, :py:func:`clear`, :py:func:`exists`
         """
-        if not callable(func):
-            raise TypeError("func must be callable")
+        def __set__(self, int value):
+            ethumb_client_video_ntimes_set(self.obj, value)
 
-        targs = (self, func, args, kargs)
-        r = ethumb_client_generate(self.obj, _generated_cb, <void*>targs,
-                                   _generated_cb_free_data)
-        if r >= 0:
-            Py_INCREF(targs)
-            return r
-        else:
-            raise SystemError("could not generate thumbnail. "
-                              "Did you set the file?")
+    property video_fps:
+        """ The thumbnail framerate.
 
-    def generate_cancel(self, int id):
-        """Cancel thumbnail request given its id.
+        Default to 10.
 
-        Calling this function aborts thumbnail generation and **func**
-        given to :py:func:`generate` will not be called!
+        :type: int (**readonly**)
 
-        :param id: identifier returned by :py:func:`generate`
         """
-        ethumb_client_generate_cancel(self.obj, id, NULL, NULL, NULL)
+        def __set__(self, int value):
+            ethumb_client_video_fps_set(self.obj, value)
 
-    def generate_cancel_all(self):
-        """Clear request queue, canceling all generation requests.
+    ## document setup
+    property document_page:
+        """ The page number to thumbnail in paged documents.
 
-        This will abort all existing requests, no **func** given to
-        :py:func:`generate` will be called.
+        :type: int
 
-        Same as calling :py:func:`cancel` in all exising requests.
         """
-        ethumb_client_generate_cancel_all(self.obj)
+        def __set__(self, int value):
+            ethumb_client_document_page_set(self.obj, value)
+
 
 init()
+atexit.register(shutdown)
diff --git a/examples/ethumb/ethumb_client.py b/examples/ethumb/ethumb_client.py
new file mode 100755
index 0000000..59b788a
--- /dev/null
+++ b/examples/ethumb/ethumb_client.py
@@ -0,0 +1,110 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+import os
+import sys
+import logging
+
+from efl import ecore
+from efl import ethumb_client as ethumb
+
+script_path = os.path.dirname(os.path.abspath(__file__))
+
+
+# parse command line arguments
+if len(sys.argv) != 2:
+    print("Python EthumbClient test application.\n\n" \
+          "usage: ethumb_client.py filename\n")
+    exit(1)
+filename = sys.argv[1]
+print("Original file: %s\n" % filename)
+
+
+# setup efl logging (you also need to set EINA_LOG_LEVEL=X)
+l = logging.getLogger("efl")
+h = logging.StreamHandler()
+h.setFormatter(logging.Formatter("EFL %(levelname)s %(message)s"))
+l.addHandler(h)
+l.setLevel(logging.DEBUG)
+
+complete_count = 0
+
+def generate_cb(client, id, file, key, thumb_path, thumb_key, success, num):
+    global complete_count
+
+    # thumbnail completed
+    if success is True:
+        print("Thumb #%d completed: '%s'" % (num, thumb_path))
+        complete_count += 1
+        if complete_count >= 6:
+            print("\nTest Complete!")
+            ecore.main_loop_quit()
+    else:
+        print("   ERROR! aborting.")
+        ecore.main_loop_quit()
+
+def connect_cb(client, success):
+    if success is False:
+        print("Connection Failed")
+        ecore.main_loop_quit()
+        return
+    else:
+        print("Connection Successfull")
+
+    # request some thumbnails
+    print("1. Request a standard FDO thumbnail (default)")
+    et.file = filename
+    et.generate(generate_cb, 1)
+
+    print("2. Request a large FDO thumbnail...")
+    et.file = filename
+    et.fdo = ethumb.ETHUMB_THUMB_LARGE
+    et.generate(generate_cb, 2)
+
+    print("3. Request a very large JPEG thumbnail...")
+    et.file = filename
+    et.format = ethumb.ETHUMB_THUMB_JPEG
+    et.size = 512, 512
+    et.generate(generate_cb, 3)
+
+    print("4. Request a cropped thumbnail...")
+    et.file = filename
+    et.aspect = ethumb.ETHUMB_THUMB_CROP
+    et.generate(generate_cb, 4)
+
+    print("5. Request a rotated thumbnail")
+    et.file = filename
+    et.orientation = ethumb.ETHUMB_THUMB_ROTATE_180
+    et.size = 256, 256
+    et.aspect = ethumb.ETHUMB_THUMB_KEEP_ASPECT
+    et.generate(generate_cb, 5)
+
+    print("6. Request a poor quality thumbnail in this folder\n")
+    et.file = filename
+    et.orientation = ethumb.ETHUMB_THUMB_ORIENT_NONE
+    et.thumb_path = os.path.join(script_path, 'big_poor2.jpg')
+    et.format = ethumb.ETHUMB_THUMB_JPEG
+    et.size = 512, 512
+    et.quality = 10
+    et.generate(generate_cb, 6)
+
+    # ...and now wait for the responses
+
+
+def server_die_cb(client):
+    print("Server die!")
+    ecore.main_loop_quit()
+
+
+# create a single Ethumb instance
+et = ethumb.EthumbClient(connect_cb)
+et.on_server_die_callback_set(server_die_cb)
+
+
+
+# enter the ecore the main loop
+ecore.main_loop_begin()
+
+# free used resource
+et.disconnect()
+
diff --git a/include/efl.ethumb_client.pxd b/include/efl.ethumb_client.pxd
index 70c7ec3..7f99043 100644
--- a/include/efl.ethumb_client.pxd
+++ b/include/efl.ethumb_client.pxd
@@ -16,17 +16,64 @@
 # along with this Python-EFL.  If not, see <http://www.gnu.org/licenses/>.
 
 from efl.eina cimport Eina_Bool, Eina_Free_Cb
-from efl.ethumb cimport Ethumb_Thumb_Orientation
+
 
 cdef extern from "Ethumb_Client.h":
+
+    ####################################################################
+    # Enums
+    #
+    cpdef enum Ethumb_Thumb_Orientation:
+        ETHUMB_THUMB_ORIENT_NONE
+        ETHUMB_THUMB_ROTATE_90_CW
+        ETHUMB_THUMB_ROTATE_180
+        ETHUMB_THUMB_ROTATE_90_CCW
+        ETHUMB_THUMB_FLIP_HORIZONTAL
+        ETHUMB_THUMB_FLIP_VERTICAL
+        ETHUMB_THUMB_FLIP_TRANSPOSE
+        ETHUMB_THUMB_FLIP_TRANSVERSE
+        ETHUMB_THUMB_ORIENT_ORIGINAL
+    ctypedef enum Ethumb_Thumb_Orientation:
+        pass
+
+    cpdef enum Ethumb_Thumb_FDO_Size:
+        ETHUMB_THUMB_NORMAL
+        ETHUMB_THUMB_LARGE
+    ctypedef enum Ethumb_Thumb_FDO_Size:
+        pass
+
+    cpdef enum Ethumb_Thumb_Format:
+        ETHUMB_THUMB_FDO
+        ETHUMB_THUMB_JPEG
+        ETHUMB_THUMB_EET
+    ctypedef enum Ethumb_Thumb_Format:
+        pass
+
+    cpdef enum Ethumb_Thumb_Aspect:
+        ETHUMB_THUMB_KEEP_ASPECT
+        ETHUMB_THUMB_IGNORE_ASPECT
+        ETHUMB_THUMB_CROP
+    ctypedef enum Ethumb_Thumb_Aspect:
+        pass
+
+    ####################################################################
+    # Structs
+    #
     ctypedef struct Ethumb_Client
     ctypedef struct Ethumb_Exists
+
+    ####################################################################
+    # Other typedefs
+    #
     ctypedef void (*Ethumb_Client_Connect_Cb)(void *data, Ethumb_Client 
*client, Eina_Bool success)
     ctypedef void (*Ethumb_Client_Die_Cb)(void *data, Ethumb_Client *client)
     ctypedef void (*Ethumb_Client_Generate_Cb)(void *data, Ethumb_Client 
*client, int id, const char *file, const char *key, const char *thumb_path, 
const char *thumb_key, Eina_Bool success)
     ctypedef void (*Ethumb_Client_Thumb_Exists_Cb)(void *data, Ethumb_Client 
*client, Ethumb_Exists *thread, Eina_Bool exists)
     ctypedef void (*Ethumb_Client_Generate_Cancel_Cb)(void *data, Eina_Bool 
success)
 
+    ####################################################################
+    # Functions
+    #
     int             ethumb_client_init()
     int             ethumb_client_shutdown()
 
@@ -90,7 +137,8 @@ cdef extern from "Ethumb_Client.h":
 
     void            ethumb_client_thumb_async_cancel(Ethumb_Client *client, 
Ethumb_Client_Async *request)
 
-cdef class Client:
+
+cdef class EthumbClient:
     cdef Ethumb_Client *obj
     cdef object _on_connect_callback
     cdef object _on_server_die_callback
diff --git a/setup.py b/setup.py
index 36a50ee..f29884e 100755
--- a/setup.py
+++ b/setup.py
@@ -351,8 +351,9 @@ if set(("build", "build_ext", "install", "bdist", "sdist")) 
& set(sys.argv):
                            extra_link_args=ethumb_libs + eina_libs)
     ext_modules.append(ethumb_ext)
 
-    ethumb_client_cflags, ethumb_client_libs = pkg_config(
-        'Ethumb_Client', 'ethumb_client', EFL_MIN_VER)
+    # === Ethumb Client ===
+    ethumb_client_cflags, ethumb_client_libs = pkg_config('Ethumb_Client',
+                                                'ethumb_client', EFL_MIN_VER)
     ethumb_client_ext = Extension("ethumb_client",
                                   ["efl/ethumb/efl.ethumb_client" + 
module_suffix],
                                   include_dirs=['include/'],

-- 


Reply via email to