diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/documentwidget.c | 130 |
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 | ||
208 | iDefineObjectConstruction(DocumentWidget) | 210 | iDefineObjectConstruction(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 | ||
262 | void deinit_DocumentWidget(iDocumentWidget *d) { | 267 | void 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 | ||
607 | static 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 | |||
598 | static void invalidate_DocumentWidget_(iDocumentWidget *d) { | 619 | static 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 | ||
679 | static void showErrorPage_DocumentWidget_(iDocumentWidget *d, enum iGmStatusCode code, | 701 | static 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 | ||
2345 | static 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 | ||
2351 | static 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 | |||
2321 | static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | 2395 | static 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; |