Source code for ooodev.format.inner.direct.structs.gradient_struct

"""
Module for ``Gradient`` struct.

.. versionadded:: 0.9.0
"""

# region Import
from __future__ import annotations
from typing import Any, Tuple, Type, cast, overload, TypeVar
import json
import uno
from ooo.dyn.awt.gradient import Gradient
from ooo.dyn.awt.gradient_style import GradientStyle

from ooodev.exceptions import ex as mEx
from ooodev.format.inner.direct.structs.struct_base import StructBase
from ooodev.format.inner.kind.format_kind import FormatKind
from ooodev.format.inner.preset import preset_gradient
from ooodev.format.inner.preset.preset_gradient import PresetGradientKind
from ooodev.units.angle import Angle
from ooodev.utils import props as mProps
from ooodev.utils.color import Color
from ooodev.utils.color import RGB
from ooodev.utils.data_type.color_range import ColorRange
from ooodev.utils.data_type.intensity import Intensity
from ooodev.utils.data_type.intensity_range import IntensityRange
from ooodev.utils.data_type.offset import Offset


# endregion Import

# see Also:
# https://github.com/LibreOffice/core/blob/f725629a6241ec064770c28957f11d306c18f130/filter/source/msfilter/escherex.cxx

_TGradientStruct = TypeVar("_TGradientStruct", bound="GradientStruct")


