diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-12 12:47:41 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-07-12 12:47:41 +0300 |
commit | fe5c564a6d0b99223b2ad56e1856f651a49f2f46 (patch) | |
tree | b93ba8ee2ff9c205242b411744836afc96bcaf25 /src/gmdocument.c | |
parent | aea927e6932fd2ef415b1f592d1c7a137ee0511f (diff) |
Update link visited status when navigating
When an URL is visited, ensure that links to that URL update their visual state.
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r-- | src/gmdocument.c | 81 |
1 files changed, 58 insertions, 23 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index f6db8a1d..d0420c9a 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
33 | #include "app.h" | 33 | #include "app.h" |
34 | #include "defs.h" | 34 | #include "defs.h" |
35 | 35 | ||
36 | #include <the_Foundation/intset.h> | ||
36 | #include <the_Foundation/ptrarray.h> | 37 | #include <the_Foundation/ptrarray.h> |
37 | #include <the_Foundation/regexp.h> | 38 | #include <the_Foundation/regexp.h> |
38 | #include <the_Foundation/stringset.h> | 39 | #include <the_Foundation/stringset.h> |
@@ -799,33 +800,31 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
799 | meta->flags |= topLeft_GmPreMetaFlag; | 800 | meta->flags |= topLeft_GmPreMetaFlag; |
800 | } | 801 | } |
801 | } | 802 | } |
802 | float lineHeightReduction = 0.0f; | ||
803 | if (!isMono) { | ||
804 | /* Upper-level headings are typeset a bit tighter. */ | ||
805 | if (type == heading1_GmLineType) { | ||
806 | lineHeightReduction = 0.10f; | ||
807 | } | ||
808 | else if (type == heading2_GmLineType) { | ||
809 | lineHeightReduction = 0.06f; | ||
810 | } | ||
811 | /* Visited links are never bold. */ | ||
812 | if (run.linkId && linkFlags_GmDocument(d, run.linkId) & visited_GmLinkFlag) { | ||
813 | run.font = paragraph_FontId; | ||
814 | } | ||
815 | } | ||
816 | iAssert(!isEmpty_Range(&runLine)); /* must have something at this point */ | 803 | iAssert(!isEmpty_Range(&runLine)); /* must have something at this point */ |
817 | /* Typeset the paragraph. */ { | 804 | /* Typeset the paragraph. */ { |
818 | iRunTypesetter rts; | 805 | iRunTypesetter rts; |
819 | init_RunTypesetter_(&rts); | 806 | init_RunTypesetter_(&rts); |
820 | rts.run = run; | 807 | rts.run = run; |
821 | rts.pos = pos; | 808 | rts.pos = pos; |
822 | rts.lineHeightReduction = lineHeightReduction; | 809 | rts.fonts = fonts; |
823 | rts.layoutWidth = d->size.x; | 810 | rts.isWordWrapped = isWordWrapped; |
824 | rts.indent = indent * gap_Text; | 811 | rts.isPreformat = isPreformat; |
825 | rts.rightMargin = rightMargin * gap_Text; | 812 | rts.layoutWidth = d->size.x; |
826 | rts.isWordWrapped = isWordWrapped; | 813 | rts.indent = indent * gap_Text; |
827 | rts.isPreformat = isPreformat; | 814 | rts.rightMargin = rightMargin * gap_Text; |
828 | rts.fonts = fonts; | 815 | if (!isMono) { |
816 | /* Upper-level headings are typeset a bit tighter. */ | ||
817 | if (type == heading1_GmLineType) { | ||
818 | rts.lineHeightReduction = 0.10f; | ||
819 | } | ||
820 | else if (type == heading2_GmLineType) { | ||
821 | rts.lineHeightReduction = 0.06f; | ||
822 | } | ||
823 | /* Visited links are never bold. */ | ||
824 | if (run.linkId && linkFlags_GmDocument(d, run.linkId) & visited_GmLinkFlag) { | ||
825 | rts.run.font = paragraph_FontId; | ||
826 | } | ||
827 | } | ||
829 | iWrapText wrapText = { .text = runLine, | 828 | iWrapText wrapText = { .text = runLine, |
830 | .maxWidth = isWordWrapped ? d->size.x - run.bounds.pos.x - | 829 | .maxWidth = isWordWrapped ? d->size.x - run.bounds.pos.x - |
831 | rts.indent - rts.rightMargin | 830 | rts.indent - rts.rightMargin |
@@ -1520,9 +1519,25 @@ void redoLayout_GmDocument(iGmDocument *d) { | |||
1520 | doLayout_GmDocument_(d); | 1519 | doLayout_GmDocument_(d); |
1521 | } | 1520 | } |
1522 | 1521 | ||
1522 | static void markLinkRunsVisited_GmDocument_(iGmDocument *d, const iIntSet *linkIds) { | ||
1523 | iForEach(Array, r, &d->layout) { | ||
1524 | iGmRun *run = r.value; | ||
1525 | if (run->linkId && !run->mediaId && contains_IntSet(linkIds, run->linkId)) { | ||
1526 | if (run->font == bold_FontId) { | ||
1527 | run->font = paragraph_FontId; | ||
1528 | } | ||
1529 | else if (run->flags & decoration_GmRunFlag) { | ||
1530 | run->color = linkColor_GmDocument(d, run->linkId, icon_GmLinkPart); | ||
1531 | } | ||
1532 | } | ||
1533 | } | ||
1534 | } | ||
1535 | |||
1523 | iBool updateOpenURLs_GmDocument(iGmDocument *d) { | 1536 | iBool updateOpenURLs_GmDocument(iGmDocument *d) { |
1524 | iBool wasChanged = iFalse; | 1537 | iBool wasChanged = iFalse; |
1525 | updateOpenURLs_GmDocument_(d); | 1538 | updateOpenURLs_GmDocument_(d); |
1539 | iIntSet linkIds; | ||
1540 | init_IntSet(&linkIds); | ||
1526 | iForEach(PtrArray, i, &d->links) { | 1541 | iForEach(PtrArray, i, &d->links) { |
1527 | iGmLink *link = i.ptr; | 1542 | iGmLink *link = i.ptr; |
1528 | if (!equal_String(&link->url, &d->url)) { | 1543 | if (!equal_String(&link->url, &d->url)) { |
@@ -1531,11 +1546,14 @@ iBool updateOpenURLs_GmDocument(iGmDocument *d) { | |||
1531 | iChangeFlags(link->flags, isOpen_GmLinkFlag, isOpen); | 1546 | iChangeFlags(link->flags, isOpen_GmLinkFlag, isOpen); |
1532 | if (isOpen) { | 1547 | if (isOpen) { |
1533 | link->flags |= visited_GmLinkFlag; | 1548 | link->flags |= visited_GmLinkFlag; |
1549 | insert_IntSet(&linkIds, index_PtrArrayIterator(&i) + 1); | ||
1534 | } | 1550 | } |
1535 | wasChanged = iTrue; | 1551 | wasChanged = iTrue; |
1536 | } | 1552 | } |
1537 | } | 1553 | } |
1538 | } | 1554 | } |
1555 | markLinkRunsVisited_GmDocument_(d, &linkIds); | ||
1556 | deinit_IntSet(&linkIds); | ||
1539 | return wasChanged; | 1557 | return wasChanged; |
1540 | } | 1558 | } |
1541 | 1559 | ||
@@ -1672,6 +1690,23 @@ void foldPre_GmDocument(iGmDocument *d, uint16_t preId) { | |||
1672 | } | 1690 | } |
1673 | } | 1691 | } |
1674 | 1692 | ||
1693 | void updateVisitedLinks_GmDocument(iGmDocument *d) { | ||
1694 | iIntSet linkIds; | ||
1695 | init_IntSet(&linkIds); | ||
1696 | iForEach(PtrArray, i, &d->links) { | ||
1697 | iGmLink *link = i.ptr; | ||
1698 | if (~link->flags & visited_GmLinkFlag) { | ||
1699 | iTime visitTime = urlVisitTime_Visited(visited_App(), &link->url); | ||
1700 | if (isValid_Time(&visitTime)) { | ||
1701 | link->flags |= visited_GmLinkFlag; | ||
1702 | insert_IntSet(&linkIds, index_PtrArrayIterator(&i) + 1); | ||
1703 | } | ||
1704 | } | ||
1705 | } | ||
1706 | markLinkRunsVisited_GmDocument_(d, &linkIds); | ||
1707 | deinit_IntSet(&linkIds); | ||
1708 | } | ||
1709 | |||
1675 | const iGmPreMeta *preMeta_GmDocument(const iGmDocument *d, uint16_t preId) { | 1710 | const iGmPreMeta *preMeta_GmDocument(const iGmDocument *d, uint16_t preId) { |
1676 | if (preId > 0 && preId <= size_Array(&d->preMeta)) { | 1711 | if (preId > 0 && preId <= size_Array(&d->preMeta)) { |
1677 | return constAt_Array(&d->preMeta, preId - 1); | 1712 | return constAt_Array(&d->preMeta, preId - 1); |