ManimPango 0.4.3__cp310-cp310-win32.whl → 1.0.0a2__cp310-cp310-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ManimPango-0.4.3.dist-info → ManimPango-1.0.0a2.dist-info}/METADATA +2 -2
- ManimPango-1.0.0a2.dist-info/RECORD +85 -0
- {ManimPango-0.4.3.dist-info → ManimPango-1.0.0a2.dist-info}/WHEEL +1 -1
- manimpango/__init__.py +5 -7
- manimpango/_distributor_init.py +36 -0
- manimpango/_version.py +1 -1
- manimpango/attributes/__init__.py +324 -0
- manimpango/attributes/attributes.pxi +219 -0
- manimpango/buffer.pxi +15 -0
- manimpango/cmanimpango.c +10025 -0
- manimpango/cmanimpango.cp310-win32.pyd +0 -0
- manimpango/enums.c +3721 -0
- manimpango/enums.cp310-win32.pyd +0 -0
- manimpango/enums.pyx +1 -10
- manimpango/exceptions.py +5 -0
- manimpango/fonts/__init__.py +153 -0
- manimpango/fonts/_font_desc.c +7576 -0
- manimpango/fonts/_font_desc.cp310-win32.pyd +0 -0
- manimpango/fonts/_font_desc.pxd +5 -0
- manimpango/fonts/_font_desc.pyi +25 -0
- manimpango/fonts/_font_desc.pyx +114 -0
- manimpango/fonts/enums.c +3628 -0
- manimpango/fonts/enums.cp310-win32.pyd +0 -0
- manimpango/fonts/enums.pyi +23 -0
- manimpango/fonts/enums.pyx +84 -0
- manimpango/{cairo.pxd → include/cairo.pxd} +21 -0
- manimpango/include/glib.pxd +36 -0
- manimpango/{pango.pxd → include/pango.pxd} +61 -0
- manimpango/include/pango_attributes.pxd +184 -0
- manimpango/layout/__init__.py +266 -0
- manimpango/layout/_layout.c +8630 -0
- manimpango/layout/_layout.cp310-win32.pyd +0 -0
- manimpango/layout/_layout.pyx +60 -0
- manimpango/layout/layout.pxi +52 -0
- manimpango/register_font.c +5016 -0
- manimpango/register_font.cp310-win32.pyd +0 -0
- manimpango/renderer/__init__.py +5 -0
- manimpango/renderer/cairo_utils.pxi +72 -0
- manimpango/renderer/image_renderer.c +12319 -0
- manimpango/renderer/image_renderer.cp310-win32.pyd +0 -0
- manimpango/renderer/image_renderer.pxd +23 -0
- manimpango/renderer/image_renderer.pyi +21 -0
- manimpango/renderer/image_renderer.pyx +219 -0
- manimpango/renderer/svg_renderer.c +10671 -0
- manimpango/renderer/svg_renderer.cp310-win32.pyd +0 -0
- manimpango/renderer/svg_renderer.pxd +23 -0
- manimpango/renderer/svg_renderer.pyi +17 -0
- manimpango/renderer/svg_renderer.pyx +174 -0
- manimpango/utils/__init__.py +3 -0
- manimpango/utils/_utils.cp310-win32.pyd +0 -0
- manimpango/utils/_utils.pyi +2 -0
- manimpango/utils/utils.c +3533 -0
- manimpango/{utils.py → utils/utils.py} +3 -1
- manimpango/utils/utils.pyx +27 -0
- ManimPango-0.4.3.dist-info/RECORD +0 -44
- manimpango/glib.pxd +0 -13
- {ManimPango-0.4.3.dist-info → ManimPango-1.0.0a2.dist-info}/LICENSE +0 -0
- {ManimPango-0.4.3.dist-info → ManimPango-1.0.0a2.dist-info}/LICENSE.win32 +0 -0
- {ManimPango-0.4.3.dist-info → ManimPango-1.0.0a2.dist-info}/top_level.txt +0 -0
- /manimpango/{CORE_MANIM_cairo-2.dll → .libs/CORE_MANIM_cairo-2.dll} +0 -0
- /manimpango/{CORE_MANIM_cairo-gobject-2.dll → .libs/CORE_MANIM_cairo-gobject-2.dll} +0 -0
- /manimpango/{CORE_MANIM_cairo-script-interpreter-2.dll → .libs/CORE_MANIM_cairo-script-interpreter-2.dll} +0 -0
- /manimpango/{CORE_MANIM_expat.dll → .libs/CORE_MANIM_expat.dll} +0 -0
- /manimpango/{CORE_MANIM_ffi-7.dll → .libs/CORE_MANIM_ffi-7.dll} +0 -0
- /manimpango/{CORE_MANIM_fontconfig-1.dll → .libs/CORE_MANIM_fontconfig-1.dll} +0 -0
- /manimpango/{CORE_MANIM_freetype-6.dll → .libs/CORE_MANIM_freetype-6.dll} +0 -0
- /manimpango/{CORE_MANIM_fribidi-0.dll → .libs/CORE_MANIM_fribidi-0.dll} +0 -0
- /manimpango/{CORE_MANIM_gio-2.0-0.dll → .libs/CORE_MANIM_gio-2.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_glib-2.0-0.dll → .libs/CORE_MANIM_glib-2.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_gmodule-2.0-0.dll → .libs/CORE_MANIM_gmodule-2.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_gobject-2.0-0.dll → .libs/CORE_MANIM_gobject-2.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_gthread-2.0-0.dll → .libs/CORE_MANIM_gthread-2.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_harfbuzz-gobject.dll → .libs/CORE_MANIM_harfbuzz-gobject.dll} +0 -0
- /manimpango/{CORE_MANIM_harfbuzz-subset.dll → .libs/CORE_MANIM_harfbuzz-subset.dll} +0 -0
- /manimpango/{CORE_MANIM_harfbuzz.dll → .libs/CORE_MANIM_harfbuzz.dll} +0 -0
- /manimpango/{CORE_MANIM_intl-8.dll → .libs/CORE_MANIM_intl-8.dll} +0 -0
- /manimpango/{CORE_MANIM_pango-1.0-0.dll → .libs/CORE_MANIM_pango-1.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_pangocairo-1.0-0.dll → .libs/CORE_MANIM_pangocairo-1.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_pangoft2-1.0-0.dll → .libs/CORE_MANIM_pangoft2-1.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_pangowin32-1.0-0.dll → .libs/CORE_MANIM_pangowin32-1.0-0.dll} +0 -0
- /manimpango/{CORE_MANIM_pixman-1-0.dll → .libs/CORE_MANIM_pixman-1-0.dll} +0 -0
- /manimpango/{CORE_MANIM_png16-16.dll → .libs/CORE_MANIM_png16-16.dll} +0 -0
- /manimpango/{CORE_MANIM_z.dll → .libs/CORE_MANIM_z.dll} +0 -0
@@ -0,0 +1,266 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
from __future__ import annotations
|
3
|
+
|
4
|
+
from ..attributes import TextAttribute
|
5
|
+
from ..enums import Alignment
|
6
|
+
from ..exceptions import MarkupParseError
|
7
|
+
from ..fonts import FontDescription
|
8
|
+
from ..utils import validate_markup
|
9
|
+
|
10
|
+
__all__ = ["Layout"]
|
11
|
+
|
12
|
+
|
13
|
+
class Layout:
|
14
|
+
"""A :class:`Layout` class represents an entire paragraph of text.
|
15
|
+
|
16
|
+
:class:`Layout` provides a high-level driver for formatting entire
|
17
|
+
paragraphs of text at once. This includes paragraph-level functionality
|
18
|
+
such as line breaking, justification, alignment and ellipsization.
|
19
|
+
|
20
|
+
A :class:`Layout` is initialized with a :class:`str`. The layout
|
21
|
+
can then be rendered. There are a number of parameters to adjust
|
22
|
+
the formatting of a :class:`Layout`.
|
23
|
+
|
24
|
+
When both :attr:`markup` and :attr:`text` is set the behavior is
|
25
|
+
unknown.
|
26
|
+
|
27
|
+
Parameters
|
28
|
+
==========
|
29
|
+
text:
|
30
|
+
The text to be set, by default None.
|
31
|
+
markup:
|
32
|
+
The text encoded in PangoMarkup, by default None.
|
33
|
+
font_desc:
|
34
|
+
The font description to be used while rendering.
|
35
|
+
|
36
|
+
Examples
|
37
|
+
========
|
38
|
+
>>> import manimpango as mp
|
39
|
+
>>> mp.Layout("hello world")
|
40
|
+
<Layout text='hello world' markup=None>
|
41
|
+
|
42
|
+
Raises
|
43
|
+
======
|
44
|
+
ValueError
|
45
|
+
If both ``text`` and ``markup`` is None.
|
46
|
+
"""
|
47
|
+
|
48
|
+
def __init__(
|
49
|
+
self,
|
50
|
+
text: str = None,
|
51
|
+
markup: str = None,
|
52
|
+
font_desc: FontDescription = None,
|
53
|
+
attributes: list[TextAttribute] = None,
|
54
|
+
width: int = None,
|
55
|
+
height: int = None,
|
56
|
+
alignment: Alignment = None,
|
57
|
+
justify: bool = None,
|
58
|
+
):
|
59
|
+
if text:
|
60
|
+
self.text = text
|
61
|
+
if markup:
|
62
|
+
self.markup = markup
|
63
|
+
if self.markup is None and self.text is None:
|
64
|
+
raise ValueError("Either 'markup' or 'text' is required.")
|
65
|
+
if font_desc:
|
66
|
+
self.font_desc = font_desc
|
67
|
+
if attributes:
|
68
|
+
self.attributes = attributes
|
69
|
+
if width:
|
70
|
+
self.width = width
|
71
|
+
if height:
|
72
|
+
self.height = height
|
73
|
+
if alignment:
|
74
|
+
self.alignment = alignment
|
75
|
+
if justify:
|
76
|
+
self.justify = justify
|
77
|
+
|
78
|
+
def __len__(self):
|
79
|
+
return len(self.text) if self.text is not None else len(self.markup)
|
80
|
+
|
81
|
+
@property
|
82
|
+
def text(self) -> str:
|
83
|
+
"""The text to render.
|
84
|
+
|
85
|
+
Raises
|
86
|
+
======
|
87
|
+
TypeError
|
88
|
+
If ``text`` is not a :class:`str`.
|
89
|
+
"""
|
90
|
+
if hasattr(self, "_text"):
|
91
|
+
return self._text
|
92
|
+
return None
|
93
|
+
|
94
|
+
@text.setter
|
95
|
+
def text(self, val: str) -> None:
|
96
|
+
if not isinstance(val, str):
|
97
|
+
raise TypeError("'text' should be a str")
|
98
|
+
self._text = val
|
99
|
+
|
100
|
+
@property
|
101
|
+
def markup(self) -> str:
|
102
|
+
"""The markup (in pango markup format) to render.
|
103
|
+
|
104
|
+
Raises
|
105
|
+
======
|
106
|
+
TypeError
|
107
|
+
If ``text`` is not a :class:`str`.
|
108
|
+
|
109
|
+
MarkupParseError
|
110
|
+
If the passed markup is invalid.
|
111
|
+
"""
|
112
|
+
if hasattr(self, "_markup"):
|
113
|
+
return self._markup
|
114
|
+
return None
|
115
|
+
|
116
|
+
@markup.setter
|
117
|
+
def markup(self, val: str) -> None:
|
118
|
+
if not isinstance(val, str):
|
119
|
+
raise TypeError("'markup' should be a str")
|
120
|
+
check = validate_markup(val)
|
121
|
+
if check:
|
122
|
+
raise MarkupParseError(check)
|
123
|
+
self._markup = val
|
124
|
+
|
125
|
+
@property
|
126
|
+
def width(self) -> int:
|
127
|
+
"""The width to which the text should be wrapped or ellipsized.
|
128
|
+
|
129
|
+
Raises
|
130
|
+
======
|
131
|
+
TypeError
|
132
|
+
If ``width`` is not a :class:`int`.
|
133
|
+
"""
|
134
|
+
if hasattr(self, "_width"):
|
135
|
+
return self._width
|
136
|
+
return None
|
137
|
+
|
138
|
+
@width.setter
|
139
|
+
def width(self, val: int) -> None:
|
140
|
+
if not isinstance(val, int):
|
141
|
+
raise TypeError("'width' should be an int")
|
142
|
+
self._width = val
|
143
|
+
|
144
|
+
@property
|
145
|
+
def height(self) -> int:
|
146
|
+
"""The height to which the text should be ellipsized at.
|
147
|
+
|
148
|
+
Raises
|
149
|
+
======
|
150
|
+
TypeError
|
151
|
+
If ``height`` is not a :class:`int`.
|
152
|
+
"""
|
153
|
+
if hasattr(self, "_height"):
|
154
|
+
return self._height
|
155
|
+
return None
|
156
|
+
|
157
|
+
@height.setter
|
158
|
+
def height(self, val: int) -> None:
|
159
|
+
if not isinstance(val, int):
|
160
|
+
raise TypeError("'height' should be an int")
|
161
|
+
self._height = val
|
162
|
+
|
163
|
+
@property
|
164
|
+
def alignment(self) -> Alignment:
|
165
|
+
if hasattr(self, "_alignment"):
|
166
|
+
return self._alignment
|
167
|
+
return None
|
168
|
+
|
169
|
+
@alignment.setter
|
170
|
+
def alignment(self, val: Alignment):
|
171
|
+
if not isinstance(val, Alignment):
|
172
|
+
raise TypeError("'alignment' should be an Alignment")
|
173
|
+
self._alignment = val
|
174
|
+
|
175
|
+
@property
|
176
|
+
def font_desc(self) -> FontDescription:
|
177
|
+
if hasattr(self, "_font_desc"):
|
178
|
+
return self._font_desc
|
179
|
+
return FontDescription()
|
180
|
+
|
181
|
+
@font_desc.setter
|
182
|
+
def font_desc(self, val: FontDescription):
|
183
|
+
if not isinstance(val, FontDescription):
|
184
|
+
raise TypeError("'font_desc' should be an FontDescription")
|
185
|
+
self._font_desc = val
|
186
|
+
|
187
|
+
@property
|
188
|
+
def attributes(self) -> list[TextAttribute]:
|
189
|
+
if hasattr(self, "_attributes"):
|
190
|
+
return self._attributes
|
191
|
+
return []
|
192
|
+
|
193
|
+
@attributes.setter
|
194
|
+
def attributes(self, val: list[TextAttribute]):
|
195
|
+
if not isinstance(val, list):
|
196
|
+
raise TypeError("'attributes' should be a list")
|
197
|
+
# check if all element of val is of type TextAttribute
|
198
|
+
if not all(isinstance(x, TextAttribute) for x in val):
|
199
|
+
raise TypeError("'attributes' should be a list of TextAttribute")
|
200
|
+
self._attributes = val
|
201
|
+
|
202
|
+
@property
|
203
|
+
def justify(self) -> bool:
|
204
|
+
"""Whether the text should be justified.
|
205
|
+
|
206
|
+
Raises
|
207
|
+
======
|
208
|
+
TypeError
|
209
|
+
If ``justify`` is not a :class:`bool`.
|
210
|
+
"""
|
211
|
+
if hasattr(self, "_justify"):
|
212
|
+
return self._justify
|
213
|
+
return False
|
214
|
+
|
215
|
+
@justify.setter
|
216
|
+
def justify(self, val: bool) -> None:
|
217
|
+
if not isinstance(val, bool):
|
218
|
+
raise TypeError("'justify' should be a bool")
|
219
|
+
self._justify = val
|
220
|
+
|
221
|
+
def get_bounding_box(self) -> tuple[int, int, int, int]:
|
222
|
+
"""Returns the bounding box of the layout.
|
223
|
+
|
224
|
+
Note that it's heavy to calculate the bounding box of a layout,
|
225
|
+
so it's better to cache the result.
|
226
|
+
|
227
|
+
Example
|
228
|
+
=======
|
229
|
+
>>> import manimpango as mp
|
230
|
+
>>> layout = mp.Layout("hello world")
|
231
|
+
>>> layout.get_bounding_box()
|
232
|
+
(0, 0, 82, 19)
|
233
|
+
|
234
|
+
Returns
|
235
|
+
=======
|
236
|
+
tuple
|
237
|
+
The bounding box of the layout in the form of
|
238
|
+
``(x, y, width, height)``.
|
239
|
+
"""
|
240
|
+
from ._layout import get_bbox
|
241
|
+
|
242
|
+
return get_bbox(self)
|
243
|
+
|
244
|
+
def render(self, file_name: str) -> None:
|
245
|
+
"""Renders the layout into a PNG or SVG file depending
|
246
|
+
on the filename.
|
247
|
+
|
248
|
+
Parameters
|
249
|
+
==========
|
250
|
+
file_name:
|
251
|
+
The filename to which the layout should be rendered.
|
252
|
+
"""
|
253
|
+
from ..renderer import ImageRenderer, SVGRenderer
|
254
|
+
|
255
|
+
bbox = self.get_bounding_box()
|
256
|
+
if file_name.endswith(".png"):
|
257
|
+
renderer = ImageRenderer(*bbox[2:], self, file_name)
|
258
|
+
elif file_name.endswith(".svg"):
|
259
|
+
renderer = SVGRenderer(*bbox[2:], self, file_name)
|
260
|
+
else:
|
261
|
+
raise ValueError("Only rendering PNG and SVG files are supported.")
|
262
|
+
renderer.render()
|
263
|
+
renderer.save()
|
264
|
+
|
265
|
+
def __repr__(self):
|
266
|
+
return f"<Layout text={repr(self.text)} markup={repr(self.markup)}>"
|