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