diff options
Diffstat (limited to 'src/ui')
-rw-r--r-- | src/ui/color.c | 7 | ||||
-rw-r--r-- | src/ui/color.h | 2 | ||||
-rw-r--r-- | src/ui/command.h | 4 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 483 | ||||
-rw-r--r-- | src/ui/documentwidget.h | 2 | ||||
-rw-r--r-- | src/ui/labelwidget.c | 4 | ||||
-rw-r--r-- | src/ui/mediaui.c | 92 | ||||
-rw-r--r-- | src/ui/mediaui.h | 20 | ||||
-rw-r--r-- | src/ui/mobile.c | 8 | ||||
-rw-r--r-- | src/ui/root.c | 16 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 18 | ||||
-rw-r--r-- | src/ui/text.c | 397 | ||||
-rw-r--r-- | src/ui/text.h | 145 | ||||
-rw-r--r-- | src/ui/uploadwidget.c | 2 | ||||
-rw-r--r-- | src/ui/util.c | 169 | ||||
-rw-r--r-- | src/ui/widget.c | 3 | ||||
-rw-r--r-- | src/ui/window.c | 8 |
17 files changed, 794 insertions, 586 deletions
diff --git a/src/ui/color.c b/src/ui/color.c index 4f275ae5..0f7d4368 100644 --- a/src/ui/color.c +++ b/src/ui/color.c | |||
@@ -309,9 +309,10 @@ void setThemePalette_Color(enum iColorTheme theme) { | |||
309 | setHsl_Color(uiBackgroundFolder_ColorId, | 309 | setHsl_Color(uiBackgroundFolder_ColorId, |
310 | addSatLum_HSLColor(get_HSLColor(uiBackgroundSidebar_ColorId), | 310 | addSatLum_HSLColor(get_HSLColor(uiBackgroundSidebar_ColorId), |
311 | 0, | 311 | 0, |
312 | theme == pureBlack_ColorTheme ? -1 | 312 | theme == pureBlack_ColorTheme ? -1 |
313 | : theme == dark_ColorTheme ? -0.04 | 313 | : theme == dark_ColorTheme ? -0.04 |
314 | : -0.075)); | 314 | : theme == pureWhite_ColorTheme ? -0.04 |
315 | : -0.055)); | ||
315 | set_Color(uiTextShortcut_ColorId, mix_Color(get_Color(uiTextShortcut_ColorId), | 316 | set_Color(uiTextShortcut_ColorId, mix_Color(get_Color(uiTextShortcut_ColorId), |
316 | get_Color(uiBackground_ColorId), | 317 | get_Color(uiBackground_ColorId), |
317 | 0.4f)); | 318 | 0.4f)); |
diff --git a/src/ui/color.h b/src/ui/color.h index 179db3e9..c9dff598 100644 --- a/src/ui/color.h +++ b/src/ui/color.h | |||
@@ -160,7 +160,7 @@ enum iColorId { | |||
160 | tmGopherLinkDomain_ColorId, | 160 | tmGopherLinkDomain_ColorId, |
161 | tmGopherLinkLastVisitDate_ColorId, | 161 | tmGopherLinkLastVisitDate_ColorId, |
162 | 162 | ||
163 | max_ColorId, | 163 | max_ColorId, /* note: GmRun packs color into limited number of bits */ |
164 | tmMax_ColorId = max_ColorId - tmFirst_ColorId | 164 | tmMax_ColorId = max_ColorId - tmFirst_ColorId |
165 | }; | 165 | }; |
166 | 166 | ||
diff --git a/src/ui/command.h b/src/ui/command.h index 8dbaafad..8dcae892 100644 --- a/src/ui/command.h +++ b/src/ui/command.h | |||
@@ -23,6 +23,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
23 | #pragma once | 23 | #pragma once |
24 | 24 | ||
25 | #include <the_Foundation/range.h> | 25 | #include <the_Foundation/range.h> |
26 | #include <the_Foundation/string.h> | ||
26 | #include <the_Foundation/vec2.h> | 27 | #include <the_Foundation/vec2.h> |
27 | 28 | ||
28 | iBool equal_Command (const char *commandWithArgs, const char *command); | 29 | iBool equal_Command (const char *commandWithArgs, const char *command); |
@@ -45,3 +46,6 @@ iString * suffix_Command (const char *, const char *label); /* until | |||
45 | iLocalDef iBool hasLabel_Command(const char *d, const char *label) { | 46 | iLocalDef iBool hasLabel_Command(const char *d, const char *label) { |
46 | return suffixPtr_Command(d, label) != NULL; | 47 | return suffixPtr_Command(d, label) != NULL; |
47 | } | 48 | } |
49 | iLocalDef const char *cstr_Command(const char *d, const char *label) { | ||
50 | return cstr_Rangecc(range_Command(d, label)); | ||
51 | } | ||
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 93b2166b..ee669c1a 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); |
@@ -496,7 +507,8 @@ static int documentWidth_DocumentWidget_(const iDocumentWidget *d) { | |||
496 | -1.0f, 10.0f); /* adapt to width */ | 507 | -1.0f, 10.0f); /* adapt to width */ |
497 | //printf("%f\n", adjust); fflush(stdout); | 508 | //printf("%f\n", adjust); fflush(stdout); |
498 | return iMini(iMax(minWidth, bounds.size.x - gap_UI * (d->pageMargin + adjust) * 2), | 509 | return iMini(iMax(minWidth, bounds.size.x - gap_UI * (d->pageMargin + adjust) * 2), |
499 | fontSize_UI * prefs->lineWidth * prefs->zoomPercent / 100); | 510 | fontSize_UI * //emRatio_Text(paragraph_FontId) * /* dependent on avg. glyph width */ |
511 | prefs->lineWidth * prefs->zoomPercent / 100); | ||
500 | } | 512 | } |
501 | 513 | ||
502 | static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { | 514 | static iRect documentBounds_DocumentWidget_(const iDocumentWidget *d) { |
@@ -563,7 +575,8 @@ static void addVisible_DocumentWidget_(void *context, const iGmRun *run) { | |||
563 | pushBack_PtrArray(&d->visibleWideRuns, run); | 575 | pushBack_PtrArray(&d->visibleWideRuns, run); |
564 | } | 576 | } |
565 | } | 577 | } |
566 | 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) { | ||
567 | iAssert(run->mediaId); | 580 | iAssert(run->mediaId); |
568 | pushBack_PtrArray(&d->visibleMedia, run); | 581 | pushBack_PtrArray(&d->visibleMedia, run); |
569 | } | 582 | } |
@@ -757,14 +770,14 @@ static uint32_t mediaUpdateInterval_DocumentWidget_(const iDocumentWidget *d) { | |||
757 | uint32_t interval = invalidInterval_; | 770 | uint32_t interval = invalidInterval_; |
758 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 771 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
759 | const iGmRun *run = i.ptr; | 772 | const iGmRun *run = i.ptr; |
760 | if (run->mediaType == audio_GmRunMediaType) { | 773 | if (run->mediaType == audio_MediaType) { |
761 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 774 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
762 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || | 775 | if (flags_Player(plr) & adjustingVolume_PlayerFlag || |
763 | (isStarted_Player(plr) && !isPaused_Player(plr))) { | 776 | (isStarted_Player(plr) && !isPaused_Player(plr))) { |
764 | interval = iMin(interval, 1000 / 15); | 777 | interval = iMin(interval, 1000 / 15); |
765 | } | 778 | } |
766 | } | 779 | } |
767 | else if (run->mediaType == download_GmRunMediaType) { | 780 | else if (run->mediaType == download_MediaType) { |
768 | interval = iMin(interval, 1000); | 781 | interval = iMin(interval, 1000); |
769 | } | 782 | } |
770 | } | 783 | } |
@@ -783,8 +796,8 @@ static void updateMedia_DocumentWidget_(iDocumentWidget *d) { | |||
783 | refresh_Widget(d); | 796 | refresh_Widget(d); |
784 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 797 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
785 | const iGmRun *run = i.ptr; | 798 | const iGmRun *run = i.ptr; |
786 | if (run->mediaType == audio_GmRunMediaType) { | 799 | if (run->mediaType == audio_MediaType) { |
787 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 800 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
788 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && | 801 | if (idleTimeMs_Player(plr) > 3000 && ~flags_Player(plr) & volumeGrabbed_PlayerFlag && |
789 | flags_Player(plr) & adjustingVolume_PlayerFlag) { | 802 | flags_Player(plr) & adjustingVolume_PlayerFlag) { |
790 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); | 803 | setFlags_Player(plr, adjustingVolume_PlayerFlag, iFalse); |
@@ -928,8 +941,9 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | |||
928 | pushBackCStr_StringArray(title, "Lagrange"); | 941 | pushBackCStr_StringArray(title, "Lagrange"); |
929 | } | 942 | } |
930 | /* Take away parts if it doesn't fit. */ | 943 | /* Take away parts if it doesn't fit. */ |
931 | const int avail = bounds_Widget(as_Widget(tabButton)).size.x - 3 * gap_UI; | 944 | const int avail = bounds_Widget(as_Widget(tabButton)).size.x - 3 * gap_UI; |
932 | iBool setWindow = (document_App() == d && isUnderKeyRoot_Widget(d)); | 945 | iBool setWindow = (document_App() == d && isUnderKeyRoot_Widget(d)); |
946 | const int font = uiLabel_FontId; | ||
933 | for (;;) { | 947 | for (;;) { |
934 | iString *text = collect_String(joinCStr_StringArray(title, " \u2014 ")); | 948 | iString *text = collect_String(joinCStr_StringArray(title, " \u2014 ")); |
935 | if (setWindow) { | 949 | if (setWindow) { |
@@ -945,7 +959,7 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | |||
945 | prependChar_String(text, siteIcon); | 959 | prependChar_String(text, siteIcon); |
946 | prependCStr_String(text, escape_Color(uiIcon_ColorId)); | 960 | prependCStr_String(text, escape_Color(uiIcon_ColorId)); |
947 | } | 961 | } |
948 | const int width = measureRange_Text(default_FontId, range_String(text)).advance.x; | 962 | const int width = measureRange_Text(font, range_String(text)).advance.x; |
949 | if (width <= avail || | 963 | if (width <= avail || |
950 | isEmpty_StringArray(title)) { | 964 | isEmpty_StringArray(title)) { |
951 | updateText_LabelWidget(tabButton, text); | 965 | updateText_LabelWidget(tabButton, text); |
@@ -954,9 +968,9 @@ static void updateWindowTitle_DocumentWidget_(const iDocumentWidget *d) { | |||
954 | if (size_StringArray(title) == 1) { | 968 | if (size_StringArray(title) == 1) { |
955 | /* Just truncate to fit. */ | 969 | /* Just truncate to fit. */ |
956 | const char *endPos; | 970 | const char *endPos; |
957 | tryAdvanceNoWrap_Text(default_FontId, | 971 | tryAdvanceNoWrap_Text(font, |
958 | range_String(text), | 972 | range_String(text), |
959 | avail - measure_Text(default_FontId, "...").advance.x, | 973 | avail - measure_Text(font, "...").advance.x, |
960 | &endPos); | 974 | &endPos); |
961 | updateText_LabelWidget( | 975 | updateText_LabelWidget( |
962 | tabButton, | 976 | tabButton, |
@@ -1242,6 +1256,9 @@ static const char *zipPageHeading_(const iRangecc mime) { | |||
1242 | if (equalCase_Rangecc(mime, "application/gpub+zip")) { | 1256 | if (equalCase_Rangecc(mime, "application/gpub+zip")) { |
1243 | return book_Icon " Gempub"; | 1257 | return book_Icon " Gempub"; |
1244 | } | 1258 | } |
1259 | else if (equalCase_Rangecc(mime, mimeType_FontPack)) { | ||
1260 | return "\U0001f520 Fontpack"; | ||
1261 | } | ||
1245 | iRangecc type = iNullRange; | 1262 | iRangecc type = iNullRange; |
1246 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ | 1263 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ |
1247 | nextSplit_Rangecc(mime, "/", &type); | 1264 | nextSplit_Rangecc(mime, "/", &type); |
@@ -1256,165 +1273,175 @@ static const char *zipPageHeading_(const iRangecc mime) { | |||
1256 | 1273 | ||
1257 | static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) { | 1274 | static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool isCached) { |
1258 | iWidget *w = as_Widget(d); | 1275 | iWidget *w = as_Widget(d); |
1259 | delete_Gempub(d->sourceGempub); | 1276 | /* Gempub page behavior and footer actions. */ { |
1260 | d->sourceGempub = NULL; | 1277 | /* TODO: move this to gempub.c */ |
1261 | if (!cmpCase_String(&d->sourceMime, "application/octet-stream") || | 1278 | delete_Gempub(d->sourceGempub); |
1262 | !cmpCase_String(&d->sourceMime, mimeType_Gempub) || | 1279 | d->sourceGempub = NULL; |
1263 | endsWithCase_String(d->mod.url, ".gpub")) { | 1280 | if (!cmpCase_String(&d->sourceMime, "application/octet-stream") || |
1264 | iGempub *gempub = new_Gempub(); | 1281 | !cmpCase_String(&d->sourceMime, mimeType_Gempub) || |
1265 | if (open_Gempub(gempub, &d->sourceContent)) { | 1282 | endsWithCase_String(d->mod.url, ".gpub")) { |
1266 | setBaseUrl_Gempub(gempub, d->mod.url); | ||
1267 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); | ||
1268 | setCStr_String(&d->sourceMime, mimeType_Gempub); | ||
1269 | d->sourceGempub = gempub; | ||
1270 | } | ||
1271 | else { | ||
1272 | delete_Gempub(gempub); | ||
1273 | } | ||
1274 | } | ||
1275 | if (!d->sourceGempub) { | ||
1276 | const iString *localPath = collect_String(localFilePathFromUrl_String(d->mod.url)); | ||
1277 | iBool isInside = iFalse; | ||
1278 | if (localPath && !fileExists_FileInfo(localPath)) { | ||
1279 | /* This URL may refer to a file inside the archive. */ | ||
1280 | localPath = findContainerArchive_Path(localPath); | ||
1281 | isInside = iTrue; | ||
1282 | } | ||
1283 | if (localPath && equal_CStr(mediaType_Path(localPath), "application/gpub+zip")) { | ||
1284 | iGempub *gempub = new_Gempub(); | 1283 | iGempub *gempub = new_Gempub(); |
1285 | if (openFile_Gempub(gempub, localPath)) { | 1284 | if (open_Gempub(gempub, &d->sourceContent)) { |
1286 | setBaseUrl_Gempub(gempub, collect_String(makeFileUrl_String(localPath))); | 1285 | setBaseUrl_Gempub(gempub, d->mod.url); |
1287 | if (!isInside) { | 1286 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); |
1288 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); | 1287 | setCStr_String(&d->sourceMime, mimeType_Gempub); |
1289 | setCStr_String(&d->sourceMime, mimeType_Gempub); | ||
1290 | } | ||
1291 | d->sourceGempub = gempub; | 1288 | d->sourceGempub = gempub; |
1292 | } | 1289 | } |
1293 | else { | 1290 | else { |
1294 | delete_Gempub(gempub); | 1291 | delete_Gempub(gempub); |
1295 | } | 1292 | } |
1296 | } | 1293 | } |
1297 | } | 1294 | if (!d->sourceGempub) { |
1298 | if (d->sourceGempub) { | 1295 | const iString *localPath = collect_String(localFilePathFromUrl_String(d->mod.url)); |
1299 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { | 1296 | iBool isInside = iFalse; |
1300 | if (!isRemote_Gempub(d->sourceGempub)) { | 1297 | if (localPath && !fileExists_FileInfo(localPath)) { |
1301 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | 1298 | /* This URL may refer to a file inside the archive. */ |
1302 | pushBack_Array( | 1299 | localPath = findContainerArchive_Path(localPath); |
1303 | items, | 1300 | isInside = iTrue; |
1304 | &(iMenuItem){ book_Icon " ${gempub.cover.view}", | ||
1305 | 0, | ||
1306 | 0, | ||
1307 | format_CStr("!open url:%s", | ||
1308 | cstr_String(indexPageUrl_Gempub(d->sourceGempub))) }); | ||
1309 | if (navSize_Gempub(d->sourceGempub) > 0) { | ||
1310 | pushBack_Array( | ||
1311 | items, | ||
1312 | &(iMenuItem){ | ||
1313 | format_CStr(forwardArrow_Icon " %s", | ||
1314 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, 0))), | ||
1315 | SDLK_RIGHT, | ||
1316 | 0, | ||
1317 | format_CStr("!open url:%s", | ||
1318 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, 0))) }); | ||
1319 | } | ||
1320 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); | ||
1321 | } | 1301 | } |
1322 | else { | 1302 | if (localPath && equal_CStr(mediaType_Path(localPath), mimeType_Gempub)) { |
1323 | makeFooterButtons_DocumentWidget_( | 1303 | iGempub *gempub = new_Gempub(); |
1324 | d, | 1304 | if (openFile_Gempub(gempub, localPath)) { |
1325 | (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", | 1305 | setBaseUrl_Gempub(gempub, collect_String(makeFileUrl_String(localPath))); |
1326 | SDLK_s, | 1306 | if (!isInside) { |
1327 | KMOD_PRIMARY | KMOD_SHIFT, | 1307 | setSource_DocumentWidget(d, collect_String(coverPageSource_Gempub(gempub))); |
1328 | "document.save open:1" }, | 1308 | setCStr_String(&d->sourceMime, mimeType_Gempub); |
1329 | { download_Icon " " saveToDownloads_Label, | 1309 | } |
1330 | SDLK_s, | 1310 | d->sourceGempub = gempub; |
1331 | KMOD_PRIMARY, | 1311 | } |
1332 | "document.save" } }, | 1312 | else { |
1333 | 2); | 1313 | delete_Gempub(gempub); |
1334 | } | 1314 | } |
1335 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { | ||
1336 | redoLayout_GmDocument(d->doc); | ||
1337 | updateVisible_DocumentWidget_(d); | ||
1338 | invalidate_DocumentWidget_(d); | ||
1339 | } | 1315 | } |
1340 | } | 1316 | } |
1341 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1317 | if (d->sourceGempub) { |
1342 | makeFooterButtons_DocumentWidget_( | 1318 | if (equal_String(d->mod.url, coverPageUrl_Gempub(d->sourceGempub))) { |
1343 | d, | 1319 | if (!isRemote_Gempub(d->sourceGempub)) { |
1344 | (iMenuItem[]){ { format_CStr(book_Icon " %s", | 1320 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1345 | cstr_String(property_Gempub(d->sourceGempub, | ||
1346 | title_GempubProperty))), | ||
1347 | SDLK_LEFT, | ||
1348 | 0, | ||
1349 | format_CStr("!open url:%s", | ||
1350 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) } }, | ||
1351 | 1); | ||
1352 | } | ||
1353 | else { | ||
1354 | /* Navigation buttons. */ | ||
1355 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | ||
1356 | const size_t navIndex = navIndex_Gempub(d->sourceGempub, d->mod.url); | ||
1357 | if (navIndex != iInvalidPos) { | ||
1358 | if (navIndex < navSize_Gempub(d->sourceGempub) - 1) { | ||
1359 | pushBack_Array( | 1321 | pushBack_Array( |
1360 | items, | 1322 | items, |
1361 | &(iMenuItem){ | 1323 | &(iMenuItem){ book_Icon " ${gempub.cover.view}", |
1362 | format_CStr(forwardArrow_Icon " %s", | 1324 | 0, |
1363 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex + 1))), | 1325 | 0, |
1364 | SDLK_RIGHT, | 1326 | format_CStr("!open url:%s", |
1365 | 0, | 1327 | cstr_String(indexPageUrl_Gempub(d->sourceGempub))) }); |
1366 | format_CStr("!open url:%s", | 1328 | if (navSize_Gempub(d->sourceGempub) > 0) { |
1367 | 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)); | ||
1368 | } | 1340 | } |
1369 | if (navIndex > 0) { | 1341 | else { |
1370 | pushBack_Array( | 1342 | makeFooterButtons_DocumentWidget_( |
1371 | items, | 1343 | d, |
1372 | &(iMenuItem){ | 1344 | (iMenuItem[]){ { book_Icon " ${menu.save.downloads.open}", |
1373 | format_CStr(backArrow_Icon " %s", | 1345 | SDLK_s, |
1374 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex - 1))), | 1346 | KMOD_PRIMARY | KMOD_SHIFT, |
1375 | SDLK_LEFT, | 1347 | "document.save open:1" }, |
1376 | 0, | 1348 | { download_Icon " " saveToDownloads_Label, |
1377 | format_CStr("!open url:%s", | 1349 | SDLK_s, |
1378 | cstr_String(navLinkUrl_Gempub(d->sourceGempub, navIndex - 1))) }); | 1350 | KMOD_PRIMARY, |
1351 | "document.save" } }, | ||
1352 | 2); | ||
1379 | } | 1353 | } |
1380 | else if (!equalCase_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1354 | if (preloadCoverImage_Gempub(d->sourceGempub, d->doc)) { |
1381 | pushBack_Array( | 1355 | redoLayout_GmDocument(d->doc); |
1382 | items, | 1356 | updateVisible_DocumentWidget_(d); |
1383 | &(iMenuItem){ | 1357 | invalidate_DocumentWidget_(d); |
1384 | format_CStr(book_Icon " %s", | ||
1385 | cstr_String(property_Gempub(d->sourceGempub, title_GempubProperty))), | ||
1386 | SDLK_LEFT, | ||
1387 | 0, | ||
1388 | format_CStr("!open url:%s", | ||
1389 | cstr_String(coverPageUrl_Gempub(d->sourceGempub))) }); | ||
1390 | } | 1358 | } |
1391 | } | 1359 | } |
1392 | if (!isEmpty_Array(items)) { | 1360 | else if (equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { |
1393 | 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); | ||
1394 | } | 1371 | } |
1395 | } | 1372 | else { |
1396 | if (!isCached && prefs_App()->pinSplit && | 1373 | /* Navigation buttons. */ |
1397 | equal_String(d->mod.url, indexPageUrl_Gempub(d->sourceGempub))) { | 1374 | iArray *items = collectNew_Array(sizeof(iMenuItem)); |
1398 | const iString *navStart = navStartLinkUrl_Gempub(d->sourceGempub); | 1375 | const size_t navIndex = navIndex_Gempub(d->sourceGempub, d->mod.url); |
1399 | if (navStart) { | 1376 | if (navIndex != iInvalidPos) { |
1400 | iWindow *win = get_Window(); | 1377 | if (navIndex < navSize_Gempub(d->sourceGempub) - 1) { |
1401 | /* Auto-split to show index and the first navigation link. */ | 1378 | pushBack_Array( |
1402 | if (numRoots_Window(win) == 2) { | 1379 | items, |
1403 | /* This document is showing the index page. */ | 1380 | &(iMenuItem){ |
1404 | iRoot *other = otherRoot_Window(win, w->root); | 1381 | format_CStr(forwardArrow_Icon " %s", |
1405 | postCommandf_Root(other, "open url:%s", cstr_String(navStart)); | 1382 | cstr_String(navLinkLabel_Gempub(d->sourceGempub, navIndex + 1))), |
1406 | if (prefs_App()->pinSplit == 1 && w->root == win->roots[1]) { | 1383 | SDLK_RIGHT, |
1407 | /* On the wrong side. */ | 1384 | 0, |
1408 | 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))) }); | ||
1409 | } | 1409 | } |
1410 | } | 1410 | } |
1411 | else { | 1411 | if (!isEmpty_Array(items)) { |
1412 | postCommandf_App( | 1412 | makeFooterButtons_DocumentWidget_(d, constData_Array(items), size_Array(items)); |
1413 | "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 | } | ||
1414 | } | 1434 | } |
1415 | } | 1435 | } |
1416 | } | 1436 | } |
1417 | } | 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 | } | ||
1418 | } | 1445 | } |
1419 | 1446 | ||
1420 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, | 1447 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, |
@@ -1482,7 +1509,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1482 | } | 1509 | } |
1483 | delete_String(localPath); | 1510 | delete_String(localPath); |
1484 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { | 1511 | if (equalCase_Rangecc(urlScheme_String(d->mod.url), "file")) { |
1485 | appendFormat_String(&str, "=> %s/ ${doc.archive.view}\n", | 1512 | appendFormat_String(&str, "=> %s/ " folder_Icon " ${doc.archive.view}\n", |
1486 | cstr_String(withSpacesEncoded_String(d->mod.url))); | 1513 | cstr_String(withSpacesEncoded_String(d->mod.url))); |
1487 | } | 1514 | } |
1488 | translate_Lang(&str); | 1515 | translate_Lang(&str); |
@@ -1619,7 +1646,7 @@ static void parseUser_DocumentWidget_(iDocumentWidget *d) { | |||
1619 | static void cacheRunGlyphs_(void *data, const iGmRun *run) { | 1646 | static void cacheRunGlyphs_(void *data, const iGmRun *run) { |
1620 | iUnused(data); | 1647 | iUnused(data); |
1621 | if (!isEmpty_Range(&run->text)) { | 1648 | if (!isEmpty_Range(&run->text)) { |
1622 | cache_Text(run->textParams.font, run->text); | 1649 | cache_Text(run->font, run->text); |
1623 | } | 1650 | } |
1624 | } | 1651 | } |
1625 | 1652 | ||
@@ -2087,7 +2114,7 @@ static iBool requestMedia_DocumentWidget_(iDocumentWidget *d, iGmLinkId linkId, | |||
2087 | } | 2114 | } |
2088 | 2115 | ||
2089 | static iBool isDownloadRequest_DocumentWidget(const iDocumentWidget *d, const iMediaRequest *req) { | 2116 | static iBool isDownloadRequest_DocumentWidget(const iDocumentWidget *d, const iMediaRequest *req) { |
2090 | return findLinkDownload_Media(constMedia_GmDocument(d->doc), req->linkId) != 0; | 2117 | return findMediaForLink_Media(constMedia_GmDocument(d->doc), req->linkId, download_MediaType).type != 0; |
2091 | } | 2118 | } |
2092 | 2119 | ||
2093 | static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { | 2120 | static iBool handleMediaCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) { |
@@ -2172,7 +2199,7 @@ static void allocVisBuffer_DocumentWidget_(const iDocumentWidget *d) { | |||
2172 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { | 2199 | static iBool fetchNextUnfetchedImage_DocumentWidget_(iDocumentWidget *d) { |
2173 | iConstForEach(PtrArray, i, &d->visibleLinks) { | 2200 | iConstForEach(PtrArray, i, &d->visibleLinks) { |
2174 | const iGmRun *run = i.ptr; | 2201 | const iGmRun *run = i.ptr; |
2175 | if (run->linkId && run->mediaType == none_GmRunMediaType && | 2202 | if (run->linkId && run->mediaType == none_MediaType && |
2176 | ~run->flags & decoration_GmRunFlag) { | 2203 | ~run->flags & decoration_GmRunFlag) { |
2177 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); | 2204 | const int linkFlags = linkFlags_GmDocument(d->doc, run->linkId); |
2178 | if (isMediaLink_GmDocument(d->doc, run->linkId) && | 2205 | if (isMediaLink_GmDocument(d->doc, run->linkId) && |
@@ -2761,8 +2788,10 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2761 | else if (equalWidget_Command(cmd, w, "document.downloadlink")) { | 2788 | else if (equalWidget_Command(cmd, w, "document.downloadlink")) { |
2762 | if (d->contextLink) { | 2789 | if (d->contextLink) { |
2763 | const iGmLinkId linkId = d->contextLink->linkId; | 2790 | const iGmLinkId linkId = d->contextLink->linkId; |
2764 | setDownloadUrl_Media( | 2791 | setUrl_Media(media_GmDocument(d->doc), |
2765 | media_GmDocument(d->doc), linkId, linkUrl_GmDocument(d->doc, linkId)); | 2792 | linkId, |
2793 | download_MediaType, | ||
2794 | linkUrl_GmDocument(d->doc, linkId)); | ||
2766 | requestMedia_DocumentWidget_(d, linkId, iFalse /* no filters */); | 2795 | requestMedia_DocumentWidget_(d, linkId, iFalse /* no filters */); |
2767 | redoLayout_GmDocument(d->doc); /* inline downloader becomes visible */ | 2796 | redoLayout_GmDocument(d->doc); /* inline downloader becomes visible */ |
2768 | updateVisible_DocumentWidget_(d); | 2797 | updateVisible_DocumentWidget_(d); |
@@ -2872,7 +2901,7 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2872 | const iMedia * media = media_GmDocument(d->doc); | 2901 | const iMedia * media = media_GmDocument(d->doc); |
2873 | const size_t num = numAudio_Media(media); | 2902 | const size_t num = numAudio_Media(media); |
2874 | for (size_t id = 1; id <= num; id++) { | 2903 | for (size_t id = 1; id <= num; id++) { |
2875 | iPlayer *plr = audioPlayer_Media(media, id); | 2904 | iPlayer *plr = audioPlayer_Media(media, (iMediaId){ audio_MediaType, id }); |
2876 | if (plr != startedPlr) { | 2905 | if (plr != startedPlr) { |
2877 | setPaused_Player(plr, iTrue); | 2906 | setPaused_Player(plr, iTrue); |
2878 | } | 2907 | } |
@@ -3210,8 +3239,8 @@ static iRect runRect_DocumentWidget_(const iDocumentWidget *d, const iGmRun *run | |||
3210 | } | 3239 | } |
3211 | 3240 | ||
3212 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { | 3241 | static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *run) { |
3213 | if (run && run->mediaType == audio_GmRunMediaType) { | 3242 | if (run && run->mediaType == audio_MediaType) { |
3214 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 3243 | iPlayer *plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
3215 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); | 3244 | setFlags_Player(plr, volumeGrabbed_PlayerFlag, iTrue); |
3216 | d->grabbedStartVolume = volume_Player(plr); | 3245 | d->grabbedStartVolume = volume_Player(plr); |
3217 | d->grabbedPlayer = run; | 3246 | d->grabbedPlayer = run; |
@@ -3219,7 +3248,7 @@ static void setGrabbedPlayer_DocumentWidget_(iDocumentWidget *d, const iGmRun *r | |||
3219 | } | 3248 | } |
3220 | else if (d->grabbedPlayer) { | 3249 | else if (d->grabbedPlayer) { |
3221 | setFlags_Player( | 3250 | setFlags_Player( |
3222 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId), | 3251 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(d->grabbedPlayer)), |
3223 | volumeGrabbed_PlayerFlag, | 3252 | volumeGrabbed_PlayerFlag, |
3224 | iFalse); | 3253 | iFalse); |
3225 | d->grabbedPlayer = NULL; | 3254 | d->grabbedPlayer = NULL; |
@@ -3247,11 +3276,21 @@ static iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev | |||
3247 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); | 3276 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); |
3248 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 3277 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
3249 | const iGmRun *run = i.ptr; | 3278 | const iGmRun *run = i.ptr; |
3250 | 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) { | ||
3251 | continue; | 3289 | continue; |
3252 | } | 3290 | } |
3291 | /* TODO: move this to mediaui.c */ | ||
3253 | const iRect rect = runRect_DocumentWidget_(d, run); | 3292 | const iRect rect = runRect_DocumentWidget_(d, run); |
3254 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), run->mediaId); | 3293 | iPlayer * plr = audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)); |
3255 | if (contains_Rect(rect, mouse)) { | 3294 | if (contains_Rect(rect, mouse)) { |
3256 | iPlayerUI ui; | 3295 | iPlayerUI ui; |
3257 | init_PlayerUI(&ui, plr, rect); | 3296 | init_PlayerUI(&ui, plr, rect); |
@@ -3439,7 +3478,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3439 | return iTrue; | 3478 | return iTrue; |
3440 | } | 3479 | } |
3441 | break; | 3480 | break; |
3442 | #if 1 | 3481 | #if !defined (NDEBUG) |
3443 | case SDLK_KP_1: | 3482 | case SDLK_KP_1: |
3444 | case '`': { | 3483 | case '`': { |
3445 | iBlock *seed = new_Block(64); | 3484 | iBlock *seed = new_Block(64); |
@@ -3631,7 +3670,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3631 | cstr_String(linkUrl)) }, | 3670 | cstr_String(linkUrl)) }, |
3632 | }, | 3671 | }, |
3633 | 3); | 3672 | 3); |
3634 | if (isNative && d->contextLink->mediaType != download_GmRunMediaType) { | 3673 | if (isNative && d->contextLink->mediaType != download_MediaType) { |
3635 | pushBackN_Array(&items, (iMenuItem[]){ | 3674 | pushBackN_Array(&items, (iMenuItem[]){ |
3636 | { "---" }, | 3675 | { "---" }, |
3637 | { download_Icon " ${link.download}", 0, 0, "document.downloadlink" }, | 3676 | { download_Icon " ${link.download}", 0, 0, "document.downloadlink" }, |
@@ -3639,7 +3678,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3639 | } | 3678 | } |
3640 | iMediaRequest *mediaReq; | 3679 | iMediaRequest *mediaReq; |
3641 | if ((mediaReq = findMediaRequest_DocumentWidget_(d, d->contextLink->linkId)) != NULL && | 3680 | if ((mediaReq = findMediaRequest_DocumentWidget_(d, d->contextLink->linkId)) != NULL && |
3642 | d->contextLink->mediaType != download_GmRunMediaType) { | 3681 | d->contextLink->mediaType != download_MediaType) { |
3643 | if (isFinished_GmRequest(mediaReq->req)) { | 3682 | if (isFinished_GmRequest(mediaReq->req)) { |
3644 | pushBack_Array(&items, | 3683 | pushBack_Array(&items, |
3645 | &(iMenuItem){ download_Icon " " saveToDownloads_Label, | 3684 | &(iMenuItem){ download_Icon " " saveToDownloads_Label, |
@@ -3761,7 +3800,7 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3761 | case drag_ClickResult: { | 3800 | case drag_ClickResult: { |
3762 | if (d->grabbedPlayer) { | 3801 | if (d->grabbedPlayer) { |
3763 | iPlayer *plr = | 3802 | iPlayer *plr = |
3764 | audioPlayer_Media(media_GmDocument(d->doc), d->grabbedPlayer->mediaId); | 3803 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(d->grabbedPlayer)); |
3765 | iPlayerUI ui; | 3804 | iPlayerUI ui; |
3766 | init_PlayerUI(&ui, plr, runRect_DocumentWidget_(d, d->grabbedPlayer)); | 3805 | init_PlayerUI(&ui, plr, runRect_DocumentWidget_(d, d->grabbedPlayer)); |
3767 | 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); |
@@ -3887,8 +3926,9 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3887 | } | 3926 | } |
3888 | if (d->hoverLink) { | 3927 | if (d->hoverLink) { |
3889 | /* TODO: Move this to a method. */ | 3928 | /* TODO: Move this to a method. */ |
3890 | const iGmLinkId linkId = d->hoverLink->linkId; | 3929 | const iGmLinkId linkId = d->hoverLink->linkId; |
3891 | const int linkFlags = linkFlags_GmDocument(d->doc, linkId); | 3930 | const iMediaId linkMedia = mediaId_GmRun(d->hoverLink); |
3931 | const int linkFlags = linkFlags_GmDocument(d->doc, linkId); | ||
3892 | iAssert(linkId); | 3932 | iAssert(linkId); |
3893 | /* Media links are opened inline by default. */ | 3933 | /* Media links are opened inline by default. */ |
3894 | if (isMediaLink_GmDocument(d->doc, linkId)) { | 3934 | if (isMediaLink_GmDocument(d->doc, linkId)) { |
@@ -3941,6 +3981,12 @@ static iBool processEvent_DocumentWidget_(iDocumentWidget *d, const SDL_Event *e | |||
3941 | } | 3981 | } |
3942 | refresh_Widget(w); | 3982 | refresh_Widget(w); |
3943 | } | 3983 | } |
3984 | else if (linkMedia.type == download_MediaType || | ||
3985 | findMediaRequest_DocumentWidget_(d, linkId)) { | ||
3986 | /* TODO: What should be done when clicking on an inline download? | ||
3987 | Maybe dismiss if finished? */ | ||
3988 | return iTrue; | ||
3989 | } | ||
3944 | else if (linkFlags & supportedScheme_GmLinkFlag) { | 3990 | else if (linkFlags & supportedScheme_GmLinkFlag) { |
3945 | int tabMode = openTabMode_Sym(modState_Keys()); | 3991 | int tabMode = openTabMode_Sym(modState_Keys()); |
3946 | if (isPinned_DocumentWidget_(d)) { | 3992 | if (isPinned_DocumentWidget_(d)) { |
@@ -4026,7 +4072,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
4026 | contains_Range(&mark, run->text.start))) { | 4072 | contains_Range(&mark, run->text.start))) { |
4027 | int x = 0; | 4073 | int x = 0; |
4028 | if (!*isInside) { | 4074 | if (!*isInside) { |
4029 | x = measureRange_Text(run->textParams.font, | 4075 | x = measureRange_Text(run->font, |
4030 | (iRangecc){ run->text.start, iMax(run->text.start, mark.start) }) | 4076 | (iRangecc){ run->text.start, iMax(run->text.start, mark.start) }) |
4031 | .advance.x; | 4077 | .advance.x; |
4032 | } | 4078 | } |
@@ -4035,7 +4081,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
4035 | iRangecc mk = !*isInside ? mark | 4081 | iRangecc mk = !*isInside ? mark |
4036 | : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) }; | 4082 | : (iRangecc){ run->text.start, iMax(run->text.start, mark.end) }; |
4037 | mk.start = iMax(mk.start, run->text.start); | 4083 | mk.start = iMax(mk.start, run->text.start); |
4038 | w = measureRange_Text(run->textParams.font, mk).advance.x; | 4084 | w = measureRange_Text(run->font, mk).advance.x; |
4039 | *isInside = iFalse; | 4085 | *isInside = iFalse; |
4040 | } | 4086 | } |
4041 | else { | 4087 | else { |
@@ -4074,7 +4120,7 @@ static void fillRange_DrawContext_(iDrawContext *d, const iGmRun *run, enum iCol | |||
4074 | 4120 | ||
4075 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { | 4121 | static void drawMark_DrawContext_(void *context, const iGmRun *run) { |
4076 | iDrawContext *d = context; | 4122 | iDrawContext *d = context; |
4077 | if (run->mediaType == none_GmRunMediaType) { | 4123 | if (run->mediaType == none_MediaType) { |
4078 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); | 4124 | fillRange_DrawContext_(d, run, uiMatching_ColorId, d->widget->foundMark, &d->inFoundMark); |
4079 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); | 4125 | fillRange_DrawContext_(d, run, uiMarked_ColorId, d->widget->selectMark, &d->inSelectMark); |
4080 | } | 4126 | } |
@@ -4088,15 +4134,15 @@ static void drawBannerRun_DrawContext_(iDrawContext *d, const iGmRun *run, iInt2 | |||
4088 | iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2)); | 4134 | iInt2 bpos = add_I2(visPos, init_I2(0, lineHeight_Text(banner_FontId) / 2)); |
4089 | if (icon) { | 4135 | if (icon) { |
4090 | appendChar_String(&str, icon); | 4136 | appendChar_String(&str, icon); |
4091 | const iRect iconRect = visualBounds_Text(run->textParams.font, range_String(&str)); | 4137 | const iRect iconRect = visualBounds_Text(run->font, range_String(&str)); |
4092 | drawRange_Text( | 4138 | drawRange_Text( |
4093 | run->textParams.font, | 4139 | run->font, |
4094 | addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->textParams.font) / 2), | 4140 | addY_I2(bpos, -mid_Rect(iconRect).y + lineHeight_Text(run->font) / 2), |
4095 | tmBannerIcon_ColorId, | 4141 | tmBannerIcon_ColorId, |
4096 | range_String(&str)); | 4142 | range_String(&str)); |
4097 | bpos.x += right_Rect(iconRect) + 3 * gap_Text; | 4143 | bpos.x += right_Rect(iconRect) + 3 * gap_Text; |
4098 | } | 4144 | } |
4099 | drawRange_Text(run->textParams.font, | 4145 | drawRange_Text(run->font, |
4100 | bpos, | 4146 | bpos, |
4101 | tmBannerTitle_ColorId, | 4147 | tmBannerTitle_ColorId, |
4102 | bannerText_DocumentWidget_(d->widget)); | 4148 | bannerText_DocumentWidget_(d->widget)); |
@@ -4181,8 +4227,8 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4181 | d->runsDrawn.end = run; | 4227 | d->runsDrawn.end = run; |
4182 | } | 4228 | } |
4183 | } | 4229 | } |
4184 | if (run->mediaType == image_GmRunMediaType) { | 4230 | if (run->mediaType == image_MediaType) { |
4185 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), run->mediaId); | 4231 | SDL_Texture *tex = imageTexture_Media(media_GmDocument(d->widget->doc), mediaId_GmRun(run)); |
4186 | const iRect dst = moved_Rect(run->visBounds, origin); | 4232 | const iRect dst = moved_Rect(run->visBounds, origin); |
4187 | if (tex) { | 4233 | if (tex) { |
4188 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ | 4234 | fillRect_Paint(&d->paint, dst, tmBackground_ColorId); /* in case the image has alpha */ |
@@ -4203,7 +4249,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4203 | /* Media UIs are drawn afterwards as a dynamic overlay. */ | 4249 | /* Media UIs are drawn afterwards as a dynamic overlay. */ |
4204 | return; | 4250 | return; |
4205 | } | 4251 | } |
4206 | enum iColorId fg = run->textParams.color; | 4252 | enum iColorId fg = run->color; |
4207 | const iGmDocument *doc = d->widget->doc; | 4253 | const iGmDocument *doc = d->widget->doc; |
4208 | const int linkFlags = linkFlags_GmDocument(doc, run->linkId); | 4254 | const int linkFlags = linkFlags_GmDocument(doc, run->linkId); |
4209 | /* Hover state of a link. */ | 4255 | /* Hover state of a link. */ |
@@ -4270,10 +4316,10 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4270 | const iInt2 margin = preRunMargin_GmDocument(doc, run->preId); | 4316 | const iInt2 margin = preRunMargin_GmDocument(doc, run->preId); |
4271 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId); | 4317 | fillRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmBackgroundAltText_ColorId); |
4272 | drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); | 4318 | drawRect_Paint(&d->paint, (iRect){ visPos, run->visBounds.size }, tmQuoteIcon_ColorId); |
4273 | drawWrapRange_Text(run->textParams.font, | 4319 | drawWrapRange_Text(run->font, |
4274 | add_I2(visPos, margin), | 4320 | add_I2(visPos, margin), |
4275 | run->visBounds.size.x - 2 * margin.x, | 4321 | run->visBounds.size.x - 2 * margin.x, |
4276 | run->textParams.color, | 4322 | run->color, |
4277 | run->text); | 4323 | run->text); |
4278 | } | 4324 | } |
4279 | else if (run->flags & siteBanner_GmRunFlag) { | 4325 | else if (run->flags & siteBanner_GmRunFlag) { |
@@ -4292,17 +4338,17 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4292 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); | 4338 | linkOrdinalChar_DocumentWidget_(d->widget, ord - d->widget->ordinalBase); |
4293 | if (ordChar) { | 4339 | if (ordChar) { |
4294 | const char *circle = "\u25ef"; /* Large Circle */ | 4340 | const char *circle = "\u25ef"; /* Large Circle */ |
4295 | const int circleFont = defaultContentRegular_FontId; | 4341 | const int circleFont = FONT_ID(default_FontId, regular_FontStyle, contentRegular_FontSize); |
4296 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), | 4342 | iRect nbArea = { init_I2(d->viewPos.x - gap_UI / 3, visPos.y), |
4297 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) }; | 4343 | init_I2(3.95f * gap_Text, 1.0f * lineHeight_Text(circleFont)) }; |
4298 | drawRange_Text( | 4344 | drawRange_Text( |
4299 | circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); | 4345 | circleFont, topLeft_Rect(nbArea), tmQuote_ColorId, range_CStr(circle)); |
4300 | iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle)); | 4346 | iRect circleArea = visualBounds_Text(circleFont, range_CStr(circle)); |
4301 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); | 4347 | addv_I2(&circleArea.pos, topLeft_Rect(nbArea)); |
4302 | drawCentered_Text(defaultContentSmall_FontId, | 4348 | drawCentered_Text(FONT_ID(default_FontId, regular_FontStyle, contentSmall_FontSize), |
4303 | circleArea, | 4349 | circleArea, |
4304 | iTrue, | 4350 | iTrue, |
4305 | tmQuote_ColorId, | 4351 | tmQuote_ColorId, |
4306 | "%lc", | 4352 | "%lc", |
4307 | (int) ordChar); | 4353 | (int) ordChar); |
4308 | goto runDrawn; | 4354 | goto runDrawn; |
@@ -4312,15 +4358,15 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4312 | if (run->flags & quoteBorder_GmRunFlag) { | 4358 | if (run->flags & quoteBorder_GmRunFlag) { |
4313 | drawVLine_Paint(&d->paint, | 4359 | drawVLine_Paint(&d->paint, |
4314 | addX_I2(visPos, | 4360 | addX_I2(visPos, |
4315 | !run->textParams.isRTL | 4361 | !run->isRTL |
4316 | ? -gap_Text * 5 / 2 | 4362 | ? -gap_Text * 5 / 2 |
4317 | : (width_Rect(run->visBounds) + gap_Text * 5 / 2)), | 4363 | : (width_Rect(run->visBounds) + gap_Text * 5 / 2)), |
4318 | height_Rect(run->visBounds), | 4364 | height_Rect(run->visBounds), |
4319 | tmQuoteIcon_ColorId); | 4365 | tmQuoteIcon_ColorId); |
4320 | } | 4366 | } |
4321 | drawBoundRange_Text(run->textParams.font, | 4367 | drawBoundRange_Text(run->font, |
4322 | visPos, | 4368 | visPos, |
4323 | (run->textParams.isRTL ? -1 : 1) * width_Rect(run->visBounds), | 4369 | (run->isRTL ? -1 : 1) * width_Rect(run->visBounds), |
4324 | fg, | 4370 | fg, |
4325 | run->text); | 4371 | run->text); |
4326 | runDrawn:; | 4372 | runDrawn:; |
@@ -4337,31 +4383,31 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4337 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); | 4383 | fg = linkColor_GmDocument(doc, run->linkId, textHover_GmLinkPart); |
4338 | iString text; | 4384 | iString text; |
4339 | init_String(&text); | 4385 | init_String(&text); |
4340 | iMediaId imageId = linkImage_GmDocument(doc, run->linkId); | 4386 | const iMediaId linkMedia = findMediaForLink_Media(constMedia_GmDocument(doc), |
4341 | iMediaId audioId = !imageId ? linkAudio_GmDocument(doc, run->linkId) : 0; | 4387 | run->linkId, none_MediaType); |
4342 | iMediaId downloadId = !imageId && !audioId ? | 4388 | iAssert(linkMedia.type != none_MediaType); |
4343 | findLinkDownload_Media(constMedia_GmDocument(doc), run->linkId) : 0; | 4389 | iGmMediaInfo info; |
4344 | iAssert(imageId || audioId || downloadId); | 4390 | info_Media(constMedia_GmDocument(doc), linkMedia, &info); |
4345 | if (imageId) { | 4391 | switch (linkMedia.type) { |
4346 | iAssert(!isEmpty_Rect(run->bounds)); | 4392 | case image_MediaType: { |
4347 | iGmMediaInfo info; | 4393 | iAssert(!isEmpty_Rect(run->bounds)); |
4348 | imageInfo_Media(constMedia_GmDocument(doc), imageId, &info); | 4394 | const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), linkMedia); |
4349 | const iInt2 imgSize = imageSize_Media(constMedia_GmDocument(doc), imageId); | 4395 | format_String(&text, "%s \u2014 %d x %d \u2014 %.1f%s", |
4350 | format_String(&text, "%s \u2014 %d x %d \u2014 %.1f%s", | 4396 | info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f, |
4351 | info.type, imgSize.x, imgSize.y, info.numBytes / 1.0e6f, | 4397 | cstr_Lang("mb")); |
4352 | cstr_Lang("mb")); | 4398 | break; |
4353 | } | 4399 | } |
4354 | else if (audioId) { | 4400 | case audio_MediaType: |
4355 | iGmMediaInfo info; | 4401 | format_String(&text, "%s", info.type); |
4356 | audioInfo_Media(constMedia_GmDocument(doc), audioId, &info); | 4402 | break; |
4357 | format_String(&text, "%s", info.type); | 4403 | case download_MediaType: |
4358 | } | 4404 | format_String(&text, "%s", info.type); |
4359 | else if (downloadId) { | 4405 | break; |
4360 | iGmMediaInfo info; | 4406 | default: |
4361 | downloadInfo_Media(constMedia_GmDocument(doc), downloadId, &info); | 4407 | break; |
4362 | format_String(&text, "%s", info.type); | ||
4363 | } | 4408 | } |
4364 | if (findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { | 4409 | if (linkMedia.type != download_MediaType && /* can't cancel downloads currently */ |
4410 | findMediaRequest_DocumentWidget_(d->widget, run->linkId)) { | ||
4365 | appendFormat_String( | 4411 | appendFormat_String( |
4366 | &text, " %s" close_Icon, isHover ? escape_Color(tmLinkText_ColorId) : ""); | 4412 | &text, " %s" close_Icon, isHover ? escape_Color(tmLinkText_ColorId) : ""); |
4367 | } | 4413 | } |
@@ -4436,7 +4482,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4436 | append_String(&str, collect_String(format_Date(&date, "%b %d"))); | 4482 | append_String(&str, collect_String(format_Date(&date, "%b %d"))); |
4437 | } | 4483 | } |
4438 | if (!isEmpty_String(&str)) { | 4484 | if (!isEmpty_String(&str)) { |
4439 | if (run->textParams.isRTL) { | 4485 | if (run->isRTL) { |
4440 | appendCStr_String(&str, " \u2014 "); | 4486 | appendCStr_String(&str, " \u2014 "); |
4441 | } | 4487 | } |
4442 | else { | 4488 | else { |
@@ -4445,7 +4491,7 @@ static void drawRun_DrawContext_(void *context, const iGmRun *run) { | |||
4445 | const iInt2 textSize = measure_Text(metaFont, cstr_String(&str)).bounds.size; | 4491 | const iInt2 textSize = measure_Text(metaFont, cstr_String(&str)).bounds.size; |
4446 | int tx = topRight_Rect(linkRect).x; | 4492 | int tx = topRight_Rect(linkRect).x; |
4447 | const char *msg = cstr_String(&str); | 4493 | const char *msg = cstr_String(&str); |
4448 | if (run->textParams.isRTL) { | 4494 | if (run->isRTL) { |
4449 | tx = topLeft_Rect(linkRect).x - textSize.x; | 4495 | tx = topLeft_Rect(linkRect).x - textSize.x; |
4450 | } | 4496 | } |
4451 | if (tx + textSize.x > right_Rect(d->widgetBounds)) { | 4497 | if (tx + textSize.x > right_Rect(d->widgetBounds)) { |
@@ -4592,18 +4638,25 @@ static void drawSideElements_DocumentWidget_(const iDocumentWidget *d) { | |||
4592 | static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { | 4638 | static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { |
4593 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 4639 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
4594 | const iGmRun * run = i.ptr; | 4640 | const iGmRun * run = i.ptr; |
4595 | if (run->mediaType == audio_GmRunMediaType) { | 4641 | if (run->mediaType == audio_MediaType) { |
4596 | iPlayerUI ui; | 4642 | iPlayerUI ui; |
4597 | init_PlayerUI(&ui, | 4643 | init_PlayerUI(&ui, |
4598 | audioPlayer_Media(media_GmDocument(d->doc), run->mediaId), | 4644 | audioPlayer_Media(media_GmDocument(d->doc), mediaId_GmRun(run)), |
4599 | runRect_DocumentWidget_(d, run)); | 4645 | runRect_DocumentWidget_(d, run)); |
4600 | draw_PlayerUI(&ui, p); | 4646 | draw_PlayerUI(&ui, p); |
4601 | } | 4647 | } |
4602 | else if (run->mediaType == download_GmRunMediaType) { | 4648 | else if (run->mediaType == download_MediaType) { |
4603 | iDownloadUI ui; | 4649 | iDownloadUI ui; |
4604 | init_DownloadUI(&ui, d, run->mediaId, runRect_DocumentWidget_(d, run)); | 4650 | init_DownloadUI(&ui, constMedia_GmDocument(d->doc), run->mediaId, |
4651 | runRect_DocumentWidget_(d, run)); | ||
4605 | draw_DownloadUI(&ui, p); | 4652 | draw_DownloadUI(&ui, p); |
4606 | } | 4653 | } |
4654 | else if (run->mediaType == fontpack_MediaType) { | ||
4655 | iFontpackUI ui; | ||
4656 | init_FontpackUI(&ui, constMedia_GmDocument(d->doc), run->mediaId, | ||
4657 | runRect_DocumentWidget_(d, run)); | ||
4658 | draw_FontpackUI(&ui, p); | ||
4659 | } | ||
4607 | } | 4660 | } |
4608 | } | 4661 | } |
4609 | 4662 | ||
@@ -4914,7 +4967,7 @@ static void draw_DocumentWidget_(const iDocumentWidget *d) { | |||
4914 | } | 4967 | } |
4915 | /* Pinch zoom indicator. */ | 4968 | /* Pinch zoom indicator. */ |
4916 | if (d->flags & pinchZoom_DocumentWidgetFlag) { | 4969 | if (d->flags & pinchZoom_DocumentWidgetFlag) { |
4917 | const int font = defaultLargeBold_FontId; | 4970 | const int font = uiLabelLargeBold_FontId; |
4918 | const int height = lineHeight_Text(font) * 2; | 4971 | const int height = lineHeight_Text(font) * 2; |
4919 | const iInt2 size = init_I2(height * 2, height); | 4972 | const iInt2 size = init_I2(height * 2, height); |
4920 | const iRect rect = { sub_I2(mid_Rect(bounds), divi_I2(size, 2)), size }; | 4973 | const iRect rect = { sub_I2(mid_Rect(bounds), divi_I2(size, 2)), size }; |
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/labelwidget.c b/src/ui/labelwidget.c index cfc81863..9713e1f2 100644 --- a/src/ui/labelwidget.c +++ b/src/ui/labelwidget.c | |||
@@ -384,7 +384,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
384 | } | 384 | } |
385 | else if (flags & alignLeft_WidgetFlag) { | 385 | else if (flags & alignLeft_WidgetFlag) { |
386 | draw_Text(d->font, add_I2(bounds.pos, addX_I2(padding_LabelWidget_(d, 0), iconPad)), | 386 | draw_Text(d->font, add_I2(bounds.pos, addX_I2(padding_LabelWidget_(d, 0), iconPad)), |
387 | fg, cstr_String(&d->label)); | 387 | fg, "%s", cstr_String(&d->label)); |
388 | if ((flags & drawKey_WidgetFlag) && d->key) { | 388 | if ((flags & drawKey_WidgetFlag) && d->key) { |
389 | iString str; | 389 | iString str; |
390 | init_String(&str); | 390 | init_String(&str); |
@@ -399,6 +399,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
399 | : colorEscape != none_ColorId ? colorEscape | 399 | : colorEscape != none_ColorId ? colorEscape |
400 | : uiTextShortcut_ColorId,*/ | 400 | : uiTextShortcut_ColorId,*/ |
401 | right_Alignment, | 401 | right_Alignment, |
402 | "%s", | ||
402 | cstr_String(&str)); | 403 | cstr_String(&str)); |
403 | deinit_String(&str); | 404 | deinit_String(&str); |
404 | } | 405 | } |
@@ -409,6 +410,7 @@ static void draw_LabelWidget_(const iLabelWidget *d) { | |||
409 | add_I2(topRight_Rect(bounds), negX_I2(padding_LabelWidget_(d, 1))), | 410 | add_I2(topRight_Rect(bounds), negX_I2(padding_LabelWidget_(d, 1))), |
410 | fg, | 411 | fg, |
411 | right_Alignment, | 412 | right_Alignment, |
413 | "%s", | ||
412 | cstr_String(&d->label)); | 414 | cstr_String(&d->label)); |
413 | } | 415 | } |
414 | else { | 416 | else { |
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c index b622a554..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; |
@@ -86,7 +87,7 @@ static int drawSevenSegmentTime_(iInt2 pos, int color, int align, int seconds) { | |||
86 | const int hours = seconds / 3600; | 87 | const int hours = seconds / 3600; |
87 | const int mins = (seconds / 60) % 60; | 88 | const int mins = (seconds / 60) % 60; |
88 | const int secs = seconds % 60; | 89 | const int secs = seconds % 60; |
89 | const int font = defaultBig_FontId; | 90 | const int font = uiLabelBig_FontId; |
90 | iString num; | 91 | iString num; |
91 | init_String(&num); | 92 | init_String(&num); |
92 | if (hours) { | 93 | if (hours) { |
@@ -113,17 +114,17 @@ 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(defaultBig_FontId); | 127 | const int hgt = lineHeight_Text(uiLabelBig_FontId); |
127 | const int yMid = mid_Rect(d->scrubberRect).y; | 128 | const int yMid = mid_Rect(d->scrubberRect).y; |
128 | const float playTime = time_Player(d->player); | 129 | const float playTime = time_Player(d->player); |
129 | const float totalTime = duration_Player(d->player); | 130 | const float totalTime = duration_Player(d->player); |
@@ -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); | ||
diff --git a/src/ui/mobile.c b/src/ui/mobile.c index 3cb6e631..f11769f5 100644 --- a/src/ui/mobile.c +++ b/src/ui/mobile.c | |||
@@ -48,11 +48,11 @@ static iBool isSideBySideLayout_(void) { | |||
48 | } | 48 | } |
49 | 49 | ||
50 | static enum iFontId labelFont_(void) { | 50 | static enum iFontId labelFont_(void) { |
51 | return deviceType_App() == phone_AppDeviceType ? defaultBig_FontId : defaultMedium_FontId; | 51 | return deviceType_App() == phone_AppDeviceType ? uiLabelBig_FontId : uiLabelMedium_FontId; |
52 | } | 52 | } |
53 | 53 | ||
54 | static enum iFontId labelBoldFont_(void) { | 54 | static enum iFontId labelBoldFont_(void) { |
55 | return deviceType_App() == phone_AppDeviceType ? defaultBigBold_FontId : defaultMediumBold_FontId; | 55 | return deviceType_App() == phone_AppDeviceType ? uiLabelBigBold_FontId : uiLabelMediumBold_FontId; |
56 | } | 56 | } |
57 | 57 | ||
58 | static void updatePanelSheetMetrics_(iWidget *sheet) { | 58 | static void updatePanelSheetMetrics_(iWidget *sheet) { |
@@ -546,7 +546,7 @@ void makePanelItem_Mobile(iWidget *panel, const iMenuItem *item) { | |||
546 | updateSize_LabelWidget(button); | 546 | updateSize_LabelWidget(button); |
547 | } | 547 | } |
548 | setId_Widget(as_Widget(button), radId); | 548 | setId_Widget(as_Widget(button), radId); |
549 | setFont_LabelWidget(button, defaultMedium_FontId); | 549 | setFont_LabelWidget(button, uiLabelMedium_FontId); |
550 | addChildFlags_Widget(widget, iClob(button), flags); | 550 | addChildFlags_Widget(widget, iClob(button), flags); |
551 | } | 551 | } |
552 | } | 552 | } |
@@ -1056,7 +1056,7 @@ void initPanels_Mobile(iWidget *panels, iWidget *parentWidget, | |||
1056 | iForEach(ObjectList, sub, children_Widget(value)) { | 1056 | iForEach(ObjectList, sub, children_Widget(value)) { |
1057 | if (isInstance_Object(sub.object, &Class_LabelWidget)) { | 1057 | if (isInstance_Object(sub.object, &Class_LabelWidget)) { |
1058 | iLabelWidget *opt = sub.object; | 1058 | iLabelWidget *opt = sub.object; |
1059 | setFont_LabelWidget(opt, defaultMedium_FontId); | 1059 | setFont_LabelWidget(opt, uiLabelMedium_FontId); |
1060 | setFlags_Widget(as_Widget(opt), noBackground_WidgetFlag, iTrue); | 1060 | setFlags_Widget(as_Widget(opt), noBackground_WidgetFlag, iTrue); |
1061 | } | 1061 | } |
1062 | } | 1062 | } |
diff --git a/src/ui/root.c b/src/ui/root.c index 63cce62d..f6d6f11d 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -447,7 +447,7 @@ static void updateNavBarIdentity_(iWidget *navBar) { | |||
447 | if (toolName) { | 447 | if (toolName) { |
448 | setOutline_LabelWidget(toolButton, ident == NULL); | 448 | setOutline_LabelWidget(toolButton, ident == NULL); |
449 | updateTextCStr_LabelWidget(toolName, subjectName ? cstr_String(subjectName) : ""); | 449 | updateTextCStr_LabelWidget(toolName, subjectName ? cstr_String(subjectName) : ""); |
450 | setFont_LabelWidget(toolButton, subjectName ? defaultMedium_FontId : uiLabelLarge_FontId); | 450 | setFont_LabelWidget(toolButton, subjectName ? uiLabelMedium_FontId : uiLabelLarge_FontId); |
451 | arrange_Widget(parent_Widget(toolButton)); | 451 | arrange_Widget(parent_Widget(toolButton)); |
452 | } | 452 | } |
453 | } | 453 | } |
@@ -566,7 +566,8 @@ static iBool willPerformSearchQuery_(const iString *userInput) { | |||
566 | if (isEmpty_String(clean)) { | 566 | if (isEmpty_String(clean)) { |
567 | return iFalse; | 567 | return iFalse; |
568 | } | 568 | } |
569 | return !isEmpty_String(&prefs_App()->searchUrl) && !isLikelyUrl_String(userInput); | 569 | return !isEmpty_String(&prefs_App()->strings[searchUrl_PrefsString]) && |
570 | !isLikelyUrl_String(userInput); | ||
570 | } | 571 | } |
571 | 572 | ||
572 | static void updateUrlInputContentPadding_(iWidget *navBar) { | 573 | static void updateUrlInputContentPadding_(iWidget *navBar) { |
@@ -996,7 +997,7 @@ void updateMetrics_Root(iRoot *d) { | |||
996 | const iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); | 997 | const iWidget *toolBar = findChild_Widget(d->widget, "toolbar"); |
997 | const iWidget *viewButton = findChild_Widget(d->widget, "toolbar.view"); | 998 | const iWidget *viewButton = findChild_Widget(d->widget, "toolbar.view"); |
998 | const iWidget *idButton = findChild_Widget(toolBar, "toolbar.ident"); | 999 | const iWidget *idButton = findChild_Widget(toolBar, "toolbar.ident"); |
999 | const int font = defaultTiny_FontId; | 1000 | const int font = uiLabelTiny_FontId; |
1000 | setFont_LabelWidget(idName, font); | 1001 | setFont_LabelWidget(idName, font); |
1001 | setPos_Widget(as_Widget(idName), | 1002 | setPos_Widget(as_Widget(idName), |
1002 | windowToLocal_Widget(as_Widget(idName), | 1003 | windowToLocal_Widget(as_Widget(idName), |
@@ -1125,7 +1126,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1125 | iClob(newIcon_LabelWidget("\U0001f513", SDLK_i, KMOD_PRIMARY, "document.info")), | 1126 | iClob(newIcon_LabelWidget("\U0001f513", SDLK_i, KMOD_PRIMARY, "document.info")), |
1126 | embedFlags | moveToParentLeftEdge_WidgetFlag); | 1127 | embedFlags | moveToParentLeftEdge_WidgetFlag); |
1127 | setId_Widget(as_Widget(lock), "navbar.lock"); | 1128 | setId_Widget(as_Widget(lock), "navbar.lock"); |
1128 | setFont_LabelWidget(lock, symbols_FontId + uiNormal_FontSize); | 1129 | // setFont_LabelWidget(lock, symbols_FontId + uiNormal_FontSize); |
1129 | updateTextCStr_LabelWidget(lock, "\U0001f512"); | 1130 | updateTextCStr_LabelWidget(lock, "\U0001f512"); |
1130 | } | 1131 | } |
1131 | /* Button for clearing the URL bar contents. */ { | 1132 | /* Button for clearing the URL bar contents. */ { |
@@ -1134,7 +1135,8 @@ void createUserInterface_Root(iRoot *d) { | |||
1134 | iClob(newIcon_LabelWidget(delete_Icon, 0, 0, "navbar.clear")), | 1135 | iClob(newIcon_LabelWidget(delete_Icon, 0, 0, "navbar.clear")), |
1135 | hidden_WidgetFlag | embedFlags | moveToParentLeftEdge_WidgetFlag | tight_WidgetFlag); | 1136 | hidden_WidgetFlag | embedFlags | moveToParentLeftEdge_WidgetFlag | tight_WidgetFlag); |
1136 | setId_Widget(as_Widget(clear), "navbar.clear"); | 1137 | setId_Widget(as_Widget(clear), "navbar.clear"); |
1137 | setFont_LabelWidget(clear, symbols2_FontId + uiNormal_FontSize); | 1138 | // setFont_LabelWidget(clear, symbols2_FontId + uiNormal_FontSize); |
1139 | setFont_LabelWidget(clear, uiLabelSymbols_FontId); | ||
1138 | // setFlags_Widget(as_Widget(clear), noBackground_WidgetFlag, iFalse); | 1140 | // setFlags_Widget(as_Widget(clear), noBackground_WidgetFlag, iFalse); |
1139 | // setBackgroundColor_Widget(as_Widget(clear), uiBackground_ColorId); | 1141 | // setBackgroundColor_Widget(as_Widget(clear), uiBackground_ColorId); |
1140 | } | 1142 | } |
@@ -1149,7 +1151,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1149 | iLabelWidget *queryInd = new_LabelWidget("${status.query} " return_Icon, NULL); | 1151 | iLabelWidget *queryInd = new_LabelWidget("${status.query} " return_Icon, NULL); |
1150 | setId_Widget(as_Widget(queryInd), "input.indicator.search"); | 1152 | setId_Widget(as_Widget(queryInd), "input.indicator.search"); |
1151 | setTextColor_LabelWidget(queryInd, uiTextAction_ColorId); | 1153 | setTextColor_LabelWidget(queryInd, uiTextAction_ColorId); |
1152 | setFont_LabelWidget(queryInd, defaultSmall_FontId); | 1154 | setFont_LabelWidget(queryInd, uiLabelSmall_FontId); |
1153 | setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); | 1155 | setBackgroundColor_Widget(as_Widget(queryInd), uiBackground_ColorId); |
1154 | setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); | 1156 | setFrameColor_Widget(as_Widget(queryInd), uiTextAction_ColorId); |
1155 | // setAlignVisually_LabelWidget(queryInd, iTrue); | 1157 | // setAlignVisually_LabelWidget(queryInd, iTrue); |
@@ -1162,7 +1164,7 @@ void createUserInterface_Root(iRoot *d) { | |||
1162 | iLabelWidget *fprog = new_LabelWidget("", NULL); | 1164 | iLabelWidget *fprog = new_LabelWidget("", NULL); |
1163 | setId_Widget(as_Widget(fprog), "feeds.progress"); | 1165 | setId_Widget(as_Widget(fprog), "feeds.progress"); |
1164 | setTextColor_LabelWidget(fprog, uiTextCaution_ColorId); | 1166 | setTextColor_LabelWidget(fprog, uiTextCaution_ColorId); |
1165 | setFont_LabelWidget(fprog, defaultSmall_FontId); | 1167 | setFont_LabelWidget(fprog, uiLabelSmall_FontId); |
1166 | setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId); | 1168 | setBackgroundColor_Widget(as_Widget(fprog), uiBackground_ColorId); |
1167 | // setAlignVisually_LabelWidget(fprog, iTrue); | 1169 | // setAlignVisually_LabelWidget(fprog, iTrue); |
1168 | setNoAutoMinHeight_LabelWidget(fprog, iTrue); | 1170 | setNoAutoMinHeight_LabelWidget(fprog, iTrue); |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index 057ff614..42661f6b 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -188,7 +188,7 @@ static iLabelWidget *addActionButton_SidebarWidget_(iSidebarWidget *d, const cha | |||
188 | // extraPadding_WidgetFlag : 0) | | 188 | // extraPadding_WidgetFlag : 0) | |
189 | flags); | 189 | flags); |
190 | setFont_LabelWidget(btn, deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide | 190 | setFont_LabelWidget(btn, deviceType_App() == phone_AppDeviceType && d->side == right_SidebarSide |
191 | ? defaultBig_FontId | 191 | ? uiLabelBig_FontId |
192 | : d->buttonFont); | 192 | : d->buttonFont); |
193 | checkIcon_LabelWidget(btn); | 193 | checkIcon_LabelWidget(btn); |
194 | return btn; | 194 | return btn; |
@@ -742,7 +742,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
742 | d->itemFonts[1] = uiContentBold_FontId; | 742 | d->itemFonts[1] = uiContentBold_FontId; |
743 | #if defined (iPlatformMobile) | 743 | #if defined (iPlatformMobile) |
744 | if (deviceType_App() == phone_AppDeviceType) { | 744 | if (deviceType_App() == phone_AppDeviceType) { |
745 | d->itemFonts[0] = defaultBig_FontId; | 745 | d->itemFonts[0] = uiLabelBig_FontId; |
746 | d->itemFonts[1] = defaultBigBold_FontId; | 746 | d->itemFonts[1] = defaultBigBold_FontId; |
747 | } | 747 | } |
748 | d->widthAsGaps = 73.0f; | 748 | d->widthAsGaps = 73.0f; |
@@ -774,7 +774,7 @@ void init_SidebarWidget(iSidebarWidget *d, enum iSidebarSide side) { | |||
774 | format_CStr("%s.mode arg:%d", cstr_String(id_Widget(w)), i))), | 774 | format_CStr("%s.mode arg:%d", cstr_String(id_Widget(w)), i))), |
775 | frameless_WidgetFlag | noBackground_WidgetFlag); | 775 | frameless_WidgetFlag | noBackground_WidgetFlag); |
776 | } | 776 | } |
777 | setButtonFont_SidebarWidget(d, isPhone ? defaultBig_FontId : uiLabel_FontId); | 777 | setButtonFont_SidebarWidget(d, isPhone ? uiLabelBig_FontId : uiLabel_FontId); |
778 | addChildFlags_Widget(vdiv, | 778 | addChildFlags_Widget(vdiv, |
779 | iClob(buttons), | 779 | iClob(buttons), |
780 | arrangeHorizontal_WidgetFlag | | 780 | arrangeHorizontal_WidgetFlag | |
@@ -936,8 +936,8 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
936 | if (deviceType_App() == phone_AppDeviceType) { | 936 | if (deviceType_App() == phone_AppDeviceType) { |
937 | /* Change font size depending on orientation. */ | 937 | /* Change font size depending on orientation. */ |
938 | const int fonts[2] = { | 938 | const int fonts[2] = { |
939 | isPortrait_App() ? defaultBig_FontId : uiContent_FontId, | 939 | isPortrait_App() ? uiLabelBig_FontId : uiContent_FontId, |
940 | isPortrait_App() ? defaultBigBold_FontId : uiContentBold_FontId | 940 | isPortrait_App() ? uiLabelBigBold_FontId : uiContentBold_FontId |
941 | }; | 941 | }; |
942 | if (d->itemFonts[0] != fonts[0]) { | 942 | if (d->itemFonts[0] != fonts[0]) { |
943 | d->itemFonts[0] = fonts[0]; | 943 | d->itemFonts[0] = fonts[0]; |
@@ -945,7 +945,7 @@ static void checkModeButtonLayout_SidebarWidget_(iSidebarWidget *d) { | |||
945 | // updateMetrics_SidebarWidget_(d); | 945 | // updateMetrics_SidebarWidget_(d); |
946 | updateItemHeight_SidebarWidget_(d); | 946 | updateItemHeight_SidebarWidget_(d); |
947 | } | 947 | } |
948 | setButtonFont_SidebarWidget(d, isPortrait_App() ? defaultBig_FontId : uiLabel_FontId); | 948 | setButtonFont_SidebarWidget(d, isPortrait_App() ? uiLabelBig_FontId : uiLabel_FontId); |
949 | } | 949 | } |
950 | const iBool isTight = | 950 | const iBool isTight = |
951 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); | 951 | (width_Rect(bounds_Widget(as_Widget(d->modeButtons[0]))) < d->maxButtonLabelWidth); |
@@ -1962,7 +1962,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
1962 | deinit_String(&str); | 1962 | deinit_String(&str); |
1963 | const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); | 1963 | const iInt2 textPos = addY_I2(topRight_Rect(iconArea), (itemHeight - lineHeight_Text(font)) / 2); |
1964 | drawRange_Text(font, textPos, fg, range_String(&d->label)); | 1964 | drawRange_Text(font, textPos, fg, range_String(&d->label)); |
1965 | const int metaFont = default_FontId; | 1965 | const int metaFont = uiLabel_FontId; |
1966 | const int metaIconWidth = 4.5f * gap_UI; | 1966 | const int metaIconWidth = 4.5f * gap_UI; |
1967 | const iInt2 metaPos = | 1967 | const iInt2 metaPos = |
1968 | init_I2(right_Rect(itemRect) - | 1968 | init_I2(right_Rect(itemRect) - |
@@ -2045,7 +2045,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
2045 | const int indent = 1.4f * lineHeight_Text(font); | 2045 | const int indent = 1.4f * lineHeight_Text(font); |
2046 | addv_I2(&cPos, | 2046 | addv_I2(&cPos, |
2047 | init_I2(3 * gap_UI, | 2047 | init_I2(3 * gap_UI, |
2048 | (itemHeight - lineHeight_Text(default_FontId) * 2 - lineHeight_Text(font)) / | 2048 | (itemHeight - lineHeight_Text(uiLabel_FontId) * 2 - lineHeight_Text(font)) / |
2049 | 2)); | 2049 | 2)); |
2050 | const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId | 2050 | const int metaFg = isHover ? permanent_ColorId | (isPressing ? uiTextPressed_ColorId |
2051 | : uiTextFramelessHover_ColorId) | 2051 | : uiTextFramelessHover_ColorId) |
@@ -2064,7 +2064,7 @@ static void draw_SidebarItem_(const iSidebarItem *d, iPaint *p, iRect itemRect, | |||
2064 | add_I2(cPos, init_I2(indent, 0)), | 2064 | add_I2(cPos, init_I2(indent, 0)), |
2065 | fg, | 2065 | fg, |
2066 | range_String(&d->label)); | 2066 | range_String(&d->label)); |
2067 | drawRange_Text(default_FontId, | 2067 | drawRange_Text(uiLabel_FontId, |
2068 | add_I2(cPos, init_I2(indent, lineHeight_Text(font))), | 2068 | add_I2(cPos, init_I2(indent, lineHeight_Text(font))), |
2069 | metaFg, | 2069 | metaFg, |
2070 | range_String(&d->meta)); | 2070 | range_String(&d->meta)); |
diff --git a/src/ui/text.c b/src/ui/text.c index cbce4715..3ed5b327 100644 --- a/src/ui/text.c +++ b/src/ui/text.c | |||
@@ -123,40 +123,60 @@ iDefineTypeConstructionArgs(Glyph, (iChar ch), ch) | |||
123 | 123 | ||
124 | static iGlyph *glyph_Font_(iFont *d, iChar ch); | 124 | static iGlyph *glyph_Font_(iFont *d, iChar ch); |
125 | 125 | ||
126 | struct Impl_Font { | 126 | iDeclareType(GlyphTable) |
127 | iBlock * data; | 127 | |
128 | enum iTextFont family; | 128 | struct Impl_GlyphTable { |
129 | stbtt_fontinfo font; | 129 | iHash glyphs; /* key is glyph index in the font */ |
130 | float xScale, yScale; | 130 | /* TODO: `glyphs` does not need to be a Hash. |
131 | int vertOffset; /* offset due to scaling */ | 131 | We could lazily allocate an array with glyphCount elements instead. */ |
132 | int height; | ||
133 | int baseline; | ||
134 | iHash glyphs; /* key is glyph index in the font */ /* TODO: does not need to be a Hash */ | ||
135 | iBool isMonospaced; | ||
136 | float emAdvance; | ||
137 | enum iFontSize sizeId; /* used to look up different fonts of matching size */ | ||
138 | uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ | 132 | uint32_t indexTable[128 - 32]; /* quick ASCII lookup */ |
139 | #if defined (LAGRANGE_ENABLE_HARFBUZZ) | ||
140 | hb_blob_t * hbBlob; /* raw TrueType data */ | ||
141 | hb_face_t * hbFace; | ||
142 | hb_font_t * hbMainFont; | ||
143 | hb_font_t * hbFont; /* may be a sub-font with customized font metrics */ | ||
144 | #endif | ||
145 | }; | 133 | }; |
146 | 134 | ||
147 | static iFont *font_Text_(enum iFontId id); | 135 | static void clearGlyphs_GlyphTable_(iGlyphTable *d) { |
148 | 136 | if (d) { | |
149 | #if 0 | 137 | iForEach(Hash, i, &d->glyphs) { |
150 | static hb_position_t hbGlyphHKernForNunito_(hb_font_t *font, void *fontData, | 138 | delete_Glyph((iGlyph *) i.value); |
151 | hb_codepoint_t firstGlyph, hb_codepoint_t secondGlyph, | 139 | } |
152 | void *userData) { | 140 | clear_Hash(&d->glyphs); |
153 | return 100; | 141 | } |
154 | } | 142 | } |
155 | #endif | ||
156 | 143 | ||
157 | static void init_Font(iFont *d, const iBlock *data, int height, float scale, | 144 | static void init_GlyphTable(iGlyphTable *d) { |
158 | enum iFontSize sizeId, iBool isMonospaced) { | ||
159 | init_Hash(&d->glyphs); | 145 | init_Hash(&d->glyphs); |
146 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); | ||
147 | } | ||
148 | |||
149 | static void deinit_GlyphTable(iGlyphTable *d) { | ||
150 | clearGlyphs_GlyphTable_(d); | ||
151 | deinit_Hash(&d->glyphs); | ||
152 | } | ||
153 | |||
154 | iDefineTypeConstruction(GlyphTable) | ||
155 | |||
156 | struct Impl_Font { | ||
157 | const iFontSpec *fontSpec; | ||
158 | const iFontFile *fontFile; | ||
159 | int height; | ||
160 | int baseline; | ||
161 | int vertOffset; /* offset due to glyph scaling */ | ||
162 | float xScale, yScale; | ||
163 | float emAdvance; | ||
164 | iGlyphTable * table; | ||
165 | }; | ||
166 | |||
167 | iLocalDef iBool isMonospaced_Font(const iFont *d) { | ||
168 | return (d->fontSpec->flags & monospace_FontSpecFlag) != 0; | ||
169 | } | ||
170 | |||
171 | static iFont *font_Text_(enum iFontId id); | ||
172 | |||
173 | static void init_Font(iFont *d, const iFontSpec *fontSpec, const iFontFile *fontFile, | ||
174 | enum iFontSize sizeId, float height) { | ||
175 | const int scaleType = scaleType_FontSpec(sizeId); | ||
176 | d->fontSpec = fontSpec; | ||
177 | d->fontFile = fontFile; | ||
178 | /* TODO: Nunito kerning fixes need to be a font parameter of its own. */ | ||
179 | #if 0 | ||
160 | d->data = NULL; | 180 | d->data = NULL; |
161 | d->family = undefined_TextFont; | 181 | d->family = undefined_TextFont; |
162 | /* Note: We only use `family` currently for applying a kerning fix to Nunito. */ | 182 | /* Note: We only use `family` currently for applying a kerning fix to Nunito. */ |
@@ -177,95 +197,44 @@ static void init_Font(iFont *d, const iBlock *data, int height, float scale, | |||
177 | data == &fontSmolEmojiRegular_Embedded) { | 197 | data == &fontSmolEmojiRegular_Embedded) { |
178 | d->family = emojiAndSymbols_TextFont; | 198 | d->family = emojiAndSymbols_TextFont; |
179 | } | 199 | } |
180 | d->isMonospaced = isMonospaced; | 200 | #endif |
181 | d->height = height; | 201 | d->height = (int) (height * fontSpec->heightScale[scaleType]); |
182 | iZap(d->font); | 202 | const float glyphScale = fontSpec->glyphScale[scaleType]; |
183 | stbtt_InitFont(&d->font, constData_Block(data), 0); | 203 | d->xScale = d->yScale = scaleForPixelHeight_FontFile(fontFile, d->height) * glyphScale; |
184 | int ascent, descent, emAdv; | 204 | if (isMonospaced_Font(d)) { |
185 | stbtt_GetFontVMetrics(&d->font, &ascent, &descent, NULL); | ||
186 | stbtt_GetCodepointHMetrics(&d->font, 'M', &emAdv, NULL); | ||
187 | d->xScale = d->yScale = stbtt_ScaleForPixelHeight(&d->font, height) * scale; | ||
188 | if (d->isMonospaced) { | ||
189 | /* It is important that monospaced fonts align 1:1 with the pixel grid so that | 205 | /* It is important that monospaced fonts align 1:1 with the pixel grid so that |
190 | box-drawing characters don't have partially occupied edge pixels, leading to seams | 206 | box-drawing characters don't have partially occupied edge pixels, leading to seams |
191 | between adjacent glyphs. */ | 207 | between adjacent glyphs. */ |
192 | const float advance = (float) emAdv * d->xScale; | 208 | const float advance = (float) fontFile->emAdvance * d->xScale; |
193 | if (advance > 4) { /* not too tiny */ | 209 | if (advance > 4) { /* not too tiny */ |
194 | d->xScale *= floorf(advance) / advance; | 210 | d->xScale *= floorf(advance) / advance; |
195 | } | 211 | } |
196 | } | 212 | } |
197 | d->emAdvance = emAdv * d->xScale; | 213 | d->emAdvance = fontFile->emAdvance * d->xScale; |
198 | d->baseline = ascent * d->yScale; | 214 | d->baseline = fontFile->ascent * d->yScale; |
199 | d->vertOffset = height * (1.0f - scale) / 2; | 215 | d->vertOffset = d->height * (1.0f - glyphScale) / 2 * fontSpec->vertOffsetScale[scaleType]; |
200 | /* Custom tweaks. */ | 216 | d->table = NULL; |
201 | if (data == &fontNotoSansSymbolsRegular_Embedded) { | 217 | // printf("{%s} height:%d baseline:%d\n", cstr_String(&d->fontSpec->id), d->height, d->baseline); |
202 | d->vertOffset *= 1.2f; | ||
203 | } | ||
204 | else if (data == &fontNotoSansSymbols2Regular_Embedded) { | ||
205 | d->vertOffset /= 2; | ||
206 | } | ||
207 | else if (data == &fontNotoEmojiRegular_Embedded) { | ||
208 | //d->vertOffset -= height / 30; | ||
209 | } | ||
210 | d->sizeId = sizeId; | ||
211 | memset(d->indexTable, 0xff, sizeof(d->indexTable)); | ||
212 | #if defined(LAGRANGE_ENABLE_HARFBUZZ) | ||
213 | /* HarfBuzz will read the font data. */ { | ||
214 | d->hbBlob = hb_blob_create(constData_Block(data), size_Block(data), | ||
215 | HB_MEMORY_MODE_READONLY, NULL, NULL); | ||
216 | d->hbFace = hb_face_create(d->hbBlob, 0); | ||
217 | d->hbMainFont = hb_font_create(d->hbFace); | ||
218 | #if 0 | ||
219 | /* TODO: The custom kerning function doesn't get called? | ||
220 | Maybe HarfBuzz needs FreeType to do kerning? */ | ||
221 | if (d->family == nunito_TextFont) { | ||
222 | /* Customize the kerning of Nunito. */ | ||
223 | d->hbFont = hb_font_create_sub_font(d->hbMainFont); | ||
224 | hb_font_funcs_t *ffs = hb_font_funcs_create(); | ||
225 | hb_font_funcs_set_glyph_h_kerning_func(ffs, hbGlyphHKernForNunito_, d, NULL); | ||
226 | hb_font_set_funcs(d->hbFont, ffs, NULL, NULL); | ||
227 | hb_font_funcs_destroy(ffs); | ||
228 | } | ||
229 | else | ||
230 | #endif | ||
231 | { | ||
232 | d->hbFont = hb_font_reference(d->hbMainFont); | ||
233 | } | ||
234 | } | ||
235 | #endif | ||
236 | } | ||
237 | |||
238 | static void clearGlyphs_Font_(iFont *d) { | ||
239 | iForEach(Hash, i, &d->glyphs) { | ||
240 | delete_Glyph((iGlyph *) i.value); | ||
241 | } | ||
242 | clear_Hash(&d->glyphs); | ||
243 | } | 218 | } |
244 | 219 | ||
245 | static void deinit_Font(iFont *d) { | 220 | static void deinit_Font(iFont *d) { |
246 | #if defined(LAGRANGE_ENABLE_HARFBUZZ) | 221 | delete_GlyphTable(d->table); |
247 | /* HarfBuzz objects. */ { | ||
248 | hb_font_destroy(d->hbFont); | ||
249 | hb_font_destroy(d->hbMainFont); | ||
250 | hb_face_destroy(d->hbFace); | ||
251 | hb_blob_destroy(d->hbBlob); | ||
252 | } | ||
253 | #endif | ||
254 | clearGlyphs_Font_(d); | ||
255 | deinit_Hash(&d->glyphs); | ||
256 | delete_Block(d->data); | ||
257 | } | 222 | } |
258 | 223 | ||
259 | static uint32_t glyphIndex_Font_(iFont *d, iChar ch) { | 224 | static uint32_t glyphIndex_Font_(iFont *d, iChar ch) { |
260 | /* TODO: Add a small cache of ~5 most recently found indices. */ | 225 | /* TODO: Add a small cache of ~5 most recently found indices. */ |
261 | const size_t entry = ch - 32; | 226 | const size_t entry = ch - 32; |
262 | if (entry < iElemCount(d->indexTable)) { | 227 | if (!d->table) { |
263 | if (d->indexTable[entry] == ~0u) { | 228 | d->table = new_GlyphTable(); |
264 | d->indexTable[entry] = stbtt_FindGlyphIndex(&d->font, ch); | 229 | } |
230 | iGlyphTable *table = d->table; | ||
231 | if (entry < iElemCount(table->indexTable)) { | ||
232 | if (table->indexTable[entry] == ~0u) { | ||
233 | table->indexTable[entry] = findGlyphIndex_FontFile(d->fontFile, ch); | ||
265 | } | 234 | } |
266 | return d->indexTable[entry]; | 235 | return table->indexTable[entry]; |
267 | } | 236 | } |
268 | return stbtt_FindGlyphIndex(&d->font, ch); | 237 | return findGlyphIndex_FontFile(d->fontFile, ch); |
269 | } | 238 | } |
270 | 239 | ||
271 | /*----------------------------------------------------------------------------------------------*/ | 240 | /*----------------------------------------------------------------------------------------------*/ |
@@ -279,10 +248,11 @@ struct Impl_CacheRow { | |||
279 | }; | 248 | }; |
280 | 249 | ||
281 | struct Impl_Text { | 250 | struct Impl_Text { |
282 | enum iTextFont contentFont; | 251 | // enum iTextFont contentFont; |
283 | enum iTextFont headingFont; | 252 | // enum iTextFont headingFont; |
284 | float contentFontSize; | 253 | float contentFontSize; |
285 | iFont fonts[max_FontId]; | 254 | iArray fonts; /* fonts currently selected for use (incl. all styles/sizes) */ |
255 | int overrideFontId; /* always checked for glyphs first, regardless of which font is used */ | ||
286 | SDL_Renderer * render; | 256 | SDL_Renderer * render; |
287 | SDL_Texture * cache; | 257 | SDL_Texture * cache; |
288 | iInt2 cacheSize; | 258 | iInt2 cacheSize; |
@@ -296,12 +266,55 @@ struct Impl_Text { | |||
296 | iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) | 266 | iDefineTypeConstructionArgs(Text, (SDL_Renderer *render), render) |
297 | 267 | ||
298 | static iText *activeText_; | 268 | static iText *activeText_; |
299 | static iBlock *userFont_; | 269 | |
270 | static void setupFontVariants_Text_(iText *d, const iFontSpec *spec, int baseId) { | ||
271 | #if defined (iPlatformMobile) | ||
272 | const float uiSize = fontSize_UI * 1.1f; | ||
273 | #else | ||
274 | const float uiSize = fontSize_UI; | ||
275 | #endif | ||
276 | const float textSize = fontSize_UI * d->contentFontSize; | ||
277 | // const float monoSize = textSize * 0.71f; | ||
278 | // const float smallMonoSize = monoSize * 0.8f; | ||
279 | if (spec->flags & override_FontSpecFlag && d->overrideFontId < 0) { | ||
280 | /* This is the highest priority override font. */ | ||
281 | d->overrideFontId = baseId; | ||
282 | } | ||
283 | for (enum iFontStyle style = 0; style < max_FontStyle; style++) { | ||
284 | for (enum iFontSize sizeId = 0; sizeId < max_FontSize; sizeId++) { | ||
285 | init_Font(font_Text_(FONT_ID(baseId, style, sizeId)), | ||
286 | spec, | ||
287 | spec->styles[style], | ||
288 | sizeId, | ||
289 | (sizeId < contentRegular_FontSize ? uiSize : textSize) * | ||
290 | scale_FontSize(sizeId)); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | iLocalDef iFont *font_Text_(enum iFontId id) { | ||
296 | return at_Array(&activeText_->fonts, id & mask_FontId); | ||
297 | } | ||
298 | |||
299 | static enum iFontId fontId_Text_(const iFont *font) { | ||
300 | return (enum iFontId) (font - (const iFont *) constData_Array(&activeText_->fonts)); | ||
301 | } | ||
302 | |||
303 | iLocalDef enum iFontSize sizeId_Text_(const iFont *d) { | ||
304 | return fontId_Text_(d) % max_FontSize; | ||
305 | } | ||
306 | |||
307 | iLocalDef enum iFontStyle styleId_Text_(const iFont *d) { | ||
308 | return (fontId_Text_(d) / max_FontSize) % max_FontStyle; | ||
309 | } | ||
310 | |||
311 | static const iFontSpec *tryFindSpec_(enum iPrefsString ps, const char *fallback) { | ||
312 | const iFontSpec *spec = findSpec_Fonts(cstr_String(&prefs_App()->strings[ps])); | ||
313 | return spec ? spec : findSpec_Fonts(fallback); | ||
314 | } | ||
300 | 315 | ||
301 | static void initFonts_Text_(iText *d) { | 316 | static void initFonts_Text_(iText *d) { |
302 | const float textSize = fontSize_UI * d->contentFontSize; | 317 | #if 0 |
303 | const float monoSize = textSize * 0.71f; | ||
304 | const float smallMonoSize = monoSize * 0.8f; | ||
305 | const iBlock *regularFont = &fontNunitoRegular_Embedded; | 318 | const iBlock *regularFont = &fontNunitoRegular_Embedded; |
306 | const iBlock *boldFont = &fontNunitoBold_Embedded; | 319 | const iBlock *boldFont = &fontNunitoBold_Embedded; |
307 | const iBlock *italicFont = &fontNunitoLightItalic_Embedded; | 320 | const iBlock *italicFont = &fontNunitoLightItalic_Embedded; |
@@ -367,15 +380,10 @@ static void initFonts_Text_(iText *d) { | |||
367 | h12Font = &fontIosevkaTermExtended_Embedded; | 380 | h12Font = &fontIosevkaTermExtended_Embedded; |
368 | h3Font = &fontIosevkaTermExtended_Embedded; | 381 | h3Font = &fontIosevkaTermExtended_Embedded; |
369 | } | 382 | } |
370 | #if defined (iPlatformMobile) | ||
371 | const float uiSize = fontSize_UI * 1.1f; | ||
372 | #else | ||
373 | const float uiSize = fontSize_UI; | ||
374 | #endif | ||
375 | const struct { | 383 | const struct { |
376 | const iBlock *ttf; | 384 | const iFontFile *fontFile; |
377 | int size; | 385 | int size; /* pixels */ |
378 | float scaling; | 386 | // float scaling; |
379 | enum iFontSize sizeId; | 387 | enum iFontSize sizeId; |
380 | /* UI sizes: 1.0, 1.125, 1.333, 1.666 */ | 388 | /* UI sizes: 1.0, 1.125, 1.333, 1.666 */ |
381 | /* Content sizes: smallmono, mono, 1.0, 1.2, 1.333, 1.666, 2.0 */ | 389 | /* Content sizes: smallmono, mono, 1.0, 1.2, 1.333, 1.666, 2.0 */ |
@@ -385,8 +393,8 @@ static void initFonts_Text_(iText *d) { | |||
385 | { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, | 393 | { &fontSourceSans3Regular_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
386 | { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, | 394 | { &fontSourceSans3Regular_Embedded, uiSize * 1.333f, 1.0f, uiBig_FontSize }, |
387 | { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, | 395 | { &fontSourceSans3Regular_Embedded, uiSize * 1.666f, 1.0f, uiLarge_FontSize }, |
388 | { &fontSourceSans3Regular_Embedded, uiSize * 0.900f, 1.0f, uiSmall_FontSize }, | ||
389 | { &fontSourceSans3Semibold_Embedded, uiSize * 0.800f, 1.0f, uiTiny_FontSize }, | 396 | { &fontSourceSans3Semibold_Embedded, uiSize * 0.800f, 1.0f, uiTiny_FontSize }, |
397 | { &fontSourceSans3Regular_Embedded, uiSize * 0.900f, 1.0f, uiSmall_FontSize }, | ||
390 | /* UI fonts: bold weight */ | 398 | /* UI fonts: bold weight */ |
391 | { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, | 399 | { &fontSourceSans3Bold_Embedded, uiSize, 1.0f, uiNormal_FontSize }, |
392 | { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, | 400 | { &fontSourceSans3Bold_Embedded, uiSize * 1.125f, 1.0f, uiMedium_FontSize }, |
@@ -408,12 +416,12 @@ static void initFonts_Text_(iText *d) { | |||
408 | { &fontSourceSans3Regular_Embedded, textSize * 0.80f, scaling, contentRegular_FontSize }, | 416 | { &fontSourceSans3Regular_Embedded, textSize * 0.80f, scaling, contentRegular_FontSize }, |
409 | /* symbols and scripts */ | 417 | /* symbols and scripts */ |
410 | #define DEFINE_FONT_SET(data, glyphScale) \ | 418 | #define DEFINE_FONT_SET(data, glyphScale) \ |
419 | { (data), uiSize * 0.800f, glyphScale, uiTiny_FontSize }, \ | ||
420 | { (data), uiSize * 0.900f, glyphScale, uiSmall_FontSize }, \ | ||
411 | { (data), uiSize, glyphScale, uiNormal_FontSize }, \ | 421 | { (data), uiSize, glyphScale, uiNormal_FontSize }, \ |
412 | { (data), uiSize * 1.125f, glyphScale, uiMedium_FontSize }, \ | 422 | { (data), uiSize * 1.125f, glyphScale, uiMedium_FontSize }, \ |
413 | { (data), uiSize * 1.333f, glyphScale, uiBig_FontSize }, \ | 423 | { (data), uiSize * 1.333f, glyphScale, uiBig_FontSize }, \ |
414 | { (data), uiSize * 1.666f, glyphScale, uiLarge_FontSize }, \ | 424 | { (data), uiSize * 1.666f, glyphScale, uiLarge_FontSize }, \ |
415 | { (data), uiSize * 0.900f, glyphScale, uiSmall_FontSize }, \ | ||
416 | { (data), uiSize * 0.800f, glyphScale, uiTiny_FontSize }, \ | ||
417 | { (data), textSize, glyphScale, contentRegular_FontSize }, \ | 425 | { (data), textSize, glyphScale, contentRegular_FontSize }, \ |
418 | { (data), textSize * 1.200f, glyphScale, contentMedium_FontSize }, \ | 426 | { (data), textSize * 1.200f, glyphScale, contentMedium_FontSize }, \ |
419 | { (data), textSize * 1.333f, glyphScale, contentBig_FontSize }, \ | 427 | { (data), textSize * 1.333f, glyphScale, contentBig_FontSize }, \ |
@@ -433,26 +441,39 @@ static void initFonts_Text_(iText *d) { | |||
433 | DEFINE_FONT_SET(&fontNotoSansArabicUIRegular_Embedded, 1.0f), | 441 | DEFINE_FONT_SET(&fontNotoSansArabicUIRegular_Embedded, 1.0f), |
434 | // DEFINE_FONT_SET(&fontScheherazadeNewRegular_Embedded, 1.0f), | 442 | // DEFINE_FONT_SET(&fontScheherazadeNewRegular_Embedded, 1.0f), |
435 | }; | 443 | }; |
436 | iForIndices(i, fontData) { | 444 | #endif |
437 | iFont *font = &d->fonts[i]; | 445 | /* The `fonts` array has precomputed scaling factors and other parameters in all sizes |
438 | init_Font(font, | 446 | and styles for each available font. Indices to `fonts` act as font runtime IDs. */ |
439 | fontData[i].ttf, | 447 | /* First the mandatory fonts. */ |
440 | fontData[i].size, | 448 | d->overrideFontId = -1; |
441 | fontData[i].scaling, | 449 | resize_Array(&d->fonts, auxiliary_FontId); /* room for the built-ins */ |
442 | fontData[i].sizeId, | 450 | setupFontVariants_Text_(d, tryFindSpec_(uiFont_PrefsString, "default"), default_FontId); |
443 | fontData[i].ttf == &fontIosevkaTermExtended_Embedded); | 451 | setupFontVariants_Text_(d, tryFindSpec_(monospaceFont_PrefsString, "iosevka"), monospace_FontId); |
452 | setupFontVariants_Text_(d, tryFindSpec_(headingFont_PrefsString, "default"), documentHeading_FontId); | ||
453 | setupFontVariants_Text_(d, tryFindSpec_(bodyFont_PrefsString, "default"), documentBody_FontId); | ||
454 | setupFontVariants_Text_(d, tryFindSpec_(monospaceDocumentFont_PrefsString, "iosevka-body"), documentMonospace_FontId); | ||
455 | /* Check if there are auxiliary fonts available and set those up, too. */ | ||
456 | iConstForEach(PtrArray, s, listSpecsByPriority_Fonts()) { | ||
457 | const iFontSpec *spec = s.ptr; | ||
458 | if (spec->flags & auxiliary_FontSpecFlag) { | ||
459 | const int fontId = size_Array(&d->fonts); | ||
460 | resize_Array(&d->fonts, fontId + maxVariants_Fonts); | ||
461 | setupFontVariants_Text_(d, spec, fontId); | ||
462 | } | ||
444 | } | 463 | } |
445 | gap_Text = iRound(gap_UI * d->contentFontSize); | 464 | gap_Text = iRound(gap_UI * d->contentFontSize); |
446 | } | 465 | } |
447 | 466 | ||
448 | static void deinitFonts_Text_(iText *d) { | 467 | static void deinitFonts_Text_(iText *d) { |
449 | iForIndices(i, d->fonts) { | 468 | iForEach(Array, i, &d->fonts) { |
450 | deinit_Font(&d->fonts[i]); | 469 | deinit_Font(i.value); |
451 | } | 470 | } |
471 | clear_Array(&d->fonts); | ||
452 | } | 472 | } |
453 | 473 | ||
454 | static int maxGlyphHeight_Text_(const iText *d) { | 474 | static int maxGlyphHeight_Text_(const iText *d) { |
455 | return 2 * d->contentFontSize * fontSize_UI; | 475 | /* Huge size is 2 * contentFontSize. */ |
476 | return 4 * d->contentFontSize * fontSize_UI; | ||
456 | } | 477 | } |
457 | 478 | ||
458 | static void initCache_Text_(iText *d) { | 479 | static void initCache_Text_(iText *d) { |
@@ -471,7 +492,7 @@ static void initCache_Text_(iText *d) { | |||
471 | /* Allocate initial (empty) rows. These will be assigned actual locations in the cache | 492 | /* Allocate initial (empty) rows. These will be assigned actual locations in the cache |
472 | once at least one glyph is stored. */ | 493 | once at least one glyph is stored. */ |
473 | for (int h = d->cacheRowAllocStep; | 494 | for (int h = d->cacheRowAllocStep; |
474 | h <= 2.5 * textSize + d->cacheRowAllocStep; | 495 | h <= 5 * textSize + d->cacheRowAllocStep; |
475 | h += d->cacheRowAllocStep) { | 496 | h += d->cacheRowAllocStep) { |
476 | pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); | 497 | pushBack_Array(&d->cacheRows, &(iCacheRow){ .height = 0 }); |
477 | } | 498 | } |
@@ -490,6 +511,7 @@ static void deinitCache_Text_(iText *d) { | |||
490 | SDL_DestroyTexture(d->cache); | 511 | SDL_DestroyTexture(d->cache); |
491 | } | 512 | } |
492 | 513 | ||
514 | #if 0 | ||
493 | void loadUserFonts_Text(void) { | 515 | void loadUserFonts_Text(void) { |
494 | if (userFont_) { | 516 | if (userFont_) { |
495 | delete_Block(userFont_); | 517 | delete_Block(userFont_); |
@@ -508,11 +530,14 @@ void loadUserFonts_Text(void) { | |||
508 | iRelease(f); | 530 | iRelease(f); |
509 | } | 531 | } |
510 | } | 532 | } |
533 | #endif | ||
511 | 534 | ||
512 | void init_Text(iText *d, SDL_Renderer *render) { | 535 | void init_Text(iText *d, SDL_Renderer *render) { |
513 | loadUserFonts_Text(); | 536 | iText *oldActive = activeText_; |
514 | d->contentFont = nunito_TextFont; | 537 | activeText_ = d; |
515 | d->headingFont = nunito_TextFont; | 538 | init_Array(&d->fonts, sizeof(iFont)); |
539 | // d->contentFont = nunito_TextFont; | ||
540 | // d->headingFont = nunito_TextFont; | ||
516 | d->contentFontSize = contentScale_Text_; | 541 | d->contentFontSize = contentScale_Text_; |
517 | d->ansiEscape = new_RegExp("[[()]([0-9;AB]*)m", 0); | 542 | d->ansiEscape = new_RegExp("[[()]([0-9;AB]*)m", 0); |
518 | d->render = render; | 543 | d->render = render; |
@@ -526,6 +551,7 @@ void init_Text(iText *d, SDL_Renderer *render) { | |||
526 | } | 551 | } |
527 | initCache_Text_(d); | 552 | initCache_Text_(d); |
528 | initFonts_Text_(d); | 553 | initFonts_Text_(d); |
554 | activeText_ = oldActive; | ||
529 | } | 555 | } |
530 | 556 | ||
531 | void deinit_Text(iText *d) { | 557 | void deinit_Text(iText *d) { |
@@ -534,6 +560,7 @@ void deinit_Text(iText *d) { | |||
534 | deinitCache_Text_(d); | 560 | deinitCache_Text_(d); |
535 | d->render = NULL; | 561 | d->render = NULL; |
536 | iRelease(d->ansiEscape); | 562 | iRelease(d->ansiEscape); |
563 | deinit_Array(&d->fonts); | ||
537 | } | 564 | } |
538 | 565 | ||
539 | void setCurrent_Text(iText *d) { | 566 | void setCurrent_Text(iText *d) { |
@@ -544,21 +571,15 @@ void setOpacity_Text(float opacity) { | |||
544 | SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); | 571 | SDL_SetTextureAlphaMod(activeText_->cache, iClamp(opacity, 0.0f, 1.0f) * 255 + 0.5f); |
545 | } | 572 | } |
546 | 573 | ||
547 | void setContentFont_Text(iText *d, enum iTextFont font) { | 574 | //void setFont_Text(iText *d, int fontId, const char *fontSpecId) { |
548 | if (d->contentFont != font) { | 575 | // setupFontVariants_Text_(d, findSpec_Fonts(fontSpecId), fontId); |
549 | d->contentFont = font; | 576 | // if (d->contentFont != font) { |
550 | resetFonts_Text(d); | 577 | // d->contentFont = font; |
551 | } | 578 | // resetFonts_Text(d); |
552 | } | 579 | // } |
580 | //} | ||
553 | 581 | ||
554 | void setHeadingFont_Text(iText *d, enum iTextFont font) { | 582 | void setDocumentFontSize_Text(iText *d, float fontSizeFactor) { |
555 | if (d->headingFont != font) { | ||
556 | d->headingFont = font; | ||
557 | resetFonts_Text(d); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | void setContentFontSize_Text(iText *d, float fontSizeFactor) { | ||
562 | fontSizeFactor *= contentScale_Text_; | 583 | fontSizeFactor *= contentScale_Text_; |
563 | iAssert(fontSizeFactor > 0); | 584 | iAssert(fontSizeFactor > 0); |
564 | if (iAbs(d->contentFontSize - fontSizeFactor) > 0.001f) { | 585 | if (iAbs(d->contentFontSize - fontSizeFactor) > 0.001f) { |
@@ -569,8 +590,8 @@ void setContentFontSize_Text(iText *d, float fontSizeFactor) { | |||
569 | 590 | ||
570 | static void resetCache_Text_(iText *d) { | 591 | static void resetCache_Text_(iText *d) { |
571 | deinitCache_Text_(d); | 592 | deinitCache_Text_(d); |
572 | for (int i = 0; i < max_FontId; i++) { | 593 | iForEach(Array, i, &d->fonts) { |
573 | clearGlyphs_Font_(&d->fonts[i]); | 594 | clearGlyphs_GlyphTable_(((iFont *) i.value)->table); |
574 | } | 595 | } |
575 | initCache_Text_(d); | 596 | initCache_Text_(d); |
576 | } | 597 | } |
@@ -582,14 +603,10 @@ void resetFonts_Text(iText *d) { | |||
582 | initFonts_Text_(d); | 603 | initFonts_Text_(d); |
583 | } | 604 | } |
584 | 605 | ||
585 | iLocalDef iFont *font_Text_(enum iFontId id) { | ||
586 | return &activeText_->fonts[id & mask_FontId]; | ||
587 | } | ||
588 | |||
589 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { | 606 | static SDL_Surface *rasterizeGlyph_Font_(const iFont *d, uint32_t glyphIndex, float xShift) { |
590 | int w, h; | 607 | int w, h; |
591 | uint8_t *bmp = stbtt_GetGlyphBitmapSubpixel( | 608 | uint8_t *bmp = rasterizeGlyph_FontFile(d->fontFile, d->xScale, d->yScale, xShift, glyphIndex, |
592 | &d->font, d->xScale, d->yScale, xShift, 0.0f, glyphIndex, &w, &h, 0, 0); | 609 | &w, &h); |
593 | SDL_Surface *surface8 = | 610 | SDL_Surface *surface8 = |
594 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); | 611 | SDL_CreateRGBSurfaceWithFormatFrom(bmp, w, h, 8, w, SDL_PIXELFORMAT_INDEX8); |
595 | SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE); | 612 | SDL_SetSurfaceBlendMode(surface8, SDL_BLENDMODE_NONE); |
@@ -636,8 +653,8 @@ static iInt2 assignCachePos_Text_(iText *d, iInt2 size) { | |||
636 | static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { | 653 | static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { |
637 | iRect *glRect = &glyph->rect[hoff]; | 654 | iRect *glRect = &glyph->rect[hoff]; |
638 | int x0, y0, x1, y1; | 655 | int x0, y0, x1, y1; |
639 | stbtt_GetGlyphBitmapBoxSubpixel( | 656 | measureGlyph_FontFile(d->fontFile, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, |
640 | &d->font, index_Glyph_(glyph), d->xScale, d->yScale, hoff * 0.5f, 0.0f, &x0, &y0, &x1, &y1); | 657 | &x0, &y0, &x1, &y1); |
641 | glRect->size = init_I2(x1 - x0, y1 - y0); | 658 | glRect->size = init_I2(x1 - x0, y1 - y0); |
642 | /* Determine placement in the glyph cache texture, advancing in rows. */ | 659 | /* Determine placement in the glyph cache texture, advancing in rows. */ |
643 | glRect->pos = assignCachePos_Text_(activeText_, glRect->size); | 660 | glRect->pos = assignCachePos_Text_(activeText_, glRect->size); |
@@ -645,7 +662,7 @@ static void allocate_Font_(iFont *d, iGlyph *glyph, int hoff) { | |||
645 | glyph->d[hoff].y += d->vertOffset; | 662 | glyph->d[hoff].y += d->vertOffset; |
646 | if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */ | 663 | if (hoff == 0) { /* hoff==1 uses same metrics as `glyph` */ |
647 | int adv; | 664 | int adv; |
648 | stbtt_GetGlyphHMetrics(&d->font, index_Glyph_(glyph), &adv, NULL); | 665 | stbtt_GetGlyphHMetrics(&d->fontFile->stbInfo, index_Glyph_(glyph), &adv, NULL); |
649 | glyph->advance = d->xScale * adv; | 666 | glyph->advance = d->xScale * adv; |
650 | } | 667 | } |
651 | } | 668 | } |
@@ -654,13 +671,18 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
654 | if (isVariationSelector_Char(ch)) { | 671 | if (isVariationSelector_Char(ch)) { |
655 | return d; | 672 | return d; |
656 | } | 673 | } |
657 | /* Smol Emoji overrides all other fonts. */ | 674 | const enum iFontStyle styleId = styleId_Text_(d); |
658 | if (ch != 0x20) { | 675 | const enum iFontSize sizeId = sizeId_Text_(d); |
659 | iFont *smol = font_Text_(smolEmoji_FontId + d->sizeId); | 676 | iFont *overrideFont = NULL; |
660 | if (smol != d && (*glyphIndex = glyphIndex_Font_(smol, ch)) != 0) { | 677 | if (ch != 0x20 && activeText_->overrideFontId >= 0) { |
661 | return smol; | 678 | /* Override font is checked first. */ |
679 | overrideFont = font_Text_(FONT_ID(activeText_->overrideFontId, styleId, sizeId)); | ||
680 | if (overrideFont != d && (*glyphIndex = glyphIndex_Font_(overrideFont, ch)) != 0) { | ||
681 | return overrideFont; | ||
662 | } | 682 | } |
663 | } | 683 | } |
684 | #if 0 | ||
685 | /* TODO: Put arrows in Smol Emoji. */ | ||
664 | /* Manual exceptions. */ { | 686 | /* Manual exceptions. */ { |
665 | if (ch >= 0x2190 && ch <= 0x2193 /* arrows */) { | 687 | if (ch >= 0x2190 && ch <= 0x2193 /* arrows */) { |
666 | d = font_Text_(iosevka_FontId + d->sizeId); | 688 | d = font_Text_(iosevka_FontId + d->sizeId); |
@@ -668,9 +690,33 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
668 | return d; | 690 | return d; |
669 | } | 691 | } |
670 | } | 692 | } |
693 | #endif | ||
694 | /* The font's own version of the glyph. */ | ||
671 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { | 695 | if ((*glyphIndex = glyphIndex_Font_(d, ch)) != 0) { |
672 | return d; | 696 | return d; |
673 | } | 697 | } |
698 | /* As a fallback, check all other available fonts of this size. */ | ||
699 | for (int aux = 0; aux < 2; aux++) { | ||
700 | for (iFont *font = font_Text_(FONT_ID(0, styleId, sizeId)); | ||
701 | font < (iFont *) end_Array(&activeText_->fonts); | ||
702 | font += maxVariants_Fonts) { | ||
703 | const iBool isAuxiliary = (font->fontSpec->flags & auxiliary_FontSpecFlag) ? 1 : 0; | ||
704 | if (aux == isAuxiliary) { | ||
705 | /* First try auxiliary fonts, then other remaining fonts. */ | ||
706 | continue; | ||
707 | } | ||
708 | if (font == d || font == overrideFont) { | ||
709 | continue; /* already checked this one */ | ||
710 | } | ||
711 | if ((*glyphIndex = glyphIndex_Font_(font, ch)) != 0) { | ||
712 | // printf("using %s[%f] for %lc (%x) => %d\n", | ||
713 | // cstr_String(&font->fontSpec->name), font->fontSpec->scaling, | ||
714 | // (int) ch, ch, glyphIndex_Font_(font, ch)); | ||
715 | return font; | ||
716 | } | ||
717 | } | ||
718 | } | ||
719 | #if 0 | ||
674 | const int fallbacks[] = { | 720 | const int fallbacks[] = { |
675 | notoEmoji_FontId, | 721 | notoEmoji_FontId, |
676 | symbols2_FontId, | 722 | symbols2_FontId, |
@@ -732,6 +778,7 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
732 | if (d != font) { | 778 | if (d != font) { |
733 | *glyphIndex = glyphIndex_Font_(font, ch); | 779 | *glyphIndex = glyphIndex_Font_(font, ch); |
734 | } | 780 | } |
781 | #endif // 0 | ||
735 | if (!*glyphIndex) { | 782 | if (!*glyphIndex) { |
736 | fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); | 783 | fprintf(stderr, "failed to find %08x (%lc)\n", ch, (int)ch); fflush(stderr); |
737 | } | 784 | } |
@@ -739,8 +786,9 @@ iLocalDef iFont *characterFont_Font_(iFont *d, iChar ch, uint32_t *glyphIndex) { | |||
739 | } | 786 | } |
740 | 787 | ||
741 | static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { | 788 | static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { |
789 | iAssert(d->table); | ||
742 | iGlyph* glyph = NULL; | 790 | iGlyph* glyph = NULL; |
743 | void * node = value_Hash(&d->glyphs, glyphIndex); | 791 | void * node = value_Hash(&d->table->glyphs, glyphIndex); |
744 | if (node) { | 792 | if (node) { |
745 | glyph = node; | 793 | glyph = node; |
746 | } | 794 | } |
@@ -758,7 +806,7 @@ static iGlyph *glyphByIndex_Font_(iFont *d, uint32_t glyphIndex) { | |||
758 | and updates the glyph metrics. */ | 806 | and updates the glyph metrics. */ |
759 | allocate_Font_(d, glyph, 0); | 807 | allocate_Font_(d, glyph, 0); |
760 | allocate_Font_(d, glyph, 1); | 808 | allocate_Font_(d, glyph, 1); |
761 | insert_Hash(&d->glyphs, &glyph->node); | 809 | insert_Hash(&d->table->glyphs, &glyph->node); |
762 | } | 810 | } |
763 | return glyph; | 811 | return glyph; |
764 | } | 812 | } |
@@ -866,10 +914,6 @@ static void finishRun_AttributedText_(iAttributedText *d, iAttributedRun *run, i | |||
866 | run->logical.start = endAt; | 914 | run->logical.start = endAt; |
867 | } | 915 | } |
868 | 916 | ||
869 | static enum iFontId fontId_Text_(const iFont *font) { | ||
870 | return (enum iFontId) (font - activeText_->fonts); | ||
871 | } | ||
872 | |||
873 | static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) { | 917 | static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iChar overrideChar) { |
874 | iAssert(isEmpty_Array(&d->runs)); | 918 | iAssert(isEmpty_Array(&d->runs)); |
875 | size_t length = 0; | 919 | size_t length = 0; |
@@ -997,14 +1041,14 @@ static void prepare_AttributedText_(iAttributedText *d, int overrideBaseDir, iCh | |||
997 | continue; | 1041 | continue; |
998 | } | 1042 | } |
999 | if (ch == 0x20) { | 1043 | if (ch == 0x20) { |
1000 | if (run.font->family == emojiAndSymbols_TextFont) { | 1044 | if (run.font->fontSpec->flags & auxiliary_FontSpecFlag) { |
1001 | finishRun_AttributedText_(d, &run, pos); | 1045 | finishRun_AttributedText_(d, &run, pos); |
1002 | run.font = d->font; /* never use space from the symbols font, it's too wide */ | 1046 | run.font = d->font; /* never use space from the symbols font, it's too wide */ |
1003 | } | 1047 | } |
1004 | continue; | 1048 | continue; |
1005 | } | 1049 | } |
1006 | iFont *currentFont = d->font; | 1050 | iFont *currentFont = d->font; |
1007 | if (run.font->family == arabic_TextFont && isPunct_Char(ch)) { | 1051 | if (run.font->fontSpec->flags & arabic_FontSpecFlag && isPunct_Char(ch)) { |
1008 | currentFont = run.font; /* remain as Arabic for whitespace */ | 1052 | currentFont = run.font; /* remain as Arabic for whitespace */ |
1009 | } | 1053 | } |
1010 | const iGlyph *glyph = glyph_Font_(currentFont, ch); | 1054 | const iGlyph *glyph = glyph_Font_(currentFont, ch); |
@@ -1283,7 +1327,7 @@ static iBool notify_WrapText_(iWrapText *d, const char *ending, int origin, int | |||
1283 | 1327 | ||
1284 | float horizKern_Font_(iFont *d, uint32_t glyph1, uint32_t glyph2) { | 1328 | float horizKern_Font_(iFont *d, uint32_t glyph1, uint32_t glyph2) { |
1285 | #if defined (LAGRANGE_ENABLE_KERNING) | 1329 | #if defined (LAGRANGE_ENABLE_KERNING) |
1286 | if (!enableKerning_Text || d->family != nunito_TextFont) { | 1330 | if (!enableKerning_Text || ~d->fontSpec->flags & fixNunitoKerning_FontSpecFlag) { |
1287 | return 0.0f; | 1331 | return 0.0f; |
1288 | } | 1332 | } |
1289 | if (glyph1 && glyph2) { | 1333 | if (glyph1 && glyph2) { |
@@ -1335,7 +1379,7 @@ static void deinit_GlyphBuffer_(iGlyphBuffer *d) { | |||
1335 | 1379 | ||
1336 | static void shape_GlyphBuffer_(iGlyphBuffer *d) { | 1380 | static void shape_GlyphBuffer_(iGlyphBuffer *d) { |
1337 | if (!d->glyphInfo) { | 1381 | if (!d->glyphInfo) { |
1338 | hb_shape(d->font->hbFont, d->hb, NULL, 0); | 1382 | hb_shape(d->font->fontFile->hbFont, d->hb, NULL, 0); |
1339 | d->glyphInfo = hb_buffer_get_glyph_infos(d->hb, &d->glyphCount); | 1383 | d->glyphInfo = hb_buffer_get_glyph_infos(d->hb, &d->glyphCount); |
1340 | d->glyphPos = hb_buffer_get_glyph_positions(d->hb, &d->glyphCount); | 1384 | d->glyphPos = hb_buffer_get_glyph_positions(d->hb, &d->glyphCount); |
1341 | } | 1385 | } |
@@ -1389,7 +1433,7 @@ static iRect run_Font_(iFont *d, const iRunArgs *args) { | |||
1389 | float xCursor = 0.0f; | 1433 | float xCursor = 0.0f; |
1390 | float yCursor = 0.0f; | 1434 | float yCursor = 0.0f; |
1391 | float xCursorMax = 0.0f; | 1435 | float xCursorMax = 0.0f; |
1392 | const iBool isMonospaced = d->isMonospaced; | 1436 | const iBool isMonospaced = isMonospaced_Font(d); |
1393 | iWrapText *wrap = args->wrap; | 1437 | iWrapText *wrap = args->wrap; |
1394 | iAssert(args->text.end >= args->text.start); | 1438 | iAssert(args->text.end >= args->text.start); |
1395 | /* Split the text into a number of attributed runs that specify exactly which | 1439 | /* Split the text into a number of attributed runs that specify exactly which |
@@ -1824,6 +1868,11 @@ int lineHeight_Text(int fontId) { | |||
1824 | return font_Text_(fontId)->height; | 1868 | return font_Text_(fontId)->height; |
1825 | } | 1869 | } |
1826 | 1870 | ||
1871 | float emRatio_Text(int fontId) { | ||
1872 | const iFont *font = font_Text_(fontId); | ||
1873 | return font->emAdvance / font->height; | ||
1874 | } | ||
1875 | |||
1827 | iTextMetrics measureRange_Text(int fontId, iRangecc text) { | 1876 | iTextMetrics measureRange_Text(int fontId, iRangecc text) { |
1828 | if (isEmpty_Range(&text)) { | 1877 | if (isEmpty_Range(&text)) { |
1829 | return (iTextMetrics){ init_Rect(0, 0, 0, lineHeight_Text(fontId)), zero_I2() }; | 1878 | return (iTextMetrics){ init_Rect(0, 0, 0, lineHeight_Text(fontId)), zero_I2() }; |
diff --git a/src/ui/text.h b/src/ui/text.h index 35ae48f8..ac59e7c8 100644 --- a/src/ui/text.h +++ b/src/ui/text.h | |||
@@ -25,108 +25,68 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
25 | #include <the_Foundation/rect.h> | 25 | #include <the_Foundation/rect.h> |
26 | #include <the_Foundation/string.h> | 26 | #include <the_Foundation/string.h> |
27 | #include <the_Foundation/vec2.h> | 27 | #include <the_Foundation/vec2.h> |
28 | |||
29 | #include <SDL_render.h> | 28 | #include <SDL_render.h> |
30 | 29 | ||
31 | /* Content sizes: regular (1x) -> medium (1.2x) -> big (1.33x) -> large (1.67x) -> huge (2x) */ | 30 | #include "fontpack.h" |
32 | 31 | ||
33 | enum iFontSize { | 32 | /* Content sizes: regular (1x) -> medium (1.2x) -> big (1.33x) -> large (1.67x) -> huge (2x) */ |
34 | uiNormal_FontSize, /* 1.000 */ | ||
35 | uiMedium_FontSize, /* 1.125 */ | ||
36 | uiBig_FontSize, /* 1.333 */ | ||
37 | uiLarge_FontSize, /* 1.666 */ | ||
38 | uiSmall_FontSize, /* 0.900 */ | ||
39 | uiTiny_FontSize, /* 0.800 */ | ||
40 | contentRegular_FontSize, | ||
41 | contentMedium_FontSize, | ||
42 | contentBig_FontSize, | ||
43 | contentLarge_FontSize, | ||
44 | contentHuge_FontSize, | ||
45 | contentMonoSmall_FontSize, | ||
46 | contentMono_FontSize, | ||
47 | max_FontSize, | ||
48 | }; | ||
49 | 33 | ||
50 | iLocalDef enum iFontSize larger_FontSize(enum iFontSize size) { | 34 | #define FONT_ID(name, style, size) ((name) + ((style) * max_FontSize) + (size)) |
51 | if (size == uiLarge_FontSize || size == contentHuge_FontSize || size == contentMono_FontSize) { | ||
52 | return size; /* biggest available */ | ||
53 | } | ||
54 | return size + 1; | ||
55 | } | ||
56 | 35 | ||
57 | enum iFontId { | 36 | enum iFontId { |
58 | /* UI fonts: normal weight (1x, 1.125x, 1.33x, 1.67x) */ | 37 | default_FontId = 0, /* default is always the first font */ |
59 | default_FontId = 0, | 38 | monospace_FontId = maxVariants_Fonts, /* 2nd font is always the monospace font */ |
60 | defaultMedium_FontId, | 39 | documentHeading_FontId = maxVariants_Fonts * 2, /* heading font */ |
61 | defaultBig_FontId, | 40 | documentBody_FontId = maxVariants_Fonts * 3, /* body font */ |
62 | defaultLarge_FontId, | 41 | documentMonospace_FontId = maxVariants_Fonts * 4, |
63 | defaultSmall_FontId, | 42 | auxiliary_FontId = maxVariants_Fonts * 5, /* the first auxiliary font (e.g., symbols) */ |
64 | defaultTiny_FontId, | ||
65 | /* UI fonts: bold weight */ | ||
66 | defaultBold_FontId, | ||
67 | defaultMediumBold_FontId, | ||
68 | defaultBigBold_FontId, | ||
69 | defaultLargeBold_FontId, | ||
70 | /* content fonts */ | ||
71 | regular_FontId, | ||
72 | bold_FontId, | ||
73 | italic_FontId, | ||
74 | medium_FontId, | ||
75 | big_FontId, | ||
76 | largeBold_FontId, | ||
77 | largeLight_FontId, | ||
78 | hugeBold_FontId, | ||
79 | monospaceSmall_FontId, | ||
80 | monospace_FontId, | ||
81 | /* extra content fonts */ | ||
82 | defaultContentRegular_FontId, /* UI font but sized to regular_FontId */ | ||
83 | defaultContentSmall_FontId, /* UI font but sized smaller */ | ||
84 | /* symbols and scripts */ | ||
85 | userSymbols_FontId, | ||
86 | iosevka_FontId = userSymbols_FontId + max_FontSize, | ||
87 | symbols_FontId = iosevka_FontId + max_FontSize, | ||
88 | symbols2_FontId = symbols_FontId + max_FontSize, | ||
89 | smolEmoji_FontId = symbols2_FontId + max_FontSize, | ||
90 | notoEmoji_FontId = smolEmoji_FontId + max_FontSize, | ||
91 | japanese_FontId = notoEmoji_FontId + max_FontSize, | ||
92 | chineseSimplified_FontId = japanese_FontId + max_FontSize, | ||
93 | korean_FontId = chineseSimplified_FontId + max_FontSize, | ||
94 | arabic_FontId = korean_FontId + max_FontSize, | ||
95 | max_FontId = arabic_FontId + max_FontSize, | ||
96 | 43 | ||
97 | /* Meta: */ | 44 | /* Meta: */ |
98 | mask_FontId = 0xffff, | 45 | mask_FontId = 0x0000ffff, /* font IDs are 16-bit; see GmRun's packing */ |
99 | alwaysVariableFlag_FontId = 0x10000, | 46 | alwaysVariableFlag_FontId = 0x00010000, |
100 | 47 | ||
101 | /* UI fonts: */ | 48 | /* UI fonts: */ |
102 | uiLabel_FontId = default_FontId, | 49 | uiLabelTiny_FontId = FONT_ID(default_FontId, semiBold_FontStyle, uiTiny_FontSize), |
103 | uiLabelBold_FontId = defaultBold_FontId, | 50 | uiLabelSmall_FontId = FONT_ID(default_FontId, regular_FontStyle, uiSmall_FontSize), |
104 | uiLabelLarge_FontId = defaultLarge_FontId, | 51 | uiLabel_FontId = FONT_ID(default_FontId, regular_FontStyle, uiNormal_FontSize), |
105 | uiLabelLargeBold_FontId = defaultLargeBold_FontId, | 52 | uiLabelMedium_FontId = FONT_ID(default_FontId, regular_FontStyle, uiMedium_FontSize), |
106 | uiShortcuts_FontId = default_FontId, | 53 | uiLabelMediumBold_FontId = FONT_ID(default_FontId, bold_FontStyle, uiMedium_FontSize), |
107 | uiInput_FontId = defaultMedium_FontId, | 54 | uiLabelBig_FontId = FONT_ID(default_FontId, regular_FontStyle, uiBig_FontSize), |
108 | uiContent_FontId = defaultMedium_FontId, | 55 | uiLabelBold_FontId = FONT_ID(default_FontId, bold_FontStyle, uiNormal_FontSize), |
109 | uiContentBold_FontId = defaultMediumBold_FontId, | 56 | uiLabelBigBold_FontId = FONT_ID(default_FontId, bold_FontStyle, uiBig_FontSize), |
110 | uiContentSymbols_FontId = symbols_FontId + uiMedium_FontSize, | 57 | uiLabelLarge_FontId = FONT_ID(default_FontId, regular_FontStyle, uiLarge_FontSize), |
111 | /* Document fonts: */ | 58 | uiLabelLargeBold_FontId = FONT_ID(default_FontId, bold_FontStyle, uiLarge_FontSize), |
112 | paragraph_FontId = regular_FontId, | 59 | uiLabelSymbols_FontId = FONT_ID(auxiliary_FontId, regular_FontStyle, uiNormal_FontSize), |
113 | firstParagraph_FontId = medium_FontId, | 60 | uiShortcuts_FontId = FONT_ID(default_FontId, regular_FontStyle, uiNormal_FontSize), |
114 | preformatted_FontId = monospace_FontId, | 61 | uiInput_FontId = FONT_ID(default_FontId, regular_FontStyle, uiMedium_FontSize), |
115 | preformattedSmall_FontId = monospaceSmall_FontId, | 62 | uiContent_FontId = FONT_ID(default_FontId, regular_FontStyle, uiMedium_FontSize), |
116 | quote_FontId = italic_FontId, | 63 | uiContentBold_FontId = FONT_ID(default_FontId, bold_FontStyle, uiMedium_FontSize), |
117 | heading1_FontId = hugeBold_FontId, | 64 | uiContentSymbols_FontId = FONT_ID(auxiliary_FontId, regular_FontStyle, uiMedium_FontSize), |
118 | heading2_FontId = largeBold_FontId, | 65 | |
119 | heading3_FontId = big_FontId, | 66 | /* Document fonts: */ |
120 | banner_FontId = largeLight_FontId, | 67 | paragraph_FontId = FONT_ID(documentBody_FontId, regular_FontStyle, contentRegular_FontSize), |
121 | regularMonospace_FontId = iosevka_FontId + contentRegular_FontSize | 68 | bold_FontId = FONT_ID(documentBody_FontId, semiBold_FontStyle, contentRegular_FontSize), |
69 | firstParagraph_FontId = FONT_ID(documentBody_FontId, regular_FontStyle, contentMedium_FontSize), | ||
70 | preformatted_FontId = FONT_ID(monospace_FontId, regular_FontStyle, contentSmall_FontSize), | ||
71 | preformattedSmall_FontId = FONT_ID(monospace_FontId, regular_FontStyle, contentTiny_FontSize), | ||
72 | quote_FontId = FONT_ID(documentBody_FontId, italic_FontStyle, contentRegular_FontSize), | ||
73 | heading1_FontId = FONT_ID(documentHeading_FontId, bold_FontStyle, contentHuge_FontSize), | ||
74 | heading2_FontId = FONT_ID(documentHeading_FontId, bold_FontStyle, contentLarge_FontSize), | ||
75 | heading3_FontId = FONT_ID(documentHeading_FontId, regular_FontStyle, contentBig_FontSize), | ||
76 | banner_FontId = FONT_ID(documentHeading_FontId, light_FontStyle, contentLarge_FontSize), | ||
77 | monospaceParagraph_FontId = FONT_ID(documentMonospace_FontId, regular_FontStyle, contentRegular_FontSize), | ||
78 | monospaceBold_FontId = FONT_ID(documentMonospace_FontId, semiBold_FontStyle, contentRegular_FontSize), | ||
79 | plainText_FontId = FONT_ID(documentMonospace_FontId, regular_FontStyle, contentRegular_FontSize), | ||
122 | }; | 80 | }; |
123 | 81 | ||
124 | iLocalDef iBool isJapanese_FontId(enum iFontId id) { | 82 | //iLocalDef iBool isJapanese_FontId(enum iFontId id) { |
125 | return id >= japanese_FontId && id < japanese_FontId + max_FontSize; | 83 | // return id >= japanese_FontId && id < japanese_FontId + max_FontSize; |
126 | } | 84 | //} |
127 | 85 | ||
128 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) | 86 | #define emojiVariationSelector_Char ((iChar) 0xfe0f) |
129 | 87 | ||
88 | #if 0 | ||
89 | /* TODO: get rid of this; configure using font ID strings, check RTL from FontFile flags */ | ||
130 | enum iTextFont { | 90 | enum iTextFont { |
131 | undefined_TextFont = -1, | 91 | undefined_TextFont = -1, |
132 | nunito_TextFont = 0, | 92 | nunito_TextFont = 0, |
@@ -139,6 +99,7 @@ enum iTextFont { | |||
139 | arabic_TextFont, | 99 | arabic_TextFont, |
140 | emojiAndSymbols_TextFont, | 100 | emojiAndSymbols_TextFont, |
141 | }; | 101 | }; |
102 | #endif | ||
142 | 103 | ||
143 | extern int gap_Text; /* affected by content font size */ | 104 | extern int gap_Text; /* affected by content font size */ |
144 | 105 | ||
@@ -150,14 +111,14 @@ void deinit_Text (iText *); | |||
150 | 111 | ||
151 | void setCurrent_Text (iText *); | 112 | void setCurrent_Text (iText *); |
152 | 113 | ||
153 | void loadUserFonts_Text (void); /* based on Prefs */ | 114 | //void setContentFont_Text (iText *, enum iTextFont font); |
154 | 115 | //void setHeadingFont_Text (iText *, enum iTextFont font); | |
155 | void setContentFont_Text (iText *, enum iTextFont font); | 116 | //void setFont_Text (iText *, int fontId, const char *fontSpecId); |
156 | void setHeadingFont_Text (iText *, enum iTextFont font); | 117 | void setDocumentFontSize_Text(iText *, float fontSizeFactor); /* affects all except `default*` fonts */ |
157 | void setContentFontSize_Text (iText *, float fontSizeFactor); /* affects all except `default*` fonts */ | ||
158 | void resetFonts_Text (iText *); | 118 | void resetFonts_Text (iText *); |
159 | 119 | ||
160 | int lineHeight_Text (int fontId); | 120 | int lineHeight_Text (int fontId); |
121 | float emRatio_Text (int fontId); /* em advance to line height ratio */ | ||
161 | iRect visualBounds_Text (int fontId, iRangecc text); | 122 | iRect visualBounds_Text (int fontId, iRangecc text); |
162 | 123 | ||
163 | iDeclareType(TextMetrics) | 124 | iDeclareType(TextMetrics) |
diff --git a/src/ui/uploadwidget.c b/src/ui/uploadwidget.c index ba7545fd..3bd11cfb 100644 --- a/src/ui/uploadwidget.c +++ b/src/ui/uploadwidget.c | |||
@@ -255,7 +255,7 @@ void init_UploadWidget(iUploadWidget *d) { | |||
255 | setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue); | 255 | setFlags_Widget(as_Widget(d->token), expand_WidgetFlag, iTrue); |
256 | setFocus_Widget(as_Widget(d->input)); | 256 | setFocus_Widget(as_Widget(d->input)); |
257 | } | 257 | } |
258 | setFont_InputWidget(d->input, iosevka_FontId); | 258 | setFont_InputWidget(d->input, FONT_ID(monospace_FontId, regular_FontStyle, uiSmall_FontSize)); |
259 | setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */ | 259 | setUseReturnKeyBehavior_InputWidget(d->input, iFalse); /* traditional text editor */ |
260 | setLineLimits_InputWidget(d->input, 7, 20); | 260 | setLineLimits_InputWidget(d->input, 7, 20); |
261 | setHint_InputWidget(d->input, "${hint.upload.text}"); | 261 | setHint_InputWidget(d->input, "${hint.upload.text}"); |
diff --git a/src/ui/util.c b/src/ui/util.c index adca6269..ab799a36 100644 --- a/src/ui/util.c +++ b/src/ui/util.c | |||
@@ -841,7 +841,7 @@ iWidget *makeMenu_Widget(iWidget *parent, const iMenuItem *items, size_t n) { | |||
841 | (isPortraitPhone_App() ? drawBackgroundToVerticalSafeArea_WidgetFlag : 0), | 841 | (isPortraitPhone_App() ? drawBackgroundToVerticalSafeArea_WidgetFlag : 0), |
842 | iTrue); | 842 | iTrue); |
843 | if (!isPortraitPhone_App()) { | 843 | if (!isPortraitPhone_App()) { |
844 | setFrameColor_Widget(menu, uiSeparator_ColorId); | 844 | setFrameColor_Widget(menu, uiBackgroundSelected_ColorId); |
845 | } | 845 | } |
846 | makeMenuItems_Widget(menu, items, n); | 846 | makeMenuItems_Widget(menu, items, n); |
847 | addChild_Widget(parent, menu); | 847 | addChild_Widget(parent, menu); |
@@ -873,7 +873,7 @@ static void updateMenuItemFonts_Widget_(iWidget *d) { | |||
873 | } | 873 | } |
874 | else if (isPortraitPhone) { | 874 | else if (isPortraitPhone) { |
875 | if (!isSlidePanel) { | 875 | if (!isSlidePanel) { |
876 | setFont_LabelWidget(label, isCaution ? defaultBigBold_FontId : defaultBig_FontId); | 876 | setFont_LabelWidget(label, isCaution ? uiLabelBigBold_FontId : uiLabelBig_FontId); |
877 | } | 877 | } |
878 | } | 878 | } |
879 | else { | 879 | else { |
@@ -1626,8 +1626,8 @@ iWidget *makeDialogButtons_Widget(const iMenuItem *actions, size_t numActions) { | |||
1626 | } | 1626 | } |
1627 | int fonts[2] = { uiLabel_FontId, uiLabelBold_FontId }; | 1627 | int fonts[2] = { uiLabel_FontId, uiLabelBold_FontId }; |
1628 | if (deviceType_App() == phone_AppDeviceType) { | 1628 | if (deviceType_App() == phone_AppDeviceType) { |
1629 | fonts[0] = defaultMedium_FontId; | 1629 | fonts[0] = uiLabelMedium_FontId; |
1630 | fonts[1] = defaultMediumBold_FontId; | 1630 | fonts[1] = uiLabelMediumBold_FontId; |
1631 | } | 1631 | } |
1632 | for (size_t i = 0; i < numActions; i++) { | 1632 | for (size_t i = 0; i < numActions; i++) { |
1633 | const char *label = actions[i].label; | 1633 | const char *label = actions[i].label; |
@@ -1694,7 +1694,7 @@ iWidget *makeValueInput_Widget(iWidget *parent, const iString *initialValue, con | |||
1694 | resizeToParentWidth_WidgetFlag); | 1694 | resizeToParentWidth_WidgetFlag); |
1695 | setContentPadding_InputWidget(input, 0.5f * gap_UI, 0.5f * gap_UI); | 1695 | setContentPadding_InputWidget(input, 0.5f * gap_UI, 0.5f * gap_UI); |
1696 | if (deviceType_App() == phone_AppDeviceType) { | 1696 | if (deviceType_App() == phone_AppDeviceType) { |
1697 | setFont_InputWidget(input, defaultBig_FontId); | 1697 | setFont_InputWidget(input, uiLabelBig_FontId); |
1698 | setBackgroundColor_Widget(dlg, uiBackgroundSidebar_ColorId); | 1698 | setBackgroundColor_Widget(dlg, uiBackgroundSidebar_ColorId); |
1699 | setContentPadding_InputWidget(input, gap_UI, gap_UI); | 1699 | setContentPadding_InputWidget(input, gap_UI, gap_UI); |
1700 | } | 1700 | } |
@@ -1811,7 +1811,7 @@ iWidget *makeQuestion_Widget(const char *title, const char *msg, | |||
1811 | resizeToParentWidth_WidgetFlag | | 1811 | resizeToParentWidth_WidgetFlag | |
1812 | (first == '&' ? selected_WidgetFlag : 0)); | 1812 | (first == '&' ? selected_WidgetFlag : 0)); |
1813 | if (deviceType_App() != desktop_AppDeviceType) { | 1813 | if (deviceType_App() != desktop_AppDeviceType) { |
1814 | setFont_LabelWidget(option, defaultBig_FontId); | 1814 | setFont_LabelWidget(option, uiLabelBig_FontId); |
1815 | } | 1815 | } |
1816 | } | 1816 | } |
1817 | } | 1817 | } |
@@ -1931,7 +1931,38 @@ static void addRadioButton_(iWidget *parent, const char *id, const char *label, | |||
1931 | id); | 1931 | id); |
1932 | } | 1932 | } |
1933 | 1933 | ||
1934 | static iBool proportionalFonts_(const iFontSpec *spec) { | ||
1935 | return (spec->flags & monospace_FontSpecFlag) == 0 && ~spec->flags & auxiliary_FontSpecFlag; | ||
1936 | } | ||
1937 | |||
1938 | static iBool monospaceFonts_(const iFontSpec *spec) { | ||
1939 | return (spec->flags & monospace_FontSpecFlag) != 0 && ~spec->flags & auxiliary_FontSpecFlag; | ||
1940 | } | ||
1941 | |||
1934 | static const iArray *makeFontItems_(const char *id) { | 1942 | static const iArray *makeFontItems_(const char *id) { |
1943 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | ||
1944 | if (!startsWith_CStr(id, "mono")) { | ||
1945 | iConstForEach(PtrArray, i, listSpecs_Fonts(proportionalFonts_)) { | ||
1946 | const iFontSpec *spec = i.ptr; | ||
1947 | pushBack_Array( | ||
1948 | items, | ||
1949 | &(iMenuItem){ cstr_String(&spec->name), | ||
1950 | 0, | ||
1951 | 0, | ||
1952 | format_CStr("!font.set %s:%s", id, cstr_String(&spec->id)) }); | ||
1953 | } | ||
1954 | pushBack_Array(items, &(iMenuItem){ "---" }); | ||
1955 | } | ||
1956 | iConstForEach(PtrArray, j, listSpecs_Fonts(monospaceFonts_)) { | ||
1957 | const iFontSpec *spec = j.ptr; | ||
1958 | pushBack_Array( | ||
1959 | items, | ||
1960 | &(iMenuItem){ cstr_String(&spec->name), | ||
1961 | 0, | ||
1962 | 0, | ||
1963 | format_CStr("!font.set %s:%s", id, cstr_String(&spec->id)) }); | ||
1964 | } | ||
1965 | #if 0 | ||
1935 | const struct { | 1966 | const struct { |
1936 | const char * name; | 1967 | const char * name; |
1937 | enum iTextFont cfgId; | 1968 | enum iTextFont cfgId; |
@@ -1943,7 +1974,6 @@ static const iArray *makeFontItems_(const char *id) { | |||
1943 | { "Tinos", tinos_TextFont }, | 1974 | { "Tinos", tinos_TextFont }, |
1944 | { "---", -1 }, | 1975 | { "---", -1 }, |
1945 | { "Iosevka", iosevka_TextFont } }; | 1976 | { "Iosevka", iosevka_TextFont } }; |
1946 | iArray *items = collectNew_Array(sizeof(iMenuItem)); | ||
1947 | iForIndices(i, fonts) { | 1977 | iForIndices(i, fonts) { |
1948 | pushBack_Array(items, | 1978 | pushBack_Array(items, |
1949 | &(iMenuItem){ fonts[i].name, | 1979 | &(iMenuItem){ fonts[i].name, |
@@ -1953,17 +1983,19 @@ static const iArray *makeFontItems_(const char *id) { | |||
1953 | ? format_CStr("!%s.set arg:%d", id, fonts[i].cfgId) | 1983 | ? format_CStr("!%s.set arg:%d", id, fonts[i].cfgId) |
1954 | : NULL }); | 1984 | : NULL }); |
1955 | } | 1985 | } |
1986 | #endif | ||
1956 | pushBack_Array(items, &(iMenuItem){ NULL }); /* terminator */ | 1987 | pushBack_Array(items, &(iMenuItem){ NULL }); /* terminator */ |
1957 | return items; | 1988 | return items; |
1958 | } | 1989 | } |
1959 | 1990 | ||
1960 | static void addFontButtons_(iWidget *parent, const char *id) { | 1991 | static void addFontButtons_(iWidget *parent, const char *id) { |
1961 | const iArray *items = makeFontItems_(id); | 1992 | const iArray *items = makeFontItems_(id); |
1962 | iLabelWidget *button = makeMenuButton_LabelWidget("Source Sans 3", | 1993 | size_t widestIndex = findWidestLabel_MenuItem(constData_Array(items), size_Array(items)); |
1994 | iLabelWidget *button = makeMenuButton_LabelWidget(constValue_Array(items, widestIndex, iMenuItem).label, | ||
1963 | constData_Array(items), size_Array(items)); | 1995 | constData_Array(items), size_Array(items)); |
1964 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), | 1996 | setBackgroundColor_Widget(findChild_Widget(as_Widget(button), "menu"), |
1965 | uiBackgroundMenu_ColorId); | 1997 | uiBackgroundMenu_ColorId); |
1966 | setId_Widget(as_Widget(button), format_CStr("prefs.%s", id)); | 1998 | setId_Widget(as_Widget(button), format_CStr("prefs.font.%s", id)); |
1967 | addChildFlags_Widget(parent, iClob(button), alignLeft_WidgetFlag); | 1999 | addChildFlags_Widget(parent, iClob(button), alignLeft_WidgetFlag); |
1968 | } | 2000 | } |
1969 | 2001 | ||
@@ -2169,6 +2201,15 @@ iWidget *makePreferences_Widget(void) { | |||
2169 | { "${prefs.imagestyle.preformat}", 0, 0, format_CStr("imagestyle.set arg:%d", preformatColorized_ImageStyle) }, | 2201 | { "${prefs.imagestyle.preformat}", 0, 0, format_CStr("imagestyle.set arg:%d", preformatColorized_ImageStyle) }, |
2170 | { NULL } | 2202 | { NULL } |
2171 | }; | 2203 | }; |
2204 | const iMenuItem lineWidthItems[] = { | ||
2205 | { "button id:prefs.linewidth.30 text:\u20132", 0, 0, "linewidth.set arg:30" }, | ||
2206 | { "button id:prefs.linewidth.34 text:\u20131", 0, 0, "linewidth.set arg:34" }, | ||
2207 | { "button id:prefs.linewidth.38 label:prefs.linewidth.normal", 0, 0, "linewidth.set arg:38" }, | ||
2208 | { "button id:prefs.linewidth.43 text:+1", 0, 0, "linewidth.set arg:43" }, | ||
2209 | { "button id:prefs.linewidth.48 text:+2", 0, 0, "linewidth.set arg:48" }, | ||
2210 | { "button id:prefs.linewidth.1000 label:prefs.linewidth.fill", 0, 0, "linewidth.set arg:1000" }, | ||
2211 | { NULL } | ||
2212 | }; | ||
2172 | /* Create the Preferences UI. */ | 2213 | /* Create the Preferences UI. */ |
2173 | if (isUsingPanelLayout_Mobile()) { | 2214 | if (isUsingPanelLayout_Mobile()) { |
2174 | const iMenuItem pinSplitItems[] = { | 2215 | const iMenuItem pinSplitItems[] = { |
@@ -2206,15 +2247,6 @@ iWidget *makePreferences_Widget(void) { | |||
2206 | { "button id:prefs.boldlink.light" }, | 2247 | { "button id:prefs.boldlink.light" }, |
2207 | { NULL } | 2248 | { NULL } |
2208 | }; | 2249 | }; |
2209 | const iMenuItem lineWidthItems[] = { | ||
2210 | { "button id:prefs.linewidth.30 text:\u20132", 0, 0, "linewidth.set arg:30" }, | ||
2211 | { "button id:prefs.linewidth.34 text:\u20131", 0, 0, "linewidth.set arg:34" }, | ||
2212 | { "button id:prefs.linewidth.38 label:prefs.linewidth.normal", 0, 0, "linewidth.set arg:38" }, | ||
2213 | { "button id:prefs.linewidth.43 text:+1", 0, 0, "linewidth.set arg:43" }, | ||
2214 | { "button id:prefs.linewidth.48 text:+2", 0, 0, "linewidth.set arg:48" }, | ||
2215 | { "button id:prefs.linewidth.1000 label:prefs.linewidth.fill", 0, 0, "linewidth.set arg:1000" }, | ||
2216 | { NULL } | ||
2217 | }; | ||
2218 | const iMenuItem quoteItems[] = { | 2250 | const iMenuItem quoteItems[] = { |
2219 | { "button id:prefs.quoteicon.1 label:prefs.quoteicon.icon", 0, 0, "quoteicon.set arg:1" }, | 2251 | { "button id:prefs.quoteicon.1 label:prefs.quoteicon.icon", 0, 0, "quoteicon.set arg:1" }, |
2220 | { "button id:prefs.quoteicon.0 label:prefs.quoteicon.line", 0, 0, "quoteicon.set arg:0" }, | 2252 | { "button id:prefs.quoteicon.0 label:prefs.quoteicon.line", 0, 0, "quoteicon.set arg:0" }, |
@@ -2491,26 +2523,13 @@ iWidget *makePreferences_Widget(void) { | |||
2491 | /* Fonts. */ { | 2523 | /* Fonts. */ { |
2492 | setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts"); | 2524 | setId_Widget(appendTwoColumnTabPage_Widget(tabs, "${heading.prefs.fonts}", '4', &headings, &values), "prefs.page.fonts"); |
2493 | /* Fonts. */ { | 2525 | /* Fonts. */ { |
2494 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.headingfont}"))); | 2526 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.heading}"))); |
2495 | addFontButtons_(values, "headingfont"); | 2527 | addFontButtons_(values, "heading"); |
2496 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font}"))); | 2528 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.body}"))); |
2497 | addFontButtons_(values, "font"); | 2529 | addFontButtons_(values, "body"); |
2530 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.mono}"))); | ||
2531 | addFontButtons_(values, "mono"); | ||
2498 | addDialogPadding_(headings, values); | 2532 | addDialogPadding_(headings, values); |
2499 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.mono}"))); | ||
2500 | iWidget *mono = new_Widget(); { | ||
2501 | iWidget *tog; | ||
2502 | setTextCStr_LabelWidget( | ||
2503 | addChild_Widget(mono, tog = iClob(makeToggle_Widget("prefs.mono.gemini"))), | ||
2504 | "${prefs.mono.gemini}"); | ||
2505 | setFlags_Widget(tog, fixedWidth_WidgetFlag, iFalse); | ||
2506 | updateSize_LabelWidget((iLabelWidget *) tog); | ||
2507 | setTextCStr_LabelWidget( | ||
2508 | addChild_Widget(mono, tog = iClob(makeToggle_Widget("prefs.mono.gopher"))), | ||
2509 | "${prefs.mono.gopher}"); | ||
2510 | setFlags_Widget(tog, fixedWidth_WidgetFlag, iFalse); | ||
2511 | updateSize_LabelWidget((iLabelWidget *) tog); | ||
2512 | } | ||
2513 | addChildFlags_Widget(values, iClob(mono), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
2514 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.boldlink}"))); | 2533 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.boldlink}"))); |
2515 | iWidget *boldLink = new_Widget(); { | 2534 | iWidget *boldLink = new_Widget(); { |
2516 | /* TODO: Add a utility function for this type of toggles? (also for above) */ | 2535 | /* TODO: Add a utility function for this type of toggles? (also for above) */ |
@@ -2528,11 +2547,32 @@ iWidget *makePreferences_Widget(void) { | |||
2528 | } | 2547 | } |
2529 | addChildFlags_Widget(values, iClob(boldLink), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 2548 | addChildFlags_Widget(values, iClob(boldLink), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
2530 | addDialogPadding_(headings, values); | 2549 | addDialogPadding_(headings, values); |
2531 | /* Custom font. */ { | 2550 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.mono}"))); |
2532 | iInputWidget *customFont = new_InputWidget(0); | 2551 | iWidget *mono = new_Widget(); { |
2533 | setHint_InputWidget(customFont, "${hint.prefs.userfont}"); | 2552 | iWidget *tog; |
2534 | addPrefsInputWithHeading_(headings, values, "prefs.userfont", iClob(customFont)); | 2553 | setTextCStr_LabelWidget( |
2554 | addChild_Widget(mono, tog = iClob(makeToggle_Widget("prefs.mono.gemini"))), | ||
2555 | "${prefs.mono.gemini}"); | ||
2556 | setFlags_Widget(tog, fixedWidth_WidgetFlag, iFalse); | ||
2557 | updateSize_LabelWidget((iLabelWidget *) tog); | ||
2558 | setTextCStr_LabelWidget( | ||
2559 | addChild_Widget(mono, tog = iClob(makeToggle_Widget("prefs.mono.gopher"))), | ||
2560 | "${prefs.mono.gopher}"); | ||
2561 | setFlags_Widget(tog, fixedWidth_WidgetFlag, iFalse); | ||
2562 | updateSize_LabelWidget((iLabelWidget *) tog); | ||
2535 | } | 2563 | } |
2564 | addChildFlags_Widget(values, iClob(mono), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | ||
2565 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.monodoc}"))); | ||
2566 | addFontButtons_(values, "monodoc"); | ||
2567 | addDialogPadding_(headings, values); | ||
2568 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.font.ui}"))); | ||
2569 | addFontButtons_(values, "ui"); | ||
2570 | // addDialogPadding_(headings, values); | ||
2571 | // /* Custom font. */ { | ||
2572 | // iInputWidget *customFont = new_InputWidget(0); | ||
2573 | // setHint_InputWidget(customFont, "${hint.prefs.userfont}"); | ||
2574 | // addPrefsInputWithHeading_(headings, values, "prefs.userfont", iClob(customFont)); | ||
2575 | // } | ||
2536 | } | 2576 | } |
2537 | } | 2577 | } |
2538 | /* Style. */ { | 2578 | /* Style. */ { |
@@ -2541,12 +2581,16 @@ iWidget *makePreferences_Widget(void) { | |||
2541 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}"))); | 2581 | addChild_Widget(headings, iClob(makeHeading_Widget("${prefs.linewidth}"))); |
2542 | iWidget *widths = new_Widget(); | 2582 | iWidget *widths = new_Widget(); |
2543 | /* Line widths. */ { | 2583 | /* Line widths. */ { |
2544 | addRadioButton_(widths, "prefs.linewidth.30", "\u20132", "linewidth.set arg:30"); | 2584 | /* TODO: Make this a utility function to build radio buttons from items. */ |
2545 | addRadioButton_(widths, "prefs.linewidth.34", "\u20131", "linewidth.set arg:34"); | 2585 | for (size_t i = 0; lineWidthItems[i].label; i++) { |
2546 | addRadioButton_(widths, "prefs.linewidth.38", "${prefs.linewidth.normal}", "linewidth.set arg:38"); | 2586 | const iMenuItem *lw = &lineWidthItems[i]; |
2547 | addRadioButton_(widths, "prefs.linewidth.43", "+1", "linewidth.set arg:43"); | 2587 | addRadioButton_(widths, |
2548 | addRadioButton_(widths, "prefs.linewidth.48", "+2", "linewidth.set arg:48"); | 2588 | cstr_Command(lw->label, "id"), |
2549 | addRadioButton_(widths, "prefs.linewidth.1000", "${prefs.linewidth.fill}", "linewidth.set arg:1000"); | 2589 | hasLabel_Command(lw->label, "label") |
2590 | ? cstr_Lang(cstr_Command(lw->label, "label")) | ||
2591 | : cstr_Command(lw->label, "text"), | ||
2592 | lw->command); | ||
2593 | } | ||
2550 | } | 2594 | } |
2551 | addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 2595 | addChildFlags_Widget(values, iClob(widths), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
2552 | addPrefsInputWithHeading_(headings, values, "prefs.linespacing", iClob(new_InputWidget(5))); | 2596 | addPrefsInputWithHeading_(headings, values, "prefs.linespacing", iClob(new_InputWidget(5))); |
@@ -2738,27 +2782,27 @@ static iBool handleFeedSettingCommands_(iWidget *dlg, const char *cmd) { | |||
2738 | } | 2782 | } |
2739 | int id = argLabel_Command(cmd, "bmid"); | 2783 | int id = argLabel_Command(cmd, "bmid"); |
2740 | const iBool headings = isSelected_Widget(findChild_Widget(dlg, "feedcfg.type.headings")); | 2784 | const iBool headings = isSelected_Widget(findChild_Widget(dlg, "feedcfg.type.headings")); |
2741 | const iString *tags = collectNewFormat_String("subscribed%s", headings ? " headings" : ""); | 2785 | const iBool ignoreWeb = isSelected_Widget(findChild_Widget(dlg, "feedcfg.ignoreweb")); |
2742 | if (!id) { | 2786 | if (!id) { |
2743 | const size_t numSubs = numSubscribed_Feeds(); | 2787 | const size_t numSubs = numSubscribed_Feeds(); |
2744 | const iString *url = url_DocumentWidget(document_App()); | 2788 | const iString *url = url_DocumentWidget(document_App()); |
2745 | add_Bookmarks(bookmarks_App(), | 2789 | id = add_Bookmarks(bookmarks_App(), |
2746 | url, | 2790 | url, |
2747 | feedTitle, | 2791 | feedTitle, |
2748 | tags, | 2792 | NULL, |
2749 | siteIcon_GmDocument(document_DocumentWidget(document_App()))); | 2793 | siteIcon_GmDocument(document_DocumentWidget(document_App()))); |
2750 | if (numSubs == 0) { | 2794 | if (numSubs == 0) { |
2751 | /* Auto-refresh after first addition. */ | 2795 | /* Auto-refresh after first addition. */ |
2796 | /* TODO: Also when settings changed? */ | ||
2752 | postCommand_App("feeds.refresh"); | 2797 | postCommand_App("feeds.refresh"); |
2753 | } | 2798 | } |
2754 | } | 2799 | } |
2755 | else { | 2800 | iBookmark *bm = get_Bookmarks(bookmarks_App(), id); |
2756 | iBookmark *bm = get_Bookmarks(bookmarks_App(), id); | 2801 | iAssert(bm); |
2757 | if (bm) { | 2802 | set_String(&bm->title, feedTitle); |
2758 | set_String(&bm->title, feedTitle); | 2803 | addOrRemoveTag_Bookmark(bm, subscribed_BookmarkTag, iTrue); |
2759 | set_String(&bm->tags, tags); | 2804 | addOrRemoveTag_Bookmark(bm, headings_BookmarkTag, headings); |
2760 | } | 2805 | addOrRemoveTag_Bookmark(bm, ignoreWeb_BookmarkTag, ignoreWeb); |
2761 | } | ||
2762 | postCommand_App("bookmarks.changed"); | 2806 | postCommand_App("bookmarks.changed"); |
2763 | setupSheetTransition_Mobile(dlg, iFalse); | 2807 | setupSheetTransition_Mobile(dlg, iFalse); |
2764 | destroy_Widget(dlg); | 2808 | destroy_Widget(dlg); |
@@ -2787,6 +2831,7 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { | |||
2787 | { format_CStr("title id:feedcfg.heading text:%s", headingText) }, | 2831 | { format_CStr("title id:feedcfg.heading text:%s", headingText) }, |
2788 | { "input id:feedcfg.title text:${dlg.feed.title}" }, | 2832 | { "input id:feedcfg.title text:${dlg.feed.title}" }, |
2789 | { "radio id:dlg.feed.entrytype", 0, 0, (const void *) typeItems }, | 2833 | { "radio id:dlg.feed.entrytype", 0, 0, (const void *) typeItems }, |
2834 | { "toggle id:feedcfg.ignoreweb text:${dlg.feed.ignoreweb}" }, | ||
2790 | { NULL } | 2835 | { NULL } |
2791 | }, actions, iElemCount(actions)); | 2836 | }, actions, iElemCount(actions)); |
2792 | } | 2837 | } |
@@ -2805,6 +2850,8 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { | |||
2805 | addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1"); | 2850 | addRadioButton_(types, "feedcfg.type.headings", "${dlg.feed.type.headings}", "feedcfg.type arg:1"); |
2806 | } | 2851 | } |
2807 | addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); | 2852 | addChildFlags_Widget(values, iClob(types), arrangeHorizontal_WidgetFlag | arrangeSize_WidgetFlag); |
2853 | addChild_Widget(headings, iClob(makeHeading_Widget("${dlg.feed.ignoreweb}"))); | ||
2854 | addChild_Widget(values, iClob(makeToggle_Widget("feedcfg.ignoreweb"))); | ||
2808 | iWidget *buttons = | 2855 | iWidget *buttons = |
2809 | addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions)))); | 2856 | addChild_Widget(dlg, iClob(makeDialogButtons_Widget(actions, iElemCount(actions)))); |
2810 | setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save"); | 2857 | setId_Widget(child_Widget(buttons, childCount_Widget(buttons) - 1), "feedcfg.save"); |
@@ -2823,6 +2870,8 @@ iWidget *makeFeedSettings_Widget(uint32_t bookmarkId) { | |||
2823 | : "feedcfg.type.gemini"), | 2870 | : "feedcfg.type.gemini"), |
2824 | selected_WidgetFlag, | 2871 | selected_WidgetFlag, |
2825 | iTrue); | 2872 | iTrue); |
2873 | setToggle_Widget(findChild_Widget(dlg, "feedcfg.ignoreweb"), | ||
2874 | hasTag_Bookmark(bm, ignoreWeb_BookmarkTag)); | ||
2826 | setCommandHandler_Widget(dlg, handleFeedSettingCommands_); | 2875 | setCommandHandler_Widget(dlg, handleFeedSettingCommands_); |
2827 | } | 2876 | } |
2828 | setupSheetTransition_Mobile(dlg, incoming_TransitionFlag); | 2877 | setupSheetTransition_Mobile(dlg, incoming_TransitionFlag); |
diff --git a/src/ui/widget.c b/src/ui/widget.c index ec92ac5a..910c31a9 100644 --- a/src/ui/widget.c +++ b/src/ui/widget.c | |||
@@ -1407,7 +1407,8 @@ void drawBackground_Widget(const iWidget *d) { | |||
1407 | fillRect_Paint(&p, rect, d->bgColor); | 1407 | fillRect_Paint(&p, rect, d->bgColor); |
1408 | } | 1408 | } |
1409 | if (d->frameColor >= 0 && ~d->flags & frameless_WidgetFlag) { | 1409 | if (d->frameColor >= 0 && ~d->flags & frameless_WidgetFlag) { |
1410 | drawRectThickness_Paint(&p, rect, gap_UI / 4, d->frameColor); | 1410 | drawRectThickness_Paint(&p, adjusted_Rect(rect, zero_I2(), neg_I2(one_I2())), |
1411 | gap_UI / 4, d->frameColor); | ||
1411 | } | 1412 | } |
1412 | } | 1413 | } |
1413 | if (d->flags & (borderTop_WidgetFlag | borderBottom_WidgetFlag)) { | 1414 | if (d->flags & (borderTop_WidgetFlag | borderBottom_WidgetFlag)) { |
diff --git a/src/ui/window.c b/src/ui/window.c index 686a6dd6..569ec919 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -1188,12 +1188,12 @@ void draw_Window(iWindow *d) { | |||
1188 | extern int drawCount_; | 1188 | extern int drawCount_; |
1189 | drawRoot_Widget(root->widget); | 1189 | drawRoot_Widget(root->widget); |
1190 | #if !defined (NDEBUG) | 1190 | #if !defined (NDEBUG) |
1191 | draw_Text(defaultBold_FontId, safeRect_Root(root).pos, red_ColorId, "%d", drawCount_); | 1191 | draw_Text(uiLabelBold_FontId, safeRect_Root(root).pos, red_ColorId, "%d", drawCount_); |
1192 | drawCount_ = 0; | 1192 | drawCount_ = 0; |
1193 | #endif | 1193 | #endif |
1194 | } | 1194 | } |
1195 | drawRectThickness_Paint( | 1195 | drawRectThickness_Paint(&p, (iRect){ zero_I2(), sub_I2(d->size, one_I2()) }, gap_UI / 4, |
1196 | &p, (iRect){ zero_I2(), sub_I2(d->size, one_I2()) }, gap_UI / 4, uiSeparator_ColorId); | 1196 | uiBackgroundSelected_ColorId); |
1197 | setCurrent_Root(NULL); | 1197 | setCurrent_Root(NULL); |
1198 | SDL_RenderPresent(d->render); | 1198 | SDL_RenderPresent(d->render); |
1199 | } | 1199 | } |
@@ -1287,7 +1287,7 @@ void draw_MainWindow(iMainWindow *d) { | |||
1287 | } | 1287 | } |
1288 | setCurrent_Root(NULL); | 1288 | setCurrent_Root(NULL); |
1289 | #if !defined (NDEBUG) | 1289 | #if !defined (NDEBUG) |
1290 | draw_Text(defaultBold_FontId, safeRect_Root(w->roots[0]).pos, red_ColorId, "%d", drawCount_); | 1290 | draw_Text(uiLabelBold_FontId, safeRect_Root(w->roots[0]).pos, red_ColorId, "%d", drawCount_); |
1291 | drawCount_ = 0; | 1291 | drawCount_ = 0; |
1292 | #endif | 1292 | #endif |
1293 | } | 1293 | } |