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:
119class SlideDeck:
120    def __init__(
121        self,
122        *,
123        width: float = 1024,
124        height: float = 768,
125        bg_color: str = "white",
126        image_directory: str | None = None,
127        resources: Resources | None = None,
128        default_font: str = "sans-serif",
129        default_monospace_font: str = "monospace",
130        default_code_theme: str = "InspiredGitHub",
131        default_code_language: str | None = None,
132    ):
133        """
134        A top-level class of Nelsie. It represents a set of slides.
135
136        Arguments:
137        * width - default width of a slide (could be overriden for each slide)
138        * height - default width of a slide (could be overriden for each slide)
139        * bg_color - default background color a slide (could be overriden for each slide)
140        * image_directory - default path where images are searched for (could be overriden for each slide)
141        * resource - Resource instance, if None a new instance is created
142        * default_font - Name of default font
143        * default_monospace_font - Name of the default monospace font
144        * default_code_theme - Name of default theme for syntax highlighting (.code() method):
145            Available themes:
146            * "base16-ocean.dark"
147            * "base16-eighties.dark"
148            * "base16-mocha.dark"
149            * "base16-ocean.light"
150            * "InspiredGitHub"
151            * "Solarized (dark)"
152            * "Solarized (light)"
153        * default_code_language - Default language to use for syntax highlighting (.code() method)
154        """
155        if resources is None:
156            resources = Resources()
157
158        self.width = width
159        self.height = height
160        self.bg_color = bg_color
161        self.image_directory = image_directory
162        self.resources = resources
163        self.default_code_theme = default_code_theme
164        self.default_code_language = default_code_language
165        self._deck = nelsie_rs.Deck(default_font, default_monospace_font)
166        self._slides: List[Slide] = []
167
168    def set_style(self, name: str, style: TextStyle):
169        self._deck.set_style(self.resources._resources, name, style, False, None, None)
170
171    def update_style(self, name: str, style: TextStyle):
172        self._deck.set_style(self.resources._resources, name, style, True, None, None)
173
174    def get_style(self, name: str, step: int = 1) -> TextStyle:
175        return _data_to_text_style(self._deck.get_style(name, step, None, None))
176
177    def new_slide(
178        self,
179        *,
180        width: float | None = None,
181        height: float | None = None,
182        bg_color: str | None = None,
183        image_directory: str | None = None,
184        name: str = "",
185        debug_steps: bool = False,
186        debug_layout: bool | str = False,
187        counters: list[str] | None = None,
188        parent_slide: tuple[Slide, int] | None = None,
189        step_1: bool = True,
190    ) -> Slide:
191        """
192        Creates a new slide in the slide deck.
193        """
194        if width is None:
195            width = self.width
196        if height is None:
197            height = self.height
198        if bg_color is None:
199            bg_color = self.bg_color
200        if image_directory is None:
201            image_directory = self.image_directory
202        debug_layout = parse_debug_layout(debug_layout)
203        slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide)
204
205        slide = Slide(self, slide_id, name, image_directory, debug_layout)
206        self._slides.append(slide)
207        return slide
208
209    def slide(
210        self,
211        *,
212        width: float | None = None,
213        height: float | None = None,
214        bg_color: str | None = None,
215        image_directory: str | None = None,
216        name: str = "",
217        debug_steps: bool = False,
218        debug_layout: bool | str = False,
219        counters: list[str] | None = None,
220        parent_slide: tuple[Slide, int] | None = None,
221        step_1: bool = True,
222    ):
223        """
224        Decorator for creating new slide.
225        It immediately calls the decorated function that should define content of the slide.
226        Slide is automatically added into the deck.
227
228        Example:
229        ```python
230        deck = SlideDeck()
231
232        @deck.slide()
233        def my_first_slide(slide):
234            slide.text("Hello!")
235        ```
236        """
237
238        def helper(fn):
239            slide = self.new_slide(
240                width=width,
241                height=height,
242                bg_color=bg_color,
243                image_directory=image_directory,
244                name=name,
245                debug_steps=debug_steps,
246                debug_layout=debug_layout,
247                counters=counters,
248                parent_slide=parent_slide,
249                step_1=step_1,
250            )
251            fn(slide)
252            return slide
253
254        return helper
255
256    def render(
257        self,
258        path: str | pathlib.Path | None,
259        output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf",
260        *,
261        verbose: int = 1,
262        compression_level: int = 1,
263        n_threads: int | None = None,
264    ) -> None | list[bytes]:
265        """
266        Render slides
267
268        If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then
269        `path` specifies a directory where the slides are created as an individual files.
270
271        If `path` is None then objects are not written to the file system, and they are returned as python objects
272        from the method call.
273
274        `compression_level` defines the level of compression for PDF, allowed ranges are 0-10
275        (0 = no compression, 1 = fast compression, 10 = maximal compression)
276        """
277        assert 0 <= compression_level <= 10
278        if path:
279            path = str(path)
280        return self._deck.render(
281            self.resources._resources,
282            verbose,
283            output_format,
284            compression_level,
285            path,
286            n_threads,
287        )
SlideDeck( *, width: float = 1024, height: float = 768, bg_color: str = 'white', image_directory: str | None = None, resources: Resources | None = None, default_font: str = 'sans-serif', default_monospace_font: str = 'monospace', default_code_theme: str = 'InspiredGitHub', default_code_language: str | None = None)
120    def __init__(
121        self,
122        *,
123        width: float = 1024,
124        height: float = 768,
125        bg_color: str = "white",
126        image_directory: str | None = None,
127        resources: Resources | None = None,
128        default_font: str = "sans-serif",
129        default_monospace_font: str = "monospace",
130        default_code_theme: str = "InspiredGitHub",
131        default_code_language: str | None = None,
132    ):
133        """
134        A top-level class of Nelsie. It represents a set of slides.
135
136        Arguments:
137        * width - default width of a slide (could be overriden for each slide)
138        * height - default width of a slide (could be overriden for each slide)
139        * bg_color - default background color a slide (could be overriden for each slide)
140        * image_directory - default path where images are searched for (could be overriden for each slide)
141        * resource - Resource instance, if None a new instance is created
142        * default_font - Name of default font
143        * default_monospace_font - Name of the default monospace font
144        * default_code_theme - Name of default theme for syntax highlighting (.code() method):
145            Available themes:
146            * "base16-ocean.dark"
147            * "base16-eighties.dark"
148            * "base16-mocha.dark"
149            * "base16-ocean.light"
150            * "InspiredGitHub"
151            * "Solarized (dark)"
152            * "Solarized (light)"
153        * default_code_language - Default language to use for syntax highlighting (.code() method)
154        """
155        if resources is None:
156            resources = Resources()
157
158        self.width = width
159        self.height = height
160        self.bg_color = bg_color
161        self.image_directory = image_directory
162        self.resources = resources
163        self.default_code_theme = default_code_theme
164        self.default_code_language = default_code_language
165        self._deck = nelsie_rs.Deck(default_font, default_monospace_font)
166        self._slides: List[Slide] = []

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):
168    def set_style(self, name: str, style: TextStyle):
169        self._deck.set_style(self.resources._resources, name, style, False, None, None)
def update_style(self, name: str, style: TextStyle):
171    def update_style(self, name: str, style: TextStyle):
172        self._deck.set_style(self.resources._resources, name, style, True, None, None)
def get_style(self, name: str, step: int = 1) -> TextStyle:
174    def get_style(self, name: str, step: int = 1) -> TextStyle:
175        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:
177    def new_slide(
178        self,
179        *,
180        width: float | None = None,
181        height: float | None = None,
182        bg_color: str | None = None,
183        image_directory: str | None = None,
184        name: str = "",
185        debug_steps: bool = False,
186        debug_layout: bool | str = False,
187        counters: list[str] | None = None,
188        parent_slide: tuple[Slide, int] | None = None,
189        step_1: bool = True,
190    ) -> Slide:
191        """
192        Creates a new slide in the slide deck.
193        """
194        if width is None:
195            width = self.width
196        if height is None:
197            height = self.height
198        if bg_color is None:
199            bg_color = self.bg_color
200        if image_directory is None:
201            image_directory = self.image_directory
202        debug_layout = parse_debug_layout(debug_layout)
203        slide_id = self._deck.new_slide(width, height, bg_color, name, step_1, debug_steps, counters, parent_slide)
204
205        slide = Slide(self, slide_id, name, image_directory, debug_layout)
206        self._slides.append(slide)
207        return slide

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):
209    def slide(
210        self,
211        *,
212        width: float | None = None,
213        height: float | None = None,
214        bg_color: str | None = None,
215        image_directory: str | None = None,
216        name: str = "",
217        debug_steps: bool = False,
218        debug_layout: bool | str = False,
219        counters: list[str] | None = None,
220        parent_slide: tuple[Slide, int] | None = None,
221        step_1: bool = True,
222    ):
223        """
224        Decorator for creating new slide.
225        It immediately calls the decorated function that should define content of the slide.
226        Slide is automatically added into the deck.
227
228        Example:
229        ```python
230        deck = SlideDeck()
231
232        @deck.slide()
233        def my_first_slide(slide):
234            slide.text("Hello!")
235        ```
236        """
237
238        def helper(fn):
239            slide = self.new_slide(
240                width=width,
241                height=height,
242                bg_color=bg_color,
243                image_directory=image_directory,
244                name=name,
245                debug_steps=debug_steps,
246                debug_layout=debug_layout,
247                counters=counters,
248                parent_slide=parent_slide,
249                step_1=step_1,
250            )
251            fn(slide)
252            return slide
253
254        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, compression_level: int = 1, n_threads: int | None = None) -> None | list[bytes]:
256    def render(
257        self,
258        path: str | pathlib.Path | None,
259        output_format: Literal["pdf"] | Literal["svg"] | Literal["png"] = "pdf",
260        *,
261        verbose: int = 1,
262        compression_level: int = 1,
263        n_threads: int | None = None,
264    ) -> None | list[bytes]:
265        """
266        Render slides
267
268        If format is "pdf" then a single PDF file is created. If format is "svg" or "png" then
269        `path` specifies a directory where the slides are created as an individual files.
270
271        If `path` is None then objects are not written to the file system, and they are returned as python objects
272        from the method call.
273
274        `compression_level` defines the level of compression for PDF, allowed ranges are 0-10
275        (0 = no compression, 1 = fast compression, 10 = maximal compression)
276        """
277        assert 0 <= compression_level <= 10
278        if path:
279            path = str(path)
280        return self._deck.render(
281            self.resources._resources,
282            verbose,
283            output_format,
284            compression_level,
285            path,
286            n_threads,
287        )

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.

