diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-05 16:30:34 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-08-05 16:30:34 +0300 |
commit | f38a940d722064e4b3fb2df6a6c0bcc025383ca0 (patch) | |
tree | f3df6097a60b04ff324cf9105f9cb1a4dbd825c9 /src/gmdocument.c | |
parent | 2b1de0641335ab1a88aeafcc8911056f155e94c9 (diff) |
Color palette theming
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r-- | src/gmdocument.c | 184 |
1 files changed, 159 insertions, 25 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index e23d5836..a631739f 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -265,14 +265,14 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
265 | regular_FontId, | 265 | regular_FontId, |
266 | }; | 266 | }; |
267 | static const int colors[max_GmLineType] = { | 267 | static const int colors[max_GmLineType] = { |
268 | gray75_ColorId, | 268 | tmParagraph_ColorId, |
269 | gray75_ColorId, | 269 | tmParagraph_ColorId, |
270 | cyan_ColorId, | 270 | tmPreformatted_ColorId, |
271 | gray75_ColorId, | 271 | tmQuote_ColorId, |
272 | white_ColorId, | 272 | tmHeader1_ColorId, |
273 | white_ColorId, | 273 | tmHeader2_ColorId, |
274 | white_ColorId, | 274 | tmHeader3_ColorId, |
275 | white_ColorId, | 275 | tmLinkText_ColorId, |
276 | }; | 276 | }; |
277 | static const int indents[max_GmLineType] = { | 277 | static const int indents[max_GmLineType] = { |
278 | 5, 10, 5, 10, 0, 0, 0, 5 | 278 | 5, 10, 5, 10, 0, 0, 0, 5 |
@@ -363,7 +363,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
363 | banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2); | 363 | banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2); |
364 | banner.font = banner_FontId; | 364 | banner.font = banner_FontId; |
365 | banner.text = bannerText; | 365 | banner.text = bannerText; |
366 | banner.color = gray50_ColorId; | 366 | banner.color = tmBannerTitle_ColorId; |
367 | pushBack_Array(&d->layout, &banner); | 367 | pushBack_Array(&d->layout, &banner); |
368 | pos.y += height_Rect(banner.visBounds) + lineHeight_Text(paragraph_FontId); | 368 | pos.y += height_Rect(banner.visBounds) + lineHeight_Text(paragraph_FontId); |
369 | } | 369 | } |
@@ -419,10 +419,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
419 | if (link->flags & remote_GmLinkFlag) { | 419 | if (link->flags & remote_GmLinkFlag) { |
420 | run.visBounds.pos.x -= gap_Text / 2; | 420 | run.visBounds.pos.x -= gap_Text / 2; |
421 | } | 421 | } |
422 | run.color = linkColor_GmDocument(d, run.linkId); | 422 | run.color = linkColor_GmDocument(d, run.linkId, icon_GmLinkPart); |
423 | if (link->flags & visited_GmLinkFlag) { | ||
424 | run.color--; /* darker */ | ||
425 | } | ||
426 | pushBack_Array(&d->layout, &run); | 423 | pushBack_Array(&d->layout, &run); |
427 | } | 424 | } |
428 | run.color = colors[type]; | 425 | run.color = colors[type]; |
@@ -433,7 +430,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
433 | int bigCount = 0; | 430 | int bigCount = 0; |
434 | if (type == text_GmLineType && isFirstText) { | 431 | if (type == text_GmLineType && isFirstText) { |
435 | run.font = firstParagraph_FontId; | 432 | run.font = firstParagraph_FontId; |
436 | run.color = white_ColorId; | 433 | run.color = tmFirstParagraph_ColorId; |
437 | bigCount = 15; /* max lines -- what if the whole document is one paragraph? */ | 434 | bigCount = 15; /* max lines -- what if the whole document is one paragraph? */ |
438 | isFirstText = iFalse; | 435 | isFirstText = iFalse; |
439 | } | 436 | } |
@@ -549,6 +546,14 @@ void reset_GmDocument(iGmDocument *d) { | |||
549 | d->themeSeed = 0; | 546 | d->themeSeed = 0; |
550 | } | 547 | } |
551 | 548 | ||
549 | static float fixHue_(float hue) { | ||
550 | if (hue > 260 && hue < 330) { | ||
551 | if (hue < 295) return hue - 90; | ||
552 | return hue + 90; | ||
553 | } | ||
554 | return hue; | ||
555 | } | ||
556 | |||
552 | void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { | 557 | void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { |
553 | static const iChar siteIcons[] = { | 558 | static const iChar siteIcons[] = { |
554 | 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, 0x265c, 0x265e, 0x2690, | 559 | 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, 0x265c, 0x265e, 0x2690, |
@@ -560,14 +565,106 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { | |||
560 | }; | 565 | }; |
561 | d->themeSeed = 0; | 566 | d->themeSeed = 0; |
562 | d->siteIcon = 0; | 567 | d->siteIcon = 0; |
568 | /* Default colors. */ { | ||
569 | const iHSLColor base = { 0, 0, 0.15f, 1.0f }; | ||
570 | setHsl_Color(tmBackground_ColorId, base); | ||
571 | } | ||
563 | if (seed && !isEmpty_Block(seed)) { | 572 | if (seed && !isEmpty_Block(seed)) { |
564 | d->themeSeed = crc32_Block(seed); | 573 | d->themeSeed = crc32_Block(seed); |
565 | d->siteIcon = siteIcons[(d->themeSeed >> 7) % iElemCount(siteIcons)]; | 574 | d->siteIcon = siteIcons[(d->themeSeed >> 7) % iElemCount(siteIcons)]; |
575 | /* Set up colors. */ { | ||
576 | static const float hues[] = { | ||
577 | 0, 60, 90, 100, 180, 210, 230, 260, 330 | ||
578 | }; | ||
579 | const iBool isDesaturated = iFalse; | ||
580 | const iBool isLowSaturated = iFalse; | ||
581 | const iBool isLightMode = iFalse; | ||
582 | const iBool isBannerLighter = (d->themeSeed & 0x4000) != 0; | ||
583 | iHSLColor base = { hues[(d->themeSeed & 0xff) % iElemCount(hues)], | ||
584 | 0.8f * (d->themeSeed >> 24) / 255.0f, | ||
585 | 0.06f + 0.09f * ((d->themeSeed >> 5) & 0x7) / 7.0f, | ||
586 | 1.0f }; | ||
587 | printf("background: %d %f %f\n", (int) base.hue, base.sat, base.lum); | ||
588 | setHsl_Color(tmBackground_ColorId, base); | ||
589 | |||
590 | setHsl_Color(tmBannerBackground_ColorId, addSatLum_HSLColor(base, 0.1f, 0.04f * (isBannerLighter ? 1 : -1))); | ||
591 | setHsl_Color(tmBannerTitle_ColorId, setLum_HSLColor(addSatLum_HSLColor(base, 0.1f, 0), 0.55f)); | ||
592 | setHsl_Color(tmBannerIcon_ColorId, setLum_HSLColor(addSatLum_HSLColor(base, 0.35f, 0), 0.65f)); | ||
593 | |||
594 | const iBool altDir = (d->themeSeed & 0x4) != 0; | ||
595 | const float altHue = fixHue_(iWrapf(base.hue + (altDir ? 90 : -90), 0, 360)); | ||
596 | const float altHue2 = fixHue_(iWrapf(base.hue + (altDir ? -30 : 30), 0, 360)); | ||
597 | iHSLColor altBase = base; | ||
598 | altBase.hue = altHue; | ||
599 | const float titleLum = 0.2f * ((d->themeSeed >> 17) & 0x7) / 7.0f; | ||
600 | setHsl_Color(tmHeader1_ColorId, setLum_HSLColor(altBase, titleLum + 0.80f)); | ||
601 | setHsl_Color(tmHeader2_ColorId, setLum_HSLColor(altBase, titleLum + 0.70f)); | ||
602 | setHsl_Color(tmHeader3_ColorId, setLum_HSLColor(altBase, titleLum + 0.60f)); | ||
603 | |||
604 | setHsl_Color(tmParagraph_ColorId, addSatLum_HSLColor(base, 0.1f, 0.6f)); | ||
605 | setHsl_Color(tmFirstParagraph_ColorId, addSatLum_HSLColor(base, 0.2f, 0.8f)); | ||
606 | setHsl_Color(tmPreformatted_ColorId, (iHSLColor){ altHue2, 1.0f, 0.75f, 1.0f }); | ||
607 | set_Color(tmQuote_ColorId, get_Color(tmPreformatted_ColorId)); | ||
608 | set_Color(tmInlineContentMetadata_ColorId, get_Color(tmHeader3_ColorId)); | ||
609 | set_Color(tmBadLink_ColorId, get_Color(red_ColorId)); | ||
610 | |||
611 | set_Color(tmLinkText_ColorId, get_Color(white_ColorId)); | ||
612 | set_Color(tmLinkIcon_ColorId, get_Color(cyan_ColorId)); | ||
613 | set_Color(tmLinkTextHover_ColorId, get_Color(cyan_ColorId)); | ||
614 | set_Color(tmLinkIconVisited_ColorId, get_Color(teal_ColorId)); | ||
615 | set_Color(tmLinkDomain_ColorId, get_Color(teal_ColorId)); | ||
616 | set_Color(tmLinkLastVisitDate_ColorId, get_Color(cyan_ColorId)); | ||
617 | |||
618 | set_Color(tmHypertextLinkText_ColorId, get_Color(white_ColorId)); | ||
619 | set_Color(tmHypertextLinkIcon_ColorId, get_Color(orange_ColorId)); | ||
620 | set_Color(tmHypertextLinkTextHover_ColorId, get_Color(orange_ColorId)); | ||
621 | set_Color(tmHypertextLinkIconVisited_ColorId, get_Color(brown_ColorId)); | ||
622 | set_Color(tmHypertextLinkDomain_ColorId, get_Color(brown_ColorId)); | ||
623 | set_Color(tmHypertextLinkLastVisitDate_ColorId, get_Color(orange_ColorId)); | ||
624 | |||
625 | set_Color(tmGopherLinkText_ColorId, get_Color(white_ColorId)); | ||
626 | set_Color(tmGopherLinkIcon_ColorId, get_Color(blue_ColorId)); | ||
627 | set_Color(tmGopherLinkTextHover_ColorId, get_Color(blue_ColorId)); | ||
628 | set_Color(tmGopherLinkIconVisited_ColorId, get_Color(magenta_ColorId)); | ||
629 | set_Color(tmGopherLinkDomain_ColorId, get_Color(magenta_ColorId)); | ||
630 | set_Color(tmGopherLinkLastVisitDate_ColorId, get_Color(blue_ColorId)); | ||
631 | |||
632 | for (int i = tmFirst_ColorId; i < max_ColorId; i++) { | ||
633 | iHSLColor color = hsl_Color(get_Color(i)); | ||
634 | if (isLightMode) { | ||
635 | color.lum = 1.0f - color.lum; | ||
636 | } | ||
637 | if (i < tmBadLink_ColorId) { /* Not a link? */ | ||
638 | if (isLowSaturated) { | ||
639 | color.sat *= 0.3f; | ||
640 | } | ||
641 | if (isDesaturated) { | ||
642 | color.sat = 0; | ||
643 | } | ||
644 | if (isLightMode) { | ||
645 | /* Darken text. */ | ||
646 | if (i == tmParagraph_ColorId || i == tmLinkText_ColorId || | ||
647 | i == tmHypertextLinkText_ColorId || i == tmGopherLinkText_ColorId) { | ||
648 | color.lum *= 0.5f; | ||
649 | } | ||
650 | else if (i == tmBannerIcon_ColorId) { | ||
651 | color.lum *= 0.75f; | ||
652 | } | ||
653 | } | ||
654 | } | ||
655 | else if (isLightMode) { | ||
656 | /* Darken links. */ | ||
657 | color.lum *= 0.75f; | ||
658 | color.sat = 1.0f; | ||
659 | } | ||
660 | setHsl_Color(i, color); | ||
661 | } | ||
662 | } | ||
566 | } | 663 | } |
567 | /* Special exceptions. */ { | 664 | /* Special exceptions. */ |
568 | const iRangecc host = urlHost_String(&d->url); | 665 | if (seed) { |
569 | if (equalCase_Rangecc(&host, "gemini.circumlunar.space")) { | 666 | if (equal_CStr(cstr_Block(seed), "gemini.circumlunar.space")) { |
570 | d->siteIcon = 0x264a; /* gemini */ | 667 | d->siteIcon = 0x264a; /* gemini symbol */ |
571 | } | 668 | } |
572 | } | 669 | } |
573 | } | 670 | } |
@@ -787,17 +884,54 @@ uint16_t linkImage_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | |||
787 | return 0; | 884 | return 0; |
788 | } | 885 | } |
789 | 886 | ||
790 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 887 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId, enum iGmLinkPart part) { |
791 | const iGmLink *link = link_GmDocument_(d, linkId); | 888 | const iGmLink *link = link_GmDocument_(d, linkId); |
792 | if (link) { | 889 | if (link) { |
793 | if ((link->flags & supportedProtocol_GmLinkFlag) == 0) { | 890 | const iBool isBad = (link->flags & supportedProtocol_GmLinkFlag) == 0; |
794 | return red_ColorId; | 891 | if (part == icon_GmLinkPart) { |
892 | if (isBad) { | ||
893 | return tmBadLink_ColorId; | ||
894 | } | ||
895 | if (link->flags & visited_GmLinkFlag) { | ||
896 | return link->flags & http_GmLinkFlag | ||
897 | ? tmHypertextLinkIconVisited_ColorId | ||
898 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkIconVisited_ColorId | ||
899 | : tmLinkIconVisited_ColorId; | ||
900 | } | ||
901 | return link->flags & http_GmLinkFlag | ||
902 | ? tmHypertextLinkIcon_ColorId | ||
903 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkIcon_ColorId | ||
904 | : tmLinkIcon_ColorId; | ||
905 | } | ||
906 | if (part == text_GmLinkPart) { | ||
907 | return link->flags & http_GmLinkFlag | ||
908 | ? tmHypertextLinkText_ColorId | ||
909 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkText_ColorId | ||
910 | : tmLinkText_ColorId; | ||
911 | } | ||
912 | if (part == textHover_GmLinkPart) { | ||
913 | return link->flags & http_GmLinkFlag | ||
914 | ? tmHypertextLinkTextHover_ColorId | ||
915 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkTextHover_ColorId | ||
916 | : tmLinkTextHover_ColorId; | ||
917 | } | ||
918 | if (part == domain_GmLinkPart) { | ||
919 | if (isBad) { | ||
920 | return tmBadLink_ColorId; | ||
921 | } | ||
922 | return link->flags & http_GmLinkFlag | ||
923 | ? tmHypertextLinkDomain_ColorId | ||
924 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkDomain_ColorId | ||
925 | : tmLinkDomain_ColorId; | ||
926 | } | ||
927 | if (part == visited_GmLinkPart) { | ||
928 | return link->flags & http_GmLinkFlag | ||
929 | ? tmHypertextLinkLastVisitDate_ColorId | ||
930 | : link->flags & gopher_GmLinkFlag ? tmGopherLinkLastVisitDate_ColorId | ||
931 | : tmLinkLastVisitDate_ColorId; | ||
795 | } | 932 | } |
796 | return link->flags & http_GmLinkFlag | ||
797 | ? orange_ColorId | ||
798 | : link->flags & gopher_GmLinkFlag ? blue_ColorId : cyan_ColorId; | ||
799 | } | 933 | } |
800 | return white_ColorId; | 934 | return tmLinkText_ColorId; |
801 | } | 935 | } |
802 | 936 | ||
803 | iBool isMediaLink_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 937 | iBool isMediaLink_GmDocument(const iGmDocument *d, iGmLinkId linkId) { |