Files
031-flash-card/src/flash_card/constants.py
T
Tirsvad ce4aacb4bc MIL-011: Menu bar
Review record RC-066 (Go, autonomous mode, not independent).

Task: MIL-011#1
Task: MIL-011#2
Task: MIL-011#3
Task: MIL-011#4
Task: MIL-011#5
Task: MIL-011#6
Task: MIL-011#7
Task: MIL-011#8
2026-10-15 09:06:47 +08:00

182 lines
8.0 KiB
Python

"""All constants of the flash card program, defined once.
@file constants.py
@brief Window, card, font, language, file and asset constants.
Imports only the standard library.
"""
from collections.abc import Mapping
from pathlib import Path
from typing import Final
from flash_card.runtime import executable_dir, is_frozen, resource_root
## @brief Window background colour.
BACKGROUND_COLOR: Final[str] = "#B1DDC6"
## @brief Window title.
WINDOW_TITLE: Final[str] = "Flashy"
## @brief Padding around the card in pixels.
WINDOW_PADDING: Final[int] = 50
## @brief Card width in pixels.
CARD_WIDTH: Final[int] = 800
## @brief Card height in pixels.
CARD_HEIGHT: Final[int] = 526
## @brief Level screen height in pixels: card plus the card window button row.
LEVEL_SCREEN_HEIGHT: Final[int] = 526 + 100
## @brief Horizontal centre of the card in pixels.
CARD_CENTER_X: Final[int] = 400
## @brief Vertical position of the language text in pixels.
LANGUAGE_TEXT_Y: Final[int] = 150
## @brief Vertical position of the word text in pixels.
WORD_TEXT_Y: Final[int] = 263
## @brief Delay before the card flips, in milliseconds.
FLIP_DELAY_MS: Final[int] = 3000
## @brief Font of the language text: family, size, style.
LANGUAGE_FONT: Final[tuple[str, int, str]] = ("Arial", 40, "italic")
## @brief Font of the word text: family, size, style.
WORD_FONT: Final[tuple[str, int, str]] = ("Arial", 60, "bold")
## @brief Text colour on the card front.
FRONT_TEXT_COLOR: Final[str] = "black"
## @brief Text colour on the card back.
BACK_TEXT_COLOR: Final[str] = "white"
## @brief Display names by language code; the caller shows unknown codes in upper case.
LANGUAGE_NAMES: Final[Mapping[str, str]] = {"ms": "Malay", "da": "Danish"}
## @brief Message shown when no word is left to learn.
FINISHED_MESSAGE: Final[str] = "Nothing left to learn"
## @brief Title of the level screen.
LEVEL_TITLE: Final[str] = "Choose your level"
## @brief Level choices in display order: label and word limit (None = all words).
LEVEL_CHOICES: Final[tuple[tuple[str, int | None], ...]] = (
("100 words", 100),
("1000 words", 1000),
("All words", None),
)
## @brief Values of the --level option and the word limit each stands for.
LEVEL_ARGUMENT_VALUES: Final[Mapping[str, int | None]] = {
"100": 100,
"1000": 1000,
"all": None,
}
## @brief Font of the level screen title: family, size, style.
LEVEL_TITLE_FONT: Final[tuple[str, int, str]] = ("Arial", 40, "italic")
## @brief Font of the level buttons: family, size, style.
LEVEL_BUTTON_FONT: Final[tuple[str, int, str]] = ("Arial", 24, "bold")
## @brief Width of every level button in characters.
LEVEL_BUTTON_WIDTH: Final[int] = 14
## @brief Background colour of the level buttons.
LEVEL_BUTTON_COLOR: Final[str] = "white"
## @brief Delimiter of the CSV files.
CSV_DELIMITER: Final[str] = ";"
## @brief Encoding of the CSV files; drops a leading byte order mark.
CSV_ENCODING: Final[str] = "utf-8-sig"
## @brief File name of the vocabulary.
VOCABULARY_FILE_NAME: Final[str] = "ms-da.csv"
## @brief File name of the words still to learn.
PROGRESS_FILE_NAME: Final[str] = "words_to_learn.csv"
## @brief File name of the words to learn of another word list; {stem} is its stem.
PROGRESS_FILE_NAME_TEMPLATE: Final[str] = "words_to_learn_{stem}.csv"
## @brief Pattern of the characters replaced in a stem (not letter, digit, - or _).
PROGRESS_STEM_FORBIDDEN: Final[str] = r"[^\w-]"
## @brief Replacement of a forbidden character in the progress file name.
PROGRESS_STEM_REPLACEMENT: Final[str] = "_"
## @brief Root folder of the project, for a source run.
PROJECT_ROOT: Final[Path] = Path(__file__).resolve().parents[2]
## @brief Folder of the image assets, inside the bundle when frozen.
ASSETS_DIR: Final[Path] = (
resource_root() / "flash_card" / "presentation" / "assets"
if is_frozen()
else Path(__file__).resolve().parent / "presentation" / "assets"
)
## @brief Folder of the word list delivered with the program.
BUNDLED_DATA_DIR: Final[Path] = resource_root() / "data"
## @brief The word list delivered with the program.
BUNDLED_VOCABULARY_PATH: Final[Path] = BUNDLED_DATA_DIR / VOCABULARY_FILE_NAME
## @brief Default folder of the data files, next to the executable when frozen.
DEFAULT_DATA_DIR: Final[Path] = executable_dir() / "data"
## @brief File name of the program icon.
ICON_FILE_NAME: Final[str] = "flash_card.ico"
## @brief Name of the executable without extension.
EXECUTABLE_NAME: Final[str] = "flash-card"
## @brief File name of the card front image.
CARD_FRONT_IMAGE_NAME: Final[str] = "card_front.png"
## @brief File name of the card back image.
CARD_BACK_IMAGE_NAME: Final[str] = "card_back.png"
## @brief File name of the right button image.
RIGHT_IMAGE_NAME: Final[str] = "right.png"
## @brief File name of the wrong button image.
WRONG_IMAGE_NAME: Final[str] = "wrong.png"
## @brief Label of the File menu.
MENU_FILE_LABEL: Final[str] = "File"
## @brief Label of the File, Open entry.
MENU_OPEN_LABEL: Final[str] = "Open..."
## @brief Label of the File, Change level entry.
MENU_CHANGE_LEVEL_LABEL: Final[str] = "Change level..."
## @brief Label of the File, Reset word list entry.
MENU_RESET_LABEL: Final[str] = "Reset word list..."
## @brief Label of the File, Exit entry.
MENU_EXIT_LABEL: Final[str] = "Exit"
## @brief Label of the About menu.
MENU_ABOUT_LABEL: Final[str] = "About"
## @brief Label of the About, Contact submenu.
MENU_CONTACT_LABEL: Final[str] = "Contact"
## @brief Index of the mnemonic letter of the File menu.
MENU_FILE_UNDERLINE: Final[int] = 0
## @brief Index of the mnemonic letter of the Open entry.
MENU_OPEN_UNDERLINE: Final[int] = 0
## @brief Index of the mnemonic letter of the Change level entry.
MENU_CHANGE_LEVEL_UNDERLINE: Final[int] = 0
## @brief Index of the mnemonic letter of the Reset word list entry.
MENU_RESET_UNDERLINE: Final[int] = 0
## @brief Index of the mnemonic letter of the Exit entry.
MENU_EXIT_UNDERLINE: Final[int] = 1
## @brief Index of the mnemonic letter of the About menu.
MENU_ABOUT_UNDERLINE: Final[int] = 0
## @brief Index of the mnemonic letter of the Contact submenu.
MENU_CONTACT_UNDERLINE: Final[int] = 0
## @brief Command name of the Open entry, as the menu view maps it.
MENU_COMMAND_OPEN: Final[str] = "open_word_list"
## @brief Command name of the Change level entry.
MENU_COMMAND_CHANGE_LEVEL: Final[str] = "change_level"
## @brief Command name of the Reset word list entry.
MENU_COMMAND_RESET: Final[str] = "reset_word_list"
## @brief Command name of the Exit entry.
MENU_COMMAND_EXIT: Final[str] = "exit_program"
## @brief Name of the author shown under About, Contact.
CONTACT_NAME: Final[str] = "Jens Tirsvad Nielsen"
## @brief Title of the author shown under About, Contact.
CONTACT_TITLE: Final[str] = "Software engineer"
## @brief LinkedIn page of the author.
CONTACT_URL: Final[str] = "https://www.linkedin.com/in/tirsvad74"
## @brief Text of the contact entry: name and title; {name} and {title}.
CONTACT_LABEL_TEMPLATE: Final[str] = "{name}, {title}"
## @brief Title of the open file dialog.
OPEN_DIALOG_TITLE: Final[str] = "Open a word list"
## @brief File types of the open file dialog: description and pattern.
OPEN_FILE_TYPES: Final[tuple[tuple[str, str], ...]] = (
("CSV files", "*.csv"),
("All files", "*.*"),
)
## @brief Title of the reset confirmation.
RESET_CONFIRM_TITLE: Final[str] = "Reset word list"
## @brief Question of the reset confirmation; {name} is the word list file name.
RESET_CONFIRM_TEMPLATE: Final[str] = (
"Start {name} from the beginning? All words will be to learn again."
)
## @brief Title of the message that tells a word list could not be opened.
OPEN_ERROR_TITLE: Final[str] = "Cannot open word list"
## @brief Message of a word list that could not be opened; {name} and {reason}.
OPEN_ERROR_TEMPLATE: Final[str] = "{name} could not be used.\n{reason}"
## @brief Title of the message that tells a word list could not be reset.
RESET_ERROR_TITLE: Final[str] = "Cannot reset word list"
## @brief Message of a word list that could not be reset; {name} and {reason}.
RESET_ERROR_TEMPLATE: Final[str] = "{name} could not be reset.\n{reason}"