from typing import Optional, Type, TYPE_CHECKING, cast
from pyexlatex.typing import PyexlatexItems, PyexlatexItem
if TYPE_CHECKING:
from pyexlatex.presentation.beamer.overlay.overlay import Overlay
from pyexlatex.models.environment import Environment
from pyexlatex.models.item import Item
from mixins.repr import ReprMixin
from pyexlatex.logic.format.contents import format_contents as fmt
from pyexlatex.logic.builder import _build
from pyexlatex.models.documentitem import DocumentItem
from pyexlatex.models.label import Label
from pyexlatex.models.containeritem import ContainerItem
[docs]class TextAreaMixin(ContainerItem):
"""
Mixin for extracting data from content then formatting it, regardless of the data type passed
"""
name = 'textarea'
next_level_down_class: Optional[Type['TextAreaBase']] = None # once subclassed, will be overridden with the next level down text area class
[docs] def __init__(self, name, contents, label: Optional[str] = None, **kwargs):
self.add_data_from_content(contents)
contents = self.format_contents(contents)
if label is not None:
label = Label(label)
if not isinstance(contents, (list, tuple)):
contents = [contents]
contents = contents + [label]
self.contents = contents
super().__init__(name, contents, **kwargs)
[docs] def format_contents(self, contents):
if isinstance(contents, (list, tuple)):
return [self.format_contents(c) for c in contents]
elif isinstance(contents, dict):
if self.next_level_down_class is None:
raise ValueError(f'cannot parse dict as have no next_level_down_class in {self.__class__.name}')
subcontents = []
for title, content in contents.items():
subcontents.append(
self.next_level_down_class(content, title=title)
)
return subcontents
else:
# Not an iterable
return self._format_content(contents)
[docs] def format_contents_and_build(self, contents: PyexlatexItems):
contents = self.format_contents(contents)
return self._build(contents)
def _build(self, contents: PyexlatexItems) -> PyexlatexItem:
if isinstance(contents, (list, tuple)):
contents = [self._build(c) for c in contents]
return _build(contents)
contents = cast(PyexlatexItem, contents)
return contents
def _format_content(self, content):
if isinstance(content, str):
return fmt(content)
else:
# Class is responsible for formatting. This may be a latex class or some
# other harmless conversion such as int. It may also be an issue if the __str__
# method of the class is not valid latex
return content
[docs]class EnvironmentTextArea(TextAreaMixin, Environment):
[docs] def __init__(self, name, modifiers: Optional[str] = None, overlay: Optional['Overlay'] = None):
Environment.__init__(self, name, modifiers=modifiers, overlay=overlay)
[docs] def wrap(self, other):
self.add_data_from_content(other)
contents = self.format_contents_and_build(other)
return super().wrap(contents)
[docs]class TextAreaBase(TextAreaMixin, Item, ReprMixin):
repr_cols = ['title', 'contents']
[docs]class SectionBase(TextAreaBase):
name = 'section'
repr_cols = ['title', 'short_title', 'contents']
[docs] def __init__(self, contents, title: str, short_title: Optional[str] = None, **kwargs):
self.title = title
self.short_title = short_title
super().__init__(self.name, contents, env_modifiers=self.env_modifiers, **kwargs)
@property
def env_modifiers(self):
modifier_str = ''
if self.short_title is not None:
modifier_str += f'[{fmt(self.short_title)}]'
modifier_str += f'{{{fmt(self.title)}}}'
return modifier_str
[docs]class ParagraphBase(TextAreaBase):
name = 'paragraph'
repr_cols = ['title', 'contents']
[docs] def __init__(self, contents, title: Optional[str] = None, **kwargs):
self.title = title
super().__init__(self.name, contents, env_modifiers=self.env_modifiers, **kwargs)
@property
def env_modifiers(self):
if self.title is not None:
return f'{{{self.title}}}'
return None