summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gmdocument.c12
-rw-r--r--src/gmdocument.h22
-rw-r--r--src/ui/documentwidget.c78
3 files changed, 78 insertions, 34 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index 15d81603..f7016ba4 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -245,7 +245,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
245 header2_FontId, 245 header2_FontId,
246 header3_FontId, 246 header3_FontId,
247 regular_FontId, 247 regular_FontId,
248 }; 248 };
249 static const int colors[max_GmLineType] = { 249 static const int colors[max_GmLineType] = {
250 gray75_ColorId, 250 gray75_ColorId,
251 gray75_ColorId, 251 gray75_ColorId,
@@ -255,7 +255,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
255 white_ColorId, 255 white_ColorId,
256 white_ColorId, 256 white_ColorId,
257 white_ColorId, 257 white_ColorId,
258 }; 258 };
259 static const int indents[max_GmLineType] = { 259 static const int indents[max_GmLineType] = {
260 5, 10, 5, 10, 0, 0, 0, 5 260 5, 10, 5, 10, 0, 0, 0, 5
261 }; 261 };
@@ -290,6 +290,7 @@ static void doLayout_GmDocument_(iGmDocument *d) {
290 } 290 }
291 while (nextSplit_Rangecc(&content, "\n", &line)) { 291 while (nextSplit_Rangecc(&content, "\n", &line)) {
292 iGmRun run; 292 iGmRun run;
293 run.flags = 0;
293 run.color = white_ColorId; 294 run.color = white_ColorId;
294 run.linkId = 0; 295 run.linkId = 0;
295 run.imageId = 0; 296 run.imageId = 0;
@@ -402,7 +403,9 @@ static void doLayout_GmDocument_(iGmDocument *d) {
402 isFirstText = iFalse; 403 isFirstText = iFalse;
403 } 404 }
404 iRangecc runLine = line; 405 iRangecc runLine = line;
405 /* Create one or more runs for this line. */ 406 /* Create one or more text runs for this line. */
407 run.flags |= startOfLine_GmRunFlag;
408 iAssert(!isEmpty_Range(&runLine)); /* must have something at this point */
406 while (!isEmpty_Range(&runLine)) { 409 while (!isEmpty_Range(&runLine)) {
407 /* Little bit of breathing space between wrapped lines. */ 410 /* Little bit of breathing space between wrapped lines. */
408 if ((type == text_GmLineType || type == quote_GmLineType || 411 if ((type == text_GmLineType || type == quote_GmLineType ||
@@ -427,10 +430,13 @@ static void doLayout_GmDocument_(iGmDocument *d) {
427 contPos = runLine.end; 430 contPos = runLine.end;
428 } 431 }
429 pushBack_Array(&d->layout, &run); 432 pushBack_Array(&d->layout, &run);
433 run.flags &= ~startOfLine_GmRunFlag;
430 runLine.start = contPos; 434 runLine.start = contPos;
431 trimStart_Rangecc(&runLine); 435 trimStart_Rangecc(&runLine);
432 pos.y += lineHeight_Text(run.font); 436 pos.y += lineHeight_Text(run.font);
433 } 437 }
438 /* Flag the end of line, too. */
439 ((iGmRun *) back_Array(&d->layout))->flags |= endOfLine_GmRunFlag;
434 /* Image content. */ 440 /* Image content. */
435 if (type == link_GmLineType) { 441 if (type == link_GmLineType) {
436 const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); 442 const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId);
diff --git a/src/gmdocument.h b/src/gmdocument.h
index 584efb5a..c353c733 100644
--- a/src/gmdocument.h
+++ b/src/gmdocument.h
@@ -12,14 +12,14 @@ iDeclareType(GmRun)
12typedef uint16_t iGmLinkId; 12typedef uint16_t iGmLinkId;
13 13
14enum iGmLinkFlags { 14enum iGmLinkFlags {
15 userFriendly_GmLinkFlag = 0x1, 15 userFriendly_GmLinkFlag = iBit(1),
16 remote_GmLinkFlag = 0x2, 16 remote_GmLinkFlag = iBit(2),
17 http_GmLinkFlag = 0x4, 17 http_GmLinkFlag = iBit(3),
18 gopher_GmLinkFlag = 0x8, 18 gopher_GmLinkFlag = iBit(4),
19 file_GmLinkFlag = 0x10, 19 file_GmLinkFlag = iBit(5),
20 imageFileExtension_GmLinkFlag = 0x20, 20 imageFileExtension_GmLinkFlag = iBit(6),
21 audioFileExtension_GmLinkFlag = 0x40, 21 audioFileExtension_GmLinkFlag = iBit(7),
22 content_GmLinkFlag = 0x80, /* content visible below */ 22 content_GmLinkFlag = iBit(8), /* content visible below */
23}; 23};
24 24
25iDeclareType(GmImageInfo) 25iDeclareType(GmImageInfo)
@@ -30,10 +30,16 @@ struct Impl_GmImageInfo {
30 const char *mime; 30 const char *mime;
31}; 31};
32 32
33enum iGmRunFlags {
34 startOfLine_GmRunFlag = iBit(1),
35 endOfLine_GmRunFlag = iBit(2),
36};
37
33struct Impl_GmRun { 38struct Impl_GmRun {
34 iRangecc text; 39 iRangecc text;
35 uint8_t font; 40 uint8_t font;
36 uint8_t color; 41 uint8_t color;
42 uint8_t flags;
37 iRect bounds; /* used for hit testing, may extend to edges */ 43 iRect bounds; /* used for hit testing, may extend to edges */
38 iRect visBounds; /* actual visual bounds */ 44 iRect visBounds; /* actual visual bounds */
39 iGmLinkId linkId; /* zero for non-links */ 45 iGmLinkId linkId; /* zero for non-links */
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 98d9eca5..e908f090 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -843,7 +843,8 @@ iDeclareType(DrawContext)
843 843
844struct Impl_DrawContext { 844struct Impl_DrawContext {
845 const iDocumentWidget *widget; 845 const iDocumentWidget *widget;
846 iRect bounds; 846 iRect widgetBounds;
847 iRect bounds; /* document area */
847 iPaint paint; 848 iPaint paint;
848 iBool inSelectMark; 849 iBool inSelectMark;
849 iBool inFoundMark; 850 iBool inFoundMark;
@@ -895,8 +896,24 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
895 initRange_String(&text, run->text); 896 initRange_String(&text, run->text);
896 enum iColorId fg = run->color; 897 enum iColorId fg = run->color;
897 const iGmDocument *doc = d->widget->doc; 898 const iGmDocument *doc = d->widget->doc;
899 const iBool isHover =
900 run->linkId != 0 && d->widget->hoverLink && run->linkId == d->widget->hoverLink->linkId &&
901 !isEmpty_Rect(run->bounds);
902 const iInt2 visPos = add_I2(run->visBounds.pos, origin);
903 /* Text markers. */
904 fillRange_DrawContext_(d, run, teal_ColorId, d->widget->foundMark, &d->inFoundMark);
905 fillRange_DrawContext_(d, run, brown_ColorId, d->widget->selectMark, &d->inSelectMark);
906 if (run->linkId) {
907 fg = linkColor_GmDocument(doc, run->linkId);
908 if (isHover && ~linkFlags_GmDocument(doc, run->linkId) & content_GmLinkFlag) {
909 fg = white_ColorId;
910 }
911 }
912 drawString_Text(run->font, visPos, fg, &text);
913 deinit_String(&text);
914 /* Presentation of links. */
898 if (run->linkId) { 915 if (run->linkId) {
899 /* TODO: Visualize an ongoing media request. */ 916 /* TODO: Show status of an ongoing media request. */
900 const int flags = linkFlags_GmDocument(doc, run->linkId); 917 const int flags = linkFlags_GmDocument(doc, run->linkId);
901 if (flags & content_GmLinkFlag) { 918 if (flags & content_GmLinkFlag) {
902 fg = linkColor_GmDocument(doc, run->linkId); 919 fg = linkColor_GmDocument(doc, run->linkId);
@@ -909,7 +926,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
909 info.mime, info.size.x, info.size.y, info.numBytes / 1.0e6f); 926 info.mime, info.size.x, info.size.y, info.numBytes / 1.0e6f);
910 if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { 927 if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) {
911 appendFormat_String( 928 appendFormat_String(
912 &text, " %s\u2715", run == d->widget->hoverLink ? white_ColorEscape : ""); 929 &text, " %s\u2715", isHover ? white_ColorEscape : "");
913 } 930 }
914 drawAlign_Text(default_FontId, 931 drawAlign_Text(default_FontId,
915 add_I2(topRight_Rect(run->bounds), origin), 932 add_I2(topRight_Rect(run->bounds), origin),
@@ -919,10 +936,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
919 deinit_String(&text); 936 deinit_String(&text);
920 } 937 }
921 } 938 }
922 else if (run == d->widget->hoverLink) { 939 else if (isHover) {
923 const iGmLinkId linkId = d->widget->hoverLink->linkId; 940 const iGmLinkId linkId = d->widget->hoverLink->linkId;
924 const iString * url = linkUrl_GmDocument(doc, linkId); 941 const iString * url = linkUrl_GmDocument(doc, linkId);
925 const int flags = linkFlags_GmDocument(doc, linkId); 942 const int flags = linkFlags_GmDocument(doc, linkId);
926 iUrl parts; 943 iUrl parts;
927 init_Url(&parts, url); 944 init_Url(&parts, url);
928 const iString *host = collect_String(newRange_String(parts.host)); 945 const iString *host = collect_String(newRange_String(parts.host));
@@ -931,27 +948,37 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) {
931 const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0; 948 const iBool showImage = (flags & imageFileExtension_GmLinkFlag) != 0;
932 const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0; 949 const iBool showAudio = (flags & audioFileExtension_GmLinkFlag) != 0;
933 iRect linkRect = moved_Rect(run->visBounds, origin); 950 iRect linkRect = moved_Rect(run->visBounds, origin);
934 if (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) || showHost) { 951 if (run->flags & endOfLine_GmRunFlag &&
952 (flags & (imageFileExtension_GmLinkFlag | audioFileExtension_GmLinkFlag) ||
953 showHost)) {
954 iString str;
955 init_String(&str);
956 format_String(&str, " \u2014%s%s%s\r%c%s",
957 showHost ? " " : "",
958 showHost ? cstr_String(host) : "",
959 showHost && (showImage || showAudio) ? " \u2014" : "",
960 showImage || showAudio ? '0' + fg : ('0' + fg - 1),
961 showImage ? " View Image \U0001f5bc"
962 : showAudio ? " Play Audio \U0001f3b5" : "");
963 const iInt2 textSize = measure_Text(default_FontId, cstr_String(&str));
964 int tx = topRight_Rect(linkRect).x;
965 const char *msg = cstr_String(&str);
966 if (tx + textSize.x > right_Rect(d->widgetBounds)) {
967 tx = right_Rect(d->widgetBounds) - textSize.x;
968 fillRect_Paint(&d->paint, (iRect){ init_I2(tx, top_Rect(linkRect)), textSize },
969 black_ColorId);
970 msg += 4; /* skip the space and dash */
971 }
935 drawAlign_Text(default_FontId, 972 drawAlign_Text(default_FontId,
936 topRight_Rect(linkRect), 973 init_I2(tx, top_Rect(linkRect)),
937 fg - 1, 974 fg - 1,
938 left_Alignment, 975 left_Alignment,
939 " \u2014%s%s%s\r%c%s", 976 "%s",
940 showHost ? " " : "", 977 msg);
941 showHost ? cstr_String(host) : "", 978 deinit_String(&str);
942 showHost && (showImage || showAudio) ? " \u2014" : "",
943 showImage || showAudio ? '0' + fg : ('0' + fg - 1),
944 showImage ? " View Image \U0001f5bc"
945 : showAudio ? " Play Audio \U0001f3b5" : "");
946 } 979 }
947 } 980 }
948 } 981 }
949 const iInt2 visPos = add_I2(run->visBounds.pos, origin);
950 /* Text markers. */
951 fillRange_DrawContext_(d, run, teal_ColorId, d->widget->foundMark, &d->inFoundMark);
952 fillRange_DrawContext_(d, run, brown_ColorId, d->widget->selectMark, &d->inSelectMark);
953 drawString_Text(run->font, visPos, fg, &text);
954 deinit_String(&text);
955 982
956// drawRect_Paint(&d->paint, (iRect){ visPos, run->bounds.size }, green_ColorId); 983// drawRect_Paint(&d->paint, (iRect){ visPos, run->bounds.size }, green_ColorId);
957// drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId); 984// drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, red_ColorId);
@@ -961,7 +988,12 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
961 const iWidget *w = constAs_Widget(d); 988 const iWidget *w = constAs_Widget(d);
962 const iRect bounds = bounds_Widget(w); 989 const iRect bounds = bounds_Widget(w);
963 draw_Widget(w); 990 draw_Widget(w);
964 iDrawContext ctx = { .widget = d, .bounds = documentBounds_DocumentWidget_(d) }; 991 iDrawContext ctx = {
992 .widget = d,
993 .widgetBounds = /* omit scrollbar width */
994 adjusted_Rect(bounds, zero_I2(), init_I2(-constAs_Widget(d->scroll)->rect.size.x, 0)),
995 .bounds = documentBounds_DocumentWidget_(d)
996 };
965 init_Paint(&ctx.paint); 997 init_Paint(&ctx.paint);
966 fillRect_Paint(&ctx.paint, bounds, gray15_ColorId); 998 fillRect_Paint(&ctx.paint, bounds, gray15_ColorId);
967 setClip_Paint(&ctx.paint, bounds); 999 setClip_Paint(&ctx.paint, bounds);