summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gmdocument.c8
-rw-r--r--src/ui/banner.c120
-rw-r--r--src/ui/banner.h1
-rw-r--r--src/ui/color.h5
-rw-r--r--src/ui/documentwidget.c86
5 files changed, 152 insertions, 68 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c
index eac0ac62..bd3fa788 100644
--- a/src/gmdocument.c
+++ b/src/gmdocument.c
@@ -1123,6 +1123,14 @@ static void setDerivedThemeColors_(enum iGmDocumentTheme theme) {
1123 mix_Color(get_Color(tmBannerTitle_ColorId), 1123 mix_Color(get_Color(tmBannerTitle_ColorId),
1124 get_Color(tmBackground_ColorId), 1124 get_Color(tmBackground_ColorId),
1125 theme == colorfulDark_GmDocumentTheme ? 0.55f : 0)); 1125 theme == colorfulDark_GmDocumentTheme ? 0.55f : 0));
1126 const int bannerItemFg = isDark_GmDocumentTheme(currentTheme_()) ? white_ColorId : black_ColorId;
1127 set_Color(tmBannerItemBackground_ColorId, mix_Color(get_Color(tmBannerBackground_ColorId),
1128 get_Color(tmBannerTitle_ColorId), 0.1f));
1129 set_Color(tmBannerItemFrame_ColorId, mix_Color(get_Color(tmBannerBackground_ColorId),
1130 get_Color(tmBannerTitle_ColorId), 0.4f));
1131 set_Color(tmBannerItemText_ColorId, mix_Color(get_Color(tmBannerBackground_ColorId),
1132 get_Color(bannerItemFg), 0.75f));
1133 set_Color(tmBannerItemTitle_ColorId, get_Color(bannerItemFg));
1126 set_Color(tmBackgroundAltText_ColorId, 1134 set_Color(tmBackgroundAltText_ColorId,
1127 mix_Color(get_Color(tmQuoteIcon_ColorId), get_Color(tmBackground_ColorId), 0.85f)); 1135 mix_Color(get_Color(tmQuoteIcon_ColorId), get_Color(tmBackground_ColorId), 0.85f));
1128 set_Color(tmBackgroundOpenLink_ColorId, 1136 set_Color(tmBackgroundOpenLink_ColorId,
diff --git a/src/ui/banner.c b/src/ui/banner.c
index d1ed470c..d95c853b 100644
--- a/src/ui/banner.c
+++ b/src/ui/banner.c
@@ -24,6 +24,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
24 24
25#include "command.h" 25#include "command.h"
26#include "documentwidget.h" 26#include "documentwidget.h"
27#include "lang.h"
27#include "paint.h" 28#include "paint.h"
28#include "util.h" 29#include "util.h"
29 30
@@ -32,17 +33,17 @@ iDeclareType(BannerItem)
32struct Impl_BannerItem { 33struct Impl_BannerItem {
33 enum iBannerType type; 34 enum iBannerType type;
34 enum iGmStatusCode code; 35 enum iGmStatusCode code;
35 iString message; 36 iString text; /* Entire message in presentation form. */
36 int height; 37 int height;
37}; 38};
38 39
39static void init_BannerItem(iBannerItem *d) { 40static void init_BannerItem(iBannerItem *d) {
40 init_String(&d->message); 41 init_String(&d->text);
41 d->height = 0; 42 d->height = 0;
42} 43}
43 44
44static void deinit_BannerItem(iBannerItem *d) { 45static void deinit_BannerItem(iBannerItem *d) {
45 deinit_String(&d->message); 46 deinit_String(&d->text);
46} 47}
47 48
48/*----------------------------------------------------------------------------------------------*/ 49/*----------------------------------------------------------------------------------------------*/
@@ -60,9 +61,20 @@ iDefineTypeConstruction(Banner)
60 61
61static void updateHeight_Banner_(iBanner *d) { 62static void updateHeight_Banner_(iBanner *d) {
62 d->rect.size.y = 0; 63 d->rect.size.y = 0;
63 if (!isEmpty_String(&d->site)) { //} || !isEmpty_String(&d->icon)) { 64 if (!isEmpty_String(&d->site)) {
64 d->rect.size.y += lineHeight_Text(banner_FontId) * 2; 65 d->rect.size.y += lineHeight_Text(banner_FontId) * 2;
65 } 66 }
67 const size_t numItems = size_Array(&d->items);
68 if (numItems) {
69 const int outerPad = 2 * gap_UI;
70 const int innerPad = gap_UI;
71 iConstForEach(Array, i, &d->items) {
72 const iBannerItem *item = i.value;
73 d->rect.size.y += item->height;
74 }
75 d->rect.size.y += (numItems - 1) * innerPad;
76 d->rect.size.y += outerPad;
77 }
66} 78}
67 79
68void init_Banner(iBanner *d) { 80void init_Banner(iBanner *d) {
@@ -85,8 +97,18 @@ void setOwner_Banner(iBanner *d, iDocumentWidget *owner) {
85 d->doc = owner; 97 d->doc = owner;
86} 98}
87 99
100static void updateItemHeight_Banner_(const iBanner *d, iBannerItem *item) {
101 item->height = measureWrapRange_Text(uiContent_FontId,
102 width_Rect(d->rect) - 6 * gap_UI,
103 range_String(&item->text))
104 .bounds.size.y + 4 * gap_UI;
105}
106
88void setWidth_Banner(iBanner *d, int width) { 107void setWidth_Banner(iBanner *d, int width) {
89 d->rect.size.x = width; 108 d->rect.size.x = width;
109 iForEach(Array, i, &d->items) {
110 updateItemHeight_Banner_(d, i.value);
111 }
90 updateHeight_Banner_(d); 112 updateHeight_Banner_(d);
91} 113}
92 114
@@ -98,6 +120,10 @@ int height_Banner(const iBanner *d) {
98 return d->rect.size.y; 120 return d->rect.size.y;
99} 121}
100 122
123size_t numItems_Banner(const iBanner *d) {
124 return size_Array(&d->items);
125}
126
101iBool contains_Banner(const iBanner *d, iInt2 coord) { 127iBool contains_Banner(const iBanner *d, iInt2 coord) {
102 return contains_Rect(d->rect, coord); 128 return contains_Rect(d->rect, coord);
103} 129}
@@ -127,7 +153,19 @@ void add_Banner(iBanner *d, enum iBannerType type, enum iGmStatusCode code, cons
127 init_BannerItem(&item); 153 init_BannerItem(&item);
128 item.type = type; 154 item.type = type;
129 item.code = code; 155 item.code = code;
130 set_String(&item.message, message); 156 const iGmError *error = get_GmError(code);
157 if (error->icon) {
158 appendCStr_String(&item.text, escape_Color(tmBannerIcon_ColorId));
159 appendChar_String(&item.text, error->icon);
160 appendCStr_String(&item.text, restore_ColorEscape);
161 }
162 appendFormat_String(&item.text, " \x1b[1m%s%s\x1b[0m \u2014 %s%s",
163 escape_Color(tmBannerItemTitle_ColorId),
164 !isEmpty_String(message) ? cstr_String(message) : error->title,
165 escape_Color(tmBannerItemText_ColorId),
166 error->info);
167 translate_Lang(&item.text);
168 updateItemHeight_Banner_(d, &item);
131 pushBack_Array(&d->items, &item); 169 pushBack_Array(&d->items, &item);
132 updateHeight_Banner_(d); 170 updateHeight_Banner_(d);
133} 171}
@@ -143,6 +181,53 @@ void remove_Banner(iBanner *d, enum iGmStatusCode code) {
143 updateHeight_Banner_(d); 181 updateHeight_Banner_(d);
144} 182}
145 183
184void draw_Banner(const iBanner *d) {
185 if (isEmpty_Banner(d)) {
186 return;
187 }
188 iRect bounds = d->rect;
189 iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2);
190 iPaint p;
191 init_Paint(&p);
192// drawRect_Paint(&p, bounds, red_ColorId);
193 /* Draw the icon. */
194 if (!isEmpty_String(&d->icon)) {
195 const int font = banner_FontId;
196 const iRect iconRect = visualBounds_Text(font, range_String(&d->icon));
197 drawRange_Text(font,
198 addY_I2(pos, -mid_Rect(iconRect).y + lineHeight_Text(font) / 2),
199 tmBannerIcon_ColorId,
200 range_String(&d->icon));
201 pos.x += right_Rect(iconRect) + 3 * gap_Text;
202 }
203 /* Draw the site name. */
204 if (!isEmpty_String(&d->site)) {
205 drawRange_Text(banner_FontId, pos, tmBannerTitle_ColorId, range_String(&d->site));
206 pos.y += lineHeight_Text(banner_FontId) * 3 / 2;
207 }
208 else {
209 pos.y = top_Rect(bounds);
210 }
211 const int innerPad = gap_UI;
212 pos.x = left_Rect(bounds);
213 iConstForEach(Array, i, &d->items) {
214 const iBannerItem *item = i.value;
215 const iRect itemRect = { pos, init_I2(d->rect.size.x, item->height) };
216 fillRect_Paint(&p, itemRect, tmBannerItemBackground_ColorId);
217 drawRect_Paint(&p, itemRect, tmBannerItemFrame_ColorId);
218 setBaseAttributes_Text(uiContent_FontId, tmBannerItemText_ColorId);
219 iWrapText wt = {
220 .text = range_String(&item->text),
221 .maxWidth = width_Rect(itemRect) - 6 * gap_UI,
222 .mode = word_WrapTextMode
223 };
224 draw_WrapText(&wt, uiContent_FontId, add_I2(pos, init_I2(3 * gap_UI, 2 * gap_UI)),
225 tmBannerItemText_ColorId);
226 pos.y += innerPad;
227 }
228 setBaseAttributes_Text(-1, -1);
229}
230
146iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { 231iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) {
147 iWidget *w = as_Widget(d->doc); 232 iWidget *w = as_Widget(d->doc);
148 switch (ev->type) { 233 switch (ev->type) {
@@ -269,28 +354,3 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2
269 deinit_String(&str); 354 deinit_String(&str);
270} 355}
271#endif 356#endif
272
273void draw_Banner(const iBanner *d) {
274 if (isEmpty_Banner(d)) {
275 return;
276 }
277 iRect bounds = d->rect;
278 iInt2 pos = addY_I2(topLeft_Rect(bounds), lineHeight_Text(banner_FontId) / 2);
279 iPaint p;
280 init_Paint(&p);
281// drawRect_Paint(&p, bounds, red_ColorId);
282 /* Draw the icon. */
283 if (!isEmpty_String(&d->icon)) {
284 const int font = banner_FontId;
285 const iRect iconRect = visualBounds_Text(font, range_String(&d->icon));
286 drawRange_Text(font,
287 addY_I2(pos, -mid_Rect(iconRect).y + lineHeight_Text(font) / 2),
288 tmBannerIcon_ColorId,
289 range_String(&d->icon));
290 pos.x += right_Rect(iconRect) + 3 * gap_Text;
291 }
292 /* Draw the site name. */
293 if (!isEmpty_String(&d->site)) {
294 drawRange_Text(banner_FontId, pos, tmBannerTitle_ColorId, range_String(&d->site));
295 }
296}
diff --git a/src/ui/banner.h b/src/ui/banner.h
index 2ee3a2bc..d652c85f 100644
--- a/src/ui/banner.h
+++ b/src/ui/banner.h
@@ -42,6 +42,7 @@ void setWidth_Banner (iBanner *, int width);
42void setPos_Banner (iBanner *, iInt2 pos); 42void setPos_Banner (iBanner *, iInt2 pos);
43 43
44int height_Banner (const iBanner *); 44int height_Banner (const iBanner *);
45size_t numItems_Banner (const iBanner *);
45iBool contains_Banner (const iBanner *, iInt2 coord); 46iBool contains_Banner (const iBanner *, iInt2 coord);
46 47
47iLocalDef iBool isEmpty_Banner(const iBanner *d) { 48iLocalDef iBool isEmpty_Banner(const iBanner *d) {
diff --git a/src/ui/color.h b/src/ui/color.h
index c9dff598..5e96c300 100644
--- a/src/ui/color.h
+++ b/src/ui/color.h
@@ -159,6 +159,11 @@ enum iColorId {
159 tmGopherLinkTextHover_ColorId, 159 tmGopherLinkTextHover_ColorId,
160 tmGopherLinkDomain_ColorId, 160 tmGopherLinkDomain_ColorId,
161 tmGopherLinkLastVisitDate_ColorId, 161 tmGopherLinkLastVisitDate_ColorId,
162
163 tmBannerItemBackground_ColorId,
164 tmBannerItemFrame_ColorId,
165 tmBannerItemTitle_ColorId,
166 tmBannerItemText_ColorId,
162 167
163 max_ColorId, /* note: GmRun packs color into limited number of bits */ 168 max_ColorId, /* note: GmRun packs color into limited number of bits */
164 tmMax_ColorId = max_ColorId - tmFirst_ColorId 169 tmMax_ColorId = max_ColorId - tmFirst_ColorId
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 75da67a1..13a8dae7 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -538,9 +538,14 @@ static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) {
538 if (d->flags & centerVertically_DocumentWidgetFlag) { 538 if (d->flags & centerVertically_DocumentWidgetFlag) {
539 const iInt2 docSize = addY_I2(size_GmDocument(d->doc), 539 const iInt2 docSize = addY_I2(size_GmDocument(d->doc),
540 iMax(height_Widget(d->footerButtons), height_Widget(d->phoneToolbar))); 540 iMax(height_Widget(d->footerButtons), height_Widget(d->phoneToolbar)));
541 if (docSize.y < rect.size.y) { 541 if (size_GmDocument(d->doc).y == 0) {
542 /* Center vertically if short. There is one empty paragraph line's worth of margin 542 rect.pos.y = top_Rect(bounds) + height_Rect(bounds) / 2 -
543 between the banner and the page contents. */ 543 documentTopPad_DocumentWidget_(d) - height_Banner(d->banner) / 2;
544 rect.size.y = 0;
545 wasCentered = iTrue;
546 }
547 else if (docSize.y < rect.size.y) {
548 /* Center vertically if page is short. */
544 int offset = iMax(0, height_Rect(bounds) / 2 549 int offset = iMax(0, height_Rect(bounds) / 2
545 - documentTopPad_DocumentWidget_(d) 550 - documentTopPad_DocumentWidget_(d)
546 - height_Banner(d->banner) 551 - height_Banner(d->banner)
@@ -1126,7 +1131,7 @@ static void replaceDocument_DocumentWidget_(iDocumentWidget *d, iGmDocument *new
1126} 1131}
1127 1132
1128static void updateBanner_DocumentWidget_(iDocumentWidget *d) { 1133static void updateBanner_DocumentWidget_(iDocumentWidget *d) {
1129 clear_Banner(d->banner); 1134 /* TODO: Set width. */
1130 setSite_Banner(d->banner, siteText_DocumentWidget_(d), siteIcon_GmDocument(d->doc)); 1135 setSite_Banner(d->banner, siteText_DocumentWidget_(d), siteIcon_GmDocument(d->doc));
1131} 1136}
1132 1137
@@ -1197,21 +1202,22 @@ static void makeFooterButtons_DocumentWidget_(iDocumentWidget *d, const iMenuIte
1197static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, 1202static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code,
1198 const iString *meta) { 1203 const iString *meta) {
1199 /* TODO: No such thing as an "error page". It should be an empty page with an error banner. */ 1204 /* TODO: No such thing as an "error page". It should be an empty page with an error banner. */
1200#if 0 1205 iString *src = collectNew_String();
1201 iString *src = collectNewCStr_String("# ");
1202 const iGmError *msg = get_GmError(code); 1206 const iGmError *msg = get_GmError(code);
1203 appendChar_String(src, msg->icon ? msg->icon : 0x2327); /* X in a box */ 1207 // appendChar_String(src, msg->icon ? msg->icon : 0x2327); /* X in a box */
1204 appendFormat_String(src, " %s\n%s", msg->title, msg->info); 1208 //appendFormat_String(src, " %s\n%s", msg->title, msg->info);
1205 iBool useBanner = iTrue; 1209// iBool useBanner = iTrue;
1210 destroy_Widget(d->footerButtons);
1211 d->footerButtons = NULL;
1206 if (meta) { 1212 if (meta) {
1207 switch (code) { 1213 switch (code) {
1208 case schemeChangeRedirect_GmStatusCode: 1214 case schemeChangeRedirect_GmStatusCode:
1209 case tooManyRedirects_GmStatusCode: 1215 case tooManyRedirects_GmStatusCode:
1210 appendFormat_String(src, "\n=> %s\n", cstr_String(meta)); 1216 appendFormat_String(src, "=> %s\n", cstr_String(meta));
1211 break; 1217 break;
1212 case tlsFailure_GmStatusCode: 1218 case tlsFailure_GmStatusCode:
1213 useBanner = iFalse; /* valid data wasn't received from host */ 1219// useBanner = iFalse; /* valid data wasn't received from host */
1214 appendFormat_String(src, "\n\n>%s\n", cstr_String(meta)); 1220// appendFormat_String(src, ">%s\n", cstr_String(meta));
1215 break; 1221 break;
1216 case tlsServerCertificateExpired_GmStatusCode: 1222 case tlsServerCertificateExpired_GmStatusCode:
1217 makeFooterButtons_DocumentWidget_( 1223 makeFooterButtons_DocumentWidget_(
@@ -1236,12 +1242,12 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
1236 break; 1242 break;
1237 case failedToOpenFile_GmStatusCode: 1243 case failedToOpenFile_GmStatusCode:
1238 case certificateNotValid_GmStatusCode: 1244 case certificateNotValid_GmStatusCode:
1239 appendFormat_String(src, "\n\n%s", cstr_String(meta)); 1245// appendFormat_String(src, "%s", cstr_String(meta));
1240 break; 1246 break;
1241 case unsupportedMimeType_GmStatusCode: { 1247 case unsupportedMimeType_GmStatusCode: {
1242 iString *key = collectNew_String(); 1248 iString *key = collectNew_String();
1243 toString_Sym(SDLK_s, KMOD_PRIMARY, key); 1249 toString_Sym(SDLK_s, KMOD_PRIMARY, key);
1244 appendFormat_String(src, "\n```\n%s\n```\n", cstr_String(meta)); 1250// appendFormat_String(src, "\n```\n%s\n```\n", cstr_String(meta));
1245 const char *mtype = mediaTypeFromFileExtension_String(d->mod.url); 1251 const char *mtype = mediaTypeFromFileExtension_String(d->mod.url);
1246 iArray items; 1252 iArray items;
1247 init_Array(&items, sizeof(iMenuItem)); 1253 init_Array(&items, sizeof(iMenuItem));
@@ -1264,9 +1270,9 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
1264 break; 1270 break;
1265 } 1271 }
1266 default: 1272 default:
1267 if (!isEmpty_String(meta)) { 1273// if (!isEmpty_String(meta)) {
1268 appendFormat_String(src, "\n\n${error.server.msg}\n> %s", cstr_String(meta)); 1274// appendFormat_String(src, "\n\n${error.server.msg}\n> %s", cstr_String(meta));
1269 } 1275// }
1270 break; 1276 break;
1271 } 1277 }
1272 } 1278 }
@@ -1277,19 +1283,17 @@ static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode
1277 { person_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" } }, 1283 { person_Icon " ${menu.identity.new}", newIdentity_KeyShortcut, "ident.new" } },
1278 2); 1284 2);
1279 } 1285 }
1280 /* Make a new document for the error page.*/ { 1286 /* Make a new document for the error page.*/
1281 iGmDocument *errorDoc = new_GmDocument(); 1287 iGmDocument *errorDoc = new_GmDocument();
1282 setUrl_GmDocument(errorDoc, d->mod.url); 1288 setUrl_GmDocument(errorDoc, d->mod.url);
1283// setBanner_GmDocument(errorDoc, useBanner ? bannerType_DocumentWidget_(d) : none_GmDocumentBanner); 1289 setFormat_GmDocument(errorDoc, gemini_SourceFormat);
1284 1290 replaceDocument_DocumentWidget_(d, errorDoc);
1285 setFormat_GmDocument(errorDoc, gemini_SourceFormat); 1291 iRelease(errorDoc);
1286 replaceDocument_DocumentWidget_(d, errorDoc); 1292 clear_Banner(d->banner);
1287 iRelease(errorDoc); 1293 add_Banner(d->banner, error_BannerType, code, meta);
1288 } 1294// translate_Lang(src);
1289 translate_Lang(src);
1290#endif
1291 d->state = ready_RequestState; 1295 d->state = ready_RequestState;
1292// setSource_DocumentWidget(d, src); 1296 setSource_DocumentWidget(d, src);
1293 updateTheme_DocumentWidget_(d); 1297 updateTheme_DocumentWidget_(d);
1294 reset_SmoothScroll(&d->scrollY); 1298 reset_SmoothScroll(&d->scrollY);
1295 init_Anim(&d->sideOpacity, 0); 1299 init_Anim(&d->sideOpacity, 0);
@@ -1818,6 +1822,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n
1818 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue); 1822 updateDocument_DocumentWidget_(d, resp, cachedDoc, iTrue);
1819// setCachedDocument_History(d->mod.history, d->doc, 1823// setCachedDocument_History(d->mod.history, d->doc,
1820// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0); 1824// (d->flags & openedFromSidebar_DocumentWidgetFlag) != 0);
1825 clear_Banner(d->banner);
1821 updateBanner_DocumentWidget_(d); 1826 updateBanner_DocumentWidget_(d);
1822 } 1827 }
1823 d->state = ready_RequestState; 1828 d->state = ready_RequestState;
@@ -2043,6 +2048,7 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) {
2043 iGmResponse *resp = lockResponse_GmRequest(d->request); 2048 iGmResponse *resp = lockResponse_GmRequest(d->request);
2044 if (d->state == fetching_RequestState) { 2049 if (d->state == fetching_RequestState) {
2045 d->state = receivedPartialResponse_RequestState; 2050 d->state = receivedPartialResponse_RequestState;
2051 clear_Banner(d->banner);
2046 updateTrust_DocumentWidget_(d, resp); 2052 updateTrust_DocumentWidget_(d, resp);
2047 if (~d->certFlags & trusted_GmCertFlag && 2053 if (~d->certFlags & trusted_GmCertFlag &&
2048 isSuccess_GmStatusCode(statusCode) && 2054 isSuccess_GmStatusCode(statusCode) &&
@@ -4941,9 +4947,12 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4941 int yTop = docBounds.pos.y + viewPos_DocumentWidget_(d); 4947 int yTop = docBounds.pos.y + viewPos_DocumentWidget_(d);
4942 const iBool isDocEmpty = size_GmDocument(d->doc).y == 0; 4948 const iBool isDocEmpty = size_GmDocument(d->doc).y == 0;
4943 const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0; 4949 const iBool isTouchSelecting = (flags_Widget(w) & touchDrag_WidgetFlag) != 0;
4944 if (!isDocEmpty) { 4950 if (!isDocEmpty || !isEmpty_Banner(d->banner)) {
4951 const int docBgColor = isDocEmpty ? tmBannerBackground_ColorId : tmBackground_ColorId;
4945 setClip_Paint(&ctx.paint, clipBounds); 4952 setClip_Paint(&ctx.paint, clipBounds);
4946 draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds)); 4953 if (!isDocEmpty) {
4954 draw_VisBuf(d->visBuf, init_I2(bounds.pos.x, yTop), ySpan_Rect(bounds));
4955 }
4947 /* Text markers. */ 4956 /* Text markers. */
4948 if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) { 4957 if (!isEmpty_Range(&d->foundMark) || !isEmpty_Range(&d->selectMark)) {
4949 SDL_Renderer *render = renderer_Window(get_Window()); 4958 SDL_Renderer *render = renderer_Window(get_Window());
@@ -4980,23 +4989,24 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
4980 fillRect_Paint(&ctx.paint, 4989 fillRect_Paint(&ctx.paint,
4981 (iRect){ bounds.pos, init_I2(bounds.size.x, yTop - top_Rect(bounds)) }, 4990 (iRect){ bounds.pos, init_I2(bounds.size.x, yTop - top_Rect(bounds)) },
4982 !isEmpty_Banner(d->banner) ? tmBannerBackground_ColorId 4991 !isEmpty_Banner(d->banner) ? tmBannerBackground_ColorId
4983 : tmBackground_ColorId); 4992 : docBgColor);
4984 } 4993 }
4985 /* Banner. */ { 4994 /* Banner. */
4995 if (!isDocEmpty || numItems_Banner(d->banner) > 0) {
4986 /* Fill the part between the banner and the top of the document. */ 4996 /* Fill the part between the banner and the top of the document. */
4987 fillRect_Paint(&ctx.paint, 4997 fillRect_Paint(&ctx.paint,
4988 (iRect){ init_I2(left_Rect(bounds), 4998 (iRect){ init_I2(left_Rect(bounds),
4989 top_Rect(docBounds) + viewPos_DocumentWidget_(d) - 4999 top_Rect(docBounds) + viewPos_DocumentWidget_(d) -
4990 documentTopPad_DocumentWidget_(d)), 5000 documentTopPad_DocumentWidget_(d)),
4991 init_I2(bounds.size.x, documentTopPad_DocumentWidget_(d)) }, 5001 init_I2(bounds.size.x, documentTopPad_DocumentWidget_(d)) },
4992 tmBackground_ColorId); 5002 docBgColor);
4993 draw_Banner(d->banner); 5003 draw_Banner(d->banner);
4994 } 5004 }
4995 const int yBottom = yTop + size_GmDocument(d->doc).y + 1; 5005 const int yBottom = yTop + size_GmDocument(d->doc).y;
4996 if (yBottom < bottom_Rect(bounds)) { 5006 if (yBottom < bottom_Rect(bounds)) {
4997 fillRect_Paint(&ctx.paint, 5007 fillRect_Paint(&ctx.paint,
4998 init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom), 5008 init_Rect(bounds.pos.x, yBottom, bounds.size.x, bottom_Rect(bounds) - yBottom),
4999 tmBackground_ColorId); 5009 !isDocEmpty ? docBgColor : tmBannerBackground_ColorId);
5000 } 5010 }
5001 unsetClip_Paint(&ctx.paint); 5011 unsetClip_Paint(&ctx.paint);
5002 drawSideElements_DocumentWidget_(d); 5012 drawSideElements_DocumentWidget_(d);
@@ -5016,9 +5026,9 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) {
5016 drawChildren_Widget(w); 5026 drawChildren_Widget(w);
5017 if (d->flags & drawDownloadCounter_DocumentWidgetFlag && isRequestOngoing_DocumentWidget(d)) { 5027 if (d->flags & drawDownloadCounter_DocumentWidgetFlag && isRequestOngoing_DocumentWidget(d)) {
5018 const int font = uiLabelLarge_FontId; 5028 const int font = uiLabelLarge_FontId;
5019 const iInt2 sevenSegWidth = measureRange_Text(font, range_CStr("\U0001fbf0")).advance; 5029 const iInt2 sevenSegWidth = measureRange_Text(font, range_CStr("\U0001fbf0")).bounds.size;
5020 drawSevenSegmentBytes_MediaUI(font, 5030 drawSevenSegmentBytes_MediaUI(font,
5021 add_I2(mid_Rect(docBounds), 5031 add_I2(mid_Rect(bounds),
5022 init_I2(sevenSegWidth.x * 4.5f, -sevenSegWidth.y / 2)), 5032 init_I2(sevenSegWidth.x * 4.5f, -sevenSegWidth.y / 2)),
5023 uiTextStrong_ColorId, uiTextDim_ColorId, 5033 uiTextStrong_ColorId, uiTextDim_ColorId,
5024 bodySize_GmRequest(d->request)); 5034 bodySize_GmRequest(d->request));