python-pptx2 2.13.0__py3-none-any.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.
- pptx2/__init__.py +152 -0
- pptx2/_color.py +75 -0
- pptx2/_slide_importer.py +597 -0
- pptx2/_svg.py +155 -0
- pptx2/_template_applier.py +292 -0
- pptx2/_textstyle.py +187 -0
- pptx2/accessibility.py +365 -0
- pptx2/action.py +270 -0
- pptx2/animation.py +2237 -0
- pptx2/api.py +49 -0
- pptx2/audit.py +258 -0
- pptx2/chart/__init__.py +0 -0
- pptx2/chart/analytics.py +381 -0
- pptx2/chart/axis.py +543 -0
- pptx2/chart/category.py +200 -0
- pptx2/chart/chart.py +670 -0
- pptx2/chart/data.py +864 -0
- pptx2/chart/datalabel.py +406 -0
- pptx2/chart/legend.py +86 -0
- pptx2/chart/marker.py +70 -0
- pptx2/chart/palettes.py +129 -0
- pptx2/chart/plot.py +462 -0
- pptx2/chart/point.py +101 -0
- pptx2/chart/quick_layouts.py +325 -0
- pptx2/chart/series.py +334 -0
- pptx2/chart/xlsx.py +272 -0
- pptx2/chart/xmlwriter.py +1845 -0
- pptx2/compose/__init__.py +28 -0
- pptx2/compose/from_spec.py +1094 -0
- pptx2/design/__init__.py +8 -0
- pptx2/design/components.py +607 -0
- pptx2/design/figures.py +389 -0
- pptx2/design/layout.py +370 -0
- pptx2/design/recipes.py +1967 -0
- pptx2/design/style.py +209 -0
- pptx2/design/tokens.py +915 -0
- pptx2/diagrams.py +754 -0
- pptx2/dml/__init__.py +0 -0
- pptx2/dml/chtfmt.py +40 -0
- pptx2/dml/color.py +496 -0
- pptx2/dml/effect.py +909 -0
- pptx2/dml/fill.py +691 -0
- pptx2/dml/line.py +287 -0
- pptx2/dml/picture.py +212 -0
- pptx2/dml/three_d.py +381 -0
- pptx2/enum/__init__.py +0 -0
- pptx2/enum/action.py +71 -0
- pptx2/enum/animation.py +31 -0
- pptx2/enum/base.py +218 -0
- pptx2/enum/chart.py +574 -0
- pptx2/enum/dml.py +740 -0
- pptx2/enum/lang.py +685 -0
- pptx2/enum/presentation.py +133 -0
- pptx2/enum/shapes.py +1029 -0
- pptx2/enum/text.py +230 -0
- pptx2/exc.py +42 -0
- pptx2/formats.py +139 -0
- pptx2/geometry.py +420 -0
- pptx2/inherit.py +109 -0
- pptx2/lint.py +2256 -0
- pptx2/math.py +177 -0
- pptx2/media.py +197 -0
- pptx2/opc/__init__.py +0 -0
- pptx2/opc/constants.py +332 -0
- pptx2/opc/oxml.py +188 -0
- pptx2/opc/package.py +762 -0
- pptx2/opc/packuri.py +109 -0
- pptx2/opc/serialized.py +296 -0
- pptx2/opc/shared.py +20 -0
- pptx2/opc/spec.py +45 -0
- pptx2/oxml/__init__.py +555 -0
- pptx2/oxml/action.py +53 -0
- pptx2/oxml/chart/__init__.py +0 -0
- pptx2/oxml/chart/axis.py +337 -0
- pptx2/oxml/chart/chart.py +481 -0
- pptx2/oxml/chart/datalabel.py +253 -0
- pptx2/oxml/chart/legend.py +72 -0
- pptx2/oxml/chart/marker.py +61 -0
- pptx2/oxml/chart/plot.py +365 -0
- pptx2/oxml/chart/series.py +425 -0
- pptx2/oxml/chart/shared.py +220 -0
- pptx2/oxml/coreprops.py +288 -0
- pptx2/oxml/dml/__init__.py +0 -0
- pptx2/oxml/dml/color.py +135 -0
- pptx2/oxml/dml/effect.py +213 -0
- pptx2/oxml/dml/fill.py +316 -0
- pptx2/oxml/dml/line.py +12 -0
- pptx2/oxml/dml/three_d.py +110 -0
- pptx2/oxml/ns.py +135 -0
- pptx2/oxml/presentation.py +313 -0
- pptx2/oxml/shapes/__init__.py +19 -0
- pptx2/oxml/shapes/autoshape.py +467 -0
- pptx2/oxml/shapes/connector.py +107 -0
- pptx2/oxml/shapes/graphfrm.py +347 -0
- pptx2/oxml/shapes/groupshape.py +329 -0
- pptx2/oxml/shapes/picture.py +270 -0
- pptx2/oxml/shapes/shared.py +577 -0
- pptx2/oxml/simpletypes.py +1027 -0
- pptx2/oxml/slide.py +563 -0
- pptx2/oxml/table.py +650 -0
- pptx2/oxml/text.py +815 -0
- pptx2/oxml/theme.py +36 -0
- pptx2/oxml/xmlchemy.py +717 -0
- pptx2/package.py +222 -0
- pptx2/parts/__init__.py +0 -0
- pptx2/parts/chart.py +95 -0
- pptx2/parts/coreprops.py +167 -0
- pptx2/parts/diagram.py +37 -0
- pptx2/parts/embeddedpackage.py +93 -0
- pptx2/parts/image.py +275 -0
- pptx2/parts/media.py +37 -0
- pptx2/parts/presentation.py +136 -0
- pptx2/parts/slide.py +371 -0
- pptx2/presentation.py +408 -0
- pptx2/py.typed +0 -0
- pptx2/render.py +586 -0
- pptx2/section.py +272 -0
- pptx2/shapes/__init__.py +26 -0
- pptx2/shapes/autoshape.py +442 -0
- pptx2/shapes/base.py +1078 -0
- pptx2/shapes/connector.py +297 -0
- pptx2/shapes/freeform.py +337 -0
- pptx2/shapes/graphfrm.py +316 -0
- pptx2/shapes/group.py +264 -0
- pptx2/shapes/picture.py +422 -0
- pptx2/shapes/placeholder.py +468 -0
- pptx2/shapes/shapetree.py +2027 -0
- pptx2/shared.py +82 -0
- pptx2/skill/SKILL.md +450 -0
- pptx2/skill/__init__.py +78 -0
- pptx2/skill/__main__.py +64 -0
- pptx2/skill/references/animations.md +189 -0
- pptx2/skill/references/basics.md +421 -0
- pptx2/skill/references/charts.md +254 -0
- pptx2/skill/references/compose.md +234 -0
- pptx2/skill/references/design.md +366 -0
- pptx2/skill/references/effects.md +249 -0
- pptx2/skill/references/end-to-end-deck.md +231 -0
- pptx2/skill/references/geometry-and-arrows.md +334 -0
- pptx2/skill/references/lint.md +275 -0
- pptx2/skill/references/math.md +86 -0
- pptx2/skill/references/picture-effects.md +129 -0
- pptx2/skill/references/render.md +151 -0
- pptx2/skill/references/smart-art.md +75 -0
- pptx2/skill/references/space-aware-authoring.md +249 -0
- pptx2/skill/references/tables.md +244 -0
- pptx2/skill/references/theme.md +127 -0
- pptx2/skill/references/three-d.md +109 -0
- pptx2/skill/references/transitions.md +100 -0
- pptx2/slide.py +1244 -0
- pptx2/smart_art.py +220 -0
- pptx2/spec.py +633 -0
- pptx2/table.py +1181 -0
- pptx2/table_styles.py +184 -0
- pptx2/templates/default.pptx +0 -0
- pptx2/templates/docx-icon.emf +0 -0
- pptx2/templates/generic-icon.emf +0 -0
- pptx2/templates/notes.xml +23 -0
- pptx2/templates/notesMaster.xml +352 -0
- pptx2/templates/pptx-icon.emf +0 -0
- pptx2/templates/theme.xml +321 -0
- pptx2/templates/xlsx-icon.emf +0 -0
- pptx2/text/__init__.py +0 -0
- pptx2/text/fonts.py +482 -0
- pptx2/text/layout.py +374 -0
- pptx2/text/text.py +1272 -0
- pptx2/theme.py +721 -0
- pptx2/types.py +36 -0
- pptx2/util.py +263 -0
- python_pptx2-2.13.0.dist-info/METADATA +351 -0
- python_pptx2-2.13.0.dist-info/RECORD +175 -0
- python_pptx2-2.13.0.dist-info/WHEEL +5 -0
- python_pptx2-2.13.0.dist-info/entry_points.txt +3 -0
- python_pptx2-2.13.0.dist-info/licenses/LICENSE +22 -0
- python_pptx2-2.13.0.dist-info/top_level.txt +1 -0
pptx2/oxml/text.py
ADDED
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
"""Custom element classes for text-related XML elements"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import re
|
|
6
|
+
from typing import TYPE_CHECKING, Callable, cast
|
|
7
|
+
|
|
8
|
+
from pptx2.enum.lang import MSO_LANGUAGE_ID
|
|
9
|
+
from pptx2.enum.text import (
|
|
10
|
+
MSO_AUTO_SIZE,
|
|
11
|
+
MSO_TEXT_UNDERLINE_TYPE,
|
|
12
|
+
MSO_VERTICAL_ANCHOR,
|
|
13
|
+
PP_PARAGRAPH_ALIGNMENT,
|
|
14
|
+
)
|
|
15
|
+
from pptx2.exc import InvalidXmlError
|
|
16
|
+
from pptx2.oxml import parse_xml, register_element_cls
|
|
17
|
+
from pptx2.oxml.dml.fill import CT_GradientFillProperties
|
|
18
|
+
from pptx2.oxml.ns import nsdecls, qn
|
|
19
|
+
from pptx2.oxml.simpletypes import (
|
|
20
|
+
ST_Coordinate32,
|
|
21
|
+
ST_Percentage,
|
|
22
|
+
ST_PositiveCoordinate32,
|
|
23
|
+
ST_TextAutonumberScheme,
|
|
24
|
+
ST_TextBulletStartAtNum,
|
|
25
|
+
ST_TextCapsType,
|
|
26
|
+
ST_TextColumnCount,
|
|
27
|
+
ST_TextFontScalePercentOrPercentString,
|
|
28
|
+
ST_TextFontSize,
|
|
29
|
+
ST_TextIndentLevelType,
|
|
30
|
+
ST_TextPoint,
|
|
31
|
+
ST_TextSpacingPercentOrPercentString,
|
|
32
|
+
ST_TextSpacingPoint,
|
|
33
|
+
ST_TextStrikeType,
|
|
34
|
+
ST_TextTabAlignType,
|
|
35
|
+
ST_TextTypeface,
|
|
36
|
+
ST_TextWrappingType,
|
|
37
|
+
XsdBoolean,
|
|
38
|
+
)
|
|
39
|
+
from pptx2.oxml.xmlchemy import (
|
|
40
|
+
BaseOxmlElement,
|
|
41
|
+
Choice,
|
|
42
|
+
OneAndOnlyOne,
|
|
43
|
+
OneOrMore,
|
|
44
|
+
OptionalAttribute,
|
|
45
|
+
RequiredAttribute,
|
|
46
|
+
ZeroOrMore,
|
|
47
|
+
ZeroOrOne,
|
|
48
|
+
ZeroOrOneChoice,
|
|
49
|
+
)
|
|
50
|
+
from pptx2.util import Emu, Length
|
|
51
|
+
|
|
52
|
+
if TYPE_CHECKING:
|
|
53
|
+
from pptx2.oxml.action import CT_Hyperlink
|
|
54
|
+
from pptx2.oxml.dml.effect import CT_EffectList
|
|
55
|
+
from pptx2.oxml.shapes.shared import CT_LineProperties
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class CT_RegularTextRun(BaseOxmlElement):
|
|
59
|
+
"""`a:r` custom element class"""
|
|
60
|
+
|
|
61
|
+
get_or_add_rPr: Callable[[], CT_TextCharacterProperties]
|
|
62
|
+
|
|
63
|
+
rPr: CT_TextCharacterProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
64
|
+
"a:rPr", successors=("a:t",)
|
|
65
|
+
)
|
|
66
|
+
t: BaseOxmlElement = OneAndOnlyOne("a:t") # pyright: ignore[reportAssignmentType]
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def text(self) -> str:
|
|
70
|
+
"""All text of (required) `a:t` child."""
|
|
71
|
+
text = self.t.text
|
|
72
|
+
# -- t.text is None when t element is empty, e.g. '<a:t/>' --
|
|
73
|
+
return text or ""
|
|
74
|
+
|
|
75
|
+
@text.setter
|
|
76
|
+
def text(self, value: str): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
77
|
+
self.t.text = self._escape_ctrl_chars(value)
|
|
78
|
+
|
|
79
|
+
@staticmethod
|
|
80
|
+
def _escape_ctrl_chars(s: str) -> str:
|
|
81
|
+
"""Return str after replacing each control character with a plain-text escape.
|
|
82
|
+
|
|
83
|
+
For example, a BEL character (x07) would appear as "_x0007_". Horizontal-tab
|
|
84
|
+
(x09) and line-feed (x0A) are not escaped. All other characters in the range
|
|
85
|
+
x00-x1F are escaped.
|
|
86
|
+
"""
|
|
87
|
+
return re.sub(r"([\x00-\x08\x0B-\x1F])", lambda match: "_x%04X_" % ord(match.group(1)), s)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class CT_TextBody(BaseOxmlElement):
|
|
91
|
+
"""`p:txBody` custom element class.
|
|
92
|
+
|
|
93
|
+
Also used for `c:txPr` in charts and perhaps other elements.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
add_p: Callable[[], CT_TextParagraph]
|
|
97
|
+
p_lst: list[CT_TextParagraph]
|
|
98
|
+
get_or_add_lstStyle: Callable[[], CT_TextListStyle]
|
|
99
|
+
|
|
100
|
+
bodyPr: CT_TextBodyProperties = OneAndOnlyOne( # pyright: ignore[reportAssignmentType]
|
|
101
|
+
"a:bodyPr"
|
|
102
|
+
)
|
|
103
|
+
lstStyle: CT_TextListStyle | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
104
|
+
"a:lstStyle", successors=("a:p",)
|
|
105
|
+
)
|
|
106
|
+
p: CT_TextParagraph = OneOrMore("a:p") # pyright: ignore[reportAssignmentType]
|
|
107
|
+
|
|
108
|
+
def clear_content(self):
|
|
109
|
+
"""Remove all `a:p` children, but leave any others.
|
|
110
|
+
|
|
111
|
+
cf. lxml `_Element.clear()` method which removes all children.
|
|
112
|
+
"""
|
|
113
|
+
for p in self.p_lst:
|
|
114
|
+
self.remove(p)
|
|
115
|
+
|
|
116
|
+
@property
|
|
117
|
+
def defRPr(self) -> CT_TextCharacterProperties:
|
|
118
|
+
"""`a:defRPr` element of required first `p` child, added with its ancestors if not present.
|
|
119
|
+
|
|
120
|
+
Used when element is a ``c:txPr`` in a chart and the `p` element is used only to specify
|
|
121
|
+
formatting, not content.
|
|
122
|
+
"""
|
|
123
|
+
p = self.p_lst[0]
|
|
124
|
+
pPr = p.get_or_add_pPr()
|
|
125
|
+
defRPr = pPr.get_or_add_defRPr()
|
|
126
|
+
return defRPr
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def is_empty(self) -> bool:
|
|
130
|
+
"""True if only a single empty `a:p` element is present."""
|
|
131
|
+
ps = self.p_lst
|
|
132
|
+
if len(ps) > 1:
|
|
133
|
+
return False
|
|
134
|
+
|
|
135
|
+
if not ps:
|
|
136
|
+
raise InvalidXmlError("p:txBody must have at least one a:p")
|
|
137
|
+
|
|
138
|
+
if ps[0].text != "":
|
|
139
|
+
return False
|
|
140
|
+
return True
|
|
141
|
+
|
|
142
|
+
@classmethod
|
|
143
|
+
def new(cls):
|
|
144
|
+
"""Return a new `p:txBody` element tree."""
|
|
145
|
+
xml = cls._txBody_tmpl()
|
|
146
|
+
txBody = parse_xml(xml)
|
|
147
|
+
return txBody
|
|
148
|
+
|
|
149
|
+
@classmethod
|
|
150
|
+
def new_a_txBody(cls) -> CT_TextBody:
|
|
151
|
+
"""Return a new `a:txBody` element tree.
|
|
152
|
+
|
|
153
|
+
Suitable for use in a table cell and possibly other situations.
|
|
154
|
+
"""
|
|
155
|
+
xml = cls._a_txBody_tmpl()
|
|
156
|
+
txBody = cast(CT_TextBody, parse_xml(xml))
|
|
157
|
+
return txBody
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def new_p_txBody(cls):
|
|
161
|
+
"""Return a new `p:txBody` element tree, suitable for use in an `p:sp` element."""
|
|
162
|
+
xml = cls._p_txBody_tmpl()
|
|
163
|
+
return parse_xml(xml)
|
|
164
|
+
|
|
165
|
+
@classmethod
|
|
166
|
+
def new_txPr(cls):
|
|
167
|
+
"""Return a `c:txPr` element tree.
|
|
168
|
+
|
|
169
|
+
Suitable for use in a chart object like data labels or tick labels.
|
|
170
|
+
The trailing ``<a:endParaRPr lang="en-US"/>`` is required by
|
|
171
|
+
PowerPoint's strict open-time validator — bare ``<a:p>...</a:p>``
|
|
172
|
+
passes the OOXML schema and LibreOffice but triggers the
|
|
173
|
+
"PowerPoint found a problem with content. Repair?" dialog,
|
|
174
|
+
after which PowerPoint silently empties the chart.
|
|
175
|
+
"""
|
|
176
|
+
xml = (
|
|
177
|
+
"<c:txPr %s>\n"
|
|
178
|
+
" <a:bodyPr/>\n"
|
|
179
|
+
" <a:lstStyle/>\n"
|
|
180
|
+
" <a:p>\n"
|
|
181
|
+
" <a:pPr>\n"
|
|
182
|
+
" <a:defRPr/>\n"
|
|
183
|
+
" </a:pPr>\n"
|
|
184
|
+
' <a:endParaRPr lang="en-US"/>\n'
|
|
185
|
+
" </a:p>\n"
|
|
186
|
+
"</c:txPr>\n"
|
|
187
|
+
) % nsdecls("c", "a")
|
|
188
|
+
txPr = parse_xml(xml)
|
|
189
|
+
return txPr
|
|
190
|
+
|
|
191
|
+
def unclear_content(self):
|
|
192
|
+
"""Ensure p:txBody has at least one a:p child.
|
|
193
|
+
|
|
194
|
+
Intuitively, reverse a ".clear_content()" operation to minimum conformance with spec
|
|
195
|
+
(single empty paragraph).
|
|
196
|
+
"""
|
|
197
|
+
if len(self.p_lst) > 0:
|
|
198
|
+
return
|
|
199
|
+
self.add_p()
|
|
200
|
+
|
|
201
|
+
@classmethod
|
|
202
|
+
def _a_txBody_tmpl(cls):
|
|
203
|
+
return "<a:txBody %s>\n <a:bodyPr/>\n <a:p/>\n</a:txBody>\n" % (nsdecls("a"))
|
|
204
|
+
|
|
205
|
+
@classmethod
|
|
206
|
+
def _p_txBody_tmpl(cls):
|
|
207
|
+
return "<p:txBody %s>\n <a:bodyPr/>\n <a:p/>\n</p:txBody>\n" % (nsdecls("p", "a"))
|
|
208
|
+
|
|
209
|
+
@classmethod
|
|
210
|
+
def _txBody_tmpl(cls):
|
|
211
|
+
return "<p:txBody %s>\n <a:bodyPr/>\n <a:lstStyle/>\n <a:p/>\n</p:txBody>\n" % (
|
|
212
|
+
nsdecls("a", "p")
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class CT_TextListStyle(BaseOxmlElement):
|
|
217
|
+
"""`a:lstStyle` custom element class.
|
|
218
|
+
|
|
219
|
+
The per-indent-level default text properties of a text body. Only
|
|
220
|
+
`a:lvl1pPr` is modelled; the other eight levels are rarely addressed
|
|
221
|
+
programmatically and are preserved verbatim when present.
|
|
222
|
+
|
|
223
|
+
Defaults written here outlive a text replacement — ``TextFrame.text = ...``
|
|
224
|
+
removes the `a:p` children and nothing else — which is what makes this the
|
|
225
|
+
right home for "style this text frame, populate it later".
|
|
226
|
+
"""
|
|
227
|
+
|
|
228
|
+
get_or_add_lvl1pPr: Callable[[], CT_TextParagraphProperties]
|
|
229
|
+
|
|
230
|
+
_lvl_tag_seq = tuple("a:lvl%dpPr" % n for n in range(1, 10)) + ("a:extLst",)
|
|
231
|
+
lvl1pPr: CT_TextParagraphProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
232
|
+
"a:lvl1pPr", successors=_lvl_tag_seq[1:]
|
|
233
|
+
)
|
|
234
|
+
del _lvl_tag_seq
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
class CT_TextBodyProperties(BaseOxmlElement):
|
|
238
|
+
"""`a:bodyPr` custom element class."""
|
|
239
|
+
|
|
240
|
+
_add_noAutofit: Callable[[], BaseOxmlElement]
|
|
241
|
+
_add_normAutofit: Callable[[], CT_TextNormalAutofit]
|
|
242
|
+
_add_spAutoFit: Callable[[], BaseOxmlElement]
|
|
243
|
+
_remove_eg_textAutoFit: Callable[[], None]
|
|
244
|
+
|
|
245
|
+
noAutofit: BaseOxmlElement | None
|
|
246
|
+
normAutofit: CT_TextNormalAutofit | None
|
|
247
|
+
spAutoFit: BaseOxmlElement | None
|
|
248
|
+
|
|
249
|
+
eg_textAutoFit = ZeroOrOneChoice(
|
|
250
|
+
(Choice("a:noAutofit"), Choice("a:normAutofit"), Choice("a:spAutoFit")),
|
|
251
|
+
successors=("a:scene3d", "a:sp3d", "a:flatTx", "a:extLst"),
|
|
252
|
+
)
|
|
253
|
+
lIns: Length = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
254
|
+
"lIns", ST_Coordinate32, default=Emu(91440)
|
|
255
|
+
)
|
|
256
|
+
tIns: Length = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
257
|
+
"tIns", ST_Coordinate32, default=Emu(45720)
|
|
258
|
+
)
|
|
259
|
+
rIns: Length = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
260
|
+
"rIns", ST_Coordinate32, default=Emu(91440)
|
|
261
|
+
)
|
|
262
|
+
bIns: Length = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
263
|
+
"bIns", ST_Coordinate32, default=Emu(45720)
|
|
264
|
+
)
|
|
265
|
+
anchor: MSO_VERTICAL_ANCHOR | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
266
|
+
"anchor", MSO_VERTICAL_ANCHOR
|
|
267
|
+
)
|
|
268
|
+
wrap: str | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
269
|
+
"wrap", ST_TextWrappingType
|
|
270
|
+
)
|
|
271
|
+
numCol: int | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
272
|
+
"numCol", ST_TextColumnCount
|
|
273
|
+
)
|
|
274
|
+
spcCol: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
275
|
+
"spcCol", ST_PositiveCoordinate32
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
@property
|
|
279
|
+
def autofit(self):
|
|
280
|
+
"""The autofit setting for the text frame, a member of the `MSO_AUTO_SIZE` enumeration."""
|
|
281
|
+
if self.noAutofit is not None:
|
|
282
|
+
return MSO_AUTO_SIZE.NONE
|
|
283
|
+
if self.normAutofit is not None:
|
|
284
|
+
return MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE
|
|
285
|
+
if self.spAutoFit is not None:
|
|
286
|
+
return MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT
|
|
287
|
+
return None
|
|
288
|
+
|
|
289
|
+
@autofit.setter
|
|
290
|
+
def autofit(self, value: MSO_AUTO_SIZE | None):
|
|
291
|
+
if value is not None and value not in MSO_AUTO_SIZE:
|
|
292
|
+
raise ValueError(
|
|
293
|
+
f"only None or a member of the MSO_AUTO_SIZE enumeration can be assigned to"
|
|
294
|
+
f" CT_TextBodyProperties.autofit, got {value}"
|
|
295
|
+
)
|
|
296
|
+
self._remove_eg_textAutoFit()
|
|
297
|
+
if value == MSO_AUTO_SIZE.NONE:
|
|
298
|
+
self._add_noAutofit()
|
|
299
|
+
elif value == MSO_AUTO_SIZE.TEXT_TO_FIT_SHAPE:
|
|
300
|
+
self._add_normAutofit()
|
|
301
|
+
elif value == MSO_AUTO_SIZE.SHAPE_TO_FIT_TEXT:
|
|
302
|
+
self._add_spAutoFit()
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class CT_TextCharacterProperties(BaseOxmlElement):
|
|
306
|
+
"""Custom element class for `a:rPr`, `a:defRPr`, and `a:endParaRPr`.
|
|
307
|
+
|
|
308
|
+
'rPr' is short for 'run properties', and it corresponds to the |Font| proxy class.
|
|
309
|
+
"""
|
|
310
|
+
|
|
311
|
+
get_or_add_hlinkClick: Callable[[], CT_Hyperlink]
|
|
312
|
+
get_or_add_latin: Callable[[], CT_TextFont]
|
|
313
|
+
get_or_add_ln: Callable[[], CT_LineProperties]
|
|
314
|
+
get_or_add_effectLst: Callable[[], CT_EffectList]
|
|
315
|
+
_remove_latin: Callable[[], None]
|
|
316
|
+
_remove_hlinkClick: Callable[[], None]
|
|
317
|
+
_remove_ln: Callable[[], None]
|
|
318
|
+
_remove_effectLst: Callable[[], None]
|
|
319
|
+
|
|
320
|
+
# -- Per ISO-IEC-29500-1 `CT_TextCharacterProperties`, the child element
|
|
321
|
+
# -- order is: ln, EG_FillProperties, EG_EffectProperties (effectLst /
|
|
322
|
+
# -- effectDag), highlight, EG_TextUnderlineLine (uLnTx / uLn),
|
|
323
|
+
# -- EG_TextUnderlineFill (uFillTx / uFill), latin, ea, cs, sym, hlinkClick,
|
|
324
|
+
# -- hlinkMouseOver, rtl, extLst.
|
|
325
|
+
ln: CT_LineProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
326
|
+
"a:ln",
|
|
327
|
+
successors=(
|
|
328
|
+
"a:noFill",
|
|
329
|
+
"a:solidFill",
|
|
330
|
+
"a:gradFill",
|
|
331
|
+
"a:blipFill",
|
|
332
|
+
"a:pattFill",
|
|
333
|
+
"a:grpFill",
|
|
334
|
+
"a:effectLst",
|
|
335
|
+
"a:effectDag",
|
|
336
|
+
"a:highlight",
|
|
337
|
+
"a:uLnTx",
|
|
338
|
+
"a:uLn",
|
|
339
|
+
"a:uFillTx",
|
|
340
|
+
"a:uFill",
|
|
341
|
+
"a:latin",
|
|
342
|
+
"a:ea",
|
|
343
|
+
"a:cs",
|
|
344
|
+
"a:sym",
|
|
345
|
+
"a:hlinkClick",
|
|
346
|
+
"a:hlinkMouseOver",
|
|
347
|
+
"a:rtl",
|
|
348
|
+
"a:extLst",
|
|
349
|
+
),
|
|
350
|
+
)
|
|
351
|
+
eg_fillProperties = ZeroOrOneChoice(
|
|
352
|
+
(
|
|
353
|
+
Choice("a:noFill"),
|
|
354
|
+
Choice("a:solidFill"),
|
|
355
|
+
Choice("a:gradFill"),
|
|
356
|
+
Choice("a:blipFill"),
|
|
357
|
+
Choice("a:pattFill"),
|
|
358
|
+
Choice("a:grpFill"),
|
|
359
|
+
),
|
|
360
|
+
successors=(
|
|
361
|
+
"a:effectLst",
|
|
362
|
+
"a:effectDag",
|
|
363
|
+
"a:highlight",
|
|
364
|
+
"a:uLnTx",
|
|
365
|
+
"a:uLn",
|
|
366
|
+
"a:uFillTx",
|
|
367
|
+
"a:uFill",
|
|
368
|
+
"a:latin",
|
|
369
|
+
"a:ea",
|
|
370
|
+
"a:cs",
|
|
371
|
+
"a:sym",
|
|
372
|
+
"a:hlinkClick",
|
|
373
|
+
"a:hlinkMouseOver",
|
|
374
|
+
"a:rtl",
|
|
375
|
+
"a:extLst",
|
|
376
|
+
),
|
|
377
|
+
)
|
|
378
|
+
effectLst: CT_EffectList | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
379
|
+
"a:effectLst",
|
|
380
|
+
successors=(
|
|
381
|
+
"a:effectDag",
|
|
382
|
+
"a:highlight",
|
|
383
|
+
"a:uLnTx",
|
|
384
|
+
"a:uLn",
|
|
385
|
+
"a:uFillTx",
|
|
386
|
+
"a:uFill",
|
|
387
|
+
"a:latin",
|
|
388
|
+
"a:ea",
|
|
389
|
+
"a:cs",
|
|
390
|
+
"a:sym",
|
|
391
|
+
"a:hlinkClick",
|
|
392
|
+
"a:hlinkMouseOver",
|
|
393
|
+
"a:rtl",
|
|
394
|
+
"a:extLst",
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
latin: CT_TextFont | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
398
|
+
"a:latin",
|
|
399
|
+
successors=(
|
|
400
|
+
"a:ea",
|
|
401
|
+
"a:cs",
|
|
402
|
+
"a:sym",
|
|
403
|
+
"a:hlinkClick",
|
|
404
|
+
"a:hlinkMouseOver",
|
|
405
|
+
"a:rtl",
|
|
406
|
+
"a:extLst",
|
|
407
|
+
),
|
|
408
|
+
)
|
|
409
|
+
hlinkClick: CT_Hyperlink | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
410
|
+
"a:hlinkClick", successors=("a:hlinkMouseOver", "a:rtl", "a:extLst")
|
|
411
|
+
)
|
|
412
|
+
|
|
413
|
+
lang: MSO_LANGUAGE_ID | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
414
|
+
"lang", MSO_LANGUAGE_ID
|
|
415
|
+
)
|
|
416
|
+
sz: int | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
417
|
+
"sz", ST_TextFontSize
|
|
418
|
+
)
|
|
419
|
+
b: bool | None = OptionalAttribute("b", XsdBoolean) # pyright: ignore[reportAssignmentType]
|
|
420
|
+
i: bool | None = OptionalAttribute("i", XsdBoolean) # pyright: ignore[reportAssignmentType]
|
|
421
|
+
u: MSO_TEXT_UNDERLINE_TYPE | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
422
|
+
"u", MSO_TEXT_UNDERLINE_TYPE
|
|
423
|
+
)
|
|
424
|
+
strike: str | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
425
|
+
"strike", ST_TextStrikeType
|
|
426
|
+
)
|
|
427
|
+
cap: str | None = OptionalAttribute("cap", ST_TextCapsType) # pyright: ignore[reportAssignmentType]
|
|
428
|
+
spc: Length | None = OptionalAttribute("spc", ST_TextPoint) # pyright: ignore[reportAssignmentType]
|
|
429
|
+
baseline: float | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
430
|
+
"baseline", ST_Percentage
|
|
431
|
+
)
|
|
432
|
+
|
|
433
|
+
def _new_gradFill(self):
|
|
434
|
+
return CT_GradientFillProperties.new_gradFill()
|
|
435
|
+
|
|
436
|
+
def add_hlinkClick(self, rId: str) -> CT_Hyperlink:
|
|
437
|
+
"""Add an `a:hlinkClick` child element with r:id attribute set to `rId`."""
|
|
438
|
+
hlinkClick = self.get_or_add_hlinkClick()
|
|
439
|
+
hlinkClick.rId = rId
|
|
440
|
+
return hlinkClick
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
class CT_TextField(BaseOxmlElement):
|
|
444
|
+
"""`a:fld` field element, for either a slide number or date field."""
|
|
445
|
+
|
|
446
|
+
get_or_add_rPr: Callable[[], CT_TextCharacterProperties]
|
|
447
|
+
|
|
448
|
+
rPr: CT_TextCharacterProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
449
|
+
"a:rPr", successors=("a:pPr", "a:t")
|
|
450
|
+
)
|
|
451
|
+
t: BaseOxmlElement | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
452
|
+
"a:t", successors=()
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
@property
|
|
456
|
+
def text(self) -> str: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
457
|
+
"""The text of the `a:t` child element."""
|
|
458
|
+
t = self.t
|
|
459
|
+
if t is None:
|
|
460
|
+
return ""
|
|
461
|
+
return t.text or ""
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
class CT_TextFont(BaseOxmlElement):
|
|
465
|
+
"""Custom element class for `a:latin`, `a:ea`, `a:cs`, and `a:sym`.
|
|
466
|
+
|
|
467
|
+
These occur as child elements of CT_TextCharacterProperties, e.g. `a:rPr`.
|
|
468
|
+
"""
|
|
469
|
+
|
|
470
|
+
typeface: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
|
471
|
+
"typeface", ST_TextTypeface
|
|
472
|
+
)
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
class CT_TextLineBreak(BaseOxmlElement):
|
|
476
|
+
"""`a:br` line break element"""
|
|
477
|
+
|
|
478
|
+
get_or_add_rPr: Callable[[], CT_TextCharacterProperties]
|
|
479
|
+
|
|
480
|
+
rPr = ZeroOrOne("a:rPr", successors=())
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def text(self): # pyright: ignore[reportIncompatibleMethodOverride]
|
|
484
|
+
"""Unconditionally a single vertical-tab character.
|
|
485
|
+
|
|
486
|
+
A line break element can contain no text other than the implicit line feed it
|
|
487
|
+
represents.
|
|
488
|
+
"""
|
|
489
|
+
return "\v"
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
class CT_OfficeMathMarker(BaseOxmlElement):
|
|
493
|
+
"""`a14:m` marker PowerPoint wraps around Office Math (OMML).
|
|
494
|
+
|
|
495
|
+
DrawingML paragraphs store native equations as this element containing
|
|
496
|
+
``m:oMath`` / ``m:oMathPara``. The marker itself has no visible run
|
|
497
|
+
text; :attr:`text` is always the empty string so paragraph concatenation
|
|
498
|
+
and ``clear()`` treat it like other content children.
|
|
499
|
+
"""
|
|
500
|
+
|
|
501
|
+
@property
|
|
502
|
+
def text(self) -> str:
|
|
503
|
+
return ""
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
class CT_TextNormalAutofit(BaseOxmlElement):
|
|
507
|
+
"""`a:normAutofit` element specifying fit text to shape font reduction, etc."""
|
|
508
|
+
|
|
509
|
+
fontScale = OptionalAttribute(
|
|
510
|
+
"fontScale", ST_TextFontScalePercentOrPercentString, default=100.0
|
|
511
|
+
)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
class CT_TextParagraph(BaseOxmlElement):
|
|
515
|
+
"""`a:p` custom element class"""
|
|
516
|
+
|
|
517
|
+
get_or_add_endParaRPr: Callable[[], CT_TextCharacterProperties]
|
|
518
|
+
get_or_add_pPr: Callable[[], CT_TextParagraphProperties]
|
|
519
|
+
r_lst: list[CT_RegularTextRun]
|
|
520
|
+
_add_br: Callable[[], CT_TextLineBreak]
|
|
521
|
+
_add_r: Callable[[], CT_RegularTextRun]
|
|
522
|
+
|
|
523
|
+
pPr: CT_TextParagraphProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
524
|
+
"a:pPr", successors=("a:r", "a:br", "a:fld", "a14:m", "a:endParaRPr")
|
|
525
|
+
)
|
|
526
|
+
r = ZeroOrMore("a:r", successors=("a:endParaRPr",))
|
|
527
|
+
br = ZeroOrMore("a:br", successors=("a:endParaRPr",))
|
|
528
|
+
endParaRPr: CT_TextCharacterProperties | None = ZeroOrOne("a:endParaRPr", successors=()) # pyright: ignore[reportAssignmentType]
|
|
529
|
+
|
|
530
|
+
def add_br(self) -> CT_TextLineBreak:
|
|
531
|
+
"""Return a newly appended `a:br` element."""
|
|
532
|
+
return self._add_br()
|
|
533
|
+
|
|
534
|
+
def add_r(self, text: str | None = None) -> CT_RegularTextRun:
|
|
535
|
+
"""Return a newly appended `a:r` element."""
|
|
536
|
+
r = self._add_r()
|
|
537
|
+
if text:
|
|
538
|
+
r.text = text
|
|
539
|
+
return r
|
|
540
|
+
|
|
541
|
+
def add_math(self, math_elm: CT_OfficeMathMarker) -> CT_OfficeMathMarker:
|
|
542
|
+
"""Append an `a14:m` equation marker before `a:endParaRPr`."""
|
|
543
|
+
self.insert_element_before(math_elm, "a:endParaRPr")
|
|
544
|
+
return math_elm
|
|
545
|
+
|
|
546
|
+
def append_text(self, text: str):
|
|
547
|
+
"""Append `a:r` and `a:br` elements to `p` based on `text`.
|
|
548
|
+
|
|
549
|
+
Any `\n` or `\v` (vertical-tab) characters in `text` delimit `a:r` (run) elements and
|
|
550
|
+
themselves are translated to `a:br` (line-break) elements. The vertical-tab character
|
|
551
|
+
appears in clipboard text from PowerPoint at "soft" line-breaks (new-line, but not new
|
|
552
|
+
paragraph).
|
|
553
|
+
"""
|
|
554
|
+
for idx, r_str in enumerate(re.split("\n|\v", text)):
|
|
555
|
+
# ---breaks are only added _between_ items, not at start---
|
|
556
|
+
if idx > 0:
|
|
557
|
+
self.add_br()
|
|
558
|
+
# ---runs that would be empty are not added---
|
|
559
|
+
if r_str:
|
|
560
|
+
self.add_r(r_str)
|
|
561
|
+
|
|
562
|
+
@property
|
|
563
|
+
def content_children(
|
|
564
|
+
self,
|
|
565
|
+
) -> tuple[CT_RegularTextRun | CT_TextLineBreak | CT_TextField | CT_OfficeMathMarker, ...]:
|
|
566
|
+
"""Sequence containing text-container child elements of this `a:p` element.
|
|
567
|
+
|
|
568
|
+
These include `a:r`, `a:br`, `a:fld`, and `a14:m` (native equations).
|
|
569
|
+
"""
|
|
570
|
+
return tuple(
|
|
571
|
+
e
|
|
572
|
+
for e in self
|
|
573
|
+
if isinstance(
|
|
574
|
+
e, (CT_RegularTextRun, CT_TextLineBreak, CT_TextField, CT_OfficeMathMarker)
|
|
575
|
+
)
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
@property
|
|
579
|
+
def text(self) -> str: # pyright: ignore[reportIncompatibleMethodOverride]
|
|
580
|
+
"""str text contained in this paragraph."""
|
|
581
|
+
# ---note this shadows the lxml _Element.text---
|
|
582
|
+
return "".join([child.text for child in self.content_children])
|
|
583
|
+
|
|
584
|
+
def _new_r(self):
|
|
585
|
+
r_xml = "<a:r %s><a:t/></a:r>" % nsdecls("a")
|
|
586
|
+
return parse_xml(r_xml)
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
class CT_TextParagraphProperties(BaseOxmlElement):
|
|
590
|
+
"""`a:pPr` custom element class."""
|
|
591
|
+
|
|
592
|
+
get_or_add_defRPr: Callable[[], CT_TextCharacterProperties]
|
|
593
|
+
get_or_add_buAutoNum: Callable[[], CT_TextAutonumberBullet]
|
|
594
|
+
get_or_add_tabLst: Callable[[], CT_TextTabStopList]
|
|
595
|
+
_add_lnSpc: Callable[[], CT_TextSpacing]
|
|
596
|
+
_add_spcAft: Callable[[], CT_TextSpacing]
|
|
597
|
+
_add_spcBef: Callable[[], CT_TextSpacing]
|
|
598
|
+
_remove_lnSpc: Callable[[], None]
|
|
599
|
+
_remove_spcAft: Callable[[], None]
|
|
600
|
+
_remove_spcBef: Callable[[], None]
|
|
601
|
+
|
|
602
|
+
_tag_seq = (
|
|
603
|
+
"a:lnSpc",
|
|
604
|
+
"a:spcBef",
|
|
605
|
+
"a:spcAft",
|
|
606
|
+
"a:buClrTx",
|
|
607
|
+
"a:buClr",
|
|
608
|
+
"a:buSzTx",
|
|
609
|
+
"a:buSzPct",
|
|
610
|
+
"a:buSzPts",
|
|
611
|
+
"a:buFontTx",
|
|
612
|
+
"a:buFont",
|
|
613
|
+
"a:buNone",
|
|
614
|
+
"a:buAutoNum",
|
|
615
|
+
"a:buChar",
|
|
616
|
+
"a:buBlip",
|
|
617
|
+
"a:tabLst",
|
|
618
|
+
"a:defRPr",
|
|
619
|
+
"a:extLst",
|
|
620
|
+
)
|
|
621
|
+
lnSpc: CT_TextSpacing | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
622
|
+
"a:lnSpc", successors=_tag_seq[1:]
|
|
623
|
+
)
|
|
624
|
+
spcBef: CT_TextSpacing | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
625
|
+
"a:spcBef", successors=_tag_seq[2:]
|
|
626
|
+
)
|
|
627
|
+
spcAft: CT_TextSpacing | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
628
|
+
"a:spcAft", successors=_tag_seq[3:]
|
|
629
|
+
)
|
|
630
|
+
buAutoNum: CT_TextAutonumberBullet | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
631
|
+
"a:buAutoNum", successors=_tag_seq[12:]
|
|
632
|
+
)
|
|
633
|
+
tabLst: CT_TextTabStopList | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
634
|
+
"a:tabLst", successors=_tag_seq[15:]
|
|
635
|
+
)
|
|
636
|
+
defRPr: CT_TextCharacterProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
637
|
+
"a:defRPr", successors=_tag_seq[16:]
|
|
638
|
+
)
|
|
639
|
+
lvl: int = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
640
|
+
"lvl", ST_TextIndentLevelType, default=0
|
|
641
|
+
)
|
|
642
|
+
algn: PP_PARAGRAPH_ALIGNMENT | None = OptionalAttribute("algn", PP_PARAGRAPH_ALIGNMENT) # pyright: ignore[reportAssignmentType]
|
|
643
|
+
rtl: bool | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
644
|
+
"rtl", XsdBoolean
|
|
645
|
+
)
|
|
646
|
+
del _tag_seq
|
|
647
|
+
|
|
648
|
+
@property
|
|
649
|
+
def line_spacing(self) -> float | Length | None:
|
|
650
|
+
"""The spacing between baselines of successive lines in this paragraph.
|
|
651
|
+
|
|
652
|
+
A float value indicates a number of lines. A |Length| value indicates a fixed spacing.
|
|
653
|
+
Value is contained in `./a:lnSpc/a:spcPts/@val` or `./a:lnSpc/a:spcPct/@val`. Value is
|
|
654
|
+
|None| if no element is present.
|
|
655
|
+
"""
|
|
656
|
+
lnSpc = self.lnSpc
|
|
657
|
+
if lnSpc is None:
|
|
658
|
+
return None
|
|
659
|
+
if lnSpc.spcPts is not None:
|
|
660
|
+
return lnSpc.spcPts.val
|
|
661
|
+
return cast(CT_TextSpacingPercent, lnSpc.spcPct).val
|
|
662
|
+
|
|
663
|
+
@line_spacing.setter
|
|
664
|
+
def line_spacing(self, value: float | Length | None):
|
|
665
|
+
self._remove_lnSpc()
|
|
666
|
+
if value is None:
|
|
667
|
+
return
|
|
668
|
+
if isinstance(value, Length):
|
|
669
|
+
self._add_lnSpc().set_spcPts(value)
|
|
670
|
+
else:
|
|
671
|
+
self._add_lnSpc().set_spcPct(value)
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def space_after(self) -> Length | None:
|
|
675
|
+
"""The EMU equivalent of the centipoints value in `./a:spcAft/a:spcPts/@val`."""
|
|
676
|
+
spcAft = self.spcAft
|
|
677
|
+
if spcAft is None:
|
|
678
|
+
return None
|
|
679
|
+
spcPts = spcAft.spcPts
|
|
680
|
+
if spcPts is None:
|
|
681
|
+
return None
|
|
682
|
+
return spcPts.val
|
|
683
|
+
|
|
684
|
+
@space_after.setter
|
|
685
|
+
def space_after(self, value: Length | None):
|
|
686
|
+
self._remove_spcAft()
|
|
687
|
+
if value is not None:
|
|
688
|
+
self._add_spcAft().set_spcPts(value)
|
|
689
|
+
|
|
690
|
+
@property
|
|
691
|
+
def space_before(self):
|
|
692
|
+
"""The EMU equivalent of the centipoints value in `./a:spcBef/a:spcPts/@val`."""
|
|
693
|
+
spcBef = self.spcBef
|
|
694
|
+
if spcBef is None:
|
|
695
|
+
return None
|
|
696
|
+
spcPts = spcBef.spcPts
|
|
697
|
+
if spcPts is None:
|
|
698
|
+
return None
|
|
699
|
+
return spcPts.val
|
|
700
|
+
|
|
701
|
+
@space_before.setter
|
|
702
|
+
def space_before(self, value: Length | None):
|
|
703
|
+
self._remove_spcBef()
|
|
704
|
+
if value is not None:
|
|
705
|
+
self._add_spcBef().set_spcPts(value)
|
|
706
|
+
|
|
707
|
+
def get_or_add_buAutoNum_only(self) -> CT_TextAutonumberBullet:
|
|
708
|
+
"""Return the `a:buAutoNum` child, adding it if not present.
|
|
709
|
+
|
|
710
|
+
The bullet element group (``buNone``/``buAutoNum``/``buChar``/``buBlip``) is an
|
|
711
|
+
XSD choice — at most one may be present — so any sibling bullet element is
|
|
712
|
+
removed first to keep the paragraph schema-valid.
|
|
713
|
+
"""
|
|
714
|
+
if self.buAutoNum is None:
|
|
715
|
+
for tag in ("a:buNone", "a:buChar", "a:buBlip"):
|
|
716
|
+
for sib in self.findall(qn(tag)):
|
|
717
|
+
self.remove(sib)
|
|
718
|
+
return self.get_or_add_buAutoNum()
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
class CT_TextAutonumberBullet(BaseOxmlElement):
|
|
722
|
+
"""`a:buAutoNum` element, an automatically-numbered list bullet."""
|
|
723
|
+
|
|
724
|
+
type: str = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
|
725
|
+
"type", ST_TextAutonumberScheme
|
|
726
|
+
)
|
|
727
|
+
startAt: int | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
728
|
+
"startAt", ST_TextBulletStartAtNum
|
|
729
|
+
)
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
class CT_TextTabStop(BaseOxmlElement):
|
|
733
|
+
"""`a:tab` element, a single tab stop in a `a:tabLst`."""
|
|
734
|
+
|
|
735
|
+
pos: Length | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
736
|
+
"pos", ST_Coordinate32
|
|
737
|
+
)
|
|
738
|
+
algn: str | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
|
|
739
|
+
"algn", ST_TextTabAlignType
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
class CT_TextTabStopList(BaseOxmlElement):
|
|
744
|
+
"""`a:tabLst` element, the ordered list of tab stops for a paragraph."""
|
|
745
|
+
|
|
746
|
+
_add_tab: Callable[[], CT_TextTabStop]
|
|
747
|
+
tab_lst: list[CT_TextTabStop]
|
|
748
|
+
|
|
749
|
+
tab = ZeroOrMore("a:tab", successors=())
|
|
750
|
+
|
|
751
|
+
def add_tab(self, pos: Length, algn: str | None = None) -> CT_TextTabStop:
|
|
752
|
+
"""Append and return an `a:tab` child with the given position and alignment."""
|
|
753
|
+
tab = self._add_tab()
|
|
754
|
+
tab.pos = pos
|
|
755
|
+
if algn is not None:
|
|
756
|
+
tab.algn = algn
|
|
757
|
+
return tab
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
class CT_TextSpacing(BaseOxmlElement):
|
|
761
|
+
"""Used for `a:lnSpc`, `a:spcBef`, and `a:spcAft` elements."""
|
|
762
|
+
|
|
763
|
+
get_or_add_spcPct: Callable[[], CT_TextSpacingPercent]
|
|
764
|
+
get_or_add_spcPts: Callable[[], CT_TextSpacingPoint]
|
|
765
|
+
_remove_spcPct: Callable[[], None]
|
|
766
|
+
_remove_spcPts: Callable[[], None]
|
|
767
|
+
|
|
768
|
+
# this should actually be a OneAndOnlyOneChoice, but that's not
|
|
769
|
+
# implemented yet.
|
|
770
|
+
spcPct: CT_TextSpacingPercent | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
771
|
+
"a:spcPct"
|
|
772
|
+
)
|
|
773
|
+
spcPts: CT_TextSpacingPoint | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
|
|
774
|
+
"a:spcPts"
|
|
775
|
+
)
|
|
776
|
+
|
|
777
|
+
def set_spcPct(self, value: float):
|
|
778
|
+
"""Set spacing to `value` lines, e.g. 1.75 lines.
|
|
779
|
+
|
|
780
|
+
A ./a:spcPts child is removed if present.
|
|
781
|
+
"""
|
|
782
|
+
self._remove_spcPts()
|
|
783
|
+
spcPct = self.get_or_add_spcPct()
|
|
784
|
+
spcPct.val = value
|
|
785
|
+
|
|
786
|
+
def set_spcPts(self, value: Length):
|
|
787
|
+
"""Set spacing to `value` points. A ./a:spcPct child is removed if present."""
|
|
788
|
+
self._remove_spcPct()
|
|
789
|
+
spcPts = self.get_or_add_spcPts()
|
|
790
|
+
spcPts.val = value
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
class CT_TextSpacingPercent(BaseOxmlElement):
|
|
794
|
+
"""`a:spcPct` element, specifying spacing in thousandths of a percent in its `val` attribute."""
|
|
795
|
+
|
|
796
|
+
val: float = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
|
797
|
+
"val", ST_TextSpacingPercentOrPercentString
|
|
798
|
+
)
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
class CT_TextSpacingPoint(BaseOxmlElement):
|
|
802
|
+
"""`a:spcPts` element, specifying spacing in centipoints in its `val` attribute."""
|
|
803
|
+
|
|
804
|
+
val: Length = RequiredAttribute( # pyright: ignore[reportAssignmentType]
|
|
805
|
+
"val", ST_TextSpacingPoint
|
|
806
|
+
)
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
# -- These element classes are introduced by the python-pptx2 fork; the global
|
|
810
|
+
# -- registry in `pptx2.oxml.__init__` doesn't know about them, so register
|
|
811
|
+
# -- them here (the `register_element_cls` callable is already defined by the
|
|
812
|
+
# -- time this module is imported during `pptx2.oxml` initialization). --
|
|
813
|
+
register_element_cls("a:buAutoNum", CT_TextAutonumberBullet)
|
|
814
|
+
register_element_cls("a:tabLst", CT_TextTabStopList)
|
|
815
|
+
register_element_cls("a:tab", CT_TextTabStop)
|