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.
Files changed (175) hide show
  1. pptx2/__init__.py +152 -0
  2. pptx2/_color.py +75 -0
  3. pptx2/_slide_importer.py +597 -0
  4. pptx2/_svg.py +155 -0
  5. pptx2/_template_applier.py +292 -0
  6. pptx2/_textstyle.py +187 -0
  7. pptx2/accessibility.py +365 -0
  8. pptx2/action.py +270 -0
  9. pptx2/animation.py +2237 -0
  10. pptx2/api.py +49 -0
  11. pptx2/audit.py +258 -0
  12. pptx2/chart/__init__.py +0 -0
  13. pptx2/chart/analytics.py +381 -0
  14. pptx2/chart/axis.py +543 -0
  15. pptx2/chart/category.py +200 -0
  16. pptx2/chart/chart.py +670 -0
  17. pptx2/chart/data.py +864 -0
  18. pptx2/chart/datalabel.py +406 -0
  19. pptx2/chart/legend.py +86 -0
  20. pptx2/chart/marker.py +70 -0
  21. pptx2/chart/palettes.py +129 -0
  22. pptx2/chart/plot.py +462 -0
  23. pptx2/chart/point.py +101 -0
  24. pptx2/chart/quick_layouts.py +325 -0
  25. pptx2/chart/series.py +334 -0
  26. pptx2/chart/xlsx.py +272 -0
  27. pptx2/chart/xmlwriter.py +1845 -0
  28. pptx2/compose/__init__.py +28 -0
  29. pptx2/compose/from_spec.py +1094 -0
  30. pptx2/design/__init__.py +8 -0
  31. pptx2/design/components.py +607 -0
  32. pptx2/design/figures.py +389 -0
  33. pptx2/design/layout.py +370 -0
  34. pptx2/design/recipes.py +1967 -0
  35. pptx2/design/style.py +209 -0
  36. pptx2/design/tokens.py +915 -0
  37. pptx2/diagrams.py +754 -0
  38. pptx2/dml/__init__.py +0 -0
  39. pptx2/dml/chtfmt.py +40 -0
  40. pptx2/dml/color.py +496 -0
  41. pptx2/dml/effect.py +909 -0
  42. pptx2/dml/fill.py +691 -0
  43. pptx2/dml/line.py +287 -0
  44. pptx2/dml/picture.py +212 -0
  45. pptx2/dml/three_d.py +381 -0
  46. pptx2/enum/__init__.py +0 -0
  47. pptx2/enum/action.py +71 -0
  48. pptx2/enum/animation.py +31 -0
  49. pptx2/enum/base.py +218 -0
  50. pptx2/enum/chart.py +574 -0
  51. pptx2/enum/dml.py +740 -0
  52. pptx2/enum/lang.py +685 -0
  53. pptx2/enum/presentation.py +133 -0
  54. pptx2/enum/shapes.py +1029 -0
  55. pptx2/enum/text.py +230 -0
  56. pptx2/exc.py +42 -0
  57. pptx2/formats.py +139 -0
  58. pptx2/geometry.py +420 -0
  59. pptx2/inherit.py +109 -0
  60. pptx2/lint.py +2256 -0
  61. pptx2/math.py +177 -0
  62. pptx2/media.py +197 -0
  63. pptx2/opc/__init__.py +0 -0
  64. pptx2/opc/constants.py +332 -0
  65. pptx2/opc/oxml.py +188 -0
  66. pptx2/opc/package.py +762 -0
  67. pptx2/opc/packuri.py +109 -0
  68. pptx2/opc/serialized.py +296 -0
  69. pptx2/opc/shared.py +20 -0
  70. pptx2/opc/spec.py +45 -0
  71. pptx2/oxml/__init__.py +555 -0
  72. pptx2/oxml/action.py +53 -0
  73. pptx2/oxml/chart/__init__.py +0 -0
  74. pptx2/oxml/chart/axis.py +337 -0
  75. pptx2/oxml/chart/chart.py +481 -0
  76. pptx2/oxml/chart/datalabel.py +253 -0
  77. pptx2/oxml/chart/legend.py +72 -0
  78. pptx2/oxml/chart/marker.py +61 -0
  79. pptx2/oxml/chart/plot.py +365 -0
  80. pptx2/oxml/chart/series.py +425 -0
  81. pptx2/oxml/chart/shared.py +220 -0
  82. pptx2/oxml/coreprops.py +288 -0
  83. pptx2/oxml/dml/__init__.py +0 -0
  84. pptx2/oxml/dml/color.py +135 -0
  85. pptx2/oxml/dml/effect.py +213 -0
  86. pptx2/oxml/dml/fill.py +316 -0
  87. pptx2/oxml/dml/line.py +12 -0
  88. pptx2/oxml/dml/three_d.py +110 -0
  89. pptx2/oxml/ns.py +135 -0
  90. pptx2/oxml/presentation.py +313 -0
  91. pptx2/oxml/shapes/__init__.py +19 -0
  92. pptx2/oxml/shapes/autoshape.py +467 -0
  93. pptx2/oxml/shapes/connector.py +107 -0
  94. pptx2/oxml/shapes/graphfrm.py +347 -0
  95. pptx2/oxml/shapes/groupshape.py +329 -0
  96. pptx2/oxml/shapes/picture.py +270 -0
  97. pptx2/oxml/shapes/shared.py +577 -0
  98. pptx2/oxml/simpletypes.py +1027 -0
  99. pptx2/oxml/slide.py +563 -0
  100. pptx2/oxml/table.py +650 -0
  101. pptx2/oxml/text.py +815 -0
  102. pptx2/oxml/theme.py +36 -0
  103. pptx2/oxml/xmlchemy.py +717 -0
  104. pptx2/package.py +222 -0
  105. pptx2/parts/__init__.py +0 -0
  106. pptx2/parts/chart.py +95 -0
  107. pptx2/parts/coreprops.py +167 -0
  108. pptx2/parts/diagram.py +37 -0
  109. pptx2/parts/embeddedpackage.py +93 -0
  110. pptx2/parts/image.py +275 -0
  111. pptx2/parts/media.py +37 -0
  112. pptx2/parts/presentation.py +136 -0
  113. pptx2/parts/slide.py +371 -0
  114. pptx2/presentation.py +408 -0
  115. pptx2/py.typed +0 -0
  116. pptx2/render.py +586 -0
  117. pptx2/section.py +272 -0
  118. pptx2/shapes/__init__.py +26 -0
  119. pptx2/shapes/autoshape.py +442 -0
  120. pptx2/shapes/base.py +1078 -0
  121. pptx2/shapes/connector.py +297 -0
  122. pptx2/shapes/freeform.py +337 -0
  123. pptx2/shapes/graphfrm.py +316 -0
  124. pptx2/shapes/group.py +264 -0
  125. pptx2/shapes/picture.py +422 -0
  126. pptx2/shapes/placeholder.py +468 -0
  127. pptx2/shapes/shapetree.py +2027 -0
  128. pptx2/shared.py +82 -0
  129. pptx2/skill/SKILL.md +450 -0
  130. pptx2/skill/__init__.py +78 -0
  131. pptx2/skill/__main__.py +64 -0
  132. pptx2/skill/references/animations.md +189 -0
  133. pptx2/skill/references/basics.md +421 -0
  134. pptx2/skill/references/charts.md +254 -0
  135. pptx2/skill/references/compose.md +234 -0
  136. pptx2/skill/references/design.md +366 -0
  137. pptx2/skill/references/effects.md +249 -0
  138. pptx2/skill/references/end-to-end-deck.md +231 -0
  139. pptx2/skill/references/geometry-and-arrows.md +334 -0
  140. pptx2/skill/references/lint.md +275 -0
  141. pptx2/skill/references/math.md +86 -0
  142. pptx2/skill/references/picture-effects.md +129 -0
  143. pptx2/skill/references/render.md +151 -0
  144. pptx2/skill/references/smart-art.md +75 -0
  145. pptx2/skill/references/space-aware-authoring.md +249 -0
  146. pptx2/skill/references/tables.md +244 -0
  147. pptx2/skill/references/theme.md +127 -0
  148. pptx2/skill/references/three-d.md +109 -0
  149. pptx2/skill/references/transitions.md +100 -0
  150. pptx2/slide.py +1244 -0
  151. pptx2/smart_art.py +220 -0
  152. pptx2/spec.py +633 -0
  153. pptx2/table.py +1181 -0
  154. pptx2/table_styles.py +184 -0
  155. pptx2/templates/default.pptx +0 -0
  156. pptx2/templates/docx-icon.emf +0 -0
  157. pptx2/templates/generic-icon.emf +0 -0
  158. pptx2/templates/notes.xml +23 -0
  159. pptx2/templates/notesMaster.xml +352 -0
  160. pptx2/templates/pptx-icon.emf +0 -0
  161. pptx2/templates/theme.xml +321 -0
  162. pptx2/templates/xlsx-icon.emf +0 -0
  163. pptx2/text/__init__.py +0 -0
  164. pptx2/text/fonts.py +482 -0
  165. pptx2/text/layout.py +374 -0
  166. pptx2/text/text.py +1272 -0
  167. pptx2/theme.py +721 -0
  168. pptx2/types.py +36 -0
  169. pptx2/util.py +263 -0
  170. python_pptx2-2.13.0.dist-info/METADATA +351 -0
  171. python_pptx2-2.13.0.dist-info/RECORD +175 -0
  172. python_pptx2-2.13.0.dist-info/WHEEL +5 -0
  173. python_pptx2-2.13.0.dist-info/entry_points.txt +3 -0
  174. python_pptx2-2.13.0.dist-info/licenses/LICENSE +22 -0
  175. python_pptx2-2.13.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,468 @@
