kuuko pushed a commit to branch master.

commit 285856ea0337a4eb7b473bae99a5b57e1f76a381
Author: Kai Huuhko <[email protected]>
Date:   Thu Apr 18 15:46:52 2013 +0000

    Elementary: Initial implementation for Store. Still needs work on
    creating the data struct, maybe using memoryviews.
    
    Includes some internal changes for Genlist.
---
 efl/elementary/enums.pxd              |   9 +
 efl/elementary/genlist.pxd            |  12 +-
 efl/elementary/genlist.pyx            |  53 ++--
 efl/elementary/store.pxd              | 111 +++++++
 efl/elementary/store.pyx              | 551 ++++++++++++++++++++++++++++++++++
 efl/elementary/store_item_mapping.pxi | 202 +++++++++++++
 examples/elementary/test_store.py     | 134 +++++++++
 setup.py                              |   1 +
 8 files changed, 1043 insertions(+), 30 deletions(-)

diff --git a/efl/elementary/enums.pxd b/efl/elementary/enums.pxd
index ee405b0..8f648a8 100644
--- a/efl/elementary/enums.pxd
+++ b/efl/elementary/enums.pxd
@@ -369,6 +369,15 @@ cdef extern from "Elementary.h":
         ELM_SOFTCURSOR_MODE_ON
         ELM_SOFTCURSOR_MODE_OFF
 
+    ctypedef enum Elm_Store_Item_Mapping_Type:
+        ELM_STORE_ITEM_MAPPING_NONE
+        ELM_STORE_ITEM_MAPPING_LABEL
+        ELM_STORE_ITEM_MAPPING_STATE
+        ELM_STORE_ITEM_MAPPING_ICON
+        ELM_STORE_ITEM_MAPPING_PHOTO
+        ELM_STORE_ITEM_MAPPING_CUSTOM
+        ELM_STORE_ITEM_MAPPING_LAST
+
     ctypedef enum Elm_Text_Format:
         ELM_TEXT_FORMAT_PLAIN_UTF8
         ELM_TEXT_FORMAT_MARKUP_UTF8
diff --git a/efl/elementary/genlist.pxd b/efl/elementary/genlist.pxd
index e1b04a4..178cc1c 100644
--- a/efl/elementary/genlist.pxd
+++ b/efl/elementary/genlist.pxd
@@ -51,7 +51,7 @@ cdef extern from "Elementary.h":
     void                    elm_genlist_item_bring_in(Elm_Object_Item *item, 
Elm_Genlist_Item_Scrollto_Type scrollto_type)
     void                    elm_genlist_item_update(Elm_Object_Item *item)
     void                    elm_genlist_item_item_class_update(Elm_Object_Item 
*it, Elm_Genlist_Item_Class *itc)
-    Elm_Genlist_Item_Class *elm_genlist_item_item_class_get(Elm_Object_Item 
*it)
+    # TODO: Elm_Genlist_Item_Class 
*elm_genlist_item_item_class_get(Elm_Object_Item *it)
     int                     elm_genlist_item_index_get(Elm_Object_Item *it)
     void                    elm_genlist_realized_items_update(Evas_Object *obj)
     unsigned int            elm_genlist_items_count(Evas_Object *obj)
@@ -104,3 +104,13 @@ cdef extern from "Elementary.h":
     void                    elm_genlist_select_mode_set(Evas_Object *obj, 
Elm_Object_Select_Mode mode)
     Elm_Object_Select_Mode  elm_genlist_select_mode_get(Evas_Object *obj)
 
