diff options
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r-- | src/ui/documentwidget.c | 226 |
1 files changed, 203 insertions, 23 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 351d1e62..0079465f 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -127,6 +127,18 @@ iDefineTypeConstruction(Model) | |||
127 | 127 | ||
128 | /*----------------------------------------------------------------------------------------------*/ | 128 | /*----------------------------------------------------------------------------------------------*/ |
129 | 129 | ||
130 | iDeclareType(OutlineItem) | ||
131 | |||
132 | struct Impl_OutlineItem { | ||
133 | iRangecc text; | ||
134 | int font; | ||
135 | iRect rect; | ||
136 | int seenColor; | ||
137 | int sepColor; | ||
138 | }; | ||
139 | |||
140 | /*----------------------------------------------------------------------------------------------*/ | ||
141 | |||
130 | static const int smoothSpeed_DocumentWidget_ = 120; /* unit: gap_Text per second */ | 142 | static const int smoothSpeed_DocumentWidget_ = 120; /* unit: gap_Text per second */ |
131 | 143 | ||
132 | enum iRequestState { | 144 | enum iRequestState { |
@@ -161,6 +173,7 @@ struct Impl_DocumentWidget { | |||
161 | const iGmRun * contextLink; | 173 | const iGmRun * contextLink; |
162 | iBool noHoverWhileScrolling; | 174 | iBool noHoverWhileScrolling; |
163 | iBool showLinkNumbers; | 175 | iBool showLinkNumbers; |
176 | const iGmRun * lastVisibleRun; | ||
164 | iClick click; | 177 | iClick click; |
165 | float initNormScrollY; | 178 | float initNormScrollY; |
166 | int scrollY; | 179 | int scrollY; |
@@ -170,6 +183,8 @@ struct Impl_DocumentWidget { | |||
170 | int smoothLastOffset; | 183 | int smoothLastOffset; |
171 | iBool smoothContinue; | 184 | iBool smoothContinue; |
172 | iAnim sideOpacity; | 185 | iAnim sideOpacity; |
186 | iAnim outlineOpacity; | ||
187 | iArray outline; | ||
173 | iWidget * menu; | 188 | iWidget * menu; |
174 | iVisBuf * visBuf; | 189 | iVisBuf * visBuf; |
175 | iPtrSet * invalidRuns; | 190 | iPtrSet * invalidRuns; |
@@ -207,8 +222,10 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
207 | d->contextLink = NULL; | 222 | d->contextLink = NULL; |
208 | d->noHoverWhileScrolling = iFalse; | 223 | d->noHoverWhileScrolling = iFalse; |
209 | d->showLinkNumbers = iFalse; | 224 | d->showLinkNumbers = iFalse; |
225 | d->lastVisibleRun = NULL; | ||
210 | d->visBuf = new_VisBuf(); | 226 | d->visBuf = new_VisBuf(); |
211 | d->invalidRuns = new_PtrSet(); | 227 | d->invalidRuns = new_PtrSet(); |
228 | init_Array(&d->outline, sizeof(iOutlineItem)); | ||
212 | init_Anim(&d->sideOpacity, 0); | 229 | init_Anim(&d->sideOpacity, 0); |
213 | init_String(&d->sourceMime); | 230 | init_String(&d->sourceMime); |
214 | init_Block(&d->sourceContent, 0); | 231 | init_Block(&d->sourceContent, 0); |
@@ -227,6 +244,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
227 | void deinit_DocumentWidget(iDocumentWidget *d) { | 244 | void deinit_DocumentWidget(iDocumentWidget *d) { |
228 | delete_VisBuf(d->visBuf); | 245 | delete_VisBuf(d->visBuf); |
229 | delete_PtrSet(d->invalidRuns); | 246 | delete_PtrSet(d->invalidRuns); |
247 | deinit_Array(&d->outline); | ||
230 | iRelease(d->media); | 248 | iRelease(d->media); |
231 | iRelease(d->request); | 249 | iRelease(d->request); |
232 | deinit_Block(&d->sourceContent); | 250 | deinit_Block(&d->sourceContent); |
@@ -314,6 +332,7 @@ static iRangei visibleRange_DocumentWidget_(const iDocumentWidget *d) { | |||
314 | 332 | ||
315 | static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { | 333 | static void addVisibleLink_DocumentWidget_(void *context, const iGmRun *run) { |
316 | iDocumentWidget *d = context; | 334 | iDocumentWidget *d = context; |
335 | d->lastVisibleRun = run; | ||
317 | if (run->linkId && linkFlags_GmDocument(d->doc, run->linkId) & supportedProtocol_GmLinkFlag) { | 336 | if (run->linkId && linkFlags_GmDocument(d->doc, run->linkId) & supportedProtocol_GmLinkFlag) { |
318 | pushBack_PtrArray(&d->visibleLinks, run); | 337 | pushBack_PtrArray(&d->visibleLinks, run); |
319 | } | 338 | } |
@@ -379,7 +398,7 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
379 | 398 | ||
380 | static void animate_DocumentWidget_(void *ticker) { | 399 | static void animate_DocumentWidget_(void *ticker) { |
381 | iDocumentWidget *d = ticker; | 400 | iDocumentWidget *d = ticker; |
382 | if (!isFinished_Anim(&d->sideOpacity)) { | 401 | if (!isFinished_Anim(&d->sideOpacity) || !isFinished_Anim(&d->outlineOpacity)) { |
383 | addTicker_App(animate_DocumentWidget_, d); | 402 | addTicker_App(animate_DocumentWidget_, d); |
384 | } | 403 | } |
385 | } | 404 | } |
@@ -390,7 +409,20 @@ static void updateSideOpacity_DocumentWidget_(iDocumentWidget *d) { | |||
390 | if (banner && bottom_Rect(banner->visBounds) < d->scrollY) { | 409 | if (banner && bottom_Rect(banner->visBounds) < d->scrollY) { |
391 | opacity = 1.0f; | 410 | opacity = 1.0f; |
392 | } | 411 | } |
393 | setValue_Anim(&d->sideOpacity, opacity, opacity < 0.5f ? 166 : 333); | 412 | setValue_Anim(&d->sideOpacity, opacity, opacity < 0.5f ? 100 : 200); |
413 | animate_DocumentWidget_(d); | ||
414 | } | ||
415 | |||
416 | static void updateOutlineOpacity_DocumentWidget_(iDocumentWidget *d) { | ||
417 | float opacity = 0.0f; | ||
418 | if (isEmpty_Array(&d->outline)) { | ||
419 | setValue_Anim(&d->outlineOpacity, 0.0f, 0); | ||
420 | return; | ||
421 | } | ||
422 | if (contains_Widget(constAs_Widget(d->scroll), mouseCoord_Window(get_Window()))) { | ||
423 | opacity = 1.0f; | ||
424 | } | ||
425 | setValue_Anim(&d->outlineOpacity, opacity, opacity > 0.5f? 166 : 333); | ||
394 | animate_DocumentWidget_(d); | 426 | animate_DocumentWidget_(d); |
395 | } | 427 | } |
396 | 428 | ||
@@ -506,16 +538,77 @@ static void invalidate_DocumentWidget_(iDocumentWidget *d) { | |||
506 | clear_PtrSet(d->invalidRuns); | 538 | clear_PtrSet(d->invalidRuns); |
507 | } | 539 | } |
508 | 540 | ||
541 | static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ | ||
542 | static const int outlineMaxWidth_DocumentWidget_ = 65; /* times gap_UI */ | ||
543 | static const int outlinePadding_DocumentWidget_ = 3; /* times gap_UI */ | ||
544 | |||
545 | static int outlineWidth_DocumentWidget_(const iDocumentWidget *d) { | ||
546 | const iWidget *w = constAs_Widget(d); | ||
547 | const iRect bounds = bounds_Widget(w); | ||
548 | const int docWidth = documentWidth_DocumentWidget_(d); | ||
549 | int width = | ||
550 | (width_Rect(bounds) - docWidth) / 2 - gap_Text * d->pageMargin - gap_UI * d->pageMargin | ||
551 | - 2 * outlinePadding_DocumentWidget_ * gap_UI; | ||
552 | if (width < outlineMinWidth_DocumentWdiget_ * gap_UI) { | ||
553 | return outlineMinWidth_DocumentWdiget_ * gap_UI; | ||
554 | } | ||
555 | return iMin(width, outlineMaxWidth_DocumentWidget_ * gap_UI); | ||
556 | } | ||
557 | |||
558 | static iRangecc bannerText_DocumentWidget_(const iDocumentWidget *d) { | ||
559 | return isEmpty_String(d->titleUser) ? range_String(bannerText_GmDocument(d->doc)) | ||
560 | : range_String(d->titleUser); | ||
561 | } | ||
562 | |||
563 | static void updateOutline_DocumentWidget_(iDocumentWidget *d) { | ||
564 | iWidget *w = as_Widget(d); | ||
565 | int outWidth = outlineWidth_DocumentWidget_(d); | ||
566 | clear_Array(&d->outline); | ||
567 | if (outWidth == 0 || d->state != ready_RequestState) { | ||
568 | return; | ||
569 | } | ||
570 | if (size_GmDocument(d->doc).y < height_Rect(bounds_Widget(w)) * 2) { | ||
571 | return; /* Too short */ | ||
572 | } | ||
573 | iInt2 pos = zero_I2(); | ||
574 | // const iRangecc topText = urlHost_String(d->mod.url); | ||
575 | // iInt2 size = advanceWrapRange_Text(uiContent_FontId, outWidth, topText); | ||
576 | // pushBack_Array(&d->outline, &(iOutlineItem){ topText, uiContent_FontId, (iRect){ pos, size }, | ||
577 | // tmBannerTitle_ColorId, none_ColorId }); | ||
578 | // pos.y += size.y; | ||
579 | iInt2 size; | ||
580 | iConstForEach(Array, i, headings_GmDocument(d->doc)) { | ||
581 | const iGmHeading *head = i.value; | ||
582 | const int indent = head->level * 5 * gap_UI; | ||
583 | size = advanceWrapRange_Text(uiLabel_FontId, outWidth - indent, head->text); | ||
584 | if (head->level == 0) { | ||
585 | pos.y += gap_UI * 1.5f; | ||
586 | } | ||
587 | pushBack_Array(&d->outline, | ||
588 | &(iOutlineItem){ head->text, | ||
589 | uiLabel_FontId, | ||
590 | (iRect){ addX_I2(pos, indent), size }, | ||
591 | head->level == 0 ? tmHeading1_ColorId | ||
592 | : head->level == 1 ? tmHeading2_ColorId | ||
593 | : tmHeading3_ColorId, | ||
594 | head->level == 0 ? tmQuoteIcon_ColorId : none_ColorId }); | ||
595 | pos.y += size.y; | ||
596 | } | ||
597 | } | ||
598 | |||
509 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { | 599 | static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source) { |
510 | setUrl_GmDocument(d->doc, d->mod.url); | 600 | setUrl_GmDocument(d->doc, d->mod.url); |
511 | setSource_GmDocument( | 601 | setSource_GmDocument( |
512 | d->doc, source, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); | 602 | d->doc, source, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); |
513 | d->foundMark = iNullRange; | 603 | d->foundMark = iNullRange; |
514 | d->selectMark = iNullRange; | 604 | d->selectMark = iNullRange; |
515 | d->hoverLink = NULL; | 605 | d->hoverLink = NULL; |
516 | d->contextLink = NULL; | 606 | d->contextLink = NULL; |
607 | d->lastVisibleRun = NULL; | ||
608 | setValue_Anim(&d->outlineOpacity, 0.0f, 0); | ||
517 | updateWindowTitle_DocumentWidget_(d); | 609 | updateWindowTitle_DocumentWidget_(d); |
518 | updateVisible_DocumentWidget_(d); | 610 | updateVisible_DocumentWidget_(d); |
611 | updateOutline_DocumentWidget_(d); | ||
519 | invalidate_DocumentWidget_(d); | 612 | invalidate_DocumentWidget_(d); |
520 | refresh_Widget(as_Widget(d)); | 613 | refresh_Widget(as_Widget(d)); |
521 | } | 614 | } |
@@ -751,6 +844,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | |||
751 | updateDocument_DocumentWidget_(d, resp); | 844 | updateDocument_DocumentWidget_(d, resp); |
752 | d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y; | 845 | d->scrollY = d->initNormScrollY * size_GmDocument(d->doc).y; |
753 | d->state = ready_RequestState; | 846 | d->state = ready_RequestState; |
847 | updateOutline_DocumentWidget_(d); | ||
754 | updateVisible_DocumentWidget_(d); | 848 | updateVisible_DocumentWidget_(d); |
755 | postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); | 849 | postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); |
756 | return iTrue; | 850 | return iTrue; |
@@ -1069,6 +1163,7 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { | |||
1069 | void updateSize_DocumentWidget(iDocumentWidget *d) { | 1163 | void updateSize_DocumentWidget(iDocumentWidget *d) { |
1070 | setWidth_GmDocument( | 1164 | setWidth_GmDocument( |
1071 | d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); | 1165 | d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); |
1166 | updateOutline_DocumentWidget_(d); | ||
1072 | updateVisible_DocumentWidget_(d); | 1167 | updateVisible_DocumentWidget_(d); |
1073 | invalidate_DocumentWidget_(d); | 1168 | invalidate_DocumentWidget_(d); |
1074 | } | 1169 | } |
@@ -1087,6 +1182,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1087 | scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue); | 1182 | scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue); |
1088 | } | 1183 | } |
1089 | } | 1184 | } |
1185 | updateOutline_DocumentWidget_(d); | ||
1090 | invalidate_DocumentWidget_(d); | 1186 | invalidate_DocumentWidget_(d); |
1091 | dealloc_VisBuf(d->visBuf); | 1187 | dealloc_VisBuf(d->visBuf); |
1092 | refresh_Widget(w); | 1188 | refresh_Widget(w); |
@@ -1109,6 +1205,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1109 | updateSize_DocumentWidget(d); | 1205 | updateSize_DocumentWidget(d); |
1110 | updateFetchProgress_DocumentWidget_(d); | 1206 | updateFetchProgress_DocumentWidget_(d); |
1111 | } | 1207 | } |
1208 | updateOutlineOpacity_DocumentWidget_(d); | ||
1112 | updateWindowTitle_DocumentWidget_(d); | 1209 | updateWindowTitle_DocumentWidget_(d); |
1113 | allocVisBuffer_DocumentWidget_(d); | 1210 | allocVisBuffer_DocumentWidget_(d); |
1114 | return iFalse; | 1211 | return iFalse; |
@@ -1213,6 +1310,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
1213 | } | 1310 | } |
1214 | iReleasePtr(&d->request); | 1311 | iReleasePtr(&d->request); |
1215 | updateVisible_DocumentWidget_(d); | 1312 | updateVisible_DocumentWidget_(d); |
1313 | updateOutline_DocumentWidget_(d); | ||
1216 | postCommandf_App("document.changed url:%s", cstr_String(d->mod.url)); | 1314 | postCommandf_App("document.changed url:%s", cstr_String(d->mod.url)); |
1217 | return iFalse; | 1315 | return iFalse; |
1218 | } | 1316 | } |
@@ -1559,6 +1657,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1559 | else { | 1657 | else { |
1560 | updateHover_DocumentWidget_(d, init_I2(ev->motion.x, ev->motion.y)); | 1658 | updateHover_DocumentWidget_(d, init_I2(ev->motion.x, ev->motion.y)); |
1561 | } | 1659 | } |
1660 | updateOutlineOpacity_DocumentWidget_(d); | ||
1562 | } | 1661 | } |
1563 | if (ev->type == SDL_MOUSEBUTTONDOWN) { | 1662 | if (ev->type == SDL_MOUSEBUTTONDOWN) { |
1564 | if (ev->button.button == SDL_BUTTON_X1) { | 1663 | if (ev->button.button == SDL_BUTTON_X1) { |
@@ -1728,11 +1827,6 @@ struct Impl_DrawContext { | |||
1728 | iBool showLinkNumbers; | 1827 | iBool showLinkNumbers; |
1729 | }; | 1828 | }; |
1730 | 1829 | ||
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 | |||
1736 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, | 1830 | static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iColorId color, |
1737 | iRangecc mark, iBool *isInside) { | 1831 | iRangecc mark, iBool *isInside) { |
1738 | if (mark.start > mark.end) { | 1832 | if (mark.start > mark.end) { |
@@ -1964,6 +2058,15 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
1964 | // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); | 2058 | // drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); |
1965 | } | 2059 | } |
1966 | 2060 | ||
2061 | static void drawSideRect_(iPaint *p, iRect rect, int thickness) { | ||
2062 | if (equal_Color(get_Color(tmBannerBackground_ColorId), get_Color(tmBackground_ColorId))) { | ||
2063 | drawRectThickness_Paint(p, rect, thickness, tmBannerIcon_ColorId); | ||
2064 | } | ||
2065 | else { | ||
2066 | fillRect_Paint(p, rect, tmBannerBackground_ColorId); | ||
2067 | } | ||
2068 | } | ||
2069 | |||
1967 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | 2070 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { |
1968 | const iWidget *w = constAs_Widget(d); | 2071 | const iWidget *w = constAs_Widget(d); |
1969 | const iRect bounds = bounds_Widget(w); | 2072 | const iRect bounds = bounds_Widget(w); |
@@ -1973,17 +2076,19 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
1973 | float opacity = value_Anim(&d->sideOpacity); | 2076 | float opacity = value_Anim(&d->sideOpacity); |
1974 | const int minBannerSize = lineHeight_Text(banner_FontId) * 2; | 2077 | const int minBannerSize = lineHeight_Text(banner_FontId) * 2; |
1975 | const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin; | 2078 | const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin; |
2079 | iPaint p; | ||
2080 | init_Paint(&p); | ||
2081 | setClip_Paint(&p, bounds); | ||
1976 | if (avail > minBannerSize) { | 2082 | if (avail > minBannerSize) { |
1977 | if (banner && opacity > 0) { | 2083 | if (banner && opacity > 0) { |
1978 | setOpacity_Text(opacity); | 2084 | setOpacity_Text(opacity); |
1979 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | 2085 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); |
1980 | const iChar icon = siteIcon_GmDocument(d->doc); | 2086 | const iChar icon = siteIcon_GmDocument(d->doc); |
1981 | iRect rect = { add_I2(topLeft_Rect(bounds), init1_I2(margin)), init1_I2(minBannerSize) }; | 2087 | 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; | 2088 | p.alpha = opacity * 255; |
1985 | int offset = iMax(0, bottom_Rect(banner->visBounds) - d->scrollY); | 2089 | //int offset = iMax(0, bottom_Rect(banner->visBounds) - d->scrollY); |
1986 | rect.pos.y += offset; | 2090 | rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0); // offset; |
2091 | drawSideRect_(&p, rect, gap_UI / 2); | ||
1987 | if (equal_Color(get_Color(tmBannerBackground_ColorId), get_Color(tmBackground_ColorId))) { | 2092 | if (equal_Color(get_Color(tmBannerBackground_ColorId), get_Color(tmBackground_ColorId))) { |
1988 | drawRectThickness_Paint(&p, rect, gap_UI / 2, tmBannerIcon_ColorId); | 2093 | drawRectThickness_Paint(&p, rect, gap_UI / 2, tmBannerIcon_ColorId); |
1989 | } | 2094 | } |
@@ -1993,28 +2098,103 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
1993 | iString str; | 2098 | iString str; |
1994 | initUnicodeN_String(&str, &icon, 1); | 2099 | initUnicodeN_String(&str, &icon, 1); |
1995 | drawCentered_Text(banner_FontId, rect, iTrue, tmBannerIcon_ColorId, "%s", cstr_String(&str)); | 2100 | drawCentered_Text(banner_FontId, rect, iTrue, tmBannerIcon_ColorId, "%s", cstr_String(&str)); |
2101 | #if 0 | ||
1996 | if (avail >= minBannerSize * 2) { | 2102 | if (avail >= minBannerSize * 2) { |
1997 | const char *endp; | 2103 | const char *endp; |
1998 | iRangecc text = bannerText_DocumentWidget_(d); | 2104 | iRangecc text = bannerText_DocumentWidget_(d); |
1999 | iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); | 2105 | iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); |
2000 | const int font = banner_FontId; | 2106 | const int font = heading3_FontId; |
2001 | while (!isEmpty_Range(&text)) { | 2107 | while (!isEmpty_Range(&text)) { |
2002 | tryAdvance_Text(font, text, avail - 2 * margin, &endp); | 2108 | tryAdvance_Text(font, text, avail - 2 * margin, &endp); |
2003 | drawRange_Text(font, pos, tmBannerSideTitle_ColorId, (iRangecc){ text.start, endp }); | 2109 | drawRange_Text( |
2110 | font, pos, tmBannerTitle_ColorId, (iRangecc){ text.start, endp }); | ||
2111 | // drawRange_Text(font, | ||
2112 | // add_I2(pos, init1_I2(-gap_UI / 4)), | ||
2113 | // tmBackground_ColorId, | ||
2114 | // (iRangecc){ text.start, endp }); | ||
2004 | text.start = endp; | 2115 | text.start = endp; |
2005 | pos.y += lineHeight_Text(font); | 2116 | pos.y += lineHeight_Text(font); |
2006 | } | 2117 | } |
2007 | } | 2118 | } |
2119 | #endif | ||
2008 | setOpacity_Text(1.0f); | 2120 | setOpacity_Text(1.0f); |
2009 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | 2121 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); |
2010 | } | 2122 | } |
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 | } | 2123 | } |
2124 | /* Reception timestamp. */ | ||
2125 | if (isValid_Time(&d->sourceTime)) { | ||
2126 | const int font = uiLabel_FontId; | ||
2127 | const iString *recv = | ||
2128 | collect_String(format_Time(&d->sourceTime, "Received at %I:%M %p\non %b %d, %Y")); | ||
2129 | const iInt2 size = advanceRange_Text(font, range_String(recv)); | ||
2130 | if (size.x <= avail) { | ||
2131 | drawString_Text(font, | ||
2132 | add_I2(bottomLeft_Rect(bounds), | ||
2133 | init_I2(margin, | ||
2134 | -margin + -size.y + | ||
2135 | iMax(0, scrollMax_DocumentWidget_(d) - d->scrollY))), | ||
2136 | tmQuoteIcon_ColorId, | ||
2137 | recv); | ||
2138 | } | ||
2139 | } | ||
2140 | /* Outline on the right side. */ | ||
2141 | const float outlineOpacity = value_Anim(&d->outlineOpacity); | ||
2142 | if (!isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) { | ||
2143 | // const int font = uiLabel_FontId; | ||
2144 | //iRect outlineRect = initCorners_Rect(topRight_Rect(docBounds), bottomRight_Rect(bounds)); | ||
2145 | //const int excess = width_Rect(outlineRect) - 75 * gap_UI; | ||
2146 | // if (excess > 0) { | ||
2147 | // adjustEdges_Rect(&outlineRect, 0, 0, 0, excess); | ||
2148 | // } | ||
2149 | // const int margin = gap_UI * d->pageMargin; | ||
2150 | const int innerWidth = outlineWidth_DocumentWidget_(d); | ||
2151 | const int outWidth = innerWidth + 2 * outlinePadding_DocumentWidget_ * gap_UI; | ||
2152 | const int topMargin = 0;//d->pageMargin * gap_UI; // + (banner ? banner->visBounds.size.y : 0); | ||
2153 | const int bottomMargin = 3 * gap_UI; //d->pageMargin * gap_UI; | ||
2154 | iInt2 pos = add_I2(topRight_Rect(bounds), init_I2(-outWidth - width_Widget(d->scroll), topMargin)); | ||
2155 | // const int lineWidth = avail - margin; | ||
2156 | // pos.y = drawRangeWrap_Text(uiContent_FontId, pos, lineWidth, tmBannerIcon_ColorId, | ||
2157 | // bannerText_DocumentWidget_(d)); | ||
2158 | // pos.y += gap_UI; | ||
2159 | const int scrollMax = scrollMax_DocumentWidget_(d); | ||
2160 | const int outHeight = bottom_Rect(((const iOutlineItem *) constBack_Array(&d->outline))->rect); | ||
2161 | const int oversize = outHeight - height_Rect(bounds) + topMargin + bottomMargin; | ||
2162 | const int scroll = | ||
2163 | (oversize > 0 && scrollMax > 0 ? oversize * d->scrollY / scrollMax_DocumentWidget_(d) | ||
2164 | : 0); | ||
2165 | /* Center short outlines vertically. */ | ||
2166 | if (oversize < 0) { | ||
2167 | pos.y -= oversize / 2;// + (banner ? banner->visBounds.size.y / 2 : 0); | ||
2168 | } | ||
2169 | pos.y -= scroll; | ||
2170 | setOpacity_Text(outlineOpacity); | ||
2171 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | ||
2172 | p.alpha = outlineOpacity * 255; | ||
2173 | drawSideRect_( | ||
2174 | &p, | ||
2175 | (iRect){ addY_I2(pos, -outlinePadding_DocumentWidget_ * gap_UI / 2), | ||
2176 | init_I2(outWidth, outHeight + outlinePadding_DocumentWidget_ * gap_UI * 1.5f) }, | ||
2177 | 1); | ||
2178 | iConstForEach(Array, i, &d->outline) { | ||
2179 | const iOutlineItem *item = i.value; | ||
2180 | iInt2 visPos = addX_I2(add_I2(pos, item->rect.pos), outlinePadding_DocumentWidget_ * gap_UI); | ||
2181 | // visPos.y -= scroll; | ||
2182 | // if (item->sepColor != none_ColorId) { | ||
2183 | // drawHLine_Paint(&p, addY_I2(visPos, -gap_UI), outWidth, item->sepColor); | ||
2184 | // } | ||
2185 | // drawRect_Paint(&p, (iRect){ visPos, item->rect.size }, red_ColorId); | ||
2186 | const iBool isVisible = d->lastVisibleRun && d->lastVisibleRun->text.start >= item->text.start; | ||
2187 | drawWrapRange_Text(item->font, | ||
2188 | visPos, | ||
2189 | innerWidth - left_Rect(item->rect), | ||
2190 | index_ArrayConstIterator(&i) == 0 || isVisible ? item->seenColor | ||
2191 | : tmQuoteIcon_ColorId, | ||
2192 | item->text); | ||
2193 | } | ||
2194 | setOpacity_Text(1.0f); | ||
2195 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); | ||
2196 | } | ||
2197 | unsetClip_Paint(&p); | ||
2018 | } | 2198 | } |
2019 | 2199 | ||
2020 | static void draw_DocumentWidget_(const iDocumentWidget *d) { | 2200 | static void draw_DocumentWidget_(const iDocumentWidget *d) { |