From 6b8b3b5da79eacf733d136decfe77e3de6c4c8c2 Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Wed, 19 Mar 2025 20:03:24 +0100 Subject: [PATCH] implement editor dnd and image insertion --- application/gtk-text.c | 122 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) diff --git a/application/gtk-text.c b/application/gtk-text.c index f1cd7c1..1133d7f 100644 --- a/application/gtk-text.c +++ b/application/gtk-text.c @@ -32,6 +32,8 @@ #include #include +#include +#include #include #include @@ -58,6 +60,13 @@ static void editor_button_released_cb( double y, NoteEditor *editor); +static gboolean editor_drop_cb( + GtkDropTarget *target, + const GValue *value, + double x, + double y, + NoteEditor *editor); + #else static gboolean editor_textview_event_after(GtkWidget *textview, GdkEvent *ev, NoteEditor *editor); @@ -97,6 +106,17 @@ void editor_init_textview(UiObject *obj, UIWIDGET textview) { GtkEventController *controller = GTK_EVENT_CONTROLLER(gtk_gesture_click_new()); g_signal_connect(controller, "released", G_CALLBACK(editor_button_released_cb), editor); gtk_widget_add_controller(textview, controller); + + // DnD + GType dnd_types[2] = { + G_TYPE_FILE, + GDK_TYPE_PIXBUF + }; + + GtkDropTarget *dndtarget = gtk_drop_target_new (G_TYPE_INVALID, GDK_ACTION_COPY); + gtk_drop_target_set_gtypes(dndtarget, dnd_types, 2); + g_signal_connect(dndtarget, "drop", G_CALLBACK(editor_drop_cb), editor); + gtk_widget_add_controller(textview, GTK_EVENT_CONTROLLER(dndtarget)); #else g_signal_connect(textview, "event-after", G_CALLBACK(editor_textview_event_after), editor); #endif @@ -150,6 +170,57 @@ static void editor_set_cursor_cb( update_cursor_paragraph_style(editor, buffer); } +static gboolean path_is_image_file(cxstring path) { + if(path.length == 0) { + return FALSE; + } + + cxstring ext = (cxstring){NULL, 0}; + for(int i=path.length-1;i>= 0;i--) { + if(path.ptr[i] == '.') { + ext = cx_strsubs(path, i+1); + break; + } + } + + if(ext.length == 0) { + return FALSE; + } + + const char *img_ext[] = { "png", "jpg", "jpeg", "webp", "tif", "bmp", NULL}; + const char **i = img_ext; + while(*i) { + if(!cx_strcmp(ext, cx_str(*i))) { + return TRUE; + } + i++; + } + return FALSE; +} + +static gboolean editor_attach_file(NoteEditor *editor, const char *path) { + return FALSE; // TODO +} + +static void editor_attach_image(NoteEditor *editor, GdkPixbuf *pixbuf) { + GtkTextView *textview = GTK_TEXT_VIEW(editor->textview); + GtkTextBuffer *buffer = gtk_text_view_get_buffer(textview); + + GtkTextMark *cursor = gtk_text_buffer_get_insert(buffer); + GtkTextIter iter; + gtk_text_buffer_get_iter_at_mark(buffer, &iter, cursor); + + GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(buffer, &iter); + GdkTexture *texture = gdk_texture_new_for_pixbuf(pixbuf); + GtkWidget *image = gtk_image_new_from_paintable(GDK_PAINTABLE(texture)); + + int width = gdk_texture_get_width(texture); + int height = gdk_texture_get_height(texture); + gtk_widget_set_size_request(image, width, height); + + gtk_text_view_add_child_at_anchor(textview, image, anchor); +} + #if GTK_CHECK_VERSION(4, 0, 0) /* @@ -188,6 +259,57 @@ static void editor_button_released_cb( } } +static gboolean editor_drop_cb( + GtkDropTarget *target, + const GValue *value, + double x, + double y, + NoteEditor *editor) +{ + gboolean success = TRUE; + GdkPixbuf *pixbuf = NULL; + if(G_VALUE_HOLDS(value, G_TYPE_FILE)) { + // dnd type: uri + GFile *file = g_value_get_object(value); + if(!file) { + return FALSE; + } + char *scheme = g_file_get_uri_scheme(file); + if(scheme && strcmp(scheme, "file")) { + g_free(scheme); + return FALSE; + } + g_free(scheme); + + char *path = g_file_get_path(file); + printf("dnd file: %s\n", path); + + if(path_is_image_file(cx_str(path))) { + GError *error = NULL; + pixbuf = gdk_pixbuf_new_from_file(path, &error); + if(!pixbuf) { + // cannot load image, attach as generic file + success = editor_attach_file(editor, path); + } + } else { + // attach generic file + success = editor_attach_file(editor, path); + } + g_free(path); + } else if(G_VALUE_HOLDS (value, GDK_TYPE_PIXBUF)) { + // dnd type image + pixbuf = g_value_get_object(value); + } else { + return FALSE; + } + + if(pixbuf && success) { + editor_attach_image(editor, pixbuf); + } + + return success; +} + #else static gboolean editor_textview_event_after(GtkWidget *textview, GdkEvent *ev, NoteEditor *editor) { -- 2.43.5