Coverage for paintmaskanimator/constants.py: 82%
49 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 04:50 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 04:50 +0000
1"""Application-wide constants.
3Note: ``CANVAS_WIDTH`` / ``CANVAS_HEIGHT`` are *mutable* runtime state — they
4change when the project canvas is resized. They are deliberately excluded from
5``__all__`` so that ``from .constants import *`` does NOT create per-module
6copies that would go stale after a resize. Always read/write them through the
7module, e.g. ``constants.CANVAS_WIDTH``.
8"""
10import sys
11from importlib.metadata import PackageNotFoundError, version
12from pathlib import Path
14try:
15 import tomllib
16except ModuleNotFoundError:
17 # tomllib is stdlib only from 3.11, and requires-python allows 3.10. It is
18 # needed solely to read the version out of pyproject.toml in an
19 # *uninstalled* source checkout, so importing the package must not depend
20 # on it -- that path just degrades to "development" below.
21 tomllib = None
24APP_NAME = "PaintMaskAnimator"
27def _application_version() -> str:
28 """Read the canonical version, including from a frozen application.
30 The build bundles ``pyproject.toml`` beside the package. Prefer it over
31 distribution metadata so a stale editable-install ``egg-info`` directory
32 can never leak the previous release number into the UI or updater.
33 """
34 if tomllib is not None: 34 ↛ 42line 34 didn't jump to line 42 because the condition on line 34 was always true
35 project_file = Path(__file__).resolve().parent.parent / "pyproject.toml"
36 try:
37 project = tomllib.loads(project_file.read_text(encoding="utf-8"))
38 return str(project["project"]["version"])
39 except (OSError, KeyError, tomllib.TOMLDecodeError):
40 pass
42 try:
43 return version("paintmaskanimator")
44 except PackageNotFoundError:
45 return "development"
48APP_VERSION = _application_version()
49APP_DISPLAY_NAME = f"{APP_NAME} V{APP_VERSION}"
50# GitHub repository: releases are distributed from here, and the in-app
51# updater reads the latest one through the public REST API (no credentials).
52GITHUB_REPO = "SehataKuro/PaintMaskAnimator"
53RELEASES_URL = f"https://github.com/{GITHUB_REPO}/releases"
54UPDATE_RELEASE_API_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
55# 「拡大縮小(押している間)」の既定キー。macOSのQtでは "Ctrl" が⌘になるが、
56# ⌘SpaceはSpotlight、⌃Space("Meta")は入力ソース切り替えにOSが既定で使って
57# いて届かないので、⌥Spaceにする。WindowsのAlt+Spaceはウィンドウメニュー。
58HOLD_ZOOM_SHORTCUT = "Alt+Space" if sys.platform == "darwin" else "Ctrl+Space"
59# 操作説明に出す修飾キー名。macOSのQtでは Ctrl 扱いのキーは⌘、Alt は⌥で、
60# 物理的なControl+クリックは右クリックになってしまう。
61CTRL_KEY_LABEL = "⌘" if sys.platform == "darwin" else "Ctrl"
62ALT_KEY_LABEL = "⌥" if sys.platform == "darwin" else "Alt"
63HOLD_ZOOM_KEY_LABEL = f"{ALT_KEY_LABEL if sys.platform == 'darwin' else CTRL_KEY_LABEL}+Space"
64CANVAS_WIDTH = 1280
65CANVAS_HEIGHT = 720
66OUTSIDE_MARGIN = 0
67MAX_UNDO = 30
68# Entry count alone does not bound undo memory: 30 full-layer snapshots of a
69# 4K canvas across several layers is multiple gigabytes, while 30 stroke tile
70# patches are a few megabytes. The stack is trimmed by whichever limit binds
71# first, and always keeps at least one entry so undo never becomes a no-op.
72MAX_UNDO_BYTES = 768 * 1024 * 1024
73MAX_PROJECT_METADATA_BYTES = 16 * 1024 * 1024
74MAX_PROJECT_FRAMES = 10000
75MAX_PROJECT_LAYERS = 256
76MAX_PROJECT_LAYER_CELLS = 100000
77MAX_PROJECT_ARCHIVE_BYTES = 8 * 1024 * 1024 * 1024
78MAX_PROJECT_IMAGE_BYTES = 512 * 1024 * 1024
79MAX_PROJECT_DECODED_PIXELS = 2 * 1024 * 1024 * 1024
80MAX_IMAGE_DIMENSION = 16384
81MAX_SINGLE_IMAGE_PIXELS = MAX_IMAGE_DIMENSION * MAX_IMAGE_DIMENSION
82TP_MASK_PROXY_THRESHOLD = 5000
83TP_MASK_PROXY_MAX_DIMENSION = 1280
84TP_MASK_PROXY_MAX_COLORS = 32
85# Exact colors the quality transform can carry through untouched. Colors are
86# one label id per pixel rather than one mask each, so the ceiling is about the
87# source still being flat-colored art, not about memory.
88TP_MASK_MAX_TRANSFORM_COLORS = 4096
89# Coverage probes per axis while dragging the low-resolution proxy: 2x2 keeps
90# the preview responsive, the committed render uses the full grid.
91TP_MASK_PROXY_SUBSAMPLES = 2
93# Everything except the mutable canvas dimensions is safe to star-import.
94__all__ = [ # pyright: ignore[reportUnsupportedDunderAll]
95 _n for _n in list(globals())
96 if _n.isupper() and _n not in ("CANVAS_WIDTH", "CANVAS_HEIGHT")
97]