compression_level defines the level of compression for PDF, allowed ranges are 0-10 (0 = no compression, 1 = fast compression, 10 = maximal compression)

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    @property
 69    def last_point(self):
 70        """
 71        Returns a last point in the path, if path is empty, returns 0,0
 72        :return: A tuple (x, y)
 73        """
 74        if len(self.points) < 2:
 75            return 0, 0
 76        else:
 77            return self.points[-2], self.points[-1]
 78
 79    def close(self):
 80        self.commands.append("close")
 81        return self
 82
 83    def move_to(self, x: PathValue, y: PathValue):
 84        self.commands.append("move")
 85        self.points.append(x)
 86        self.points.append(y)
 87        return self
 88
 89    def move_by(self, x: PathValue, y: PathValue) -> "Path":
 90        """
 91        Perform a move relative to the last point of the path.
 92        If path is empty, it starts from 0,0
 93        """
 94        x_old, y_old = self.last_point
 95
 96        return self.move_to(x_old + x, y_old + y)
 97
 98    def line_to(self, x: PathValue, y: PathValue):
 99        self.commands.append("line")
100        self.points.append(x)
101        self.points.append(y)
102        return self
103
104    def line_by(self, x: PathValue, y: PathValue):
105        """
106        Draw a line relative to the last point of the path.
107        If path is empty, it starts from 0,0
108        """
109        x_old, y_old = self.last_point
110        return self.line_to(x_old + x, y_old + y)
111
112    def quad_to(self, x1: PathValue, y1: PathValue, x: PathValue, y: PathValue):
113        self.commands.append("quad")
114        self.points.append(x1)
115        self.points.append(y1)
116        self.points.append(x)
117        self.points.append(y)
118        return self
119
120    def cubic_to(
121        self,
122        x1: PathValue,
123        y1: PathValue,
124        x2: PathValue,
125        y2: PathValue,
126        x: PathValue,
127        y: PathValue,
128    ):
129        self.commands.append("cubic")
130        self.points.append(x1)
131        self.points.append(y1)
132        self.points.append(x2)
133        self.points.append(y2)
134        self.points.append(x)
135        self.points.append(y)
136        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
last_point
68    @property
69    def last_point(self):
70        """
71        Returns a last point in the path, if path is empty, returns 0,0
72        :return: A tuple (x, y)
73        """
74        if len(self.points) < 2:
75            return 0, 0
76        else:
77            return self.points[-2], self.points[-1]

Returns a last point in the path, if path is empty, returns 0,0

Returns

A tuple (x, y)

