summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJaakko Keränen <jaakko.keranen@iki.fi>2020-10-28 18:31:42 +0200
committerJaakko Keränen <jaakko.keranen@iki.fi>2020-10-28 18:31:42 +0200
commit646dca0a709712e0e4ae9396a2cbd8c159d61668 (patch)
treef33169a08e303d7662624d3a2252a3026c379cc4 /src
parent61cfbe8d9b00616f7b4e70f050a9dc0f54e93348 (diff)
DocumentWidget: Current heading on the side
Redraw the side icon and heading when the current top heading changes.
Diffstat (limited to 'src')
-rw-r--r--src/ui/documentwidget.c135
1 files changed, 82 insertions, 53 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index d1381a3b..07b0cc63 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -143,7 +143,8 @@ struct Impl_OutlineItem {
143 143
144/*----------------------------------------------------------------------------------------------*/ 144/*----------------------------------------------------------------------------------------------*/
145 145
146static void animatePlayers_DocumentWidget_(iDocumentWidget *d); 146static void animatePlayers_DocumentWidget_ (iDocumentWidget *d);
147static void updateSideIconBuf_DocumentWidget_ (iDocumentWidget *d);
147 148
148static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */ 149static const int smoothDuration_DocumentWidget_ = 600; /* milliseconds */
149static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */ 150static const int outlineMinWidth_DocumentWdiget_ = 45; /* times gap_UI */
@@ -515,6 +516,24 @@ static void animatePlayers_DocumentWidget_(iDocumentWidget *d) {
515 } 516 }
516} 517}
517 518
519static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) {
520 iRangecc heading = iNullRange;
521 if (d->firstVisibleRun) {
522 iConstForEach(Array, i, headings_GmDocument(d->doc)) {
523 const iGmHeading *head = i.value;
524 if (head->level == 0) {
525 if (head->text.start <= d->firstVisibleRun->text.start) {
526 heading = head->text;
527 }
528 if (d->lastVisibleRun && head->text.start > d->lastVisibleRun->text.start) {
529 break;
530 }
531 }
532 }
533 }
534 return heading;
535}
536
518static void updateVisible_DocumentWidget_(iDocumentWidget *d) { 537static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
519 const iRangei visRange = visibleRange_DocumentWidget_(d); 538 const iRangei visRange = visibleRange_DocumentWidget_(d);
520 const iRect bounds = bounds_Widget(as_Widget(d)); 539 const iRect bounds = bounds_Widget(as_Widget(d));
@@ -525,8 +544,15 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
525 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0); 544 docSize > 0 ? height_Rect(bounds) * size_Range(&visRange) / docSize : 0);
526 clear_PtrArray(&d->visibleLinks); 545 clear_PtrArray(&d->visibleLinks);
527 clear_PtrArray(&d->visiblePlayers); 546 clear_PtrArray(&d->visiblePlayers);
528 d->firstVisibleRun = NULL; 547 const iRangecc oldHeading = currentHeading_DocumentWidget_(d);
529 render_GmDocument(d->doc, visRange, addVisible_DocumentWidget_, d); 548 /* Scan for visible runs. */ {
549 d->firstVisibleRun = NULL;
550 render_GmDocument(d->doc, visRange, addVisible_DocumentWidget_, d);
551 }
552 const iRangecc newHeading = currentHeading_DocumentWidget_(d);
553 if (memcmp(&oldHeading, &newHeading, sizeof(oldHeading))) {
554 updateSideIconBuf_DocumentWidget_(d);
555 }
530 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window())); 556 updateHover_DocumentWidget_(d, mouseCoord_Window(get_Window()));
531 updateSideOpacity_DocumentWidget_(d, iTrue); 557 updateSideOpacity_DocumentWidget_(d, iTrue);
532 animatePlayers_DocumentWidget_(d); 558 animatePlayers_DocumentWidget_(d);
@@ -682,6 +708,7 @@ static void setSource_DocumentWidget_(iDocumentWidget *d, const iString *source)
682 setValue_Anim(&d->outlineOpacity, 0.0f, 0); 708 setValue_Anim(&d->outlineOpacity, 0.0f, 0);
683 updateWindowTitle_DocumentWidget_(d); 709 updateWindowTitle_DocumentWidget_(d);
684 updateVisible_DocumentWidget_(d); 710 updateVisible_DocumentWidget_(d);
711 updateSideIconBuf_DocumentWidget_(d);
685 updateOutline_DocumentWidget_(d); 712 updateOutline_DocumentWidget_(d);
686 invalidate_DocumentWidget_(d); 713 invalidate_DocumentWidget_(d);
687 refresh_Widget(as_Widget(d)); 714 refresh_Widget(as_Widget(d));
@@ -938,6 +965,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
938 init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y); 965 init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y);
939 d->state = ready_RequestState; 966 d->state = ready_RequestState;
940 updateSideOpacity_DocumentWidget_(d, iFalse); 967 updateSideOpacity_DocumentWidget_(d, iFalse);
968 updateSideIconBuf_DocumentWidget_(d);
941 updateOutline_DocumentWidget_(d); 969 updateOutline_DocumentWidget_(d);
942 updateVisible_DocumentWidget_(d); 970 updateVisible_DocumentWidget_(d);
943 postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url)); 971 postCommandf_App("document.changed doc:%p url:%s", d, cstr_String(d->mod.url));
@@ -1227,11 +1255,12 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1227 scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue); 1255 scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue);
1228 } 1256 }
1229 } 1257 }
1258 updateSideIconBuf_DocumentWidget_(d);
1230 updateOutline_DocumentWidget_(d); 1259 updateOutline_DocumentWidget_(d);
1231 invalidate_DocumentWidget_(d); 1260 invalidate_DocumentWidget_(d);
1232 dealloc_VisBuf(d->visBuf); 1261 dealloc_VisBuf(d->visBuf);
1233 refresh_Widget(w);
1234 updateWindowTitle_DocumentWidget_(d); 1262 updateWindowTitle_DocumentWidget_(d);
1263 refresh_Widget(w);
1235 } 1264 }
1236 else if (equal_Command(cmd, "window.mouse.exited")) { 1265 else if (equal_Command(cmd, "window.mouse.exited")) {
1237 updateOutlineOpacity_DocumentWidget_(d); 1266 updateOutlineOpacity_DocumentWidget_(d);
@@ -1239,6 +1268,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1239 } 1268 }
1240 else if (equal_Command(cmd, "theme.changed") && document_App() == d) { 1269 else if (equal_Command(cmd, "theme.changed") && document_App() == d) {
1241 updateTheme_DocumentWidget_(d); 1270 updateTheme_DocumentWidget_(d);
1271 updateSideIconBuf_DocumentWidget_(d);
1242 invalidate_DocumentWidget_(d); 1272 invalidate_DocumentWidget_(d);
1243 refresh_Widget(w); 1273 refresh_Widget(w);
1244 } 1274 }
@@ -1361,6 +1391,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1361 } 1391 }
1362 iReleasePtr(&d->request); 1392 iReleasePtr(&d->request);
1363 updateVisible_DocumentWidget_(d); 1393 updateVisible_DocumentWidget_(d);
1394 updateSideIconBuf_DocumentWidget_(d);
1364 updateOutline_DocumentWidget_(d); 1395 updateOutline_DocumentWidget_(d);
1365 postCommandf_App("document.changed url:%s", cstr_String(d->mod.url)); 1396 postCommandf_App("document.changed url:%s", cstr_String(d->mod.url));
1366 return iFalse; 1397 return iFalse;
@@ -2324,51 +2355,42 @@ static int drawSideRect_(iPaint *p, iRect rect) {
2324 return fg; 2355 return fg;
2325} 2356}
2326 2357
2327static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) {
2328 iRangecc heading = iNullRange;
2329 if (d->firstVisibleRun) {
2330 iConstForEach(Array, i, headings_GmDocument(d->doc)) {
2331 const iGmHeading *head = i.value;
2332 if (head->level == 0) {
2333 if (head->text.start <= d->firstVisibleRun->text.start) {
2334 heading = head->text;
2335 }
2336 if (d->lastVisibleRun && head->text.start > d->lastVisibleRun->text.start) {
2337 break;
2338 }
2339 }
2340 }
2341 }
2342 return heading;
2343}
2344
2345static int sideElementAvailWidth_DocumentWidget_(const iDocumentWidget *d) { 2358static int sideElementAvailWidth_DocumentWidget_(const iDocumentWidget *d) {
2346 return left_Rect(documentBounds_DocumentWidget_(d)) - 2359 return left_Rect(documentBounds_DocumentWidget_(d)) -
2347 left_Rect(bounds_Widget(constAs_Widget(d))) - 2 * d->pageMargin * gap_UI; 2360 left_Rect(bounds_Widget(constAs_Widget(d))) - 2 * d->pageMargin * gap_UI;
2348} 2361}
2349 2362
2350#if 0 2363static iBool isSideHeadingVisible_DocumentWidget_(const iDocumentWidget *d) {
2364 return sideElementAvailWidth_DocumentWidget_(d) >= lineHeight_Text(banner_FontId) * 4.5f;
2365}
2366
2351static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) { 2367static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) {
2352 if (d->sideIconBuf) { 2368 if (d->sideIconBuf) {
2353 SDL_DestroyTexture(d->sideIconBuf); 2369 SDL_DestroyTexture(d->sideIconBuf);
2354 d->sideIconBuf = NULL; 2370 d->sideIconBuf = NULL;
2355 } 2371 }
2356 const iWidget *w = constAs_Widget(d); 2372 const iGmRun *banner = siteBanner_GmDocument(d->doc);
2357 const iRect bounds = bounds_Widget(w); 2373 if (!banner) {
2358 const int margin = gap_UI * d->pageMargin; 2374 return;
2359 const iGmRun * banner = siteBanner_GmDocument(d->doc); 2375 }
2360 const int minBannerSize = lineHeight_Text(banner_FontId) * 2; 2376 const int margin = gap_UI * d->pageMargin;
2361 const iChar icon = siteIcon_GmDocument(d->doc); 2377 const int minBannerSize = lineHeight_Text(banner_FontId) * 2;
2362 const int avail = sideElementAvailWidth_DocumentWidget_(d) - margin; 2378 const iChar icon = siteIcon_GmDocument(d->doc);
2379 const int avail = sideElementAvailWidth_DocumentWidget_(d) - margin;
2380 iBool isHeadingVisible = isSideHeadingVisible_DocumentWidget_(d);
2363 /* Determine the required size. */ 2381 /* Determine the required size. */
2364 iInt2 bufSize = init1_I2(minBannerSize); 2382 iInt2 bufSize = init1_I2(minBannerSize);
2365 const iInt2 headingSize = advanceWrapRange_Text(heading3_FontId, avail, currentHeading_DocumentWidget_(d)); 2383 if (isHeadingVisible) {
2366 bufSize.y += gap_Text + headingSize.y; 2384 const iInt2 headingSize = advanceWrapRange_Text(heading3_FontId, avail,
2367 bufSize.x = iMax(bufSize.x, headingSize.x); 2385 currentHeading_DocumentWidget_(d));
2368 2386 if (headingSize.x > 0) {
2369// iRect rect = { add_I2(topLeft_Rect(bounds), init1_I2(margin)), init1_I2(minBannerSize) }; 2387 bufSize.y += gap_Text + headingSize.y;
2370// p.alpha = opacity * 255; 2388 bufSize.x = iMax(bufSize.x, headingSize.x);
2371// rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0); 2389 }
2390 else {
2391 isHeadingVisible = iFalse;
2392 }
2393 }
2372 d->sideIconBuf = SDL_CreateTexture(renderer_Window(get_Window()), 2394 d->sideIconBuf = SDL_CreateTexture(renderer_Window(get_Window()),
2373 SDL_PIXELFORMAT_RGBA4444, 2395 SDL_PIXELFORMAT_RGBA4444,
2374 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, 2396 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
@@ -2376,21 +2398,21 @@ static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) {
2376 iPaint p; 2398 iPaint p;
2377 init_Paint(&p); 2399 init_Paint(&p);
2378 beginTarget_Paint(&p, d->sideIconBuf); 2400 beginTarget_Paint(&p, d->sideIconBuf);
2379 fillRect_Paint(&p, ) 2401 const iRect iconRect = { zero_I2(), init1_I2(minBannerSize) };
2380 int fg = drawSideRect_(&p, rect); 2402 int fg = drawSideRect_(&p, iconRect);
2381 iString str; 2403 iString str;
2382 initUnicodeN_String(&str, &icon, 1); 2404 initUnicodeN_String(&str, &icon, 1);
2383 drawCentered_Text(banner_FontId, rect, iTrue, fg, "%s", cstr_String(&str)); 2405 drawCentered_Text(banner_FontId, iconRect, iTrue, fg, "%s", cstr_String(&str));
2384 deinit_String(&str); 2406 deinit_String(&str);
2385 if (avail >= minBannerSize * 2.25f) { 2407 if (isHeadingVisible) {
2386 iRangecc text = currentHeading_DocumentWidget_(d); 2408 iRangecc text = currentHeading_DocumentWidget_(d);
2387 iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text); 2409 iInt2 pos = addY_I2(bottomLeft_Rect(iconRect), gap_Text);
2388 const int font = heading3_FontId; 2410 const int font = heading3_FontId;
2389 drawWrapRange_Text(font, pos, avail - margin, tmBannerSideTitle_ColorId, text); 2411 drawWrapRange_Text(font, pos, avail, tmBannerSideTitle_ColorId, text);
2390 } 2412 }
2391 endTarget_Paint(&p); 2413 endTarget_Paint(&p);
2414 SDL_SetTextureBlendMode(d->sideIconBuf, SDL_BLENDMODE_BLEND);
2392} 2415}
2393#endif
2394 2416
2395static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { 2417static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2396 const iWidget *w = constAs_Widget(d); 2418 const iWidget *w = constAs_Widget(d);
@@ -2402,16 +2424,22 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2402 iPaint p; 2424 iPaint p;
2403 init_Paint(&p); 2425 init_Paint(&p);
2404 setClip_Paint(&p, bounds); 2426 setClip_Paint(&p, bounds);
2405#if 0 2427 /* Side icon and current heading. */
2406 if (prefs_App()->sideIcon && opacity > 0 && d->sideIconBuf && avail > size_SDLTexture(d->sideIconBuf).x) { 2428 if (prefs_App()->sideIcon && opacity > 0 && d->sideIconBuf) {
2407 if (banner) { 2429 const iInt2 texSize = size_SDLTexture(d->sideIconBuf);
2408 setOpacity_Text(opacity); 2430 if (avail > texSize.x) {
2409 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); 2431 const int minBannerSize = lineHeight_Text(banner_FontId) * 2;
2410 setOpacity_Text(1.0f); 2432 iInt2 pos = addY_I2(add_I2(topLeft_Rect(bounds), init_I2(margin, 0)),
2411 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 2433 height_Rect(bounds) / 2 - minBannerSize / 2 -
2434 (texSize.y > minBannerSize
2435 ? (gap_Text + lineHeight_Text(heading3_FontId)) / 2
2436 : 0));
2437 SDL_SetTextureAlphaMod(d->sideIconBuf, 255 * opacity);
2438 SDL_RenderCopy(renderer_Window(get_Window()),
2439 d->sideIconBuf, NULL,
2440 &(SDL_Rect){ pos.x, pos.y, texSize.x, texSize.y });
2412 } 2441 }
2413 } 2442 }
2414#endif
2415 /* Reception timestamp. */ 2443 /* Reception timestamp. */
2416 if (d->timestampBuf && d->timestampBuf->size.x <= avail) { 2444 if (d->timestampBuf && d->timestampBuf->size.x <= avail) {
2417 draw_TextBuf( 2445 draw_TextBuf(
@@ -2479,7 +2507,7 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2479 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 2507 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
2480 } 2508 }
2481 unsetClip_Paint(&p); 2509 unsetClip_Paint(&p);
2482} 2510 }
2483 2511
2484static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { 2512static void drawPlayers_DocumentWidget_(const iDocumentWidget *d, iPaint *p) {
2485 iConstForEach(PtrArray, i, &d->visiblePlayers) { 2513 iConstForEach(PtrArray, i, &d->visiblePlayers) {
@@ -2673,6 +2701,7 @@ iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {
2673void updateSize_DocumentWidget(iDocumentWidget *d) { 2701void updateSize_DocumentWidget(iDocumentWidget *d) {
2674 setWidth_GmDocument( 2702 setWidth_GmDocument(
2675 d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d)); 2703 d->doc, documentWidth_DocumentWidget_(d), forceBreakWidth_DocumentWidget_(d));
2704 updateSideIconBuf_DocumentWidget_(d);
2676 updateOutline_DocumentWidget_(d); 2705 updateOutline_DocumentWidget_(d);
2677 updateVisible_DocumentWidget_(d); 2706 updateVisible_DocumentWidget_(d);
2678 invalidate_DocumentWidget_(d); 2707 invalidate_DocumentWidget_(d);