summaryrefslogtreecommitdiff
path: root/src/ui/inputwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/inputwidget.c')
-rw-r--r--src/ui/inputwidget.c116
1 files changed, 56 insertions, 60 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index c60aa474..16098d83 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -58,9 +58,9 @@ static void enableEditorKeysInMenus_(iBool enable) {
58iDeclareType(InputLine) 58iDeclareType(InputLine)
59 59
60struct Impl_InputLine { 60struct Impl_InputLine {
61 iString text; /* UTF-8 */ 61 iString text;
62 iRanges range; /* byte offset inside the entire content; for marking */ 62 iRanges range; /* byte offset inside the entire content; for marking */
63 iRangei wrapLines; /* range of visual wrapped lines */ 63 iRangei wrapLines; /* range of visual wrapped lines */
64}; 64};
65 65
66static void init_InputLine(iInputLine *d) { 66static void init_InputLine(iInputLine *d) {
@@ -323,17 +323,35 @@ static int visLineOffsetY_InputWidget_(const iInputWidget *d) {
323 return (line->wrapLines.start - d->visWrapLines.start) * lineHeight_Text(d->font); 323 return (line->wrapLines.start - d->visWrapLines.start) * lineHeight_Text(d->font);
324} 324}
325 325
326static iWrapText wrap_InputWidget_(const iInputWidget *d, int y) {
327 return (iWrapText){
328 .text = range_String(&line_InputWidget_(d, y)->text),
329 .maxWidth = width_Rect(contentBounds_InputWidget_(d)),
330 .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode
331 : word_WrapTextMode),
332 };
333}
334
335static iInt2 relativeCursorCoord_InputWidget_(const iInputWidget *d) {
336 /* Relative to the start of the line on which the cursor is. */
337 iWrapText wt = wrap_InputWidget_(d, d->cursor.y);
338 wt.hitChar = wt.text.start + d->cursor.x;
339 measure_WrapText(&wt, d->font);
340 return wt.hitAdvance_out;
341}
342
326static void updateVisible_InputWidget_(iInputWidget *d) { 343static void updateVisible_InputWidget_(iInputWidget *d) {
327 const int totalWraps = numWrapLines_InputWidget_(d); 344 const int totalWraps = numWrapLines_InputWidget_(d);
328 const int visWraps = iClamp(totalWraps, d->minWrapLines, d->maxWrapLines); 345 const int visWraps = iClamp(totalWraps, d->minWrapLines, d->maxWrapLines);
329 /* Resize the height of the editor. */ 346 /* Resize the height of the editor. */
330 d->visWrapLines.end = d->visWrapLines.start + visWraps; 347 d->visWrapLines.end = d->visWrapLines.start + visWraps;
331 /* Determine which wraps are currently visible. */ 348 /* Determine which wraps are currently visible. */
349 d->cursor.y = iMin(d->cursor.y, size_Array(&d->lines) - 1);
332 const iInputLine *curLine = constAt_Array(&d->lines, d->cursor.y); 350 const iInputLine *curLine = constAt_Array(&d->lines, d->cursor.y);
333 const int cursorY = curLine->wrapLines.start + 351 const int cursorY = curLine->wrapLines.start +
334 measureRange_Text(d->font, rangeSize_String(&curLine->text, d->cursor.x)) 352 relativeCursorCoord_InputWidget_(d).y / lineHeight_Text(d->font);
335 .advance.y / lineHeight_Text(d->font); 353// measureRange_Text(d->font, rangeSize_String(&curLine->text, d->cursor.x))
336 354// .advance.y / lineHeight_Text(d->font);
337 //int scrollY = d->visLineOffsetY / lineHeight_Text(d->font); 355 //int scrollY = d->visLineOffsetY / lineHeight_Text(d->font);
338 /* Scroll to cursor. */ 356 /* Scroll to cursor. */
339 int delta = 0; 357 int delta = 0;
@@ -528,12 +546,7 @@ static void updateMetrics_InputWidget_(iInputWidget *d) {
528 546
529static void updateLine_InputWidget_(iInputWidget *d, iInputLine *line) { 547static void updateLine_InputWidget_(iInputWidget *d, iInputLine *line) {
530 iAssert(endsWith_String(&line->text, "\n") || isLastLine_InputWidget_(d, line)); 548 iAssert(endsWith_String(&line->text, "\n") || isLastLine_InputWidget_(d, line));
531 iWrapText wrapText = { 549 iWrapText wrapText = wrap_InputWidget_(d, indexOf_Array(&d->lines, line));
532 .text = range_String(&line->text),
533 .maxWidth = width_Rect(contentBounds_InputWidget_(d)),
534 .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode
535 : word_WrapTextMode),
536 };
537 if (wrapText.maxWidth <= 0) { 550 if (wrapText.maxWidth <= 0) {
538 line->wrapLines.end = line->wrapLines.start + 1; 551 line->wrapLines.end = line->wrapLines.start + 1;
539 return; 552 return;
@@ -1087,16 +1100,17 @@ static iBool findXBreaks_LineMover_(iWrapText *wrap, iRangecc wrappedText,
1087 1100
1088} 1101}
1089 1102
1090static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) { 1103static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir, int horiz) {
1091 const iInputLine *line = cursorLine_InputWidget_(d); 1104 const iInputLine *line = cursorLine_InputWidget_(d);
1092 iRangecc text = range_String(&line->text); 1105 iRangecc text = range_String(&line->text);
1093 iWrapText wrapText = { 1106// iWrapText wrapText = {
1094 .text = rangeSize_String(&line->text, d->cursor.x), 1107// .text = rangeSize_String(&line->text, d->cursor.x),
1095 .maxWidth = width_Rect(contentBounds_InputWidget_(d)), 1108// .maxWidth = width_Rect(contentBounds_InputWidget_(d)),
1096 .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode 1109// .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode
1097 : word_WrapTextMode), 1110// : word_WrapTextMode),
1098 }; 1111// };
1099 iInt2 relCoord = measure_WrapText(&wrapText, d->font).advance; 1112 //iInt2 relCoord = measure_WrapText(&wrapText, d->font).advance;
1113 iInt2 relCoord = relativeCursorCoord_InputWidget_(d);
1100 const int cursorWidth = measureN_Text(d->font, charPos_InputWidget_(d, d->cursor), 1).advance.x; 1114 const int cursorWidth = measureN_Text(d->font, charPos_InputWidget_(d, d->cursor), 1).advance.x;
1101 int relLine = relCoord.y / lineHeight_Text(d->font); 1115 int relLine = relCoord.y / lineHeight_Text(d->font);
1102 if ((dir < 0 && relLine > 0) || (dir > 0 && relLine < numWrapLines_InputLine_(line) - 1)) { 1116 if ((dir < 0 && relLine > 0) || (dir > 0 && relLine < numWrapLines_InputLine_(line) - 1)) {
@@ -1113,14 +1127,17 @@ static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) {
1113 line = cursorLine_InputWidget_(d); 1127 line = cursorLine_InputWidget_(d);
1114 relCoord.y = 0; 1128 relCoord.y = 0;
1115 } 1129 }
1130 else if (dir == 0 && horiz != 0) {
1131 relCoord.x = (horiz < 0 ? 0 : width_Widget(d));
1132 }
1116 else { 1133 else {
1117 return iFalse; 1134 return iFalse;
1118 } 1135 }
1119 wrapText.text = range_String(&cursorLine_InputWidget_(d)->text); 1136 iWrapText wt = wrap_InputWidget_(d, d->cursor.y);
1120 wrapText.hitPoint = addY_I2(relCoord, 1); //arelCddX_I2(relCoord, cursorWidth), 1137 wt.hitPoint = addY_I2(relCoord, 1); /* never (0, 0) because that disables the hit test */
1121 measure_WrapText(&wrapText, d->font); 1138 measure_WrapText(&wt, d->font);
1122 if (wrapText.hitChar_out) { 1139 if (wt.hitChar_out) {
1123 d->cursor.x = wrapText.hitChar_out - wrapText.text.start; 1140 d->cursor.x = wt.hitChar_out - wt.text.start;
1124 } 1141 }
1125 else { 1142 else {
1126 d->cursor.x = endX_InputWidget_(d, d->cursor.y); 1143 d->cursor.x = endX_InputWidget_(d, d->cursor.y);
@@ -1134,32 +1151,8 @@ static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) {
1134 } 1151 }
1135 }*/ 1152 }*/
1136 //showCursor_InputWidget_(d); 1153 //showCursor_InputWidget_(d);
1137 setCursor_InputWidget(d, d->cursor); 1154 setCursor_InputWidget(d, d->cursor); /* mark, show */
1138 return iTrue; 1155 return iTrue;
1139
1140#if 0
1141 const iInputLine *line = line_InputWidget_(d, d->cursorLine);
1142 int xPos1 = maxWidth_TextMetrics(measureN_Text(d->font,
1143 cstr_String(&line->text),
1144 d->cursor - line->offset));
1145 int xPos2 = maxWidth_TextMetrics(measureN_Text(d->font,
1146 cstr_String(&line->text),
1147 iMin(d->cursor + 1 - line->offset, line->len)));
1148 const int xPos = (xPos1 + xPos2) / 2;
1149 size_t newCursor = iInvalidPos;
1150 const size_t numLines = size_Array(&d->lines);
1151 if (dir < 0 && d->cursorLine > 0) {
1152 newCursor = indexForRelativeX_InputWidget_(d, xPos, --line);
1153 }
1154 else if (dir > 0 && d->cursorLine < numLines - 1) {
1155 newCursor = indexForRelativeX_InputWidget_(d, xPos, ++line);
1156 }
1157 if (newCursor != iInvalidPos) {
1158 setCursor_InputWidget(d, newCursor);
1159 return iTrue;
1160 }
1161#endif
1162 return iFalse;
1163} 1156}
1164 1157
1165void setSensitiveContent_InputWidget(iInputWidget *d, iBool isSensitive) { 1158void setSensitiveContent_InputWidget(iInputWidget *d, iBool isSensitive) {
@@ -1449,7 +1442,8 @@ static void paste_InputWidget_(iInputWidget *d) {
1449 } 1442 }
1450 } 1443 }
1451 SDL_free(text); 1444 SDL_free(text);
1452 iConstForEach(String, i, paste) { insertChar_InputWidget_(d, i.value); } 1445 //iConstForEach(String, i, paste) { insertChar_InputWidget_(d, i.value); }
1446 insertRange_InputWidget_(d, range_String(paste));
1453 contentsWereChanged_InputWidget_(d); 1447 contentsWereChanged_InputWidget_(d);
1454 } 1448 }
1455} 1449}
@@ -1826,7 +1820,8 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1826 case SDLK_RIGHT: { 1820 case SDLK_RIGHT: {
1827 const int dir = (key == SDLK_LEFT ? -1 : +1); 1821 const int dir = (key == SDLK_LEFT ? -1 : +1);
1828 if (mods & byLine_KeyModifier) { 1822 if (mods & byLine_KeyModifier) {
1829 setCursor_InputWidget(d, dir < 0 ? lineFirst : lineLast); 1823 //setCursor_InputWidget(d, dir < 0 ? lineFirst : lineLast);
1824 moveCursorByLine_InputWidget_(d, 0, dir);
1830 } 1825 }
1831 else if (mods & byWord_KeyModifier) { 1826 else if (mods & byWord_KeyModifier) {
1832 setCursor_InputWidget(d, skipWord_InputWidget_(d, d->cursor, dir)); 1827 setCursor_InputWidget(d, skipWord_InputWidget_(d, d->cursor, dir));
@@ -1847,7 +1842,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1847 return processEvent_Widget(as_Widget(d), ev); 1842 return processEvent_Widget(as_Widget(d), ev);
1848 case SDLK_UP: 1843 case SDLK_UP:
1849 case SDLK_DOWN: 1844 case SDLK_DOWN:
1850 if (moveCursorByLine_InputWidget_(d, key == SDLK_UP ? -1 : +1)) { 1845 if (moveCursorByLine_InputWidget_(d, key == SDLK_UP ? -1 : +1, 0)) {
1851 refresh_Widget(d); 1846 refresh_Widget(d);
1852 return iTrue; 1847 return iTrue;
1853 } 1848 }
@@ -1856,7 +1851,7 @@ static iBool processEvent_InputWidget_(iInputWidget *d, const SDL_Event *ev) {
1856 case SDLK_PAGEUP: 1851 case SDLK_PAGEUP:
1857 case SDLK_PAGEDOWN: 1852 case SDLK_PAGEDOWN:
1858 for (int count = 0; count < 5; count++) { 1853 for (int count = 0; count < 5; count++) {
1859 moveCursorByLine_InputWidget_(d, key == SDLK_PAGEUP ? -1 : +1); 1854 moveCursorByLine_InputWidget_(d, key == SDLK_PAGEUP ? -1 : +1, 0);
1860 } 1855 }
1861 refresh_Widget(d); 1856 refresh_Widget(d);
1862 return iTrue; 1857 return iTrue;
@@ -2050,16 +2045,17 @@ static void draw_InputWidget_(const iInputWidget *d) {
2050 /* Bar cursor. */ 2045 /* Bar cursor. */
2051 curSize = init_I2(gap_UI / 2, lineHeight_Text(d->font)); 2046 curSize = init_I2(gap_UI / 2, lineHeight_Text(d->font));
2052// } 2047// }
2053 const iInputLine *curLine = constCursorLine_InputWidget_(d); 2048 //const iInputLine *curLine = constCursorLine_InputWidget_(d);
2054 const iString * text = &curLine->text; 2049 //const iString * text = &curLine->text;
2055 /* The bounds include visible characters, while advance includes whitespace as well. 2050 /* The bounds include visible characters, while advance includes whitespace as well.
2056 Normally only the advance is needed, but if the cursor is at a newline, the advance 2051 Normally only the advance is needed, but if the cursor is at a newline, the advance
2057 will have reset back to zero. */ 2052 will have reset back to zero. */
2058 wrapText.text = range_String(text); 2053 //wrapText.text = range_String(text);
2059 wrapText.hitChar = wrapText.text.start + d->cursor.x; 2054 //wrapText.hitChar = wrapText.text.start + d->cursor.x;
2060 //const int prefixSize = maxWidth_TextMetrics( 2055 //const int prefixSize = maxWidth_TextMetrics(
2061 measure_WrapText(&wrapText, d->font); 2056 //measure_WrapText(&wrapText, d->font);
2062 const iInt2 advance = wrapText.hitAdvance_out; 2057 //const iInt2 advance = wrapText.hitAdvance_out;
2058 const iInt2 advance = relativeCursorCoord_InputWidget_(d);
2063 // const iInt2 curPos = addX_I2(addY_I2(contentBounds.pos, lineHeight_Text(d->font) 2059 // const iInt2 curPos = addX_I2(addY_I2(contentBounds.pos, lineHeight_Text(d->font)
2064 // * d->cursorLine), 2060 // * d->cursorLine),
2065 // prefixSize + 2061 // prefixSize +