diff -r 19d37cb9c96c -r 05a18c56d9ca ui/gtk/text.c --- 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 #include +#include #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 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) { + +}