Fri, 28 Mar 2014 20:03:49 +0100
merge
--- a/ui/gtk/text.c Fri Mar 28 20:03:01 2014 +0100 +++ b/ui/gtk/text.c Fri Mar 28 20:03:49 2014 +0100 @@ -132,15 +132,22 @@ 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; + if(elm) { + mgr->cur->next = NULL; + while(elm) { + elm->prev = NULL; + UcxList *next = elm->next; + ui_free_textbuf_op(elm->data); + free(elm); + elm = next; + } } UiTextBufOp *last_op = mgr->cur->data; - if(ui_check_insertstr(last_op->text, last_op->len, text, length) == 0) { + if( + last_op->type == UI_TEXTBUF_INSERT && + 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); @@ -186,11 +193,15 @@ 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; + if(elm) { + mgr->cur->next = NULL; + while(elm) { + elm->prev = NULL; + UcxList *next = elm->next; + ui_free_textbuf_op(elm->data); + free(elm); + elm = next; + } } } @@ -223,7 +234,7 @@ void ui_free_textbuf_op(UiTextBufOp *op) { if(op->text) { - g_free(op->text); + free(op->text); } free(op); }
--- a/ui/motif/text.c Fri Mar 28 20:03:01 2014 +0100 +++ b/ui/motif/text.c Fri Mar 28 20:03:49 2014 +0100 @@ -52,6 +52,16 @@ value->set = ui_textarea_set; value->value = NULL; value->obj = text_area; + + if(!value->undomgr) { + value->undomgr = ui_create_undomgr(); + } + + XtAddCallback( + text_area, + XmNmodifyVerifyCallback, + (XtCallbackProc)ui_text_modify_callback, + value); } return text_area; @@ -74,3 +84,160 @@ text->value = NULL; XmTextSetString(text->obj, str); } + +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_text_modify_callback(Widget widget, UiText *value, XtPointer data) { + XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data; + int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE; + UiUndoMgr *mgr = value->undomgr; + if(!mgr->event) { + return; + } + + char *text = txv->text->ptr; + int length = txv->text->length; + + if(mgr->cur) { + UcxList *elm = mgr->cur->next; + if(elm) { + mgr->cur->next = NULL; + while(elm) { + elm->prev = NULL; + UcxList *next = elm->next; + ui_free_textbuf_op(elm->data); + free(elm); + elm = next; + } + } + + if(type == UI_TEXTBUF_INSERT) { + UiTextBufOp *last_op = mgr->cur->data; + if( + last_op->type == UI_TEXTBUF_INSERT && + 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 *str; + if(type == UI_TEXTBUF_INSERT) { + str = malloc(length + 1); + memcpy(str, text, length); + str[length] = 0; + } else { + length = txv->endPos - txv->startPos; + str = malloc(length + 1); + XmTextGetSubstring(value->obj, txv->startPos, length, length+1, str); + } + + UiTextBufOp *op = malloc(sizeof(UiTextBufOp)); + op->type = type; + op->start = txv->startPos; + op->end = txv->endPos + 1; + op->len = length; + op->text = str; + + UcxList *elm = ucx_list_append(NULL, op); + mgr->cur = elm; + mgr->begin = ucx_list_concat(mgr->begin, elm); +} + +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_free_textbuf_op(UiTextBufOp *op) { + if(op->text) { + free(op->text); + } + free(op); +} + + +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: { + XmTextReplace(value->obj, op->start, op->end, ""); + break; + } + case UI_TEXTBUF_DELETE: { + XmTextInsert(value->obj, op->start, op->text); + break; + } + } + mgr->event = 1; + mgr->cur = mgr->cur->prev; + } +} + +void ui_text_redo(UiText *value) { + UiUndoMgr *mgr = value->undomgr; + + UcxList *elm = NULL; + if(mgr->cur) { + if(mgr->cur->next) { + elm = mgr->cur->next; + } + } else if(mgr->begin) { + elm = mgr->begin; + } + + if(elm) { + UiTextBufOp *op = elm->data; + mgr->event = 0; + switch(op->type) { + case UI_TEXTBUF_INSERT: { + XmTextInsert(value->obj, op->start, op->text); + break; + } + case UI_TEXTBUF_DELETE: { + XmTextReplace(value->obj, op->start, op->end, ""); + break; + } + } + mgr->event = 1; + mgr->cur = elm; + } +}
--- a/ui/motif/text.h Fri Mar 28 20:03:01 2014 +0100 +++ b/ui/motif/text.h Fri Mar 28 20:03:49 2014 +0100 @@ -31,14 +31,36 @@ #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); +UiUndoMgr* ui_create_undomgr(); +void ui_text_modify_callback(Widget widget, UiText *value, XtPointer data); +int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen); +void ui_free_textbuf_op(UiTextBufOp *op); #ifdef __cplusplus }