From 87ee22d55910144f13a0048c2ebfbfe7d07b1420 Mon Sep 17 00:00:00 2001 From: Kai Huuhko Date: Thu, 10 Oct 2013 05:42:39 +0300 Subject: [PATCH] Elementary: DnD work - Genlist default animation test functional - Some callbacks are still missing --- efl/elementary/cnp_callbacks.pxi | 150 +++++++++++++++++++++++++++- efl/elementary/genlist_widget.pxi | 13 ++- examples/elementary/test_dnd.py | 157 +++++++++++++----------------- 3 files changed, 223 insertions(+), 97 deletions(-) diff --git a/efl/elementary/cnp_callbacks.pxi b/efl/elementary/cnp_callbacks.pxi index 958bbb6..c41c86e 100644 --- a/efl/elementary/cnp_callbacks.pxi +++ b/efl/elementary/cnp_callbacks.pxi @@ -1,5 +1,6 @@ from efl.elementary.enums cimport Elm_Sel_Type, Elm_Sel_Format, \ Elm_Xdnd_Action +from efl.utils.conversions cimport python_list_objects_to_eina_list cdef extern from "Elementary.h": struct _Elm_Selection_Data: @@ -78,7 +79,7 @@ cdef class SelectionData(object): property data: def __get__(self): # TODO: void * - return None + return self.sel_data.data property len: """:type: size_t""" @@ -103,6 +104,8 @@ cdef Eina_Bool py_elm_drop_cb(void *data, Evas_Object *obj, Elm_Selection_Data * :param ev: struct holding information about selected data """ + print("in drop_cb") + assert data != NULL, "data is NULL" cdef: SelectionData sd = SelectionData.__new__(SelectionData) bint ret @@ -146,10 +149,10 @@ cdef Elm_Object_Item *py_elm_xy_item_get_cb(Evas_Object *obj, Evas_Coord x, Evas if xpos1 is not None: xpos2 = xpos1 - xposret = &xpos2 + xposret[0] = xpos2 if ypos1 is not None: ypos2 = ypos1 - yposret = &ypos2 + yposret[0] = ypos2 return it.item @@ -181,6 +184,40 @@ cdef Evas_Object *py_elm_drag_icon_create_cb( """ print("in drag_icon_create_cb") + assert data != NULL, "data is NULL" + + cdef: + evasObject win1 = object_from_instance(win) + evasObject icon + object xoff1 = None, yoff1 = None + Evas_Coord xoff2, yoff2 + + createicon, createdata = data + + if xoff != NULL: + xoff1 = xoff[0] + if yoff != NULL: + yoff1 = yoff[0] + + try: + ret = createicon(win1, xoff1, yoff1, createdata) + except: + traceback.print_exc() + return NULL + + if ret is None: + return NULL + + icon, xoff1, yoff1 = ret + + if xoff1 is not None: + xoff2 = xoff1 + xoff[0] = xoff2 + if yoff1 is not None: + yoff2 = yoff1 + yoff[0] = yoff2 + + return icon.obj cdef void py_elm_drag_state_cb(void *data, Evas_Object *obj) with gil: """Callback called when a drag is finished, enters, or leaves an object @@ -192,6 +229,28 @@ cdef void py_elm_drag_state_cb(void *data, Evas_Object *obj) with gil: """ print("in drag_state_cb") +cdef void py_elm_drag_done_cb(void *data, Evas_Object *obj, Eina_Bool accepted) with gil: + """Callback called when a drag is finished. + + @param data Application specific data + @param obj The object where the drag started + @param accepted TRUE if the droppped-data is accepted on drop + :since: 1.8 + + """ + print("in drag_done_cb") + assert data != NULL, "data is NULL" + + cdef: + evasObject o = object_from_instance(obj) + + donecb, donedata = data + + try: + donecb(o, accepted, donedata) + except: + traceback.print_exc() + cdef void py_elm_drag_accept_cb(void *data, Evas_Object *obj, Eina_Bool doaccept) with gil: """Callback called when a drag is responded to with an accept or deny @@ -215,7 +274,17 @@ cdef void py_elm_drag_pos_cb(void *data, Evas_Object *obj, """ print("in drag_pos_cb") + assert data != NULL, "data is NULL" + cdef: + evasObject o = object_from_instance(obj) + + dragpos, dragdata = data + + try: + dragpos(o, x, y, action, dragdata) + except: + traceback.print_exc() cdef void py_elm_drag_item_container_pos( void *data, Evas_Object *cont, Elm_Object_Item *it, @@ -254,7 +323,26 @@ cdef Eina_Bool py_elm_drop_item_container_cb( """ print("in drop_item_container_cb") + assert obj != NULL, "obj is NULL" + cdef: + evasObject o = object_from_instance(obj) + ObjectItem item = _object_item_to_python(it) + SelectionData evdata = SelectionData.__new__(SelectionData) + object cbdata = None + + evdata.sel_data = ev + + cb = o.data["drop_item_container_cb"] + + if data != NULL: + cbdata = data + + try: + ret = cb(o, item, evdata, xposret, yposret, cbdata) + except: + traceback.print_exc() + return 0 cdef class DragUserInfo(object): """ @@ -277,8 +365,21 @@ cdef class DragUserInfo(object): @param donecbdata Application data to pass to @p dragdone (output) """ + cdef: + public Elm_Sel_Format format + public Elm_Xdnd_Action action + public list icons + public object createicon, createdata, dragpos, dragdata + public object acceptcb, acceptdata, dragdone, donecbdata + const_char *_data - cdef Elm_Drag_User_Info *info + property data: + def __get__(self): + return _ctouni(self._data) + + def __set__(self, value): + if isinstance(value, unicode): value = PyUnicode_AsUTF8String(value) + self._data = value # Elm_Sel_Format format; # const char *data; @@ -306,3 +407,44 @@ cdef Eina_Bool py_elm_item_container_data_get_cb( """ print("in item_container_data_get_cb") + + cdef: + DragUserInfo ret + evasObject o = object_from_instance(obj) + ObjectItem item = _object_item_to_python(it) + + try: + ret = o.data["item_container_data_get_cb"](o, item) + except: + traceback.print_exc() + return 0 + + if ret is not None: + print("populating info") + info.format = ret.format + info.data = ret._data + info.icons = python_list_objects_to_eina_list(ret.icons) + if ret.createicon is not None: + info.createicon = py_elm_drag_icon_create_cb + createdata = (ret.createicon, ret.createdata) + Py_INCREF(createdata) + info.createdata = createdata + if ret.dragpos is not None: + info.dragpos = py_elm_drag_pos_cb + dragdata = (ret.dragpos, ret.dragdata) + Py_INCREF(dragdata) + info.dragdata = dragdata + if ret.acceptcb is not None: + info.acceptcb = py_elm_drag_accept_cb + acceptdata = (ret.acceptcb, ret.acceptdata) + Py_INCREF(acceptdata) + info.acceptdata = acceptdata + if ret.dragdone is not None: + info.dragdone =py_elm_drag_done_cb + donecbdata = (ret.dragdone, ret.donecbdata) + Py_INCREF(donecbdata) + info.donecbdata = donecbdata + return 1 + else: + print("ret is None") + return 0 diff --git a/efl/elementary/genlist_widget.pxi b/efl/elementary/genlist_widget.pxi index d3fac26..1530a4f 100644 --- a/efl/elementary/genlist_widget.pxi +++ b/efl/elementary/genlist_widget.pxi @@ -694,6 +694,8 @@ cdef class Genlist(Object): raise TypeError("itemgetcb must be callable.") self.data["xy_item_get_cb"] = itemgetcb + self.data["item_container_data_get_cb"] = data_get + if not elm_drag_item_container_add(self.obj, tm_to_anim, tm_to_drag, @@ -742,17 +744,20 @@ cdef class Genlist(Object): raise TypeError("itemgetcb must be callable.") self.data["xy_item_get_cb"] = itemgetcb + self.data["drag_item_container_pos"] = poscb + self.data["drop_item_container_cb"] = dropcb + if not elm_drop_item_container_add(self.obj, format, py_elm_xy_item_get_cb if itemgetcb is not None else NULL, py_elm_drag_state_cb if entercb is not None else NULL, - enterdata, + enterdata if enterdata is not None else NULL, py_elm_drag_state_cb if leavecb is not None else NULL, - leavedata, + leavedata if leavedata is not None else NULL, py_elm_drag_item_container_pos if poscb is not None else NULL, - posdata, + posdata if posdata is not None else NULL, py_elm_drop_item_container_cb if dropcb is not None else NULL, - cbdata): + cbdata if cbdata is not None else NULL): raise RuntimeError def drop_item_container_del(self): diff --git a/examples/elementary/test_dnd.py b/examples/elementary/test_dnd.py index 9053b8f..f989aa5 100644 --- a/examples/elementary/test_dnd.py +++ b/examples/elementary/test_dnd.py @@ -7,7 +7,7 @@ from efl.elementary.box import Box from efl.elementary.window import StandardWindow from efl.elementary.icon import Icon from efl.elementary.genlist import Genlist, GenlistItemClass, \ - ELM_SEL_FORMAT_TARGETS, ELM_GENLIST_ITEM_NONE + ELM_SEL_FORMAT_TARGETS, ELM_GENLIST_ITEM_NONE, DragUserInfo img = ( "panel_01.jpg", @@ -39,19 +39,12 @@ img = ( DRAG_TIMEOUT = 0.3 ANIM_TIME = 0.5 -def item_ptr_cmp(d1, d2): - return (d1 - d2) - -#static Elm_Genlist_Item_Class *itc1 -#static Elm_Gengrid_Item_Class *gic - - class DndItemClass(GenlistItemClass): def text_get(self, obj, part, data, *args): return data def content_get(self, obj, part, data, *args): - if not part == "elm.swallow.icon": + if part == "elm.swallow.icon": icon = Icon(obj) icon.file = data icon.size_hint_aspect = evas.EVAS_ASPECT_CONTROL_VERTICAL, 1, 1 @@ -59,8 +52,10 @@ class DndItemClass(GenlistItemClass): return icon return None +itc1 = DndItemClass() + def win_del(obj, data): - #print("<%s> <%d> will del <%p>\n", __func__, __LINE__, data) + print("will del <%s>" % data) data.drop_item_container_del() data.drag_item_container_del() @@ -73,12 +68,11 @@ def win_del(obj, data): def gl_item_getcb(gl, x, y): # This function returns pointer to item under (x,y) coords - #print("<%s> <%d> obj=<%p>\n", __func__, __LINE__, gl) gli, yposret = gl.at_xy_item_get(x, y) if gli is not None: - print("over <%s>, gli=<%s> yposret %i\n" % (gli.part_text_get("elm.text"), gli, yposret)) + print("over <%s>, gli=<%s> yposret %i" % (gli.part_text_get("elm.text"), gli, yposret)) else: - print("over none, yposret %i\n", yposret) + print("over none, yposret %i" % yposret) return gli, None, yposret # def grid_item_getcb(obj, x, y, int *xposret, int *yposret): @@ -92,42 +86,33 @@ def gl_item_getcb(gl, x, y): # print("over none, xposret %i yposret %i\n", *xposret, *yposret) # return item -def gl_dropcb(data, obj, it, - ev, # Elm_Selection_Data * - xposret, yposret): +def gl_dropcb(obj, it, ev, xposret, yposret, data): # This function is called when data is dropped on the genlist - #print("<%s> <%d> str=<%s>\n", __func__, __LINE__, (char *) ev->data) if ev.data is None: return False p = ev.data - p = strchr(p, '#') - while p is not None: - p += 1 - p2 = strchr(p, '#') - if p2 is not None: - p2 = '\0' - print("Item %s\n", p) - if yposret == -1: - obj.item_insert_before(itc1, p, before=it, - flags=ELM_GENLIST_ITEM_NONE) - elif yposret == 0 or yposret == 1: - if not it: - it = obj.last_item - if it: - it = obj.item_insert_after(itc1, p, None, it, - ELM_GENLIST_ITEM_NONE) - else: - it = obj.item_append(itc1, p, None, - ELM_GENLIST_ITEM_NONE) + wh0rdlist = p.split("#") + + wh0rdlist.pop(0) + wh0rdlist.pop() + + for wh0rd in wh0rdlist: + print("Item %s" % wh0rd) + + if yposret == -1: + obj.item_insert_before(itc1, wh0rd, before_item=it, flags=ELM_GENLIST_ITEM_NONE) + elif yposret == 0 or yposret == 1: + if not it: + it = obj.last_item + + if it: + it = obj.item_insert_after(itc1, wh0rd, after_item=it, flags=ELM_GENLIST_ITEM_NONE) else: - return False - - p = p2 - + it = obj.item_append(itc1, wh0rd, flags=ELM_GENLIST_ITEM_NONE) else: - p = None + return False return True @@ -284,44 +269,43 @@ def gl_dropcb(data, obj, it, # # END - Handling drag start animation def gl_dragdone(obj, doaccept, data): - #print("<%s> <%d> data=<%p> doaccept=<%d>\n", __func__, __LINE__, data, doaccept) - if doaccept: # Remove items dragged out (accepted by target) for it in data: it.delete() -def gl_createicon(data, win, xoff, yoff): +def gl_createicon(win, xoff, yoff, data): #print("<%s> <%d>\n", __func__, __LINE__) it = data o = it.part_content_get("elm.swallow.icon") - if o is not None: - w = h = 30 + if o is None: + return - f, g = o.file + w = h = 30 - xm, ym = o.evas.pointer_canvas_xy + f, g = o.file - if xoff is not None: - xoff = xm - (w/2) - if yoff is not None: - yoff = ym - (h/2) + xm, ym = o.evas.pointer_canvas_xy - icon = Icon(win) - icon.file = f, g - icon.size_hint_align = evas.EVAS_HINT_FILL, evas.EVAS_HINT_FILL - icon.size_hint_weight = evas.EVAS_HINT_EXPAND, evas.EVAS_HINT_EXPAND + if xoff is not None: + xoff = xm - (w/2) + if yoff is not None: + yoff = ym - (h/2) - if xoff is not None and yoff is not None: - icon.move(xoff, yoff) - icon.resize(w, h) + icon = Icon(win) + icon.file = f, g + icon.size_hint_align = evas.EVAS_HINT_FILL, evas.EVAS_HINT_FILL + icon.size_hint_weight = evas.EVAS_HINT_EXPAND, evas.EVAS_HINT_EXPAND - return icon + if (xoff is not None) and (yoff is not None): + icon.move(xoff, yoff) + icon.resize(w, h) + + return icon, xoff, yoff def gl_icons_get(data): # Start icons animation before actually drag-starts - #print("<%s> <%d>\n", __func__, __LINE__) gl = data yposret = 0 @@ -329,18 +313,17 @@ def gl_icons_get(data): icons = [] xm, ym = gl.evas.pointer_canvas_xy - items = gl.selected_items - gli = gl.at_xy_item_get(xm, ym, yposret) + items = list(gl.selected_items) + gli, yposret = gl.at_xy_item_get(xm, ym) if gli is not None: # Add the item mouse is over to the list if NOT seleced - p = eina_list_search_unsorted(items, _item_ptr_cmp, gli) - if p is not None: - items = eina_list_append(items, gli) + if not gli in items: + items.append(gli) - for gli in items: + for it in items: # Now add icons to animation window - o = gli.part_content_get("elm.swallow.icon") + o = it.part_content_get("elm.swallow.icon") if o is not None: f, g = o.file @@ -356,22 +339,19 @@ def gl_icons_get(data): icons.append(ic) - eina_list_free(items) return icons -def gl_get_drag_data(gl, it, items): +def gl_get_drag_data(gl, it): # Construct a string of dragged info, user frees returned string drag_data = None - #print("<%s> <%d>\n", __func__, __LINE__) - items = gl.selected_items + items = list(gl.selected_items) if it is not None: # Add the item mouse is over to the list if NOT seleced - p = eina_list_search_unsorted(items, _item_ptr_cmp, it) - if p is None: - items = eina_list_append(items, it) + if not it in items: + items.append(it) - if items: + if items is not None: # Now we can actually compose string to send and start dragging drag_data = "file://" @@ -383,9 +363,9 @@ def gl_get_drag_data(gl, it, items): drag_data += "#" - #print("<%s> <%d> Sending <%s>\n", __func__, __LINE__, drag_data) + print("Sending <%s>" % drag_data) - return drag_data + return drag_data, items # def grid_get_drag_data(gg, it, Eina_List **items): # # Construct a string of dragged info, user frees returned string @@ -432,26 +412,25 @@ def gl_get_drag_data(gl, it, items): # return drag_data -def gl_dnd_default_anim_data_getcb(gl, it, - info # Elm_Drag_User_Info * - ): +def gl_dnd_default_anim_data_getcb(gl, it): # This called before starting to drag, mouse-down was on it + info = DragUserInfo() info.format = ELM_SEL_FORMAT_TARGETS - info.createicon = _gl_createicon + info.createicon = gl_createicon info.createdata = it - info.icons = _gl_icons_get(obj) - info.dragdone = _gl_dragdone + info.icons = gl_icons_get(gl) + info.dragdone = gl_dragdone # Now, collect data to send for drop from ALL selected items # Save list pointer to remove items after drop and free list on done - info.data = _gl_get_drag_data(obj, it, info.donecbdata) - #print("%s - data = %s\n", __FUNCTION__, info->data) + info.data, info.donecbdata = gl_get_drag_data(gl, it) + info.acceptdata = info.donecbdata if info.data is not None: - return True + return info else: - return False + return # def gl_data_getcb(gl, it, # Elm_Drag_User_Info *info): @@ -563,7 +542,7 @@ def dnd_genlist_default_anim_clicked(*args): bxx.pack_end(gl) gl.show() - itc1 = DndItemClass() + #itc1 = DndItemClass() for i in range (20): gl.item_append(itc1, "images/{0}".format(img[i % 9]), flags=ELM_GENLIST_ITEM_NONE)