python-gtk-pygobject
python-gtk-pygobject copied to clipboard
Drag and drop widgets
I came across your repo recently, and finally found an example drag and drop implementation in GTK4 - also, the whole repo is impressive.
Though, I tried to modify the example, so it supports dragging and dropping the widgets (for example to reorder the labels) but no luck so far. Do you have any idea for this scenario?
Hello @swanux.
Thank you very much!
Over the weekend I will try to recreate the scenario you described.
The only reference I could find was an example in C in the Gtk 4 demo, I'll try to recreate it in Python:

If you have any tips or tutorials, be sure to share them here 😁.
Hello @natorsc
Thank you for the response.
I took a look into the demo app, and translated the part of the code I thought may be relevant (not a proper translation, just a quick overview). Here it is:
C:
static void
canvas_item_init (CanvasItem *item)
{
char *text;
char *id;
GdkRGBA rgba;
GtkDropTarget *dest;
GtkGesture *gesture;
GType types[2] = { GDK_TYPE_RGBA, G_TYPE_STRING };
n_items++;
text = g_strdup_printf ("Item %d", n_items);
item->label = gtk_label_new (text);
gtk_widget_add_css_class (item->label, "canvasitem");
g_free (text);
item->fixed = gtk_fixed_new ();
gtk_widget_set_parent (item->fixed, GTK_WIDGET (item));
gtk_fixed_put (GTK_FIXED (item->fixed), item->label, 0, 0);
gtk_widget_add_css_class (item->label, "frame");
id = g_strdup_printf ("item%d", n_items);
gtk_widget_set_name (item->label, id);
g_free (id);
if (theme_is_dark ())
gdk_rgba_parse (&rgba, "blue");
else
gdk_rgba_parse (&rgba, "yellow");
set_color (item, &rgba);
item->angle = 0;
dest = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_COPY);
gtk_drop_target_set_gtypes (dest, types, G_N_ELEMENTS (types));
g_signal_connect (dest, "drop", G_CALLBACK (item_drag_drop), NULL);
gtk_widget_add_controller (GTK_WIDGET (item->label), GTK_EVENT_CONTROLLER (dest));
gesture = gtk_gesture_rotate_new ();
g_signal_connect (gesture, "angle-changed", G_CALLBACK (angle_changed), NULL);
g_signal_connect (gesture, "end", G_CALLBACK (rotate_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
gesture = gtk_gesture_click_new ();
g_signal_connect (gesture, "released", G_CALLBACK (click_done), NULL);
gtk_widget_add_controller (GTK_WIDGET (item), GTK_EVENT_CONTROLLER (gesture));
}
Python:
def canvas_item_init(item):
text = "Item %d" % n_items
item.label = Gtk.Label(text)
item.label.get_style_context().add_class("canvasitem")
item.fixed = Gtk.Fixed()
item.fixed.set_parent(item)
item.fixed.put(item.label, 0, 0)
item.label.get_style_context().add_class("frame")
id = "item%d" % n_items
item.label.set_name(id)
if theme_is_dark():
rgba = Gdk.RGBA()
rgba.parse("blue")
else:
rgba = Gdk.RGBA()
rgba.parse("yellow")
set_color(item, rgba)
item.angle = 0
dest = Gtk.DropTarget.new(GObject.TYPE_INVALID, Gdk.DragAction.COPY)
dest.set_gtypes([Gdk.RGBA, GObject.TYPE_STRING])
dest.connect("drop", item_drag_drop)
item.label.add_controller(dest)
gesture = Gtk.GestureRotate.new()
gesture.connect("angle-changed", angle_changed)
gesture.connect("end", rotate_done)
item.add_controller(gesture)
gesture = Gtk.GestureClick.new()
gesture.connect("released", click_done)
item.add_controller(gesture)
Also, here's an auto-generated API documentation (I find it useful overall): https://amolenaar.github.io/pgi-docgen/
Currently I believe the issue is with the Gtk.DropTarget and what type it accepts - as tested with your code I get every signal emitted, except tha drop which would be the point. Also the usual dnd highlight doesn't appear.
Edit: Here are some other resources concerning dnd in GTK4 and Python https://stackoverflow.com/questions/70921068/drag-and-drop-with-gtk4-connecting-dragsource-and-droptarget-via-contentprovide
This one for the types maybe (based on the API doc): https://stackoverflow.com/questions/24795405/gdk-type-pixbuf-in-gtk-3