diff options
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r-- | src/ui/documentwidget.c | 98 |
1 files changed, 76 insertions, 22 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 384c51b5..50df05f5 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -264,6 +264,7 @@ struct Impl_DocumentWidget { | |||
264 | int pinchZoomPosted; | 264 | int pinchZoomPosted; |
265 | float swipeSpeed; /* points/sec */ | 265 | float swipeSpeed; /* points/sec */ |
266 | iString pendingGotoHeading; | 266 | iString pendingGotoHeading; |
267 | iString linePrecedingLink; | ||
267 | 268 | ||
268 | /* Network request: */ | 269 | /* Network request: */ |
269 | enum iRequestState state; | 270 | enum iRequestState state; |
@@ -391,6 +392,7 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
391 | d->grabbedPlayer = NULL; | 392 | d->grabbedPlayer = NULL; |
392 | d->mediaTimer = 0; | 393 | d->mediaTimer = 0; |
393 | init_String(&d->pendingGotoHeading); | 394 | init_String(&d->pendingGotoHeading); |
395 | init_String(&d->linePrecedingLink); | ||
394 | init_Click(&d->click, d, SDL_BUTTON_LEFT); | 396 | init_Click(&d->click, d, SDL_BUTTON_LEFT); |
395 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); | 397 | addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); |
396 | d->menu = NULL; /* created when clicking */ | 398 | d->menu = NULL; /* created when clicking */ |
@@ -437,6 +439,7 @@ void deinit_DocumentWidget(iDocumentWidget *d) { | |||
437 | iRelease(d->media); | 439 | iRelease(d->media); |
438 | iRelease(d->request); | 440 | iRelease(d->request); |
439 | delete_Gempub(d->sourceGempub); | 441 | delete_Gempub(d->sourceGempub); |
442 | deinit_String(&d->linePrecedingLink); | ||
440 | deinit_String(&d->pendingGotoHeading); | 443 | deinit_String(&d->pendingGotoHeading); |
441 | deinit_Block(&d->sourceContent); | 444 | deinit_Block(&d->sourceContent); |
442 | deinit_String(&d->sourceMime); | 445 | deinit_String(&d->sourceMime); |
@@ -1893,7 +1896,7 @@ static void addBannerWarnings_DocumentWidget_(iDocumentWidget *d) { | |||
1893 | 1896 | ||
1894 | static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, | 1897 | static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float normScrollY, |
1895 | const iGmResponse *resp, iGmDocument *cachedDoc) { | 1898 | const iGmResponse *resp, iGmDocument *cachedDoc) { |
1896 | iAssert(width_Widget(d) > 0); /* must be laid out by now */ | 1899 | // iAssert(width_Widget(d) > 0); /* must be laid out by now */ |
1897 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 1900 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
1898 | clear_ObjectList(d->media); | 1901 | clear_ObjectList(d->media); |
1899 | delete_Gempub(d->sourceGempub); | 1902 | delete_Gempub(d->sourceGempub); |
@@ -1918,9 +1921,6 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1918 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d), width_Widget(d)); | 1921 | setWidth_GmDocument(d->doc, documentWidth_DocumentWidget_(d), width_Widget(d)); |
1919 | } | 1922 | } |
1920 | updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); | 1923 | updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); |
1921 | // if (!cachedDoc) { | ||
1922 | // setCachedDocument_History(d->mod.history, d->doc, iFalse); | ||
1923 | // } | ||
1924 | clear_Banner(d->banner); | 1924 | clear_Banner(d->banner); |
1925 | updateBanner_DocumentWidget_(d); | 1925 | updateBanner_DocumentWidget_(d); |
1926 | addBannerWarnings_DocumentWidget_(d); | 1926 | addBannerWarnings_DocumentWidget_(d); |
@@ -2242,6 +2242,16 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
2242 | if (lineBreak && deviceType_App() != desktop_AppDeviceType) { | 2242 | if (lineBreak && deviceType_App() != desktop_AppDeviceType) { |
2243 | addChildPos_Widget(buttons, iClob(lineBreak), front_WidgetAddPos); | 2243 | addChildPos_Widget(buttons, iClob(lineBreak), front_WidgetAddPos); |
2244 | } | 2244 | } |
2245 | /* Menu for additional actions, past entries. */ { | ||
2246 | iMenuItem items[] = { { "${menu.input.precedingline}", | ||
2247 | SDLK_v, | ||
2248 | KMOD_PRIMARY | KMOD_SHIFT, | ||
2249 | format_CStr("!valueinput.set ptr:%p text:%s", | ||
2250 | buttons, | ||
2251 | cstr_String(&d->linePrecedingLink)) } }; | ||
2252 | iLabelWidget *menu = makeMenuButton_LabelWidget(midEllipsis_Icon, items, 1); | ||
2253 | addChildPos_Widget(buttons, iClob(menu), front_WidgetAddPos); | ||
2254 | } | ||
2245 | setValidator_InputWidget(findChild_Widget(dlg, "input"), inputQueryValidator_, d); | 2255 | setValidator_InputWidget(findChild_Widget(dlg, "input"), inputQueryValidator_, d); |
2246 | setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"), | 2256 | setSensitiveContent_InputWidget(findChild_Widget(dlg, "input"), |
2247 | statusCode == sensitiveInput_GmStatusCode); | 2257 | statusCode == sensitiveInput_GmStatusCode); |
@@ -3836,6 +3846,30 @@ static void beginMarkingSelection_DocumentWidget_(iDocumentWidget *d, iInt2 pos) | |||
3836 | refresh_Widget(as_Widget(d)); | 3846 | refresh_Widget(as_Widget(d)); |
3837 | } | 3847 | } |
3838 | 3848 | ||
3849 | static void linkWasTriggered_DocumentWidget_(iDocumentWidget *d, iGmLinkId id) { | ||
3850 | iRangecc loc = linkUrlRange_GmDocument(d->doc, id); | ||
3851 | if (!loc.start) { | ||
3852 | clear_String(&d->linePrecedingLink); | ||
3853 | return; | ||
3854 | } | ||
3855 | const char *start = range_String(source_GmDocument(d->doc)).start; | ||
3856 | /* Find the preceding line. This is offered as a prefill option for a possible input query. */ | ||
3857 | while (loc.start > start && *loc.start != '\n') { | ||
3858 | loc.start--; | ||
3859 | } | ||
3860 | loc.end = loc.start; /* End of the preceding line. */ | ||
3861 | if (loc.start > start) { | ||
3862 | loc.start--; | ||
3863 | } | ||
3864 | while (loc.start > start && *loc.start != '\n') { | ||
3865 | loc.start--; | ||
3866 | } | ||
3867 | if (*loc.start == '\n') { | ||
3868 | loc.start++; /* Start of the preceding line. */ | ||
3869 | } | ||
3870 | setRange_String(&d->linePrecedingLink, loc); | ||
3871 | } | ||
3872 | |||
3839 | static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { | 3873 | static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *ev) { |
3840 | iWidget *w = as_Widget(d); | 3874 | iWidget *w = as_Widget(d); |
3841 | if (isMetricsChange_UserEvent(ev)) { | 3875 | if (isMetricsChange_UserEvent(ev)) { |
@@ -3878,6 +3912,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3878 | : (d->flags & newTabViaHomeKeys_DocumentWidgetFlag ? 1 : 0)), | 3912 | : (d->flags & newTabViaHomeKeys_DocumentWidgetFlag ? 1 : 0)), |
3879 | cstr_String(absoluteUrl_String( | 3913 | cstr_String(absoluteUrl_String( |
3880 | d->mod.url, linkUrl_GmDocument(d->doc, run->linkId)))); | 3914 | d->mod.url, linkUrl_GmDocument(d->doc, run->linkId)))); |
3915 | linkWasTriggered_DocumentWidget_(d, run->linkId); | ||
3881 | } | 3916 | } |
3882 | setLinkNumberMode_DocumentWidget_(d, iFalse); | 3917 | setLinkNumberMode_DocumentWidget_(d, iFalse); |
3883 | invalidateVisibleLinks_DocumentWidget_(d); | 3918 | invalidateVisibleLinks_DocumentWidget_(d); |
@@ -3995,6 +4030,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3995 | return iTrue; | 4030 | return iTrue; |
3996 | } | 4031 | } |
3997 | if (ev->button.button == SDL_BUTTON_MIDDLE && d->hoverLink) { | 4032 | if (ev->button.button == SDL_BUTTON_MIDDLE && d->hoverLink) { |
4033 | linkWasTriggered_DocumentWidget_(d, d->hoverLink->linkId); | ||
3998 | postCommandf_Root(w->root, "open newtab:%d url:%s", | 4034 | postCommandf_Root(w->root, "open newtab:%d url:%s", |
3999 | (isPinned_DocumentWidget_(d) ? otherRoot_OpenTabFlag : 0) | | 4035 | (isPinned_DocumentWidget_(d) ? otherRoot_OpenTabFlag : 0) | |
4000 | (modState_Keys() & KMOD_SHIFT ? new_OpenTabFlag : newBackground_OpenTabFlag), | 4036 | (modState_Keys() & KMOD_SHIFT ? new_OpenTabFlag : newBackground_OpenTabFlag), |
@@ -4015,6 +4051,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
4015 | init_Array(&items, sizeof(iMenuItem)); | 4051 | init_Array(&items, sizeof(iMenuItem)); |
4016 | if (d->contextLink) { | 4052 | if (d->contextLink) { |
4017 | /* Context menu for a link. */ | 4053 | /* Context menu for a link. */ |
4054 | linkWasTriggered_DocumentWidget_(d, d->contextLink->linkId); /* perhaps will be triggered */ | ||
4018 | const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); | 4055 | const iString *linkUrl = linkUrl_GmDocument(d->doc, d->contextLink->linkId); |
4019 | // const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); | 4056 | // const int linkFlags = linkFlags_GmDocument(d->doc, d->contextLink->linkId); |
4020 | const iRangecc scheme = urlScheme_String(linkUrl); | 4057 | const iRangecc scheme = urlScheme_String(linkUrl); |
@@ -4034,23 +4071,30 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
4034 | /* Regular links that we can open. */ | 4071 | /* Regular links that we can open. */ |
4035 | pushBackN_Array( | 4072 | pushBackN_Array( |
4036 | &items, | 4073 | &items, |
4037 | (iMenuItem[]){ | 4074 | (iMenuItem[]){ { openTab_Icon " ${link.newtab}", |
4038 | { openTab_Icon " ${link.newtab}", | 4075 | 0, |
4039 | 0, | 4076 | 0, |
4040 | 0, | 4077 | format_CStr("!open newtab:1 origin:%s url:%s", |
4041 | format_CStr("!open newtab:1 url:%s", cstr_String(linkUrl)) }, | 4078 | cstr_String(id_Widget(w)), |
4042 | { openTabBg_Icon " ${link.newtab.background}", | 4079 | cstr_String(linkUrl)) }, |
4043 | 0, | 4080 | { openTabBg_Icon " ${link.newtab.background}", |
4044 | 0, | 4081 | 0, |
4045 | format_CStr("!open newtab:2 url:%s", cstr_String(linkUrl)) }, | 4082 | 0, |
4046 | { "${link.side}", | 4083 | format_CStr("!open newtab:2 origin:%s url:%s", |
4047 | 0, | 4084 | cstr_String(id_Widget(w)), |
4048 | 0, | 4085 | cstr_String(linkUrl)) }, |
4049 | format_CStr("!open newtab:4 url:%s", cstr_String(linkUrl)) }, | 4086 | { "${link.side}", |
4050 | { "${link.side.newtab}", | 4087 | 0, |
4051 | 0, | 4088 | 0, |
4052 | 0, | 4089 | format_CStr("!open newtab:4 origin:%s url:%s", |
4053 | format_CStr("!open newtab:5 url:%s", cstr_String(linkUrl)) } }, | 4090 | cstr_String(id_Widget(w)), |
4091 | cstr_String(linkUrl)) }, | ||
4092 | { "${link.side.newtab}", | ||
4093 | 0, | ||
4094 | 0, | ||
4095 | format_CStr("!open newtab:5 origin:%s url:%s", | ||
4096 | cstr_String(id_Widget(w)), | ||
4097 | cstr_String(linkUrl)) } }, | ||
4054 | 4); | 4098 | 4); |
4055 | if (deviceType_App() == phone_AppDeviceType) { | 4099 | if (deviceType_App() == phone_AppDeviceType) { |
4056 | removeN_Array(&items, size_Array(&items) - 2, iInvalidSize); | 4100 | removeN_Array(&items, size_Array(&items) - 2, iInvalidSize); |
@@ -4072,7 +4116,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
4072 | { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}", | 4116 | { isGemini ? "${link.noproxy}" : openExt_Icon " ${link.browser}", |
4073 | 0, | 4117 | 0, |
4074 | 0, | 4118 | 0, |
4075 | format_CStr("!open noproxy:1 url:%s", cstr_String(linkUrl)) } }, | 4119 | format_CStr("!open origin:%s noproxy:1 url:%s", |
4120 | cstr_String(id_Widget(w)), | ||
4121 | cstr_String(linkUrl)) } }, | ||
4076 | 2); | 4122 | 2); |
4077 | } | 4123 | } |
4078 | iString *linkLabel = collectNewRange_String( | 4124 | iString *linkLabel = collectNewRange_String( |
@@ -4414,6 +4460,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
4414 | if (isPinned_DocumentWidget_(d)) { | 4460 | if (isPinned_DocumentWidget_(d)) { |
4415 | tabMode ^= otherRoot_OpenTabFlag; | 4461 | tabMode ^= otherRoot_OpenTabFlag; |
4416 | } | 4462 | } |
4463 | linkWasTriggered_DocumentWidget_(d, linkId); | ||
4417 | postCommandf_Root(w->root, "open newtab:%d url:%s", | 4464 | postCommandf_Root(w->root, "open newtab:%d url:%s", |
4418 | tabMode, | 4465 | tabMode, |
4419 | cstr_String(absoluteUrl_String( | 4466 | cstr_String(absoluteUrl_String( |
@@ -5495,6 +5542,13 @@ iDocumentWidget *duplicate_DocumentWidget(const iDocumentWidget *orig) { | |||
5495 | return d; | 5542 | return d; |
5496 | } | 5543 | } |
5497 | 5544 | ||
5545 | void setOrigin_DocumentWidget(iDocumentWidget *d, const iDocumentWidget *other) { | ||
5546 | if (d != other) { | ||
5547 | /* TODO: Could remember the other's ID? */ | ||
5548 | set_String(&d->linePrecedingLink, &other->linePrecedingLink); | ||
5549 | } | ||
5550 | } | ||
5551 | |||
5498 | void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { | 5552 | void setUrl_DocumentWidget(iDocumentWidget *d, const iString *url) { |
5499 | setUrlFlags_DocumentWidget(d, url, 0); | 5553 | setUrlFlags_DocumentWidget(d, url, 0); |
5500 | } | 5554 | } |