diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ui/inputwidget.c | 43 | ||||
-rw-r--r-- | src/ui/text.c | 19 | ||||
-rw-r--r-- | src/ui/text.h | 14 |
3 files changed, 51 insertions, 25 deletions
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index a5e8cf43..f7d41a44 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -1090,8 +1090,13 @@ static iBool findXBreaks_LineMover_(iWrapText *wrap, iRangecc wrappedText, | |||
1090 | static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) { | 1090 | static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) { |
1091 | const iInputLine *line = cursorLine_InputWidget_(d); | 1091 | const iInputLine *line = cursorLine_InputWidget_(d); |
1092 | iRangecc text = range_String(&line->text); | 1092 | iRangecc text = range_String(&line->text); |
1093 | iInt2 relCoord = measureRange_Text(d->font, (iRangecc){ text.start, | 1093 | iWrapText wrapText = { |
1094 | text.start + d->cursor.x }).advance; | 1094 | .text = rangeSize_String(&line->text, d->cursor.x), |
1095 | .maxWidth = width_Rect(contentBounds_InputWidget_(d)), | ||
1096 | .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode | ||
1097 | : word_WrapTextMode), | ||
1098 | }; | ||
1099 | iInt2 relCoord = measure_WrapText(&wrapText, d->font).advance; | ||
1095 | const int cursorWidth = measureN_Text(d->font, charPos_InputWidget_(d, d->cursor), 1).advance.x; | 1100 | const int cursorWidth = measureN_Text(d->font, charPos_InputWidget_(d, d->cursor), 1).advance.x; |
1096 | int relLine = relCoord.y / lineHeight_Text(d->font); | 1101 | int relLine = relCoord.y / lineHeight_Text(d->font); |
1097 | if ((dir < 0 && relLine > 0) || (dir > 0 && relLine < numWrapLines_InputLine_(line) - 1)) { | 1102 | if ((dir < 0 && relLine > 0) || (dir > 0 && relLine < numWrapLines_InputLine_(line) - 1)) { |
@@ -1111,13 +1116,8 @@ static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) { | |||
1111 | else { | 1116 | else { |
1112 | return iFalse; | 1117 | return iFalse; |
1113 | } | 1118 | } |
1114 | iWrapText wrapText = { | 1119 | wrapText.text = range_String(&cursorLine_InputWidget_(d)->text); |
1115 | .text = range_String(&cursorLine_InputWidget_(d)->text), | 1120 | wrapText.hitPoint = addY_I2(relCoord, 1); //arelCddX_I2(relCoord, cursorWidth), |
1116 | .maxWidth = width_Rect(contentBounds_InputWidget_(d)), | ||
1117 | .mode = (d->inFlags & isUrl_InputWidgetFlag ? anyCharacter_WrapTextMode | ||
1118 | : word_WrapTextMode), | ||
1119 | .hitPoint = addY_I2(relCoord, 1), //arelCddX_I2(relCoord, cursorWidth), | ||
1120 | }; | ||
1121 | measure_WrapText(&wrapText, d->font); | 1121 | measure_WrapText(&wrapText, d->font); |
1122 | iAssert(wrapText.hitChar_out); | 1122 | iAssert(wrapText.hitChar_out); |
1123 | d->cursor.x = wrapText.hitChar_out - wrapText.text.start; | 1123 | d->cursor.x = wrapText.hitChar_out - wrapText.text.start; |
@@ -1129,7 +1129,8 @@ static iBool moveCursorByLine_InputWidget_(iInputWidget *d, int dir) { | |||
1129 | d->cursor.x += n; | 1129 | d->cursor.x += n; |
1130 | } | 1130 | } |
1131 | }*/ | 1131 | }*/ |
1132 | showCursor_InputWidget_(d); | 1132 | //showCursor_InputWidget_(d); |
1133 | setCursor_InputWidget(d, d->cursor); | ||
1133 | return iTrue; | 1134 | return iTrue; |
1134 | 1135 | ||
1135 | #if 0 | 1136 | #if 0 |
@@ -1896,20 +1897,28 @@ static iBool draw_MarkPainter_(iWrapText *wrapText, iRangecc wrappedText, int or | |||
1896 | wrappedText.end - cstr + mp->line->range.start | 1897 | wrappedText.end - cstr + mp->line->range.start |
1897 | }; | 1898 | }; |
1898 | if (mark.end <= lineRange.start || mark.start >= lineRange.end) { | 1899 | if (mark.end <= lineRange.start || mark.start >= lineRange.end) { |
1900 | mp->pos.y += lineHeight_Text(mp->d->font); | ||
1899 | return iTrue; /* outside of mark */ | 1901 | return iTrue; /* outside of mark */ |
1900 | } | 1902 | } |
1901 | iRect rect = { addX_I2(mp->pos, origin), init_I2(advance, lineHeight_Text(mp->d->font)) }; | 1903 | iRect rect = { addX_I2(mp->pos, origin), init_I2(advance, lineHeight_Text(mp->d->font)) }; |
1902 | if (mark.end < lineRange.end) { | 1904 | if (mark.end < lineRange.end) { |
1903 | /* Calculate where the mark ends. */ | 1905 | /* Calculate where the mark ends. */ |
1904 | const iRangecc markedPrefix = { cstr, cstr + mark.end - lineRange.start }; | 1906 | const iRangecc markedPrefix = { //cstr, cstr + mark.end - lineRange.start }; |
1907 | wrappedText.start, | ||
1908 | wrappedText.start + mark.end - lineRange.start | ||
1909 | }; | ||
1905 | rect.size.x = measureRange_Text(mp->d->font, markedPrefix).advance.x; | 1910 | rect.size.x = measureRange_Text(mp->d->font, markedPrefix).advance.x; |
1906 | } | 1911 | } |
1907 | if (mark.start > lineRange.start) { | 1912 | if (mark.start > lineRange.start) { |
1908 | /* Calculate where the mark starts. */ | 1913 | /* Calculate where the mark starts. */ |
1909 | const iRangecc unmarkedPrefix = { cstr, cstr + mark.start - lineRange.start }; | 1914 | const iRangecc unmarkedPrefix = { //cstr, cstr + mark.start - lineRange.start |
1915 | wrappedText.start, | ||
1916 | wrappedText.start + mark.start - lineRange.start | ||
1917 | }; | ||
1910 | adjustEdges_Rect(&rect, 0, 0, 0, measureRange_Text(mp->d->font, unmarkedPrefix).advance.x); | 1918 | adjustEdges_Rect(&rect, 0, 0, 0, measureRange_Text(mp->d->font, unmarkedPrefix).advance.x); |
1911 | } | 1919 | } |
1912 | rect.size.x = iMax(gap_UI / 3, rect.size.x); | 1920 | rect.size.x = iMax(gap_UI / 3, rect.size.x); |
1921 | mp->pos.y += lineHeight_Text(mp->d->font); | ||
1913 | fillRect_Paint(mp->paint, rect, uiMarked_ColorId); | 1922 | fillRect_Paint(mp->paint, rect, uiMarked_ColorId); |
1914 | return iTrue; | 1923 | return iTrue; |
1915 | } | 1924 | } |
@@ -2041,11 +2050,11 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
2041 | /* The bounds include visible characters, while advance includes whitespace as well. | 2050 | /* The bounds include visible characters, while advance includes whitespace as well. |
2042 | 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 |
2043 | will have reset back to zero. */ | 2052 | will have reset back to zero. */ |
2044 | wrapText.text = range_String(text); | 2053 | wrapText.text = range_String(text); |
2045 | wrapText.text.end = wrapText.text.start + d->cursor.x; | 2054 | wrapText.hitChar = wrapText.text.start + d->cursor.x; |
2046 | iAssert(wrapText.text.end <= constEnd_String(text)); | ||
2047 | //const int prefixSize = maxWidth_TextMetrics( | 2055 | //const int prefixSize = maxWidth_TextMetrics( |
2048 | const iTextMetrics tm = measure_WrapText(&wrapText, d->font); | 2056 | measure_WrapText(&wrapText, d->font); |
2057 | const iInt2 advance = wrapText.hitAdvance_out; | ||
2049 | // const iInt2 curPos = addX_I2(addY_I2(contentBounds.pos, lineHeight_Text(d->font) | 2058 | // const iInt2 curPos = addX_I2(addY_I2(contentBounds.pos, lineHeight_Text(d->font) |
2050 | // * d->cursorLine), | 2059 | // * d->cursorLine), |
2051 | // prefixSize + | 2060 | // prefixSize + |
@@ -2054,7 +2063,7 @@ static void draw_InputWidget_(const iInputWidget *d) { | |||
2054 | //printf("%d -> tm.advance: %d, %d\n", d->cursor.x, tm.advance.x, tm.advance.y); | 2063 | //printf("%d -> tm.advance: %d, %d\n", d->cursor.x, tm.advance.x, tm.advance.y); |
2055 | const iInt2 curPos = add_I2(addY_I2(topLeft_Rect(contentBounds), visLineOffsetY + | 2064 | const iInt2 curPos = add_I2(addY_I2(topLeft_Rect(contentBounds), visLineOffsetY + |
2056 | visWrapsAbove * lineHeight_Text(d->font)), | 2065 | visWrapsAbove * lineHeight_Text(d->font)), |
2057 | addX_I2(tm.advance, | 2066 | addX_I2(advance, |
2058 | (d->mode == insert_InputMode ? -curSize.x / 2 : 0))); | 2067 | (d->mode == insert_InputMode ? -curSize.x / 2 : 0))); |
2059 | const iRect curRect = { curPos, curSize }; | 2068 | const iRect curRect = { curPos, curSize }; |
2060 | fillRect_Paint(&p, curRect, uiInputCursor_ColorId); | 2069 | fillRect_Paint(&p, curRect, uiInputCursor_ColorId); |
diff --git a/src/ui/text.c b/src/ui/text.c index d6a45c69..ce383ccf 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -1380,8 +1380,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1380 | /* TODO: Duplicated args? */ | 1380 | /* TODO: Duplicated args? */ |
1381 | iAssert(equalRange_Rangecc(wrap->text, args->text)); | 1381 | iAssert(equalRange_Rangecc(wrap->text, args->text)); |
1382 | /* Initialize the wrap range. */ | 1382 | /* Initialize the wrap range. */ |
1383 | wrap->wrapRange_ = args->text; | 1383 | wrap->wrapRange_ = args->text; |
1384 | wrap->hitChar_out = NULL; | 1384 | wrap->hitAdvance_out = zero_I2(); |
1385 | wrap->hitChar_out = NULL; | ||
1385 | wrap->hitGlyphNormX_out = 0.0f; | 1386 | wrap->hitGlyphNormX_out = 0.0f; |
1386 | } | 1387 | } |
1387 | const iChar *logicalText = constData_Array(&attrText.logical); | 1388 | const iChar *logicalText = constData_Array(&attrText.logical); |
@@ -1427,6 +1428,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1427 | const int layoutBound = (wrap ? wrap->maxWidth : 0); | 1428 | const int layoutBound = (wrap ? wrap->maxWidth : 0); |
1428 | iBool isFirst = iTrue; | 1429 | iBool isFirst = iTrue; |
1429 | const iBool checkHitPoint = wrap && !isEqual_I2(wrap->hitPoint, zero_I2()); | 1430 | const iBool checkHitPoint = wrap && !isEqual_I2(wrap->hitPoint, zero_I2()); |
1431 | const iBool checkHitChar = wrap && wrap->hitChar; | ||
1430 | while (!isEmpty_Range(&wrapRuns)) { | 1432 | while (!isEmpty_Range(&wrapRuns)) { |
1431 | if (isFirst) { | 1433 | if (isFirst) { |
1432 | isFirst = iFalse; | 1434 | isFirst = iFalse; |
@@ -1446,6 +1448,11 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1446 | for (size_t runIndex = wrapRuns.start; runIndex < wrapRuns.end; runIndex++) { | 1448 | for (size_t runIndex = wrapRuns.start; runIndex < wrapRuns.end; runIndex++) { |
1447 | const iAttributedRun *run = at_Array(&attrText.runs, runIndex); | 1449 | const iAttributedRun *run = at_Array(&attrText.runs, runIndex); |
1448 | if (run->flags.isLineBreak) { | 1450 | if (run->flags.isLineBreak) { |
1451 | if (checkHitChar) { | ||
1452 | if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, run->logical.start)) { | ||
1453 | wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor); | ||
1454 | } | ||
1455 | } | ||
1449 | wrapPosRange.end = run->logical.start; | 1456 | wrapPosRange.end = run->logical.start; |
1450 | wrapResumePos = run->logical.end; | 1457 | wrapResumePos = run->logical.end; |
1451 | wrapRuns.end = runIndex; | 1458 | wrapRuns.end = runIndex; |
@@ -1468,6 +1475,11 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1468 | if (logPos < wrapPosRange.start || logPos >= wrapPosRange.end) { | 1475 | if (logPos < wrapPosRange.start || logPos >= wrapPosRange.end) { |
1469 | continue; | 1476 | continue; |
1470 | } | 1477 | } |
1478 | if (checkHitChar) { | ||
1479 | if (wrap->hitChar == sourcePtr_AttributedText_(&attrText, logPos)) { | ||
1480 | wrap->hitAdvance_out = init_I2(wrapAdvance, yCursor); | ||
1481 | } | ||
1482 | } | ||
1471 | /* Check if the hit point is on the left side of this line. */ | 1483 | /* Check if the hit point is on the left side of this line. */ |
1472 | if (isHitPointOnThisLine && !wrap->hitChar_out && wrap->hitPoint.x < orig.x) { | 1484 | if (isHitPointOnThisLine && !wrap->hitChar_out && wrap->hitPoint.x < orig.x) { |
1473 | wrap->hitChar_out = sourcePtr_AttributedText_(&attrText, logPos); | 1485 | wrap->hitChar_out = sourcePtr_AttributedText_(&attrText, logPos); |
@@ -1723,6 +1735,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1723 | wrapPosRange.start = wrapResumePos; | 1735 | wrapPosRange.start = wrapResumePos; |
1724 | wrapPosRange.end = textLen; | 1736 | wrapPosRange.end = textLen; |
1725 | } | 1737 | } |
1738 | if (checkHitChar && wrap->hitChar == args->text.end) { | ||
1739 | wrap->hitAdvance_out = init_I2(xCursor, yCursor); | ||
1740 | } | ||
1726 | if (endsWith_Rangecc(args->text, "\n")) { | 1741 | if (endsWith_Rangecc(args->text, "\n")) { |
1727 | /* FIXME: This is a kludge, the wrap loop should handle this case, too. */ | 1742 | /* FIXME: This is a kludge, the wrap loop should handle this case, too. */ |
1728 | /* The last wrap is an empty newline wrap. */ | 1743 | /* The last wrap is an empty newline wrap. */ |
diff --git a/src/ui/text.h b/src/ui/text.h index a82da22c..322d2938 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -206,15 +206,17 @@ enum iWrapTextMode { | |||
206 | 206 | ||
207 | struct Impl_WrapText { | 207 | struct Impl_WrapText { |
208 | /* arguments */ | 208 | /* arguments */ |
209 | iRangecc text; | 209 | iRangecc text; |
210 | int maxWidth; | 210 | int maxWidth; |
211 | enum iWrapTextMode mode; | 211 | enum iWrapTextMode mode; |
212 | iBool (*wrapFunc)(iWrapText *, iRangecc wrappedText, int origin, int advance, iBool isBaseRTL); | 212 | iBool (*wrapFunc)(iWrapText *, iRangecc wrappedText, int origin, int advance, iBool isBaseRTL); |
213 | void * context; | 213 | void * context; |
214 | int baseDir; /* set to +1 for LTR, -1 for RTL */ | 214 | int baseDir; /* set to +1 for LTR, -1 for RTL */ |
215 | iInt2 hitPoint; | 215 | iInt2 hitPoint; /* sets hitChar_out */ |
216 | const char *hitChar; /* sets hitAdvance_out */ | ||
216 | /* output */ | 217 | /* output */ |
217 | const char *hitChar_out; | 218 | const char *hitChar_out; |
219 | iInt2 hitAdvance_out; | ||
218 | float hitGlyphNormX_out; /* normalized X inside the glyph */ | 220 | float hitGlyphNormX_out; /* normalized X inside the glyph */ |
219 | /* internal */ | 221 | /* internal */ |
220 | iRangecc wrapRange_; | 222 | iRangecc wrapRange_; |