"""Per-directory custom folder icons (Features: "Add custom icons for directories... should be able to be changed in properties"). Independent of the global fullness-variant system in Core.py's FolderIconBands/ AppConfig.FolderFullnessThreshold — a directory listed here always shows its own fixed icon/image regardless of how full it is; see Browser.py's _ResolveFolderIcon for how the two combine.""" from dataclasses import dataclass from pathlib import Path import toml from Core import ConfigDir FolderIconsPath = ConfigDir / "FolderIcons.toml" # Pre-made choices for the icon picker (Features: "Use the pre-made ones" / # "add more folder icons (e.g. documents and such)"): Material's own # folder-shape variants first, then purpose/content icons so a folder can be # marked by what's in it, not just shape — common special-folder categories # (Documents, Desktop, Fonts, Games, ...) plus Bookmarks' original set. FolderIconChoices = [ "FOLDER_OUTLINED", "FOLDER_OPEN", "FOLDER_SPECIAL", "FOLDER_SHARED", "FOLDER_ZIP", "FOLDER_COPY", "SNIPPET_FOLDER", "RULE_FOLDER", "STAR_OUTLINE", "FAVORITE_OUTLINE", "WORK_OUTLINE", "HOME_OUTLINED", "DOWNLOAD_OUTLINED", "IMAGE_OUTLINED", "MUSIC_NOTE_OUTLINED", "VIDEOCAM_OUTLINED", "CODE_OUTLINED", "DESCRIPTION_OUTLINED", "DESKTOP_WINDOWS_OUTLINED", "FONT_DOWNLOAD_OUTLINED", "SPORTS_ESPORTS_OUTLINED", "BACKUP_OUTLINED", "CLOUD_OUTLINED", "DELETE_OUTLINE", "SETTINGS_OUTLINED", "MENU_BOOK_OUTLINED", "MAIL_OUTLINE", "CONTACTS_OUTLINED", "SCHOOL_OUTLINED", "BUSINESS_CENTER_OUTLINED", "SCIENCE_OUTLINED", "PUBLIC_OUTLINED", "LOCK_OUTLINE", "ATTACH_MONEY_OUTLINED", "RECEIPT_LONG_OUTLINED", "BUILD_OUTLINED", "EXTENSION_OUTLINED", ] FolderIconLabelOverrides = { "FOLDER_OUTLINED": "Default", "FOLDER_OPEN": "Open", "FOLDER_SPECIAL": "Special", "FOLDER_SHARED": "Shared", "FOLDER_ZIP": "Archive", "FOLDER_COPY": "Copy", "SNIPPET_FOLDER": "Snippet", "RULE_FOLDER": "Rules", "VIDEOCAM_OUTLINED": "Videos", "DESCRIPTION_OUTLINED": "Documents", "DESKTOP_WINDOWS_OUTLINED": "Desktop", "FONT_DOWNLOAD_OUTLINED": "Fonts", "SPORTS_ESPORTS_OUTLINED": "Games", "BACKUP_OUTLINED": "Backup", "CLOUD_OUTLINED": "Cloud", "DELETE_OUTLINE": "Trash", "SETTINGS_OUTLINED": "Config", "MENU_BOOK_OUTLINED": "Books", "MAIL_OUTLINE": "Mail", "CONTACTS_OUTLINED": "Contacts", "SCHOOL_OUTLINED": "School", "BUSINESS_CENTER_OUTLINED": "Business", "SCIENCE_OUTLINED": "Projects", "PUBLIC_OUTLINED": "Public", "LOCK_OUTLINE": "Private", "ATTACH_MONEY_OUTLINED": "Finance", "RECEIPT_LONG_OUTLINED": "Receipts", "BUILD_OUTLINED": "Tools", "EXTENSION_OUTLINED": "Plugins", } @dataclass class FolderIconOverride: Icon: str = "" ImagePath: str = "" def LoadFolderIconOverrides() -> dict[Path, FolderIconOverride]: if not FolderIconsPath.exists(): return {} try: Data = toml.loads(FolderIconsPath.read_text()) except toml.TomlDecodeError: return {} Overrides: dict[Path, FolderIconOverride] = {} for PathText, Entry in Data.items(): if isinstance(Entry, dict): Overrides[Path(PathText)] = FolderIconOverride( Icon=Entry.get("Icon", ""), ImagePath=Entry.get("ImagePath", "") ) return Overrides def SetFolderIconOverride(TargetPath: Path, Icon: str, ImagePath: str) -> None: """Icon and ImagePath both blank clears the override, back to whatever the global fullness-variant system would otherwise show.""" Overrides = LoadFolderIconOverrides() if Icon or ImagePath: Overrides[TargetPath] = FolderIconOverride(Icon, ImagePath) else: Overrides.pop(TargetPath, None) ConfigDir.mkdir(parents=True, exist_ok=True) Data = {str(P): {"Icon": O.Icon, "ImagePath": O.ImagePath} for P, O in Overrides.items()} FolderIconsPath.write_text(toml.dumps(Data))