332 lines
11 KiB
Python
332 lines
11 KiB
Python
# pyright: reportAssignmentType=false
|
|
|
|
"""Custom element classes related to run properties (font)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Callable
|
|
|
|
from docx.enum.dml import MSO_THEME_COLOR
|
|
from docx.enum.text import WD_COLOR_INDEX, WD_UNDERLINE
|
|
from docx.oxml.ns import nsdecls
|
|
from docx.oxml.parser import parse_xml
|
|
from docx.oxml.simpletypes import (
|
|
ST_HexColor,
|
|
ST_HpsMeasure,
|
|
ST_String,
|
|
ST_VerticalAlignRun,
|
|
)
|
|
from docx.oxml.xmlchemy import (
|
|
BaseOxmlElement,
|
|
OptionalAttribute,
|
|
RequiredAttribute,
|
|
ZeroOrOne,
|
|
)
|
|
from docx.shared import RGBColor
|
|
|
|
if TYPE_CHECKING:
|
|
from docx.oxml.shared import CT_OnOff, CT_String
|
|
from docx.shared import Length
|
|
|
|
|
|
class CT_Color(BaseOxmlElement):
|
|
"""`w:color` element, specifying the color of a font and perhaps other objects."""
|
|
|
|
val: RGBColor | str = RequiredAttribute("w:val", ST_HexColor)
|
|
themeColor: MSO_THEME_COLOR | None = OptionalAttribute("w:themeColor", MSO_THEME_COLOR)
|
|
|
|
|
|
class CT_Fonts(BaseOxmlElement):
|
|
"""`<w:rFonts>` element.
|
|
|
|
Specifies typeface name for the various language types.
|
|
"""
|
|
|
|
ascii: str | None = OptionalAttribute("w:ascii", ST_String)
|
|
hAnsi: str | None = OptionalAttribute("w:hAnsi", ST_String)
|
|
|
|
|
|
class CT_Highlight(BaseOxmlElement):
|
|
"""`w:highlight` element, specifying font highlighting/background color."""
|
|
|
|
val: WD_COLOR_INDEX = RequiredAttribute("w:val", WD_COLOR_INDEX)
|
|
|
|
|
|
class CT_HpsMeasure(BaseOxmlElement):
|
|
"""Used for `<w:sz>` element and others, specifying font size in half-points."""
|
|
|
|
val: Length = RequiredAttribute("w:val", ST_HpsMeasure)
|
|
|
|
|
|
class CT_RPr(BaseOxmlElement):
|
|
"""`<w:rPr>` element, containing the properties for a run."""
|
|
|
|
get_or_add_color: Callable[[], CT_Color]
|
|
get_or_add_highlight: Callable[[], CT_Highlight]
|
|
get_or_add_rFonts: Callable[[], CT_Fonts]
|
|
get_or_add_sz: Callable[[], CT_HpsMeasure]
|
|
get_or_add_vertAlign: Callable[[], CT_VerticalAlignRun]
|
|
_add_rStyle: Callable[..., CT_String]
|
|
_add_u: Callable[[], CT_Underline]
|
|
_remove_color: Callable[[], None]
|
|
_remove_highlight: Callable[[], None]
|
|
_remove_rFonts: Callable[[], None]
|
|
_remove_rStyle: Callable[[], None]
|
|
_remove_sz: Callable[[], None]
|
|
_remove_u: Callable[[], None]
|
|
_remove_vertAlign: Callable[[], None]
|
|
|
|
_tag_seq = (
|
|
"w:rStyle",
|
|
"w:rFonts",
|
|
"w:b",
|
|
"w:bCs",
|
|
"w:i",
|
|
"w:iCs",
|
|
"w:caps",
|
|
"w:smallCaps",
|
|
"w:strike",
|
|
"w:dstrike",
|
|
"w:outline",
|
|
"w:shadow",
|
|
"w:emboss",
|
|
"w:imprint",
|
|
"w:noProof",
|
|
"w:snapToGrid",
|
|
"w:vanish",
|
|
"w:webHidden",
|
|
"w:color",
|
|
"w:spacing",
|
|
"w:w",
|
|
"w:kern",
|
|
"w:position",
|
|
"w:sz",
|
|
"w:szCs",
|
|
"w:highlight",
|
|
"w:u",
|
|
"w:effect",
|
|
"w:bdr",
|
|
"w:shd",
|
|
"w:fitText",
|
|
"w:vertAlign",
|
|
"w:rtl",
|
|
"w:cs",
|
|
"w:em",
|
|
"w:lang",
|
|
"w:eastAsianLayout",
|
|
"w:specVanish",
|
|
"w:oMath",
|
|
)
|
|
rStyle: CT_String | None = ZeroOrOne("w:rStyle", successors=_tag_seq[1:])
|
|
rFonts: CT_Fonts | None = ZeroOrOne("w:rFonts", successors=_tag_seq[2:])
|
|
b: CT_OnOff | None = ZeroOrOne("w:b", successors=_tag_seq[3:])
|
|
bCs = ZeroOrOne("w:bCs", successors=_tag_seq[4:])
|
|
i = ZeroOrOne("w:i", successors=_tag_seq[5:])
|
|
iCs = ZeroOrOne("w:iCs", successors=_tag_seq[6:])
|
|
caps = ZeroOrOne("w:caps", successors=_tag_seq[7:])
|
|
smallCaps = ZeroOrOne("w:smallCaps", successors=_tag_seq[8:])
|
|
strike = ZeroOrOne("w:strike", successors=_tag_seq[9:])
|
|
dstrike = ZeroOrOne("w:dstrike", successors=_tag_seq[10:])
|
|
outline = ZeroOrOne("w:outline", successors=_tag_seq[11:])
|
|
shadow = ZeroOrOne("w:shadow", successors=_tag_seq[12:])
|
|
emboss = ZeroOrOne("w:emboss", successors=_tag_seq[13:])
|
|
imprint = ZeroOrOne("w:imprint", successors=_tag_seq[14:])
|
|
noProof = ZeroOrOne("w:noProof", successors=_tag_seq[15:])
|
|
snapToGrid = ZeroOrOne("w:snapToGrid", successors=_tag_seq[16:])
|
|
vanish = ZeroOrOne("w:vanish", successors=_tag_seq[17:])
|
|
webHidden = ZeroOrOne("w:webHidden", successors=_tag_seq[18:])
|
|
color: CT_Color | None = ZeroOrOne("w:color", successors=_tag_seq[19:])
|
|
sz: CT_HpsMeasure | None = ZeroOrOne("w:sz", successors=_tag_seq[24:])
|
|
highlight: CT_Highlight | None = ZeroOrOne("w:highlight", successors=_tag_seq[26:])
|
|
u: CT_Underline | None = ZeroOrOne("w:u", successors=_tag_seq[27:])
|
|
vertAlign: CT_VerticalAlignRun | None = ZeroOrOne("w:vertAlign", successors=_tag_seq[32:])
|
|
rtl = ZeroOrOne("w:rtl", successors=_tag_seq[33:])
|
|
cs = ZeroOrOne("w:cs", successors=_tag_seq[34:])
|
|
specVanish = ZeroOrOne("w:specVanish", successors=_tag_seq[38:])
|
|
oMath = ZeroOrOne("w:oMath", successors=_tag_seq[39:])
|
|
del _tag_seq
|
|
|
|
def _new_color(self):
|
|
"""Override metaclass method to set `w:color/@val` to RGB black on create."""
|
|
return parse_xml('<w:color %s w:val="000000"/>' % nsdecls("w"))
|
|
|
|
@property
|
|
def highlight_val(self) -> WD_COLOR_INDEX | None:
|
|
"""Value of `./w:highlight/@val`.
|
|
|
|
Specifies font's highlight color, or `None` if the text is not highlighted.
|
|
"""
|
|
highlight = self.highlight
|
|
if highlight is None:
|
|
return None
|
|
return highlight.val
|
|
|
|
@highlight_val.setter
|
|
def highlight_val(self, value: WD_COLOR_INDEX | None) -> None:
|
|
if value is None:
|
|
self._remove_highlight()
|
|
return
|
|
highlight = self.get_or_add_highlight()
|
|
highlight.val = value
|
|
|
|
@property
|
|
def rFonts_ascii(self) -> str | None:
|
|
"""The value of `w:rFonts/@w:ascii` or |None| if not present.
|
|
|
|
Represents the assigned typeface name. The rFonts element also specifies other
|
|
special-case typeface names; this method handles the case where just the common
|
|
name is required.
|
|
"""
|
|
rFonts = self.rFonts
|
|
if rFonts is None:
|
|
return None
|
|
return rFonts.ascii
|
|
|
|
@rFonts_ascii.setter
|
|
def rFonts_ascii(self, value: str | None) -> None:
|
|
if value is None:
|
|
self._remove_rFonts()
|
|
return
|
|
rFonts = self.get_or_add_rFonts()
|
|
rFonts.ascii = value
|
|
|
|
@property
|
|
def rFonts_hAnsi(self) -> str | None:
|
|
"""The value of `w:rFonts/@w:hAnsi` or |None| if not present."""
|
|
rFonts = self.rFonts
|
|
if rFonts is None:
|
|
return None
|
|
return rFonts.hAnsi
|
|
|
|
@rFonts_hAnsi.setter
|
|
def rFonts_hAnsi(self, value: str | None):
|
|
if value is None and self.rFonts is None:
|
|
return
|
|
rFonts = self.get_or_add_rFonts()
|
|
rFonts.hAnsi = value
|
|
|
|
@property
|
|
def style(self) -> str | None:
|
|
"""String in `./w:rStyle/@val`, or None if `w:rStyle` is not present."""
|
|
rStyle = self.rStyle
|
|
if rStyle is None:
|
|
return None
|
|
return rStyle.val
|
|
|
|
@style.setter
|
|
def style(self, style: str | None) -> None:
|
|
"""Set `./w:rStyle/@val` to `style`, adding the `w:rStyle` element if necessary.
|
|
|
|
If `style` is |None|, remove `w:rStyle` element if present.
|
|
"""
|
|
if style is None:
|
|
self._remove_rStyle()
|
|
elif self.rStyle is None:
|
|
self._add_rStyle(val=style)
|
|
else:
|
|
self.rStyle.val = style
|
|
|
|
@property
|
|
def subscript(self) -> bool | None:
|
|
"""|True| if `./w:vertAlign/@w:val` is "subscript".
|
|
|
|
|False| if `w:vertAlign/@w:val` contains any other value. |None| if
|
|
`w:vertAlign` is not present.
|
|
"""
|
|
vertAlign = self.vertAlign
|
|
if vertAlign is None:
|
|
return None
|
|
return vertAlign.val == ST_VerticalAlignRun.SUBSCRIPT
|
|
|
|
@subscript.setter
|
|
def subscript(self, value: bool | None) -> None:
|
|
if value is None:
|
|
self._remove_vertAlign()
|
|
elif bool(value) is True:
|
|
self.get_or_add_vertAlign().val = ST_VerticalAlignRun.SUBSCRIPT
|
|
# -- assert bool(value) is False --
|
|
elif self.vertAlign is not None and self.vertAlign.val == ST_VerticalAlignRun.SUBSCRIPT:
|
|
self._remove_vertAlign()
|
|
|
|
@property
|
|
def superscript(self) -> bool | None:
|
|
"""|True| if `w:vertAlign/@w:val` is 'superscript'.
|
|
|
|
|False| if `w:vertAlign/@w:val` contains any other value. |None| if
|
|
`w:vertAlign` is not present.
|
|
"""
|
|
vertAlign = self.vertAlign
|
|
if vertAlign is None:
|
|
return None
|
|
return vertAlign.val == ST_VerticalAlignRun.SUPERSCRIPT
|
|
|
|
@superscript.setter
|
|
def superscript(self, value: bool | None):
|
|
if value is None:
|
|
self._remove_vertAlign()
|
|
elif bool(value) is True:
|
|
self.get_or_add_vertAlign().val = ST_VerticalAlignRun.SUPERSCRIPT
|
|
# -- assert bool(value) is False --
|
|
elif self.vertAlign is not None and self.vertAlign.val == ST_VerticalAlignRun.SUPERSCRIPT:
|
|
self._remove_vertAlign()
|
|
|
|
@property
|
|
def sz_val(self) -> Length | None:
|
|
"""The value of `w:sz/@w:val` or |None| if not present."""
|
|
sz = self.sz
|
|
if sz is None:
|
|
return None
|
|
return sz.val
|
|
|
|
@sz_val.setter
|
|
def sz_val(self, value: Length | None):
|
|
if value is None:
|
|
self._remove_sz()
|
|
return
|
|
sz = self.get_or_add_sz()
|
|
sz.val = value
|
|
|
|
@property
|
|
def u_val(self) -> WD_UNDERLINE | None:
|
|
"""Value of `w:u/@val`, or None if not present.
|
|
|
|
Values `WD_UNDERLINE.SINGLE` and `WD_UNDERLINE.NONE` are mapped to `True` and
|
|
`False` respectively.
|
|
"""
|
|
u = self.u
|
|
if u is None:
|
|
return None
|
|
return u.val
|
|
|
|
@u_val.setter
|
|
def u_val(self, value: WD_UNDERLINE | None):
|
|
self._remove_u()
|
|
if value is not None:
|
|
self._add_u().val = value
|
|
|
|
def _get_bool_val(self, name: str) -> bool | None:
|
|
"""Value of boolean child with `name`, e.g. "w:b", "w:i", and "w:smallCaps"."""
|
|
element = getattr(self, name)
|
|
if element is None:
|
|
return None
|
|
return element.val
|
|
|
|
def _set_bool_val(self, name: str, value: bool | None):
|
|
if value is None:
|
|
getattr(self, "_remove_%s" % name)()
|
|
return
|
|
element = getattr(self, "get_or_add_%s" % name)()
|
|
element.val = value
|
|
|
|
|
|
class CT_Underline(BaseOxmlElement):
|
|
"""`<w:u>` element, specifying the underlining style for a run."""
|
|
|
|
val: WD_UNDERLINE | None = OptionalAttribute("w:val", WD_UNDERLINE)
|
|
|
|
|
|
class CT_VerticalAlignRun(BaseOxmlElement):
|
|
"""`<w:vertAlign>` element, specifying subscript or superscript."""
|
|
|
|
val: str = RequiredAttribute("w:val", ST_VerticalAlignRun)
|