]> uap-core.de Git - note.git/commitdiff
implement loading images from attachments in editor_load_markdown/editor_apply_styles
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 16 Apr 2025 19:22:21 +0000 (21:22 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Wed, 16 Apr 2025 19:22:21 +0000 (21:22 +0200)
application/editor.c
application/editor.h
application/gtk-text.c
application/note.c
application/note.h
application/notebook.c
ui/gtk/image.c

index f8d8e09b86b2e12e16440a6d36790248f1b6393b..cb39004049a2aeb5d8174f2e86c4b4db68da03d7 100644 (file)
@@ -35,7 +35,8 @@
 
 
 
-void editor_load_markdown(UiText *text, cxmutstr markdown) {
+void editor_load_markdown(Resource *note, UIWIDGET textview, cxmutstr markdown) {
+    UiText *text = note->model->text;
     // make sure the textbuf is initialized
     editor_init_textbuf(text);
     
@@ -46,7 +47,7 @@ void editor_load_markdown(UiText *text, cxmutstr markdown) {
     }
     MDDocLinear lin = mddoc_linearization(doc);
     ui_set(text, lin.content.ptr);
-    editor_apply_styles(text, lin.styles);
+    editor_apply_styles(note, ui_textarea_gettextwidget(textview), text, lin.styles);
     
     free(lin.content.ptr);
     cxListFree(lin.styles);
index b5745d7d9e78e18cfd7621be8c5037c12b4dc967..690589d20973e5a9463246f3142150e551b8ff42 100644 (file)
@@ -111,7 +111,7 @@ struct MDActiveStyles {
     
 void editor_init(UiText *text);
     
-void editor_load_markdown(UiText *text, cxmutstr markdown);
+void editor_load_markdown(Resource *note, UIWIDGET textview, cxmutstr markdown);
 
 MDDoc* parse_markdown(cxstring markdown);
 void mddoc_free(MDDoc *doc);
@@ -126,7 +126,7 @@ MDDocLinear mddoc_linearization(MDDoc *doc);
 void editor_global_init();
 void editor_init_textview(UiObject *obj, UIWIDGET textview);
 void editor_init_textbuf(UiText *text);
-void editor_apply_styles(UiText *text, CxList /* MDDocStyleSection */ *styles);
+void editor_apply_styles(Resource *note, UIWIDGET textview, UiText *text, CxList /* MDDocStyleSection */ *styles);
 cxmutstr editor_get_markdown(UiText *text, const CxAllocator *a);
 
 UiBool editor_set_style(UiText *text, const char *style, UiBool enabled);
index 471d8837de6124306953fab890b561d96f411711..875fdbdb9965549ba58817d06c0a67fd2dc27b59 100644 (file)
@@ -711,14 +711,45 @@ void init_tagtable(GtkTextTagTable *table) {
 /*
  * Applies all styles from the MDDocStyleSection list to the text buffer
  */
-void editor_apply_styles(UiText *text, CxList /* MDDocStyleSection */ *styles) {
+void editor_apply_styles(Resource *note, UIWIDGET textview, UiText *text, CxList /* MDDocStyleSection */ *styles) {
     GtkTextBuffer *buffer = text->data1;
     GtkTextTagTable *tagtable = gtk_text_buffer_get_tag_table(buffer);
     
     CxIterator i = cxListIterator(styles);
     cx_foreach(MDDocStyleSection*, sec, i) {
         if(sec->length == MDDocStyleSection_IMAGE) {
-            // TODO: insert image
+            Attachment *attachment = note_get_attachment(note, sec->link);
+            if(attachment && attachment->bin_content.length > 0) {
+                // we can use ui_image_load_data to load the image, but we
+                // need an UiGeneric object for that
+                UiGeneric imgobj;
+                memset(&imgobj, 0, sizeof(UiGeneric));
+                if(!ui_image_load_data(&imgobj, attachment->bin_content.ptr, attachment->bin_content.length)) {
+                    GdkPixbuf *pixbuf = imgobj.value;
+                    
+                    // TODO: remove code dup
+                    GtkTextIter iter;
+                    gtk_text_buffer_get_iter_at_offset(buffer, &iter, sec->pos);
+                    GtkTextChildAnchor *anchor = gtk_text_buffer_create_child_anchor(buffer, &iter);
+                    GtkWidget *image = embedded_image_create(pixbuf);
+                    gtk_text_view_add_child_at_anchor(GTK_TEXT_VIEW(textview), image, anchor);
+                    
+                    EmbeddedWidget *em = malloc(sizeof(EmbeddedWidget));
+                    em->widget = image;
+                    em->anchor = anchor;
+                    em->data1 = attachment;
+                    em->data2 = NULL;
+                    em->serialize = md_serialize_image;
+                    g_object_ref(image);
+                    g_object_ref(anchor);
+
+                    g_object_set_data(G_OBJECT(anchor), "em", em);
+                } else {
+                    fprintf(stderr, "Error: cannot load image data\n");
+                }
+            } else {
+                // TODO: what do we do in this case?
+            }
             continue;
         }
         
index 3d3c9469a317661d68e649dc009e997a2494b10e..b06f0dd2fba2d3c7e855ff35fdfc4824e530b12b 100644 (file)
@@ -107,12 +107,13 @@ typedef struct LoadNoteContent {
     UiBool attachments;
 } LoadNoteContent;
 
-static void note_loading_completed(LoadNoteContent *op) {
+static void note_loading_completed(UiObject *obj, LoadNoteContent *op) {
     Resource *note = op->note;
+    MainWindow *wdata = obj->window;
     free(op);
     
     if(note->model) {
-        editor_load_markdown(note->model->text, note->content);
+        editor_load_markdown(note, wdata->textview, note->content);
     }
     note->content_loaded = TRUE;
 }
@@ -123,7 +124,7 @@ static void note_content_loaded(UiEvent *event, cxmutstr result, void *userdata)
     printf("note content: %s\n", result.ptr);
     op->content = TRUE;
     if(op->attachments) {
-        note_loading_completed(op);
+        note_loading_completed(event->obj, op);
     }
 }
 
@@ -142,7 +143,7 @@ static void note_attachments_loaded(UiEvent *event, int error, void *userdata) {
     }
     
     if(op->content) {
-        note_loading_completed(op);
+        note_loading_completed(event->obj, op);
     }
 }
 
@@ -275,3 +276,17 @@ void note_destroy(const CxAllocator *a, Resource *note) {
         // TODO: destroy model->context
     }
 }
+
+Attachment* note_get_attachment(Resource *note, const char *path) {
+    if(!note->attachments) {
+        return NULL;
+    }
+    CxIterator i = cxListIterator(note->attachments);
+    cx_foreach(Attachment *, attachment, i) {
+        // TODO: support path, not just the name
+        if(!strcmp(attachment->name, path)) {
+            return attachment;
+        }
+    }
+    return NULL;
+}
index 04524f47a0dbaa7dcb90004186480ebfaba10ac7..d560d8f4b1001bee2b7d8dfe00b0418b9e331932 100644 (file)
@@ -66,6 +66,8 @@ void note_update_title(NotebookModel *notebook, Resource *note);
 const char* note_get_title(Resource *note);
 void note_destroy(const CxAllocator *a, Resource *note);
 
+Attachment* note_get_attachment(Resource *note, const char *path);
+
 #ifdef __cplusplus
 }
 #endif
index 2342415f3cf29ee5bda65ccf3f51f419041ecf47..e2487cd283b25cdc26c211b43233b9eb9b8b8932 100644 (file)
@@ -197,7 +197,7 @@ void notebookmodel_new_note(NotebookModel *model) {
     new_note->model->modified = TRUE;
     // initialize note content
     // possible to implement something like note templates here
-    editor_load_markdown(new_note->model->text, cx_mutstrn("", 0));
+    editor_load_markdown(new_note, model->window->textview, cx_mutstrn("", 0));
 }
 
 typedef struct NoteDeleteOp {
index db060f18ce6f03df78ec024e02b98fbc25e3915a..8ce1b4bdce5cc95029be51b47ce7e7cbeee49799 100644 (file)
@@ -346,7 +346,6 @@ UIEXPORT int ui_image_load_data(UiGeneric *obj, const void *imgdata, size_t size
     GInputStream *in = g_memory_input_stream_new_from_bytes(bytes);
     GError *error = NULL;
     GdkPixbuf *pixbuf = gdk_pixbuf_new_from_stream(in, NULL, &error);
-    g_object_unref(bytes);
     g_object_unref(in);
     if(!pixbuf) {
         return 1;