summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/banner.c3
-rw-r--r--src/ui/documentwidget.c39
-rw-r--r--src/ui/linkinfo.c4
-rw-r--r--src/ui/sidebarwidget.c54
-rw-r--r--src/ui/text.c40
-rw-r--r--src/ui/text.h2
-rw-r--r--src/ui/util.c111
-rw-r--r--src/ui/util.h14
8 files changed, 207 insertions, 60 deletions
diff --git a/src/ui/banner.c b/src/ui/banner.c
index 11ae1574..79d70039 100644
--- a/src/ui/banner.c
+++ b/src/ui/banner.c
@@ -327,7 +327,8 @@ iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
327 else { 327 else {
328 switch (item->code) { 328 switch (item->code) {
329 case missingGlyphs_GmStatusCode: 329 case missingGlyphs_GmStatusCode:
330 postCommandf_App("open newtab:1 url:about:fonts"); 330 //postCommandf_App("open newtab:1 url:about:fonts");
331 makeGlyphFinder_Widget();
331 break; 332 break;
332 case ansiEscapes_GmStatusCode: 333 case ansiEscapes_GmStatusCode:
333 makeQuestion_Widget( 334 makeQuestion_Widget(
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index a52e99af..7d9ac154 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -358,6 +358,7 @@ static void updateSideIconBuf_DocumentWidget_ (const iDocumentWidget *d);
358static void prerender_DocumentWidget_ (iAny *); 358static void prerender_DocumentWidget_ (iAny *);
359static void scrollBegan_DocumentWidget_ (iAnyObject *, int, uint32_t); 359static void scrollBegan_DocumentWidget_ (iAnyObject *, int, uint32_t);
360static void refreshWhileScrolling_DocumentWidget_ (iAny *); 360static void refreshWhileScrolling_DocumentWidget_ (iAny *);
361static iBool requestMedia_DocumentWidget_ (iDocumentWidget *d, iGmLinkId linkId, iBool enableFilters);
361 362
362/* TODO: The following methods are called from DocumentView, which goes the wrong way. */ 363/* TODO: The following methods are called from DocumentView, which goes the wrong way. */
363 364
@@ -1824,7 +1825,7 @@ static void draw_DocumentView_(const iDocumentView *d) {
1824 } 1825 }
1825 if (d->drawBufs->flags & updateSideBuf_DrawBufsFlag) { 1826 if (d->drawBufs->flags & updateSideBuf_DrawBufsFlag) {
1826 updateSideIconBuf_DocumentView_(d); 1827 updateSideIconBuf_DocumentView_(d);
1827 } 1828 }
1828 const iRect docBounds = documentBounds_DocumentView_(d); 1829 const iRect docBounds = documentBounds_DocumentView_(d);
1829 const iRangei vis = visibleRange_DocumentView_(d); 1830 const iRangei vis = visibleRange_DocumentView_(d);
1830 iDrawContext ctx = { 1831 iDrawContext ctx = {
@@ -2410,6 +2411,20 @@ static const char *zipPageHeading_(const iRangecc mime) {
2410 2411
2411static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) { 2412static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) {
2412 iWidget *w = as_Widget(d); 2413 iWidget *w = as_Widget(d);
2414 /* Embedded images in data links can be shown immediately as they are already fetched
2415 data that is part of the document. */
2416 if (prefs_App()->openDataUrlImagesOnLoad) {
2417 iGmDocument *doc = d->view.doc;
2418 for (size_t linkId = 1; ; linkId++) {
2419 const int linkFlags = linkFlags_GmDocument(doc, linkId);
2420 const iString *linkUrl = linkUrl_GmDocument(doc, linkId);
2421 if (!linkUrl) break;
2422 if (scheme_GmLinkFlag(linkFlags) == data_GmLinkScheme &&
2423 (linkFlags & imageFileExtension_GmLinkFlag)) {
2424 requestMedia_DocumentWidget_(d, linkId, 0);
2425 }
2426 }
2427 }
2413 /* Gempub page behavior and footer actions. */ { 2428 /* Gempub page behavior and footer actions. */ {
2414 /* TODO: move this to gempub.c */ 2429 /* TODO: move this to gempub.c */
2415 delete_Gempub(d->sourceGempub); 2430 delete_Gempub(d->sourceGempub);
@@ -2681,7 +2696,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d,
2681 if (loadArchive_FontPack(fp, zip)) { 2696 if (loadArchive_FontPack(fp, zip)) {
2682 appendFormat_String(&str, "# " fontpack_Icon "%s\n%s", 2697 appendFormat_String(&str, "# " fontpack_Icon "%s\n%s",
2683 cstr_String(id_FontPack(fp).id), 2698 cstr_String(id_FontPack(fp).id),
2684 cstrCollect_String(infoText_FontPack(fp))); 2699 cstrCollect_String(infoText_FontPack(fp, iTrue)));
2685 } 2700 }
2686 appendCStr_String(&str, "\n"); 2701 appendCStr_String(&str, "\n");
2687 appendCStr_String(&str, cstr_Lang("fontpack.help")); 2702 appendCStr_String(&str, cstr_Lang("fontpack.help"));
@@ -3921,12 +3936,12 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
3921 const char *unchecked = red_ColorEscape "\u2610"; 3936 const char *unchecked = red_ColorEscape "\u2610";
3922 const char *checked = green_ColorEscape "\u2611"; 3937 const char *checked = green_ColorEscape "\u2611";
3923 const iBool haveFingerprint = (d->certFlags & haveFingerprint_GmCertFlag) != 0; 3938 const iBool haveFingerprint = (d->certFlags & haveFingerprint_GmCertFlag) != 0;
3924 const int requiredForTrust = (available_GmCertFlag | haveFingerprint_GmCertFlag | 3939 const int requiredForTrust =
3925 timeVerified_GmCertFlag); 3940 (available_GmCertFlag | haveFingerprint_GmCertFlag | timeVerified_GmCertFlag);
3926 const iBool canTrust = ~d->certFlags & trusted_GmCertFlag && 3941 const iBool canTrust = ~d->certFlags & trusted_GmCertFlag &&
3927 ((d->certFlags & requiredForTrust) == requiredForTrust); 3942 ((d->certFlags & requiredForTrust) == requiredForTrust);
3928 const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history); 3943 const iRecentUrl *recent = constMostRecentUrl_History(d->mod.history);
3929 const iString *meta = &d->sourceMime; 3944 const iString *meta = &d->sourceMime;
3930 if (recent && recent->cachedResponse) { 3945 if (recent && recent->cachedResponse) {
3931 meta = &recent->cachedResponse->meta; 3946 meta = &recent->cachedResponse->meta;
3932 } 3947 }
@@ -3991,6 +4006,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
3991 if (haveFingerprint) { 4006 if (haveFingerprint) {
3992 pushBack_Array(items, &(iMenuItem){ "${dlg.cert.fingerprint}", 0, 0, "server.copycert" }); 4007 pushBack_Array(items, &(iMenuItem){ "${dlg.cert.fingerprint}", 0, 0, "server.copycert" });
3993 } 4008 }
4009 const iRangecc root = urlRoot_String(d->mod.url);
4010 if (!isEmpty_Range(&root)) {
4011 pushBack_Array(items, &(iMenuItem){ "${pageinfo.settings}", 0, 0, "document.sitespec" });
4012 }
3994 if (!isEmpty_Array(items)) { 4013 if (!isEmpty_Array(items)) {
3995 pushBack_Array(items, &(iMenuItem){ "---", 0, 0, 0 }); 4014 pushBack_Array(items, &(iMenuItem){ "---", 0, 0, 0 });
3996 } 4015 }
@@ -4922,7 +4941,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e
4922 for (size_t i = 0; i < 64; ++i) { 4941 for (size_t i = 0; i < 64; ++i) {
4923 setByte_Block(seed, i, iRandom(0, 256)); 4942 setByte_Block(seed, i, iRandom(0, 256));
4924 } 4943 }
4925 setThemeSeed_GmDocument(view->doc, seed); 4944 setThemeSeed_GmDocument(view->doc, seed, NULL);
4926 delete_Block(seed); 4945 delete_Block(seed);
4927 invalidate_DocumentWidget_(d); 4946 invalidate_DocumentWidget_(d);
4928 refresh_Widget(w); 4947 refresh_Widget(w);
@@ -5545,10 +5564,10 @@ static void prerender_DocumentWidget_(iAny *context) {
5545 } 5564 }
5546 const iDocumentWidget *d = context; 5565 const iDocumentWidget *d = context;
5547 iDrawContext ctx = { 5566 iDrawContext ctx = {
5548 .view = &d->view, 5567 .view = &d->view,
5549 .docBounds = documentBounds_DocumentView_(&d->view), 5568 .docBounds = documentBounds_DocumentView_(&d->view),
5550 .vis = visibleRange_DocumentView_(&d->view), 5569 .vis = visibleRange_DocumentView_(&d->view),
5551 .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0 5570 .showLinkNumbers = (d->flags & showLinkNumbers_DocumentWidgetFlag) != 0
5552 }; 5571 };
5553 // printf("%u prerendering\n", SDL_GetTicks()); 5572 // printf("%u prerendering\n", SDL_GetTicks());
5554 if (d->view.visBuf->buffers[0].texture) { 5573 if (d->view.visBuf->buffers[0].texture) {
diff --git a/src/ui/linkinfo.c b/src/ui/linkinfo.c
index 36ab00c8..15aea16e 100644
--- a/src/ui/linkinfo.c
+++ b/src/ui/linkinfo.c
@@ -91,6 +91,10 @@ void infoText_LinkInfo(const iGmDocument *doc, iGmLinkId linkId, iString *text_o
91 appendCStr_String(text_out, "\x1b[0m"); 91 appendCStr_String(text_out, "\x1b[0m");
92 appendRange_String(text_out, (iRangecc){ parts.path.start, constEnd_String(url) }); 92 appendRange_String(text_out, (iRangecc){ parts.path.start, constEnd_String(url) });
93 } 93 }
94 else if (scheme == data_GmLinkScheme) {
95 appendCStr_String(text_out, paperclip_Icon " ");
96 append_String(text_out, prettyDataUrl_String(url, none_ColorId));
97 }
94 else if (scheme != gemini_GmLinkScheme) { 98 else if (scheme != gemini_GmLinkScheme) {
95 const size_t maxDispLen = 300; 99 const size_t maxDispLen = 300;
96 appendCStr_String(text_out, scheme == file_GmLinkScheme ? "" : globe_Icon " "); 100 appendCStr_String(text_out, scheme == file_GmLinkScheme ? "" : globe_Icon " ");
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c
index da377ac2..73023a4f 100644
--- a/src/ui/sidebarwidget.c
+++ b/src/ui/sidebarwidget.c
@@ -2156,28 +2156,38 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect,
2156 : uiTextDim_ColorId; 2156 : uiTextDim_ColorId;
2157 iUrl parts; 2157 iUrl parts;
2158 init_Url(&parts, &d->label); 2158 init_Url(&parts, &d->label);
2159 const iBool isAbout = equalCase_Rangecc(parts.scheme, "about"); 2159 const iBool isAbout = equalCase_Rangecc(parts.scheme, "about");
2160 const iBool isGemini = equalCase_Rangecc(parts.scheme, "gemini"); 2160 const iBool isGemini = equalCase_Rangecc(parts.scheme, "gemini");
2161 draw_Text(font, 2161 const iBool isData = equalCase_Rangecc(parts.scheme, "data");
2162 add_I2(topLeft_Rect(itemRect), 2162 const int queryColor = isPressing ? uiTextPressed_ColorId
2163 init_I2(3 * gap_UI, (itemHeight - lineHeight_Text(font)) / 2)), 2163 : isHover ? uiText_ColorId
2164 fg, 2164 : uiAnnotation_ColorId;
2165 "%s%s%s%s%s%s%s%s", 2165 const iInt2 textPos =
2166 isGemini ? "" : cstr_Rangecc(parts.scheme), 2166 add_I2(topLeft_Rect(itemRect),
2167 isGemini ? "" 2167 init_I2(3 * gap_UI, (itemHeight - lineHeight_Text(font)) / 2));
2168 : isAbout ? ":" 2168 if (isData) {
2169 : "://", 2169 drawRange_Text(
2170 escape_Color(isHover ? (isPressing ? uiTextPressed_ColorId 2170 font, textPos, fg, range_String(prettyDataUrl_String(&d->label, queryColor)));
2171 : uiTextFramelessHover_ColorId) 2171 }
2172 : uiTextStrong_ColorId), 2172 else {
2173 cstr_Rangecc(parts.host), 2173 draw_Text(
2174 escape_Color(fg), 2174 font,
2175 cstr_Rangecc(parts.path), 2175 textPos,
2176 !isEmpty_Range(&parts.query) ? escape_Color(isPressing ? uiTextPressed_ColorId 2176 fg,
2177 : isHover ? uiText_ColorId 2177 "%s%s%s%s%s%s%s%s",
2178 : uiAnnotation_ColorId) 2178 isGemini ? "" : cstr_Rangecc(parts.scheme),
2179 : "", 2179 isGemini ? ""
2180 !isEmpty_Range(&parts.query) ? cstr_Rangecc(parts.query) : ""); 2180 : isAbout ? ":"
2181 : "://",
2182 escape_Color(isHover ? (isPressing ? uiTextPressed_ColorId
2183 : uiTextFramelessHover_ColorId)
2184 : uiTextStrong_ColorId),
2185 cstr_Rangecc(parts.host),
2186 escape_Color(fg),
2187 cstr_Rangecc(parts.path),
2188 !isEmpty_Range(&parts.query) ? escape_Color(queryColor) : "",
2189 !isEmpty_Range(&parts.query) ? cstr_Rangecc(parts.query) : "");
2190 }
2181 } 2191 }
2182 iEndCollect(); 2192 iEndCollect();
2183 } 2193 }
diff --git a/src/ui/text.c b/src/ui/text.c
index c19aed2f..51531057 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -258,8 +258,6 @@ static int cmp_PrioMapItem_(const void *a, const void *b) {
258} 258}
259 259
260struct Impl_Text { 260struct Impl_Text {
261// enum iTextFont contentFont;
262// enum iTextFont headingFont;
263 float contentFontSize; 261 float contentFontSize;
264 iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */ 262 iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */
265 int overrideFontId; /* always checked for glyphs first, regardless of which font is used */ 263 int overrideFontId; /* always checked for glyphs first, regardless of which font is used */
@@ -276,7 +274,8 @@ struct Impl_Text {
276 int ansiFlags; 274 int ansiFlags;
277 int baseFontId; /* base attributes (for restoring via escapes) */ 275 int baseFontId; /* base attributes (for restoring via escapes) */
278 int baseFgColorId; 276 int baseFgColorId;
279 iBool missingGlyphs; /* true if a glyph couldn't be found */ 277 iBool missingGlyphs; /* true if a glyph couldn't be found */
278 iChar missingChars[20]; /* rotating buffer of the latest missing characters */
280}; 279};
281 280
282iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) 281iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render)
@@ -357,6 +356,8 @@ static void initFonts_Text_(iText *d) {
357 printf("[Text] %zu font variants ready\n", size_Array(&d->fonts)); 356 printf("[Text] %zu font variants ready\n", size_Array(&d->fonts));
358#endif 357#endif
359 gap_Text = iRound(gap_UI * d->contentFontSize); 358 gap_Text = iRound(gap_UI * d->contentFontSize);
359// d->missingGlyphs = iFalse;
360// iZap(d->missingChars);
360} 361}
361 362
362static void deinitFonts_Text_(iText *d) { 363static void deinitFonts_Text_(iText *d) {
@@ -424,6 +425,7 @@ void init_Text(iText *d, SDL_Renderer *render) {
424 d->baseFontId = -1; 425 d->baseFontId = -1;
425 d->baseFgColorId = -1; 426 d->baseFgColorId = -1;
426 d->missingGlyphs = iFalse; 427 d->missingGlyphs = iFalse;
428 iZap(d->missingChars);
427 d->render = render; 429 d->render = render;
428 /* A grayscale palette for rasterized glyphs. */ { 430 /* A grayscale palette for rasterized glyphs. */ {
429 SDL_Color colors[256]; 431 SDL_Color colors[256];
@@ -610,8 +612,23 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
610 } 612 }
611 } 613 }
612 if (!*glyphIndex) { 614 if (!*glyphIndex) {
613 activeText_->missingGlyphs = iTrue; 615 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int) ch); fflush(stderr);
614 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); 616 iText *tx = activeText_;
617 tx->missingGlyphs = iTrue;
618 /* Remember a few of the latest missing characters. */
619 iBool gotIt = iFalse;
620 for (size_t i = 0; i < iElemCount(tx->missingChars); i++) {
621 if (tx->missingChars[i] == ch) {
622 gotIt = iTrue;
623 break;
624 }
625 }
626 if (!gotIt) {
627 memmove(tx->missingChars + 1,
628 tx->missingChars,
629 sizeof(tx->missingChars) - sizeof(tx->missingChars[0]));
630 tx->missingChars[0] = ch;
631 }
615 } 632 }
616 return d; 633 return d;
617} 634}
@@ -2250,6 +2267,19 @@ iBool checkMissing_Text(void) {
2250 return missing; 2267 return missing;
2251} 2268}
2252 2269
2270iChar missing_Text(size_t index) {
2271 const iText *d = activeText_;
2272 if (index >= iElemCount(d->missingChars)) {
2273 return 0;
2274 }
2275 return d->missingChars[index];
2276}
2277
2278void resetMissing_Text(iText *d) {
2279 d->missingGlyphs = iFalse;
2280 iZap(d->missingChars);
2281}
2282
2253SDL_Texture *glyphCache_Text(void) { 2283SDL_Texture *glyphCache_Text(void) {
2254 return activeText_->cache; 2284 return activeText_->cache;
2255} 2285}
diff --git a/src/ui/text.h b/src/ui/text.h
index b952df84..e741880d 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -227,6 +227,8 @@ struct Impl_WrapText {
227iTextMetrics measure_WrapText (iWrapText *, int fontId); 227iTextMetrics measure_WrapText (iWrapText *, int fontId);
228iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color); 228iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color);
229 229
230iChar missing_Text (size_t index);
231void resetMissing_Text (iText *);
230iBool checkMissing_Text (void); /* returns the flag, and clears it */ 232iBool checkMissing_Text (void); /* returns the flag, and clears it */
231SDL_Texture * glyphCache_Text (void); 233SDL_Texture * glyphCache_Text (void);
232 234
diff --git a/src/ui/util.c b/src/ui/util.c
index 5dd8a0bd..54715121 100644
--- a/src/ui/util.c
+++ b/src/ui/util.c
@@ -903,6 +903,7 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) {
903#else 903#else
904 /* Non-native custom popup menu. This may still be displayed inside a separate window. */ 904 /* Non-native custom popup menu. This may still be displayed inside a separate window. */
905 setDrawBufferEnabled_Widget(menu, iTrue); 905 setDrawBufferEnabled_Widget(menu, iTrue);
906 setFrameColor_Widget(menu, uiSeparator_ColorId);
906 setBackgroundColor_Widget(menu, uiBackgroundMenu_ColorId); 907 setBackgroundColor_Widget(menu, uiBackgroundMenu_ColorId);
907 if (deviceType_App() != desktop_AppDeviceType) { 908 if (deviceType_App() != desktop_AppDeviceType) {
908 setPadding1_Widget(menu, 2 * gap_UI); 909 setPadding1_Widget(menu, 2 * gap_UI);
@@ -1084,12 +1085,12 @@ void openMenuFlags_Widget(iWidget *d, iInt2 windowCoord, int menuOpenFlags) {
1084 setFlags_Widget(d, hidden_WidgetFlag, iFalse); 1085 setFlags_Widget(d, hidden_WidgetFlag, iFalse);
1085 setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue); 1086 setFlags_Widget(d, commandOnMouseMiss_WidgetFlag, iTrue);
1086 setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse); 1087 setFlags_Widget(findChild_Widget(d, "menu.cancel"), disabled_WidgetFlag, iFalse);
1087 if (!isPortraitPhone) { 1088// if (!isPortraitPhone) {
1088 setFrameColor_Widget(d, uiBackgroundSelected_ColorId); 1089// setFrameColor_Widget(d, uiSeparator_ColorId);
1089 } 1090// }
1090 else { 1091// else {
1091 setFrameColor_Widget(d, none_ColorId); 1092// setFrameColor_Widget(d, none_ColorId);
1092 } 1093// }
1093 arrange_Widget(d); /* need to know the height */ 1094 arrange_Widget(d); /* need to know the height */
1094 iBool allowOverflow = iFalse; 1095 iBool allowOverflow = iFalse;
1095 /* A vertical offset determined by a possible selected label in the menu. */ 1096 /* A vertical offset determined by a possible selected label in the menu. */
@@ -1327,6 +1328,7 @@ int checkContextMenu_Widget(iWidget *menu, const SDL_Event *ev) {
1327iLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *items, size_t n) { 1328iLabelWidget *makeMenuButton_LabelWidget(const char *label, const iMenuItem *items, size_t n) {
1328 iLabelWidget *button = new_LabelWidget(label, "menu.open"); 1329 iLabelWidget *button = new_LabelWidget(label, "menu.open");
1329 iWidget *menu = makeMenu_Widget(as_Widget(button), items, n); 1330 iWidget *menu = makeMenu_Widget(as_Widget(button), items, n);
1331 setFrameColor_Widget(menu, uiBackgroundSelected_ColorId);
1330 setId_Widget(menu, "menu"); 1332 setId_Widget(menu, "menu");
1331 return button; 1333 return button;
1332} 1334}
@@ -2495,6 +2497,7 @@ iWidget *makePreferences_Widget(void) {
2495 { "input id:prefs.searchurl url:1 noheading:1" }, 2497 { "input id:prefs.searchurl url:1 noheading:1" },
2496 { "padding" }, 2498 { "padding" },
2497 { "toggle id:prefs.bookmarks.addbottom" }, 2499 { "toggle id:prefs.bookmarks.addbottom" },
2500 { "toggle id:prefs.dataurl.openimages" },
2498 { "toggle id:prefs.archive.openindex" }, 2501 { "toggle id:prefs.archive.openindex" },
2499 { "radio device:1 id:prefs.pinsplit", 0, 0, (const void *) pinSplitItems }, 2502 { "radio device:1 id:prefs.pinsplit", 0, 0, (const void *) pinSplitItems },
2500 { "padding" }, 2503 { "padding" },
@@ -2567,6 +2570,7 @@ iWidget *makePreferences_Widget(void) {
2567 const iMenuItem networkPanelItems[] = { 2570 const iMenuItem networkPanelItems[] = {
2568 { "title id:heading.prefs.network" }, 2571 { "title id:heading.prefs.network" },
2569 { "toggle id:prefs.decodeurls" }, 2572 { "toggle id:prefs.decodeurls" },
2573 { "input id:prefs.urlsize maxlen:10 selectall:1" },
2570 { "padding" }, 2574 { "padding" },
2571 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" }, 2575 { "input id:prefs.cachesize maxlen:4 selectall:1 unit:mb" },
2572 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" }, 2576 { "input id:prefs.memorysize maxlen:4 selectall:1 unit:mb" },
@@ -2640,8 +2644,9 @@ iWidget *makePreferences_Widget(void) {
2640 setUrlContent_InputWidget(searchUrl, iTrue); 2644 setUrlContent_InputWidget(searchUrl, iTrue);
2641 addDialogPadding_(headings, values); 2645 addDialogPadding_(headings, values);
2642 addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink"); 2646 addDialogToggle_(headings, values, "${prefs.hoverlink}", "prefs.hoverlink");
2643 addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom"); 2647 addDialogToggle_(headings, values, "${prefs.dataurl.openimages}", "prefs.dataurl.openimages");
2644 addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex"); 2648 addDialogToggle_(headings, values, "${prefs.archive.openindex}", "prefs.archive.openindex");
2649 addDialogToggle_(headings, values, "${prefs.bookmarks.addbottom}", "prefs.bookmarks.addbottom");
2645 if (deviceType_App() != phone_AppDeviceType) { 2650 if (deviceType_App() != phone_AppDeviceType) {
2646 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.pinsplit}"))); 2651 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.pinsplit}")));
2647 iWidget *pinSplit = new_Widget(); 2652 iWidget *pinSplit = new_Widget();
@@ -2900,6 +2905,7 @@ iWidget *makePreferences_Widget(void) {
2900 appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.network}", '6', &headings, &values); 2905 appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.network}", '6', &headings, &values);
2901 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}"))); 2906 addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.decodeurls}")));
2902 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls"))); 2907 addChild_Widget(values, iClob(makeToggle_Widget("prefs.decodeurls")));
2908 addPrefsInputWithHeading_(headings, values, "prefs.urlsize", iClob(new_InputWidget(10)));
2903 /* Cache size. */ { 2909 /* Cache size. */ {
2904 iInputWidget *cache = new_InputWidget(4); 2910 iInputWidget *cache = new_InputWidget(4);
2905 setSelectAllOnFocus_InputWidget(cache, iTrue); 2911 setSelectAllOnFocus_InputWidget(cache, iTrue);
@@ -3163,15 +3169,14 @@ static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) {
3163} 3169}
3164 3170
3165iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { 3171iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
3166 const char *headingText = bookmarkId ? uiHeading_ColorEscape "${heading.feedcfg}" 3172 iWidget *dlg;
3167 : uiHeading_ColorEscape "${heading.subscribe}"; 3173 const char *headingText = bookmarkId ? "${heading.feedcfg}" : "${heading.subscribe}";
3168 const iMenuItem actions[] = { { "${cancel}" }, 3174 const iMenuItem actions[] = { { "${cancel}" },
3169 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}" 3175 { bookmarkId ? uiTextCaution_ColorEscape "${dlg.feed.save}"
3170 : uiTextCaution_ColorEscape "${dlg.feed.sub}", 3176 : uiTextCaution_ColorEscape "${dlg.feed.sub}",
3171 SDLK_RETURN, 3177 SDLK_RETURN,
3172 KMOD_PRIMARY, 3178 KMOD_PRIMARY,
3173 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } }; 3179 format_CStr("feedcfg.accept bmid:%d", bookmarkId) } };
3174 iWidget *dlg;
3175 if (isUsingPanelLayout_Mobile()) { 3180 if (isUsingPanelLayout_Mobile()) {
3176 const iMenuItem typeItems[] = { 3181 const iMenuItem typeItems[] = {
3177 { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" }, 3182 { "button id:feedcfg.type.gemini label:dlg.feed.type.gemini", 0, 0, "feedcfg.type arg:0" },
@@ -3228,6 +3233,32 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) {
3228 return dlg; 3233 return dlg;
3229} 3234}
3230 3235
3236iWidget *makeSiteSpecificSettings_Widget(const iString *url) {
3237 iWidget *dlg;
3238 const iMenuItem actions[] = {
3239 { "${cancel}" }, { "${sitespec.accept}", SDLK_RETURN, KMOD_PRIMARY, "sitespec.accept" }
3240 };
3241 if (isUsingPanelLayout_Mobile()) {
3242 iAssert(iFalse);
3243 }
3244 else {
3245 iWidget *headings, *values;
3246 dlg = makeSheet_Widget("sitespec");
3247 addDialogTitle_(dlg, "${heading.sitespec}", "heading.sitespec");
3248 addChild_Widget(dlg, iClob(makeTwoColumns_Widget(&headings, &values)));
3249 addDialogToggle_(headings, values, "${sitespec.ansi}", "sitespec.ansi");
3250 iInputWidget *palInput = new_InputWidget(0);
3251 addPrefsInputWithHeading_(headings, values, "sitespec.palette", iClob(palInput));
3252 as_Widget(palInput)->rect.size.x = 80 * gap_UI;
3253 addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions))));
3254 }
3255 /* Initialize. */ {
3256 const iRangecc root = urlRoot_String(url);
3257
3258 }
3259 return dlg;
3260}
3261
3231iWidget *makeIdentityCreation_Widget(void) { 3262iWidget *makeIdentityCreation_Widget(void) {
3232 const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" }, 3263 const iMenuItem actions[] = { { "${dlg.newident.more}", 0, 0, "ident.showmore" },
3233 { "---" }, 3264 { "---" },
@@ -3451,6 +3482,54 @@ iWidget *makeTranslation_Widget(iWidget *parent) {
3451 return dlg; 3482 return dlg;
3452} 3483}
3453 3484
3485iWidget *makeGlyphFinder_Widget(void) {
3486 iString msg;
3487 iString command;
3488 init_String(&msg);
3489 initCStr_String(&command, "!font.find chars:");
3490 for (size_t i = 0; ; i++) {
3491 iChar ch = missing_Text(i);
3492 if (!ch) break;
3493 appendFormat_String(&msg, " U+%04X", ch);
3494 appendChar_String(&command, ch);
3495 }
3496 iArray items;
3497 init_Array(&items, sizeof(iMenuItem));
3498 if (!isEmpty_String(&msg)) {
3499 prependCStr_String(&msg, "${dlg.glyphfinder.missing} ");
3500 appendCStr_String(&msg, "\n\n${dlg.glyphfinder.help}");
3501 pushBackN_Array(
3502 &items,
3503 (iMenuItem[]){
3504 { "${menu.fonts}", 0, 0, "!open newtab:1 url:about:fonts" },
3505 { "${dlg.glyphfinder.disable}", 0, 0, "prefs.font.warnmissing.changed arg:0" },
3506 { "---" },
3507 { uiTextCaution_ColorEscape magnifyingGlass_Icon " ${dlg.glyphfinder.search}",
3508 0,
3509 0,
3510 cstr_String(&command) },
3511 { "${close}", 0, 0, "cancel" } },
3512 5);
3513 }
3514 else {
3515 setCStr_String(&msg, "${dlg.glyphfinder.help.empty}");
3516 pushBackN_Array(&items,
3517 (iMenuItem[]){ { "${menu.reload}", 0, 0, "navigate.reload" },
3518 { "${close}", 0, 0, "cancel" } },
3519 2);
3520 }
3521 iWidget *dlg = makeQuestion_Widget("${heading.glyphfinder}", cstr_String(&msg),
3522 constData_Array(&items),
3523 size_Array(&items));
3524 arrange_Widget(dlg);
3525 deinit_Array(&items);
3526 deinit_String(&command);
3527 deinit_String(&msg);
3528 return dlg;
3529}
3530
3531/*----------------------------------------------------------------------------------------------*/
3532
3454void init_PerfTimer(iPerfTimer *d) { 3533void init_PerfTimer(iPerfTimer *d) {
3455 d->ticks = SDL_GetPerformanceCounter(); 3534 d->ticks = SDL_GetPerformanceCounter();
3456} 3535}
diff --git a/src/ui/util.h b/src/ui/util.h
index 98ce784c..31c8cedc 100644
--- a/src/ui/util.h
+++ b/src/ui/util.h
@@ -336,12 +336,14 @@ iWidget * makeQuestion_Widget (const char *title, const char *msg,
336iWidget * makePreferences_Widget (void); 336iWidget * makePreferences_Widget (void);
337void updatePreferencesLayout_Widget (iWidget *prefs); 337void updatePreferencesLayout_Widget (iWidget *prefs);
338 338
339iWidget * makeBookmarkEditor_Widget (void); 339iWidget * makeBookmarkEditor_Widget (void);
340void setBookmarkEditorFolder_Widget(iWidget *editor, uint32_t folderId); 340void setBookmarkEditorFolder_Widget (iWidget *editor, uint32_t folderId);
341iWidget * makeBookmarkCreation_Widget (const iString *url, const iString *title, iChar icon); 341iWidget * makeBookmarkCreation_Widget (const iString *url, const iString *title, iChar icon);
342iWidget * makeIdentityCreation_Widget (void); 342iWidget * makeIdentityCreation_Widget (void);
343iWidget * makeFeedSettings_Widget (uint32_t bookmarkId); 343iWidget * makeFeedSettings_Widget (uint32_t bookmarkId);
344iWidget * makeTranslation_Widget (iWidget *parent); 344iWidget * makeSiteSpecificSettings_Widget (const iString *url);
345iWidget * makeTranslation_Widget (iWidget *parent);
346iWidget * makeGlyphFinder_Widget (void);
345 347
346const char * languageId_String (const iString *menuItemLabel); 348const char * languageId_String (const iString *menuItemLabel);
347int languageIndex_CStr (const char *langId); 349int languageIndex_CStr (const char *langId);