summaryrefslogtreecommitdiff
path: root/src/ui/text.c
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-12-12 10:41:44 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-12-12 10:41:44 +0200
commit7bc2f1b1dd089bfd362ad04dad47ab38c6d9ff37 (patch)
treef0e2f02a5adb9038401c2713772c2bc82a2c57c3 /src/ui/text.c
parent96a7ee14151b250e0587ec81a50afb7fe34c7567 (diff)
InputWidget: Allow variable-width fonts
Diffstat (limited to 'src/ui/text.c')
-rw-r--r--src/ui/text.c86
1 files changed, 58 insertions, 28 deletions
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) {
426} 426}
427 427
428iLocalDef iFont *font_Text_(enum iFontId id) { 428iLocalDef iFont *font_Text_(enum iFontId id) {
429 return &text_.fonts[id]; 429 return &text_.fonts[id & mask_FontId];
430} 430}
431 431
432static void freeBmp_(void *ptr) { 432static void freeBmp_(void *ptr) {
@@ -582,11 +582,14 @@ static const iGlyph *glyph_Font_(iFont *d, iChar ch) {
582} 582}
583 583
584enum iRunMode { 584enum iRunMode {
585 measure_RunMode, 585 measure_RunMode = 0,
586 measureNoWrap_RunMode, 586 draw_RunMode = 1,
587 measureVisual_RunMode, /* actual visible bounding box of the glyph, e.g., for icons */ 587 modeMask_RunMode = 0x00ff,
588 draw_RunMode, 588 flagsMask_RunMode = 0xff00,
589 drawPermanentColor_RunMode 589 noWrapFlag_RunMode = iBit(9),
590 visualFlag_RunMode = iBit(10), /* actual visible bounding box of the glyph, e.g., for icons */
591 permanentColorFlag_RunMode = iBit(11),
592 alwaysVariableWidthFlag_RunMode = iBit(12),
590}; 593};
591 594
592static iChar nextChar_(const char **chPos, const char *end) { 595static iChar nextChar_(const char **chPos, const char *end) {
@@ -625,8 +628,7 @@ iLocalDef iBool isWrapBoundary_(iChar prevC, iChar c) {
625} 628}
626 629
627iLocalDef iBool isMeasuring_(enum iRunMode mode) { 630iLocalDef iBool isMeasuring_(enum iRunMode mode) {
628 return mode == measure_RunMode || mode == measureNoWrap_RunMode || 631 return (mode & modeMask_RunMode) == measure_RunMode;
629 mode == measureVisual_RunMode;
630} 632}
631 633
632static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLen, iInt2 pos, 634static 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
642 *continueFrom_out = text.end; 644 *continueFrom_out = text.end;
643 } 645 }
644 iChar prevCh = 0; 646 iChar prevCh = 0;
645 if (d->isMonospaced) { 647 const iBool isMonospaced = d->isMonospaced && !(mode & alwaysVariableWidthFlag_RunMode);
648 if (isMonospaced) {
646 monoAdvance = glyph_Font_(d, 'M')->advance; 649 monoAdvance = glyph_Font_(d, 'M')->advance;
647 } 650 }
648 for (const char *chPos = text.start; chPos != text.end; ) { 651 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
654 iRegExpMatch m; 657 iRegExpMatch m;
655 init_RegExpMatch(&m); 658 init_RegExpMatch(&m);
656 if (match_RegExp(text_.ansiEscape, chPos, text.end - chPos, &m)) { 659 if (match_RegExp(text_.ansiEscape, chPos, text.end - chPos, &m)) {
657 if (mode == draw_RunMode) { 660 if (mode & draw_RunMode) {
658 /* Change the color. */ 661 /* Change the color. */
659 const iColor clr = 662 const iColor clr =
660 ansiForeground_Color(capturedRange_RegExpMatch(&m, 1), tmParagraph_ColorId); 663 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
713 } 716 }
714 if (ch == '\r') { 717 if (ch == '\r') {
715 const iChar esc = nextChar_(&chPos, text.end); 718 const iChar esc = nextChar_(&chPos, text.end);
716 if (mode == draw_RunMode) { 719 if (mode & draw_RunMode) {
717 const iColor clr = get_Color(esc - asciiBase_ColorEscape); 720 const iColor clr = get_Color(esc - asciiBase_ColorEscape);
718 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b); 721 SDL_SetTextureColorMod(text_.cache, clr.r, clr.g, clr.b);
719 } 722 }
@@ -743,8 +746,14 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
743 pos.y + glyph->font->baseline + glyph->d[hoff].y, 746 pos.y + glyph->font->baseline + glyph->d[hoff].y,
744 glyph->rect[hoff].size.x, 747 glyph->rect[hoff].size.x,
745 glyph->rect[hoff].size.y }; 748 glyph->rect[hoff].size.y };
749 if (glyph->font != d) {
750 if (glyph->font->height > d->height) {
751 /* Center-align vertically so the baseline isn't totally offset. */
752 dst.y -= (glyph->font->height - d->height) / 2;
753 }
754 }
746 /* Update the bounding box. */ 755 /* Update the bounding box. */
747 if (mode == measureVisual_RunMode) { 756 if (mode & visualFlag_RunMode) {
748 if (isEmpty_Rect(bounds)) { 757 if (isEmpty_Rect(bounds)) {
749 bounds = init_Rect(dst.x, dst.y, dst.w, dst.h); 758 bounds = init_Rect(dst.x, dst.y, dst.w, dst.h);
750 } 759 }
@@ -779,12 +788,12 @@ static iRect run_Font_(iFont *d, enum iRunMode mode, iRangecc text, size_t maxLe
779 is monospaced. Except with Japanese script, that's larger than the normal monospace. */ 788 is monospaced. Except with Japanese script, that's larger than the normal monospace. */
780 xpos += advance; 789 xpos += advance;
781 xposMax = iMax(xposMax, xpos); 790 xposMax = iMax(xposMax, xpos);
782 if (continueFrom_out && (mode == measureNoWrap_RunMode || isWrapBoundary_(prevCh, ch))) { 791 if (continueFrom_out && ((mode & noWrapFlag_RunMode) || isWrapBoundary_(prevCh, ch))) {
783 lastWordEnd = chPos; 792 lastWordEnd = chPos;
784 } 793 }
785#if defined (LAGRANGE_ENABLE_KERNING) 794#if defined (LAGRANGE_ENABLE_KERNING)
786 /* Check the next character. */ 795 /* Check the next character. */
787 if (!d->isMonospaced && glyph->font == d) { 796 if (!isMonospaced && glyph->font == d) {
788 /* TODO: No need to decode the next char twice; check this on the next iteration. */ 797 /* TODO: No need to decode the next char twice; check this on the next iteration. */
789 const char *peek = chPos; 798 const char *peek = chPos;
790 const iChar next = nextChar_(&peek, text.end); 799 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
805} 814}
806 815
807int lineHeight_Text(int fontId) { 816int lineHeight_Text(int fontId) {
808 return text_.fonts[fontId].height; 817 return font_Text_(fontId)->height;
809} 818}
810 819
811iInt2 measureRange_Text(int fontId, iRangecc text) { 820iInt2 measureRange_Text(int fontId, iRangecc text) {
812 if (isEmpty_Range(&text)) { 821 if (isEmpty_Range(&text)) {
813 return init_I2(0, lineHeight_Text(fontId)); 822 return init_I2(0, lineHeight_Text(fontId));
814 } 823 }
815 return run_Font_(&text_.fonts[fontId], 824 return run_Font_(font_Text_(fontId),
816 measure_RunMode, 825 measure_RunMode,
817 text, 826 text,
818 iInvalidSize, 827 iInvalidSize,
@@ -823,18 +832,32 @@ iInt2 measureRange_Text(int fontId, iRangecc text) {
823} 832}
824 833
825iRect visualBounds_Text(int fontId, iRangecc text) { 834iRect visualBounds_Text(int fontId, iRangecc text) {
826 return run_Font_( 835 return run_Font_(font_Text_(fontId),
827 font_Text_(fontId), measureVisual_RunMode, text, iInvalidSize, zero_I2(), 0, NULL, NULL); 836 measure_RunMode | visualFlag_RunMode,
837 text,
838 iInvalidSize,
839 zero_I2(),
840 0,
841 NULL,
842 NULL);
828} 843}
829 844
830iInt2 measure_Text(int fontId, const char *text) { 845iInt2 measure_Text(int fontId, const char *text) {
831 return measureRange_Text(fontId, range_CStr(text)); 846 return measureRange_Text(fontId, range_CStr(text));
832} 847}
833 848
849static int runFlagsFromId_(enum iFontId fontId) {
850 int runFlags = 0;
851 if (fontId & alwaysVariableFlag_FontId) {
852 runFlags |= alwaysVariableWidthFlag_RunMode;
853 }
854 return runFlags;
855}
856
834iInt2 advanceRange_Text(int fontId, iRangecc text) { 857iInt2 advanceRange_Text(int fontId, iRangecc text) {
835 int advance; 858 int advance;
836 const int height = run_Font_(&text_.fonts[fontId], 859 const int height = run_Font_(font_Text_(fontId),
837 measure_RunMode, 860 measure_RunMode | runFlagsFromId_(fontId),
838 text, 861 text,
839 iInvalidSize, 862 iInvalidSize,
840 zero_I2(), 863 zero_I2(),
@@ -847,8 +870,8 @@ iInt2 advanceRange_Text(int fontId, iRangecc text) {
847 870
848iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos) { 871iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos) {
849 int advance; 872 int advance;
850 const int height = run_Font_(&text_.fonts[fontId], 873 const int height = run_Font_(font_Text_(fontId),
851 measure_RunMode, 874 measure_RunMode | runFlagsFromId_(fontId),
852 text, 875 text,
853 iInvalidSize, 876 iInvalidSize,
854 zero_I2(), 877 zero_I2(),
@@ -861,8 +884,8 @@ iInt2 tryAdvance_Text(int fontId, iRangecc text, int width, const char **endPos)
861 884
862iInt2 tryAdvanceNoWrap_Text(int fontId, iRangecc text, int width, const char **endPos) { 885iInt2 tryAdvanceNoWrap_Text(int fontId, iRangecc text, int width, const char **endPos) {
863 int advance; 886 int advance;
864 const int height = run_Font_(&text_.fonts[fontId], 887 const int height = run_Font_(font_Text_(fontId),
865 measureNoWrap_RunMode, 888 measure_RunMode | noWrapFlag_RunMode | runFlagsFromId_(fontId),
866 text, 889 text,
867 iInvalidSize, 890 iInvalidSize,
868 zero_I2(), 891 zero_I2(),
@@ -882,8 +905,14 @@ iInt2 advanceN_Text(int fontId, const char *text, size_t n) {
882 return init_I2(0, lineHeight_Text(fontId)); 905 return init_I2(0, lineHeight_Text(fontId));
883 } 906 }
884 int advance; 907 int advance;
885 run_Font_( 908 run_Font_(font_Text_(fontId),
886 &text_.fonts[fontId], measure_RunMode, range_CStr(text), n, zero_I2(), 0, NULL, &advance); 909 measure_RunMode | runFlagsFromId_(fontId),
910 range_CStr(text),
911 n,
912 zero_I2(),
913 0,
914 NULL,
915 &advance);
887 return init_I2(advance, lineHeight_Text(fontId)); 916 return init_I2(advance, lineHeight_Text(fontId));
888} 917}
889 918
@@ -891,8 +920,9 @@ static void draw_Text_(int fontId, iInt2 pos, int color, iRangecc text) {
891 iText *d = &text_; 920 iText *d = &text_;
892 const iColor clr = get_Color(color & mask_ColorId); 921 const iColor clr = get_Color(color & mask_ColorId);
893 SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b); 922 SDL_SetTextureColorMod(d->cache, clr.r, clr.g, clr.b);
894 run_Font_(&d->fonts[fontId], 923 run_Font_(font_Text_(fontId),
895 color & permanent_ColorId ? drawPermanentColor_RunMode : draw_RunMode, 924 draw_RunMode | (color & permanent_ColorId ? permanentColorFlag_RunMode : 0) |
925 runFlagsFromId_(fontId),
896 text, 926 text,
897 iInvalidSize, 927 iInvalidSize,
898 pos, 928 pos,