summaryrefslogtreecommitdiff
path: root/src/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/banner.c77
-rw-r--r--src/ui/documentwidget.c27
-rw-r--r--src/ui/labelwidget.c8
-rw-r--r--src/ui/text.c9
-rw-r--r--src/ui/text.h1
5 files changed, 101 insertions, 21 deletions
diff --git a/src/ui/banner.c b/src/ui/banner.c
index d95c853b..e817f1bb 100644
--- a/src/ui/banner.c
+++ b/src/ui/banner.c
@@ -27,6 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
27#include "lang.h" 27#include "lang.h"
28#include "paint.h" 28#include "paint.h"
29#include "util.h" 29#include "util.h"
30#include "app.h"
30 31
31iDeclareType(BannerItem) 32iDeclareType(BannerItem)
32 33
@@ -53,27 +54,33 @@ struct Impl_Banner {
53 iRect rect; 54 iRect rect;
54 iString site; 55 iString site;
55 iString icon; 56 iString icon;
57 int siteHeight;
56 iArray items; 58 iArray items;
57 iBool isClick; 59 iBool isClick;
58}; 60};
59 61
60iDefineTypeConstruction(Banner) 62iDefineTypeConstruction(Banner)
61 63
64#define itemGap_Banner_ (3 * gap_UI)
65#define itemVPad_Banner_ (2 * gap_UI)
66#define itemHPad_Banner_ (3 * gap_UI)
67#define bottomPad_Banner_ (4 * gap_UI)
68
62static void updateHeight_Banner_(iBanner *d) { 69static void updateHeight_Banner_(iBanner *d) {
63 d->rect.size.y = 0; 70 d->rect.size.y = 0;
64 if (!isEmpty_String(&d->site)) { 71 if (!isEmpty_String(&d->site)) {
65 d->rect.size.y += lineHeight_Text(banner_FontId) * 2; 72 d->siteHeight = lineHeight_Text(banner_FontId) * 2;
73 d->rect.size.y += d->siteHeight;
66 } 74 }
67 const size_t numItems = size_Array(&d->items); 75 const size_t numItems = size_Array(&d->items);
68 if (numItems) { 76 if (numItems) {
69 const int outerPad = 2 * gap_UI;
70 const int innerPad = gap_UI; 77 const int innerPad = gap_UI;
71 iConstForEach(Array, i, &d->items) { 78 iConstForEach(Array, i, &d->items) {
72 const iBannerItem *item = i.value; 79 const iBannerItem *item = i.value;
73 d->rect.size.y += item->height; 80 d->rect.size.y += item->height;
74 } 81 }
75 d->rect.size.y += (numItems - 1) * innerPad; 82 d->rect.size.y += (numItems - 1) * itemGap_Banner_;
76 d->rect.size.y += outerPad; 83 d->rect.size.y += bottomPad_Banner_;
77 } 84 }
78} 85}
79 86
@@ -99,9 +106,9 @@ void setOwner_Banner(iBanner *d, iDocumentWidget *owner) {
99 106
100static void updateItemHeight_Banner_(const iBanner *d, iBannerItem *item) { 107static void updateItemHeight_Banner_(const iBanner *d, iBannerItem *item) {
101 item->height = measureWrapRange_Text(uiContent_FontId, 108 item->height = measureWrapRange_Text(uiContent_FontId,
102 width_Rect(d->rect) - 6 * gap_UI, 109 width_Rect(d->rect) - 2 * itemHPad_Banner_,
103 range_String(&item->text)) 110 range_String(&item->text))
104 .bounds.size.y + 4 * gap_UI; 111 .bounds.size.y + 2 * itemVPad_Banner_;
105} 112}
106 113
107void setWidth_Banner(iBanner *d, int width) { 114void setWidth_Banner(iBanner *d, int width) {
@@ -186,6 +193,7 @@ void draw_Banner(const iBanner *d) {
186 return; 193 return;
187 } 194 }
188 iRect bounds = d->rect; 195 iRect bounds = d->rect;
196 /* TODO: use d->siteHeight */
189 iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2); 197 iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2);
190 iPaint p; 198 iPaint p;
191 init_Paint(&p); 199 init_Paint(&p);
@@ -218,16 +226,28 @@ void draw_Banner(const iBanner *d) {
218 setBaseAttributes_Text(uiContent_FontId, tmBannerItemText_ColorId); 226 setBaseAttributes_Text(uiContent_FontId, tmBannerItemText_ColorId);
219 iWrapText wt = { 227 iWrapText wt = {
220 .text = range_String(&item->text), 228 .text = range_String(&item->text),
221 .maxWidth = width_Rect(itemRect) - 6 * gap_UI, 229 .maxWidth = width_Rect(itemRect) - 2 * itemHPad_Banner_,
222 .mode = word_WrapTextMode 230 .mode = word_WrapTextMode
223 }; 231 };
224 draw_WrapText(&wt, uiContent_FontId, add_I2(pos, init_I2(3 * gap_UI, 2 * gap_UI)), 232 draw_WrapText(&wt, uiContent_FontId, add_I2(pos, init_I2(itemHPad_Banner_, itemVPad_Banner_)),
225 tmBannerItemText_ColorId); 233 tmBannerItemText_ColorId);
226 pos.y += innerPad; 234 pos.y += item->height + itemGap_Banner_;
227 } 235 }
228 setBaseAttributes_Text(-1, -1); 236 setBaseAttributes_Text(-1, -1);
229} 237}
230 238
239static size_t itemAtCoord_Banner_(const iBanner *d, iInt2 coord) {
240 iInt2 pos = addY_I2(topLeft_Rect(d->rect), lineHeight_Text(banner_FontId) * 2);
241 iConstForEach(Array, i, &d->items) {
242 const iBannerItem *item = i.value;
243 if (contains_Rect((iRect){ pos, init_I2(d->rect.size.x, item->height)}, coord)) {
244 return index_ArrayConstIterator(&i);
245 }
246 pos.y += itemGap_Banner_ + item->height;
247 }
248 return iInvalidPos;
249}
250
231iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { 251iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
232 iWidget *w = as_Widget(d->doc); 252 iWidget *w = as_Widget(d->doc);
233 switch (ev->type) { 253 switch (ev->type) {
@@ -240,14 +260,49 @@ iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
240 case SDL_MOUSEBUTTONUP: 260 case SDL_MOUSEBUTTONUP:
241 /* Clicking on the top/side banner navigates to site root. */ 261 /* Clicking on the top/side banner navigates to site root. */
242 if (ev->button.button == SDL_BUTTON_LEFT) { 262 if (ev->button.button == SDL_BUTTON_LEFT) {
243 const iBool isInside = contains_Rect(d->rect, init_I2(ev->button.x, ev->button.y)); 263 const iInt2 coord = init_I2(ev->button.x, ev->button.y);
264 const iBool isInside = contains_Rect(d->rect, coord);
244 if (isInside && ev->button.state == SDL_PRESSED) { 265 if (isInside && ev->button.state == SDL_PRESSED) {
245 d->isClick = iTrue; 266 d->isClick = iTrue;
246 return iTrue; 267 return iTrue;
247 } 268 }
248 else if (ev->button.state == SDL_RELEASED) { 269 else if (ev->button.state == SDL_RELEASED) {
249 if (d->isClick && isInside) { 270 if (d->isClick && isInside) {
250 postCommand_Widget(d->doc, "navigate.root"); 271 const size_t index = itemAtCoord_Banner_(d, coord);
272 if (index == iInvalidPos) {
273 if (coord.y < top_Rect(d->rect) + d->siteHeight) {
274 postCommand_Widget(d->doc, "navigate.root");
275 }
276 }
277 else {
278 const iBannerItem *item = constAt_Array(&d->items, index);
279 if (item->type == error_BannerType) {
280 postCommand_Widget(d->doc, "document.info");
281 }
282 else {
283 switch (item->code) {
284 case missingGlyphs_GmStatusCode:
285 postCommandf_App("open newtab:1 url:about:fonts");
286 break;
287 case ansiEscapes_GmStatusCode:
288 makeQuestion_Widget(uiHeading_ColorEscape "${heading.dismiss.warning}",
289 format_Lang("${dlg.dismiss.ansi}",
290 format_CStr(uiTextStrong_ColorEscape "%s"
291 restore_ColorEscape, cstr_Rangecc(urlHost_String(url_DocumentWidget(d->doc))))),
292 (iMenuItem[]){ { "${cancel}" },
293 { uiTextAction_ColorEscape "${dlg.dismiss.warning}",
294 SDLK_RETURN, 0,
295 format_CStr("document.dismiss warning:%d",
296 ansiEscapes_GmDocumentWarning)
297 }
298 }, 2);
299 break;
300 default:
301 postCommand_Widget(d->doc, "document.info");
302 break;
303 }
304 }
305 }
251 } 306 }
252 d->isClick = iFalse; 307 d->isClick = iFalse;
253 } 308 }
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 13a8dae7..755cec6a 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -934,7 +934,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
934 updateSideOpacity_DocumentWidget_(d, iTrue); 934 updateSideOpacity_DocumentWidget_(d, iTrue);
935 animateMedia_DocumentWidget_(d); 935 animateMedia_DocumentWidget_(d);
936 setPos_Banner(d->banner, addY_I2(topLeft_Rect(documentBounds_DocumentWidget_(d)), 936 setPos_Banner(d->banner, addY_I2(topLeft_Rect(documentBounds_DocumentWidget_(d)),
937 -pos_SmoothScroll(&d->scrollY))); 937 -pos_SmoothScroll(&d->scrollY)));
938 /*init_I2(documentBounds_DocumentWidget_(d).pos.x, 938 /*init_I2(documentBounds_DocumentWidget_(d).pos.x,
939 viewPos_DocumentWidget_(d) - 939 viewPos_DocumentWidget_(d) -
940 documentTopPad_DocumentWidget_(d)));*/ 940 documentTopPad_DocumentWidget_(d)));*/
@@ -1291,7 +1291,6 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
1291 iRelease(errorDoc); 1291 iRelease(errorDoc);
1292 clear_Banner(d->banner); 1292 clear_Banner(d->banner);
1293 add_Banner(d->banner, error_BannerType, code, meta); 1293 add_Banner(d->banner, error_BannerType, code, meta);
1294// translate_Lang(src);
1295 d->state = ready_RequestState; 1294 d->state = ready_RequestState;
1296 setSource_DocumentWidget(d, src); 1295 setSource_DocumentWidget(d, src);
1297 updateTheme_DocumentWidget_(d); 1296 updateTheme_DocumentWidget_(d);
@@ -1798,6 +1797,16 @@ static void cacheDocumentGlyphs_DocumentWidget_(const iDocumentWidget *d) {
1798 } 1797 }
1799} 1798}
1800 1799
1800static void addBannerWarnings_DocumentWidget_(iDocumentWidget *d) {
1801 if (warnings_GmDocument(d->doc) & missingGlyphs_GmDocumentWarning) {
1802 add_Banner(d->banner, warning_BannerType, missingGlyphs_GmStatusCode, NULL);
1803 /* TODO: List one or more of the missing characters and/or their Unicode blocks? */
1804 }
1805 if (warnings_GmDocument(d->doc) & ansiEscapes_GmDocumentWarning) {
1806 add_Banner(d->banner, warning_BannerType, ansiEscapes_GmStatusCode, NULL);
1807 }
1808}
1809
1801static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, 1810static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY,
1802 const iGmResponse *resp, iGmDocument *cachedDoc) { 1811 const iGmResponse *resp, iGmDocument *cachedDoc) {
1803 setLinkNumberMode_DocumentWidget_(d, iFalse); 1812 setLinkNumberMode_DocumentWidget_(d, iFalse);
@@ -1824,6 +1833,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n
1824// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); 1833// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0);
1825 clear_Banner(d->banner); 1834 clear_Banner(d->banner);
1826 updateBanner_DocumentWidget_(d); 1835 updateBanner_DocumentWidget_(d);
1836 addBannerWarnings_DocumentWidget_(d);
1827 } 1837 }
1828 d->state = ready_RequestState; 1838 d->state = ready_RequestState;
1829 postProcessRequestContent_DocumentWidget_(d, iTrue); 1839 postProcessRequestContent_DocumentWidget_(d, iTrue);
@@ -2864,10 +2874,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2864 size_Array(items)); 2874 size_Array(items));
2865 delete_Array(items); 2875 delete_Array(items);
2866 /* Enforce a minimum size. */ 2876 /* Enforce a minimum size. */
2867 iWidget *sizer = new_Widget(); 2877// iWidget *sizer = new_Widget();
2868 setFixedSize_Widget(sizer, init_I2(gap_UI * 65, 1)); 2878// setFixedSize_Widget(sizer, init_I2(gap_UI * 65, 1));
2869 addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag); 2879// addChildFlags_Widget(dlg, iClob(sizer), frameless_WidgetFlag);
2870 setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse); 2880// setFlags_Widget(dlg, centerHorizontal_WidgetFlag, iFalse);
2871 if (deviceType_App() != phone_AppDeviceType) { 2881 if (deviceType_App() != phone_AppDeviceType) {
2872 const iWidget *lockButton = findWidget_Root("navbar.lock"); 2882 const iWidget *lockButton = findWidget_Root("navbar.lock");
2873 setPos_Widget(dlg, windowToLocal_Widget(dlg, bottomLeft_Rect(bounds_Widget(lockButton)))); 2883 setPos_Widget(dlg, windowToLocal_Widget(dlg, bottomLeft_Rect(bounds_Widget(lockButton))));
@@ -2989,6 +2999,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
2989 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) { 2999 if (category_GmStatusCode(status_GmRequest(d->request)) == categorySuccess_GmStatusCode) {
2990 init_Anim(&d->scrollY.pos, d->initNormScrollY * pageHeight_DocumentWidget_(d)); /* TODO: unless user already scrolled! */ 3000 init_Anim(&d->scrollY.pos, d->initNormScrollY * pageHeight_DocumentWidget_(d)); /* TODO: unless user already scrolled! */
2991 } 3001 }
3002 addBannerWarnings_DocumentWidget_(d);
2992 iChangeFlags(d->flags, 3003 iChangeFlags(d->flags,
2993 urlChanged_DocumentWidgetFlag | drawDownloadCounter_DocumentWidgetFlag, 3004 urlChanged_DocumentWidgetFlag | drawDownloadCounter_DocumentWidgetFlag,
2994 iFalse); 3005 iFalse);
@@ -4377,7 +4388,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
4377 if (run->flags & altText_GmRunFlag) { 4388 if (run->flags & altText_GmRunFlag) {
4378 const iInt2 margin = preRunMargin_GmDocument(doc, preId_GmRun(run)); 4389 const iInt2 margin = preRunMargin_GmDocument(doc, preId_GmRun(run));
4379 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId); 4390 fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId);
4380 drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); 4391 drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmFrameAltText_ColorId);
4381 drawWrapRange_Text(run->font, 4392 drawWrapRange_Text(run->font,
4382 add_I2(visPos, margin), 4393 add_I2(visPos, margin),
4383 run->visBounds.size.x - 2 * margin.x, 4394 run->visBounds.size.x - 2 * margin.x,
@@ -5053,7 +5064,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
5053 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); 5064 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND);
5054 } 5065 }
5055 fillRect_Paint(&ctx.paint, altRect, tmBackgroundAltText_ColorId); 5066 fillRect_Paint(&ctx.paint, altRect, tmBackgroundAltText_ColorId);
5056 drawRect_Paint(&ctx.paint, altRect, tmQuoteIcon_ColorId); 5067 drawRect_Paint(&ctx.paint, altRect, tmFrameAltText_ColorId);
5057 setOpacity_Text(altTextOpacity); 5068 setOpacity_Text(altTextOpacity);
5058 drawWrapRange_Text(altFont, addX_I2(pos, margin), wrap, 5069 drawWrapRange_Text(altFont, addX_I2(pos, margin), wrap,
5059 tmQuote_ColorId, meta->altText); 5070 tmQuote_ColorId, meta->altText);
diff --git a/src/ui/labelwidget.c b/src/ui/labelwidget.c
index fbcd24b9..daca05d1 100644
--- a/src/ui/labelwidget.c
+++ b/src/ui/labelwidget.c
@@ -380,8 +380,12 @@ static void draw_LabelWidget_(const iLabelWidget *d) {
380 } 380 }
381 if (d->flags.wrap) { 381 if (d->flags.wrap) {
382 const iRect cont = contentBounds_LabelWidget_(d); 382 const iRect cont = contentBounds_LabelWidget_(d);
383 drawWrapRange_Text( 383 iWrapText wt = {
384 d->font, topLeft_Rect(cont), width_Rect(cont), fg, range_String(&d->label)); 384 .text = range_String(&d->label),
385 .maxWidth = width_Rect(cont),
386 .mode = word_WrapTextMode,
387 };
388 draw_WrapText(&wt, d->font, topLeft_Rect(cont), fg);
385 } 389 }
386 else if (flags & alignLeft_WidgetFlag) { 390 else if (flags & alignLeft_WidgetFlag) {
387 draw_Text(d->font, add_I2(bounds.pos, addX_I2(padding_LabelWidget_(d, 0), iconPad)), 391 draw_Text(d->font, add_I2(bounds.pos, addX_I2(padding_LabelWidget_(d, 0), iconPad)),
diff --git a/src/ui/text.c b/src/ui/text.c
index 106c55e9..2ef54d39 100644
--- a/src/ui/text.c
+++ b/src/ui/text.c
@@ -264,6 +264,7 @@ struct Impl_Text {
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 baseColorId;
267 iBool missingGlyphs; /* true if a glyph couldn't be found */
267}; 268};
268 269
269iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) 270iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render)
@@ -797,6 +798,7 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) {
797 } 798 }
798#endif // 0 799#endif // 0
799 if (!*glyphIndex) { 800 if (!*glyphIndex) {
801 activeText_->missingGlyphs = iTrue;
800 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); 802 fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr);
801 } 803 }
802 return d; 804 return d;
@@ -2260,6 +2262,13 @@ iTextMetrics draw_WrapText(iWrapText *d, int fontId, iInt2 pos, int color) {
2260 return tm; 2262 return tm;
2261} 2263}
2262 2264
2265iBool checkMissing_Text(void) {
2266 iText *d = activeText_;
2267 const iBool missing = d->missingGlyphs;
2268 d->missingGlyphs = iFalse;
2269 return missing;
2270}
2271
2263SDL_Texture *glyphCache_Text(void) { 2272SDL_Texture *glyphCache_Text(void) {
2264 return activeText_->cache; 2273 return activeText_->cache;
2265} 2274}
diff --git a/src/ui/text.h b/src/ui/text.h
index 99ddb704..13a636d4 100644
--- a/src/ui/text.h
+++ b/src/ui/text.h
@@ -220,6 +220,7 @@ struct Impl_WrapText {
220iTextMetrics measure_WrapText (iWrapText *, int fontId); 220iTextMetrics measure_WrapText (iWrapText *, int fontId);
221iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color); 221iTextMetrics draw_WrapText (iWrapText *, int fontId, iInt2 pos, int color);
222 222
223iBool checkMissing_Text (void); /* returns the flag, and clears it */
223SDL_Texture * glyphCache_Text (void); 224SDL_Texture * glyphCache_Text (void);
224 225
225enum iTextBlockMode { quadrants_TextBlockMode, shading_TextBlockMode }; 226enum iTextBlockMode { quadrants_TextBlockMode, shading_TextBlockMode };