added undo for text

Mon, 24 Mar 2014 11:21:59 +0100

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Mon, 24 Mar 2014 11:21:59 +0100
changeset 6
05a18c56d9ca
parent 5
19d37cb9c96c
child 7
431dde3c5fbe

added undo for text

application/main.c file | annotate | diff | comparison | revisions
ui/gtk/text.c file | annotate | diff | comparison | revisions
ui/gtk/text.h file | annotate | diff | comparison | revisions
ui/ui/text.h file | annotate | diff | comparison | revisions
ui/ui/toolkit.h file | annotate | diff | comparison | revisions
--- a/application/main.c	Sat Mar 22 19:45:44 2014 +0100
+++ b/application/main.c	Mon Mar 24 11:21:59 2014 +0100
@@ -79,6 +79,17 @@
     }
 }
 
+void action_undo(UiEvent *event, void *data) {
+    printf("undo\n");
+    TestWindowData *wd = event->window;
+    ui_text_undo(&wd->text);
+}
+
+void action_redo(UiEvent *event, void *data) {
+    printf("redo\n");
+}
+
+
 int main(int argc, char** argv) {
     ui_init("app1", argc, argv);
     
@@ -96,11 +107,15 @@
     ui_toolitem_st("open", UI_STOCK_OPEN, action_open, NULL);
     ui_toolitem_st("save", UI_STOCK_SAVE, action_save, NULL);
     ui_toolitem_st("close", UI_STOCK_CLOSE, action_close, NULL);
+    ui_toolitem_st("undo", UI_STOCK_UNDO, action_undo, NULL);
+    ui_toolitem_st("redo", UI_STOCK_REDO, action_redo, NULL);
     
     ui_toolbar_add_default("new");
     ui_toolbar_add_default("open");
     ui_toolbar_add_default("save");
     ui_toolbar_add_default("close");
+    ui_toolbar_add_default("undo");
+    ui_toolbar_add_default("redo");
     
     
     UiObject *window = ui_window("Mod0", NULL);
--- 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) {
+    
+}
--- a/ui/gtk/text.h	Sat Mar 22 19:45:44 2014 +0100
+++ b/ui/gtk/text.h	Mon Mar 24 11:21:59 2014 +0100
@@ -31,11 +31,29 @@
 
 #include "../ui/text.h"
 #include "toolkit.h"
+#include "../../ucx/list.h"
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
+#define UI_TEXTBUF_INSERT 0
+#define UI_TEXTBUF_DELETE 1
+typedef struct UiTextBufOp {
+    int  type; // UI_TEXTBUF_INSERT, UI_TEXTBUF_DELETE
+    int  start;
+    int  end;
+    int  len;
+    char *text;
+} UiTextBufOp;
+
+typedef struct UiUndoMgr {
+    UcxList *begin;
+    UcxList *cur;
+    int     length;
+    int     event;
+} UiUndoMgr;
+
 char* ui_textarea_get(UiText *text);
 void ui_textarea_set(UiText *text, char *str);
 void ui_textarea_realize_event(GtkWidget *widget, gpointer data);
@@ -50,6 +68,9 @@
         GtkTextIter *start,
         GtkTextIter *end,
         void *data);
+UiUndoMgr* ui_create_undomgr();
+void ui_free_textbuf_op(UiTextBufOp *op);
+int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen);
 
 #ifdef	__cplusplus
 }
--- a/ui/ui/text.h	Sat Mar 22 19:45:44 2014 +0100
+++ b/ui/ui/text.h	Mon Mar 24 11:21:59 2014 +0100
@@ -37,6 +37,8 @@
 
 UIWIDGET ui_textarea(UiObject *obj, UiText *value);
 
+void ui_text_undo(UiText *value);
+void ui_text_redo(UiText *value);
 
 #ifdef	__cplusplus
 }
--- a/ui/ui/toolkit.h	Sat Mar 22 19:45:44 2014 +0100
+++ b/ui/ui/toolkit.h	Mon Mar 24 11:21:59 2014 +0100
@@ -124,6 +124,7 @@
     void  (*set)(UiText*, char*);
     char* value;
     void  *obj;
+    void  *undomgr;
     // TODO: selection, undo, replace, ...
 };
 

mercurial