diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-21 18:26:41 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-21 18:26:41 +0300 |
commit | be456258d7160a110e8ea13cd0a17db1513224ff (patch) | |
tree | 76a2236d084947db287c43b976a1cd88d7151fbc /src | |
parent | 80382aa115963c07140ad6350fd70541092a6eac (diff) |
InputWidget: Overwrite mode and max length
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/inputwidget.c | 122 |
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 | ||
303 | static 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 | |||
303 | static iRangecc rangeSize_String(const iString *d, size_t size) { | 336 | static 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 | ||
472 | static const char *sensitive_ = "\u25cf"; /* black circle */ | ||
473 | |||
439 | static iString *visText_InputWidget_(const iInputWidget *d) { | 474 | static 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 | ||
1282 | static 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 | |||
1315 | iLocalDef iBool movePos_InputWidget_(const iInputWidget *d, iInt2 *pos, int dir) { | 1330 | iLocalDef 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); |