[docs]class GradientStruct(StructBase): """ Represents UNO ``Gradient`` struct. .. versionadded:: 0.9.0 """
[docs] def __init__( self, *, style: GradientStyle = GradientStyle.LINEAR, step_count: int = 0, x_offset: Intensity | int = 50, y_offset: Intensity | int = 50, angle: Angle | int = 0, border: Intensity | int = 0, start_color: Color = Color(0), start_intensity: Intensity | int = 100, end_color: Color = Color(16777215), end_intensity: Intensity | int = 100, ) -> None: """ Constructor Args: style (GradientStyle, optional): Specifies the style of the gradient. Defaults to ``GradientStyle.LINEAR``. step_count (int, optional): Specifies the number of steps of change color. Defaults to ``0``. x_offset (Intensity, int, optional): Specifies the X-coordinate, where the gradient begins. This is effectively the center of the ``RADIAL``, ``ELLIPTICAL``, ``SQUARE`` and ``RECT`` style gradients. Defaults to ``50``. y_offset (Intensity, int, optional): Specifies the Y-coordinate, where the gradient begins. See: ``x_offset``. Defaults to ``50``. angle (Angle, int, optional): Specifies angle of the gradient. Defaults to 0. border (int, optional): Specifies percent of the total width where just the start color is used. Defaults to 0. start_color (:py:data:`~.utils.color.Color`, optional): Specifies the color at the start point of the gradient. Defaults to ``Color(0)``. start_intensity (Intensity, int, optional): Specifies the intensity at the start point of the gradient. Defaults to ``100``. end_color (:py:data:`~.utils.color.Color`, optional): Specifies the color at the end point of the gradient. Defaults to ``Color(16777215)``. end_intensity (Intensity, int, optional): Specifies the intensity at the end point of the gradient. Defaults to ``100``. Raises: ValueError: If ``step_count`` is less than zero. Returns: None: """ if not isinstance(angle, Angle): angle = Angle(angle) if not isinstance(end_intensity, Intensity): end_intensity = Intensity(end_intensity) if not isinstance(start_intensity, Intensity): start_intensity = Intensity(start_intensity) if not isinstance(x_offset, Intensity): x_offset = Intensity(x_offset) if not isinstance(y_offset, Intensity): y_offset = Intensity(y_offset) if not isinstance(border, Intensity): border = Intensity(border) # step_count must be between 3 and 256 when not automatic in paragraph gradient if step_count < 0: raise ValueError("step_count must be a positive number") init_vals = { "Style": style, "StartColor": start_color, "EndColor": end_color, "Angle": angle.value * 10, "Border": border.value, "XOffset": x_offset.value, "YOffset": y_offset.value, "StartIntensity": start_intensity.value, "EndIntensity": end_intensity.value, "StepCount": step_count, } super().__init__(**init_vals)
# region methods def _supported_services(self) -> Tuple[str, ...]: try: return self._supported_services_values except AttributeError: self._supported_services_values = ("com.sun.star.text.TextFrame",) return self._supported_services_values def _get_property_name(self) -> str: try: return self._property_name except AttributeError: self._property_name = "FillGradient" return self._property_name
[docs] def get_attrs(self) -> Tuple[str, ...]: return (self._get_property_name(),)
[docs] def get_uno_struct(self) -> Gradient: """ Gets UNO ``Gradient`` from instance. Returns: Gradient: ``Gradient`` instance """ return Gradient( Style=self._get("Style"), StartColor=self._get("StartColor"), EndColor=self._get("EndColor"), Angle=self._get("Angle"), Border=self._get("Border"), XOffset=self._get("XOffset"), YOffset=self._get("YOffset"), StartIntensity=self._get("StartIntensity"), EndIntensity=self._get("EndIntensity"), StepCount=self._get("StepCount"), )
def __eq__(self, oth: object) -> bool: obj2 = None if isinstance(oth, GradientStruct): obj2 = oth.get_uno_struct() if getattr(oth, "typeName", None) in ("com.sun.star.awt.Gradient", "com.sun.star.awt.Gradient2"): obj2 = cast(Gradient, oth) # Gradient2 is new in LO 7.6 and has a new property ColorStops if obj2: obj1 = self.get_uno_struct() return ( obj1.Style == obj2.Style and obj1.StartColor == obj2.StartColor and obj1.EndColor == obj2.EndColor and obj1.Angle == obj2.Angle and obj1.Border == obj2.Border and obj1.XOffset == obj2.XOffset and obj1.YOffset == obj2.YOffset and obj1.StartIntensity == obj2.StartIntensity and obj1.EndIntensity == obj2.EndIntensity and obj1.StepCount == obj2.StepCount ) return NotImplemented # region apply() @overload def apply(self, obj: Any) -> None: # type: ignore ...
[docs] def apply(self, obj: Any, **kwargs) -> None: """ Applies tab properties to ``obj`` Args: obj (object): UNO object. Returns: None: """ # override_dv p_name = self._get_property_name() if not p_name: return if not mProps.Props.has(obj, self._get_property_name()): self._print_not_valid_srv("apply") return grad = self.get_uno_struct() props = {self._get_property_name(): grad} super().apply(obj=obj, override_dv=props)
# endregion apply() # region JSON
[docs] def get_json(self) -> str: """ Get Gradient represented as a json string for use with dispatch commands. Returns: str: Json string. """ # See Also: https://tinyurl.com/2p7o5tvt search for FillPageGradientJSON # It seems dispatch commands (at least Writer) do not seem to work. # possible dispatch commands are: # props = Props.make_props(FillPageGradientJSON=json_dat) # or # props = Props.make_props(FillGradientJSON=json_dat) # # Lo.dispatch_cmd("FillPageGradient", props) # or # Lo.dispatch_cmd("FillGradient", props) # # see: https://wiki.documentfoundation.org/Development/DispatchCommands search for .uno:FillGradient d = { "style": cast(uno.Enum, self._get("Style")).value, "startcolor": RGB.from_int(self._get("StartColor")).to_hex(), "endcolor": RGB.from_int(self._get("EndColor")).to_hex(), "angle": str(self._get("Angle")), "border": str(self._get("Border")), "x": str(self._get("XOffset")), "y": str(self._get("YOffset")), "intensstart": str(self._get("StartIntensity")), "intensend": str(self._get("EndIntensity")), "stepcount": str(self._get("StepCount")), } return json.dumps(d)
# endregion JSON # region static methods # region from_uno_struct() @overload @classmethod def from_uno_struct(cls: Type[_TGradientStruct], value: Gradient) -> _TGradientStruct: ... @overload @classmethod def from_uno_struct(cls: Type[_TGradientStruct], value: Gradient, **kwargs) -> _TGradientStruct: ...
[docs] @classmethod def from_uno_struct(cls: Type[_TGradientStruct], value: Gradient, **kwargs) -> _TGradientStruct: """ Converts a ``Gradient`` instance to a ``GradientStruct``. Args: value (Gradient): UNO ``Gradient``. Returns: GradientStruct: ``GradientStruct`` set with ``Gradient`` properties. """ inst = cls(**kwargs) inst._set("Style", value.Style) inst._set("StartColor", value.StartColor) inst._set("EndColor", value.EndColor) inst._set("Angle", value.Angle) inst._set("Border", value.Border) inst._set("XOffset", value.XOffset) inst._set("YOffset", value.YOffset) inst._set("StartIntensity", value.StartIntensity) inst._set("EndIntensity", value.EndIntensity) inst._set("StepCount", value.StepCount) return inst
# endregion from_uno_struct() # region from_obj() @overload @classmethod def from_obj(cls: Type[_TGradientStruct], obj: Any) -> _TGradientStruct: ... @overload @classmethod def from_obj(cls: Type[_TGradientStruct], obj: Any, **kwargs) -> _TGradientStruct: ...
[docs] @classmethod def from_obj(cls: Type[_TGradientStruct], obj: Any, **kwargs) -> _TGradientStruct: """ Gets instance from object Args: obj (object): UNO object Raises: PropertyNotFoundError: If ``obj`` does not have required property Returns: GradientStruct: ``GradientStruct`` instance that represents ``obj`` gradient properties. """ # this nu is only used to get Property Name nu = cls(**kwargs) prop_name = nu._get_property_name() try: grad = cast(Gradient, mProps.Props.get(obj, prop_name)) except mEx.PropertyNotFoundError as e: raise mEx.PropertyNotFoundError(prop_name, f"from_obj() obj as no {prop_name} property") from e return cls.from_uno_struct(grad, **kwargs)
# endregion from_obj() # region from_preset() @overload @classmethod def from_preset(cls: Type[_TGradientStruct], preset: PresetGradientKind) -> _TGradientStruct: ... @overload @classmethod def from_preset(cls: Type[_TGradientStruct], preset: PresetGradientKind, **kwargs) -> _TGradientStruct: ...
[docs] @classmethod def from_preset(cls: Type[_TGradientStruct], preset: PresetGradientKind, **kwargs) -> _TGradientStruct: """ Gets instance from preset. Args: preset (PresetGradientKind): Preset. Returns: GradientStruct: Gradient from a preset. .. versionadded:: 0.10.2 """ args = preset_gradient.get_preset(preset) style = cast(GradientStyle, args.pop("style")) step_count = cast(int, args.pop("step_count")) offset = cast(Offset, args.pop("offset")) angle = Angle(int(args.pop("angle"))) border = Intensity(int(args.pop("border"))) grad_color = cast(ColorRange, args.pop("grad_color")) grad_intensity = cast(IntensityRange, args.pop("grad_intensity")) return cls( style=style, step_count=step_count, x_offset=offset.x, y_offset=offset.y, angle=angle, border=border, start_color=grad_color.start, start_intensity=grad_intensity.start, end_color=grad_color.end, end_intensity=grad_intensity.end, **kwargs, )
# endregion from_preset() # endregion static methods # endregion methods # region properties @property def prop_format_kind(self) -> FormatKind: """Gets the kind of style""" try: return self._format_kind_prop except AttributeError: self._format_kind_prop = FormatKind.PARA | FormatKind.TXT_CONTENT return self._format_kind_prop @property def prop_style(self) -> GradientStyle: """Gets/Sets the style of the gradient.""" return self._get("Style") @prop_style.setter def prop_style(self, value: GradientStyle): self._set("Style", value) @property def prop_step_count(self) -> int: """Gets/Sets the number of steps of change color.""" return self._get("StepCount") @prop_step_count.setter def prop_step_count(self, value: int): self._set("StepCount", value) @property def prop_x_offset(self) -> Intensity: """Gets/Sets the X-coordinate, where the gradient begins.""" pv = cast(int, self._get("XOffset")) return Intensity(pv) @prop_x_offset.setter def prop_x_offset(self, value: Intensity | int): if not isinstance(value, Intensity): value = Intensity(value) self._set("XOffset", value.value) @property def prop_y_offset(self) -> Intensity: """Gets/Sets the Y-coordinate, where the gradient begins.""" pv = cast(int, self._get("YOffset")) return Intensity(pv) @prop_y_offset.setter def prop_y_offset(self, value: Intensity | int): if not isinstance(value, Intensity): value = Intensity(value) self._set("YOffset", value.value) @property def prop_angle(self) -> Angle: """Gets/Sets angle of the gradient.""" pv = cast(int, self._get("Angle")) return Angle(0) if pv == 0 else Angle(round(pv / 10)) @prop_angle.setter def prop_angle(self, value: Angle | int): if not isinstance(value, Angle): value = Angle(value) self._set("Angle", value.value * 10) @property def prop_border(self) -> Intensity: """Gets/Sets percent of the total width where just the start color is used.""" pv = cast(int, self._get("Border")) return Intensity(pv) @prop_border.setter def prop_border(self, value: Intensity | int): if not isinstance(value, Intensity): value = Intensity(value) self._set("Border", value.value) @property def prop_start_color(self) -> Color: """Gets/Sets the color at the start point of the gradient.""" return self._get("StartColor") @prop_start_color.setter def prop_start_color(self, value: Color): self._set("StartColor", value) @property def prop_start_intensity(self) -> Intensity: """Gets/Sets the intensity at the start point of the gradient.""" pv = cast(int, self._get("StartIntensity")) return Intensity(pv) @prop_start_intensity.setter def prop_start_intensity(self, value: Intensity | int): if not isinstance(value, Intensity): value = Intensity(value) self._set("StartIntensity", value.value) @property def prop_end_color(self) -> Color: """Gets/Sets the color at the end point of the gradient.""" return self._get("EndColor") @prop_end_color.setter def prop_end_color(self, value: Color): self._set("EndColor", value) @property def prop_end_intensity(self) -> Intensity: """Gets/Sets the intensity at the end point of the gradient.""" pv = cast(int, self._get("EndIntensity")) return Intensity(pv) @prop_end_intensity.setter def prop_end_intensity(self, value: Intensity | int): if not isinstance(value, Intensity): value = Intensity(value) self._set("EndIntensity", value.value)
# endregion properties