summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/app.c34
-rw-r--r--src/gmdocument.c171
-rw-r--r--src/gmdocument.h10
-rw-r--r--src/ui/util.c25
4 files changed, 176 insertions, 64 deletions
diff --git a/src/app.c b/src/app.c
index ac970865..cf9ef425 100644
--- a/src/app.c
+++ b/src/app.c
@@ -184,6 +184,8 @@ static iString *serializePrefs_App_(const iApp *d) {
184 appendFormat_String(str, "prefs.hoveroutline.changed arg:%d\n", d->prefs.hoverOutline); 184 appendFormat_String(str, "prefs.hoveroutline.changed arg:%d\n", d->prefs.hoverOutline);
185 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme); 185 appendFormat_String(str, "theme.set arg:%d auto:1\n", d->prefs.theme);
186 appendFormat_String(str, "ostheme arg:%d\n", d->prefs.useSystemTheme); 186 appendFormat_String(str, "ostheme arg:%d\n", d->prefs.useSystemTheme);
187 appendFormat_String(str, "doctheme.dark.set arg:%d\n", d->prefs.docThemeDark);
188 appendFormat_String(str, "doctheme.light.set arg:%d\n", d->prefs.docThemeLight);
187 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f)); 189 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f));
188 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.gopherProxy)); 190 appendFormat_String(str, "proxy.gopher address:%s\n", cstr_String(&d->prefs.gopherProxy));
189 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy)); 191 appendFormat_String(str, "proxy.http address:%s\n", cstr_String(&d->prefs.httpProxy));
@@ -700,6 +702,18 @@ static void updatePrefsThemeButtons_(iWidget *d) {
700 } 702 }
701} 703}
702 704
705static void updateColorThemeButton_(iLabelWidget *button, int theme) {
706 const char *mode = strstr(cstr_String(id_Widget(as_Widget(button))), ".dark") ? "dark" : "light";
707 const char *command = format_CStr("doctheme.%s.set arg:%d", mode, theme);
708 iForEach(ObjectList, i, children_Widget(findChild_Widget(as_Widget(button), "menu"))) {
709 iLabelWidget *item = i.object;
710 if (!cmp_String(command_LabelWidget(item), command)) {
711 updateText_LabelWidget(button, label_LabelWidget(item));
712 break;
713 }
714 }
715}
716
703static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { 717static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
704 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) { 718 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) {
705 setUiScale_Window(get_Window(), 719 setUiScale_Window(get_Window(),
@@ -720,6 +734,14 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
720 destroy_Widget(d); 734 destroy_Widget(d);
721 return iTrue; 735 return iTrue;
722 } 736 }
737 else if (equal_Command(cmd, "doctheme.dark.set")) {
738 updateColorThemeButton_(findChild_Widget(d, "prefs.doctheme.dark"), arg_Command(cmd));
739 return iFalse;
740 }
741 else if (equal_Command(cmd, "doctheme.light.set")) {
742 updateColorThemeButton_(findChild_Widget(d, "prefs.doctheme.light"), arg_Command(cmd));
743 return iFalse;
744 }
723 else if (equal_Command(cmd, "prefs.ostheme.changed")) { 745 else if (equal_Command(cmd, "prefs.ostheme.changed")) {
724 postCommandf_App("ostheme arg:%d", arg_Command(cmd)); 746 postCommandf_App("ostheme arg:%d", arg_Command(cmd));
725 } 747 }
@@ -908,6 +930,16 @@ iBool handleCommand_App(const char *cmd) {
908 d->prefs.useSystemTheme = arg_Command(cmd); 930 d->prefs.useSystemTheme = arg_Command(cmd);
909 return iTrue; 931 return iTrue;
910 } 932 }
933 else if (equal_Command(cmd, "doctheme.dark.set")) {
934 d->prefs.docThemeDark = arg_Command(cmd);
935 postCommand_App("theme.changed auto:1");
936 return iTrue;
937 }
938 else if (equal_Command(cmd, "doctheme.light.set")) {
939 d->prefs.docThemeLight = arg_Command(cmd);
940 postCommand_App("theme.changed auto:1");
941 return iTrue;
942 }
911 else if (equal_Command(cmd, "linewidth.set")) { 943 else if (equal_Command(cmd, "linewidth.set")) {
912 d->prefs.lineWidth = iMax(20, arg_Command(cmd)); 944 d->prefs.lineWidth = iMax(20, arg_Command(cmd));
913 postCommand_App("document.layout.changed"); 945 postCommand_App("document.layout.changed");
@@ -1060,6 +1092,8 @@ iBool handleCommand_App(const char *cmd) {
1060 iTrue); 1092 iTrue);
1061 setToggle_Widget(findChild_Widget(dlg, "prefs.biglede"), d->prefs.bigFirstParagraph); 1093 setToggle_Widget(findChild_Widget(dlg, "prefs.biglede"), d->prefs.bigFirstParagraph);
1062 setToggle_Widget(findChild_Widget(dlg, "prefs.sideicon"), d->prefs.sideIcon); 1094 setToggle_Widget(findChild_Widget(dlg, "prefs.sideicon"), d->prefs.sideIcon);
1095 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.dark"), d->prefs.docThemeDark);
1096 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.light"), d->prefs.docThemeLight);
1063 setFlags_Widget( 1097 setFlags_Widget(
1064 findChild_Widget( 1098 findChild_Widget(
1065 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))), 1099 dlg, format_CStr("prefs.saturation.%d", (int) (d->prefs.saturation * 3.99f))),
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 4240b960..389cbfb2 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -631,12 +631,20 @@ void reset_GmDocument(iGmDocument *d) {
631 d->themeSeed = 0; 631 d->themeSeed = 0;
632} 632}
633 633
634static float dimLightness_(float hue, float baseOffset) {
635 const float blueDiff = iWrapf(hue - 245, -180, 180);
636 float extra = 0.0f;
637 const float maxDiff = 60;
638 if (iAbs(blueDiff) < maxDiff) {
639 extra = 0.2f * (1.0f - iAbs(blueDiff) / maxDiff);
640 }
641 return baseOffset + extra;
642}
643
634void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { 644void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
635 const iPrefs * prefs = prefs_App(); 645 const iPrefs * prefs = prefs_App();
636 enum iGmDocumentTheme theme = 646 enum iGmDocumentTheme theme =
637 (isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight); 647 (isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight);
638// const iBool isLightMode = isLight_ColorTheme(colorTheme_App());
639// const iBool isDarkMode = !isLightMode;
640 static const iChar siteIcons[] = { 648 static const iChar siteIcons[] = {
641 0x203b, 0x2042, 0x205c, 0x2182, 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606, 649 0x203b, 0x2042, 0x205c, 0x2182, 0x25ed, 0x2600, 0x2601, 0x2604, 0x2605, 0x2606,
642 0x265c, 0x265e, 0x2690, 0x2691, 0x2693, 0x2698, 0x2699, 0x26f0, 0x270e, 0x2728, 650 0x265c, 0x265e, 0x2690, 0x2691, 0x2693, 0x2698, 0x2699, 0x26f0, 0x270e, 0x2728,
@@ -645,20 +653,10 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
645 0x1f306, 0x1f308, 0x1f30a, 0x1f319, 0x1f31f, 0x1f320, 0x1f340, 0x1f4cd, 0x1f4e1, 0x1f531, 653 0x1f306, 0x1f308, 0x1f30a, 0x1f319, 0x1f31f, 0x1f320, 0x1f340, 0x1f4cd, 0x1f4e1, 0x1f531,
646 0x1f533, 0x1f657, 0x1f659, 0x1f665, 0x1f668, 0x1f66b, 0x1f78b, 0x1f796, 0x1f79c, 654 0x1f533, 0x1f657, 0x1f659, 0x1f665, 0x1f668, 0x1f66b, 0x1f78b, 0x1f796, 0x1f79c,
647 }; 655 };
648 /* Default colors. */ { 656 /* Default colors. These are used on "about:" pages and local files, for example. */ {
649 if (theme == colorfulDark_GmDocumentTheme) { 657 /* Link colors are generally the same in all themes. */
650 const iHSLColor base = { 200, 0, 0.15f, 1.0f }; 658 set_Color(tmBadLink_ColorId, get_Color(red_ColorId));
651 setHsl_Color(tmBackground_ColorId, base); 659 if (isDark_GmDocumentTheme(theme)) {
652 set_Color(tmParagraph_ColorId, get_Color(gray75_ColorId));
653 setHsl_Color(tmFirstParagraph_ColorId, addSatLum_HSLColor(base, 0, 0.75f));
654 set_Color(tmQuote_ColorId, get_Color(cyan_ColorId));
655 set_Color(tmPreformatted_ColorId, get_Color(cyan_ColorId));
656 set_Color(tmHeading1_ColorId, get_Color(white_ColorId));
657 setHsl_Color(tmHeading2_ColorId, addSatLum_HSLColor(base, 0.5f, 0.5f));
658 setHsl_Color(tmHeading3_ColorId, addSatLum_HSLColor(base, 1.0f, 0.4f));
659 set_Color(tmBannerBackground_ColorId, get_Color(black_ColorId));
660 set_Color(tmBannerTitle_ColorId, get_Color(white_ColorId));
661 set_Color(tmBannerIcon_ColorId, get_Color(orange_ColorId));
662 set_Color(tmInlineContentMetadata_ColorId, get_Color(cyan_ColorId)); 660 set_Color(tmInlineContentMetadata_ColorId, get_Color(cyan_ColorId));
663 set_Color(tmLinkText_ColorId, get_Color(white_ColorId)); 661 set_Color(tmLinkText_ColorId, get_Color(white_ColorId));
664 set_Color(tmLinkIcon_ColorId, get_Color(cyan_ColorId)); 662 set_Color(tmLinkIcon_ColorId, get_Color(cyan_ColorId));
@@ -680,18 +678,6 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
680 set_Color(tmGopherLinkLastVisitDate_ColorId, get_Color(blue_ColorId)); 678 set_Color(tmGopherLinkLastVisitDate_ColorId, get_Color(blue_ColorId));
681 } 679 }
682 else { 680 else {
683 const iHSLColor base = { 40, 0, 1.0f, 1.0f };
684 setHsl_Color(tmBackground_ColorId, base);
685 set_Color(tmParagraph_ColorId, get_Color(gray25_ColorId));
686 set_Color(tmFirstParagraph_ColorId, get_Color(black_ColorId));
687 set_Color(tmQuote_ColorId, get_Color(brown_ColorId));
688 set_Color(tmPreformatted_ColorId, get_Color(brown_ColorId));
689 set_Color(tmHeading1_ColorId, get_Color(black_ColorId));
690 setHsl_Color(tmHeading2_ColorId, addSatLum_HSLColor(base, 0.15f, -0.7f));
691 setHsl_Color(tmHeading3_ColorId, addSatLum_HSLColor(base, 0.3f, -0.6f));
692 set_Color(tmBannerBackground_ColorId, get_Color(white_ColorId));
693 set_Color(tmBannerTitle_ColorId, get_Color(gray50_ColorId));
694 set_Color(tmBannerIcon_ColorId, get_Color(teal_ColorId));
695 set_Color(tmInlineContentMetadata_ColorId, get_Color(brown_ColorId)); 681 set_Color(tmInlineContentMetadata_ColorId, get_Color(brown_ColorId));
696 set_Color(tmLinkText_ColorId, get_Color(black_ColorId)); 682 set_Color(tmLinkText_ColorId, get_Color(black_ColorId));
697 set_Color(tmLinkIcon_ColorId, get_Color(teal_ColorId)); 683 set_Color(tmLinkIcon_ColorId, get_Color(teal_ColorId));
@@ -712,7 +698,88 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
712 set_Color(tmGopherLinkDomain_ColorId, get_Color(magenta_ColorId)); 698 set_Color(tmGopherLinkDomain_ColorId, get_Color(magenta_ColorId));
713 set_Color(tmGopherLinkLastVisitDate_ColorId, get_Color(blue_ColorId)); 699 set_Color(tmGopherLinkLastVisitDate_ColorId, get_Color(blue_ColorId));
714 } 700 }
715 set_Color(tmBadLink_ColorId, get_Color(red_ColorId)); 701 /* Set the non-link colors. */
702 if (theme == colorfulDark_GmDocumentTheme) {
703 const iHSLColor base = { 200, 0, 0.15f, 1.0f };
704 setHsl_Color(tmBackground_ColorId, base);
705 set_Color(tmParagraph_ColorId, get_Color(gray75_ColorId));
706 setHsl_Color(tmFirstParagraph_ColorId, addSatLum_HSLColor(base, 0, 0.75f));
707 set_Color(tmQuote_ColorId, get_Color(cyan_ColorId));
708 set_Color(tmPreformatted_ColorId, get_Color(cyan_ColorId));
709 set_Color(tmHeading1_ColorId, get_Color(white_ColorId));
710 setHsl_Color(tmHeading2_ColorId, addSatLum_HSLColor(base, 0.5f, 0.5f));
711 setHsl_Color(tmHeading3_ColorId, addSatLum_HSLColor(base, 1.0f, 0.4f));
712 set_Color(tmBannerBackground_ColorId, get_Color(black_ColorId));
713 set_Color(tmBannerTitle_ColorId, get_Color(white_ColorId));
714 set_Color(tmBannerIcon_ColorId, get_Color(orange_ColorId));
715 }
716 else if (theme == black_GmDocumentTheme) {
717 set_Color(tmBackground_ColorId, get_Color(black_ColorId));
718 set_Color(tmParagraph_ColorId, get_Color(gray75_ColorId));
719 set_Color(tmFirstParagraph_ColorId, mix_Color(get_Color(gray75_ColorId), get_Color(white_ColorId), 0.5f));
720 set_Color(tmQuote_ColorId, get_Color(orange_ColorId));
721 set_Color(tmPreformatted_ColorId, get_Color(orange_ColorId));
722 set_Color(tmHeading1_ColorId, get_Color(cyan_ColorId));
723 set_Color(tmHeading2_ColorId, mix_Color(get_Color(cyan_ColorId), get_Color(white_ColorId), 0.66f));
724 set_Color(tmHeading3_ColorId, get_Color(white_ColorId));
725 set_Color(tmBannerBackground_ColorId, get_Color(black_ColorId));
726 set_Color(tmBannerTitle_ColorId, get_Color(teal_ColorId));
727 set_Color(tmBannerIcon_ColorId, get_Color(teal_ColorId));
728 }
729 else if (theme == gray_GmDocumentTheme) {
730 set_Color(tmBackground_ColorId, mix_Color(get_Color(gray25_ColorId), get_Color(black_ColorId), 0.25f));
731 set_Color(tmParagraph_ColorId, mix_Color(get_Color(gray75_ColorId), get_Color(white_ColorId), 0.0f));
732 set_Color(tmFirstParagraph_ColorId, mix_Color(get_Color(gray75_ColorId), get_Color(white_ColorId), 0.5f));
733 set_Color(tmQuote_ColorId, get_Color(orange_ColorId));
734 set_Color(tmPreformatted_ColorId, get_Color(orange_ColorId));
735 set_Color(tmHeading1_ColorId, get_Color(cyan_ColorId));
736 set_Color(tmHeading2_ColorId, mix_Color(get_Color(cyan_ColorId), get_Color(white_ColorId), 0.66f));
737 set_Color(tmHeading3_ColorId, get_Color(white_ColorId));
738 set_Color(tmBannerBackground_ColorId, mix_Color(get_Color(gray25_ColorId), get_Color(black_ColorId), 0.5f));
739 set_Color(tmBannerTitle_ColorId, get_Color(teal_ColorId));
740 set_Color(tmBannerIcon_ColorId, get_Color(teal_ColorId));
741 }
742 else if (theme == sepia_GmDocumentTheme) {
743 const iHSLColor base = { 40, 0.6f, 0.9f, 1.0f };
744 setHsl_Color(tmBackground_ColorId, base);
745 set_Color(tmParagraph_ColorId, get_Color(black_ColorId));
746 set_Color(tmFirstParagraph_ColorId, get_Color(black_ColorId));
747 set_Color(tmQuote_ColorId, get_Color(brown_ColorId));
748 set_Color(tmPreformatted_ColorId, get_Color(brown_ColorId));
749 set_Color(tmHeading1_ColorId, get_Color(brown_ColorId));
750 set_Color(tmHeading2_ColorId, mix_Color(get_Color(brown_ColorId), get_Color(black_ColorId), 0.5f));
751 set_Color(tmHeading3_ColorId, get_Color(black_ColorId));
752 set_Color(tmBannerBackground_ColorId, mix_Color(get_Color(tmBackground_ColorId), get_Color(brown_ColorId), 0.15f));
753 set_Color(tmBannerTitle_ColorId, get_Color(brown_ColorId));
754 set_Color(tmBannerIcon_ColorId, get_Color(brown_ColorId));
755 }
756 else if (theme == white_GmDocumentTheme) {
757 const iHSLColor base = { 40, 0, 1.0f, 1.0f };
758 setHsl_Color(tmBackground_ColorId, base);
759 set_Color(tmParagraph_ColorId, get_Color(gray25_ColorId));
760 set_Color(tmFirstParagraph_ColorId, get_Color(black_ColorId));
761 set_Color(tmQuote_ColorId, get_Color(brown_ColorId));
762 set_Color(tmPreformatted_ColorId, get_Color(brown_ColorId));
763 set_Color(tmHeading1_ColorId, get_Color(black_ColorId));
764 setHsl_Color(tmHeading2_ColorId, addSatLum_HSLColor(base, 0.15f, -0.7f));
765 setHsl_Color(tmHeading3_ColorId, addSatLum_HSLColor(base, 0.3f, -0.6f));
766 set_Color(tmBannerBackground_ColorId, get_Color(white_ColorId));
767 set_Color(tmBannerTitle_ColorId, get_Color(gray50_ColorId));
768 set_Color(tmBannerIcon_ColorId, get_Color(teal_ColorId));
769 }
770 else if (theme == highContrast_GmDocumentTheme) {
771 set_Color(tmBackground_ColorId, get_Color(white_ColorId));
772 set_Color(tmParagraph_ColorId, get_Color(black_ColorId));
773 set_Color(tmFirstParagraph_ColorId, get_Color(black_ColorId));
774 set_Color(tmQuote_ColorId, get_Color(black_ColorId));
775 set_Color(tmPreformatted_ColorId, get_Color(black_ColorId));
776 set_Color(tmHeading1_ColorId, get_Color(black_ColorId));
777 set_Color(tmHeading2_ColorId, get_Color(black_ColorId));
778 set_Color(tmHeading3_ColorId, get_Color(black_ColorId));
779 set_Color(tmBannerBackground_ColorId, mix_Color(get_Color(gray75_ColorId), get_Color(white_ColorId), 0.75f));
780 set_Color(tmBannerTitle_ColorId, get_Color(black_ColorId));
781 set_Color(tmBannerIcon_ColorId, get_Color(black_ColorId));
782 }
716 /* Apply the saturation setting. */ 783 /* Apply the saturation setting. */
717 for (int i = tmFirst_ColorId; i < max_ColorId; i++) { 784 for (int i = tmFirst_ColorId; i < max_ColorId; i++) {
718 if (!isLink_ColorId(i)) { 785 if (!isLink_ColorId(i)) {
@@ -819,7 +886,7 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
819 set_Color(tmQuote_ColorId, get_Color(tmPreformatted_ColorId)); 886 set_Color(tmQuote_ColorId, get_Color(tmPreformatted_ColorId));
820 set_Color(tmInlineContentMetadata_ColorId, get_Color(tmHeading3_ColorId)); 887 set_Color(tmInlineContentMetadata_ColorId, get_Color(tmHeading3_ColorId));
821 } 888 }
822 else { 889 else if (theme == white_GmDocumentTheme) {
823 iHSLColor base = { hues[primIndex], 1.0f, 0.3f, 1.0f }; 890 iHSLColor base = { hues[primIndex], 1.0f, 0.3f, 1.0f };
824 iHSLColor altBase = { altHue, base.sat, base.lum - 0.1f, 1 }; 891 iHSLColor altBase = { altHue, base.sat, base.lum - 0.1f, 1 };
825 892
@@ -838,39 +905,23 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) {
838 set_Color(tmQuote_ColorId, get_Color(tmPreformatted_ColorId)); 905 set_Color(tmQuote_ColorId, get_Color(tmPreformatted_ColorId));
839 set_Color(tmInlineContentMetadata_ColorId, get_Color(tmHeading3_ColorId)); 906 set_Color(tmInlineContentMetadata_ColorId, get_Color(tmHeading3_ColorId));
840 } 907 }
908 else if (theme == black_GmDocumentTheme || theme == gray_GmDocumentTheme) {
909 const float primHue = hues[primIndex];
910 const iHSLColor primBright = { primHue, 1, 0.6f, 1 };
911 const iHSLColor primDim = { primHue, 1, dimLightness_(primHue, theme == black_GmDocumentTheme ? 0.25f : 0.45f), 1};
912 const iHSLColor altBright = { altHue, 1, 0.6f, 1 };
913 setHsl_Color(tmQuote_ColorId, altBright);
914 setHsl_Color(tmPreformatted_ColorId, altBright);
915 setHsl_Color(tmHeading1_ColorId, primBright);
916 set_Color(tmHeading2_ColorId, mix_Color(get_Color(tmHeading1_ColorId), get_Color(white_ColorId), 0.66f));
917 setHsl_Color(tmBannerTitle_ColorId, primDim);
918 setHsl_Color(tmBannerIcon_ColorId, primDim);
919 }
841 920
842 /* Adjust colors based on light/dark mode. */ 921 /* Adjust colors based on light/dark mode. */
843 for (int i = tmFirst_ColorId; i < max_ColorId; i++) { 922 for (int i = tmFirst_ColorId; i < max_ColorId; i++) {
844 iHSLColor color = hsl_Color(get_Color(i)); 923 iHSLColor color = hsl_Color(get_Color(i));
845 if (theme == white_GmDocumentTheme) { 924 if (theme == colorfulDark_GmDocumentTheme) { /* dark mode */
846#if 0
847 if (isLink_ColorId(i)) continue;
848 color.lum = 1.0f - color.lum; /* All colors invert lightness. */
849 if (isRegularText_ColorId(i)) {
850 /* Darken paragraphs and default state link text. */
851 color.lum *= 0.5f;
852 }
853 else if (i == tmBackground_ColorId) {
854 color.sat = (color.sat + 1) / 2;
855 color.lum += 0.06f;
856 }
857 else if (i == tmHeading3_ColorId) {
858 color.lum *= 0.75f;
859 }
860 else if (i == tmBannerIcon_ColorId || i == tmBannerTitle_ColorId) {
861 color.sat = 1.0f;
862 color.lum = 0.35f;
863 }
864 else if (i == tmBannerBackground_ColorId) {
865 color = hsl_Color(get_Color(tmBackground_ColorId));
866 }
867 else if (isText_ColorId(i)) {
868 color.sat = 0.9f;
869 color.lum = (9 * color.lum + 0.5f) / 10;
870 }
871#endif
872 }
873 else { /* dark mode */
874 if (!isLink_ColorId(i)) { 925 if (!isLink_ColorId(i)) {
875 if (isDarkBgSat) { 926 if (isDarkBgSat) {
876 /* Saturate background, desaturate text. */ 927 /* Saturate background, desaturate text. */
diff --git a/src/gmdocument.h b/src/gmdocument.h
index 19a6036f..05bf026c 100644
--- a/src/gmdocument.h
+++ b/src/gmdocument.h
@@ -36,9 +36,19 @@ iDeclareType(GmRun)
36 36
37enum iGmDocumentTheme { 37enum iGmDocumentTheme {
38 colorfulDark_GmDocumentTheme, 38 colorfulDark_GmDocumentTheme,
39 colorfulLight_GmDocumentTheme,
40 black_GmDocumentTheme,
41 gray_GmDocumentTheme,
39 white_GmDocumentTheme, 42 white_GmDocumentTheme,
43 sepia_GmDocumentTheme,
44 highContrast_GmDocumentTheme,
40}; 45};
41 46
47iLocalDef iBool isDark_GmDocumentTheme(enum iGmDocumentTheme d) {
48 return d == colorfulDark_GmDocumentTheme || d == black_GmDocumentTheme ||
49 d == gray_GmDocumentTheme;
50}
51
42typedef uint16_t iGmLinkId; 52typedef uint16_t iGmLinkId;
43 53
44enum iGmLinkFlags { 54enum iGmLinkFlags {
diff --git a/src/ui/util.c b/src/ui/util.c
index c99df1fd..5762f8d1 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -965,10 +965,27 @@ iWidget *makePreferences_Widget(void) {
965 } 965 }
966 /* Colors. */ { 966 /* Colors. */ {
967 appendTwoColumnPage_(tabs, "Colors", '3', &headings, &values); 967 appendTwoColumnPage_(tabs, "Colors", '3', &headings, &values);
968 addChild_Widget(headings, iClob(makeHeading_Widget("Dark theme:"))); 968 for (int i = 0; i < 2; ++i) {
969 addChild_Widget(values, iClob(new_LabelWidget("Colorful", 0, 0, 0))); 969 const iBool isDark = (i == 0);
970 addChild_Widget(headings, iClob(makeHeading_Widget("Light theme:"))); 970 const char *mode = isDark ? "dark" : "light";
971 addChild_Widget(values, iClob(new_LabelWidget("White", 0, 0, 0))); 971 const iMenuItem themes[] = {
972 { "Colorful Dark", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulDark_GmDocumentTheme) },
973 { "Colorful Light", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, colorfulLight_GmDocumentTheme) },
974 { "Black", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, black_GmDocumentTheme) },
975 { "Gray", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, gray_GmDocumentTheme) },
976 { "Sepia", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, sepia_GmDocumentTheme) },
977 { "White", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, white_GmDocumentTheme) },
978 { "High Contrast", 0, 0, format_CStr("doctheme.%s.set arg:%d", mode, highContrast_GmDocumentTheme) },
979 };
980 addChild_Widget(headings, iClob(makeHeading_Widget(isDark ? "Dark theme:" : "Light theme:")));
981 setId_Widget(addChild_Widget(values,
982 iClob(makeMenuButton_LabelWidget(
983 themes[0].label, themes, iElemCount(themes)))),
984 format_CStr("prefs.doctheme.%s", mode));
985 }
986 //addChild_Widget(values, iClob(new_LabelWidget("Colorful", 0, 0, 0)));
987// addChild_Widget(headings, iClob(makeHeading_Widget("Light theme:")));
988// addChild_Widget(values, iClob(new_LabelWidget("White", 0, 0, 0)));
972 addChild_Widget(headings, iClob(makeHeading_Widget("Saturation:"))); 989 addChild_Widget(headings, iClob(makeHeading_Widget("Saturation:")));
973 iWidget *sats = new_Widget(); 990 iWidget *sats = new_Widget();
974 /* Saturation levels. */ { 991 /* Saturation levels. */ {