Source code for

# region Import
from __future__ import annotations
from typing import Any, Tuple, overload, cast, Type, TypeVar

from ooo.dyn.drawing.fill_style import FillStyle
from ooo.dyn.drawing.hatch_style import HatchStyle
from ooo.dyn.drawing.hatch import Hatch as UnoHatch

from import KeyValCancelArgs
from import FormatNamedEvent
from ooodev.exceptions import ex as mEx
from import HatchStruct
from import Color as FillColor
from ooodev.format.inner.kind.format_kind import FormatKind
from ooodev.format.inner.preset import preset_hatch as mPreset
from ooodev.format.inner.preset.preset_hatch import PresetHatchKind
from ooodev.format.inner.style_base import StyleMulti
from ooodev.loader import lo as mLo
from ooodev.units.angle import Angle
from ooodev.units.unit_convert import UnitConvert
from ooodev.units.unit_obj import UnitT
from ooodev.utils import props as mProps
from ooodev.utils.color import Color, StandardColor

# endregion Import


_THatch = TypeVar(name="_THatch", bound="Hatch")

class _HatchStruct(HatchStruct):
    """Hatch Struct for para Hatch"""

    def _supported_services(self) -> Tuple[str, ...]:
            return self._supported_services_values
        except AttributeError:
            self._supported_services_values = (
        return self._supported_services_values

[docs]class Hatch(StyleMulti): """ Class for Fill Properties Fill Hatch. .. seealso:: - :ref:`help_writer_format_direct_para_area_hatch` .. versionadded:: 0.9.0 """
[docs] def __init__( self, *, style: HatchStyle = HatchStyle.SINGLE, color: Color = Color(0), space: float | UnitT = 0.0, angle: Angle | int = 0, bg_color: Color = Color(-1), name: str = "", auto_name: bool = False, ) -> None: """ Constructor Args: style (HatchStyle, optional): Specifies the kind of lines used to draw this hatch. Default ``HatchStyle.SINGLE``. color (:py:data:`~.utils.color.Color`, optional): Specifies the color of the hatch lines. Default ``0``. space (float, UnitT, optional): Specifies the space between the lines in the hatch (in ``mm`` units) or :ref:`proto_unit_obj`. Default ``0.0`` angle (Angle, int, optional): Specifies angle of the hatch in degrees. Default to ``0``. bg_color(:py:data:`~.utils.color.Color`, optional): Specifies the background Color. Set this ``-1`` (default) for no background color. name (str, optional): Specifies the Hatch Name. auto_name (bool, optional): Specifies if Hatch is give an auto name such as ``Hatch``. Default ``False``. Returns: None: See Also: - :ref:`help_writer_format_direct_para_area_hatch` """ self._auto_name = auto_name self._name = name # this may change in _set_fill_hatch() init_vals = {"ParaBackTransparent": False, "FillStyle": FillStyle.HATCH} bk_color = FillColor(bg_color) # FillStyle is set by this class bk_color._remove("FillStyle") # add event listener to prevent FillStyle from being set bk_color.add_event_listener(FormatNamedEvent.STYLE_SETTING, _on_bg_color_setting) bk_color.prop_color = bg_color init_vals["FillBackground"] = bg_color >= 0 super().__init__(**init_vals) self._set_bg_color(color) in_hatch = self._get_inner_hatch()(style=style, color=color, distance=space, angle=angle) self._set_fill_hatch(in_hatch, False) self._set_style("fill_color", bk_color, *bk_color.get_attrs()) # type: ignore
# region Internal Methods def _get_inner_hatch(self) -> Type[HatchStruct]: return _HatchStruct def _set_bg_color(self, color: int) -> None: # Writer stores ParaBackColor as flag values when there is no background color # When there is background color then ParaBackColor contains the actual color. # To find the flag value a known value was used. # In this case the Hatch Color is used as part of the flag. # # background colors # ParaBackColor HEX Name # 2130706432 0x7f000000 "Black 0 Degrees" # 2130706432 0x7f000000 "Black 90 Degrees" # 2130706432 0x7f000000 "Black 180 Degrees Crossed" # 2133483673 0x7f2a6099 "Blue 45 Degrees" # 2133483673 0x7f2a6099 "Blue -45 Degrees" # 2133483673 0x7f2a6099 "Blue 45 Degrees Crossed" # 2147467008 0x7fffbf00 "Yellow 45 Degrees" # 2130749747 0x7f00a933 "Green 30 Degrees" # 2147418112 0x7fff0000 "Red 45 Degrees" # # BLACK_HATCH = 0x7F000000 # flags = BLUE_HATCH & ~StandardColor.BLUE # print(hex(flags)) # '0x7F000000' # # This is the flags value assigned to PARA_BACK_COLOR_FLAGS # see also: # # # fb = cast(bool, self._get("FillBackground")) para_bg_color = color if fb else PARA_BACK_COLOR_FLAGS | color self._set("ParaBackColor", para_bg_color) def _set_fill_hatch(self, hatch_struct: HatchStruct, ignore_preset: bool) -> None: self._del_attribs("_direct_inner_hatch") name_hatch = self._get_named_hatch_struct(hatch_struct, self._name, ignore_preset) self._set("FillHatchName", self._name) self._set_style("fill_hatch", name_hatch, *name_hatch.get_attrs()) def _get_named_hatch_struct(self, hatch_struct: HatchStruct, name: str, ignore_preset: bool) -> HatchStruct: # if the name passed in already exist in the Hatch Table then it is returned. # Otherwise, the hatch is added to the Hatch Table and then returned # unless name is a present name. # If it is a preset name any value in the Hatch Table is ignored. # This is due to Writer alters the stored Struct for some unknown reason. # Presets are not added to Hatch Table. Write handles this for hatch. # # After Hatch is added to table all other subsequent call of this name will return (unless preset) # that Hatch from the Table. Except auto_name which will force a new entry # into the Table each time. self._is_preset = False if name: if not ignore_preset and PresetHatchKind.is_preset(name): self._is_preset = True # When getting value from Hatch table that Writer has inserted # The values are somehow changed by Writer # For this reason will return directly here return hatch_struct else: self._auto_name = True name = "Hatch" nc = self._container_get_inst() if self._auto_name: # if auto name is True then will no longer be treated as a preset. # for preset expect name similar to 'Black 0 Degrees 1' self._is_preset = False name = f"{name.rstrip()} " self._name = self._container_get_unique_el_name(name, nc) else: self._name = name hatch = self._container_get_value(self._name, nc) # raises value error if name is empty if hatch is not None: return self._get_inner_hatch().from_uno_struct(hatch) self._container_add_value(name=self._name, obj=hatch_struct.get_uno_struct(), allow_update=False, nc=nc) hatch = self._container_get_value(self._name, nc) return self._get_inner_hatch().from_uno_struct(hatch) def _on_hatch_property_change(self) -> None: if self._is_preset: self._auto_name = True self._set_fill_hatch(self.prop_inner_hatch, True) self._is_preset = False # endregion Internal Methods # region Overrides def _supported_services(self) -> Tuple[str, ...]: try: return self._supported_services_values except AttributeError: self._supported_services_values = ( "", "", "", "", ) return self._supported_services_values def _container_get_service_name(self) -> str: # return "" # region copy() @overload def copy(self: _THatch) -> _THatch: ... @overload def copy(self: _THatch, **kwargs) -> _THatch: ...
[docs] def copy(self: _THatch, **kwargs) -> _THatch: """Gets a copy of instance as a new instance""" # pylint: disable=protected-access cp = super().copy(**kwargs) cp._name = self._name cp._is_preset = self._is_preset cp._auto_name = self._auto_name return cp
# endregion copy() # region apply() @overload def apply(self, obj: Any) -> None: ... @overload def apply(self, obj: Any, **kwargs) -> None: ...
[docs] def apply(self, obj: Any, **kwargs) -> None: """ Applies styles to object Args: obj (object): UNO object. Returns: None: """ super().apply(obj, **kwargs)
def _props_set(self, obj: Any, **kwargs: Any) -> None: try: super()._props_set(obj, **kwargs) except mEx.MultiError as e: mLo.Lo.print("Hatch.apply(): Unable to set Property") for err in e.errors: mLo.Lo.print(f" {err}") # endregion apply() # endregion Overrides # region Static Methods # region from_preset() @overload @classmethod def from_preset(cls: Type[_THatch], preset: PresetHatchKind) -> _THatch: ... @overload @classmethod def from_preset(cls: Type[_THatch], preset: PresetHatchKind, **kwargs) -> _THatch: ...
[docs] @classmethod def from_preset(cls: Type[_THatch], preset: PresetHatchKind, **kwargs) -> _THatch: """ Gets an instance from a preset Args: preset (PresetHatchKind): Preset Returns: Hatch: Instance from preset. """ # kargs = mPreset.get_write_preset(preset) kargs = mPreset.get_preset(preset) kargs["name"] = str(preset) kargs["auto_name"] = False kargs.update(kwargs) return cls(**kargs)
# endregion from_preset() # region from_obj() @overload @classmethod def from_obj(cls: Type[_THatch], obj: Any) -> _THatch: ... @overload @classmethod def from_obj(cls: Type[_THatch], obj: Any, **kwargs) -> _THatch: ...
[docs] @classmethod def from_obj(cls: Type[_THatch], obj: Any, **kwargs) -> _THatch: """ Gets instance from object Args: obj (object): UNO object. Raises: NotSupportedError: If ``obj`` is not supported. Returns: Hatch: ``Hatch`` instance that represents ``obj`` hatch pattern. """ # pylint: disable=protected-access nu = cls(**kwargs) if not nu._is_valid_obj(obj): raise mEx.NotSupportedError("Object is not support to convert to Hatch") hatch = cast(UnoHatch, mProps.Props.get(obj, "FillHatch")) fc = FillColor.from_obj(obj) result = cls( style=hatch.Style, color=hatch.Color, # type: ignore space=UnitConvert.convert_mm100_mm(hatch.Distance), angle=hatch.Angle, bg_color=fc.prop_color, name=mProps.Props.get(obj, "FillHatchName"), auto_name=False, **kwargs, ) result.set_update_obj(obj) return result
# endregion from_obj() # endregion Static 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.TXT_CONTENT | FormatKind.FILL | FormatKind.PARA return self._format_kind_prop @property def prop_name(self) -> str: """Gets the name of the hatch.""" return self._name @property def prop_bg_color(self) -> Color: """Gets sets if fill image is tiled""" return self.prop_inner_color.prop_color @prop_bg_color.setter def prop_bg_color(self, value: Color): self.prop_inner_color.prop_color = value if value < 0: self._set("FillBackground", False) else: self._set("FillBackground", True) self._set_bg_color(self.prop_color) @property def prop_style(self) -> HatchStyle: """Gets/Sets the style of the hatch.""" return self.prop_inner_hatch.prop_style @prop_style.setter def prop_style(self, value: HatchStyle): self._on_hatch_property_change() self.prop_inner_hatch.prop_style = value @property def prop_color(self) -> Color: """Gets/Sets the color of the hatch lines.""" return self.prop_inner_hatch.prop_color @prop_color.setter def prop_color(self, value: Color): self._on_hatch_property_change() self.prop_inner_hatch.prop_color = value self._set_bg_color(value) @property def prop_space(self) -> UnitT: """Gets/Sets the distance between the lines in the hatch (in ``mm`` units).""" return self.prop_inner_hatch.prop_distance @prop_space.setter def prop_space(self, value: float | UnitT): self._on_hatch_property_change() self.prop_inner_hatch.prop_distance = value @property def prop_angle(self) -> Angle: """Gets/Sets angle of the hatch.""" return self.prop_inner_hatch.prop_angle @prop_angle.setter def prop_angle(self, value: Angle | int): self._on_hatch_property_change() self.prop_inner_hatch.prop_angle = value @property def prop_inner_hatch(self) -> HatchStruct: """Gets Hatch struct instance""" try: return self._direct_inner_hatch except AttributeError: self._direct_inner_hatch = cast(HatchStruct, self._get_style_inst("fill_hatch")) return self._direct_inner_hatch @property def prop_inner_color(self) -> FillColor: """Gets Fill color instance""" try: return self._direct_inner_color except AttributeError: self._direct_inner_color = cast(FillColor, self._get_style_inst("fill_color")) return self._direct_inner_color
# endregion Properties def _on_bg_color_setting(source: Any, event_args: KeyValCancelArgs, *args, **kwargs) -> None: if event_args.key == "FillStyle": event_args.cancel = True elif event_args.key == "FillColor": # -1 means automatic color. # Fillcolor for hatch has not automatic color if event_args.value == -1: # strictly speaking this is not needed but follows how Draw handles it. event_args.value = StandardColor.DEFAULT_BLUE