diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gmdocument.c | 8 | ||||
-rw-r--r-- | src/ui/banner.c | 120 | ||||
-rw-r--r-- | src/ui/banner.h | 1 | ||||
-rw-r--r-- | src/ui/color.h | 5 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 86 |
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) | |||
32 | struct Impl_BannerItem { | 33 | struct 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 | ||
39 | static void init_BannerItem(iBannerItem *d) { | 40 | static 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 | ||
44 | static void deinit_BannerItem(iBannerItem *d) { | 45 | static 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 | ||
61 | static void updateHeight_Banner_(iBanner *d) { | 62 | static 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 | ||
68 | void init_Banner(iBanner *d) { | 80 | void 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 | ||
100 | static 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 | |||
88 | void setWidth_Banner(iBanner *d, int width) { | 107 | void 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 | ||
123 | size_t numItems_Banner(const iBanner *d) { | ||
124 | return size_Array(&d->items); | ||
125 | } | ||
126 | |||
101 | iBool contains_Banner(const iBanner *d, iInt2 coord) { | 127 | iBool 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 | ||
184 | void 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 | |||
146 | iBool processEvent_Banner(iBanner *d, const SDL_Event *ev) { | 231 | iBool 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 | |||
273 | void 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); | |||
42 | void setPos_Banner (iBanner *, iInt2 pos); | 42 | void setPos_Banner (iBanner *, iInt2 pos); |
43 | 43 | ||
44 | int height_Banner (const iBanner *); | 44 | int height_Banner (const iBanner *); |
45 | size_t numItems_Banner (const iBanner *); | ||
45 | iBool contains_Banner (const iBanner *, iInt2 coord); | 46 | iBool contains_Banner (const iBanner *, iInt2 coord); |
46 | 47 | ||
47 | iLocalDef iBool isEmpty_Banner(const iBanner *d) { | 48 | iLocalDef 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 | ||
1128 | static void updateBanner_DocumentWidget_(iDocumentWidget *d) { | 1133 | static 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 | |||
1197 | static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, | 1202 | static 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)); |