from dataclasses import dataclass from typing import Generator from docx.shared import Parented from .caption import CaptionInfo from .image import Image from .listing import Listing from .renderable import Renderable from .requires_numbering import RequiresNumbering from ..diagram_renderer import render_diagram from ..layout_tracker import LayoutState from ..rendered_info import RenderedInfo class DiagramFigure(Renderable, RequiresNumbering): """UML / Mermaid / scheme fence → figure (+ optional source listing).""" def __init__( self, parent: Parented, lang: str, source: str, caption_info: CaptionInfo | None = None, with_listing: bool = False, ): super().__init__("Рисунок") self._parent = parent self._lang = lang self._source = source self._caption_info = caption_info self._with_listing = with_listing or ( caption_info.with_listing if caption_info else False ) self._number = None self._listing_number = None self.landscape = bool(caption_info and caption_info.landscape) if caption_info and caption_info.unique_name: self.unique_name = caption_info.unique_name self.listing: Listing | None = None if self._with_listing: listing_caption = CaptionInfo( self.unique_name, # same id → @Листинг:id caption_info.text if caption_info else None, ) self.listing = Listing(parent, lang, listing_caption) self.listing.set_text(source) def set_number(self, number: str): self._number = number def set_listing_number(self, number: str): self._listing_number = number if self.listing: self.listing.set_number(number) def render(self, previous_rendered: RenderedInfo, layout_state: LayoutState) \ -> Generator[RenderedInfo, None, None]: result = render_diagram(self._lang, self._source) image = Image( self._parent, result.png_path, self._caption_info, svg_path=result.svg_path, pixel_scale=result.pixel_scale, ) if self._number is not None: image.set_number(self._number) yield from image.render(previous_rendered, layout_state) if self.listing is not None: if self._listing_number is not None: self.listing.set_number(self._listing_number) yield from self.listing.render(None, layout_state)