Source code for bacommon.text

# Released under the MIT License. See LICENSE for details.
#
"""Text related bits."""

from __future__ import annotations  # Docs-generation hack.

from enum import Enum
from functools import cache, cached_property
from typing import TYPE_CHECKING, assert_never

if TYPE_CHECKING:
    pass


[docs] class SpecialChar(Enum): """Custom unicode characters the engine can display. Each value is the character itself, ready to drop into a string. These utilize the private-use block of unicode characters (U+E000-U+F8FF) and are specific to the game; exporting or rendering them elsewhere will be meaningless. This is the one list of these characters; the engine's own table is generated from it. It is also available as ``babase.SpecialChar`` and ``bauiv1.SpecialChar``. """ LEFT_ARROW = '\ue001' RIGHT_ARROW = '\ue002' UP_ARROW = '\ue003' DOWN_ARROW = '\ue004' LEFT_BUTTON = '\ue005' TOP_BUTTON = '\ue006' RIGHT_BUTTON = '\ue007' BOTTOM_BUTTON = '\ue008' DELETE = '\ue009' SHIFT = '\ue00a' BACK = '\ue00b' LOGO_FLAT = '\ue00c' REWIND_BUTTON = '\ue00d' PLAY_PAUSE_BUTTON = '\ue00e' FAST_FORWARD_BUTTON = '\ue00f' DPAD_CENTER_BUTTON = '\ue010' PLAY_STATION_CROSS_BUTTON = '\ue011' PLAY_STATION_CIRCLE_BUTTON = '\ue012' PLAY_STATION_TRIANGLE_BUTTON = '\ue013' PLAY_STATION_SQUARE_BUTTON = '\ue014' PLAY_BUTTON = '\ue015' PAUSE_BUTTON = '\ue016' CLOSE = '\ue017' OUYA_BUTTON_O = '\ue019' OUYA_BUTTON_U = '\ue01a' OUYA_BUTTON_Y = '\ue01b' OUYA_BUTTON_A = '\ue01c' TOKEN = '\ue01d' LOGO = '\ue01e' TICKET = '\ue01f' GOOGLE_PLAY_GAMES_LOGO = '\ue020' GAME_CENTER_LOGO = '\ue021' DICE_BUTTON1 = '\ue022' DICE_BUTTON2 = '\ue023' DICE_BUTTON3 = '\ue024' DICE_BUTTON4 = '\ue025' DISCORD_LOGO = '\ue026' PARTY_ICON = '\ue027' TEST_ACCOUNT = '\ue028' TICKET_BACKING = '\ue029' TROPHY1 = '\ue02a' TROPHY2 = '\ue02b' TROPHY3 = '\ue02c' TROPHY0A = '\ue02d' TROPHY0B = '\ue02e' TROPHY4 = '\ue02f' LOCAL_ACCOUNT = '\ue030' EXPLODINARY_LOGO = '\ue031' FLAG_UNITED_STATES = '\ue032' FLAG_MEXICO = '\ue033' FLAG_GERMANY = '\ue034' FLAG_BRAZIL = '\ue035' FLAG_RUSSIA = '\ue036' FLAG_CHINA = '\ue037' FLAG_UNITED_KINGDOM = '\ue038' FLAG_CANADA = '\ue039' FLAG_INDIA = '\ue03a' FLAG_JAPAN = '\ue03b' FLAG_FRANCE = '\ue03c' FLAG_INDONESIA = '\ue03d' FLAG_ITALY = '\ue03e' FLAG_SOUTH_KOREA = '\ue03f' FLAG_NETHERLANDS = '\ue040' FEDORA = '\ue041' HAL = '\ue042' CROWN = '\ue043' YIN_YANG = '\ue044' EYE_BALL = '\ue045' SKULL = '\ue046' HEART = '\ue047' DRAGON = '\ue048' HELMET = '\ue049' MUSHROOM = '\ue04a' NINJA_STAR = '\ue04b' VIKING_HELMET = '\ue04c' MOON = '\ue04d' SPIDER = '\ue04e' FIREBALL = '\ue04f' FLAG_UNITED_ARAB_EMIRATES = '\ue050' FLAG_QATAR = '\ue051' FLAG_EGYPT = '\ue052' FLAG_KUWAIT = '\ue053' FLAG_ALGERIA = '\ue054' FLAG_SAUDI_ARABIA = '\ue055' FLAG_MALAYSIA = '\ue056' FLAG_CZECH_REPUBLIC = '\ue057' FLAG_AUSTRALIA = '\ue058' FLAG_SINGAPORE = '\ue059' OCULUS_LOGO = '\ue05a' STEAM_LOGO = '\ue05b' NVIDIA_LOGO = '\ue05c' FLAG_IRAN = '\ue05d' FLAG_POLAND = '\ue05e' FLAG_ARGENTINA = '\ue05f' FLAG_PHILIPPINES = '\ue060' FLAG_CHILE = '\ue061' MIKIROG = '\ue062' V2_LOGO = '\ue063' SANTA_HAT = '\ue064' POTATO = '\ue065' PALM_TREE = '\ue066' BOXING_GLOVE = '\ue067' ANNIVERSARY_15_CAKE = '\ue068' ANNIVERSARY_15_SPAZ = '\ue069' ANNIVERSARY_15_BOMB = '\ue06a' POPUP_ICON = '\ue018' # Full-size twins of the superscript icons above (see full_size). LOGO_FULL = '\ue06b' GOOGLE_PLAY_GAMES_LOGO_FULL = '\ue06c' GAME_CENTER_LOGO_FULL = '\ue06d' DISCORD_LOGO_FULL = '\ue06e' TEST_ACCOUNT_FULL = '\ue06f' LOCAL_ACCOUNT_FULL = '\ue070' EXPLODINARY_LOGO_FULL = '\ue071' FLAG_UNITED_STATES_FULL = '\ue072' FLAG_MEXICO_FULL = '\ue073' FLAG_GERMANY_FULL = '\ue074' FLAG_BRAZIL_FULL = '\ue075' FLAG_RUSSIA_FULL = '\ue076' FLAG_CHINA_FULL = '\ue077' FLAG_UNITED_KINGDOM_FULL = '\ue078' FLAG_CANADA_FULL = '\ue079' FLAG_INDIA_FULL = '\ue07a' FLAG_JAPAN_FULL = '\ue07b' FLAG_FRANCE_FULL = '\ue07c' FLAG_INDONESIA_FULL = '\ue07d' FLAG_ITALY_FULL = '\ue07e' FLAG_SOUTH_KOREA_FULL = '\ue07f' FLAG_NETHERLANDS_FULL = '\ue080' FEDORA_FULL = '\ue081' HAL_FULL = '\ue082' CROWN_FULL = '\ue083' YIN_YANG_FULL = '\ue084' EYE_BALL_FULL = '\ue085' SKULL_FULL = '\ue086' HEART_FULL = '\ue087' DRAGON_FULL = '\ue088' HELMET_FULL = '\ue089' MUSHROOM_FULL = '\ue08a' NINJA_STAR_FULL = '\ue08b' VIKING_HELMET_FULL = '\ue08c' MOON_FULL = '\ue08d' SPIDER_FULL = '\ue08e' FIREBALL_FULL = '\ue08f' FLAG_UNITED_ARAB_EMIRATES_FULL = '\ue090' FLAG_QATAR_FULL = '\ue091' FLAG_EGYPT_FULL = '\ue092' FLAG_KUWAIT_FULL = '\ue093' FLAG_ALGERIA_FULL = '\ue094' FLAG_SAUDI_ARABIA_FULL = '\ue095' FLAG_MALAYSIA_FULL = '\ue096' FLAG_CZECH_REPUBLIC_FULL = '\ue097' FLAG_AUSTRALIA_FULL = '\ue098' FLAG_SINGAPORE_FULL = '\ue099' OCULUS_LOGO_FULL = '\ue09a' STEAM_LOGO_FULL = '\ue09b' NVIDIA_LOGO_FULL = '\ue09c' FLAG_IRAN_FULL = '\ue09d' FLAG_POLAND_FULL = '\ue09e' FLAG_ARGENTINA_FULL = '\ue09f' FLAG_PHILIPPINES_FULL = '\ue0a0' FLAG_CHILE_FULL = '\ue0a1' MIKIROG_FULL = '\ue0a2' V2_LOGO_FULL = '\ue0a3' SANTA_HAT_FULL = '\ue0a4' POTATO_FULL = '\ue0a5' PALM_TREE_FULL = '\ue0a6' BOXING_GLOVE_FULL = '\ue0a7' ANNIVERSARY_15_CAKE_FULL = '\ue0a8' ANNIVERSARY_15_SPAZ_FULL = '\ue0a9' ANNIVERSARY_15_BOMB_FULL = '\ue0aa'
[docs] @cached_property def min_engine_build(self) -> int: """The first engine build able to draw this character. Older builds have no glyph for it and show a blank, so anything offering characters to a particular client (a store, an icon picker) should leave out ones newer than that client's build. When adding a character, give it its own case here returning the build number that first ships its glyph. Everything that predates this property returns 0 (we don't know when those were added, and every client we talk to can draw them). """ cls = type(self) match self: case ( cls.LEFT_ARROW | cls.RIGHT_ARROW | cls.UP_ARROW | cls.DOWN_ARROW | cls.LEFT_BUTTON | cls.TOP_BUTTON | cls.RIGHT_BUTTON | cls.BOTTOM_BUTTON | cls.DELETE | cls.SHIFT | cls.BACK | cls.LOGO_FLAT | cls.REWIND_BUTTON | cls.PLAY_PAUSE_BUTTON | cls.FAST_FORWARD_BUTTON | cls.DPAD_CENTER_BUTTON | cls.PLAY_STATION_CROSS_BUTTON | cls.PLAY_STATION_CIRCLE_BUTTON | cls.PLAY_STATION_TRIANGLE_BUTTON | cls.PLAY_STATION_SQUARE_BUTTON | cls.PLAY_BUTTON | cls.PAUSE_BUTTON | cls.CLOSE | cls.OUYA_BUTTON_O | cls.OUYA_BUTTON_U | cls.OUYA_BUTTON_Y | cls.OUYA_BUTTON_A | cls.TOKEN | cls.LOGO | cls.TICKET | cls.GOOGLE_PLAY_GAMES_LOGO | cls.GAME_CENTER_LOGO | cls.DICE_BUTTON1 | cls.DICE_BUTTON2 | cls.DICE_BUTTON3 | cls.DICE_BUTTON4 | cls.DISCORD_LOGO | cls.PARTY_ICON | cls.TEST_ACCOUNT | cls.TICKET_BACKING | cls.TROPHY1 | cls.TROPHY2 | cls.TROPHY3 | cls.TROPHY0A | cls.TROPHY0B | cls.TROPHY4 | cls.LOCAL_ACCOUNT | cls.EXPLODINARY_LOGO | cls.FLAG_UNITED_STATES | cls.FLAG_MEXICO | cls.FLAG_GERMANY | cls.FLAG_BRAZIL | cls.FLAG_RUSSIA | cls.FLAG_CHINA | cls.FLAG_UNITED_KINGDOM | cls.FLAG_CANADA | cls.FLAG_INDIA | cls.FLAG_JAPAN | cls.FLAG_FRANCE | cls.FLAG_INDONESIA | cls.FLAG_ITALY | cls.FLAG_SOUTH_KOREA | cls.FLAG_NETHERLANDS | cls.FEDORA | cls.HAL | cls.CROWN | cls.YIN_YANG | cls.EYE_BALL | cls.SKULL | cls.HEART | cls.DRAGON | cls.HELMET | cls.MUSHROOM | cls.NINJA_STAR | cls.VIKING_HELMET | cls.MOON | cls.SPIDER | cls.FIREBALL | cls.FLAG_UNITED_ARAB_EMIRATES | cls.FLAG_QATAR | cls.FLAG_EGYPT | cls.FLAG_KUWAIT | cls.FLAG_ALGERIA | cls.FLAG_SAUDI_ARABIA | cls.FLAG_MALAYSIA | cls.FLAG_CZECH_REPUBLIC | cls.FLAG_AUSTRALIA | cls.FLAG_SINGAPORE | cls.OCULUS_LOGO | cls.STEAM_LOGO | cls.NVIDIA_LOGO | cls.FLAG_IRAN | cls.FLAG_POLAND | cls.FLAG_ARGENTINA | cls.FLAG_PHILIPPINES | cls.FLAG_CHILE | cls.MIKIROG | cls.V2_LOGO | cls.SANTA_HAT | cls.POTATO | cls.PALM_TREE | cls.BOXING_GLOVE | cls.POPUP_ICON ): return 0 case ( cls.ANNIVERSARY_15_CAKE | cls.ANNIVERSARY_15_SPAZ | cls.ANNIVERSARY_15_BOMB ): return 23057 case ( cls.LOGO_FULL | cls.GOOGLE_PLAY_GAMES_LOGO_FULL | cls.GAME_CENTER_LOGO_FULL | cls.DISCORD_LOGO_FULL | cls.TEST_ACCOUNT_FULL | cls.LOCAL_ACCOUNT_FULL | cls.EXPLODINARY_LOGO_FULL | cls.FLAG_UNITED_STATES_FULL | cls.FLAG_MEXICO_FULL | cls.FLAG_GERMANY_FULL | cls.FLAG_BRAZIL_FULL | cls.FLAG_RUSSIA_FULL | cls.FLAG_CHINA_FULL | cls.FLAG_UNITED_KINGDOM_FULL | cls.FLAG_CANADA_FULL | cls.FLAG_INDIA_FULL | cls.FLAG_JAPAN_FULL | cls.FLAG_FRANCE_FULL | cls.FLAG_INDONESIA_FULL | cls.FLAG_ITALY_FULL | cls.FLAG_SOUTH_KOREA_FULL | cls.FLAG_NETHERLANDS_FULL | cls.FEDORA_FULL | cls.HAL_FULL | cls.CROWN_FULL | cls.YIN_YANG_FULL | cls.EYE_BALL_FULL | cls.SKULL_FULL | cls.HEART_FULL | cls.DRAGON_FULL | cls.HELMET_FULL | cls.MUSHROOM_FULL | cls.NINJA_STAR_FULL | cls.VIKING_HELMET_FULL | cls.MOON_FULL | cls.SPIDER_FULL | cls.FIREBALL_FULL | cls.FLAG_UNITED_ARAB_EMIRATES_FULL | cls.FLAG_QATAR_FULL | cls.FLAG_EGYPT_FULL | cls.FLAG_KUWAIT_FULL | cls.FLAG_ALGERIA_FULL | cls.FLAG_SAUDI_ARABIA_FULL | cls.FLAG_MALAYSIA_FULL | cls.FLAG_CZECH_REPUBLIC_FULL | cls.FLAG_AUSTRALIA_FULL | cls.FLAG_SINGAPORE_FULL | cls.OCULUS_LOGO_FULL | cls.STEAM_LOGO_FULL | cls.NVIDIA_LOGO_FULL | cls.FLAG_IRAN_FULL | cls.FLAG_POLAND_FULL | cls.FLAG_ARGENTINA_FULL | cls.FLAG_PHILIPPINES_FULL | cls.FLAG_CHILE_FULL | cls.MIKIROG_FULL | cls.V2_LOGO_FULL | cls.SANTA_HAT_FULL | cls.POTATO_FULL | cls.PALM_TREE_FULL | cls.BOXING_GLOVE_FULL | cls.ANNIVERSARY_15_CAKE_FULL | cls.ANNIVERSARY_15_SPAZ_FULL | cls.ANNIVERSARY_15_BOMB_FULL ): return 23073 case _: assert_never(self)
[docs] @cached_property def full_size(self) -> SpecialChar | None: """This character's full-size form, if it has one. Profile icons, flags and account/platform logos come in two forms: a small raised (superscript) one for showing next to a name -- the long-standing character, which is what travels in names -- and a full-size ``_FULL`` twin for showing framed or as a button label (newer clients only; see :attr:`min_engine_build`). The superscript form's metrics are derived from its twin's, so only the twin is ever tuned. Returns the twin for a superscript character, the character itself for a full-size one, and None for everything else. When adding a character, give it a case here: an icon gets both forms, paired here. """ # One case per icon pair, exhaustively (mypy catches a member # nobody classified). # pylint: disable=too-many-return-statements, too-many-branches cls = type(self) match self: case cls.LOGO: return cls.LOGO_FULL case cls.GOOGLE_PLAY_GAMES_LOGO: return cls.GOOGLE_PLAY_GAMES_LOGO_FULL case cls.GAME_CENTER_LOGO: return cls.GAME_CENTER_LOGO_FULL case cls.DISCORD_LOGO: return cls.DISCORD_LOGO_FULL case cls.TEST_ACCOUNT: return cls.TEST_ACCOUNT_FULL case cls.LOCAL_ACCOUNT: return cls.LOCAL_ACCOUNT_FULL case cls.EXPLODINARY_LOGO: return cls.EXPLODINARY_LOGO_FULL case cls.FLAG_UNITED_STATES: return cls.FLAG_UNITED_STATES_FULL case cls.FLAG_MEXICO: return cls.FLAG_MEXICO_FULL case cls.FLAG_GERMANY: return cls.FLAG_GERMANY_FULL case cls.FLAG_BRAZIL: return cls.FLAG_BRAZIL_FULL case cls.FLAG_RUSSIA: return cls.FLAG_RUSSIA_FULL case cls.FLAG_CHINA: return cls.FLAG_CHINA_FULL case cls.FLAG_UNITED_KINGDOM: return cls.FLAG_UNITED_KINGDOM_FULL case cls.FLAG_CANADA: return cls.FLAG_CANADA_FULL case cls.FLAG_INDIA: return cls.FLAG_INDIA_FULL case cls.FLAG_JAPAN: return cls.FLAG_JAPAN_FULL case cls.FLAG_FRANCE: return cls.FLAG_FRANCE_FULL case cls.FLAG_INDONESIA: return cls.FLAG_INDONESIA_FULL case cls.FLAG_ITALY: return cls.FLAG_ITALY_FULL case cls.FLAG_SOUTH_KOREA: return cls.FLAG_SOUTH_KOREA_FULL case cls.FLAG_NETHERLANDS: return cls.FLAG_NETHERLANDS_FULL case cls.FEDORA: return cls.FEDORA_FULL case cls.HAL: return cls.HAL_FULL case cls.CROWN: return cls.CROWN_FULL case cls.YIN_YANG: return cls.YIN_YANG_FULL case cls.EYE_BALL: return cls.EYE_BALL_FULL case cls.SKULL: return cls.SKULL_FULL case cls.HEART: return cls.HEART_FULL case cls.DRAGON: return cls.DRAGON_FULL case cls.HELMET: return cls.HELMET_FULL case cls.MUSHROOM: return cls.MUSHROOM_FULL case cls.NINJA_STAR: return cls.NINJA_STAR_FULL case cls.VIKING_HELMET: return cls.VIKING_HELMET_FULL case cls.MOON: return cls.MOON_FULL case cls.SPIDER: return cls.SPIDER_FULL case cls.FIREBALL: return cls.FIREBALL_FULL case cls.FLAG_UNITED_ARAB_EMIRATES: return cls.FLAG_UNITED_ARAB_EMIRATES_FULL case cls.FLAG_QATAR: return cls.FLAG_QATAR_FULL case cls.FLAG_EGYPT: return cls.FLAG_EGYPT_FULL case cls.FLAG_KUWAIT: return cls.FLAG_KUWAIT_FULL case cls.FLAG_ALGERIA: return cls.FLAG_ALGERIA_FULL case cls.FLAG_SAUDI_ARABIA: return cls.FLAG_SAUDI_ARABIA_FULL case cls.FLAG_MALAYSIA: return cls.FLAG_MALAYSIA_FULL case cls.FLAG_CZECH_REPUBLIC: return cls.FLAG_CZECH_REPUBLIC_FULL case cls.FLAG_AUSTRALIA: return cls.FLAG_AUSTRALIA_FULL case cls.FLAG_SINGAPORE: return cls.FLAG_SINGAPORE_FULL case cls.OCULUS_LOGO: return cls.OCULUS_LOGO_FULL case cls.STEAM_LOGO: return cls.STEAM_LOGO_FULL case cls.NVIDIA_LOGO: return cls.NVIDIA_LOGO_FULL case cls.FLAG_IRAN: return cls.FLAG_IRAN_FULL case cls.FLAG_POLAND: return cls.FLAG_POLAND_FULL case cls.FLAG_ARGENTINA: return cls.FLAG_ARGENTINA_FULL case cls.FLAG_PHILIPPINES: return cls.FLAG_PHILIPPINES_FULL case cls.FLAG_CHILE: return cls.FLAG_CHILE_FULL case cls.MIKIROG: return cls.MIKIROG_FULL case cls.V2_LOGO: return cls.V2_LOGO_FULL case cls.SANTA_HAT: return cls.SANTA_HAT_FULL case cls.POTATO: return cls.POTATO_FULL case cls.PALM_TREE: return cls.PALM_TREE_FULL case cls.BOXING_GLOVE: return cls.BOXING_GLOVE_FULL case cls.ANNIVERSARY_15_CAKE: return cls.ANNIVERSARY_15_CAKE_FULL case cls.ANNIVERSARY_15_SPAZ: return cls.ANNIVERSARY_15_SPAZ_FULL case cls.ANNIVERSARY_15_BOMB: return cls.ANNIVERSARY_15_BOMB_FULL case ( cls.LOGO_FULL | cls.GOOGLE_PLAY_GAMES_LOGO_FULL | cls.GAME_CENTER_LOGO_FULL | cls.DISCORD_LOGO_FULL | cls.TEST_ACCOUNT_FULL | cls.LOCAL_ACCOUNT_FULL | cls.EXPLODINARY_LOGO_FULL | cls.FLAG_UNITED_STATES_FULL | cls.FLAG_MEXICO_FULL | cls.FLAG_GERMANY_FULL | cls.FLAG_BRAZIL_FULL | cls.FLAG_RUSSIA_FULL | cls.FLAG_CHINA_FULL | cls.FLAG_UNITED_KINGDOM_FULL | cls.FLAG_CANADA_FULL | cls.FLAG_INDIA_FULL | cls.FLAG_JAPAN_FULL | cls.FLAG_FRANCE_FULL | cls.FLAG_INDONESIA_FULL | cls.FLAG_ITALY_FULL | cls.FLAG_SOUTH_KOREA_FULL | cls.FLAG_NETHERLANDS_FULL | cls.FEDORA_FULL | cls.HAL_FULL | cls.CROWN_FULL | cls.YIN_YANG_FULL | cls.EYE_BALL_FULL | cls.SKULL_FULL | cls.HEART_FULL | cls.DRAGON_FULL | cls.HELMET_FULL | cls.MUSHROOM_FULL | cls.NINJA_STAR_FULL | cls.VIKING_HELMET_FULL | cls.MOON_FULL | cls.SPIDER_FULL | cls.FIREBALL_FULL | cls.FLAG_UNITED_ARAB_EMIRATES_FULL | cls.FLAG_QATAR_FULL | cls.FLAG_EGYPT_FULL | cls.FLAG_KUWAIT_FULL | cls.FLAG_ALGERIA_FULL | cls.FLAG_SAUDI_ARABIA_FULL | cls.FLAG_MALAYSIA_FULL | cls.FLAG_CZECH_REPUBLIC_FULL | cls.FLAG_AUSTRALIA_FULL | cls.FLAG_SINGAPORE_FULL | cls.OCULUS_LOGO_FULL | cls.STEAM_LOGO_FULL | cls.NVIDIA_LOGO_FULL | cls.FLAG_IRAN_FULL | cls.FLAG_POLAND_FULL | cls.FLAG_ARGENTINA_FULL | cls.FLAG_PHILIPPINES_FULL | cls.FLAG_CHILE_FULL | cls.MIKIROG_FULL | cls.V2_LOGO_FULL | cls.SANTA_HAT_FULL | cls.POTATO_FULL | cls.PALM_TREE_FULL | cls.BOXING_GLOVE_FULL | cls.ANNIVERSARY_15_CAKE_FULL | cls.ANNIVERSARY_15_SPAZ_FULL | cls.ANNIVERSARY_15_BOMB_FULL ): return self case ( cls.LEFT_ARROW | cls.RIGHT_ARROW | cls.UP_ARROW | cls.DOWN_ARROW | cls.LEFT_BUTTON | cls.TOP_BUTTON | cls.RIGHT_BUTTON | cls.BOTTOM_BUTTON | cls.DELETE | cls.SHIFT | cls.BACK | cls.LOGO_FLAT | cls.REWIND_BUTTON | cls.PLAY_PAUSE_BUTTON | cls.FAST_FORWARD_BUTTON | cls.DPAD_CENTER_BUTTON | cls.PLAY_STATION_CROSS_BUTTON | cls.PLAY_STATION_CIRCLE_BUTTON | cls.PLAY_STATION_TRIANGLE_BUTTON | cls.PLAY_STATION_SQUARE_BUTTON | cls.PLAY_BUTTON | cls.PAUSE_BUTTON | cls.CLOSE | cls.OUYA_BUTTON_O | cls.OUYA_BUTTON_U | cls.OUYA_BUTTON_Y | cls.OUYA_BUTTON_A | cls.TOKEN | cls.TICKET | cls.DICE_BUTTON1 | cls.DICE_BUTTON2 | cls.DICE_BUTTON3 | cls.DICE_BUTTON4 | cls.PARTY_ICON | cls.TICKET_BACKING | cls.TROPHY1 | cls.TROPHY2 | cls.TROPHY3 | cls.TROPHY0A | cls.TROPHY0B | cls.TROPHY4 | cls.POPUP_ICON ): return None case _: assert_never(self)
@property def is_superscript(self) -> bool: """Whether this is the raised form of a two-form icon.""" full = self.full_size return full is not None and full is not self @property def superscript(self) -> SpecialChar | None: """This character's raised form, if it is a two-form icon.""" if self.is_superscript: return self if self.full_size is self: return _superscript_of()[self] return None
@cache def _superscript_of() -> dict[SpecialChar, SpecialChar]: """Map each full-size icon to its superscript form.""" return { full: char for char in SpecialChar if (full := char.full_size) is not None and full is not char } #: Chars that count as letters or symbols but draw nothing (the usual #: tricks for blank-looking names). _BLANK_CHARS = frozenset('ㅤᅟᅠᅠ⠀')
[docs] def has_visible_chars(text: str) -> bool: """Return whether text has anything that actually draws. True if at least one char is a letter, number, punctuation or symbol (other than a few that draw blank, such as Hangul fillers). Whitespace, format chars (zero-width spaces, direction marks, ...), control chars and lone combining marks don't count, so a name made only of those is invisible. """ import unicodedata return any( unicodedata.category(c)[0] in 'LNPS' and c not in _BLANK_CHARS for c in text )
# Docs-generation hack; import some stuff that we likely only forward-declared # in our actual source code so that docs tools can find it. from typing import (Coroutine, Any, Literal, Callable, Generator, Awaitable, Sequence, Self, TypeIs) import asyncio from concurrent.futures import Future from pathlib import Path from enum import Enum