diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/color.c | 67 | ||||
-rw-r--r-- | src/ui/color.h | 3 | ||||
-rw-r--r-- | src/ui/text.c | 234 | ||||
-rw-r--r-- | src/ui/text.h | 5 |
4 files changed, 153 insertions, 156 deletions
diff --git a/src/ui/color.c b/src/ui/color.c index 0f7d4368..adbe444b 100644 --- a/src/ui/color.c +++ b/src/ui/color.c | |||
@@ -785,8 +785,14 @@ static const iColor ansi8BitColors_[256] = { | |||
785 | { 255, 255, 255, 255 } | 785 | { 255, 255, 255, 255 } |
786 | }; | 786 | }; |
787 | 787 | ||
788 | iColor ansiForeground_Color(iRangecc escapeSequence, int fallback) { | 788 | void ansiColors_Color(iRangecc escapeSequence, int fgDefault, int bgDefault, |
789 | iColor clr = get_Color(fallback); | 789 | iColor *fg_out, iColor *bg_out) { |
790 | if (!fg_out && !bg_out) { | ||
791 | return; | ||
792 | } | ||
793 | iColor fg, bg; | ||
794 | iZap(fg); | ||
795 | iZap(bg); | ||
790 | for (const char *ch = escapeSequence.start; ch < escapeSequence.end; ch++) { | 796 | for (const char *ch = escapeSequence.start; ch < escapeSequence.end; ch++) { |
791 | char *endPtr; | 797 | char *endPtr; |
792 | unsigned long arg = strtoul(ch, &endPtr, 10); | 798 | unsigned long arg = strtoul(ch, &endPtr, 10); |
@@ -802,19 +808,37 @@ iColor ansiForeground_Color(iRangecc escapeSequence, int fallback) { | |||
802 | case 35: | 808 | case 35: |
803 | case 36: | 809 | case 36: |
804 | case 37: | 810 | case 37: |
805 | clr = ansi8BitColors_[arg - 30]; | 811 | fg = ansi8BitColors_[arg - 30]; |
806 | break; | 812 | break; |
807 | case 38: { | 813 | case 38: |
814 | case 48: { | ||
815 | iColor *dst = (arg == 38 ? &fg : &bg); | ||
808 | /* Extended foreground color. */ | 816 | /* Extended foreground color. */ |
809 | arg = strtoul(ch + 1, &endPtr, 10); | 817 | arg = strtoul(ch + 1, &endPtr, 10); |
810 | ch = endPtr; | 818 | ch = endPtr; |
811 | if (arg == 5) /* 8-bit palette */ { | 819 | if (arg == 5) /* 8-bit palette */ { |
812 | arg = strtoul(ch + 1, &endPtr, 10); | 820 | arg = strtoul(ch + 1, &endPtr, 10); |
813 | ch = endPtr; | 821 | ch = endPtr; |
814 | clr = ansi8BitColors_[iClamp(arg, 0, 255)]; | 822 | *dst = ansi8BitColors_[iClamp(arg, 0, 255)]; |
815 | } | 823 | } |
816 | break; | 824 | break; |
817 | } | 825 | } |
826 | case 39: | ||
827 | fg = get_Color(fgDefault); | ||
828 | break; | ||
829 | case 40: | ||
830 | case 41: | ||
831 | case 42: | ||
832 | case 43: | ||
833 | case 44: | ||
834 | case 45: | ||
835 | case 46: | ||
836 | case 47: | ||
837 | bg = ansi8BitColors_[arg - 40]; | ||
838 | break; | ||
839 | case 49: | ||
840 | bg = get_Color(bgDefault); | ||
841 | break; | ||
818 | case 90: | 842 | case 90: |
819 | case 91: | 843 | case 91: |
820 | case 92: | 844 | case 92: |
@@ -823,17 +847,36 @@ iColor ansiForeground_Color(iRangecc escapeSequence, int fallback) { | |||
823 | case 95: | 847 | case 95: |
824 | case 96: | 848 | case 96: |
825 | case 97: | 849 | case 97: |
826 | clr = ansi8BitColors_[8 + arg - 90]; | 850 | fg = ansi8BitColors_[8 + arg - 90]; |
827 | break; | 851 | break; |
828 | } | 852 | } |
829 | } | 853 | } |
830 | /* On light backgrounds, darken the colors to make them more legible. */ | 854 | /* Ensure legibility if only one of the colors is set. */ |
831 | if (get_HSLColor(tmBackground_ColorId).lum > 0.5f) { | 855 | /* TODO: Force darkening of the background color, unless it is also specified. */ |
832 | clr.r /= 2; | 856 | #if 0 |
833 | clr.g /= 2; | 857 | if (bg.a == 0 && !equal_Color(fg, get_Color(fgDefault))) { |
834 | clr.b /= 2; | 858 | if (delta_Color(fg, get_Color(tmBackground_ColorId)) < 64) { |
859 | const iHSLColor fgHsl = hsl_Color(fg); | ||
860 | iHSLColor legibleBg = get_HSLColor(tmBackground_ColorId); | ||
861 | if () | ||
862 | bg = rgb_HSLColor(bgHsl); | ||
863 | } | ||
864 | } | ||
865 | } | ||
866 | #endif | ||
867 | /* | ||
868 | if (!bg_out || get_HSLColor(tmBackground_ColorId).lum > 0.5f) { | ||
869 | fg.r /= 2; | ||
870 | fg.g /= 2; | ||
871 | fg.b /= 2; | ||
872 | } | ||
873 | */ | ||
874 | if (fg.a && fg_out) { | ||
875 | *fg_out = fg; | ||
876 | } | ||
877 | if (bg.a && bg_out) { | ||
878 | *bg_out = bg; | ||
835 | } | 879 | } |
836 | return clr; | ||
837 | } | 880 | } |
838 | 881 | ||
839 | iBool loadPalette_Color(const char *path) { | 882 | iBool loadPalette_Color(const char *path) { |
diff --git a/src/ui/color.h b/src/ui/color.h index 03172fcb..6602b226 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -255,7 +255,8 @@ iLocalDef void setHsl_Color(int color, iHSLColor hsl) { | |||
255 | iBool loadPalette_Color (const char *path); | 255 | iBool loadPalette_Color (const char *path); |
256 | void setThemePalette_Color (enum iColorTheme theme); | 256 | void setThemePalette_Color (enum iColorTheme theme); |
257 | 257 | ||
258 | iColor ansiForeground_Color (iRangecc escapeSequence, int fallback); | 258 | void ansiColors_Color (iRangecc escapeSequence, int fgDefault, int bgDefault, |
259 | iColor *fg_out, iColor *bg_out); /* can be NULL */ | ||
259 | const char * escape_Color (int color); | 260 | const char * escape_Color (int color); |
260 | enum iColorId parseEscape_Color (const char *cstr, const char **endp); | 261 | enum iColorId parseEscape_Color (const char *cstr, const char **endp); |
261 | 262 | ||
diff --git a/src/ui/text.c b/src/ui/text.c index 91633f27..91ff137a 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -263,7 +263,7 @@ struct Impl_Text { | |||
263 | iRegExp * ansiEscape; | 263 | iRegExp * ansiEscape; |
264 | int ansiFlags; | 264 | int ansiFlags; |
265 | int baseFontId; /* base attributes (for restoring via escapes) */ | 265 | int baseFontId; /* base attributes (for restoring via escapes) */ |
266 | int baseColorId; | 266 | int baseFgColorId; |
267 | iBool missingGlyphs; /* true if a glyph couldn't be found */ | 267 | iBool missingGlyphs; /* true if a glyph couldn't be found */ |
268 | }; | 268 | }; |
269 | 269 | ||
@@ -390,35 +390,14 @@ static void deinitCache_Text_(iText *d) { | |||
390 | SDL_DestroyTexture(d->cache); | 390 | SDL_DestroyTexture(d->cache); |
391 | } | 391 | } |
392 | 392 | ||
393 | #if 0 | ||
394 | void loadUserFonts_Text(void) { | ||
395 | if (userFont_) { | ||
396 | delete_Block(userFont_); | ||
397 | userFont_ = NULL; | ||
398 | } | ||
399 | /* Load the system font. */ | ||
400 | const iPrefs *prefs = prefs_App(); | ||
401 | if (!isEmpty_String(&prefs->symbolFontPath)) { | ||
402 | iFile *f = new_File(&prefs->symbolFontPath); | ||
403 | if (open_File(f, readOnly_FileMode)) { | ||
404 | userFont_ = readAll_File(f); | ||
405 | } | ||
406 | else { | ||
407 | fprintf(stderr, "[Text] failed to open: %s\n", cstr_String(&prefs->symbolFontPath)); | ||
408 | } | ||
409 | iRelease(f); | ||
410 | } | ||
411 | } | ||
412 | #endif | ||
413 | |||
414 | void init_Text(iText *d, SDL_Renderer *render) { | 393 | void init_Text(iText *d, SDL_Renderer *render) { |
415 | iText *oldActive = activeText_; | 394 | iText *oldActive = activeText_; |
416 | activeText_ = d; | 395 | activeText_ = d; |
417 | init_Array(&d->fonts, sizeof(iFont)); | 396 | init_Array(&d->fonts, sizeof(iFont)); |
418 | d->contentFontSize = contentScale_Text_; | 397 | d->contentFontSize = contentScale_Text_; |
419 | d->ansiEscape = new_RegExp("[[()]([0-9;AB]*?)m", 0); | 398 | d->ansiEscape = new_RegExp("[[()][?]?([0-9;AB]*?)([ABCDEFGHJKSTfhilmn])", 0); |
420 | d->baseFontId = -1; | 399 | d->baseFontId = -1; |
421 | d->baseColorId = -1; | 400 | d->baseFgColorId = -1; |
422 | d->render = render; | 401 | d->render = render; |
423 | /* A grayscale palette for rasterized glyphs. */ { | 402 | /* A grayscale palette for rasterized glyphs. */ { |
424 | SDL_Color colors[256]; | 403 | SDL_Color colors[256]; |
@@ -459,9 +438,10 @@ void setOpacity_Text(float opacity) { | |||
459 | SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); | 438 | SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); |
460 | } | 439 | } |
461 | 440 | ||
462 | void setBaseAttributes_Text(int fontId, int colorId) { | 441 | void setBaseAttributes_Text(int fontId, int fgColorId) { |
463 | activeText_->baseFontId = fontId; | 442 | iText *d = activeText_; |
464 | activeText_->baseColorId = colorId; | 443 | d->baseFontId = fontId; |
444 | d->baseFgColorId = fgColorId; | ||
465 | } | 445 | } |
466 | 446 | ||
467 | void setAnsiFlags_Text(int ansiFlags) { | 447 | void setAnsiFlags_Text(int ansiFlags) { |
@@ -574,16 +554,6 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
574 | return overrideFont; | 554 | return overrideFont; |
575 | } | 555 | } |
576 | } | 556 | } |
577 | #if 0 | ||
578 | /* TODO: Put arrows in Smol Emoji. */ | ||
579 | /* Manual exceptions. */ { | ||
580 | if (ch >= 0x2190 && ch <= 0x2193 /* arrows */) { | ||
581 | d = font_Text_(iosevka_FontId + d->sizeId); | ||
582 | *glyphIndex = glyphIndex_Font_(d, ch); | ||
583 | return d; | ||
584 | } | ||
585 | } | ||
586 | #endif | ||
587 | /* The font's own version of the glyph. */ | 557 | /* The font's own version of the glyph. */ |
588 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { | 558 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { |
589 | return d; | 559 | return d; |
@@ -609,69 +579,6 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
609 | } | 579 | } |
610 | } | 580 | } |
611 | } | 581 | } |
612 | #if 0 | ||
613 | const int fallbacks[] = { | ||
614 | notoEmoji_FontId, | ||
615 | symbols2_FontId, | ||
616 | symbols_FontId | ||
617 | }; | ||
618 | /* First fallback is Smol Emoji. */ | ||
619 | if (ch != 0x20) { | ||
620 | iForIndices(i, fallbacks) { | ||
621 | iFont *fallback = font_Text_(fallbacks[i] + d->sizeId); | ||
622 | if (fallback != d && (*glyphIndex = glyphIndex_Font_(fallback, ch)) != 0) { | ||
623 | return fallback; | ||
624 | } | ||
625 | } | ||
626 | } | ||
627 | /* Try Simplified Chinese. */ | ||
628 | if (ch >= 0x2e80) { | ||
629 | iFont *sc = font_Text_(chineseSimplified_FontId + d->sizeId); | ||
630 | if (sc != d && (*glyphIndex = glyphIndex_Font_(sc, ch)) != 0) { | ||
631 | return sc; | ||
632 | } | ||
633 | } | ||
634 | /* Could be Korean. */ | ||
635 | if (ch >= 0x3000) { | ||
636 | iFont *korean = font_Text_(korean_FontId + d->sizeId); | ||
637 | if (korean != d && (*glyphIndex = glyphIndex_Font_(korean, ch)) != 0) { | ||
638 | return korean; | ||
639 | } | ||
640 | } | ||
641 | /* Japanese perhaps? */ | ||
642 | if (ch > 0x3040) { | ||
643 | iFont *japanese = font_Text_(japanese_FontId + d->sizeId); | ||
644 | if (japanese != d && (*glyphIndex = glyphIndex_Font_(japanese, ch)) != 0) { | ||
645 | return japanese; | ||
646 | } | ||
647 | } | ||
648 | /* Maybe Arabic. */ | ||
649 | if (ch >= 0x600) { | ||
650 | iFont *arabic = font_Text_(arabic_FontId + d->sizeId); | ||
651 | if (arabic != d && (*glyphIndex = glyphIndex_Font_(arabic, ch)) != 0) { | ||
652 | return arabic; | ||
653 | } | ||
654 | } | ||
655 | #if defined (iPlatformApple) | ||
656 | /* White up arrow is used for the Shift key on macOS. Symbola's glyph is not a great | ||
657 | match to the other text, so use the UI font instead. */ | ||
658 | if ((ch == 0x2318 || ch == 0x21e7) && d == font_Text_(regular_FontId)) { | ||
659 | *glyphIndex = glyphIndex_Font_(d = font_Text_(defaultContentRegular_FontId), ch); | ||
660 | return d; | ||
661 | } | ||
662 | #endif | ||
663 | /* User's symbols font. */ { | ||
664 | iFont *sys = font_Text_(userSymbols_FontId + d->sizeId); | ||
665 | if (sys != d && (*glyphIndex = glyphIndex_Font_(sys, ch)) != 0) { | ||
666 | return sys; | ||
667 | } | ||
668 | } | ||
669 | /* Final fallback. */ | ||
670 | iFont *font = font_Text_(iosevka_FontId + d->sizeId); | ||
671 | if (d != font) { | ||
672 | *glyphIndex = glyphIndex_Font_(font, ch); | ||
673 | } | ||
674 | #endif // 0 | ||
675 | if (!*glyphIndex) { | 582 | if (!*glyphIndex) { |
676 | activeText_->missingGlyphs = iTrue; | 583 | activeText_->missingGlyphs = iTrue; |
677 | fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); | 584 | fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); |
@@ -680,7 +587,9 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
680 | } | 587 | } |
681 | 588 | ||
682 | static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { | 589 | static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { |
683 | iAssert(d->table); | 590 | if (!d->table) { |
591 | d->table = new_GlyphTable(); | ||
592 | } | ||
684 | iGlyph* glyph = NULL; | 593 | iGlyph* glyph = NULL; |
685 | void * node = value_Hash(&d->table->glyphs, glyphIndex); | 594 | void * node = value_Hash(&d->table->glyphs, glyphIndex); |
686 | if (node) { | 595 | if (node) { |
@@ -739,6 +648,7 @@ struct Impl_AttributedRun { | |||
739 | iTextAttrib attrib; | 648 | iTextAttrib attrib; |
740 | iFont *font; | 649 | iFont *font; |
741 | iColor fgColor_; /* any RGB color; A > 0 */ | 650 | iColor fgColor_; /* any RGB color; A > 0 */ |
651 | iColor bgColor_; /* any RGB color; A > 0 */ | ||
742 | struct { | 652 | struct { |
743 | uint8_t isLineBreak : 1; | 653 | uint8_t isLineBreak : 1; |
744 | // uint8_t isRTL : 1; | 654 | // uint8_t isRTL : 1; |
@@ -750,29 +660,45 @@ static iColor fgColor_AttributedRun_(const iAttributedRun *d) { | |||
750 | if (d->fgColor_.a) { | 660 | if (d->fgColor_.a) { |
751 | return d->fgColor_; | 661 | return d->fgColor_; |
752 | } | 662 | } |
753 | if (d->attrib.colorId == none_ColorId) { | 663 | if (d->attrib.fgColorId == none_ColorId) { |
754 | return (iColor){ 255, 255, 255, 255 }; | 664 | return (iColor){ 255, 255, 255, 255 }; |
755 | } | 665 | } |
756 | return get_Color(d->attrib.colorId); | 666 | return get_Color(d->attrib.fgColorId); |
667 | } | ||
668 | |||
669 | static iColor bgColor_AttributedRun_(const iAttributedRun *d) { | ||
670 | if (d->bgColor_.a) { | ||
671 | return d->bgColor_; | ||
672 | } | ||
673 | return (iColor){ 255, 255, 255, 0 }; | ||
674 | if (d->attrib.bgColorId == none_ColorId) { | ||
675 | return (iColor){ 255, 255, 255, 0 }; | ||
676 | } | ||
677 | return get_Color(d->attrib.bgColorId); | ||
757 | } | 678 | } |
758 | 679 | ||
759 | static void setFgColor_AttributedRun_(iAttributedRun *d, int colorId) { | 680 | static void setFgColor_AttributedRun_(iAttributedRun *d, int colorId) { |
760 | d->attrib.colorId = colorId; | 681 | d->attrib.fgColorId = colorId; |
761 | d->fgColor_.a = 0; | 682 | d->fgColor_.a = 0; |
762 | } | 683 | } |
763 | 684 | ||
685 | static void setBgColor_AttributedRun_(iAttributedRun *d, int colorId) { | ||
686 | d->attrib.bgColorId = colorId; | ||
687 | d->bgColor_.a = 0; | ||
688 | } | ||
689 | |||
764 | iDeclareType(AttributedText) | 690 | iDeclareType(AttributedText) |
765 | iDeclareTypeConstructionArgs(AttributedText, iRangecc text, size_t maxLen, iFont *font, | 691 | iDeclareTypeConstructionArgs(AttributedText, iRangecc text, size_t maxLen, iFont *font, |
766 | int colorId, int baseDir, iFont *baseFont, int baseColorId, | 692 | int colorId, int baseDir, iFont *baseFont, int baseFgColorId, |
767 | iChar overrideChar) | 693 | iChar overrideChar) |
768 | 694 | ||
769 | struct Impl_AttributedText { | 695 | struct Impl_AttributedText { |
770 | iRangecc source; /* original source text */ | 696 | iRangecc source; /* original source text */ |
771 | size_t maxLen; | 697 | size_t maxLen; |
772 | iFont * font; | 698 | iFont * font; |
773 | int colorId; | 699 | int fgColorId; |
774 | iFont * baseFont; | 700 | iFont * baseFont; |
775 | int baseColorId; | 701 | int baseFgColorId; |
776 | iBool isBaseRTL; | 702 | iBool isBaseRTL; |
777 | iArray runs; | 703 | iArray runs; |
778 | iArray logical; /* UTF-32 text in logical order (mixed directions; matches source) */ | 704 | iArray logical; /* UTF-32 text in logical order (mixed directions; matches source) */ |
@@ -785,9 +711,9 @@ struct Impl_AttributedText { | |||
785 | 711 | ||
786 | iDefineTypeConstructionArgs(AttributedText, | 712 | iDefineTypeConstructionArgs(AttributedText, |
787 | (iRangecc text, size_t maxLen, iFont *font, int colorId, | 713 | (iRangecc text, size_t maxLen, iFont *font, int colorId, |
788 | int baseDir, iFont *baseFont, int baseColorId, | 714 | int baseDir, iFont *baseFont, int baseFgColorId, |
789 | iChar overrideChar), | 715 | iChar overrideChar), |
790 | text, maxLen, font, colorId, baseDir, baseFont, baseColorId, | 716 | text, maxLen, font, colorId, baseDir, baseFont, baseFgColorId, |
791 | overrideChar) | 717 | overrideChar) |
792 | 718 | ||
793 | static const char *sourcePtr_AttributedText_(const iAttributedText *d, int logicalPos) { | 719 | static const char *sourcePtr_AttributedText_(const iAttributedText *d, int logicalPos) { |
@@ -897,7 +823,8 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
897 | } | 823 | } |
898 | iAttributedRun run = { | 824 | iAttributedRun run = { |
899 | .logical = { 0, length }, | 825 | .logical = { 0, length }, |
900 | .attrib = { .colorId = d->colorId, .isBaseRTL = d->isBaseRTL }, | 826 | .attrib = { .fgColorId = d->fgColorId, .bgColorId = none_ColorId, |
827 | .isBaseRTL = d->isBaseRTL }, | ||
901 | .font = d->font, | 828 | .font = d->font, |
902 | }; | 829 | }; |
903 | const int *logToSource = constData_Array(&d->logicalToSourceOffset); | 830 | const int *logToSource = constData_Array(&d->logicalToSourceOffset); |
@@ -935,12 +862,13 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
935 | if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) { | 862 | if (match_RegExp(activeText_->ansiEscape, srcPos, d->source.end - srcPos, &m)) { |
936 | finishRun_AttributedText_(d, &run, pos - 1); | 863 | finishRun_AttributedText_(d, &run, pos - 1); |
937 | const int ansi = activeText_->ansiFlags; | 864 | const int ansi = activeText_->ansiFlags; |
938 | if (ansi) { | 865 | if (ansi && capturedRange_RegExpMatch(&m, 2).start[0] == |
866 | 'm' /* Select Graphic Rendition */) { | ||
939 | const iRangecc sequence = capturedRange_RegExpMatch(&m, 1); | 867 | const iRangecc sequence = capturedRange_RegExpMatch(&m, 1); |
940 | /* Note: This styling is hardcoded to match `typesetOneLine_RunTypesetter_()`. */ | 868 | /* Note: This styling is hardcoded to match `typesetOneLine_RunTypesetter_()`. */ |
941 | if (ansi & allowFontStyle_AnsiFlag && equal_Rangecc(sequence, "1")) { | 869 | if (ansi & allowFontStyle_AnsiFlag && equal_Rangecc(sequence, "1")) { |
942 | run.attrib.bold = iTrue; | 870 | run.attrib.bold = iTrue; |
943 | if (d->baseColorId == tmParagraph_ColorId) { | 871 | if (d->baseFgColorId == tmParagraph_ColorId) { |
944 | setFgColor_AttributedRun_(&run, tmFirstParagraph_ColorId); | 872 | setFgColor_AttributedRun_(&run, tmFirstParagraph_ColorId); |
945 | } | 873 | } |
946 | attribFont = font_Text_(fontWithStyle_Text(fontId_Text_(d->baseFont), | 874 | attribFont = font_Text_(fontWithStyle_Text(fontId_Text_(d->baseFont), |
@@ -962,10 +890,13 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
962 | run.attrib.italic = iFalse; | 890 | run.attrib.italic = iFalse; |
963 | run.attrib.monospace = iFalse; | 891 | run.attrib.monospace = iFalse; |
964 | attribFont = run.font = d->baseFont; | 892 | attribFont = run.font = d->baseFont; |
965 | setFgColor_AttributedRun_(&run, d->baseColorId); | 893 | setFgColor_AttributedRun_(&run, d->baseFgColorId); |
894 | setBgColor_AttributedRun_(&run, none_ColorId); | ||
966 | } | 895 | } |
967 | else if (ansi & allowFg_AnsiFlag) { | 896 | else { |
968 | run.fgColor_ = ansiForeground_Color(sequence, tmParagraph_ColorId); | 897 | ansiColors_Color(sequence, d->baseFgColorId, none_ColorId, |
898 | ansi & allowFg_AnsiFlag ? &run.fgColor_ : NULL, | ||
899 | ansi & allowBg_AnsiFlag ? &run.bgColor_ : NULL); | ||
969 | } | 900 | } |
970 | } | 901 | } |
971 | pos += length_Rangecc(capturedRange_RegExpMatch(&m, 0)); | 902 | pos += length_Rangecc(capturedRange_RegExpMatch(&m, 0)); |
@@ -988,7 +919,7 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
988 | colorNum = esc - asciiBase_ColorEscape; | 919 | colorNum = esc - asciiBase_ColorEscape; |
989 | } | 920 | } |
990 | run.logical.start = pos + 1; | 921 | run.logical.start = pos + 1; |
991 | setFgColor_AttributedRun_(&run, colorNum >= 0 ? colorNum : d->colorId); | 922 | setFgColor_AttributedRun_(&run, colorNum >= 0 ? colorNum : d->fgColorId); |
992 | continue; | 923 | continue; |
993 | } | 924 | } |
994 | if (ch == '\n') { | 925 | if (ch == '\n') { |
@@ -1051,14 +982,15 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
1051 | } | 982 | } |
1052 | 983 | ||
1053 | void init_AttributedText(iAttributedText *d, iRangecc text, size_t maxLen, iFont *font, int colorId, | 984 | void init_AttributedText(iAttributedText *d, iRangecc text, size_t maxLen, iFont *font, int colorId, |
1054 | int baseDir, iFont *baseFont, int baseColorId, iChar overrideChar) { | 985 | int baseDir, iFont *baseFont, int baseFgColorId, |
1055 | d->source = text; | 986 | iChar overrideChar) { |
1056 | d->maxLen = maxLen ? maxLen : iInvalidSize; | 987 | d->source = text; |
1057 | d->font = font; | 988 | d->maxLen = maxLen ? maxLen : iInvalidSize; |
1058 | d->colorId = colorId; | 989 | d->font = font; |
1059 | d->baseFont = baseFont; | 990 | d->fgColorId = colorId; |
1060 | d->baseColorId = baseColorId; | 991 | d->baseFont = baseFont; |
1061 | d->isBaseRTL = iFalse; | 992 | d->baseFgColorId = baseFgColorId; |
993 | d->isBaseRTL = iFalse; | ||
1062 | init_Array(&d->runs, sizeof(iAttributedRun)); | 994 | init_Array(&d->runs, sizeof(iAttributedRun)); |
1063 | init_Array(&d->logical, sizeof(iChar)); | 995 | init_Array(&d->logical, sizeof(iChar)); |
1064 | init_Array(&d->visual, sizeof(iChar)); | 996 | init_Array(&d->visual, sizeof(iChar)); |
@@ -1412,7 +1344,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1412 | init_AttributedText(&attrText, args->text, args->maxLen, d, args->color, | 1344 | init_AttributedText(&attrText, args->text, args->maxLen, d, args->color, |
1413 | args->baseDir, | 1345 | args->baseDir, |
1414 | activeText_->baseFontId >= 0 ? font_Text_(activeText_->baseFontId) : d, | 1346 | activeText_->baseFontId >= 0 ? font_Text_(activeText_->baseFontId) : d, |
1415 | activeText_->baseColorId, | 1347 | activeText_->baseFgColorId, |
1416 | wrap ? wrap->overrideChar : 0); | 1348 | wrap ? wrap->overrideChar : 0); |
1417 | if (wrap) { | 1349 | if (wrap) { |
1418 | wrap->baseDir = attrText.isBaseRTL ? -1 : +1; | 1350 | wrap->baseDir = attrText.isBaseRTL ? -1 : +1; |
@@ -1464,7 +1396,9 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1464 | iRangei wrapPosRange = { 0, textLen }; | 1396 | iRangei wrapPosRange = { 0, textLen }; |
1465 | int wrapResumePos = textLen; /* logical position where next line resumes */ | 1397 | int wrapResumePos = textLen; /* logical position where next line resumes */ |
1466 | size_t wrapResumeRunIndex = runCount; /* index of run where next line resumes */ | 1398 | size_t wrapResumeRunIndex = runCount; /* index of run where next line resumes */ |
1467 | iTextAttrib attrib = { .colorId = args->color, .isBaseRTL = attrText.isBaseRTL }; | 1399 | iTextAttrib attrib = { .fgColorId = args->color, |
1400 | .bgColorId = none_ColorId, | ||
1401 | .isBaseRTL = attrText.isBaseRTL }; | ||
1468 | iTextAttrib wrapAttrib = attrib; | 1402 | iTextAttrib wrapAttrib = attrib; |
1469 | iTextAttrib lastAttrib = attrib; | 1403 | iTextAttrib lastAttrib = attrib; |
1470 | const int layoutBound = (wrap ? wrap->maxWidth : 0); | 1404 | const int layoutBound = (wrap ? wrap->maxWidth : 0); |
@@ -1712,6 +1646,12 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1712 | yCursor += d->height; | 1646 | yCursor += d->height; |
1713 | continue; | 1647 | continue; |
1714 | } | 1648 | } |
1649 | const iColor fgClr = fgColor_AttributedRun_(run); | ||
1650 | const iColor bgClr = bgColor_AttributedRun_(run); | ||
1651 | iBool isBgFilled = iFalse; | ||
1652 | if (~mode & permanentColorFlag_RunMode) { | ||
1653 | isBgFilled = (bgClr.a != 0) || (mode & fillBackground_RunMode); | ||
1654 | } | ||
1715 | iGlyphBuffer *buf = at_Array(&buffers, runIndex); | 1655 | iGlyphBuffer *buf = at_Array(&buffers, runIndex); |
1716 | shape_GlyphBuffer_(buf); | 1656 | shape_GlyphBuffer_(buf); |
1717 | iAssert(run->font == buf->font); | 1657 | iAssert(run->font == buf->font); |
@@ -1772,34 +1712,46 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1772 | bounds.size.x = iMax(bounds.size.x, dst.x + dst.w - orig.x); | 1712 | bounds.size.x = iMax(bounds.size.x, dst.x + dst.w - orig.x); |
1773 | bounds.size.y = iMax(bounds.size.y, yCursor + glyph->font->height); | 1713 | bounds.size.y = iMax(bounds.size.y, yCursor + glyph->font->height); |
1774 | } | 1714 | } |
1775 | if (mode & draw_RunMode && logicalText[logPos] > 0x20) { | 1715 | const iBool isSpace = (logicalText[logPos] == 0x20); |
1716 | if (mode & draw_RunMode && (isBgFilled || !isSpace)) { | ||
1776 | /* Draw the glyph. */ | 1717 | /* Draw the glyph. */ |
1777 | if (!isRasterized_Glyph_(glyph, hoff)) { | 1718 | if (!isSpace && !isRasterized_Glyph_(glyph, hoff)) { |
1778 | cacheSingleGlyph_Font_(run->font, glyphId); /* may cause cache reset */ | 1719 | cacheSingleGlyph_Font_(run->font, glyphId); /* may cause cache reset */ |
1779 | glyph = glyphByIndex_Font_(run->font, glyphId); | 1720 | glyph = glyphByIndex_Font_(run->font, glyphId); |
1780 | iAssert(isRasterized_Glyph_(glyph, hoff)); | 1721 | iAssert(isRasterized_Glyph_(glyph, hoff)); |
1781 | } | 1722 | } |
1782 | if (~mode & permanentColorFlag_RunMode) { | 1723 | if (~mode & permanentColorFlag_RunMode) { |
1783 | const iColor clr = fgColor_AttributedRun_(run); | 1724 | SDL_SetTextureColorMod(activeText_->cache, fgClr.r, fgClr.g, fgClr.b); |
1784 | SDL_SetTextureColorMod(activeText_->cache, clr.r, clr.g, clr.b); | ||
1785 | if (args->mode & fillBackground_RunMode) { | ||
1786 | SDL_SetRenderDrawColor(activeText_->render, clr.r, clr.g, clr.b, 0); | ||
1787 | } | ||
1788 | } | 1725 | } |
1789 | SDL_Rect src; | ||
1790 | memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect)); | ||
1791 | dst.x += origin_Paint.x; | 1726 | dst.x += origin_Paint.x; |
1792 | dst.y += origin_Paint.y; | 1727 | dst.y += origin_Paint.y; |
1793 | if (args->mode & fillBackground_RunMode) { | 1728 | if (isBgFilled) { |
1794 | /* Alpha blending looks much better if the RGB components don't change in | ||
1795 | the partially transparent pixels. */ | ||
1796 | /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ | 1729 | /* TODO: Backgrounds of all glyphs should be cleared before drawing anything else. */ |
1797 | SDL_RenderFillRect(activeText_->render, &dst); | 1730 | if (bgClr.a) { |
1731 | SDL_SetRenderDrawColor(activeText_->render, bgClr.r, bgClr.g, bgClr.b, 255); | ||
1732 | const SDL_Rect bgRect = { | ||
1733 | origin_Paint.x + orig.x + xCursor, | ||
1734 | origin_Paint.y + orig.y + yCursor, | ||
1735 | xAdvance, | ||
1736 | d->height, | ||
1737 | }; | ||
1738 | SDL_RenderFillRect(activeText_->render, &bgRect); | ||
1739 | } | ||
1740 | else if (args->mode & fillBackground_RunMode) { | ||
1741 | /* Alpha blending looks much better if the RGB components don't change | ||
1742 | in the partially transparent pixels. */ | ||
1743 | SDL_SetRenderDrawColor(activeText_->render, fgClr.r, fgClr.g, fgClr.b, 0); | ||
1744 | SDL_RenderFillRect(activeText_->render, &dst); | ||
1745 | } | ||
1746 | } | ||
1747 | if (!isSpace) { | ||
1748 | SDL_Rect src; | ||
1749 | memcpy(&src, &glyph->rect[hoff], sizeof(SDL_Rect)); | ||
1750 | SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst); | ||
1798 | } | 1751 | } |
1799 | SDL_RenderCopy(activeText_->render, activeText_->cache, &src, &dst); | ||
1800 | #if 0 | 1752 | #if 0 |
1801 | /* Show spaces and direction. */ | 1753 | /* Show spaces and direction. */ |
1802 | if (logicalText[logPos] == 0x20) { | 1754 | if (isSpace) { |
1803 | const iColor debug = get_Color(run->flags.isRTL ? yellow_ColorId : red_ColorId); | 1755 | const iColor debug = get_Color(run->flags.isRTL ? yellow_ColorId : red_ColorId); |
1804 | SDL_SetRenderDrawColor(text_.render, debug.r, debug.g, debug.b, 255); | 1756 | SDL_SetRenderDrawColor(text_.render, debug.r, debug.g, debug.b, 255); |
1805 | dst.w = xAdvance; | 1757 | dst.w = xAdvance; |
diff --git a/src/ui/text.h b/src/ui/text.h index 13a636d4..de76ed09 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -157,7 +157,7 @@ enum iAnsiFlag { | |||
157 | }; | 157 | }; |
158 | 158 | ||
159 | void setOpacity_Text (float opacity); | 159 | void setOpacity_Text (float opacity); |
160 | void setBaseAttributes_Text (int fontId, int colorId); /* current "normal" text attributes */ | 160 | void setBaseAttributes_Text (int fontId, int fgColorId); /* current "normal" text attributes */ |
161 | void setAnsiFlags_Text (int ansiFlags); | 161 | void setAnsiFlags_Text (int ansiFlags); |
162 | 162 | ||
163 | void cache_Text (int fontId, iRangecc text); /* pre-render glyphs */ | 163 | void cache_Text (int fontId, iRangecc text); /* pre-render glyphs */ |
@@ -187,7 +187,8 @@ iDeclareType(TextAttrib) | |||
187 | /* Initial attributes at the start of a text string. These may be modified by control | 187 | /* Initial attributes at the start of a text string. These may be modified by control |
188 | sequences inside a text run. */ | 188 | sequences inside a text run. */ |
189 | struct Impl_TextAttrib { | 189 | struct Impl_TextAttrib { |
190 | int16_t colorId; | 190 | int16_t fgColorId; |
191 | int16_t bgColorId; | ||
191 | struct { | 192 | struct { |
192 | uint16_t bold : 1; | 193 | uint16_t bold : 1; |
193 | uint16_t italic : 1; | 194 | uint16_t italic : 1; |