+cdef class GenlistItemClass(object):
+    cdef:
+        Elm_Genlist_Item_Class cls
+        object _text_get_func
+        object _content_get_func
+        object _state_get_func
+        object _del_func
+        object _item_style
+        object _decorate_item_style
+        object _decorate_all_item_style
diff --git a/efl/elementary/genlist.pyx b/efl/elementary/genlist.pyx
index 240ea5a..53d20b3 100644
--- a/efl/elementary/genlist.pyx
+++ b/efl/elementary/genlist.pyx
@@ -658,27 +658,22 @@ cdef class GenlistItemClass(object):
     constructor parameters.
 
     """
-    cdef:
-        Elm_Genlist_Item_Class cls
-        Elm_Genlist_Item_Class *obj
-        object _text_get_func
-        object _content_get_func
-        object _state_get_func
-        object _del_func
-        object _item_style
-        object _decorate_item_style
-        object _decorate_all_item_style
+    # In pxd:
+    # Elm_Genlist_Item_Class cls
+    # object _text_get_func
+    # object _content_get_func
+    # object _state_get_func
+    # object _del_func
+    # object _item_style
+    # object _decorate_item_style
+    # object _decorate_all_item_style
 
     def __cinit__(self):
-        self.obj = &self.cls
-        self.obj.item_style = NULL
-        self.obj.decorate_item_style = NULL
-        self.obj.decorate_all_item_style = NULL
-        self.obj.func.text_get = _py_elm_genlist_item_text_get
-        self.obj.func.content_get = _py_elm_genlist_item_content_get
-        self.obj.func.state_get = _py_elm_genlist_item_state_get
+        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
         # TODO: Check if the struct member is named del_
-        self.obj.func.del_ = _py_elm_genlist_object_item_del
+        self.cls.func.del_ = _py_elm_genlist_object_item_del
 
     def __init__(self, item_style=None, text_get_func=None,
                  content_get_func=None, state_get_func=None, del_func=None,
@@ -773,15 +768,15 @@ cdef class GenlistItemClass(object):
         self._decorate_item_style = a2
         self._decorate_all_item_style = a3
 
-        self.obj.item_style = <char *>self._item_style if self._item_style is 
not None else NULL
-        self.obj.decorate_item_style = <char *>self._decorate_item_style if 
self._decorate_item_style is not None else NULL
-        self.obj.decorate_all_item_style = <char 
*>self._decorate_all_item_style if self._decorate_all_item_style is not None 
else NULL
+        self.cls.item_style = <char *>self._item_style if self._item_style is 
not None else NULL
+        self.cls.decorate_item_style = <char *>self._decorate_item_style if 
self._decorate_item_style is not None else NULL
+        self.cls.decorate_all_item_style = <char 
*>self._decorate_all_item_style if self._decorate_all_item_style is not None 
else NULL
 
     def __str__(self):
         return ("%s(item_style=%r, text_get_func=%s, content_get_func=%s, "
                 "state_get_func=%s, del_func=%s)") % \
                (self.__class__.__name__,
-                _ctouni(self.obj.item_style),
+                _ctouni(self.cls.item_style),
                 self._text_get_func,
                 self._content_get_func,
                 self._state_get_func,
@@ -794,8 +789,8 @@ cdef class GenlistItemClass(object):
                (self.__class__.__name__,
                 <unsigned long><void *>self,
                 PY_REFCOUNT(self),
-                <unsigned long>&self.obj,
-                _ctouni(self.obj.item_style),
+                <unsigned long>&self.cls,
+                _ctouni(self.cls.item_style),
                 self._text_get_func,
                 self._content_get_func,
                 self._state_get_func,
@@ -809,7 +804,7 @@ cdef class GenlistItemClass(object):
         def __set__(self, style):
             if isinstance(style, unicode): style = style.encode("UTF-8")
             self._item_style = style
-            self.obj.item_style = <char *>style if style is not None else NULL
+            self.cls.item_style = <char *>style if style is not None else NULL
 
     property decorate_item_style:
         """The decoration style of this item class."""
@@ -819,7 +814,7 @@ cdef class GenlistItemClass(object):
         def __set__(self, style):
             if isinstance(style, unicode): style = style.encode("UTF-8")
             self._decorate_item_style = style
-            self.obj.decorate_item_style = <char *>style if style is not None 
else NULL
+            self.cls.decorate_item_style = <char *>style if style is not None 
else NULL
 
     property decorate_all_item_style:
         """Decorate all style of this item class."""
@@ -829,7 +824,7 @@ cdef class GenlistItemClass(object):
         def __set__(self, style):
             if isinstance(style, unicode): style = style.encode("UTF-8")
             self._decorate_all_item_style = style
-            self.obj.decorate_all_item_style = <char *>style if style is not 
None else NULL
+            self.cls.decorate_all_item_style = <char *>style if style is not 
None else NULL
 
     def text_get(self, evasObject obj, part, item_data):
         """To be called by Genlist for each row to get its label.
@@ -927,7 +922,7 @@ cdef class GenlistItem(ObjectItem):
 
         """
 
-        self.item_class = item_class.obj
+        self.item_class = &item_class.cls
 
         self.parent_item = _object_item_from_python(parent_item) if 
parent_item is not None else NULL
 
@@ -1238,7 +1233,7 @@ cdef class GenlistItem(ObjectItem):
         called on the item.
 
         """
