diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gempub.c | 19 | ||||
-rw-r--r-- | src/gempub.h | 1 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 70 |
3 files changed, 64 insertions, 26 deletions
diff --git a/src/gempub.c b/src/gempub.c index f3021add..1f5d58ce 100644 --- a/src/gempub.c +++ b/src/gempub.c | |||
@@ -94,6 +94,9 @@ static void parseNavigationLinks_Gempub_(const iGempub *d) { | |||
94 | set_String(&link.url, absoluteUrl_String(url_GmRequest(index), collectNewRange_String(url))); | 94 | set_String(&link.url, absoluteUrl_String(url_GmRequest(index), collectNewRange_String(url))); |
95 | setRange_String(&link.label, capturedRange_RegExpMatch(&m, 2)); | 95 | setRange_String(&link.label, capturedRange_RegExpMatch(&m, 2)); |
96 | trim_String(&link.label); | 96 | trim_String(&link.label); |
97 | if (isEmpty_String(&link.label)) { | ||
98 | setRange_String(&link.label, url); | ||
99 | } | ||
97 | pushBack_Array(d->navLinks, &link); | 100 | pushBack_Array(d->navLinks, &link); |
98 | } | 101 | } |
99 | iEndCollect(); | 102 | iEndCollect(); |
@@ -280,7 +283,7 @@ static void appendProperty_Gempub_(const iGempub *d, const char *label, | |||
280 | } | 283 | } |
281 | } | 284 | } |
282 | 285 | ||
283 | static iBool isRemote_Gempub_(const iGempub *d) { | 286 | iBool isRemote_Gempub(const iGempub *d) { |
284 | return !equalCase_Rangecc(urlScheme_String(&d->baseUrl), "file"); | 287 | return !equalCase_Rangecc(urlScheme_String(&d->baseUrl), "file"); |
285 | } | 288 | } |
286 | 289 | ||
@@ -295,7 +298,7 @@ iString *coverPageSource_Gempub(const iGempub *d) { | |||
295 | } | 298 | } |
296 | appendCStr_String(out, "\n"); | 299 | appendCStr_String(out, "\n"); |
297 | appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); | 300 | appendProperty_Gempub_(d, "${gempub.meta.author}:", author_GempubProperty, out); |
298 | if (!isRemote_Gempub_(d)) { | 301 | if (!isRemote_Gempub(d)) { |
299 | appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", | 302 | appendFormat_String(out, "\n=> %s " book_Icon " ${gempub.cover.view}\n", |
300 | cstr_String(indexPageUrl_Gempub(d))); | 303 | cstr_String(indexPageUrl_Gempub(d))); |
301 | if (hasProperty_Gempub_(d, cover_GempubProperty)) { | 304 | if (hasProperty_Gempub_(d, cover_GempubProperty)) { |
@@ -306,12 +309,12 @@ iString *coverPageSource_Gempub(const iGempub *d) { | |||
306 | else { | 309 | else { |
307 | iString *key = collectNew_String(); /* TODO: add a helper for this */ | 310 | iString *key = collectNew_String(); /* TODO: add a helper for this */ |
308 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); | 311 | toString_Sym(SDLK_s, KMOD_PRIMARY, key); |
309 | appendCStr_String(out, "\n${gempub.cover.viewlocal} "); | 312 | appendCStr_String(out, "\n${gempub.cover.viewlocal}\n"); |
310 | appendFormat_String(out, | 313 | // appendFormat_String(out, |
311 | cstr_Lang("error.unsupported.suggestsave"), | 314 | // cstr_Lang("error.unsupported.suggestsave"), |
312 | cstr_String(key), | 315 | // cstr_String(key), |
313 | saveToDownloads_Label); | 316 | // saveToDownloads_Label); |
314 | appendCStr_String(out, "\n"); | 317 | // appendCStr_String(out, "\n"); |
315 | } | 318 | } |
316 | appendCStr_String(out, "\n## ${gempub.cover.aboutbook}\n"); | 319 | appendCStr_String(out, "\n## ${gempub.cover.aboutbook}\n"); |
317 | appendProperty_Gempub_(d, "${gempub.meta.version}:", version_GempubProperty, out); | 320 | appendProperty_Gempub_(d, "${gempub.meta.version}:", version_GempubProperty, out); |
diff --git a/src/gempub.h b/src/gempub.h index c03cabe6..e5f1b8eb 100644 --- a/src/gempub.h +++ b/src/gempub.h | |||
@@ -53,6 +53,7 @@ void close_Gempub (iGempub *); | |||
53 | void setBaseUrl_Gempub (iGempub *, const iString *baseUrl); | 53 | void setBaseUrl_Gempub (iGempub *, const iString *baseUrl); |
54 | 54 | ||
55 | iBool isOpen_Gempub (const iGempub *); | 55 | iBool isOpen_Gempub (const iGempub *); |
56 | iBool isRemote_Gempub (const iGempub *); | ||
56 | iString * coverPageSource_Gempub (const iGempub *); | 57 | iString * coverPageSource_Gempub (const iGempub *); |
57 | iBool preloadCoverImage_Gempub(const iGempub *, iGmDocument *doc); | 58 | iBool preloadCoverImage_Gempub(const iGempub *, iGmDocument *doc); |
58 | 59 | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index c8aad02b..a02e0bca 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -820,6 +820,13 @@ static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) { | |||
820 | return heading; | 820 | return heading; |
821 | } | 821 | } |
822 | 822 | ||
823 | static int updateScrollMax_DocumentWidget_(iDocumentWidget *d) { | ||
824 | arrange_Widget(d->footerButtons); /* scrollMax depends on footer height */ | ||
825 | const int scrollMax = scrollMax_DocumentWidget_(d); | ||
826 | setMax_SmoothScroll(&d->scrollY, scrollMax); | ||
827 | return scrollMax; | ||
828 | } | ||
829 | |||
823 | static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | 830 | static void updateVisible_DocumentWidget_(iDocumentWidget *d) { |
824 | iChangeFlags(d->flags, | 831 | iChangeFlags(d->flags, |
825 | centerVertically_DocumentWidgetFlag, | 832 | centerVertically_DocumentWidgetFlag, |
@@ -827,7 +834,7 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
827 | !isSuccess_GmStatusCode(d->sourceStatus)); | 834 | !isSuccess_GmStatusCode(d->sourceStatus)); |
828 | const iRangei visRange = visibleRange_DocumentWidget_(d); | 835 | const iRangei visRange = visibleRange_DocumentWidget_(d); |
829 | const iRect bounds = bounds_Widget(as_Widget(d)); | 836 | const iRect bounds = bounds_Widget(as_Widget(d)); |
830 | const int scrollMax = scrollMax_DocumentWidget_(d); | 837 | const int scrollMax = updateScrollMax_DocumentWidget_(d); |
831 | /* Reposition the footer buttons as appropriate. */ | 838 | /* Reposition the footer buttons as appropriate. */ |
832 | /* TODO: You can just position `footerButtons` here completely without having to get | 839 | /* TODO: You can just position `footerButtons` here completely without having to get |
833 | `Widget` involved with the offset in any way. */ | 840 | `Widget` involved with the offset in any way. */ |
@@ -837,7 +844,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
837 | const int hPad = (width_Rect(bounds) - iMin(120 * gap_UI, width_Rect(docBounds))) / 2; | 844 | const int hPad = (width_Rect(bounds) - iMin(120 * gap_UI, width_Rect(docBounds))) / 2; |
838 | const int vPad = 3 * gap_UI; | 845 | const int vPad = 3 * gap_UI; |
839 | setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); | 846 | setPadding_Widget(d->footerButtons, hPad, vPad, hPad, vPad); |
840 | arrange_Widget(d->footerButtons); | ||
841 | d->footerButtons->animOffsetRef = (scrollMax > 0 ? &d->scrollY.pos : NULL); | 847 | d->footerButtons->animOffsetRef = (scrollMax > 0 ? &d->scrollY.pos : NULL); |
842 | if (scrollMax <= 0) { | 848 | if (scrollMax <= 0) { |
843 | d->footerButtons->animOffsetRef = NULL; | 849 | d->footerButtons->animOffsetRef = NULL; |
@@ -848,7 +854,6 @@ static void updateVisible_DocumentWidget_(iDocumentWidget *d) { | |||
848 | d->footerButtons->rect.pos.y = size_GmDocument(d->doc).y + 2 * gap_UI * d->pageMargin; | 854 | d->footerButtons->rect.pos.y = size_GmDocument(d->doc).y + 2 * gap_UI * d->pageMargin; |
849 | } | 855 | } |
850 | } | 856 | } |
851 | setMax_SmoothScroll(&d->scrollY, scrollMax); | ||
852 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); | 857 | setRange_ScrollWidget(d->scroll, (iRangei){ 0, scrollMax }); |
853 | const int docSize = size_GmDocument(d->doc).y; | 858 | const int docSize = size_GmDocument(d->doc).y; |
854 | setThumb_ScrollWidget(d->scroll, | 859 | setThumb_ScrollWidget(d->scroll, |
@@ -1066,7 +1071,7 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte | |||
1066 | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | | 1071 | resizeWidthOfChildren_WidgetFlag | arrangeHeight_WidgetFlag | |
1067 | fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, | 1072 | fixedPosition_WidgetFlag | resizeToParentWidth_WidgetFlag, |
1068 | iTrue); | 1073 | iTrue); |
1069 | setBackgroundColor_Widget(d->footerButtons, tmBackground_ColorId); | 1074 | //setBackgroundColor_Widget(d->footerButtons, tmBackground_ColorId); |
1070 | for (size_t i = 0; i < count; ++i) { | 1075 | for (size_t i = 0; i < count; ++i) { |
1071 | iLabelWidget *button = addChildFlags_Widget( | 1076 | iLabelWidget *button = addChildFlags_Widget( |
1072 | d->footerButtons, | 1077 | d->footerButtons, |
@@ -1079,6 +1084,7 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte | |||
1079 | addChild_Widget(as_Widget(d), iClob(d->footerButtons)); | 1084 | addChild_Widget(as_Widget(d), iClob(d->footerButtons)); |
1080 | arrange_Widget(d->footerButtons); | 1085 | arrange_Widget(d->footerButtons); |
1081 | arrange_Widget(w); | 1086 | arrange_Widget(w); |
1087 | updateVisible_DocumentWidget_(d); /* final placement for the buttons */ | ||
1082 | } | 1088 | } |
1083 | 1089 | ||
1084 | static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, | 1090 | static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, |
@@ -1222,7 +1228,7 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool | |||
1222 | } | 1228 | } |
1223 | if (d->sourceGempub) { | 1229 | if (d->sourceGempub) { |
1224 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { | 1230 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { |
1225 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { | 1231 | if (!isRemote_Gempub(d->sourceGempub)) { |
1226 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | 1232 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1227 | pushBack_Array( | 1233 | pushBack_Array( |
1228 | items, | 1234 | items, |
@@ -1244,6 +1250,19 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool | |||
1244 | } | 1250 | } |
1245 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); | 1251 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); |
1246 | } | 1252 | } |
1253 | else { | ||
1254 | makeFooterButtons_DocumentWidget_( | ||
1255 | d, | ||
1256 | (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", | ||
1257 | SDLK_s, | ||
1258 | KMOD_PRIMARY | KMOD_SHIFT, | ||
1259 | "document.save open:1" }, | ||
1260 | { download_Icon " " saveToDownloads_Label, | ||
1261 | SDLK_s, | ||
1262 | KMOD_PRIMARY, | ||
1263 | "document.save" } }, | ||
1264 | 2); | ||
1265 | } | ||
1247 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { | 1266 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { |
1248 | redoLayout_GmDocument(d->doc); | 1267 | redoLayout_GmDocument(d->doc); |
1249 | updateVisible_DocumentWidget_(d); | 1268 | updateVisible_DocumentWidget_(d); |
@@ -2048,7 +2067,8 @@ static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { | |||
2048 | return iFalse; | 2067 | return iFalse; |
2049 | } | 2068 | } |
2050 | 2069 | ||
2051 | static void saveToDownloads_(const iString *url, const iString *mime, const iBlock *content) { | 2070 | static const iString *saveToDownloads_(const iString *url, const iString *mime, const iBlock *content, |
2071 | iBool showDialog) { | ||
2052 | const iString *savePath = downloadPathForUrl_App(url, mime); | 2072 | const iString *savePath = downloadPathForUrl_App(url, mime); |
2053 | /* Write the file. */ { | 2073 | /* Write the file. */ { |
2054 | iFile *f = new_File(savePath); | 2074 | iFile *f = new_File(savePath); |
@@ -2060,17 +2080,22 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo | |||
2060 | #if defined (iPlatformAppleMobile) | 2080 | #if defined (iPlatformAppleMobile) |
2061 | exportDownloadedFile_iOS(savePath); | 2081 | exportDownloadedFile_iOS(savePath); |
2062 | #else | 2082 | #else |
2063 | const iMenuItem items[2] = { | 2083 | if (showDialog) { |
2064 | { "${dlg.save.opendownload}", 0, 0, | 2084 | const iMenuItem items[2] = { |
2065 | format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, | 2085 | { "${dlg.save.opendownload}", 0, 0, |
2066 | { "${dlg.message.ok}", 0, 0, "message.ok" }, | 2086 | format_CStr("!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))) }, |
2067 | }; | 2087 | { "${dlg.message.ok}", 0, 0, "message.ok" }, |
2068 | makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", | 2088 | }; |
2069 | format_CStr("%s\n${dlg.save.size} %.3f %s", cstr_String(path_File(f)), | 2089 | makeMessage_Widget(uiHeading_ColorEscape "${heading.save}", |
2070 | isMega ? size / 1.0e6f : (size / 1.0e3f), | 2090 | format_CStr("%s\n${dlg.save.size} %.3f %s", |
2071 | isMega ? "${mb}" : "${kb}"), | 2091 | cstr_String(path_File(f)), |
2072 | items, iElemCount(items)); | 2092 | isMega ? size / 1.0e6f : (size / 1.0e3f), |
2093 | isMega ? "${mb}" : "${kb}"), | ||
2094 | items, | ||
2095 | iElemCount(items)); | ||
2096 | } | ||
2073 | #endif | 2097 | #endif |
2098 | return savePath; | ||
2074 | } | 2099 | } |
2075 | else { | 2100 | else { |
2076 | makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}", | 2101 | makeSimpleMessage_Widget(uiTextCaution_ColorEscape "${heading.save.error}", |
@@ -2078,6 +2103,7 @@ static void saveToDownloads_(const iString *url, const iString *mime, const iBlo | |||
2078 | } | 2103 | } |
2079 | iRelease(f); | 2104 | iRelease(f); |
2080 | } | 2105 | } |
2106 | return collectNew_String(); | ||
2081 | } | 2107 | } |
2082 | 2108 | ||
2083 | static void addAllLinks_(void *context, const iGmRun *run) { | 2109 | static void addAllLinks_(void *context, const iGmRun *run) { |
@@ -2556,7 +2582,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2556 | const iMediaRequest *media = findMediaRequest_DocumentWidget_(d, linkId); | 2582 | const iMediaRequest *media = findMediaRequest_DocumentWidget_(d, linkId); |
2557 | if (media) { | 2583 | if (media) { |
2558 | saveToDownloads_(url_GmRequest(media->req), meta_GmRequest(media->req), | 2584 | saveToDownloads_(url_GmRequest(media->req), meta_GmRequest(media->req), |
2559 | body_GmRequest(media->req)); | 2585 | body_GmRequest(media->req), iTrue); |
2560 | } | 2586 | } |
2561 | } | 2587 | } |
2562 | else if (equal_Command(cmd, "document.save") && document_App() == d) { | 2588 | else if (equal_Command(cmd, "document.save") && document_App() == d) { |
@@ -2565,7 +2591,13 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2565 | "${dlg.save.incomplete}"); | 2591 | "${dlg.save.incomplete}"); |
2566 | } | 2592 | } |
2567 | else if (!isEmpty_Block(&d->sourceContent)) { | 2593 | else if (!isEmpty_Block(&d->sourceContent)) { |
2568 | saveToDownloads_(d->mod.url, &d->sourceMime, &d->sourceContent); | 2594 | const iBool doOpen = argLabel_Command(cmd, "open"); |
2595 | const iString *savePath = saveToDownloads_(d->mod.url, &d->sourceMime, | ||
2596 | &d->sourceContent, !doOpen); | ||
2597 | if (!isEmpty_String(savePath) && doOpen) { | ||
2598 | postCommandf_Root( | ||
2599 | w->root, "!open url:%s", cstrCollect_String(makeFileUrl_String(savePath))); | ||
2600 | } | ||
2569 | } | 2601 | } |
2570 | return iTrue; | 2602 | return iTrue; |
2571 | } | 2603 | } |
@@ -2675,6 +2707,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2675 | return iTrue; | 2707 | return iTrue; |
2676 | } | 2708 | } |
2677 | else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { | 2709 | else if (equal_Command(cmd, "scroll.bottom") && document_App() == d) { |
2710 | updateScrollMax_DocumentWidget_(d); /* scrollY.max might not be fully updated */ | ||
2678 | init_Anim(&d->scrollY.pos, d->scrollY.max); | 2711 | init_Anim(&d->scrollY.pos, d->scrollY.max); |
2679 | invalidate_VisBuf(d->visBuf); | 2712 | invalidate_VisBuf(d->visBuf); |
2680 | clampScroll_DocumentWidget_(d); | 2713 | clampScroll_DocumentWidget_(d); |
@@ -3188,6 +3221,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3188 | iArray items; | 3221 | iArray items; |
3189 | init_Array(&items, sizeof(iMenuItem)); | 3222 | init_Array(&items, sizeof(iMenuItem)); |
3190 | if (d->contextLink) { | 3223 | if (d->contextLink) { |
3224 | /* Context menu for a link. */ | ||
3191 | const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); | 3225 | const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); |
3192 | // const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); | 3226 | // const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); |
3193 | const iRangecc scheme = urlScheme_String(linkUrl); | 3227 | const iRangecc scheme = urlScheme_String(linkUrl); |