summaryrefslogtreecommitdiff
path: root/src/ui/text.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2021-09-20 11:37:23 +0300
committerJaakko Keränen <jaakko.keranen@iki.fi>2021-09-20 11:37:23 +0300
commit2d81addf78d6a8b0fb2f2959b04a385c4adffdf2 (patch)
tree5e0f45b9c945499bc6a6669563de13c5203981a6 /src/ui/text.c
parent201021092d204680b353c82ce9e9beb76f3044e8 (diff)
Experimenting with independent popup windows
Toe dipping into multiple window support by allowing popup menu widgets to be displayed in independent windows. This is not a 100% replacement for native menus, but it gets pretty close.
Diffstat (limited to 'src/ui/text.c')
-rw-r--r--src/ui/text.c93
1 files changed, 48 insertions, 45 deletions
diff --git a/src/ui/text.c b/src/ui/text.c
index f7fff4bc..bf71b0e9 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -290,7 +290,9 @@ struct Impl_Text {
290 iRegExp * ansiEscape; 290 iRegExp * ansiEscape;
291}; 291};
292 292
293static iText text_; 293iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render)
294
295static iText *activeText_;
294static iBlock *userFont_; 296static iBlock *userFont_;
295 297
296static void initFonts_Text_(iText *d) { 298static void initFonts_Text_(iText *d) {
@@ -501,8 +503,7 @@ void loadUserFonts_Text(void) {
501 } 503 }
502} 504}
503 505
504void init_Text(SDL_Renderer *render) { 506void init_Text(iText *d, SDL_Renderer *render) {
505 iText *d = &text_;
506 loadUserFonts_Text(); 507 loadUserFonts_Text();
507 d->contentFont = nunito_TextFont; 508 d->contentFont = nunito_TextFont;
508 d->headingFont = nunito_TextFont; 509 d->headingFont = nunito_TextFont;
@@ -521,8 +522,7 @@ void init_Text(SDL_Renderer *render) {
521 initFonts_Text_(d); 522 initFonts_Text_(d);
522} 523}
523 524
524void deinit_Text(void) { 525void deinit_Text(iText *d) {
525 iText *d = &text_;
526 SDL_FreePalette(d->grayscale); 526 SDL_FreePalette(d->grayscale);
527 deinitFonts_Text_(d); 527 deinitFonts_Text_(d);
528 deinitCache_Text_(d); 528 deinitCache_Text_(d);
@@ -530,30 +530,34 @@ void deinit_Text(void) {
530 iRelease(d->ansiEscape); 530 iRelease(d->ansiEscape);
531} 531}
532 532
533void setCurrent_Text(iText *d) {
534 activeText_ = d;
535}
536
533void setOpacity_Text(float opacity) { 537void setOpacity_Text(float opacity) {
534 SDL_SetTextureAlphaMod(text_.cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); 538 SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f);
535} 539}
536 540
537void setContentFont_Text(enum iTextFont font) { 541void setContentFont_Text(iText *d, enum iTextFont font) {
538 if (text_.contentFont != font) { 542 if (d->contentFont != font) {
539 text_.contentFont = font; 543 d->contentFont = font;
540 resetFonts_Text(); 544 resetFonts_Text(d);
541 } 545 }
542} 546}
543 547
544void setHeadingFont_Text(enum iTextFont font) { 548void setHeadingFont_Text(iText *d, enum iTextFont font) {
545 if (text_.headingFont != font) { 549 if (d->headingFont != font) {
546 text_.headingFont = font; 550 d->headingFont = font;
547 resetFonts_Text(); 551 resetFonts_Text(d);
548 } 552 }
549} 553}
550 554
551void setContentFontSize_Text(float fontSizeFactor) { 555void setContentFontSize_Text(iText *d, float fontSizeFactor) {
552 fontSizeFactor *= contentScale_Text_; 556 fontSizeFactor *= contentScale_Text_;
553 iAssert(fontSizeFactor > 0); 557 iAssert(fontSizeFactor > 0);
554 if (iAbs(text_.contentFontSize - fontSizeFactor) > 0.001f) { 558 if (iAbs(d->contentFontSize - fontSizeFactor) > 0.001f) {
555 text_.contentFontSize = fontSizeFactor; 559 d->contentFontSize = fontSizeFactor;
556 resetFonts_Text(); 560 resetFonts_Text(d);
557 } 561 }
558} 562}
559 563
@@ -565,8 +569,7 @@ static void resetCache_Text_(iText *d) {
565 initCache_Text_(d); 569 initCache_Text_(d);
566} 570}
567 571
568void resetFonts_Text(void) { 572void resetFonts_Text(iText *d) {
569 iText *d = &text_;
570 deinitFonts_Text_(d); 573 deinitFonts_Text_(d);
571 deinitCache_Text_(d); 574 deinitCache_Text_(d);
572 initCache_Text_(d); 575 initCache_Text_(d);
@@ -574,7 +577,7 @@ void resetFonts_Text(void) {
574} 577}
575 578
576iLocalDef iFont *font_Text_(enum iFontId id) { 579iLocalDef iFont *font_Text_(enum iFontId id) {
577 return &text_.fonts[id & mask_FontId]; 580 return &activeText_->fonts[id & mask_FontId];
578} 581}
579 582
580static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { 583static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) {
@@ -584,7 +587,7 @@ static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, fl
584 SDL_Surface *surface8 = 587 SDL_Surface *surface8 =
585 SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); 588 SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8);
586 SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE); 589 SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE);
587 SDL_SetSurfacePalette(surface8, text_.grayscale); 590 SDL_SetSurfacePalette(surface8, activeText_->grayscale);
588#if LAGRANGE_RASTER_DEPTH != 8 591#if LAGRANGE_RASTER_DEPTH != 8
589 /* Convert to the cache format. */ 592 /* Convert to the cache format. */
590 SDL_Surface *surf = SDL_ConvertSurfaceFormat(surface8, LAGRANGE_RASTER_FORMAT, 0); 593 SDL_Surface *surf = SDL_ConvertSurfaceFormat(surface8, LAGRANGE_RASTER_FORMAT, 0);
@@ -631,7 +634,7 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) {
631 &d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1); 634 &d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1);
632 glRect->size = init_I2(x1 - x0, y1 - y0); 635 glRect->size = init_I2(x1 - x0, y1 - y0);
633 /* Determine placement in the glyph cache texture, advancing in rows. */ 636 /* Determine placement in the glyph cache texture, advancing in rows. */
634 glRect->pos = assignCachePos_Text_(&text_, glRect->size); 637 glRect->pos = assignCachePos_Text_(activeText_, glRect->size);
635 glyph->d[hoff] = init_I2(x0, y0); 638 glyph->d[hoff] = init_I2(x0, y0);
636 glyph->d[hoff].y += d->vertOffset; 639 glyph->d[hoff].y += d->vertOffset;
637 if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */ 640 if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */
@@ -737,11 +740,11 @@ static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) {
737 } 740 }
738 else { 741 else {
739 /* If the cache is running out of space, clear it and we'll recache what's needed currently. */ 742 /* If the cache is running out of space, clear it and we'll recache what's needed currently. */
740 if (text_.cacheBottom > text_.cacheSize.y - maxGlyphHeight_Text_(&text_)) { 743 if (activeText_->cacheBottom > activeText_->cacheSize.y - maxGlyphHeight_Text_(activeText_)) {
741#if !defined (NDEBUG) 744#if !defined (NDEBUG)
742 printf("[Text] glyph cache is full, clearing!\n"); fflush(stdout); 745 printf("[Text] glyph cache is full, clearing!\n"); fflush(stdout);
743#endif 746#endif
744 resetCache_Text_(&text_); 747 resetCache_Text_(activeText_);
745 } 748 }
746 glyph = new_Glyph(glyphIndex); 749 glyph = new_Glyph(glyphIndex);
747 glyph->font = d; 750 glyph->font = d;
@@ -858,7 +861,7 @@ static void finishRun_AttributedText_(iAttributedText *d, iAttributedRun *run, i
858} 861}
859 862
860static enum iFontId fontId_Text_(const iFont *font) { 863static enum iFontId fontId_Text_(const iFont *font) {
861 return (enum iFontId) (font - text_.fonts); 864 return (enum iFontId) (font - activeText_->fonts);
862} 865}
863 866
864static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) { 867static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) {
@@ -949,7 +952,7 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh
949 /* Do a regexp match in the source text. */ 952 /* Do a regexp match in the source text. */
950 iRegExpMatch m; 953 iRegExpMatch m;
951 init_RegExpMatch(&m); 954 init_RegExpMatch(&m);
952 if (match_RegExp(text_.ansiEscape, srcPos, d->source.end - srcPos, &m)) { 955 if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) {
953 finishRun_AttributedText_(d, &run, pos - 1); 956 finishRun_AttributedText_(d, &run, pos - 1);
954 run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), 957 run.fgColor = ansiForeground_Color(capturedRange_RegExpMatch(&m, 1),
955 tmParagraph_ColorId); 958 tmParagraph_ColorId);
@@ -1082,9 +1085,9 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {
1082 while (index < size_Array(glyphIndices)) { 1085 while (index < size_Array(glyphIndices)) {
1083 for (; index < size_Array(glyphIndices); index++) { 1086 for (; index < size_Array(glyphIndices); index++) {
1084 const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t); 1087 const uint32_t glyphIndex = constValue_Array(glyphIndices, index, uint32_t);
1085 const int lastCacheBottom = text_.cacheBottom; 1088 const int lastCacheBottom = activeText_->cacheBottom;
1086 iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex); 1089 iGlyph *glyph = glyphByIndex_Font_(d, glyphIndex);
1087 if (text_.cacheBottom < lastCacheBottom) { 1090 if (activeText_->cacheBottom < lastCacheBottom) {
1088 /* The cache was reset due to running out of space. We need to restart from 1091 /* The cache was reset due to running out of space. We need to restart from
1089 the beginning! */ 1092 the beginning! */
1090 bufX = 0; 1093 bufX = 0;
@@ -1103,7 +1106,7 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {
1103 LAGRANGE_RASTER_DEPTH, 1106 LAGRANGE_RASTER_DEPTH,
1104 LAGRANGE_RASTER_FORMAT); 1107 LAGRANGE_RASTER_FORMAT);
1105 SDL_SetSurfaceBlendMode(buf, SDL_BLENDMODE_NONE); 1108 SDL_SetSurfaceBlendMode(buf, SDL_BLENDMODE_NONE);
1106 SDL_SetSurfacePalette(buf, text_.grayscale); 1109 SDL_SetSurfacePalette(buf, activeText_->grayscale);
1107 } 1110 }
1108 SDL_Surface *surfaces[2] = { 1111 SDL_Surface *surfaces[2] = {
1109 !isRasterized_Glyph_(glyph, 0) ? 1112 !isRasterized_Glyph_(glyph, 0) ?
@@ -1147,19 +1150,19 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {
1147 } 1150 }
1148 /* Finished or the buffer is full, copy the glyphs to the cache texture. */ 1151 /* Finished or the buffer is full, copy the glyphs to the cache texture. */
1149 if (!isEmpty_Array(rasters)) { 1152 if (!isEmpty_Array(rasters)) {
1150 SDL_Texture *bufTex = SDL_CreateTextureFromSurface(text_.render, buf); 1153 SDL_Texture *bufTex = SDL_CreateTextureFromSurface(activeText_->render, buf);
1151 SDL_SetTextureBlendMode(bufTex, SDL_BLENDMODE_NONE); 1154 SDL_SetTextureBlendMode(bufTex, SDL_BLENDMODE_NONE);
1152 if (!isTargetChanged) { 1155 if (!isTargetChanged) {
1153 isTargetChanged = iTrue; 1156 isTargetChanged = iTrue;
1154 oldTarget = SDL_GetRenderTarget(text_.render); 1157 oldTarget = SDL_GetRenderTarget(activeText_->render);
1155 SDL_SetRenderTarget(text_.render, text_.cache); 1158 SDL_SetRenderTarget(activeText_->render, activeText_->cache);
1156 } 1159 }
1157// printf("copying %zu rasters from %p\n", size_Array(rasters), bufTex); fflush(stdout); 1160// printf("copying %zu rasters from %p\n", size_Array(rasters), bufTex); fflush(stdout);
1158 iConstForEach(Array, i, rasters) { 1161 iConstForEach(Array, i, rasters) {
1159 const iRasterGlyph *rg = i.value; 1162 const iRasterGlyph *rg = i.value;
1160// iAssert(isEqual_I2(rg->rect.size, rg->glyph->rect[rg->hoff].size)); 1163// iAssert(isEqual_I2(rg->rect.size, rg->glyph->rect[rg->hoff].size));
1161 const iRect *glRect = &rg->glyph->rect[rg->hoff]; 1164 const iRect *glRect = &rg->glyph->rect[rg->hoff];
1162 SDL_RenderCopy(text_.render, 1165 SDL_RenderCopy(activeText_->render,
1163 bufTex, 1166 bufTex,
1164 (const SDL_Rect *) &rg->rect, 1167 (const SDL_Rect *) &rg->rect,
1165 (const SDL_Rect *) glRect); 1168 (const SDL_Rect *) glRect);
@@ -1179,7 +1182,7 @@ static void cacheGlyphs_Font_(iFont *d, const iArray *glyphIndices) {
1179 SDL_FreeSurface(buf); 1182 SDL_FreeSurface(buf);
1180 } 1183 }
1181 if (isTargetChanged) { 1184 if (isTargetChanged) {
1182 SDL_SetRenderTarget(text_.render, oldTarget); 1185 SDL_SetRenderTarget(activeText_->render, oldTarget);
1183 } 1186 }
1184} 1187}
1185 1188
@@ -1706,9 +1709,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1706 } 1709 }
1707 if (~mode & permanentColorFlag_RunMode) { 1710 if (~mode & permanentColorFlag_RunMode) {
1708 const iColor clr = run->fgColor; 1711 const iColor clr = run->fgColor;
1709 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); 1712 SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b);
1710 if (args->mode & fillBackground_RunMode) { 1713 if (args->mode & fillBackground_RunMode) {
1711 SDL_SetRenderDrawColor(text_.render, clr.r, clr.g, clr.b, 0); 1714 SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0);
1712 } 1715 }
1713 } 1716 }
1714 SDL_Rect src; 1717 SDL_Rect src;
@@ -1719,9 +1722,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) {
1719 /* Alpha blending looks much better if the RGB components don't change in 1722 /* Alpha blending looks much better if the RGB components don't change in
1720 the partially transparent pixels. */ 1723 the partially transparent pixels. */
1721 /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ 1724 /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */
1722 SDL_RenderFillRect(text_.render, &dst); 1725 SDL_RenderFillRect(activeText_->render, &dst);
1723 } 1726 }
1724 SDL_RenderCopy(text_.render, text_.cache, &src, &dst); 1727 SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst);
1725#if 0 1728#if 0
1726 /* Show spaces and direction. */ 1729 /* Show spaces and direction. */
1727 if (logicalText[logPos] == 0x20) { 1730 if (logicalText[logPos] == 0x20) {
@@ -1863,7 +1866,7 @@ iTextMetrics measureN_Text(int fontId, const char *text, size_t n) {
1863} 1866}
1864 1867
1865static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) { 1868static void drawBoundedN_Text_(int fontId, iInt2 pos, int xposBound, int color, iRangecc text, size_t maxLen) {
1866 iText * d = &text_; 1869 iText * d = activeText_;
1867 iFont * font = font_Text_(fontId); 1870 iFont * font = font_Text_(fontId);
1868 const iColor clr = get_Color(color & mask_ColorId); 1871 const iColor clr = get_Color(color & mask_ColorId);
1869 SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b); 1872 SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b);
@@ -2057,7 +2060,7 @@ iTextMetrics draw_WrapText(iWrapText *d, int fontId, iInt2 pos, int color) {
2057} 2060}
2058 2061
2059SDL_Texture *glyphCache_Text(void) { 2062SDL_Texture *glyphCache_Text(void) {
2060 return text_.cache; 2063 return activeText_->cache;
2061} 2064}
2062 2065
2063static void freeBitmap_(void *ptr) { 2066static void freeBitmap_(void *ptr) {
@@ -2170,7 +2173,7 @@ iString *renderBlockChars_Text(const iBlock *fontData, int height, enum iTextBlo
2170iDefineTypeConstructionArgs(TextBuf, (iWrapText *wrapText, int font, int color), wrapText, font, color) 2173iDefineTypeConstructionArgs(TextBuf, (iWrapText *wrapText, int font, int color), wrapText, font, color)
2171 2174
2172void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) { 2175void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) {
2173 SDL_Renderer *render = text_.render; 2176 SDL_Renderer *render = activeText_->render;
2174 d->size = measure_WrapText(wrapText, font).bounds.size; 2177 d->size = measure_WrapText(wrapText, font).bounds.size;
2175 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0"); 2178 SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
2176 if (d->size.x * d->size.y) { 2179 if (d->size.x * d->size.y) {
@@ -2191,9 +2194,9 @@ void init_TextBuf(iTextBuf *d, iWrapText *wrapText, int font, int color) {
2191 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE); 2194 SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_NONE);
2192 SDL_SetRenderDrawColor(render, 255, 255, 255, 0); 2195 SDL_SetRenderDrawColor(render, 255, 255, 255, 0);
2193 SDL_RenderClear(render); 2196 SDL_RenderClear(render);
2194 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */ 2197 SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_NONE); /* blended when TextBuf is drawn */
2195 draw_WrapText(wrapText, font, zero_I2(), color | fillBackground_ColorId); 2198 draw_WrapText(wrapText, font, zero_I2(), color | fillBackground_ColorId);
2196 SDL_SetTextureBlendMode(text_.cache, SDL_BLENDMODE_BLEND); 2199 SDL_SetTextureBlendMode(activeText_->cache, SDL_BLENDMODE_BLEND);
2197 SDL_SetRenderTarget(render, oldTarget); 2200 SDL_SetRenderTarget(render, oldTarget);
2198 origin_Paint = oldOrigin; 2201 origin_Paint = oldOrigin;
2199 SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND); 2202 SDL_SetTextureBlendMode(d->texture, SDL_BLENDMODE_BLEND);
@@ -2212,7 +2215,7 @@ void draw_TextBuf(const iTextBuf *d, iInt2 pos, int color) {
2212 addv_I2(&pos, origin_Paint); 2215 addv_I2(&pos, origin_Paint);
2213 const iColor clr = get_Color(color); 2216 const iColor clr = get_Color(color);
2214 SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b); 2217 SDL_SetTextureColorMod(d->texture, clr.r, clr.g, clr.b);
2215 SDL_RenderCopy(text_.render, 2218 SDL_RenderCopy(activeText_->render,
2216 d->texture, 2219 d->texture,
2217 &(SDL_Rect){ 0, 0, d->size.x, d->size.y }, 2220 &(SDL_Rect){ 0, 0, d->size.x, d->size.y },
2218 &(SDL_Rect){ pos.x, pos.y, d->size.x, d->size.y }); 2221 &(SDL_Rect){ pos.x, pos.y, d->size.x, d->size.y });