1
+ """Placeholder-related objects.
2
+
3
+ Specific to shapes having a `p:ph` element. A placeholder has distinct behaviors
4
+ depending on whether it appears on a slide, layout, or master. Hence there is a
5
+ non-trivial class inheritance structure.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from typing import TYPE_CHECKING
11
+
12
+ from pptx2.enum.shapes import MSO_SHAPE_TYPE, PP_PLACEHOLDER
13
+ from pptx2.oxml.shapes.graphfrm import CT_GraphicalObjectFrame
14
+ from pptx2.oxml.shapes.picture import CT_Picture
15
+ from pptx2.shapes.autoshape import Shape
16
+ from pptx2.shapes.graphfrm import GraphicFrame
17
+ from pptx2.shapes.picture import Picture
18
+ from pptx2.util import Emu
19
+
20
+ if TYPE_CHECKING:
21
+ from pptx2.oxml.shapes.autoshape import CT_Shape
22
+
23
+
24
+ class _InheritsDimensions(object):
25
+ """
26
+ Mixin class that provides inherited dimension behavior. Specifically,
27
+ left, top, width, and height report the value from the layout placeholder
28
+ where they would have otherwise reported |None|. This behavior is
29
+ distinctive to placeholders. :meth:`_base_placeholder` must be overridden
30
+ by all subclasses to provide lookup of the appropriate base placeholder
31
+ to inherit from.
32
+ """
33
+
34
+ @property
35
+ def height(self):
36
+ """
37
+ The effective height of this placeholder shape; its directly-applied
38
+ height if it has one, otherwise the height of its parent layout
39
+ placeholder.
40
+ """
41
+ return self._effective_value("height")
42
+
43
+ @height.setter
44
+ def height(self, value):
45
+ # ``cy`` shares its parent element with the sibling dimension, so
46
+ # writing it materialises that sibling too -- at zero unless the
47
+ # inherited value is pinned down first. See ``_freeze_sibling``.
48
+ self._freeze_sibling("height")
49
+ self._element.cy = value
50
+
51
+ @property
52
+ def left(self):
53
+ """
54
+ The effective left of this placeholder shape; its directly-applied
55
+ left if it has one, otherwise the left of its parent layout
56
+ placeholder.
57
+ """
58
+ return self._effective_value("left")
59
+
60
+ @left.setter
61
+ def left(self, value):
62
+ # ``x`` shares its parent element with the sibling dimension, so
63
+ # writing it materialises that sibling too -- at zero unless the
64
+ # inherited value is pinned down first. See ``_freeze_sibling``.
65
+ self._freeze_sibling("left")
66
+ self._element.x = value
67
+
68
+ @property
69
+ def shape_type(self):
70
+ """
71
+ Member of :ref:`MsoShapeType` specifying the type of this shape.
72
+ Unconditionally ``MSO_SHAPE_TYPE.PLACEHOLDER`` in this case.
73
+ Read-only.
74
+ """
75
+ return MSO_SHAPE_TYPE.PLACEHOLDER
76
+
77
+ @property
78
+ def top(self):
79
+ """
80
+ The effective top of this placeholder shape; its directly-applied
81
+ top if it has one, otherwise the top of its parent layout
82
+ placeholder.
83
+ """
84
+ return self._effective_value("top")
85
+
86
+ @top.setter
87
+ def top(self, value):
88
+ # ``y`` shares its parent element with the sibling dimension, so
89
+ # writing it materialises that sibling too -- at zero unless the
90
+ # inherited value is pinned down first. See ``_freeze_sibling``.
91
+ self._freeze_sibling("top")
92
+ self._element.y = value
93
+
94
+ @property
95
+ def width(self):
96
+ """
97
+ The effective width of this placeholder shape; its directly-applied
98
+ width if it has one, otherwise the width of its parent layout
99
+ placeholder.
100
+ """
101
+ return self._effective_value("width")
102
+
103
+ @width.setter
104
+ def width(self, value):
105
+ # ``cx`` shares its parent element with the sibling dimension, so
106
+ # writing it materialises that sibling too -- at zero unless the
107
+ # inherited value is pinned down first. See ``_freeze_sibling``.
108
+ self._freeze_sibling("width")
109
+ self._element.cx = value
110
+
111
+ #: The dimension each setter must pin down before writing, because the
112
+ #: two share one XML element: ``left``/``top`` live in ``<a:off>`` and
113
+ #: ``width``/``height`` in ``<a:ext>``.
114
+ _SIBLING_DIMENSION = {
115
+ "left": "top",
116
+ "top": "left",
117
+ "width": "height",
118
+ "height": "width",
119
+ }
120
+
121
+ _ELEMENT_ATTR = {"left": "x", "top": "y", "width": "cx", "height": "cy"}
122
+
123
+ def _freeze_sibling(self, attr_name):
124
+ """Write the inherited sibling of *attr_name* before it is clobbered.
125
+
126
+ A placeholder with no directly-applied geometry has neither
127
+ ``<a:off>`` nor ``<a:ext>``; both dimensions come from the layout.
128
+ Setting just one of them creates the shared element, and the
129
+ dimension the caller did *not* set is written as ``0`` -- so
130
+ ``body.width = Inches(4)`` used to silently collapse the height to
131
+ nothing and make the shape invisible, with no warning.
132
+
133
+ Copying the currently-inherited sibling across first makes a
134
+ single-dimension assignment mean what it reads as: change this one,
135
+ leave the other where the layout put it. A sibling that is already
136
+ directly applied is left alone, and so is a placeholder that
137
+ inherits nothing.
138
+ """
139
+ sibling = self._SIBLING_DIMENSION[attr_name]
140
+ directly_applied = getattr(super(_InheritsDimensions, self), sibling)
141
+ if directly_applied is not None:
142
+ return
143
+ try:
144
+ inherited = self._inherited_value(sibling)
145
+ except Exception:
146
+ # Resolving the base placeholder needs a slide part and a
147
+ # layout to walk up to. A placeholder built outside that
148
+ # graph has nothing to inherit, and this is a best-effort
149
+ # improvement -- it must never turn an assignment that used
150
+ # to work into one that raises.
151
+ return
152
+ if inherited is None:
153
+ return
154
+ setattr(self._element, self._ELEMENT_ATTR[sibling], inherited)
155
+
156
+ @property
157
+ def _base_placeholder(self):
158
+ """
159
+ Return the layout or master placeholder shape this placeholder
160
+ inherits from. Not to be confused with an instance of
161
+ |BasePlaceholder| (necessarily).
162
+ """
163
+ raise NotImplementedError("Must be implemented by all subclasses.")
164
+
165
+ def _effective_value(self, attr_name):
166
+ """
167
+ The effective value of *attr_name* on this placeholder shape; its
168
+ directly-applied value if it has one, otherwise the value on the
169
+ layout placeholder it inherits from.
170
+ """
171
+ directly_applied_value = getattr(super(_InheritsDimensions, self), attr_name)
172
+ if directly_applied_value is not None:
173
+ return directly_applied_value
174
+ return self._inherited_value(attr_name)
175
+
176
+ def _inherited_value(self, attr_name):
177
+ """
178
+ Return the attribute value, e.g. 'width' of the base placeholder this
179
+ placeholder inherits from.
180
+ """
181
+ base_placeholder = self._base_placeholder
182
+ if base_placeholder is None:
183
+ return None
184
+ inherited_value = getattr(base_placeholder, attr_name)
185
+ return inherited_value
186
+
187
+
188
+ class _BaseSlidePlaceholder(_InheritsDimensions, Shape):
189
+ """Base class for placeholders on slides.
190
+
191
+ Provides common behaviors such as inherited dimensions.
192
+ """
193
+
194
+ @property
195
+ def is_placeholder(self):
196
+ """
197
+ Boolean indicating whether this shape is a placeholder.
198
+ Unconditionally |True| in this case.
199
+ """
200
+ return True
201
+
202
+ @property
203
+ def shape_type(self):
204
+ """
205
+ Member of :ref:`MsoShapeType` specifying the type of this shape.
206
+ Unconditionally ``MSO_SHAPE_TYPE.PLACEHOLDER`` in this case.
207
+ Read-only.
208
+ """
209
+ return MSO_SHAPE_TYPE.PLACEHOLDER
210
+
211
+ @property
212
+ def _base_placeholder(self):
213
+ """
214
+ Return the layout placeholder this slide placeholder inherits from.
215
+ Not to be confused with an instance of |BasePlaceholder|
216
+ (necessarily).
217
+ """
218
+ layout, idx = self.part.slide_layout, self._element.ph_idx
219
+ return layout.placeholders.get(idx=idx)
220
+
221
+ def _replace_placeholder_with(self, element):
222
+ """
223
+ Substitute *element* for this placeholder element in the shapetree.
224
+ This placeholder's `._element` attribute is set to |None| and its
225
+ original element is free for garbage collection. Any attribute access
226
+ (including a method call) on this placeholder after this call raises
227
+ |AttributeError|.
228
+ """
229
+ element._nvXxPr.nvPr._insert_ph(self._element.ph)
230
+ self._element.addprevious(element)
231
+ self._element.getparent().remove(self._element)
232
+ self._element = None
233
+
234
+
235
+ class BasePlaceholder(Shape):
236
+ """
237
+ NOTE: This class is deprecated and will be removed from a future release
238
+ along with the properties *idx*, *orient*, *ph_type*, and *sz*. The *idx*
239
+ property will be available via the .placeholder_format property. The
240
+ others will be accessed directly from the oxml layer as they are only
241
+ used for internal purposes.
242
+
243
+ Base class for placeholder subclasses that differentiate the varying
244
+ behaviors of placeholders on a master, layout, and slide.
245
+ """
246
+
247
+ @property
248
+ def idx(self):
249
+ """
250
+ Integer placeholder 'idx' attribute, e.g. 0
251
+ """
252
+ return self._sp.ph_idx
253
+
254
+ @property
255
+ def orient(self):
256
+ """
257
+ Placeholder orientation, e.g. ST_Direction.HORZ
258
+ """
259
+ return self._sp.ph_orient
260
+
261
+ @property
262
+ def ph_type(self):
263
+ """
264
+ Placeholder type, e.g. PP_PLACEHOLDER.CENTER_TITLE
265
+ """
266
+ return self._sp.ph_type
267
+
268
+ @property
269
+ def sz(self):
270
+ """
271
+ Placeholder 'sz' attribute, e.g. ST_PlaceholderSize.FULL
272
+ """
273
+ return self._sp.ph_sz
274
+
275
+
276
+ class LayoutPlaceholder(_InheritsDimensions, Shape):
277
+ """Placeholder shape on a slide layout.
278
+
279
+ Provides differentiated behavior for slide layout placeholders, in particular, inheriting
280
+ shape properties from the master placeholder having the same type, when a matching one exists.
281
+ """
282
+
283
+ element: CT_Shape # pyright: ignore[reportIncompatibleMethodOverride]
284
+
285
+ @property
286
+ def _base_placeholder(self):
287
+ """
288
+ Return the master placeholder this layout placeholder inherits from.
289
+ """
290
+ base_ph_type = {
291
+ PP_PLACEHOLDER.BODY: PP_PLACEHOLDER.BODY,
292
+ PP_PLACEHOLDER.CHART: PP_PLACEHOLDER.BODY,
293
+ PP_PLACEHOLDER.BITMAP: PP_PLACEHOLDER.BODY,
294
+ PP_PLACEHOLDER.CENTER_TITLE: PP_PLACEHOLDER.TITLE,
295
+ PP_PLACEHOLDER.ORG_CHART: PP_PLACEHOLDER.BODY,
296
+ PP_PLACEHOLDER.DATE: PP_PLACEHOLDER.DATE,
297
+ PP_PLACEHOLDER.FOOTER: PP_PLACEHOLDER.FOOTER,
298
+ PP_PLACEHOLDER.MEDIA_CLIP: PP_PLACEHOLDER.BODY,
299
+ PP_PLACEHOLDER.OBJECT: PP_PLACEHOLDER.BODY,
300
+ PP_PLACEHOLDER.PICTURE: PP_PLACEHOLDER.BODY,
301
+ PP_PLACEHOLDER.SLIDE_NUMBER: PP_PLACEHOLDER.SLIDE_NUMBER,
302
+ PP_PLACEHOLDER.SUBTITLE: PP_PLACEHOLDER.BODY,
303
+ PP_PLACEHOLDER.TABLE: PP_PLACEHOLDER.BODY,
304
+ PP_PLACEHOLDER.TITLE: PP_PLACEHOLDER.TITLE,
305
+ }[self._element.ph_type]
306
+ slide_master = self.part.slide_master
307
+ return slide_master.placeholders.get(base_ph_type, None)
308
+
309
+
310
+ class MasterPlaceholder(BasePlaceholder):
311
+ """Placeholder shape on a slide master."""
312
+
313
+ element: CT_Shape # pyright: ignore[reportIncompatibleMethodOverride]
314
+
315
+
316
+ class NotesSlidePlaceholder(_InheritsDimensions, Shape):
317
+ """
318
+ Placeholder shape on a notes slide. Inherits shape properties from the
319
+ placeholder on the notes master that has the same type (e.g. 'body').
320
+ """
321
+
322
+ @property
323
+ def _base_placeholder(self):
324
+ """
325
+ Return the notes master placeholder this notes slide placeholder
326
+ inherits from, or |None| if no placeholder of the matching type is
327
+ present.
328
+ """
329
+ notes_master = self.part.notes_master
330
+ ph_type = self.element.ph_type
331
+ return notes_master.placeholders.get(ph_type=ph_type)
332
+
333
+
334
+ class SlidePlaceholder(_BaseSlidePlaceholder):
335
+ """
336
+ Placeholder shape on a slide. Inherits shape properties from its
337
+ corresponding slide layout placeholder.
338
+ """
339
+
340
+
341
+ class ChartPlaceholder(_BaseSlidePlaceholder):
342
+ """Placeholder shape that can only accept a chart."""
343
+
344
+ def insert_chart(self, chart_type, chart_data):
345
+ """
346
+ Return a |PlaceholderGraphicFrame| object containing a new chart of
347
+ *chart_type* depicting *chart_data* and having the same position and
348
+ size as this placeholder. *chart_type* is one of the
349
+ :ref:`XlChartType` enumeration values. *chart_data* is a |ChartData|
350
+ object populated with the categories and series values for the chart.
351
+ Note that the new |Chart| object is not returned directly. The chart
352
+ object may be accessed using the
353
+ :attr:`~.PlaceholderGraphicFrame.chart` property of the returned
354
+ |PlaceholderGraphicFrame| object.
355
+ """
356
+ rId = self.part.add_chart_part(chart_type, chart_data)
357
+ graphicFrame = self._new_chart_graphicFrame(
358
+ rId, self.left, self.top, self.width, self.height
359
+ )
360
+ self._replace_placeholder_with(graphicFrame)
361
+ return PlaceholderGraphicFrame(graphicFrame, self._parent)
362
+
363
+ def _new_chart_graphicFrame(self, rId, x, y, cx, cy):
364
+ """
365
+ Return a newly created `p:graphicFrame` element having the specified
366
+ position and size and containing the chart identified by *rId*.
367
+ """
368
+ id_, name = self.shape_id, self.name
369
+ return CT_GraphicalObjectFrame.new_chart_graphicFrame(id_, name, rId, x, y, cx, cy)
370
+
371
+
372
+ class PicturePlaceholder(_BaseSlidePlaceholder):
373
+ """Placeholder shape that can only accept a picture."""
374
+
375
+ def insert_picture(self, image_file):
376
+ """Return a |PlaceholderPicture| object depicting the image in `image_file`.
377
+
378
+ `image_file` may be either a path (string) or a file-like object. The image is
379
+ cropped to fill the entire space of the placeholder. A |PlaceholderPicture|
380
+ object has all the properties and methods of a |Picture| shape except that the
381
+ value of its :attr:`~._BaseSlidePlaceholder.shape_type` property is
382
+ `MSO_SHAPE_TYPE.PLACEHOLDER` instead of `MSO_SHAPE_TYPE.PICTURE`.
383
+ """
384
+ pic = self._new_placeholder_pic(image_file)
385
+ self._replace_placeholder_with(pic)
386
+ return PlaceholderPicture(pic, self._parent)
387
+
388
+ def _new_placeholder_pic(self, image_file):
389
+ """
390
+ Return a new `p:pic` element depicting the image in *image_file*,
391
+ suitable for use as a placeholder. In particular this means not
392
+ having an `a:xfrm` element, allowing its extents to be inherited from
393
+ its layout placeholder.
394
+ """
395
+ rId, desc, image_size = self._get_or_add_image(image_file)
396
+ shape_id, name = self.shape_id, self.name
397
+ pic = CT_Picture.new_ph_pic(shape_id, name, desc, rId)
398
+ pic.crop_to_fit(image_size, (self.width, self.height))
399
+ return pic
400
+
401
+ def _get_or_add_image(self, image_file):
402
+ """
403
+ Return an (rId, description, image_size) 3-tuple identifying the
404
+ related image part containing *image_file* and describing the image.
405
+ """
406
+ image_part, rId = self.part.get_or_add_image_part(image_file)
407
+ desc, image_size = image_part.desc, image_part._px_size
408
+ return rId, desc, image_size
409
+
410
+
411
+ class PlaceholderGraphicFrame(GraphicFrame):
412
+ """
413
+ Placeholder shape populated with a table, chart, or smart art.
414
+ """
415
+
416
+ @property
417
+ def is_placeholder(self):
418
+ """
419
+ Boolean indicating whether this shape is a placeholder.
420
+ Unconditionally |True| in this case.
421
+ """
422
+ return True
423
+
424
+
425
+ class PlaceholderPicture(_InheritsDimensions, Picture):
426
+ """
427
+ Placeholder shape populated with a picture.
428
+ """
429
+
430
+ @property
431
+ def _base_placeholder(self):
432
+ """
433
+ Return the layout placeholder this picture placeholder inherits from.
434
+ """
435
+ layout, idx = self.part.slide_layout, self._element.ph_idx
436
+ return layout.placeholders.get(idx=idx)
437
+
438
+
439
+ class TablePlaceholder(_BaseSlidePlaceholder):
440
+ """Placeholder shape that can only accept a table."""
441
+
442
+ def insert_table(self, rows, cols):
443
+ """Return |PlaceholderGraphicFrame| object containing a `rows` by `cols` table.
444
+
445
+ The position and width of the table are those of the placeholder and its height
446
+ is proportional to the number of rows. A |PlaceholderGraphicFrame| object has
447
+ all the properties and methods of a |GraphicFrame| shape except that the value
448
+ of its :attr:`~._BaseSlidePlaceholder.shape_type` property is unconditionally
449
+ `MSO_SHAPE_TYPE.PLACEHOLDER`. Note that the return value is not the new table
450
+ but rather *contains* the new table. The table can be accessed using the
451
+ :attr:`~.PlaceholderGraphicFrame.table` property of the returned
452
+ |PlaceholderGraphicFrame| object.
453
+ """
454
+ graphicFrame = self._new_placeholder_table(rows, cols)
455
+ self._replace_placeholder_with(graphicFrame)
456
+ return PlaceholderGraphicFrame(graphicFrame, self._parent)
457
+
458
+ def _new_placeholder_table(self, rows, cols):
459
+ """
460
+ Return a newly added `p:graphicFrame` element containing an empty
461
+ table with *rows* rows and *cols* columns, positioned at the location
462
+ of this placeholder and having its same width. The table's height is
463
+ determined by the number of rows.
464
+ """
465
+ shape_id, name, height = self.shape_id, self.name, Emu(rows * 370840)
466
+ return CT_GraphicalObjectFrame.new_table_graphicFrame(
467
+ shape_id, name, rows, cols, self.left, self.top, self.width, height
468
+ )