diff --git a/src-python/config.py b/src-python/config.py index 74e0e7c0..ab836dd8 100644 --- a/src-python/config.py +++ b/src-python/config.py @@ -3,8 +3,6 @@ import inspect from os import path as os_path, makedirs as os_makedirs from json import load as json_load from json import dump as json_dump -import tkinter as tk -from tkinter import font from models.transcription.transcription_utils import device_manager from models.transcription.transcription_languages import transcription_lang from utils import generatePercentageStringsList, isUniqueStrings @@ -399,12 +397,9 @@ class Config: @FONT_FAMILY.setter def FONT_FAMILY(self, value): - root = tk.Tk() - root.withdraw() - if value in list(font.families()): + if isinstance(value, str): self._FONT_FAMILY = value saveJson(self.PATH_CONFIG, inspect.currentframe().f_code.co_name, value) - root.destroy() @property @json_serializable('UI_LANGUAGE') diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 500b6b63..26914709 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -6,6 +6,7 @@ version = 3 name = "VRCT" version = "0.0.0" dependencies = [ + "font-kit", "serde", "serde_json", "tauri", @@ -322,8 +323,8 @@ dependencies = [ "block", "cocoa-foundation", "core-foundation", - "core-graphics", - "foreign-types", + "core-graphics 0.22.3", + "foreign-types 0.3.2", "libc", "objc", ] @@ -389,7 +390,20 @@ dependencies = [ "bitflags 1.3.2", "core-foundation", "core-graphics-types", - "foreign-types", + "foreign-types 0.3.2", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types 0.5.0", "libc", ] @@ -404,6 +418,18 @@ dependencies = [ "libc", ] +[[package]] +name = "core-text" +version = "20.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d2790b5c08465d49f8dc05c8bcae9fea467855947db39b0f8145c091aaced5" +dependencies = [ + "core-foundation", + "core-graphics 0.23.2", + "foreign-types 0.5.0", + "libc", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -571,6 +597,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-next" version = "2.0.0" @@ -581,6 +616,18 @@ dependencies = [ "dirs-sys-next", ] +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "dirs-sys-next" version = "0.1.2" @@ -598,6 +645,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "dtoa" version = "1.0.9" @@ -619,6 +675,18 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +[[package]] +name = "dwrote" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da3498378ed373237bdef1eddcc64e7be2d3ba4841f4c22a998e81cadeea83c" +dependencies = [ + "lazy_static", + "libc", + "winapi", + "wio", +] + [[package]] name = "embed-resource" version = "2.4.2" @@ -711,19 +779,71 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "float-ord" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce81f49ae8a0482e4c55ea62ebbd7e5a686af544c00b9d090bba3ff9be97b3d" + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "font-kit" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64b34f4efd515f905952d91bc185039863705592c0c53ae6d979805dd154520" +dependencies = [ + "bitflags 2.5.0", + "byteorder", + "core-foundation", + "core-graphics 0.23.2", + "core-text", + "dirs", + "dwrote", + "float-ord", + "freetype-sys", + "lazy_static", + "libc", + "log", + "pathfinder_geometry", + "pathfinder_simd", + "walkdir", + "winapi", + "yeslogic-fontconfig-sys", +] + [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared", + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.65", ] [[package]] @@ -732,6 +852,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + [[package]] name = "form_urlencoded" version = "1.2.1" @@ -741,6 +867,17 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "freetype-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7edc5b9669349acfda99533e9e0bcf26a51862ab43b08ee7745c55d28eb134" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "futf" version = "0.1.5" @@ -1413,6 +1550,16 @@ version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.5", +] + [[package]] name = "libredox" version = "0.1.3" @@ -1684,6 +1831,12 @@ dependencies = [ "windows-sys 0.42.0", ] +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "os_pipe" version = "1.1.5" @@ -1754,6 +1907,25 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pathfinder_geometry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b7e7b4ea703700ce73ebf128e1450eb69c3a8329199ffbfb9b2a0418e5ad3" +dependencies = [ + "log", + "pathfinder_simd", +] + +[[package]] +name = "pathfinder_simd" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cf07ef4804cfa9aea3b04a7bbdd5a40031dbb6b4f2cbaf2b011666c80c5b4f2" +dependencies = [ + "rustc_version", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2579,7 +2751,7 @@ dependencies = [ "cc", "cocoa", "core-foundation", - "core-graphics", + "core-graphics 0.22.3", "crossbeam-channel", "dispatch", "gdk", @@ -3694,6 +3866,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "wio" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5" +dependencies = [ + "winapi", +] + [[package]] name = "wry" version = "0.24.10" @@ -3703,7 +3884,7 @@ dependencies = [ "base64 0.13.1", "block", "cocoa", - "core-graphics", + "core-graphics 0.22.3", "crossbeam-channel", "dunce", "gdk", @@ -3763,3 +3944,14 @@ dependencies = [ "linux-raw-sys", "rustix", ] + +[[package]] +name = "yeslogic-fontconfig-sys" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503a066b4c037c440169d995b869046827dbc71263f6e8f3be6d77d4f3229dbd" +dependencies = [ + "dlib", + "once_cell", + "pkg-config", +] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 9c80759d..3c28deba 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -14,6 +14,7 @@ tauri-build = { version = "1", features = [] } tauri = { version = "1", features = [ "window-set-decorations", "window-set-always-on-top", "shell-sidecar", "shell-open", "devtools"] } serde = { version = "1", features = ["derive"] } serde_json = "1" +font-kit = "0.14.2" [features] # This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!! diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 7bb53643..098c2185 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -10,8 +10,27 @@ fn main() { app.get_window("main").unwrap().open_devtools(); // `main` is the first window from tauri.conf.json without an explicit label Ok(()) }) - // .invoke_handler(tauri::generate_handler![greet, run_python_script]) + .invoke_handler(tauri::generate_handler![get_font_list]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } + +use font_kit::{source::SystemSource}; +use std::collections::HashSet; + +#[tauri::command] +async fn get_font_list() -> Vec { + let source = SystemSource::new(); + let mut font_families = HashSet::new(); + + if let Ok(fonts) = source.all_fonts() { + for font in fonts { + if let Ok(info) = font.load() { + font_families.insert(info.family_name().to_string()); + } + } + } + + font_families.into_iter().collect() +} diff --git a/src-ui/app/App.jsx b/src-ui/app/App.jsx index 28cd4be8..4fa13e09 100644 --- a/src-ui/app/App.jsx +++ b/src-ui/app/App.jsx @@ -15,6 +15,7 @@ export const App = () => { + ); }; @@ -33,6 +34,7 @@ import { useSendMessageButtonType } from "@logics_configs/useSendMessageButtonTy import { useUiLanguage } from "@logics_configs/useUiLanguage"; import { useUiScaling } from "@logics_configs/useUiScaling"; import { useMessageLogUiScaling } from "@logics_configs/useMessageLogUiScaling"; +import { useSelectedFontFamily } from "@logics_configs/useSelectedFontFamily"; import { useIsMainPageCompactMode } from "@logics_main/useIsMainPageCompactMode"; import { useLanguageSettings } from "@logics_main/useLanguageSettings"; @@ -47,6 +49,7 @@ const StartPythonFacadeComponent = () => { const { asyncStartPython } = useStartPython(); const hasRunRef = useRef(false); const main_page = getCurrent(); + const { asyncFetchFonts } = useAsyncFetchFonts(); const { getMicHostList } = useMicHostList(); const { getMicDeviceList } = useMicDeviceList(); @@ -66,6 +69,7 @@ const StartPythonFacadeComponent = () => { const { getUiLanguage } = useUiLanguage(); const { getUiScaling } = useUiScaling(); const { getMessageLogUiScaling } = useMessageLogUiScaling(); + const { getSelectedFontFamily } = useSelectedFontFamily(); const { getSelectedPresetTabNumber, @@ -89,6 +93,9 @@ const StartPythonFacadeComponent = () => { getIsMainPageCompactMode(); getMessageInputBoxRatio(); + asyncFetchFonts(); + getSelectedFontFamily(); + getSoftwareVersion(); getSelectedPresetTabNumber(); @@ -191,7 +198,36 @@ const UiSizeController = () => { useEffect(() => { document.documentElement.style.setProperty("font-size", `${font_size}%`); + document.documentElement.style.setProperty("font-family", `Yu Gothic UI`); }, [currentUiScaling.data]); return null; +}; + + +const FontFamilyController = () => { + const { currentSelectedFontFamily } = useSelectedFontFamily(); + useEffect(() => { + document.documentElement.style.setProperty("font-family", `${currentSelectedFontFamily.data}`); + }, [currentSelectedFontFamily.data]); + + return null; +}; + +import { useStore_SelectableFontFamilyList } from "@store"; +import { arrayToObject } from "@utils/arrayToObject"; + +import { invoke } from "@tauri-apps/api/tauri"; +const useAsyncFetchFonts = () => { + const { updateSelectableFontFamilyList } = useStore_SelectableFontFamilyList(); + const asyncFetchFonts = async () => { + try { + let fonts = await invoke("get_font_list"); + fonts = fonts.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: "base" })); + updateSelectableFontFamilyList(arrayToObject(fonts)); + } catch (error) { + console.error("Error fetching fonts:", error); + } + }; + return { asyncFetchFonts }; }; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx b/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx index ee5c7bd2..2c14f4da 100644 --- a/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/appearance/Appearance.jsx @@ -25,6 +25,7 @@ export const Appearance = () => { + @@ -184,4 +185,28 @@ const MessageLogUiScalingContainer = () => { track={false} /> ); +}; +import { useStore_SelectableFontFamilyList } from "@store"; +import { DropdownMenuContainer } from "../components/useSettingBox"; +import { useSelectedFontFamily } from "@logics_configs/useSelectedFontFamily"; +const FontFamilyContainer = () => { + const { t } = useTranslation(); + const { currentSelectedFontFamily, setSelectedFontFamily } = useSelectedFontFamily(); + + const selectFunction = (selected_data) => { + setSelectedFontFamily(selected_data.selected_id); + }; + const { currentSelectableFontFamilyList } = useStore_SelectableFontFamilyList(); + + return ( + + ); }; \ No newline at end of file diff --git a/src-ui/app/config_page/setting_section/setting_box/components/dropdown_menu/DropdownMenu.module.scss b/src-ui/app/config_page/setting_section/setting_box/components/dropdown_menu/DropdownMenu.module.scss index 2dc94d7c..f7181e72 100644 --- a/src-ui/app/config_page/setting_section/setting_box/components/dropdown_menu/DropdownMenu.module.scss +++ b/src-ui/app/config_page/setting_section/setting_box/components/dropdown_menu/DropdownMenu.module.scss @@ -60,6 +60,8 @@ flex-direction: column; gap: 0.1rem; white-space: nowrap; + max-height: 20rem; + overflow-y: scroll; } .value_button { diff --git a/src-ui/logics/configs/useSelectedFontFamily.js b/src-ui/logics/configs/useSelectedFontFamily.js new file mode 100644 index 00000000..bfb43029 --- /dev/null +++ b/src-ui/logics/configs/useSelectedFontFamily.js @@ -0,0 +1,24 @@ +import { useStore_SelectedFontFamily } from "@store"; +import { useStdoutToPython } from "@logics/useStdoutToPython"; + +export const useSelectedFontFamily = () => { + const { asyncStdoutToPython } = useStdoutToPython(); + const { currentSelectedFontFamily, updateSelectedFontFamily, pendingSelectedFontFamily } = useStore_SelectedFontFamily(); + + const getSelectedFontFamily = () => { + pendingSelectedFontFamily(); + asyncStdoutToPython("/get/data/font_family"); + }; + + const setSelectedFontFamily = (selected_font_family) => { + pendingSelectedFontFamily(); + asyncStdoutToPython("/set/data/font_family", selected_font_family); + }; + + return { + currentSelectedFontFamily, + getSelectedFontFamily, + updateSelectedFontFamily, + setSelectedFontFamily, + }; +}; \ No newline at end of file diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index c74e6681..bfc06aea 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -25,6 +25,7 @@ import { useMicThreshold } from "@logics_configs/useMicThreshold"; import { useSpeakerThreshold } from "@logics_configs/useSpeakerThreshold"; import { useEnableAutoClearMessageBox } from "@logics_configs/useEnableAutoClearMessageBox"; import { useSendMessageButtonType } from "@logics_configs/useSendMessageButtonType"; +import { useSelectedFontFamily } from "@logics_configs/useSelectedFontFamily"; import { useUiLanguage } from "@logics_configs/useUiLanguage"; import { useUiScaling } from "@logics_configs/useUiScaling"; @@ -75,6 +76,7 @@ export const useReceiveRoutes = () => { } = useVolume(); const { updateMessageInputBoxRatio } = useMessageInputBoxRatio(); + const { updateSelectedFontFamily } = useSelectedFontFamily(); const routes = { @@ -208,6 +210,9 @@ export const useReceiveRoutes = () => { "/get/data/textbox_ui_scaling": updateMessageLogUiScaling, "/set/data/textbox_ui_scaling": updateMessageLogUiScaling, + "/get/data/font_family": updateSelectedFontFamily, + "/set/data/font_family": updateSelectedFontFamily, + // Others Tab "/get/data/auto_clear_message_box": updateEnableAutoClearMessageBox, "/set/enable/auto_clear_message_box": updateEnableAutoClearMessageBox, diff --git a/src-ui/store.js b/src-ui/store.js index 7afbd47c..e21379f0 100644 --- a/src-ui/store.js +++ b/src-ui/store.js @@ -172,6 +172,8 @@ export const { atomInstance: Atom_EnableAutomaticSpeakerThreshold, useHook: useS export const { atomInstance: Atom_UiLanguage, useHook: useStore_UiLanguage } = createAtomWithHook("en", "UiLanguage"); export const { atomInstance: Atom_UiScaling, useHook: useStore_UiScaling } = createAtomWithHook(100, "UiScaling"); export const { atomInstance: Atom_MessageLogUiScaling, useHook: useStore_MessageLogUiScaling } = createAtomWithHook(100, "MessageLogUiScaling"); +export const { atomInstance: Atom_SelectedFontFamily, useHook: useStore_SelectedFontFamily } = createAtomWithHook("Yu Gothic UI", "SelectedFontFamily"); +export const { atomInstance: Atom_SelectableFontFamilyList, useHook: useStore_SelectableFontFamilyList } = createAtomWithHook({}, "SelectableFontFamilyList"); export const { atomInstance: Atom_IsOpenedWordFilterList, useHook: useStore_IsOpenedWordFilterList } = createAtomWithHook(false, "IsOpenedWordFilterList"); diff --git a/src-ui/utils/root.css b/src-ui/utils/root.css index 23055345..87388742 100644 --- a/src-ui/utils/root.css +++ b/src-ui/utils/root.css @@ -24,6 +24,7 @@ html, body { height: 100%; + font-family: "Yu Gothic UI"; /* If not found the font family where 'root:' that is selected by user*/ }