diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-04 17:14:06 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-05-04 17:14:06 +0300 |
commit | 347b4c1cb3482fd43251bf4d4ab7807360bbb938 (patch) | |
tree | a3a1ad51b392891f87ebd6ef438a1d16c5dd376e /src/ui | |
parent | 6cbaa38d4ebf5a911e908b72bf721985bde87e44 (diff) |
Highlight links opened in other tabs
The primary purpose is to aid navigation in split view, so one can see exactly which links have been opened.
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/color.h | 4 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 67 |
2 files changed, 58 insertions, 13 deletions
diff --git a/src/ui/color.h b/src/ui/color.h index c0db4382..d2fa3c00 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -132,7 +132,9 @@ enum iColorId { | |||
132 | tmBannerIcon_ColorId, | 132 | tmBannerIcon_ColorId, |
133 | tmBannerSideTitle_ColorId, | 133 | tmBannerSideTitle_ColorId, |
134 | tmInlineContentMetadata_ColorId, | 134 | tmInlineContentMetadata_ColorId, |
135 | tmAltTextBackground_ColorId, /* derived from other theme colors */ | 135 | tmBackgroundAltText_ColorId, /* derived from other theme colors */ |
136 | tmBackgroundOpenLink_ColorId, /* derived from other theme colors */ | ||
137 | tmFrameOpenLink_ColorId, /* derived from other theme colors */ | ||
136 | tmLinkCustomIconVisited_ColorId, /* derived from other theme colors */ | 138 | tmLinkCustomIconVisited_ColorId, /* derived from other theme colors */ |
137 | tmBadLink_ColorId, | 139 | tmBadLink_ColorId, |
138 | 140 | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 16d2a84a..6a44fd5f 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -286,7 +286,7 @@ struct Impl_DocumentWidget { | |||
286 | iWidget * playerMenu; | 286 | iWidget * playerMenu; |
287 | iWidget * copyMenu; | 287 | iWidget * copyMenu; |
288 | iVisBuf * visBuf; | 288 | iVisBuf * visBuf; |
289 | iGmRunRange * visBufMeta; | 289 | iVisBufMeta * visBufMeta; |
290 | iPtrSet * invalidRuns; | 290 | iPtrSet * invalidRuns; |
291 | iDrawBufs * drawBufs; /* dynamic state for drawing */ | 291 | iDrawBufs * drawBufs; /* dynamic state for drawing */ |
292 | iTranslation * translation; | 292 | iTranslation * translation; |
@@ -1881,7 +1881,15 @@ static iBool handlePinch_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | |||
1881 | 1881 | ||
1882 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 1882 | static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
1883 | iWidget *w = as_Widget(d); | 1883 | iWidget *w = as_Widget(d); |
1884 | if (equal_Command(cmd, "document.render")) /* Periodic makes direct dispatch to here */ { | 1884 | if (equal_Command(cmd, "document.openurls.changed")) { |
1885 | /* When any tab changes its document URL, update the open link indicators. */ | ||
1886 | if (updateOpenURLs_GmDocument(d->doc)) { | ||
1887 | invalidate_DocumentWidget_(d); | ||
1888 | refresh_Widget(d); | ||
1889 | } | ||
1890 | return iFalse; | ||
1891 | } | ||
1892 | if (equal_Command(cmd, "document.render")) /* `Periodic` makes direct dispatch to here */ { | ||
1885 | // printf("%u: document.render\n", SDL_GetTicks()); | 1893 | // printf("%u: document.render\n", SDL_GetTicks()); |
1886 | if (SDL_GetTicks() - d->drawBufs->lastRenderTime > 150) { | 1894 | if (SDL_GetTicks() - d->drawBufs->lastRenderTime > 150) { |
1887 | remove_Periodic(periodic_App(), d); | 1895 | remove_Periodic(periodic_App(), d); |
@@ -3486,15 +3494,18 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3486 | /* Media UIs are drawn afterwards as a dynamic overlay. */ | 3494 | /* Media UIs are drawn afterwards as a dynamic overlay. */ |
3487 | return; | 3495 | return; |
3488 | } | 3496 | } |
3489 | // printf(" drawRun: {%s}\n", cstr_Rangecc(run->text)); | 3497 | enum iColorId fg = run->color; |
3490 | enum iColorId fg = run->color; | 3498 | const iGmDocument *doc = d->widget->doc; |
3491 | const iGmDocument *doc = d->widget->doc; | 3499 | const int linkFlags = linkFlags_GmDocument(doc, run->linkId); |
3492 | iBool isHover = | 3500 | /* Hover state of a link. */ |
3501 | iBool isHover = | ||
3493 | (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && | 3502 | (run->linkId && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId && |
3494 | ~run->flags & decoration_GmRunFlag); | 3503 | ~run->flags & decoration_GmRunFlag); |
3504 | /* Visible (scrolled) position of the run. */ | ||
3495 | const iInt2 visPos = addX_I2(add_I2(run->visBounds.pos, origin), | 3505 | const iInt2 visPos = addX_I2(add_I2(run->visBounds.pos, origin), |
3496 | /* Preformatted runs can be scrolled. */ | 3506 | /* Preformatted runs can be scrolled. */ |
3497 | runOffset_DocumentWidget_(d->widget, run)); | 3507 | runOffset_DocumentWidget_(d->widget, run)); |
3508 | const iRect visRect = { visPos, run->visBounds.size }; | ||
3498 | if (run->flags & footer_GmRunFlag) { | 3509 | if (run->flags & footer_GmRunFlag) { |
3499 | iRect footerBack = | 3510 | iRect footerBack = |
3500 | (iRect){ visPos, init_I2(width_Rect(d->widgetBounds), run->visBounds.size.y) }; | 3511 | (iRect){ visPos, init_I2(width_Rect(d->widgetBounds), run->visBounds.size.y) }; |
@@ -3502,16 +3513,48 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3502 | fillRect_Paint(&d->paint, footerBack, tmBackground_ColorId); | 3513 | fillRect_Paint(&d->paint, footerBack, tmBackground_ColorId); |
3503 | return; | 3514 | return; |
3504 | } | 3515 | } |
3505 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackground_ColorId); | 3516 | /* Fill the background. */ { |
3517 | if (run->linkId && linkFlags & isOpen_GmLinkFlag) { | ||
3518 | /* Open links get a highlighted background. */ | ||
3519 | int bg = tmBackgroundOpenLink_ColorId; | ||
3520 | const int frame = tmFrameOpenLink_ColorId; | ||
3521 | iRect wideRect = { init_I2(left_Rect(d->widgetBounds), visPos.y), | ||
3522 | init_I2(width_Rect(d->widgetBounds) + | ||
3523 | width_Widget(d->widget->scroll), | ||
3524 | height_Rect(run->visBounds)) }; | ||
3525 | /* The first line is composed of two runs that may be drawn in either order, so | ||
3526 | only draw half of the background. */ | ||
3527 | if (run->flags & decoration_GmRunFlag) { | ||
3528 | wideRect.size.x = right_Rect(visRect) - left_Rect(wideRect); | ||
3529 | } | ||
3530 | else if (run->flags & startOfLine_GmRunFlag) { | ||
3531 | wideRect.size.x = right_Rect(wideRect) - left_Rect(visRect); | ||
3532 | wideRect.pos.x = left_Rect(visRect); | ||
3533 | } | ||
3534 | fillRect_Paint(&d->paint, wideRect, bg); | ||
3535 | if (run->flags & (startOfLine_GmRunFlag | decoration_GmRunFlag)) { | ||
3536 | drawHLine_Paint(&d->paint, topLeft_Rect(wideRect), width_Rect(wideRect), frame); | ||
3537 | } | ||
3538 | /* TODO: The decoration is not marked as endOfLine, so it lacks the bottom line. */ | ||
3539 | // if (run->flags & endOfLine_GmRunFlag) { | ||
3540 | // drawHLine_Paint( | ||
3541 | // &d->paint, addY_I2(bottomLeft_Rect(wideRect), -1), width_Rect(wideRect), frame); | ||
3542 | // } | ||
3543 | } | ||
3544 | else { | ||
3545 | /* Normal background for other runs. */ | ||
3546 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackground_ColorId); | ||
3547 | } | ||
3548 | } | ||
3506 | if (run->linkId && ~run->flags & decoration_GmRunFlag) { | 3549 | if (run->linkId && ~run->flags & decoration_GmRunFlag) { |
3507 | fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart); | 3550 | fg = linkColor_GmDocument(doc, run->linkId, isHover ? textHover_GmLinkPart : text_GmLinkPart); |
3508 | if (linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) { | 3551 | if (linkFlags & content_GmLinkFlag) { |
3509 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); /* link is inactive */ | 3552 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); /* link is inactive */ |
3510 | } | 3553 | } |
3511 | } | 3554 | } |
3512 | if (run->flags & altText_GmRunFlag) { | 3555 | if (run->flags & altText_GmRunFlag) { |
3513 | const iInt2 margin = preRunMargin_GmDocument(doc, run->preId); | 3556 | const iInt2 margin = preRunMargin_GmDocument(doc, run->preId); |
3514 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmAltTextBackground_ColorId); | 3557 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId); |
3515 | drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); | 3558 | drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); |
3516 | drawWrapRange_Text(run->font, add_I2(visPos, margin), | 3559 | drawWrapRange_Text(run->font, add_I2(visPos, margin), |
3517 | run->visBounds.size.x - 2 * margin.x, run->color, run->text); | 3560 | run->visBounds.size.x - 2 * margin.x, run->color, run->text); |
@@ -3552,7 +3595,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3552 | if (run->linkId && ~run->flags & decoration_GmRunFlag) { | 3595 | if (run->linkId && ~run->flags & decoration_GmRunFlag) { |
3553 | const int metaFont = paragraph_FontId; | 3596 | const int metaFont = paragraph_FontId; |
3554 | /* TODO: Show status of an ongoing media request. */ | 3597 | /* TODO: Show status of an ongoing media request. */ |
3555 | const int flags = linkFlags_GmDocument(doc, run->linkId); | 3598 | const int flags = linkFlags; |
3556 | const iRect linkRect = moved_Rect(run->visBounds, origin); | 3599 | const iRect linkRect = moved_Rect(run->visBounds, origin); |
3557 | iMediaRequest *mr = NULL; | 3600 | iMediaRequest *mr = NULL; |
3558 | /* Show metadata about inline content. */ | 3601 | /* Show metadata about inline content. */ |
@@ -3614,7 +3657,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
3614 | else if (isHover) { | 3657 | else if (isHover) { |
3615 | const iGmLinkId linkId = d->widget->hoverLink->linkId; | 3658 | const iGmLinkId linkId = d->widget->hoverLink->linkId; |
3616 | const iString * url = linkUrl_GmDocument(doc, linkId); | 3659 | const iString * url = linkUrl_GmDocument(doc, linkId); |
3617 | const int flags = linkFlags_GmDocument(doc, linkId); | 3660 | const int flags = linkFlags; |
3618 | iUrl parts; | 3661 | iUrl parts; |
3619 | init_Url(&parts, url); | 3662 | init_Url(&parts, url); |
3620 | fg = linkColor_GmDocument(doc, linkId, textHover_GmLinkPart); | 3663 | fg = linkColor_GmDocument(doc, linkId, textHover_GmLinkPart); |
@@ -4122,7 +4165,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4122 | if (altTextOpacity < 1) { | 4165 | if (altTextOpacity < 1) { |
4123 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); | 4166 | SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); |
4124 | } | 4167 | } |
4125 | fillRect_Paint(&ctx.paint, altRect, tmAltTextBackground_ColorId); | 4168 | fillRect_Paint(&ctx.paint, altRect, tmBackgroundAltText_ColorId); |
4126 | drawRect_Paint(&ctx.paint, altRect, tmQuoteIcon_ColorId); | 4169 | drawRect_Paint(&ctx.paint, altRect, tmQuoteIcon_ColorId); |
4127 | setOpacity_Text(altTextOpacity); | 4170 | setOpacity_Text(altTextOpacity); |
4128 | drawWrapRange_Text(altFont, addX_I2(pos, margin), wrap, | 4171 | drawWrapRange_Text(altFont, addX_I2(pos, margin), wrap, |