summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--po/en.po15
-rw-r--r--res/lang/de.binbin23761 -> 23942 bytes
-rw-r--r--res/lang/en.binbin22362 -> 22543 bytes
-rw-r--r--res/lang/es.binbin24888 -> 25069 bytes
-rw-r--r--res/lang/fi.binbin24893 -> 25074 bytes
-rw-r--r--res/lang/fr.binbin25862 -> 26043 bytes
-rw-r--r--res/lang/ia.binbin24489 -> 24670 bytes
-rw-r--r--res/lang/ie.binbin24247 -> 24428 bytes
-rw-r--r--res/lang/pl.binbin25422 -> 25603 bytes
-rw-r--r--res/lang/ru.binbin37144 -> 37325 bytes
-rw-r--r--res/lang/sr.binbin36801 -> 36982 bytes
-rw-r--r--res/lang/tok.binbin22683 -> 22864 bytes
-rw-r--r--res/lang/zh_Hans.binbin21441 -> 21622 bytes
-rw-r--r--res/lang/zh_Hant.binbin21626 -> 21807 bytes
-rw-r--r--src/app.c16
-rw-r--r--src/defs.h7
-rw-r--r--src/gmdocument.c10
-rw-r--r--src/media.c35
-rw-r--r--src/prefs.c1
-rw-r--r--src/prefs.h1
-rw-r--r--src/ui/util.c17
21 files changed, 98 insertions, 4 deletions
diff --git a/po/en.po b/po/en.po
index 609a4bca..46514e49 100644
--- a/po/en.po
+++ b/po/en.po
@@ -1333,6 +1333,21 @@ msgstr "High Contrast"
1333msgid "prefs.saturation" 1333msgid "prefs.saturation"
1334msgstr "Saturation:" 1334msgstr "Saturation:"
1335 1335
1336msgid "prefs.imagestyle"
1337msgstr "Colorize images:"
1338
1339msgid "prefs.imagestyle.original"
1340msgstr "None"
1341
1342msgid "prefs.imagestyle.grayscale"
1343msgstr "Grayscale"
1344
1345msgid "prefs.imagestyle.text"
1346msgstr "Text Color"
1347
1348msgid "prefs.imagestyle.preformat"
1349msgstr "Preformatted Color"
1350
1336msgid "prefs.headingfont" 1351msgid "prefs.headingfont"
1337msgstr "Heading font:" 1352msgstr "Heading font:"
1338 1353
diff --git a/res/lang/de.bin b/res/lang/de.bin
index bac3d41b..5788ed84 100644
--- a/res/lang/de.bin
+++ b/res/lang/de.bin
Binary files differ
diff --git a/res/lang/en.bin b/res/lang/en.bin
index d2f19cef..536ca6a2 100644
--- a/res/lang/en.bin
+++ b/res/lang/en.bin
Binary files differ
diff --git a/res/lang/es.bin b/res/lang/es.bin
index 8462461d..14203f8e 100644
--- a/res/lang/es.bin
+++ b/res/lang/es.bin
Binary files differ
diff --git a/res/lang/fi.bin b/res/lang/fi.bin
index 2f1bb18f..875413a5 100644
--- a/res/lang/fi.bin
+++ b/res/lang/fi.bin
Binary files differ
diff --git a/res/lang/fr.bin b/res/lang/fr.bin
index 86282bc2..6976a00f 100644
--- a/res/lang/fr.bin
+++ b/res/lang/fr.bin
Binary files differ
diff --git a/res/lang/ia.bin b/res/lang/ia.bin
index 4b82125e..a77a1d61 100644
--- a/res/lang/ia.bin
+++ b/res/lang/ia.bin
Binary files differ
diff --git a/res/lang/ie.bin b/res/lang/ie.bin
index a8bce39d..33850dc5 100644
--- a/res/lang/ie.bin
+++ b/res/lang/ie.bin
Binary files differ
diff --git a/res/lang/pl.bin b/res/lang/pl.bin
index f905414b..0b4c3e10 100644
--- a/res/lang/pl.bin
+++ b/res/lang/pl.bin
Binary files differ
diff --git a/res/lang/ru.bin b/res/lang/ru.bin
index 687adc01..fbafc283 100644
--- a/res/lang/ru.bin
+++ b/res/lang/ru.bin
Binary files differ
diff --git a/res/lang/sr.bin b/res/lang/sr.bin
index df8e532b..b9ce2f5a 100644
--- a/res/lang/sr.bin
+++ b/res/lang/sr.bin
Binary files differ
diff --git a/res/lang/tok.bin b/res/lang/tok.bin
index f2b59891..f1988dff 100644
--- a/res/lang/tok.bin
+++ b/res/lang/tok.bin
Binary files differ
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin
index 49decd2d..0ef1a915 100644
--- a/res/lang/zh_Hans.bin
+++ b/res/lang/zh_Hans.bin
Binary files differ
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin
index 10a8e86c..f12f0ef2 100644
--- a/res/lang/zh_Hant.bin
+++ b/res/lang/zh_Hant.bin
Binary files differ
diff --git a/src/app.c b/src/app.c
index be96bf6c..9ff8ebc8 100644
--- a/src/app.c
+++ b/src/app.c
@@ -242,6 +242,7 @@ static iString *serializePrefs_App_(const iApp *d) {
242 appendFormat_String(str, "doctheme.dark.set arg:%d\n", d->prefs.docThemeDark); 242 appendFormat_String(str, "doctheme.dark.set arg:%d\n", d->prefs.docThemeDark);
243 appendFormat_String(str, "doctheme.light.set arg:%d\n", d->prefs.docThemeLight); 243 appendFormat_String(str, "doctheme.light.set arg:%d\n", d->prefs.docThemeLight);
244 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f)); 244 appendFormat_String(str, "saturation.set arg:%d\n", (int) ((d->prefs.saturation * 100) + 0.5f));
245 appendFormat_String(str, "imagestyle.set arg:%d\n", d->prefs.imageStyle);
245 appendFormat_String(str, "ca.file noset:1 path:%s\n", cstr_String(&d->prefs.caFile)); 246 appendFormat_String(str, "ca.file noset:1 path:%s\n", cstr_String(&d->prefs.caFile));
246 appendFormat_String(str, "ca.path path:%s\n", cstr_String(&d->prefs.caPath)); 247 appendFormat_String(str, "ca.path path:%s\n", cstr_String(&d->prefs.caPath));
247 appendFormat_String(str, "proxy.gemini address:%s\n", cstr_String(&d->prefs.geminiProxy)); 248 appendFormat_String(str, "proxy.gemini address:%s\n", cstr_String(&d->prefs.geminiProxy));
@@ -1655,6 +1656,7 @@ static void updateDropdownSelection_(iLabelWidget *dropButton, const char *selec
1655} 1656}
1656 1657
1657static void updateColorThemeButton_(iLabelWidget *button, int theme) { 1658static void updateColorThemeButton_(iLabelWidget *button, int theme) {
1659 /* TODO: These three functions are all the same? Cleanup? */
1658 if (!button) return; 1660 if (!button) return;
1659 updateDropdownSelection_(button, format_CStr(".set arg:%d", theme)); 1661 updateDropdownSelection_(button, format_CStr(".set arg:%d", theme));
1660} 1662}
@@ -1664,6 +1666,11 @@ static void updateFontButton_(iLabelWidget *button, int font) {
1664 updateDropdownSelection_(button, format_CStr(".set arg:%d", font)); 1666 updateDropdownSelection_(button, format_CStr(".set arg:%d", font));
1665} 1667}
1666 1668
1669static void updateImageStyleButton_(iLabelWidget *button, int style) {
1670 if (!button) return;
1671 updateDropdownSelection_(button, format_CStr(".set arg:%d", style));
1672}
1673
1667static iBool handlePrefsCommands_(iWidget *d, const char *cmd) { 1674static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1668 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) { 1675 if (equal_Command(cmd, "prefs.dismiss") || equal_Command(cmd, "preferences")) {
1669 setupSheetTransition_Mobile(d, iFalse); 1676 setupSheetTransition_Mobile(d, iFalse);
@@ -1745,6 +1752,10 @@ static iBool handlePrefsCommands_(iWidget *d, const char *cmd) {
1745 updateColorThemeButton_(findChild_Widget(d, "prefs.doctheme.light"), arg_Command(cmd)); 1752 updateColorThemeButton_(findChild_Widget(d, "prefs.doctheme.light"), arg_Command(cmd));
1746 return iFalse; 1753 return iFalse;
1747 } 1754 }
1755 else if (equal_Command(cmd, "imagestyle.set")) {
1756 updateImageStyleButton_(findChild_Widget(d, "prefs.imagestyle"), arg_Command(cmd));
1757 return iFalse;
1758 }
1748 else if (equal_Command(cmd, "font.set")) { 1759 else if (equal_Command(cmd, "font.set")) {
1749 updateFontButton_(findChild_Widget(d, "prefs.font"), arg_Command(cmd)); 1760 updateFontButton_(findChild_Widget(d, "prefs.font"), arg_Command(cmd));
1750 return iFalse; 1761 return iFalse;
@@ -2177,6 +2188,10 @@ iBool handleCommand_App(const char *cmd) {
2177 } 2188 }
2178 return iTrue; 2189 return iTrue;
2179 } 2190 }
2191 else if (equal_Command(cmd, "imagestyle.set")) {
2192 d->prefs.imageStyle = arg_Command(cmd);
2193 return iTrue;
2194 }
2180 else if (equal_Command(cmd, "linewidth.set")) { 2195 else if (equal_Command(cmd, "linewidth.set")) {
2181 d->prefs.lineWidth = iMax(20, arg_Command(cmd)); 2196 d->prefs.lineWidth = iMax(20, arg_Command(cmd));
2182 postCommand_App("document.layout.changed"); 2197 postCommand_App("document.layout.changed");
@@ -2611,6 +2626,7 @@ iBool handleCommand_App(const char *cmd) {
2611 setToggle_Widget(findChild_Widget(dlg, "prefs.collapsepreonload"), d->prefs.collapsePreOnLoad); 2626 setToggle_Widget(findChild_Widget(dlg, "prefs.collapsepreonload"), d->prefs.collapsePreOnLoad);
2612 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.dark"), d->prefs.docThemeDark); 2627 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.dark"), d->prefs.docThemeDark);
2613 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.light"), d->prefs.docThemeLight); 2628 updateColorThemeButton_(findChild_Widget(dlg, "prefs.doctheme.light"), d->prefs.docThemeLight);
2629 updateImageStyleButton_(findChild_Widget(dlg, "prefs.imagestyle"), d->prefs.imageStyle);
2614 updateFontButton_(findChild_Widget(dlg, "prefs.font"), d->prefs.font); 2630 updateFontButton_(findChild_Widget(dlg, "prefs.font"), d->prefs.font);
2615 updateFontButton_(findChild_Widget(dlg, "prefs.headingfont"), d->prefs.headingFont); 2631 updateFontButton_(findChild_Widget(dlg, "prefs.headingfont"), d->prefs.headingFont);
2616 setFlags_Widget( 2632 setFlags_Widget(
diff --git a/src/defs.h b/src/defs.h
index cf04514e..135cc053 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -41,6 +41,13 @@ enum iFileVersion {
41 latest_FileVersion = 4, 41 latest_FileVersion = 4,
42}; 42};
43 43
44enum iImageStyle {
45 original_ImageStyle = 0,
46 grayscale_ImageStyle = 1,
47 textColorized_ImageStyle = 2,
48 preformatColorized_ImageStyle = 3,
49};
50
44enum iScrollType { 51enum iScrollType {
45 keyboard_ScrollType, 52 keyboard_ScrollType,
46 mouse_ScrollType, 53 mouse_ScrollType,
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 75f6f06b..4e92c89c 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -464,6 +464,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
464 const iBool isNarrow = d->size.x < 90 * gap_Text; 464 const iBool isNarrow = d->size.x < 90 * gap_Text;
465 const iBool isVeryNarrow = d->size.x <= 70 * gap_Text; 465 const iBool isVeryNarrow = d->size.x <= 70 * gap_Text;
466 const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text; 466 const iBool isExtremelyNarrow = d->size.x <= 60 * gap_Text;
467 const iBool isFullWidthImages = (d->outsideMargin < 5 * gap_UI);
467 const iBool isDarkBg = isDark_GmDocumentTheme( 468 const iBool isDarkBg = isDark_GmDocumentTheme(
468 isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight); 469 isDark_ColorTheme(colorTheme_App()) ? prefs->docThemeDark : prefs->docThemeLight);
469 /* TODO: Collect these parameters into a GmTheme. */ 470 /* TODO: Collect these parameters into a GmTheme. */
@@ -817,7 +818,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
817 rts.layoutWidth = d->size.x; 818 rts.layoutWidth = d->size.x;
818 rts.indent = indent * gap_Text; 819 rts.indent = indent * gap_Text;
819 /* The right margin is used for balancing lines horizontally. */ 820 /* The right margin is used for balancing lines horizontally. */
820 if (isVeryNarrow) { 821 if (isVeryNarrow || isFullWidthImages) {
821 rts.rightMargin = 0; 822 rts.rightMargin = 0;
822 } 823 }
823 else { 824 else {
@@ -900,14 +901,15 @@ static void doLayout_GmDocument_(iGmDocument *d) {
900 pos.y += margin; 901 pos.y += margin;
901 run.bounds.pos = pos; 902 run.bounds.pos = pos;
902 run.bounds.size.x = d->size.x; 903 run.bounds.size.x = d->size.x;
904 const float aspect = (float) imgSize.y / (float) imgSize.x;
905 run.bounds.size.y = d->size.x * aspect;
903 /* Extend the image to full width, including outside margin, if the viewport 906 /* Extend the image to full width, including outside margin, if the viewport
904 is narrow enough. */ 907 is narrow enough. */
905 if (d->outsideMargin < 5 * gap_UI) { 908 if (isFullWidthImages) {
906 run.bounds.size.x += d->outsideMargin * 2; 909 run.bounds.size.x += d->outsideMargin * 2;
910 run.bounds.size.y += d->outsideMargin * 2 * aspect;
907 run.bounds.pos.x -= d->outsideMargin; 911 run.bounds.pos.x -= d->outsideMargin;
908 } 912 }
909 const float aspect = (float) imgSize.y / (float) imgSize.x;
910 run.bounds.size.y = d->size.x * aspect;
911 run.visBounds = run.bounds; 913 run.visBounds = run.bounds;
912 const iInt2 maxSize = mulf_I2(imgSize, get_Window()->pixelRatio); 914 const iInt2 maxSize = mulf_I2(imgSize, get_Window()->pixelRatio);
913 if (width_Rect(run.visBounds) > maxSize.x) { 915 if (width_Rect(run.visBounds) > maxSize.x) {
diff --git a/src/media.c b/src/media.c
index 5240ab5d..e47c5278 100644
--- a/src/media.c
+++ b/src/media.c
@@ -87,6 +87,40 @@ void deinit_GmImage(iGmImage *d) {
87 deinit_GmMediaProps_(&d->props); 87 deinit_GmMediaProps_(&d->props);
88} 88}
89 89
90static void applyImageStyle_(enum iImageStyle style, iInt2 size, uint8_t *imgData) {
91 if (style == original_ImageStyle) {
92 return;
93 }
94 iColor colorize = (iColor){ 255, 255, 255, 255};
95 float brighten = 0.0f;
96 if (style != grayscale_ImageStyle) {
97 colorize = get_Color(style == textColorized_ImageStyle ? tmParagraph_ColorId
98 : tmPreformatted_ColorId);
99 /* Maximize contrast. */
100 const int colMax = iMax(iMax(colorize.r, colorize.g), colorize.b);
101 if (colMax >= 8) {
102 colorize.r = colorize.r * 255 / colMax;
103 colorize.g = colorize.g * 255 / colMax;
104 colorize.b = colorize.b * 255 / colMax;
105 }
106 else {
107 colorize = (iColor){ 255, 255, 255, 255};
108 }
109// printf("colorize:%d %d %d\n", colorize.r, colorize.g, colorize.b);
110// brighten = iClamp(1.0f - (colorize.r + colorize.g + colorize.b) / 600.0f, 0.0f, 0.5f); /* compensate loss of light */
111// printf("bright:%f\n", brighten);
112 }
113 uint8_t *pos = imgData;
114 size_t numPixels = size.x * size.y;
115 while (numPixels-- > 0) {
116 iHSLColor hsl = hsl_Color((iColor){ pos[0], pos[1], pos[2], 255 });
117 pos[0] = powf((colorize.r * hsl.lum) / 255.0f, 1.0f - brighten) * 255;
118 pos[1] = powf((colorize.g * hsl.lum) / 255.0f, 1.0f - brighten) * 255;
119 pos[2] = powf((colorize.b * hsl.lum) / 255.0f, 1.0f - brighten) * 255;
120 pos += 4;
121 }
122}
123
90void makeTexture_GmImage(iGmImage *d) { 124void makeTexture_GmImage(iGmImage *d) {
91 iBlock *data = &d->partialData; 125 iBlock *data = &d->partialData;
92 d->numBytes = size_Block(data); 126 d->numBytes = size_Block(data);
@@ -105,6 +139,7 @@ void makeTexture_GmImage(iGmImage *d) {
105 d->texture = NULL; 139 d->texture = NULL;
106 } 140 }
107 else { 141 else {
142 applyImageStyle_(prefs_App()->imageStyle, d->size, imgData);
108 /* TODO: Save some memory by checking if the alpha channel is actually in use. */ 143 /* TODO: Save some memory by checking if the alpha channel is actually in use. */
109 iWindow *window = get_Window(); 144 iWindow *window = get_Window();
110 iInt2 texSize = d->size; 145 iInt2 texSize = d->size;
diff --git a/src/prefs.c b/src/prefs.c
index 13a95a3d..749accf8 100644
--- a/src/prefs.c
+++ b/src/prefs.c
@@ -62,6 +62,7 @@ void init_Prefs(iPrefs *d) {
62 d->quoteIcon = iTrue; 62 d->quoteIcon = iTrue;
63 d->centerShortDocs = iTrue; 63 d->centerShortDocs = iTrue;
64 d->plainTextWrap = iTrue; 64 d->plainTextWrap = iTrue;
65 d->imageStyle = original_ImageStyle;
65 d->docThemeDark = colorfulDark_GmDocumentTheme; 66 d->docThemeDark = colorfulDark_GmDocumentTheme;
66 d->docThemeLight = white_GmDocumentTheme; 67 d->docThemeLight = white_GmDocumentTheme;
67 d->saturation = 1.0f; 68 d->saturation = 1.0f;
diff --git a/src/prefs.h b/src/prefs.h
index 58c73bf7..21960646 100644
--- a/src/prefs.h
+++ b/src/prefs.h
@@ -86,6 +86,7 @@ struct Impl_Prefs {
86 iBool quoteIcon; 86 iBool quoteIcon;
87 iBool centerShortDocs; 87 iBool centerShortDocs;
88 iBool plainTextWrap; 88 iBool plainTextWrap;
89 enum iImageStyle imageStyle;
89 /* Colors */ 90 /* Colors */
90 enum iGmDocumentTheme docThemeDark; 91 enum iGmDocumentTheme docThemeDark;
91 enum iGmDocumentTheme docThemeLight; 92 enum iGmDocumentTheme docThemeLight;
diff --git a/src/ui/util.c b/src/ui/util.c
index b6ecc7d5..8a42f75b 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -1831,6 +1831,23 @@ iWidget *makePreferences_Widget(void) {
1831 addRadioButton_(sats, "prefs.saturation.0", "0 %", "saturation.set arg:0"); 1831 addRadioButton_(sats, "prefs.saturation.0", "0 %", "saturation.set arg:0");
1832 } 1832 }
1833 addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); 1833 addChildFlags_Widget(values, iClob(sats), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag);
1834 /* Colorize images. */ {
1835 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.imagestyle}")));
1836 const iMenuItem imgStyles[] = {
1837 { "${prefs.imagestyle.original}", 0, 0, format_CStr("imagestyle.set arg:%d", original_ImageStyle) },
1838 { "${prefs.imagestyle.grayscale}", 0, 0, format_CStr("imagestyle.set arg:%d", grayscale_ImageStyle) },
1839 { "${prefs.imagestyle.text}", 0, 0, format_CStr("imagestyle.set arg:%d", textColorized_ImageStyle) },
1840 { "${prefs.imagestyle.preformat}", 0, 0, format_CStr("imagestyle.set arg:%d", preformatColorized_ImageStyle) },
1841 };
1842 iLabelWidget *button = makeMenuButton_LabelWidget(
1843 imgStyles[findWidestItemLabel_(imgStyles, iElemCount(imgStyles))].label,
1844 imgStyles,
1845 iElemCount(imgStyles));
1846 setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"),
1847 uiBackgroundMenu_ColorId);
1848 setId_Widget(addChildFlags_Widget(values, iClob(button), alignLeft_WidgetFlag),
1849 "prefs.imagestyle");
1850 }
1834 } 1851 }
1835 /* Fonts. */ { 1852 /* Fonts. */ {
1836 setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts"); 1853 setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts");