nelsie

 1from .basictypes import AlignItems, AlignContent, FlexWrap, Stroke, TextAlign
 2from .insteps import InSteps
 3from .shapes import Arrow, Path
 4from .slidedeck import Resources, SlideDeck, Slide
 5from .textstyle import FontStretch, TextStyle
 6from .box import Box, BoxBuilder
 7
 8__all__ = [
 9    "SlideDeck",
10    "InSteps",
11    "Path",
12    "Stroke",
13    "TextStyle",
14    "Resources",
15    "FontStretch",
16    "TextAlign",
17    "FlexWrap",
18    "AlignItems",
19    "AlignContent",
20    "Arrow",
21    "BoxBuilder",
22    "Box",
23    "Slide",
24]
class SlideDeck:
 69class SlideDeck:
 70    def __init__(
 71        self,
 72        *,
 73        width: float = 1024,
 74        height: float = 768,
 75        bg_color: str = "white",
 76        image_directory: str | None = None,
 77        resources: Resources | None = None,
 78        default_font: str | None = None,
 79        default_monospace_font: str | None = None,
 80        default_code_theme: str = "InspiredGitHub",
 81        default_code_language: str | None = None,
 82    ):
 83        """
 84        A top-level class of Nelsie. It represents a set of slides.
 85
 86        Arguments:
 87        * width - default width of a slide (could be overriden for each slide)
 88        * height - default width of a slide (could be overriden for each slide)
 89        * bg_color - default background color a slide (could be overriden for each slide)
 90        * image_directory - default path where images are searched for (could be overriden for each slide)
 91        * resource - Resource instance, if None a new instance is created
 92        * default_font - Name of default font
 93        * default_monospace_font - Name of the default monospace font
 94        * default_code_theme - Name of default theme for syntax highlighting (.code() method):
 95            Available themes:
 96            * "base16-ocean.dark"
 97            * "base16-eighties.dark"
 98            * "base16-mocha.dark"
 99            * "base16-ocean.light"
100            * "InspiredGitHub"
101            * "Solarized (dark)"
102            * "Solarized (light)"
103        * default_code_language - Default language to use for syntax highlighting (.code() method)
104        """
105        if resources is None:
106            resources = Resources()
107
108        self.width = width
109        self.height = height
110        self.bg_color = bg_color
111        self.image_directory = image_directory
112        self.resources = resources
113        self.default_code_theme = default_code_theme
114        self.default_code_language = default_code_language
115        self._deck = nelsie_rs.Deck(resources, default_font, default_monospace_font)
116
117    def set_style(self, name: str, style: TextStyle):
118        self._deck.set_style(self.resources, name, style, False, None, None)
119
120    def update_style(self, name: str, style: TextStyle):
121        self._deck.set_style(self.resources, name, style, True, None, None)
122
123    def get_style(self, name: str, step: int = 1) -> TextStyle:
124        return _data_to_text_style(self._deck.get_style(name, step, None, None))
125
126    def new_slide(
127        self,
128        *,
129        width: float | None = None,
130        height: float | None = None,
131        bg_color: str | None = None,
132        image_directory: str | None = None,
133        name: str = "",
134        debug_steps: bool = False,
135        debug_layout: bool | str = False,
136        counters: list[str] | None = None,
137        parent_slide: tuple[Slide, int] | None = None,
138        step_1: bool = True,
139    ) -> Slide:
140        """
141        Creates a new slide in the slide deck.
142        """
143        if width is None:
144            width = self.width
145        if height is None:
146            height = self.height
147        if bg_color is None:
148            bg_color = self.bg_color
149        if image_directory is None:
150            image_directory = self.image_directory
151        debug_layout = parse_debug_layout(debug_layout)
152        slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide)
153        return Slide(self, slide_id, name, image_directory, debug_layout)
154
155    def slide(
156        self,
157        *,
158        width: float | None = None,
159        height: float | None = None,
160        bg_color: str | None = None,
161        image_directory: str | None = None,
162        name: str = "",
163        debug_steps: bool = False,
164        debug_layout: bool | str = False,
165        counters: list[str] | None = None,
166        parent_slide: tuple[Slide, int] | None = None,
167        step_1: bool = True,
168    ):
169        """
170        Decorator for creating new slide.
171        It immediately calls the decorated function that should define content of the slide.
172        Slide is automatically added into the deck.
173
174        Example:
175        ```python
176        deck = SlideDeck()
177
178        @deck.slide()
179        def my_first_slide(slide):
180            slide.text("Hello!")
181        ```
182        """
183
184        def helper(fn):
185            slide = self.new_slide(
186                width=width,
187                height=height,
188                bg_color=bg_color,
189                image_directory=image_directory,
190                name=name,
191                debug_steps=debug_steps,
192                debug_layout=debug_layout,
193                counters=counters,
194                parent_slide=parent_slide,
195                step_1=step_1,
196            )
197            fn(slide)
198            return slide
199
200        return helper
201
202    def render(
203        self,
204        path: str | pathlib.Path | None,
205        output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf",
206        *,
207        verbose: int = 1,
208        n_threads: int | None = None,
209    ) -> None | list[bytes]:
210        """
211        Render slides
212
213        If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then
214        `path` specifies a directory where the slides are created as an individual files.
215
216        If `path` is None then objects are not written to the file system, and they are returned as python objects
217        from the method call.
218        """
219        if path:
220            path = str(path)
221        return self._deck.render(self.resources, verbose, output_format, path, n_threads)
SlideDeck( *, width: float = 1024, height: float = 768, bg_color: str = 'white', image_directory: str | None = None, resources: Resources | None = None, default_font: str | None = None, default_monospace_font: str | None = None, default_code_theme: str = 'InspiredGitHub', default_code_language: str | None = None)
 70    def __init__(
 71        self,
 72        *,
 73        width: float = 1024,
 74        height: float = 768,
 75        bg_color: str = "white",
 76        image_directory: str | None = None,
 77        resources: Resources | None = None,
 78        default_font: str | None = None,
 79        default_monospace_font: str | None = None,
 80        default_code_theme: str = "InspiredGitHub",
 81        default_code_language: str | None = None,
 82    ):
 83        """
 84        A top-level class of Nelsie. It represents a set of slides.
 85
 86        Arguments:
 87        * width - default width of a slide (could be overriden for each slide)
 88        * height - default width of a slide (could be overriden for each slide)
 89        * bg_color - default background color a slide (could be overriden for each slide)
 90        * image_directory - default path where images are searched for (could be overriden for each slide)
 91        * resource - Resource instance, if None a new instance is created
 92        * default_font - Name of default font
 93        * default_monospace_font - Name of the default monospace font
 94        * default_code_theme - Name of default theme for syntax highlighting (.code() method):
 95            Available themes:
 96            * "base16-ocean.dark"
 97            * "base16-eighties.dark"
 98            * "base16-mocha.dark"
 99            * "base16-ocean.light"
100            * "InspiredGitHub"
101            * "Solarized (dark)"
102            * "Solarized (light)"
103        * default_code_language - Default language to use for syntax highlighting (.code() method)
104        """
105        if resources is None:
106            resources = Resources()
107
108        self.width = width
109        self.height = height
110        self.bg_color = bg_color
111        self.image_directory = image_directory
112        self.resources = resources
113        self.default_code_theme = default_code_theme
114        self.default_code_language = default_code_language
115        self._deck = nelsie_rs.Deck(resources, default_font, default_monospace_font)

A top-level class of Nelsie. It represents a set of slides.

Arguments:

  • width - default width of a slide (could be overriden for each slide)
  • height - default width of a slide (could be overriden for each slide)
  • bg_color - default background color a slide (could be overriden for each slide)
  • image_directory - default path where images are searched for (could be overriden for each slide)
  • resource - Resource instance, if None a new instance is created
  • default_font - Name of default font
  • default_monospace_font - Name of the default monospace font
  • default_code_theme - Name of default theme for syntax highlighting (.code() method): Available themes:
    • "base16-ocean.dark"
    • "base16-eighties.dark"
    • "base16-mocha.dark"
    • "base16-ocean.light"
    • "InspiredGitHub"
    • "Solarized (dark)"
    • "Solarized (light)"
  • default_code_language - Default language to use for syntax highlighting (.code() method)
width
height
bg_color
image_directory
resources
default_code_theme
default_code_language
def set_style(self, name: str, style: TextStyle):
117    def set_style(self, name: str, style: TextStyle):
118        self._deck.set_style(self.resources, name, style, False, None, None)
def update_style(self, name: str, style: TextStyle):
120    def update_style(self, name: str, style: TextStyle):
121        self._deck.set_style(self.resources, name, style, True, None, None)
def get_style(self, name: str, step: int = 1) -> TextStyle:
123    def get_style(self, name: str, step: int = 1) -> TextStyle:
124        return _data_to_text_style(self._deck.get_style(name, step, None, None))
def new_slide( self, *, width: float | None = None, height: float | None = None, bg_color: str | None = None, image_directory: str | None = None, name: str = '', debug_steps: bool = False, debug_layout: bool | str = False, counters: list[str] | None = None, parent_slide: tuple[Slide, int] | None = None, step_1: bool = True) -> Slide:
126    def new_slide(
127        self,
128        *,
129        width: float | None = None,
130        height: float | None = None,
131        bg_color: str | None = None,
132        image_directory: str | None = None,
133        name: str = "",
134        debug_steps: bool = False,
135        debug_layout: bool | str = False,
136        counters: list[str] | None = None,
137        parent_slide: tuple[Slide, int] | None = None,
138        step_1: bool = True,
139    ) -> Slide:
140        """
141        Creates a new slide in the slide deck.
142        """
143        if width is None:
144            width = self.width
145        if height is None:
146            height = self.height
147        if bg_color is None:
148            bg_color = self.bg_color
149        if image_directory is None:
150            image_directory = self.image_directory
151        debug_layout = parse_debug_layout(debug_layout)
152        slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide)
153        return Slide(self, slide_id, name, image_directory, debug_layout)

Creates a new slide in the slide deck.

def slide( self, *, width: float | None = None, height: float | None = None, bg_color: str | None = None, image_directory: str | None = None, name: str = '', debug_steps: bool = False, debug_layout: bool | str = False, counters: list[str] | None = None, parent_slide: tuple[Slide, int] | None = None, step_1: bool = True):
155    def slide(
156        self,
157        *,
158        width: float | None = None,
159        height: float | None = None,
160        bg_color: str | None = None,
161        image_directory: str | None = None,
162        name: str = "",
163        debug_steps: bool = False,
164        debug_layout: bool | str = False,
165        counters: list[str] | None = None,
166        parent_slide: tuple[Slide, int] | None = None,
167        step_1: bool = True,
168    ):
169        """
170        Decorator for creating new slide.
171        It immediately calls the decorated function that should define content of the slide.
172        Slide is automatically added into the deck.
173
174        Example:
175        ```python
176        deck = SlideDeck()
177
178        @deck.slide()
179        def my_first_slide(slide):
180            slide.text("Hello!")
181        ```
182        """
183
184        def helper(fn):
185            slide = self.new_slide(
186                width=width,
187                height=height,
188                bg_color=bg_color,
189                image_directory=image_directory,
190                name=name,
191                debug_steps=debug_steps,
192                debug_layout=debug_layout,
193                counters=counters,
194                parent_slide=parent_slide,
195                step_1=step_1,
196            )
197            fn(slide)
198            return slide
199
200        return helper

Decorator for creating new slide. It immediately calls the decorated function that should define content of the slide. Slide is automatically added into the deck.

Example:

deck = SlideDeck()

@deck.slide()
def my_first_slide(slide):
    slide.text("Hello!")
def render( self, path: str | pathlib.Path | None, output_format: Union[Literal['pdf'], Literal['svg'], Literal['png']] = 'pdf', *, verbose: int = 1, n_threads: int | None = None) -> None | list[bytes]:
202    def render(
203        self,
204        path: str | pathlib.Path | None,
205        output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf",
206        *,
207        verbose: int = 1,
208        n_threads: int | None = None,
209    ) -> None | list[bytes]:
210        """
211        Render slides
212
213        If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then
214        `path` specifies a directory where the slides are created as an individual files.
215
216        If `path` is None then objects are not written to the file system, and they are returned as python objects
217        from the method call.
218        """
219        if path:
220            path = str(path)
221        return self._deck.render(self.resources, verbose, output_format, path, n_threads)

Render slides

If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then path specifies a directory where the slides are created as an individual files.

If path is None then objects are not written to the file system, and they are returned as python objects from the method call.

class InSteps(typing.Generic[~T]):
10class InSteps(Generic[T]):
11    """
12    InSteps is a wrapper that allows to set a different values for each step.
13    InSteps defines values in "key" steps, in other steps the value remains until it is changed
14    another key step.
15
16    Example:
17    ```python
18    slide.box(..., bg_color=InSteps({1: "green", 4: "red"})
19    ```
20
21    Defines "green" background for steps 1, 2, 3; and "red" for step 4 and further.
22
23    InSteps can be also initialized by a list, then it defines values for first `n` steps,
24    where `n` is a length of the list. It means that `InSteps(["a", "b", "c"])` is equal to
25    `InSteps({1: "a", 2: "b", 3: "c"})`
26    """
27
28    def __init__(
29        self,
30        values: Sequence[T] | dict[Step | int, T],
31    ):
32        if isinstance(values, Sequence):
33            tmp = {}
34            prev = None
35            for i, v in enumerate(values):
36                if i != 0 and v == prev:
37                    continue
38                tmp[i + 1] = v
39                prev = v
40            values = tmp
41        elif not isinstance(values, dict):
42            raise ValueError("Invalid type for values")
43        self.in_step_values = values
44
45    def get(self, step: int, default: S = None) -> T | None:
46        v = self.in_step_values.get(step)
47        if v is not None:
48            return v
49        if step <= 0:
50            return default
51        return self.get(step - 1, default)
52
53    def map(self, fn):
54        return InSteps(
55            {step: fn(v) for step, v in self.in_step_values.items()},
56        )
57
58    def key_steps(self):
59        return self.in_step_values.keys()
60
61    def zip(self, other: "InSteps[S]") -> "InSteps[tuple[S, T]]":
62        keys = set(self.key_steps())
63        keys.update(other.key_steps())
64        return InSteps(
65            {step: (self.get(step), other.get(step)) for step in keys},
66        )

InSteps is a wrapper that allows to set a different values for each step. InSteps defines values in "key" steps, in other steps the value remains until it is changed another key step.

Example:

slide.box(..., bg_color=InSteps({1: "green", 4: "red"})

Defines "green" background for steps 1, 2, 3; and "red" for step 4 and further.

InSteps can be also initialized by a list, then it defines values for first n steps, where n is a length of the list. It means that InSteps(["a", "b", "c"]) is equal to InSteps({1: "a", 2: "b", 3: "c"})

InSteps(values: Union[Sequence[~T], dict[tuple[int] | int, ~T]])
28    def __init__(
29        self,
30        values: Sequence[T] | dict[Step | int, T],
31    ):
32        if isinstance(values, Sequence):
33            tmp = {}
34            prev = None
35            for i, v in enumerate(values):
36                if i != 0 and v == prev:
37                    continue
38                tmp[i + 1] = v
39                prev = v
40            values = tmp
41        elif not isinstance(values, dict):
42            raise ValueError("Invalid type for values")
43        self.in_step_values = values
in_step_values
def get(self, step: int, default: ~S = None) -> Optional[~T]:
45    def get(self, step: int, default: S = None) -> T | None:
46        v = self.in_step_values.get(step)
47        if v is not None:
48            return v
49        if step <= 0:
50            return default
51        return self.get(step - 1, default)
def map(self, fn):
53    def map(self, fn):
54        return InSteps(
55            {step: fn(v) for step, v in self.in_step_values.items()},
56        )
def key_steps(self):
58    def key_steps(self):
59        return self.in_step_values.keys()
def zip( self, other: InSteps[~S]) -> InSteps[tuple[~S, ~T]]:
61    def zip(self, other: "InSteps[S]") -> "InSteps[tuple[S, T]]":
62        keys = set(self.key_steps())
63        keys.update(other.key_steps())
64        return InSteps(
65            {step: (self.get(step), other.get(step)) for step in keys},
66        )
class Path:
 37class Path:
 38    def __init__(
 39        self,
 40        *,
 41        stroke: Stroke | None = None,
 42        fill_color: str | None = None,
 43        arrow_start: Arrow | None = None,
 44        arrow_end: Arrow | None = None,
 45    ):
 46        self.stroke = stroke
 47        self.fill_color = fill_color
 48        self.commands = []
 49        self.points = []
 50        self.arrow_start = arrow_start
 51        self.arrow_end = arrow_end
 52
 53    @staticmethod
 54    def oval(
 55        x1: PathValue,
 56        y1: PathValue,
 57        x2: PathValue,
 58        y2: PathValue,
 59        *,
 60        stroke: Stroke | None = None,
 61        fill_color: str | None = None,
 62    ):
 63        path = Path(stroke=stroke, fill_color=fill_color)
 64        path.commands.append("oval")
 65        path.points = [x1, y1, x2, y2]
 66        return path
 67
 68    def close(self):
 69        self.commands.append("close")
 70        return self
 71
 72    def move_to(self, x: PathValue, y: PathValue):
 73        self.commands.append("move")
 74        self.points.append(x)
 75        self.points.append(y)
 76        return self
 77
 78    def line_to(self, x: PathValue, y: PathValue):
 79        self.commands.append("line")
 80        self.points.append(x)
 81        self.points.append(y)
 82        return self
 83
 84    def quad_to(self, x1: PathValue, y1: PathValue, x: PathValue, y: PathValue):
 85        self.commands.append("quad")
 86        self.points.append(x1)
 87        self.points.append(y1)
 88        self.points.append(x)
 89        self.points.append(y)
 90        return self
 91
 92    def cubic_to(
 93        self,
 94        x1: PathValue,
 95        y1: PathValue,
 96        x2: PathValue,
 97        y2: PathValue,
 98        x: PathValue,
 99        y: PathValue,
100    ):
101        self.commands.append("cubic")
102        self.points.append(x1)
103        self.points.append(y1)
104        self.points.append(x2)
105        self.points.append(y2)
106        self.points.append(x)
107        self.points.append(y)
108        return self
Path( *, stroke: Stroke | None = None, fill_color: str | None = None, arrow_start: Arrow | None = None, arrow_end: Arrow | None = None)
38    def __init__(
39        self,
40        *,
41        stroke: Stroke | None = None,
42        fill_color: str | None = None,
43        arrow_start: Arrow | None = None,
44        arrow_end: Arrow | None = None,
45    ):
46        self.stroke = stroke
47        self.fill_color = fill_color
48        self.commands = []
49        self.points = []
50        self.arrow_start = arrow_start
51        self.arrow_end = arrow_end
stroke
fill_color
commands
points
arrow_start
arrow_end
@staticmethod
def oval( x1: int | float | nelsie.layoutexpr.LayoutExpr, y1: int | float | nelsie.layoutexpr.LayoutExpr, x2: int | float | nelsie.layoutexpr.LayoutExpr, y2: int | float | nelsie.layoutexpr.LayoutExpr, *, stroke: Stroke | None = None, fill_color: str | None = None):
53    @staticmethod
54    def oval(
55        x1: PathValue,
56        y1: PathValue,
57        x2: PathValue,
58        y2: PathValue,
59        *,
60        stroke: Stroke | None = None,
61        fill_color: str | None = None,
62    ):
63        path = Path(stroke=stroke, fill_color=fill_color)
64        path.commands.append("oval")
65        path.points = [x1, y1, x2, y2]
66        return path
def close(self):
68    def close(self):
69        self.commands.append("close")
70        return self
def move_to( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
72    def move_to(self, x: PathValue, y: PathValue):
73        self.commands.append("move")
74        self.points.append(x)
75        self.points.append(y)
76        return self
def line_to( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
78    def line_to(self, x: PathValue, y: PathValue):
79        self.commands.append("line")
80        self.points.append(x)
81        self.points.append(y)
82        return self
def quad_to( self, x1: int | float | nelsie.layoutexpr.LayoutExpr, y1: int | float | nelsie.layoutexpr.LayoutExpr, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
84    def quad_to(self, x1: PathValue, y1: PathValue, x: PathValue, y: PathValue):
85        self.commands.append("quad")
86        self.points.append(x1)
87        self.points.append(y1)
88        self.points.append(x)
89        self.points.append(y)
90        return self
def cubic_to( self, x1: int | float | nelsie.layoutexpr.LayoutExpr, y1: int | float | nelsie.layoutexpr.LayoutExpr, x2: int | float | nelsie.layoutexpr.LayoutExpr, y2: int | float | nelsie.layoutexpr.LayoutExpr, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
 92    def cubic_to(
 93        self,
 94        x1: PathValue,
 95        y1: PathValue,
 96        x2: PathValue,
 97        y2: PathValue,
 98        x: PathValue,
 99        y: PathValue,
100    ):
101        self.commands.append("cubic")
102        self.points.append(x1)
103        self.points.append(y1)
104        self.points.append(x2)
105        self.points.append(y2)
106        self.points.append(x)
107        self.points.append(y)
108        return self
@dataclass
class Stroke:
14@dataclass
15class Stroke:
16    color: str
17    width: float = 1.0
18    dash_array: list[float] | None = None
19    dash_offset: float = 0.0
Stroke( color: str, width: float = 1.0, dash_array: list[float] | None = None, dash_offset: float = 0.0)
color: str
width: float = 1.0
dash_array: list[float] | None = None
dash_offset: float = 0.0
@dataclass(frozen=True)
class TextStyle:
22@dataclass(frozen=True)
23class TextStyle:
24    font_family: str | list[str] | None = None
25    color: str | Literal["empty"] | None = None
26    stroke: Stroke | Literal["empty"] | None = None
27    size: float | None = None
28    line_spacing: float | None = None
29    italic: bool | None = None
30    stretch: FontStretch | None = None
31    underline: bool | None = None
32    overline: bool | None = None
33    line_through: bool | None = None
34
35    # 1-1000; 400 = Normal, 700 = Bold
36    weight: int | None = None
37
38    def __post_init__(self):
39        if self.size is not None:
40            assert self.size >= 0
41        if self.line_spacing is not None:
42            assert self.line_spacing >= 0
43        if self.weight is not None:
44            assert 1 <= self.weight <= 1000
45
46    def merge(self, other: "TextStyle") -> "TextStyle":
47        assert isinstance(other, TextStyle)
48        return TextStyle(
49            *[b if b is not None else a for (a, b) in zip(unpack_dataclass(self), unpack_dataclass(other))]
50        )
TextStyle( font_family: str | list[str] | None = None, color: Union[str, Literal['empty'], NoneType] = None, stroke: Union[Stroke, Literal['empty'], NoneType] = None, size: float | None = None, line_spacing: float | None = None, italic: bool | None = None, stretch: FontStretch | None = None, underline: bool | None = None, overline: bool | None = None, line_through: bool | None = None, weight: int | None = None)
font_family: str | list[str] | None = None
color: Union[str, Literal['empty'], NoneType] = None
stroke: Union[Stroke, Literal['empty'], NoneType] = None
size: float | None = None
line_spacing: float | None = None
italic: bool | None = None
stretch: FontStretch | None = None
underline: bool | None = None
overline: bool | None = None
line_through: bool | None = None
weight: int | None = None
def merge(self, other: TextStyle) -> TextStyle:
46    def merge(self, other: "TextStyle") -> "TextStyle":
47        assert isinstance(other, TextStyle)
48        return TextStyle(
49            *[b if b is not None else a for (a, b) in zip(unpack_dataclass(self), unpack_dataclass(other))]
50        )
class Resources:
def load_code_syntax_dir(self, /, path):
def load_code_theme_dir(self, /, path):
def load_fonts_dir(self, /, path):
def syntaxes(self, /):
def themes(self, /):
class FontStretch(enum.IntEnum):
10class FontStretch(IntEnum):
11    UltraCondensed = 1
12    ExtraCondensed = 2
13    Condensed = 3
14    SemiCondensed = 4
15    Normal = 5
16    SemiExpanded = 6
17    Expanded = 7
18    ExtraExpanded = 8
19    UltraExpanded = 9

An enumeration.

UltraCondensed = <FontStretch.UltraCondensed: 1>
ExtraCondensed = <FontStretch.ExtraCondensed: 2>
Condensed = <FontStretch.Condensed: 3>
SemiCondensed = <FontStretch.SemiCondensed: 4>
Normal = <FontStretch.Normal: 5>
SemiExpanded = <FontStretch.SemiExpanded: 6>
Expanded = <FontStretch.Expanded: 7>
ExtraExpanded = <FontStretch.ExtraExpanded: 8>
UltraExpanded = <FontStretch.UltraExpanded: 9>
Inherited Members
enum.Enum
name
value
builtins.int
conjugate
bit_length
bit_count
to_bytes
from_bytes
as_integer_ratio
real
imag
numerator
denominator
TextAlign = typing.Literal['start', 'center', 'end']
FlexWrap = typing.Literal['nowrap', 'wrap', 'wrap-reverse']
AlignItems = typing.Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']
AlignContent = typing.Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-evenly', 'space-around']
@dataclass
class Arrow:
10@dataclass
11class Arrow:
12    """
13    Represents an SVG arrow head. Can be attached to the start or end points of lines.
14    """
15
16    size: float = 10
17    """Size of the arrow head in pixels."""
18
19    angle: float = 40
20    """Angle of the arrow head."""
21
22    color: str | None = None
23    """Color of arrow, if None color is taken from path"""
24
25    stroke_width: float | None = None
26    """If None then a filled arrow is drawn, if float then stroked arrow is drawn with the given stroke width"""
27
28    inner_point: float | None = None
29    """ Shape of the arrow head.
30
31        * < 1.0 -> Sharper arrow.
32        * = 1.0 -> Normal arrow.
33        * > 1.0 -> Diamond shape arrow.
34    """

Represents an SVG arrow head. Can be attached to the start or end points of lines.

Arrow( size: float = 10, angle: float = 40, color: str | None = None, stroke_width: float | None = None, inner_point: float | None = None)
size: float = 10

Size of the arrow head in pixels.

angle: float = 40

Angle of the arrow head.

color: str | None = None

Color of arrow, if None color is taken from path

stroke_width: float | None = None

If None then a filled arrow is drawn, if float then stroked arrow is drawn with the given stroke width

inner_point: float | None = None

Shape of the arrow head.

  • < 1.0 -> Sharper arrow.
  • = 1.0 -> Normal arrow.
  • > 1.0 -> Diamond shape arrow.
class BoxBuilder:
 50class BoxBuilder:
 51    def get_box(self):
 52        """
 53        @private
 54        """
 55        raise NotImplementedError
 56
 57    def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
 58        """
 59        Set text style under given name.
 60        """
 61        box = self.get_box()
 62        deck = box.deck
 63        deck._deck.set_style(deck.resources, name, style, False, box.slide._slide_id, box._box_id)
 64
 65    def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
 66        """
 67        Load a text style and merge it with the `style` and save it back.
 68        Throws an exception if a style under given name does not exist.
 69        """
 70        box = self.get_box()
 71        deck = box.deck
 72        deck._deck.set_style(deck.resources, name, style, True, box.slide._slide_id, box._box_id)
 73
 74    def get_style(self, name: str, step: int = 1) -> TextStyle:
 75        """
 76        Get text style under given name. Style is returned for a given `step`.
 77        Throws an exception if a style under given name does not exist.
 78
 79        This function returns text style even when InSteps was used to set the style,
 80        as it returns text style for a given step.
 81        """
 82
 83        box = self.get_box()
 84        return _data_to_text_style(box.deck._deck.get_style(name, step, box.slide._slide_id, box._box_id))
 85
 86    def image(self, path: str | None | InSteps[str | None], enable_steps=True, shift_steps=0, **box_args):
 87        """
 88        Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA
 89        """
 90        assert shift_steps >= 0
 91
 92        def process_path(p):
 93            if p is None:
 94                return None
 95            if slide.image_directory is not None:
 96                p = os.path.join(slide.image_directory, p)
 97            p = os.path.abspath(p)
 98            watch_path(p)
 99            return p
100
101        slide = self.get_box().slide
102        if isinstance(path, InSteps):
103            path = path.map(process_path)
104        else:
105            path = process_path(path)
106        image = ImageContent(
107            path=path,
108            enable_steps=enable_steps,
109            shift_steps=shift_steps,
110        )
111        return self.box(_content=image, **box_args)
112
113    def text(
114        self,
115        text: str | InSteps[str],
116        style: str | TextStyle | InSteps[TextStyle] | None = None,
117        *,
118        parse_styles: bool = True,
119        style_delimiters: str | None = "~{}",
120        tab_width: int = 4,
121        align: TextAlign = "start",
122        strip=True,
123        parse_counters: bool = False,
124        **box_args,
125    ):
126        """
127        Create a box with a text.
128        """
129        box_args.setdefault("name", "text")
130        return self._text_box(
131            text,
132            style,
133            None,
134            style_delimiters if parse_styles else None,
135            tab_width,
136            box_args,
137            align,
138            None,
139            None,
140            strip,
141            parse_counters,
142        )
143
144    def code(
145        self,
146        text: str | InSteps[str],
147        language: str | None = "default",
148        style: str | TextStyle | InSteps[TextStyle] | None = None,
149        *,
150        theme: str | None = None,
151        parse_styles: bool = False,
152        style_delimiters: str | None = "~{}",
153        tab_width: int = 4,
154        align: TextAlign = "start",
155        strip: bool = True,
156        parse_counters: bool = False,
157        **box_args,
158    ):
159        """
160        Create a box with a syntax highlighted text.
161        """
162        box_args.setdefault("name", "code")
163        if theme is None:
164            theme = self.get_box().deck.default_code_theme
165        if language == "default":
166            language = self.get_box().deck.default_code_language
167        return self._text_box(
168            text,
169            "code",
170            style,
171            style_delimiters if parse_styles else None,
172            tab_width,
173            box_args,
174            align,
175            language,
176            theme,
177            strip,
178            parse_counters,
179        )
180
181    def _text_box(
182        self,
183        text,
184        style1,
185        style2,
186        delimiters,
187        tab_width,
188        box_args,
189        align,
190        language,
191        theme,
192        strip,
193        parse_counters,
194    ):
195        def text_preprocess(x):
196            if strip:
197                x = x.strip()
198            return x.replace("\t", " " * tab_width)
199
200        if isinstance(text, str):
201            text = text_preprocess(text)
202        elif isinstance(text, list):
203            text = zip_in_steps(text, "").map(lambda x: text_preprocess("".join(x)))
204        elif isinstance(text, InSteps):
205            text = text.map(text_preprocess)
206        else:
207            raise Exception("Invalid type for text")
208
209        if align == "start":
210            align = 0
211        elif align == "center":
212            align = 1
213        elif align == "end":
214            align = 2
215        else:
216            raise Exception(f"Invalid alignment: {align}")
217        text_content = TextContent(
218            text=text,
219            style1=style1,
220            style2=style2,
221            formatting_delimiters=delimiters,
222            text_align=align,
223            syntax_language=language,
224            syntax_theme=theme,
225            parse_counters=parse_counters,
226        )
227        return self.box(_content=text_content, **box_args)
228
229    def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]):
230        """
231        Draw one or paths in the slide.
232        """
233
234        if isinstance(paths, Path):
235            paths = [paths]
236        elif isinstance(paths, InSteps):
237            paths = paths.map(lambda p: [p] if isinstance(p, Path) else p)
238        box = self.get_box()
239        box.deck._deck.draw(box.slide._slide_id, box._box_id, paths)
240
241    def box(
242        self,
243        *,
244        active: bool | str | int | InSteps[bool] = True,
245        show: bool | str | int | InSteps[bool] = True,
246        z_level: int | InSteps[int] | None = None,
247        x: Position | InSteps[Position] = None,
248        y: Position | InSteps[Position] = None,
249        width: Size | InSteps[Size] = None,
250        height: Size | InSteps[Size] = None,
251        border_radius: float | InSteps[float] = 0,
252        p_left: Length | InSteps[Length] | None = None,
253        p_right: Length | InSteps[Length] | None = None,
254        p_top: Length | InSteps[Length] | None = None,
255        p_bottom: Length | InSteps[Length] | None = None,
256        p_x: Length | InSteps[Length] = 0,
257        p_y: Length | InSteps[Length] = 0,
258        m_left: LengthAuto | InSteps[LengthAuto] | None = None,
259        m_right: LengthAuto | InSteps[LengthAuto] | None = None,
260        m_top: LengthAuto | InSteps[LengthAuto] | None = None,
261        m_bottom: LengthAuto | InSteps[LengthAuto] | None = None,
262        m_x: LengthAuto | InSteps[LengthAuto] = 0,
263        m_y: LengthAuto | InSteps[LengthAuto] = 0,
264        row: bool | InSteps[bool] = False,
265        reverse: bool | InSteps[bool] = False,
266        flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap",
267        flex_grow: float | InSteps[float] = 0.0,
268        flex_shrink: float | InSteps[float] = 1.0,
269        align_items: AlignItemsSteps = None,
270        align_self: AlignItemsSteps = None,
271        justify_self: AlignItemsSteps = None,
272        align_content: AlignContentSteps = None,
273        justify_content: AlignContentSteps = None,
274        gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0),
275        grid_template_rows: GridTemplate = (),
276        grid_template_columns: GridTemplate = (),
277        grid_row: GridPosition = "auto",
278        grid_column: GridPosition = "auto",
279        bg_color: str | None | InSteps[str | None] = None,
280        url: None | str | InSteps[None | str] = None,
281        name: str = "",
282        debug_layout: bool | str | None = None,
283        replace_steps: dict[int, int] | None = None,
284        _content: NodeContent | InSteps[NodeContent] = None,
285    ):
286        """
287        Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation
288        """
289        parent_box = self.get_box()
290        if debug_layout is None:
291            debug_layout = parent_box.slide.debug_layout
292        else:
293            debug_layout = parse_debug_layout(debug_layout)
294        if z_level is None:
295            z_level = parent_box.z_level
296
297        if p_left is None:
298            p_left = p_x
299        if p_right is None:
300            p_right = p_x
301        if p_bottom is None:
302            p_bottom = p_y
303        if p_top is None:
304            p_top = p_y
305
306        if m_left is None:
307            m_left = m_x
308        if m_right is None:
309            m_right = m_x
310        if m_bottom is None:
311            m_bottom = m_y
312        if m_top is None:
313            m_top = m_y
314
315        deck = parent_box.deck
316        box_id, node_id = deck._deck.new_box(
317            deck.resources,
318            parent_box.slide._slide_id,
319            parent_box._box_id,
320            active=active,
321            show=show,
322            z_level=z_level,
323            x=x,
324            y=y,
325            width=width,
326            height=height,
327            border_radius=border_radius,
328            p_left=p_left,
329            p_right=p_right,
330            p_top=p_top,
331            p_bottom=p_bottom,
332            m_left=m_left,
333            m_right=m_right,
334            m_top=m_top,
335            m_bottom=m_bottom,
336            row=row,
337            reverse=reverse,
338            flex_wrap=flex_wrap,
339            flex_grow=flex_grow,
340            flex_shrink=flex_shrink,
341            align_items=align_items,
342            align_self=align_self,
343            justify_self=justify_self,
344            align_content=align_content,
345            justify_content=justify_content,
346            gap=gap,
347            grid_template_rows=grid_template_rows,
348            grid_template_columns=grid_template_columns,
349            grid_row=grid_row,
350            grid_column=grid_column,
351            bg_color=bg_color,
352            url=url,
353            name=name,
354            debug_layout=debug_layout,
355            replace_steps=replace_steps,
356            content=_content,
357        )
358        return Box(deck, parent_box.slide, box_id, node_id, name, z_level)
359
360    def overlay(self, **box_args):
361        """
362        Create a new box that spans over the box
363        """
364        box_args.setdefault("x", 0)
365        box_args.setdefault("y", 0)
366        box_args.setdefault("width", "100%")
367        box_args.setdefault("height", "100%")
368        return self.box(**box_args)
369
370    def line_box(self, line_idx: int, **box_args):
371        """
372        Creates a new box over a text line in the box
373        """
374        return self.box(
375            x=self.line_x(line_idx),
376            y=self.line_y(line_idx),
377            width=self.line_width(line_idx),
378            height=self.line_height(line_idx),
379            **box_args,
380        )
381
382    def text_anchor_box(self, anchor_id: int, **box_args):
383        """
384        Creates a new box over a text anchor in the box
385        """
386
387        return self.box(
388            x=self.text_anchor_x(anchor_id),
389            y=self.text_anchor_y(anchor_id),
390            width=self.text_anchor_width(anchor_id),
391            height=self.text_anchor_height(anchor_id),
392            **box_args,
393        )
394
395    def x(self, width_fraction: float | int | None = None) -> LayoutExpr:
396        """
397        Get an expression with X coordinate relative to the box.
398        """
399
400        node_id = self.get_box().node_id
401        expr = LayoutExpr.x(node_id)
402        if width_fraction is None:
403            return expr
404        return expr + LayoutExpr.width(node_id, width_fraction)
405
406    def y(self, height_fraction: float | int | None = None) -> LayoutExpr:
407        """
408        Get an expression with Y coordinate relative to the box.
409        """
410        node_id = self.get_box().node_id
411        expr = LayoutExpr.y(node_id)
412        if height_fraction is None:
413            return expr
414        return expr + LayoutExpr.height(node_id, height_fraction)
415
416    def width(self, fraction: float | int = 1.0) -> LayoutExpr:
417        """
418        Get an expression with width of the parent box.
419        """
420        node_id = self.get_box().node_id
421        return LayoutExpr.width(node_id, fraction)
422
423    def height(self, fraction: float | int = 1.0) -> LayoutExpr:
424        """
425        Get an expression with height of the parent box.
426        """
427        node_id = self.get_box().node_id
428        return LayoutExpr.height(node_id, fraction)
429
430    def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr:
431        """
432        Get an expression with X coordinate of a given line of text in the box.
433        """
434        node_id = self.get_box().node_id
435        expr = LayoutExpr.line_x(node_id, line_idx)
436        if width_fraction is None:
437            return expr
438        return expr + LayoutExpr.line_width(node_id, line_idx, width_fraction)
439
440    def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr:
441        """
442        Get an expression with Y coordinate of a given line of text in the box.
443        """
444        node_id = self.get_box().node_id
445        expr = LayoutExpr.line_y(node_id, line_idx)
446        if height_fraction is None:
447            return expr
448        return expr + LayoutExpr.line_height(node_id, line_idx, height_fraction)
449
450    def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
451        """
452        Get an expression with a width of a given line of text in the box.
453        """
454        node_id = self.get_box().node_id
455        return LayoutExpr.line_width(node_id, line_idx, fraction)
456
457    def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
458        """
459        Get an expression with a height of a given line of text in the box.
460        """
461        node_id = self.get_box().node_id
462        return LayoutExpr.line_height(node_id, line_idx, fraction)
463
464    def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr:
465        """
466        Get an expression with X coordinate of a given text anchor in the box.
467        """
468        node_id = self.get_box().node_id
469        expr = LayoutExpr.text_anchor_x(node_id, anchor_id)
470        if width_fraction is None:
471            return expr
472        return expr + LayoutExpr.text_anchor_width(node_id, anchor_id, width_fraction)
473
474    def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr:
475        """
476        Get an expression with Y coordinate of a given text anchor in the box.
477        """
478        node_id = self.get_box().node_id
479        expr = LayoutExpr.text_anchor_y(node_id, anchor_id)
480        if height_fraction is None:
481            return expr
482        return expr + LayoutExpr.text_anchor_height(node_id, anchor_id, height_fraction)
483
484    def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
485        """
486        Get an expression with a height of a given text anchor in the box.
487        """
488        node_id = self.get_box().node_id
489        return LayoutExpr.text_anchor_width(node_id, anchor_id, fraction)
490
491    def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
492        """
493        Get an expression with a height of a given text anchor in the box.
494        """
495        node_id = self.get_box().node_id
496        return LayoutExpr.text_anchor_height(node_id, anchor_id, fraction)
def set_style( self, name: str, style: Union[TextStyle, InSteps[TextStyle]]):
57    def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
58        """
59        Set text style under given name.
60        """
61        box = self.get_box()
62        deck = box.deck
63        deck._deck.set_style(deck.resources, name, style, False, box.slide._slide_id, box._box_id)

Set text style under given name.

def update_style( self, name: str, style: Union[TextStyle, InSteps[TextStyle]]):
65    def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
66        """
67        Load a text style and merge it with the `style` and save it back.
68        Throws an exception if a style under given name does not exist.
69        """
70        box = self.get_box()
71        deck = box.deck
72        deck._deck.set_style(deck.resources, name, style, True, box.slide._slide_id, box._box_id)

Load a text style and merge it with the style and save it back. Throws an exception if a style under given name does not exist.

def get_style(self, name: str, step: int = 1) -> TextStyle:
74    def get_style(self, name: str, step: int = 1) -> TextStyle:
75        """
76        Get text style under given name. Style is returned for a given `step`.
77        Throws an exception if a style under given name does not exist.
78
79        This function returns text style even when InSteps was used to set the style,
80        as it returns text style for a given step.
81        """
82
83        box = self.get_box()
84        return _data_to_text_style(box.deck._deck.get_style(name, step, box.slide._slide_id, box._box_id))

Get text style under given name. Style is returned for a given step. Throws an exception if a style under given name does not exist.

This function returns text style even when InSteps was used to set the style, as it returns text style for a given step.

def image( self, path: Union[str, NoneType, InSteps[str | None]], enable_steps=True, shift_steps=0, **box_args):
 86    def image(self, path: str | None | InSteps[str | None], enable_steps=True, shift_steps=0, **box_args):
 87        """
 88        Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA
 89        """
 90        assert shift_steps >= 0
 91
 92        def process_path(p):
 93            if p is None:
 94                return None
 95            if slide.image_directory is not None:
 96                p = os.path.join(slide.image_directory, p)
 97            p = os.path.abspath(p)
 98            watch_path(p)
 99            return p
100
101        slide = self.get_box().slide
102        if isinstance(path, InSteps):
103            path = path.map(process_path)
104        else:
105            path = process_path(path)
106        image = ImageContent(
107            path=path,
108            enable_steps=enable_steps,
109            shift_steps=shift_steps,
110        )
111        return self.box(_content=image, **box_args)

Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA

def text( self, text: Union[str, InSteps[str]], style: Union[str, TextStyle, InSteps[TextStyle], NoneType] = None, *, parse_styles: bool = True, style_delimiters: str | None = '~{}', tab_width: int = 4, align: Literal['start', 'center', 'end'] = 'start', strip=True, parse_counters: bool = False, **box_args):
113    def text(
114        self,
115        text: str | InSteps[str],
116        style: str | TextStyle | InSteps[TextStyle] | None = None,
117        *,
118        parse_styles: bool = True,
119        style_delimiters: str | None = "~{}",
120        tab_width: int = 4,
121        align: TextAlign = "start",
122        strip=True,
123        parse_counters: bool = False,
124        **box_args,
125    ):
126        """
127        Create a box with a text.
128        """
129        box_args.setdefault("name", "text")
130        return self._text_box(
131            text,
132            style,
133            None,
134            style_delimiters if parse_styles else None,
135            tab_width,
136            box_args,
137            align,
138            None,
139            None,
140            strip,
141            parse_counters,
142        )

Create a box with a text.

def code( self, text: Union[str, InSteps[str]], language: str | None = 'default', style: Union[str, TextStyle, InSteps[TextStyle], NoneType] = None, *, theme: str | None = None, parse_styles: bool = False, style_delimiters: str | None = '~{}', tab_width: int = 4, align: Literal['start', 'center', 'end'] = 'start', strip: bool = True, parse_counters: bool = False, **box_args):
144    def code(
145        self,
146        text: str | InSteps[str],
147        language: str | None = "default",
148        style: str | TextStyle | InSteps[TextStyle] | None = None,
149        *,
150        theme: str | None = None,
151        parse_styles: bool = False,
152        style_delimiters: str | None = "~{}",
153        tab_width: int = 4,
154        align: TextAlign = "start",
155        strip: bool = True,
156        parse_counters: bool = False,
157        **box_args,
158    ):
159        """
160        Create a box with a syntax highlighted text.
161        """
162        box_args.setdefault("name", "code")
163        if theme is None:
164            theme = self.get_box().deck.default_code_theme
165        if language == "default":
166            language = self.get_box().deck.default_code_language
167        return self._text_box(
168            text,
169            "code",
170            style,
171            style_delimiters if parse_styles else None,
172            tab_width,
173            box_args,
174            align,
175            language,
176            theme,
177            strip,
178            parse_counters,
179        )

Create a box with a syntax highlighted text.

def draw( self, paths: Union[Path, list[Path], InSteps[Path | list[Path]]]):
229    def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]):
230        """
231        Draw one or paths in the slide.
232        """
233
234        if isinstance(paths, Path):
235            paths = [paths]
236        elif isinstance(paths, InSteps):
237            paths = paths.map(lambda p: [p] if isinstance(p, Path) else p)
238        box = self.get_box()
239        box.deck._deck.draw(box.slide._slide_id, box._box_id, paths)

Draw one or paths in the slide.

def box( self, *, active: Union[bool, str, int, InSteps[bool]] = True, show: Union[bool, str, int, InSteps[bool]] = True, z_level: Union[int, InSteps[int], NoneType] = None, x: Union[int, float, str, NoneType, nelsie.layoutexpr.LayoutExpr, InSteps[int | float | str | None | nelsie.layoutexpr.LayoutExpr]] = None, y: Union[int, float, str, NoneType, nelsie.layoutexpr.LayoutExpr, InSteps[int | float | str | None | nelsie.layoutexpr.LayoutExpr]] = None, width: Union[int, float, str, NoneType, InSteps[int | float | str | None]] = None, height: Union[int, float, str, NoneType, InSteps[int | float | str | None]] = None, border_radius: Union[float, InSteps[float]] = 0, p_left: Union[int, float, str, InSteps[int | float | str], NoneType] = None, p_right: Union[int, float, str, InSteps[int | float | str], NoneType] = None, p_top: Union[int, float, str, InSteps[int | float | str], NoneType] = None, p_bottom: Union[int, float, str, InSteps[int | float | str], NoneType] = None, p_x: Union[int, float, str, InSteps[int | float | str]] = 0, p_y: Union[int, float, str, InSteps[int | float | str]] = 0, m_left: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]], NoneType] = None, m_right: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]], NoneType] = None, m_top: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]], NoneType] = None, m_bottom: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]], NoneType] = None, m_x: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]]] = 0, m_y: Union[int, float, str, Literal['auto'], InSteps[Union[int, float, str, Literal['auto']]]] = 0, row: Union[bool, InSteps[bool]] = False, reverse: Union[bool, InSteps[bool]] = False, flex_wrap: Union[Literal['nowrap', 'wrap', 'wrap-reverse'], InSteps[Literal['nowrap', 'wrap', 'wrap-reverse']]] = 'nowrap', flex_grow: Union[float, InSteps[float]] = 0.0, flex_shrink: Union[float, InSteps[float]] = 1.0, align_items: Union[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'], NoneType, InSteps[Optional[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']]]] = None, align_self: Union[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'], NoneType, InSteps[Optional[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']]]] = None, justify_self: Union[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'], NoneType, InSteps[Optional[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline']]]] = None, align_content: Union[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-evenly', 'space-around'], NoneType, InSteps[Optional[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-evenly', 'space-around']]]] = None, justify_content: Union[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-evenly', 'space-around'], NoneType, InSteps[Optional[Literal['start', 'end', 'flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-evenly', 'space-around']]]] = None, gap: Union[tuple[int | float | str, int | float | str], InSteps[tuple[int | float | str, int | float | str]]] = (0.0, 0.0), grid_template_rows: Union[Sequence[float | str], InSteps[Sequence[float | str]]] = (), grid_template_columns: Union[Sequence[float | str], InSteps[Sequence[float | str]]] = (), grid_row: Union[int, str, tuple[int | str], InSteps[int | str | tuple[int | str]]] = 'auto', grid_column: Union[int, str, tuple[int | str], InSteps[int | str | tuple[int | str]]] = 'auto', bg_color: Union[str, NoneType, InSteps[str | None]] = None, url: Union[str, NoneType, InSteps[str | None]] = None, name: str = '', debug_layout: bool | str | None = None, replace_steps: dict[int, int] | None = None, _content: Union[nelsie.box.ImageContent, nelsie.box.TextContent, NoneType, InSteps[nelsie.box.ImageContent | nelsie.box.TextContent | None]] = None):
241    def box(
242        self,
243        *,
244        active: bool | str | int | InSteps[bool] = True,
245        show: bool | str | int | InSteps[bool] = True,
246        z_level: int | InSteps[int] | None = None,
247        x: Position | InSteps[Position] = None,
248        y: Position | InSteps[Position] = None,
249        width: Size | InSteps[Size] = None,
250        height: Size | InSteps[Size] = None,
251        border_radius: float | InSteps[float] = 0,
252        p_left: Length | InSteps[Length] | None = None,
253        p_right: Length | InSteps[Length] | None = None,
254        p_top: Length | InSteps[Length] | None = None,
255        p_bottom: Length | InSteps[Length] | None = None,
256        p_x: Length | InSteps[Length] = 0,
257        p_y: Length | InSteps[Length] = 0,
258        m_left: LengthAuto | InSteps[LengthAuto] | None = None,
259        m_right: LengthAuto | InSteps[LengthAuto] | None = None,
260        m_top: LengthAuto | InSteps[LengthAuto] | None = None,
261        m_bottom: LengthAuto | InSteps[LengthAuto] | None = None,
262        m_x: LengthAuto | InSteps[LengthAuto] = 0,
263        m_y: LengthAuto | InSteps[LengthAuto] = 0,
264        row: bool | InSteps[bool] = False,
265        reverse: bool | InSteps[bool] = False,
266        flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap",
267        flex_grow: float | InSteps[float] = 0.0,
268        flex_shrink: float | InSteps[float] = 1.0,
269        align_items: AlignItemsSteps = None,
270        align_self: AlignItemsSteps = None,
271        justify_self: AlignItemsSteps = None,
272        align_content: AlignContentSteps = None,
273        justify_content: AlignContentSteps = None,
274        gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0),
275        grid_template_rows: GridTemplate = (),
276        grid_template_columns: GridTemplate = (),
277        grid_row: GridPosition = "auto",
278        grid_column: GridPosition = "auto",
279        bg_color: str | None | InSteps[str | None] = None,
280        url: None | str | InSteps[None | str] = None,
281        name: str = "",
282        debug_layout: bool | str | None = None,
283        replace_steps: dict[int, int] | None = None,
284        _content: NodeContent | InSteps[NodeContent] = None,
285    ):
286        """
287        Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation
288        """
289        parent_box = self.get_box()
290        if debug_layout is None:
291            debug_layout = parent_box.slide.debug_layout
292        else:
293            debug_layout = parse_debug_layout(debug_layout)
294        if z_level is None:
295            z_level = parent_box.z_level
296
297        if p_left is None:
298            p_left = p_x
299        if p_right is None:
300            p_right = p_x
301        if p_bottom is None:
302            p_bottom = p_y
303        if p_top is None:
304            p_top = p_y
305
306        if m_left is None:
307            m_left = m_x
308        if m_right is None:
309            m_right = m_x
310        if m_bottom is None:
311            m_bottom = m_y
312        if m_top is None:
313            m_top = m_y
314
315        deck = parent_box.deck
316        box_id, node_id = deck._deck.new_box(
317            deck.resources,
318            parent_box.slide._slide_id,
319            parent_box._box_id,
320            active=active,
321            show=show,
322            z_level=z_level,
323            x=x,
324            y=y,
325            width=width,
326            height=height,
327            border_radius=border_radius,
328            p_left=p_left,
329            p_right=p_right,
330            p_top=p_top,
331            p_bottom=p_bottom,
332            m_left=m_left,
333            m_right=m_right,
334            m_top=m_top,
335            m_bottom=m_bottom,
336            row=row,
337            reverse=reverse,
338            flex_wrap=flex_wrap,
339            flex_grow=flex_grow,
340            flex_shrink=flex_shrink,
341            align_items=align_items,
342            align_self=align_self,
343            justify_self=justify_self,
344            align_content=align_content,
345            justify_content=justify_content,
346            gap=gap,
347            grid_template_rows=grid_template_rows,
348            grid_template_columns=grid_template_columns,
349            grid_row=grid_row,
350            grid_column=grid_column,
351            bg_color=bg_color,
352            url=url,
353            name=name,
354            debug_layout=debug_layout,
355            replace_steps=replace_steps,
356            content=_content,
357        )
358        return Box(deck, parent_box.slide, box_id, node_id, name, z_level)

Create a new child box. See Box reference for documentation

def overlay(self, **box_args):
360    def overlay(self, **box_args):
361        """
362        Create a new box that spans over the box
363        """
364        box_args.setdefault("x", 0)
365        box_args.setdefault("y", 0)
366        box_args.setdefault("width", "100%")
367        box_args.setdefault("height", "100%")
368        return self.box(**box_args)

Create a new box that spans over the box

def line_box(self, line_idx: int, **box_args):
370    def line_box(self, line_idx: int, **box_args):
371        """
372        Creates a new box over a text line in the box
373        """
374        return self.box(
375            x=self.line_x(line_idx),
376            y=self.line_y(line_idx),
377            width=self.line_width(line_idx),
378            height=self.line_height(line_idx),
379            **box_args,
380        )

Creates a new box over a text line in the box

def text_anchor_box(self, anchor_id: int, **box_args):
382    def text_anchor_box(self, anchor_id: int, **box_args):
383        """
384        Creates a new box over a text anchor in the box
385        """
386
387        return self.box(
388            x=self.text_anchor_x(anchor_id),
389            y=self.text_anchor_y(anchor_id),
390            width=self.text_anchor_width(anchor_id),
391            height=self.text_anchor_height(anchor_id),
392            **box_args,
393        )

Creates a new box over a text anchor in the box

def x( self, width_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
395    def x(self, width_fraction: float | int | None = None) -> LayoutExpr:
396        """
397        Get an expression with X coordinate relative to the box.
398        """
399
400        node_id = self.get_box().node_id
401        expr = LayoutExpr.x(node_id)
402        if width_fraction is None:
403            return expr
404        return expr + LayoutExpr.width(node_id, width_fraction)

Get an expression with X coordinate relative to the box.

def y( self, height_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
406    def y(self, height_fraction: float | int | None = None) -> LayoutExpr:
407        """
408        Get an expression with Y coordinate relative to the box.
409        """
410        node_id = self.get_box().node_id
411        expr = LayoutExpr.y(node_id)
412        if height_fraction is None:
413            return expr
414        return expr + LayoutExpr.height(node_id, height_fraction)

Get an expression with Y coordinate relative to the box.

def width(self, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
416    def width(self, fraction: float | int = 1.0) -> LayoutExpr:
417        """
418        Get an expression with width of the parent box.
419        """
420        node_id = self.get_box().node_id
421        return LayoutExpr.width(node_id, fraction)

Get an expression with width of the parent box.

def height(self, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
423    def height(self, fraction: float | int = 1.0) -> LayoutExpr:
424        """
425        Get an expression with height of the parent box.
426        """
427        node_id = self.get_box().node_id
428        return LayoutExpr.height(node_id, fraction)

Get an expression with height of the parent box.

def line_x( self, line_idx: int, width_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
430    def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr:
431        """
432        Get an expression with X coordinate of a given line of text in the box.
433        """
434        node_id = self.get_box().node_id
435        expr = LayoutExpr.line_x(node_id, line_idx)
436        if width_fraction is None:
437            return expr
438        return expr + LayoutExpr.line_width(node_id, line_idx, width_fraction)

Get an expression with X coordinate of a given line of text in the box.

def line_y( self, line_idx: int, height_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
440    def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr:
441        """
442        Get an expression with Y coordinate of a given line of text in the box.
443        """
444        node_id = self.get_box().node_id
445        expr = LayoutExpr.line_y(node_id, line_idx)
446        if height_fraction is None:
447            return expr
448        return expr + LayoutExpr.line_height(node_id, line_idx, height_fraction)

Get an expression with Y coordinate of a given line of text in the box.

def line_width( self, line_idx: int, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
450    def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
451        """
452        Get an expression with a width of a given line of text in the box.
453        """
454        node_id = self.get_box().node_id
455        return LayoutExpr.line_width(node_id, line_idx, fraction)

Get an expression with a width of a given line of text in the box.

def line_height( self, line_idx: int, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
457    def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
458        """
459        Get an expression with a height of a given line of text in the box.
460        """
461        node_id = self.get_box().node_id
462        return LayoutExpr.line_height(node_id, line_idx, fraction)

Get an expression with a height of a given line of text in the box.

def text_anchor_x( self, anchor_id: int, width_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
464    def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr:
465        """
466        Get an expression with X coordinate of a given text anchor in the box.
467        """
468        node_id = self.get_box().node_id
469        expr = LayoutExpr.text_anchor_x(node_id, anchor_id)
470        if width_fraction is None:
471            return expr
472        return expr + LayoutExpr.text_anchor_width(node_id, anchor_id, width_fraction)

Get an expression with X coordinate of a given text anchor in the box.

def text_anchor_y( self, anchor_id: int, height_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
474    def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr:
475        """
476        Get an expression with Y coordinate of a given text anchor in the box.
477        """
478        node_id = self.get_box().node_id
479        expr = LayoutExpr.text_anchor_y(node_id, anchor_id)
480        if height_fraction is None:
481            return expr
482        return expr + LayoutExpr.text_anchor_height(node_id, anchor_id, height_fraction)

Get an expression with Y coordinate of a given text anchor in the box.

def text_anchor_width( self, anchor_id: int, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
484    def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
485        """
486        Get an expression with a height of a given text anchor in the box.
487        """
488        node_id = self.get_box().node_id
489        return LayoutExpr.text_anchor_width(node_id, anchor_id, fraction)

Get an expression with a height of a given text anchor in the box.

def text_anchor_height( self, anchor_id: int, fraction: float | int = 1.0) -> nelsie.layoutexpr.LayoutExpr:
491    def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
492        """
493        Get an expression with a height of a given text anchor in the box.
494        """
495        node_id = self.get_box().node_id
496        return LayoutExpr.text_anchor_height(node_id, anchor_id, fraction)

Get an expression with a height of a given text anchor in the box.

class Box(nelsie.BoxBuilder):
499class Box(BoxBuilder):
500    """
501    The box in slide layout.
502
503    It should be created via calling method `.box()` on a slide or another box.
504    Note that interesting methods came from Box's parent: BoxBuilder.
505    """
506
507    def __init__(
508        self,
509        deck,
510        slide,
511        box_id,
512        node_id,
513        name: str,
514        z_level: int,
515    ):
516        """
517        @private
518        """
519        self.deck = deck
520        self.slide = slide
521        self._box_id = box_id
522        self.node_id = node_id
523        self.name = name
524        self.z_level = z_level
525
526    def get_box(self):
527        """
528        @private
529        """
530        return self

The box in slide layout.

It should be created via calling method .box() on a slide or another box. Note that interesting methods came from Box's parent: BoxBuilder.

deck
slide
node_id
name
z_level
class Slide(nelsie.BoxBuilder):
14class Slide(BoxBuilder):
15    """
16    Represents a slide in a slide deck.
17
18    It should be created via calling method `.new_slide()` on a deck via decorator `@deck.slide()`
19    """
20
21    def __init__(
22        self,
23        deck: "SlideDeck",
24        slide_id: int,
25        name: str,
26        image_directory: str,
27        debug_layout: str | None,
28    ):
29        """
30        @private
31        """
32        self.deck = deck
33        self._slide_id = slide_id
34        self.name = name
35        self.image_directory = image_directory
36        self.debug_layout = debug_layout
37        self.root_box = Box(deck, self, [], 0, name, 0)
38
39    def get_box(self):
40        """
41        @private
42        """
43        return self.root_box
44
45    def insert_step(self, value: Step):
46        self.deck._deck.insert_step(self._slide_id, value)
47
48    def remove_step(self, value: Step):
49        self.deck._deck.remove_step(self._slide_id, value)
50
51    def remove_steps_below(self, value: Step):
52        self.deck._deck.remove_steps_below(self._slide_id, value)
53
54    def remove_steps_above(self, value: Step):
55        self.deck._deck.remove_steps_above(self._slide_id, value)
56
57    def get_steps(self) -> list[Step]:
58        return self.deck._deck.get_steps(self._slide_id)
59
60    def new_slide_at(self, step: int, **slide_kwargs):
61        slide_kwargs["parent_slide"] = (self._slide_id, step)
62        return self.deck.new_slide(**slide_kwargs)
63
64    def slide_at(self, step: int, **slide_kwargs):
65        slide_kwargs["parent_slide"] = (self._slide_id, step)
66        return self.deck.slide(**slide_kwargs)

Represents a slide in a slide deck.

It should be created via calling method .new_slide() on a deck via decorator @deck.slide()

deck
name
image_directory
debug_layout
root_box
def insert_step(self, value: tuple[int]):
45    def insert_step(self, value: Step):
46        self.deck._deck.insert_step(self._slide_id, value)
def remove_step(self, value: tuple[int]):
48    def remove_step(self, value: Step):
49        self.deck._deck.remove_step(self._slide_id, value)
def remove_steps_below(self, value: tuple[int]):
51    def remove_steps_below(self, value: Step):
52        self.deck._deck.remove_steps_below(self._slide_id, value)
def remove_steps_above(self, value: tuple[int]):
54    def remove_steps_above(self, value: Step):
55        self.deck._deck.remove_steps_above(self._slide_id, value)
def get_steps(self) -> list[tuple[int]]:
57    def get_steps(self) -> list[Step]:
58        return self.deck._deck.get_steps(self._slide_id)
def new_slide_at(self, step: int, **slide_kwargs):
60    def new_slide_at(self, step: int, **slide_kwargs):
61        slide_kwargs["parent_slide"] = (self._slide_id, step)
62        return self.deck.new_slide(**slide_kwargs)
def slide_at(self, step: int, **slide_kwargs):
64    def slide_at(self, step: int, **slide_kwargs):
65        slide_kwargs["parent_slide"] = (self._slide_id, step)
66        return self.deck.slide(**slide_kwargs)