summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-21 22:09:27 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-21 22:09:27 +0300
commit10999deaeec452e8db76b4d017e922f74a6dccf6 (patch)
tree8169c7f016de7e59f826646d85acf754a6b78d75
parent5729595e6e3e4c44f272eaae86aeaa8ae31872ab (diff)
Text: Draw tab indicators; jump to tab stops
-rw-r--r--src/ui/text.c41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/ui/text.c b/src/ui/text.c
index bf71b0e9..2c17b3da 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -121,6 +121,8 @@ iDefineTypeConstructionArgs(Glyph, (iChar ch), ch)
121 121
122/*-----------------------------------------------------------------------------------------------*/ 122/*-----------------------------------------------------------------------------------------------*/
123 123
124static iGlyph *glyph_Font_(iFont *d, iChar ch);
125
124struct Impl_Font { 126struct Impl_Font {
125 iBlock * data; 127 iBlock * data;
126 enum iTextFont family; 128 enum iTextFont family;
@@ -131,6 +133,7 @@ struct Impl_Font {
131 int baseline; 133 int baseline;
132 iHash glyphs; /* key is glyph index in the font */ /* TODO: does not need to be a Hash */ 134 iHash glyphs; /* key is glyph index in the font */ /* TODO: does not need to be a Hash */
133 iBool isMonospaced; 135 iBool isMonospaced;
136 float emAdvance;
134 enum iFontSize sizeId; /* used to look up different fonts of matching size */ 137 enum iFontSize sizeId; /* used to look up different fonts of matching size */
135 uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ 138 uint32_t indexTable[128 - 32]; /* quick ASCII lookup */
136#if defined (LAGRANGE_ENABLE_HARFBUZZ) 139#if defined (LAGRANGE_ENABLE_HARFBUZZ)
@@ -178,20 +181,20 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale,
178 d->height = height; 181 d->height = height;
179 iZap(d->font); 182 iZap(d->font);
180 stbtt_InitFont(&d->font, constData_Block(data), 0); 183 stbtt_InitFont(&d->font, constData_Block(data), 0);
181 int ascent, descent; 184 int ascent, descent, emAdv;
182 stbtt_GetFontVMetrics(&d->font, &ascent, &descent, NULL); 185 stbtt_GetFontVMetrics(&d->font, &ascent, &descent, NULL);
186 stbtt_GetCodepointHMetrics(&d->font, 'M', &emAdv, NULL);
183 d->xScale = d->yScale = stbtt_ScaleForPixelHeight(&d->font, height) * scale; 187 d->xScale = d->yScale = stbtt_ScaleForPixelHeight(&d->font, height) * scale;
184 if (d->isMonospaced) { 188 if (d->isMonospaced) {
185 /* It is important that monospaced fonts align 1:1 with the pixel grid so that 189 /* It is important that monospaced fonts align 1:1 with the pixel grid so that
186 box-drawing characters don't have partially occupied edge pixels, leading to seams 190 box-drawing characters don't have partially occupied edge pixels, leading to seams
187 between adjacent glyphs. */ 191 between adjacent glyphs. */
188 int adv; 192 const float advance = (float) emAdv * d->xScale;
189 stbtt_GetCodepointHMetrics(&d->font, 'M', &adv, NULL);
190 const float advance = (float) adv * d->xScale;
191 if (advance > 4) { /* not too tiny */ 193 if (advance > 4) { /* not too tiny */
192 d->xScale *= floorf(advance) / advance; 194 d->xScale *= floorf(advance) / advance;
193 } 195 }
194 } 196 }
197 d->emAdvance = emAdv * d->xScale;
195 d->baseline = ascent * d->yScale; 198 d->baseline = ascent * d->yScale;
196 d->vertOffset = height * (1.0f - scale) / 2; 199 d->vertOffset = height * (1.0f - scale) / 2;
197 /* Custom tweaks. */ 200 /* Custom tweaks. */
@@ -1335,6 +1338,11 @@ static void shape_GlyphBuffer_(iGlyphBuffer *d) {
1335 } 1338 }
1336} 1339}
1337 1340
1341static float nextTabStop_Font_(const iFont *d, float x) {
1342 const float stop = 4 * d->emAdvance;
1343 return floorf(x / stop) * stop + stop;
1344}
1345
1338static float advance_GlyphBuffer_(const iGlyphBuffer *d, iRangei wrapPosRange) { 1346static float advance_GlyphBuffer_(const iGlyphBuffer *d, iRangei wrapPosRange) {
1339 float x = 0.0f; 1347 float x = 0.0f;
1340 for (unsigned int i = 0; i < d->glyphCount; i++) { 1348 for (unsigned int i = 0; i < d->glyphCount; i++) {
@@ -1343,6 +1351,9 @@ static float advance_GlyphBuffer_(const iGlyphBuffer *d, iRangei wrapPosRange) {
1343 continue; 1351 continue;
1344 } 1352 }
1345 x += d->font->xScale * d->glyphPos[i].x_advance; 1353 x += d->font->xScale * d->glyphPos[i].x_advance;
1354 if (d->logicalText[logPos] == '\t') {
1355 x = nextTabStop_Font_(d->font, x);
1356 }
1346 if (i + 1 < d->glyphCount) { 1357 if (i + 1 < d->glyphCount) {
1347 x += horizKern_Font_(d->font, 1358 x += horizKern_Font_(d->font,
1348 d->glyphInfo[i].codepoint, 1359 d->glyphInfo[i].codepoint,
@@ -1354,7 +1365,7 @@ static float advance_GlyphBuffer_(const iGlyphBuffer *d, iRangei wrapPosRange) {
1354 1365
1355static void evenMonospaceAdvances_GlyphBuffer_(iGlyphBuffer *d, iFont *baseFont) { 1366static void evenMonospaceAdvances_GlyphBuffer_(iGlyphBuffer *d, iFont *baseFont) {
1356 shape_GlyphBuffer_(d); 1367 shape_GlyphBuffer_(d);
1357 const float monoAdvance = glyph_Font_(baseFont, 'M')->advance; 1368 const float monoAdvance = baseFont->emAdvance;
1358 for (unsigned int i = 0; i < d->glyphCount; ++i) { 1369 for (unsigned int i = 0; i < d->glyphCount; ++i) {
1359 const hb_glyph_info_t *info = d->glyphInfo + i; 1370 const hb_glyph_info_t *info = d->glyphInfo + i;
1360 if (d->glyphPos[i].x_advance > 0 && d->font != baseFont) { 1371 if (d->glyphPos[i].x_advance > 0 && d->font != baseFont) {
@@ -1498,10 +1509,10 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1498 const int glyphFlags = hb_glyph_info_get_glyph_flags(info); 1509 const int glyphFlags = hb_glyph_info_get_glyph_flags(info);
1499 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset; 1510 const float xOffset = run->font->xScale * buf->glyphPos[i].x_offset;
1500 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance; 1511 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance;
1512 const iChar ch = logicalText[logPos];
1501 iAssert(xAdvance >= 0); 1513 iAssert(xAdvance >= 0);
1502 if (args->wrap->mode == word_WrapTextMode) { 1514 if (args->wrap->mode == word_WrapTextMode) {
1503 /* When word wrapping, only consider certain places breakable. */ 1515 /* When word wrapping, only consider certain places breakable. */
1504 const iChar ch = logicalText[logPos];
1505 if ((ch >= 128 || !ispunct(ch)) && (prevCh == '-' || prevCh == '/')) { 1516 if ((ch >= 128 || !ispunct(ch)) && (prevCh == '-' || prevCh == '/')) {
1506 safeBreakPos = logPos; 1517 safeBreakPos = logPos;
1507 breakAdvance = wrapAdvance; 1518 breakAdvance = wrapAdvance;
@@ -1527,6 +1538,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1527 wrap->hitGlyphNormX_out = (wrap->hitPoint.x - wrapAdvance) / xAdvance; 1538 wrap->hitGlyphNormX_out = (wrap->hitPoint.x - wrapAdvance) / xAdvance;
1528 } 1539 }
1529 } 1540 }
1541 if (ch == '\t') {
1542 wrapAdvance = nextTabStop_Font_(d, wrapAdvance) - xAdvance;
1543 }
1530 /* Out of room? */ 1544 /* Out of room? */
1531 if (wrap->maxWidth > 0 && 1545 if (wrap->maxWidth > 0 &&
1532 wrapAdvance + xOffset + glyph->d[0].x + glyph->rect[0].size.x > 1546 wrapAdvance + xOffset + glyph->d[0].x + glyph->rect[0].size.x >
@@ -1681,6 +1695,21 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1681 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance; 1695 const float xAdvance = run->font->xScale * buf->glyphPos[i].x_advance;
1682 const float yAdvance = run->font->yScale * buf->glyphPos[i].y_advance; 1696 const float yAdvance = run->font->yScale * buf->glyphPos[i].y_advance;
1683 const iGlyph *glyph = glyphByIndex_Font_(run->font, glyphId); 1697 const iGlyph *glyph = glyphByIndex_Font_(run->font, glyphId);
1698 if (logicalText[logPos] == '\t') {
1699 if (mode & draw_RunMode) {
1700 /* Tab indicator. */
1701 iColor tabColor = get_Color(uiTextAction_ColorId);
1702 SDL_SetRenderDrawColor(activeText_->render, tabColor.r, tabColor.g, tabColor.b, 255);
1703 const int pad = d->height / 6;
1704 SDL_RenderFillRect(activeText_->render, &(SDL_Rect){
1705 orig.x + xCursor,
1706 orig.y + yCursor + d->height / 2 - pad / 2,
1707 pad,
1708 pad
1709 });
1710 }
1711 xCursor = nextTabStop_Font_(d, xCursor) - xAdvance;
1712 }
1684 const float xf = xCursor + xOffset; 1713 const float xf = xCursor + xOffset;
1685 const int hoff = enableHalfPixelGlyphs_Text ? (xf - ((int) xf) > 0.5f ? 1 : 0) : 0; 1714 const int hoff = enableHalfPixelGlyphs_Text ? (xf - ((int) xf) > 0.5f ? 1 : 0) : 0;
1686 /* Output position for the glyph. */ 1715 /* Output position for the glyph. */