diff options
-rw-r--r-- | src/gmdocument.c | 18 | ||||
-rw-r--r-- | src/gmdocument.h | 7 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 20 |
3 files changed, 34 insertions, 11 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index 723e3eaf..b2561ee0 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -64,11 +64,13 @@ struct Impl_GmImage { | |||
64 | size_t numBytes; | 64 | size_t numBytes; |
65 | iString mime; | 65 | iString mime; |
66 | iGmLinkId linkId; | 66 | iGmLinkId linkId; |
67 | iBool isPermanent; | ||
67 | SDL_Texture *texture; | 68 | SDL_Texture *texture; |
68 | }; | 69 | }; |
69 | 70 | ||
70 | void init_GmImage(iGmImage *d, const iBlock *data) { | 71 | void init_GmImage(iGmImage *d, const iBlock *data) { |
71 | init_String(&d->mime); | 72 | init_String(&d->mime); |
73 | d->isPermanent = iFalse; | ||
72 | d->numBytes = size_Block(data); | 74 | d->numBytes = size_Block(data); |
73 | uint8_t *imgData = stbi_load_from_memory( | 75 | uint8_t *imgData = stbi_load_from_memory( |
74 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | 76 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); |
@@ -542,8 +544,14 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
542 | if (type == link_GmLineType) { | 544 | if (type == link_GmLineType) { |
543 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); | 545 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); |
544 | if (imgIndex != iInvalidPos) { | 546 | if (imgIndex != iInvalidPos) { |
545 | ((iGmLink *) at_PtrArray(&d->links, run.linkId - 1))->flags |= content_GmLinkFlag; | ||
546 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); | 547 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); |
548 | /* Mark the link as having content. */ { | ||
549 | iGmLink *link = at_PtrArray(&d->links, run.linkId - 1); | ||
550 | link->flags |= content_GmLinkFlag; | ||
551 | if (img->isPermanent) { | ||
552 | link->flags |= permanent_GmLinkFlag; | ||
553 | } | ||
554 | } | ||
547 | const int margin = 0.5f * lineHeight_Text(paragraph_FontId); | 555 | const int margin = 0.5f * lineHeight_Text(paragraph_FontId); |
548 | pos.y += margin; | 556 | pos.y += margin; |
549 | run.bounds.pos = pos; | 557 | run.bounds.pos = pos; |
@@ -952,7 +960,8 @@ void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int | |||
952 | setWidth_GmDocument(d, width, forceBreakWidth); /* re-do layout */ | 960 | setWidth_GmDocument(d, width, forceBreakWidth); /* re-do layout */ |
953 | } | 961 | } |
954 | 962 | ||
955 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { | 963 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data, |
964 | iBool allowHide) { | ||
956 | if (!mime || !data) { | 965 | if (!mime || !data) { |
957 | iGmImage *img; | 966 | iGmImage *img; |
958 | if (take_PtrArray(&d->images, findLinkImage_GmDocument_(d, linkId), (void **) &img)) { | 967 | if (take_PtrArray(&d->images, findLinkImage_GmDocument_(d, linkId), (void **) &img)) { |
@@ -961,16 +970,17 @@ void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, | |||
961 | } | 970 | } |
962 | else { | 971 | else { |
963 | /* TODO: check if we know this MIME type */ | 972 | /* TODO: check if we know this MIME type */ |
964 | /* Load the image. */ { | 973 | /* Upload the image. */ { |
965 | iGmImage *img = new_GmImage(data); | 974 | iGmImage *img = new_GmImage(data); |
966 | img->linkId = linkId; /* TODO: use a hash? */ | 975 | img->linkId = linkId; /* TODO: use a hash? */ |
976 | img->isPermanent = !allowHide; | ||
967 | set_String(&img->mime, mime); | 977 | set_String(&img->mime, mime); |
968 | if (img->texture) { | 978 | if (img->texture) { |
969 | pushBack_PtrArray(&d->images, img); | 979 | pushBack_PtrArray(&d->images, img); |
970 | } | 980 | } |
971 | else { | 981 | else { |
972 | delete_GmImage(img); | 982 | delete_GmImage(img); |
973 | } | 983 | } |
974 | } | 984 | } |
975 | } | 985 | } |
976 | doLayout_GmDocument_(d); | 986 | doLayout_GmDocument_(d); |
diff --git a/src/gmdocument.h b/src/gmdocument.h index 5e5f282e..23ce5e8a 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -44,13 +44,15 @@ enum iGmLinkFlags { | |||
44 | file_GmLinkFlag = iBit(4), | 44 | file_GmLinkFlag = iBit(4), |
45 | data_GmLinkFlag = iBit(5), | 45 | data_GmLinkFlag = iBit(5), |
46 | about_GmLinkFlag = iBit(6), | 46 | about_GmLinkFlag = iBit(6), |
47 | supportedProtocol_GmLinkFlag = 0x3f, | 47 | mailto_GmLinkFlag = iBit(7), |
48 | supportedProtocol_GmLinkFlag = 0xff, | ||
48 | remote_GmLinkFlag = iBit(9), | 49 | remote_GmLinkFlag = iBit(9), |
49 | userFriendly_GmLinkFlag = iBit(10), | 50 | userFriendly_GmLinkFlag = iBit(10), |
50 | imageFileExtension_GmLinkFlag = iBit(11), | 51 | imageFileExtension_GmLinkFlag = iBit(11), |
51 | audioFileExtension_GmLinkFlag = iBit(12), | 52 | audioFileExtension_GmLinkFlag = iBit(12), |
52 | content_GmLinkFlag = iBit(13), /* content visible below */ | 53 | content_GmLinkFlag = iBit(13), /* content visible below */ |
53 | visited_GmLinkFlag = iBit(14), /* in the history */ | 54 | visited_GmLinkFlag = iBit(14), /* in the history */ |
55 | permanent_GmLinkFlag = iBit(15), /* content cannot be dismissed; media link */ | ||
54 | }; | 56 | }; |
55 | 57 | ||
56 | struct Impl_GmImageInfo { | 58 | struct Impl_GmImageInfo { |
@@ -98,7 +100,8 @@ void setFormat_GmDocument (iGmDocument *, enum iGmDocumentFormat format); | |||
98 | void setWidth_GmDocument (iGmDocument *, int width, int forceBreakWidth); | 100 | void setWidth_GmDocument (iGmDocument *, int width, int forceBreakWidth); |
99 | void setUrl_GmDocument (iGmDocument *, const iString *url); | 101 | void setUrl_GmDocument (iGmDocument *, const iString *url); |
100 | void setSource_GmDocument (iGmDocument *, const iString *source, int width, int forceBreakWidth); | 102 | void setSource_GmDocument (iGmDocument *, const iString *source, int width, int forceBreakWidth); |
101 | void setImage_GmDocument (iGmDocument *, iGmLinkId linkId, const iString *mime, const iBlock *data); | 103 | void setImage_GmDocument (iGmDocument *, iGmLinkId linkId, const iString *mime, const iBlock *data, |
104 | iBool allowHide); | ||
102 | 105 | ||
103 | void reset_GmDocument (iGmDocument *); /* free images */ | 106 | void reset_GmDocument (iGmDocument *); /* free images */ |
104 | 107 | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index ab8af9b8..84ad1139 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -363,6 +363,10 @@ static void updateHover_DocumentWidget_(iDocumentWidget *d, iInt2 mouse) { | |||
363 | if (isHover_Widget(w) && !contains_Widget(constAs_Widget(d->scroll), mouse)) { | 363 | if (isHover_Widget(w) && !contains_Widget(constAs_Widget(d->scroll), mouse)) { |
364 | setCursor_Window(get_Window(), | 364 | setCursor_Window(get_Window(), |
365 | d->hoverLink ? SDL_SYSTEM_CURSOR_HAND : SDL_SYSTEM_CURSOR_IBEAM); | 365 | d->hoverLink ? SDL_SYSTEM_CURSOR_HAND : SDL_SYSTEM_CURSOR_IBEAM); |
366 | if (d->hoverLink && | ||
367 | linkFlags_GmDocument(d->doc, d->hoverLink->linkId) & permanent_GmLinkFlag) { | ||
368 | setCursor_Window(get_Window(), SDL_SYSTEM_CURSOR_ARROW); /* not dismissable */ | ||
369 | } | ||
366 | } | 370 | } |
367 | } | 371 | } |
368 | 372 | ||
@@ -575,7 +579,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse | |||
575 | } | 579 | } |
576 | format_String( | 580 | format_String( |
577 | &str, "=> %s %s\n", cstr_String(d->mod.url), imageTitle); | 581 | &str, "=> %s %s\n", cstr_String(d->mod.url), imageTitle); |
578 | setImage_GmDocument(d->doc, 1, mimeStr, &response->body); | 582 | setImage_GmDocument(d->doc, 1, mimeStr, &response->body, iFalse /* it's fixed */); |
579 | } | 583 | } |
580 | else { | 584 | else { |
581 | clear_String(&str); | 585 | clear_String(&str); |
@@ -974,7 +978,7 @@ static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char * | |||
974 | // cstr_String(meta_GmRequest(req->req))); | 978 | // cstr_String(meta_GmRequest(req->req))); |
975 | if (startsWith_String(meta_GmRequest(req->req), "image/")) { | 979 | if (startsWith_String(meta_GmRequest(req->req), "image/")) { |
976 | setImage_GmDocument(d->doc, req->linkId, meta_GmRequest(req->req), | 980 | setImage_GmDocument(d->doc, req->linkId, meta_GmRequest(req->req), |
977 | body_GmRequest(req->req)); | 981 | body_GmRequest(req->req), iTrue); |
978 | updateVisible_DocumentWidget_(d); | 982 | updateVisible_DocumentWidget_(d); |
979 | invalidate_DocumentWidget_(d); | 983 | invalidate_DocumentWidget_(d); |
980 | refresh_Widget(as_Widget(d)); | 984 | refresh_Widget(as_Widget(d)); |
@@ -1489,10 +1493,16 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1489 | iAssert(linkId); | 1493 | iAssert(linkId); |
1490 | /* Media links are opened inline by default. */ | 1494 | /* Media links are opened inline by default. */ |
1491 | if (isMediaLink_GmDocument(d->doc, linkId)) { | 1495 | if (isMediaLink_GmDocument(d->doc, linkId)) { |
1496 | const int linkFlags = linkFlags_GmDocument(d->doc, linkId); | ||
1497 | if (linkFlags & content_GmLinkFlag && linkFlags & permanent_GmLinkFlag) { | ||
1498 | /* We have the image and it cannot be dismissed, so nothing | ||
1499 | further to do. */ | ||
1500 | return iTrue; | ||
1501 | } | ||
1492 | if (!requestMedia_DocumentWidget_(d, linkId)) { | 1502 | if (!requestMedia_DocumentWidget_(d, linkId)) { |
1493 | if (linkFlags_GmDocument(d->doc, linkId) & content_GmLinkFlag) { | 1503 | if (linkFlags & content_GmLinkFlag) { |
1494 | /* Dismiss shown content on click. */ | 1504 | /* Dismiss shown content on click. */ |
1495 | setImage_GmDocument(d->doc, linkId, NULL, NULL); | 1505 | setImage_GmDocument(d->doc, linkId, NULL, NULL, iTrue); |
1496 | d->hoverLink = NULL; | 1506 | d->hoverLink = NULL; |
1497 | scroll_DocumentWidget_(d, 0); | 1507 | scroll_DocumentWidget_(d, 0); |
1498 | updateVisible_DocumentWidget_(d); | 1508 | updateVisible_DocumentWidget_(d); |
@@ -1505,7 +1515,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
1505 | iMediaRequest *req = findMediaRequest_DocumentWidget_(d, linkId); | 1515 | iMediaRequest *req = findMediaRequest_DocumentWidget_(d, linkId); |
1506 | if (req) { | 1516 | if (req) { |
1507 | setImage_GmDocument(d->doc, linkId, meta_GmRequest(req->req), | 1517 | setImage_GmDocument(d->doc, linkId, meta_GmRequest(req->req), |
1508 | body_GmRequest(req->req)); | 1518 | body_GmRequest(req->req), iTrue); |
1509 | updateVisible_DocumentWidget_(d); | 1519 | updateVisible_DocumentWidget_(d); |
1510 | invalidate_DocumentWidget_(d); | 1520 | invalidate_DocumentWidget_(d); |
1511 | refresh_Widget(w); | 1521 | refresh_Widget(w); |