chore: import upstream snapshot with attribution
Publish SDK (PyPI) / publish (push) Has been cancelled
Publish SDK (npm) / publish (@aionui/officecli-sdk) (push) Has been cancelled
SDK smoke / smoke (windows-latest) (push) Has been cancelled
Publish SDK (npm) / publish (@officecli/officecli-sdk) (push) Has been cancelled
Publish SDK (npm) / publish (@officecli/sdk) (push) Has been cancelled
Publish SDK (npm) / publish (officecli-sdk) (push) Has been cancelled
SDK smoke / smoke (macos-latest) (push) Has been cancelled
SDK smoke / smoke (ubuntu-latest) (push) Has been cancelled
Skill parity / diff (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:09:29 +08:00
commit 8cb1f9f479
1189 changed files with 386007 additions and 0 deletions
@@ -0,0 +1,372 @@
# Advanced PPT Textbox Typography
This demo consists of three files that work together:
- **textboxes-advanced.sh** — Shell script that calls `officecli` commands to generate the deck.
- **textboxes-advanced.pptx** — The generated 6-slide deck (per-paragraph overrides, paragraph indents, per-paragraph styling, per-run typography, subscript/superscript aliases, textbox meta props).
- **textboxes-advanced.md** — This file. Covers per-paragraph and per-run overrides not shown in textboxes-basic.
## Regenerate
```bash
cd examples/ppt
bash textboxes/textboxes-advanced.sh
# → textboxes/textboxes-advanced.pptx
```
## Slides
### Slide 1 — Per-Paragraph Overrides (align / lineSpacing inside one textbox)
One textbox with five paragraphs; each paragraph overrides a different shape-level default.
```bash
officecli create textboxes-advanced.pptx
officecli open textboxes-advanced.pptx
officecli add textboxes-advanced.pptx / --type slide
LOREM='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia odio vitae vestibulum vestibulum.'
# Shape-level defaults: align=left, lineSpacing=1x
officecli add textboxes-advanced.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=13in --prop height=5.5in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[shape default: align=left, single-spaced] $LOREM"
# Each paragraph below overrides one property independently
officecli add textboxes-advanced.pptx '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=center] $LOREM" --prop align=center
officecli add textboxes-advanced.pptx '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=right] $LOREM" --prop align=right
officecli add textboxes-advanced.pptx '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=justify + lineSpacing=2x] $LOREM $LOREM" \
--prop align=justify --prop lineSpacing=2x
officecli add textboxes-advanced.pptx '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: lineSpacing=18pt fixed] $LOREM" \
--prop lineSpacing=18pt
```
**Features:** `--type paragraph` with `align` (center, right, justify) and `lineSpacing` (2x multiplier, 18pt fixed) override the shape defaults per-paragraph without affecting sibling paragraphs
---
### Slide 2 — Paragraph Indents (indent / marginLeft / marginRight)
Five textboxes showing every paragraph-level indent form: left-aligned indent, first-line indent, hanging indent, and right margin.
```bash
officecli add textboxes-advanced.pptx / --type slide
# Reference — no indent
officecli add textboxes-advanced.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=1.3in --prop width=13in --prop height=1in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[default: no indent] $LOREM $LOREM"
# marginLeft — whole paragraph body shifted right
officecli add textboxes-advanced.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=2.5in --prop width=13in --prop height=1in \
--prop fill=A8DADC --prop size=14 \
--prop text="[marginLeft=1in] $LOREM $LOREM" \
--prop marginLeft=1in
# indent — first-line indent only (subsequent lines flush left)
officecli add textboxes-advanced.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=3.7in --prop width=13in --prop height=1in \
--prop fill=F4A261 --prop size=14 \
--prop text="[indent=0.5in first-line] $LOREM $LOREM" \
--prop indent=0.5in
# Hanging indent — negative indent + positive marginLeft (first line extends further left)
officecli add textboxes-advanced.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=4.9in --prop width=13in --prop height=1in \
--prop fill=A8DADC --prop size=14 \
--prop text="[hanging: marginLeft=0.6in + indent=-0.5in] $LOREM $LOREM" \
--prop marginLeft=0.6in --prop indent=-0.5in
# marginRight — text column narrowed from the right
officecli add textboxes-advanced.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=6.1in --prop width=13in --prop height=1in \
--prop fill=F4A261 --prop size=14 \
--prop text="[marginRight=2in] $LOREM $LOREM" \
--prop marginRight=2in
```
**Features:** `marginLeft` (left paragraph indent; in, cm, pt), `indent` (first-line indent only; negative = hanging), `marginRight` (right margin; narrows from right edge), all at both textbox-creation time and as `--type paragraph` overrides
---
### Slide 3 — Per-Paragraph Styling (bold / italic / color / size / lang)
One textbox where each paragraph carries its own style without needing explicit runs.
```bash
officecli add textboxes-advanced.pptx / --type slide
# Shape default: 14pt black
officecli add textboxes-advanced.pptx '/slide[3]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=13in --prop height=5in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[shape default: 14pt black] Default paragraph styling."
# Each appended paragraph has a single style override — no runs needed
officecli add textboxes-advanced.pptx '/slide[3]/shape[2]' --type paragraph \
--prop text="[bold=true at paragraph level] Whole paragraph is bold." \
--prop bold=true
officecli add textboxes-advanced.pptx '/slide[3]/shape[2]' --type paragraph \
--prop text="[italic=true at paragraph level] Whole paragraph is italic." \
--prop italic=true
officecli add textboxes-advanced.pptx '/slide[3]/shape[2]' --type paragraph \
--prop text="[color=E63946 at paragraph level] Whole paragraph is red." \
--prop color=E63946
officecli add textboxes-advanced.pptx '/slide[3]/shape[2]' --type paragraph \
--prop text="[size=22 at paragraph level] Whole paragraph is 22pt." \
--prop size=22
officecli add textboxes-advanced.pptx '/slide[3]/shape[2]' --type paragraph \
--prop text="[lang=fr-FR at paragraph level] Lorem ipsum dolor sit amet." \
--prop lang=fr-FR --prop color=2A9D8F
```
**Features:** `--type paragraph` with `bold`, `italic`, `color`, `size`, `lang` (BCP-47) — all applied at the paragraph level without explicit runs, cheaper when the whole paragraph shares one style
---
### Slide 4 — Per-Run Typography (font / size / spacing / kern / lang)
Four textboxes built run-by-run, demonstrating font mixing, character spacing, kerning, and per-run language tagging inside one paragraph.
```bash
officecli add textboxes-advanced.pptx / --type slide
# Font mixing — four fonts at different sizes in one paragraph
officecli add textboxes-advanced.pptx '/slide[4]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=13in --prop height=1in \
--prop text="" --prop size=20
officecli add textboxes-advanced.pptx '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Mix "
officecli add textboxes-advanced.pptx '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Times " --prop font="Times New Roman" --prop size=24
officecli add textboxes-advanced.pptx '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Courier " --prop font="Courier New" --prop size=18
officecli add textboxes-advanced.pptx '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Georgia" --prop font="Georgia" --prop size=28 --prop bold=true
# Per-run character spacing (1/100 pt; negative = tighter, positive = looser)
officecli add textboxes-advanced.pptx '/slide[4]' --type textbox \
--prop x=0.5in --prop y=3in --prop width=13in --prop height=1in \
--prop text="" --prop size=20 --prop bold=true
officecli add textboxes-advanced.pptx '/slide[4]/shape[2]/p[1]' --type run \
--prop text="Normal "
officecli add textboxes-advanced.pptx '/slide[4]/shape[2]/p[1]' --type run \
--prop text="TIGHTENED " --prop spacing=-1 --prop color=E63946
officecli add textboxes-advanced.pptx '/slide[4]/shape[2]/p[1]' --type run \
--prop text="LOOSENED " --prop spacing=4 --prop color=2A9D8F
officecli add textboxes-advanced.pptx '/slide[4]/shape[2]/p[1]' --type run \
--prop text="EXPANDED" --prop spacing=8 --prop color=1D3557
# Per-run kerning threshold
officecli add textboxes-advanced.pptx '/slide[4]' --type textbox \
--prop x=0.5in --prop y=4.3in --prop width=13in --prop height=1in \
--prop text="" --prop size=20 --prop bold=true
officecli add textboxes-advanced.pptx '/slide[4]/shape[3]/p[1]' --type run \
--prop text="AV AT WA — kern=0 " --prop kern=0
officecli add textboxes-advanced.pptx '/slide[4]/shape[3]/p[1]' --type run \
--prop text="AV AT WA — kern=1" --prop kern=1 --prop color=E63946
# Per-run lang tag — drives spellcheck for each run independently
officecli add textboxes-advanced.pptx '/slide[4]' --type textbox \
--prop x=0.5in --prop y=5.6in --prop width=13in --prop height=1in \
--prop text="" --prop size=20
officecli add textboxes-advanced.pptx '/slide[4]/shape[4]/p[1]' --type run \
--prop text="English: color " --prop lang=en-US
officecli add textboxes-advanced.pptx '/slide[4]/shape[4]/p[1]' --type run \
--prop text="British: colour " --prop lang=en-GB --prop color=2A9D8F
officecli add textboxes-advanced.pptx '/slide[4]/shape[4]/p[1]' --type run \
--prop text="Français: couleur" --prop lang=fr-FR --prop color=E63946
```
**Features:** `font` (per-run typeface override), `size` (per-run pt), `spacing` (character spacing in 1/100 pt per run), `kern` (kerning threshold in 1/100 pt per run), `lang` (BCP-47 per-run spellcheck tag)
---
### Slide 5 — subscript / superscript Aliases vs canonical baseline=
`subscript=true` and `superscript=true` are convenience aliases. `baseline=` accepts any signed integer percent for custom vertical offset.
```bash
officecli add textboxes-advanced.pptx / --type slide
# Convenience aliases: subscript=true / superscript=true
officecli add textboxes-advanced.pptx '/slide[5]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=13in --prop height=1in \
--prop text="" --prop size=24
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="H"
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop subscript=true
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="SO"
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="4" --prop subscript=true
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text=" x"
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text=" + y"
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text=" = r"
officecli add textboxes-advanced.pptx '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
# Custom baseline percent — neither alias supports this
officecli add textboxes-advanced.pptx '/slide[5]' --type textbox \
--prop x=0.5in --prop y=3.7in --prop width=13in --prop height=1in \
--prop text="" --prop size=24
officecli add textboxes-advanced.pptx '/slide[5]/shape[3]/p[1]' --type run \
--prop text="Custom: "
officecli add textboxes-advanced.pptx '/slide[5]/shape[3]/p[1]' --type run \
--prop text="50%" --prop baseline=50 --prop color=E63946
officecli add textboxes-advanced.pptx '/slide[5]/shape[3]/p[1]' --type run \
--prop text=" higher / "
officecli add textboxes-advanced.pptx '/slide[5]/shape[3]/p[1]' --type run \
--prop text="-40%" --prop baseline=-40 --prop color=2A9D8F
officecli add textboxes-advanced.pptx '/slide[5]/shape[3]/p[1]' --type run \
--prop text=" lower"
# Per-run case: cap=small / cap=all / allCaps boolean alias
officecli add textboxes-advanced.pptx '/slide[5]' --type textbox \
--prop x=0.5in --prop y=5.9in --prop width=13in --prop height=0.8in \
--prop text="" --prop size=20 --prop bold=true
officecli add textboxes-advanced.pptx '/slide[5]/shape[4]/p[1]' --type run \
--prop text="default "
officecli add textboxes-advanced.pptx '/slide[5]/shape[4]/p[1]' --type run \
--prop text="small caps " --prop cap=small --prop color=2A9D8F
officecli add textboxes-advanced.pptx '/slide[5]/shape[4]/p[1]' --type run \
--prop text="ALL CAPS" --prop allCaps=true --prop color=E63946
```
**Features:** `subscript` (true — alias for baseline=sub, approx -25%), `superscript` (true — alias for baseline=super, approx +30%), `baseline` (signed integer %; arbitrary vertical offset), `cap` (small, all, none — per-run), `allCaps` / `smallCaps` (boolean aliases for cap=all / cap=small)
---
### Slide 6 — name / zorder / autoFit / direction / font.cs (Textbox-Specific)
Textbox identity, stacking, overflow, and complex-script typography.
```bash
officecli add textboxes-advanced.pptx / --type slide
# name= — stable @name address for later targeting
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=5in --prop height=1.5in \
--prop fill=F1FAEE --prop size=16 --prop bold=true \
--prop text="This is intro-box." \
--prop name="intro-box"
# zorder= — three overlapping textboxes with explicit stack depth
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=6in --prop y=1.2in --prop width=3in --prop height=2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="back (zorder=1)" \
--prop name="tb-back" --prop zorder=1
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=7in --prop y=1.6in --prop width=3in --prop height=2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="mid (zorder=2)" \
--prop name="tb-mid" --prop zorder=2
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=8in --prop y=2.0in --prop width=3in --prop height=2in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="front (zorder=3)" \
--prop name="tb-front" --prop zorder=3
# autoFit=normal — text shrinks to fit a fixed-height box
LONGTEXT='Vivamus lacinia odio vitae vestibulum vestibulum. Sed molestie augue sit amet leo consequat posuere.'
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=0.5in --prop y=3.6in --prop width=3in --prop height=1.2in \
--prop fill=FFE66D --prop size=16 --prop text="$LONGTEXT" \
--prop autoFit=normal
# direction=rtl + font.cs — RTL textbox with complex-script font
officecli add textboxes-advanced.pptx '/slide[6]' --type textbox \
--prop x=0.5in --prop y=5.6in --prop width=5in --prop height=1.2in \
--prop fill=A8DADC --prop size=20 --prop bold=true \
--prop text="مرحبا بالعالم — 2026" \
--prop direction=rtl --prop align=right \
--prop font.cs="Arabic Typesetting"
officecli close textboxes-advanced.pptx
officecli validate textboxes-advanced.pptx
```
**Features:** `name` (stable identifier; addressable as `/slide[N]/shape[@name=...]`), `zorder` (integer stack depth; aliases: z-order, order), `autoFit` (normal — text shrinks), `direction` (rtl; aliases: dir, rtl), `font.cs` (complex-script font slot), `align=right` (combined with rtl for correct Arabic/Hebrew layout)
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **Per-paragraph align override:** center, right, justify inside one textbox | 1 |
| **Per-paragraph lineSpacing override:** multiplier (2x) + fixed (18pt) | 1 |
| **marginLeft:** left indent (whole paragraph) | 2 |
| **indent:** first-line indent only (negative = hanging) | 2 |
| **marginRight:** narrow text from right edge | 2 |
| **Per-paragraph bold / italic:** whole paragraph style, no run needed | 3 |
| **Per-paragraph color / size:** whole paragraph style | 3 |
| **Per-paragraph lang:** BCP-47 spellcheck tag at paragraph scope | 3 |
| **Per-run font:** typeface override | 4 |
| **Per-run size:** point size override | 4 |
| **Per-run spacing:** character spacing in 1/100 pt | 4 |
| **Per-run kern:** kerning threshold in 1/100 pt | 4 |
| **Per-run lang:** BCP-47 spellcheck tag at run scope | 4 |
| **subscript / superscript:** boolean aliases for baseline=sub/super | 5 |
| **baseline:** signed integer % — arbitrary vertical offset | 5 |
| **Per-run cap:** small, all, none | 5 |
| **allCaps / smallCaps:** boolean aliases for cap=all/small | 5 |
| **name=:** stable @name addressing | 6 |
| **zorder=:** explicit stack depth | 6 |
| **autoFit=normal:** text shrinks to fit fixed box | 6 |
| **direction=rtl:** RTL paragraph direction in textbox | 6 |
| **font.cs:** complex-script font slot | 6 |
## Inspect the Generated File
```bash
# Check per-paragraph overrides in the slide 1 textbox
officecli get textboxes-advanced.pptx '/slide[1]/shape[2]'
officecli query textboxes-advanced.pptx '/slide[1]/shape[2]' paragraph
# Inspect indent values on slide 2
officecli get textboxes-advanced.pptx '/slide[2]/shape[3]'
officecli get textboxes-advanced.pptx '/slide[2]/shape[4]'
# Get per-run font data on slide 4 shape 1
officecli query textboxes-advanced.pptx '/slide[4]/shape[1]/p[1]' run
# Check baseline values on slide 5
officecli get textboxes-advanced.pptx '/slide[5]/shape[3]'
# Verify name + zorder on slide 6
officecli get textboxes-advanced.pptx '/slide[6]/shape[@name=tb-back]'
officecli get textboxes-advanced.pptx '/slide[6]/shape[@name=tb-front]'
```
Binary file not shown.
@@ -0,0 +1,334 @@
#!/usr/bin/env python3
"""
Advanced PPT textbox typography — per-paragraph and per-run overrides that the
basic example didn't reach. Each slide demonstrates a different scope:
slide 1 — per-paragraph align / lineSpacing override (shape default vs paragraph)
slide 2 — paragraph indents (indent / marginLeft / marginRight) for hanging-indent style
slide 3 — per-paragraph styling (bold / italic / color / size / lang) without runs
slide 4 — per-run typography (font / size / spacing / kern / lang) inside one paragraph
slide 5 — subscript / superscript convenience aliases vs canonical baseline=
slide 6 — name / zorder / autoFit / direction / font.cs (textbox-specific)
SDK twin of textboxes-advanced.sh (officecli CLI). Both produce an equivalent
textboxes-advanced.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape,
paragraph and run is shipped over the named pipe in a single `doc.batch(...)`
round-trip. Each item is the same `{"command","parent","type","props"}` dict
you'd put in an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 textboxes-advanced.py
"""
import os
import sys
# --- locate the SDK: prefer an installed `officecli-sdk`, else the in-repo copy
try:
import officecli # pip install officecli-sdk
except ImportError:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "..", "..", "sdk", "python"))
import officecli
FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "textboxes-advanced.pptx")
LOREM = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Vivamus lacinia odio vitae vestibulum vestibulum.")
LONGTEXT = ("Vivamus lacinia odio vitae vestibulum vestibulum. "
"Sed molestie augue sit amet leo consequat posuere.")
def add(parent, type_, **props):
"""One `add` item in batch-shape."""
return {"command": "add", "parent": parent, "type": type_, "props": props}
def slide():
return {"command": "add", "parent": "/", "type": "slide", "props": {}}
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = [
# =====================================================================
# Slide 1 — Per-paragraph overrides (align / lineSpacing in one textbox)
# =====================================================================
slide(),
add("/slide[1]", "textbox",
text="Per-paragraph overrides inside one textbox",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"),
# One textbox; shape-level defaults are align=left, lineSpacing=1x.
# Each paragraph overrides one of them.
add("/slide[1]", "textbox",
x="0.5in", y="1.2in", width="13in", height="5.5in",
fill="F1FAEE", size="14",
text=f"[shape default: align=left, single-spaced] {LOREM}"),
add("/slide[1]/shape[2]", "paragraph",
text=f"[paragraph override: align=center] {LOREM}", align="center"),
add("/slide[1]/shape[2]", "paragraph",
text=f"[paragraph override: align=right] {LOREM}", align="right"),
add("/slide[1]/shape[2]", "paragraph",
text=f"[paragraph override: align=justify + lineSpacing=2x] {LOREM} {LOREM}",
align="justify", lineSpacing="2x"),
add("/slide[1]/shape[2]", "paragraph",
text=f"[paragraph override: lineSpacing=18pt fixed] {LOREM}",
lineSpacing="18pt"),
# =====================================================================
# Slide 2 — Paragraph indents (indent / marginLeft / marginRight)
# =====================================================================
slide(),
add("/slide[2]", "textbox",
text="Paragraph indents — indent / marginLeft / marginRight",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"),
# Reference (no indent)
add("/slide[2]", "textbox",
x="0.5in", y="1.3in", width="13in", height="1in",
fill="F1FAEE", size="14",
text=f"[default: no indent] {LOREM} {LOREM}"),
# Left indent (whole paragraph shifted right)
add("/slide[2]", "textbox",
x="0.5in", y="2.5in", width="13in", height="1in",
fill="A8DADC", size="14",
text=f"[marginLeft=1in] {LOREM} {LOREM}",
marginLeft="1in"),
# First-line indent (only first line is shifted; rest flush left)
add("/slide[2]", "textbox",
x="0.5in", y="3.7in", width="13in", height="1in",
fill="F4A261", size="14",
text=f"[indent=0.5in first-line] {LOREM} {LOREM}",
indent="0.5in"),
# Hanging indent (negative indent + positive marginLeft pulls first line back left)
add("/slide[2]", "textbox",
x="0.5in", y="4.9in", width="13in", height="1in",
fill="A8DADC", size="14",
text=f"[hanging: marginLeft=0.6in + indent=-0.5in] {LOREM} {LOREM}",
marginLeft="0.6in", indent="-0.5in"),
# Right margin (text narrowed from the right)
add("/slide[2]", "textbox",
x="0.5in", y="6.1in", width="13in", height="1in",
fill="F4A261", size="14",
text=f"[marginRight=2in] {LOREM} {LOREM}",
marginRight="2in"),
# =====================================================================
# Slide 3 — Per-paragraph styling (bold / italic / color / size / lang)
# =====================================================================
slide(),
add("/slide[3]", "textbox",
text="Per-paragraph styling (no runs needed)",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"),
# One textbox; each paragraph carries its own bold/italic/color/size/lang.
add("/slide[3]", "textbox",
x="0.5in", y="1.2in", width="13in", height="5in",
fill="F1FAEE", size="14",
text="[shape default: 14pt black] Default paragraph styling."),
add("/slide[3]/shape[2]", "paragraph",
text="[bold=true at paragraph level] Whole paragraph is bold.",
bold="true"),
add("/slide[3]/shape[2]", "paragraph",
text="[italic=true at paragraph level] Whole paragraph is italic.",
italic="true"),
add("/slide[3]/shape[2]", "paragraph",
text="[color=E63946 at paragraph level] Whole paragraph is red.",
color="E63946"),
add("/slide[3]/shape[2]", "paragraph",
text="[size=22 at paragraph level] Whole paragraph is 22pt.",
size="22"),
add("/slide[3]/shape[2]", "paragraph",
text="[lang=fr-FR at paragraph level] Lorem ipsum dolor sit amet.",
lang="fr-FR", color="2A9D8F"),
# =====================================================================
# Slide 4 — Per-run typography (font / size / spacing / kern / lang)
# =====================================================================
slide(),
add("/slide[4]", "textbox",
text="Per-run typography in one paragraph",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"),
# Empty textbox we'll build run-by-run
add("/slide[4]", "textbox",
x="0.5in", y="1.5in", width="13in", height="1in",
text="", size="20"),
add("/slide[4]/shape[1]/p[1]", "run", text="Mix "),
add("/slide[4]/shape[1]/p[1]", "run",
text="Times ", font="Times New Roman", size="24"),
add("/slide[4]/shape[1]/p[1]", "run",
text="Courier ", font="Courier New", size="18"),
add("/slide[4]/shape[1]/p[1]", "run",
text="Georgia", font="Georgia", size="28", bold="true"),
# Per-run character spacing
add("/slide[4]", "textbox",
x="0.5in", y="3in", width="13in", height="1in",
text="", size="20", bold="true"),
add("/slide[4]/shape[2]/p[1]", "run", text="Normal "),
add("/slide[4]/shape[2]/p[1]", "run",
text="TIGHTENED ", spacing="-1", color="E63946"),
add("/slide[4]/shape[2]/p[1]", "run",
text="LOOSENED ", spacing="4", color="2A9D8F"),
add("/slide[4]/shape[2]/p[1]", "run",
text="EXPANDED", spacing="8", color="1D3557"),
# Per-run kerning threshold
add("/slide[4]", "textbox",
x="0.5in", y="4.3in", width="13in", height="1in",
text="", size="20", bold="true"),
add("/slide[4]/shape[3]/p[1]", "run",
text="AV AT WA — kern=0 ", kern="0"),
add("/slide[4]/shape[3]/p[1]", "run",
text="AV AT WA — kern=1", kern="1", color="E63946"),
# Per-run lang tag (drives spellcheck per-run)
add("/slide[4]", "textbox",
x="0.5in", y="5.6in", width="13in", height="1in",
text="", size="20"),
add("/slide[4]/shape[4]/p[1]", "run",
text="English: color ", lang="en-US"),
add("/slide[4]/shape[4]/p[1]", "run",
text="British: colour ", lang="en-GB", color="2A9D8F"),
add("/slide[4]/shape[4]/p[1]", "run",
text="Français: couleur", lang="fr-FR", color="E63946"),
# =====================================================================
# Slide 5 — subscript / superscript aliases vs canonical baseline=
# =====================================================================
slide(),
add("/slide[5]", "textbox",
text="subscript / superscript aliases",
size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"),
# Convenience form: subscript=true and superscript=true
add("/slide[5]", "textbox",
x="0.5in", y="1.5in", width="13in", height="1in",
text="", size="24"),
add("/slide[5]/shape[1]/p[1]", "run", text="H"),
add("/slide[5]/shape[1]/p[1]", "run", text="2", subscript="true"),
add("/slide[5]/shape[1]/p[1]", "run", text="SO"),
add("/slide[5]/shape[1]/p[1]", "run", text="4", subscript="true"),
add("/slide[5]/shape[1]/p[1]", "run", text=" x"),
add("/slide[5]/shape[1]/p[1]", "run", text="2", superscript="true"),
add("/slide[5]/shape[1]/p[1]", "run", text=" + y"),
add("/slide[5]/shape[1]/p[1]", "run", text="2", superscript="true"),
add("/slide[5]/shape[1]/p[1]", "run", text=" = r"),
add("/slide[5]/shape[1]/p[1]", "run", text="2", superscript="true"),
add("/slide[5]", "textbox",
text="subscript=true ≡ baseline=sub superscript=true ≡ baseline=super",
size="14", italic="true", color="666666",
x="0.5in", y="2.8in", width="13in", height="0.5in"),
# Custom baseline percent — neither alias gives you this
add("/slide[5]", "textbox",
x="0.5in", y="3.7in", width="13in", height="1in",
text="", size="24"),
add("/slide[5]/shape[3]/p[1]", "run", text="Custom: "),
add("/slide[5]/shape[3]/p[1]", "run",
text="50%", baseline="50", color="E63946"),
add("/slide[5]/shape[3]/p[1]", "run", text=" higher / "),
add("/slide[5]/shape[3]/p[1]", "run",
text="-40%", baseline="-40", color="2A9D8F"),
add("/slide[5]/shape[3]/p[1]", "run", text=" lower"),
add("/slide[5]", "textbox",
text=("baseline= accepts signed integer percent (super≡+30, sub≡-25 by "
"convention). Custom values give arbitrary vertical offset."),
size="14", italic="true", color="666666",
x="0.5in", y="5in", width="13in", height="0.6in"),
# Per-run case rendering — run Add accepts cap / allCaps / smallCaps
add("/slide[5]", "textbox",
x="0.5in", y="5.9in", width="13in", height="0.8in",
text="", size="20", bold="true"),
add("/slide[5]/shape[4]/p[1]", "run", text="default "),
add("/slide[5]/shape[4]/p[1]", "run",
text="small caps ", cap="small", color="2A9D8F"),
add("/slide[5]/shape[4]/p[1]", "run",
text="ALL CAPS", allCaps="true", color="E63946"),
add("/slide[5]", "textbox",
text="Per-run cap=small / cap=all / cap=none, plus allCaps / smallCaps boolean aliases.",
size="12", italic="true", color="666666",
x="0.5in", y="6.8in", width="13in", height="0.5in"),
# =====================================================================
# Slide 6 — name / zorder / autoFit / direction / font.cs
# =====================================================================
slide(),
add("/slide[6]", "textbox",
text="name / zorder / autoFit / direction / font.cs",
size="28", bold="true",
x="0.5in", y="0.3in", width="13in", height="0.6in"),
# name= — label the textbox so it can be re-addressed by @name later
add("/slide[6]", "textbox",
x="0.5in", y="1.2in", width="5in", height="1.5in",
fill="F1FAEE", size="16", bold="true",
text="This is intro-box.",
name="intro-box"),
add("/slide[6]", "textbox",
text='name="intro-box" → addressable as /slide[6]/shape[@name=intro-box]',
size="12", italic="true", color="666666",
x="0.5in", y="2.8in", width="5in", height="0.5in"),
# zorder= — three overlapping textboxes with explicit stack order
add("/slide[6]", "textbox",
x="6in", y="1.2in", width="3in", height="2in",
fill="4472C4", color="FFFFFF", bold="true", size="16",
text="back (zorder=1)",
name="tb-back", zorder="1"),
add("/slide[6]", "textbox",
x="7in", y="1.6in", width="3in", height="2in",
fill="E63946", color="FFFFFF", bold="true", size="16",
text="mid (zorder=2)",
name="tb-mid", zorder="2"),
add("/slide[6]", "textbox",
x="8in", y="2.0in", width="3in", height="2in",
fill="2A9D8F", color="FFFFFF", bold="true", size="16",
text="front (zorder=3)",
name="tb-front", zorder="3"),
add("/slide[6]", "textbox",
text="zorder= controls stack depth; aliases: z-order, order.",
size="12", italic="true", color="666666",
x="6in", y="4.2in", width="5in", height="0.5in"),
# autoFit= — overflow behavior for textbox (same as shape)
add("/slide[6]", "textbox",
x="0.5in", y="3.6in", width="3in", height="1.2in",
fill="FFE66D", size="16", text=LONGTEXT,
autoFit="normal"),
add("/slide[6]", "textbox",
text="autoFit=normal (shrinks text to fit)",
size="12", italic="true", color="666666",
x="0.5in", y="4.9in", width="3in", height="0.5in"),
# direction=rtl — paragraph flows right-to-left inside a textbox
add("/slide[6]", "textbox",
x="0.5in", y="5.6in", width="5in", height="1.2in",
fill="A8DADC", size="20", bold="true",
text="مرحبا بالعالم — 2026",
direction="rtl", align="right",
**{"font.cs": "Arabic Typesetting"}),
add("/slide[6]", "textbox",
text='direction=rtl + font.cs="Arabic Typesetting" (complex-script slot)',
size="12", italic="true", color="666666",
x="0.5in", y="6.9in", width="5in", height="0.5in"),
]
doc.batch(items)
print(f" added {len(items)} slides/shapes/paragraphs/runs")
doc.send({"command": "save"})
print(f"Generated: {FILE}")
+330
View File
@@ -0,0 +1,330 @@
#!/bin/bash
# Advanced PPT textbox typography — per-paragraph and per-run overrides that the
# basic example didn't reach. Each slide demonstrates a different scope:
# slide 1 — per-paragraph align / lineSpacing override (shape default vs paragraph)
# slide 2 — paragraph indents (indent / marginLeft / marginRight) for hanging-indent style
# slide 3 — per-paragraph styling (bold / italic / color / size / lang) without runs
# slide 4 — per-run typography (font / size / spacing / kern / lang) inside one paragraph
# slide 5 — subscript / superscript convenience aliases vs canonical baseline=
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
DIR="$(dirname "$0")"
PPTX="$DIR/textboxes-advanced.pptx"
rm -f "$PPTX"
officecli create "$PPTX"
officecli open "$PPTX"
LOREM='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia odio vitae vestibulum vestibulum.'
# ─────────────────────────────────────────────────────────────────────────────
# Slide 1 — Per-paragraph overrides (align / lineSpacing inside one textbox)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop text="Per-paragraph overrides inside one textbox" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# One textbox; shape-level defaults are align=left, lineSpacing=1x.
# Each paragraph overrides one of them.
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=13in --prop height=5.5in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[shape default: align=left, single-spaced] $LOREM"
officecli add "$PPTX" '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=center] $LOREM" --prop align=center
officecli add "$PPTX" '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=right] $LOREM" --prop align=right
officecli add "$PPTX" '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: align=justify + lineSpacing=2x] $LOREM $LOREM" \
--prop align=justify --prop lineSpacing=2x
officecli add "$PPTX" '/slide[1]/shape[2]' --type paragraph \
--prop text="[paragraph override: lineSpacing=18pt fixed] $LOREM" \
--prop lineSpacing=18pt
# ─────────────────────────────────────────────────────────────────────────────
# Slide 2 — Paragraph indents (indent / marginLeft / marginRight)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop text="Paragraph indents — indent / marginLeft / marginRight" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Reference (no indent)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=1.3in --prop width=13in --prop height=1in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[default: no indent] $LOREM $LOREM"
# Left indent (whole paragraph shifted right)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=2.5in --prop width=13in --prop height=1in \
--prop fill=A8DADC --prop size=14 \
--prop text="[marginLeft=1in] $LOREM $LOREM" \
--prop marginLeft=1in
# First-line indent (only first line is shifted; rest flush left)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=3.7in --prop width=13in --prop height=1in \
--prop fill=F4A261 --prop size=14 \
--prop text="[indent=0.5in first-line] $LOREM $LOREM" \
--prop indent=0.5in
# Hanging indent (negative indent + positive marginLeft pulls first line back left)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=4.9in --prop width=13in --prop height=1in \
--prop fill=A8DADC --prop size=14 \
--prop text="[hanging: marginLeft=0.6in + indent=-0.5in] $LOREM $LOREM" \
--prop marginLeft=0.6in --prop indent=-0.5in
# Right margin (text narrowed from the right)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=6.1in --prop width=13in --prop height=1in \
--prop fill=F4A261 --prop size=14 \
--prop text="[marginRight=2in] $LOREM $LOREM" \
--prop marginRight=2in
# ─────────────────────────────────────────────────────────────────────────────
# Slide 3 — Per-paragraph styling (bold / italic / color / size / lang)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop text="Per-paragraph styling (no runs needed)" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# One textbox; each paragraph carries its own bold/italic/color/size/lang.
# This is cheaper than adding a run when the whole paragraph shares one style.
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=13in --prop height=5in \
--prop fill=F1FAEE --prop size=14 \
--prop text="[shape default: 14pt black] Default paragraph styling."
officecli add "$PPTX" '/slide[3]/shape[2]' --type paragraph \
--prop text="[bold=true at paragraph level] Whole paragraph is bold." \
--prop bold=true
officecli add "$PPTX" '/slide[3]/shape[2]' --type paragraph \
--prop text="[italic=true at paragraph level] Whole paragraph is italic." \
--prop italic=true
officecli add "$PPTX" '/slide[3]/shape[2]' --type paragraph \
--prop text="[color=E63946 at paragraph level] Whole paragraph is red." \
--prop color=E63946
officecli add "$PPTX" '/slide[3]/shape[2]' --type paragraph \
--prop text="[size=22 at paragraph level] Whole paragraph is 22pt." \
--prop size=22
officecli add "$PPTX" '/slide[3]/shape[2]' --type paragraph \
--prop text="[lang=fr-FR at paragraph level] Lorem ipsum dolor sit amet." \
--prop lang=fr-FR --prop color=2A9D8F
# ─────────────────────────────────────────────────────────────────────────────
# Slide 4 — Per-run typography (font / size / spacing / kern / lang in one paragraph)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="Per-run typography in one paragraph" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Empty textbox we'll build run-by-run
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=13in --prop height=1in \
--prop text="" --prop size=20
officecli add "$PPTX" '/slide[4]/shape[1]/p[1]' --type run --prop text="Mix "
officecli add "$PPTX" '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Times " --prop font="Times New Roman" --prop size=24
officecli add "$PPTX" '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Courier " --prop font="Courier New" --prop size=18
officecli add "$PPTX" '/slide[4]/shape[1]/p[1]' --type run \
--prop text="Georgia" --prop font="Georgia" --prop size=28 --prop bold=true
# Per-run character spacing
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=3in --prop width=13in --prop height=1in \
--prop text="" --prop size=20 --prop bold=true
officecli add "$PPTX" '/slide[4]/shape[2]/p[1]' --type run --prop text="Normal "
officecli add "$PPTX" '/slide[4]/shape[2]/p[1]' --type run \
--prop text="TIGHTENED " --prop spacing=-1 --prop color=E63946
officecli add "$PPTX" '/slide[4]/shape[2]/p[1]' --type run \
--prop text="LOOSENED " --prop spacing=4 --prop color=2A9D8F
officecli add "$PPTX" '/slide[4]/shape[2]/p[1]' --type run \
--prop text="EXPANDED" --prop spacing=8 --prop color=1D3557
# Per-run kerning threshold
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=4.3in --prop width=13in --prop height=1in \
--prop text="" --prop size=20 --prop bold=true
officecli add "$PPTX" '/slide[4]/shape[3]/p[1]' --type run \
--prop text="AV AT WA — kern=0 " --prop kern=0
officecli add "$PPTX" '/slide[4]/shape[3]/p[1]' --type run \
--prop text="AV AT WA — kern=1" --prop kern=1 --prop color=E63946
# Per-run lang tag (drives spellcheck per-run)
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=5.6in --prop width=13in --prop height=1in \
--prop text="" --prop size=20
officecli add "$PPTX" '/slide[4]/shape[4]/p[1]' --type run \
--prop text="English: color " --prop lang=en-US
officecli add "$PPTX" '/slide[4]/shape[4]/p[1]' --type run \
--prop text="British: colour " --prop lang=en-GB --prop color=2A9D8F
officecli add "$PPTX" '/slide[4]/shape[4]/p[1]' --type run \
--prop text="Français: couleur" --prop lang=fr-FR --prop color=E63946
# ─────────────────────────────────────────────────────────────────────────────
# Slide 5 — subscript / superscript aliases vs canonical baseline=
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop text="subscript / superscript aliases" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Convenience form: subscript=true and superscript=true
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=13in --prop height=1in \
--prop text="" --prop size=24
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run --prop text="H"
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop subscript=true
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run --prop text="SO"
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run \
--prop text="4" --prop subscript=true
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run --prop text=" x"
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run --prop text=" + y"
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run --prop text=" = r"
officecli add "$PPTX" '/slide[5]/shape[1]/p[1]' --type run \
--prop text="2" --prop superscript=true
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop text='subscript=true ≡ baseline=sub superscript=true ≡ baseline=super' \
--prop size=14 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=2.8in --prop width=13in --prop height=0.5in
# Custom baseline percent — neither alias gives you this
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop x=0.5in --prop y=3.7in --prop width=13in --prop height=1in \
--prop text="" --prop size=24
officecli add "$PPTX" '/slide[5]/shape[3]/p[1]' --type run --prop text="Custom: "
officecli add "$PPTX" '/slide[5]/shape[3]/p[1]' --type run \
--prop text="50%" --prop baseline=50 --prop color=E63946
officecli add "$PPTX" '/slide[5]/shape[3]/p[1]' --type run --prop text=" higher / "
officecli add "$PPTX" '/slide[5]/shape[3]/p[1]' --type run \
--prop text="-40%" --prop baseline=-40 --prop color=2A9D8F
officecli add "$PPTX" '/slide[5]/shape[3]/p[1]' --type run --prop text=" lower"
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop text='baseline= accepts signed integer percent (super≡+30, sub≡-25 by convention). Custom values give arbitrary vertical offset.' \
--prop size=14 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=5in --prop width=13in --prop height=0.6in
# Per-run case rendering — cap on run Add accepts cap / allCaps / smallCaps
# directly (canonical + aliases). Same enum surface as the shape-level Set.
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop x=0.5in --prop y=5.9in --prop width=13in --prop height=0.8in \
--prop text="" --prop size=20 --prop bold=true
officecli add "$PPTX" '/slide[5]/shape[4]/p[1]' --type run --prop text="default "
officecli add "$PPTX" '/slide[5]/shape[4]/p[1]' --type run \
--prop text="small caps " --prop cap=small --prop color=2A9D8F
officecli add "$PPTX" '/slide[5]/shape[4]/p[1]' --type run \
--prop text="ALL CAPS" --prop allCaps=true --prop color=E63946
officecli add "$PPTX" '/slide[5]' --type textbox \
--prop text='Per-run cap=small / cap=all / cap=none, plus allCaps / smallCaps boolean aliases.' \
--prop size=12 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=6.8in --prop width=13in --prop height=0.5in
# ─────────────────────────────────────────────────────────────────────────────
# Slide 6 — name / zorder / autoFit / direction / font.cs (textbox-specific)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop text="name / zorder / autoFit / direction / font.cs" \
--prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=13in --prop height=0.6in
# name= — label the textbox so it can be re-addressed by @name later
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=5in --prop height=1.5in \
--prop fill=F1FAEE --prop size=16 --prop bold=true \
--prop text="This is intro-box." \
--prop name="intro-box"
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop text='name="intro-box" → addressable as /slide[6]/shape[@name=intro-box]' \
--prop size=12 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=2.8in --prop width=5in --prop height=0.5in
# zorder= — three overlapping textboxes with explicit stack order
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=6in --prop y=1.2in --prop width=3in --prop height=2in \
--prop fill=4472C4 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="back (zorder=1)" \
--prop name="tb-back" --prop zorder=1
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=7in --prop y=1.6in --prop width=3in --prop height=2in \
--prop fill=E63946 --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="mid (zorder=2)" \
--prop name="tb-mid" --prop zorder=2
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=8in --prop y=2.0in --prop width=3in --prop height=2in \
--prop fill=2A9D8F --prop color=FFFFFF --prop bold=true --prop size=16 \
--prop text="front (zorder=3)" \
--prop name="tb-front" --prop zorder=3
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop text='zorder= controls stack depth; aliases: z-order, order.' \
--prop size=12 --prop italic=true --prop color=666666 \
--prop x=6in --prop y=4.2in --prop width=5in --prop height=0.5in
# autoFit= — overflow behavior for textbox (same as shape)
LONGTEXT='Vivamus lacinia odio vitae vestibulum vestibulum. Sed molestie augue sit amet leo consequat posuere.'
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=0.5in --prop y=3.6in --prop width=3in --prop height=1.2in \
--prop fill=FFE66D --prop size=16 --prop text="$LONGTEXT" \
--prop autoFit=normal
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop text='autoFit=normal (shrinks text to fit)' \
--prop size=12 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=4.9in --prop width=3in --prop height=0.5in
# direction=rtl — paragraph flows right-to-left inside a textbox
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop x=0.5in --prop y=5.6in --prop width=5in --prop height=1.2in \
--prop fill=A8DADC --prop size=20 --prop bold=true \
--prop text="مرحبا بالعالم — 2026" \
--prop direction=rtl --prop align=right \
--prop font.cs="Arabic Typesetting"
officecli add "$PPTX" '/slide[6]' --type textbox \
--prop text='direction=rtl + font.cs="Arabic Typesetting" (complex-script slot)' \
--prop size=12 --prop italic=true --prop color=666666 \
--prop x=0.5in --prop y=6.9in --prop width=5in --prop height=0.5in
officecli close "$PPTX"
officecli validate "$PPTX"
echo "Created: $PPTX"
+247
View File
@@ -0,0 +1,247 @@
# Basic PPT Textboxes
This demo consists of three files that work together:
- **textboxes-basic.sh** — Shell script that calls `officecli` commands to generate the deck.
- **textboxes-basic.pptx** — The generated 4-slide deck (alignment, multi-paragraph lists, styled runs, multilingual fonts + layout).
- **textboxes-basic.md** — This file. Maps each slide to the features it demonstrates.
## Regenerate
```bash
cd examples/ppt
bash textboxes/textboxes-basic.sh
# → textboxes/textboxes-basic.pptx
```
## Slides
### Slide 1 — Horizontal Alignment
Four textboxes with identical long text, one per `align=` value.
```bash
officecli create textboxes-basic.pptx
officecli open textboxes-basic.pptx
officecli add textboxes-basic.pptx / --type slide
LOREM='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia odio vitae vestibulum vestibulum.'
# align=left (default)
officecli add textboxes-basic.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=1.3in --prop width=12in --prop height=1.3in \
--prop fill=F1FAEE --prop text="[align=left] $LOREM" --prop size=14 \
--prop align=left
# align=center
officecli add textboxes-basic.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=2.8in --prop width=12in --prop height=1.3in \
--prop fill=F1FAEE --prop text="[align=center] $LOREM" --prop size=14 \
--prop align=center
# align=right
officecli add textboxes-basic.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=4.3in --prop width=12in --prop height=1.3in \
--prop fill=F1FAEE --prop text="[align=right] $LOREM" --prop size=14 \
--prop align=right
# align=justify
officecli add textboxes-basic.pptx '/slide[1]' --type textbox \
--prop x=0.5in --prop y=5.8in --prop width=12in --prop height=1.3in \
--prop fill=F1FAEE --prop text="[align=justify] $LOREM" --prop size=14 \
--prop align=justify
```
**Features:** `--type textbox` (alias for `--type shape` — both are textboxes in OOXML), `align` (left, center, right, justify), `fill`, `text`, `size`, `x`/`y`/`width`/`height`
---
### Slide 2 — Multi-Paragraph + Bulleted / Numbered Lists
Two textboxes: a bulleted list on the left and a numbered list with a sub-item on the right.
```bash
officecli add textboxes-basic.pptx / --type slide
# Bulleted list — add title paragraph first, then append body paragraphs,
# then apply list=bullet via Set to turn all paragraphs into bullets.
officecli add textboxes-basic.pptx '/slide[2]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=6in --prop height=4in \
--prop text="Coffee preparation steps" \
--prop bold=true --prop size=18 --prop color=1D3557
officecli add textboxes-basic.pptx '/slide[2]/shape[1]' --type paragraph \
--prop text="Grind beans to medium-fine"
officecli add textboxes-basic.pptx '/slide[2]/shape[1]' --type paragraph \
--prop text="Heat water to 93°C"
officecli add textboxes-basic.pptx '/slide[2]/shape[1]' --type paragraph \
--prop text="Bloom 30s with 2× coffee weight"
officecli add textboxes-basic.pptx '/slide[2]/shape[1]' --type paragraph \
--prop text="Pour remaining water in spirals"
officecli add textboxes-basic.pptx '/slide[2]/shape[1]' --type paragraph \
--prop text="Total brew time: 3-4 minutes"
# Turn all paragraphs into bullets at shape level
officecli set textboxes-basic.pptx '/slide[2]/shape[1]' --prop list=bullet
# Numbered list — similar pattern
officecli add textboxes-basic.pptx '/slide[2]' --type textbox \
--prop x=7in --prop y=1.2in --prop width=6in --prop height=4in \
--prop text="Release checklist" \
--prop bold=true --prop size=18 --prop color=1D3557
officecli add textboxes-basic.pptx '/slide[2]/shape[2]' --type paragraph \
--prop text="Run tests"
officecli add textboxes-basic.pptx '/slide[2]/shape[2]' --type paragraph \
--prop text="Tag the release"
officecli add textboxes-basic.pptx '/slide[2]/shape[2]' --type paragraph \
--prop text="Push to registry"
officecli add textboxes-basic.pptx '/slide[2]/shape[2]' --type paragraph \
--prop text="Announce in #releases"
officecli set textboxes-basic.pptx '/slide[2]/shape[2]' --prop list=numbered
# Sub-item: level=1 nests one step deeper
officecli add textboxes-basic.pptx '/slide[2]/shape[2]' --type paragraph \
--prop text="(verify checksum)" --prop level=1
officecli set textboxes-basic.pptx '/slide[2]/shape[2]' --prop list=numbered
```
**Features:** `--type paragraph` (appends a paragraph to the parent shape), `list` (bullet, numbered — applied via `set` at shape level), `level` (indent depth; 0 = top-level, 1 = one indent, …)
---
### Slide 3 — Styled Runs (Rich Text)
Three textboxes demonstrating per-run styling within a single paragraph.
```bash
officecli add textboxes-basic.pptx / --type slide
# Empty textbox — filled run-by-run via --type run
officecli add textboxes-basic.pptx '/slide[3]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=12in --prop height=1in \
--prop text="" --prop size=20
# Append runs with different styles to paragraph [1]
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="The "
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="quick " --prop bold=true --prop color=E63946
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="brown " --prop italic=true --prop color=A0522D
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="fox jumps over the "
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="lazy " --prop underline=single --prop color=2A9D8F
officecli add textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' --type run \
--prop text="dog."
# Superscript / subscript via baseline= (also accepts baseline=super/sub)
officecli add textboxes-basic.pptx '/slide[3]' --type textbox \
--prop x=0.5in --prop y=3in --prop width=12in --prop height=0.8in \
--prop text="" --prop size=24
officecli add textboxes-basic.pptx '/slide[3]/shape[2]/p[1]' --type run \
--prop text="E = mc"
officecli add textboxes-basic.pptx '/slide[3]/shape[2]/p[1]' --type run \
--prop text="2" --prop baseline=super
officecli add textboxes-basic.pptx '/slide[3]/shape[2]/p[1]' --type run \
--prop text=" and H"
officecli add textboxes-basic.pptx '/slide[3]/shape[2]/p[1]' --type run \
--prop text="2" --prop baseline=sub
officecli add textboxes-basic.pptx '/slide[3]/shape[2]/p[1]' --type run \
--prop text="O"
# Strikethrough + size override in one paragraph
officecli add textboxes-basic.pptx '/slide[3]' --type textbox \
--prop x=0.5in --prop y=4.2in --prop width=12in --prop height=0.8in \
--prop text="" --prop size=20
officecli add textboxes-basic.pptx '/slide[3]/shape[3]/p[1]' --type run \
--prop text="OLD PRICE: \$99 " --prop strike=single --prop color=999999
officecli add textboxes-basic.pptx '/slide[3]/shape[3]/p[1]' --type run \
--prop text="NOW \$49!" --prop bold=true --prop color=E63946 --prop size=24
```
**Features:** `--type run` (appends a run to the parent `p[N]` paragraph), `bold`, `italic`, `underline` (single, double, …), `strike` (single, double), `color` (hex), `size` (pt), `baseline` (super, sub, or signed integer %)
---
### Slide 4 — Multilingual Fonts + Vertical Alignment + Padding
Per-script font selection, vertical text alignment within a tall box, and inner margin padding.
```bash
officecli add textboxes-basic.pptx / --type slide
# Mixed-script textbox: font.latin for Latin text, font.ea for East Asian characters
officecli add textboxes-basic.pptx '/slide[4]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=6in --prop height=2in \
--prop fill=F1FAEE --prop margin=0.2in \
--prop text="Hello, 世界! こんにちは、世界。" \
--prop size=24 --prop bold=true \
--prop font.latin="Georgia" --prop font.ea="Yu Mincho"
# valign — vertical text position inside a tall fixed-height box
# top (default), middle, bottom
X=7
for va in top middle bottom; do
officecli add textboxes-basic.pptx '/slide[4]' --type textbox \
--prop x="${X}in" --prop y=1.5in --prop width=2in --prop height=3in \
--prop fill=A8DADC --prop margin=0.15in \
--prop text="valign=$va" --prop size=16 --prop bold=true \
--prop valign="$va" --prop align=center
X=$(echo "$X + 2.2" | bc -l)
done
officecli close textboxes-basic.pptx
officecli validate textboxes-basic.pptx
```
**Features:** `font.latin` (Latin script font slot), `font.ea` (East Asian script font slot), `valign` (top, middle, bottom), `margin` (uniform inner padding; also `marginLeft`, `marginRight`, `marginTop`, `marginBottom`), `align=center`
---
## Complete Feature Coverage
| Feature | Slide |
|---------|-------|
| **align:** left, center, right, justify | 1 |
| **fill:** hex color background | 14 |
| **--type paragraph:** append paragraph to existing shape | 2 |
| **list=bullet:** bulleted list at shape level | 2 |
| **list=numbered:** numbered list at shape level | 2 |
| **level:** indent depth for sub-items (0=top, 1=nested, …) | 2 |
| **--type run:** append styled run to a paragraph | 3 |
| **bold / italic:** per-run weight and style | 3 |
| **underline:** single, double, heavy, dotted, dash | 3 |
| **strike:** single, double | 3 |
| **color:** per-run text color (hex) | 3 |
| **size:** per-run font size (pt) | 3 |
| **baseline:** super, sub, or signed integer % offset | 3 |
| **font.latin / font.ea:** per-script font slots | 4 |
| **valign:** top, middle, bottom | 4 |
| **margin:** uniform inner text padding | 4 |
| **align=center:** horizontal center within valign demo | 4 |
## Inspect the Generated File
```bash
# List shapes on slide 1
officecli query textboxes-basic.pptx '/slide[1]' shape
# Get alignment on each textbox
officecli get textboxes-basic.pptx '/slide[1]/shape[2]'
# Check list type on slide 2 shapes
officecli get textboxes-basic.pptx '/slide[2]/shape[1]'
officecli get textboxes-basic.pptx '/slide[2]/shape[2]'
# Inspect paragraph [1] runs on slide 3
officecli query textboxes-basic.pptx '/slide[3]/shape[1]/p[1]' run
# Get valign and font on slide 4
officecli get textboxes-basic.pptx '/slide[4]/shape[1]'
officecli get textboxes-basic.pptx '/slide[4]/shape[3]'
```
Binary file not shown.
+200
View File
@@ -0,0 +1,200 @@
#!/usr/bin/env python3
"""
Basic PowerPoint textboxes — alignment, multi-paragraph, bulleted/numbered
lists, styled runs, per-script fonts (Latin/EastAsian), vertical alignment and
padding. Demonstrates: type "textbox" (an alias for "shape"), type "paragraph"
with align/level, type "run" with bold/italic/underline/strike/color/baseline,
shape-level list=bullet|numbered, font.latin/font.ea, valign and margin.
SDK twin of textboxes-basic.sh (officecli CLI). Both produce an equivalent
textboxes-basic.pptx. This one drives the **officecli Python SDK**
(`pip install officecli-sdk`): one resident is started and every slide, shape,
paragraph and run is shipped over the named pipe in a single `doc.batch(...)`
round-trip — items apply in order, so a paragraph/run can target a shape an
earlier item in the same list just created. Each item is the same
`{"command","parent","type","props"}` dict you'd put in an `officecli batch` list.
Usage:
pip install officecli-sdk # plus the `officecli` binary on PATH
python3 textboxes-basic.py
"""
import os
import sys
# --- locate the SDK: prefer an installed `officecli-sdk`, else the in-repo copy
try:
import officecli # pip install officecli-sdk
except ImportError:
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
"..", "..", "..", "sdk", "python"))
import officecli
FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "textboxes-basic.pptx")
def slide(**props):
"""One `add slide` item in batch-shape."""
return {"command": "add", "parent": "/", "type": "slide", "props": props}
def textbox(parent, **props):
"""One `add textbox` item in batch-shape."""
return {"command": "add", "parent": parent, "type": "textbox", "props": props}
def paragraph(parent, **props):
"""One `add paragraph` item in batch-shape."""
return {"command": "add", "parent": parent, "type": "paragraph", "props": props}
def run(parent, **props):
"""One `add run` item in batch-shape."""
return {"command": "add", "parent": parent, "type": "run", "props": props}
def setp(path, **props):
"""One `set` item in batch-shape."""
return {"command": "set", "path": path, "props": props}
LOREM = ("Lorem ipsum dolor sit amet, consectetur adipiscing elit. "
"Vivamus lacinia odio vitae vestibulum vestibulum.")
print(f"Building {FILE} ...")
with officecli.create(FILE, "--force") as doc:
items = []
# ===================================================================
# Slide 1 — Horizontal alignment (4 textboxes, one per align value)
# ===================================================================
items.append(slide())
items.append(textbox("/slide[1]",
text="Horizontal Alignment", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
y = 1.3
for a in ("left", "center", "right", "justify"):
items.append(textbox("/slide[1]",
x="0.5in", y=f"{y}in", width="12in", height="1.3in",
fill="F1FAEE", text=f"[align={a}] {LOREM}", size="14",
align=a))
y += 1.5
# ===================================================================
# Slide 2 — Multi-paragraph + bulleted / numbered lists
# ===================================================================
items.append(slide())
items.append(textbox("/slide[2]",
text="Lists and Multi-Paragraph", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Bulleted list — start with one initial paragraph (the title), append the
# rest, then turn on bullets.
items.append(textbox("/slide[2]",
x="0.5in", y="1.2in", width="6in", height="4in",
text="Coffee preparation steps",
bold="true", size="18", color="1D3557"))
for t in ("Grind beans to medium-fine",
"Heat water to 93°C",
"Bloom 30s with 2× coffee weight",
"Pour remaining water in spirals",
"Total brew time: 3-4 minutes"):
items.append(paragraph("/slide[2]/shape[1]", text=t))
# Turn paragraphs 2-6 into bullets (level 0). Paragraph 1 is the title.
items.append(setp("/slide[2]/shape[1]", list="bullet"))
# Numbered list (ordered)
items.append(textbox("/slide[2]",
x="7in", y="1.2in", width="6in", height="4in",
text="Release checklist",
bold="true", size="18", color="1D3557"))
for t in ("Run tests", "Tag the release", "Push to registry",
"Announce in #releases"):
items.append(paragraph("/slide[2]/shape[2]", text=t))
items.append(setp("/slide[2]/shape[2]", list="numbered"))
# Indented sub-bullet — level=1 on a paragraph nests it one step in.
items.append(paragraph("/slide[2]/shape[2]",
text="(verify checksum)", level="1"))
items.append(setp("/slide[2]/shape[2]", list="numbered"))
# ===================================================================
# Slide 3 — Styled runs (rich text within one paragraph)
# ===================================================================
items.append(slide())
items.append(textbox("/slide[3]",
text="Rich Text — Runs", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Empty paragraph that we'll fill with multiple runs of different styles.
items.append(textbox("/slide[3]",
x="0.5in", y="1.5in", width="12in", height="1in",
text="", size="20"))
items.append(run("/slide[3]/shape[1]/p[1]", text="The "))
items.append(run("/slide[3]/shape[1]/p[1]", text="quick ", bold="true", color="E63946"))
items.append(run("/slide[3]/shape[1]/p[1]", text="brown ", italic="true", color="A0522D"))
items.append(run("/slide[3]/shape[1]/p[1]", text="fox jumps over the "))
items.append(run("/slide[3]/shape[1]/p[1]", text="lazy ", underline="single", color="2A9D8F"))
items.append(run("/slide[3]/shape[1]/p[1]", text="dog."))
# Superscript / subscript via baseline
items.append(textbox("/slide[3]",
x="0.5in", y="3in", width="12in", height="0.8in",
text="", size="24"))
items.append(run("/slide[3]/shape[2]/p[1]", text="E = mc"))
items.append(run("/slide[3]/shape[2]/p[1]", text="2", baseline="super"))
items.append(run("/slide[3]/shape[2]/p[1]", text=" and H"))
items.append(run("/slide[3]/shape[2]/p[1]", text="2", baseline="sub"))
items.append(run("/slide[3]/shape[2]/p[1]", text="O"))
# Strikethrough + colored
items.append(textbox("/slide[3]",
x="0.5in", y="4.2in", width="12in", height="0.8in",
text="", size="20"))
items.append(run("/slide[3]/shape[3]/p[1]",
text="OLD PRICE: $99 ", strike="single", color="999999"))
items.append(run("/slide[3]/shape[3]/p[1]",
text="NOW $49!", bold="true", color="E63946", size="24"))
# ===================================================================
# Slide 4 — Per-script fonts (Latin + EastAsian) + vertical alignment
# ===================================================================
items.append(slide())
items.append(textbox("/slide[4]",
text="Multilingual Fonts + Layout", size="28", bold="true",
x="0.5in", y="0.3in", width="12in", height="0.6in"))
# Mixed-script box: separate fonts for Latin and EastAsian text.
items.append(textbox("/slide[4]",
x="0.5in", y="1.5in", width="6in", height="2in",
fill="F1FAEE", margin="0.2in",
text="Hello, 世界! こんにちは、世界。",
size="24", bold="true",
**{"font.latin": "Georgia", "font.ea": "Yu Mincho"}))
items.append(textbox("/slide[4]",
x="0.5in", y="3.7in", width="6in", height="0.5in",
text='font.latin=Georgia, font.ea="Yu Mincho"',
size="12", italic="true", color="666666"))
# Vertical alignment within a tall box
x = 7.0
for va in ("top", "middle", "bottom"):
items.append(textbox("/slide[4]",
x=f"{x}in", y="1.5in", width="2in", height="3in",
fill="A8DADC", margin="0.15in",
text=f"valign={va}", size="16", bold="true",
valign=va, align="center"))
x += 2.2
items.append(textbox("/slide[4]",
x="7in", y="4.8in", width="6in", height="0.5in",
text="valign + per-box margin + align=center",
size="12", italic="true", color="666666"))
doc.batch(items)
print(f" added {len(items)} slides/shapes/paragraphs/runs")
print(f"Generated: {FILE}")
+169
View File
@@ -0,0 +1,169 @@
#!/bin/bash
# Basic PowerPoint textboxes — alignment, multi-paragraph, bulleted lists,
# styled runs, per-script fonts (Latin/EastAsian), vertical alignment, padding.
# Demonstrates: --type textbox vs --type shape (textbox is an alias for shape),
# --type paragraph with align/lineSpacing/indent, --type run with bold/color/baseline,
# shape-level list=bullet|ordered, font.latin/font.ea, valign and margin/autoFit.
# NOTE: intentionally NO `set -e`. Like the SDK twin's doc.batch, this script
# tolerates forward-compat 'UNSUPPORTED props' warnings (officecli exit 2) and
# keeps building so the full document is produced.
DIR="$(dirname "$0")"
PPTX="$DIR/textboxes-basic.pptx"
rm -f "$PPTX"
officecli create "$PPTX"
officecli open "$PPTX"
# ─────────────────────────────────────────────────────────────────────────────
# Slide 1 — Horizontal alignment (4 textboxes, one per align value)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop text="Horizontal Alignment" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
LOREM='Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus lacinia odio vitae vestibulum vestibulum.'
Y=1.3
for a in left center right justify; do
officecli add "$PPTX" '/slide[1]' --type textbox \
--prop x=0.5in --prop y="${Y}in" --prop width=12in --prop height=1.3in \
--prop fill=F1FAEE --prop text="[align=$a] $LOREM" --prop size=14 \
--prop align="$a"
Y=$(echo "$Y + 1.5" | bc -l)
done
# ─────────────────────────────────────────────────────────────────────────────
# Slide 2 — Multi-paragraph + bulleted / numbered lists
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop text="Lists and Multi-Paragraph" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Bulleted list — start with one initial paragraph, append the rest, then turn on bullets.
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=0.5in --prop y=1.2in --prop width=6in --prop height=4in \
--prop text="Coffee preparation steps" \
--prop bold=true --prop size=18 --prop color=1D3557
officecli add "$PPTX" '/slide[2]/shape[1]' --type paragraph --prop text="Grind beans to medium-fine"
officecli add "$PPTX" '/slide[2]/shape[1]' --type paragraph --prop text="Heat water to 93°C"
officecli add "$PPTX" '/slide[2]/shape[1]' --type paragraph --prop text="Bloom 30s with 2× coffee weight"
officecli add "$PPTX" '/slide[2]/shape[1]' --type paragraph --prop text="Pour remaining water in spirals"
officecli add "$PPTX" '/slide[2]/shape[1]' --type paragraph --prop text="Total brew time: 3-4 minutes"
# Turn paragraphs 2-6 into bullets (level 0). Paragraph 1 is the title — leave unbulleted.
officecli set "$PPTX" '/slide[2]/shape[1]' --prop list=bullet
# Numbered list (ordered)
officecli add "$PPTX" '/slide[2]' --type textbox \
--prop x=7in --prop y=1.2in --prop width=6in --prop height=4in \
--prop text="Release checklist" \
--prop bold=true --prop size=18 --prop color=1D3557
officecli add "$PPTX" '/slide[2]/shape[2]' --type paragraph --prop text="Run tests"
officecli add "$PPTX" '/slide[2]/shape[2]' --type paragraph --prop text="Tag the release"
officecli add "$PPTX" '/slide[2]/shape[2]' --type paragraph --prop text="Push to registry"
officecli add "$PPTX" '/slide[2]/shape[2]' --type paragraph --prop text="Announce in #releases"
officecli set "$PPTX" '/slide[2]/shape[2]' --prop list=numbered
# Indented sub-bullet — level=1 on a paragraph nests it one step in.
officecli add "$PPTX" '/slide[2]/shape[2]' --type paragraph \
--prop text="(verify checksum)" --prop level=1
officecli set "$PPTX" '/slide[2]/shape[2]' --prop list=numbered
# ─────────────────────────────────────────────────────────────────────────────
# Slide 3 — Styled runs (rich text within one paragraph)
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop text="Rich Text — Runs" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Empty paragraph that we'll fill with multiple runs of different styles.
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=12in --prop height=1in \
--prop text="" --prop size=20
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run --prop text="The "
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run \
--prop text="quick " --prop bold=true --prop color=E63946
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run \
--prop text="brown " --prop italic=true --prop color=A0522D
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run --prop text="fox jumps over the "
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run \
--prop text="lazy " --prop underline=single --prop color=2A9D8F
officecli add "$PPTX" '/slide[3]/shape[1]/p[1]' --type run --prop text="dog."
# Superscript / subscript via baseline
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop x=0.5in --prop y=3in --prop width=12in --prop height=0.8in \
--prop text="" --prop size=24
officecli add "$PPTX" '/slide[3]/shape[2]/p[1]' --type run --prop text="E = mc"
officecli add "$PPTX" '/slide[3]/shape[2]/p[1]' --type run --prop text="2" --prop baseline=super
officecli add "$PPTX" '/slide[3]/shape[2]/p[1]' --type run --prop text=" and H"
officecli add "$PPTX" '/slide[3]/shape[2]/p[1]' --type run --prop text="2" --prop baseline=sub
officecli add "$PPTX" '/slide[3]/shape[2]/p[1]' --type run --prop text="O"
# Strikethrough + small caps + colored
officecli add "$PPTX" '/slide[3]' --type textbox \
--prop x=0.5in --prop y=4.2in --prop width=12in --prop height=0.8in \
--prop text="" --prop size=20
officecli add "$PPTX" '/slide[3]/shape[3]/p[1]' --type run \
--prop text="OLD PRICE: \$99 " --prop strike=single --prop color=999999
officecli add "$PPTX" '/slide[3]/shape[3]/p[1]' --type run \
--prop text="NOW \$49!" --prop bold=true --prop color=E63946 --prop size=24
# ─────────────────────────────────────────────────────────────────────────────
# Slide 4 — Per-script fonts (Latin + East Asian) + vertical alignment + padding
# ─────────────────────────────────────────────────────────────────────────────
officecli add "$PPTX" / --type slide
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop text="Multilingual Fonts + Layout" --prop size=28 --prop bold=true \
--prop x=0.5in --prop y=0.3in --prop width=12in --prop height=0.6in
# Mixed-script box: separate fonts for Latin and EastAsian text.
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=1.5in --prop width=6in --prop height=2in \
--prop fill=F1FAEE --prop margin=0.2in \
--prop text="Hello, 世界! こんにちは、世界。" \
--prop size=24 --prop bold=true \
--prop font.latin="Georgia" --prop font.ea="Yu Mincho"
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=0.5in --prop y=3.7in --prop width=6in --prop height=0.5in \
--prop text='font.latin=Georgia, font.ea="Yu Mincho"' \
--prop size=12 --prop italic=true --prop color=666666
# Vertical alignment within a tall box
for va in top middle bottom; do
case $va in
top) X=7 ;;
middle) X=9.5 ;;
bottom) X=12 ;; # off-slide — squeeze
esac
done
X=7
for va in top middle bottom; do
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x="${X}in" --prop y=1.5in --prop width=2in --prop height=3in \
--prop fill=A8DADC --prop margin=0.15in \
--prop text="valign=$va" --prop size=16 --prop bold=true \
--prop valign="$va" --prop align=center
X=$(echo "$X + 2.2" | bc -l)
done
officecli add "$PPTX" '/slide[4]' --type textbox \
--prop x=7in --prop y=4.8in --prop width=6in --prop height=0.5in \
--prop text='valign + per-box margin + align=center' \
--prop size=12 --prop italic=true --prop color=666666
officecli close "$PPTX"
officecli validate "$PPTX"
echo "Created: $PPTX"