diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-07-29 07:42:30 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-07-29 07:42:30 +0300 |
commit | 4deb72ba6ea6c055dff69d74669887f30ea01e54 (patch) | |
tree | ea9b9645b38367afabaa66637c15d9a1cd0c3374 | |
parent | d921021132367076cd2a5f120b3a49db6e29acf7 (diff) |
Showing and hiding image content
-rw-r--r-- | src/gmdocument.c | 89 | ||||
-rw-r--r-- | src/gmdocument.h | 11 | ||||
-rw-r--r-- | src/ui/color.c | 25 | ||||
-rw-r--r-- | src/ui/color.h | 5 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 97 | ||||
-rw-r--r-- | src/ui/window.c | 6 |
6 files changed, 178 insertions, 55 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index f8998c17..4a3f8e06 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -33,12 +33,16 @@ iDefineTypeConstruction(GmLink) | |||
33 | iDeclareType(GmImage) | 33 | iDeclareType(GmImage) |
34 | 34 | ||
35 | struct Impl_GmImage { | 35 | struct Impl_GmImage { |
36 | iInt2 size; | 36 | iInt2 size; |
37 | size_t numBytes; | ||
38 | iString mime; | ||
39 | iGmLinkId linkId; | ||
37 | SDL_Texture *texture; | 40 | SDL_Texture *texture; |
38 | iGmLinkId linkId; | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | void init_GmImage(iGmImage *d, const iBlock *data) { | 43 | void init_GmImage(iGmImage *d, const iBlock *data) { |
44 | init_String(&d->mime); | ||
45 | d->numBytes = size_Block(data); | ||
42 | uint8_t *imgData = stbi_load_from_memory( | 46 | uint8_t *imgData = stbi_load_from_memory( |
43 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | 47 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); |
44 | if (!imgData) { | 48 | if (!imgData) { |
@@ -60,6 +64,7 @@ void init_GmImage(iGmImage *d, const iBlock *data) { | |||
60 | 64 | ||
61 | void deinit_GmImage(iGmImage *d) { | 65 | void deinit_GmImage(iGmImage *d) { |
62 | SDL_DestroyTexture(d->texture); | 66 | SDL_DestroyTexture(d->texture); |
67 | deinit_String(&d->mime); | ||
63 | } | 68 | } |
64 | 69 | ||
65 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) | 70 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) |
@@ -379,6 +384,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
379 | if (link->flags & remote_GmLinkFlag) { | 384 | if (link->flags & remote_GmLinkFlag) { |
380 | run.visBounds.pos.x -= gap_UI / 2; | 385 | run.visBounds.pos.x -= gap_UI / 2; |
381 | } | 386 | } |
387 | |||
382 | run.color = linkColor_GmDocument(d, run.linkId); | 388 | run.color = linkColor_GmDocument(d, run.linkId); |
383 | pushBack_Array(&d->layout, &run); | 389 | pushBack_Array(&d->layout, &run); |
384 | } | 390 | } |
@@ -429,18 +435,29 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
429 | if (type == link_GmLineType) { | 435 | if (type == link_GmLineType) { |
430 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); | 436 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); |
431 | if (imgIndex != iInvalidPos) { | 437 | if (imgIndex != iInvalidPos) { |
438 | ((iGmLink *) at_PtrArray(&d->links, run.linkId - 1))->flags |= content_GmLinkFlag; | ||
432 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); | 439 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); |
440 | const int margin = 0.5f * lineHeight_Text(paragraph_FontId); | ||
441 | pos.y += margin; | ||
433 | run.bounds.pos = pos; | 442 | run.bounds.pos = pos; |
434 | run.bounds.size.x = d->size.x; | 443 | run.bounds.size.x = d->size.x; |
435 | const float aspect = (float) img->size.y / (float) img->size.x; | 444 | const float aspect = (float) img->size.y / (float) img->size.x; |
436 | run.bounds.size.y = d->size.x * aspect; | 445 | run.bounds.size.y = d->size.x * aspect; |
437 | run.visBounds = run.bounds; /* TODO: limit max height? */ | 446 | run.visBounds = run.bounds; |
447 | const iInt2 maxSize = mulf_I2(img->size, get_Window()->pixelRatio); | ||
448 | if (width_Rect(run.visBounds) > maxSize.x) { | ||
449 | /* Don't scale the image up. */ | ||
450 | run.visBounds.size.y = run.visBounds.size.y * maxSize.x / width_Rect(run.visBounds); | ||
451 | run.visBounds.size.x = img->size.x; | ||
452 | run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2; | ||
453 | run.bounds.size.y = run.visBounds.size.y; | ||
454 | } | ||
438 | run.text = iNullRange; | 455 | run.text = iNullRange; |
439 | run.font = 0; | 456 | run.font = 0; |
440 | run.color = 0; | 457 | run.color = 0; |
441 | run.imageId = imgIndex + 1; | 458 | run.imageId = imgIndex + 1; |
442 | pushBack_Array(&d->layout, &run); | 459 | pushBack_Array(&d->layout, &run); |
443 | pos.y += run.bounds.size.y; | 460 | pos.y += run.bounds.size.y + margin; |
444 | } | 461 | } |
445 | } | 462 | } |
446 | prevType = type; | 463 | prevType = type; |
@@ -559,17 +576,26 @@ void setSource_GmDocument(iGmDocument *d, const iString *source, int width) { | |||
559 | } | 576 | } |
560 | 577 | ||
561 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { | 578 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { |
562 | /* TODO: check if we know this MIME type */ | 579 | if (!mime || !data) { |
563 | /* Load the image. */ { | 580 | iGmImage *img; |
564 | iGmImage *img = new_GmImage(data); | 581 | if (take_PtrArray(&d->images, findLinkImage_GmDocument_(d, linkId), (void **) &img)) { |
565 | img->linkId = linkId; /* TODO: use a hash? */ | ||
566 | if (img->texture) { | ||
567 | pushBack_PtrArray(&d->images, img); | ||
568 | } | ||
569 | else { | ||
570 | delete_GmImage(img); | 582 | delete_GmImage(img); |
571 | } | 583 | } |
572 | } | 584 | } |
585 | else { | ||
586 | /* TODO: check if we know this MIME type */ | ||
587 | /* Load the image. */ { | ||
588 | iGmImage *img = new_GmImage(data); | ||
589 | img->linkId = linkId; /* TODO: use a hash? */ | ||
590 | set_String(&img->mime, mime); | ||
591 | if (img->texture) { | ||
592 | pushBack_PtrArray(&d->images, img); | ||
593 | } | ||
594 | else { | ||
595 | delete_GmImage(img); | ||
596 | } | ||
597 | } | ||
598 | } | ||
573 | doLayout_GmDocument_(d); | 599 | doLayout_GmDocument_(d); |
574 | } | 600 | } |
575 | 601 | ||
@@ -649,25 +675,34 @@ const iGmRun *findRunAtLoc_GmDocument(const iGmDocument *d, const char *textCStr | |||
649 | return NULL; | 675 | return NULL; |
650 | } | 676 | } |
651 | 677 | ||
652 | const iString *linkUrl_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 678 | static const iGmLink *link_GmDocument_(const iGmDocument *d, iGmLinkId id) { |
653 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 679 | if (id > 0 && id <= size_PtrArray(&d->links)) { |
654 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 680 | return constAt_PtrArray(&d->links, id - 1); |
655 | return &link->url; | ||
656 | } | 681 | } |
657 | return NULL; | 682 | return NULL; |
658 | } | 683 | } |
659 | 684 | ||
685 | const iString *linkUrl_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | ||
686 | const iGmLink *link = link_GmDocument_(d, linkId); | ||
687 | return link ? &link->url : NULL; | ||
688 | } | ||
689 | |||
660 | int linkFlags_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 690 | int linkFlags_GmDocument(const iGmDocument *d, iGmLinkId linkId) { |
661 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 691 | const iGmLink *link = link_GmDocument_(d, linkId); |
662 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 692 | return link ? link->flags : 0; |
663 | return link->flags; | 693 | } |
694 | |||
695 | uint16_t linkImage_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | ||
696 | size_t index = findLinkImage_GmDocument_(d, linkId); | ||
697 | if (index != iInvalidPos) { | ||
698 | return index + 1; | ||
664 | } | 699 | } |
665 | return 0; | 700 | return 0; |
666 | } | 701 | } |
667 | 702 | ||
668 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 703 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId) { |
669 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 704 | const iGmLink *link = link_GmDocument_(d, linkId); |
670 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 705 | if (link) { |
671 | return link->flags & http_GmLinkFlag | 706 | return link->flags & http_GmLinkFlag |
672 | ? orange_ColorId | 707 | ? orange_ColorId |
673 | : link->flags & gopher_GmLinkFlag ? blue_ColorId : cyan_ColorId; | 708 | : link->flags & gopher_GmLinkFlag ? blue_ColorId : cyan_ColorId; |
@@ -688,6 +723,18 @@ SDL_Texture *imageTexture_GmDocument(const iGmDocument *d, uint16_t imageId) { | |||
688 | return NULL; | 723 | return NULL; |
689 | } | 724 | } |
690 | 725 | ||
726 | void imageInfo_GmDocument(const iGmDocument *d, uint16_t imageId, iGmImageInfo *info_out) { | ||
727 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { | ||
728 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); | ||
729 | info_out->size = img->size; | ||
730 | info_out->numBytes = img->numBytes; | ||
731 | info_out->mime = cstr_String(&img->mime); | ||
732 | } | ||
733 | else { | ||
734 | iZap(*info_out); | ||
735 | } | ||
736 | } | ||
737 | |||
691 | const iString *title_GmDocument(const iGmDocument *d) { | 738 | const iString *title_GmDocument(const iGmDocument *d) { |
692 | return &d->title; | 739 | return &d->title; |
693 | } | 740 | } |
diff --git a/src/gmdocument.h b/src/gmdocument.h index c619c47b..584efb5a 100644 --- a/src/gmdocument.h +++ b/src/gmdocument.h | |||
@@ -19,6 +19,15 @@ enum iGmLinkFlags { | |||
19 | file_GmLinkFlag = 0x10, | 19 | file_GmLinkFlag = 0x10, |
20 | imageFileExtension_GmLinkFlag = 0x20, | 20 | imageFileExtension_GmLinkFlag = 0x20, |
21 | audioFileExtension_GmLinkFlag = 0x40, | 21 | audioFileExtension_GmLinkFlag = 0x40, |
22 | content_GmLinkFlag = 0x80, /* content visible below */ | ||
23 | }; | ||
24 | |||
25 | iDeclareType(GmImageInfo) | ||
26 | |||
27 | struct Impl_GmImageInfo { | ||
28 | iInt2 size; | ||
29 | size_t numBytes; | ||
30 | const char *mime; | ||
22 | }; | 31 | }; |
23 | 32 | ||
24 | struct Impl_GmRun { | 33 | struct Impl_GmRun { |
@@ -61,9 +70,11 @@ const iGmRun * findRun_GmDocument (const iGmDocument *, iInt2 pos); | |||
61 | const char * findLoc_GmDocument (const iGmDocument *, iInt2 pos); | 70 | const char * findLoc_GmDocument (const iGmDocument *, iInt2 pos); |
62 | const iGmRun * findRunAtLoc_GmDocument (const iGmDocument *, const char *loc); | 71 | const iGmRun * findRunAtLoc_GmDocument (const iGmDocument *, const char *loc); |
63 | const iString * linkUrl_GmDocument (const iGmDocument *, iGmLinkId linkId); | 72 | const iString * linkUrl_GmDocument (const iGmDocument *, iGmLinkId linkId); |
73 | uint16_t linkImage_GmDocument (const iGmDocument *, iGmLinkId linkId); | ||
64 | int linkFlags_GmDocument (const iGmDocument *, iGmLinkId linkId); | 74 | int linkFlags_GmDocument (const iGmDocument *, iGmLinkId linkId); |
65 | enum iColorId linkColor_GmDocument (const iGmDocument *, iGmLinkId linkId); | 75 | enum iColorId linkColor_GmDocument (const iGmDocument *, iGmLinkId linkId); |
66 | iBool isMediaLink_GmDocument (const iGmDocument *, iGmLinkId linkId); | 76 | iBool isMediaLink_GmDocument (const iGmDocument *, iGmLinkId linkId); |
67 | const iString * title_GmDocument (const iGmDocument *); | 77 | const iString * title_GmDocument (const iGmDocument *); |
68 | 78 | ||
69 | SDL_Texture * imageTexture_GmDocument (const iGmDocument *, uint16_t imageId); | 79 | SDL_Texture * imageTexture_GmDocument (const iGmDocument *, uint16_t imageId); |
80 | void imageInfo_GmDocument (const iGmDocument *, uint16_t imageId, iGmImageInfo *info_out); | ||
diff --git a/src/ui/color.c b/src/ui/color.c index 330dab1d..46d8a71f 100644 --- a/src/ui/color.c +++ b/src/ui/color.c | |||
@@ -30,6 +30,31 @@ iColor get_Color(int color) { | |||
30 | return *clr; | 30 | return *clr; |
31 | } | 31 | } |
32 | 32 | ||
33 | const char *escape_Color(int color) { | ||
34 | static const char *esc[] = { | ||
35 | black_ColorEscape, | ||
36 | gray15_ColorEscape, | ||
37 | gray25_ColorEscape, | ||
38 | gray50_ColorEscape, | ||
39 | gray75_ColorEscape, | ||
40 | gray88_ColorEscape, | ||
41 | white_ColorEscape, | ||
42 | brown_ColorEscape, | ||
43 | orange_ColorEscape, | ||
44 | teal_ColorEscape, | ||
45 | cyan_ColorEscape, | ||
46 | yellow_ColorEscape, | ||
47 | red_ColorEscape, | ||
48 | magenta_ColorEscape, | ||
49 | blue_ColorEscape, | ||
50 | green_ColorEscape, | ||
51 | }; | ||
52 | if (color >= 0 && color < max_ColorId) { | ||
53 | return esc[color]; | ||
54 | } | ||
55 | return white_ColorEscape; | ||
56 | } | ||
57 | |||
33 | iColor ansi_Color(iRangecc escapeSequence, int fallback) { | 58 | iColor ansi_Color(iRangecc escapeSequence, int fallback) { |
34 | iColor clr = get_Color(fallback); | 59 | iColor clr = get_Color(fallback); |
35 | for (const char *ch = escapeSequence.start; ch < escapeSequence.end; ch++) { | 60 | for (const char *ch = escapeSequence.start; ch < escapeSequence.end; ch++) { |
diff --git a/src/ui/color.h b/src/ui/color.h index d8b1f4d1..01e49c9c 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -49,5 +49,6 @@ struct Impl_Color { | |||
49 | uint8_t r, g, b, a; | 49 | uint8_t r, g, b, a; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | iColor get_Color (int color); | 52 | iColor get_Color (int color); |
53 | iColor ansi_Color (iRangecc escapeSequence, int fallback); | 53 | iColor ansi_Color (iRangecc escapeSequence, int fallback); |
54 | const char * escape_Color (int color); | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index cffd284f..f63e98bf 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -497,13 +497,15 @@ static iMediaRequest *findMediaRequest_DocumentWidget_(const iDocumentWidget *d, | |||
497 | return NULL; | 497 | return NULL; |
498 | } | 498 | } |
499 | 499 | ||
500 | static void requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId) { | 500 | static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId) { |
501 | if (!findMediaRequest_DocumentWidget_(d, linkId)) { | 501 | if (!findMediaRequest_DocumentWidget_(d, linkId)) { |
502 | pushBack_ObjectList( | 502 | pushBack_ObjectList( |
503 | d->media, | 503 | d->media, |
504 | iClob(new_MediaRequest( | 504 | iClob(new_MediaRequest( |
505 | d, linkId, absoluteUrl_DocumentWidget_(d, linkUrl_GmDocument(d->doc, linkId))))); | 505 | d, linkId, absoluteUrl_DocumentWidget_(d, linkUrl_GmDocument(d->doc, linkId))))); |
506 | return iTrue; | ||
506 | } | 507 | } |
508 | return iFalse; | ||
507 | } | 509 | } |
508 | 510 | ||
509 | static iBool handleMediaEvent_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 511 | static iBool handleMediaEvent_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
@@ -777,7 +779,26 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
777 | iAssert(linkId); | 779 | iAssert(linkId); |
778 | /* Media links are opened inline by default. */ | 780 | /* Media links are opened inline by default. */ |
779 | if (isMediaLink_GmDocument(d->doc, linkId)) { | 781 | if (isMediaLink_GmDocument(d->doc, linkId)) { |
780 | requestMedia_DocumentWidget_(d, linkId); | 782 | if (!requestMedia_DocumentWidget_(d, linkId)) { |
783 | if (linkFlags_GmDocument(d->doc, linkId) & content_GmLinkFlag) { | ||
784 | setImage_GmDocument(d->doc, linkId, NULL, NULL); | ||
785 | d->hoverLink = NULL; | ||
786 | updateVisible_DocumentWidget_(d); | ||
787 | refresh_Widget(w); | ||
788 | return iTrue; | ||
789 | } | ||
790 | else { | ||
791 | /* Show the existing content again if we have it. */ | ||
792 | iMediaRequest *req = findMediaRequest_DocumentWidget_(d, linkId); | ||
793 | if (req) { | ||
794 | setImage_GmDocument(d->doc, linkId, meta_GmRequest(req->req), | ||
795 | body_GmRequest(req->req)); | ||
796 | updateVisible_DocumentWidget_(d); | ||
797 | refresh_Widget(w); | ||
798 | return iTrue; | ||
799 | } | ||
800 | } | ||
801 | } | ||
781 | } | 802 | } |
782 | else { | 803 | else { |
783 | postCommandf_App("open url:%s", | 804 | postCommandf_App("open url:%s", |
@@ -840,8 +861,8 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
840 | } | 861 | } |
841 | 862 | ||
842 | static void drawRun_DrawContext_(void *context, const iGmRun *run) { | 863 | static void drawRun_DrawContext_(void *context, const iGmRun *run) { |
843 | iDrawContext *d = context; | 864 | iDrawContext *d = context; |
844 | const iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); | 865 | const iInt2 origin = addY_I2(d->bounds.pos, -d->widget->scrollY); |
845 | if (run->imageId) { | 866 | if (run->imageId) { |
846 | SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId); | 867 | SDL_Texture *tex = imageTexture_GmDocument(d->widget->doc, run->imageId); |
847 | if (tex) { | 868 | if (tex) { |
@@ -854,32 +875,50 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
854 | iString text; | 875 | iString text; |
855 | /* TODO: making a copy is unnecessary; the text routines should accept Rangecc */ | 876 | /* TODO: making a copy is unnecessary; the text routines should accept Rangecc */ |
856 | initRange_String(&text, run->text); | 877 | initRange_String(&text, run->text); |
857 | enum iColorId fg = run->color; | 878 | enum iColorId fg = run->color; |
858 | if (run == d->widget->hoverLink) { | 879 | const iGmDocument *doc = d->widget->doc; |
859 | const iGmDocument *doc = d->widget->doc; | 880 | if (run->linkId) { |
860 | const iGmLinkId linkId = d->widget->hoverLink->linkId; | 881 | /* TODO: Visualize an ongoing media request. */ |
861 | const iString * url = linkUrl_GmDocument(doc, linkId); | 882 | const int flags = linkFlags_GmDocument(doc, run->linkId); |
862 | const int flags = linkFlags_GmDocument(doc, linkId); | 883 | if (flags & content_GmLinkFlag) { |
863 | iUrl parts; | 884 | fg = linkColor_GmDocument(doc, run->linkId); |
864 | init_Url(&parts, url); | 885 | if (!isEmpty_Rect(run->bounds)) { |
865 | const iString *host = collect_String(newRange_String(parts.host)); | 886 | iGmImageInfo info; |
866 | fg = linkColor_GmDocument(doc, linkId); | 887 | imageInfo_GmDocument(doc, linkImage_GmDocument(doc, run->linkId), &info); |
867 | const iBool showHost = (!isEmpty_String(host) && flags & userFriendly_GmLinkFlag); | 888 | drawAlign_Text(default_FontId, |
868 | const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0; | 889 | add_I2(topRight_Rect(run->bounds), origin), |
869 | const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0; | 890 | fg, |
870 | if (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) || showHost) { | 891 | right_Alignment, |
892 | "%s \u2014 %d x %d \u2014 %.1fMB %s \u2715", | ||
893 | info.mime, info.size.x, info.size.y, info.numBytes / 1.0e6f, | ||
894 | run == d->widget->hoverLink ? white_ColorEscape : ""); | ||
895 | } | ||
896 | } | ||
897 | else if (run == d->widget->hoverLink) { | ||
898 | const iGmLinkId linkId = d->widget->hoverLink->linkId; | ||
899 | const iString * url = linkUrl_GmDocument(doc, linkId); | ||
900 | const int flags = linkFlags_GmDocument(doc, linkId); | ||
901 | iUrl parts; | ||
902 | init_Url(&parts, url); | ||
903 | const iString *host = collect_String(newRange_String(parts.host)); | ||
904 | fg = linkColor_GmDocument(doc, linkId); | ||
905 | const iBool showHost = (!isEmpty_String(host) && flags & userFriendly_GmLinkFlag); | ||
906 | const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0; | ||
907 | const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0; | ||
871 | iRect linkRect = moved_Rect(run->visBounds, origin); | 908 | iRect linkRect = moved_Rect(run->visBounds, origin); |
872 | drawAlign_Text(default_FontId, | 909 | if (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) || showHost) { |
873 | topRight_Rect(linkRect), | 910 | drawAlign_Text(default_FontId, |
874 | fg - 1, | 911 | topRight_Rect(linkRect), |
875 | left_Alignment, | 912 | fg - 1, |
876 | " \u2014%s%s%s\r%c%s", | 913 | left_Alignment, |
877 | showHost ? " " : "", | 914 | " \u2014%s%s%s\r%c%s", |
878 | showHost ? cstr_String(host) : "", | 915 | showHost ? " " : "", |
879 | showHost && (showImage || showAudio) ? " \u2014" : "", | 916 | showHost ? cstr_String(host) : "", |
880 | showImage || showAudio ? '0' + fg : ('0' + fg - 1), | 917 | showHost && (showImage || showAudio) ? " \u2014" : "", |
881 | showImage ? " View Image \U0001f5bc" | 918 | showImage || showAudio ? '0' + fg : ('0' + fg - 1), |
882 | : showAudio ? " Play Audio \U0001f3b5" : ""); | 919 | showImage ? " View Image \U0001f5bc" |
920 | : showAudio ? " Play Audio \U0001f3b5" : ""); | ||
921 | } | ||
883 | } | 922 | } |
884 | } | 923 | } |
885 | const iInt2 visPos = add_I2(run->visBounds.pos, origin); | 924 | const iInt2 visPos = add_I2(run->visBounds.pos, origin); |
diff --git a/src/ui/window.c b/src/ui/window.c index a7291320..feb917ff 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -204,9 +204,9 @@ static void setupUserInterface_Window(iWindow *d) { | |||
204 | iInputWidget *input = new_InputWidget(0); | 204 | iInputWidget *input = new_InputWidget(0); |
205 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), | 205 | setId_Widget(addChildFlags_Widget(searchBar, iClob(input), expand_WidgetFlag), |
206 | "find.input"); | 206 | "find.input"); |
207 | addChild_Widget(searchBar, iClob(new_LabelWidget(" \U0001f86b ", 'g', KMOD_PRIMARY, "find.next"))); | 207 | addChild_Widget(searchBar, iClob(new_LabelWidget(" \U0001f86b ", 'g', KMOD_PRIMARY, "find.next"))); |
208 | addChild_Widget(searchBar, iClob(new_LabelWidget(" \U0001f869 ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); | 208 | addChild_Widget(searchBar, iClob(new_LabelWidget(" \U0001f869 ", 'g', KMOD_PRIMARY | KMOD_SHIFT, "find.prev"))); |
209 | addChild_Widget(searchBar, iClob(new_LabelWidget("\u00d7", SDLK_ESCAPE, 0, "find.close"))); | 209 | addChild_Widget(searchBar, iClob(new_LabelWidget("\u2715", SDLK_ESCAPE, 0, "find.close"))); |
210 | } | 210 | } |
211 | 211 | ||
212 | #if 0 | 212 | #if 0 |