ui/gtk/list.c

changeset 90
f501f0efc9a8
parent 88
e27526429d85
child 98
16e84fac48bd
--- a/ui/gtk/list.c	Tue Nov 26 11:38:10 2024 +0100
+++ b/ui/gtk/list.c	Wed Nov 27 13:27:30 2024 +0100
@@ -35,9 +35,12 @@
 #include "../common/object.h"
 #include "container.h"
 
+#include <cx/array_list.h>
+
 #include "list.h"
 #include "icon.h"
 #include "menu.h"
+#include "dnd.h"
 
 
 void* ui_strmodel_getvalue(void *elm, int column) {
@@ -366,6 +369,12 @@
     tableview->widget = view;
     tableview->var = var;
     tableview->model = model;
+    tableview->ondragstart = args.ondragstart;
+    tableview->ondragstartdata = args.ondragstartdata;
+    tableview->ondragcomplete = args.ondragcomplete;
+    tableview->ondragcompletedata = args.ondragcompletedata;
+    tableview->ondrop = args.ondrop;
+    tableview->ondropdata = args.ondropsdata;
     g_signal_connect(
                 view,
                 "destroy",
@@ -403,6 +412,13 @@
     }
     // TODO: destroy callback
     
+    
+    if(args.ondragstart) {
+        ui_listview_add_dnd(tableview, &args);
+    }
+    if(args.ondrop) {
+        ui_listview_enable_drop(tableview, &args);
+    }
       
     GtkTreeSelection *selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
     if(args.multiselection) {
@@ -432,6 +448,234 @@
     return scroll_area;
 }
 
+#if GTK_MAJOR_VERSION >= 4
+
+static GdkContentProvider *ui_listview_dnd_prepare(GtkDragSource *source, double x, double y, void *data) {
+    //printf("drag prepare\n");
+    UiListView *listview = data;
+    
+    UiDnD *dnd = ui_create_dnd();
+    GdkContentProvider *provider = NULL;
+    
+    
+    if(listview->ondragstart) {
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = dnd;
+        event.intval = 0;
+        listview->ondragstart(&event, listview->ondragstartdata);
+    }
+    
+    size_t numproviders = cxListSize(dnd->providers);
+    if(numproviders > 0) {
+        GdkContentProvider **providers = (GdkContentProvider**)cxListAt(dnd->providers, 0);
+        provider = gdk_content_provider_new_union(providers, numproviders);
+    }
+    ui_dnd_free(dnd);
+    
+    return provider;
+}
+
+static void ui_listview_drag_begin(GtkDragSource *self, GdkDrag *drag, gpointer userdata) {
+    //printf("drag begin\n");
+}
+
+static void ui_listview_drag_end(GtkDragSource *self, GdkDrag *drag, gboolean delete_data, gpointer user_data) {
+    //printf("drag end\n");
+    UiListView *listview = user_data;
+    if(listview->ondragcomplete) {
+        UiDnD dnd;
+        dnd.target = NULL;
+        dnd.value = NULL;
+        dnd.providers = NULL;
+        dnd.selected_action = gdk_drag_get_selected_action(drag);
+        dnd.delete = delete_data;
+        dnd.accept = FALSE;
+        
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = &dnd;
+        event.intval = 0;
+        listview->ondragcomplete(&event, listview->ondragcompletedata);
+    }
+}
+
+static gboolean ui_listview_drop(
+        GtkDropTarget *target,
+        const GValue* value,
+        gdouble x,
+        gdouble y,
+        gpointer user_data)
+{
+    UiListView *listview = user_data;
+    UiDnD dnd;
+    dnd.providers = NULL;
+    dnd.target = target;
+    dnd.value = value;
+    dnd.selected_action = 0;
+    dnd.delete = FALSE;
+    dnd.accept = FALSE;
+    
+    if(listview->ondrop) {
+        dnd.accept = TRUE;
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = &dnd;
+        event.intval = 0;
+        listview->ondrop(&event, listview->ondropdata);
+    }
+    
+    return dnd.accept;
+}
+
+void ui_listview_add_dnd(UiListView *listview, UiListArgs *args) {
+    GtkDragSource *dragsource = gtk_drag_source_new();
+    gtk_widget_add_controller(listview->widget, GTK_EVENT_CONTROLLER(dragsource));
+    g_signal_connect (dragsource, "prepare", G_CALLBACK (ui_listview_dnd_prepare), listview);
+    g_signal_connect(
+            dragsource,
+            "drag-begin",
+            G_CALLBACK(ui_listview_drag_begin),
+            listview);
+    g_signal_connect(
+            dragsource,
+            "drag-end",
+            G_CALLBACK(ui_listview_drag_end),
+            listview);
+}
+
+void ui_listview_enable_drop(UiListView *listview, UiListArgs *args) {
+    GtkDropTarget *target = gtk_drop_target_new(G_TYPE_INVALID, GDK_ACTION_COPY);
+    gtk_widget_add_controller(listview->widget, GTK_EVENT_CONTROLLER(target));
+    GType default_types[2] = { GDK_TYPE_FILE_LIST, G_TYPE_STRING };
+    gtk_drop_target_set_gtypes(target, default_types, 2);
+    g_signal_connect(target, "drop", G_CALLBACK(ui_listview_drop), listview);
+}
+
+#else
+
+static GtkTargetEntry targetentries[] =
+{
+    { "STRING",        0, 0 },
+    { "text/plain",    0, 1 },
+    { "text/uri-list", 0, 2 },
+};
+
+static void ui_listview_drag_getdata(
+        GtkWidget* self,
+        GdkDragContext* context,
+        GtkSelectionData* data,
+        guint info,
+        guint time,
+        gpointer user_data)
+{
+    UiListView *listview = user_data;
+    UiDnD dnd;
+    dnd.context = context;
+    dnd.data = data;
+    dnd.selected_action = 0;
+    dnd.delete = FALSE;
+    dnd.accept = FALSE;
+    
+    if(listview->ondragstart) {
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = &dnd;
+        event.intval = 0;
+        listview->ondragstart(&event, listview->ondragstartdata);
+    }
+}
+
+static void ui_listview_drag_end(
+        GtkWidget *widget,
+        GdkDragContext *context,
+        guint time,
+        gpointer user_data)
+{
+    UiListView *listview = user_data;
+    UiDnD dnd;
+    dnd.context = context;
+    dnd.data = NULL;
+    dnd.selected_action = gdk_drag_context_get_selected_action(context);
+    dnd.delete = dnd.selected_action == UI_DND_ACTION_MOVE ? TRUE : FALSE;
+    dnd.accept = FALSE;
+    if(listview->ondragcomplete) {
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = &dnd;
+        event.intval = 0;
+        listview->ondragcomplete(&event, listview->ondragcompletedata);
+    }
+}
+
+void ui_listview_add_dnd(UiListView *listview, UiListArgs *args) {
+    gtk_tree_view_enable_model_drag_source(
+            GTK_TREE_VIEW(listview->widget),
+            GDK_BUTTON1_MASK,
+            targetentries,
+            2,
+            GDK_ACTION_COPY);
+    
+    g_signal_connect(listview->widget, "drag-data-get", G_CALLBACK(ui_listview_drag_getdata), listview);
+    g_signal_connect(listview->widget, "drag-end", G_CALLBACK(ui_listview_drag_end), listview);
+}
+
+
+
+
+static void ui_listview_drag_data_received(
+        GtkWidget *self,
+        GdkDragContext *context,
+        gint x,
+        gint y,
+        GtkSelectionData *data,
+        guint info,
+        guint time,
+        gpointer user_data)
+{
+    UiListView *listview = user_data;
+    UiDnD dnd;
+    dnd.context = context;
+    dnd.data = data;
+    dnd.selected_action = 0;
+    dnd.delete = FALSE;
+    dnd.accept = FALSE;
+    
+    if(listview->ondrop) {
+        dnd.accept = TRUE;
+        UiEvent event;
+        event.obj = listview->obj;
+        event.window = event.obj->window;
+        event.document = event.obj->ctx->document;
+        event.eventdata = &dnd;
+        event.intval = 0;
+        listview->ondrop(&event, listview->ondropdata);
+    }
+}
+
+void ui_listview_enable_drop(UiListView *listview, UiListArgs *args) {
+    gtk_tree_view_enable_model_drag_dest(
+            GTK_TREE_VIEW(listview->widget),
+            targetentries,
+            3,
+            GDK_ACTION_COPY);
+    if(listview->ondrop) {
+        g_signal_connect(listview->widget, "drag_data_received", G_CALLBACK(ui_listview_drag_data_received), listview);
+    }
+}
+
+#endif
+
 
 GtkWidget* ui_get_tree_widget(UIWIDGET widget) {
     return SCROLLEDWINDOW_GET_CHILD(widget);

mercurial