-        elm_genlist_item_item_class_update(self.item, itc.obj)
+        elm_genlist_item_item_class_update(self.item, &itc.cls)
 
     #TODO: def item_class_get(self):
         """This returns the Genlist_Item_Class for the given item. It can be
diff --git a/efl/elementary/store.pxd b/efl/elementary/store.pxd
new file mode 100644
index 0000000..8415dfb
--- /dev/null
+++ b/efl/elementary/store.pxd
@@ -0,0 +1,111 @@
+from libc.stdlib cimport const_void
+from libc.string cimport const_char
+
+from efl cimport Eina_Bool
+from efl.evas cimport Evas_Object
+from enums cimport Elm_Icon_Lookup_Order, Elm_Store_Item_Mapping_Type
+from genlist cimport Elm_Genlist_Item_Class
+from object_item cimport Elm_Object_Item, const_Elm_Object_Item
+
+cdef extern from "Python.h":
+    void PyEval_InitThreads()
+
+cdef extern from "Elementary.h":
+    struct _Elm_Store:
+        pass
+
+    struct _Elm_Store_Item:
+        pass
+
+    ctypedef _Elm_Store         Elm_Store # A store object
+    ctypedef _Elm_Store         const_Elm_Store
+    ctypedef _Elm_Store_Item    Elm_Store_Item # A handle of a store item 
passed to store fetch/unfetch functions
+    ctypedef _Elm_Store_Item    const_Elm_Store_Item
+
+    ctypedef void                                 
(*Elm_Store_Item_Fetch_Cb)(void *data, Elm_Store_Item *sti) # Function to call 
to fetch item data
+    ctypedef void                                 
(*Elm_Store_Item_Unfetch_Cb)(void *data, Elm_Store_Item *sti) # Function to cal 
lto un-fetch (free) an item
+    ctypedef void                                
*(*Elm_Store_Item_Mapping_Cb)(void *data, Elm_Store_Item *sti, const_char 
*part) # Custom mapping function to call
+
+    struct _Elm_Store_Item_Mapping_Icon:
+        int                   w, h # The desired icon size in addition to the 
file path returned from the mapping
+        Elm_Icon_Lookup_Order lookup_order # The order in which to find the 
icon
+        Eina_Bool             standard_name # Use a standard name to find it 
(EINA_TRUE) or not
+        Eina_Bool             no_scale # EINA_TRUE is you don't want the icon 
scaled
+        Eina_Bool             smooth # EINA_TRUE if icon is to be smooth scaled
+        Eina_Bool             scale_up # EINA_TRUE if scaling up is allowed
+        Eina_Bool             scale_down # EINA_TRUE if scaling down is allowed
+
+    ctypedef _Elm_Store_Item_Mapping_Icon    Elm_Store_Item_Mapping_Icon # The 
data being mapped at the given address is an icon, so use these properties for 
finding it
+
+    struct _Elm_Store_Item_Mapping_Empty:
+        Eina_Bool dummy # dummy entry - set to anything you like
+
+    ctypedef _Elm_Store_Item_Mapping_Empty   Elm_Store_Item_Mapping_Empty # An 
empty piece of mapping information. Useful for String labels as they get used 
directly
+
+    struct _Elm_Store_Item_Mapping_Photo:
+        int size # Photo size to use (see elm_photo_add()) with the given 
photo path
+
+    ctypedef _Elm_Store_Item_Mapping_Photo   Elm_Store_Item_Mapping_Photo # 
The data is a photo, so use these parameters to find it
+
+    struct _Elm_Store_Item_Mapping_Custom:
+        Elm_Store_Item_Mapping_Cb func # The function called to do the custom 
mapping and return it
+
+    ctypedef _Elm_Store_Item_Mapping_Custom  Elm_Store_Item_Mapping_Custom # 
The item needs a custom mapping which means calling a function and returning a 
string from it, as opposed to a static lookup. It should not be allocated, and 
should live in a buffer in memory that survives the return of this function if 
its a label, or an allocated icon object if its an icon needed etc.
+
+    union _Elm_Store_Item_Mapping_Details:
+        # Allowed to be one of these possible mapping types
+        Elm_Store_Item_Mapping_Empty  empty
+        Elm_Store_Item_Mapping_Icon   icon
+        Elm_Store_Item_Mapping_Photo  photo
+        Elm_Store_Item_Mapping_Custom custom
+        # add more types here
+
+    struct _Elm_Store_Item_Mapping:
+        Elm_Store_Item_Mapping_Type type # what kind of mapping is this
+        const_char                 *part # what part name in the genlist item 
is this filling in
+        int                         offset # offset in memory (in bytes) 
relative to base of structure for item data where the data for the mapping lives
+        _Elm_Store_Item_Mapping_Details details
+
+    ctypedef _Elm_Store_Item_Mapping        Elm_Store_Item_Mapping # A basic 
way of telling Store how to take your return data (string, or something else 
from your struct) and convert it into something genlist can use
+    ctypedef _Elm_Store_Item_Mapping        const_Elm_Store_Item_Mapping
+
+    struct _Elm_Store_Item_Info:
+        Elm_Genlist_Item_Class       *item_class # The genlist item class that 
should be used for the item that has been listed
+        const_Elm_Store_Item_Mapping *mapping # What kind of mappings do we 
use for the fields of this item to fill in the genlist item. Terminate array 
pointed to here with ELM_STORE_ITEM_MAPPING_END
+        void                         *data # Pointer to pass to struct data in 
memory if its already there, of not, NULL
+        char                         *sort_id # Sort ID string (strduped()) to 
know how to wort items, or NULL, if you don't care
+
+    ctypedef _Elm_Store_Item_Info            Elm_Store_Item_Info # Basic 
information about a store item - always cast into a specific type like 
Elm_Store_Item_Info_Filesystem
+
+    ctypedef Eina_Bool                            
(*Elm_Store_Item_List_Cb)(void *data, Elm_Store_Item_Info *info) # Function to 
call for listing an item
+
+    struct _Elm_Store_Item_Info_Filesystem:
+        Elm_Store_Item_Info base # Base information about an item
+        char               *path # Extra information specific to the 
filesystem store
+
+    ctypedef _Elm_Store_Item_Info_Filesystem Elm_Store_Item_Info_Filesystem # 
Filesystem specific information about a store item
+
+    #define ELM_STORE_ITEM_MAPPING_END { ELM_STORE_ITEM_MAPPING_NONE, NULL, 0, 
{ .empty = { EINA_TRUE } } } # Use this to end a list of mappings
+    #define ELM_STORE_ITEM_MAPPING_OFFSET(st, it) offsetof(st, it) # Use this 
to get the offset in bytes in memory for where the data for the mapping lives 
relative to the item data (a private struct pointed to owned by the user
+
+
+
+    Elm_Store              *elm_store_filesystem_new()
+    void                    elm_store_free(Elm_Store *st)
+    void                    elm_store_filesystem_directory_set(Elm_Store *st, 
const_char *dir)
+    const_char             *elm_store_filesystem_directory_get(const_Elm_Store 
*st)
+    const_char             
*elm_store_item_filesystem_path_get(const_Elm_Store_Item *sti)
+    void                    elm_store_target_genlist_set(Elm_Store *st, 
Evas_Object *obj)
+    void                    elm_store_cache_set(Elm_Store *st, int max)
+    int                     elm_store_cache_get(const_Elm_Store *st)
+    void                    elm_store_list_func_set(Elm_Store *st, 
Elm_Store_Item_List_Cb func, const_void *data)
+    void                    elm_store_fetch_func_set(Elm_Store *st, 
Elm_Store_Item_Fetch_Cb func, const_void *data)
+    void                    elm_store_unfetch_func_set(Elm_Store *st, 
Elm_Store_Item_Unfetch_Cb func, const_void *data)
+    void                    elm_store_fetch_thread_set(Elm_Store *st, 
Eina_Bool use_thread)
+    Eina_Bool               elm_store_fetch_thread_get(const_Elm_Store *st)
+    void                    elm_store_sorted_set(Elm_Store *st, Eina_Bool 
sorted)
+    Eina_Bool               elm_store_sorted_get(const_Elm_Store *st)
+    void                    elm_store_item_data_set(Elm_Store_Item *sti, void 
*data)
+    void                   *elm_store_item_data_get(Elm_Store_Item *sti)
+    const_Elm_Store        *elm_store_item_store_get(const_Elm_Store_Item *sti)
+    const_Elm_Object_Item  
*elm_store_item_genlist_item_get(const_Elm_Store_Item *sti)
diff --git a/efl/elementary/store.pyx b/efl/elementary/store.pyx
new file mode 100644
index 0000000..c085165
--- /dev/null
+++ b/efl/elementary/store.pyx
@@ -0,0 +1,551 @@
+# 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 <http://www.gnu.org/licenses/>.
+
+"""
+
+Store Elementary Store
+
+Store is an abstracting API that is intended to farm off fetching of data
+to threads running asynchronously from the mainloop that actually fetch
+data needed for a genlist (or possibly future other widgets) so scrolling
+never blocks waiting on IO (though normally this should be the users
+job - if using genlist, to ensure all data genlist needs is in memory at
+the time it needs it, and if it isn't to queue and defer a fetch and let
+genlist know later when its ready. Store actually does this and implements
+the infrastructure of this, leaving the actual fetch and convert up to
+functions provided by the user).
+
+It is possible for store to run inline without a thread, but this is
+highly inadvisable. you can disable this with::
+
+    st.fetch_thread = False
+
+Store works first by creating a store, setting up functions to list items
+and fetch items. Currently the only store type supported is the
+filesystem store, which will list the files inside a directory (not
+recursively) and then hand each file it finds (the file path) to the
+list function for evaluation.
+
+The list function may look at filename, may open the file or do
+anything it likes to determine something about the file. Either it
+filters it out (returns EINA_FALSE) and it is discarded or it
+returns EINA_TRUE and also provides a "sort id" which is a string
+store uses to figure out sorting. This string could be the filename, or
+some data based on its contents. The strings are sorted alphabetically
+like any normal ASCII strings, with case being important. As this listing
+function runs in a thread, it can do blocking IO and parsing without
+hurting the fluidity of the main loop and GUI. The list function also
+returns information on how to map fields in the source file to elements
+of the genlist item. For example, how the fetcher reads the private
+data struct of the user (what memory offset in the struct the data is at)
+and what type is there (it's a label of some sort, an icon, or with a
+custom mapping function that figures it out itself and creates the
+content needed for the genlist item).
+
+Store then uses this sort id to build (over time) a sorted list of items
+that then map 1:1 to genlist items. When these items are visible and
+need content, Store calls the fetch function per item, which is responsible
+for fetching the data from the given item and returning data to store
+so it can map this to some item content. This function also runs in a
+thread, and thus can do blocking IO work to later return the data. Sorting
+is optional and can be enabled or disabled too.
+
+When items are no longer needed, store will cal the unfetch function to
+free data in memory about that item that is no longer needed. This function
+is called in the mainloop and is expected to take minimal or almost no time
+to simply free up memory resources.
+
+
+.. _Elm_Store_Item_Mapping_Type:
+
+.. rubric:: Store item mapping types
+
+.. data:: ELM_STORE_ITEM_MAPPING_NONE
+
+    None
+
+.. data:: ELM_STORE_ITEM_MAPPING_LABEL
+
+    const_char * -> label
+
+.. data:: ELM_STORE_ITEM_MAPPING_STATE
+
+    Eina_Bool -> state
+
+.. data:: ELM_STORE_ITEM_MAPPING_ICON
+
+    char * -> icon path
+
+.. data:: ELM_STORE_ITEM_MAPPING_PHOTO
+
+    char * -> photo path
+
+.. data:: ELM_STORE_ITEM_MAPPING_CUSTOM
+
+    item->custom(it->data, it, part) -> void * (-> any)
+
+"""
+
+from libc.string cimport strdup
+from cpython cimport Py_INCREF, Py_DECREF
+from efl.eo cimport _ctouni, _touni
+from object cimport Object
+from object_item cimport _object_item_to_python
+from genlist cimport GenlistItemClass
+
+import traceback
+
+PyEval_InitThreads()
+
+cdef Eina_Bool store_fs_item_list_cb(void *data, Elm_Store_Item_Info *info) 
with gil:
+    """Function to call for listing an item (filesystem)"""
+    cdef StoreItemInfoFilesystem ifs = 
StoreItemInfoFilesystem.__new__(StoreItemInfoFilesystem)
+    ifs.info_fs = <Elm_Store_Item_Info_Filesystem *>info
+    func, args, kwargs = <object>data
+    try:
+        ret = func(ifs, args, kwargs)
+    except Exception, e:
+        traceback.print_exc()
+
+    ifs.info_fs = NULL
+
+    if ret is not None:
+        return bool(ret)
+    else:
+        return 0
+
+cdef void store_item_fetch_cb(void *data, Elm_Store_Item *sti) with gil:
+    """Function to call to fetch item data"""
+    cdef StoreItem it = StoreItem.__new__(StoreItem)
+    it.sti = sti
+    func, args, kwargs = <object>data
+    try:
+        func(it, args, kwargs)
+    except Exception, e:
+        traceback.print_exc()
+
+    it.sti = NULL
+
+cdef void store_item_unfetch_cb(void *data, Elm_Store_Item *sti) with gil:
+    """Function to call to un-fetch (free) an item"""
+    cdef StoreItem it = StoreItem.__new__(StoreItem)
+    it.sti = sti
+    func, args, kwargs = <object>data
+    try:
+        func(it, args, kwargs)
+    except Exception, e:
+        traceback.print_exc()
+
+    it.sti = NULL
+
+cdef void *store_item_mapping_cb(void *data, Elm_Store_Item *sti, const_char 
*part) with gil:
+    """Custom mapping function to call"""
+    pass
+
+cimport enums
+
+ELM_STORE_ITEM_MAPPING_NONE = enums.ELM_STORE_ITEM_MAPPING_NONE
+ELM_STORE_ITEM_MAPPING_LABEL = enums.ELM_STORE_ITEM_MAPPING_LABEL
+ELM_STORE_ITEM_MAPPING_STATE = enums.ELM_STORE_ITEM_MAPPING_STATE
+ELM_STORE_ITEM_MAPPING_ICON = enums.ELM_STORE_ITEM_MAPPING_ICON
+ELM_STORE_ITEM_MAPPING_PHOTO = enums.ELM_STORE_ITEM_MAPPING_PHOTO
+ELM_STORE_ITEM_MAPPING_CUSTOM = enums.ELM_STORE_ITEM_MAPPING_CUSTOM
+
+"""
+struct _Elm_Store_Item_Mapping_Custom:
+    Elm_Store_Item_Mapping_Cb func # The function called to do the custom 
mapping and return it
+
+#define ELM_STORE_ITEM_MAPPING_END { ELM_STORE_ITEM_MAPPING_NONE, NULL, 0, { 
.empty = { EINA_TRUE } } } # Use this to end a list of mappings
+#define ELM_STORE_ITEM_MAPPING_OFFSET(st, it) offsetof(st, it)
+"""
+
+include "store_item_mapping.pxi"
+
+cdef class StoreItemInfo(object):
+
+    cdef:
+        Elm_Store_Item_Info *info
+
+    property item_class:
+        """The genlist item class that should be used for the item that has 
been
+        listed
+
+        :type: :py:class:`GenlistItemClass 
<efl.elementary.genlist.GenlistItemClass>`
+
+        """
+        def __set__(self, GenlistItemClass value):
+            self.info.item_class = &value.cls
+
+        def __get__(self):
+            cdef GenlistItemClass ret = 
GenlistItemClass.__new__(GenlistItemClass)
+            ret.cls = self.info.item_class[0]
+            return ret
+
+    # property mapping:
+    #     """What kind of mappings do we use for the fields of this item to 
fill
+    #     in the genlist item. Terminate array pointed to here with
+    #     ELM_STORE_ITEM_MAPPING_END
+
+    #     :type: StoreItemMapping
+
+    #     """
+    #     def __set__(self, value):
+    #         self.info.mapping = value
+
+    #     def __get__(self):
+    #         cdef StoreItemMapping
+    #         return self.info.mapping
+
+    property data:
+        """Pointer to pass to struct data in memory if its already there, or
+        NULL if not.
+
+        :type: object
+
+        """
+        def __set__(self, value):
+            self.info.data = <void *>value
+
+        def __get__(self):
+            if not self.info.data == NULL:
+                return <object>self.info.data
+
+    property sort_id:
+        """Sort ID string (strduped()) to know how to sort items, or NULL, if
+        you don't care.
+
+        :type: unicode
+
+        """
+        def __set__(self, value):
+            if isinstance(value, unicode): value = value.encode("UTF-8")
+            self.info.sort_id = strdup(value)
+
+        def __get__(self):
+            return _touni(self.info.sort_id)
+
+cdef class StoreItemInfoFilesystem(object):
+
+    cdef Elm_Store_Item_Info_Filesystem *info_fs
+
+    property base:
+        """Base information about an item
+
+        :type: StoreItemInfo
+
+        """
+        def __get__(self):
+            cdef StoreItemInfo ret = StoreItemInfo.__new__(StoreItemInfo)
+            ret.info = &self.info_fs.base
+            return ret
+
+    property path:
+        """Extra information specific to the filesystem store
+
+        :type: unicode
+
+        """
+        def __set__(self, value):
+            if isinstance(value, unicode): value = value.encode("UTF-8")
+            self.info_fs.path = strdup(value)
+
+        def __get__(self):
+            return _touni(self.info_fs.path)
+
+
+cdef class Store(object):
+
+    """The class that holds the implementation of the widget."""
+
+    cdef Elm_Store *st
+
+    def __init__(self, store_type = None):
+        self.st = elm_store_filesystem_new()
+
+        if self.st == NULL:
+            Py_DECREF(self)
+
+    def delete(self):
+        """Free the store object and all items it manages
+
+        This frees the given @p st store and all the items it manages. It will
+        clear the List that it populated, but otherwise leave it alone. It will
+        cancel background threads (and may have to wait for them to complete a
+        pending operation to do this).
+
+        """
+        elm_store_free(self.st)
+
+    property filesystem_directory:
+        """The path to the directory to scan for a filesystem store
+
+        This sets the directory (@p dir) to scan and begins scanning in the
+        the background in threads (or not if threading is disabled with
+        elm_store_fetch_thread_set()). Note that Listing is always done in a 
thread
+        but fetching may not be if disabled here. This should be the last thing
+        called after fetch, list and unfetch functions are set, as well as 
target
+        genlist etc. You also should not change the directory once set. If you
+        need a new directory scanned, create a new store.
+
+        This gets the directory set by elm_store_filesystem_directory_set(). 
This
+        string returned will be valid until 
elm_store_filesystem_directory_set()
+        changes it or until the store is freed with elm_store_free().
+
+        :type: unicode
+
+        """
+        def __set__(self, value):
+            self.filesystem_directory_set(value)
+
+        def __get__(self):
+            return self.filesystem_directory_get()
+
+    cpdef filesystem_directory_set(self, directory):
+        if isinstance(directory, unicode): directory = 
directory.encode("UTF-8")
+        elm_store_filesystem_directory_set(self.st,
+            <const_char *>directory if directory is not None else NULL)
+
+    cpdef filesystem_directory_get(self):
+        return _ctouni(elm_store_filesystem_directory_get(self.st))
+
+    property target_genlist:
+        """Set the target genlist to fill in from the store
+
+        This tells the store the target genlist to use to fill in content from
+        the store. Once a store starts "going" via 
elm_store_filesystem_directory_set()
+        The target should never be changed again.
+
+        :type: :py:class:`Genlist <efl.elementary.genlist.Genlist>`
+
+        """
+        def __set__(self, value):
+            self.target_genlist_set(value)
+
+    cpdef target_genlist_set(self, Object target):
+        elm_store_target_genlist_set(self.st, target.obj)
+
+    property cache_size:
+        """Set the maximum number of items that are not visible to keep cached
+
+        Store may keep some items around for caching purposes that cannot be 
seen,
+        so this controls the maximum number. The default is 128, but may change
+        at any point in time in the future.
+
+        :param max: The number of items to keep (should be greater than or 
equal to 0)
+
+        """
+        def __set__(self, value):
+            self.cache_set(value)
+
+        def __get__(self):
+            return self.cache_get()
+
+    cpdef cache_size_set(self, int maximum):
+        elm_store_cache_set(self.st, maximum)
+
+    cpdef cache_size_get(self):
+        return elm_store_cache_get(self.st)
+
+    def fs_list_func_set(self, func, *args, **kwargs):
+        """Set the function used to deal with listing of items
+
+        This function is called per item that is found so it can examine the
+        item and discard it (return EINA_FALSE to discard, or EINA_TRUE to
+        accept), and work out some sorting ID (that may be filename or anything
+        else based on content). This function is always called from a thread.
+
+        :param func: The function to be called
+
+        """
+        if not callable(func):
+            raise TypeError("func is not callable.")
+
+        data = (func, args, kwargs)
+        Py_INCREF(data)
+
+        elm_store_list_func_set(self.st, store_fs_item_list_cb,
+            <const_void *>data)
+
+    def fetch_func_set(self, func, *args, **kwargs):
+        """Set the function used to deal with fetching of items
+
+        This function is called per item that needs data to be fetched when it
+        becomes visible and such data is needed. This function is normally run
+        from a thread (unless elm_store_fetch_thread_set() disables this). The
+        fetch function is to read data from the source and fill a structure
+        allocated for this item with fields and then rely on the mapping setup
+        to tell Store how to take a field in the structure and apply it to a
+        genlist item.
+
+        :param func: The function to be called
+
+        """
+        if not callable(func):
+            raise TypeError("func is not callable.")
+
+        data = (func, args, kwargs)
+        Py_INCREF(data)
+
+        elm_store_fetch_func_set(self.st, store_item_fetch_cb,
+            <const_void *>data)
+
+    def unfetch_func_set(self, func, *args, **kwargs):
+        """Set the function used to free the structure allocated for the item
+
+        This function is called per item when it is not needed in memory 
anymore
+        and should free the structure allocated in and filled in the function
+        set by elm_store_fetch_func_set().
+
+        :param func: The function to be called
+
+        """
+        if not callable(func):
+            raise TypeError("func is not callable.")
+
+        data = (func, args, kwargs)
+        Py_INCREF(data)
+
+        elm_store_unfetch_func_set(self.st, store_item_unfetch_cb,
+            <const_void *>data)
+
+    property fetch_thread:
+        """Enable or disable fetching in a thread for Store
+
+        :type: bool
+
+        """
+        def __set__(self, value):
+            self.fetch_thread_set(value)
+
+        def __get__(self):
+            return self.fetch_thread_get()
+
+    cpdef fetch_thread_set(self, bint use_thread):
+        elm_store_fetch_thread_set(self.st, use_thread)
+
+    cpdef bint fetch_thread_get(self):
+        return elm_store_fetch_thread_get(self.st)
+
+    property items_sorted:
+        """Set if items are to be sorted or not.
+
+        By default items are not sorted, but read "in order" as they are 
found. If
+        you want to sort, your list function set by elm_store_list_func_set() 
must
+        provide a sort ID to sort by, and then Store will take care of sorting 
when
+        it inserts items. You should set this up before you begin listing items
+        in the store and then never change it again.
+
+        :type: bool
+
+        """
+        def __set__(self, value):
+            self.sorted_set(value)
+
+        def __get__(self):
+            return self.sorted_get()
+
+    cpdef sorted_set(self, bint items_sorted):
+        elm_store_sorted_set(self.st, items_sorted)
+
+    cpdef bint sorted_get(self):
+        return elm_store_sorted_get(self.st)
+
+
+cdef class StoreItem(object):
+
+    cdef Elm_Store_Item *sti
+
+    property filesystem_path:
+        """Get the path of a specific store item
+
+        This returns the full path of a store item. This string is valid only
+        during the list function set by elm_store_list_func_set() or during the
+        fetch function set by elm_store_fetch_func_set() or during the unfetch
+        function set by elm_store_unfetch_func_set().
+
+        :param sti: The store item to get the path from
+        :return: A full path in a string or NULL if none available
+
+        """
+        def __get__(self):
+            return self.filesystem_path_get()
+
+    cpdef filesystem_path_get(self):
+        return _ctouni(elm_store_item_filesystem_path_get(self.sti))
+
+    property data:
+        """Set the item data holding item fields to map to item values in 
genlist
+
+        Once you decode an item, allocate a structure for it and fill the 
structure,
+        you should set the item data with this function (eg in the fetch 
function).
+        This item pointer is the base offset to use when mapping fields to item
+        values. Once you unfetch, store will handle NULLing the data pointer 
for you.
+
+        :param sti: The store item to set the data pointer of
+        :param data: The data pointer to set.
+
+        """
+        def __set__(self, value):
+            self.data_set(value)
+
+        def __get__(self):
+            return self.data_get()
+
+    cpdef data_set(self, data):
+        elm_store_item_data_set(self.sti, <void *>data)
+
+    cpdef data_get(self):
+        cdef void *data = elm_store_item_data_get(self.sti)
+        if data == NULL: return None
+        return <object>elm_store_item_data_get(self.sti)
+
+    property store:
+        """Fetch the store than a store item belongs to
+
+        This fetches the store object that owns the store item.
+
+        :param sti: The store item to query
+        :return: The store the item belongs to
+
+        """
+        def __get__(self):
+            return self.store_get()
+
+    cpdef store_get(self):
+        cdef:
+            Store ret
+            Elm_Store *st = <Elm_Store *>elm_store_item_store_get(self.sti)
+
+        if st == NULL:
+            return None
+
+        ret = Store.__new__()
+        ret.st = st
+        return ret
+
+    property genlist_item:
+        """Fetch the genlist item that this store item controls
+
+        :param sti: The store item to query
+        :return: The genlist object item handle controlled by this store item
+
+        """
+        def __get__(self):
+            return self.genlist_item_get()
+
+    cpdef genlist_item_get(self):
+        return _object_item_to_python(<Elm_Object_Item 
*>elm_store_item_genlist_item_get(self.sti))
diff --git a/efl/elementary/store_item_mapping.pxi 
b/efl/elementary/store_item_mapping.pxi
new file mode 100644
index 0000000..42a8233
--- /dev/null
+++ b/efl/elementary/store_item_mapping.pxi
@@ -0,0 +1,202 @@
+cdef class StoreItemMapping(object):
+
+    cdef Elm_Store_Item_Mapping mapping
+
+    property mapping_type:
+        """What kind of mapping is this
+
+        :type: :ref:`Mapping type <Elm_Store_Item_Mapping_Type>`
+
+        """
+        def __set__(self, value):
+            self.mapping.type = value
+
+        def __get__(self):
+            return self.mapping.type
+
+    property part:
+        """What part name in the genlist item is this filling in
+
+        :type: unicode
+
+        """
+        def __set__(self, value):
+            if isinstance(value, unicode): value = value.encode("UTF-8")
+            self.mapping.part = strdup(value)
+
+        def __get__(self):
+            return _ctouni(self.mapping.part)
+
+    property offset:
+        """Offset in memory (in bytes) relative to base of structure for item
+        data where the data for the mapping lives.
+
+        :type: int
+
+        """
+        def __set__(self, value):
+            self.mapping.offset = value
+
+        def __get__(self):
+            return self.mapping.offset
+
+
+
+cdef class StoreItemMappingIcon(StoreItemMapping):
+
+    cdef Elm_Store_Item_Mapping_Icon details
+
+    property w:
+        """The desired icon size in addition to the file path returned from
+        the mapping
+
+        :type: int
+
+        """
+        def __set__(self, int value):
+            self.details.w = value
+
+        def __get__(self):
+            return self.details.w
+
+    property h:
+        """The desired icon size in addition to the file path returned from
+        the mapping
+
+        :type: int
+
+        """
+        def __set__(self, int value):
+            self.details.h = value
+
+        def __get__(self):
+            return self.details.h
+
+    property lookup_order:
+        """The order in which to find the icon
+
+        :type: Elm_Icon_Lookup_Order
+
+        """
+        def __set__(self, Elm_Icon_Lookup_Order value):
+            self.details.lookup_order = value
+
+        def __get__(self):
+            return self.details.lookup_order
+
+    property standard_name:
+        """Use a standard name to find it (EINA_TRUE) or not
+
+        :type: bool
+
+        """
+        def __set__(self, bint value):
+            self.details.standard_name = value
+
+        def __get__(self):
+            return bool(self.details.standard_name)
+
+    property no_scale:
+        """EINA_TRUE is you don't want the icon scaled
+
+        :type: bool
+
+        """
+        def __set__(self, bint value):
+            self.details.no_scale = value
+
+        def __get__(self):
+            return bool(self.details.no_scale)
+
+    property smooth:
+        """EINA_TRUE if icon is to be smooth scaled
+
+        :type: bool
+
+        """
+        def __set__(self, bint value):
+            self.details.smooth = value
+
+        def __get__(self):
+            return bool(self.details.smooth)
+
+    property scale_up:
+        """EINA_TRUE if scaling up is allowed
+
+        :type: bool
+
+        """
+        def __set__(self, bint value):
+            self.details.scale_up = value
+
+        def __get__(self):
+            return bool(self.details.scale_up)
+
+    property scale_down:
+        """EINA_TRUE if scaling down is allowed
+
+        :type: bool
+
+        """
+        def __set__(self, bint value):
+            self.details.scale_down = value
+
+        def __get__(self):
+            return bool(self.details.scale_down)
+
+
+
+cdef class StoreItemMappingEmpty(StoreItemMapping):
+
+    cdef Elm_Store_Item_Mapping_Empty details
+
+    def __cinit__(self):
+        self.details.dummy = 1
+        self.mapping.details.empty = self.details
+
+cdef class StoreItemMappingNone(StoreItemMappingEmpty):
+    def __init__(self, part, data):
+        if isinstance(part, unicode): part = part.encode("UTF-8")
+        self.mapping.type = enums.ELM_STORE_ITEM_MAPPING_NONE
+        self.mapping.part = part
+        self.mapping.offset = 0
+
+cdef class StoreItemMappingLabel(StoreItemMappingEmpty):
+    def __init__(self, part, data):
+        if isinstance(part, unicode): part = part.encode("UTF-8")
+        self.mapping.type = enums.ELM_STORE_ITEM_MAPPING_LABEL
+        self.mapping.part = part
+        self.mapping.offset = 0
+
+cdef class StoreItemMappingState(StoreItemMappingEmpty):
+    def __init__(self, part, data):
+        if isinstance(part, unicode): part = part.encode("UTF-8")
+        self.mapping.type = enums.ELM_STORE_ITEM_MAPPING_STATE
+        self.mapping.part = part
+        self.mapping.offset = 0
+
+
+
+cdef class StoreItemMappingPhoto(StoreItemMapping):
+
+    cdef Elm_Store_Item_Mapping_Photo details
+
+    def __init__(self, part, data, size):
+        if isinstance(part, unicode): part = part.encode("UTF-8")
+        self.mapping.type = enums.ELM_STORE_ITEM_MAPPING_PHOTO
+        self.mapping.part = part
+        self.mapping.offset = 0
+        self.details.size = size
+        self.mapping.details.photo = self.details
+
+    property size:
+        """Photo size to use (see elm_photo_add()) with the given photo path
+
+        :type: int
+
+        """
+        def __set__(self, value):
+            self.mapping.details.photo.size = value
+
+        def __get__(self):
+            return self.mapping.details.photo.size
diff --git a/examples/elementary/test_store.py 
b/examples/elementary/test_store.py
new file mode 100644
index 0000000..303d1bb
--- /dev/null
+++ b/examples/elementary/test_store.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# encoding: utf-8
+
+from efl.evas import EVAS_HINT_EXPAND, EVAS_HINT_FILL
+from efl import elementary
+from efl.elementary.genlist import Genlist, GenlistItemClass, ELM_LIST_COMPRESS
+from efl.elementary.store import Store, StoreItemMappingLabel, 
StoreItemMappingNone
+from efl.elementary.box import Box
+from efl.elementary.window import StandardWindow
+
+class My_Item(object):
+    sender = None
+    subject = None
+    date = None
+    head_content = None
+
+# callbacks just to see user interacting with genlist
+def st_selected(obj, event_info):
+    print("selected: %s" % event_info)
+
+def st_double_clicked(obj, event_info):
+    print("double clicked: %s" % event_info)
+
+def st_longpress(obj, event_info):
+    print("longpress %s" % event_info)
+
+mapping = [
+    StoreItemMappingLabel("elm.title.1", 1),
+    StoreItemMappingLabel("elm.title.2", 2),
+    StoreItemMappingLabel("elm.text", 3),
+    StoreItemMappingNone("elm.swallow.icon", 0),
+    StoreItemMappingNone("elm.swallow.end", 0),
+]
+
+def st_store_list(info, *args, **kwargs):
+    if info.path.endswith("py"):
+        info.base.item_class = GenlistItemClass(item_style="default")
+        return True
+    else:
+        return False
+    # char sort_id[7];
+
+    # # create a sort id based on the filename itself assuming it is a numeric
+    # # value like the id number in mh mail folders which is what this test
+    # # uses as a data source
+    # file = strrchr(info.path, '/')
+    # if file: file++
+    # else file = info.path
+    # id = atoi(file);
+    # sort_id[0] = ((id >> 30) & 0x3f) + 32;
+    # sort_id[1] = ((id >> 24) & 0x3f) + 32;
+    # sort_id[2] = ((id >> 18) & 0x3f) + 32;
+    # sort_id[3] = ((id >> 12) & 0x3f) + 32;
+    # sort_id[4] = ((id >>  6) & 0x3f) + 32;
+    # sort_id[5] = ((id >>  0) & 0x3f) + 32;
+    # sort_id[6] = 0;
+    # info.base.sort_id = strdup(sort_id);
+    # # choose the item genlist item class to use (only item style should be
+    # # provided by the app, store will fill everything else in, so it also
+    # # has to be writable
+    # info.base.item_class = itc1; # based on item info - return the item 
class wanted (only style field used - rest reset to internal funcs store sets 
up to get label/icon etc)
+    # info.base.mapping = it1_mapping;
+    # info.base.data = NULL; # if we can already parse and load all of item 
here and want to - set this
+    # return True; # return true to include this, false not to
+
+def st_store_fetch(sti, *args, **kwargs):
+    if sti.data: return
+    path = sti.filesystem_path
+    have_content = None
+    content = []
+    myit = My_Item()
+    with open(path, "r", encoding="UTF-8") as f:
+        for line in f:
+            if have_content is None:
+                if line.startswith("From:"):
+                    myit.sender = line[5:]
+                elif line.startswith("Subject:"):
+                    myit.subject = line[8:]
+                elif line.startswith("Date:"):
+                    myit.date = line[5:]
+                elif line == "\n":
+                    have_content = True
+            else:
+                content.append(line)
+
+    myit.head_content = content #elm_entry_utf8_to_markup(content)
+    sti.data = myit
+
+def st_store_unfetch(sti, *args, **kwargs):
+    print("unfetch")
+
+def store_clicked(obj):
+    win = StandardWindow("store", "Store")
+    win.autodel = True
+    if obj is None:
+        win.callback_delete_request_add(lambda o: elementary.exit())
+
+    bx = Box(win)
+    bx.size_hint_weight = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
+    win.resize_object_add(bx)
+    bx.show()
+
+    gl = Genlist(win)
+    gl.mode = ELM_LIST_COMPRESS
+    gl.callback_selected_add(st_selected)
+    gl.callback_clicked_double_add(st_double_clicked)
+    gl.callback_longpressed_add(st_longpress)
+    gl.size_hint_weight = EVAS_HINT_EXPAND, EVAS_HINT_EXPAND
+    gl.size_hint_align = EVAS_HINT_FILL, EVAS_HINT_FILL
+    bx.pack_end(gl)
+    gl.show()
+
+    itc1 = GenlistItemClass()
+    itc1.item_style = "message"
+
+    st = Store()
+    st.fs_list_func_set(st_store_list)
+    st.fetch_func_set(st_store_fetch)
+    #st.fetch_thread = False
+    #st.unfetch_func_set(st_store_unfetch)
+    st.items_sorted = False
+    st.target_genlist = gl
+    st.filesystem_directory = "."
+
+    win.size = 480, 800
+    win.show()
+
+if __name__ == "__main__":
+    elementary.init()
+
+    store_clicked(None)
+
+    elementary.run()
+    elementary.shutdown()
diff --git a/setup.py b/setup.py
index a2688fd..2b48b7f 100755
--- a/setup.py
+++ b/setup.py
@@ -200,6 +200,7 @@ else:
         Extension("efl.elementary.slider", ["efl/elementary/slider.pyx"]),
         Extension("efl.elementary.slideshow", 
["efl/elementary/slideshow.pyx"]),
         Extension("efl.elementary.spinner", ["efl/elementary/spinner.pyx"]),
+        #Extension("efl.elementary.store", ["efl/elementary/store.pyx"]),
         Extension("efl.elementary.table", ["efl/elementary/table.pyx"]),
         Extension("efl.elementary.theme", ["efl/elementary/theme.pyx"]),
         Extension("efl.elementary.thumb", ["efl/elementary/thumb.pyx"]),

-- 

------------------------------------------------------------------------------
Precog is a next-generation analytics platform capable of advanced
analytics on semi-structured data. The platform includes APIs for building
apps and a phenomenal toolset for data science. Developers can use
our toolset for easy data analysis & visualization. Get a free account!
http://www2.precog.com/precogplatform/slashdotnewsletter

Reply via email to