From: Olaf Wintermann Date: Mon, 9 Feb 2026 20:37:42 +0000 (+0100) Subject: improve editor textview: implement automatic list element insertion X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;ds=sidebyside;p=note.git improve editor textview: implement automatic list element insertion --- diff --git a/application/gtk-text.c b/application/gtk-text.c index 3521972..08abca0 100644 --- a/application/gtk-text.c +++ b/application/gtk-text.c @@ -311,10 +311,52 @@ static void edit_insert_text_cb( GtkTextIter begin = *location; GtkTextIter end = begin; + int insert_offset = gtk_text_iter_get_offset(location) - len; + if(!gtk_text_iter_backward_chars(&begin, len)) { return; // should not happen } + cxstring ins_text = cx_strn(text, len); + + cxstring lines[64]; + size_t nlines = cx_strsplit(ins_text, "\n", 64, lines); + + int list_depth = 0; + int list_style = 0; + int list_num = 0; + if(nlines > 1) { + // Inserted text contains at least one linebreak + // Check if the current line contains a list + GtkTextIter prev_line = begin; + if(gtk_text_iter_backward_line(&prev_line)) { + GtkTextChildAnchor *anchor = NULL; + GtkTextChildAnchor *prevAnchor = NULL; + int end_offset = gtk_text_iter_get_offset(&begin); + // iterate over chars in line and check for anchors + while(gtk_text_iter_get_offset(&prev_line) < end_offset) { + if(!gtk_text_iter_forward_to_tag_toggle(&prev_line, NULL)) { + prev_line = begin; + } + + anchor = gtk_text_iter_get_child_anchor(&prev_line); + if(anchor && anchor != prevAnchor) { + EmbeddedWidget *em = g_object_get_data(G_OBJECT(anchor), "em"); + if(em) { + if(em->type == EMBEDDED_WIDGET_LIST) { + list_style = em->intdata1; + list_num = em->intdata2; + list_depth++; + } else if(em->type == EMBEDDED_WIDGET_LIST_INDENT) { + list_depth++; + } // else: other type of embedded widget (image, ...) + } + } + prevAnchor = anchor; + } + } + } + GtkTextIter prev = begin; if(gtk_text_iter_backward_char(&prev)) { // a previous position exists, apply tags from it @@ -345,6 +387,18 @@ static void edit_insert_text_cb( } g_slist_free(tags); } + + if(list_depth > 0) { + // Insert list elements for all inserted lines + // The first line is skipped, because the text will be part of the current list line + const char *style_name = list_style == 1 ? EDITOR_STYLE_LIST0 : EDITOR_STYLE_ORDLIST0; + for(int i=nlines-1;i>0;i--) { + intptr_t line_off = (intptr_t)(lines[i].ptr - text); + GtkTextIter iter; + gtk_text_buffer_get_iter_at_offset(buffer, &iter, insert_offset + line_off); + editor_insert_list_element(editor, &iter, style_name, list_num+i+1); + } + } } static gboolean path_is_image_file(cxstring path) { @@ -410,6 +464,7 @@ static void editor_insert_image(NoteEditor *editor, Attachment *attachment, GtkT gtk_widget_show_all(image); #endif + em->type = EMBEDDED_WIDGET_IMAGE; em->widget = image; em->anchor = anchor; em->data1 = attachment; @@ -1344,8 +1399,11 @@ void editor_insert_list_element(NoteEditor *editor, GtkTextIter *iter, const cha int height = pango_font_metrics_get_height(metrics) / PANGO_SCALE; ListElmWidget *elm = malloc(sizeof(ListElmWidget)); + int liststyle = 0; if(!strcmp(style, EDITOR_STYLE_LIST0)) { elm->str = strdup("•"); + liststyle = 1; + num = 0; } else { char buf[32]; snprintf(buf, 32, "%d.", num+1); @@ -1386,9 +1444,12 @@ void editor_insert_list_element(NoteEditor *editor, GtkTextIter *iter, const cha #if GTK_MAJOR_VERSION < 4 gtk_widget_show_all(widget); #endif + em->type = EMBEDDED_WIDGET_LIST; em->widget = widget; em->anchor = anchor; em->serialize = md_serialize_list; + em->intdata1 = liststyle; + em->intdata2 = num; g_object_ref(widget); g_object_ref(anchor); diff --git a/application/gtk-text.h b/application/gtk-text.h index c62b8c8..c7392c9 100644 --- a/application/gtk-text.h +++ b/application/gtk-text.h @@ -62,10 +62,19 @@ typedef struct BufferEmbeddedObjects { CxList *objects; } BufferEmbeddedObjects; +enum EmbeddedWidgetType { + EMBEDDED_WIDGET_IMAGE = 0, + EMBEDDED_WIDGET_LIST, + EMBEDDED_WIDGET_LIST_INDENT +}; + +typedef enum EmbeddedWidgetType EmbeddedWidgetType; + typedef struct EmbeddedWidget EmbeddedWidget; struct EmbeddedWidget { GtkWidget *widget; GtkTextChildAnchor *anchor; + EmbeddedWidgetType type; int width; int height; void (*adjust_size)(EmbeddedWidget *em, int max_width); @@ -74,6 +83,8 @@ struct EmbeddedWidget { void *wdata1; // wdata1/wdata2 filled by widget constructor void *wdata2; // and used by adjust_size void (*serialize)(EmbeddedWidget *e, CxBuffer *out); + int intdata1; + int intdata2; }; typedef struct ListElmWidget {