#include <cx/buffer.h>
#include <cx/hash_map.h>
+#include <cx/string.h>
+#include <cx/printf.h>
#include <ctype.h>
#include <string.h>
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);
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
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)
/*
}
}
+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) {