def close(self):
79    def close(self):
80        self.commands.append("close")
81        return self
def move_to( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
83    def move_to(self, x: PathValue, y: PathValue):
84        self.commands.append("move")
85        self.points.append(x)
86        self.points.append(y)
87        return self
def move_by( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr) -> Path:
89    def move_by(self, x: PathValue, y: PathValue) -> "Path":
90        """
91        Perform a move relative to the last point of the path.
92        If path is empty, it starts from 0,0
93        """
94        x_old, y_old = self.last_point
95
96        return self.move_to(x_old + x, y_old + y)

Perform a move relative to the last point of the path. If path is empty, it starts from 0,0

def line_to( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
 98    def line_to(self, x: PathValue, y: PathValue):
 99        self.commands.append("line")
100        self.points.append(x)
101        self.points.append(y)
102        return self
def line_by( self, x: int | float | nelsie.layoutexpr.LayoutExpr, y: int | float | nelsie.layoutexpr.LayoutExpr):
104    def line_by(self, x: PathValue, y: PathValue):
105        """
106        Draw a line relative to the last point of the path.
107        If path is empty, it starts from 0,0
108        """
109        x_old, y_old = self.last_point
110        return self.line_to(x_old + x, y_old + y)

Draw a line relative to the last point of the path. If path is empty, it starts from 0,0

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):
112    def quad_to(self, x1: PathValue, y1: PathValue, x: PathValue, y: PathValue):
113        self.commands.append("quad")
114        self.points.append(x1)
115        self.points.append(y1)
116        self.points.append(x)
117        self.points.append(y)
118        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):
120    def cubic_to(
121        self,
122        x1: PathValue,
123        y1: PathValue,
124        x2: PathValue,
125        y2: PathValue,
126        x: PathValue,
127        y: PathValue,
128    ):
129        self.commands.append("cubic")
130        self.points.append(x1)
131        self.points.append(y1)
132        self.points.append(x2)
133        self.points.append(y2)
134        self.points.append(x)
135        self.points.append(y)
136        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:
19@dataclass(frozen=True)
20class TextStyle:
21    font_family: str | list[str] | None = None
22    color: str | None = None
23    size: float | None = None
24    line_spacing: float | None = None
25    italic: bool | None = None
26    stretch: FontStretch | None = None
27    underline: bool | None = None
28    line_through: bool | None = None
29
30    # 1-1000; 400 = Normal, 700 = Bold
31    weight: int | None = None
32
33    # Init only fields
34    # These are used as helpers for initializing
35    # commonly used attributes
36    bold: InitVar[bool | None] = None
37
38    def __post_init__(self, bold: bool | None):
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            if bold is not None:
46                raise Exception("Cannot set both `weight` and `bold` when creating a TextStyle")
47        if bold is not None:
48            # Workaround to set frozen attribute
49            super().__setattr__("weight", 700)
50
51    def merge(self, other: "TextStyle") -> "TextStyle":
52        assert isinstance(other, TextStyle)
53        return TextStyle(
54            *[b if b is not None else a for (a, b) in zip(unpack_dataclass(self), unpack_dataclass(other))]
55        )
TextStyle( font_family: str | list[str] | None = None, color: str | None = None, size: float | None = None, line_spacing: float | None = None, italic: bool | None = None, stretch: FontStretch | None = None, underline: bool | None = None, line_through: bool | None = None, weight: int | None = None, bold: dataclasses.InitVar[bool | None] = None)
font_family: str | list[str] | None = None
color: str | None = None
size: float | None = None
line_spacing: float | None = None
italic: bool | None = None
stretch: FontStretch | None = None
underline: bool | None = None
line_through: bool | None = None
weight: int | None = None
bold: dataclasses.InitVar[bool | None] = None
def merge(self, other: TextStyle) -> TextStyle:
51    def merge(self, other: "TextStyle") -> "TextStyle":
52        assert isinstance(other, TextStyle)
53        return TextStyle(
54            *[b if b is not None else a for (a, b) in zip(unpack_dataclass(self), unpack_dataclass(other))]
55        )
class Resources:
18class Resources:
19    def __init__(
20        self,
21        *,
22        builtin_fonts: bool = True,
23        system_fonts: bool = False,
24        system_fonts_for_svg: bool = True,
25        default_code_syntaxes: bool = True,
26        default_code_themes: bool = True,
27    ):
28        self._resources = nelsie_rs.Resources(
29            system_fonts, system_fonts_for_svg, default_code_syntaxes, default_code_themes
30        )
31        if builtin_fonts:
32            self._resources.load_fonts_dir(BUILTIN_FONTS_DIR)
33            self._resources.set_generic_family("sans-serif", "DejaVu Sans")
34            self._resources.set_generic_family("monospace", "DejaVu Sans Mono")
35
36    def set_sans_serif(self, font_name):
37        self._resources.set_generic_family("sans-serif", font_name)
38
39    def set_monospace(self, font_name):
40        self._resources.set_generic_family("monospace", font_name)
41
42    def set_serif(self, font_name):
43        self._resources.set_generic_family("serif", font_name)
44
45    def load_code_syntax_dir(self, path: str):
46        self._resources.load_code_syntax_dir(path)
47
48    def load_code_theme_dir(self, path: str):
49        self._resources.load_code_theme_dir(path)
50
51    def load_fonts_dir(self, path: str):
52        self._resources.load_fonts_dir(path)
53
54    def syntaxes(self) -> list[tuple[str, list[str]]]:
55        return self._resources.syntaxes()
56
57    def themes(self) -> list[str]:
58        return self._resources.themes()
Resources( *, builtin_fonts: bool = True, system_fonts: bool = False, system_fonts_for_svg: bool = True, default_code_syntaxes: bool = True, default_code_themes: bool = True)
19    def __init__(
20        self,
21        *,
22        builtin_fonts: bool = True,
23        system_fonts: bool = False,
24        system_fonts_for_svg: bool = True,
25        default_code_syntaxes: bool = True,
26        default_code_themes: bool = True,
27    ):
28        self._resources = nelsie_rs.Resources(
29            system_fonts, system_fonts_for_svg, default_code_syntaxes, default_code_themes
30        )
31        if builtin_fonts:
32            self._resources.load_fonts_dir(BUILTIN_FONTS_DIR)
33            self._resources.set_generic_family("sans-serif", "DejaVu Sans")
34            self._resources.set_generic_family("monospace", "DejaVu Sans Mono")
def set_sans_serif(self, font_name):
36    def set_sans_serif(self, font_name):
37        self._resources.set_generic_family("sans-serif", font_name)
def set_monospace(self, font_name):
39    def set_monospace(self, font_name):
40        self._resources.set_generic_family("monospace", font_name)
def set_serif(self, font_name):
42    def set_serif(self, font_name):
43        self._resources.set_generic_family("serif", font_name)
def load_code_syntax_dir(self, path: str):
45    def load_code_syntax_dir(self, path: str):
46        self._resources.load_code_syntax_dir(path)
def load_code_theme_dir(self, path: str):
48    def load_code_theme_dir(self, path: str):
49        self._resources.load_code_theme_dir(path)
def load_fonts_dir(self, path: str):
51    def load_fonts_dir(self, path: str):
52        self._resources.load_fonts_dir(path)
def syntaxes(self) -> list[tuple[str, list[str]]]:
54    def syntaxes(self) -> list[tuple[str, list[str]]]:
55        return self._resources.syntaxes()
def themes(self) -> list[str]:
57    def themes(self) -> list[str]:
58        return self._resources.themes()
class FontStretch(enum.IntEnum):
 7class FontStretch(IntEnum):
 8    UltraCondensed = 1
 9    ExtraCondensed = 2
10    Condensed = 3
11    SemiCondensed = 4
12    Normal = 5
13    SemiExpanded = 6
14    Expanded = 7
15    ExtraExpanded = 8
16    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>
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:
 61class BoxBuilder:
 62    def get_box(self):
 63        """
 64        @private
 65        """
 66        raise NotImplementedError
 67
 68    def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
 69        """
 70        Set text style under given name.
 71        """
 72        box = self.get_box()
 73        deck = box.deck
 74        deck._deck.set_style(
 75            deck.resources._resources,
 76            name,
 77            style,
 78            False,
 79            box.slide._slide_id,
 80            box._box_id,
 81        )
 82
 83    def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
 84        """
 85        Load a text style and merge it with the `style` and save it back.
 86        Throws an exception if a style under given name does not exist.
 87        """
 88        box = self.get_box()
 89        deck = box.deck
 90        deck._deck.set_style(
 91            deck.resources._resources,
 92            name,
 93            style,
 94            True,
 95            box.slide._slide_id,
 96            box._box_id,
 97        )
 98
 99    def get_style(self, name: str, step: int = 1) -> TextStyle:
100        """
101        Get text style under given name. Style is returned for a given `step`.
102        Throws an exception if a style under given name does not exist.
103
104        This function returns text style even when InSteps was used to set the style,
105        as it returns text style for a given step.
106        """
107
108        box = self.get_box()
109        return _data_to_text_style(box.deck._deck.get_style(name, step, box.slide._slide_id, box._box_id))
110
111    def image(
112        self,
113        path_or_data: PathOrData | InSteps[PathOrData],
114        *,
115        enable_steps=True,
116        shift_steps=0,
117        **box_args,
118    ):
119        """
120        Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA
121        """
122        assert shift_steps >= 0
123
124        def process_path(p):
125            if not isinstance(p, str):
126                return p
127            if slide.image_directory is not None:
128                p = os.path.join(slide.image_directory, p)
129            p = os.path.abspath(p)
130            watch_path(p)
131            return p
132
133        slide = self.get_box().slide
134        if isinstance(path_or_data, InSteps):
135            path_or_data = path_or_data.map(process_path)
136        else:
137            path_or_data = process_path(path_or_data)
138        image = ImageContent(
139            path_or_data=path_or_data,
140            enable_steps=enable_steps,
141            shift_steps=shift_steps,
142        )
143        return self.box(_content=image, **box_args)
144
145    def text(
146        self,
147        text: str | InSteps[str],
148        style: str | TextStyle | InSteps[TextStyle] | None = None,
149        *,
150        parse_styles: bool = True,
151        style_delimiters: str | None = "~{}",
152        tab_width: int = 4,
153        align: TextAlign = "start",
154        strip=True,
155        parse_counters: bool = False,
156        **box_args,
157    ):
158        """
159        Create a box with a text.
160        """
161        box_args.setdefault("name", "text")
162        return self._text_box(
163            text,
164            style,
165            None,
166            style_delimiters if parse_styles else None,
167            tab_width,
168            box_args,
169            align,
170            None,
171            None,
172            strip,
173            parse_counters,
174        )
175
176    def code(
177        self,
178        text: str | InSteps[str],
179        language: str | None = "default",
180        style: str | TextStyle | InSteps[TextStyle] | None = None,
181        *,
182        theme: str | None = None,
183        parse_styles: bool = False,
184        style_delimiters: str | None = "~{}",
185        tab_width: int = 4,
186        align: TextAlign = "start",
187        strip: bool = True,
188        parse_counters: bool = False,
189        **box_args,
190    ):
191        """
192        Create a box with a syntax highlighted text.
193        """
194        box_args.setdefault("name", "code")
195        if theme is None:
196            theme = self.get_box().deck.default_code_theme
197        if language == "default":
198            language = self.get_box().deck.default_code_language
199        return self._text_box(
200            text,
201            "code",
202            style,
203            style_delimiters if parse_styles else None,
204            tab_width,
205            box_args,
206            align,
207            language,
208            theme,
209            strip,
210            parse_counters,
211        )
212
213    def _text_box(
214        self,
215        text,
216        style1,
217        style2,
218        delimiters,
219        tab_width,
220        box_args,
221        align,
222        language,
223        theme,
224        strip,
225        parse_counters,
226    ):
227        def text_preprocess(x):
228            if strip:
229                x = x.strip()
230            return x.replace("\t", " " * tab_width)
231
232        if isinstance(text, str):
233            text = text_preprocess(text)
234        elif isinstance(text, list):
235            text = zip_in_steps(text, "").map(lambda x: text_preprocess("".join(x)))
236        elif isinstance(text, InSteps):
237            text = text.map(text_preprocess)
238        else:
239            raise Exception("Invalid type for text")
240
241        if align == "start":
242            align = 0
243        elif align == "center":
244            align = 1
245        elif align == "end":
246            align = 2
247        else:
248            raise Exception(f"Invalid alignment: {align}")
249        text_content = TextContent(
250            text=text,
251            style1=style1,
252            style2=style2,
253            formatting_delimiters=delimiters,
254            text_align=align,
255            syntax_language=language,
256            syntax_theme=theme,
257            parse_counters=parse_counters,
258        )
259        return self.box(_content=text_content, **box_args)
260
261    def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]):
262        """
263        Draw one or more paths in the slide.
264        """
265
266        if isinstance(paths, Path):
267            paths = [paths]
268        elif isinstance(paths, InSteps):
269            paths = paths.map(lambda p: [p] if isinstance(p, Path) else p)
270        box = self.get_box()
271        box.deck._deck.draw(box.slide._slide_id, box._box_id, paths)
272
273    def video(
274        self,
275        path: str,
276        *,
277        data_type: str = "video/mp4",
278        cover_image: str | None = None,
279        show_controls: bool = False,
280        **box_args,
281    ):
282        """
283        Insert video into slide.````
284        """
285        if cover_image:
286            slide = self.get_box().slide
287            if slide.image_directory is not None:
288                cover_image = os.path.join(slide.image_directory, cover_image)
289            cover_image = os.path.abspath(cover_image)
290            watch_path(cover_image)
291        path = os.path.abspath(path)
292        watch_path(path)
293        video = VideoContent(path=path, data_type=data_type, cover_image=cover_image, show_controls=show_controls)
294        return self.box(_content=video, **box_args)
295
296    def box(
297        self,
298        *,
299        active: bool | str | int | InSteps[bool] = True,
300        show: bool | str | int | InSteps[bool] = True,
301        z_level: int | InSteps[int] | None = None,
302        x: Position | InSteps[Position] = None,
303        y: Position | InSteps[Position] = None,
304        width: Size | InSteps[Size] = None,
305        height: Size | InSteps[Size] = None,
306        border_radius: float | InSteps[float] = 0,
307        p_left: Length | InSteps[Length] | None = None,
308        p_right: Length | InSteps[Length] | None = None,
309        p_top: Length | InSteps[Length] | None = None,
310        p_bottom: Length | InSteps[Length] | None = None,
311        p_x: Length | InSteps[Length] = 0,
312        p_y: Length | InSteps[Length] = 0,
313        m_left: LengthAuto | InSteps[LengthAuto] | None = None,
314        m_right: LengthAuto | InSteps[LengthAuto] | None = None,
315        m_top: LengthAuto | InSteps[LengthAuto] | None = None,
316        m_bottom: LengthAuto | InSteps[LengthAuto] | None = None,
317        m_x: LengthAuto | InSteps[LengthAuto] = 0,
318        m_y: LengthAuto | InSteps[LengthAuto] = 0,
319        row: bool | InSteps[bool] = False,
320        reverse: bool | InSteps[bool] = False,
321        flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap",
322        flex_grow: float | InSteps[float] = 0.0,
323        flex_shrink: float | InSteps[float] = 1.0,
324        align_items: AlignItemsSteps = None,
325        align_self: AlignItemsSteps = None,
326        justify_self: AlignItemsSteps = None,
327        align_content: AlignContentSteps = None,
328        justify_content: AlignContentSteps = None,
329        gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0),
330        grid_template_rows: GridTemplate = (),
331        grid_template_columns: GridTemplate = (),
332        grid_row: GridPosition = "auto",
333        grid_column: GridPosition = "auto",
334        bg_color: str | None | InSteps[str | None] = None,
335        url: None | str | InSteps[None | str] = None,
336        name: str = "",
337        debug_layout: bool | str | None = None,
338        replace_steps: dict[int, int] | None = None,
339        _content: NodeContent | InSteps[NodeContent] = None,
340    ):
341        """
342        Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation
343        """
344        parent_box = self.get_box()
345        if debug_layout is None:
346            debug_layout = parent_box.slide.debug_layout
347        else:
348            debug_layout = parse_debug_layout(debug_layout)
349        if z_level is None:
350            z_level = parent_box.z_level
351
352        if p_left is None:
353            p_left = p_x
354        if p_right is None:
355            p_right = p_x
356        if p_bottom is None:
357            p_bottom = p_y
358        if p_top is None:
359            p_top = p_y
360
361        if m_left is None:
362            m_left = m_x
363        if m_right is None:
364            m_right = m_x
365        if m_bottom is None:
366            m_bottom = m_y
367        if m_top is None:
368            m_top = m_y
369
370        deck = parent_box.deck
371        box_id, node_id = deck._deck.new_box(
372            deck.resources._resources,
373            parent_box.slide._slide_id,
374            parent_box._box_id,
375            active=active,
376            show=show,
377            z_level=z_level,
378            x=x,
379            y=y,
380            width=width,
381            height=height,
382            border_radius=border_radius,
383            p_left=p_left,
384            p_right=p_right,
385            p_top=p_top,
386            p_bottom=p_bottom,
387            m_left=m_left,
388            m_right=m_right,
389            m_top=m_top,
390            m_bottom=m_bottom,
391            row=row,
392            reverse=reverse,
393            flex_wrap=flex_wrap,
394            flex_grow=flex_grow,
395            flex_shrink=flex_shrink,
396            align_items=align_items,
397            align_self=align_self,
398            justify_self=justify_self,
399            align_content=align_content,
400            justify_content=justify_content,
401            gap=gap,
402            grid_template_rows=grid_template_rows,
403            grid_template_columns=grid_template_columns,
404            grid_row=grid_row,
405            grid_column=grid_column,
406            bg_color=bg_color,
407            url=url,
408            name=name,
409            debug_layout=debug_layout,
410            replace_steps=replace_steps,
411            content=_content,
412        )
413        return Box(deck, parent_box.slide, box_id, node_id, name, z_level)
414
415    def overlay(self, **box_args):
416        """
417        Create a new box that spans over the box
418        """
419        box_args.setdefault("x", 0)
420        box_args.setdefault("y", 0)
421        box_args.setdefault("width", "100%")
422        box_args.setdefault("height", "100%")
423        return self.box(**box_args)
424
425    def line_box(self, line_idx: int, **box_args):
426        """
427        Creates a new box over a text line in the box
428        """
429        return self.box(
430            x=self.line_x(line_idx),
431            y=self.line_y(line_idx),
432            width=self.line_width(line_idx),
433            height=self.line_height(line_idx),
434            **box_args,
435        )
436
437    def text_anchor_box(self, anchor_id: int, **box_args):
438        """
439        Creates a new box over a text anchor in the box
440        """
441
442        return self.box(
443            x=self.text_anchor_x(anchor_id),
444            y=self.text_anchor_y(anchor_id),
445            width=self.text_anchor_width(anchor_id),
446            height=self.text_anchor_height(anchor_id),
447            **box_args,
448        )
449
450    def x(self, width_fraction: float | int | None = None) -> LayoutExpr:
451        """
452        Get an expression with X coordinate relative to the box.
453        """
454
455        node_id = self.get_box().node_id
456        expr = LayoutExpr.x(node_id)
457        if width_fraction is None:
458            return expr
459        return expr + LayoutExpr.width(node_id, width_fraction)
460
461    def y(self, height_fraction: float | int | None = None) -> LayoutExpr:
462        """
463        Get an expression with Y coordinate relative to the box.
464        """
465        node_id = self.get_box().node_id
466        expr = LayoutExpr.y(node_id)
467        if height_fraction is None:
468            return expr
469        return expr + LayoutExpr.height(node_id, height_fraction)
470
471    def width(self, fraction: float | int = 1.0) -> LayoutExpr:
472        """
473        Get an expression with width of the parent box.
474        """
475        node_id = self.get_box().node_id
476        return LayoutExpr.width(node_id, fraction)
477
478    def height(self, fraction: float | int = 1.0) -> LayoutExpr:
479        """
480        Get an expression with height of the parent box.
481        """
482        node_id = self.get_box().node_id
483        return LayoutExpr.height(node_id, fraction)
484
485    def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr:
486        """
487        Get an expression with X coordinate of a given line of text in the box.
488        """
489        node_id = self.get_box().node_id
490        expr = LayoutExpr.line_x(node_id, line_idx)
491        if width_fraction is None:
492            return expr
493        return expr + LayoutExpr.line_width(node_id, line_idx, width_fraction)
494
495    def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr:
496        """
497        Get an expression with Y coordinate of a given line of text in the box.
498        """
499        node_id = self.get_box().node_id
500        expr = LayoutExpr.line_y(node_id, line_idx)
501        if height_fraction is None:
502            return expr
503        return expr + LayoutExpr.line_height(node_id, line_idx, height_fraction)
504
505    def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
506        """
507        Get an expression with a width of a given line of text in the box.
508        """
509        node_id = self.get_box().node_id
510        return LayoutExpr.line_width(node_id, line_idx, fraction)
511
512    def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
513        """
514        Get an expression with a height of a given line of text in the box.
515        """
516        node_id = self.get_box().node_id
517        return LayoutExpr.line_height(node_id, line_idx, fraction)
518
519    def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr:
520        """
521        Get an expression with X coordinate of a given text anchor in the box.
522        """
523        node_id = self.get_box().node_id
524        expr = LayoutExpr.text_anchor_x(node_id, anchor_id)
525        if width_fraction is None:
526            return expr
527        return expr + LayoutExpr.text_anchor_width(node_id, anchor_id, width_fraction)
528
529    def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr:
530        """
531        Get an expression with Y coordinate of a given text anchor in the box.
532        """
533        node_id = self.get_box().node_id
534        expr = LayoutExpr.text_anchor_y(node_id, anchor_id)
535        if height_fraction is None:
536            return expr
537        return expr + LayoutExpr.text_anchor_height(node_id, anchor_id, height_fraction)
538
539    def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
540        """
541        Get an expression with a height of a given text anchor in the box.
542        """
543        node_id = self.get_box().node_id
544        return LayoutExpr.text_anchor_width(node_id, anchor_id, fraction)
545
546    def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
547        """
548        Get an expression with a height of a given text anchor in the box.
549        """
550        node_id = self.get_box().node_id
551        return LayoutExpr.text_anchor_height(node_id, anchor_id, fraction)
def set_style( self, name: str, style: Union[TextStyle, InSteps[TextStyle]]):
68    def set_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
69        """
70        Set text style under given name.
71        """
72        box = self.get_box()
73        deck = box.deck
74        deck._deck.set_style(
75            deck.resources._resources,
76            name,
77            style,
78            False,
79            box.slide._slide_id,
80            box._box_id,
81        )

Set text style under given name.

def update_style( self, name: str, style: Union[TextStyle, InSteps[TextStyle]]):
83    def update_style(self, name: str, style: TextStyle | InSteps[TextStyle]):
84        """
85        Load a text style and merge it with the `style` and save it back.
86        Throws an exception if a style under given name does not exist.
87        """
88        box = self.get_box()
89        deck = box.deck
90        deck._deck.set_style(
91            deck.resources._resources,
92            name,
93            style,
94            True,
95            box.slide._slide_id,
96            box._box_id,
97        )

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:
 99    def get_style(self, name: str, step: int = 1) -> TextStyle:
100        """
101        Get text style under given name. Style is returned for a given `step`.
102        Throws an exception if a style under given name does not exist.
103
104        This function returns text style even when InSteps was used to set the style,
105        as it returns text style for a given step.
106        """
107
108        box = self.get_box()
109        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_or_data: Union[str, NoneType, tuple[bytes, str], InSteps[str | None | tuple[bytes, str]]], *, enable_steps=True, shift_steps=0, **box_args):
111    def image(
112        self,
113        path_or_data: PathOrData | InSteps[PathOrData],
114        *,
115        enable_steps=True,
116        shift_steps=0,
117        **box_args,
118    ):
119        """
120        Create a box with an image. Supported formats: SVG, PNG, JPEG, GIF, ORA
121        """
122        assert shift_steps >= 0
123
124        def process_path(p):
125            if not isinstance(p, str):
126                return p
127            if slide.image_directory is not None:
128                p = os.path.join(slide.image_directory, p)
129            p = os.path.abspath(p)
130            watch_path(p)
131            return p
132
133        slide = self.get_box().slide
134        if isinstance(path_or_data, InSteps):
135            path_or_data = path_or_data.map(process_path)
136        else:
137            path_or_data = process_path(path_or_data)
138        image = ImageContent(
139            path_or_data=path_or_data,
140            enable_steps=enable_steps,
141            shift_steps=shift_steps,
142        )
143        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):
145    def text(
146        self,
147        text: str | InSteps[str],
148        style: str | TextStyle | InSteps[TextStyle] | None = None,
149        *,
150        parse_styles: bool = True,
151        style_delimiters: str | None = "~{}",
152        tab_width: int = 4,
153        align: TextAlign = "start",
154        strip=True,
155        parse_counters: bool = False,
156        **box_args,
157    ):
158        """
159        Create a box with a text.
160        """
161        box_args.setdefault("name", "text")
162        return self._text_box(
163            text,
164            style,
165            None,
166            style_delimiters if parse_styles else None,
167            tab_width,
168            box_args,
169            align,
170            None,
171            None,
172            strip,
173            parse_counters,
174        )

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):
176    def code(
177        self,
178        text: str | InSteps[str],
179        language: str | None = "default",
180        style: str | TextStyle | InSteps[TextStyle] | None = None,
181        *,
182        theme: str | None = None,
183        parse_styles: bool = False,
184        style_delimiters: str | None = "~{}",
185        tab_width: int = 4,
186        align: TextAlign = "start",
187        strip: bool = True,
188        parse_counters: bool = False,
189        **box_args,
190    ):
191        """
192        Create a box with a syntax highlighted text.
193        """
194        box_args.setdefault("name", "code")
195        if theme is None:
196            theme = self.get_box().deck.default_code_theme
197        if language == "default":
198            language = self.get_box().deck.default_code_language
199        return self._text_box(
200            text,
201            "code",
202            style,
203            style_delimiters if parse_styles else None,
204            tab_width,
205            box_args,
206            align,
207            language,
208            theme,
209            strip,
210            parse_counters,
211        )

Create a box with a syntax highlighted text.

def draw( self, paths: Union[Path, list[Path], InSteps[Path | list[Path]]]):
261    def draw(self, paths: Path | list[Path] | InSteps[Path | list[Path]]):
262        """
263        Draw one or more paths in the slide.
264        """
265
266        if isinstance(paths, Path):
267            paths = [paths]
268        elif isinstance(paths, InSteps):
269            paths = paths.map(lambda p: [p] if isinstance(p, Path) else p)
270        box = self.get_box()
271        box.deck._deck.draw(box.slide._slide_id, box._box_id, paths)

Draw one or more paths in the slide.

def video( self, path: str, *, data_type: str = 'video/mp4', cover_image: str | None = None, show_controls: bool = False, **box_args):
273    def video(
274        self,
275        path: str,
276        *,
277        data_type: str = "video/mp4",
278        cover_image: str | None = None,
279        show_controls: bool = False,
280        **box_args,
281    ):
282        """
283        Insert video into slide.````
284        """
285        if cover_image:
286            slide = self.get_box().slide
287            if slide.image_directory is not None:
288                cover_image = os.path.join(slide.image_directory, cover_image)
289            cover_image = os.path.abspath(cover_image)
290            watch_path(cover_image)
291        path = os.path.abspath(path)
292        watch_path(path)
293        video = VideoContent(path=path, data_type=data_type, cover_image=cover_image, show_controls=show_controls)
294        return self.box(_content=video, **box_args)

Insert video into 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, nelsie.box.VideoContent, NoneType, InSteps[nelsie.box.ImageContent | nelsie.box.TextContent | nelsie.box.VideoContent | None]] = None):
296    def box(
297        self,
298        *,
299        active: bool | str | int | InSteps[bool] = True,
300        show: bool | str | int | InSteps[bool] = True,
301        z_level: int | InSteps[int] | None = None,
302        x: Position | InSteps[Position] = None,
303        y: Position | InSteps[Position] = None,
304        width: Size | InSteps[Size] = None,
305        height: Size | InSteps[Size] = None,
306        border_radius: float | InSteps[float] = 0,
307        p_left: Length | InSteps[Length] | None = None,
308        p_right: Length | InSteps[Length] | None = None,
309        p_top: Length | InSteps[Length] | None = None,
310        p_bottom: Length | InSteps[Length] | None = None,
311        p_x: Length | InSteps[Length] = 0,
312        p_y: Length | InSteps[Length] = 0,
313        m_left: LengthAuto | InSteps[LengthAuto] | None = None,
314        m_right: LengthAuto | InSteps[LengthAuto] | None = None,
315        m_top: LengthAuto | InSteps[LengthAuto] | None = None,
316        m_bottom: LengthAuto | InSteps[LengthAuto] | None = None,
317        m_x: LengthAuto | InSteps[LengthAuto] = 0,
318        m_y: LengthAuto | InSteps[LengthAuto] = 0,
319        row: bool | InSteps[bool] = False,
320        reverse: bool | InSteps[bool] = False,
321        flex_wrap: FlexWrap | InSteps[FlexWrap] = "nowrap",
322        flex_grow: float | InSteps[float] = 0.0,
323        flex_shrink: float | InSteps[float] = 1.0,
324        align_items: AlignItemsSteps = None,
325        align_self: AlignItemsSteps = None,
326        justify_self: AlignItemsSteps = None,
327        align_content: AlignContentSteps = None,
328        justify_content: AlignContentSteps = None,
329        gap: tuple[Length, Length] | InSteps[tuple[Length, Length]] = (0.0, 0.0),
330        grid_template_rows: GridTemplate = (),
331        grid_template_columns: GridTemplate = (),
332        grid_row: GridPosition = "auto",
333        grid_column: GridPosition = "auto",
334        bg_color: str | None | InSteps[str | None] = None,
335        url: None | str | InSteps[None | str] = None,
336        name: str = "",
337        debug_layout: bool | str | None = None,
338        replace_steps: dict[int, int] | None = None,
339        _content: NodeContent | InSteps[NodeContent] = None,
340    ):
341        """
342        Create a new child box. See [Box reference](https://spirali.github.io/nelsie/guide/box/) for documentation
343        """
344        parent_box = self.get_box()
345        if debug_layout is None:
346            debug_layout = parent_box.slide.debug_layout
347        else:
348            debug_layout = parse_debug_layout(debug_layout)
349        if z_level is None:
350            z_level = parent_box.z_level
351
352        if p_left is None:
353            p_left = p_x
354        if p_right is None:
355            p_right = p_x
356        if p_bottom is None:
357            p_bottom = p_y
358        if p_top is None:
359            p_top = p_y
360
361        if m_left is None:
362            m_left = m_x
363        if m_right is None:
364            m_right = m_x
365        if m_bottom is None:
366            m_bottom = m_y
367        if m_top is None:
368            m_top = m_y
369
370        deck = parent_box.deck
371        box_id, node_id = deck._deck.new_box(
372            deck.resources._resources,
373            parent_box.slide._slide_id,
374            parent_box._box_id,
375            active=active,
376            show=show,
377            z_level=z_level,
378            x=x,
379            y=y,
380            width=width,
381            height=height,
382            border_radius=border_radius,
383            p_left=p_left,
384            p_right=p_right,
385            p_top=p_top,
386            p_bottom=p_bottom,
387            m_left=m_left,
388            m_right=m_right,
389            m_top=m_top,
390            m_bottom=m_bottom,
391            row=row,
392            reverse=reverse,
393            flex_wrap=flex_wrap,
394            flex_grow=flex_grow,
395            flex_shrink=flex_shrink,
396            align_items=align_items,
397            align_self=align_self,
398            justify_self=justify_self,
399            align_content=align_content,
400            justify_content=justify_content,
401            gap=gap,
402            grid_template_rows=grid_template_rows,
403            grid_template_columns=grid_template_columns,
404            grid_row=grid_row,
405            grid_column=grid_column,
406            bg_color=bg_color,
407            url=url,
408            name=name,
409            debug_layout=debug_layout,
410            replace_steps=replace_steps,
411            content=_content,
412        )
413        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):
415    def overlay(self, **box_args):
416        """
417        Create a new box that spans over the box
418        """
419        box_args.setdefault("x", 0)
420        box_args.setdefault("y", 0)
421        box_args.setdefault("width", "100%")
422        box_args.setdefault("height", "100%")
423        return self.box(**box_args)

Create a new box that spans over the box

def line_box(self, line_idx: int, **box_args):
425    def line_box(self, line_idx: int, **box_args):
426        """
427        Creates a new box over a text line in the box
428        """
429        return self.box(
430            x=self.line_x(line_idx),
431            y=self.line_y(line_idx),
432            width=self.line_width(line_idx),
433            height=self.line_height(line_idx),
434            **box_args,
435        )

Creates a new box over a text line in the box

def text_anchor_box(self, anchor_id: int, **box_args):
437    def text_anchor_box(self, anchor_id: int, **box_args):
438        """
439        Creates a new box over a text anchor in the box
440        """
441
442        return self.box(
443            x=self.text_anchor_x(anchor_id),
444            y=self.text_anchor_y(anchor_id),
445            width=self.text_anchor_width(anchor_id),
446            height=self.text_anchor_height(anchor_id),
447            **box_args,
448        )

Creates a new box over a text anchor in the box

def x( self, width_fraction: float | int | None = None) -> nelsie.layoutexpr.LayoutExpr:
450    def x(self, width_fraction: float | int | None = None) -> LayoutExpr:
451        """
452        Get an expression with X coordinate relative to the box.
453        """
454
455        node_id = self.get_box().node_id
456        expr = LayoutExpr.x(node_id)
457        if width_fraction is None:
458            return expr
459        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:
461    def y(self, height_fraction: float | int | None = None) -> LayoutExpr:
462        """
463        Get an expression with Y coordinate relative to the box.
464        """
465        node_id = self.get_box().node_id
466        expr = LayoutExpr.y(node_id)
467        if height_fraction is None:
468            return expr
469        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:
471    def width(self, fraction: float | int = 1.0) -> LayoutExpr:
472        """
473        Get an expression with width of the parent box.
474        """
475        node_id = self.get_box().node_id
476        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:
478    def height(self, fraction: float | int = 1.0) -> LayoutExpr:
479        """
480        Get an expression with height of the parent box.
481        """
482        node_id = self.get_box().node_id
483        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:
485    def line_x(self, line_idx: int, width_fraction: float | int | None = None) -> LayoutExpr:
486        """
487        Get an expression with X coordinate of a given line of text in the box.
488        """
489        node_id = self.get_box().node_id
490        expr = LayoutExpr.line_x(node_id, line_idx)
491        if width_fraction is None:
492            return expr
493        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:
495    def line_y(self, line_idx: int, height_fraction: float | int | None = None) -> LayoutExpr:
496        """
497        Get an expression with Y coordinate of a given line of text in the box.
498        """
499        node_id = self.get_box().node_id
500        expr = LayoutExpr.line_y(node_id, line_idx)
501        if height_fraction is None:
502            return expr
503        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:
505    def line_width(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
506        """
507        Get an expression with a width of a given line of text in the box.
508        """
509        node_id = self.get_box().node_id
510        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:
512    def line_height(self, line_idx: int, fraction: float | int = 1.0) -> LayoutExpr:
513        """
514        Get an expression with a height of a given line of text in the box.
515        """
516        node_id = self.get_box().node_id
517        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:
519    def text_anchor_x(self, anchor_id: int, width_fraction: float | int | None = None) -> LayoutExpr:
520        """
521        Get an expression with X coordinate of a given text anchor in the box.
522        """
523        node_id = self.get_box().node_id
524        expr = LayoutExpr.text_anchor_x(node_id, anchor_id)
525        if width_fraction is None:
526            return expr
527        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:
529    def text_anchor_y(self, anchor_id: int, height_fraction: float | int | None = None) -> LayoutExpr:
530        """
531        Get an expression with Y coordinate of a given text anchor in the box.
532        """
533        node_id = self.get_box().node_id
534        expr = LayoutExpr.text_anchor_y(node_id, anchor_id)
535        if height_fraction is None:
536            return expr
537        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:
539    def text_anchor_width(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
540        """
541        Get an expression with a height of a given text anchor in the box.
542        """
543        node_id = self.get_box().node_id
544        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:
546    def text_anchor_height(self, anchor_id: int, fraction: float | int = 1.0) -> LayoutExpr:
547        """
548        Get an expression with a height of a given text anchor in the box.
549        """
550        node_id = self.get_box().node_id
551        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):
554class Box(BoxBuilder):
555    """
556    The box in slide layout.
557
558    It should be created via calling method `.box()` on a slide or another box.
559    Note that interesting methods came from Box's parent: BoxBuilder.
560    """
561
562    def __init__(
563        self,
564        deck,
565        slide,
566        box_id,
567        node_id,
568        name: str,
569        z_level: int,
570    ):
571        """
572        @private
573        """
574        self.deck = deck
575        self.slide = slide
576        self._box_id = box_id
577        self.node_id = node_id
578        self.name = name
579        self.z_level = z_level
580
581    def get_box(self):
582        """
583        @private
584        """
585        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):
 61class Slide(BoxBuilder):
 62    """
 63    Represents a slide in a slide deck.
 64
 65    It should be created via calling method `.new_slide()` on a deck via decorator `@deck.slide()`
 66    """
 67
 68    def __init__(
 69        self,
 70        deck: "SlideDeck",
 71        slide_id: int,
 72        name: str,
 73        image_directory: str,
 74        debug_layout: str | None,
 75    ):
 76        """
 77        @private
 78        """
 79        self.deck = deck
 80        self._slide_id = slide_id
 81        self.name = name
 82        self.image_directory = image_directory
 83        self.debug_layout = debug_layout
 84        self.root_box = Box(deck, self, [], 0, name, 0)
 85
 86    def get_box(self):
 87        """
 88        @private
 89        """
 90        return self.root_box
 91
 92    def insert_step(self, value: Step):
 93        self.deck._deck.insert_step(self._slide_id, value)
 94
 95    def remove_step(self, value: Step):
 96        self.deck._deck.remove_step(self._slide_id, value)
 97
 98    def remove_steps_below(self, value: Step):
 99        self.deck._deck.remove_steps_below(self._slide_id, value)
100
101    def remove_steps_above(self, value: Step):
102        self.deck._deck.remove_steps_above(self._slide_id, value)
103
104    def set_steps(self, values: set[Step] | frozenset[Step]):
105        self.deck._deck.set_steps(self._slide_id, values)
106
107    def get_steps(self) -> list[Step]:
108        return self.deck._deck.get_steps(self._slide_id)
109
110    def new_slide_at(self, step: int, **slide_kwargs):
111        slide_kwargs["parent_slide"] = (self._slide_id, step)
112        return self.deck.new_slide(**slide_kwargs)
113
114    def slide_at(self, step: int, **slide_kwargs):
115        slide_kwargs["parent_slide"] = (self._slide_id, step)
116        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]):
92    def insert_step(self, value: Step):
93        self.deck._deck.insert_step(self._slide_id, value)
def remove_step(self, value: tuple[int]):
95    def remove_step(self, value: Step):
96        self.deck._deck.remove_step(self._slide_id, value)
def remove_steps_below(self, value: tuple[int]):
98    def remove_steps_below(self, value: Step):
99        self.deck._deck.remove_steps_below(self._slide_id, value)
def remove_steps_above(self, value: tuple[int]):
101    def remove_steps_above(self, value: Step):
102        self.deck._deck.remove_steps_above(self._slide_id, value)
def set_steps(self, values: set[tuple[int]] | frozenset[tuple[int]]):
104    def set_steps(self, values: set[Step] | frozenset[Step]):
105        self.deck._deck.set_steps(self._slide_id, values)
def get_steps(self) -> list[tuple[int]]:
107    def get_steps(self) -> list[Step]:
108        return self.deck._deck.get_steps(self._slide_id)
def new_slide_at(self, step: int, **slide_kwargs):
110    def new_slide_at(self, step: int, **slide_kwargs):
111        slide_kwargs["parent_slide"] = (self._slide_id, step)
112        return self.deck.new_slide(**slide_kwargs)
def slide_at(self, step: int, **slide_kwargs):
114    def slide_at(self, step: int, **slide_kwargs):
115        slide_kwargs["parent_slide"] = (self._slide_id, step)
116        return self.deck.slide(**slide_kwargs)