From 7bc2f1b1dd089bfd362ad04dad47ab38c6d9ff37 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jaakko=20Ker=C3=A4nen?= jaakko.keranen@iki.fi
Date: Sat, 12 Dec 2020 10:41:44 +0200
Subject: [PATCH 1/1] InputWidget: Allow variable-width fonts
src/ui/inputwidget.c | 8 +++--
src/ui/text.c | 86 +++++++++++++++++++++++++++++---------------
src/ui/text.h | 2 ++
3 files changed, 65 insertions(+), 31 deletions(-)
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c
index 4f9bd367..018daec8 100644
--- a/src/ui/inputwidget.c
+++ b/src/ui/inputwidget.c
@@ -98,7 +98,7 @@ void init_InputWidget(iInputWidget *d, size_t maxLen) {
init_Array(&d->oldText, sizeof(iChar));
init_String(&d->hint);
init_Array(&d->undoStack, sizeof(iInputUndo));
d->cursor = 0;
d->lastCursor = 0;
d->inFlags = eatEscape_InputWidgetFlag;
@@ -789,11 +789,13 @@ static void draw_InputWidget_(const iInputWidget *d) {
else {
initCStr_String(&cur, " ");
}
/* The `gap_UI` offsets below are a hack. They are used because for some reason the
cursor rect and the glyph inside don't quite position like during `run_Text_()`. */
const iInt2 prefixSize = advanceN_Text(d->font, cstr_String(text), d->cursor);
const iInt2 curPos = addX_I2(textOrigin, prefixSize.x);
const iRect curRect = { curPos, addX_I2(advance_Text(d->font, cstr_String(&cur)), 1) };
const iRect curRect = { curPos, addX_I2(advance_Text(d->font, cstr_String(&cur)), iMin(2, gap_UI / 4)) };
fillRect_Paint(&p, curRect, uiInputCursor_ColorId);
draw_Text(d->font, curPos, uiInputCursorText_ColorId, "%s", cstr_String(&cur));
draw_Text(d->font, addX_I2(curPos, iMin(1, gap_UI / 8)), uiInputCursorText_ColorId, "%s", cstr_String(&cur));
deinit_String(&cur);
}
delete_String(text);
diff --git a/src/ui/text.c b/src/ui/text.c
index 3e1d732a..4229217c 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -426,7 +426,7 @@ void resetFonts_Text(void) {
}
iLocalDef iFont *font_Text_(enum iFontId id) {
}
static void freeBmp_(void *ptr) {
@@ -582,11 +582,14 @@ static const iGlyph *glyph_Font_(iFont *d, iChar ch) {
}
enum iRunMode {
};
static iChar nextChar_(const char **chPos, const char *end) {
@@ -625,8 +628,7 @@ iLocalDef iBool isWrapBoundary_(iChar prevC, iChar c) {
}
iLocalDef iBool isMeasuring_(enum iRunMode mode) {
mode == measureVisual_RunMode;
}
static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLen, iInt2 pos,
@@ -642,7 +644,8 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
*continueFrom_out = text.end;
}
iChar prevCh = 0;
monoAdvance = glyph_Font_(d, 'M')->advance;
}
for (const char *chPos = text.start; chPos != text.end; ) {
@@ -654,7 +657,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
iRegExpMatch m;
init_RegExpMatch(&m);
if (match_RegExp(text_.ansiEscape, chPos, text.end - chPos, &m)) {
if (mode == draw_RunMode) {
if (mode & draw_RunMode) {
/* Change the color. */
const iColor clr =
ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), tmParagraph_ColorId);
@@ -713,7 +716,7 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
}
if (ch == '\r') {
const iChar esc = nextChar_(&chPos, text.end);
if (mode == draw_RunMode) {
if (mode & draw_RunMode) {
const iColor clr = get_Color(esc - asciiBase_ColorEscape);
SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);
}
@@ -743,8 +746,14 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
pos.y + glyph->font->baseline + glyph->d[hoff].y,
glyph->rect[hoff].size.x,
glyph->rect[hoff].size.y };
if (glyph->font != d) {
if (glyph->font->height > d->height) {
/* Center-align vertically so the baseline isn't totally offset. */
dst.y -= (glyph->font->height - d->height) / 2;
}
}
/* Update the bounding box. */
if (mode == measureVisual_RunMode) {
if (mode & visualFlag_RunMode) {
if (isEmpty_Rect(bounds)) {
bounds = init_Rect(dst.x, dst.y, dst.w, dst.h);
}
@@ -779,12 +788,12 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
is monospaced. Except with Japanese script, that's larger than the normal monospace. */
xpos += advance;
xposMax = iMax(xposMax, xpos);
if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) {
if (continueFrom_out && ((mode & noWrapFlag_RunMode) || isWrapBoundary_(prevCh, ch))) {
lastWordEnd = chPos;
}
#if defined (LAGRANGE_ENABLE_KERNING)
/* Check the next character. */
if (!d->isMonospaced && glyph->font == d) {
if (!isMonospaced && glyph->font == d) {
/* TODO: No need to decode the next char twice; check this on the next iteration. */
const char *peek = chPos;
const iChar next = nextChar_(&peek, text.end);
@@ -805,14 +814,14 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
}
int lineHeight_Text(int fontId) {
}
iInt2 measureRange_Text(int fontId, iRangecc text) {
if (isEmpty_Range(&text)) {
return init_I2(0, lineHeight_Text(fontId));
}
measure_RunMode,
text,
iInvalidSize,
@@ -823,18 +832,32 @@ iInt2 measureRange_Text(int fontId, iRangecc text) {
}
iRect visualBounds_Text(int fontId, iRangecc text) {
font_Text_(fontId), measureVisual_RunMode, text, iInvalidSize, zero_I2(), 0, NULL, NULL);
measure_RunMode | visualFlag_RunMode,
text,
iInvalidSize,
zero_I2(),
0,
NULL,
NULL);
}
iInt2 measure_Text(int fontId, const char *text) {
return measureRange_Text(fontId, range_CStr(text));
}
+static int runFlagsFromId_(enum iFontId fontId) {
runFlags |= alwaysVariableWidthFlag_RunMode;
+}
iInt2 advanceRange_Text(int fontId, iRangecc text) {
int advance;
measure_RunMode,
measure_RunMode | runFlagsFromId_(fontId),
text,
iInvalidSize,
zero_I2(),
@@ -847,8 +870,8 @@ iInt2 advanceRange_Text(int fontId, iRangecc text) {
iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos) {
int advance;
measure_RunMode,
measure_RunMode | runFlagsFromId_(fontId),
text,
iInvalidSize,
zero_I2(),
@@ -861,8 +884,8 @@ iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos)
iInt2 tryAdvanceNoWrap_Text(int fontId, iRangecc text, int width, const char **endPos) {
int advance;
measureNoWrap_RunMode,
measure_RunMode | noWrapFlag_RunMode | runFlagsFromId_(fontId),
text,
iInvalidSize,
zero_I2(),
@@ -882,8 +905,14 @@ iInt2 advanceN_Text(int fontId, const char *text, size_t n) {
return init_I2(0, lineHeight_Text(fontId));
}
int advance;
&text_.fonts[fontId], measure_RunMode, range_CStr(text), n, zero_I2(), 0, NULL, &advance);
measure_RunMode | runFlagsFromId_(fontId),
range_CStr(text),
n,
zero_I2(),
0,
NULL,
&advance);
return init_I2(advance, lineHeight_Text(fontId));
}
@@ -891,8 +920,9 @@ static void draw_Text_(int fontId, iInt2 pos, int color, iRangecc text) {
iText *d = &text_;
const iColor clr = get_Color(color & mask_ColorId);
SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b);
color & permanent_ColorId ? drawPermanentColor_RunMode : draw_RunMode,
draw_RunMode | (color & permanent_ColorId ? permanentColorFlag_RunMode : 0) |
runFlagsFromId_(fontId),
text,
iInvalidSize,
pos,
diff --git a/src/ui/text.h b/src/ui/text.h
index a0b2dc1a..6728bb62 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -91,6 +91,8 @@ enum iFontId {
/* Meta: */
fromSymbolsToEmojiOffset_FontId = 10,
/* UI fonts: */
uiLabel_FontId = default_FontId,
--
2.25.1
text/plain
This content has been proxied by September (ba2dc).