From e0e53e4a51afcbd22345d12416645d3fc5483a18 Mon Sep 17 00:00:00 2001 From: Jaakko Keränen Date: Wed, 22 Jul 2020 15:34:08 +0300 Subject: Text wrapping; basic scrolling in DocumentWidget --- src/ui/documentwidget.c | 21 ++++++++--- src/ui/text.c | 95 +++++++++++++++++++++++++++++++++---------------- src/ui/text.h | 1 + 3 files changed, 81 insertions(+), 36 deletions(-) (limited to 'src/ui') diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index c0dbcded..7fe30f1e 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c @@ -25,6 +25,7 @@ struct Impl_DocumentWidget { iString *newSource; iGmDocument *doc; int pageMargin; + int scrollY; }; iDeclareType(Url) @@ -71,6 +72,7 @@ void init_DocumentWidget(iDocumentWidget *d) { d->newSource = new_String(); d->doc = new_GmDocument(); d->pageMargin = 5; + d->scrollY = 0; setUrl_DocumentWidget(d, collectNewCStr_String("file:///home/jaakko/test.gmi")); } @@ -173,13 +175,18 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e return iTrue; } } + else if (ev->type == SDL_MOUSEWHEEL) { + d->scrollY -= 3 * ev->wheel.y * lineHeight_Text(default_FontId); + postRefresh_App(); + return iTrue; + } return processEvent_Widget(w, ev); } iDeclareType(DrawContext) struct Impl_DrawContext { - const iDocumentWidget *d; + const iDocumentWidget *widget; iRect bounds; iPaint paint; }; @@ -189,8 +196,9 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { iString text; /* TODO: making a copy is unnecessary; the text routines should accept Rangecc */ initRange_String(&text, run->text); - drawString_Text(run->font, add_I2(d->bounds.pos, run->bounds.pos), run->color, &text); - drawRect_Paint(&d->paint, moved_Rect(run->bounds, d->bounds.pos), red_ColorId); + iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); + drawString_Text(run->font, add_I2(run->bounds.pos, origin), run->color, &text); +// drawRect_Paint(&d->paint, moved_Rect(run->bounds, origin), red_ColorId); deinit_String(&text); } @@ -206,11 +214,14 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { iConstCast(iDocumentWidget *, d)->state = ready_DocumentState; } if (d->state != ready_DocumentState) return; - iDrawContext ctx = {.d = d, .bounds = bounds_Widget(w) }; + iDrawContext ctx = {.widget = d, .bounds = bounds_Widget(w) }; shrink_Rect(&ctx.bounds, init1_I2(gap_UI * d->pageMargin)); init_Paint(&ctx.paint); drawRect_Paint(&ctx.paint, ctx.bounds, teal_ColorId); - render_GmDocument(d->doc, (iRangei){ 0, height_Rect(ctx.bounds) }, drawRun_DrawContext_, &ctx); + render_GmDocument(d->doc, + (iRangei){ d->scrollY, d->scrollY + height_Rect(ctx.bounds) }, + drawRun_DrawContext_, + &ctx); } iBeginDefineSubclass(DocumentWidget, Widget) diff --git a/src/ui/text.c b/src/ui/text.c index 23e28e4d..afad778c 100644 --- a/src/ui/text.c +++ b/src/ui/text.c @@ -15,6 +15,7 @@ #include #include +#include #include iDeclareType(Glyph) @@ -115,12 +116,12 @@ void init_Text(SDL_Renderer *render) { /* Load the fonts. */ { const struct { const iBlock *ttf; int size; } fontData[max_FontId] = { { &fontFiraSansRegular_Embedded, fontSize_UI }, - { &fontFiraMonoRegular_Embedded, fontSize_UI }, + { &fontFiraMonoRegular_Embedded, fontSize_UI * 0.85f }, { &fontFiraSansRegular_Embedded, fontSize_UI * 1.5f }, { &fontFiraSansLightItalic_Embedded, fontSize_UI }, { &fontFiraSansBold_Embedded, fontSize_UI }, - { &fontFiraSansBold_Embedded, fontSize_UI * 1.5f }, - { &fontFiraSansBold_Embedded, fontSize_UI * 1.75f }, + { &fontFiraSansBold_Embedded, fontSize_UI * 1.35f }, + { &fontFiraSansBold_Embedded, fontSize_UI * 1.7f }, { &fontFiraSansBold_Embedded, fontSize_UI * 2.0f }, }; iForIndices(i, fontData) { @@ -377,18 +378,26 @@ static iChar nextChar_(const char **chPos, const char *end) { } static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLen, iInt2 pos, - int *runAdvance_out) { + int xposLimit, const char **continueFrom_out, int *runAdvance_out) { iInt2 size = zero_I2(); const iInt2 orig = pos; const stbtt_fontinfo *info = &d->font; float xpos = pos.x; float xposMax = xpos; + iAssert(xposLimit == 0 || mode == measure_RunMode); + const char *lastWordEnd = text.start; + if (continueFrom_out) { + *continueFrom_out = text.end; + } + iChar prevCh = 0; for (const char *chPos = text.start; chPos != text.end; ) { + iAssert(chPos < text.end); iChar ch = nextChar_(&chPos, text.end); /* Special instructions. */ { if (ch == '\n') { xpos = pos.x; pos.y += d->height; + prevCh = ch; continue; } if (ch == '\r') { @@ -397,20 +406,26 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe if (mode == draw_RunMode) { SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); } + prevCh = 0; continue; } } const iGlyph *glyph = glyph_Font_(d, ch); - int x1 = iRound(xpos); - int x2 = x1 + glyph->rect.size.x; + float x1 = xpos; + float x2 = x1 + glyph->rect.size.x; + if (xposLimit > 0 && x2 > xposLimit) { + /* Out of space. */ + *continueFrom_out = lastWordEnd; + break; + } size.x = iMax(size.x, x2 - orig.x); size.y = iMax(size.y, pos.y + d->height - orig.y); if (mode != measure_RunMode) { - SDL_Rect dst = { x1 + glyph->dx, - pos.y + d->baseline + glyph->dy, - glyph->rect.size.x, - glyph->rect.size.y }; - SDL_RenderCopy(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect, &dst); + SDL_FRect dst = { x1 + glyph->dx, + pos.y + d->baseline + glyph->dy, + glyph->rect.size.x, + glyph->rect.size.y }; + SDL_RenderCopyF(text_.render, text_.cache, (const SDL_Rect *) &glyph->rect, &dst); } int advance, lsb; const iBool spec = isSpecialChar_(ch); @@ -420,6 +435,9 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe } xpos += d->scale * advance; xposMax = iMax(xposMax, xpos); + if (!isSpace_Char(prevCh) && isSpace_Char(ch)) { + lastWordEnd = chPos; + } /* Check the next character. */ { /* TODO: No need to decode the next char twice; check this on the next iteration. */ const char *peek = chPos; @@ -428,6 +446,7 @@ static iInt2 run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe xpos += d->scale * stbtt_GetCodepointKernAdvance(info, ch, next); } } + prevCh = ch; if (--maxLen == 0) { break; } @@ -446,44 +465,56 @@ iInt2 measure_Text(int fontId, const char *text) { if (!*text) { return init_I2(0, lineHeight_Text(fontId)); } - return run_Font_( - &text_.fonts[fontId], measure_RunMode, range_CStr(text), iInvalidSize, zero_I2(), NULL); + return run_Font_(&text_.fonts[fontId], + measure_RunMode, + range_CStr(text), + iInvalidSize, + zero_I2(), + 0, + NULL, + NULL); } -iInt2 advance_Text(int fontId, const char *text) { +iInt2 advanceRange_Text(int fontId, iRangecc text) { int advance; const int height = run_Font_(&text_.fonts[fontId], measure_RunMode, - range_CStr(text), + text, iInvalidSize, zero_I2(), + 0, + NULL, &advance) .y; return init_I2(advance, height); } -iInt2 advanceN_Text(int fontId, const char *text, size_t n) { - if (n == 0) { - return init_I2(0, lineHeight_Text(fontId)); - } +iInt2 tryAdvanceRange_Text(int fontId, iRangecc text, int width, const char **endPos) { int advance; - run_Font_(&text_.fonts[fontId], measure_RunMode, range_CStr(text), n, zero_I2(), &advance); - return init_I2(advance, lineHeight_Text(fontId)); + const int height = run_Font_(&text_.fonts[fontId], + measure_RunMode, + text, + iInvalidSize, + zero_I2(), + width, + endPos, + &advance) + .y; + return init_I2(advance, height); } -iInt2 advanceRange_Text(int fontId, iRangecc text) { - /* TODO: Rangecc should be the default for runs; no need to copy here */ - iString str; - initRange_String(&str, text); - const iInt2 metrics = advance_Text(fontId, cstr_String(&str)); - deinit_String(&str); - return metrics; +iInt2 advance_Text(int fontId, const char *text) { + return advanceRange_Text(fontId, range_CStr(text)); } -iInt2 tryAdvanceRange_Text(int fontId, iRangecc text, int width, const char **endPos) { +iInt2 advanceN_Text(int fontId, const char *text, size_t n) { + if (n == 0) { + return init_I2(0, lineHeight_Text(fontId)); + } int advance; - const int height = run_Font_(&text_.fonts[fontId], measure_RunMode, text, iInvalidSize, zero_I2(), &advance).y; - + run_Font_( + &text_.fonts[fontId], measure_RunMode, range_CStr(text), n, zero_I2(), 0, NULL, &advance); + return init_I2(advance, lineHeight_Text(fontId)); } static void draw_Text_(int fontId, iInt2 pos, int color, iRangecc text) { @@ -495,6 +526,8 @@ static void draw_Text_(int fontId, iInt2 pos, int color, iRangecc text) { text, iInvalidSize, pos, + 0, + NULL, NULL); } diff --git a/src/ui/text.h b/src/ui/text.h index 9bf69c80..ddf9da86 100644 --- a/src/ui/text.h +++ b/src/ui/text.h @@ -42,6 +42,7 @@ iInt2 measure_Text (int fontId, const char *text); iInt2 advance_Text (int fontId, const char *text); iInt2 advanceN_Text (int fontId, const char *text, size_t n); /* `n` in characters */ iInt2 advanceRange_Text (int fontId, iRangecc text); +iInt2 tryAdvanceRange_Text(int fontId, iRangecc text, int width, const char **endPos); void draw_Text (int fontId, iInt2 pos, int color, const char *text, ...); /* negative pos to switch alignment */ void drawString_Text (int fontId, iInt2 pos, int color, const iString *text); -- cgit v1.2.3