]> uap-core.de Git - note.git/commitdiff
improve editor textview: implement automatic list element insertion main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 9 Feb 2026 20:37:42 +0000 (21:37 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 9 Feb 2026 20:37:42 +0000 (21:37 +0100)
application/gtk-text.c
application/gtk-text.h

index 3521972f4b5ad61aa9ef0c7415cdc6c91ccfad30..08abca0962581b255c1c1500dca73781a227f2f1 100644 (file)
@@ -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);
     
index c62b8c80d4165c3f320f103d69b44be225c39d3d..c7392c9c149e925625f27f720718ab1f4db47e64 100644 (file)
@@ -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 {