--- a/ui/motif/text.c Wed Dec 04 08:57:35 2024 +0100 +++ b/ui/motif/text.c Wed Dec 04 18:31:22 2024 +0100 @@ -32,476 +32,3 @@ #include "text.h" #include "container.h" - -UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) { - UiContainer *ct = uic_get_current_container(obj); - int n = 0; - Arg args[16]; - - //XtSetArg(args[n], XmNeditable, TRUE); - //n++; - XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); - n++; - - Widget parent = ct->prepare(ct, args, &n, TRUE); - Widget text_area = XmCreateScrolledText(parent, "text_area", args, n); - ct->add(ct, XtParent(text_area)); - XtManageChild(text_area); - - UiTextArea *uitext = cxMalloc( - obj->ctx->allocator, - sizeof(UiTextArea)); - uitext->ctx = obj->ctx; - uitext->last_selection_state = 0; - XtAddCallback( - text_area, - XmNmotionVerifyCallback, - (XtCallbackProc)ui_text_selection_callback, - uitext); - - // bind value - if(var->value) { - UiText *value = var->value; - if(value->value.ptr) { - XmTextSetString(text_area, value->value.ptr); - value->value.free(value->value.ptr); - } - - value->set = ui_textarea_set; - value->get = ui_textarea_get; - value->getsubstr = ui_textarea_getsubstr; - value->insert = ui_textarea_insert; - value->setposition = ui_textarea_setposition; - value->position = ui_textarea_position; - value->selection = ui_textarea_selection; - value->length = ui_textarea_length; - value->value.ptr = NULL; - value->obj = text_area; - - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); - } - - XtAddCallback( - text_area, - XmNmodifyVerifyCallback, - (XtCallbackProc)ui_text_modify_callback, - var); - } - - return text_area; -} - -UIWIDGET ui_textarea(UiObject *obj, UiText *value) { - UiVar *var = malloc(sizeof(UiVar)); - var->value = value; - var->type = UI_VAR_SPECIAL; - return ui_textarea_var(obj, var); -} - -UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT); - if(var) { - return ui_textarea_var(obj, var); - } else { - // TODO: error - } - return NULL; -} - -char* ui_textarea_get(UiText *text) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - char *str = XmTextGetString(text->obj); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; -} - -void ui_textarea_set(UiText *text, const char *str) { - XmTextSetString(text->obj, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - text->value.ptr = NULL; -} - -char* ui_textarea_getsubstr(UiText *text, int begin, int end) { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - int length = end - begin; - char *str = XtMalloc(length + 1); - XmTextGetSubstring(text->obj, begin, length, length + 1, str); - text->value.ptr = str; - text->value.free = (ui_freefunc)XtFree; - return str; -} - -void ui_textarea_insert(UiText *text, int pos, char *str) { - text->value.ptr = NULL; - XmTextInsert(text->obj, pos, str); - if(text->value.ptr) { - text->value.free(text->value.ptr); - } -} - -void ui_textarea_setposition(UiText *text, int pos) { - XmTextSetInsertionPosition(text->obj, pos); -} - -int ui_textarea_position(UiText *text) { - long begin; - long end; - XmTextGetSelectionPosition(text->obj, &begin, &end); - text->pos = begin; - return text->pos; -} - -void ui_textarea_selection(UiText *text, int *begin, int *end) { - XmTextGetSelectionPosition(text->obj, (long*)begin, (long*)end); -} - -int ui_textarea_length(UiText *text) { - return (int)XmTextGetLastPosition(text->obj); -} - - -void ui_text_set(UiText *text, char *str) { - if(text->set) { - text->set(text, str); - } else { - if(text->value.ptr) { - text->value.free(text->value.ptr); - } - text->value.ptr = XtNewString(str); - text->value.free = (ui_freefunc)XtFree; - } -} - -char* ui_text_get(UiText *text) { - if(text->get) { - return text->get(text); - } else { - return text->value.ptr; - } -} - - -UiUndoMgr* ui_create_undomgr() { - UiUndoMgr *mgr = malloc(sizeof(UiUndoMgr)); - mgr->begin = NULL; - mgr->end = NULL; - mgr->cur = NULL; - mgr->length = 0; - mgr->event = 1; - return mgr; -} - -void ui_destroy_undomgr(UiUndoMgr *mgr) { - UiTextBufOp *op = mgr->begin; - while(op) { - UiTextBufOp *nextOp = op->next; - if(op->text) { - free(op->text); - } - free(op); - op = nextOp; - } - free(mgr); -} - -void ui_text_selection_callback( - Widget widget, - UiTextArea *textarea, - XtPointer data) -{ - long left = 0; - long right = 0; - XmTextGetSelectionPosition(widget, &left, &right); - int sel = left < right ? 1 : 0; - if(sel != textarea->last_selection_state) { - if(sel) { - ui_set_group(textarea->ctx, UI_GROUP_SELECTION); - } else { - ui_unset_group(textarea->ctx, UI_GROUP_SELECTION); - } - } - textarea->last_selection_state = sel; -} - -void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data) { - UiText *value = var->value; - if(!value->obj) { - // TODO: bug, fix - return; - } - if(!value->undomgr) { - value->undomgr = ui_create_undomgr(); - } - - 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) { - UiTextBufOp *elm = mgr->cur->next; - if(elm) { - mgr->cur->next = NULL; - mgr->end = mgr->cur; - while(elm) { - elm->prev = NULL; - UiTextBufOp *next = elm->next; - ui_free_textbuf_op(elm); - elm = next; - } - } - - UiTextBufOp *last_op = mgr->cur; - 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->prev = NULL; - op->next = NULL; - op->type = type; - op->start = txv->startPos; - op->end = txv->endPos + 1; - op->len = length; - op->text = str; - - cx_linked_list_add( - (void**)&mgr->begin, - (void**)&mgr->end, - offsetof(UiTextBufOp, prev), - offsetof(UiTextBufOp, next), - op); - - mgr->cur = 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_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; - 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; - - UiTextBufOp *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; - 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; - } -} - - -/* ------------------------- textfield ------------------------- */ - -static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) { - UiContainer *ct = uic_get_current_container(obj); - int n = 0; - Arg args[16]; - XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT); - n++; - if(width > 0) { - XtSetArg(args[n], XmNcolumns, width / 2 + 1); - n++; - } - if(frameless) { - XtSetArg(args[n], XmNshadowThickness, 0); - n++; - } - if(password) { - // TODO - } - - Widget parent = ct->prepare(ct, args, &n, FALSE); - Widget textfield = XmCreateText(parent, "text_field", args, n); - ct->add(ct, textfield); - XtManageChild(textfield); - - // bind value - if(value) { - if(value->value.ptr) { - XmTextSetString(textfield, value->value.ptr); - value->value.free(value->value.ptr); - } - - value->set = ui_textfield_set; - value->get = ui_textfield_get; - value->value.ptr = NULL; - value->obj = textfield; - } - - return textfield; -} - -static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) { - UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING); - if(var) { - UiString *value = var->value; - return ui_textfield(obj, value); - } else { - // TODO: error - } - return NULL; -} - -UIWIDGET ui_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, FALSE, varname); -} - -UIWIDGET ui_textfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, FALSE, value); -} - -UIWIDGET ui_textfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, FALSE, varname); -} - -UIWIDGET ui_frameless_textfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, TRUE, FALSE, value); -} - -UIWIDGET ui_frameless_textfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, TRUE, FALSE, varname); -} - -UIWIDGET ui_passwordfield(UiObject *obj, UiString *value) { - return create_textfield(obj, 0, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_nv(UiObject *obj, char *varname) { - return create_textfield_nv(obj, 0, FALSE, TRUE, varname); -} - -UIWIDGET ui_passwordfield_w(UiObject *obj, int width, UiString *value) { - return create_textfield(obj, width, FALSE, TRUE, value); -} - -UIWIDGET ui_passwordfield_wnv(UiObject *obj, int width, char *varname) { - return create_textfield_nv(obj, width, FALSE, TRUE, varname); -} - - -char* ui_textfield_get(UiString *str) { - if(str->value.ptr) { - str->value.free(str->value.ptr); - } - char *value = XmTextGetString(str->obj); - str->value.ptr = value; - str->value.free = (ui_freefunc)XtFree; - return value; -} - -void ui_textfield_set(UiString *str, char *value) { - XmTextSetString(str->obj, value); - if(str->value.ptr) { - str->value.free(str->value.ptr); - } - str->value.ptr = NULL; -} -