ui/gtk/text.c

changeset 6
05a18c56d9ca
parent 5
19d37cb9c96c
child 8
84a541c6e093
--- a/ui/gtk/text.c	Sat Mar 22 19:45:44 2014 +0100
+++ b/ui/gtk/text.c	Mon Mar 24 11:21:59 2014 +0100
@@ -28,6 +28,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #include "text.h"
 #include "container.h"
@@ -68,18 +69,21 @@
         value->value = NULL;
         GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text_area));
         value->obj = buf;
+        if(!value->undomgr) {
+            value->undomgr = ui_create_undomgr();
+        }
         
         // register undo manager
         g_signal_connect(
                 buf,
                 "insert-text",
                 G_CALLBACK(ui_textbuf_insert),
-                NULL);
+                value);
         g_signal_connect(
                 buf,
                 "delete-range",
                 G_CALLBACK(ui_textbuf_delete),
-                NULL);
+                value);
     }
     
     return scroll_area;
@@ -110,14 +114,63 @@
     gtk_widget_grab_focus(widget);
 }
 
+
+// undo manager functions
+
 void ui_textbuf_insert(
         GtkTextBuffer *textbuffer,
         GtkTextIter *location,
         char *text,
-        int len,
+        int length,
         void *data)
 {
-    //TODO
+    UiText *value = data;
+    UiUndoMgr *mgr = value->undomgr;
+    if(!mgr->event) {
+        return;
+    }
+    
+    printf("insert\n");
+    if(mgr->cur) {
+        UcxList *elm = mgr->cur->next;
+        while(elm) {
+            ui_free_textbuf_op(elm->data);
+            UcxList *next = elm->next;
+            ucx_list_remove(mgr->begin, elm);
+            elm = next;
+        }
+        
+        UiTextBufOp *last_op = mgr->cur->data;
+        if(ui_check_insertstr(last_op->text, last_op->len, text, length) == 0) {
+            // append text to last op       
+            int ln = last_op->len;
+            char *newtext = malloc(ln + length + 1);
+            memcpy(newtext, last_op->text, ln);
+            memcpy(newtext+ln, text, length);
+            newtext[ln+length] = '\0';
+            
+            last_op->text = newtext;
+            last_op->len = ln + length;
+            last_op->end += length;
+            
+            return;
+        }
+    }
+    
+    char *dpstr = malloc(length + 1);
+    memcpy(dpstr, text, length);
+    dpstr[length] = 0;
+    
+    UiTextBufOp *op = malloc(sizeof(UiTextBufOp));
+    op->type = UI_TEXTBUF_INSERT;
+    op->start = gtk_text_iter_get_offset(location);
+    op->end = op->start+length;
+    op->len = length;
+    op->text = dpstr;
+    
+    UcxList *elm = ucx_list_append(NULL, op);
+    mgr->cur = elm;
+    mgr->begin = ucx_list_concat(mgr->begin, elm);
 }
 
 void ui_textbuf_delete(
@@ -126,5 +179,106 @@
         GtkTextIter *end,
         void *data)
 {
-    //TODO
+    UiText *value = data;
+    UiUndoMgr *mgr = value->undomgr;
+    if(!mgr->event) {
+        return;
+    }
+    
+    printf("delete\n");
+    if(mgr->cur) {
+        UcxList *elm = mgr->cur->next;
+        while(elm) {
+            ui_free_textbuf_op(elm->data);
+            UcxList *next = elm->next;
+            ucx_list_remove(mgr->begin, elm);
+            elm = next;
+        }
+    }
+    
+    char *text = gtk_text_buffer_get_text(value->obj, start, end, FALSE);
+    
+    UiTextBufOp *op = malloc(sizeof(UiTextBufOp));
+    op->type = UI_TEXTBUF_DELETE;
+    op->start = gtk_text_iter_get_offset(start);
+    op->end = gtk_text_iter_get_offset(end);
+    op->len = op->end - op->start;
+    
+    char *dpstr = malloc(op->len + 1);
+    memcpy(dpstr, text, op->len);
+    dpstr[op->len] = 0;
+    op->text = dpstr;
+    
+    UcxList *elm = ucx_list_append(NULL, op);
+    mgr->cur = elm;
+    mgr->begin = ucx_list_concat(mgr->begin, elm);
+}
+
+UiUndoMgr* ui_create_undomgr() {
+    UiUndoMgr *mgr = malloc(sizeof(UiUndoMgr));
+    mgr->begin = NULL;
+    mgr->cur = NULL;
+    mgr->length = 0;
+    mgr->event = 1;
+    return mgr;
+}
+
+void ui_free_textbuf_op(UiTextBufOp *op) {
+    if(op->text) {
+        g_free(op->text);
+    }
+    free(op);
 }
+
+int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) {
+    // return 1 if oldstr + newstr are one word
+    
+    int has_space = 0;
+    for(int i=0;i<oldlen;i++) {
+        if(oldstr[i] < 33) {
+            has_space = 1;
+            break;
+        }
+    }
+    
+    for(int i=0;i<newlen;i++) {
+        if(has_space && newstr[i] > 32) {
+            return 1;
+        }
+    }
+    
+    return 0;
+}
+
+void ui_text_undo(UiText *value) {
+    UiUndoMgr *mgr = value->undomgr;
+    
+    if(mgr->cur) {
+        UiTextBufOp *op = mgr->cur->data;
+        mgr->event = 0;
+        switch(op->type) {
+            case UI_TEXTBUF_INSERT: {
+                GtkTextIter begin;
+                GtkTextIter end;
+                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
+                gtk_text_buffer_delete(value->obj, &begin, &end);
+                break;
+            }
+            case UI_TEXTBUF_DELETE: {
+                GtkTextIter begin;
+                GtkTextIter end;
+                gtk_text_buffer_get_iter_at_offset(value->obj, &begin, op->start);
+                gtk_text_buffer_get_iter_at_offset(value->obj, &end, op->end);
+                gtk_text_buffer_insert(value->obj, &begin, op->text, op->len);
+                break;
+            }
+        }
+        mgr->event = 1;
+        mgr->cur = mgr->cur->prev;
+    }
+}
+
+void ui_text_redo(UiText *value) {
+    
+}

mercurial