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 | |
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')
-rw-r--r-- | src/ui/documentwidget.c | 429 | ||||
-rw-r--r-- | src/ui/documentwidget.h | 2 | ||||
-rw-r--r-- | src/ui/mediaui.c | 88 | ||||
-rw-r--r-- | src/ui/mediaui.h | 20 |
4 files changed, 338 insertions, 201 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 | ||
diff --git a/src/ui/documentwidget.h b/src/ui/documentwidget.h index cc09c72d..1f2ecfc0 100644 --- a/src/ui/documentwidget.h +++ b/src/ui/documentwidget.h | |||
@@ -32,6 +32,8 @@ iDeclareType(History) | |||
32 | iDeclareWidgetClass(DocumentWidget) | 32 | iDeclareWidgetClass(DocumentWidget) |
33 | iDeclareObjectConstruction(DocumentWidget) | 33 | iDeclareObjectConstruction(DocumentWidget) |
34 | 34 | ||
35 | void cancelAllRequests_DocumentWidget(iDocumentWidget *); | ||
36 | |||
35 | void serializeState_DocumentWidget (const iDocumentWidget *, iStream *outs); | 37 | void serializeState_DocumentWidget (const iDocumentWidget *, iStream *outs); |
36 | void deserializeState_DocumentWidget (iDocumentWidget *, iStream *ins); | 38 | void deserializeState_DocumentWidget (iDocumentWidget *, iStream *ins); |
37 | 39 | ||
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c index 22552027..aa45d73a 100644 --- a/src/ui/mediaui.c +++ b/src/ui/mediaui.c | |||
@@ -30,6 +30,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
30 | #include "lang.h" | 30 | #include "lang.h" |
31 | 31 | ||
32 | #include <the_Foundation/path.h> | 32 | #include <the_Foundation/path.h> |
33 | #include <the_Foundation/stringlist.h> | ||
33 | 34 | ||
34 | static const char *volumeChar_(float volume) { | 35 | static const char *volumeChar_(float volume) { |
35 | if (volume <= 0) { | 36 | if (volume <= 0) { |
@@ -61,7 +62,7 @@ void init_PlayerUI(iPlayerUI *d, const iPlayer *player, iRect bounds) { | |||
61 | } | 62 | } |
62 | } | 63 | } |
63 | 64 | ||
64 | static void drawPlayerButton_(iPaint *p, iRect rect, const char *label, int font) { | 65 | static void drawInlineButton_(iPaint *p, iRect rect, const char *label, int font) { |
65 | const iInt2 mouse = mouseCoord_Window(get_Window(), 0); | 66 | const iInt2 mouse = mouseCoord_Window(get_Window(), 0); |
66 | const iBool isHover = contains_Rect(rect, mouse); | 67 | const iBool isHover = contains_Rect(rect, mouse); |
67 | const iBool isPressed = isHover && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT) != 0; | 68 | const iBool isPressed = isHover && (SDL_GetMouseState(NULL, NULL) & SDL_BUTTON_LEFT) != 0; |
@@ -113,14 +114,14 @@ void draw_PlayerUI(iPlayerUI *d, iPaint *p) { | |||
113 | const iBool isAdjusting = (flags_Player(d->player) & adjustingVolume_PlayerFlag) != 0; | 114 | const iBool isAdjusting = (flags_Player(d->player) & adjustingVolume_PlayerFlag) != 0; |
114 | fillRect_Paint(p, d->bounds, playerBackground_ColorId); | 115 | fillRect_Paint(p, d->bounds, playerBackground_ColorId); |
115 | drawRect_Paint(p, d->bounds, playerFrame_ColorId); | 116 | drawRect_Paint(p, d->bounds, playerFrame_ColorId); |
116 | drawPlayerButton_(p, | 117 | drawInlineButton_(p, |
117 | d->playPauseRect, | 118 | d->playPauseRect, |
118 | isPaused_Player(d->player) ? "\U0001f782" : "\u23f8", | 119 | isPaused_Player(d->player) ? "\U0001f782" : "\u23f8", |
119 | uiContent_FontId); | 120 | uiContent_FontId); |
120 | drawPlayerButton_(p, d->rewindRect, "\u23ee", uiContent_FontId); | 121 | drawInlineButton_(p, d->rewindRect, "\u23ee", uiContent_FontId); |
121 | drawPlayerButton_(p, d->menuRect, menu_Icon, uiContent_FontId); | 122 | drawInlineButton_(p, d->menuRect, menu_Icon, uiContent_FontId); |
122 | if (!isAdjusting) { | 123 | if (!isAdjusting) { |
123 | drawPlayerButton_( | 124 | drawInlineButton_( |
124 | p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId); | 125 | p, d->volumeRect, volumeChar_(volume_Player(d->player)), uiContentSymbols_FontId); |
125 | } | 126 | } |
126 | const int hgt = lineHeight_Text(uiLabelBig_FontId); | 127 | const int hgt = lineHeight_Text(uiLabelBig_FontId); |
@@ -228,24 +229,26 @@ static void drawSevenSegmentBytes_(iInt2 pos, int color, size_t numBytes) { | |||
228 | deinit_String(&digits); | 229 | deinit_String(&digits); |
229 | } | 230 | } |
230 | 231 | ||
231 | void init_DownloadUI(iDownloadUI *d, const iDocumentWidget *doc, uint16_t mediaId, iRect bounds) { | 232 | void init_DownloadUI(iDownloadUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) { |
232 | d->doc = doc; | 233 | d->media = media; |
233 | d->mediaId = mediaId; | 234 | d->mediaId = mediaId; |
234 | d->bounds = bounds; | 235 | d->bounds = bounds; |
235 | } | 236 | } |
236 | 237 | ||
238 | /*----------------------------------------------------------------------------------------------*/ | ||
239 | |||
237 | iBool processEvent_DownloadUI(iDownloadUI *d, const SDL_Event *ev) { | 240 | iBool processEvent_DownloadUI(iDownloadUI *d, const SDL_Event *ev) { |
238 | return iFalse; | 241 | return iFalse; |
239 | } | 242 | } |
240 | 243 | ||
241 | void draw_DownloadUI(const iDownloadUI *d, iPaint *p) { | 244 | void draw_DownloadUI(const iDownloadUI *d, iPaint *p) { |
242 | const iMedia *media = constMedia_GmDocument(document_DocumentWidget(d->doc)); | ||
243 | iGmMediaInfo info; | 245 | iGmMediaInfo info; |
244 | float bytesPerSecond; | 246 | float bytesPerSecond; |
245 | const iString *path; | 247 | const iString *path; |
246 | iBool isFinished; | 248 | iBool isFinished; |
247 | downloadInfo_Media(media, d->mediaId, &info); | 249 | downloadInfo_Media(d->media, d->mediaId, &info); |
248 | downloadStats_Media(media, d->mediaId, &path, &bytesPerSecond, &isFinished); | 250 | downloadStats_Media(d->media, (iMediaId){ download_MediaType, d->mediaId }, |
251 | &path, &bytesPerSecond, &isFinished); | ||
249 | fillRect_Paint(p, d->bounds, uiBackground_ColorId); | 252 | fillRect_Paint(p, d->bounds, uiBackground_ColorId); |
250 | drawRect_Paint(p, d->bounds, uiSeparator_ColorId); | 253 | drawRect_Paint(p, d->bounds, uiSeparator_ColorId); |
251 | iRect rect = d->bounds; | 254 | iRect rect = d->bounds; |
@@ -275,3 +278,68 @@ void draw_DownloadUI(const iDownloadUI *d, iPaint *p) { | |||
275 | translateCStr_Lang("\u2014 ${mb.per.sec}")); | 278 | translateCStr_Lang("\u2014 ${mb.per.sec}")); |
276 | } | 279 | } |
277 | } | 280 | } |
281 | |||
282 | /*----------------------------------------------------------------------------------------------*/ | ||
283 | |||
284 | void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) { | ||
285 | d->media = media; | ||
286 | d->mediaId = mediaId; | ||
287 | d->bounds = bounds; | ||
288 | d->installRect.size = add_I2(measure_Text(uiLabel_FontId, "${media.fontpack.install}").bounds.size, | ||
289 | muli_I2(gap2_UI, 3)); | ||
290 | d->installRect.pos.x = right_Rect(d->bounds) - gap_UI - d->installRect.size.x; | ||
291 | d->installRect.pos.y = mid_Rect(d->bounds).y - d->installRect.size.y / 2; | ||
292 | } | ||
293 | |||
294 | iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) { | ||
295 | switch (ev->type) { | ||
296 | case SDL_MOUSEBUTTONDOWN: | ||
297 | case SDL_MOUSEBUTTONUP: { | ||
298 | const iInt2 pos = init_I2(ev->button.x, ev->button.y); | ||
299 | if (contains_Rect(d->installRect, pos)) { | ||
300 | return iTrue; | ||
301 | } | ||
302 | break; | ||
303 | } | ||
304 | case SDL_MOUSEMOTION: | ||
305 | if (contains_Rect(d->bounds, init_I2(ev->motion.x, ev->motion.y))) { | ||
306 | return iTrue; | ||
307 | } | ||
308 | break; | ||
309 | } | ||
310 | return iFalse; | ||
311 | } | ||
312 | |||
313 | int height_FontpackUI(const iMedia *media, uint16_t mediaId, int width) { | ||
314 | const iStringList *names; | ||
315 | iFontpackMediaInfo info; | ||
316 | fontpackInfo_Media(media, (iMediaId){ fontpack_MediaType, mediaId }, &info); | ||
317 | return lineHeight_Text(uiContent_FontId) + | ||
318 | lineHeight_Text(uiLabel_FontId) * (1 + size_StringList(info.names)); | ||
319 | } | ||
320 | |||
321 | void draw_FontpackUI(const iFontpackUI *d, iPaint *p) { | ||
322 | /* Draw a background box. */ | ||
323 | fillRect_Paint(p, d->bounds, uiBackground_ColorId); | ||
324 | drawRect_Paint(p, d->bounds, uiSeparator_ColorId); | ||
325 | iFontpackMediaInfo info; | ||
326 | fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &info); | ||
327 | iInt2 pos = topLeft_Rect(d->bounds); | ||
328 | const char *checks[] = { "\u2610", "\u2611" }; | ||
329 | draw_Text(uiContentBold_FontId, pos, uiHeading_ColorId, "\"%s\" v%d", | ||
330 | cstr_String(info.packId.id), info.packId.version); | ||
331 | pos.y += lineHeight_Text(uiContentBold_FontId); | ||
332 | draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s", | ||
333 | info.sizeInBytes / 1.0e6, size_StringList(info.names), | ||
334 | // checks[info.isValid], info.isValid ? "No errors" : "Errors detected", | ||
335 | checks[info.isInstalled], info.isInstalled ? "Installed" : "Not installed", | ||
336 | info.isReadOnly ? "Read-Only" : ""); | ||
337 | pos.y += lineHeight_Text(uiLabelBold_FontId); | ||
338 | iConstForEach(StringList, i, info.names) { | ||
339 | drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value)); | ||
340 | pos.y += lineHeight_Text(uiLabel_FontId); | ||
341 | } | ||
342 | /* Buttons. */ | ||
343 | drawInlineButton_(p, d->installRect, | ||
344 | "${media.fontpack.install}", uiLabel_FontId); | ||
345 | } | ||
diff --git a/src/ui/mediaui.h b/src/ui/mediaui.h index e79dedc0..73de1994 100644 --- a/src/ui/mediaui.h +++ b/src/ui/mediaui.h | |||
@@ -51,11 +51,27 @@ iDeclareType(Media) | |||
51 | iDeclareType(DownloadUI) | 51 | iDeclareType(DownloadUI) |
52 | 52 | ||
53 | struct Impl_DownloadUI { | 53 | struct Impl_DownloadUI { |
54 | const iDocumentWidget *doc; | 54 | const iMedia *media; |
55 | uint16_t mediaId; | 55 | uint16_t mediaId; |
56 | iRect bounds; | 56 | iRect bounds; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | void init_DownloadUI (iDownloadUI *, const iDocumentWidget *doc, uint16_t mediaId, iRect bounds); | 59 | void init_DownloadUI (iDownloadUI *, const iMedia *media, uint16_t mediaId, iRect bounds); |
60 | iBool processEvent_DownloadUI (iDownloadUI *, const SDL_Event *ev); | 60 | iBool processEvent_DownloadUI (iDownloadUI *, const SDL_Event *ev); |
61 | void draw_DownloadUI (const iDownloadUI *, iPaint *p); | 61 | void draw_DownloadUI (const iDownloadUI *, iPaint *p); |
62 | |||
63 | /*----------------------------------------------------------------------------------------------*/ | ||
64 | |||
65 | iDeclareType(FontpackUI) | ||
66 | |||
67 | struct Impl_FontpackUI { | ||
68 | const iMedia *media; | ||
69 | uint16_t mediaId; | ||
70 | iRect bounds; | ||
71 | iRect installRect; | ||
72 | }; | ||
73 | |||
74 | void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds); | ||
75 | int height_FontpackUI (const iMedia *media, uint16_t mediaId, int width); | ||
76 | iBool processEvent_FontpackUI (iFontpackUI *, const SDL_Event *ev); | ||
77 | void draw_FontpackUI (const iFontpackUI *, iPaint *p); | ||