From 448493faa5c39550b1a62650ebafedde8a5e187c Mon Sep 17 00:00:00 2001 From: Olaf Wintermann Date: Wed, 16 Apr 2025 21:22:21 +0200 Subject: [PATCH] implement loading images from attachments in editor_load_markdown/editor_apply_styles --- application/editor.c | 5 +++-- application/editor.h | 4 ++-- application/gtk-text.c | 35 +++++++++++++++++++++++++++++++++-- application/note.c | 23 +++++++++++++++++++---- application/note.h | 2 ++ application/notebook.c | 2 +- ui/gtk/image.c | 1 - 7 files changed, 60 insertions(+), 12 deletions(-) diff --git a/application/editor.c b/application/editor.c index f8d8e09..cb39004 100644 --- a/application/editor.c +++ b/application/editor.c @@ -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); diff --git a/application/editor.h b/application/editor.h index b5745d7..690589d 100644 --- a/application/editor.h +++ b/application/editor.h @@ -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); diff --git a/application/gtk-text.c b/application/gtk-text.c index 471d883..875fdbd 100644 --- a/application/gtk-text.c +++ b/application/gtk-text.c @@ -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; } diff --git a/application/note.c b/application/note.c index 3d3c946..b06f0dd 100644 --- a/application/note.c +++ b/application/note.c @@ -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; +} diff --git a/application/note.h b/application/note.h index 04524f4..d560d8f 100644 --- a/application/note.h +++ b/application/note.h @@ -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 diff --git a/application/notebook.c b/application/notebook.c index 2342415..e2487cd 100644 --- a/application/notebook.c +++ b/application/notebook.c @@ -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 { diff --git a/ui/gtk/image.c b/ui/gtk/image.c index db060f1..8ce1b4b 100644 --- a/ui/gtk/image.c +++ b/ui/gtk/image.c @@ -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; -- 2.43.5