"""
Module for managing character fonts.
.. versionadded:: 0.9.0
"""
# region Imports
from __future__ import annotations
from typing import Any, Tuple, Type, cast, overload, TypeVar
from ooo.dyn.awt.font_strikeout import FontStrikeoutEnum
from ooo.dyn.awt.font_underline import FontUnderlineEnum
from ooo.dyn.style.case_map import CaseMapEnum
from ooo.dyn.awt.font_relief import FontReliefEnum
from ooodev.events.args.cancel_event_args import CancelEventArgs
from ooodev.exceptions import ex as mEx
from ooodev.format.inner.kind.format_kind import FormatKind
from ooodev.format.inner.style_base import StyleBase
from ooodev.utils import props as mProps
from ooodev.utils.color import Color
from ooodev.utils.color import StandardColor
from ooodev.utils.data_type.intensity import Intensity
# endregion Imports
_TFontEffects = TypeVar("_TFontEffects", bound="FontEffects")
[docs]class FontLine:
"""Font Line such as overline and underline."""
[docs] def __init__(self, line: FontUnderlineEnum | None = None, color: Color | None = None) -> None:
"""
Constructor
Args:
line (FontUnderlineEnum, optional): Font Line kind.
color (:py:data:`~.utils.color.Color`, optional): Line color. If value is ``-1`` the automatic color is applied.
Returns:
None:
See Also:
- :ref:`help_writer_format_direct_char_font_effects`
"""
self._line = line
self._color = color
def __eq__(self, oth: object) -> bool:
if isinstance(oth, FontLine):
return self.color == oth.color and self.line == oth.line
return NotImplemented
[docs] def has_values(self) -> bool:
"""Gets if instance has any values."""
return self._line is not None or self._color is not None
@property
def line(self) -> FontUnderlineEnum | None:
"""
Gets/Sets line.
"""
return self._line
@line.setter
def line(self, value: FontUnderlineEnum | None):
self._line = value
@property
def color(self) -> Color | None:
"""
Gets/Sets color.
"""
return self._color
@color.setter
def color(self, value: Color | None):
self._color = value
[docs]class FontEffects(StyleBase):
"""
Character Font Effects
Any properties starting with ``prop_`` set or get current instance values.
All methods starting with ``fmt_`` can be used to chain together font properties.
Many properties can be chained together.
.. versionadded:: 0.9.0
"""
[docs] def __init__(
self,
*,
color: Color | None = None,
transparency: Intensity | int | None = None,
overline: FontLine | None = None,
underline: FontLine | None = None,
strike: FontStrikeoutEnum | None = None,
word_mode: bool | None = None,
case: CaseMapEnum | None = None,
relief: FontReliefEnum | None = None,
outline: bool | None = None,
hidden: bool | None = None,
shadowed: bool | None = None,
) -> None:
"""
Font options used in styles.
Args:
color (:py:data:`~.utils.color.Color`, optional): The value of the text color.
If value is ``-1`` the automatic color is applied.
transparency (Intensity, int, optional): The transparency value from ``0`` to ``100`` for the font color.
overline (FontLine, optional): Character overline values.
underline (FontLine, optional): Character underline values.
strike (FontStrikeoutEnum, optional): Determines the type of the strike out of the character.
word_mode(bool, optional): If ``True``, the underline and strike-through properties are not applied
to white spaces.
case (CaseMapEnum, optional): Specifies the case of the font.
relief (FontReliefEnum, optional): Specifies the relief of the font.
outline (bool, optional): Specifies if the font is outlined.
hidden (bool, optional): Specifies if the font is hidden.
shadowed (bool, optional): Specifies if the characters are formatted and displayed with a shadow effect.
Returns:
None:
See Also:
- :ref:`help_writer_format_direct_char_font_effects`
"""
# could not find any documentation in the API or elsewhere online for Overline
# see: https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1style_1_1CharacterProperties.html
super().__init__()
if transparency is not None:
self.prop_transparency = transparency
if color is not None:
self.prop_color = color
if overline is not None:
self.prop_overline = overline
if underline is not None:
self.prop_underline = underline
if strike is not None:
self.prop_strike = strike
if word_mode is not None:
self.prop_word_mode = word_mode
if case is not None:
self.prop_case = case
if relief is not None:
self.prop_relief = relief
if outline is not None:
self.prop_outline = outline
if hidden is not None:
self.prop_hidden = hidden
if shadowed is not None:
self.prop_shadowed = shadowed
# region methods
def _supported_services(self) -> Tuple[str, ...]:
try:
return self._supported_services_values
except AttributeError:
self._supported_services_values = (
"com.sun.star.style.CharacterProperties",
"com.sun.star.style.CharacterStyle",
"com.sun.star.style.ParagraphStyle",
"com.sun.star.drawing.ControlShape",
"com.sun.star.chart2.Legend",
)
return self._supported_services_values
def _on_modifying(self, source: Any, event: CancelEventArgs) -> None:
if self._is_default_inst:
raise ValueError("Modifying a default instance is not allowed")
return super()._on_modifying(source, event)
# region apply()
@overload
def apply(self, obj: Any) -> None: # type: ignore
...
@overload
def apply(self, obj: Any, **kwargs: Any) -> None: # type: ignore
...
[docs] def apply(self, obj: Any, **kwargs: Any) -> None:
"""
Applies styles to object
Args:
obj (object): UNO object that has supports ``com.sun.star.style.CharacterProperties`` service.
Returns:
None:
"""
super().apply(obj, **kwargs)
# endregion apply()
# region from_obj()
@overload
@classmethod
def from_obj(cls: Type[_TFontEffects], obj: Any) -> _TFontEffects: ...
@overload
@classmethod
def from_obj(cls: Type[_TFontEffects], obj: Any, **kwargs) -> _TFontEffects: ...
[docs] @classmethod
def from_obj(cls: Type[_TFontEffects], obj: Any, **kwargs) -> _TFontEffects:
"""
Gets instance from object
Args:
obj (object): UNO object.
Raises:
NotSupportedError: If ``obj`` is not supported.
Returns:
FontEffects: ``FontEffects`` instance that represents ``obj`` font effects.
"""
# pylint: disable=protected-access
inst = cls(**kwargs)
if not inst._is_valid_obj(obj):
raise mEx.NotSupportedError(f'Object is not supported for conversion to "{cls.__name__}"')
def set_prop(key: str, fe: FontEffects):
nonlocal obj
val = mProps.Props.get(obj, key, None)
if val is not None:
fe._set(key, val)
set_prop("CharColor", inst)
set_prop("CharOverline", inst)
set_prop("CharOverlineColor", inst)
set_prop("CharOverlineHasColor", inst)
set_prop("CharUnderline", inst)
set_prop("CharUnderlineColor", inst)
set_prop("CharUnderlineHasColor", inst)
set_prop("CharWordMode", inst)
set_prop("CharShadowed", inst)
set_prop("CharContoured", inst)
set_prop("CharHidden", inst)
set_prop("CharTransparence", inst)
set_prop("CharStrikeout", inst)
set_prop("CharCaseMap", inst)
set_prop("CharRelief", inst)
inst.set_update_obj(obj)
return inst
# endregion from_obj()
# endregion methods
# region Format Methods
[docs] def fmt_color(self: _TFontEffects, value: Color | None = None) -> _TFontEffects:
"""
Gets copy of instance with text color set or removed.
Args:
value (:py:data:`~.utils.color.Color`, optional): The text color.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_color = value
return ft
[docs] def fmt_transparency(self: _TFontEffects, value: bool | None = None) -> _TFontEffects:
"""
Gets copy of instance with text background transparency set or removed.
Args:
value (bool, optional): The text background transparency.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_transparency = value
return ft
[docs] def fmt_overline(self: _TFontEffects, value: FontUnderlineEnum | None = None) -> _TFontEffects:
"""
Gets copy of instance with overline set or removed.
Args:
value (FontUnderlineEnum, optional): The size of the characters in point units.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
fl = ft.prop_overline
fl.line = value
ft.prop_overline = fl
return ft
[docs] def fmt_overline_color(self: _TFontEffects, value: Color | None = None) -> _TFontEffects:
"""
Gets copy of instance with text overline color set or removed.
Args:
value (:py:data:`~.utils.color.Color`, optional): The color is used for an overline.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
fl = ft.prop_overline
fl.color = value
ft.prop_overline = fl
return ft
[docs] def fmt_strike(self: _TFontEffects, value: FontStrikeoutEnum | None = None) -> _TFontEffects:
"""
Gets copy of instance with strike set or removed.
Args:
value (FontStrikeoutEnum, optional): The type of the strike out of the character.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_strike = value
return ft
[docs] def fmt_underline(self: _TFontEffects, value: FontUnderlineEnum | None = None) -> _TFontEffects:
"""
Gets copy of instance with underline set or removed.
Args:
value (FontUnderlineEnum, optional): The value for the character underline.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
fl = ft.prop_underline
fl.line = value
ft.prop_underline = fl
return ft
[docs] def fmt_underline_color(self: _TFontEffects, value: Color | None = None) -> _TFontEffects:
"""
Gets copy of instance with text underline color set or removed.
Args:
value (:py:data:`~.utils.color.Color`, optional): The color is used for an underline.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
fl = ft.prop_underline
fl.color = value
ft.prop_underline = fl
return ft
[docs] def fmt_word_mode(self: _TFontEffects, value: bool | None = None) -> _TFontEffects:
"""
Gets copy of instance with word mode set or removed.
The underline and strike-through properties are not applied to white spaces when set to ``True``.
Args:
value (bool, optional): The word mode.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_word_mode = value
return ft
[docs] def fmt_case(self: _TFontEffects, value: CaseMapEnum | None = None) -> _TFontEffects:
"""
Gets copy of instance with case set or removed.
Args:
value (CaseMapEnum, optional): The case value.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_case = value
return ft
[docs] def fmt_relief(self: _TFontEffects, value: FontReliefEnum | None = None) -> _TFontEffects:
"""
Gets copy of instance with relief set or removed.
Args:
value (FontReliefEnum, optional): The relief value.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_relief = value
return ft
[docs] def fmt_outline(self: _TFontEffects, value: bool | None = None) -> _TFontEffects:
"""
Gets copy of instance with outline set or removed.
Args:
value (bool, optional): The outline value.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_outline = value
return ft
[docs] def fmt_hidden(self: _TFontEffects, value: bool | None = None) -> _TFontEffects:
"""
Gets copy of instance with hidden set or removed.
Args:
value (bool, optional): The hidden value.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_hidden = value
return ft
[docs] def fmt_shadowed(self: _TFontEffects, value: bool | None = None) -> _TFontEffects:
"""
Gets copy of instance with shadowed set or removed.
Args:
value (bool, optional): The shadowed value.
If ``None`` style is removed. Default ``None``
Returns:
FontEffects: Font with style added or removed
"""
ft = self.copy()
ft.prop_shadowed = value
return ft
# endregion Format Methods
# region Style Properties
@property
def color_auto(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with color set to automatic"""
ft = self.copy()
ft.prop_color = StandardColor.AUTO_COLOR
return ft
@property
def overline(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with overline set"""
ft = self.copy()
ft.prop_overline = FontLine(line=FontUnderlineEnum.SINGLE, color=StandardColor.AUTO_COLOR)
return ft
@property
def overline_color_auto(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with overline color set to automatic"""
ft = self.copy()
fl = ft.prop_overline
fl.color = StandardColor.AUTO_COLOR
ft.prop_overline = fl
return ft
@property
def underline(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with underline set"""
ft = self.copy()
ft.prop_underline = FontLine(line=FontUnderlineEnum.SINGLE, color=StandardColor.AUTO_COLOR)
return ft
@property
def under_color_auto(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with underline color set to automatic"""
ft = self.copy()
fl = ft.prop_underline
fl.color = StandardColor.AUTO_COLOR
ft.prop_underline = fl
return ft
@property
def strike(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with strike set"""
ft = self.copy()
ft.prop_strike = FontStrikeoutEnum.SINGLE
return ft
@property
def word_mode(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with word mode set"""
ft = self.copy()
ft.prop_word_mode = True
return ft
@property
def outline(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with outline set"""
ft = self.copy()
ft.prop_outline = True
return ft
@property
def hidden(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with hidden set"""
ft = self.copy()
ft.prop_hidden = True
return ft
@property
def shadowed(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with shadow set"""
ft = self.copy()
ft.prop_shadowed = True
return ft
@property
def case_upper(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with case set to upper"""
ft = self.copy()
ft.prop_case = CaseMapEnum.UPPERCASE
return ft
@property
def case_lower(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with case set to lower"""
ft = self.copy()
ft.prop_case = CaseMapEnum.LOWERCASE
return ft
@property
def case_title(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with case set to title"""
ft = self.copy()
ft.prop_case = CaseMapEnum.TITLE
return ft
@property
def case_small_caps(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with case set to small caps"""
ft = self.copy()
ft.prop_case = CaseMapEnum.SMALLCAPS
return ft
@property
def case_none(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with no case set"""
ft = self.copy()
ft.prop_case = CaseMapEnum.NONE
return ft
@property
def relief_none(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with no relief set"""
ft = self.copy()
ft.prop_relief = FontReliefEnum.NONE
return ft
@property
def relief_embossed(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with relief set to embossed"""
ft = self.copy()
ft.prop_relief = FontReliefEnum.EMBOSSED
return ft
@property
def relief_engraved(self: _TFontEffects) -> _TFontEffects:
"""Gets copy of instance with relief set to engraved"""
ft = self.copy()
ft.prop_relief = FontReliefEnum.ENGRAVED
return ft
# endregion Style Properties
# region Prop 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.CHAR
return self._format_kind_prop
@property
def prop_color(self) -> Color | None:
"""Gets/Sets the value of the text color."""
return self._get("CharColor")
@prop_color.setter
def prop_color(self, value: Color | None) -> None:
if value is None:
self._remove("CharColor")
return
if value < 0:
self._set("CharColor", -1)
else:
self._set("CharColor", value)
@property
def prop_transparency(self) -> Intensity | None:
"""Gets/Sets The transparency value"""
pv = cast(int, self._get("CharTransparence"))
return Intensity(pv) if pv is not None else None
@prop_transparency.setter
def prop_transparency(self, value: Intensity | int | None) -> None:
if value is None:
self._remove("CharTransparence")
return
self._set("CharTransparence", Intensity(int(value)).value)
@property
def prop_overline(self) -> FontLine:
"""This property contains the value for the character overline."""
pv = cast(int, self._get("CharOverline"))
line = None if pv is None else FontUnderlineEnum(pv)
return FontLine(line=line, color=cast(Color, self._get("CharOverlineColor")))
@prop_overline.setter
def prop_overline(self, value: FontLine | None) -> None:
if value is None:
self._remove("CharOverline")
self._remove("CharOverlineColor")
self._remove("CharOverlineHasColor")
return
if value.line is None:
self._remove("CharOverline")
else:
self._set("CharOverline", value.line.value)
if value.color is None:
self._remove("CharOverlineColor")
self._remove("CharOverlineHasColor")
elif value.color < 0:
# automatic color
self._set("CharOverlineHasColor", False)
self._set("CharOverlineColor", -1)
else:
self._set("CharOverlineHasColor", True)
self._set("CharOverlineColor", value.color)
@property
def prop_underline(self) -> FontLine:
"""This property contains the value for the character underline."""
pv = cast(int, self._get("CharUnderline"))
line = None if pv is None else FontUnderlineEnum(pv)
return FontLine(line=line, color=cast(Color, self._get("CharUnderlineColor")))
@prop_underline.setter
def prop_underline(self, value: FontLine | None) -> None:
if value is None:
self._remove("CharUnderline")
self._remove("CharUnderlineColor")
self._remove("CharUnderlineHasColor")
return
if value.line is None:
self._remove("CharUnderline")
else:
self._set("CharUnderline", value.line.value)
if value.color is None:
self._remove("CharUnderlineColor")
self._remove("CharUnderlineHasColor")
elif value.color < 0:
# automatic color
self._set("CharUnderlineHasColor", False)
self._set("CharUnderlineColor", -1)
else:
self._set("CharUnderlineHasColor", True)
self._set("CharUnderlineColor", value.color)
@property
def prop_strike(self) -> FontStrikeoutEnum | None:
"""Gets/Sets the type of the strike out of the character."""
pv = cast(int, self._get("CharStrikeout"))
return FontStrikeoutEnum(pv) if pv is not None else None
@prop_strike.setter
def prop_strike(self, value: FontStrikeoutEnum | None) -> None:
if value is None:
self._remove("CharStrikeout")
return
self._set("CharStrikeout", value.value)
@property
def prop_word_mode(self) -> bool | None:
"""Gets/Sets Character word mode. If this property is ``True``, the underline and strike-through properties are not applied to white spaces."""
return self._get("CharWordMode")
@prop_word_mode.setter
def prop_word_mode(self, value: bool | None) -> None:
if value is None:
self._remove("CharWordMode")
return
self._set("CharWordMode", value)
@property
def prop_case(self) -> CaseMapEnum | None:
"""Gets/Sets Font Case Value"""
pv = cast(int, self._get("CharCaseMap"))
return None if pv is None else CaseMapEnum(pv)
@prop_case.setter
def prop_case(self, value: CaseMapEnum | None) -> None:
if value is None:
self._remove("CharCaseMap")
return
self._set("CharCaseMap", value.value)
@property
def prop_relief(self) -> FontReliefEnum | None:
"""Gets/Sets Font Relief Value"""
pv = cast(int, self._get("CharRelief"))
return None if pv is None else FontReliefEnum(pv)
@prop_relief.setter
def prop_relief(self, value: FontReliefEnum | None) -> None:
if value is None:
self._remove("CharRelief")
return
self._set("CharRelief", value.value)
@property
def prop_outline(self) -> bool | None:
"""Gets/Sets if the font is outlined"""
return self._get("CharContoured")
@prop_outline.setter
def prop_outline(self, value: bool | None) -> None:
if value is None:
self._remove("CharContoured")
return
self._set("CharContoured", value)
@property
def prop_hidden(self) -> bool | None:
"""Gets/Sets if the font is hidden"""
return self._get("CharHidden")
@prop_hidden.setter
def prop_hidden(self, value: bool | None) -> None:
if value is None:
self._remove("CharHidden")
return
self._set("CharHidden", value)
@property
def prop_shadowed(self) -> bool | None:
"""Gets/Sets if the characters are formatted and displayed with a shadow effect."""
return self._get("CharShadowed")
@prop_shadowed.setter
def prop_shadowed(self, value: bool | None) -> None:
if value is None:
self._remove("CharShadowed")
return
self._set("CharShadowed", value)
@property
def default(self: _TFontEffects) -> _TFontEffects: # type: ignore[misc]
"""Gets Font Position default."""
try:
return self._default_inst
except AttributeError:
# pylint: disable=protected-access
# pylint: disable=unexpected-keyword-arg
fe = self.__class__(_cattribs=self._get_internal_cattribs())
fe._set("CharColor", -1)
fe._set("CharOverline", 0)
fe._set("CharOverlineColor", -1)
fe._set("CharOverlineHasColor", False)
fe._set("CharUnderline", 0)
fe._set("CharUnderlineColor", -1)
fe._set("CharUnderlineHasColor", False)
fe._set("CharWordMode", False)
fe._set("CharShadowed", False)
fe._set("CharContoured", False)
fe._set("CharHidden", False)
fe._set("CharTransparence", 100)
fe._set("CharStrikeout", 0)
fe._set("CharCaseMap", 0)
fe._set("CharRelief", 0)
fe._is_default_inst = True
self._default_inst = fe
return self._default_inst
# endregion Prop Properties