init: 폴더구조 설계 및 인프라 설계
This commit is contained in:
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
"""|ChartFormat| and related objects.
|
||||
|
||||
|ChartFormat| acts as proxy for the `spPr` element, which provides visual shape properties such as
|
||||
line and fill for chart elements.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pptx.dml.fill import FillFormat
|
||||
from pptx.dml.line import LineFormat
|
||||
from pptx.shared import ElementProxy
|
||||
from pptx.util import lazyproperty
|
||||
|
||||
|
||||
class ChartFormat(ElementProxy):
|
||||
"""
|
||||
The |ChartFormat| object provides access to visual shape properties for
|
||||
chart elements like |Axis|, |Series|, and |MajorGridlines|. It has two
|
||||
properties, :attr:`fill` and :attr:`line`, which return a |FillFormat|
|
||||
and |LineFormat| object respectively. The |ChartFormat| object is
|
||||
provided by the :attr:`format` property on the target axis, series, etc.
|
||||
"""
|
||||
|
||||
@lazyproperty
|
||||
def fill(self):
|
||||
"""
|
||||
|FillFormat| instance for this object, providing access to fill
|
||||
properties such as fill color.
|
||||
"""
|
||||
spPr = self._element.get_or_add_spPr()
|
||||
return FillFormat.from_fill_parent(spPr)
|
||||
|
||||
@lazyproperty
|
||||
def line(self):
|
||||
"""
|
||||
The |LineFormat| object providing access to the visual properties of
|
||||
this object, such as line color and line style.
|
||||
"""
|
||||
spPr = self._element.get_or_add_spPr()
|
||||
return LineFormat(spPr)
|
||||
@@ -0,0 +1,301 @@
|
||||
"""DrawingML objects related to color, ColorFormat being the most prominent."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pptx.enum.dml import MSO_COLOR_TYPE, MSO_THEME_COLOR
|
||||
from pptx.oxml.dml.color import (
|
||||
CT_HslColor,
|
||||
CT_PresetColor,
|
||||
CT_SchemeColor,
|
||||
CT_ScRgbColor,
|
||||
CT_SRgbColor,
|
||||
CT_SystemColor,
|
||||
)
|
||||
|
||||
|
||||
class ColorFormat(object):
|
||||
"""
|
||||
Provides access to color settings such as RGB color, theme color, and
|
||||
luminance adjustments.
|
||||
"""
|
||||
|
||||
def __init__(self, eg_colorChoice_parent, color):
|
||||
super(ColorFormat, self).__init__()
|
||||
self._xFill = eg_colorChoice_parent
|
||||
self._color = color
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
"""
|
||||
Read/write float value between -1.0 and 1.0 indicating the brightness
|
||||
adjustment for this color, e.g. -0.25 is 25% darker and 0.4 is 40%
|
||||
lighter. 0 means no brightness adjustment.
|
||||
"""
|
||||
return self._color.brightness
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, value):
|
||||
self._validate_brightness_value(value)
|
||||
self._color.brightness = value
|
||||
|
||||
@classmethod
|
||||
def from_colorchoice_parent(cls, eg_colorChoice_parent):
|
||||
xClr = eg_colorChoice_parent.eg_colorChoice
|
||||
color = _Color(xClr)
|
||||
color_format = cls(eg_colorChoice_parent, color)
|
||||
return color_format
|
||||
|
||||
@property
|
||||
def rgb(self):
|
||||
"""
|
||||
|RGBColor| value of this color, or None if no RGB color is explicitly
|
||||
defined for this font. Setting this value to an |RGBColor| instance
|
||||
causes its type to change to MSO_COLOR_TYPE.RGB. If the color was a
|
||||
theme color with a brightness adjustment, the brightness adjustment
|
||||
is removed when changing it to an RGB color.
|
||||
"""
|
||||
return self._color.rgb
|
||||
|
||||
@rgb.setter
|
||||
def rgb(self, rgb):
|
||||
if not isinstance(rgb, RGBColor):
|
||||
raise ValueError("assigned value must be type RGBColor")
|
||||
# change to rgb color format if not already
|
||||
if not isinstance(self._color, _SRgbColor):
|
||||
srgbClr = self._xFill.get_or_change_to_srgbClr()
|
||||
self._color = _SRgbColor(srgbClr)
|
||||
# call _SRgbColor instance to do the setting
|
||||
self._color.rgb = rgb
|
||||
|
||||
@property
|
||||
def theme_color(self):
|
||||
"""Theme color value of this color.
|
||||
|
||||
Value is a member of :ref:`MsoThemeColorIndex`, e.g.
|
||||
``MSO_THEME_COLOR.ACCENT_1``. Raises AttributeError on access if the
|
||||
color is not type ``MSO_COLOR_TYPE.SCHEME``. Assigning a member of
|
||||
:ref:`MsoThemeColorIndex` causes the color's type to change to
|
||||
``MSO_COLOR_TYPE.SCHEME``.
|
||||
"""
|
||||
return self._color.theme_color
|
||||
|
||||
@theme_color.setter
|
||||
def theme_color(self, mso_theme_color_idx):
|
||||
# change to theme color format if not already
|
||||
if not isinstance(self._color, _SchemeColor):
|
||||
schemeClr = self._xFill.get_or_change_to_schemeClr()
|
||||
self._color = _SchemeColor(schemeClr)
|
||||
self._color.theme_color = mso_theme_color_idx
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""
|
||||
Read-only. A value from :ref:`MsoColorType`, either RGB or SCHEME,
|
||||
corresponding to the way this color is defined, or None if no color
|
||||
is defined at the level of this font.
|
||||
"""
|
||||
return self._color.color_type
|
||||
|
||||
def _validate_brightness_value(self, value):
|
||||
if value < -1.0 or value > 1.0:
|
||||
raise ValueError("brightness must be number in range -1.0 to 1.0")
|
||||
if isinstance(self._color, _NoneColor):
|
||||
msg = (
|
||||
"can't set brightness when color.type is None. Set color.rgb"
|
||||
" or .theme_color first."
|
||||
)
|
||||
raise ValueError(msg)
|
||||
|
||||
|
||||
class _Color(object):
|
||||
"""
|
||||
Object factory for color object of the appropriate type, also the base
|
||||
class for all color type classes such as SRgbColor.
|
||||
"""
|
||||
|
||||
def __new__(cls, xClr):
|
||||
color_cls = {
|
||||
type(None): _NoneColor,
|
||||
CT_HslColor: _HslColor,
|
||||
CT_PresetColor: _PrstColor,
|
||||
CT_SchemeColor: _SchemeColor,
|
||||
CT_ScRgbColor: _ScRgbColor,
|
||||
CT_SRgbColor: _SRgbColor,
|
||||
CT_SystemColor: _SysColor,
|
||||
}[type(xClr)]
|
||||
return super(_Color, cls).__new__(color_cls)
|
||||
|
||||
def __init__(self, xClr):
|
||||
super(_Color, self).__init__()
|
||||
self._xClr = xClr
|
||||
|
||||
@property
|
||||
def brightness(self):
|
||||
lumMod, lumOff = self._xClr.lumMod, self._xClr.lumOff
|
||||
# a tint is lighter, a shade is darker
|
||||
# only tints have lumOff child
|
||||
if lumOff is not None:
|
||||
brightness = lumOff.val
|
||||
return brightness
|
||||
# which leaves shades, if lumMod is present
|
||||
if lumMod is not None:
|
||||
brightness = lumMod.val - 1.0
|
||||
return brightness
|
||||
# there's no brightness adjustment if no lum{Mod|Off} elements
|
||||
return 0
|
||||
|
||||
@brightness.setter
|
||||
def brightness(self, value):
|
||||
if value > 0:
|
||||
self._tint(value)
|
||||
elif value < 0:
|
||||
self._shade(value)
|
||||
else:
|
||||
self._xClr.clear_lum()
|
||||
|
||||
@property
|
||||
def color_type(self): # pragma: no cover
|
||||
tmpl = ".color_type property must be implemented on %s"
|
||||
raise NotImplementedError(tmpl % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def rgb(self):
|
||||
"""
|
||||
Raises TypeError on access unless overridden by subclass.
|
||||
"""
|
||||
tmpl = "no .rgb property on color type '%s'"
|
||||
raise AttributeError(tmpl % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def theme_color(self):
|
||||
"""
|
||||
Raises TypeError on access unless overridden by subclass.
|
||||
"""
|
||||
return MSO_THEME_COLOR.NOT_THEME_COLOR
|
||||
|
||||
def _shade(self, value):
|
||||
lumMod_val = 1.0 - abs(value)
|
||||
color_elm = self._xClr.clear_lum()
|
||||
color_elm.add_lumMod(lumMod_val)
|
||||
|
||||
def _tint(self, value):
|
||||
lumOff_val = value
|
||||
lumMod_val = 1.0 - lumOff_val
|
||||
color_elm = self._xClr.clear_lum()
|
||||
color_elm.add_lumMod(lumMod_val)
|
||||
color_elm.add_lumOff(lumOff_val)
|
||||
|
||||
|
||||
class _HslColor(_Color):
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.HSL
|
||||
|
||||
|
||||
class _NoneColor(_Color):
|
||||
@property
|
||||
def color_type(self):
|
||||
return None
|
||||
|
||||
@property
|
||||
def theme_color(self):
|
||||
"""
|
||||
Raise TypeError on attempt to access .theme_color when no color
|
||||
choice is present.
|
||||
"""
|
||||
tmpl = "no .theme_color property on color type '%s'"
|
||||
raise AttributeError(tmpl % self.__class__.__name__)
|
||||
|
||||
|
||||
class _PrstColor(_Color):
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.PRESET
|
||||
|
||||
|
||||
class _SchemeColor(_Color):
|
||||
def __init__(self, schemeClr):
|
||||
super(_SchemeColor, self).__init__(schemeClr)
|
||||
self._schemeClr = schemeClr
|
||||
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.SCHEME
|
||||
|
||||
@property
|
||||
def theme_color(self):
|
||||
"""
|
||||
Theme color value of this color, one of those defined in the
|
||||
MSO_THEME_COLOR enumeration, e.g. MSO_THEME_COLOR.ACCENT_1. None if
|
||||
no theme color is explicitly defined for this font. Setting this to a
|
||||
value in MSO_THEME_COLOR causes the color's type to change to
|
||||
``MSO_COLOR_TYPE.SCHEME``.
|
||||
"""
|
||||
return self._schemeClr.val
|
||||
|
||||
@theme_color.setter
|
||||
def theme_color(self, mso_theme_color_idx):
|
||||
self._schemeClr.val = mso_theme_color_idx
|
||||
|
||||
|
||||
class _ScRgbColor(_Color):
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.SCRGB
|
||||
|
||||
|
||||
class _SRgbColor(_Color):
|
||||
def __init__(self, srgbClr):
|
||||
super(_SRgbColor, self).__init__(srgbClr)
|
||||
self._srgbClr = srgbClr
|
||||
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.RGB
|
||||
|
||||
@property
|
||||
def rgb(self):
|
||||
"""
|
||||
|RGBColor| value of this color, corresponding to the value in the
|
||||
required ``val`` attribute of the ``<a:srgbColr>`` element.
|
||||
"""
|
||||
return RGBColor.from_string(self._srgbClr.val)
|
||||
|
||||
@rgb.setter
|
||||
def rgb(self, rgb):
|
||||
self._srgbClr.val = str(rgb)
|
||||
|
||||
|
||||
class _SysColor(_Color):
|
||||
@property
|
||||
def color_type(self):
|
||||
return MSO_COLOR_TYPE.SYSTEM
|
||||
|
||||
|
||||
class RGBColor(tuple):
|
||||
"""
|
||||
Immutable value object defining a particular RGB color.
|
||||
"""
|
||||
|
||||
def __new__(cls, r, g, b):
|
||||
msg = "RGBColor() takes three integer values 0-255"
|
||||
for val in (r, g, b):
|
||||
if not isinstance(val, int) or val < 0 or val > 255:
|
||||
raise ValueError(msg)
|
||||
return super(RGBColor, cls).__new__(cls, (r, g, b))
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Return a hex string rgb value, like '3C2F80'
|
||||
"""
|
||||
return "%02X%02X%02X" % self
|
||||
|
||||
@classmethod
|
||||
def from_string(cls, rgb_hex_str):
|
||||
"""
|
||||
Return a new instance from an RGB color hex string like ``'3C2F80'``.
|
||||
"""
|
||||
r = int(rgb_hex_str[:2], 16)
|
||||
g = int(rgb_hex_str[2:4], 16)
|
||||
b = int(rgb_hex_str[4:], 16)
|
||||
return cls(r, g, b)
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Visual effects on a shape such as shadow, glow, and reflection."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class ShadowFormat(object):
|
||||
"""Provides access to shadow effect on a shape."""
|
||||
|
||||
def __init__(self, spPr):
|
||||
# ---spPr may also be a grpSpPr; both have a:effectLst child---
|
||||
self._element = spPr
|
||||
|
||||
@property
|
||||
def inherit(self):
|
||||
"""True if shape inherits shadow settings.
|
||||
|
||||
Read/write. An explicitly-defined shadow setting on a shape causes
|
||||
this property to return |False|. A shape with no explicitly-defined
|
||||
shadow setting inherits its shadow settings from the style hierarchy
|
||||
(and so returns |True|).
|
||||
|
||||
Assigning |True| causes any explicitly-defined shadow setting to be
|
||||
removed and inheritance is restored. Note this has the side-effect of
|
||||
removing **all** explicitly-defined effects, such as glow and
|
||||
reflection, and restoring inheritance for all effects on the shape.
|
||||
Assigning |False| causes the inheritance link to be broken and **no**
|
||||
effects to appear on the shape.
|
||||
"""
|
||||
if self._element.effectLst is None:
|
||||
return True
|
||||
return False
|
||||
|
||||
@inherit.setter
|
||||
def inherit(self, value):
|
||||
inherit = bool(value)
|
||||
if inherit:
|
||||
# ---remove any explicitly-defined effects
|
||||
self._element._remove_effectLst()
|
||||
else:
|
||||
# ---ensure at least the effectLst element is present
|
||||
self._element.get_or_add_effectLst()
|
||||
@@ -0,0 +1,398 @@
|
||||
"""DrawingML objects related to fill."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from pptx.dml.color import ColorFormat
|
||||
from pptx.enum.dml import MSO_FILL
|
||||
from pptx.oxml.dml.fill import (
|
||||
CT_BlipFillProperties,
|
||||
CT_GradientFillProperties,
|
||||
CT_GroupFillProperties,
|
||||
CT_NoFillProperties,
|
||||
CT_PatternFillProperties,
|
||||
CT_SolidColorFillProperties,
|
||||
)
|
||||
from pptx.oxml.xmlchemy import BaseOxmlElement
|
||||
from pptx.shared import ElementProxy
|
||||
from pptx.util import lazyproperty
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pptx.enum.dml import MSO_FILL_TYPE
|
||||
from pptx.oxml.xmlchemy import BaseOxmlElement
|
||||
|
||||
|
||||
class FillFormat(object):
|
||||
"""Provides access to the current fill properties.
|
||||
|
||||
Also provides methods to change the fill type.
|
||||
"""
|
||||
|
||||
def __init__(self, eg_fill_properties_parent: BaseOxmlElement, fill_obj: _Fill):
|
||||
super(FillFormat, self).__init__()
|
||||
self._xPr = eg_fill_properties_parent
|
||||
self._fill = fill_obj
|
||||
|
||||
@classmethod
|
||||
def from_fill_parent(cls, eg_fillProperties_parent: BaseOxmlElement) -> FillFormat:
|
||||
"""
|
||||
Return a |FillFormat| instance initialized to the settings contained
|
||||
in *eg_fillProperties_parent*, which must be an element having
|
||||
EG_FillProperties in its child element sequence in the XML schema.
|
||||
"""
|
||||
fill_elm = eg_fillProperties_parent.eg_fillProperties
|
||||
fill = _Fill(fill_elm)
|
||||
fill_format = cls(eg_fillProperties_parent, fill)
|
||||
return fill_format
|
||||
|
||||
@property
|
||||
def back_color(self):
|
||||
"""Return a |ColorFormat| object representing background color.
|
||||
|
||||
This property is only applicable to pattern fills and lines.
|
||||
"""
|
||||
return self._fill.back_color
|
||||
|
||||
def background(self):
|
||||
"""
|
||||
Sets the fill type to noFill, i.e. transparent.
|
||||
"""
|
||||
noFill = self._xPr.get_or_change_to_noFill()
|
||||
self._fill = _NoFill(noFill)
|
||||
|
||||
@property
|
||||
def fore_color(self):
|
||||
"""
|
||||
Return a |ColorFormat| instance representing the foreground color of
|
||||
this fill.
|
||||
"""
|
||||
return self._fill.fore_color
|
||||
|
||||
def gradient(self):
|
||||
"""Sets the fill type to gradient.
|
||||
|
||||
If the fill is not already a gradient, a default gradient is added.
|
||||
The default gradient corresponds to the default in the built-in
|
||||
PowerPoint "White" template. This gradient is linear at angle
|
||||
90-degrees (upward), with two stops. The first stop is Accent-1 with
|
||||
tint 100%, shade 100%, and satMod 130%. The second stop is Accent-1
|
||||
with tint 50%, shade 100%, and satMod 350%.
|
||||
"""
|
||||
gradFill = self._xPr.get_or_change_to_gradFill()
|
||||
self._fill = _GradFill(gradFill)
|
||||
|
||||
@property
|
||||
def gradient_angle(self):
|
||||
"""Angle in float degrees of line of a linear gradient.
|
||||
|
||||
Read/Write. May be |None|, indicating the angle should be inherited
|
||||
from the style hierarchy. An angle of 0.0 corresponds to
|
||||
a left-to-right gradient. Increasing angles represent
|
||||
counter-clockwise rotation of the line, for example 90.0 represents
|
||||
a bottom-to-top gradient. Raises |TypeError| when the fill type is
|
||||
not MSO_FILL_TYPE.GRADIENT. Raises |ValueError| for a non-linear
|
||||
gradient (e.g. a radial gradient).
|
||||
"""
|
||||
if self.type != MSO_FILL.GRADIENT:
|
||||
raise TypeError("Fill is not of type MSO_FILL_TYPE.GRADIENT")
|
||||
return self._fill.gradient_angle
|
||||
|
||||
@gradient_angle.setter
|
||||
def gradient_angle(self, value):
|
||||
if self.type != MSO_FILL.GRADIENT:
|
||||
raise TypeError("Fill is not of type MSO_FILL_TYPE.GRADIENT")
|
||||
self._fill.gradient_angle = value
|
||||
|
||||
@property
|
||||
def gradient_stops(self):
|
||||
"""|GradientStops| object providing access to stops of this gradient.
|
||||
|
||||
Raises |TypeError| when fill is not gradient (call `fill.gradient()`
|
||||
first). Each stop represents a color between which the gradient
|
||||
smoothly transitions.
|
||||
"""
|
||||
if self.type != MSO_FILL.GRADIENT:
|
||||
raise TypeError("Fill is not of type MSO_FILL_TYPE.GRADIENT")
|
||||
return self._fill.gradient_stops
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
"""Return member of :ref:`MsoPatternType` indicating fill pattern.
|
||||
|
||||
Raises |TypeError| when fill is not patterned (call
|
||||
`fill.patterned()` first). Returns |None| if no pattern has been set;
|
||||
PowerPoint may display the default `PERCENT_5` pattern in this case.
|
||||
Assigning |None| will remove any explicit pattern setting, although
|
||||
relying on the default behavior is discouraged and may produce
|
||||
rendering differences across client applications.
|
||||
"""
|
||||
return self._fill.pattern
|
||||
|
||||
@pattern.setter
|
||||
def pattern(self, pattern_type):
|
||||
self._fill.pattern = pattern_type
|
||||
|
||||
def patterned(self):
|
||||
"""Selects the pattern fill type.
|
||||
|
||||
Note that calling this method does not by itself set a foreground or
|
||||
background color of the pattern. Rather it enables subsequent
|
||||
assignments to properties like fore_color to set the pattern and
|
||||
colors.
|
||||
"""
|
||||
pattFill = self._xPr.get_or_change_to_pattFill()
|
||||
self._fill = _PattFill(pattFill)
|
||||
|
||||
def solid(self):
|
||||
"""
|
||||
Sets the fill type to solid, i.e. a solid color. Note that calling
|
||||
this method does not set a color or by itself cause the shape to
|
||||
appear with a solid color fill; rather it enables subsequent
|
||||
assignments to properties like fore_color to set the color.
|
||||
"""
|
||||
solidFill = self._xPr.get_or_change_to_solidFill()
|
||||
self._fill = _SolidFill(solidFill)
|
||||
|
||||
@property
|
||||
def type(self) -> MSO_FILL_TYPE:
|
||||
"""The type of this fill, e.g. `MSO_FILL_TYPE.SOLID`."""
|
||||
return self._fill.type
|
||||
|
||||
|
||||
class _Fill(object):
|
||||
"""
|
||||
Object factory for fill object of class matching fill element, such as
|
||||
_SolidFill for ``<a:solidFill>``; also serves as the base class for all
|
||||
fill classes
|
||||
"""
|
||||
|
||||
def __new__(cls, xFill):
|
||||
if xFill is None:
|
||||
fill_cls = _NoneFill
|
||||
elif isinstance(xFill, CT_BlipFillProperties):
|
||||
fill_cls = _BlipFill
|
||||
elif isinstance(xFill, CT_GradientFillProperties):
|
||||
fill_cls = _GradFill
|
||||
elif isinstance(xFill, CT_GroupFillProperties):
|
||||
fill_cls = _GrpFill
|
||||
elif isinstance(xFill, CT_NoFillProperties):
|
||||
fill_cls = _NoFill
|
||||
elif isinstance(xFill, CT_PatternFillProperties):
|
||||
fill_cls = _PattFill
|
||||
elif isinstance(xFill, CT_SolidColorFillProperties):
|
||||
fill_cls = _SolidFill
|
||||
else:
|
||||
fill_cls = _Fill
|
||||
return super(_Fill, cls).__new__(fill_cls)
|
||||
|
||||
@property
|
||||
def back_color(self):
|
||||
"""Raise TypeError for types that do not override this property."""
|
||||
tmpl = "fill type %s has no background color, call .patterned() first"
|
||||
raise TypeError(tmpl % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def fore_color(self):
|
||||
"""Raise TypeError for types that do not override this property."""
|
||||
tmpl = "fill type %s has no foreground color, call .solid() or .pattern" "ed() first"
|
||||
raise TypeError(tmpl % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
"""Raise TypeError for fills that do not override this property."""
|
||||
tmpl = "fill type %s has no pattern, call .patterned() first"
|
||||
raise TypeError(tmpl % self.__class__.__name__)
|
||||
|
||||
@property
|
||||
def type(self) -> MSO_FILL_TYPE: # pragma: no cover
|
||||
raise NotImplementedError(
|
||||
f".type property must be implemented on {self.__class__.__name__}"
|
||||
)
|
||||
|
||||
|
||||
class _BlipFill(_Fill):
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.PICTURE
|
||||
|
||||
|
||||
class _GradFill(_Fill):
|
||||
"""Proxies an `a:gradFill` element."""
|
||||
|
||||
def __init__(self, gradFill):
|
||||
self._element = self._gradFill = gradFill
|
||||
|
||||
@property
|
||||
def gradient_angle(self):
|
||||
"""Angle in float degrees of line of a linear gradient.
|
||||
|
||||
Read/Write. May be |None|, indicating the angle is inherited from the
|
||||
style hierarchy. An angle of 0.0 corresponds to a left-to-right
|
||||
gradient. Increasing angles represent clockwise rotation of the line,
|
||||
for example 90.0 represents a top-to-bottom gradient. Raises
|
||||
|TypeError| when the fill type is not MSO_FILL_TYPE.GRADIENT. Raises
|
||||
|ValueError| for a non-linear gradient (e.g. a radial gradient).
|
||||
"""
|
||||
# ---case 1: gradient path is explicit, but not linear---
|
||||
path = self._gradFill.path
|
||||
if path is not None:
|
||||
raise ValueError("not a linear gradient")
|
||||
|
||||
# ---case 2: gradient path is inherited (no a:lin OR a:path)---
|
||||
lin = self._gradFill.lin
|
||||
if lin is None:
|
||||
return None
|
||||
|
||||
# ---case 3: gradient path is explicitly linear---
|
||||
# angle is stored in XML as a clockwise angle, whereas the UI
|
||||
# reports it as counter-clockwise from horizontal-pointing-right.
|
||||
# Since the UI is consistent with trigonometry conventions, we
|
||||
# respect that in the API.
|
||||
clockwise_angle = lin.ang
|
||||
counter_clockwise_angle = 0.0 if clockwise_angle == 0.0 else (360.0 - clockwise_angle)
|
||||
return counter_clockwise_angle
|
||||
|
||||
@gradient_angle.setter
|
||||
def gradient_angle(self, value):
|
||||
lin = self._gradFill.lin
|
||||
if lin is None:
|
||||
raise ValueError("not a linear gradient")
|
||||
lin.ang = 360.0 - value
|
||||
|
||||
@lazyproperty
|
||||
def gradient_stops(self):
|
||||
"""|_GradientStops| object providing access to gradient colors.
|
||||
|
||||
Each stop represents a color between which the gradient smoothly
|
||||
transitions.
|
||||
"""
|
||||
return _GradientStops(self._gradFill.get_or_add_gsLst())
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.GRADIENT
|
||||
|
||||
|
||||
class _GrpFill(_Fill):
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.GROUP
|
||||
|
||||
|
||||
class _NoFill(_Fill):
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.BACKGROUND
|
||||
|
||||
|
||||
class _NoneFill(_Fill):
|
||||
@property
|
||||
def type(self):
|
||||
return None
|
||||
|
||||
|
||||
class _PattFill(_Fill):
|
||||
"""Provides access to patterned fill properties."""
|
||||
|
||||
def __init__(self, pattFill):
|
||||
super(_PattFill, self).__init__()
|
||||
self._element = self._pattFill = pattFill
|
||||
|
||||
@lazyproperty
|
||||
def back_color(self):
|
||||
"""Return |ColorFormat| object that controls background color."""
|
||||
bgClr = self._pattFill.get_or_add_bgClr()
|
||||
return ColorFormat.from_colorchoice_parent(bgClr)
|
||||
|
||||
@lazyproperty
|
||||
def fore_color(self):
|
||||
"""Return |ColorFormat| object that controls foreground color."""
|
||||
fgClr = self._pattFill.get_or_add_fgClr()
|
||||
return ColorFormat.from_colorchoice_parent(fgClr)
|
||||
|
||||
@property
|
||||
def pattern(self):
|
||||
"""Return member of :ref:`MsoPatternType` indicating fill pattern.
|
||||
|
||||
Returns |None| if no pattern has been set; PowerPoint may display the
|
||||
default `PERCENT_5` pattern in this case. Assigning |None| will
|
||||
remove any explicit pattern setting.
|
||||
"""
|
||||
return self._pattFill.prst
|
||||
|
||||
@pattern.setter
|
||||
def pattern(self, pattern_type):
|
||||
self._pattFill.prst = pattern_type
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.PATTERNED
|
||||
|
||||
|
||||
class _SolidFill(_Fill):
|
||||
"""Provides access to fill properties such as color for solid fills."""
|
||||
|
||||
def __init__(self, solidFill):
|
||||
super(_SolidFill, self).__init__()
|
||||
self._solidFill = solidFill
|
||||
|
||||
@lazyproperty
|
||||
def fore_color(self):
|
||||
"""Return |ColorFormat| object controlling fill color."""
|
||||
return ColorFormat.from_colorchoice_parent(self._solidFill)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return MSO_FILL.SOLID
|
||||
|
||||
|
||||
class _GradientStops(Sequence):
|
||||
"""Collection of |GradientStop| objects defining gradient colors.
|
||||
|
||||
A gradient must have a minimum of two stops, but can have as many more
|
||||
than that as required to achieve the desired effect (three is perhaps
|
||||
most common). Stops are sequenced in the order they are transitioned
|
||||
through.
|
||||
"""
|
||||
|
||||
def __init__(self, gsLst):
|
||||
self._gsLst = gsLst
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return _GradientStop(self._gsLst[idx])
|
||||
|
||||
def __len__(self):
|
||||
return len(self._gsLst)
|
||||
|
||||
|
||||
class _GradientStop(ElementProxy):
|
||||
"""A single gradient stop.
|
||||
|
||||
A gradient stop defines a color and a position.
|
||||
"""
|
||||
|
||||
def __init__(self, gs):
|
||||
super(_GradientStop, self).__init__(gs)
|
||||
self._gs = gs
|
||||
|
||||
@lazyproperty
|
||||
def color(self):
|
||||
"""Return |ColorFormat| object controlling stop color."""
|
||||
return ColorFormat.from_colorchoice_parent(self._gs)
|
||||
|
||||
@property
|
||||
def position(self):
|
||||
"""Location of stop in gradient path as float between 0.0 and 1.0.
|
||||
|
||||
The value represents a percentage, where 0.0 (0%) represents the
|
||||
start of the path and 1.0 (100%) represents the end of the path. For
|
||||
a linear gradient, these would represent opposing extents of the
|
||||
filled area.
|
||||
"""
|
||||
return self._gs.pos
|
||||
|
||||
@position.setter
|
||||
def position(self, value):
|
||||
self._gs.pos = float(value)
|
||||
@@ -0,0 +1,100 @@
|
||||
"""DrawingML objects related to line formatting."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pptx.dml.fill import FillFormat
|
||||
from pptx.enum.dml import MSO_FILL
|
||||
from pptx.util import Emu, lazyproperty
|
||||
|
||||
|
||||
class LineFormat(object):
|
||||
"""Provides access to line properties such as color, style, and width.
|
||||
|
||||
A LineFormat object is typically accessed via the ``.line`` property of
|
||||
a shape such as |Shape| or |Picture|.
|
||||
"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super(LineFormat, self).__init__()
|
||||
self._parent = parent
|
||||
|
||||
@lazyproperty
|
||||
def color(self):
|
||||
"""
|
||||
The |ColorFormat| instance that provides access to the color settings
|
||||
for this line. Essentially a shortcut for ``line.fill.fore_color``.
|
||||
As a side-effect, accessing this property causes the line fill type
|
||||
to be set to ``MSO_FILL.SOLID``. If this sounds risky for your use
|
||||
case, use ``line.fill.type`` to non-destructively discover the
|
||||
existing fill type.
|
||||
"""
|
||||
if self.fill.type != MSO_FILL.SOLID:
|
||||
self.fill.solid()
|
||||
return self.fill.fore_color
|
||||
|
||||
@property
|
||||
def dash_style(self):
|
||||
"""Return value indicating line style.
|
||||
|
||||
Returns a member of :ref:`MsoLineDashStyle` indicating line style, or
|
||||
|None| if no explicit value has been set. When no explicit value has
|
||||
been set, the line dash style is inherited from the style hierarchy.
|
||||
|
||||
Assigning |None| removes any existing explicitly-defined dash style.
|
||||
"""
|
||||
ln = self._ln
|
||||
if ln is None:
|
||||
return None
|
||||
return ln.prstDash_val
|
||||
|
||||
@dash_style.setter
|
||||
def dash_style(self, dash_style):
|
||||
if dash_style is None:
|
||||
ln = self._ln
|
||||
if ln is None:
|
||||
return
|
||||
ln._remove_prstDash()
|
||||
ln._remove_custDash()
|
||||
return
|
||||
ln = self._get_or_add_ln()
|
||||
ln.prstDash_val = dash_style
|
||||
|
||||
@lazyproperty
|
||||
def fill(self):
|
||||
"""
|
||||
|FillFormat| instance for this line, providing access to fill
|
||||
properties such as foreground color.
|
||||
"""
|
||||
ln = self._get_or_add_ln()
|
||||
return FillFormat.from_fill_parent(ln)
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
"""
|
||||
The width of the line expressed as an integer number of :ref:`English
|
||||
Metric Units <EMU>`. The returned value is an instance of |Length|,
|
||||
a value class having properties such as `.inches`, `.cm`, and `.pt`
|
||||
for converting the value into convenient units.
|
||||
"""
|
||||
ln = self._ln
|
||||
if ln is None:
|
||||
return Emu(0)
|
||||
return ln.w
|
||||
|
||||
@width.setter
|
||||
def width(self, emu):
|
||||
if emu is None:
|
||||
emu = 0
|
||||
ln = self._get_or_add_ln()
|
||||
ln.w = emu
|
||||
|
||||
def _get_or_add_ln(self):
|
||||
"""
|
||||
Return the ``<a:ln>`` element containing the line format properties
|
||||
in the XML.
|
||||
"""
|
||||
return self._parent.get_or_add_ln()
|
||||
|
||||
@property
|
||||
def _ln(self):
|
||||
return self._parent.ln
|
||||
Reference in New Issue
Block a user