diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-22 11:37:15 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-22 11:37:15 +0300 |
commit | 8700c039dc04b4c9f22584d4e901ed372442b0f4 (patch) | |
tree | c89a1c5cda9baa3204b46df0162f5b1ba62add04 | |
parent | c6182b6b4158a3227546ae55895b72a326db19fb (diff) |
DocumentWidget: Drawing side elements
The banner appears on the left, if there is room in the margin. Also added a document timestamp in the bottom to see when the data was received.
-rw-r--r-- | src/gmdocument.c | 22 | ||||
-rw-r--r-- | src/gmdocument.h | 2 | ||||
-rw-r--r-- | src/gmrequest.c | 6 | ||||
-rw-r--r-- | src/gmrequest.h | 1 | ||||
-rw-r--r-- | src/ui/color.h | 5 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 88 |
6 files changed, 120 insertions, 4 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 4414b04f..0d104dde 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -110,6 +110,7 @@ struct Impl_GmDocument { | |||
110 | iInt2 size; | 110 | iInt2 size; |
111 | iArray layout; /* contents of source, laid out in document space */ | 111 | iArray layout; /* contents of source, laid out in document space */ |
112 | iPtrArray links; | 112 | iPtrArray links; |
113 | iString bannerText; | ||
113 | iString title; /* the first top-level title */ | 114 | iString title; /* the first top-level title */ |
114 | iArray headings; | 115 | iArray headings; |
115 | iPtrArray images; /* persistent across layouts, references links by ID */ | 116 | iPtrArray images; /* persistent across layouts, references links by ID */ |
@@ -336,6 +337,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
336 | clearLinks_GmDocument_(d); | 337 | clearLinks_GmDocument_(d); |
337 | clear_Array(&d->headings); | 338 | clear_Array(&d->headings); |
338 | clear_String(&d->title); | 339 | clear_String(&d->title); |
340 | clear_String(&d->bannerText); | ||
339 | if (d->size.x <= 0 || isEmpty_String(&d->source)) { | 341 | if (d->size.x <= 0 || isEmpty_String(&d->source)) { |
340 | return; | 342 | return; |
341 | } | 343 | } |
@@ -419,6 +421,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
419 | addSiteBanner = iFalse; | 421 | addSiteBanner = iFalse; |
420 | const iRangecc bannerText = urlHost_String(&d->url); | 422 | const iRangecc bannerText = urlHost_String(&d->url); |
421 | if (!isEmpty_Range(&bannerText)) { | 423 | if (!isEmpty_Range(&bannerText)) { |
424 | setRange_String(&d->bannerText, bannerText); | ||
422 | iGmRun banner = { .flags = decoration_GmRunFlag | siteBanner_GmRunFlag }; | 425 | iGmRun banner = { .flags = decoration_GmRunFlag | siteBanner_GmRunFlag }; |
423 | banner.bounds = zero_Rect(); | 426 | banner.bounds = zero_Rect(); |
424 | banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2); | 427 | banner.visBounds = init_Rect(0, 0, d->size.x, lineHeight_Text(banner_FontId) * 2); |
@@ -618,6 +621,7 @@ void init_GmDocument(iGmDocument *d) { | |||
618 | d->size = zero_I2(); | 621 | d->size = zero_I2(); |
619 | init_Array(&d->layout, sizeof(iGmRun)); | 622 | init_Array(&d->layout, sizeof(iGmRun)); |
620 | init_PtrArray(&d->links); | 623 | init_PtrArray(&d->links); |
624 | init_String(&d->bannerText); | ||
621 | init_String(&d->title); | 625 | init_String(&d->title); |
622 | init_Array(&d->headings, sizeof(iGmHeading)); | 626 | init_Array(&d->headings, sizeof(iGmHeading)); |
623 | init_PtrArray(&d->images); | 627 | init_PtrArray(&d->images); |
@@ -626,6 +630,7 @@ void init_GmDocument(iGmDocument *d) { | |||
626 | } | 630 | } |
627 | 631 | ||
628 | void deinit_GmDocument(iGmDocument *d) { | 632 | void deinit_GmDocument(iGmDocument *d) { |
633 | deinit_String(&d->bannerText); | ||
629 | deinit_String(&d->title); | 634 | deinit_String(&d->title); |
630 | clearLinks_GmDocument_(d); | 635 | clearLinks_GmDocument_(d); |
631 | deinit_PtrArray(&d->links); | 636 | deinit_PtrArray(&d->links); |
@@ -903,8 +908,12 @@ void setThemeSeed_GmDocument(iGmDocument *d, const iBlock *seed) { | |||
903 | setHsl_Color(i, color); | 908 | setHsl_Color(i, color); |
904 | } | 909 | } |
905 | } | 910 | } |
911 | /* Derived colors. */ | ||
906 | set_Color(tmQuoteIcon_ColorId, | 912 | set_Color(tmQuoteIcon_ColorId, |
907 | mix_Color(get_Color(tmQuote_ColorId), get_Color(tmBackground_ColorId), 0.55f)); | 913 | mix_Color(get_Color(tmQuote_ColorId), get_Color(tmBackground_ColorId), 0.55f)); |
914 | set_Color(tmBannerSideTitle_ColorId, | ||
915 | mix_Color(get_Color(tmBannerTitle_ColorId), get_Color(tmBackground_ColorId), | ||
916 | theme == colorfulDark_GmDocumentTheme ? 0.55f : 0)); | ||
908 | /* Special exceptions. */ | 917 | /* Special exceptions. */ |
909 | if (seed) { | 918 | if (seed) { |
910 | if (equal_CStr(cstr_Block(seed), "gemini.circumlunar.space")) { | 919 | if (equal_CStr(cstr_Block(seed), "gemini.circumlunar.space")) { |
@@ -1047,11 +1056,22 @@ iInt2 size_GmDocument(const iGmDocument *d) { | |||
1047 | } | 1056 | } |
1048 | 1057 | ||
1049 | iBool hasSiteBanner_GmDocument(const iGmDocument *d) { | 1058 | iBool hasSiteBanner_GmDocument(const iGmDocument *d) { |
1059 | return siteBanner_GmDocument(d) != NULL; | ||
1060 | } | ||
1061 | |||
1062 | const iGmRun *siteBanner_GmDocument(const iGmDocument *d) { | ||
1050 | if (isEmpty_Array(&d->layout)) { | 1063 | if (isEmpty_Array(&d->layout)) { |
1051 | return iFalse; | 1064 | return iFalse; |
1052 | } | 1065 | } |
1053 | const iGmRun *first = constFront_Array(&d->layout); | 1066 | const iGmRun *first = constFront_Array(&d->layout); |
1054 | return (first->flags & siteBanner_GmRunFlag) != 0; | 1067 | if (first->flags & siteBanner_GmRunFlag) { |
1068 | return first; | ||
1069 | } | ||
1070 | return NULL; | ||
1071 | } | ||
1072 | |||
1073 | const iString *bannerText_GmDocument(const iGmDocument *d) { | ||
1074 | return &d->bannerText; | ||
1055 | } | 1075 | } |
1056 | 1076 | ||
1057 | const iArray *headings_GmDocument(const iGmDocument *d) { | 1077 | const iArray *headings_GmDocument(const iGmDocument *d) { |
diff --git a/src/gmdocument.h b/src/gmdocument.h index b16df677..ec47258a 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -115,7 +115,9 @@ typedef void (*iGmDocumentRenderFunc)(void *, const iGmRun *); | |||
115 | void render_GmDocument (const iGmDocument *, iRangei visRangeY, | 115 | void render_GmDocument (const iGmDocument *, iRangei visRangeY, |
116 | iGmDocumentRenderFunc render, void *); | 116 | iGmDocumentRenderFunc render, void *); |
117 | iInt2 size_GmDocument (const iGmDocument *); | 117 | iInt2 size_GmDocument (const iGmDocument *); |
118 | const iGmRun * siteBanner_GmDocument (const iGmDocument *); | ||
118 | iBool hasSiteBanner_GmDocument (const iGmDocument *); | 119 | iBool hasSiteBanner_GmDocument (const iGmDocument *); |
120 | const iString * bannerText_GmDocument (const iGmDocument *); | ||
119 | const iArray * headings_GmDocument (const iGmDocument *); | 121 | const iArray * headings_GmDocument (const iGmDocument *); |
120 | const iString * source_GmDocument (const iGmDocument *); | 122 | const iString * source_GmDocument (const iGmDocument *); |
121 | 123 | ||
diff --git a/src/gmrequest.c b/src/gmrequest.c index 43cc874a..b667c82a 100644 --- a/src/gmrequest.c +++ b/src/gmrequest.c | |||
@@ -44,6 +44,7 @@ void init_GmResponse(iGmResponse *d) { | |||
44 | d->certFlags = 0; | 44 | d->certFlags = 0; |
45 | iZap(d->certValidUntil); | 45 | iZap(d->certValidUntil); |
46 | init_String(&d->certSubject); | 46 | init_String(&d->certSubject); |
47 | iZap(d->when); | ||
47 | } | 48 | } |
48 | 49 | ||
49 | void initCopy_GmResponse(iGmResponse *d, const iGmResponse *other) { | 50 | void initCopy_GmResponse(iGmResponse *d, const iGmResponse *other) { |
@@ -53,6 +54,7 @@ void initCopy_GmResponse(iGmResponse *d, const iGmResponse *other) { | |||
53 | d->certFlags = other->certFlags; | 54 | d->certFlags = other->certFlags; |
54 | d->certValidUntil = other->certValidUntil; | 55 | d->certValidUntil = other->certValidUntil; |
55 | initCopy_String(&d->certSubject, &other->certSubject); | 56 | initCopy_String(&d->certSubject, &other->certSubject); |
57 | d->when = other->when; | ||
56 | } | 58 | } |
57 | 59 | ||
58 | void deinit_GmResponse(iGmResponse *d) { | 60 | void deinit_GmResponse(iGmResponse *d) { |
@@ -68,6 +70,7 @@ void clear_GmResponse(iGmResponse *d) { | |||
68 | d->certFlags = 0; | 70 | d->certFlags = 0; |
69 | iZap(d->certValidUntil); | 71 | iZap(d->certValidUntil); |
70 | clear_String(&d->certSubject); | 72 | clear_String(&d->certSubject); |
73 | iZap(d->when); | ||
71 | } | 74 | } |
72 | 75 | ||
73 | iGmResponse *copy_GmResponse(const iGmResponse *d) { | 76 | iGmResponse *copy_GmResponse(const iGmResponse *d) { |
@@ -83,6 +86,7 @@ void serialize_GmResponse(const iGmResponse *d, iStream *outs) { | |||
83 | write32_Stream(outs, d->certFlags); | 86 | write32_Stream(outs, d->certFlags); |
84 | serialize_Date(&d->certValidUntil, outs); | 87 | serialize_Date(&d->certValidUntil, outs); |
85 | serialize_String(&d->certSubject, outs); | 88 | serialize_String(&d->certSubject, outs); |
89 | /* TODO: Include the timestamp. */ | ||
86 | } | 90 | } |
87 | 91 | ||
88 | void deserialize_GmResponse(iGmResponse *d, iStream *ins) { | 92 | void deserialize_GmResponse(iGmResponse *d, iStream *ins) { |
@@ -270,6 +274,7 @@ static void readIncoming_GmRequest_(iAnyObject *obj) { | |||
270 | restartTimeout_GmRequest_(d); | 274 | restartTimeout_GmRequest_(d); |
271 | notifyUpdate = iTrue; | 275 | notifyUpdate = iTrue; |
272 | } | 276 | } |
277 | initCurrent_Time(&d->resp.when); | ||
273 | delete_Block(data); | 278 | delete_Block(data); |
274 | unlock_Mutex(&d->mutex); | 279 | unlock_Mutex(&d->mutex); |
275 | if (notifyUpdate) { | 280 | if (notifyUpdate) { |
@@ -287,6 +292,7 @@ static void requestFinished_GmRequest_(iAnyObject *obj) { | |||
287 | iBlock *data = readAll_TlsRequest(d->req); | 292 | iBlock *data = readAll_TlsRequest(d->req); |
288 | iAssert(isEmpty_Block(data)); | 293 | iAssert(isEmpty_Block(data)); |
289 | delete_Block(data); | 294 | delete_Block(data); |
295 | initCurrent_Time(&d->resp.when); | ||
290 | } | 296 | } |
291 | SDL_RemoveTimer(d->timeoutId); | 297 | SDL_RemoveTimer(d->timeoutId); |
292 | d->timeoutId = 0; | 298 | d->timeoutId = 0; |
diff --git a/src/gmrequest.h b/src/gmrequest.h index 2f1a4261..4d413430 100644 --- a/src/gmrequest.h +++ b/src/gmrequest.h | |||
@@ -44,6 +44,7 @@ struct Impl_GmResponse { | |||
44 | int certFlags; | 44 | int certFlags; |
45 | iDate certValidUntil; | 45 | iDate certValidUntil; |
46 | iString certSubject; | 46 | iString certSubject; |
47 | iTime when; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | iDeclareTypeConstruction(GmResponse) | 50 | iDeclareTypeConstruction(GmResponse) |
diff --git a/src/ui/color.h b/src/ui/color.h index 51d3370f..0f534272 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -117,6 +117,7 @@ enum iColorId { | |||
117 | tmBannerBackground_ColorId, | 117 | tmBannerBackground_ColorId, |
118 | tmBannerTitle_ColorId, | 118 | tmBannerTitle_ColorId, |
119 | tmBannerIcon_ColorId, | 119 | tmBannerIcon_ColorId, |
120 | tmBannerSideTitle_ColorId, | ||
120 | tmInlineContentMetadata_ColorId, | 121 | tmInlineContentMetadata_ColorId, |
121 | tmBadLink_ColorId, | 122 | tmBadLink_ColorId, |
122 | 123 | ||
@@ -193,6 +194,10 @@ struct Impl_Color { | |||
193 | uint8_t r, g, b, a; | 194 | uint8_t r, g, b, a; |
194 | }; | 195 | }; |
195 | 196 | ||
197 | iLocalDef iBool equal_Color(const iColor a, const iColor b) { | ||
198 | return memcmp(&a, &b, sizeof(a)) == 0; | ||
199 | } | ||
200 | |||
196 | struct Impl_HSLColor { | 201 | struct Impl_HSLColor { |
197 | float hue, sat, lum, a; | 202 | float hue, sat, lum, a; |
198 | }; | 203 | }; |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 2fc5c548..351d1e62 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -146,6 +146,7 @@ struct Impl_DocumentWidget { | |||
146 | iObjectList * media; | 146 | iObjectList * media; |
147 | iString sourceMime; | 147 | iString sourceMime; |
148 | iBlock sourceContent; /* original content as received, for saving */ | 148 | iBlock sourceContent; /* original content as received, for saving */ |
149 | iTime sourceTime; | ||
149 | iGmDocument * doc; | 150 | iGmDocument * doc; |
150 | int certFlags; | 151 | int certFlags; |
151 | iDate certExpiry; | 152 | iDate certExpiry; |
@@ -168,6 +169,7 @@ struct Impl_DocumentWidget { | |||
168 | int smoothSpeed; | 169 | int smoothSpeed; |
169 | int smoothLastOffset; | 170 | int smoothLastOffset; |
170 | iBool smoothContinue; | 171 | iBool smoothContinue; |
172 | iAnim sideOpacity; | ||
171 | iWidget * menu; | 173 | iWidget * menu; |
172 | iVisBuf * visBuf; | 174 | iVisBuf * visBuf; |
173 | iPtrSet * invalidRuns; | 175 | iPtrSet * invalidRuns; |
@@ -207,6 +209,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
207 | d->showLinkNumbers = iFalse; | 209 | d->showLinkNumbers = iFalse; |
208 | d->visBuf = new_VisBuf(); | 210 | d->visBuf = new_VisBuf(); |
209 | d->invalidRuns = new_PtrSet(); | 211 | d->invalidRuns = new_PtrSet(); |
212 | init_Anim(&d->sideOpacity, 0); | ||
210 | init_String(&d->sourceMime); | 213 | init_String(&d->sourceMime); |
211 | init_Block(&d->sourceContent, 0); | 214 | init_Block(&d->sourceContent, 0); |
212 | init_PtrArray(&d->visibleLinks); | 215 | init_PtrArray(&d->visibleLinks); |
@@ -374,6 +377,23 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
374 | } | 377 | } |
375 | } | 378 | } |
376 | 379 | ||
380 | static void animate_DocumentWidget_(void *ticker) { | ||
381 | iDocumentWidget *d = ticker; | ||
382 | if (!isFinished_Anim(&d->sideOpacity)) { | ||
383 | addTicker_App(animate_DocumentWidget_, d); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d) { | ||
388 | float opacity = 0.0f; | ||
389 | const iGmRun *banner = siteBanner_GmDocument(d->doc); | ||
390 | if (banner && bottom_Rect(banner->visBounds) < d->scrollY) { | ||
391 | opacity = 1.0f; | ||
392 | } | ||
393 | setValue_Anim(&d->sideOpacity, opacity, opacity < 0.5f ? 166 : 333); | ||
394 | animate_DocumentWidget_(d); | ||
395 | } | ||
396 | |||
377 | static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | 397 | static void updateVisible_DocumentWidget_(iDocumentWidget *d) { |
378 | const iRangei visRange = visibleRange_DocumentWidget_(d); | 398 | const iRangei visRange = visibleRange_DocumentWidget_(d); |
379 | const iRect bounds = bounds_Widget(as_Widget(d)); | 399 | const iRect bounds = bounds_Widget(as_Widget(d)); |
@@ -385,6 +405,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
385 | clear_PtrArray(&d->visibleLinks); | 405 | clear_PtrArray(&d->visibleLinks); |
386 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); | 406 | render_GmDocument(d->doc, visRange, addVisibleLink_DocumentWidget_, d); |
387 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); | 407 | updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); |
408 | updateSideOpacity_DocumentWidget_(d); | ||
388 | /* Remember scroll positions of recently visited pages. */ { | 409 | /* Remember scroll positions of recently visited pages. */ { |
389 | iRecentUrl *recent = mostRecentUrl_History(d->mod.history); | 410 | iRecentUrl *recent = mostRecentUrl_History(d->mod.history); |
390 | if (recent && docSize && d->state == ready_RequestState) { | 411 | if (recent && docSize && d->state == ready_RequestState) { |
@@ -537,6 +558,7 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode | |||
537 | setSource_DocumentWidget_(d, src); | 558 | setSource_DocumentWidget_(d, src); |
538 | resetSmoothScroll_DocumentWidget_(d); | 559 | resetSmoothScroll_DocumentWidget_(d); |
539 | d->scrollY = 0; | 560 | d->scrollY = 0; |
561 | init_Anim(&d->sideOpacity, 0); | ||
540 | d->state = ready_RequestState; | 562 | d->state = ready_RequestState; |
541 | } | 563 | } |
542 | 564 | ||
@@ -578,7 +600,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
578 | updateTheme_DocumentWidget_(d); | 600 | updateTheme_DocumentWidget_(d); |
579 | } | 601 | } |
580 | clear_String(&d->sourceMime); | 602 | clear_String(&d->sourceMime); |
581 | // set_Block(&d->sourceContent, &response->body); | 603 | d->sourceTime = response->when; |
582 | initBlock_String(&str, &response->body); | 604 | initBlock_String(&str, &response->body); |
583 | if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) { | 605 | if (category_GmStatusCode(statusCode) == categorySuccess_GmStatusCode) { |
584 | /* Check the MIME type. */ | 606 | /* Check the MIME type. */ |
@@ -1706,6 +1728,11 @@ struct Impl_DrawContext { | |||
1706 | iBool showLinkNumbers; | 1728 | iBool showLinkNumbers; |
1707 | }; | 1729 | }; |
1708 | 1730 | ||
1731 | static iRangecc bannerText_DocumentWidget_(const iDocumentWidget *d) { | ||
1732 | return isEmpty_String(d->titleUser) ? range_String(bannerText_GmDocument(d->doc)) | ||
1733 | : range_String(d->titleUser); | ||
1734 | } | ||
1735 | |||
1709 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, | 1736 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, |
1710 | iRangecc mark, iBool *isInside) { | 1737 | iRangecc mark, iBool *isInside) { |
1711 | if (mark.start > mark.end) { | 1738 | if (mark.start > mark.end) { |
@@ -1802,8 +1829,9 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
1802 | drawRange_Text(run->font, | 1829 | drawRange_Text(run->font, |
1803 | bpos, | 1830 | bpos, |
1804 | tmBannerTitle_ColorId, | 1831 | tmBannerTitle_ColorId, |
1805 | isEmpty_String(d->widget->titleUser) ? run->text | 1832 | bannerText_DocumentWidget_(d->widget)); |
1806 | : range_String(d->widget->titleUser)); | 1833 | // isEmpty_String(d->widget->titleUser) ? run->text |
1834 | // : range_String(d->widget->titleUser)); | ||
1807 | deinit_String(&bannerText); | 1835 | deinit_String(&bannerText); |
1808 | } | 1836 | } |
1809 | else { | 1837 | else { |
@@ -1936,6 +1964,59 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
1936 | // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); | 1964 | // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); |
1937 | } | 1965 | } |
1938 | 1966 | ||
1967 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | ||
1968 | const iWidget *w = constAs_Widget(d); | ||
1969 | const iRect bounds = bounds_Widget(w); | ||
1970 | const iRect docBounds = documentBounds_DocumentWidget_(d); | ||
1971 | const int margin = gap_UI * d->pageMargin; | ||
1972 | const iGmRun * banner = siteBanner_GmDocument(d->doc); | ||
1973 | float opacity = value_Anim(&d->sideOpacity); | ||
1974 | const int minBannerSize = lineHeight_Text(banner_FontId) * 2; | ||
1975 | const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin; | ||
1976 | if (avail > minBannerSize) { | ||
1977 | if (banner && opacity > 0) { | ||
1978 | setOpacity_Text(opacity); | ||
1979 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | ||
1980 | const iChar icon = siteIcon_GmDocument(d->doc); | ||
1981 | iRect rect = { add_I2(topLeft_Rect(bounds), init1_I2(margin)), init1_I2(minBannerSize) }; | ||
1982 | iPaint p; | ||
1983 | init_Paint(&p); | ||
1984 | p.alpha = opacity * 255; | ||
1985 | int offset = iMax(0, bottom_Rect(banner->visBounds) - d->scrollY); | ||
1986 | rect.pos.y += offset; | ||
1987 | if (equal_Color(get_Color(tmBannerBackground_ColorId), get_Color(tmBackground_ColorId))) { | ||
1988 | drawRectThickness_Paint(&p, rect, gap_UI / 2, tmBannerIcon_ColorId); | ||
1989 | } | ||
1990 | else { | ||
1991 | fillRect_Paint(&p, rect, tmBannerBackground_ColorId); | ||
1992 | } | ||
1993 | iString str; | ||
1994 | initUnicodeN_String(&str, &icon, 1); | ||
1995 | drawCentered_Text(banner_FontId, rect, iTrue, tmBannerIcon_ColorId, "%s", cstr_String(&str)); | ||
1996 | if (avail >= minBannerSize * 2) { | ||
1997 | const char *endp; | ||
1998 | iRangecc text = bannerText_DocumentWidget_(d); | ||
1999 | iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); | ||
2000 | const int font = banner_FontId; | ||
2001 | while (!isEmpty_Range(&text)) { | ||
2002 | tryAdvance_Text(font, text, avail - 2 * margin, &endp); | ||
2003 | drawRange_Text(font, pos, tmBannerSideTitle_ColorId, (iRangecc){ text.start, endp }); | ||
2004 | text.start = endp; | ||
2005 | pos.y += lineHeight_Text(font); | ||
2006 | } | ||
2007 | } | ||
2008 | setOpacity_Text(1.0f); | ||
2009 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | ||
2010 | } | ||
2011 | /* Update date. */ | ||
2012 | drawString_Text(default_FontId, | ||
2013 | add_I2(bottomLeft_Rect(bounds), | ||
2014 | init_I2(margin, -margin + -2 * lineHeight_Text(default_FontId))), | ||
2015 | tmQuoteIcon_ColorId, | ||
2016 | collect_String(format_Time(&d->sourceTime, "Received\n%H:%M %b %d, %Y"))); | ||
2017 | } | ||
2018 | } | ||
2019 | |||
1939 | static void draw_DocumentWidget_(const iDocumentWidget *d) { | 2020 | static void draw_DocumentWidget_(const iDocumentWidget *d) { |
1940 | const iWidget *w = constAs_Widget(d); | 2021 | const iWidget *w = constAs_Widget(d); |
1941 | const iRect bounds = bounds_Widget(w); | 2022 | const iRect bounds = bounds_Widget(w); |
@@ -2025,6 +2106,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
2025 | init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), | 2106 | init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), |
2026 | tmBackground_ColorId); | 2107 | tmBackground_ColorId); |
2027 | } | 2108 | } |
2109 | drawSideElements_DocumentWidget_(d); | ||
2028 | draw_Widget(w); | 2110 | draw_Widget(w); |
2029 | } | 2111 | } |
2030 | 2112 | ||