diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-17 20:33:14 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-10-17 20:33:14 +0300 |
commit | b3ae7efcb9adb1de3d02f0753e2a79888bdb71ac (patch) | |
tree | 57fb9f82f2d19a1c8e6d1aa85865f9df210e2c4b | |
parent | 2e2b823bfb5d34d42c6b6c1b289193c854459b45 (diff) |
FontPack management via "about:fonts"
-rw-r--r-- | po/en.po | 69 | ||||
-rw-r--r-- | res/lang/de.bin | bin | 26398 -> 27035 bytes | |||
-rw-r--r-- | res/lang/en.bin | bin | 23836 -> 24559 bytes | |||
-rw-r--r-- | res/lang/eo.bin | bin | 22690 -> 23327 bytes | |||
-rw-r--r-- | res/lang/es.bin | bin | 26782 -> 27419 bytes | |||
-rw-r--r-- | res/lang/es_MX.bin | bin | 24750 -> 25387 bytes | |||
-rw-r--r-- | res/lang/fi.bin | bin | 26694 -> 27331 bytes | |||
-rw-r--r-- | res/lang/fr.bin | bin | 27604 -> 28241 bytes | |||
-rw-r--r-- | res/lang/gl.bin | bin | 26058 -> 26695 bytes | |||
-rw-r--r-- | res/lang/ia.bin | bin | 25723 -> 26360 bytes | |||
-rw-r--r-- | res/lang/ie.bin | bin | 25928 -> 26565 bytes | |||
-rw-r--r-- | res/lang/isv.bin | bin | 22626 -> 23263 bytes | |||
-rw-r--r-- | res/lang/pl.bin | bin | 26999 -> 27636 bytes | |||
-rw-r--r-- | res/lang/ru.bin | bin | 39338 -> 39975 bytes | |||
-rw-r--r-- | res/lang/sk.bin | bin | 22959 -> 23596 bytes | |||
-rw-r--r-- | res/lang/sr.bin | bin | 39243 -> 39880 bytes | |||
-rw-r--r-- | res/lang/tok.bin | bin | 24173 -> 24810 bytes | |||
-rw-r--r-- | res/lang/zh_Hans.bin | bin | 22675 -> 23312 bytes | |||
-rw-r--r-- | res/lang/zh_Hant.bin | bin | 22816 -> 23453 bytes | |||
-rw-r--r-- | src/app.c | 50 | ||||
-rw-r--r-- | src/defs.h | 5 | ||||
-rw-r--r-- | src/fontpack.c | 197 | ||||
-rw-r--r-- | src/fontpack.h | 13 | ||||
-rw-r--r-- | src/gmdocument.c | 37 | ||||
-rw-r--r-- | src/gmutil.c | 3 | ||||
-rw-r--r-- | src/lang.c | 9 | ||||
-rw-r--r-- | src/lang.h | 1 | ||||
-rw-r--r-- | src/media.c | 129 | ||||
-rw-r--r-- | src/media.h | 17 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 75 | ||||
-rw-r--r-- | src/ui/mediaui.c | 82 | ||||
-rw-r--r-- | src/ui/mediaui.h | 17 |
32 files changed, 341 insertions, 363 deletions
@@ -448,6 +448,16 @@ msgid_plural "num.bytes.n" | |||
448 | msgstr[0] "%zu byte" | 448 | msgstr[0] "%zu byte" |
449 | msgstr[1] "%zu bytes" | 449 | msgstr[1] "%zu bytes" |
450 | 450 | ||
451 | msgid "num.files" | ||
452 | msgid_plural "num.files.n" | ||
453 | msgstr[0] "%zu file" | ||
454 | msgstr[1] "%zu files" | ||
455 | |||
456 | msgid "num.fonts" | ||
457 | msgid_plural "num.fonts.n" | ||
458 | msgstr[0] "%zu font" | ||
459 | msgstr[1] "%zu fonts" | ||
460 | |||
451 | # strftime() formatted, split on two lines | 461 | # strftime() formatted, split on two lines |
452 | #, c-format | 462 | #, c-format |
453 | msgid "page.timestamp" | 463 | msgid "page.timestamp" |
@@ -1869,4 +1879,61 @@ msgid "gempub.meta.lang" | |||
1869 | msgstr "Language" | 1879 | msgstr "Language" |
1870 | 1880 | ||
1871 | msgid "gempub.meta.license" | 1881 | msgid "gempub.meta.license" |
1872 | msgstr "License" \ No newline at end of file | 1882 | msgstr "License" |
1883 | |||
1884 | msgid "heading.fontpack.meta" | ||
1885 | msgstr "Fonts" | ||
1886 | |||
1887 | msgid "heading.fontpack.meta.enabled" | ||
1888 | msgstr "Enabled fontpacks" | ||
1889 | |||
1890 | msgid "heading.fontpack.meta.disabled" | ||
1891 | msgstr "Disabled fontpacks" | ||
1892 | |||
1893 | # Action label | ||
1894 | msgid "fontpack.meta.viewfile" | ||
1895 | msgstr "View file" | ||
1896 | |||
1897 | #, c-format | ||
1898 | msgid "fontpack.meta.version" | ||
1899 | msgstr "Version %d" | ||
1900 | |||
1901 | msgid "fontpack.meta.installed" | ||
1902 | msgstr "Installed" | ||
1903 | |||
1904 | msgid "fontpack.meta.notinstalled" | ||
1905 | msgstr "Not installed" | ||
1906 | |||
1907 | msgid "fontpack.meta.disabled" | ||
1908 | msgstr ", disabled" | ||
1909 | |||
1910 | #, c-format | ||
1911 | msgid "fontpack.enable" | ||
1912 | msgstr "Enable \"%s\"" | ||
1913 | |||
1914 | #, c-format | ||
1915 | msgid "fontpack.disable" | ||
1916 | msgstr "Disable \"%s\"" | ||
1917 | |||
1918 | #, c-format | ||
1919 | msgid "fontpack.install" | ||
1920 | msgstr "Install \"%s\"" | ||
1921 | |||
1922 | #, c-format | ||
1923 | msgid "fontpack.upgrade" | ||
1924 | msgstr "Upgrade \"%s\" to version %d" | ||
1925 | |||
1926 | #, c-format | ||
1927 | msgid "fontpack.delete" | ||
1928 | msgstr "Permanently delete \"%s\"" | ||
1929 | |||
1930 | msgid "heading.fontpack.delete" | ||
1931 | msgstr "DELETE FONTPACK" | ||
1932 | |||
1933 | #, c-format | ||
1934 | msgid "dlg.fontpack.delete.confirm" | ||
1935 | msgstr "Do you really want to permanently delete\nthe fontpack \"%s\"?" | ||
1936 | |||
1937 | msgid "dlg.fontpack.delete" | ||
1938 | msgstr "Delete Fontpack" | ||
1939 | |||
diff --git a/res/lang/de.bin b/res/lang/de.bin index 17a2d191..332da0e3 100644 --- a/res/lang/de.bin +++ b/res/lang/de.bin | |||
Binary files differ | |||
diff --git a/res/lang/en.bin b/res/lang/en.bin index 51b9a10d..429b639f 100644 --- a/res/lang/en.bin +++ b/res/lang/en.bin | |||
Binary files differ | |||
diff --git a/res/lang/eo.bin b/res/lang/eo.bin index 7b83b77f..2c4b98fc 100644 --- a/res/lang/eo.bin +++ b/res/lang/eo.bin | |||
Binary files differ | |||
diff --git a/res/lang/es.bin b/res/lang/es.bin index 91121500..bc3e23fc 100644 --- a/res/lang/es.bin +++ b/res/lang/es.bin | |||
Binary files differ | |||
diff --git a/res/lang/es_MX.bin b/res/lang/es_MX.bin index df129a8a..d158cc92 100644 --- a/res/lang/es_MX.bin +++ b/res/lang/es_MX.bin | |||
Binary files differ | |||
diff --git a/res/lang/fi.bin b/res/lang/fi.bin index fad0413b..4c21d7f9 100644 --- a/res/lang/fi.bin +++ b/res/lang/fi.bin | |||
Binary files differ | |||
diff --git a/res/lang/fr.bin b/res/lang/fr.bin index 20fd19ef..42b96be1 100644 --- a/res/lang/fr.bin +++ b/res/lang/fr.bin | |||
Binary files differ | |||
diff --git a/res/lang/gl.bin b/res/lang/gl.bin index 1cac09b9..8c0010b6 100644 --- a/res/lang/gl.bin +++ b/res/lang/gl.bin | |||
Binary files differ | |||
diff --git a/res/lang/ia.bin b/res/lang/ia.bin index 64ebfe03..2ee2884f 100644 --- a/res/lang/ia.bin +++ b/res/lang/ia.bin | |||
Binary files differ | |||
diff --git a/res/lang/ie.bin b/res/lang/ie.bin index 87064cef..3524454f 100644 --- a/res/lang/ie.bin +++ b/res/lang/ie.bin | |||
Binary files differ | |||
diff --git a/res/lang/isv.bin b/res/lang/isv.bin index 726441ce..cbe694c0 100644 --- a/res/lang/isv.bin +++ b/res/lang/isv.bin | |||
Binary files differ | |||
diff --git a/res/lang/pl.bin b/res/lang/pl.bin index a857c547..207f588d 100644 --- a/res/lang/pl.bin +++ b/res/lang/pl.bin | |||
Binary files differ | |||
diff --git a/res/lang/ru.bin b/res/lang/ru.bin index c1884651..5f8a3aa5 100644 --- a/res/lang/ru.bin +++ b/res/lang/ru.bin | |||
Binary files differ | |||
diff --git a/res/lang/sk.bin b/res/lang/sk.bin index 981ab7e1..766a7d1c 100644 --- a/res/lang/sk.bin +++ b/res/lang/sk.bin | |||
Binary files differ | |||
diff --git a/res/lang/sr.bin b/res/lang/sr.bin index 384665cc..d9b85067 100644 --- a/res/lang/sr.bin +++ b/res/lang/sr.bin | |||
Binary files differ | |||
diff --git a/res/lang/tok.bin b/res/lang/tok.bin index 51080283..9b80ccba 100644 --- a/res/lang/tok.bin +++ b/res/lang/tok.bin | |||
Binary files differ | |||
diff --git a/res/lang/zh_Hans.bin b/res/lang/zh_Hans.bin index 0cf56935..07f65240 100644 --- a/res/lang/zh_Hans.bin +++ b/res/lang/zh_Hans.bin | |||
Binary files differ | |||
diff --git a/res/lang/zh_Hant.bin b/res/lang/zh_Hant.bin index 28e7cedf..d0846df8 100644 --- a/res/lang/zh_Hant.bin +++ b/res/lang/zh_Hant.bin | |||
Binary files differ | |||
@@ -2566,12 +2566,23 @@ iBool handleCommand_App(const char *cmd) { | |||
2566 | const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0; | 2566 | const iBool fromSidebar = argLabel_Command(cmd, "fromsidebar") != 0; |
2567 | iUrl parts; | 2567 | iUrl parts; |
2568 | init_Url(&parts, url); | 2568 | init_Url(&parts, url); |
2569 | if (equal_Rangecc(parts.scheme, "about") && equal_Rangecc(parts.path, "command") && | ||
2570 | !isEmpty_Range(&parts.query)) { | ||
2571 | /* NOTE: Careful here! `about:command` allows issuing UI events via links on the page. | ||
2572 | There is a special set of pages where these are allowed (e.g., "about:fonts"). | ||
2573 | On every other page, `about:command` links will not be clickable. */ | ||
2574 | iString *query = collectNewRange_String((iRangecc){ | ||
2575 | parts.query.start + 1, parts.query.end | ||
2576 | }); | ||
2577 | replace_String(query, "%20", " "); | ||
2578 | postCommandString_Root(NULL, query); | ||
2579 | return iTrue; | ||
2580 | } | ||
2569 | if (equalCase_Rangecc(parts.scheme, "titan")) { | 2581 | if (equalCase_Rangecc(parts.scheme, "titan")) { |
2570 | iUploadWidget *upload = new_UploadWidget(); | 2582 | iUploadWidget *upload = new_UploadWidget(); |
2571 | setUrl_UploadWidget(upload, url); | 2583 | setUrl_UploadWidget(upload, url); |
2572 | setResponseViewer_UploadWidget(upload, document_App()); | 2584 | setResponseViewer_UploadWidget(upload, document_App()); |
2573 | addChild_Widget(get_Root()->widget, iClob(upload)); | 2585 | addChild_Widget(get_Root()->widget, iClob(upload)); |
2574 | // finalizeSheet_Mobile(as_Widget(upload)); | ||
2575 | setupSheetTransition_Mobile(as_Widget(upload), iTrue); | 2586 | setupSheetTransition_Mobile(as_Widget(upload), iTrue); |
2576 | postRefresh_App(); | 2587 | postRefresh_App(); |
2577 | return iTrue; | 2588 | return iTrue; |
@@ -3043,8 +3054,8 @@ iBool handleCommand_App(const char *cmd) { | |||
3043 | } | 3054 | } |
3044 | return iFalse; | 3055 | return iFalse; |
3045 | } | 3056 | } |
3046 | else if (equal_Command(cmd, "media.fontpack.enable")) { | 3057 | else if (equal_Command(cmd, "fontpack.enable")) { |
3047 | const iString *packId = collect_String(suffix_Command(cmd, "packid")); | 3058 | const iString *packId = collect_String(suffix_Command(cmd, "id")); |
3048 | if (arg_Command(cmd)) { | 3059 | if (arg_Command(cmd)) { |
3049 | remove_StringSet(d->prefs.disabledFontPacks, packId); | 3060 | remove_StringSet(d->prefs.disabledFontPacks, packId); |
3050 | } | 3061 | } |
@@ -3052,10 +3063,35 @@ iBool handleCommand_App(const char *cmd) { | |||
3052 | insert_StringSet(d->prefs.disabledFontPacks, packId); | 3063 | insert_StringSet(d->prefs.disabledFontPacks, packId); |
3053 | } | 3064 | } |
3054 | resetFonts_App(); | 3065 | resetFonts_App(); |
3055 | const iMedia *media = pointerLabel_Command(cmd, "media"); | 3066 | postCommand_App("navigate.reload"); |
3056 | if (media) { | 3067 | return iTrue; |
3057 | postCommandf_App("media.fontpack.updated id:%u media:%p", | 3068 | } |
3058 | argU32Label_Command(cmd, "mediaid"), media); | 3069 | else if (equal_Command(cmd, "fontpack.delete")) { |
3070 | const iString *packId = collect_String(suffix_Command(cmd, "id")); | ||
3071 | if (isEmpty_String(packId)) { | ||
3072 | return iTrue; | ||
3073 | } | ||
3074 | const iFontPack *pack = pack_Fonts(cstr_String(packId)); | ||
3075 | if (pack && loadPath_FontPack(pack)) { | ||
3076 | if (argLabel_Command(cmd, "confirmed")) { | ||
3077 | remove_StringSet(d->prefs.disabledFontPacks, packId); | ||
3078 | remove(cstr_String(loadPath_FontPack(pack))); | ||
3079 | reload_Fonts(); | ||
3080 | postCommand_App("navigate.reload"); | ||
3081 | } | ||
3082 | else { | ||
3083 | makeQuestion_Widget( | ||
3084 | uiTextCaution_ColorEscape "${heading.fontpack.delete}", | ||
3085 | format_Lang("${dlg.fontpack.delete.confirm}", | ||
3086 | cstr_String(packId)), | ||
3087 | (iMenuItem[]){ { "${cancel}" }, | ||
3088 | { uiTextCaution_ColorEscape " ${dlg.fontpack.delete}", | ||
3089 | 0, | ||
3090 | 0, | ||
3091 | format_CStr("!fontpack.delete confirmed:1 id:%s", | ||
3092 | cstr_String(packId)) } }, | ||
3093 | 2); | ||
3094 | } | ||
3059 | } | 3095 | } |
3060 | return iTrue; | 3096 | return iTrue; |
3061 | } | 3097 | } |
@@ -126,8 +126,8 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) { | |||
126 | #define delete_Icon "\u232b" | 126 | #define delete_Icon "\u232b" |
127 | #define copy_Icon "\u2398" //"\u2bba" | 127 | #define copy_Icon "\u2398" //"\u2bba" |
128 | #define check_Icon "\u2714" | 128 | #define check_Icon "\u2714" |
129 | #define ballotChecked_Icon "\U0001f5f9" | 129 | #define ballotChecked_Icon "\u2611" |
130 | #define ballotUnchecked_Icon "\U0001f5f9" | 130 | #define ballotUnchecked_Icon "\u2610" |
131 | #define inbox_Icon "\U0001f4e5" | 131 | #define inbox_Icon "\U0001f4e5" |
132 | #define book_Icon "\U0001f56e" | 132 | #define book_Icon "\U0001f56e" |
133 | #define bookmark_Icon "\U0001f516" | 133 | #define bookmark_Icon "\U0001f516" |
@@ -162,6 +162,7 @@ iLocalDef int acceptKeyMod_ReturnKeyBehavior(int behavior) { | |||
162 | #define select_Icon "\u2b1a" | 162 | #define select_Icon "\u2b1a" |
163 | #define downAngle_Icon "\ufe40" | 163 | #define downAngle_Icon "\ufe40" |
164 | #define photo_Icon "\U0001f5bc" | 164 | #define photo_Icon "\U0001f5bc" |
165 | #define fontpack_Icon "\U0001f520" | ||
165 | 166 | ||
166 | #if defined (iPlatformApple) | 167 | #if defined (iPlatformApple) |
167 | # define shift_Icon "\u21e7" | 168 | # define shift_Icon "\u21e7" |
diff --git a/src/fontpack.c b/src/fontpack.c index 9603bded..9b165051 100644 --- a/src/fontpack.c +++ b/src/fontpack.c | |||
@@ -32,6 +32,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
32 | #include <the_Foundation/path.h> | 32 | #include <the_Foundation/path.h> |
33 | #include <the_Foundation/ptrarray.h> | 33 | #include <the_Foundation/ptrarray.h> |
34 | #include <the_Foundation/string.h> | 34 | #include <the_Foundation/string.h> |
35 | #include <the_Foundation/stringlist.h> | ||
35 | #include <the_Foundation/toml.h> | 36 | #include <the_Foundation/toml.h> |
36 | 37 | ||
37 | const char *mimeType_FontPack = "application/lagrange-fontpack+zip"; | 38 | const char *mimeType_FontPack = "application/lagrange-fontpack+zip"; |
@@ -236,6 +237,10 @@ iFontPackId id_FontPack(const iFontPack *d) { | |||
236 | return (iFontPackId){ &d->id, d->version }; | 237 | return (iFontPackId){ &d->id, d->version }; |
237 | } | 238 | } |
238 | 239 | ||
240 | const iString *loadPath_FontPack(const iFontPack *d) { | ||
241 | return d->loadPath; | ||
242 | } | ||
243 | |||
239 | const iPtrArray *listSpecs_FontPack(const iFontPack *d) { | 244 | const iPtrArray *listSpecs_FontPack(const iFontPack *d) { |
240 | if (!d) return NULL; | 245 | if (!d) return NULL; |
241 | iPtrArray *list = collectNew_PtrArray(); | 246 | iPtrArray *list = collectNew_PtrArray(); |
@@ -441,6 +446,20 @@ void setLoadPath_FontPack(iFontPack *d, const iString *path) { | |||
441 | setRange_String(&d->id, withoutExtension_Path(&d->id)); | 446 | setRange_String(&d->id, withoutExtension_Path(&d->id)); |
442 | } | 447 | } |
443 | 448 | ||
449 | const iString *idFromUrl_FontPack(const iString *url) { | ||
450 | iString *id = new_String(); | ||
451 | iUrl parts; | ||
452 | init_Url(&parts, url); | ||
453 | setRange_String(id, baseName_Path(collectNewRange_String(parts.path))); | ||
454 | setRange_String(id, withoutExtension_Path(id)); | ||
455 | return collect_String(id); | ||
456 | } | ||
457 | |||
458 | void setUrl_FontPack(iFontPack *d, const iString *url) { | ||
459 | /* TODO: Should we remember the URL as well? */ | ||
460 | set_String(&d->id, idFromUrl_FontPack(url)); | ||
461 | } | ||
462 | |||
444 | void setStandalone_FontPack(iFontPack *d, iBool standalone) { | 463 | void setStandalone_FontPack(iFontPack *d, iBool standalone) { |
445 | d->isStandalone = standalone; | 464 | d->isStandalone = standalone; |
446 | } | 465 | } |
@@ -486,7 +505,7 @@ static void sortSpecs_Fonts_(iFonts *d) { | |||
486 | clear_PtrArray(&d->specOrder); | 505 | clear_PtrArray(&d->specOrder); |
487 | iConstForEach(PtrArray, p, &d->packs) { | 506 | iConstForEach(PtrArray, p, &d->packs) { |
488 | const iFontPack *pack = p.ptr; | 507 | const iFontPack *pack = p.ptr; |
489 | if (!contains_StringSet(prefs_App()->disabledFontPacks, &pack->id)) { | 508 | if (!isDisabled_FontPack(pack)) { |
490 | iConstForEach(Array, i, &pack->fonts) { | 509 | iConstForEach(Array, i, &pack->fonts) { |
491 | pushBack_PtrArray(&d->specOrder, i.value); | 510 | pushBack_PtrArray(&d->specOrder, i.value); |
492 | } | 511 | } |
@@ -620,24 +639,131 @@ const iPtrArray *listSpecsByPriority_Fonts(void) { | |||
620 | return &fonts_.specOrder; | 639 | return &fonts_.specOrder; |
621 | } | 640 | } |
622 | 641 | ||
642 | iString *infoText_FontPack(const iFontPack *d) { | ||
643 | const iFontPack *installed = pack_Fonts(cstr_String(&d->id)); | ||
644 | const iBool isInstalled = (installed != NULL); | ||
645 | const int installedVersion = installed ? installed->version : 0; | ||
646 | const iBool isDisabled = isDisabled_FontPack(d); | ||
647 | iString *str = new_String(); | ||
648 | size_t sizeInBytes = 0; | ||
649 | iPtrSet *uniqueFiles = new_PtrSet(); | ||
650 | iStringList *names = new_StringList(); | ||
651 | iConstForEach(PtrArray, i, listSpecs_FontPack(d)) { | ||
652 | const iFontSpec *spec = i.ptr; | ||
653 | pushBack_StringList(names, &spec->name); | ||
654 | iForIndices(j, spec->styles) { | ||
655 | insert_PtrSet(uniqueFiles, spec->styles[j]); | ||
656 | } | ||
657 | } | ||
658 | iConstForEach(PtrSet, j, uniqueFiles) { | ||
659 | sizeInBytes += size_Block(&((const iFontFile *) *j.value)->sourceData); | ||
660 | } | ||
661 | appendFormat_String(str, "%.1f ${mb} (%s)\n%s: %s\n", | ||
662 | sizeInBytes / 1.0e6, | ||
663 | formatCStrs_Lang("num.files.n", size_PtrSet(uniqueFiles)), | ||
664 | formatCStrs_Lang("num.fonts.n", size_StringList(names)), | ||
665 | cstrCollect_String(joinCStr_StringList(names, ", ")), | ||
666 | d->version); | ||
667 | if (isInstalled && installedVersion != d->version) { | ||
668 | appendCStr_String(str, format_Lang("${fontpack.meta.version}\n", d->version)); | ||
669 | } | ||
670 | if (!isEmpty_String(&d->id)) { | ||
671 | appendFormat_String(str, "%s %s%s\n", | ||
672 | isInstalled ? ballotChecked_Icon : ballotUnchecked_Icon, | ||
673 | isInstalled ? (installedVersion == d->version ? "${fontpack.meta.installed}" | ||
674 | : format_CStr("${fontpack.meta.installed} (%s)", | ||
675 | format_Lang("${fontpack.meta.version}", | ||
676 | installedVersion))) | ||
677 | : "${fontpack.meta.notinstalled}", | ||
678 | isDisabled ? "${fontpack.meta.disabled}" : ""); | ||
679 | } | ||
680 | iRelease(names); | ||
681 | delete_PtrSet(uniqueFiles); | ||
682 | return str; | ||
683 | } | ||
684 | |||
685 | const iArray *actions_FontPack(const iFontPack *d) { | ||
686 | iArray *items = new_Array(sizeof(iMenuItem)); | ||
687 | const iFontPackId fp = id_FontPack(d); | ||
688 | const char *fpId = cstr_String(fp.id); | ||
689 | const iFontPack *installed = pack_Fonts(fpId); | ||
690 | const iBool isEnabled = !isDisabled_FontPack(d); | ||
691 | if (isInstalled_Fonts(fpId)) { | ||
692 | if (d->version > installed->version) { | ||
693 | pushBack_Array(items, &(iMenuItem){ | ||
694 | format_Lang(add_Icon " ${fontpack.upgrade}", fpId, d->version), | ||
695 | SDLK_RETURN, 0, "fontpack.install" | ||
696 | }); | ||
697 | } | ||
698 | pushBack_Array(items, &(iMenuItem){ | ||
699 | format_Lang(isEnabled ? close_Icon " ${fontpack.disable}" | ||
700 | : leftArrowhead_Icon " ${fontpack.enable}", fpId), 0, 0, | ||
701 | format_CStr("fontpack.enable arg:%d id:%s", !isEnabled, fpId) }); | ||
702 | if (!d->isReadOnly && installed->loadPath && d->loadPath && | ||
703 | !cmpString_String(installed->loadPath, d->loadPath)) { | ||
704 | pushBack_Array(items, &(iMenuItem){ | ||
705 | format_Lang(delete_Icon " ${fontpack.delete}", fpId), 0, 0, | ||
706 | format_CStr("fontpack.delete id:%s", fpId) }); | ||
707 | } | ||
708 | } | ||
709 | else if (d->isStandalone) { | ||
710 | pushBack_Array(items, &(iMenuItem){ | ||
711 | format_Lang(add_Icon " ${fontpack.install}", fpId), | ||
712 | SDLK_RETURN, 0, "fontpack.install" | ||
713 | }); | ||
714 | } | ||
715 | return collect_Array(items); | ||
716 | } | ||
717 | |||
718 | iBool isDisabled_FontPack(const iFontPack *d) { | ||
719 | return contains_StringSet(prefs_App()->disabledFontPacks, &d->id); | ||
720 | } | ||
721 | |||
623 | const iString *infoPage_Fonts(void) { | 722 | const iString *infoPage_Fonts(void) { |
624 | iFonts *d = &fonts_; | 723 | iFonts *d = &fonts_; |
625 | iString *str = collectNewCStr_String("# Fonts\n"); | 724 | iString *str = collectNewCStr_String("# ${heading.fontpack.meta}\n" |
725 | "=> gemini://skyjake.fi/fonts Download more fonts\n" | ||
726 | "=> about:command?!open%20newtab:1%20gotoheading:1%20url:about:help Using fonts in Lagrange\n" | ||
727 | "=> about:command?!open%20newtab:1%20gotoheading:1%20url:about:help How to create a fontpack\n"); | ||
626 | iPtrArray *specsByPack = collectNew_PtrArray(); | 728 | iPtrArray *specsByPack = collectNew_PtrArray(); |
627 | setCopy_PtrArray(specsByPack, &d->specOrder); | 729 | setCopy_PtrArray(specsByPack, &d->specOrder); |
628 | sort_Array(specsByPack, cmpSourceAndPriority_FontSpecPtr_); | 730 | sort_Array(specsByPack, cmpSourceAndPriority_FontSpecPtr_); |
629 | iString *currentSourcePath = collectNew_String(); | 731 | iString *currentSourcePath = collectNew_String(); |
630 | iConstForEach(PtrArray, i, specsByPack) { | 732 | for (int group = 0; group < 2; group++) { |
631 | const iFontSpec *spec = i.ptr; | 733 | iBool isFirst = iTrue; |
632 | if (isEmpty_String(&spec->sourcePath)) { | 734 | iConstForEach(PtrArray, i, specsByPack) { |
633 | continue; /* built-in font */ | 735 | const iFontSpec *spec = i.ptr; |
634 | } | 736 | if (isEmpty_String(&spec->sourcePath)) { |
635 | if (!equal_String(&spec->sourcePath, currentSourcePath)) { | 737 | continue; /* built-in font */ |
636 | appendFormat_String(str, "=> %s %s%s\n", | 738 | } |
637 | cstrCollect_String(makeFileUrl_String(&spec->sourcePath)), | 739 | if (!equal_String(&spec->sourcePath, currentSourcePath)) { |
638 | endsWithCase_String(&spec->sourcePath, ".fontpack") ? "\U0001f520 " : "", | 740 | set_String(currentSourcePath, &spec->sourcePath); |
639 | cstr_Rangecc(baseName_Path(&spec->sourcePath))); | 741 | /* Print some information about this page. */ |
640 | set_String(currentSourcePath, &spec->sourcePath); | 742 | const iFontPack *pack = packByPath_Fonts(currentSourcePath); |
743 | if (pack) { | ||
744 | if (!isDisabled_FontPack(pack) ^ group) { | ||
745 | if (isFirst) { | ||
746 | appendCStr_String(str, "\n## "); | ||
747 | appendCStr_String(str, group == 0 ? "${heading.fontpack.meta.enabled}" | ||
748 | : "${heading.fontpack.meta.disabled}"); | ||
749 | appendCStr_String(str, "\n\n"); | ||
750 | isFirst = iFalse; | ||
751 | } | ||
752 | const iString *packId = id_FontPack(pack).id; | ||
753 | appendFormat_String(str, "### %s\n=> %s ${fontpack.meta.viewfile}\n", | ||
754 | isEmpty_String(packId) ? "fonts.ini" : | ||
755 | cstr_String(packId), | ||
756 | cstrCollect_String(makeFileUrl_String(&spec->sourcePath))); | ||
757 | append_String(str, collect_String(infoText_FontPack(pack))); | ||
758 | iConstForEach(Array, a, actions_FontPack(pack)) { | ||
759 | const iMenuItem *item = a.value; | ||
760 | appendFormat_String(str, "=> about:command?%s %s\n", | ||
761 | cstr_String(withSpacesEncoded_String(collectNewCStr_String(item->command))), | ||
762 | item->label); | ||
763 | } | ||
764 | } | ||
765 | } | ||
766 | } | ||
641 | } | 767 | } |
642 | } | 768 | } |
643 | return str; | 769 | return str; |
@@ -645,6 +771,9 @@ const iString *infoPage_Fonts(void) { | |||
645 | 771 | ||
646 | const iFontPack *pack_Fonts(const char *packId) { | 772 | const iFontPack *pack_Fonts(const char *packId) { |
647 | iFonts *d = &fonts_; | 773 | iFonts *d = &fonts_; |
774 | if (!*packId) { | ||
775 | return NULL; | ||
776 | } | ||
648 | iConstForEach(PtrArray, i, &d->packs) { | 777 | iConstForEach(PtrArray, i, &d->packs) { |
649 | const iFontPack *pack = i.ptr; | 778 | const iFontPack *pack = i.ptr; |
650 | if (!cmp_String(&pack->id, packId)) { | 779 | if (!cmp_String(&pack->id, packId)) { |
@@ -675,10 +804,15 @@ void reload_Fonts(void) { | |||
675 | delete_String(userDir); | 804 | delete_String(userDir); |
676 | } | 805 | } |
677 | 806 | ||
678 | void install_Fonts(const iString *fontId, const iBlock *data) { | 807 | void install_Fonts(const iString *packId, const iBlock *data) { |
808 | if (!detect_FontPack(data)) { | ||
809 | return; | ||
810 | } | ||
811 | /* Newly installed packs will never be disabled. */ | ||
812 | remove_StringSet(prefs_App()->disabledFontPacks, packId); | ||
679 | iFonts *d = &fonts_; | 813 | iFonts *d = &fonts_; |
680 | iFile *f = new_File(collect_String(concatCStr_Path( | 814 | iFile *f = new_File(collect_String(concatCStr_Path( |
681 | userFontsDirectory_Fonts_(d), format_CStr("%s.fontpack", cstr_String(fontId))))); | 815 | userFontsDirectory_Fonts_(d), format_CStr("%s.fontpack", cstr_String(packId))))); |
682 | if (open_File(f, writeOnly_FileMode)) { | 816 | if (open_File(f, writeOnly_FileMode)) { |
683 | write_File(f, data); | 817 | write_File(f, data); |
684 | } | 818 | } |
@@ -687,38 +821,5 @@ void install_Fonts(const iString *fontId, const iBlock *data) { | |||
687 | reload_Fonts(); | 821 | reload_Fonts(); |
688 | } | 822 | } |
689 | 823 | ||
690 | iBool preloadLocalFontpackForPreview_Fonts(iGmDocument *doc) { | ||
691 | iBool wasLoaded = iFalse; | ||
692 | for (size_t linkId = 1; ; linkId++) { | ||
693 | const iString *linkUrl = linkUrl_GmDocument(doc, linkId); | ||
694 | if (!linkUrl) { | ||
695 | break; /* ran out of links */ | ||
696 | } | ||
697 | const int linkFlags = linkFlags_GmDocument(doc, linkId); | ||
698 | if (linkFlags & fontpackFileExtension_GmLinkFlag && | ||
699 | scheme_GmLinkFlag(linkFlags) == file_GmLinkScheme) { | ||
700 | iMediaId linkMedia = findMediaForLink_Media(media_GmDocument(doc), linkId, fontpack_MediaType); | ||
701 | if (linkMedia.type) { | ||
702 | continue; /* got this one already */ | ||
703 | } | ||
704 | iString *filePath = localFilePathFromUrl_String(linkUrl); | ||
705 | iFile *f = new_File(filePath); | ||
706 | if (open_File(f, readOnly_FileMode)) { | ||
707 | iBlock *fontPackArchiveData = readAll_File(f); | ||
708 | setUrl_Media(media_GmDocument(doc), linkId, fontpack_MediaType, linkUrl); | ||
709 | setData_Media(media_GmDocument(doc), | ||
710 | linkId, | ||
711 | collectNewCStr_String(mimeType_FontPack), | ||
712 | fontPackArchiveData, | ||
713 | 0); | ||
714 | delete_Block(fontPackArchiveData); | ||
715 | wasLoaded = iTrue; | ||
716 | } | ||
717 | iRelease(f); | ||
718 | } | ||
719 | } | ||
720 | return wasLoaded; | ||
721 | } | ||
722 | |||
723 | iDefineClass(FontFile) | 824 | iDefineClass(FontFile) |
724 | 825 | ||
diff --git a/src/fontpack.h b/src/fontpack.h index 2fdfa9ab..fb8d757e 100644 --- a/src/fontpack.h +++ b/src/fontpack.h | |||
@@ -148,12 +148,21 @@ struct Impl_FontPackId { | |||
148 | void setReadOnly_FontPack (iFontPack *, iBool readOnly); | 148 | void setReadOnly_FontPack (iFontPack *, iBool readOnly); |
149 | void setStandalone_FontPack (iFontPack *, iBool standalone); | 149 | void setStandalone_FontPack (iFontPack *, iBool standalone); |
150 | void setLoadPath_FontPack (iFontPack *, const iString *path); | 150 | void setLoadPath_FontPack (iFontPack *, const iString *path); |
151 | void setUrl_FontPack (iFontPack *, const iString *url); | ||
151 | iBool loadArchive_FontPack (iFontPack *, const iArchive *zip); | 152 | iBool loadArchive_FontPack (iFontPack *, const iArchive *zip); |
152 | iBool detect_FontPack (const iBlock *data); | 153 | iBool detect_FontPack (const iBlock *data); |
153 | 154 | ||
154 | iFontPackId id_FontPack (const iFontPack *); | 155 | iFontPackId id_FontPack (const iFontPack *); |
155 | const iPtrArray * listSpecs_FontPack (const iFontPack *); | 156 | const iString * loadPath_FontPack (const iFontPack *); /* may return NULL */ |
157 | iBool isDisabled_FontPack (const iFontPack *); | ||
156 | iBool isReadOnly_FontPack (const iFontPack *); | 158 | iBool isReadOnly_FontPack (const iFontPack *); |
159 | const iPtrArray * listSpecs_FontPack (const iFontPack *); | ||
160 | iString * infoText_FontPack (const iFontPack *); | ||
161 | const iArray * actions_FontPack (const iFontPack *); | ||
162 | |||
163 | const iString * idFromUrl_FontPack (const iString *url); | ||
164 | |||
165 | /*----------------------------------------------------------------------------------------------*/ | ||
157 | 166 | ||
158 | iDeclareType(GmDocument) | 167 | iDeclareType(GmDocument) |
159 | 168 | ||
@@ -170,8 +179,6 @@ const iString * infoPage_Fonts (void); | |||
170 | void install_Fonts (const iString *fontId, const iBlock *data); | 179 | void install_Fonts (const iString *fontId, const iBlock *data); |
171 | void reload_Fonts (void); | 180 | void reload_Fonts (void); |
172 | 181 | ||
173 | iBool preloadLocalFontpackForPreview_Fonts (iGmDocument *doc); | ||
174 | |||
175 | iLocalDef iBool isInstalled_Fonts(const char *packId) { | 182 | iLocalDef iBool isInstalled_Fonts(const char *packId) { |
176 | return pack_Fonts(packId) != NULL; | 183 | return pack_Fonts(packId) != NULL; |
177 | } | 184 | } |
diff --git a/src/gmdocument.c b/src/gmdocument.c index 0adf5243..1f66e978 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -94,6 +94,7 @@ struct Impl_GmDocument { | |||
94 | iString localHost; | 94 | iString localHost; |
95 | iInt2 size; | 95 | iInt2 size; |
96 | int outsideMargin; | 96 | int outsideMargin; |
97 | iBool enableCommandLinks; /* `about:command?` only allowed on selected pages */ | ||
97 | iArray layout; /* contents of source, laid out in document space */ | 98 | iArray layout; /* contents of source, laid out in document space */ |
98 | iPtrArray links; | 99 | iPtrArray links; |
99 | enum iGmDocumentBanner bannerType; | 100 | enum iGmDocumentBanner bannerType; |
@@ -256,6 +257,14 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li | |||
256 | link->urlRange = capturedRange_RegExpMatch(&m, 1); | 257 | link->urlRange = capturedRange_RegExpMatch(&m, 1); |
257 | setRange_String(&link->url, link->urlRange); | 258 | setRange_String(&link->url, link->urlRange); |
258 | set_String(&link->url, canonicalUrl_String(absoluteUrl_String(&d->url, &link->url))); | 259 | set_String(&link->url, canonicalUrl_String(absoluteUrl_String(&d->url, &link->url))); |
260 | if (startsWithCase_String(&link->url, "about:command")) { | ||
261 | /* This is a special internal page that allows submitting UI events. */ | ||
262 | if (!d->enableCommandLinks) { | ||
263 | delete_GmLink(link); | ||
264 | *linkId = 0; | ||
265 | return line; | ||
266 | } | ||
267 | } | ||
259 | /* Check the URL. */ { | 268 | /* Check the URL. */ { |
260 | iUrl parts; | 269 | iUrl parts; |
261 | init_Url(&parts, &link->url); | 270 | init_Url(&parts, &link->url); |
@@ -336,7 +345,7 @@ static iRangecc addLink_GmDocument_(iGmDocument *d, iRangecc line, iGmLinkId *li | |||
336 | /* Check for a custom icon. */ | 345 | /* Check for a custom icon. */ |
337 | enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags); | 346 | enum iGmLinkScheme scheme = scheme_GmLinkFlag(link->flags); |
338 | if ((scheme == gemini_GmLinkScheme && ~link->flags & remote_GmLinkFlag) || | 347 | if ((scheme == gemini_GmLinkScheme && ~link->flags & remote_GmLinkFlag) || |
339 | scheme == file_GmLinkScheme || | 348 | scheme == about_GmLinkScheme || scheme == file_GmLinkScheme || |
340 | scheme == mailto_GmLinkScheme) { | 349 | scheme == mailto_GmLinkScheme) { |
341 | iChar icon = 0; | 350 | iChar icon = 0; |
342 | int len = 0; | 351 | int len = 0; |
@@ -826,6 +835,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
826 | : scheme == mailto_GmLinkScheme ? envelope | 835 | : scheme == mailto_GmLinkScheme ? envelope |
827 | : link->flags & remote_GmLinkFlag ? globe | 836 | : link->flags & remote_GmLinkFlag ? globe |
828 | : link->flags & imageFileExtension_GmLinkFlag ? image | 837 | : link->flags & imageFileExtension_GmLinkFlag ? image |
838 | : link->flags & fontpackFileExtension_GmLinkFlag ? fontpack_Icon | ||
829 | : scheme == file_GmLinkScheme ? folder | 839 | : scheme == file_GmLinkScheme ? folder |
830 | : arrow); | 840 | : arrow); |
831 | /* Custom link icon is shown on local Gemini links only. */ | 841 | /* Custom link icon is shown on local Gemini links only. */ |
@@ -1012,14 +1022,6 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
1012 | pushBack_Array(&d->layout, &run); | 1022 | pushBack_Array(&d->layout, &run); |
1013 | break; | 1023 | break; |
1014 | } | 1024 | } |
1015 | case fontpack_MediaType: { | ||
1016 | run.bounds.pos = pos; | ||
1017 | run.bounds.size.x = d->size.x; | ||
1018 | run.bounds.size.y = height_FontpackUI(d->media, media.id, d->size.x); | ||
1019 | run.visBounds = run.bounds; | ||
1020 | pushBack_Array(&d->layout, &run); | ||
1021 | break; | ||
1022 | } | ||
1023 | default: | 1025 | default: |
1024 | break; | 1026 | break; |
1025 | } | 1027 | } |
@@ -1069,6 +1071,7 @@ void init_GmDocument(iGmDocument *d) { | |||
1069 | d->bannerType = siteDomain_GmDocumentBanner; | 1071 | d->bannerType = siteDomain_GmDocumentBanner; |
1070 | d->outsideMargin = 0; | 1072 | d->outsideMargin = 0; |
1071 | d->size = zero_I2(); | 1073 | d->size = zero_I2(); |
1074 | d->enableCommandLinks = iFalse; | ||
1072 | init_Array(&d->layout, sizeof(iGmRun)); | 1075 | init_Array(&d->layout, sizeof(iGmRun)); |
1073 | init_PtrArray(&d->links); | 1076 | init_PtrArray(&d->links); |
1074 | init_String(&d->bannerText); | 1077 | init_String(&d->bannerText); |
@@ -1760,6 +1763,10 @@ void setUrl_GmDocument(iGmDocument *d, const iString *url) { | |||
1760 | init_Url(&parts, url); | 1763 | init_Url(&parts, url); |
1761 | setRange_String(&d->localHost, parts.host); | 1764 | setRange_String(&d->localHost, parts.host); |
1762 | updateIconBasedOnUrl_GmDocument_(d); | 1765 | updateIconBasedOnUrl_GmDocument_(d); |
1766 | if (!cmp_String(url, "about:fonts")) { | ||
1767 | /* This is an interactive internal page. */ | ||
1768 | d->enableCommandLinks = iTrue; | ||
1769 | } | ||
1763 | } | 1770 | } |
1764 | 1771 | ||
1765 | static int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement, | 1772 | static int replaceRegExp_String(iString *d, const iRegExp *regexp, const char *replacement, |
@@ -1973,9 +1980,15 @@ void setSource_GmDocument(iGmDocument *d, const iString *source, int width, int | |||
1973 | d->theme.ansiEscapesEnabled = prefs_App()->gemtextAnsiEscapes; | 1980 | d->theme.ansiEscapesEnabled = prefs_App()->gemtextAnsiEscapes; |
1974 | } | 1981 | } |
1975 | else if (d->format == markdown_SourceFormat) { | 1982 | else if (d->format == markdown_SourceFormat) { |
1976 | convertMarkdownToGemtext_GmDocument_(d); | 1983 | /* Attempt a conversion to Gemtext when viewing local Markdown files. */ |
1977 | set_String(&d->unormSource, &d->source); /* use the converted source from now on */ | 1984 | if (equalCase_Rangecc(urlScheme_String(&d->url), "file")) { |
1978 | d->theme.ansiEscapesEnabled = iTrue; /* escapes are used for styling */ | 1985 | convertMarkdownToGemtext_GmDocument_(d); |
1986 | set_String(&d->unormSource, &d->source); /* use the converted source from now on */ | ||
1987 | d->theme.ansiEscapesEnabled = iTrue; /* escapes are used for styling */ | ||
1988 | } | ||
1989 | else { | ||
1990 | d->format = plainText_SourceFormat; /* just show as plain text */ | ||
1991 | } | ||
1979 | } | 1992 | } |
1980 | else { | 1993 | else { |
1981 | d->theme.ansiEscapesEnabled = iTrue; | 1994 | d->theme.ansiEscapesEnabled = iTrue; |
diff --git a/src/gmutil.c b/src/gmutil.c index 692c1cb9..e44971d0 100644 --- a/src/gmutil.c +++ b/src/gmutil.c | |||
@@ -539,6 +539,9 @@ const char *mediaTypeFromFileExtension_String(const iString *d) { | |||
539 | else if (endsWithCase_String(d, ".fontpack")) { | 539 | else if (endsWithCase_String(d, ".fontpack")) { |
540 | return mimeType_FontPack; | 540 | return mimeType_FontPack; |
541 | } | 541 | } |
542 | else if (endsWithCase_String(d, ".ttf")) { | ||
543 | return "font/ttf"; | ||
544 | } | ||
542 | else if (endsWithCase_String(d, ".xml")) { | 545 | else if (endsWithCase_String(d, ".xml")) { |
543 | return "text/xml"; | 546 | return "text/xml"; |
544 | } | 547 | } |
@@ -247,3 +247,12 @@ const char *formatCStr_Lang(const char *formatMsgId, int count) { | |||
247 | const char *formatCStrs_Lang(const char *formatMsgId, size_t count) { | 247 | const char *formatCStrs_Lang(const char *formatMsgId, size_t count) { |
248 | return format_CStr(cstrCount_Lang(formatMsgId, (int) count), count); | 248 | return format_CStr(cstrCount_Lang(formatMsgId, (int) count), count); |
249 | } | 249 | } |
250 | |||
251 | const char *format_Lang(const char *formatTextWithIds, ...) { | ||
252 | iBlock *msg = new_Block(0); | ||
253 | va_list args; | ||
254 | va_start(args, formatTextWithIds); | ||
255 | vprintf_Block(msg, translateCStr_Lang(formatTextWithIds), args); | ||
256 | va_end(args); | ||
257 | return cstr_Block(collect_Block(msg)); | ||
258 | } | ||
@@ -39,3 +39,4 @@ const char * translateCStr_Lang (const char *textWithIds); | |||
39 | const char * cstrCount_Lang (const char *msgId, int count); | 39 | const char * cstrCount_Lang (const char *msgId, int count); |
40 | const char * formatCStr_Lang (const char *formatMsgId, int count); | 40 | const char * formatCStr_Lang (const char *formatMsgId, int count); |
41 | const char * formatCStrs_Lang (const char *formatMsgId, size_t count); | 41 | const char * formatCStrs_Lang (const char *formatMsgId, size_t count); |
42 | const char * format_Lang (const char *formatTextWithIds, ...); | ||
diff --git a/src/media.c b/src/media.c index 412205a7..a3f381ec 100644 --- a/src/media.c +++ b/src/media.c | |||
@@ -288,76 +288,6 @@ iDefineTypeConstruction(GmDownload) | |||
288 | 288 | ||
289 | /*----------------------------------------------------------------------------------------------*/ | 289 | /*----------------------------------------------------------------------------------------------*/ |
290 | 290 | ||
291 | iDeclareType(GmFontpack) | ||
292 | |||
293 | struct Impl_GmFontpack { | ||
294 | iGmMediaProps props; | ||
295 | iString packId; | ||
296 | iFontpackMediaInfo info; | ||
297 | /* TODO: Font preview images? */ | ||
298 | }; | ||
299 | |||
300 | void init_GmFontpack(iGmFontpack *d) { | ||
301 | init_GmMediaProps_(&d->props); | ||
302 | init_String(&d->packId); | ||
303 | iZap(d->info); | ||
304 | d->info.names = new_StringList(); | ||
305 | } | ||
306 | |||
307 | void deinit_GmFontpack(iGmFontpack *d) { | ||
308 | iRelease(d->info.names); | ||
309 | deinit_String(&d->packId); | ||
310 | deinit_GmMediaProps_(&d->props); | ||
311 | } | ||
312 | |||
313 | static void loadData_GmFontpack_(iGmFontpack *d, const iBlock *data) { | ||
314 | const iString *loadPath = collect_String(localFilePathFromUrl_String(&d->props.url)); | ||
315 | const iFontPack *pack = packByPath_Fonts(loadPath); | ||
316 | d->info.isValid = d->info.isInstalled = pack != NULL; | ||
317 | d->info.isReadOnly = iFalse; | ||
318 | d->info.isDisabled = iFalse; | ||
319 | clear_StringList(d->info.names); | ||
320 | clear_String(&d->packId); | ||
321 | if (!pack) { | ||
322 | /* Let's load it now temporarily and see what's inside. */ | ||
323 | iArchive *zip = new_Archive(); | ||
324 | if (openData_Archive(zip, data)) { | ||
325 | iFontPack *fp = collect_FontPack(new_FontPack()); | ||
326 | setLoadPath_FontPack(fp, loadPath); | ||
327 | /* TODO: No need to load all the font files here, just the metadata. */ | ||
328 | setStandalone_FontPack(fp, iTrue); | ||
329 | if (loadArchive_FontPack(fp, zip)) { | ||
330 | d->info.isValid = iTrue; | ||
331 | pack = fp; | ||
332 | } | ||
333 | } | ||
334 | iRelease(zip); | ||
335 | } | ||
336 | if (pack) { | ||
337 | set_String(&d->packId, id_FontPack(pack).id); | ||
338 | d->info.packId.id = &d->packId; /* we own this String */ | ||
339 | d->info.packId.version = id_FontPack(pack).version; | ||
340 | d->info.isReadOnly = isReadOnly_FontPack(pack); | ||
341 | d->info.isDisabled = contains_StringSet(prefs_App()->disabledFontPacks, &d->packId); | ||
342 | } | ||
343 | iPtrSet *unique = new_PtrSet(); | ||
344 | iConstForEach(PtrArray, i, listSpecs_FontPack(pack)) { | ||
345 | const iFontSpec *spec = i.ptr; | ||
346 | pushBack_StringList(d->info.names, &spec->name); | ||
347 | iForIndices(j, spec->styles) { | ||
348 | insert_PtrSet(unique, spec->styles[j]); | ||
349 | } | ||
350 | } | ||
351 | iConstForEach(PtrSet, j, unique) { | ||
352 | d->info.sizeInBytes += size_Block(&((const iFontFile *) *j.value)->sourceData); | ||
353 | } | ||
354 | delete_PtrSet(unique); | ||
355 | } | ||
356 | |||
357 | iDefineTypeConstruction(GmFontpack) | ||
358 | |||
359 | /*----------------------------------------------------------------------------------------------*/ | ||
360 | |||
361 | struct Impl_Media { | 291 | struct Impl_Media { |
362 | iPtrArray items[max_MediaType]; | 292 | iPtrArray items[max_MediaType]; |
363 | /* TODO: Add a hash to quickly look up a link's media. */ | 293 | /* TODO: Add a hash to quickly look up a link's media. */ |
@@ -388,9 +318,6 @@ void clear_Media(iMedia *d) { | |||
388 | iForEach(PtrArray, n, &d->items[download_MediaType]) { | 318 | iForEach(PtrArray, n, &d->items[download_MediaType]) { |
389 | deinit_GmDownload(n.ptr); | 319 | deinit_GmDownload(n.ptr); |
390 | } | 320 | } |
391 | iForEach(PtrArray, f, &d->items[fontpack_MediaType]) { | ||
392 | deinit_GmFontpack(f.ptr); | ||
393 | } | ||
394 | iForIndices(type, d->items) { | 321 | iForIndices(type, d->items) { |
395 | clear_PtrArray(&d->items[type]); | 322 | clear_PtrArray(&d->items[type]); |
396 | } | 323 | } |
@@ -436,17 +363,6 @@ iBool setUrl_Media(iMedia *d, iGmLinkId linkId, enum iMediaType mediaType, const | |||
436 | } | 363 | } |
437 | props = &dl->props; | 364 | props = &dl->props; |
438 | } | 365 | } |
439 | else if (mediaType == fontpack_MediaType) { | ||
440 | iGmFontpack *fp = NULL; | ||
441 | if (isNew) { | ||
442 | fp = new_GmFontpack(); | ||
443 | pushBack_PtrArray(&d->items[fontpack_MediaType], fp); | ||
444 | } | ||
445 | else { | ||
446 | fp = at_PtrArray(&d->items[fontpack_MediaType], index_MediaId(existing)); | ||
447 | } | ||
448 | props = &fp->props; | ||
449 | } | ||
450 | if (props) { | 366 | if (props) { |
451 | props->linkId = linkId; | 367 | props->linkId = linkId; |
452 | props->isPermanent = iTrue; | 368 | props->isPermanent = iTrue; |
@@ -517,21 +433,6 @@ iBool setData_Media(iMedia *d, iGmLinkId linkId, const iString *mime, const iBlo | |||
517 | } | 433 | } |
518 | } | 434 | } |
519 | } | 435 | } |
520 | else if (existing.type == fontpack_MediaType) { | ||
521 | iGmFontpack *fp; | ||
522 | if (isDeleting) { | ||
523 | take_PtrArray(&d->items[fontpack_MediaType], existingIndex, (void **) &fp); | ||
524 | delete_GmFontpack(fp); | ||
525 | } | ||
526 | else { | ||
527 | iAssert(!isPartial); | ||
528 | fp = at_PtrArray(&d->items[fontpack_MediaType], existingIndex); | ||
529 | if (isEmpty_String(&fp->props.mime)) { | ||
530 | set_String(&fp->props.mime, mime); | ||
531 | } | ||
532 | loadData_GmFontpack_(fp, data); | ||
533 | } | ||
534 | } | ||
535 | else if (!isDeleting) { | 436 | else if (!isDeleting) { |
536 | if (startsWith_String(mime, "image/")) { | 437 | if (startsWith_String(mime, "image/")) { |
537 | /* Copy the image to a texture. */ | 438 | /* Copy the image to a texture. */ |
@@ -591,23 +492,6 @@ iMediaId findMediaForLink_Media(const iMedia *d, iGmLinkId linkId, enum iMediaTy | |||
591 | return mid; | 492 | return mid; |
592 | } | 493 | } |
593 | 494 | ||
594 | #if 0 | ||
595 | iMediaId findUrl_Media(const iMedia *d, const iString *url) { | ||
596 | iMediaId mid = iInvalidMediaId; | ||
597 | for (int i = 0; i < max_MediaType; i++) { | ||
598 | for (int j = 0; j < size_PtrArray(&d->items[i]); j++) { | ||
599 | const iGmMediaProps *props = constAt_PtrArray(&d->items[i], j); | ||
600 | if (equal_String(&props->url, url)) { | ||
601 | mid.type = i; | ||
602 | mid.id = j + 1; | ||
603 | break; | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | return mid; | ||
608 | } | ||
609 | #endif | ||
610 | |||
611 | size_t numAudio_Media(const iMedia *d) { | 495 | size_t numAudio_Media(const iMedia *d) { |
612 | return size_PtrArray(&d->items[audio_MediaType]); | 496 | return size_PtrArray(&d->items[audio_MediaType]); |
613 | } | 497 | } |
@@ -662,9 +546,6 @@ iBool info_Media(const iMedia *d, iMediaId mediaId, iGmMediaInfo *info_out) { | |||
662 | return iTrue; | 546 | return iTrue; |
663 | } | 547 | } |
664 | break; | 548 | break; |
665 | case fontpack_MediaType: | ||
666 | /* TODO */ | ||
667 | break; | ||
668 | default: | 549 | default: |
669 | break; | 550 | break; |
670 | } | 551 | } |
@@ -718,16 +599,6 @@ void downloadStats_Media(const iMedia *d, iMediaId downloadId, const iString **p | |||
718 | } | 599 | } |
719 | } | 600 | } |
720 | 601 | ||
721 | void fontpackInfo_Media(const iMedia *d, iMediaId fontpackId, iFontpackMediaInfo *info_out) { | ||
722 | iAssert(fontpackId.type == fontpack_MediaType); | ||
723 | iZap(*info_out); | ||
724 | const size_t index = index_MediaId(fontpackId); | ||
725 | if (index < size_PtrArray(&d->items[fontpack_MediaType])) { | ||
726 | const iGmFontpack *fp = constAt_PtrArray(&d->items[fontpack_MediaType], index); | ||
727 | *info_out = fp->info; | ||
728 | } | ||
729 | } | ||
730 | |||
731 | /*----------------------------------------------------------------------------------------------*/ | 602 | /*----------------------------------------------------------------------------------------------*/ |
732 | 603 | ||
733 | static void updated_MediaRequest_(iAnyObject *obj) { | 604 | static void updated_MediaRequest_(iAnyObject *obj) { |
diff --git a/src/media.h b/src/media.h index 92a46cd3..3b329716 100644 --- a/src/media.h +++ b/src/media.h | |||
@@ -53,7 +53,6 @@ enum iMediaType { /* Note: There is a limited number of bits for these; see GmRu | |||
53 | //animatedImage_MediaType, /* TODO */ | 53 | //animatedImage_MediaType, /* TODO */ |
54 | audio_MediaType, | 54 | audio_MediaType, |
55 | download_MediaType, | 55 | download_MediaType, |
56 | fontpack_MediaType, | ||
57 | max_MediaType | 56 | max_MediaType |
58 | }; | 57 | }; |
59 | 58 | ||
@@ -74,7 +73,6 @@ iBool setData_Media (iMedia *, uint16_t linkId, const iStrin | |||
74 | 73 | ||
75 | size_t memorySize_Media (const iMedia *); | 74 | size_t memorySize_Media (const iMedia *); |
76 | iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType); | 75 | iMediaId findMediaForLink_Media (const iMedia *, uint16_t linkId, enum iMediaType mediaType); |
77 | //iMediaId findUrl_Media (const iMedia *, const iString *url); | ||
78 | 76 | ||
79 | iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type); | 77 | iMediaId id_Media (const iMedia *, uint16_t linkId, enum iMediaType type); |
80 | iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out); | 78 | iBool info_Media (const iMedia *, iMediaId mediaId, iGmMediaInfo *info_out); |
@@ -109,21 +107,6 @@ void pauseAllPlayers_Media (const iMedia *, iBool setPaused); | |||
109 | void downloadStats_Media (const iMedia *, iMediaId downloadId, const iString **path_out, | 107 | void downloadStats_Media (const iMedia *, iMediaId downloadId, const iString **path_out, |
110 | float *bytesPerSecond_out, iBool *isFinished_out); | 108 | float *bytesPerSecond_out, iBool *isFinished_out); |
111 | 109 | ||
112 | iDeclareType(FontpackMediaInfo) | ||
113 | |||
114 | struct Impl_FontpackMediaInfo { | ||
115 | iFontPackId packId; | ||
116 | iBool isValid; | ||
117 | iBool isInstalled; | ||
118 | iBool isDisabled; | ||
119 | iBool isReadOnly; | ||
120 | size_t sizeInBytes; | ||
121 | iStringList *names; | ||
122 | }; | ||
123 | |||
124 | void fontpackInfo_Media (const iMedia *, iMediaId fontpackId, | ||
125 | iFontpackMediaInfo *info_out); | ||
126 | |||
127 | /*----------------------------------------------------------------------------------------------*/ | 110 | /*----------------------------------------------------------------------------------------------*/ |
128 | 111 | ||
129 | iDeclareType(GmRequest) | 112 | iDeclareType(GmRequest) |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index 1aca895c..a1992967 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1257,7 +1257,7 @@ static const char *zipPageHeading_(const iRangecc mime) { | |||
1257 | return book_Icon " Gempub"; | 1257 | return book_Icon " Gempub"; |
1258 | } | 1258 | } |
1259 | else if (equalCase_Rangecc(mime, mimeType_FontPack)) { | 1259 | else if (equalCase_Rangecc(mime, mimeType_FontPack)) { |
1260 | return "\U0001f520 Fontpack"; | 1260 | return fontpack_Icon " Fontpack"; |
1261 | } | 1261 | } |
1262 | iRangecc type = iNullRange; | 1262 | iRangecc type = iNullRange; |
1263 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ | 1263 | nextSplit_Rangecc(mime, "/", &type); /* skip the part before the slash */ |
@@ -1435,13 +1435,6 @@ static void postProcessRequestContent_DocumentWidget_(iDocumentWidget *d, iBool | |||
1435 | } | 1435 | } |
1436 | } | 1436 | } |
1437 | } | 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 | } | ||
1445 | } | 1438 | } |
1446 | 1439 | ||
1447 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, | 1440 | static void updateDocument_DocumentWidget_(iDocumentWidget *d, |
@@ -1503,6 +1496,25 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1503 | appendFormat_String(&str, | 1496 | appendFormat_String(&str, |
1504 | cstr_Lang("doc.archive"), | 1497 | cstr_Lang("doc.archive"), |
1505 | cstr_Rangecc(baseName_Path(d->mod.url))); | 1498 | cstr_Rangecc(baseName_Path(d->mod.url))); |
1499 | if (isRequestFinished) { | ||
1500 | if (equal_Rangecc(param, mimeType_FontPack)) { | ||
1501 | /* Show some information about fontpacks, and set up footer actions. */ | ||
1502 | iArchive *zip = iClob(new_Archive()); | ||
1503 | if (openData_Archive(zip, &d->sourceContent)) { | ||
1504 | iFontPack *fp = new_FontPack(); | ||
1505 | setUrl_FontPack(fp, d->mod.url); | ||
1506 | setStandalone_FontPack(fp, iTrue); | ||
1507 | if (loadArchive_FontPack(fp, zip)) { | ||
1508 | appendFormat_String(&str, "\n\n%s", | ||
1509 | cstrCollect_String(infoText_FontPack(fp))); | ||
1510 | } | ||
1511 | const iArray *actions = actions_FontPack(fp); | ||
1512 | makeFooterButtons_DocumentWidget_(d, constData_Array(actions), | ||
1513 | size_Array(actions)); | ||
1514 | delete_FontPack(fp); | ||
1515 | } | ||
1516 | } | ||
1517 | } | ||
1506 | appendCStr_String(&str, "\n\n"); | 1518 | appendCStr_String(&str, "\n\n"); |
1507 | iString *localPath = localFilePathFromUrl_String(d->mod.url); | 1519 | iString *localPath = localFilePathFromUrl_String(d->mod.url); |
1508 | if (!localPath) { | 1520 | if (!localPath) { |
@@ -2916,27 +2928,6 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2916 | updateMedia_DocumentWidget_(d); | 2928 | updateMedia_DocumentWidget_(d); |
2917 | return iFalse; | 2929 | return iFalse; |
2918 | } | 2930 | } |
2919 | else if (equal_Command(cmd, "media.fontpack.updated")) { | ||
2920 | iMedia *media = pointerLabel_Command(cmd, "media"); | ||
2921 | if (media == media_GmDocument(d->doc)) { | ||
2922 | /*iGmMediaInfo info; | ||
2923 | if (info_Media(media, | ||
2924 | (iMediaId){ fontpack_MediaType, argU32Label_Command(cmd, "id")}, | ||
2925 | &info)) { | ||
2926 | |||
2927 | }*/ | ||
2928 | |||
2929 | // findCachedContent_App(<#const iString *url#>, <#iString *mime_out#>, <#iBlock *data_out#>) | ||
2930 | // setData_Media(media, | ||
2931 | } | ||
2932 | return iFalse; | ||
2933 | } | ||
2934 | else if (equal_Command(cmd, "media.fontpack.install")) { | ||
2935 | if (pointerLabel_Command(cmd, "media") == media_GmDocument(d->doc)) { | ||
2936 | /* TODO: This is ours, we may have a MediaRequest with the data in memory. */ | ||
2937 | } | ||
2938 | return iFalse; | ||
2939 | } | ||
2940 | else if (equal_Command(cmd, "document.stop") && document_App() == d) { | 2931 | else if (equal_Command(cmd, "document.stop") && document_App() == d) { |
2941 | if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) { | 2932 | if (cancelRequest_DocumentWidget_(d, iTrue /* navigate back */)) { |
2942 | return iTrue; | 2933 | return iTrue; |
@@ -3253,7 +3244,16 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
3253 | return handleSwipe_DocumentWidget_(d, cmd); | 3244 | return handleSwipe_DocumentWidget_(d, cmd); |
3254 | } | 3245 | } |
3255 | else if (equal_Command(cmd, "document.setmediatype") && document_App() == d) { | 3246 | else if (equal_Command(cmd, "document.setmediatype") && document_App() == d) { |
3256 | setUrlAndSource_DocumentWidget(d, d->mod.url, string_Command(cmd, "mime"), &d->sourceContent); | 3247 | if (!isRequestOngoing_DocumentWidget(d)) { |
3248 | setUrlAndSource_DocumentWidget(d, d->mod.url, string_Command(cmd, "mime"), | ||
3249 | &d->sourceContent); | ||
3250 | } | ||
3251 | return iTrue; | ||
3252 | } | ||
3253 | else if (equalWidget_Command(cmd, w, "fontpack.install")) { | ||
3254 | const iString *id = idFromUrl_FontPack(d->mod.url); | ||
3255 | install_Fonts(id, &d->sourceContent); | ||
3256 | postCommandf_App("open gotoheading:%s url:about:fonts", cstr_String(id)); | ||
3257 | return iTrue; | 3257 | return iTrue; |
3258 | } | 3258 | } |
3259 | return iFalse; | 3259 | return iFalse; |
@@ -3302,15 +3302,6 @@ static iBool processMediaEvents_DocumentWidget_(iDocumentWidget *d, const SDL_Ev | |||
3302 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); | 3302 | const iInt2 mouse = init_I2(ev->button.x, ev->button.y); |
3303 | iConstForEach(PtrArray, i, &d->visibleMedia) { | 3303 | iConstForEach(PtrArray, i, &d->visibleMedia) { |
3304 | const iGmRun *run = i.ptr; | 3304 | const iGmRun *run = i.ptr; |
3305 | if (run->mediaType == fontpack_MediaType) { | ||
3306 | iFontpackUI ui; | ||
3307 | init_FontpackUI(&ui, media_GmDocument(d->doc), run->mediaId, | ||
3308 | runRect_DocumentWidget_(d, run)); | ||
3309 | if (processEvent_FontpackUI(&ui, ev)) { | ||
3310 | refresh_Widget(d); | ||
3311 | return iTrue; | ||
3312 | } | ||
3313 | } | ||
3314 | if (run->mediaType != audio_MediaType) { | 3305 | if (run->mediaType != audio_MediaType) { |
3315 | continue; | 3306 | continue; |
3316 | } | 3307 | } |
@@ -4685,12 +4676,6 @@ static void drawMedia_DocumentWidget_(const iDocumentWidget *d, iPaint *p) { | |||
4685 | runRect_DocumentWidget_(d, run)); | 4676 | runRect_DocumentWidget_(d, run)); |
4686 | draw_DownloadUI(&ui, p); | 4677 | draw_DownloadUI(&ui, p); |
4687 | } | 4678 | } |
4688 | else if (run->mediaType == fontpack_MediaType) { | ||
4689 | iFontpackUI ui; | ||
4690 | init_FontpackUI(&ui, constMedia_GmDocument(d->doc), run->mediaId, | ||
4691 | runRect_DocumentWidget_(d, run)); | ||
4692 | draw_FontpackUI(&ui, p); | ||
4693 | } | ||
4694 | } | 4679 | } |
4695 | } | 4680 | } |
4696 | 4681 | ||
diff --git a/src/ui/mediaui.c b/src/ui/mediaui.c index ac9475dd..d85d0df9 100644 --- a/src/ui/mediaui.c +++ b/src/ui/mediaui.c | |||
@@ -279,85 +279,3 @@ void draw_DownloadUI(const iDownloadUI *d, iPaint *p) { | |||
279 | translateCStr_Lang("\u2014 ${mb.per.sec}")); | 279 | translateCStr_Lang("\u2014 ${mb.per.sec}")); |
280 | } | 280 | } |
281 | } | 281 | } |
282 | |||
283 | /*----------------------------------------------------------------------------------------------*/ | ||
284 | |||
285 | static iMenuItem action_FontpackUI_(const iFontpackUI *d) { | ||
286 | if (d->info.isInstalled) { | ||
287 | return (iMenuItem){ d->info.isDisabled ? "${media.fontpack.enable}" | ||
288 | : close_Icon " ${media.fontpack.disable}", | ||
289 | 0, 0, format_CStr("media.fontpack.enable arg:%d", d->info.isDisabled) }; | ||
290 | } | ||
291 | return (iMenuItem){ d->info.isInstalled ? close_Icon " ${media.fontpack.disable}" | ||
292 | : "${media.fontpack.install}", | ||
293 | 0, 0, | ||
294 | d->info.isInstalled ? "media.fontpack.enable arg:0" : "media.fontpack.install" }; | ||
295 | } | ||
296 | |||
297 | void init_FontpackUI(iFontpackUI *d, const iMedia *media, uint16_t mediaId, iRect bounds) { | ||
298 | d->media = media; | ||
299 | d->mediaId = mediaId; | ||
300 | fontpackInfo_Media(d->media, (iMediaId){ fontpack_MediaType, d->mediaId }, &d->info); | ||
301 | d->bounds = bounds; | ||
302 | iMenuItem action = action_FontpackUI_(d); | ||
303 | d->buttonRect.size = add_I2(measure_Text(uiLabel_FontId, action.label).bounds.size, | ||
304 | muli_I2(gap2_UI, 3)); | ||
305 | d->buttonRect.pos.x = right_Rect(d->bounds) - gap_UI - d->buttonRect.size.x; | ||
306 | d->buttonRect.pos.y = mid_Rect(d->bounds).y - d->buttonRect.size.y / 2; | ||
307 | } | ||
308 | |||
309 | iBool processEvent_FontpackUI(iFontpackUI *d, const SDL_Event *ev) { | ||
310 | switch (ev->type) { | ||
311 | case SDL_MOUSEBUTTONDOWN: | ||
312 | case SDL_MOUSEBUTTONUP: { | ||
313 | const iInt2 pos = init_I2(ev->button.x, ev->button.y); | ||
314 | if (contains_Rect(d->buttonRect, pos)) { | ||
315 | if (ev->type == SDL_MOUSEBUTTONUP) { | ||
316 | postCommandf_App("%s media:%p mediaid:%u packid:%s", | ||
317 | action_FontpackUI_(d).command, | ||
318 | d->media, d->mediaId, cstr_String(d->info.packId.id)); | ||
319 | } | ||
320 | return iTrue; | ||
321 | } | ||
322 | break; | ||
323 | } | ||
324 | case SDL_MOUSEMOTION: | ||
325 | if (contains_Rect(d->bounds, init_I2(ev->motion.x, ev->motion.y))) { | ||
326 | return iTrue; | ||
327 | } | ||
328 | break; | ||
329 | } | ||
330 | return iFalse; | ||
331 | } | ||
332 | |||
333 | int height_FontpackUI(const iMedia *media, uint16_t mediaId, int width) { | ||
334 | const iStringList *names; | ||
335 | iFontpackMediaInfo info; | ||
336 | fontpackInfo_Media(media, (iMediaId){ fontpack_MediaType, mediaId }, &info); | ||
337 | return lineHeight_Text(uiContent_FontId) + | ||
338 | lineHeight_Text(uiLabel_FontId) * (1 + size_StringList(info.names)); | ||
339 | } | ||
340 | |||
341 | void draw_FontpackUI(const iFontpackUI *d, iPaint *p) { | ||
342 | /* Draw a background box. */ | ||
343 | fillRect_Paint(p, d->bounds, uiBackground_ColorId); | ||
344 | drawRect_Paint(p, d->bounds, uiSeparator_ColorId); | ||
345 | iInt2 pos = topLeft_Rect(d->bounds); | ||
346 | const char *checks[] = { "\u2610", "\u2611" }; | ||
347 | draw_Text(uiContentBold_FontId, pos, | ||
348 | d->info.isDisabled ? uiText_ColorId : uiHeading_ColorId, "\"%s\" v%d", | ||
349 | cstr_String(d->info.packId.id), d->info.packId.version); | ||
350 | pos.y += lineHeight_Text(uiContentBold_FontId); | ||
351 | draw_Text(uiLabelBold_FontId, pos, uiText_ColorId, "%.1f MB, %d fonts %s %s %s", | ||
352 | d->info.sizeInBytes / 1.0e6, size_StringList(d->info.names), | ||
353 | // checks[info.isValid], info.isValid ? "No errors" : "Errors detected", | ||
354 | checks[d->info.isInstalled], d->info.isInstalled ? "Installed" : "Not installed", | ||
355 | d->info.isReadOnly ? "Read-Only" : ""); | ||
356 | pos.y += lineHeight_Text(uiLabelBold_FontId); | ||
357 | iConstForEach(StringList, i, d->info.names) { | ||
358 | drawRange_Text(uiLabel_FontId, pos, uiText_ColorId, range_String(i.value)); | ||
359 | pos.y += lineHeight_Text(uiLabel_FontId); | ||
360 | } | ||
361 | /* Buttons. */ | ||
362 | drawInlineButton_(p, d->buttonRect, action_FontpackUI_(d).label, uiLabel_FontId); | ||
363 | } | ||
diff --git a/src/ui/mediaui.h b/src/ui/mediaui.h index 03ea0afc..3d51e4c9 100644 --- a/src/ui/mediaui.h +++ b/src/ui/mediaui.h | |||
@@ -59,20 +59,3 @@ struct Impl_DownloadUI { | |||
59 | void init_DownloadUI (iDownloadUI *, const iMedia *media, 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 | iFontpackMediaInfo info; | ||
71 | iRect bounds; | ||
72 | iRect buttonRect; | ||
73 | }; | ||
74 | |||
75 | void init_FontpackUI (iFontpackUI *, const iMedia *media, uint16_t mediaId, iRect bounds); | ||
76 | int height_FontpackUI (const iMedia *media, uint16_t mediaId, int width); | ||
77 | iBool processEvent_FontpackUI (iFontpackUI *, const SDL_Event *ev); | ||
78 | void draw_FontpackUI (const iFontpackUI *, iPaint *p); | ||