aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/pptx/oxml/slide.py
diff options
context:
space:
mode:
Diffstat (limited to '.venv/lib/python3.12/site-packages/pptx/oxml/slide.py')
-rw-r--r--.venv/lib/python3.12/site-packages/pptx/oxml/slide.py347
1 files changed, 347 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/pptx/oxml/slide.py b/.venv/lib/python3.12/site-packages/pptx/oxml/slide.py
new file mode 100644
index 00000000..37a9780f
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/pptx/oxml/slide.py
@@ -0,0 +1,347 @@
+"""Slide-related custom element classes, including those for masters."""
+
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Callable, cast
+
+from pptx.oxml import parse_from_template, parse_xml
+from pptx.oxml.dml.fill import CT_GradientFillProperties
+from pptx.oxml.ns import nsdecls
+from pptx.oxml.simpletypes import XsdString
+from pptx.oxml.xmlchemy import (
+ BaseOxmlElement,
+ Choice,
+ OneAndOnlyOne,
+ OptionalAttribute,
+ RequiredAttribute,
+ ZeroOrMore,
+ ZeroOrOne,
+ ZeroOrOneChoice,
+)
+
+if TYPE_CHECKING:
+ from pptx.oxml.shapes.groupshape import CT_GroupShape
+
+
+class _BaseSlideElement(BaseOxmlElement):
+ """Base class for the six slide types, providing common methods."""
+
+ cSld: CT_CommonSlideData
+
+ @property
+ def spTree(self) -> CT_GroupShape:
+ """Return required `p:cSld/p:spTree` grandchild."""
+ return self.cSld.spTree
+
+
+class CT_Background(BaseOxmlElement):
+ """`p:bg` element."""
+
+ _insert_bgPr: Callable[[CT_BackgroundProperties], None]
+
+ # ---these two are actually a choice, not a sequence, but simpler for
+ # ---present purposes this way.
+ _tag_seq = ("p:bgPr", "p:bgRef")
+ bgPr: CT_BackgroundProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
+ "p:bgPr", successors=()
+ )
+ bgRef = ZeroOrOne("p:bgRef", successors=())
+ del _tag_seq
+
+ def add_noFill_bgPr(self):
+ """Return a new `p:bgPr` element with noFill properties."""
+ xml = "<p:bgPr %s>\n" " <a:noFill/>\n" " <a:effectLst/>\n" "</p:bgPr>" % nsdecls("a", "p")
+ bgPr = cast(CT_BackgroundProperties, parse_xml(xml))
+ self._insert_bgPr(bgPr)
+ return bgPr
+
+
+class CT_BackgroundProperties(BaseOxmlElement):
+ """`p:bgPr` element."""
+
+ _tag_seq = (
+ "a:noFill",
+ "a:solidFill",
+ "a:gradFill",
+ "a:blipFill",
+ "a:pattFill",
+ "a:grpFill",
+ "a:effectLst",
+ "a:effectDag",
+ "a:extLst",
+ )
+ eg_fillProperties = ZeroOrOneChoice(
+ (
+ Choice("a:noFill"),
+ Choice("a:solidFill"),
+ Choice("a:gradFill"),
+ Choice("a:blipFill"),
+ Choice("a:pattFill"),
+ Choice("a:grpFill"),
+ ),
+ successors=_tag_seq[6:],
+ )
+ del _tag_seq
+
+ def _new_gradFill(self):
+ """Override default to add default gradient subtree."""
+ return CT_GradientFillProperties.new_gradFill()
+
+
+class CT_CommonSlideData(BaseOxmlElement):
+ """`p:cSld` element."""
+
+ _remove_bg: Callable[[], None]
+ get_or_add_bg: Callable[[], CT_Background]
+
+ _tag_seq = ("p:bg", "p:spTree", "p:custDataLst", "p:controls", "p:extLst")
+ bg: CT_Background | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
+ "p:bg", successors=_tag_seq[1:]
+ )
+ spTree: CT_GroupShape = OneAndOnlyOne("p:spTree") # pyright: ignore[reportAssignmentType]
+ del _tag_seq
+ name: str = OptionalAttribute( # pyright: ignore[reportAssignmentType]
+ "name", XsdString, default=""
+ )
+
+ def get_or_add_bgPr(self) -> CT_BackgroundProperties:
+ """Return `p:bg/p:bgPr` grandchild.
+
+ If no such grandchild is present, any existing `p:bg` child is first removed and a new
+ default `p:bg` with noFill settings is added.
+ """
+ bg = self.bg
+ if bg is None or bg.bgPr is None:
+ bg = self._change_to_noFill_bg()
+ return cast(CT_BackgroundProperties, bg.bgPr)
+
+ def _change_to_noFill_bg(self) -> CT_Background:
+ """Establish a `p:bg` child with no-fill settings.
+
+ Any existing `p:bg` child is first removed.
+ """
+ self._remove_bg()
+ bg = self.get_or_add_bg()
+ bg.add_noFill_bgPr()
+ return bg
+
+
+class CT_NotesMaster(_BaseSlideElement):
+ """`p:notesMaster` element, root of a notes master part."""
+
+ _tag_seq = ("p:cSld", "p:clrMap", "p:hf", "p:notesStyle", "p:extLst")
+ cSld: CT_CommonSlideData = OneAndOnlyOne("p:cSld") # pyright: ignore[reportAssignmentType]
+ del _tag_seq
+
+ @classmethod
+ def new_default(cls) -> CT_NotesMaster:
+ """Return a new `p:notesMaster` element based on the built-in default template."""
+ return cast(CT_NotesMaster, parse_from_template("notesMaster"))
+
+
+class CT_NotesSlide(_BaseSlideElement):
+ """`p:notes` element, root of a notes slide part."""
+
+ _tag_seq = ("p:cSld", "p:clrMapOvr", "p:extLst")
+ cSld: CT_CommonSlideData = OneAndOnlyOne("p:cSld") # pyright: ignore[reportAssignmentType]
+ del _tag_seq
+
+ @classmethod
+ def new(cls) -> CT_NotesSlide:
+ """Return a new ``<p:notes>`` element based on the default template.
+
+ Note that the template does not include placeholders, which must be subsequently cloned
+ from the notes master.
+ """
+ return cast(CT_NotesSlide, parse_from_template("notes"))
+
+
+class CT_Slide(_BaseSlideElement):
+ """`p:sld` element, root element of a slide part (XML document)."""
+
+ _tag_seq = ("p:cSld", "p:clrMapOvr", "p:transition", "p:timing", "p:extLst")
+ cSld: CT_CommonSlideData = OneAndOnlyOne("p:cSld") # pyright: ignore[reportAssignmentType]
+ clrMapOvr = ZeroOrOne("p:clrMapOvr", successors=_tag_seq[2:])
+ timing = ZeroOrOne("p:timing", successors=_tag_seq[4:])
+ del _tag_seq
+
+ @classmethod
+ def new(cls) -> CT_Slide:
+ """Return new `p:sld` element configured as base slide shape."""
+ return cast(CT_Slide, parse_xml(cls._sld_xml()))
+
+ @property
+ def bg(self):
+ """Return `p:bg` grandchild or None if not present."""
+ return self.cSld.bg
+
+ def get_or_add_childTnLst(self):
+ """Return parent element for a new `p:video` child element.
+
+ The `p:video` element causes play controls to appear under a video
+ shape (pic shape containing video). There can be more than one video
+ shape on a slide, which causes the precondition to vary. It needs to
+ handle the case when there is no `p:sld/p:timing` element and when
+ that element already exists. If the case isn't simple, it just nukes
+ what's there and adds a fresh one. This could theoretically remove
+ desired existing timing information, but there isn't any evidence
+ available to me one way or the other, so I've taken the simple
+ approach.
+ """
+ childTnLst = self._childTnLst
+ if childTnLst is None:
+ childTnLst = self._add_childTnLst()
+ return childTnLst
+
+ def _add_childTnLst(self):
+ """Add `./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst` descendant.
+
+ Any existing `p:timing` child element is ruthlessly removed and
+ replaced.
+ """
+ self.remove(self.get_or_add_timing())
+ timing = parse_xml(self._childTnLst_timing_xml())
+ self._insert_timing(timing)
+ return timing.xpath("./p:tnLst/p:par/p:cTn/p:childTnLst")[0]
+
+ @property
+ def _childTnLst(self):
+ """Return `./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst` descendant.
+
+ Return None if that element is not present.
+ """
+ childTnLsts = self.xpath("./p:timing/p:tnLst/p:par/p:cTn/p:childTnLst")
+ if not childTnLsts:
+ return None
+ return childTnLsts[0]
+
+ @staticmethod
+ def _childTnLst_timing_xml():
+ return (
+ "<p:timing %s>\n"
+ " <p:tnLst>\n"
+ " <p:par>\n"
+ ' <p:cTn id="1" dur="indefinite" restart="never" nodeType="'
+ 'tmRoot">\n'
+ " <p:childTnLst/>\n"
+ " </p:cTn>\n"
+ " </p:par>\n"
+ " </p:tnLst>\n"
+ "</p:timing>" % nsdecls("p")
+ )
+
+ @staticmethod
+ def _sld_xml():
+ return (
+ "<p:sld %s>\n"
+ " <p:cSld>\n"
+ " <p:spTree>\n"
+ " <p:nvGrpSpPr>\n"
+ ' <p:cNvPr id="1" name=""/>\n'
+ " <p:cNvGrpSpPr/>\n"
+ " <p:nvPr/>\n"
+ " </p:nvGrpSpPr>\n"
+ " <p:grpSpPr/>\n"
+ " </p:spTree>\n"
+ " </p:cSld>\n"
+ " <p:clrMapOvr>\n"
+ " <a:masterClrMapping/>\n"
+ " </p:clrMapOvr>\n"
+ "</p:sld>" % nsdecls("a", "p", "r")
+ )
+
+
+class CT_SlideLayout(_BaseSlideElement):
+ """`p:sldLayout` element, root of a slide layout part."""
+
+ _tag_seq = ("p:cSld", "p:clrMapOvr", "p:transition", "p:timing", "p:hf", "p:extLst")
+ cSld: CT_CommonSlideData = OneAndOnlyOne("p:cSld") # pyright: ignore[reportAssignmentType]
+ del _tag_seq
+
+
+class CT_SlideLayoutIdList(BaseOxmlElement):
+ """`p:sldLayoutIdLst` element, child of `p:sldMaster`.
+
+ Contains references to the slide layouts that inherit from the slide master.
+ """
+
+ sldLayoutId_lst: list[CT_SlideLayoutIdListEntry]
+
+ sldLayoutId = ZeroOrMore("p:sldLayoutId")
+
+
+class CT_SlideLayoutIdListEntry(BaseOxmlElement):
+ """`p:sldLayoutId` element, child of `p:sldLayoutIdLst`.
+
+ Contains a reference to a slide layout.
+ """
+
+ rId: str = RequiredAttribute("r:id", XsdString) # pyright: ignore[reportAssignmentType]
+
+
+class CT_SlideMaster(_BaseSlideElement):
+ """`p:sldMaster` element, root of a slide master part."""
+
+ get_or_add_sldLayoutIdLst: Callable[[], CT_SlideLayoutIdList]
+
+ _tag_seq = (
+ "p:cSld",
+ "p:clrMap",
+ "p:sldLayoutIdLst",
+ "p:transition",
+ "p:timing",
+ "p:hf",
+ "p:txStyles",
+ "p:extLst",
+ )
+ cSld: CT_CommonSlideData = OneAndOnlyOne("p:cSld") # pyright: ignore[reportAssignmentType]
+ sldLayoutIdLst: CT_SlideLayoutIdList = ZeroOrOne( # pyright: ignore[reportAssignmentType]
+ "p:sldLayoutIdLst", successors=_tag_seq[3:]
+ )
+ del _tag_seq
+
+
+class CT_SlideTiming(BaseOxmlElement):
+ """`p:timing` element, specifying animations and timed behaviors."""
+
+ _tag_seq = ("p:tnLst", "p:bldLst", "p:extLst")
+ tnLst = ZeroOrOne("p:tnLst", successors=_tag_seq[1:])
+ del _tag_seq
+
+
+class CT_TimeNodeList(BaseOxmlElement):
+ """`p:tnLst` or `p:childTnList` element."""
+
+ def add_video(self, shape_id):
+ """Add a new `p:video` child element for movie having *shape_id*."""
+ video_xml = (
+ "<p:video %s>\n"
+ ' <p:cMediaNode vol="80000">\n'
+ ' <p:cTn id="%d" fill="hold" display="0">\n'
+ " <p:stCondLst>\n"
+ ' <p:cond delay="indefinite"/>\n'
+ " </p:stCondLst>\n"
+ " </p:cTn>\n"
+ " <p:tgtEl>\n"
+ ' <p:spTgt spid="%d"/>\n'
+ " </p:tgtEl>\n"
+ " </p:cMediaNode>\n"
+ "</p:video>\n" % (nsdecls("p"), self._next_cTn_id, shape_id)
+ )
+ video = parse_xml(video_xml)
+ self.append(video)
+
+ @property
+ def _next_cTn_id(self):
+ """Return the next available unique ID (int) for p:cTn element."""
+ cTn_id_strs = self.xpath("/p:sld/p:timing//p:cTn/@id")
+ ids = [int(id_str) for id_str in cTn_id_strs]
+ return max(ids) + 1
+
+
+class CT_TLMediaNodeVideo(BaseOxmlElement):
+ """`p:video` element, specifying video media details."""
+
+ _tag_seq = ("p:cMediaNode",)
+ cMediaNode = OneAndOnlyOne("p:cMediaNode")
+ del _tag_seq