python-efl/examples/elementary/test_dnd.py

615 lines
18 KiB
Python

#!/usr/bin/env python
# encoding: utf-8
import os
from efl.ecore import Timer, ECORE_CALLBACK_CANCEL, ECORE_CALLBACK_RENEW, \
AnimatorTimeline
from efl.evas import EVAS_HINT_EXPAND, EVAS_HINT_FILL, EXPAND_BOTH, FILL_BOTH, \
EVAS_ASPECT_CONTROL_VERTICAL, EVAS_CALLBACK_MOUSE_MOVE, \
EVAS_CALLBACK_MOUSE_UP, EVAS_CALLBACK_MOUSE_DOWN, \
EVAS_EVENT_FLAG_ON_HOLD
from efl import elementary
from efl.elementary.label import Label
from efl.elementary.frame import Frame
from efl.elementary.list import List
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, DragUserInfo
from efl.elementary.gengrid import Gengrid, GengridItemClass
from efl.elementary.configuration import Configuration
conf = Configuration()
script_path = os.path.dirname(os.path.abspath(__file__))
img_path = os.path.join(script_path, "images")
img = (
"panel_01.jpg",
"plant_01.jpg",
"rock_01.jpg",
"rock_02.jpg",
"sky_01.jpg",
"sky_02.jpg",
"sky_03.jpg",
"sky_04.jpg",
"wood_01.jpg",
)
class AnimIconSt:
start_x = 0
start_y = 0
o = None
class DragAnimSt:
icwin = None
e = None
mdx = 0 # Mouse-down x
mdy = 0 # Mouse-down y
icons = [] # List of icons to animate (anim_icon_st)
tm = None
ea = None
gl = None
DRAG_TIMEOUT = 0.3
ANIM_TIME = 0.5
class DndGenlistItemClass(GenlistItemClass):
def text_get(self, obj, part, data, *args):
return data
def content_get(self, obj, part, data, *args):
if part == "elm.swallow.icon":
icon = Icon(obj, file=os.path.join(img_path, data),
size_hint_aspect=(EVAS_ASPECT_CONTROL_VERTICAL, 1, 1))
icon.show()
return icon
return None
itc1 = DndGenlistItemClass()
class DndGengridItemClass(GengridItemClass):
def text_get(self, obj, part, data, *args):
return data
def content_get(self, obj, part, data, *args):
if part == "elm.swallow.icon":
icon = Icon(obj, file=os.path.join(img_path, data),
size_hint_aspect=(EVAS_ASPECT_CONTROL_VERTICAL, 1, 1))
icon.show()
return icon
return None
gic = DndGengridItemClass()
def win_del(obj, data):
print("will del <%s>" % data)
data.drop_item_container_del()
data.drag_item_container_del()
#elementary.exit()
def gl_item_getcb(gl, x, y):
# This function returns pointer to item under (x,y) coords
gli, yposret = gl.at_xy_item_get(x, y)
if gli is not None:
print("over <%s>, gli=%r yposret=%i" % (
gli.part_text_get("elm.text"), gli, yposret))
else:
print("over none, yposret=%i" % yposret)
return gli, None, yposret
def grid_item_getcb(grid, x, y):
# This function returns pointer to item under (x,y) coords
item, xposret, yposret = grid.at_xy_item_get(x, y)
if item is not None:
print("over <%s>, item=%r xposret=%i yposret=%i" % (
item.part_text_get("elm.text"), item, xposret, yposret))
else:
print("over none, xposret=%i yposret=%i", xposret, yposret)
return item, xposret, yposret
def gl_dropcb(obj, it, ev, xposret, yposret, data):
# This function is called when data is dropped on the genlist
if ev.data is None:
return False
p = ev.data
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:
obj.item_insert_after(itc1, wh0rd, after_item=it, flags=ELM_GENLIST_ITEM_NONE)
else:
obj.item_append(itc1, wh0rd, flags=ELM_GENLIST_ITEM_NONE)
else:
return False
return True
def grid_dropcb(obj, it, ev, xposret, yposret, data):
# This function is called when data is dropped on the gengrid
if ev.data is None:
return False
p = ev.data
wh0rdlist = p.split("#")
wh0rdlist.pop(0)
wh0rdlist.pop()
for wh0rd in wh0rdlist:
print("Item %s" % wh0rd)
if not it:
it = obj.last_item
if it:
it = obj.item_insert_after(gic, wh0rd, after_item=it)
else:
it = obj.item_append(gic, wh0rd)
return True
def anim_st_free(anim_st):
# Stops and free mem of ongoing animation
if anim_st is not None:
anim_st.gl.event_callback_del(
EVAS_CALLBACK_MOUSE_MOVE, gl_obj_mouse_move)
anim_st.gl.event_callback_del(
EVAS_CALLBACK_MOUSE_UP, gl_obj_mouse_up)
if anim_st.tm is not None:
anim_st.tm.delete()
anim_st.tm = None
if anim_st.ea is not None:
anim_st.ea.delete()
anim_st.ea = None
for st in anim_st.icons:
st.o.delete()
def drag_anim_play(pos, anim_st):
# Impl of the animation of icons, called on frame time
if anim_st is not None:
if pos > 0.99:
anim_st.ea = None # Avoid deleting on mouse up
for st in anim_st.icons:
st.o.hide() # Hide animated icons
anim_st_free(anim_st)
return ECORE_CALLBACK_CANCEL
for st in anim_st.icons:
w, h = st.o.size
xm, ym = anim_st.e.pointer_canvas_xy
x = st.start_x + (pos * (xm - (st.start_x + (w/2))))
y = st.start_y + (pos * (ym - (st.start_y + (h/2))))
st.o.move(x, y)
return ECORE_CALLBACK_RENEW
return ECORE_CALLBACK_CANCEL
def gl_anim_start(anim_st):
# Start icons animation before actually drag-starts
yposret = 0
items = list(anim_st.gl.selected_items)
gli, yposret = anim_st.gl.at_xy_item_get(anim_st.mdx, anim_st.mdy)
if gli is not None:
# Add the item mouse is over to the list if NOT seleced
if not gli in items:
items.append(gli)
for gli in items:
# Now add icons to animation window
o = gli.part_content_get("elm.swallow.icon")
if o is not None:
st = AnimIconSt()
ic = Icon(anim_st.gl, file=o.file, size_hint_align=FILL_BOTH,
size_hint_weight=EXPAND_BOTH, pos=o.pos, size=o.size)
st.start_x, st.start_y = o.pos
ic.show()
st.o = ic
anim_st.icons.append(st)
anim_st.tm = None
anim_st.ea = AnimatorTimeline(drag_anim_play, DRAG_TIMEOUT,
anim_st)
return ECORE_CALLBACK_CANCEL
def gl_obj_mouse_up(obj, event_info, data):
# Cancel any drag waiting to start on timeout
anim_st_free(data)
def gl_obj_mouse_move(obj, event_info, data):
# Cancel any drag waiting to start on timeout
if event_info.event_flags & EVAS_EVENT_FLAG_ON_HOLD:
print("event on hold")
anim_st_free(data)
def gl_obj_mouse_down(obj, event_info, data):
# Launch a timer to start drag animation
anim_st = DragAnimSt()
anim_st.e = obj.evas
anim_st.mdx = event_info.position.canvas.x
anim_st.mdy = event_info.position.canvas.y
anim_st.gl = data
anim_st.tm = Timer(DRAG_TIMEOUT, gl_anim_start, anim_st)
data.event_callback_add(EVAS_CALLBACK_MOUSE_UP,
gl_obj_mouse_up, anim_st)
data.event_callback_add(EVAS_CALLBACK_MOUSE_MOVE,
gl_obj_mouse_move, anim_st)
# END - Handling drag start animation
def gl_dragdone(obj, doaccept, data):
if doaccept:
# Remove items dragged out (accepted by target)
for it in data:
it.delete()
def gl_createicon(win, xoff, yoff, data):
it = data
o = it.part_content_get("elm.swallow.icon")
if o is None:
return
w = h = 30
f, g = o.file
xm, ym = o.evas.pointer_canvas_xy
if xoff is not None:
xoff = xm - (w/2)
if yoff is not None:
yoff = ym - (h/2)
icon = Icon(win, file=(f, g), size_hint_weight=EXPAND_BOTH,
size_hint_align=FILL_BOTH)
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(gl):
# Start icons animation before actually drag-starts
yposret = 0
icons = []
xm, ym = gl.evas.pointer_canvas_xy
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
if not gli in items:
items.append(gli)
for it in items:
# Now add icons to animation window
o = it.part_content_get("elm.swallow.icon")
if o is not None:
f, g = o.file
x, y, w, h = o.geometry
ic = Icon(gl, file=(f, g), size_hint_align=FILL_BOTH,
size_hint_weight=EXPAND_BOTH, pos=(x,y), size=(w,h))
ic.show()
icons.append(ic)
return icons
def gl_get_drag_data(gl, it):
# Construct a string of dragged info, user frees returned string
drag_data = None
items = list(gl.selected_items)
if it is not None:
# Add the item mouse is over to the list if NOT seleced
if not it in items:
items.append(it)
if items is not None:
# Now we can actually compose string to send and start dragging
drag_data = "file://"
for it in items:
t = it.part_text_get("elm.text")
if t is not None:
drag_data += "#"
drag_data += t
drag_data += "#"
print("Sending <%s>" % drag_data)
return drag_data, items
def grid_get_drag_data(gg, it):
# Construct a string of dragged info, user frees returned string
drag_data = None
items = list(gg.selected_items)
if it is not None:
# Add the item mouse is over to the list if NOT seleced
if not it in items:
items.append(it)
if items is not None:
# Now we can actually compose string to send and start dragging
drag_data = "file://"
for it in items:
t = it.part_text_get("elm.text")
if t is not None:
drag_data += "#"
drag_data += t
drag_data += "#"
print("Sending <%s>" % drag_data)
return drag_data, items
def gl_dnd_default_anim_data_getcb(gl, it, info):
# This called before starting to drag, mouse-down was on it
info.format = ELM_SEL_FORMAT_TARGETS
info.createicon = gl_createicon
info.createdata = it
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, info.donecbdata = gl_get_drag_data(gl, it)
info.acceptdata = info.donecbdata
if info.data is not None:
return info
else:
return
def gl_data_getcb(gl, it, info):
# This called before starting to drag, mouse-down was on it
info.format = ELM_SEL_FORMAT_TARGETS
info.createicon = gl_createicon
info.createdata = it
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, info.donecbdata = gl_get_drag_data(gl, it)
info.acceptdata = info.donecbdata
if info.data is not None:
return True
else:
return False
def grid_icons_get(grid):
# Start icons animation before actually drag-starts
xposret, yposret = 0, 0
icons = []
xm, ym = grid.evas.pointer_canvas_xy
items = list(grid.selected_items)
print(items)
gli, xposret, yposret = grid.at_xy_item_get(xm, ym)
if gli is not None:
# Add the item mouse is over to the list if NOT seleced
if not gli in items:
items.append(gli)
print(items)
for gli in items:
# Now add icons to animation window
o = gli.part_content_get("elm.swallow.icon")
if o is not None:
ic = Icon(grid, file=o.file, pos=o.pos, size=o.size,
size_hint_align=FILL_BOTH, size_hint_weight=EXPAND_BOTH)
ic.show()
icons.append(ic)
return icons
def grid_data_getcb(grid, it, info):
# This called before starting to drag, mouse-down was on it
info.format = ELM_SEL_FORMAT_TARGETS
info.createicon = gl_createicon
info.createdata = it
info.icons = grid_icons_get(grid)
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, info.donecbdata = grid_get_drag_data(grid, it)
info.acceptdata = info.donecbdata
if info.data:
return True
else:
return False
def dnd_genlist_default_anim_clicked(obj, item=None):
win = StandardWindow("dnd-genlist-default-anim",
"DnD-Genlist-Default-Anim", autodel=True, size=(680, 800))
bxx = Box(win, horizontal=True, size_hint_weight=EXPAND_BOTH)
win.resize_object_add(bxx)
bxx.show()
for j in range(2):
gl = Genlist(win, multi_select=True, size_hint_weight=EXPAND_BOTH,
size_hint_align=FILL_BOTH)
# START Drag and Drop handling
win.callback_delete_request_add(win_del, gl)
gl.drop_item_container_add(ELM_SEL_FORMAT_TARGETS, gl_item_getcb,
dropcb=gl_dropcb)
gl.drag_item_container_add(ANIM_TIME, DRAG_TIMEOUT, gl_item_getcb,
gl_dnd_default_anim_data_getcb)
# FIXME: This causes genlist to resize the horiz axis very slowly :(
# Reenable this and resize the window horizontally, then try
# to resize it back.
#elm_genlist_mode_set(gl, ELM_LIST_LIMIT)
bxx.pack_end(gl)
gl.show()
for i in range (20):
gl.item_append(itc1, img[i % 9], flags=ELM_GENLIST_ITEM_NONE)
win.show()
def dnd_genlist_user_anim_clicked(obj, item=None):
win = StandardWindow("dnd-genlist-user-anim", "DnD-Genlist-User-Anim",
autodel=True, size=(680,800))
bxx = Box(win, horizontal=True, size_hint_weight=EXPAND_BOTH)
win.resize_object_add(bxx)
bxx.show()
for j in range(2):
gl = Genlist(win, multi_select=True, size_hint_weight=EXPAND_BOTH,
size_hint_align=FILL_BOTH)
# START Drag and Drop handling
win.callback_delete_request_add(win_del, gl)
gl.drop_item_container_add(ELM_SEL_FORMAT_TARGETS, gl_item_getcb,
dropcb=gl_dropcb)
gl.drag_item_container_add(ANIM_TIME, DRAG_TIMEOUT, gl_item_getcb,
gl_data_getcb)
# We add mouse-down, up callbacks to start/stop drag animation
gl.event_callback_add(EVAS_CALLBACK_MOUSE_DOWN, gl_obj_mouse_down, gl)
# END Drag and Drop handling
# FIXME: This causes genlist to resize the horiz axis very slowly :(
# Reenable this and resize the window horizontally, then try to resize it back
#elm_genlist_mode_set(gl, ELM_LIST_LIMIT)
bxx.pack_end(gl)
gl.show()
for i in range(20):
gl.item_append(itc1, img[i % 9], flags=ELM_GENLIST_ITEM_NONE)
win.show()
def dnd_genlist_gengrid_clicked(obj, item=None):
win = StandardWindow("dnd-genlist-gengrid", "DnD-Genlist-Gengrid",
autodel=True, size=(680,800))
bxx = Box(win, horizontal=True, size_hint_weight=EXPAND_BOTH)
win.resize_object_add(bxx)
bxx.show()
gl = Genlist(win, multi_select=True,
size_hint_weight=EXPAND_BOTH, size_hint_align=FILL_BOTH)
win.callback_delete_request_add(win_del, gl)
# START Drag and Drop handling
gl.drop_item_container_add(ELM_SEL_FORMAT_TARGETS, gl_item_getcb,
dropcb=gl_dropcb)
gl.drag_item_container_add(ANIM_TIME, DRAG_TIMEOUT, gl_item_getcb,
gl_dnd_default_anim_data_getcb)
# END Drag and Drop handling
# FIXME: This causes genlist to resize the horiz axis very slowly :(
# Reenable this and resize the window horizontally, then try to resize it back
#elm_genlist_mode_set(gl, ELM_LIST_LIMIT)
bxx.pack_end(gl)
gl.show()
for i in range(20):
gl.item_append(itc1, img[i % 9], flags=ELM_GENLIST_ITEM_NONE)
grid = Gengrid(win, item_size=(conf.scale * 150, conf.scale * 150),
horizontal=False, reorder_mode=False, multi_select=True,
size_hint_weight=EXPAND_BOTH, size_hint_align=FILL_BOTH)
win.callback_delete_request_add(win_del, grid)
grid.drop_item_container_add(ELM_SEL_FORMAT_TARGETS, grid_item_getcb,
dropcb=grid_dropcb)
grid.drag_item_container_add(ANIM_TIME, DRAG_TIMEOUT, grid_item_getcb,
grid_data_getcb)
for i in range(20):
grid.item_append(gic, img[i % 9])
bxx.pack_end(grid)
grid.show()
win.show()
if __name__ == "__main__":
win = StandardWindow("test", "python-elementary test application",
size=(320,520))
win.callback_delete_request_add(lambda o: elementary.exit())
box0 = Box(win, size_hint_weight=EXPAND_BOTH)
win.resize_object_add(box0)
box0.show()
lb = Label(win)
lb.text_set("Please select a test from the list below<br>"
"by clicking the test button to show the<br>"
"test window.")
lb.show()
fr = Frame(win, text="Information", content=lb)
box0.pack_end(fr)
fr.show()
items = [
("DnD Genlist Default Anim", dnd_genlist_default_anim_clicked),
("DnD Genlist User Anim", dnd_genlist_user_anim_clicked),
("DnD Genlist+Gengrid", dnd_genlist_gengrid_clicked),
]
li = List(win, size_hint_weight=EXPAND_BOTH, size_hint_align=FILL_BOTH)
box0.pack_end(li)
li.show()
for item in items:
li.item_append(item[0], callback=item[1])
li.go()
win.show()
elementary.run()