Coverage for src/rtflite/core/constants.py: 100%
69 statements
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-25 22:35 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2025-08-25 22:35 +0000
1"""RTF constants and magic numbers consolidated in a single source of truth.
3This module eliminates magic numbers scattered throughout the codebase and provides
4clear documentation for all RTF-related constants used in the library.
5"""
7from collections.abc import Mapping
8from typing import Final
11class RTFConstants:
12 """Core RTF constants for measurements, formatting, and control codes."""
14 # === Measurement Constants ===
15 TWIPS_PER_INCH: Final[int] = 1440
16 """Number of twips in one inch. RTF uses twips as the base unit."""
18 POINTS_PER_INCH: Final[int] = 72
19 """Number of points in one inch."""
21 LINE_SPACING_FACTOR: Final[int] = 240
22 """Factor used for line spacing calculations in RTF."""
24 # === Default Dimensions ===
25 DEFAULT_BORDER_WIDTH: Final[int] = 15
26 """Default border width in twips."""
28 DEFAULT_CELL_HEIGHT: Final[float] = 0.15
29 """Default cell height in inches."""
31 DEFAULT_SPACE_BEFORE: Final[int] = 15
32 """Default space before paragraph in points."""
34 DEFAULT_SPACE_AFTER: Final[int] = 15
35 """Default space after paragraph in points."""
37 # === Font Sizes ===
38 DEFAULT_FONT_SIZE: Final[float] = 9
39 """Default font size in points."""
41 # === RTF Control Codes ===
42 class Control:
43 """RTF control word constants."""
45 # Text formatting
46 SUPER: Final[str] = "\\super "
47 SUB: Final[str] = "\\sub "
48 LINE_BREAK: Final[str] = "\\line "
49 PAGE_BREAK: Final[str] = "\\page"
51 # Document structure
52 RTF_HEADER: Final[str] = "{\\rtf1\\ansi"
53 FONT_TABLE_START: Final[str] = "{\\fonttbl"
54 COLOR_TABLE_START: Final[str] = "{\\colortbl"
56 # Page formatting
57 PAGE_NUMBER: Final[str] = "\\chpgn "
58 TOTAL_PAGES: Final[str] = "\\totalpage "
59 PAGE_FIELD: Final[str] = "{\\field{\\*\\fldinst NUMPAGES }} "
61 # Paragraph formatting
62 PARAGRAPH_START: Final[str] = "\\pard"
63 CELL_END: Final[str] = "\\cell"
64 ROW_END: Final[str] = "\\row"
66 # === Format Codes ===
67 FORMAT_CODES: Final[Mapping[str, str]] = {
68 "": "",
69 "b": "\\b", # Bold
70 "i": "\\i", # Italic
71 "u": "\\ul", # Underline
72 "s": "\\strike", # Strikethrough
73 "^": "\\super", # Superscript
74 "_": "\\sub", # Subscript
75 }
77 # === Text Justification Codes ===
78 TEXT_JUSTIFICATION_CODES: Final[Mapping[str, str]] = {
79 "": "",
80 "l": "\\ql", # Left
81 "c": "\\qc", # Center
82 "r": "\\qr", # Right
83 "d": "\\qd", # Distributed
84 "j": "\\qj", # Justified
85 }
87 # === Row Justification Codes ===
88 ROW_JUSTIFICATION_CODES: Final[Mapping[str, str]] = {
89 "": "",
90 "l": "\\trql", # Left
91 "c": "\\trqc", # Center
92 "r": "\\trqr", # Right
93 }
95 # === Border Style Codes ===
96 BORDER_CODES: Final[Mapping[str, str]] = {
97 "single": "\\brdrs",
98 "double": "\\brdrdb",
99 "thick": "\\brdrth",
100 "dotted": "\\brdrdot",
101 "dashed": "\\brdrdash",
102 "small-dash": "\\brdrdashsm",
103 "dash-dotted": "\\brdrdashd",
104 "dash-dot-dotted": "\\brdrdashdd",
105 "triple": "\\brdrtriple",
106 "wavy": "\\brdrwavy",
107 "double-wavy": "\\brdrwavydb",
108 "striped": "\\brdrengrave",
109 "embossed": "\\brdremboss",
110 "engraved": "\\brdrengrave",
111 "frame": "\\brdrframe",
112 "": "", # No border
113 }
115 # === Vertical Alignment Codes ===
116 VERTICAL_ALIGNMENT_CODES: Final[Mapping[str, str]] = {
117 "top": "\\clvertalt",
118 "center": "\\clvertalc",
119 "bottom": "\\clvertalb",
120 "merge_first": "\\clvertalc\\clvmgf",
121 "merge_rest": "\\clvertalc\\clvmrg",
122 "": "",
123 }
125 # === Character Conversion Mapping ===
126 RTF_CHAR_MAPPING: Final[Mapping[str, str]] = {
127 "^": "\\super ",
128 "_": "\\sub ",
129 ">=": "\\geq ",
130 "<=": "\\leq ",
131 "\n": "\\line ",
132 "\\pagenumber": "\\chpgn ",
133 "\\totalpage": "\\totalpage ",
134 "\\pagefield": "{\\field{\\*\\fldinst NUMPAGES }} ",
135 }
138class RTFDefaults:
139 """Default values for RTF document configuration."""
141 # === Page Settings ===
142 ORIENTATION: Final[str] = "portrait"
143 BORDER_FIRST: Final[str] = "double"
144 BORDER_LAST: Final[str] = "double"
145 USE_COLOR: Final[bool] = False
147 # === Text Settings ===
148 TEXT_FONT: Final[int] = 1
149 TEXT_ALIGNMENT: Final[str] = "l" # Left
150 TEXT_HYPHENATION: Final[bool] = True
151 TEXT_CONVERT: Final[bool] = True # Enable LaTeX to Unicode conversion
153 # === Table Settings ===
154 TABLE_ALIGNMENT: Final[str] = "c" # Center
156 # === Color Defaults ===
157 @classmethod
158 def get_default_colors(cls) -> Mapping[str, str]:
159 """Get all colors from the comprehensive color table."""
160 from rtflite.dictionary.color_table import name_to_rtf
162 return name_to_rtf
164 # Provide DEFAULT_COLORS as a cached property for backward compatibility
165 _default_colors_cache = None
167 @classmethod
168 def DEFAULT_COLORS(cls) -> Mapping[str, str]:
169 """Get all colors from the comprehensive color table (cached)."""
170 if cls._default_colors_cache is None:
171 cls._default_colors_cache = cls.get_default_colors()
172 return cls._default_colors_cache
175class RTFMeasurements:
176 """Utility class for RTF measurement conversions."""
178 @staticmethod
179 def inch_to_twip(inches: float) -> int:
180 """Convert inches to twips.
182 Args:
183 inches: Length in inches
185 Returns:
186 Length in twips (1/1440 of an inch)
187 """
188 return round(inches * RTFConstants.TWIPS_PER_INCH)
190 @staticmethod
191 def twip_to_inch(twips: int) -> float:
192 """Convert twips to inches.
194 Args:
195 twips: Length in twips
197 Returns:
198 Length in inches
199 """
200 return twips / RTFConstants.TWIPS_PER_INCH
202 @staticmethod
203 def point_to_halfpoint(points: float) -> int:
204 """Convert points to half-points for RTF font sizes.
206 Args:
207 points: Font size in points
209 Returns:
210 Font size in half-points (RTF format)
211 """
212 return int(points * 2)