2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2014 Olaf Wintermann. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
33 #include "container.h"
36 UIWIDGET ui_textarea_var(UiObject *obj, UiVar *var) {
37 UiContainer *ct = uic_get_current_container(obj);
41 //XtSetArg(args[n], XmNeditable, TRUE);
43 XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT);
46 Widget parent = ct->prepare(ct, args, &n, TRUE);
47 Widget text_area = XmCreateScrolledText(parent, "text_area", args, n);
48 ct->add(ct, XtParent(text_area));
49 XtManageChild(text_area);
51 UiTextArea *uitext = ucx_mempool_malloc(
54 uitext->ctx = obj->ctx;
55 uitext->last_selection_state = 0;
58 XmNmotionVerifyCallback,
59 (XtCallbackProc)ui_text_selection_callback,
64 UiText *value = var->value;
65 if(value->value.ptr) {
66 XmTextSetString(text_area, value->value.ptr);
67 value->value.free(value->value.ptr);
70 value->set = ui_textarea_set;
71 value->get = ui_textarea_get;
72 value->getsubstr = ui_textarea_getsubstr;
73 value->insert = ui_textarea_insert;
74 value->setposition = ui_textarea_setposition;
75 value->position = ui_textarea_position;
76 value->selection = ui_textarea_selection;
77 value->length = ui_textarea_length;
78 value->value.ptr = NULL;
79 value->obj = text_area;
82 value->undomgr = ui_create_undomgr();
87 XmNmodifyVerifyCallback,
88 (XtCallbackProc)ui_text_modify_callback,
95 UIWIDGET ui_textarea(UiObject *obj, UiText *value) {
96 UiVar *var = malloc(sizeof(UiVar));
98 var->type = UI_VAR_SPECIAL;
99 return ui_textarea_var(obj, var);
102 UIWIDGET ui_textarea_nv(UiObject *obj, char *varname) {
103 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_TEXT);
105 return ui_textarea_var(obj, var);
112 char* ui_textarea_get(UiText *text) {
113 if(text->value.ptr) {
114 text->value.free(text->value.ptr);
116 char *str = XmTextGetString(text->obj);
117 text->value.ptr = str;
118 text->value.free = (ui_freefunc)XtFree;
122 void ui_textarea_set(UiText *text, char *str) {
123 XmTextSetString(text->obj, str);
124 if(text->value.ptr) {
125 text->value.free(text->value.ptr);
127 text->value.ptr = NULL;
130 char* ui_textarea_getsubstr(UiText *text, int begin, int end) {
131 if(text->value.ptr) {
132 text->value.free(text->value.ptr);
134 int length = end - begin;
135 char *str = XtMalloc(length + 1);
136 XmTextGetSubstring(text->obj, begin, length, length + 1, str);
137 text->value.ptr = str;
138 text->value.free = (ui_freefunc)XtFree;
142 void ui_textarea_insert(UiText *text, int pos, char *str) {
143 text->value.ptr = NULL;
144 XmTextInsert(text->obj, pos, str);
145 if(text->value.ptr) {
146 text->value.free(text->value.ptr);
150 void ui_textarea_setposition(UiText *text, int pos) {
151 XmTextSetInsertionPosition(text->obj, pos);
154 int ui_textarea_position(UiText *text) {
157 XmTextGetSelectionPosition(text->obj, &begin, &end);
162 void ui_textarea_selection(UiText *text, int *begin, int *end) {
163 XmTextGetSelectionPosition(text->obj, (long*)begin, (long*)end);
166 int ui_textarea_length(UiText *text) {
167 return (int)XmTextGetLastPosition(text->obj);
171 void ui_text_set(UiText *text, char *str) {
173 text->set(text, str);
175 if(text->value.ptr) {
176 text->value.free(text->value.ptr);
178 text->value.ptr = XtNewString(str);
179 text->value.free = (ui_freefunc)XtFree;
183 char* ui_text_get(UiText *text) {
185 return text->get(text);
187 return text->value.ptr;
192 UiUndoMgr* ui_create_undomgr() {
193 UiUndoMgr *mgr = malloc(sizeof(UiUndoMgr));
201 void ui_text_selection_callback(
203 UiTextArea *textarea,
208 XmTextGetSelectionPosition(widget, &left, &right);
209 int sel = left < right ? 1 : 0;
210 if(sel != textarea->last_selection_state) {
212 ui_set_group(textarea->ctx, UI_GROUP_SELECTION);
214 ui_unset_group(textarea->ctx, UI_GROUP_SELECTION);
217 textarea->last_selection_state = sel;
220 void ui_text_modify_callback(Widget widget, UiVar *var, XtPointer data) {
221 UiText *value = var->value;
226 if(!value->undomgr) {
227 value->undomgr = ui_create_undomgr();
230 XmTextVerifyCallbackStruct *txv = (XmTextVerifyCallbackStruct*)data;
231 int type = txv->text->length > 0 ? UI_TEXTBUF_INSERT : UI_TEXTBUF_DELETE;
232 UiUndoMgr *mgr = value->undomgr;
237 char *text = txv->text->ptr;
238 int length = txv->text->length;
241 UcxList *elm = mgr->cur->next;
243 mgr->cur->next = NULL;
246 UcxList *next = elm->next;
247 ui_free_textbuf_op(elm->data);
253 if(type == UI_TEXTBUF_INSERT) {
254 UiTextBufOp *last_op = mgr->cur->data;
256 last_op->type == UI_TEXTBUF_INSERT &&
257 ui_check_insertstr(last_op->text, last_op->len, text, length) == 0)
259 // append text to last op
260 int ln = last_op->len;
261 char *newtext = malloc(ln + length + 1);
262 memcpy(newtext, last_op->text, ln);
263 memcpy(newtext+ln, text, length);
264 newtext[ln+length] = '\0';
266 last_op->text = newtext;
267 last_op->len = ln + length;
268 last_op->end += length;
276 if(type == UI_TEXTBUF_INSERT) {
277 str = malloc(length + 1);
278 memcpy(str, text, length);
281 length = txv->endPos - txv->startPos;
282 str = malloc(length + 1);
283 XmTextGetSubstring(value->obj, txv->startPos, length, length+1, str);
286 UiTextBufOp *op = malloc(sizeof(UiTextBufOp));
288 op->start = txv->startPos;
289 op->end = txv->endPos + 1;
293 UcxList *elm = ucx_list_append(NULL, op);
295 mgr->begin = ucx_list_concat(mgr->begin, elm);
298 int ui_check_insertstr(char *oldstr, int oldlen, char *newstr, int newlen) {
299 // return 1 if oldstr + newstr are one word
302 for(int i=0;i<oldlen;i++) {
309 for(int i=0;i<newlen;i++) {
310 if(has_space && newstr[i] > 32) {
318 void ui_free_textbuf_op(UiTextBufOp *op) {
326 void ui_text_undo(UiText *value) {
327 UiUndoMgr *mgr = value->undomgr;
330 UiTextBufOp *op = mgr->cur->data;
333 case UI_TEXTBUF_INSERT: {
334 XmTextReplace(value->obj, op->start, op->end, "");
337 case UI_TEXTBUF_DELETE: {
338 XmTextInsert(value->obj, op->start, op->text);
343 mgr->cur = mgr->cur->prev;
347 void ui_text_redo(UiText *value) {
348 UiUndoMgr *mgr = value->undomgr;
353 elm = mgr->cur->next;
355 } else if(mgr->begin) {
360 UiTextBufOp *op = elm->data;
363 case UI_TEXTBUF_INSERT: {
364 XmTextInsert(value->obj, op->start, op->text);
367 case UI_TEXTBUF_DELETE: {
368 XmTextReplace(value->obj, op->start, op->end, "");
378 /* ------------------------- textfield ------------------------- */
380 static UIWIDGET create_textfield(UiObject *obj, int width, UiBool frameless, UiBool password, UiString *value) {
381 UiContainer *ct = uic_get_current_container(obj);
384 XtSetArg(args[n], XmNeditMode, XmSINGLE_LINE_EDIT);
387 XtSetArg(args[n], XmNcolumns, width / 2 + 1);
391 XtSetArg(args[n], XmNshadowThickness, 0);
398 Widget parent = ct->prepare(ct, args, &n, FALSE);
399 Widget textfield = XmCreateText(parent, "text_field", args, n);
400 ct->add(ct, textfield);
401 XtManageChild(textfield);
405 if(value->value.ptr) {
406 XmTextSetString(textfield, value->value.ptr);
407 value->value.free(value->value.ptr);
410 value->set = ui_textfield_set;
411 value->get = ui_textfield_get;
412 value->value.ptr = NULL;
413 value->obj = textfield;
419 static UIWIDGET create_textfield_nv(UiObject *obj, int width, UiBool frameless, UiBool password, char *varname) {
420 UiVar *var = uic_create_var(obj->ctx, varname, UI_VAR_STRING);
422 UiString *value = var->value;
423 return ui_textfield(obj, value);
430 UIWIDGET ui_textfield(UiObject *obj, UiString *value) {
431 return create_textfield(obj, 0, FALSE, FALSE, value);
434 UIWIDGET ui_textfield_nv(UiObject *obj, char *varname) {
435 return create_textfield_nv(obj, 0, FALSE, FALSE, varname);
438 UIWIDGET ui_textfield_w(UiObject *obj, int width, UiString *value) {
439 return create_textfield(obj, width, FALSE, FALSE, value);
442 UIWIDGET ui_textfield_wnv(UiObject *obj, int width, char *varname) {
443 return create_textfield_nv(obj, width, FALSE, FALSE, varname);
446 UIWIDGET ui_frameless_textfield(UiObject *obj, UiString *value) {
447 return create_textfield(obj, 0, TRUE, FALSE, value);
450 UIWIDGET ui_frameless_textfield_nv(UiObject *obj, char *varname) {
451 return create_textfield_nv(obj, 0, TRUE, FALSE, varname);
454 UIWIDGET ui_passwordfield(UiObject *obj, UiString *value) {
455 return create_textfield(obj, 0, FALSE, TRUE, value);
458 UIWIDGET ui_passwordfield_nv(UiObject *obj, char *varname) {
459 return create_textfield_nv(obj, 0, FALSE, TRUE, varname);
462 UIWIDGET ui_passwordfield_w(UiObject *obj, int width, UiString *value) {
463 return create_textfield(obj, width, FALSE, TRUE, value);
466 UIWIDGET ui_passwordfield_wnv(UiObject *obj, int width, char *varname) {
467 return create_textfield_nv(obj, width, FALSE, TRUE, varname);
471 char* ui_textfield_get(UiString *str) {
473 str->value.free(str->value.ptr);
475 char *value = XmTextGetString(str->obj);
476 str->value.ptr = value;
477 str->value.free = (ui_freefunc)XtFree;
481 void ui_textfield_set(UiString *str, char *value) {
482 XmTextSetString(str->obj, value);
484 str->value.free(str->value.ptr);
486 str->value.ptr = NULL;