|
4 | 4 |
|
5 | 5 | from typing import TYPE_CHECKING, Iterator, cast |
6 | 6 |
|
| 7 | +from pptx.dml.color import RGBColor |
7 | 8 | from pptx.dml.fill import FillFormat |
8 | 9 | from pptx.enum.shapes import PP_PLACEHOLDER |
| 10 | +from pptx.enum.text import PP_ALIGN |
9 | 11 | from pptx.opc.constants import RELATIONSHIP_TYPE as RT |
10 | 12 | from pptx.shapes.shapetree import ( |
11 | 13 | LayoutPlaceholders, |
|
18 | 20 | SlideShapes, |
19 | 21 | ) |
20 | 22 | from pptx.shared import ElementProxy, ParentedElementProxy, PartElementProxy |
21 | | -from pptx.util import lazyproperty |
| 23 | +from pptx.util import Inches, Length, Pt, lazyproperty |
22 | 24 |
|
23 | 25 | if TYPE_CHECKING: |
24 | 26 | from pptx.oxml.presentation import CT_SlideIdList, CT_SlideMasterIdList |
25 | 27 | from pptx.oxml.slide import ( |
26 | 28 | CT_CommonSlideData, |
| 29 | + CT_HandoutMaster, |
27 | 30 | CT_NotesMaster, |
28 | 31 | CT_NotesSlide, |
29 | 32 | CT_Slide, |
|
34 | 37 | from pptx.parts.presentation import PresentationPart |
35 | 38 | from pptx.parts.slide import SlideLayoutPart, SlideMasterPart, SlidePart |
36 | 39 | from pptx.presentation import Presentation |
| 40 | + from pptx.shapes.autoshape import Shape |
37 | 41 | from pptx.shapes.placeholder import LayoutPlaceholder, MasterPlaceholder, SlidePlaceholder |
38 | 42 | from pptx.shapes.shapetree import NotesSlidePlaceholder |
39 | 43 | from pptx.text.text import TextFrame |
@@ -97,7 +101,7 @@ def shapes(self): |
97 | 101 | class _HeaderFooterVisibility: |
98 | 102 | """Provides access to header/footer visibility settings on a slide template.""" |
99 | 103 |
|
100 | | - _element: CT_SlideLayout | CT_SlideMaster | CT_NotesMaster |
| 104 | + _element: CT_SlideLayout | CT_SlideMaster | CT_NotesMaster | CT_HandoutMaster |
101 | 105 |
|
102 | 106 | def _get_hf_visibility(self, attr_name: str) -> bool: |
103 | 107 | """Return effective `attr_name` value, defaulting to |True| when `<p:hf>` is absent.""" |
@@ -178,6 +182,15 @@ class NotesMaster(_HeaderFooterVisibility, _BaseMaster): |
178 | 182 | """ |
179 | 183 |
|
180 | 184 |
|
| 185 | +class HandoutMaster(_HeaderFooterVisibility, _BaseMaster): |
| 186 | + """Proxy for the handout master XML document. |
| 187 | +
|
| 188 | + Provides access to shapes and header/footer visibility settings when a deck already |
| 189 | + contains a handout master. Auto-create is deliberately deferred until a built-in |
| 190 | + `handoutMaster.xml` template ships in this fork. |
| 191 | + """ |
| 192 | + |
| 193 | + |
181 | 194 | class NotesSlide(_BaseSlide): |
182 | 195 | """Notes slide object. |
183 | 196 |
|
@@ -735,6 +748,39 @@ class SlideMaster(_HeaderFooterVisibility, _BaseMaster): |
735 | 748 |
|
736 | 749 | _element: CT_SlideMaster # pyright: ignore[reportIncompatibleVariableOverride] |
737 | 750 |
|
| 751 | + def add_text_watermark( |
| 752 | + self, |
| 753 | + text: str, |
| 754 | + *, |
| 755 | + font_size: Length = Pt(72), |
| 756 | + transparency: float = 0.7, |
| 757 | + font_name: str = "Calibri", |
| 758 | + ) -> Shape: |
| 759 | + """Add and return a centered watermark textbox on this slide master. |
| 760 | +
|
| 761 | + The watermark is a large mid-gray text box sized for the standard 10in x 7.5in |
| 762 | + slide canvas. `transparency` is applied to the run's solid font fill. |
| 763 | + """ |
| 764 | + slide_width = Inches(10) |
| 765 | + slide_height = Inches(7.5) |
| 766 | + textbox_width = Inches(6) |
| 767 | + textbox_height = Inches(1.5) |
| 768 | + # ---center a 6in x 1.5in textbox on a standard 10in x 7.5in slide--- |
| 769 | + left = (slide_width - textbox_width) // 2 |
| 770 | + top = (slide_height - textbox_height) // 2 |
| 771 | + |
| 772 | + shape = self.shapes.add_textbox(left, top, textbox_width, textbox_height) |
| 773 | + paragraph = shape.text_frame.paragraphs[0] |
| 774 | + paragraph.text = text |
| 775 | + paragraph.alignment = PP_ALIGN.CENTER |
| 776 | + run = paragraph.runs[0] |
| 777 | + run.font.name = font_name |
| 778 | + run.font.size = font_size |
| 779 | + run.font.fill.solid() |
| 780 | + run.font.fill.fore_color.rgb = RGBColor(0x80, 0x80, 0x80) |
| 781 | + run.font.fill.transparency = transparency |
| 782 | + return shape |
| 783 | + |
738 | 784 | @lazyproperty |
739 | 785 | def slide_layouts(self) -> SlideLayouts: |
740 | 786 | """|SlideLayouts| object providing access to this slide-master's layouts.""" |
|
0 commit comments