# HG changeset patch # User Olaf Wintermann # Date 1395656519 -3600 # Node ID 05a18c56d9ca63ab50d717a59f9c829fb12a8d4b # Parent 19d37cb9c96c8e68ba09d120d18f6d389665ea66 added undo for text diff -r 19d37cb9c96c -r 05a18c56d9ca application/main.c --- 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); 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) { + +} diff -r 19d37cb9c96c -r 05a18c56d9ca ui/gtk/text.h --- 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 } diff -r 19d37cb9c96c -r 05a18c56d9ca ui/ui/text.h --- 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 } diff -r 19d37cb9c96c -r 05a18c56d9ca ui/ui/toolkit.h --- 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, ... };