diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-11 12:22:54 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-11 12:22:54 +0300 |
commit | 960df03c17091aca37f53eaab8fc27c669d26a5e (patch) | |
tree | 18721567f227928c528430daf9d06248a2443598 /src/ui/documentwidget.c | |
parent | bf9158b29df506698e267d4583459ee4ebf20685 (diff) |
Media refactoring; working on FontPack management
Media still needs more work to get rid of redundancies and make lookups faster.
FontPacks are manipulated as Media items (not unlike images) so they can be previewed on page, and installed via a click.
FontPack management is not trivial as it includes such details as versioning and whether individual packs are enabled or disabled.
Diffstat (limited to 'src/ui/documentwidget.c')
-rw-r--r-- | src/ui/documentwidget.c | 429 |
1 files changed, 240 insertions, 189 deletions
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 45a8cf2d..44db3e5b 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -400,7 +400,18 @@ void init_DocumentWidget(iDocumentWidget *d) { | |||
400 | addAction_Widget(w, navigateRoot_KeyShortcut, "navigate.root"); | 400 | addAction_Widget(w, navigateRoot_KeyShortcut, "navigate.root"); |
401 | } | 401 | } |
402 | 402 | ||
403 | void cancelAllRequests_DocumentWidget(iDocumentWidget *d) { | ||
404 | iForEach(ObjectList, i, d->media) { | ||
405 | iMediaRequest *mr = i.object; | ||
406 | cancel_GmRequest(mr->req); | ||
407 | } | ||
408 | if (d->request) { | ||
409 | cancel_GmRequest(d->request); | ||
410 | } | ||
411 | } | ||
412 | |||
403 | void deinit_DocumentWidget(iDocumentWidget *d) { | 413 | void deinit_DocumentWidget(iDocumentWidget *d) { |
414 | cancelAllRequests_DocumentWidget(d); | ||
404 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); | 415 | pauseAllPlayers_Media(media_GmDocument(d->doc), iTrue); |
405 | removeTicker_App(animate_DocumentWidget_, d); | 416 | removeTicker_App(animate_DocumentWidget_, d); |
406 | removeTicker_App(prerender_DocumentWidget_, d); | 417 | removeTicker_App(prerender_DocumentWidget_, d); |
@@ -564,7 +575,8 @@ static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { | |||
564 | pushBack_PtrArray(&d->visibleWideRuns, run); | 575 | pushBack_PtrArray(&d->visibleWideRuns, run); |
565 | } | 576 | } |
566 | } | 577 | } |
567 | if (run->mediaType == audio_GmRunMediaType || run->mediaType == download_GmRunMediaType) { | 578 | /* Image runs are static so they're drawn as part of the content. */ |
579 | if (run->mediaType && run->mediaType != image_MediaType) { | ||
568 | iAssert(run->mediaId); | 580 | iAssert(run->mediaId); |
569 | pushBack_PtrArray(&d->visibleMedia, run); | 581 | pushBack_PtrArray(&d->visibleMedia, run); |
570 | } | 582 | } |
@@ -758,14 +770,14 @@ static uint32_t mediaUpdateInterval_DocumentWidget_(const iDocumentWidget *d) { | |||
758 | uint32_t interval = invalidInterval_; | 770 | uint32_t interval = invalidInterval_; |
759 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 771 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
760 | const iGmRun *run = i.ptr; | 772 | const iGmRun *run = i.ptr; |
761 | if (run->mediaType == audio_GmRunMediaType) { | 773 | if (run->mediaType == audio_MediaType) { |
762 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 774 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
763 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || | 775 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || |
764 | (isStarted_Player(plr) && !isPaused_Player(plr))) { | 776 | (isStarted_Player(plr) && !isPaused_Player(plr))) { |
765 | interval = iMin(interval, 1000 / 15); | 777 | interval = iMin(interval, 1000 / 15); |
766 | } | 778 | } |
767 | } | 779 | } |
768 | else if (run->mediaType == download_GmRunMediaType) { | 780 | else if (run->mediaType == download_MediaType) { |
769 | interval = iMin(interval, 1000); | 781 | interval = iMin(interval, 1000); |
770 | } | 782 | } |
771 | } | 783 | } |
@@ -784,8 +796,8 @@ static void updateMedia_DocumentWidget_(iDocumentWidget *d) { | |||
784 | refresh_Widget(d); | 796 | refresh_Widget(d); |
785 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 797 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
786 | const iGmRun *run = i.ptr; | 798 | const iGmRun *run = i.ptr; |
787 | if (run->mediaType == audio_GmRunMediaType) { | 799 | if (run->mediaType == audio_MediaType) { |
788 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 800 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
789 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && | 801 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && |
790 | flags_Player(plr) & adjustingVolume_PlayerFlag) { | 802 | flags_Player(plr) & adjustingVolume_PlayerFlag) { |
791 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); | 803 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); |
@@ -1244,6 +1256,9 @@ static const char *zipPageHeading_(const iRangecc mime) { | |||
1244 | if (equalCase_Rangecc(mime, "application/gpub+zip")) { | 1256 | if (equalCase_Rangecc(mime, "application/gpub+zip")) { |
1245 | return book_Icon " Gempub"; | 1257 | return book_Icon " Gempub"; |
1246 | } | 1258 | } |
1259 | else if (equalCase_Rangecc(mime, mimeType_FontPack)) { | ||
1260 | return "\U0001f520 Fontpack"; | ||
1261 | } | ||
1247 | iRangecc type = iNullRange; | 1262 | iRangecc type = iNullRange; |
1248 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ | 1263 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ |
1249 | nextSplit_Rangecc(mime, "/", &type); | 1264 | nextSplit_Rangecc(mime, "/", &type); |
@@ -1258,165 +1273,175 @@ static const char *zipPageHeading_(const iRangecc mime) { | |||
1258 | 1273 | ||
1259 | static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) { | 1274 | static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) { |
1260 | iWidget *w = as_Widget(d); | 1275 | iWidget *w = as_Widget(d); |
1261 | delete_Gempub(d->sourceGempub); | 1276 | /* Gempub page behavior and footer actions. */ { |
1262 | d->sourceGempub = NULL; | 1277 | /* TODO: move this to gempub.c */ |
1263 | if (!cmpCase_String(&d->sourceMime, "application/octet-stream") || | 1278 | delete_Gempub(d->sourceGempub); |
1264 | !cmpCase_String(&d->sourceMime, mimeType_Gempub) || | 1279 | d->sourceGempub = NULL; |
1265 | endsWithCase_String(d->mod.url, ".gpub")) { | 1280 | if (!cmpCase_String(&d->sourceMime, "application/octet-stream") || |
1266 | iGempub *gempub = new_Gempub(); | 1281 | !cmpCase_String(&d->sourceMime, mimeType_Gempub) || |
1267 | if (open_Gempub(gempub, &d->sourceContent)) { | 1282 | endsWithCase_String(d->mod.url, ".gpub")) { |
1268 | setBaseUrl_Gempub(gempub, d->mod.url); | ||
1269 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); | ||
1270 | setCStr_String(&d->sourceMime, mimeType_Gempub); | ||
1271 | d->sourceGempub = gempub; | ||
1272 | } | ||
1273 | else { | ||
1274 | delete_Gempub(gempub); | ||
1275 | } | ||
1276 | } | ||
1277 | if (!d->sourceGempub) { | ||
1278 | const iString *localPath = collect_String(localFilePathFromUrl_String(d->mod.url)); | ||
1279 | iBool isInside = iFalse; | ||
1280 | if (localPath && !fileExists_FileInfo(localPath)) { | ||
1281 | /* This URL may refer to a file inside the archive. */ | ||
1282 | localPath = findContainerArchive_Path(localPath); | ||
1283 | isInside = iTrue; | ||
1284 | } | ||
1285 | if (localPath && equal_CStr(mediaType_Path(localPath), "application/gpub+zip")) { | ||
1286 | iGempub *gempub = new_Gempub(); | 1283 | iGempub *gempub = new_Gempub(); |
1287 | if (openFile_Gempub(gempub, localPath)) { | 1284 | if (open_Gempub(gempub, &d->sourceContent)) { |
1288 | setBaseUrl_Gempub(gempub, collect_String(makeFileUrl_String(localPath))); | 1285 | setBaseUrl_Gempub(gempub, d->mod.url); |
1289 | if (!isInside) { | 1286 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); |
1290 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); | 1287 | setCStr_String(&d->sourceMime, mimeType_Gempub); |
1291 | setCStr_String(&d->sourceMime, mimeType_Gempub); | ||
1292 | } | ||
1293 | d->sourceGempub = gempub; | 1288 | d->sourceGempub = gempub; |
1294 | } | 1289 | } |
1295 | else { | 1290 | else { |
1296 | delete_Gempub(gempub); | 1291 | delete_Gempub(gempub); |
1297 | } | 1292 | } |
1298 | } | 1293 | } |
1299 | } | 1294 | if (!d->sourceGempub) { |
1300 | if (d->sourceGempub) { | 1295 | const iString *localPath = collect_String(localFilePathFromUrl_String(d->mod.url)); |
1301 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { | 1296 | iBool isInside = iFalse; |
1302 | if (!isRemote_Gempub(d->sourceGempub)) { | 1297 | if (localPath && !fileExists_FileInfo(localPath)) { |
1303 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | 1298 | /* This URL may refer to a file inside the archive. */ |
1304 | pushBack_Array( | 1299 | localPath = findContainerArchive_Path(localPath); |
1305 | items, | 1300 | isInside = iTrue; |
1306 | &(iMenuItem){ book_Icon " ${gempub.cover.view}", | ||
1307 | 0, | ||
1308 | 0, | ||
1309 | format_CStr("!open url:%s", | ||
1310 | cstr_String(indexPageUrl_Gempub(d->sourceGempub))) }); | ||
1311 | if (navSize_Gempub(d->sourceGempub) > 0) { | ||
1312 | pushBack_Array( | ||
1313 | items, | ||
1314 | &(iMenuItem){ | ||
1315 | format_CStr(forwardArrow_Icon " %s", | ||
1316 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, 0))), | ||
1317 | SDLK_RIGHT, | ||
1318 | 0, | ||
1319 | format_CStr("!open url:%s", | ||
1320 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, 0))) }); | ||
1321 | } | ||
1322 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); | ||
1323 | } | 1301 | } |
1324 | else { | 1302 | if (localPath && equal_CStr(mediaType_Path(localPath), mimeType_Gempub)) { |
1325 | makeFooterButtons_DocumentWidget_( | 1303 | iGempub *gempub = new_Gempub(); |
1326 | d, | 1304 | if (openFile_Gempub(gempub, localPath)) { |
1327 | (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", | 1305 | setBaseUrl_Gempub(gempub, collect_String(makeFileUrl_String(localPath))); |
1328 | SDLK_s, | 1306 | if (!isInside) { |
1329 | KMOD_PRIMARY | KMOD_SHIFT, | 1307 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); |
1330 | "document.save open:1" }, | 1308 | setCStr_String(&d->sourceMime, mimeType_Gempub); |
1331 | { download_Icon " " saveToDownloads_Label, | 1309 | } |
1332 | SDLK_s, | 1310 | d->sourceGempub = gempub; |
1333 | KMOD_PRIMARY, | 1311 | } |
1334 | "document.save" } }, | 1312 | else { |
1335 | 2); | 1313 | delete_Gempub(gempub); |
1336 | } | 1314 | } |
1337 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { | ||
1338 | redoLayout_GmDocument(d->doc); | ||
1339 | updateVisible_DocumentWidget_(d); | ||
1340 | invalidate_DocumentWidget_(d); | ||
1341 | } | 1315 | } |
1342 | } | 1316 | } |
1343 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1317 | if (d->sourceGempub) { |
1344 | makeFooterButtons_DocumentWidget_( | 1318 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { |
1345 | d, | 1319 | if (!isRemote_Gempub(d->sourceGempub)) { |
1346 | (iMenuItem[]){ { format_CStr(book_Icon " %s", | 1320 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1347 | cstr_String(property_Gempub(d->sourceGempub, | ||
1348 | title_GempubProperty))), | ||
1349 | SDLK_LEFT, | ||
1350 | 0, | ||
1351 | format_CStr("!open url:%s", | ||
1352 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) } }, | ||
1353 | 1); | ||
1354 | } | ||
1355 | else { | ||
1356 | /* Navigation buttons. */ | ||
1357 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | ||
1358 | const size_t navIndex = navIndex_Gempub(d->sourceGempub, d->mod.url); | ||
1359 | if (navIndex != iInvalidPos) { | ||
1360 | if (navIndex < navSize_Gempub(d->sourceGempub) - 1) { | ||
1361 | pushBack_Array( | 1321 | pushBack_Array( |
1362 | items, | 1322 | items, |
1363 | &(iMenuItem){ | 1323 | &(iMenuItem){ book_Icon " ${gempub.cover.view}", |
1364 | format_CStr(forwardArrow_Icon " %s", | 1324 | 0, |
1365 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex + 1))), | 1325 | 0, |
1366 | SDLK_RIGHT, | 1326 | format_CStr("!open url:%s", |
1367 | 0, | 1327 | cstr_String(indexPageUrl_Gempub(d->sourceGempub))) }); |
1368 | format_CStr("!open url:%s", | 1328 | if (navSize_Gempub(d->sourceGempub) > 0) { |
1369 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex + 1))) }); | 1329 | pushBack_Array( |
1330 | items, | ||
1331 | &(iMenuItem){ | ||
1332 | format_CStr(forwardArrow_Icon " %s", | ||
1333 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, 0))), | ||
1334 | SDLK_RIGHT, | ||
1335 | 0, | ||
1336 | format_CStr("!open url:%s", | ||
1337 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, 0))) }); | ||
1338 | } | ||
1339 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); | ||
1370 | } | 1340 | } |
1371 | if (navIndex > 0) { | 1341 | else { |
1372 | pushBack_Array( | 1342 | makeFooterButtons_DocumentWidget_( |
1373 | items, | 1343 | d, |
1374 | &(iMenuItem){ | 1344 | (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", |
1375 | format_CStr(backArrow_Icon " %s", | 1345 | SDLK_s, |
1376 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex - 1))), | 1346 | KMOD_PRIMARY | KMOD_SHIFT, |
1377 | SDLK_LEFT, | 1347 | "document.save open:1" }, |
1378 | 0, | 1348 | { download_Icon " " saveToDownloads_Label, |
1379 | format_CStr("!open url:%s", | 1349 | SDLK_s, |
1380 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex - 1))) }); | 1350 | KMOD_PRIMARY, |
1351 | "document.save" } }, | ||
1352 | 2); | ||
1381 | } | 1353 | } |
1382 | else if (!equalCase_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1354 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { |
1383 | pushBack_Array( | 1355 | redoLayout_GmDocument(d->doc); |
1384 | items, | 1356 | updateVisible_DocumentWidget_(d); |
1385 | &(iMenuItem){ | 1357 | invalidate_DocumentWidget_(d); |
1386 | format_CStr(book_Icon " %s", | ||
1387 | cstr_String(property_Gempub(d->sourceGempub, title_GempubProperty))), | ||
1388 | SDLK_LEFT, | ||
1389 | 0, | ||
1390 | format_CStr("!open url:%s", | ||
1391 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) }); | ||
1392 | } | 1358 | } |
1393 | } | 1359 | } |
1394 | if (!isEmpty_Array(items)) { | 1360 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { |
1395 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); | 1361 | makeFooterButtons_DocumentWidget_( |
1362 | d, | ||
1363 | (iMenuItem[]){ { format_CStr(book_Icon " %s", | ||
1364 | cstr_String(property_Gempub(d->sourceGempub, | ||
1365 | title_GempubProperty))), | ||
1366 | SDLK_LEFT, | ||
1367 | 0, | ||
1368 | format_CStr("!open url:%s", | ||
1369 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) } }, | ||
1370 | 1); | ||
1396 | } | 1371 | } |
1397 | } | 1372 | else { |
1398 | if (!isCached && prefs_App()->pinSplit && | 1373 | /* Navigation buttons. */ |
1399 | equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1374 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1400 | const iString *navStart = navStartLinkUrl_Gempub(d->sourceGempub); | 1375 | const size_t navIndex = navIndex_Gempub(d->sourceGempub, d->mod.url); |
1401 | if (navStart) { | 1376 | if (navIndex != iInvalidPos) { |
1402 | iWindow *win = get_Window(); | 1377 | if (navIndex < navSize_Gempub(d->sourceGempub) - 1) { |
1403 | /* Auto-split to show index and the first navigation link. */ | 1378 | pushBack_Array( |
1404 | if (numRoots_Window(win) == 2) { | 1379 | items, |
1405 | /* This document is showing the index page. */ | 1380 | &(iMenuItem){ |
1406 | iRoot *other = otherRoot_Window(win, w->root); | 1381 | format_CStr(forwardArrow_Icon " %s", |
1407 | postCommandf_Root(other, "open url:%s", cstr_String(navStart)); | 1382 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex + 1))), |
1408 | if (prefs_App()->pinSplit == 1 && w->root == win->roots[1]) { | 1383 | SDLK_RIGHT, |
1409 | /* On the wrong side. */ | 1384 | 0, |
1410 | postCommand_App("ui.split swap:1"); | 1385 | format_CStr("!open url:%s", |
1386 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex + 1))) }); | ||
1387 | } | ||
1388 | if (navIndex > 0) { | ||
1389 | pushBack_Array( | ||
1390 | items, | ||
1391 | &(iMenuItem){ | ||
1392 | format_CStr(backArrow_Icon " %s", | ||
1393 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex - 1))), | ||
1394 | SDLK_LEFT, | ||
1395 | 0, | ||
1396 | format_CStr("!open url:%s", | ||
1397 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex - 1))) }); | ||
1398 | } | ||
1399 | else if (!equalCase_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | ||
1400 | pushBack_Array( | ||
1401 | items, | ||
1402 | &(iMenuItem){ | ||
1403 | format_CStr(book_Icon " %s", | ||
1404 | cstr_String(property_Gempub(d->sourceGempub, title_GempubProperty))), | ||
1405 | SDLK_LEFT, | ||
1406 | 0, | ||
1407 | format_CStr("!open url:%s", | ||
1408 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) }); | ||
1411 | } | 1409 | } |
1412 | } | 1410 | } |
1413 | else { | 1411 | if (!isEmpty_Array(items)) { |
1414 | postCommandf_App( | 1412 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); |
1415 | "open newtab:%d url:%s", otherRoot_OpenTabFlag, cstr_String(navStart)); | 1413 | } |
1414 | } | ||
1415 | if (!isCached && prefs_App()->pinSplit && | ||
1416 | equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | ||
1417 | const iString *navStart = navStartLinkUrl_Gempub(d->sourceGempub); | ||
1418 | if (navStart) { | ||
1419 | iWindow *win = get_Window(); | ||
1420 | /* Auto-split to show index and the first navigation link. */ | ||
1421 | if (numRoots_Window(win) == 2) { | ||
1422 | /* This document is showing the index page. */ | ||
1423 | iRoot *other = otherRoot_Window(win, w->root); | ||
1424 | postCommandf_Root(other, "open url:%s", cstr_String(navStart)); | ||
1425 | if (prefs_App()->pinSplit == 1 && w->root == win->roots[1]) { | ||
1426 | /* On the wrong side. */ | ||
1427 | postCommand_App("ui.split swap:1"); | ||
1428 | } | ||
1429 | } | ||
1430 | else { | ||
1431 | postCommandf_App( | ||
1432 | "open newtab:%d url:%s", otherRoot_OpenTabFlag, cstr_String(navStart)); | ||
1433 | } | ||
1416 | } | 1434 | } |
1417 | } | 1435 | } |
1418 | } | 1436 | } |
1419 | } | 1437 | } |
1438 | /* Local fontpacks are automatically shown. */ | ||
1439 | if (preloadLocalFontpackForPreview_Fonts(d->doc)) { | ||
1440 | documentRunsInvalidated_DocumentWidget_(d); | ||
1441 | redoLayout_GmDocument(d->doc); | ||
1442 | updateVisible_DocumentWidget_(d); | ||
1443 | invalidate_DocumentWidget_(d); | ||
1444 | } | ||
1420 | } | 1445 | } |
1421 | 1446 | ||
1422 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, | 1447 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, |
@@ -1484,7 +1509,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1484 | } | 1509 | } |
1485 | delete_String(localPath); | 1510 | delete_String(localPath); |
1486 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { | 1511 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { |
1487 | appendFormat_String(&str, "=> %s/ ${doc.archive.view}\n", | 1512 | appendFormat_String(&str, "=> %s/ " folder_Icon " ${doc.archive.view}\n", |
1488 | cstr_String(withSpacesEncoded_String(d->mod.url))); | 1513 | cstr_String(withSpacesEncoded_String(d->mod.url))); |
1489 | } | 1514 | } |
1490 | translate_Lang(&str); | 1515 | translate_Lang(&str); |
@@ -2089,7 +2114,7 @@ static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId, | |||
2089 | } | 2114 | } |
2090 | 2115 | ||
2091 | static iBool isDownloadRequest_DocumentWidget(const iDocumentWidget *d, const iMediaRequest *req) { | 2116 | static iBool isDownloadRequest_DocumentWidget(const iDocumentWidget *d, const iMediaRequest *req) { |
2092 | return findLinkDownload_Media(constMedia_GmDocument(d->doc), req->linkId) != 0; | 2117 | return findMediaForLink_Media(constMedia_GmDocument(d->doc), req->linkId, download_MediaType).type != 0; |
2093 | } | 2118 | } |
2094 | 2119 | ||
2095 | static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 2120 | static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
@@ -2174,7 +2199,7 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { | |||
2174 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { | 2199 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { |
2175 | iConstForEach(PtrArray, i, &d->visibleLinks) { | 2200 | iConstForEach(PtrArray, i, &d->visibleLinks) { |
2176 | const iGmRun *run = i.ptr; | 2201 | const iGmRun *run = i.ptr; |
2177 | if (run->linkId && run->mediaType == none_GmRunMediaType && | 2202 | if (run->linkId && run->mediaType == none_MediaType && |
2178 | ~run->flags & decoration_GmRunFlag) { | 2203 | ~run->flags & decoration_GmRunFlag) { |
2179 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); | 2204 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); |
2180 | if (isMediaLink_GmDocument(d->doc, run->linkId) && | 2205 | if (isMediaLink_GmDocument(d->doc, run->linkId) && |
@@ -2763,8 +2788,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2763 | else if (equalWidget_Command(cmd, w, "document.downloadlink")) { | 2788 | else if (equalWidget_Command(cmd, w, "document.downloadlink")) { |
2764 | if (d->contextLink) { | 2789 | if (d->contextLink) { |
2765 | const iGmLinkId linkId = d->contextLink->linkId; | 2790 | const iGmLinkId linkId = d->contextLink->linkId; |
2766 | setDownloadUrl_Media( | 2791 | setUrl_Media(media_GmDocument(d->doc), |
2767 | media_GmDocument(d->doc), linkId, linkUrl_GmDocument(d->doc, linkId)); | 2792 | linkId, |
2793 | download_MediaType, | ||
2794 | linkUrl_GmDocument(d->doc, linkId)); | ||
2768 | requestMedia_DocumentWidget_(d, linkId, iFalse /* no filters */); | 2795 | requestMedia_DocumentWidget_(d, linkId, iFalse /* no filters */); |
2769 | redoLayout_GmDocument(d->doc); /* inline downloader becomes visible */ | 2796 | redoLayout_GmDocument(d->doc); /* inline downloader becomes visible */ |
2770 | updateVisible_DocumentWidget_(d); | 2797 | updateVisible_DocumentWidget_(d); |
@@ -2874,7 +2901,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2874 | const iMedia * media = media_GmDocument(d->doc); | 2901 | const iMedia * media = media_GmDocument(d->doc); |
2875 | const size_t num = numAudio_Media(media); | 2902 | const size_t num = numAudio_Media(media); |
2876 | for (size_t id = 1; id <= num; id++) { | 2903 | for (size_t id = 1; id <= num; id++) { |
2877 | iPlayer *plr = audioPlayer_Media(media, id); | 2904 | iPlayer *plr = audioPlayer_Media(media, (iMediaId){ audio_MediaType, id }); |
2878 | if (plr != startedPlr) { | 2905 | if (plr != startedPlr) { |
2879 | setPaused_Player(plr, iTrue); | 2906 | setPaused_Player(plr, iTrue); |
2880 | } | 2907 | } |
@@ -3212,8 +3239,8 @@ static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run | |||
3212 | } | 3239 | } |
3213 | 3240 | ||
3214 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { | 3241 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { |
3215 | if (run && run->mediaType == audio_GmRunMediaType) { | 3242 | if (run && run->mediaType == audio_MediaType) { |
3216 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 3243 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
3217 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); | 3244 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); |
3218 | d->grabbedStartVolume = volume_Player(plr); | 3245 | d->grabbedStartVolume = volume_Player(plr); |
3219 | d->grabbedPlayer = run; | 3246 | d->grabbedPlayer = run; |
@@ -3221,7 +3248,7 @@ static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *r | |||
3221 | } | 3248 | } |
3222 | else if (d->grabbedPlayer) { | 3249 | else if (d->grabbedPlayer) { |
3223 | setFlags_Player( | 3250 | setFlags_Player( |
3224 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId), | 3251 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(d->grabbedPlayer)), |
3225 | volumeGrabbed_PlayerFlag, | 3252 | volumeGrabbed_PlayerFlag, |
3226 | iFalse); | 3253 | iFalse); |
3227 | d->grabbedPlayer = NULL; | 3254 | d->grabbedPlayer = NULL; |
@@ -3249,11 +3276,21 @@ static iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev | |||
3249 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); | 3276 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); |
3250 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 3277 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
3251 | const iGmRun *run = i.ptr; | 3278 | const iGmRun *run = i.ptr; |
3252 | if (run->mediaType != audio_GmRunMediaType) { | 3279 | if (run->mediaType == fontpack_MediaType) { |
3280 | iFontpackUI ui; | ||
3281 | init_FontpackUI(&ui, media_GmDocument(d->doc), run->mediaId, | ||
3282 | runRect_DocumentWidget_(d, run)); | ||
3283 | if (processEvent_FontpackUI(&ui, ev)) { | ||
3284 | refresh_Widget(d); | ||
3285 | return iTrue; | ||
3286 | } | ||
3287 | } | ||
3288 | if (run->mediaType != audio_MediaType) { | ||
3253 | continue; | 3289 | continue; |
3254 | } | 3290 | } |
3291 | /* TODO: move this to mediaui.c */ | ||
3255 | const iRect rect = runRect_DocumentWidget_(d, run); | 3292 | const iRect rect = runRect_DocumentWidget_(d, run); |
3256 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 3293 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
3257 | if (contains_Rect(rect, mouse)) { | 3294 | if (contains_Rect(rect, mouse)) { |
3258 | iPlayerUI ui; | 3295 | iPlayerUI ui; |
3259 | init_PlayerUI(&ui, plr, rect); | 3296 | init_PlayerUI(&ui, plr, rect); |
@@ -3633,7 +3670,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3633 | cstr_String(linkUrl)) }, | 3670 | cstr_String(linkUrl)) }, |
3634 | }, | 3671 | }, |
3635 | 3); | 3672 | 3); |
3636 | if (isNative && d->contextLink->mediaType != download_GmRunMediaType) { | 3673 | if (isNative && d->contextLink->mediaType != download_MediaType) { |
3637 | pushBackN_Array(&items, (iMenuItem[]){ | 3674 | pushBackN_Array(&items, (iMenuItem[]){ |
3638 | { "---" }, | 3675 | { "---" }, |
3639 | { download_Icon " ${link.download}", 0, 0, "document.downloadlink" }, | 3676 | { download_Icon " ${link.download}", 0, 0, "document.downloadlink" }, |
@@ -3641,7 +3678,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3641 | } | 3678 | } |
3642 | iMediaRequest *mediaReq; | 3679 | iMediaRequest *mediaReq; |
3643 | if ((mediaReq = findMediaRequest_DocumentWidget_(d, d->contextLink->linkId)) != NULL && | 3680 | if ((mediaReq = findMediaRequest_DocumentWidget_(d, d->contextLink->linkId)) != NULL && |
3644 | d->contextLink->mediaType != download_GmRunMediaType) { | 3681 | d->contextLink->mediaType != download_MediaType) { |
3645 | if (isFinished_GmRequest(mediaReq->req)) { | 3682 | if (isFinished_GmRequest(mediaReq->req)) { |
3646 | pushBack_Array(&items, | 3683 | pushBack_Array(&items, |
3647 | &(iMenuItem){ download_Icon " " saveToDownloads_Label, | 3684 | &(iMenuItem){ download_Icon " " saveToDownloads_Label, |
@@ -3763,7 +3800,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3763 | case drag_ClickResult: { | 3800 | case drag_ClickResult: { |
3764 | if (d->grabbedPlayer) { | 3801 | if (d->grabbedPlayer) { |
3765 | iPlayer *plr = | 3802 | iPlayer *plr = |
3766 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId); | 3803 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(d->grabbedPlayer)); |
3767 | iPlayerUI ui; | 3804 | iPlayerUI ui; |
3768 | init_PlayerUI(&ui, plr, runRect_DocumentWidget_(d, d->grabbedPlayer)); | 3805 | init_PlayerUI(&ui, plr, runRect_DocumentWidget_(d, d->grabbedPlayer)); |
3769 | float off = (float) delta_Click(&d->click).x / (float) width_Rect(ui.volumeSlider); | 3806 | float off = (float) delta_Click(&d->click).x / (float) width_Rect(ui.volumeSlider); |
@@ -3883,8 +3920,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3883 | } | 3920 | } |
3884 | if (d->hoverLink) { | 3921 | if (d->hoverLink) { |
3885 | /* TODO: Move this to a method. */ | 3922 | /* TODO: Move this to a method. */ |
3886 | const iGmLinkId linkId = d->hoverLink->linkId; | 3923 | const iGmLinkId linkId = d->hoverLink->linkId; |
3887 | const int linkFlags = linkFlags_GmDocument(d->doc, linkId); | 3924 | const iMediaId linkMedia = mediaId_GmRun(d->hoverLink); |
3925 | const int linkFlags = linkFlags_GmDocument(d->doc, linkId); | ||
3888 | iAssert(linkId); | 3926 | iAssert(linkId); |
3889 | /* Media links are opened inline by default. */ | 3927 | /* Media links are opened inline by default. */ |
3890 | if (isMediaLink_GmDocument(d->doc, linkId)) { | 3928 | if (isMediaLink_GmDocument(d->doc, linkId)) { |
@@ -3937,6 +3975,12 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3937 | } | 3975 | } |
3938 | refresh_Widget(w); | 3976 | refresh_Widget(w); |
3939 | } | 3977 | } |
3978 | else if (linkMedia.type == download_MediaType || | ||
3979 | findMediaRequest_DocumentWidget_(d, linkId)) { | ||
3980 | /* TODO: What should be done when clicking on an inline download? | ||
3981 | Maybe dismiss if finished? */ | ||
3982 | return iTrue; | ||
3983 | } | ||
3940 | else if (linkFlags & supportedScheme_GmLinkFlag) { | 3984 | else if (linkFlags & supportedScheme_GmLinkFlag) { |
3941 | int tabMode = openTabMode_Sym(modState_Keys()); | 3985 | int tabMode = openTabMode_Sym(modState_Keys()); |
3942 | if (isPinned_DocumentWidget_(d)) { | 3986 | if (isPinned_DocumentWidget_(d)) { |
@@ -4071,7 +4115,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
4071 | 4115 | ||
4072 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { | 4116 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { |
4073 | iDrawContext *d = context; | 4117 | iDrawContext *d = context; |
4074 | if (run->mediaType == none_GmRunMediaType) { | 4118 | if (run->mediaType == none_MediaType) { |
4075 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); | 4119 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); |
4076 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); | 4120 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); |
4077 | } | 4121 | } |
@@ -4178,8 +4222,8 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4178 | d->runsDrawn.end = run; | 4222 | d->runsDrawn.end = run; |
4179 | } | 4223 | } |
4180 | } | 4224 | } |
4181 | if (run->mediaType == image_GmRunMediaType) { | 4225 | if (run->mediaType == image_MediaType) { |
4182 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), run->mediaId); | 4226 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), mediaId_GmRun(run)); |
4183 | const iRect dst = moved_Rect(run->visBounds, origin); | 4227 | const iRect dst = moved_Rect(run->visBounds, origin); |
4184 | if (tex) { | 4228 | if (tex) { |
4185 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ | 4229 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ |
@@ -4334,31 +4378,31 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4334 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); | 4378 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); |
4335 | iString text; | 4379 | iString text; |
4336 | init_String(&text); | 4380 | init_String(&text); |
4337 | iMediaId imageId = linkImage_GmDocument(doc, run->linkId); | 4381 | const iMediaId linkMedia = findMediaForLink_Media(constMedia_GmDocument(doc), |
4338 | iMediaId audioId = !imageId ? linkAudio_GmDocument(doc, run->linkId) : 0; | 4382 | run->linkId, none_MediaType); |
4339 | iMediaId downloadId = !imageId && !audioId ? | 4383 | iAssert(linkMedia.type != none_MediaType); |
4340 | findLinkDownload_Media(constMedia_GmDocument(doc), run->linkId) : 0; | 4384 | iGmMediaInfo info; |
4341 | iAssert(imageId || audioId || downloadId); | 4385 | info_Media(constMedia_GmDocument(doc), linkMedia, &info); |
4342 | if (imageId) { | 4386 | switch (linkMedia.type) { |
4343 | iAssert(!isEmpty_Rect(run->bounds)); | 4387 | case image_MediaType: { |
4344 | iGmMediaInfo info; | 4388 | iAssert(!isEmpty_Rect(run->bounds)); |
4345 | imageInfo_Media(constMedia_GmDocument(doc), imageId, &info); | 4389 | const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), linkMedia); |
4346 | const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), imageId); | 4390 | format_String(&text, "%s \u2014 %d x %d \u2014 %.1f%s", |
4347 | format_String(&text, "%s \u2014 %d x %d \u2014 %.1f%s", | 4391 | info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f, |
4348 | info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f, | 4392 | cstr_Lang("mb")); |
4349 | cstr_Lang("mb")); | 4393 | break; |
4350 | } | 4394 | } |
4351 | else if (audioId) { | 4395 | case audio_MediaType: |
4352 | iGmMediaInfo info; | 4396 | format_String(&text, "%s", info.type); |
4353 | audioInfo_Media(constMedia_GmDocument(doc), audioId, &info); | 4397 | break; |
4354 | format_String(&text, "%s", info.type); | 4398 | case download_MediaType: |
4355 | } | 4399 | format_String(&text, "%s", info.type); |
4356 | else if (downloadId) { | 4400 | break; |
4357 | iGmMediaInfo info; | 4401 | default: |
4358 | downloadInfo_Media(constMedia_GmDocument(doc), downloadId, &info); | 4402 | break; |
4359 | format_String(&text, "%s", info.type); | ||
4360 | } | 4403 | } |
4361 | if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { | 4404 | if (linkMedia.type != download_MediaType && /* can't cancel downloads currently */ |
4405 | findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { | ||
4362 | appendFormat_String( | 4406 | appendFormat_String( |
4363 | &text, " %s" close_Icon, isHover ? escape_Color(tmLinkText_ColorId) : ""); | 4407 | &text, " %s" close_Icon, isHover ? escape_Color(tmLinkText_ColorId) : ""); |
4364 | } | 4408 | } |
@@ -4589,18 +4633,25 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
4589 | static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { | 4633 | static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { |
4590 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 4634 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
4591 | const iGmRun * run = i.ptr; | 4635 | const iGmRun * run = i.ptr; |
4592 | if (run->mediaType == audio_GmRunMediaType) { | 4636 | if (run->mediaType == audio_MediaType) { |
4593 | iPlayerUI ui; | 4637 | iPlayerUI ui; |
4594 | init_PlayerUI(&ui, | 4638 | init_PlayerUI(&ui, |
4595 | audioPlayer_Media(media_GmDocument(d->doc), run->mediaId), | 4639 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)), |
4596 | runRect_DocumentWidget_(d, run)); | 4640 | runRect_DocumentWidget_(d, run)); |
4597 | draw_PlayerUI(&ui, p); | 4641 | draw_PlayerUI(&ui, p); |
4598 | } | 4642 | } |
4599 | else if (run->mediaType == download_GmRunMediaType) { | 4643 | else if (run->mediaType == download_MediaType) { |
4600 | iDownloadUI ui; | 4644 | iDownloadUI ui; |
4601 | init_DownloadUI(&ui, d, run->mediaId, runRect_DocumentWidget_(d, run)); | 4645 | init_DownloadUI(&ui, constMedia_GmDocument(d->doc), run->mediaId, |
4646 | runRect_DocumentWidget_(d, run)); | ||
4602 | draw_DownloadUI(&ui, p); | 4647 | draw_DownloadUI(&ui, p); |
4603 | } | 4648 | } |
4649 | else if (run->mediaType == fontpack_MediaType) { | ||
4650 | iFontpackUI ui; | ||
4651 | init_FontpackUI(&ui, constMedia_GmDocument(d->doc), run->mediaId, | ||
4652 | runRect_DocumentWidget_(d, run)); | ||
4653 | draw_FontpackUI(&ui, p); | ||
4654 | } | ||
4604 | } | 4655 | } |
4605 | } | 4656 | } |
4606 | 4657 | ||