summaryrefslogtreecommitdiff
path: root/src/ui/documentwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r--src/ui/documentwidget.c130
1 files changed, 92 insertions, 38 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c
index 3f08e678..d1381a3b 100644
--- a/src/ui/documentwidget.c
+++ b/src/ui/documentwidget.c
@@ -203,6 +203,8 @@ struct Impl_DocumentWidget {
203 iWidget * playerMenu; 203 iWidget * playerMenu;
204 iVisBuf * visBuf; 204 iVisBuf * visBuf;
205 iPtrSet * invalidRuns; 205 iPtrSet * invalidRuns;
206 SDL_Texture * sideIconBuf;
207 iTextBuf * timestampBuf;
206}; 208};
207 209
208iDefineObjectConstruction(DocumentWidget) 210iDefineObjectConstruction(DocumentWidget)
@@ -240,14 +242,17 @@ void init_DocumentWidget(iDocumentWidget *d) {
240 init_Anim(&d->outlineOpacity, 0); 242 init_Anim(&d->outlineOpacity, 0);
241 init_String(&d->sourceMime); 243 init_String(&d->sourceMime);
242 init_Block(&d->sourceContent, 0); 244 init_Block(&d->sourceContent, 0);
245 iZap(d->sourceTime);
243 init_PtrArray(&d->visibleLinks); 246 init_PtrArray(&d->visibleLinks);
244 init_PtrArray(&d->visiblePlayers); 247 init_PtrArray(&d->visiblePlayers);
245 d->grabbedPlayer = NULL; 248 d->grabbedPlayer = NULL;
246 d->playerTimer = 0; 249 d->playerTimer = 0;
247 init_Click(&d->click, d, SDL_BUTTON_LEFT); 250 init_Click(&d->click, d, SDL_BUTTON_LEFT);
248 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget())); 251 addChild_Widget(w, iClob(d->scroll = new_ScrollWidget()));
249 d->menu = NULL; /* created when clicking */ 252 d->menu = NULL; /* created when clicking */
250 d->playerMenu = NULL; 253 d->playerMenu = NULL;
254 d->sideIconBuf = NULL;
255 d->timestampBuf = NULL;
251 addChildFlags_Widget(w, 256 addChildFlags_Widget(w,
252 iClob(new_IndicatorWidget()), 257 iClob(new_IndicatorWidget()),
253 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag); 258 resizeToParentWidth_WidgetFlag | resizeToParentHeight_WidgetFlag);
@@ -260,6 +265,10 @@ void init_DocumentWidget(iDocumentWidget *d) {
260} 265}
261 266
262void deinit_DocumentWidget(iDocumentWidget *d) { 267void deinit_DocumentWidget(iDocumentWidget *d) {
268 if (d->sideIconBuf) {
269 SDL_DestroyTexture(d->sideIconBuf);
270 }
271 delete_TextBuf(d->timestampBuf);
263 delete_VisBuf(d->visBuf); 272 delete_VisBuf(d->visBuf);
264 delete_PtrSet(d->invalidRuns); 273 delete_PtrSet(d->invalidRuns);
265 deinit_Array(&d->outline); 274 deinit_Array(&d->outline);
@@ -595,6 +604,18 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) {
595 } 604 }
596} 605}
597 606
607static void updateTimestampBuf_DocumentWidget_(iDocumentWidget *d) {
608 if (d->timestampBuf) {
609 delete_TextBuf(d->timestampBuf);
610 d->timestampBuf = NULL;
611 }
612 if (isValid_Time(&d->sourceTime)) {
613 d->timestampBuf = new_TextBuf(
614 uiLabel_FontId,
615 cstrCollect_String(format_Time(&d->sourceTime, "Received at %I:%M %p\non %b %d, %Y")));
616 }
617}
618
598static void invalidate_DocumentWidget_(iDocumentWidget *d) { 619static void invalidate_DocumentWidget_(iDocumentWidget *d) {
599 invalidate_VisBuf(d->visBuf); 620 invalidate_VisBuf(d->visBuf);
600 clear_PtrSet(d->invalidRuns); 621 clear_PtrSet(d->invalidRuns);
@@ -674,6 +695,7 @@ static void updateTheme_DocumentWidget_(iDocumentWidget *d) {
674 else { 695 else {
675 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars); 696 setThemeSeed_GmDocument(d->doc, &d->titleUser->chars);
676 } 697 }
698 updateTimestampBuf_DocumentWidget_(d);
677} 699}
678 700
679static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, 701static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code,
@@ -756,6 +778,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, const iGmResponse
756 } 778 }
757 clear_String(&d->sourceMime); 779 clear_String(&d->sourceMime);
758 d->sourceTime = response->when; 780 d->sourceTime = response->when;
781 updateTimestampBuf_DocumentWidget_(d);
759 initBlock_String(&str, &response->body); 782 initBlock_String(&str, &response->body);
760 if (isSuccess_GmStatusCode(statusCode)) { 783 if (isSuccess_GmStatusCode(statusCode)) {
761 /* Check the MIME type. */ 784 /* Check the MIME type. */
@@ -909,6 +932,7 @@ static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) {
909 /* Use the cached response data. */ 932 /* Use the cached response data. */
910 updateTrust_DocumentWidget_(d, resp); 933 updateTrust_DocumentWidget_(d, resp);
911 d->sourceTime = resp->when; 934 d->sourceTime = resp->when;
935 updateTimestampBuf_DocumentWidget_(d);
912 set_Block(&d->sourceContent, &resp->body); 936 set_Block(&d->sourceContent, &resp->body);
913 updateDocument_DocumentWidget_(d, resp, iTrue); 937 updateDocument_DocumentWidget_(d, resp, iTrue);
914 init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y); 938 init_Anim(&d->scrollY, d->initNormScrollY * size_GmDocument(d->doc).y);
@@ -2318,61 +2342,91 @@ static iRangecc currentHeading_DocumentWidget_(const iDocumentWidget *d) {
2318 return heading; 2342 return heading;
2319} 2343}
2320 2344
2345static int sideElementAvailWidth_DocumentWidget_(const iDocumentWidget *d) {
2346 return left_Rect(documentBounds_DocumentWidget_(d)) -
2347 left_Rect(bounds_Widget(constAs_Widget(d))) - 2 * d->pageMargin * gap_UI;
2348}
2349
2350#if 0
2351static void updateSideIconBuf_DocumentWidget_(iDocumentWidget *d) {
2352 if (d->sideIconBuf) {
2353 SDL_DestroyTexture(d->sideIconBuf);
2354 d->sideIconBuf = NULL;
2355 }
2356 const iWidget *w = constAs_Widget(d);
2357 const iRect bounds = bounds_Widget(w);
2358 const int margin = gap_UI * d->pageMargin;
2359 const iGmRun * banner = siteBanner_GmDocument(d->doc);
2360 const int minBannerSize = lineHeight_Text(banner_FontId) * 2;
2361 const iChar icon = siteIcon_GmDocument(d->doc);
2362 const int avail = sideElementAvailWidth_DocumentWidget_(d) - margin;
2363 /* Determine the required size. */
2364 iInt2 bufSize = init1_I2(minBannerSize);
2365 const iInt2 headingSize = advanceWrapRange_Text(heading3_FontId, avail, currentHeading_DocumentWidget_(d));
2366 bufSize.y += gap_Text + headingSize.y;
2367 bufSize.x = iMax(bufSize.x, headingSize.x);
2368
2369// iRect rect = { add_I2(topLeft_Rect(bounds), init1_I2(margin)), init1_I2(minBannerSize) };
2370// p.alpha = opacity * 255;
2371// rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0);
2372 d->sideIconBuf = SDL_CreateTexture(renderer_Window(get_Window()),
2373 SDL_PIXELFORMAT_RGBA4444,
2374 SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET,
2375 bufSize.x, bufSize.y);
2376 iPaint p;
2377 init_Paint(&p);
2378 beginTarget_Paint(&p, d->sideIconBuf);
2379 fillRect_Paint(&p, )
2380 int fg = drawSideRect_(&p, rect);
2381 iString str;
2382 initUnicodeN_String(&str, &icon, 1);
2383 drawCentered_Text(banner_FontId, rect, iTrue, fg, "%s", cstr_String(&str));
2384 deinit_String(&str);
2385 if (avail >= minBannerSize * 2.25f) {
2386 iRangecc text = currentHeading_DocumentWidget_(d);
2387 iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text);
2388 const int font = heading3_FontId;
2389 drawWrapRange_Text(font, pos, avail - margin, tmBannerSideTitle_ColorId, text);
2390 }
2391 endTarget_Paint(&p);
2392}
2393#endif
2394
2321static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { 2395static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) {
2322 const iWidget *w = constAs_Widget(d); 2396 const iWidget *w = constAs_Widget(d);
2323 const iRect bounds = bounds_Widget(w); 2397 const iRect bounds = bounds_Widget(w);
2324 const iRect docBounds = documentBounds_DocumentWidget_(d); 2398 const iRect docBounds = documentBounds_DocumentWidget_(d);
2325 const int margin = gap_UI * d->pageMargin; 2399 const int margin = gap_UI * d->pageMargin;
2326 const iGmRun * banner = siteBanner_GmDocument(d->doc);
2327 float opacity = value_Anim(&d->sideOpacity); 2400 float opacity = value_Anim(&d->sideOpacity);
2328 const int minBannerSize = lineHeight_Text(banner_FontId) * 2; 2401 const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin;
2329 const int avail = left_Rect(docBounds) - left_Rect(bounds) - 2 * margin;
2330 iPaint p; 2402 iPaint p;
2331 init_Paint(&p); 2403 init_Paint(&p);
2332 setClip_Paint(&p, bounds); 2404 setClip_Paint(&p, bounds);
2333 if (prefs_App()->sideIcon && avail > minBannerSize) { 2405#if 0
2334 if (banner && opacity > 0) { 2406 if (prefs_App()->sideIcon && opacity > 0 && d->sideIconBuf && avail > size_SDLTexture(d->sideIconBuf).x) {
2407 if (banner) {
2335 setOpacity_Text(opacity); 2408 setOpacity_Text(opacity);
2336 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND); 2409 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_BLEND);
2337 const iChar icon = siteIcon_GmDocument(d->doc);
2338 iRect rect = { add_I2(topLeft_Rect(bounds), init1_I2(margin)), init1_I2(minBannerSize) };
2339 p.alpha = opacity * 255;
2340 rect.pos.y += height_Rect(bounds) / 2 - rect.size.y / 2 - (banner ? banner->visBounds.size.y / 2 : 0);
2341 int fg = drawSideRect_(&p, rect);
2342 iString str;
2343 initUnicodeN_String(&str, &icon, 1);
2344 drawCentered_Text(banner_FontId, rect, iTrue, fg, "%s", cstr_String(&str));
2345 if (avail >= minBannerSize * 2.25f) {
2346 iRangecc text = currentHeading_DocumentWidget_(d);// bannerText_DocumentWidget_(d);
2347 iInt2 pos = addY_I2(bottomLeft_Rect(rect), gap_Text);
2348 const int font = heading3_FontId;
2349 drawWrapRange_Text(font, pos, avail - margin, tmBannerSideTitle_ColorId, text);
2350 }
2351 setOpacity_Text(1.0f); 2410 setOpacity_Text(1.0f);
2352 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE); 2411 SDL_SetRenderDrawBlendMode(renderer_Window(get_Window()), SDL_BLENDMODE_NONE);
2353 } 2412 }
2354 } 2413 }
2414#endif
2355 /* Reception timestamp. */ 2415 /* Reception timestamp. */
2356 if (isValid_Time(&d->sourceTime)) { 2416 if (d->timestampBuf && d->timestampBuf->size.x <= avail) {
2357 const int font = uiLabel_FontId; 2417 draw_TextBuf(
2358 const iString *recv = 2418 d->timestampBuf,
2359 collect_String(format_Time(&d->sourceTime, "Received at %I:%M %p\non %b %d, %Y")); 2419 add_I2(
2360 const iInt2 size = advanceRange_Text(font, range_String(recv)); 2420 bottomLeft_Rect(bounds),
2361 if (size.x <= avail) { 2421 init_I2(margin,
2362 drawString_Text( 2422 -margin + -d->timestampBuf->size.y +
2363 font, 2423 iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))),
2364 add_I2( 2424 tmQuoteIcon_ColorId);
2365 bottomLeft_Rect(bounds),
2366 init_I2(margin,
2367 -margin + -size.y +
2368 iMax(0, scrollMax_DocumentWidget_(d) - value_Anim(&d->scrollY)))),
2369 tmQuoteIcon_ColorId,
2370 recv);
2371 }
2372 } 2425 }
2373 /* Outline on the right side. */ 2426 /* Outline on the right side. */
2374 const float outlineOpacity = value_Anim(&d->outlineOpacity); 2427 const float outlineOpacity = value_Anim(&d->outlineOpacity);
2375 if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) { 2428 if (prefs_App()->hoverOutline && !isEmpty_Array(&d->outline) && outlineOpacity > 0.0f) {
2429 /* TODO: This is very slow to draw; should be buffered appropriately. */
2376 const int innerWidth = outlineWidth_DocumentWidget_(d); 2430 const int innerWidth = outlineWidth_DocumentWidget_(d);
2377 const int outWidth = innerWidth + 2 * outlinePadding_DocumentWidget_ * gap_UI; 2431 const int outWidth = innerWidth + 2 * outlinePadding_DocumentWidget_ * gap_UI;
2378 const int topMargin = 0; 2432 const int topMargin = 0;