On Tue, 25 Nov 2003 02:36:55 -0600
Michael Urman <[EMAIL PROTECTED]> wrote:
> On Sat, Nov 22, 2003 at 05:06:10PM +0100, Walter Anger wrote:
> > I suppose you are asking two questions:
> > 1. how to tell gtk, that you can't drop to a certain row.
> > 2. how to communicate that to the user before the drop occurs.
>
> These are indeed my fundamental questions, but the version I am
> looking for is much more linked than the version you suggested.
> Normally when you do DND in GTK (on X), the cursor is the upper-left
> corner. If you are over a spot where a drop is accepted, a triangle
> is also part of the cursor. If not, it's just the corner.
indeed, i didn't even observe that untill now. evidence that the
feedback should be enhanced with nice eye-candy that even blind guys
like me may see whats going on.
> You can see this, for example, dragging below the bottom element of a
> treeview. Or dragging over an element that does not accept a drop at
> all. This is the behavior I would like to conditionally invoke. (I
> know when; I can detect that. I can "not do" the drop in the
> drag-data-received handler. But I want the user to know ahead of time
> with the standard DND feedback that nothing will happen on a drop
> right there.)
<cite>
http://www.moeraki.com/pygtkreference/pygtk2reference/class-gtkwidget.html
some widgets may have different valid targets for different parts of the
widget; in that case, they will have to implement a "drag-motion"
handler that passes the correct target list to this function
</cite>
and that seems to be the key to solving your problem - the "string
representing the drag type" has to be changed depending on the location
of the drag icon. that changes the cursor automatically.
the appended example does what you want. but i have a strong feeling
that one should put much work in improving the performance, in
particular with the onDragMove callback. hopefully someone here has some
good ideas.
walter
#!/usr/bin/env python
try:
import pygtk; pygtk.require("2.0")
except:
pass
import gtk
import gobject
data = [[0,"parent",True],[1,"parent",True],[2,"parent",True],[3,"parent",True],
[4,"no parent",False],[5,"no parent",False],[6,"no parent",False],[7,"no
parent",False]]
drop_yes = ("drop_yes", gtk.TARGET_SAME_WIDGET, 0)
drop_no = ("drop_no", gtk.TARGET_SAME_WIDGET, 0)
class TreeDNDExample:
def checkSanity(self, model, source, target):
source_path = model.get_path(source)
target_path = model.get_path(target)
if target_path[0:len(source_path)] == source_path:
return False
else:
return True
def checkParentability(self, model, target, drop_position):
if (drop_position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE
or drop_position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER) \
and model.get_value(target, 2) == False:
return False
else:
return True
def expandToPath(self, treeview, path):
for i in range(len(path)):
treeview.expand_row(path[:i+1], open_all=gtk.FALSE)
def copyRow(self, treeview, model, source, target, drop_position):
source_row = model[source]
if drop_position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE:
new = model.prepend(target, source_row)
elif drop_position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER:
new = model.append(target, source_row)
elif drop_position == gtk.TREE_VIEW_DROP_BEFORE:
new = model.insert_before(None, target, source_row)
elif drop_position == gtk.TREE_VIEW_DROP_AFTER:
new = model.insert_after(None, target, source_row)
for n in range(model.iter_n_children(source)):
child = model.iter_nth_child(source, n)
self.copyRow(treeview, model, child, new,
gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)
source_is_expanded = treeview.row_expanded(model.get_path(source))
if source_is_expanded:
self.expandToPath(treeview, model.get_path(new))
def onDragDataReceived(self, treeview, drag_context, x, y,
selection_data, info, eventtime):
target_path, drop_position = treeview.get_dest_row_at_pos(x, y)
model, source = treeview.get_selection().get_selected()
target = model.get_iter(target_path)
is_sane = self.checkSanity(model, source, target)
is_parentable = self.checkParentability(model, target, drop_position)
if is_sane and is_parentable:
self.copyRow(treeview, model, source, target, drop_position)
if (drop_position == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE
or drop_position == gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
treeview.expand_row(target_path, gtk.FALSE)
drag_context.finish(gtk.TRUE, gtk.TRUE, eventtime)
else:
drag_context.finish(gtk.FALSE, gtk.FALSE, eventtime)
def onDragMotion(self, treeview, drag_context, x, y, eventtime):
try:
target_path, drop_position = treeview.get_dest_row_at_pos(x, y)
model, source = treeview.get_selection().get_selected()
target = model.get_iter(target_path)
except:
return
is_sane = self.checkSanity(model, source, target)
is_parentable = self.checkParentability(model, target, drop_position)
if is_sane and is_parentable:
treeview.enable_model_drag_dest([drop_yes], gtk.gdk.ACTION_MOVE)
else:
treeview.enable_model_drag_dest([drop_no], gtk.gdk.ACTION_MOVE)
def setupDND(self, treeview):
treeview.enable_model_drag_source(
gtk.gdk.BUTTON1_MASK, [drop_yes], gtk.gdk.ACTION_MOVE)
treeview.enable_model_drag_dest(
[drop_yes], gtk.gdk.ACTION_MOVE)
treeview.connect("drag-data-received", self.onDragDataReceived)
treeview.connect("drag-motion", self.onDragMotion)
def __init__(self):
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect("delete-event", gtk.mainquit)
window.set_default_size(250, 350)
scrolledwin = gtk.ScrolledWindow()
scrolledwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
window.add(scrolledwin)
model = gtk.TreeStore(int, str, gobject.TYPE_BOOLEAN)
for item in data:
model.append(None, item)
treeview = gtk.TreeView(model)
scrolledwin.add(treeview)
cell = gtk.CellRendererText()
tv_insert = treeview.insert_column_with_attributes
tv_insert(-1, "Integer", cell, text=0)
tv_insert(-1, "String", cell, text=1)
self.setupDND(treeview)
window.show_all()
def main():
gtk.main()
return 0
if __name__ == "__main__":
TreeDNDExample()
main()
_______________________________________________
pygtk mailing list [EMAIL PROTECTED]
http://www.daa.com.au/mailman/listinfo/pygtk
Read the PyGTK FAQ: http://www.async.com.br/faq/pygtk/