diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-17 07:24:23 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-09-17 07:24:23 +0300 |
commit | 115602cf34dfb2f151846673468a41f16712eb49 (patch) | |
tree | d6f4330d55799fdb18df2bcd5d96e2c04c8d51f5 /src | |
parent | a48aa018640b2d631f318585da23e4ec7f8e8bdc (diff) |
DocumentWidget: Permanent images
A dynamically generated page showing nothing but an image should not be treated the same way as an inline image. I.e., disallow hiding the image on an image page.
Diffstat (limited to 'src')
-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); |