summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c66
1 files changed, 47 insertions, 19 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 603af076..232b4140 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -133,6 +133,7 @@ enum iDocumentWidgetFlag {
133 showLinkNumbers_DocumentWidgetFlag = iBit(3), 133 showLinkNumbers_DocumentWidgetFlag = iBit(3),
134 setHoverViaKeys_DocumentWidgetFlag = iBit(4), 134 setHoverViaKeys_DocumentWidgetFlag = iBit(4),
135 newTabViaHomeKeys_DocumentWidgetFlag = iBit(5), 135 newTabViaHomeKeys_DocumentWidgetFlag = iBit(5),
136 centerVertically_DocumentWidgetFlag = iBit(6),
136}; 137};
137 138
138enum iDocumentLinkOrdinalMode { 139enum iDocumentLinkOrdinalMode {
@@ -151,6 +152,7 @@ struct Impl_DocumentWidget {
151 iGmRequest * request; 152 iGmRequest * request;
152 iAtomicInt isRequestUpdated; /* request has new content, need to parse it */ 153 iAtomicInt isRequestUpdated; /* request has new content, need to parse it */
153 iObjectList * media; 154 iObjectList * media;
155 enum iGmStatusCode sourceStatus;
154 iString sourceHeader; 156 iString sourceHeader;
155 iString sourceMime; 157 iString sourceMime;
156 iBlock sourceContent; /* original content as received, for saving */ 158 iBlock sourceContent; /* original content as received, for saving */
@@ -231,6 +233,7 @@ void init_DocumentWidget(iDocumentWidget *d) {
231 init_Array(&d->outline, sizeof(iOutlineItem)); 233 init_Array(&d->outline, sizeof(iOutlineItem));
232 init_Anim(&d->sideOpacity, 0); 234 init_Anim(&d->sideOpacity, 0);
233 init_Anim(&d->outlineOpacity, 0); 235 init_Anim(&d->outlineOpacity, 0);
236 d->sourceStatus = none_GmStatusCode;
234 init_String(&d->sourceHeader); 237 init_String(&d->sourceHeader);
235 init_String(&d->sourceMime); 238 init_String(&d->sourceMime);
236 init_Block(&d->sourceContent, 0); 239 init_Block(&d->sourceContent, 0);
@@ -332,7 +335,7 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) {
332 rect.pos.y += margin; 335 rect.pos.y += margin;
333 rect.size.y -= margin; 336 rect.size.y -= margin;
334 } 337 }
335 if (prefs_App()->centerShortDocs) { 338 if (d->flags & centerVertically_DocumentWidgetFlag) {
336 const iInt2 docSize = size_GmDocument(d->doc); 339 const iInt2 docSize = size_GmDocument(d->doc);
337 if (docSize.y < rect.size.y) { 340 if (docSize.y < rect.size.y) {
338 /* Center vertically if short. There is one empty paragraph line's worth of margin 341 /* Center vertically if short. There is one empty paragraph line's worth of margin
@@ -592,6 +595,10 @@ static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) {
592} 595}
593 596
594static void updateVisible_DocumentWidget_(iDocumentWidget *d) { 597static void updateVisible_DocumentWidget_(iDocumentWidget *d) {
598 iChangeFlags(d->flags,
599 centerVertically_DocumentWidgetFlag,
600 prefs_App()->centerShortDocs || startsWithCase_String(d->mod.url, "about:") ||
601 !isSuccess_GmStatusCode(d->sourceStatus));
595 const iRangei visRange = visibleRange_DocumentWidget_(d); 602 const iRangei visRange = visibleRange_DocumentWidget_(d);
596 const iRect bounds = bounds_Widget(as_Widget(d)); 603 const iRect bounds = bounds_Widget(as_Widget(d));
597 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) }); 604 setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax_DocumentWidget_(d) });
@@ -1038,6 +1045,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
1038 /* Use the cached response data. */ 1045 /* Use the cached response data. */
1039 updateTrust_DocumentWidget_(d, resp); 1046 updateTrust_DocumentWidget_(d, resp);
1040 d->sourceTime = resp->when; 1047 d->sourceTime = resp->when;
1048 d->sourceStatus = success_GmStatusCode;
1041 format_String(&d->sourceHeader, "(cached content)"); 1049 format_String(&d->sourceHeader, "(cached content)");
1042 updateTimestampBuf_DocumentWidget_(d); 1050 updateTimestampBuf_DocumentWidget_(d);
1043 set_Block(&d->sourceContent, &resp->body); 1051 set_Block(&d->sourceContent, &resp->body);
@@ -1113,6 +1121,9 @@ static void scroll_DocumentWidget_(iDocumentWidget *d, int offset) {
1113} 1121}
1114 1122
1115static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) { 1123static void scrollTo_DocumentWidget_(iDocumentWidget *d, int documentY, iBool centered) {
1124 if (!hasSiteBanner_GmDocument(d->doc)) {
1125 documentY += d->pageMargin * gap_UI;
1126 }
1116 init_Anim(&d->scrollY, 1127 init_Anim(&d->scrollY,
1117 documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2 1128 documentY - (centered ? documentBounds_DocumentWidget_(d).size.y / 2
1118 : lineHeight_Text(paragraph_FontId))); 1129 : lineHeight_Text(paragraph_FontId)));
@@ -1192,6 +1203,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
1192 updateTrust_DocumentWidget_(d, resp); 1203 updateTrust_DocumentWidget_(d, resp);
1193 init_Anim(&d->sideOpacity, 0); 1204 init_Anim(&d->sideOpacity, 0);
1194 format_String(&d->sourceHeader, "%d %s", statusCode, get_GmError(statusCode)->title); 1205 format_String(&d->sourceHeader, "%d %s", statusCode, get_GmError(statusCode)->title);
1206 d->sourceStatus = statusCode;
1195 switch (category_GmStatusCode(statusCode)) { 1207 switch (category_GmStatusCode(statusCode)) {
1196 case categoryInput_GmStatusCode: { 1208 case categoryInput_GmStatusCode: {
1197 iUrl parts; 1209 iUrl parts;
@@ -1538,28 +1550,43 @@ static const int homeRowKeys_[] = {
1538 't', 'y', 1550 't', 'y',
1539}; 1551};
1540 1552
1553static void updateDocumentWidthRetainingScrollPosition_DocumentWidget_(iDocumentWidget *d,
1554 iBool keepCenter) {
1555 /* Font changes (i.e., zooming) will keep the view centered, otherwise keep the top
1556 of the visible area fixed. */
1557 const iGmRun *run = keepCenter ? middleRun_DocumentWidget_(d) : d->firstVisibleRun;
1558 const char * runLoc = (run ? run->text.start : NULL);
1559 int voffset = 0;
1560 if (!keepCenter && run) {
1561 /* Keep the first visible run visible at the same position. */
1562 /* TODO: First *fully* visible run? */
1563 voffset = visibleRange_DocumentWidget_(d).start - top_Rect(run->visBounds);
1564 }
1565 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d));
1566 if (runLoc && !keepCenter) {
1567 run = findRunAtLoc_GmDocument(d->doc, runLoc);
1568 if (run) {
1569 scrollTo_DocumentWidget_(d,
1570 top_Rect(run->visBounds) +
1571 lineHeight_Text(paragraph_FontId) + voffset,
1572 iFalse);
1573 }
1574 }
1575 else if (runLoc && keepCenter) {
1576 run = findRunAtLoc_GmDocument(d->doc, runLoc);
1577 if (run) {
1578 scrollTo_DocumentWidget_(d, mid_Rect(run->bounds).y, iTrue);
1579 }
1580 }
1581}
1582
1541static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { 1583static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) {
1542 iWidget *w = as_Widget(d); 1584 iWidget *w = as_Widget(d);
1543 if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) { 1585 if (equal_Command(cmd, "window.resized") || equal_Command(cmd, "font.changed")) {
1544 const iBool isVerticalOnly =
1545 !argLabel_Command(cmd, "horiz") && argLabel_Command(cmd, "vert");
1546 /* Alt/Option key may be involved in window size changes. */ 1586 /* Alt/Option key may be involved in window size changes. */
1547 iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse); 1587 iChangeFlags(d->flags, showLinkNumbers_DocumentWidgetFlag, iFalse);
1548 if (isVerticalOnly) { 1588 const iBool keepCenter = equal_Command(cmd, "font.changed");
1549 scroll_DocumentWidget_(d, 0); /* prevent overscroll */ 1589 updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, keepCenter);
1550 }
1551 else {
1552 const iGmRun *mid = middleRun_DocumentWidget_(d);
1553 const char *midLoc = (mid ? mid->text.start : NULL);
1554 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d));
1555 scroll_DocumentWidget_(d, 0);
1556 if (midLoc) {
1557 mid = findRunAtLoc_GmDocument(d->doc, midLoc);
1558 if (mid) {
1559 scrollTo_DocumentWidget_(d, mid_Rect(mid->bounds).y, iTrue);
1560 }
1561 }
1562 }
1563 updateSideIconBuf_DocumentWidget_(d); 1590 updateSideIconBuf_DocumentWidget_(d);
1564 updateOutline_DocumentWidget_(d); 1591 updateOutline_DocumentWidget_(d);
1565 invalidate_DocumentWidget_(d); 1592 invalidate_DocumentWidget_(d);
@@ -1581,6 +1608,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd)
1581 } 1608 }
1582 else if (equal_Command(cmd, "theme.changed") && document_App() == d) { 1609 else if (equal_Command(cmd, "theme.changed") && document_App() == d) {
1583 updateTheme_DocumentWidget_(d); 1610 updateTheme_DocumentWidget_(d);
1611 updateVisible_DocumentWidget_(d);
1584 updateTrust_DocumentWidget_(d, NULL); 1612 updateTrust_DocumentWidget_(d, NULL);
1585 updateSideIconBuf_DocumentWidget_(d); 1613 updateSideIconBuf_DocumentWidget_(d);
1586 invalidate_DocumentWidget_(d); 1614 invalidate_DocumentWidget_(d);
@@ -3398,7 +3426,7 @@ iBool isRequestOngoing_DocumentWidget(const iDocumentWidget *d) {
3398} 3426}
3399 3427
3400void updateSize_DocumentWidget(iDocumentWidget *d) { 3428void updateSize_DocumentWidget(iDocumentWidget *d) {
3401 setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d)); 3429 updateDocumentWidthRetainingScrollPosition_DocumentWidget_(d, iFalse);
3402 resetWideRuns_DocumentWidget_(d); 3430 resetWideRuns_DocumentWidget_(d);
3403 updateSideIconBuf_DocumentWidget_(d); 3431 updateSideIconBuf_DocumentWidget_(d);
3404 updateOutline_DocumentWidget_(d); 3432 updateOutline_DocumentWidget_(d);