summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-07-21 18:26:41 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-07-21 18:26:41 +0300
commitbe456258d7160a110e8ea13cd0a17db1513224ff (patch)
tree76a2236d084947db287c43b976a1cd88d7151fbc /src/ui
parent80382aa115963c07140ad6350fd70541092a6eac (diff)
InputWidget: Overwrite mode and max length
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/inputwidget.c122
1 files changed, 68 insertions, 54 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index c1232d13..38c93f93 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -300,6 +300,39 @@ static int endX_InputWidget_(const iInputWidget *d, int y) {
300 return line->range.end - (isLastLine_InputWidget_(d, line) ? 0 : 1) - line->range.start; 300 return line->range.end - (isLastLine_InputWidget_(d, line) ? 0 : 1) - line->range.start;
301} 301}
302 302
303static iInt2 movedCursor_InputWidget_(const iInputWidget *d, iInt2 pos, int xDir, int yDir) {
304 iChar ch;
305 if (xDir < 0) {
306 if (pos.x == 0) {
307 if (pos.y > 0) {
308 pos.x = endX_InputWidget_(d, --pos.y);
309 }
310 }
311 else {
312 iAssert(pos.x > 0);
313 int n = decodePrecedingBytes_MultibyteChar(charPos_InputWidget_(d, pos),
314 cstr_String(lineString_InputWidget_(d, pos.y)),
315 &ch);
316 pos.x -= n;
317 }
318 }
319 else if (xDir > 0) {
320 if (pos.x == endX_InputWidget_(d, pos.y)) {
321 if (pos.y < size_Array(&d->lines) - 1) {
322 pos.y++;
323 pos.x = 0;
324 }
325 }
326 else {
327 int n = decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos),
328 constEnd_String(lineString_InputWidget_(d, pos.y)),
329 &ch);
330 pos.x += n;
331 }
332 }
333 return pos;
334}
335
303static iRangecc rangeSize_String(const iString *d, size_t size) { 336static iRangecc rangeSize_String(const iString *d, size_t size) {
304 return (iRangecc){ 337 return (iRangecc){
305 constBegin_String(d), 338 constBegin_String(d),
@@ -436,8 +469,9 @@ static size_t length_InputWidget_(const iInputWidget *d) {
436 return len; 469 return len;
437} 470}
438 471
472static const char *sensitive_ = "\u25cf"; /* black circle */
473
439static iString *visText_InputWidget_(const iInputWidget *d) { 474static iString *visText_InputWidget_(const iInputWidget *d) {
440 static const iChar sensitiveChar_ = 0x25cf; /* black circle */
441 iString *text; 475 iString *text;
442 if (~d->inFlags & isSensitive_InputWidgetFlag) { 476 if (~d->inFlags & isSensitive_InputWidgetFlag) {
443 text = text_InputWidget_(d); 477 text = text_InputWidget_(d);
@@ -446,7 +480,7 @@ static iString *visText_InputWidget_(const iInputWidget *d) {
446 text = new_String(); 480 text = new_String();
447 iAssert(d->length == length_InputWidget_(d)); 481 iAssert(d->length == length_InputWidget_(d));
448 for (size_t i = 0; i < d->length; i++) { 482 for (size_t i = 0; i < d->length; i++) {
449 appendChar_String(text, sensitiveChar_); 483 appendCStr_String(text, sensitive_);
450 } 484 }
451 } 485 }
452 return text; 486 return text;
@@ -989,8 +1023,12 @@ static void insertRange_InputWidget_(iInputWidget *d, iRangecc range) {
989 iInputLine *line = cursorLine_InputWidget_(d); 1023 iInputLine *line = cursorLine_InputWidget_(d);
990 if (d->mode == insert_InputMode) { 1024 if (d->mode == insert_InputMode) {
991 insertData_Block(&line->text.chars, d->cursor.x, range.start, size_Range(&range)); 1025 insertData_Block(&line->text.chars, d->cursor.x, range.start, size_Range(&range));
992 d->cursor.x += size_Range(&range);
993 } 1026 }
1027 else {
1028 iAssert(!newline);
1029 setSubData_Block(&line->text.chars, d->cursor.x, range.start, size_Range(&range));
1030 }
1031 d->cursor.x += size_Range(&range);
994 if (!newline) { 1032 if (!newline) {
995 break; 1033 break;
996 } 1034 }
@@ -1005,6 +1043,16 @@ static void insertRange_InputWidget_(iInputWidget *d, iRangecc range) {
1005 insert_Array(&d->lines, ++d->cursor.y, &split); 1043 insert_Array(&d->lines, ++d->cursor.y, &split);
1006 d->cursor.x = 0; 1044 d->cursor.x = 0;
1007 } 1045 }
1046 if (d->maxLen > 0) {
1047 iAssert(size_Array(&d->lines) == 1);
1048 iAssert(d->cursor.y == 0);
1049 iInputLine *line = front_Array(&d->lines);
1050 size_t len = length_String(&line->text);
1051 if (len > d->maxLen) {
1052 removeEnd_String(&line->text, len - d->maxLen);
1053 d->cursor.x = endX_InputWidget_(d, 0);
1054 }
1055 }
1008 textOfLinesWasChanged_InputWidget_(d, (iRangei){ firstModified, d->cursor.y + 1 }); 1056 textOfLinesWasChanged_InputWidget_(d, (iRangei){ firstModified, d->cursor.y + 1 });
1009#if 0 1057#if 0
1010 else if (d->maxLen == 0 || d->cursor < d->maxLen) { 1058 else if (d->maxLen == 0 || d->cursor < d->maxLen) {
@@ -1279,39 +1327,6 @@ static iBool isWordChar_InputWidget_(const iInputWidget *d, iInt2 pos) {
1279 return isAlphaNumeric_Char(at_InputWidget_(d, pos)); 1327 return isAlphaNumeric_Char(at_InputWidget_(d, pos));
1280} 1328}
1281 1329
1282static iInt2 movedCursor_InputWidget_(const iInputWidget *d, iInt2 pos, int xDir, int yDir) {
1283 iChar ch;
1284 if (xDir < 0) {
1285 if (pos.x == 0) {
1286 if (pos.y > 0) {
1287 pos.x = endX_InputWidget_(d, --pos.y);
1288 }
1289 }
1290 else {
1291 iAssert(pos.x > 0);
1292 int n = decodePrecedingBytes_MultibyteChar(charPos_InputWidget_(d, pos),
1293 cstr_String(lineString_InputWidget_(d, pos.y)),
1294 &ch);
1295 pos.x -= n;
1296 }
1297 }
1298 else if (xDir > 0) {
1299 if (pos.x == endX_InputWidget_(d, pos.y)) {
1300 if (pos.y < size_Array(&d->lines) - 1) {
1301 pos.y++;
1302 pos.x = 0;
1303 }
1304 }
1305 else {
1306 int n = decodeBytes_MultibyteChar(charPos_InputWidget_(d, pos),
1307 constEnd_String(lineString_InputWidget_(d, pos.y)),
1308 &ch);
1309 pos.x += n;
1310 }
1311 }
1312 return pos;
1313}
1314
1315iLocalDef iBool movePos_InputWidget_(const iInputWidget *d, iInt2 *pos, int dir) { 1330iLocalDef iBool movePos_InputWidget_(const iInputWidget *d, iInt2 *pos, int dir) {
1316 iInt2 npos = movedCursor_InputWidget_(d, *pos, dir, 0); 1331 iInt2 npos = movedCursor_InputWidget_(d, *pos, dir, 0);
1317 if (isEqual_I2(*pos, npos)) { 1332 if (isEqual_I2(*pos, npos)) {
@@ -2023,35 +2038,36 @@ static void draw_InputWidget_(const iInputWidget *d) {
2023 unsetClip_Paint(&p); 2038 unsetClip_Paint(&p);
2024 /* Draw the insertion point. */ 2039 /* Draw the insertion point. */
2025 if (isFocused && d->cursorVis) { 2040 if (isFocused && d->cursorVis) {
2026 iString cur;
2027 iInt2 curSize; 2041 iInt2 curSize;
2042 iRangecc cursorChar = iNullRange;
2028 int visWrapsAbove = 0; 2043 int visWrapsAbove = 0;
2029 for (int i = d->cursor.y - 1; i >= visLines.start; i--) { 2044 for (int i = d->cursor.y - 1; i >= visLines.start; i--) {
2030 const iInputLine *line = constAt_Array(&d->lines, i); 2045 const iInputLine *line = constAt_Array(&d->lines, i);
2031 visWrapsAbove += numWrapLines_InputLine_(line); 2046 visWrapsAbove += numWrapLines_InputLine_(line);
2032 } 2047 }
2033#if 0
2034 if (d->mode == overwrite_InputMode) { 2048 if (d->mode == overwrite_InputMode) {
2035 /* Block cursor that overlaps a character. */ 2049 /* Block cursor that overlaps a character. */
2036 if (d->cursor < size_Array(&d->text)) { 2050 cursorChar.start = charPos_InputWidget_(d, d->cursor);
2037 if (~d->inFlags & isSensitive_InputWidgetFlag) { 2051 iChar ch = 0;
2038 initUnicodeN_String(&cur, constAt_Array(&d->text, d->cursor), 1); 2052 int n = decodeBytes_MultibyteChar(cursorChar.start,
2039 } 2053 constEnd_String(&constCursorLine_InputWidget_(d)->text),
2040 else { 2054 &ch);
2041 initUnicodeN_String(&cur, &sensitiveChar_, 1); 2055 cursorChar.end = cursorChar.start + iMax(n, 0);
2056 if (ch) {
2057 if (d->inFlags & isSensitive_InputWidgetFlag) {
2058 cursorChar = range_CStr(sensitive_);
2042 } 2059 }
2043 } 2060 }
2044 else { 2061 else {
2045 initCStr_String(&cur, " "); 2062 cursorChar = range_CStr(" ");
2046 } 2063 }
2047 curSize = addX_I2(measure_Text(d->font, cstr_String(&cur)).bounds.size, 2064 curSize = addX_I2(measureRange_Text(d->font, ch ? cursorChar : range_CStr("_")).bounds.size,
2048 iMin(2, gap_UI / 4)); 2065 iMin(2, gap_UI / 4));
2049 } 2066 }
2050 else { 2067 else {
2051#endif
2052 /* Bar cursor. */ 2068 /* Bar cursor. */
2053 curSize = init_I2(gap_UI / 2, lineHeight_Text(d->font)); 2069 curSize = init_I2(gap_UI / 2, lineHeight_Text(d->font));
2054// } 2070 }
2055 //const iInputLine *curLine = constCursorLine_InputWidget_(d); 2071 //const iInputLine *curLine = constCursorLine_InputWidget_(d);
2056 //const iString * text = &curLine->text; 2072 //const iString * text = &curLine->text;
2057 /* The bounds include visible characters, while advance includes whitespace as well. 2073 /* The bounds include visible characters, while advance includes whitespace as well.
@@ -2078,12 +2094,10 @@ static void draw_InputWidget_(const iInputWidget *d) {
2078 if (d->mode == overwrite_InputMode) { 2094 if (d->mode == overwrite_InputMode) {
2079 /* The `gap_UI` offsets below are a hack. They are used because for some reason the 2095 /* The `gap_UI` offsets below are a hack. They are used because for some reason the
2080 cursor rect and the glyph inside don't quite position like during `run_Text_()`. */ 2096 cursor rect and the glyph inside don't quite position like during `run_Text_()`. */
2081 draw_Text(d->font, 2097 drawRange_Text(d->font,
2082 addX_I2(curPos, iMin(1, gap_UI / 8)), 2098 addX_I2(curPos, iMin(1, gap_UI / 8)),
2083 uiInputCursorText_ColorId, 2099 uiInputCursorText_ColorId,
2084 "%s", 2100 cursorChar);
2085 cstr_String(&cur));
2086 deinit_String(&cur);
2087 } 2101 }
2088 } 2102 }
2089 drawChildren_Widget(w); 2103 drawChildren_Widget(w);